2 * gtkcols.c - implementation of the `Columns' GTK layout container.
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);
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);
24 static GType columns_child_type(GtkContainer *container);
25 #if GTK_CHECK_VERSION(3,0,0)
26 static void columns_get_preferred_width(GtkWidget *widget,
27 gint *min, gint *nat);
28 static void columns_get_preferred_height(GtkWidget *widget,
29 gint *min, gint *nat);
30 static void columns_get_preferred_width_for_height(GtkWidget *widget,
32 gint *min, gint *nat);
33 static void columns_get_preferred_height_for_width(GtkWidget *widget,
35 gint *min, gint *nat);
37 static void columns_size_request(GtkWidget *widget, GtkRequisition *req);
39 static void columns_size_allocate(GtkWidget *widget, GtkAllocation *alloc);
41 static GtkContainerClass *parent_class = NULL;
43 #if !GTK_CHECK_VERSION(2,0,0)
44 GType columns_get_type(void)
46 static GType columns_type = 0;
49 static const GtkTypeInfo columns_info = {
53 (GtkClassInitFunc) columns_class_init,
54 (GtkObjectInitFunc) columns_init,
55 /* reserved_1 */ NULL,
56 /* reserved_2 */ NULL,
57 (GtkClassInitFunc) NULL,
60 columns_type = gtk_type_unique(GTK_TYPE_CONTAINER, &columns_info);
66 GType columns_get_type(void)
68 static GType columns_type = 0;
71 static const GTypeInfo columns_info = {
75 (GClassInitFunc) columns_class_init,
80 (GInstanceInitFunc)columns_init,
83 columns_type = g_type_register_static(GTK_TYPE_CONTAINER, "Columns",
91 #if !GTK_CHECK_VERSION(2,0,0)
92 static gint (*columns_inherited_focus)(GtkContainer *container,
93 GtkDirectionType direction);
96 static void columns_class_init(ColumnsClass *klass)
98 #if !GTK_CHECK_VERSION(2,0,0)
99 /* GtkObjectClass *object_class = (GtkObjectClass *)klass; */
100 GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
101 GtkContainerClass *container_class = (GtkContainerClass *)klass;
103 /* GObjectClass *object_class = G_OBJECT_CLASS(klass); */
104 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
105 GtkContainerClass *container_class = GTK_CONTAINER_CLASS(klass);
108 #if !GTK_CHECK_VERSION(2,0,0)
109 parent_class = gtk_type_class(GTK_TYPE_CONTAINER);
111 parent_class = g_type_class_peek_parent(klass);
114 widget_class->map = columns_map;
115 widget_class->unmap = columns_unmap;
116 #if !GTK_CHECK_VERSION(2,0,0)
117 widget_class->draw = columns_draw;
118 widget_class->expose_event = columns_expose;
120 #if GTK_CHECK_VERSION(3,0,0)
121 widget_class->get_preferred_width = columns_get_preferred_width;
122 widget_class->get_preferred_height = columns_get_preferred_height;
123 widget_class->get_preferred_width_for_height =
124 columns_get_preferred_width_for_height;
125 widget_class->get_preferred_height_for_width =
126 columns_get_preferred_height_for_width;
128 widget_class->size_request = columns_size_request;
130 widget_class->size_allocate = columns_size_allocate;
132 container_class->add = columns_base_add;
133 container_class->remove = columns_remove;
134 container_class->forall = columns_forall;
135 container_class->child_type = columns_child_type;
136 #if !GTK_CHECK_VERSION(2,0,0)
137 /* Save the previous value of this method. */
138 if (!columns_inherited_focus)
139 columns_inherited_focus = container_class->focus;
140 container_class->focus = columns_focus;
144 static void columns_init(Columns *cols)
146 gtk_widget_set_has_window(GTK_WIDGET(cols), FALSE);
148 cols->children = NULL;
153 * These appear to be thoroughly tedious functions; the only reason
154 * we have to reimplement them at all is because we defined our own
155 * format for our GList of children...
157 static void columns_map(GtkWidget *widget)
163 g_return_if_fail(widget != NULL);
164 g_return_if_fail(IS_COLUMNS(widget));
166 cols = COLUMNS(widget);
167 gtk_widget_set_mapped(GTK_WIDGET(cols), TRUE);
169 for (children = cols->children;
170 children && (child = children->data);
171 children = children->next) {
173 gtk_widget_get_visible(child->widget) &&
174 !gtk_widget_get_mapped(child->widget))
175 gtk_widget_map(child->widget);
178 static void columns_unmap(GtkWidget *widget)
184 g_return_if_fail(widget != NULL);
185 g_return_if_fail(IS_COLUMNS(widget));
187 cols = COLUMNS(widget);
188 gtk_widget_set_mapped(GTK_WIDGET(cols), FALSE);
190 for (children = cols->children;
191 children && (child = children->data);
192 children = children->next) {
194 gtk_widget_get_visible(child->widget) &&
195 gtk_widget_get_mapped(child->widget))
196 gtk_widget_unmap(child->widget);
199 #if !GTK_CHECK_VERSION(2,0,0)
200 static void columns_draw(GtkWidget *widget, GdkRectangle *area)
205 GdkRectangle child_area;
207 g_return_if_fail(widget != NULL);
208 g_return_if_fail(IS_COLUMNS(widget));
210 if (GTK_WIDGET_DRAWABLE(widget)) {
211 cols = COLUMNS(widget);
213 for (children = cols->children;
214 children && (child = children->data);
215 children = children->next) {
217 GTK_WIDGET_DRAWABLE(child->widget) &&
218 gtk_widget_intersect(child->widget, area, &child_area))
219 gtk_widget_draw(child->widget, &child_area);
223 static gint columns_expose(GtkWidget *widget, GdkEventExpose *event)
228 GdkEventExpose child_event;
230 g_return_val_if_fail(widget != NULL, FALSE);
231 g_return_val_if_fail(IS_COLUMNS(widget), FALSE);
232 g_return_val_if_fail(event != NULL, FALSE);
234 if (GTK_WIDGET_DRAWABLE(widget)) {
235 cols = COLUMNS(widget);
236 child_event = *event;
238 for (children = cols->children;
239 children && (child = children->data);
240 children = children->next) {
242 GTK_WIDGET_DRAWABLE(child->widget) &&
243 GTK_WIDGET_NO_WINDOW(child->widget) &&
244 gtk_widget_intersect(child->widget, &event->area,
246 gtk_widget_event(child->widget, (GdkEvent *)&child_event);
253 static void columns_base_add(GtkContainer *container, GtkWidget *widget)
257 g_return_if_fail(container != NULL);
258 g_return_if_fail(IS_COLUMNS(container));
259 g_return_if_fail(widget != NULL);
261 cols = COLUMNS(container);
264 * Default is to add a new widget spanning all columns.
266 columns_add(cols, widget, 0, 0); /* 0 means ncols */
269 static void columns_remove(GtkContainer *container, GtkWidget *widget)
275 gboolean was_visible;
277 g_return_if_fail(container != NULL);
278 g_return_if_fail(IS_COLUMNS(container));
279 g_return_if_fail(widget != NULL);
281 cols = COLUMNS(container);
283 for (children = cols->children;
284 children && (child = children->data);
285 children = children->next) {
286 if (child->widget != widget)
289 was_visible = gtk_widget_get_visible(widget);
290 gtk_widget_unparent(widget);
291 cols->children = g_list_remove_link(cols->children, children);
292 g_list_free(children);
294 if (child->same_height_as) {
295 g_return_if_fail(child->same_height_as->same_height_as == child);
296 child->same_height_as->same_height_as = NULL;
297 if (gtk_widget_get_visible(child->same_height_as->widget))
298 gtk_widget_queue_resize(GTK_WIDGET(container));
303 gtk_widget_queue_resize(GTK_WIDGET(container));
307 for (children = cols->taborder;
308 children && (childw = children->data);
309 children = children->next) {
310 if (childw != widget)
313 cols->taborder = g_list_remove_link(cols->taborder, children);
314 g_list_free(children);
315 #if GTK_CHECK_VERSION(2,0,0)
316 gtk_container_set_focus_chain(container, cols->taborder);
322 static void columns_forall(GtkContainer *container, gboolean include_internals,
323 GtkCallback callback, gpointer callback_data)
327 GList *children, *next;
329 g_return_if_fail(container != NULL);
330 g_return_if_fail(IS_COLUMNS(container));
331 g_return_if_fail(callback != NULL);
333 cols = COLUMNS(container);
335 for (children = cols->children;
336 children && (child = children->data);
339 * We can't wait until after the callback to assign
340 * `children = children->next', because the callback might
341 * be gtk_widget_destroy, which would remove the link
342 * `children' from the list! So instead we must get our
343 * hands on the value of the `next' pointer _before_ the
346 next = children->next;
348 callback(child->widget, callback_data);
352 static GType columns_child_type(GtkContainer *container)
354 return GTK_TYPE_WIDGET;
357 GtkWidget *columns_new(gint spacing)
361 #if !GTK_CHECK_VERSION(2,0,0)
362 cols = gtk_type_new(columns_get_type());
364 cols = g_object_new(TYPE_COLUMNS, NULL);
367 cols->spacing = spacing;
369 return GTK_WIDGET(cols);
372 void columns_set_cols(Columns *cols, gint ncols, const gint *percentages)
374 ColumnsChild *childdata;
377 g_return_if_fail(cols != NULL);
378 g_return_if_fail(IS_COLUMNS(cols));
379 g_return_if_fail(ncols > 0);
380 g_return_if_fail(percentages != NULL);
382 childdata = g_new(ColumnsChild, 1);
383 childdata->widget = NULL;
384 childdata->ncols = ncols;
385 childdata->percentages = g_new(gint, ncols);
386 childdata->force_left = FALSE;
387 for (i = 0; i < ncols; i++)
388 childdata->percentages[i] = percentages[i];
390 cols->children = g_list_append(cols->children, childdata);
393 void columns_add(Columns *cols, GtkWidget *child,
394 gint colstart, gint colspan)
396 ColumnsChild *childdata;
398 g_return_if_fail(cols != NULL);
399 g_return_if_fail(IS_COLUMNS(cols));
400 g_return_if_fail(child != NULL);
401 g_return_if_fail(gtk_widget_get_parent(child) == NULL);
403 childdata = g_new(ColumnsChild, 1);
404 childdata->widget = child;
405 childdata->colstart = colstart;
406 childdata->colspan = colspan;
407 childdata->force_left = FALSE;
408 childdata->same_height_as = NULL;
410 cols->children = g_list_append(cols->children, childdata);
411 cols->taborder = g_list_append(cols->taborder, child);
413 gtk_widget_set_parent(child, GTK_WIDGET(cols));
415 #if GTK_CHECK_VERSION(2,0,0)
416 gtk_container_set_focus_chain(GTK_CONTAINER(cols), cols->taborder);
419 if (gtk_widget_get_realized(GTK_WIDGET(cols)))
420 gtk_widget_realize(child);
422 if (gtk_widget_get_visible(GTK_WIDGET(cols)) &&
423 gtk_widget_get_visible(child)) {
424 if (gtk_widget_get_mapped(GTK_WIDGET(cols)))
425 gtk_widget_map(child);
426 gtk_widget_queue_resize(child);
430 static ColumnsChild *columns_find_child(Columns *cols, GtkWidget *widget)
435 for (children = cols->children;
436 children && (child = children->data);
437 children = children->next) {
439 if (child->widget == widget)
446 void columns_force_left_align(Columns *cols, GtkWidget *widget)
450 g_return_if_fail(cols != NULL);
451 g_return_if_fail(IS_COLUMNS(cols));
452 g_return_if_fail(widget != NULL);
454 child = columns_find_child(cols, widget);
455 g_return_if_fail(child != NULL);
457 child->force_left = TRUE;
458 if (gtk_widget_get_visible(widget))
459 gtk_widget_queue_resize(GTK_WIDGET(cols));
462 void columns_force_same_height(Columns *cols, GtkWidget *cw1, GtkWidget *cw2)
464 ColumnsChild *child1, *child2;
466 g_return_if_fail(cols != NULL);
467 g_return_if_fail(IS_COLUMNS(cols));
468 g_return_if_fail(cw1 != NULL);
469 g_return_if_fail(cw2 != NULL);
471 child1 = columns_find_child(cols, cw1);
472 g_return_if_fail(child1 != NULL);
473 child2 = columns_find_child(cols, cw2);
474 g_return_if_fail(child2 != NULL);
476 child1->same_height_as = child2;
477 child2->same_height_as = child1;
478 if (gtk_widget_get_visible(cw1) || gtk_widget_get_visible(cw2))
479 gtk_widget_queue_resize(GTK_WIDGET(cols));
482 void columns_taborder_last(Columns *cols, GtkWidget *widget)
487 g_return_if_fail(cols != NULL);
488 g_return_if_fail(IS_COLUMNS(cols));
489 g_return_if_fail(widget != NULL);
491 for (children = cols->taborder;
492 children && (childw = children->data);
493 children = children->next) {
494 if (childw != widget)
497 cols->taborder = g_list_remove_link(cols->taborder, children);
498 g_list_free(children);
499 cols->taborder = g_list_append(cols->taborder, widget);
500 #if GTK_CHECK_VERSION(2,0,0)
501 gtk_container_set_focus_chain(GTK_CONTAINER(cols), cols->taborder);
507 #if !GTK_CHECK_VERSION(2,0,0)
509 * Override GtkContainer's focus movement so the user can
510 * explicitly specify the tab order.
512 static gint columns_focus(GtkContainer *container, GtkDirectionType dir)
516 GtkWidget *focuschild;
518 g_return_val_if_fail(container != NULL, FALSE);
519 g_return_val_if_fail(IS_COLUMNS(container), FALSE);
521 cols = COLUMNS(container);
523 if (!GTK_WIDGET_DRAWABLE(cols) ||
524 !GTK_WIDGET_IS_SENSITIVE(cols))
527 if (!GTK_WIDGET_CAN_FOCUS(container) &&
528 (dir == GTK_DIR_TAB_FORWARD || dir == GTK_DIR_TAB_BACKWARD)) {
530 focuschild = container->focus_child;
531 gtk_container_set_focus_child(container, NULL);
533 if (dir == GTK_DIR_TAB_FORWARD)
534 pos = cols->taborder;
536 pos = g_list_last(cols->taborder);
539 GtkWidget *child = pos->data;
542 if (focuschild == child) {
543 focuschild = NULL; /* now we can start looking in here */
544 if (GTK_WIDGET_DRAWABLE(child) &&
545 GTK_IS_CONTAINER(child) &&
546 !GTK_WIDGET_HAS_FOCUS(child)) {
547 if (gtk_container_focus(GTK_CONTAINER(child), dir))
551 } else if (GTK_WIDGET_DRAWABLE(child)) {
552 if (GTK_IS_CONTAINER(child)) {
553 if (gtk_container_focus(GTK_CONTAINER(child), dir))
555 } else if (GTK_WIDGET_CAN_FOCUS(child)) {
556 gtk_widget_grab_focus(child);
561 if (dir == GTK_DIR_TAB_FORWARD)
569 return columns_inherited_focus(container, dir);
574 * Underlying parts of the layout algorithm, to compute the Columns
575 * container's width or height given the widths or heights of its
576 * children. These will be called in various ways with different
577 * notions of width and height in use, so we abstract them out and
578 * pass them a 'get width' or 'get height' function pointer.
581 typedef gint (*widget_dim_fn_t)(ColumnsChild *child);
583 static gint columns_compute_width(Columns *cols, widget_dim_fn_t get_width)
587 gint i, ncols, colspan, retwidth, childwidth;
588 const gint *percentages;
589 static const gint onecol[] = { 100 };
594 percentages = onecol;
596 for (children = cols->children;
597 children && (child = children->data);
598 children = children->next) {
600 if (!child->widget) {
601 /* Column reconfiguration. */
602 ncols = child->ncols;
603 percentages = child->percentages;
607 /* Only take visible widgets into account. */
608 if (!gtk_widget_get_visible(child->widget))
611 childwidth = get_width(child);
612 colspan = child->colspan ? child->colspan : ncols-child->colstart;
615 * To compute width: we know that childwidth + cols->spacing
616 * needs to equal a certain percentage of the full width of
617 * the container. So we work this value out, figure out how
618 * wide the container will need to be to make that percentage
619 * of it equal to that width, and ensure our returned width is
620 * at least that much. Very simple really.
623 int percent, thiswid, fullwid;
626 for (i = 0; i < colspan; i++)
627 percent += percentages[child->colstart+i];
629 thiswid = childwidth + cols->spacing;
631 * Since childwidth is (at least sometimes) the _minimum_
632 * size the child needs, we must ensure that it gets _at
633 * least_ that size. Hence, when scaling thiswid up to
634 * fullwid, we must round up, which means adding percent-1
635 * before dividing by percent.
637 fullwid = (thiswid * 100 + percent - 1) / percent;
640 * The above calculation assumes every widget gets
641 * cols->spacing on the right. So we subtract
642 * cols->spacing here to account for the extra load of
643 * spacing on the right.
645 if (retwidth < fullwid - cols->spacing)
646 retwidth = fullwid - cols->spacing;
650 retwidth += 2*gtk_container_get_border_width(GTK_CONTAINER(cols));
655 static void columns_alloc_horiz(Columns *cols, gint ourwidth,
656 widget_dim_fn_t get_width)
660 gint i, ncols, colspan, border, *colxpos, childwidth;
661 const gint *percentages;
662 static const gint onecol[] = { 100 };
664 border = gtk_container_get_border_width(GTK_CONTAINER(cols));
667 percentages = onecol;
668 /* colxpos gives the starting x position of each column.
669 * We supply n+1 of them, so that we can find the RH edge easily.
670 * All ending x positions are expected to be adjusted afterwards by
671 * subtracting the spacing. */
672 colxpos = g_new(gint, 2);
674 colxpos[1] = ourwidth - 2*border + cols->spacing;
676 for (children = cols->children;
677 children && (child = children->data);
678 children = children->next) {
680 if (!child->widget) {
683 /* Column reconfiguration. */
684 ncols = child->ncols;
685 percentages = child->percentages;
686 colxpos = g_renew(gint, colxpos, ncols + 1);
689 for (i = 0; i < ncols; i++) {
690 percent += percentages[i];
691 colxpos[i+1] = (((ourwidth - 2*border) + cols->spacing)
697 /* Only take visible widgets into account. */
698 if (!gtk_widget_get_visible(child->widget))
701 childwidth = get_width(child);
702 colspan = child->colspan ? child->colspan : ncols-child->colstart;
705 * Starting x position is cols[colstart].
706 * Ending x position is cols[colstart+colspan] - spacing.
708 * Unless we're forcing left, in which case the width is
709 * exactly the requisition width.
711 child->x = colxpos[child->colstart];
712 if (child->force_left)
713 child->w = childwidth;
715 child->w = (colxpos[child->colstart+colspan] -
716 colxpos[child->colstart] - cols->spacing);
722 static gint columns_compute_height(Columns *cols, widget_dim_fn_t get_height)
726 gint i, ncols, colspan, *colypos, retheight, childheight;
728 retheight = cols->spacing;
731 colypos = g_new(gint, 1);
734 for (children = cols->children;
735 children && (child = children->data);
736 children = children->next) {
738 if (!child->widget) {
739 /* Column reconfiguration. */
740 for (i = 1; i < ncols; i++) {
741 if (colypos[0] < colypos[i])
742 colypos[0] = colypos[i];
744 ncols = child->ncols;
745 colypos = g_renew(gint, colypos, ncols);
746 for (i = 1; i < ncols; i++)
747 colypos[i] = colypos[0];
751 /* Only take visible widgets into account. */
752 if (!gtk_widget_get_visible(child->widget))
755 childheight = get_height(child);
756 if (child->same_height_as) {
757 gint childheight2 = get_height(child->same_height_as);
758 if (childheight < childheight2)
759 childheight = childheight2;
761 colspan = child->colspan ? child->colspan : ncols-child->colstart;
764 * To compute height: the widget's top will be positioned at
765 * the largest y value so far reached in any of the columns it
766 * crosses. Then it will go down by childheight plus padding;
767 * and the point it reaches at the bottom is the new y value
768 * in all those columns, and minus the padding it is also a
769 * lower bound on our own height.
775 for (i = 0; i < colspan; i++) {
776 if (topy < colypos[child->colstart+i])
777 topy = colypos[child->colstart+i];
779 boty = topy + childheight + cols->spacing;
780 for (i = 0; i < colspan; i++) {
781 colypos[child->colstart+i] = boty;
784 if (retheight < boty - cols->spacing)
785 retheight = boty - cols->spacing;
789 retheight += 2*gtk_container_get_border_width(GTK_CONTAINER(cols));
796 static void columns_alloc_vert(Columns *cols, gint ourheight,
797 widget_dim_fn_t get_height)
801 gint i, ncols, colspan, *colypos, realheight, fakeheight;
804 /* As in size_request, colypos is the lowest y reached in each column. */
805 colypos = g_new(gint, 1);
808 for (children = cols->children;
809 children && (child = children->data);
810 children = children->next) {
811 if (!child->widget) {
812 /* Column reconfiguration. */
813 for (i = 1; i < ncols; i++) {
814 if (colypos[0] < colypos[i])
815 colypos[0] = colypos[i];
817 ncols = child->ncols;
818 colypos = g_renew(gint, colypos, ncols);
819 for (i = 1; i < ncols; i++)
820 colypos[i] = colypos[0];
824 /* Only take visible widgets into account. */
825 if (!gtk_widget_get_visible(child->widget))
828 realheight = fakeheight = get_height(child);
829 if (child->same_height_as) {
830 gint childheight2 = get_height(child->same_height_as);
831 if (fakeheight < childheight2)
832 fakeheight = childheight2;
834 colspan = child->colspan ? child->colspan : ncols-child->colstart;
837 * To compute height: the widget's top will be positioned
838 * at the largest y value so far reached in any of the
839 * columns it crosses. Then it will go down by creq.height
840 * plus padding; and the point it reaches at the bottom is
841 * the new y value in all those columns.
847 for (i = 0; i < colspan; i++) {
848 if (topy < colypos[child->colstart+i])
849 topy = colypos[child->colstart+i];
851 child->y = topy + fakeheight/2 - realheight/2;
852 child->h = realheight;
853 boty = topy + fakeheight + cols->spacing;
854 for (i = 0; i < colspan; i++) {
855 colypos[child->colstart+i] = boty;
864 * Now here comes the interesting bit. The actual layout part is
865 * done in the following two functions:
867 * columns_size_request() examines the list of widgets held in the
868 * Columns, and returns a requisition stating the absolute minimum
869 * size it can bear to be.
871 * columns_size_allocate() is given an allocation telling it what
872 * size the whole container is going to be, and it calls
873 * gtk_widget_size_allocate() on all of its (visible) children to
874 * set their size and position relative to the top left of the
878 #if !GTK_CHECK_VERSION(3,0,0)
880 static gint columns_gtk2_get_width(ColumnsChild *child)
883 gtk_widget_size_request(child->widget, &creq);
887 static gint columns_gtk2_get_height(ColumnsChild *child)
890 gtk_widget_size_request(child->widget, &creq);
894 static void columns_size_request(GtkWidget *widget, GtkRequisition *req)
898 g_return_if_fail(widget != NULL);
899 g_return_if_fail(IS_COLUMNS(widget));
900 g_return_if_fail(req != NULL);
902 cols = COLUMNS(widget);
904 req->width = columns_compute_width(cols, columns_gtk2_get_width);
905 req->height = columns_compute_height(cols, columns_gtk2_get_height);
908 static void columns_size_allocate(GtkWidget *widget, GtkAllocation *alloc)
915 g_return_if_fail(widget != NULL);
916 g_return_if_fail(IS_COLUMNS(widget));
917 g_return_if_fail(alloc != NULL);
919 cols = COLUMNS(widget);
920 gtk_widget_set_allocation(widget, alloc);
922 border = gtk_container_get_border_width(GTK_CONTAINER(cols));
924 columns_alloc_horiz(cols, alloc->width, columns_gtk2_get_width);
925 columns_alloc_vert(cols, alloc->height, columns_gtk2_get_height);
927 for (children = cols->children;
928 children && (child = children->data);
929 children = children->next) {
930 if (child->widget && gtk_widget_get_visible(child->widget)) {
932 call.x = alloc->x + border + child->x;
933 call.y = alloc->y + border + child->y;
934 call.width = child->w;
935 call.height = child->h;
936 gtk_widget_size_allocate(child->widget, &call);
941 #else /* GTK_CHECK_VERSION(3,0,0) */
943 static gint columns_gtk3_get_min_width(ColumnsChild *child)
946 gtk_widget_get_preferred_width(child->widget, &ret, NULL);
950 static gint columns_gtk3_get_nat_width(ColumnsChild *child)
954 if (GTK_IS_LABEL(child->widget) &&
955 gtk_label_get_line_wrap(GTK_LABEL(child->widget))) {
957 * We treat wrapping GtkLabels as a special case in this
958 * layout class, because the whole point of those is that I
959 * _don't_ want them to take up extra horizontal space for
960 * long text, but instead to wrap it to whatever size is used
961 * by the rest of the layout.
963 gtk_widget_get_preferred_width(child->widget, &ret, NULL);
965 gtk_widget_get_preferred_width(child->widget, NULL, &ret);
970 static gint columns_gtk3_get_minfh_width(ColumnsChild *child)
973 gtk_widget_get_preferred_width_for_height(child->widget, child->h,
978 static gint columns_gtk3_get_natfh_width(ColumnsChild *child)
981 gtk_widget_get_preferred_width_for_height(child->widget, child->h,
986 static gint columns_gtk3_get_min_height(ColumnsChild *child)
989 gtk_widget_get_preferred_height(child->widget, &ret, NULL);
993 static gint columns_gtk3_get_nat_height(ColumnsChild *child)
996 gtk_widget_get_preferred_height(child->widget, NULL, &ret);
1000 static gint columns_gtk3_get_minfw_height(ColumnsChild *child)
1003 gtk_widget_get_preferred_height_for_width(child->widget, child->w,
1008 static gint columns_gtk3_get_natfw_height(ColumnsChild *child)
1011 gtk_widget_get_preferred_height_for_width(child->widget, child->w,
1016 static void columns_get_preferred_width(GtkWidget *widget,
1017 gint *min, gint *nat)
1021 g_return_if_fail(widget != NULL);
1022 g_return_if_fail(IS_COLUMNS(widget));
1024 cols = COLUMNS(widget);
1027 *min = columns_compute_width(cols, columns_gtk3_get_min_width);
1029 *nat = columns_compute_width(cols, columns_gtk3_get_nat_width);
1032 static void columns_get_preferred_height(GtkWidget *widget,
1033 gint *min, gint *nat)
1037 g_return_if_fail(widget != NULL);
1038 g_return_if_fail(IS_COLUMNS(widget));
1040 cols = COLUMNS(widget);
1043 *min = columns_compute_height(cols, columns_gtk3_get_min_height);
1045 *nat = columns_compute_height(cols, columns_gtk3_get_nat_height);
1048 static void columns_get_preferred_width_for_height(GtkWidget *widget,
1050 gint *min, gint *nat)
1054 g_return_if_fail(widget != NULL);
1055 g_return_if_fail(IS_COLUMNS(widget));
1057 cols = COLUMNS(widget);
1059 /* FIXME: which one should the get-height function here be? */
1060 columns_alloc_vert(cols, height, columns_gtk3_get_nat_height);
1063 *min = columns_compute_width(cols, columns_gtk3_get_minfh_width);
1065 *nat = columns_compute_width(cols, columns_gtk3_get_natfh_width);
1068 static void columns_get_preferred_height_for_width(GtkWidget *widget,
1070 gint *min, gint *nat)
1074 g_return_if_fail(widget != NULL);
1075 g_return_if_fail(IS_COLUMNS(widget));
1077 cols = COLUMNS(widget);
1079 /* FIXME: which one should the get-height function here be? */
1080 columns_alloc_horiz(cols, width, columns_gtk3_get_nat_width);
1083 *min = columns_compute_height(cols, columns_gtk3_get_minfw_height);
1085 *nat = columns_compute_height(cols, columns_gtk3_get_natfw_height);
1088 static void columns_size_allocate(GtkWidget *widget, GtkAllocation *alloc)
1091 ColumnsChild *child;
1095 g_return_if_fail(widget != NULL);
1096 g_return_if_fail(IS_COLUMNS(widget));
1097 g_return_if_fail(alloc != NULL);
1099 cols = COLUMNS(widget);
1100 gtk_widget_set_allocation(widget, alloc);
1102 border = gtk_container_get_border_width(GTK_CONTAINER(cols));
1104 columns_alloc_horiz(cols, alloc->width, columns_gtk3_get_min_width);
1105 columns_alloc_vert(cols, alloc->height, columns_gtk3_get_minfw_height);
1107 for (children = cols->children;
1108 children && (child = children->data);
1109 children = children->next) {
1110 if (child->widget && gtk_widget_get_visible(child->widget)) {
1112 call.x = alloc->x + border + child->x;
1113 call.y = alloc->y + border + child->y;
1114 call.width = child->w;
1115 call.height = child->h;
1116 gtk_widget_size_allocate(child->widget, &call);