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);
295 gtk_widget_queue_resize(GTK_WIDGET(container));
299 for (children = cols->taborder;
300 children && (childw = children->data);
301 children = children->next) {
302 if (childw != widget)
305 cols->taborder = g_list_remove_link(cols->taborder, children);
306 g_list_free(children);
307 #if GTK_CHECK_VERSION(2,0,0)
308 gtk_container_set_focus_chain(container, cols->taborder);
314 static void columns_forall(GtkContainer *container, gboolean include_internals,
315 GtkCallback callback, gpointer callback_data)
319 GList *children, *next;
321 g_return_if_fail(container != NULL);
322 g_return_if_fail(IS_COLUMNS(container));
323 g_return_if_fail(callback != NULL);
325 cols = COLUMNS(container);
327 for (children = cols->children;
328 children && (child = children->data);
331 * We can't wait until after the callback to assign
332 * `children = children->next', because the callback might
333 * be gtk_widget_destroy, which would remove the link
334 * `children' from the list! So instead we must get our
335 * hands on the value of the `next' pointer _before_ the
338 next = children->next;
340 callback(child->widget, callback_data);
344 static GType columns_child_type(GtkContainer *container)
346 return GTK_TYPE_WIDGET;
349 GtkWidget *columns_new(gint spacing)
353 #if !GTK_CHECK_VERSION(2,0,0)
354 cols = gtk_type_new(columns_get_type());
356 cols = g_object_new(TYPE_COLUMNS, NULL);
359 cols->spacing = spacing;
361 return GTK_WIDGET(cols);
364 void columns_set_cols(Columns *cols, gint ncols, const gint *percentages)
366 ColumnsChild *childdata;
369 g_return_if_fail(cols != NULL);
370 g_return_if_fail(IS_COLUMNS(cols));
371 g_return_if_fail(ncols > 0);
372 g_return_if_fail(percentages != NULL);
374 childdata = g_new(ColumnsChild, 1);
375 childdata->widget = NULL;
376 childdata->ncols = ncols;
377 childdata->percentages = g_new(gint, ncols);
378 childdata->force_left = FALSE;
379 for (i = 0; i < ncols; i++)
380 childdata->percentages[i] = percentages[i];
382 cols->children = g_list_append(cols->children, childdata);
385 void columns_add(Columns *cols, GtkWidget *child,
386 gint colstart, gint colspan)
388 ColumnsChild *childdata;
390 g_return_if_fail(cols != NULL);
391 g_return_if_fail(IS_COLUMNS(cols));
392 g_return_if_fail(child != NULL);
393 g_return_if_fail(gtk_widget_get_parent(child) == NULL);
395 childdata = g_new(ColumnsChild, 1);
396 childdata->widget = child;
397 childdata->colstart = colstart;
398 childdata->colspan = colspan;
399 childdata->force_left = FALSE;
401 cols->children = g_list_append(cols->children, childdata);
402 cols->taborder = g_list_append(cols->taborder, child);
404 gtk_widget_set_parent(child, GTK_WIDGET(cols));
406 #if GTK_CHECK_VERSION(2,0,0)
407 gtk_container_set_focus_chain(GTK_CONTAINER(cols), cols->taborder);
410 if (gtk_widget_get_realized(GTK_WIDGET(cols)))
411 gtk_widget_realize(child);
413 if (gtk_widget_get_visible(GTK_WIDGET(cols)) &&
414 gtk_widget_get_visible(child)) {
415 if (gtk_widget_get_mapped(GTK_WIDGET(cols)))
416 gtk_widget_map(child);
417 gtk_widget_queue_resize(child);
421 void columns_force_left_align(Columns *cols, GtkWidget *widget)
426 g_return_if_fail(cols != NULL);
427 g_return_if_fail(IS_COLUMNS(cols));
428 g_return_if_fail(widget != NULL);
430 for (children = cols->children;
431 children && (child = children->data);
432 children = children->next) {
433 if (child->widget != widget)
436 child->force_left = TRUE;
437 if (gtk_widget_get_visible(widget))
438 gtk_widget_queue_resize(GTK_WIDGET(cols));
443 void columns_taborder_last(Columns *cols, GtkWidget *widget)
448 g_return_if_fail(cols != NULL);
449 g_return_if_fail(IS_COLUMNS(cols));
450 g_return_if_fail(widget != NULL);
452 for (children = cols->taborder;
453 children && (childw = children->data);
454 children = children->next) {
455 if (childw != widget)
458 cols->taborder = g_list_remove_link(cols->taborder, children);
459 g_list_free(children);
460 cols->taborder = g_list_append(cols->taborder, widget);
461 #if GTK_CHECK_VERSION(2,0,0)
462 gtk_container_set_focus_chain(GTK_CONTAINER(cols), cols->taborder);
468 #if !GTK_CHECK_VERSION(2,0,0)
470 * Override GtkContainer's focus movement so the user can
471 * explicitly specify the tab order.
473 static gint columns_focus(GtkContainer *container, GtkDirectionType dir)
477 GtkWidget *focuschild;
479 g_return_val_if_fail(container != NULL, FALSE);
480 g_return_val_if_fail(IS_COLUMNS(container), FALSE);
482 cols = COLUMNS(container);
484 if (!GTK_WIDGET_DRAWABLE(cols) ||
485 !GTK_WIDGET_IS_SENSITIVE(cols))
488 if (!GTK_WIDGET_CAN_FOCUS(container) &&
489 (dir == GTK_DIR_TAB_FORWARD || dir == GTK_DIR_TAB_BACKWARD)) {
491 focuschild = container->focus_child;
492 gtk_container_set_focus_child(container, NULL);
494 if (dir == GTK_DIR_TAB_FORWARD)
495 pos = cols->taborder;
497 pos = g_list_last(cols->taborder);
500 GtkWidget *child = pos->data;
503 if (focuschild == child) {
504 focuschild = NULL; /* now we can start looking in here */
505 if (GTK_WIDGET_DRAWABLE(child) &&
506 GTK_IS_CONTAINER(child) &&
507 !GTK_WIDGET_HAS_FOCUS(child)) {
508 if (gtk_container_focus(GTK_CONTAINER(child), dir))
512 } else if (GTK_WIDGET_DRAWABLE(child)) {
513 if (GTK_IS_CONTAINER(child)) {
514 if (gtk_container_focus(GTK_CONTAINER(child), dir))
516 } else if (GTK_WIDGET_CAN_FOCUS(child)) {
517 gtk_widget_grab_focus(child);
522 if (dir == GTK_DIR_TAB_FORWARD)
530 return columns_inherited_focus(container, dir);
535 * Underlying parts of the layout algorithm, to compute the Columns
536 * container's width or height given the widths or heights of its
537 * children. These will be called in various ways with different
538 * notions of width and height in use, so we abstract them out and
539 * pass them a 'get width' or 'get height' function pointer.
542 typedef gint (*widget_dim_fn_t)(ColumnsChild *child);
544 static gint columns_compute_width(Columns *cols, widget_dim_fn_t get_width)
548 gint i, ncols, colspan, retwidth, childwidth;
549 const gint *percentages;
550 static const gint onecol[] = { 100 };
555 percentages = onecol;
557 for (children = cols->children;
558 children && (child = children->data);
559 children = children->next) {
561 if (!child->widget) {
562 /* Column reconfiguration. */
563 ncols = child->ncols;
564 percentages = child->percentages;
568 /* Only take visible widgets into account. */
569 if (!gtk_widget_get_visible(child->widget))
572 childwidth = get_width(child);
573 colspan = child->colspan ? child->colspan : ncols-child->colstart;
576 * To compute width: we know that childwidth + cols->spacing
577 * needs to equal a certain percentage of the full width of
578 * the container. So we work this value out, figure out how
579 * wide the container will need to be to make that percentage
580 * of it equal to that width, and ensure our returned width is
581 * at least that much. Very simple really.
584 int percent, thiswid, fullwid;
587 for (i = 0; i < colspan; i++)
588 percent += percentages[child->colstart+i];
590 thiswid = childwidth + cols->spacing;
592 * Since childwidth is (at least sometimes) the _minimum_
593 * size the child needs, we must ensure that it gets _at
594 * least_ that size. Hence, when scaling thiswid up to
595 * fullwid, we must round up, which means adding percent-1
596 * before dividing by percent.
598 fullwid = (thiswid * 100 + percent - 1) / percent;
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.
606 if (retwidth < fullwid - cols->spacing)
607 retwidth = fullwid - cols->spacing;
611 retwidth += 2*gtk_container_get_border_width(GTK_CONTAINER(cols));
616 static void columns_alloc_horiz(Columns *cols, gint ourwidth,
617 widget_dim_fn_t get_width)
621 gint i, ncols, colspan, border, *colxpos, childwidth;
622 const gint *percentages;
623 static const gint onecol[] = { 100 };
625 border = gtk_container_get_border_width(GTK_CONTAINER(cols));
628 percentages = onecol;
629 /* colxpos gives the starting x position of each column.
630 * We supply n+1 of them, so that we can find the RH edge easily.
631 * All ending x positions are expected to be adjusted afterwards by
632 * subtracting the spacing. */
633 colxpos = g_new(gint, 2);
635 colxpos[1] = ourwidth - 2*border + cols->spacing;
637 for (children = cols->children;
638 children && (child = children->data);
639 children = children->next) {
641 if (!child->widget) {
644 /* Column reconfiguration. */
645 ncols = child->ncols;
646 percentages = child->percentages;
647 colxpos = g_renew(gint, colxpos, ncols + 1);
650 for (i = 0; i < ncols; i++) {
651 percent += percentages[i];
652 colxpos[i+1] = (((ourwidth - 2*border) + cols->spacing)
658 /* Only take visible widgets into account. */
659 if (!gtk_widget_get_visible(child->widget))
662 childwidth = get_width(child);
663 colspan = child->colspan ? child->colspan : ncols-child->colstart;
666 * Starting x position is cols[colstart].
667 * Ending x position is cols[colstart+colspan] - spacing.
669 * Unless we're forcing left, in which case the width is
670 * exactly the requisition width.
672 child->x = colxpos[child->colstart];
673 if (child->force_left)
674 child->w = childwidth;
676 child->w = (colxpos[child->colstart+colspan] -
677 colxpos[child->colstart] - cols->spacing);
683 static gint columns_compute_height(Columns *cols, widget_dim_fn_t get_height)
687 gint i, ncols, colspan, *colypos, retheight, childheight;
689 retheight = cols->spacing;
692 colypos = g_new(gint, 1);
695 for (children = cols->children;
696 children && (child = children->data);
697 children = children->next) {
699 if (!child->widget) {
700 /* Column reconfiguration. */
701 for (i = 1; i < ncols; i++) {
702 if (colypos[0] < colypos[i])
703 colypos[0] = colypos[i];
705 ncols = child->ncols;
706 colypos = g_renew(gint, colypos, ncols);
707 for (i = 1; i < ncols; i++)
708 colypos[i] = colypos[0];
712 /* Only take visible widgets into account. */
713 if (!gtk_widget_get_visible(child->widget))
716 childheight = get_height(child);
717 colspan = child->colspan ? child->colspan : ncols-child->colstart;
720 * To compute height: the widget's top will be positioned at
721 * the largest y value so far reached in any of the columns it
722 * crosses. Then it will go down by childheight plus padding;
723 * and the point it reaches at the bottom is the new y value
724 * in all those columns, and minus the padding it is also a
725 * lower bound on our own height.
731 for (i = 0; i < colspan; i++) {
732 if (topy < colypos[child->colstart+i])
733 topy = colypos[child->colstart+i];
735 boty = topy + childheight + cols->spacing;
736 for (i = 0; i < colspan; i++) {
737 colypos[child->colstart+i] = boty;
740 if (retheight < boty - cols->spacing)
741 retheight = boty - cols->spacing;
745 retheight += 2*gtk_container_get_border_width(GTK_CONTAINER(cols));
752 static void columns_alloc_vert(Columns *cols, gint ourheight,
753 widget_dim_fn_t get_height)
757 gint i, ncols, colspan, *colypos, childheight;
760 /* As in size_request, colypos is the lowest y reached in each column. */
761 colypos = g_new(gint, 1);
764 for (children = cols->children;
765 children && (child = children->data);
766 children = children->next) {
767 if (!child->widget) {
768 /* Column reconfiguration. */
769 for (i = 1; i < ncols; i++) {
770 if (colypos[0] < colypos[i])
771 colypos[0] = colypos[i];
773 ncols = child->ncols;
774 colypos = g_renew(gint, colypos, ncols);
775 for (i = 1; i < ncols; i++)
776 colypos[i] = colypos[0];
780 /* Only take visible widgets into account. */
781 if (!gtk_widget_get_visible(child->widget))
784 childheight = get_height(child);
785 colspan = child->colspan ? child->colspan : ncols-child->colstart;
788 * To compute height: the widget's top will be positioned
789 * at the largest y value so far reached in any of the
790 * columns it crosses. Then it will go down by creq.height
791 * plus padding; and the point it reaches at the bottom is
792 * the new y value in all those columns.
798 for (i = 0; i < colspan; i++) {
799 if (topy < colypos[child->colstart+i])
800 topy = colypos[child->colstart+i];
803 child->h = childheight;
804 boty = topy + childheight + cols->spacing;
805 for (i = 0; i < colspan; i++) {
806 colypos[child->colstart+i] = boty;
815 * Now here comes the interesting bit. The actual layout part is
816 * done in the following two functions:
818 * columns_size_request() examines the list of widgets held in the
819 * Columns, and returns a requisition stating the absolute minimum
820 * size it can bear to be.
822 * columns_size_allocate() is given an allocation telling it what
823 * size the whole container is going to be, and it calls
824 * gtk_widget_size_allocate() on all of its (visible) children to
825 * set their size and position relative to the top left of the
829 #if !GTK_CHECK_VERSION(3,0,0)
831 static gint columns_gtk2_get_width(ColumnsChild *child)
834 gtk_widget_size_request(child->widget, &creq);
838 static gint columns_gtk2_get_height(ColumnsChild *child)
841 gtk_widget_size_request(child->widget, &creq);
845 static void columns_size_request(GtkWidget *widget, GtkRequisition *req)
849 g_return_if_fail(widget != NULL);
850 g_return_if_fail(IS_COLUMNS(widget));
851 g_return_if_fail(req != NULL);
853 cols = COLUMNS(widget);
855 req->width = columns_compute_width(cols, columns_gtk2_get_width);
856 req->height = columns_compute_height(cols, columns_gtk2_get_height);
859 static void columns_size_allocate(GtkWidget *widget, GtkAllocation *alloc)
866 g_return_if_fail(widget != NULL);
867 g_return_if_fail(IS_COLUMNS(widget));
868 g_return_if_fail(alloc != NULL);
870 cols = COLUMNS(widget);
871 gtk_widget_set_allocation(widget, alloc);
873 border = gtk_container_get_border_width(GTK_CONTAINER(cols));
875 columns_alloc_horiz(cols, alloc->width, columns_gtk2_get_width);
876 columns_alloc_vert(cols, alloc->height, columns_gtk2_get_height);
878 for (children = cols->children;
879 children && (child = children->data);
880 children = children->next) {
881 if (child->widget && gtk_widget_get_visible(child->widget)) {
883 call.x = alloc->x + border + child->x;
884 call.y = alloc->y + border + child->y;
885 call.width = child->w;
886 call.height = child->h;
887 gtk_widget_size_allocate(child->widget, &call);
892 #else /* GTK_CHECK_VERSION(3,0,0) */
894 static gint columns_gtk3_get_min_width(ColumnsChild *child)
897 gtk_widget_get_preferred_width(child->widget, &ret, NULL);
901 static gint columns_gtk3_get_nat_width(ColumnsChild *child)
905 if (GTK_IS_LABEL(child->widget) &&
906 gtk_label_get_line_wrap(GTK_LABEL(child->widget))) {
908 * We treat wrapping GtkLabels as a special case in this
909 * layout class, because the whole point of those is that I
910 * _don't_ want them to take up extra horizontal space for
911 * long text, but instead to wrap it to whatever size is used
912 * by the rest of the layout.
914 gtk_widget_get_preferred_width(child->widget, &ret, NULL);
916 gtk_widget_get_preferred_width(child->widget, NULL, &ret);
921 static gint columns_gtk3_get_minfh_width(ColumnsChild *child)
924 gtk_widget_get_preferred_width_for_height(child->widget, child->h,
929 static gint columns_gtk3_get_natfh_width(ColumnsChild *child)
932 gtk_widget_get_preferred_width_for_height(child->widget, child->h,
937 static gint columns_gtk3_get_min_height(ColumnsChild *child)
940 gtk_widget_get_preferred_height(child->widget, &ret, NULL);
944 static gint columns_gtk3_get_nat_height(ColumnsChild *child)
947 gtk_widget_get_preferred_height(child->widget, NULL, &ret);
951 static gint columns_gtk3_get_minfw_height(ColumnsChild *child)
954 gtk_widget_get_preferred_height_for_width(child->widget, child->w,
959 static gint columns_gtk3_get_natfw_height(ColumnsChild *child)
962 gtk_widget_get_preferred_height_for_width(child->widget, child->w,
967 static void columns_get_preferred_width(GtkWidget *widget,
968 gint *min, gint *nat)
972 g_return_if_fail(widget != NULL);
973 g_return_if_fail(IS_COLUMNS(widget));
975 cols = COLUMNS(widget);
978 *min = columns_compute_width(cols, columns_gtk3_get_min_width);
980 *nat = columns_compute_width(cols, columns_gtk3_get_nat_width);
983 static void columns_get_preferred_height(GtkWidget *widget,
984 gint *min, gint *nat)
988 g_return_if_fail(widget != NULL);
989 g_return_if_fail(IS_COLUMNS(widget));
991 cols = COLUMNS(widget);
994 *min = columns_compute_height(cols, columns_gtk3_get_min_height);
996 *nat = columns_compute_height(cols, columns_gtk3_get_nat_height);
999 static void columns_get_preferred_width_for_height(GtkWidget *widget,
1001 gint *min, gint *nat)
1005 g_return_if_fail(widget != NULL);
1006 g_return_if_fail(IS_COLUMNS(widget));
1008 cols = COLUMNS(widget);
1010 /* FIXME: which one should the get-height function here be? */
1011 columns_alloc_vert(cols, height, columns_gtk3_get_nat_height);
1014 *min = columns_compute_width(cols, columns_gtk3_get_minfh_width);
1016 *nat = columns_compute_width(cols, columns_gtk3_get_natfh_width);
1019 static void columns_get_preferred_height_for_width(GtkWidget *widget,
1021 gint *min, gint *nat)
1025 g_return_if_fail(widget != NULL);
1026 g_return_if_fail(IS_COLUMNS(widget));
1028 cols = COLUMNS(widget);
1030 /* FIXME: which one should the get-height function here be? */
1031 columns_alloc_horiz(cols, width, columns_gtk3_get_nat_width);
1034 *min = columns_compute_height(cols, columns_gtk3_get_minfw_height);
1036 *nat = columns_compute_height(cols, columns_gtk3_get_natfw_height);
1039 static void columns_size_allocate(GtkWidget *widget, GtkAllocation *alloc)
1042 ColumnsChild *child;
1046 g_return_if_fail(widget != NULL);
1047 g_return_if_fail(IS_COLUMNS(widget));
1048 g_return_if_fail(alloc != NULL);
1050 cols = COLUMNS(widget);
1051 gtk_widget_set_allocation(widget, alloc);
1053 border = gtk_container_get_border_width(GTK_CONTAINER(cols));
1055 columns_alloc_horiz(cols, alloc->width, columns_gtk3_get_min_width);
1056 columns_alloc_vert(cols, alloc->height, columns_gtk3_get_minfw_height);
1058 for (children = cols->children;
1059 children && (child = children->data);
1060 children = children->next) {
1061 if (child->widget && gtk_widget_get_visible(child->widget)) {
1063 call.x = alloc->x + border + child->x;
1064 call.y = alloc->y + border + child->y;
1065 call.width = child->w;
1066 call.height = child->h;
1067 gtk_widget_size_allocate(child->widget, &call);