diff --git a/gtk/gtkboxlayout.c b/gtk/gtkboxlayout.c
index f080748830..99feca37e5 100644
--- a/gtk/gtkboxlayout.c
+++ b/gtk/gtkboxlayout.c
@@ -256,11 +256,46 @@ gtk_box_layout_compute_size (GtkBoxLayout *self,
static void
gtk_box_layout_compute_opposite_size (GtkBoxLayout *self,
GtkWidget *widget,
- int for_size,
int *minimum,
int *natural,
int *min_baseline,
int *nat_baseline)
+{
+ GtkWidget *child;
+ int largest_min = 0, largest_nat = 0;
+
+ for (child = gtk_widget_get_first_child (widget);
+ child != NULL;
+ child = gtk_widget_get_next_sibling (child))
+ {
+ int child_min = 0;
+ int child_nat = 0;
+
+ if (!gtk_widget_should_layout (child))
+ continue;
+
+ gtk_widget_measure (child,
+ OPPOSITE_ORIENTATION (self->orientation),
+ -1,
+ &child_min, &child_nat,
+ NULL, NULL);
+
+ largest_min = MAX (largest_min, child_min);
+ largest_nat = MAX (largest_nat, child_nat);
+ }
+
+ *minimum = largest_min;
+ *natural = largest_nat;
+}
+
+static void
+gtk_box_layout_compute_opposite_size_for_size (GtkBoxLayout *self,
+ GtkWidget *widget,
+ int for_size,
+ int *minimum,
+ int *natural,
+ int *min_baseline,
+ int *nat_baseline)
{
GtkWidget *child;
int nvis_children;
@@ -437,9 +472,18 @@ gtk_box_layout_measure (GtkLayoutManager *layout_manager,
if (self->orientation != orientation)
{
- gtk_box_layout_compute_opposite_size (self, widget, for_size,
- minimum, natural,
- min_baseline, nat_baseline);
+ if (for_size < 0)
+ {
+ gtk_box_layout_compute_opposite_size (self, widget,
+ minimum, natural,
+ min_baseline, nat_baseline);
+ }
+ else
+ {
+ gtk_box_layout_compute_opposite_size_for_size (self, widget, for_size,
+ minimum, natural,
+ min_baseline, nat_baseline);
+ }
}
else
{
diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c
index 661902a275..3580deae1e 100644
--- a/gtk/gtklabel.c
+++ b/gtk/gtklabel.c
@@ -1018,8 +1018,7 @@ gtk_label_get_measuring_layout (GtkLabel *self,
}
static int
-get_char_pixels (GtkWidget *self,
- PangoLayout *layout)
+get_char_pixels (PangoLayout *layout)
{
PangoContext *context;
PangoFontMetrics *metrics;
@@ -1034,6 +1033,88 @@ get_char_pixels (GtkWidget *self,
return MAX (char_width, digit_width);
}
+static void
+get_default_widths (GtkLabel *self,
+ int *minimum,
+ int *natural)
+{
+ int char_pixels;
+
+ if (self->width_chars < 0 && self->max_width_chars < 0)
+ {
+ if (minimum)
+ *minimum = -1;
+ if (natural)
+ *natural = -1;
+ return;
+ }
+
+ gtk_label_ensure_layout (self);
+ char_pixels = get_char_pixels (self->layout);
+
+ if (minimum)
+ {
+ if (self->width_chars < 0)
+ *minimum = -1;
+ else
+ *minimum = char_pixels * self->width_chars;
+ }
+
+ if (natural)
+ {
+ if (self->max_width_chars < 0)
+ *natural = -1;
+ else
+ *natural = char_pixels * MAX (self->width_chars, self->max_width_chars);
+ }
+}
+
+static void
+get_static_size (GtkLabel *self,
+ GtkOrientation orientation,
+ int *minimum,
+ int *natural,
+ int *minimum_baseline,
+ int *natural_baseline)
+{
+ PangoLayout *layout;
+
+ layout = gtk_label_get_measuring_layout (self, NULL, -1);
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ int minimum_default, natural_default;
+
+ pango_layout_get_size (layout, natural, NULL);
+ if (self->ellipsize)
+ {
+ layout = gtk_label_get_measuring_layout (self, layout, 0);
+ pango_layout_get_size (layout, minimum, NULL);
+ /* yes, Pango ellipsizes even when that needs more space */
+ *minimum = MIN (*minimum, *natural);
+ }
+ 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
+ {
+ pango_layout_get_size (layout, NULL, minimum);
+ *minimum_baseline = pango_layout_get_baseline (layout);
+
+ *natural = *minimum;
+ *natural_baseline = *minimum_baseline;
+ }
+
+ g_object_unref (layout);
+}
+
static void
get_height_for_width (GtkLabel *self,
int width,
@@ -1043,165 +1124,95 @@ get_height_for_width (GtkLabel *self,
int *natural_baseline)
{
PangoLayout *layout;
- int text_height, baseline;
+ int natural_width, text_height, baseline;
- width *= PANGO_SCALE;
- if (self->max_width_chars > -1)
+ if (width < 0)
{
- int char_pixels, width_chars;
-
+ /* Minimum height is assuming infinite width */
layout = gtk_label_get_measuring_layout (self, NULL, -1);
- char_pixels = get_char_pixels (GTK_WIDGET (self), layout);
- if (self->width_chars > self->max_width_chars)
- width_chars = self->width_chars;
- else
- width_chars = self->max_width_chars;
- width = MIN (char_pixels * width_chars, width);
+ pango_layout_get_size (layout, NULL, minimum_height);
+ baseline = pango_layout_get_baseline (layout);
+ *minimum_baseline = baseline;
+
+ /* Natural height is assuming natural width */
+ get_default_widths (self, NULL, &natural_width);
+
+ layout = gtk_label_get_measuring_layout (self, layout, natural_width);
+ pango_layout_get_size (layout, NULL, natural_height);
+ baseline = pango_layout_get_baseline (layout);
+ *natural_baseline = baseline;
}
- layout = gtk_label_get_measuring_layout (self, NULL, width);
+ else
+ {
+ /* minimum = natural for any given width */
+ layout = gtk_label_get_measuring_layout (self, NULL, width);
- pango_layout_get_pixel_size (layout, NULL, &text_height);
+ pango_layout_get_size (layout, NULL, &text_height);
- *minimum_height = text_height;
- *natural_height = text_height;
+ *minimum_height = text_height;
+ *natural_height = text_height;
- baseline = pango_layout_get_baseline (layout) / PANGO_SCALE;
- *minimum_baseline = baseline;
- *natural_baseline = baseline;
+ baseline = pango_layout_get_baseline (layout);
+ *minimum_baseline = baseline;
+ *natural_baseline = baseline;
+ }
g_object_unref (layout);
}
static void
-gtk_label_get_preferred_layout_size (GtkLabel *self,
- PangoRectangle *smallest,
- PangoRectangle *widest,
- int *smallest_baseline,
- int *widest_baseline)
+get_width_for_height (GtkLabel *self,
+ int height,
+ int *minimum_width,
+ int *natural_width)
{
PangoLayout *layout;
- int char_pixels;
+ int minimum_default, natural_default;
- /* "width-chars" Hard-coded minimum width:
- * - minimum size should be MAX (width-chars, strlen ("..."));
- * - natural size should be MAX (width-chars, strlen (self->text));
- *
- * "max-width-chars" User specified maximum size requisition
- * - minimum size should be MAX (width-chars, 0)
- * - natural size should be MIN (max-width-chars, strlen (self->text))
- *
- * For ellipsizing labels; if max-width-chars is specified: either it is used as
- * a minimum size or the label text as a minimum size (natural size still overflows).
- *
- * For wrapping labels; A reasonable minimum size is useful to naturally layout
- * interfaces automatically. In this case if no "width-chars" is specified, the minimum
- * width will default to the wrap guess that gtk_label_ensure_layout() does.
- */
+ get_default_widths (self, &minimum_default, &natural_default);
- /* Start off with the pixel extents of an as-wide-as-possible layout */
- layout = gtk_label_get_measuring_layout (self, NULL, -1);
-
- if (self->width_chars > -1 || self->max_width_chars > -1)
- char_pixels = get_char_pixels (GTK_WIDGET (self), layout);
- else
- char_pixels = 0;
-
- pango_layout_get_extents (layout, NULL, widest);
- widest->width = MAX (widest->width, char_pixels * self->width_chars);
- widest->x = widest->y = 0;
- *widest_baseline = pango_layout_get_baseline (layout) / PANGO_SCALE;
-
- if (self->ellipsize || self->wrap)
+ if (height < 0)
{
- /* a layout with width 0 will be as small as humanly possible */
- layout = gtk_label_get_measuring_layout (self,
- layout,
- self->width_chars > -1 ? char_pixels * self->width_chars
- : 0);
+ /* Minimum width is as many line breaks as possible */
+ layout = gtk_label_get_measuring_layout (self, NULL, MAX (minimum_default, 0));
+ pango_layout_get_size (layout, minimum_width, NULL);
- pango_layout_get_extents (layout, NULL, smallest);
- smallest->width = MAX (smallest->width, char_pixels * self->width_chars);
- smallest->x = smallest->y = 0;
-
- *smallest_baseline = pango_layout_get_baseline (layout) / PANGO_SCALE;
-
- if (self->max_width_chars > -1 && widest->width > char_pixels * self->max_width_chars)
- {
- layout = gtk_label_get_measuring_layout (self,
- layout,
- MAX (smallest->width, char_pixels * self->max_width_chars));
- pango_layout_get_extents (layout, NULL, widest);
- widest->width = MAX (widest->width, char_pixels * self->width_chars);
- widest->x = widest->y = 0;
-
- *widest_baseline = pango_layout_get_baseline (layout) / PANGO_SCALE;
- }
-
- if (widest->width < smallest->width)
- {
- *smallest = *widest;
- *smallest_baseline = *widest_baseline;
- }
+ /* 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
{
- *smallest = *widest;
- *smallest_baseline = *widest_baseline;
+ int min, max, mid, text_width, text_height;
+
+ /* binary search for the smallest width where the height doesn't
+ * eclipse the given height */
+ min = MAX (minimum_default, 0);
+ layout = gtk_label_get_measuring_layout (self, NULL, -1);
+ pango_layout_get_size (layout, &max, NULL);
+
+ while (min < max)
+ {
+ mid = (min + max) / 2;
+ layout = gtk_label_get_measuring_layout (self, layout, mid);
+ pango_layout_get_size (layout, &text_width, &text_height);
+ if (text_width > mid)
+ min = mid = text_width;
+ if (text_height > height)
+ min = mid + 1;
+ else
+ max = text_width;
+ }
+
+ *minimum_width = min;
+ *natural_width = min;
}
g_object_unref (layout);
}
-static void
-gtk_label_get_preferred_size (GtkWidget *widget,
- GtkOrientation orientation,
- int *minimum_size,
- int *natural_size,
- int *minimum_baseline,
- int *natural_baseline)
-{
- GtkLabel *self = GTK_LABEL (widget);
- PangoRectangle widest_rect;
- PangoRectangle smallest_rect;
- int smallest_baseline;
- int widest_baseline;
-
- gtk_label_get_preferred_layout_size (self,
- &smallest_rect, &widest_rect,
- &smallest_baseline, &widest_baseline);
-
- widest_rect.width = PANGO_PIXELS_CEIL (widest_rect.width);
- widest_rect.height = PANGO_PIXELS_CEIL (widest_rect.height);
-
- smallest_rect.width = PANGO_PIXELS_CEIL (smallest_rect.width);
- smallest_rect.height = PANGO_PIXELS_CEIL (smallest_rect.height);
-
- if (orientation == GTK_ORIENTATION_HORIZONTAL)
- {
- /* Normal desired width */
- *minimum_size = smallest_rect.width;
- *natural_size = widest_rect.width;
- }
- else /* GTK_ORIENTATION_VERTICAL */
- {
- if (smallest_rect.height < widest_rect.height)
- {
- *minimum_size = smallest_rect.height;
- *natural_size = widest_rect.height;
- *minimum_baseline = smallest_baseline;
- *natural_baseline = widest_baseline;
- }
- else
- {
- *minimum_size = widest_rect.height;
- *natural_size = smallest_rect.height;
- *minimum_baseline = widest_baseline;
- *natural_baseline = smallest_baseline;
- }
- }
-}
-
-
static void
gtk_label_measure (GtkWidget *widget,
GtkOrientation orientation,
@@ -1213,14 +1224,22 @@ gtk_label_measure (GtkWidget *widget,
{
GtkLabel *self = GTK_LABEL (widget);
- if (orientation == GTK_ORIENTATION_VERTICAL && for_size != -1 && self->wrap)
- {
- gtk_label_clear_layout (self);
+ if (for_size > 0)
+ for_size *= PANGO_SCALE;
- get_height_for_width (self, for_size, minimum, natural, minimum_baseline, natural_baseline);
- }
+ if (!self->wrap)
+ get_static_size (self, orientation, minimum, natural, minimum_baseline, natural_baseline);
+ else if (orientation == GTK_ORIENTATION_VERTICAL)
+ get_height_for_width (self, for_size, minimum, natural, minimum_baseline, natural_baseline);
else
- gtk_label_get_preferred_size (widget, orientation, minimum, natural, minimum_baseline, natural_baseline);
+ get_width_for_height (self, for_size, minimum, natural);
+
+ *minimum = PANGO_PIXELS_CEIL (*minimum);
+ *natural = PANGO_PIXELS_CEIL (*natural);
+ if (*minimum_baseline > 0)
+ *minimum_baseline = PANGO_PIXELS_CEIL (*minimum_baseline);
+ if (*natural_baseline > 0)
+ *natural_baseline = PANGO_PIXELS_CEIL (*natural_baseline);
}
static void
diff --git a/gtk/gtkpicture.c b/gtk/gtkpicture.c
index 7694888c68..6821ecacfb 100644
--- a/gtk/gtkpicture.c
+++ b/gtk/gtkpicture.c
@@ -884,6 +884,9 @@ gtk_picture_set_can_shrink (GtkPicture *self,
return;
self->can_shrink = can_shrink;
+
+ gtk_widget_queue_resize (GTK_WIDGET (self));
+
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CAN_SHRINK]);
}
diff --git a/testsuite/reftests/label-max-width-chars-and-halign-and-infinite-width.ref.ui b/testsuite/reftests/label-max-width-chars-and-halign-and-infinite-width.ref.ui
index 68c5d0a112..d3f075290b 100644
--- a/testsuite/reftests/label-max-width-chars-and-halign-and-infinite-width.ref.ui
+++ b/testsuite/reftests/label-max-width-chars-and-halign-and-infinite-width.ref.ui
@@ -8,9 +8,7 @@
start
end
0
- ABCDE
-ABCD
- 4
+ ABCDE ABCD
diff --git a/testsuite/reftests/label-sizing.ref.ui b/testsuite/reftests/label-sizing.ref.ui
index 1616ef4f2f..4235424e80 100644
--- a/testsuite/reftests/label-sizing.ref.ui
+++ b/testsuite/reftests/label-sizing.ref.ui
@@ -212,8 +212,7 @@
end
end
0
- ABCDE
-ABCD
+ ABCDE ABCD
@@ -224,8 +223,7 @@ ABCD
end
start
0
- ABCDE
-ABCD
+ ABCDE ABCD
@@ -646,8 +644,7 @@ ABCD
end
end
0
- ABCDE
-ABCD
+ ABCDE ABCD
4
@@ -659,8 +656,7 @@ ABCD
end
start
0
- ABCDE
-ABCD
+ ABCDE ABCD
4
@@ -1092,8 +1088,7 @@ ABCD
end
end
0
- ABCDE
-ABCD
+ ABCDE ABCD
8
@@ -1105,8 +1100,7 @@ ABCD
end
start
0
- ABCDE
-ABCD
+ ABCDE ABCD
8
@@ -1982,8 +1976,7 @@ ABCD
end
end
0
- ABCDE
-ABCD
+ ABCDE ABCD
4
@@ -1995,8 +1988,7 @@ ABCD
end
start
0
- ABCDE
-ABCD
+ ABCDE ABCD
4
@@ -2016,8 +2008,7 @@ ABCD
start
end
0
- ABCDE
-ABCD
+ ABCDE ABCD
4
@@ -2029,8 +2020,7 @@ ABCD
start
start
0
- ABCDE
-ABCD
+ ABCDE ABCD
4
@@ -2434,8 +2424,7 @@ ABCD
end
end
0
- ABCDE
-ABCD
+ ABCDE ABCD
4
4
@@ -2448,8 +2437,7 @@ ABCD
end
start
0
- ABCDE
-ABCD
+ ABCDE ABCD
4
4
@@ -2470,8 +2458,7 @@ ABCD
start
end
0
- ABCDE
-ABCD
+ ABCDE ABCD
4
4
@@ -2484,8 +2471,7 @@ ABCD
start
start
0
- ABCDE
-ABCD
+ ABCDE ABCD
4
4
@@ -2898,8 +2884,7 @@ ABCD
end
end
0
- ABCDE
-ABCD
+ ABCDE ABCD
8
4
@@ -2912,8 +2897,7 @@ ABCD
end
start
0
- ABCDE
-ABCD
+ ABCDE ABCD
8
4
@@ -2934,8 +2918,7 @@ ABCD
start
end
0
- ABCDE
-ABCD
+ ABCDE ABCD
8
4
@@ -2948,8 +2931,7 @@ ABCD
start
start
0
- ABCDE
-ABCD
+ ABCDE ABCD
8
4
@@ -3818,8 +3800,7 @@ ABCD
end
end
0
- ABCDE
-ABCD
+ ABCDE ABCD
8
@@ -3831,8 +3812,7 @@ ABCD
end
start
0
- ABCDE
-ABCD
+ ABCDE ABCD
8
@@ -3852,8 +3832,7 @@ ABCD
start
end
0
- ABCDE
-ABCD
+ ABCDE ABCD
8
@@ -3865,8 +3844,7 @@ ABCD
start
start
0
- ABCDE
-ABCD
+ ABCDE ABCD
8
@@ -4270,8 +4248,7 @@ ABCD
end
end
0
- ABCDE
-ABCD
+ ABCDE ABCD
4
8
@@ -4284,8 +4261,7 @@ ABCD
end
start
0
- ABCDE
-ABCD
+ ABCDE ABCD
4
8
@@ -4306,8 +4282,7 @@ ABCD
start
end
0
- ABCDE
-ABCD
+ ABCDE ABCD
4
8
@@ -4320,8 +4295,7 @@ ABCD
start
start
0
- ABCDE
-ABCD
+ ABCDE ABCD
4
8
@@ -4734,8 +4708,7 @@ ABCD
end
end
0
- ABCDE
-ABCD
+ ABCDE ABCD
8
8
@@ -4748,8 +4721,7 @@ ABCD
end
start
0
- ABCDE
-ABCD
+ ABCDE ABCD
8
8
@@ -4770,8 +4742,7 @@ ABCD
start
end
0
- ABCDE
-ABCD
+ ABCDE ABCD
8
8
@@ -4784,8 +4755,7 @@ ABCD
start
start
0
- ABCDE
-ABCD
+ ABCDE ABCD
8
8
@@ -5654,8 +5624,7 @@ ABCD
end
end
0
- ABCDE
-ABCD
+ ABCDE ABCD
12
@@ -5667,8 +5636,7 @@ ABCD
end
start
0
- ABCDE
-ABCD
+ ABCDE ABCD
12
@@ -6104,8 +6072,7 @@ ABCD
end
end
0
- ABCDE
-ABCD
+ ABCDE ABCD
4
12
@@ -6118,8 +6085,7 @@ ABCD
end
start
0
- ABCDE
-ABCD
+ ABCDE ABCD
4
12
@@ -6566,8 +6532,7 @@ ABCD
end
end
0
- ABCDE
-ABCD
+ ABCDE ABCD
8
12
@@ -6580,8 +6545,7 @@ ABCD
end
start
0
- ABCDE
-ABCD
+ ABCDE ABCD
8
12
diff --git a/testsuite/reftests/meson.build b/testsuite/reftests/meson.build
index b033760ed7..692a427438 100644
--- a/testsuite/reftests/meson.build
+++ b/testsuite/reftests/meson.build
@@ -498,6 +498,8 @@ testdata = [
'unresolvable.css',
'unresolvable.ref.ui',
'unresolvable.ui',
+ 'vbox-with-max-width-chars-label.ref.ui',
+ 'vbox-with-max-width-chars-label.ui',
'window-border-width.ref.ui',
'window-border-width.ui',
'window-default-size.ref.ui',
diff --git a/testsuite/reftests/vbox-with-max-width-chars-label.ref.ui b/testsuite/reftests/vbox-with-max-width-chars-label.ref.ui
new file mode 100644
index 0000000000..aa732c608d
--- /dev/null
+++ b/testsuite/reftests/vbox-with-max-width-chars-label.ref.ui
@@ -0,0 +1,18 @@
+
+
+
+
diff --git a/testsuite/reftests/vbox-with-max-width-chars-label.ui b/testsuite/reftests/vbox-with-max-width-chars-label.ui
new file mode 100644
index 0000000000..3a7d52e4a4
--- /dev/null
+++ b/testsuite/reftests/vbox-with-max-width-chars-label.ui
@@ -0,0 +1,18 @@
+
+
+
+ 0
+
+
+ vertical
+
+
+ Hello World
+ 1
+ 1
+
+
+
+
+
+