Sebastian Kuschel reports that pfd_closing can be called for a socket
[u/mdw/putty] / unix / gtkcols.c
CommitLineData
d9b15094 1/*
2 * gtkcols.c - implementation of the `Columns' GTK layout container.
3 */
4
5#include "gtkcols.h"
f160b7b8 6#include <gtk/gtk.h>
d9b15094 7
8static void columns_init(Columns *cols);
9static void columns_class_init(ColumnsClass *klass);
10static void columns_map(GtkWidget *widget);
11static void columns_unmap(GtkWidget *widget);
f160b7b8 12#if !GTK_CHECK_VERSION(2,0,0)
d9b15094 13static void columns_draw(GtkWidget *widget, GdkRectangle *area);
14static gint columns_expose(GtkWidget *widget, GdkEventExpose *event);
f160b7b8 15#endif
d9b15094 16static void columns_base_add(GtkContainer *container, GtkWidget *widget);
17static void columns_remove(GtkContainer *container, GtkWidget *widget);
18static void columns_forall(GtkContainer *container, gboolean include_internals,
19 GtkCallback callback, gpointer callback_data);
f160b7b8 20#if !GTK_CHECK_VERSION(2,0,0)
d9b15094 21static gint columns_focus(GtkContainer *container, GtkDirectionType dir);
f160b7b8 22#endif
d9b15094 23static GtkType columns_child_type(GtkContainer *container);
24static void columns_size_request(GtkWidget *widget, GtkRequisition *req);
25static void columns_size_allocate(GtkWidget *widget, GtkAllocation *alloc);
26
27static GtkContainerClass *parent_class = NULL;
28
f160b7b8 29#if !GTK_CHECK_VERSION(2,0,0)
d9b15094 30GtkType columns_get_type(void)
31{
32 static GtkType columns_type = 0;
33
34 if (!columns_type) {
35 static const GtkTypeInfo columns_info = {
36 "Columns",
37 sizeof(Columns),
38 sizeof(ColumnsClass),
39 (GtkClassInitFunc) columns_class_init,
40 (GtkObjectInitFunc) columns_init,
41 /* reserved_1 */ NULL,
42 /* reserved_2 */ NULL,
43 (GtkClassInitFunc) NULL,
44 };
45
46 columns_type = gtk_type_unique(GTK_TYPE_CONTAINER, &columns_info);
47 }
48
49 return columns_type;
50}
f160b7b8 51#else
52GType columns_get_type(void)
53{
54 static GType columns_type = 0;
55
56 if (!columns_type) {
57 static const GTypeInfo columns_info = {
58 sizeof(ColumnsClass),
59 NULL,
60 NULL,
61 (GClassInitFunc) columns_class_init,
62 NULL,
63 NULL,
64 sizeof(Columns),
65 0,
66 (GInstanceInitFunc)columns_init,
67 };
68
69 columns_type = g_type_register_static(GTK_TYPE_CONTAINER, "Columns",
70 &columns_info, 0);
71 }
72
73 return columns_type;
74}
75#endif
d9b15094 76
f160b7b8 77#if !GTK_CHECK_VERSION(2,0,0)
d9b15094 78static gint (*columns_inherited_focus)(GtkContainer *container,
79 GtkDirectionType direction);
f160b7b8 80#endif
d9b15094 81
82static void columns_class_init(ColumnsClass *klass)
83{
f160b7b8 84#if !GTK_CHECK_VERSION(2,0,0)
85 /* GtkObjectClass *object_class = (GtkObjectClass *)klass; */
86 GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
87 GtkContainerClass *container_class = (GtkContainerClass *)klass;
88#else
89 /* GObjectClass *object_class = G_OBJECT_CLASS(klass); */
90 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
91 GtkContainerClass *container_class = GTK_CONTAINER_CLASS(klass);
92#endif
93
94#if !GTK_CHECK_VERSION(2,0,0)
d9b15094 95 parent_class = gtk_type_class(GTK_TYPE_CONTAINER);
f160b7b8 96#else
97 parent_class = g_type_class_peek_parent(klass);
98#endif
d9b15094 99
100 widget_class->map = columns_map;
101 widget_class->unmap = columns_unmap;
f160b7b8 102#if !GTK_CHECK_VERSION(2,0,0)
d9b15094 103 widget_class->draw = columns_draw;
104 widget_class->expose_event = columns_expose;
f160b7b8 105#endif
d9b15094 106 widget_class->size_request = columns_size_request;
107 widget_class->size_allocate = columns_size_allocate;
108
109 container_class->add = columns_base_add;
110 container_class->remove = columns_remove;
111 container_class->forall = columns_forall;
112 container_class->child_type = columns_child_type;
f160b7b8 113#if !GTK_CHECK_VERSION(2,0,0)
d9b15094 114 /* Save the previous value of this method. */
115 if (!columns_inherited_focus)
116 columns_inherited_focus = container_class->focus;
117 container_class->focus = columns_focus;
f160b7b8 118#endif
d9b15094 119}
120
121static void columns_init(Columns *cols)
122{
123 GTK_WIDGET_SET_FLAGS(cols, GTK_NO_WINDOW);
124
125 cols->children = NULL;
126 cols->spacing = 0;
127}
128
129/*
130 * These appear to be thoroughly tedious functions; the only reason
131 * we have to reimplement them at all is because we defined our own
132 * format for our GList of children...
133 */
134static void columns_map(GtkWidget *widget)
135{
136 Columns *cols;
137 ColumnsChild *child;
138 GList *children;
139
140 g_return_if_fail(widget != NULL);
141 g_return_if_fail(IS_COLUMNS(widget));
142
143 cols = COLUMNS(widget);
144 GTK_WIDGET_SET_FLAGS(cols, GTK_MAPPED);
145
146 for (children = cols->children;
147 children && (child = children->data);
148 children = children->next) {
149 if (child->widget &&
150 GTK_WIDGET_VISIBLE(child->widget) &&
151 !GTK_WIDGET_MAPPED(child->widget))
152 gtk_widget_map(child->widget);
153 }
154}
155static void columns_unmap(GtkWidget *widget)
156{
157 Columns *cols;
158 ColumnsChild *child;
159 GList *children;
160
161 g_return_if_fail(widget != NULL);
162 g_return_if_fail(IS_COLUMNS(widget));
163
164 cols = COLUMNS(widget);
165 GTK_WIDGET_UNSET_FLAGS(cols, GTK_MAPPED);
166
167 for (children = cols->children;
168 children && (child = children->data);
169 children = children->next) {
170 if (child->widget &&
171 GTK_WIDGET_VISIBLE(child->widget) &&
172 GTK_WIDGET_MAPPED(child->widget))
173 gtk_widget_unmap(child->widget);
174 }
175}
f160b7b8 176#if !GTK_CHECK_VERSION(2,0,0)
d9b15094 177static void columns_draw(GtkWidget *widget, GdkRectangle *area)
178{
179 Columns *cols;
180 ColumnsChild *child;
181 GList *children;
182 GdkRectangle child_area;
183
184 g_return_if_fail(widget != NULL);
185 g_return_if_fail(IS_COLUMNS(widget));
186
187 if (GTK_WIDGET_DRAWABLE(widget)) {
188 cols = COLUMNS(widget);
189
190 for (children = cols->children;
191 children && (child = children->data);
192 children = children->next) {
193 if (child->widget &&
194 GTK_WIDGET_DRAWABLE(child->widget) &&
195 gtk_widget_intersect(child->widget, area, &child_area))
196 gtk_widget_draw(child->widget, &child_area);
197 }
198 }
199}
200static gint columns_expose(GtkWidget *widget, GdkEventExpose *event)
201{
202 Columns *cols;
203 ColumnsChild *child;
204 GList *children;
205 GdkEventExpose child_event;
206
207 g_return_val_if_fail(widget != NULL, FALSE);
208 g_return_val_if_fail(IS_COLUMNS(widget), FALSE);
209 g_return_val_if_fail(event != NULL, FALSE);
210
211 if (GTK_WIDGET_DRAWABLE(widget)) {
212 cols = COLUMNS(widget);
213 child_event = *event;
214
215 for (children = cols->children;
216 children && (child = children->data);
217 children = children->next) {
218 if (child->widget &&
219 GTK_WIDGET_DRAWABLE(child->widget) &&
220 GTK_WIDGET_NO_WINDOW(child->widget) &&
221 gtk_widget_intersect(child->widget, &event->area,
222 &child_event.area))
223 gtk_widget_event(child->widget, (GdkEvent *)&child_event);
224 }
225 }
226 return FALSE;
227}
f160b7b8 228#endif
d9b15094 229
230static void columns_base_add(GtkContainer *container, GtkWidget *widget)
231{
232 Columns *cols;
233
234 g_return_if_fail(container != NULL);
235 g_return_if_fail(IS_COLUMNS(container));
236 g_return_if_fail(widget != NULL);
237
238 cols = COLUMNS(container);
239
240 /*
241 * Default is to add a new widget spanning all columns.
242 */
243 columns_add(cols, widget, 0, 0); /* 0 means ncols */
244}
245
246static void columns_remove(GtkContainer *container, GtkWidget *widget)
247{
248 Columns *cols;
249 ColumnsChild *child;
250 GtkWidget *childw;
251 GList *children;
252 gboolean was_visible;
253
254 g_return_if_fail(container != NULL);
255 g_return_if_fail(IS_COLUMNS(container));
256 g_return_if_fail(widget != NULL);
257
258 cols = COLUMNS(container);
259
260 for (children = cols->children;
261 children && (child = children->data);
262 children = children->next) {
263 if (child->widget != widget)
264 continue;
265
266 was_visible = GTK_WIDGET_VISIBLE(widget);
267 gtk_widget_unparent(widget);
268 cols->children = g_list_remove_link(cols->children, children);
269 g_list_free(children);
270 g_free(child);
271 if (was_visible)
272 gtk_widget_queue_resize(GTK_WIDGET(container));
273 break;
274 }
275
276 for (children = cols->taborder;
277 children && (childw = children->data);
278 children = children->next) {
279 if (childw != widget)
280 continue;
281
282 cols->taborder = g_list_remove_link(cols->taborder, children);
283 g_list_free(children);
f160b7b8 284#if GTK_CHECK_VERSION(2,0,0)
285 gtk_container_set_focus_chain(container, cols->taborder);
286#endif
d9b15094 287 break;
288 }
289}
290
291static void columns_forall(GtkContainer *container, gboolean include_internals,
292 GtkCallback callback, gpointer callback_data)
293{
294 Columns *cols;
295 ColumnsChild *child;
39016687 296 GList *children, *next;
d9b15094 297
298 g_return_if_fail(container != NULL);
299 g_return_if_fail(IS_COLUMNS(container));
300 g_return_if_fail(callback != NULL);
301
302 cols = COLUMNS(container);
303
304 for (children = cols->children;
305 children && (child = children->data);
39016687 306 children = next) {
307 /*
308 * We can't wait until after the callback to assign
309 * `children = children->next', because the callback might
310 * be gtk_widget_destroy, which would remove the link
311 * `children' from the list! So instead we must get our
312 * hands on the value of the `next' pointer _before_ the
313 * callback.
314 */
315 next = children->next;
d9b15094 316 if (child->widget)
317 callback(child->widget, callback_data);
39016687 318 }
d9b15094 319}
320
321static GtkType columns_child_type(GtkContainer *container)
322{
323 return GTK_TYPE_WIDGET;
324}
325
326GtkWidget *columns_new(gint spacing)
327{
328 Columns *cols;
329
f160b7b8 330#if !GTK_CHECK_VERSION(2,0,0)
d9b15094 331 cols = gtk_type_new(columns_get_type());
f160b7b8 332#else
333 cols = g_object_new(TYPE_COLUMNS, NULL);
334#endif
335
d9b15094 336 cols->spacing = spacing;
337
338 return GTK_WIDGET(cols);
339}
340
341void columns_set_cols(Columns *cols, gint ncols, const gint *percentages)
342{
343 ColumnsChild *childdata;
344 gint i;
345
346 g_return_if_fail(cols != NULL);
347 g_return_if_fail(IS_COLUMNS(cols));
348 g_return_if_fail(ncols > 0);
349 g_return_if_fail(percentages != NULL);
350
351 childdata = g_new(ColumnsChild, 1);
352 childdata->widget = NULL;
353 childdata->ncols = ncols;
354 childdata->percentages = g_new(gint, ncols);
355 childdata->force_left = FALSE;
356 for (i = 0; i < ncols; i++)
357 childdata->percentages[i] = percentages[i];
358
359 cols->children = g_list_append(cols->children, childdata);
360}
361
362void columns_add(Columns *cols, GtkWidget *child,
363 gint colstart, gint colspan)
364{
365 ColumnsChild *childdata;
366
367 g_return_if_fail(cols != NULL);
368 g_return_if_fail(IS_COLUMNS(cols));
369 g_return_if_fail(child != NULL);
370 g_return_if_fail(child->parent == NULL);
371
372 childdata = g_new(ColumnsChild, 1);
373 childdata->widget = child;
374 childdata->colstart = colstart;
375 childdata->colspan = colspan;
376 childdata->force_left = FALSE;
377
378 cols->children = g_list_append(cols->children, childdata);
379 cols->taborder = g_list_append(cols->taborder, child);
380
381 gtk_widget_set_parent(child, GTK_WIDGET(cols));
382
f160b7b8 383#if GTK_CHECK_VERSION(2,0,0)
384 gtk_container_set_focus_chain(GTK_CONTAINER(cols), cols->taborder);
385#endif
386
d9b15094 387 if (GTK_WIDGET_REALIZED(cols))
388 gtk_widget_realize(child);
389
390 if (GTK_WIDGET_VISIBLE(cols) && GTK_WIDGET_VISIBLE(child)) {
391 if (GTK_WIDGET_MAPPED(cols))
392 gtk_widget_map(child);
393 gtk_widget_queue_resize(child);
394 }
395}
396
397void columns_force_left_align(Columns *cols, GtkWidget *widget)
398{
399 ColumnsChild *child;
400 GList *children;
401
402 g_return_if_fail(cols != NULL);
403 g_return_if_fail(IS_COLUMNS(cols));
404 g_return_if_fail(widget != NULL);
405
406 for (children = cols->children;
407 children && (child = children->data);
408 children = children->next) {
409 if (child->widget != widget)
410 continue;
411
412 child->force_left = TRUE;
413 if (GTK_WIDGET_VISIBLE(widget))
414 gtk_widget_queue_resize(GTK_WIDGET(cols));
415 break;
416 }
417}
418
419void columns_taborder_last(Columns *cols, GtkWidget *widget)
420{
421 GtkWidget *childw;
422 GList *children;
423
424 g_return_if_fail(cols != NULL);
425 g_return_if_fail(IS_COLUMNS(cols));
426 g_return_if_fail(widget != NULL);
427
428 for (children = cols->taborder;
429 children && (childw = children->data);
430 children = children->next) {
431 if (childw != widget)
432 continue;
433
434 cols->taborder = g_list_remove_link(cols->taborder, children);
435 g_list_free(children);
436 cols->taborder = g_list_append(cols->taborder, widget);
f160b7b8 437#if GTK_CHECK_VERSION(2,0,0)
438 gtk_container_set_focus_chain(GTK_CONTAINER(cols), cols->taborder);
439#endif
d9b15094 440 break;
441 }
442}
443
f160b7b8 444#if !GTK_CHECK_VERSION(2,0,0)
d9b15094 445/*
446 * Override GtkContainer's focus movement so the user can
447 * explicitly specify the tab order.
448 */
449static gint columns_focus(GtkContainer *container, GtkDirectionType dir)
450{
451 Columns *cols;
452 GList *pos;
453 GtkWidget *focuschild;
454
455 g_return_val_if_fail(container != NULL, FALSE);
456 g_return_val_if_fail(IS_COLUMNS(container), FALSE);
457
458 cols = COLUMNS(container);
459
460 if (!GTK_WIDGET_DRAWABLE(cols) ||
461 !GTK_WIDGET_IS_SENSITIVE(cols))
462 return FALSE;
463
464 if (!GTK_WIDGET_CAN_FOCUS(container) &&
465 (dir == GTK_DIR_TAB_FORWARD || dir == GTK_DIR_TAB_BACKWARD)) {
466
467 focuschild = container->focus_child;
468 gtk_container_set_focus_child(container, NULL);
469
470 if (dir == GTK_DIR_TAB_FORWARD)
471 pos = cols->taborder;
472 else
473 pos = g_list_last(cols->taborder);
474
475 while (pos) {
476 GtkWidget *child = pos->data;
477
478 if (focuschild) {
479 if (focuschild == child) {
480 focuschild = NULL; /* now we can start looking in here */
481 if (GTK_WIDGET_DRAWABLE(child) &&
482 GTK_IS_CONTAINER(child) &&
483 !GTK_WIDGET_HAS_FOCUS(child)) {
484 if (gtk_container_focus(GTK_CONTAINER(child), dir))
485 return TRUE;
486 }
487 }
488 } else if (GTK_WIDGET_DRAWABLE(child)) {
489 if (GTK_IS_CONTAINER(child)) {
490 if (gtk_container_focus(GTK_CONTAINER(child), dir))
491 return TRUE;
492 } else if (GTK_WIDGET_CAN_FOCUS(child)) {
493 gtk_widget_grab_focus(child);
494 return TRUE;
495 }
496 }
497
498 if (dir == GTK_DIR_TAB_FORWARD)
499 pos = pos->next;
500 else
501 pos = pos->prev;
502 }
503
504 return FALSE;
505 } else
506 return columns_inherited_focus(container, dir);
507}
f160b7b8 508#endif
d9b15094 509
510/*
511 * Now here comes the interesting bit. The actual layout part is
512 * done in the following two functions:
513 *
514 * columns_size_request() examines the list of widgets held in the
515 * Columns, and returns a requisition stating the absolute minimum
516 * size it can bear to be.
517 *
518 * columns_size_allocate() is given an allocation telling it what
519 * size the whole container is going to be, and it calls
520 * gtk_widget_size_allocate() on all of its (visible) children to
521 * set their size and position relative to the top left of the
522 * container.
523 */
524
525static void columns_size_request(GtkWidget *widget, GtkRequisition *req)
526{
527 Columns *cols;
528 ColumnsChild *child;
529 GList *children;
530 gint i, ncols, colspan, *colypos;
531 const gint *percentages;
532 static const gint onecol[] = { 100 };
533
534 g_return_if_fail(widget != NULL);
535 g_return_if_fail(IS_COLUMNS(widget));
536 g_return_if_fail(req != NULL);
537
538 cols = COLUMNS(widget);
539
540 req->width = 0;
541 req->height = cols->spacing;
542
543 ncols = 1;
544 colypos = g_new(gint, 1);
545 colypos[0] = 0;
546 percentages = onecol;
547
548 for (children = cols->children;
549 children && (child = children->data);
550 children = children->next) {
551 GtkRequisition creq;
552
553 if (!child->widget) {
554 /* Column reconfiguration. */
555 for (i = 1; i < ncols; i++) {
556 if (colypos[0] < colypos[i])
557 colypos[0] = colypos[i];
558 }
559 ncols = child->ncols;
560 percentages = child->percentages;
561 colypos = g_renew(gint, colypos, ncols);
562 for (i = 1; i < ncols; i++)
563 colypos[i] = colypos[0];
564 continue;
565 }
566
567 /* Only take visible widgets into account. */
568 if (!GTK_WIDGET_VISIBLE(child->widget))
569 continue;
570
571 gtk_widget_size_request(child->widget, &creq);
572 colspan = child->colspan ? child->colspan : ncols-child->colstart;
573
574 /*
575 * To compute width: we know that creq.width plus
576 * cols->spacing needs to equal a certain percentage of the
577 * full width of the container. So we work this value out,
578 * figure out how wide the container will need to be to
579 * make that percentage of it equal to that width, and
580 * ensure our returned width is at least that much. Very
581 * simple really.
582 */
583 {
584 int percent, thiswid, fullwid;
585
586 percent = 0;
587 for (i = 0; i < colspan; i++)
588 percent += percentages[child->colstart+i];
589
590 thiswid = creq.width + cols->spacing;
591 /*
592 * Since creq is the _minimum_ size the child needs, we
593 * must ensure that it gets _at least_ that size.
594 * Hence, when scaling thiswid up to fullwid, we must
595 * round up, which means adding percent-1 before
596 * dividing by percent.
597 */
598 fullwid = (thiswid * 100 + percent - 1) / percent;
599
600 /*
601 * The above calculation assumes every widget gets
602 * cols->spacing on the right. So we subtract
603 * cols->spacing here to account for the extra load of
604 * spacing on the right.
605 */
606 if (req->width < fullwid - cols->spacing)
607 req->width = fullwid - cols->spacing;
608 }
609
610 /*
611 * To compute height: the widget's top will be positioned
612 * at the largest y value so far reached in any of the
613 * columns it crosses. Then it will go down by creq.height
614 * plus padding; and the point it reaches at the bottom is
615 * the new y value in all those columns, and minus the
616 * padding it is also a lower bound on our own size
617 * request.
618 */
619 {
620 int topy, boty;
621
622 topy = 0;
623 for (i = 0; i < colspan; i++) {
624 if (topy < colypos[child->colstart+i])
625 topy = colypos[child->colstart+i];
626 }
627 boty = topy + creq.height + cols->spacing;
628 for (i = 0; i < colspan; i++) {
629 colypos[child->colstart+i] = boty;
630 }
631
632 if (req->height < boty - cols->spacing)
633 req->height = boty - cols->spacing;
634 }
635 }
636
637 req->width += 2*GTK_CONTAINER(cols)->border_width;
638 req->height += 2*GTK_CONTAINER(cols)->border_width;
639
640 g_free(colypos);
641}
642
643static void columns_size_allocate(GtkWidget *widget, GtkAllocation *alloc)
644{
645 Columns *cols;
646 ColumnsChild *child;
647 GList *children;
648 gint i, ncols, colspan, border, *colxpos, *colypos;
649 const gint *percentages;
650 static const gint onecol[] = { 100 };
651
652 g_return_if_fail(widget != NULL);
653 g_return_if_fail(IS_COLUMNS(widget));
654 g_return_if_fail(alloc != NULL);
655
656 cols = COLUMNS(widget);
657 widget->allocation = *alloc;
658 border = GTK_CONTAINER(cols)->border_width;
659
660 ncols = 1;
661 percentages = onecol;
662 /* colxpos gives the starting x position of each column.
663 * We supply n+1 of them, so that we can find the RH edge easily.
664 * All ending x positions are expected to be adjusted afterwards by
665 * subtracting the spacing. */
666 colxpos = g_new(gint, 2);
667 colxpos[0] = 0;
668 colxpos[1] = alloc->width - 2*border + cols->spacing;
669 /* As in size_request, colypos is the lowest y reached in each column. */
670 colypos = g_new(gint, 1);
671 colypos[0] = 0;
672
673 for (children = cols->children;
674 children && (child = children->data);
675 children = children->next) {
676 GtkRequisition creq;
677 GtkAllocation call;
678
679 if (!child->widget) {
680 gint percent;
681
682 /* Column reconfiguration. */
683 for (i = 1; i < ncols; i++) {
684 if (colypos[0] < colypos[i])
685 colypos[0] = colypos[i];
686 }
687 ncols = child->ncols;
688 percentages = child->percentages;
689 colypos = g_renew(gint, colypos, ncols);
690 for (i = 1; i < ncols; i++)
691 colypos[i] = colypos[0];
692 colxpos = g_renew(gint, colxpos, ncols + 1);
693 colxpos[0] = 0;
694 percent = 0;
695 for (i = 0; i < ncols; i++) {
696 percent += percentages[i];
697 colxpos[i+1] = (((alloc->width - 2*border) + cols->spacing)
698 * percent / 100);
699 }
700 continue;
701 }
702
703 /* Only take visible widgets into account. */
704 if (!GTK_WIDGET_VISIBLE(child->widget))
705 continue;
706
707 gtk_widget_get_child_requisition(child->widget, &creq);
708 colspan = child->colspan ? child->colspan : ncols-child->colstart;
709
710 /*
711 * Starting x position is cols[colstart].
712 * Ending x position is cols[colstart+colspan] - spacing.
713 *
714 * Unless we're forcing left, in which case the width is
715 * exactly the requisition width.
716 */
717 call.x = alloc->x + border + colxpos[child->colstart];
718 if (child->force_left)
719 call.width = creq.width;
720 else
721 call.width = (colxpos[child->colstart+colspan] -
722 colxpos[child->colstart] - cols->spacing);
723
724 /*
725 * To compute height: the widget's top will be positioned
726 * at the largest y value so far reached in any of the
727 * columns it crosses. Then it will go down by creq.height
728 * plus padding; and the point it reaches at the bottom is
729 * the new y value in all those columns.
730 */
731 {
732 int topy, boty;
733
734 topy = 0;
735 for (i = 0; i < colspan; i++) {
736 if (topy < colypos[child->colstart+i])
737 topy = colypos[child->colstart+i];
738 }
739 call.y = alloc->y + border + topy;
740 call.height = creq.height;
741 boty = topy + creq.height + cols->spacing;
742 for (i = 0; i < colspan; i++) {
743 colypos[child->colstart+i] = boty;
744 }
745 }
746
747 gtk_widget_size_allocate(child->widget, &call);
748 }
749
750 g_free(colxpos);
751 g_free(colypos);
752}