OSDN Git Service

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