]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - unix/gtkcols.c
Update version number for 0.66 release.
[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
8 static void columns_init(Columns *cols);
9 static void columns_class_init(ColumnsClass *klass);
10 static void columns_map(GtkWidget *widget);
11 static void columns_unmap(GtkWidget *widget);
12 #if !GTK_CHECK_VERSION(2,0,0)
13 static void columns_draw(GtkWidget *widget, GdkRectangle *area);
14 static gint columns_expose(GtkWidget *widget, GdkEventExpose *event);
15 #endif
16 static void columns_base_add(GtkContainer *container, GtkWidget *widget);
17 static void columns_remove(GtkContainer *container, GtkWidget *widget);
18 static void columns_forall(GtkContainer *container, gboolean include_internals,
19                            GtkCallback callback, gpointer callback_data);
20 #if !GTK_CHECK_VERSION(2,0,0)
21 static gint columns_focus(GtkContainer *container, GtkDirectionType dir);
22 #endif
23 static GtkType columns_child_type(GtkContainer *container);
24 static void columns_size_request(GtkWidget *widget, GtkRequisition *req);
25 static void columns_size_allocate(GtkWidget *widget, GtkAllocation *alloc);
26
27 static GtkContainerClass *parent_class = NULL;
28
29 #if !GTK_CHECK_VERSION(2,0,0)
30 GtkType 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 }
51 #else
52 GType 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
76
77 #if !GTK_CHECK_VERSION(2,0,0)
78 static gint (*columns_inherited_focus)(GtkContainer *container,
79                                        GtkDirectionType direction);
80 #endif
81
82 static void columns_class_init(ColumnsClass *klass)
83 {
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)
95     parent_class = gtk_type_class(GTK_TYPE_CONTAINER);
96 #else
97     parent_class = g_type_class_peek_parent(klass);
98 #endif
99
100     widget_class->map = columns_map;
101     widget_class->unmap = columns_unmap;
102 #if !GTK_CHECK_VERSION(2,0,0)
103     widget_class->draw = columns_draw;
104     widget_class->expose_event = columns_expose;
105 #endif
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;
113 #if !GTK_CHECK_VERSION(2,0,0)
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;
118 #endif
119 }
120
121 static 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  */
134 static 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 }
155 static 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 }
176 #if !GTK_CHECK_VERSION(2,0,0)
177 static 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 }
200 static 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 }
228 #endif
229
230 static 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
246 static 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);
284 #if GTK_CHECK_VERSION(2,0,0)
285         gtk_container_set_focus_chain(container, cols->taborder);
286 #endif
287         break;
288     }
289 }
290
291 static void columns_forall(GtkContainer *container, gboolean include_internals,
292                            GtkCallback callback, gpointer callback_data)
293 {
294     Columns *cols;
295     ColumnsChild *child;
296     GList *children, *next;
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);
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;
316         if (child->widget)
317             callback(child->widget, callback_data);
318     }
319 }
320
321 static GtkType columns_child_type(GtkContainer *container)
322 {
323     return GTK_TYPE_WIDGET;
324 }
325
326 GtkWidget *columns_new(gint spacing)
327 {
328     Columns *cols;
329
330 #if !GTK_CHECK_VERSION(2,0,0)
331     cols = gtk_type_new(columns_get_type());
332 #else
333     cols = g_object_new(TYPE_COLUMNS, NULL);
334 #endif
335
336     cols->spacing = spacing;
337
338     return GTK_WIDGET(cols);
339 }
340
341 void 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
362 void 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
383 #if GTK_CHECK_VERSION(2,0,0)
384     gtk_container_set_focus_chain(GTK_CONTAINER(cols), cols->taborder);
385 #endif
386
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
397 void 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
419 void 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);
437 #if GTK_CHECK_VERSION(2,0,0)
438         gtk_container_set_focus_chain(GTK_CONTAINER(cols), cols->taborder);
439 #endif
440         break;
441     }
442 }
443
444 #if !GTK_CHECK_VERSION(2,0,0)
445 /*
446  * Override GtkContainer's focus movement so the user can
447  * explicitly specify the tab order.
448  */
449 static 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 }
508 #endif
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
525 static 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
643 static 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 }