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