From cce6a603a6aa054d2d5aaaf9b3b0671cb6a9970c Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 6 Nov 2021 16:17:59 +0100 Subject: [PATCH 1/7] label: max-width-chars has no effect on smaller text Having a short text and a large max-width-chars should request the natural width of the text, not the limit from max-width-chars. This caused huge message dialogs. Reftests added. --- gtk/gtklabel.c | 11 ++++------- .../reftests/label-huge-max-width-chars.ref.ui | 11 +++++++++++ testsuite/reftests/label-huge-max-width-chars.ui | 12 ++++++++++++ .../label-wrapped-huge-max-width-chars.ref.ui | 12 ++++++++++++ .../reftests/label-wrapped-huge-max-width-chars.ui | 13 +++++++++++++ testsuite/reftests/meson.build | 4 ++++ 6 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 testsuite/reftests/label-huge-max-width-chars.ref.ui create mode 100644 testsuite/reftests/label-huge-max-width-chars.ui create mode 100644 testsuite/reftests/label-wrapped-huge-max-width-chars.ref.ui create mode 100644 testsuite/reftests/label-wrapped-huge-max-width-chars.ui diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c index 3c3be85406..46af2fb174 100644 --- a/gtk/gtklabel.c +++ b/gtk/gtklabel.c @@ -1077,14 +1077,15 @@ get_static_size (GtkLabel *self, int *minimum_baseline, int *natural_baseline) { + int minimum_default, natural_default; PangoLayout *layout; - layout = gtk_label_get_measuring_layout (self, NULL, -1); + get_default_widths (self, &minimum_default, &natural_default); + + layout = gtk_label_get_measuring_layout (self, NULL, natural_default); if (orientation == GTK_ORIENTATION_HORIZONTAL) { - int minimum_default, natural_default; - pango_layout_get_size (layout, natural, NULL); if (self->ellipsize) { @@ -1096,11 +1097,8 @@ get_static_size (GtkLabel *self, else *minimum = *natural; - get_default_widths (self, &minimum_default, &natural_default); if (minimum_default > *minimum) *minimum = minimum_default; - if (natural_default > -1) - *natural = natural_default; *natural = MAX (*minimum, *natural); } else @@ -1180,7 +1178,6 @@ get_width_for_height (GtkLabel *self, /* Natural width is natural width - or as wide as possible */ layout = gtk_label_get_measuring_layout (self, layout, natural_default); pango_layout_get_size (layout, natural_width, NULL); - *natural_width = MAX (*natural_width, natural_default); *natural_width = MAX (*natural_width, *minimum_width); } else diff --git a/testsuite/reftests/label-huge-max-width-chars.ref.ui b/testsuite/reftests/label-huge-max-width-chars.ref.ui new file mode 100644 index 0000000000..ec722f56ce --- /dev/null +++ b/testsuite/reftests/label-huge-max-width-chars.ref.ui @@ -0,0 +1,11 @@ + + + + 0 + + + Hello World + + + + diff --git a/testsuite/reftests/label-huge-max-width-chars.ui b/testsuite/reftests/label-huge-max-width-chars.ui new file mode 100644 index 0000000000..bf1237c1de --- /dev/null +++ b/testsuite/reftests/label-huge-max-width-chars.ui @@ -0,0 +1,12 @@ + + + + 0 + + + Hello World + 1000 + + + + diff --git a/testsuite/reftests/label-wrapped-huge-max-width-chars.ref.ui b/testsuite/reftests/label-wrapped-huge-max-width-chars.ref.ui new file mode 100644 index 0000000000..5ec6dea124 --- /dev/null +++ b/testsuite/reftests/label-wrapped-huge-max-width-chars.ref.ui @@ -0,0 +1,12 @@ + + + + 0 + + + Hello World + 1 + + + + diff --git a/testsuite/reftests/label-wrapped-huge-max-width-chars.ui b/testsuite/reftests/label-wrapped-huge-max-width-chars.ui new file mode 100644 index 0000000000..cc21161d61 --- /dev/null +++ b/testsuite/reftests/label-wrapped-huge-max-width-chars.ui @@ -0,0 +1,13 @@ + + + + 0 + + + Hello World + 1000 + 1 + + + + diff --git a/testsuite/reftests/meson.build b/testsuite/reftests/meson.build index 7917c1d388..d6857190cf 100644 --- a/testsuite/reftests/meson.build +++ b/testsuite/reftests/meson.build @@ -347,6 +347,8 @@ testdata = [ 'label-fonts.css', 'label-fonts.ref.ui', 'label-fonts.ui', + 'label-huge-max-width-chars.ref.ui', + 'label-huge-max-width-chars.ui', 'label-max-width-chars-and-halign-and-infinite-width.ui', 'label-max-width-chars-and-halign-and-infinite-width.ref.ui', 'label-shadows.css', @@ -365,6 +367,8 @@ testdata = [ 'label-text-shadow-changes-modify-clip.ui', 'label-width-chars-dont-shrink.ref.ui', 'label-width-chars-dont-shrink.ui', + 'label-wrapped-huge-max-width-chars.ref.ui', + 'label-wrapped-huge-max-width-chars.ui', # this seems to make assumptions on text positioning # that are not valid with subpixel positioning #'label-wrap-justify.ref.ui', From 81169d18c3d2f22263ea04361ac6944eef892855 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 6 Nov 2021 16:25:11 +0100 Subject: [PATCH 2/7] label: max-width-chars should be ignored sometimes When a widget is neither wrappable nor ellipsizable, we cannot modify the label to fit into any size. So we cannot respect max-width-chars. --- gtk/gtklabel.c | 2 +- .../reftests/label-small-max-width-chars.ref.ui | 11 +++++++++++ testsuite/reftests/label-small-max-width-chars.ui | 12 ++++++++++++ testsuite/reftests/meson.build | 2 ++ 4 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 testsuite/reftests/label-small-max-width-chars.ref.ui create mode 100644 testsuite/reftests/label-small-max-width-chars.ui diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c index 46af2fb174..a82ec7bb77 100644 --- a/gtk/gtklabel.c +++ b/gtk/gtklabel.c @@ -1082,7 +1082,7 @@ get_static_size (GtkLabel *self, get_default_widths (self, &minimum_default, &natural_default); - layout = gtk_label_get_measuring_layout (self, NULL, natural_default); + layout = gtk_label_get_measuring_layout (self, NULL, self->ellipsize ? natural_default : -1); if (orientation == GTK_ORIENTATION_HORIZONTAL) { diff --git a/testsuite/reftests/label-small-max-width-chars.ref.ui b/testsuite/reftests/label-small-max-width-chars.ref.ui new file mode 100644 index 0000000000..ec722f56ce --- /dev/null +++ b/testsuite/reftests/label-small-max-width-chars.ref.ui @@ -0,0 +1,11 @@ + + + + 0 + + + Hello World + + + + diff --git a/testsuite/reftests/label-small-max-width-chars.ui b/testsuite/reftests/label-small-max-width-chars.ui new file mode 100644 index 0000000000..d3236e8035 --- /dev/null +++ b/testsuite/reftests/label-small-max-width-chars.ui @@ -0,0 +1,12 @@ + + + + 0 + + + Hello World + 2 + + + + diff --git a/testsuite/reftests/meson.build b/testsuite/reftests/meson.build index d6857190cf..9f40c0f3a0 100644 --- a/testsuite/reftests/meson.build +++ b/testsuite/reftests/meson.build @@ -359,6 +359,8 @@ testdata = [ 'label-sizing.ui', 'label-small-ellipsized.ref.ui', 'label-small-ellipsized.ui', + 'label-small-max-width-chars.ref.ui', + 'label-small-max-width-chars.ui', 'label-text-shadow-clipping.css', 'label-text-shadow-clipping.ref.ui', 'label-text-shadow-clipping.ui', From 129042425d5fb867607004d592d4dbf8f9321c78 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 6 Nov 2021 16:39:01 +0100 Subject: [PATCH 3/7] demos: Update for climate change and Covid --- demos/widget-factory/widget-factory.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/widget-factory/widget-factory.ui b/demos/widget-factory/widget-factory.ui index 7c190d08cb..e31629d986 100644 --- a/demos/widget-factory/widget-factory.ui +++ b/demos/widget-factory/widget-factory.ui @@ -2923,7 +2923,7 @@ microphone-sensitivity-medium-symbolic 0 1 Do something? - If you do something, + If you don't do something, bad things might happen. 1 From b004706009f9ad19e34a82928b383345b50a5075 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 6 Nov 2021 18:26:41 +0100 Subject: [PATCH 4/7] Revert "sizerequest: Only check reported baselines if requested" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit cf7fa931d380c6d205478c87f0f3973f496f9d2a. We store the baseline in the cache and we do not know if baselines might be queried in the future. So always store them. No reftest because I don't know how to write one. premature optimization == √😈 --- gtk/gtksizerequest.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gtk/gtksizerequest.c b/gtk/gtksizerequest.c index 45770d5498..a0f066b997 100644 --- a/gtk/gtksizerequest.c +++ b/gtk/gtksizerequest.c @@ -139,7 +139,6 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget, int *minimum_baseline, int *natural_baseline) { - const gboolean baselines_requested = (minimum_baseline != NULL || natural_baseline != NULL); SizeRequestCache *cache; int min_size = 0; int nat_size = 0; @@ -361,7 +360,7 @@ gtk_widget_query_size_for_orientation (GtkWidget *widget, nat_size = adjusted_natural; } - if (baselines_requested && (min_baseline != -1 || nat_baseline != -1)) + if (min_baseline != -1 || nat_baseline != -1) { if (orientation == GTK_ORIENTATION_HORIZONTAL) { From afe94e303a797381daa5e5175de4c3c3d3b55104 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Mon, 8 Nov 2021 17:49:15 +0100 Subject: [PATCH 5/7] boxlayout: Don't listen to comments ... when they are wrong. Instead, remove them. Or in other words: GTK4 does not have a fill child property anymore, so we don't need to run the measuring loop above to determine the size. --- gtk/gtkboxlayout.c | 76 ++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 40 deletions(-) diff --git a/gtk/gtkboxlayout.c b/gtk/gtkboxlayout.c index 20b462eb40..d942167a3d 100644 --- a/gtk/gtkboxlayout.c +++ b/gtk/gtkboxlayout.c @@ -322,53 +322,49 @@ gtk_box_layout_compute_opposite_size_for_size (GtkBoxLayout *self, sizes = g_newa (GtkRequestedSize, nvis_children); extra_space = MAX (0, for_size - (nvis_children - 1) * spacing); - /* Retrieve desired size for visible children */ - for (i = 0, child = _gtk_widget_get_first_child (widget); - child != NULL; - child = _gtk_widget_get_next_sibling (child)) - { - int min_opposite, nat_for_min; - - if (!gtk_widget_should_layout (child)) - continue; - - gtk_widget_measure (child, - self->orientation, - -1, - &sizes[i].minimum_size, &sizes[i].natural_size, - NULL, NULL); - /* Don't just use the natural size as the max size, - * the natural size is the ideal size, not necessarily - * the maximum size. - * Also check the nat size for opposite min size. - */ - gtk_widget_measure (child, - OPPOSITE_ORIENTATION (self->orientation), - -1, - &min_opposite, NULL, - NULL, NULL); - gtk_widget_measure (child, - self->orientation, - min_opposite, - NULL, &nat_for_min, - NULL, NULL); - sizes[i].natural_size = MAX (sizes[i].natural_size, nat_for_min); - - children_minimum_size += sizes[i].minimum_size; - i += 1; - } - if (self->homogeneous) { - /* We still need to run the above loop to populate the minimum sizes for - * children that aren't going to fill. - */ - size_given_to_child = extra_space / nvis_children; n_extra_widgets = extra_space % nvis_children; } else { + /* Retrieve desired size for visible children */ + for (i = 0, child = _gtk_widget_get_first_child (widget); + child != NULL; + child = _gtk_widget_get_next_sibling (child)) + { + int min_opposite, nat_for_min; + + if (!gtk_widget_should_layout (child)) + continue; + + gtk_widget_measure (child, + self->orientation, + -1, + &sizes[i].minimum_size, &sizes[i].natural_size, + NULL, NULL); + /* Don't just use the natural size as the max size, + * the natural size is the ideal size, not necessarily + * the maximum size. + * Also check the nat size for opposite min size. + */ + gtk_widget_measure (child, + OPPOSITE_ORIENTATION (self->orientation), + -1, + &min_opposite, NULL, + NULL, NULL); + gtk_widget_measure (child, + self->orientation, + min_opposite, + NULL, &nat_for_min, + NULL, NULL); + sizes[i].natural_size = MAX (sizes[i].natural_size, nat_for_min); + + children_minimum_size += sizes[i].minimum_size; + i += 1; + } + /* Bring children up to size first */ extra_space -= children_minimum_size; extra_space = MAX (0, extra_space); From 0a31201c889a49667d7411bdafc7998a10a220ce Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 9 Nov 2021 01:59:08 +0100 Subject: [PATCH 6/7] boxlayout: Split loop into if statmement Turns it into 2 loops, one for the homogeneous part and one for the complicated part. --- gtk/gtkboxlayout.c | 111 ++++++++++++++++++++++++++------------------- 1 file changed, 65 insertions(+), 46 deletions(-) diff --git a/gtk/gtkboxlayout.c b/gtk/gtkboxlayout.c index d942167a3d..44394059d4 100644 --- a/gtk/gtkboxlayout.c +++ b/gtk/gtkboxlayout.c @@ -311,7 +311,7 @@ gtk_box_layout_compute_opposite_size_for_size (GtkBoxLayout *self, int child_minimum_baseline, child_natural_baseline; int n_extra_widgets = 0; int spacing; - gboolean have_baseline; + gboolean have_baseline = FALSE; count_expand_children (widget, self->orientation, &nvis_children, &nexpand_children); @@ -320,12 +320,51 @@ gtk_box_layout_compute_opposite_size_for_size (GtkBoxLayout *self, spacing = get_spacing (self, gtk_widget_get_css_node (widget)); sizes = g_newa (GtkRequestedSize, nvis_children); - extra_space = MAX (0, for_size - (nvis_children - 1) * spacing); + g_assert ((nvis_children - 1) * spacing <= for_size); + extra_space = for_size - (nvis_children - 1) * spacing; if (self->homogeneous) { size_given_to_child = extra_space / nvis_children; n_extra_widgets = extra_space % nvis_children; + + for (child = _gtk_widget_get_first_child (widget); + child != NULL; + child = _gtk_widget_get_next_sibling (child)) + { + if (!gtk_widget_should_layout (child)) + continue; + + child_size = size_given_to_child; + if (n_extra_widgets) + { + child_size++; + n_extra_widgets--; + } + + child_minimum_baseline = child_natural_baseline = -1; + /* Assign the child's position. */ + gtk_widget_measure (child, + OPPOSITE_ORIENTATION (self->orientation), + child_size, + &child_minimum, &child_natural, + &child_minimum_baseline, &child_natural_baseline); + + if (child_minimum_baseline >= 0) + { + have_baseline = TRUE; + computed_minimum_below = MAX (computed_minimum_below, child_minimum - child_minimum_baseline); + computed_natural_below = MAX (computed_natural_below, child_natural - child_natural_baseline); + computed_minimum_above = MAX (computed_minimum_above, child_minimum_baseline); + computed_natural_above = MAX (computed_natural_above, child_natural_baseline); + } + else + { + computed_minimum = MAX (computed_minimum, child_minimum); + computed_natural = MAX (computed_natural, child_natural); + } + } + } else { @@ -360,14 +399,15 @@ gtk_box_layout_compute_opposite_size_for_size (GtkBoxLayout *self, NULL, &nat_for_min, NULL, NULL); sizes[i].natural_size = MAX (sizes[i].natural_size, nat_for_min); + sizes[i].data = child; children_minimum_size += sizes[i].minimum_size; i += 1; } /* Bring children up to size first */ + g_assert (children_minimum_size <= extra_space); extra_space -= children_minimum_size; - extra_space = MAX (0, extra_space); extra_space = gtk_distribute_natural_allocation (extra_space, nvis_children, sizes); /* Calculate space which hasn't distributed yet, @@ -382,32 +422,12 @@ gtk_box_layout_compute_opposite_size_for_size (GtkBoxLayout *self, { size_given_to_child = 0; } - } - have_baseline = FALSE; - for (i = 0, child = _gtk_widget_get_first_child (widget); - child != NULL; - child = _gtk_widget_get_next_sibling (child)) - { - if (!gtk_widget_should_layout (child)) - continue; - - /* Assign the child's size. */ - if (self->homogeneous) - { - child_size = size_given_to_child; - - if (n_extra_widgets > 0) - { - child_size++; - n_extra_widgets--; - } - } - else + for (i = 0; i < nvis_children; i++) { child_size = sizes[i].minimum_size; - if (gtk_widget_compute_expand (child, self->orientation)) + if (gtk_widget_compute_expand (sizes[i].data, self->orientation)) { child_size += size_given_to_child; @@ -417,30 +437,29 @@ gtk_box_layout_compute_opposite_size_for_size (GtkBoxLayout *self, n_extra_widgets--; } } - } - child_minimum_baseline = child_natural_baseline = -1; - /* Assign the child's position. */ - gtk_widget_measure (child, - OPPOSITE_ORIENTATION (self->orientation), - child_size, - &child_minimum, &child_natural, - &child_minimum_baseline, &child_natural_baseline); + child_minimum_baseline = child_natural_baseline = -1; + /* Assign the child's position. */ + gtk_widget_measure (sizes[i].data, + OPPOSITE_ORIENTATION (self->orientation), + child_size, + &child_minimum, &child_natural, + &child_minimum_baseline, &child_natural_baseline); - if (child_minimum_baseline >= 0) - { - have_baseline = TRUE; - computed_minimum_below = MAX (computed_minimum_below, child_minimum - child_minimum_baseline); - computed_natural_below = MAX (computed_natural_below, child_natural - child_natural_baseline); - computed_minimum_above = MAX (computed_minimum_above, child_minimum_baseline); - computed_natural_above = MAX (computed_natural_above, child_natural_baseline); + if (child_minimum_baseline >= 0) + { + have_baseline = TRUE; + computed_minimum_below = MAX (computed_minimum_below, child_minimum - child_minimum_baseline); + computed_natural_below = MAX (computed_natural_below, child_natural - child_natural_baseline); + computed_minimum_above = MAX (computed_minimum_above, child_minimum_baseline); + computed_natural_above = MAX (computed_natural_above, child_natural_baseline); + } + else + { + computed_minimum = MAX (computed_minimum, child_minimum); + computed_natural = MAX (computed_natural, child_natural); + } } - else - { - computed_minimum = MAX (computed_minimum, child_minimum); - computed_natural = MAX (computed_natural, child_natural); - } - i += 1; } if (have_baseline) From 76c46739447023368db4c3e6d008b52ff4b249e0 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 9 Nov 2021 03:28:29 +0100 Subject: [PATCH 7/7] boxlayout: Fix broken min-size-for-opposite-size Assume a vbox with 2 wrapping labels saying Hello World Hi Ho being measured for their minimum width for 3 rows of text. This should be layouted like Hello World Hi Ho and measured accordingly. However, previously this was layouted as Hello World Hi Ho with 1.5 lines being assigned to both labels. That will obviously not compute the above wrapping which clearly results in a smaller min width. A reftest testing exactly this was included. --- gtk/gtkboxlayout.c | 161 +++++++++++++----- testsuite/reftests/meson.build | 2 + ...apping-labels-where-one-should-wrap.ref.ui | 27 +++ ...2-wrapping-labels-where-one-should-wrap.ui | 30 ++++ 4 files changed, 178 insertions(+), 42 deletions(-) create mode 100644 testsuite/reftests/vbox-with-2-wrapping-labels-where-one-should-wrap.ref.ui create mode 100644 testsuite/reftests/vbox-with-2-wrapping-labels-where-one-should-wrap.ui diff --git a/gtk/gtkboxlayout.c b/gtk/gtkboxlayout.c index 44394059d4..e79c5e202a 100644 --- a/gtk/gtkboxlayout.c +++ b/gtk/gtkboxlayout.c @@ -288,6 +288,64 @@ gtk_box_layout_compute_opposite_size (GtkBoxLayout *self, *natural = largest_nat; } +static int +distribute_remaining_size (GtkRequestedSize *sizes, + gsize n_sizes, + GtkOrientation orientation, + int available, + int min, + int max) +{ + int total_size = 0; + gsize i; + + if (n_sizes == 0) + return available; + + for (i = 0; i < n_sizes; i++) + { + gtk_widget_measure (sizes[i].data, + orientation, + min, + &sizes[i].minimum_size, &sizes[i].natural_size, + NULL, NULL); + total_size += sizes[i].minimum_size; + } + + if (total_size <= available) + return available - total_size; + + /* total_size > available happens when we last ran for values too big, + * rerun for the correct value min == max in that case */ + while (min < max || total_size > available) + { + int test; + + if (max == G_MAXINT) + test = min * 2; + else + test = (min + max) / 2; + + total_size = 0; + for (i = 0; i < n_sizes; i++) + { + gtk_widget_measure (sizes[i].data, + orientation, + test, + &sizes[i].minimum_size, &sizes[i].natural_size, + NULL, NULL); + total_size += sizes[i].minimum_size; + } + + if (total_size > available) + min = test + 1; + else + max = test; + } + + return available - total_size; +} + static void gtk_box_layout_compute_opposite_size_for_size (GtkBoxLayout *self, GtkWidget *widget, @@ -305,8 +363,7 @@ gtk_box_layout_compute_opposite_size_for_size (GtkBoxLayout *self, int computed_minimum_below = 0, computed_natural_below = 0; int computed_minimum_baseline = -1, computed_natural_baseline = -1; GtkRequestedSize *sizes; - int extra_space, size_given_to_child, i; - int children_minimum_size = 0; + int available, size_given_to_child, i; int child_size, child_minimum, child_natural; int child_minimum_baseline, child_natural_baseline; int n_extra_widgets = 0; @@ -321,12 +378,12 @@ gtk_box_layout_compute_opposite_size_for_size (GtkBoxLayout *self, spacing = get_spacing (self, gtk_widget_get_css_node (widget)); sizes = g_newa (GtkRequestedSize, nvis_children); g_assert ((nvis_children - 1) * spacing <= for_size); - extra_space = for_size - (nvis_children - 1) * spacing; + available = for_size - (nvis_children - 1) * spacing; if (self->homogeneous) { - size_given_to_child = extra_space / nvis_children; - n_extra_widgets = extra_space % nvis_children; + size_given_to_child = available / nvis_children; + n_extra_widgets = available % nvis_children; for (child = _gtk_widget_get_first_child (widget); child != NULL; @@ -364,70 +421,90 @@ gtk_box_layout_compute_opposite_size_for_size (GtkBoxLayout *self, computed_natural = MAX (computed_natural, child_natural); } } - } else { + int min_size = 0, child_min_size; + int n_inconstant = 0; + /* Retrieve desired size for visible children */ for (i = 0, child = _gtk_widget_get_first_child (widget); child != NULL; child = _gtk_widget_get_next_sibling (child)) { - int min_opposite, nat_for_min; - if (!gtk_widget_should_layout (child)) continue; - gtk_widget_measure (child, - self->orientation, - -1, - &sizes[i].minimum_size, &sizes[i].natural_size, - NULL, NULL); - /* Don't just use the natural size as the max size, - * the natural size is the ideal size, not necessarily - * the maximum size. - * Also check the nat size for opposite min size. - */ - gtk_widget_measure (child, - OPPOSITE_ORIENTATION (self->orientation), - -1, - &min_opposite, NULL, - NULL, NULL); - gtk_widget_measure (child, - self->orientation, - min_opposite, - NULL, &nat_for_min, - NULL, NULL); - sizes[i].natural_size = MAX (sizes[i].natural_size, nat_for_min); - sizes[i].data = child; - - children_minimum_size += sizes[i].minimum_size; - i += 1; + if (gtk_widget_get_request_mode (child) == GTK_SIZE_REQUEST_CONSTANT_SIZE) + { + gtk_widget_measure (child, + self->orientation, + -1, + &sizes[i].minimum_size, &sizes[i].natural_size, + NULL, NULL); + sizes[i].data = child; + g_assert (available >= sizes[i].minimum_size); + available -= sizes[i].minimum_size; + i++; + } + else + { + gtk_widget_measure (child, + OPPOSITE_ORIENTATION (self->orientation), + -1, + &child_min_size, NULL, + NULL, NULL); + min_size = MAX (min_size, child_min_size); + n_inconstant++; + sizes[nvis_children - n_inconstant].data = child; + } } + available = distribute_remaining_size (sizes + nvis_children - n_inconstant, + n_inconstant, + self->orientation, + available, + min_size, + G_MAXINT); + /* Bring children up to size first */ - g_assert (children_minimum_size <= extra_space); - extra_space -= children_minimum_size; - extra_space = gtk_distribute_natural_allocation (extra_space, nvis_children, sizes); + available = gtk_distribute_natural_allocation (available, nvis_children, sizes); /* Calculate space which hasn't distributed yet, * and is available for expanding children. */ if (nexpand_children > 0) { - size_given_to_child = extra_space / nexpand_children; - n_extra_widgets = extra_space % nexpand_children; + size_given_to_child = available / nexpand_children; + n_extra_widgets = available % nexpand_children; } else { size_given_to_child = 0; } - for (i = 0; i < nvis_children; i++) + i = 0; + n_inconstant = 0; + for (child = _gtk_widget_get_first_child (widget); + child != NULL; + child = _gtk_widget_get_next_sibling (child)) { - child_size = sizes[i].minimum_size; + if (!gtk_widget_should_layout (child)) + continue; - if (gtk_widget_compute_expand (sizes[i].data, self->orientation)) + if (sizes[i].data == child) + { + child_size = sizes[i].minimum_size; + i++; + } + else + { + n_inconstant++; + g_assert (sizes[nvis_children - n_inconstant].data == child); + child_size = sizes[nvis_children - n_inconstant].minimum_size; + } + + if (gtk_widget_compute_expand (child, self->orientation)) { child_size += size_given_to_child; @@ -440,7 +517,7 @@ gtk_box_layout_compute_opposite_size_for_size (GtkBoxLayout *self, child_minimum_baseline = child_natural_baseline = -1; /* Assign the child's position. */ - gtk_widget_measure (sizes[i].data, + gtk_widget_measure (child, OPPOSITE_ORIENTATION (self->orientation), child_size, &child_minimum, &child_natural, diff --git a/testsuite/reftests/meson.build b/testsuite/reftests/meson.build index 9f40c0f3a0..83a06c9c80 100644 --- a/testsuite/reftests/meson.build +++ b/testsuite/reftests/meson.build @@ -506,6 +506,8 @@ testdata = [ 'unresolvable.css', 'unresolvable.ref.ui', 'unresolvable.ui', + 'vbox-with-2-wrapping-labels-where-one-should-wrap.ref.ui', + 'vbox-with-2-wrapping-labels-where-one-should-wrap.ui', 'vbox-with-max-width-chars-label.ref.ui', 'vbox-with-max-width-chars-label.ui', 'window-border-width.ref.ui', diff --git a/testsuite/reftests/vbox-with-2-wrapping-labels-where-one-should-wrap.ref.ui b/testsuite/reftests/vbox-with-2-wrapping-labels-where-one-should-wrap.ref.ui new file mode 100644 index 0000000000..ec575c07d9 --- /dev/null +++ b/testsuite/reftests/vbox-with-2-wrapping-labels-where-one-should-wrap.ref.ui @@ -0,0 +1,27 @@ + + + + 0 + + + + + 1 + + + Hello +World + + + + + Hi Ho + + + + + + + + + diff --git a/testsuite/reftests/vbox-with-2-wrapping-labels-where-one-should-wrap.ui b/testsuite/reftests/vbox-with-2-wrapping-labels-where-one-should-wrap.ui new file mode 100644 index 0000000000..f398308496 --- /dev/null +++ b/testsuite/reftests/vbox-with-2-wrapping-labels-where-one-should-wrap.ui @@ -0,0 +1,30 @@ + + + + 0 + + + + + 1 + + + Hello World + 1 + 1 + + + + + Hi Ho + 1 + 1 + + + + + + + + +