After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 628902 - use expand flags to determine window resizability
use expand flags to determine window resizability
Status: RESOLVED OBSOLETE
Product: gtk+
Classification: Platform
Component: Widget: Other
unspecified
Other All
: Normal enhancement
: ---
Assigned To: gtk-bugs
gtk-bugs
Depends on: 628884
Blocks:
 
 
Reported: 2010-09-06 16:46 UTC by Havoc Pennington
Modified: 2018-04-15 00:12 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Add horizontal and vertical expand flags, compute_expand() to GtkWidget (14.64 KB, patch)
2010-09-06 16:46 UTC, Havoc Pennington
reviewed Details | Review
Support GtkWidget expand properties in GtkBox (4.44 KB, patch)
2010-09-06 16:46 UTC, Havoc Pennington
none Details | Review
add tests/testexpand.c used to test the expand props on GtkWidget (6.47 KB, patch)
2010-09-06 16:46 UTC, Havoc Pennington
none Details | Review
Add horizontal and vertical expand flags, compute_expand() to GtkWidget (27.96 KB, patch)
2010-09-07 03:06 UTC, Havoc Pennington
none Details | Review
Support GtkWidget expand properties in GtkBox (5.20 KB, patch)
2010-09-07 03:06 UTC, Havoc Pennington
none Details | Review
add tests/testexpand.c used to test the expand props on GtkWidget (6.52 KB, patch)
2010-09-07 03:06 UTC, Havoc Pennington
none Details | Review
Add horizontal and vertical expand flags, compute_expand() to GtkWidget (27.99 KB, patch)
2010-09-13 02:19 UTC, Havoc Pennington
committed Details | Review
Support GtkWidget expand properties in GtkBox (5.20 KB, patch)
2010-09-13 02:19 UTC, Havoc Pennington
committed Details | Review
add tests/testexpand.c used to test the expand props on GtkWidget (6.52 KB, patch)
2010-09-13 02:19 UTC, Havoc Pennington
committed Details | Review
gtkwindow wip patch (3.76 KB, patch)
2010-10-12 02:40 UTC, Matthias Clasen
none Details | Review
another iteration of the window patch (6.50 KB, patch)
2010-10-13 14:54 UTC, Matthias Clasen
needs-work Details | Review

Description Havoc Pennington 2010-09-06 16:46:42 UTC
This is inspired by a mention of Rapicorn's "spread" flag on
http://live.gnome.org/GTK%2B/3.0/Roadmap

The idea is that GtkWidget has h and v expand flags.
If a child is expand=true, then the parent is automatically
also expand=true. So expansion is only set in one place
instead of having to be kept in sync all the way up 
the widget tree.

This would make redundant the expand flags on layout
containers such as Box, Table, WrapBox.

The patches are not really complete. Missing parts:
* GtkWindow smart behavior (see below)
* Adapting all other containers with expand flags,
  in the same way as the GtkBox patch
* add GObject properties for the expand flags to
  GtkWidget
* documentation updates/additions

GtkWindow behavior: set_resizable should become automatic,
with set_resizable() overriding the automatic behavior if set.
* there would be a resizable_set flag for whether set_resizable
  has forced behavior
* automatic behavior is:
  - min size in each h/v dimension is always the min size request
  - default size is always the natural size in the dimension
    unless set with set_default_size or constrained by screen size
  - if expandable in a dimension, max size is infinite
  - if not expandable in a dimension, max size is natural size
  - if min size == natural size, and not expandable,
    window is not resizable (since max size is natural size,
    min size is min size, and therefore min size == max size)
* if resizable_set (set_resizable() has been called) then we 
  would behave as GtkWindow does now

This GtkWindow behavior should mean that windows are automatically
resizable when it makes sense, and automatically not resizable if
there's nothing to expand. Moreover if you toggle expansion or whether
a label can ellipsize or whatever, the window would automatically
update whether it's resizable.
Comment 1 Havoc Pennington 2010-09-06 16:46:44 UTC
Created attachment 169585 [details] [review]
Add horizontal and vertical expand flags, compute_expand() to GtkWidget

GtkWidget now has flags for horizontal and vertical expand, and
a compute_expand() method. compute_expand() is used by containers
to set a default expand flag. (If a widget has expand set explicitly,
it always overrides the results of compute_expand.)

GtkContainer has a default implementation of compute_expand which
simply walks over all child widgets and sets expand=TRUE
if any child is expanding.

The overall effect is that you only have to set expand on
leaf nodes in the widget tree, while previously you had to
set expand all the way up the tree as you packed every
container. Also, now containers need not have their own child
properties for expand.

For old containers which do have "expand" child properties,
they should override compute_expand and include the child
properties in whether the container is expand=TRUE.
Also, the old container should use
"child_prop_expand || gtk_widget_get_expand()" everywhere
it previously used simply "child_prop_expand"
Comment 2 Havoc Pennington 2010-09-06 16:46:48 UTC
Created attachment 169586 [details] [review]
Support GtkWidget expand properties in GtkBox

This consists of:
* expand a child if either child->expand || gtk_widget_get_expand(child)
* override compute_expand so that child->expand will cause us to
  return TRUE for gtk_widget_get_expand()
Comment 3 Havoc Pennington 2010-09-06 16:46:52 UTC
Created attachment 169587 [details] [review]
add tests/testexpand.c used to test the expand props on GtkWidget

There are two colored boxes with toggle buttons nested
inside several GtkBox. Toggling these to expand mode
should automatically propagate expansion up through
the several GtkBox such that resizing the window
results in resizing the colored boxes.
Comment 4 Matthias Clasen 2010-09-06 21:48:39 UTC
Review of attachment 169585 [details] [review]:

::: gtk/gtkwidget.c
@@ +3113,3 @@
   gtk_widget_set_parent_window (widget, NULL);
+
+  gtk_widget_queue_compute_expand (old_parent); /* parent may no longer expand */

I guess this could be conditional on the child being expand and visible ?

@@ +3304,3 @@
 
+      /* a parent may now be expand=FALSE since we're hidden. */
+      gtk_widget_queue_compute_expand (widget);

Could be conditional on the child being expand, I guess ?

@@ +10430,3 @@
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+  /* We never make a window expand if not even showing. */

s/window/widget/ in the comment ?

@@ +10436,3 @@
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    {
+      gtk_widget_compute_expand (widget);

Could pull the compute_expand before the if here.

::: gtk/gtkwidget.h
@@ +795,3 @@
+void     gtk_widget_set_expand_set       (GtkWidget      *widget,
+                                          GtkOrientation  orientation,
+                                          gboolean        set);

This is a little out-of-style for gtk. I'd expect separate
h-expand / v-expand properties with separate setters and getters, instead passing the orientation in like this.
Comment 5 Havoc Pennington 2010-09-06 22:12:37 UTC
I was going back and forth on the orientation arg. 

For get_expand, it's generally going to be used like in the gtkbox.c patch, you can kind of see the mess you'd get, rather than:

 child->expand || gtk_widget_get_expand(child->widget, box->orientation)

you probably have to make a temporary variable so you can write something clunky like
 expand = orientation == GTK_ORIENTATION_HORIZONTAL ? get_h_expand() : get_v_expand() 

probably in gtkbox.c, you'd end up just making a little wrapper that took the orientation arg.

On the other hand, for the setter, it'd usually be used by an app, and there I agree you want two setters. Also, the object props (not added yet) have to be separate h-expand and v-expand. so two setters would be consistent.

split up will also be consistent with the padding patch so that's probably good.


I guess I agree it needs to be split up, but it's tempting to have the get_expand() with orientation also, just for containers to use ...
Comment 6 Matthias Clasen 2010-09-06 22:21:22 UTC
Thats true, hmm. We could have both separate getters to go with the separate properties, and the orientation-taking one for the benefit of flippable containers.
Comment 7 Matthias Clasen 2010-09-06 23:14:54 UTC
Patches depend on bug 628884, it seems.
Comment 8 Matthias Clasen 2010-09-06 23:23:10 UTC
Review of attachment 169585 [details] [review]:

::: gtk/gtkwidget.h
@@ +284,3 @@
+  guint GSEAL (h_expand_set) : 1;        /* whether to use application-forced  */
+  guint GSEAL (v_expand_set) : 1;        /* instead of computing from children */
+

Quite a few bits used for expand. I guess you could try to get away without separate bits for h_expand and computed_h_expand.
Comment 9 Havoc Pennington 2010-09-07 02:53:19 UTC
Hmm. doesn't look like we can lose the separate h_expand and computed_h_expand because if you toggled off h_expand_set then the h_expand flag would mysteriously change.

What we could do potentially is move h_expand, v_expand, h_expand_set, v_expand_set to AuxInfo; or only h_expand and v_expand to AuxInfo if we want to look up the AuxInfo less. Since only a few widgets in a window would typically have expand set on them, in theory.

Seems a bit clunky to do until we actually run out of bits, though.
We don't have to prematurely optimize if GtkWidget struct is private, in theory.
Comment 10 Havoc Pennington 2010-09-07 03:06:42 UTC
Created attachment 169640 [details] [review]
Add horizontal and vertical expand flags, compute_expand() to GtkWidget

GtkWidget now has flags for horizontal and vertical expand, and
a compute_expand() method. compute_expand() is used by containers
to set a default expand flag. (If a widget has expand set explicitly,
it always overrides the results of compute_expand.)

GtkContainer has a default implementation of compute_expand which
simply walks over all child widgets and sets expand=TRUE
if any child is expanding.

The overall effect is that you only have to set expand on
leaf nodes in the widget tree, while previously you had to
set expand all the way up the tree as you packed every
container. Also, now containers need not have their own child
properties for expand.

For old containers which do have "expand" child properties,
they should override compute_expand and include the child
properties in whether the container is expand=TRUE.
Also, the old container should use
"child_prop_expand || gtk_widget_get_expand()" everywhere
it previously used simply "child_prop_expand"
Comment 11 Havoc Pennington 2010-09-07 03:06:49 UTC
Created attachment 169641 [details] [review]
Support GtkWidget expand properties in GtkBox

This consists of:
* expand a child if either child->expand || gtk_widget_get_expand(child)
* override compute_expand so that child->expand will cause us to
  return TRUE for gtk_widget_get_expand()
Comment 12 Havoc Pennington 2010-09-07 03:06:56 UTC
Created attachment 169642 [details] [review]
add tests/testexpand.c used to test the expand props on GtkWidget

There are two colored boxes with toggle buttons nested
inside several GtkBox. Toggling these to expand mode
should automatically propagate expansion up through
the several GtkBox such that resizing the window
results in resizing the colored boxes.
Comment 13 Havoc Pennington 2010-09-07 03:09:51 UTC
I decided it might make sense if 
gtk_widget_get_h_expand() returned simply widget->h_expand to match the 
property exactly
and then
gtk_widget_compute_expand(widget, orientation)
returns the computed value to be used by layout containers.

I also added the object properties and some docs.

The object props include an "expand" prop which sets h and v at the same time.
Comment 14 Matthias Clasen 2010-09-07 03:58:13 UTC
Review of attachment 169640 [details] [review]:

::: gtk/gtkwidget.c
@@ +10569,3 @@
+ * The computed expand value uses either the expand setting explicitly
+ * set on the widget itself, or, if none has been explicitly set,
+ * the widget will expand if any of its children wants to expand.

This should probably be a little more vague, like:

"...or, if none has been explicitly set, the widget may expand if some of its children do."

@@ +10689,3 @@
+ * this function, to see whether a widget, or any of its children,
+ * has the expand flag set. If any child of a widget needs to
+ * expand, the parent needs to expand also.

Again, could be a little less assertive here.

@@ +10722,3 @@
+ * By default, widgets automatically expand if any of their children
+ * want to expand. (To see if a widget will automatically expand
+ * given its current children and state, call gtk_widget_compute_expand()).

Could add something like: "A container implementation can decide how the expandability of the children affects the expandability of the container, by overriding the ... method.
Comment 15 Matthias Clasen 2010-09-07 04:00:52 UTC
Review of attachment 169641 [details] [review]:

::: gtk/gtkbox.c
@@ +682,3 @@
+
+      if (our_expand && opposite_expand)
+        break;

As I said on the list, shouldn't this require that _all_ children are expandable before making the container expandable in the opposite direction ?

Eg an hbox should only be vertically expandable, if every child is...
Comment 16 Benjamin Otte (Company) 2010-09-08 18:31:14 UTC
Looking at http://git.gnome.org/browse/gtk+/commit/?h=widget-expand&id=6f3c6caadaf9b8c015572c69857b1e241cdc5d26 - in hide/show, it should probably call queue_compute_expand() on the parent.
Comment 17 Havoc Pennington 2010-09-13 02:19:24 UTC
Created attachment 170108 [details] [review]
Add horizontal and vertical expand flags, compute_expand() to GtkWidget

GtkWidget now has flags for horizontal and vertical expand, and
a compute_expand() method. compute_expand() is used by containers
to set a default expand flag. (If a widget has expand set explicitly,
it always overrides the results of compute_expand.)

GtkContainer has a default implementation of compute_expand which
simply walks over all child widgets and sets expand=TRUE
if any child is expanding.

The overall effect is that you only have to set expand on
leaf nodes in the widget tree, while previously you had to
set expand all the way up the tree as you packed every
container. Also, now containers need not have their own child
properties for expand.

For old containers which do have "expand" child properties,
they should override compute_expand and include the child
properties in whether the container is expand=TRUE.
Also, the old container should use
"child_prop_expand || gtk_widget_compute_expand()" everywhere
it previously used simply "child_prop_expand"
Comment 18 Havoc Pennington 2010-09-13 02:19:32 UTC
Created attachment 170109 [details] [review]
Support GtkWidget expand properties in GtkBox

This consists of:
* expand a child if either child->expand || gtk_widget_get_expand(child)
* override compute_expand so that child->expand will cause us to
  return TRUE for gtk_widget_get_expand()
Comment 19 Havoc Pennington 2010-09-13 02:19:44 UTC
Created attachment 170110 [details] [review]
add tests/testexpand.c used to test the expand props on GtkWidget

There are two colored boxes with toggle buttons nested
inside several GtkBox. Toggling these to expand mode
should automatically propagate expansion up through
the several GtkBox such that resizing the window
results in resizing the colored boxes.
Comment 20 Matthias Clasen 2010-09-25 15:08:53 UTC
I'm still interested in this. I think we should get it landed...
Comment 21 Havoc Pennington 2010-09-25 16:03:37 UTC
I pushed widget-expand-3 with a rebase, rename h_expand to hexpand to match the margins patch, and docs tweaks as suggested. I deleted widget-expand and widget-expand-2 old branches.

I don't think box should require all children to be expand in the opposing orientation before expanding.

If you had a scrolled window that could usefully grow and drop scrollbars in both directions, inside a box, that behavior should not vanish just because you pack something next to it. The thing next to it can just get extra space and align or whatever. Boxes already force all children to expand in the opposing direction up to the size of the largest child in that direction, before these patches. i.e. in the opposing direction everything is basically packed fill=true expand=true already.

The remaining work items (which may or may not block landing what we have):

* magic resizability behavior on GtkWindow
* do the equivalent of the GtkBox patch to GtkTable (I think that's the only other container?)

I don't think I can do these this weekend but I can hopefully do them soon. GtkTable is trivial and mechanical, GtkWindow may be a little tricky.
Comment 22 Benjamin Otte (Company) 2010-09-25 16:12:06 UTC
Expander, Toolbar, Notebook and Paned are other widgets where I'm not sure how child expanding flags should be honored. GtkBin is pretty obvious after I guess.
Comment 23 Matthias Clasen 2010-09-25 18:41:14 UTC
Containers where we currently have some expand-like child properties include:

GtkBox (done)
GtkTable (easy)
GtkWrapBox (propagate)
GtkToolbar (probably no propagation)
GtkNotebook (propagate for content, but not for tabs)
GtkPaned (propagate ?)
GtkToolItemGroup (don't propagate ?)
GtkToolPalette (expand here is really 'expanded', should probably be renamed)

there are some containers that don't have expand-like child properties, but should
probably still pass expand on:

GtkExpander (only propagate if expanded ?)
GtkFrame (propagate)
GtkScrolledWindow (propagate)
Comment 24 Havoc Pennington 2010-09-25 20:34:53 UTC
The ones that propagate always should have no patch, since gtkcontainer already does that by default.

I wonder if it's worth an override in toolbar, notebook tabs, and tool item group. While yes it doesn't make sense to set expand on these things, at the same time, it's not like expand is set by default. So putting in the override would just be "if you set expand like a dork, we ignore you" ; maybe it's better to avoid the extra code and say "don't do that then" - and if someone comes up with some reason to expand, fine? Though if someone does want to expand a toolbar, even if we override to ignore it by default, they could do it by setting expand on both contents and toolbar itself.

Anyway it seems like avoiding special cases could make the whole expand thing easier to understand; if I'm messing around in a UI builder maybe toolbar should just work like anything else to illustrate the expand concept, instead of me having to know that some containers special-case ignore me if I ask to do something silly.

GtkExpander only propagate if expanded sounds right (since the contents are effectively hidden if not expanded). There is a possible weird side effect though, which is forcing the toplevel to resize when you collapse the expander. Say your scrolled window in an expander is the only expanding thing in the window. When you open expander, you can resize the window up. But when you close the expander, the window will become not resizable and snap to the min size. I don't know, arguably that's the correct behavior anyway, and it can be fixed by manually forcing resizability on the toplevel.

An alternate behavior I haven't seen on other platforms would be for GtkExpander to always propagate expand and if you resize and the expander gets extra space of at least child_min_size, it auto-opens. Between 0 and child_min_size of allocation maybe the arrow starts to rotate as a function of the allocation. Too fancy?

Rather than patching GtkExpander specifically, maybe having gtk_widget_set_child_visible() do the right thing would be appropriate. However, this would make GtkNotebook do the wrong thing I think, since notebook size request and expansion seems to always be a function of all pages even hidden ones.
Comment 25 Havoc Pennington 2010-09-25 20:37:11 UTC
The auto-open-expander-on-extra-space idea is not good among other reasons because generally expanders are to hide "advanced" or clutter type of stuff, and so people probably don't want them open just because there's space or someone happened to maximize the window.
Comment 26 Benjamin Otte (Company) 2010-09-25 23:11:49 UTC
(In reply to comment #23)
> GtkToolbar (probably no propagation)
> GtkNotebook (propagate for content, but not for tabs)
I think I agree with Havoc here that we should propagate.

> GtkPaned (propagate ?)
At least. We might also want to expand into the orientation's direction by default. It's weird if you can resize both widgets inside the paned but not the paned itself.
Also, the default position of the paned could maybe be influenced by the expand flags of its children?

> GtkExpander (only propagate if expanded ?)
I agree with Havoc that it should always propagate. It's weird if the resizability of windows depends on the expand state of an expander. (Fwiw, the "expander" and the "expand" flags have nothing to do with each other, can we find a better naming for the flags?)

> GtkScrolledWindow (propagate)
Hrm, don't you always want a scrolled window to expand if it has a scrollbar in that direction? I can't imagine a case where you'd say "keep my scrolled window small so the user has to scroll".
You could argue you'd have the contents of the scrolled window on expand, but I can at least find examples for where that's not the case: property editors in the GTK tests for exmaple, like when clicking columns in tests/testtreeview.
Comment 27 Alexander Larsson 2010-10-10 22:07:42 UTC
How exactly do:
gtk_widget_set_h_expand_set(widget, TRUE);
and
gtk_widget_set_halign(widget, GTK_ALIGN_FILL)

differ?

I get how the expand propagation is nice, but it seems to me that ALIGN_FILL already covers the leaf widget "should expand" case.
Comment 28 Havoc Pennington 2010-10-10 23:04:45 UTC
Interesting question, short answer I believe is that expand=true|false is whether the widget wants (requests?) extra space while alignment is what widget does if it gets extra space.

In most cases, widgets don't get extra space if they don't want it, however, the cases where they do get unrequested extra space are the cases where align=FILL differs in intent from expand=true.

Say you have some buttons in a vbox. They would all be the same width, and may or may not have expand=true. However, all but one of them will have extra horizontal size. You could legitimately want any of the alignments within the extra horizontal space - make all buttons match (FILL) or left-align them or whatever. I don't think you necessarily want the whole vbox to be hexpand=true, though; i.e. you probably want to be able to make the max width of the button box just match the largest button.

Same basic thing arises with a SizeGroup or table column or whatever.


If we collapsed expand and fill I guess it might look like:
 PackMode = { EXPAND, CENTER, START, END }

Issues might include

1. right now the align default is FILL for (in my opinion) back compat reasons; I don't much like the default but changing it would make all existing expand=TRUE layouts break. (expand=TRUE here means expand flag on Box, Table, etc.)  Assuming propagation, defaulting to PackMode.EXPAND would be bad... most windows only have a couple things that should expand, so this default would be backward big time. But defaulting to say CENTER is huge, epic, very visible API breakage. (Because it breaks the existing expand/fill child properties by vetoing them on the child widget level.)

2. if a widget doesn't expand, it can't get extra allocation to align within, in general. (the exception is if the widget's size is tied to that of another widget which does expand.) So for the most part, CENTER, START, END would never do anything. You would have to use a GtkAlignment again I think...

I think maybe what it ends up looking like is to drop alignment, only have expand=true|false, and go back to using a GtkAlignment when alignment is desired.

Hmm. To avoid that, I guess the PackMode could have yet another setting:

 PackMode = { FILL, CENTER, START, END, NO_EXPAND } 

Where FILL, CENTER, START, END all imply expand=true and NO_EXPAND means don't give us extra space - so it doesn't matter how we position the widget's allocation inside extra space. However, this breaks because of "unrequested" extra space... to handle "unrequested" space you need to add FILL_NO_EXPAND, CENTER_NO_EXPAND, START_NO_EXPAND, END_NO_EXPAND and of course that's just a separate expand flag again.
Comment 29 Matthias Clasen 2010-10-11 12:59:42 UTC
I think having expand separate is much clearer, tbh.
Comment 30 Matthias Clasen 2010-10-12 02:40:25 UTC
Created attachment 172151 [details] [review]
gtkwindow wip patch

Here is a patch that almost kinda works. I can grow a window until the scrollbar of the scrolled content disappears, and then the expandability of the scrolledwindow is flipped, and the window picks it up. Unfortunately, it then resets the window max size to the requisition, which causes the window to jump back in size,  flicker wildly, or start wandering, depending on which side you drag. I haven't found a way to make the max size the current size without causing infinite loops.
Comment 31 Havoc Pennington 2010-10-12 03:11:37 UTC
I think the problem may be that scrolled window expand should depend on scrollbar *policy* not scrollbar *visibility*

expand flag should not be changing during a user resize operation
Comment 32 Matthias Clasen 2010-10-12 16:52:17 UTC
(In reply to comment #31)
> I think the problem may be that scrolled window expand should depend on
> scrollbar *policy* not scrollbar *visibility*
> 
> expand flag should not be changing during a user resize operation

Hmm, maybe. But then we won't get the magic 'window stops resizing if fully expanded'. Maybe that is not so important.

But I do think it is a problem that the window jumps to a smaller size if it is not longer resizable. The same thing happens when you set resizable to FALSE.  The window gets shrunken to its requisition.
Comment 33 Havoc Pennington 2010-10-12 17:00:42 UTC
I think it's right that a nonresizable window gets shrunk to a fixed size. If you have a nonresizable window then basically it always resizes to just match its contents. It shouldn't be a problem in real life since you wouldn't become nonresizable during a user resize operation or anything.

However this definitely interacts with that long thread on gtk-devel-list right now... the min size may not be an especially 'good' size. Maybe nonresizable windows should snap to something closer to the default size instead of just the min size request.

To get "magic stop resizing when fully expanded" I think we'd have to add max size to min and natural, in the get_preferred_{width,height} calls. "max size" means "ignore expand flag above this size"
Comment 34 Matthias Clasen 2010-10-12 22:44:53 UTC
> I think the problem may be that scrolled window expand should depend on
> scrollbar *policy* not scrollbar *visibility*

Hmm, but which way will it go ?

expand = policy != never || child_exand

?

This seems slightly counter-intuitive to me, since allowing a scrollbar is in a
way saying 'its ok if this gets a smaller area, the user can scroll'
Comment 35 Havoc Pennington 2010-10-12 22:59:21 UTC
hmm, just noticed the way I described toplevel resizing in the original bug description is a bit more elaborate. I proposed that for a window with no expand flags, min size = min size, max size = natural size

In that scenario, for a scrolled window, it shouldn't be expand=true at all in general. The min size would show almost nothing, the natural size would drop scrollbars and show everything. 

So it would be 
scrolled_window_expand = (policy == never && child_expand)

i.e. propagate if no scrollbar, otherwise sw doesn't need to expand beyond natural size?
Comment 36 Matthias Clasen 2010-10-12 23:04:56 UTC
> So it would be 
> scrolled_window_expand = (policy == never && child_expand)
> 
> i.e. propagate if no scrollbar, otherwise sw doesn't need to expand beyond
> natural size?


Yes, that makes sense from a can afford to be small' perspective. But it is very natural to have the content area (eg in gedit) in a scrolledwindow with policy == automatic), and this would defeat the 'make content area expand, and it will get all extra space' idea.
Comment 37 Havoc Pennington 2010-10-12 23:11:42 UTC
maybe ScrolledWindow just isn't a special case - it expands if the child does? But to just allow resizing between "tiny" and "natural size of child" you don't need to set expand=true on anything. expand is only needed if you want the child to grow above its natural size / don't want to set max size on the window.

Of course, there is this issue that setting max sizes on windows produces sort of bizarre UI behavior, at least for window types that are normally maximizable / fullscreenable.
Comment 38 Benjamin Otte (Company) 2010-10-12 23:14:21 UTC
This also does not mean that simething like a IRC user list or a file chooser resizes the window all the time as users/files are added and removed, right?

Just pointing that out so that tree views with changing number of contents are on everybody's radar.
Comment 39 Matthias Clasen 2010-10-12 23:22:56 UTC
(In reply to comment #38)
> This also does not mean that simething like a IRC user list or a file chooser
> resizes the window all the time as users/files are added and removed, right?
> 
> Just pointing that out so that tree views with changing number of contents are
> on everybody's radar.

No, expand is all about accepting extra space, not about forcing things to be larger.
Comment 40 Havoc Pennington 2010-10-12 23:45:05 UTC
This isn't really different from the current set_resizeable behavior; if you are resizeable=false then the window just resizes itself to match the content, if you are resizeable=true then the user's resize "sticks" unless the min size goes up and then the window self-resizes up to the min size.

The idea "set max size to natural size if nothing is expand=true" does add a new twist, which is an auto-computed max size that may not equal min size. So the window is resizeable but with a max, while current resizeable=true windows have only a min, not a max; and current resizeable=false windows have a max but it equals min. So the max size=natural, means the window is somewhat resizeable, but if the max goes down, the window would autoshrink, just as currently when the min goes up, the window autogrows.

This is probably all logical. yeah it can misbehave in certain cases, but if you have a list of files or users, you should set expand=true which would remove the max size, I guess.

One thing is that if doing this, now we have that issue Owen raised for min size, only on the max size as well... i.e. what's the for-width to compute the max height? The max height becomes something really short I guess?

So maybe it's simpler to dump the "max size of natural size" idea.
Comment 41 Matthias Clasen 2010-10-13 12:28:44 UTC
The one case that really misbehaves with max sze == natural size is that the scrolled window currently doesn't set a natural size that lets you get rid of the scrollbars. If we fix that, things will behave relatively nicely, I think.
Comment 42 Matthias Clasen 2010-10-13 14:54:15 UTC
Created attachment 172275 [details] [review]
another iteration of the window patch
Comment 43 Matthias Clasen 2010-10-13 14:57:23 UTC
I have now merged the branch. I've not done anything special for GtkScrolledWindow, so it just propagates its childs expand. And I've left out the window resizability.

The patch above almost seems to work fine, but there are some cases where it gets confused, if you set and then unset expand or expand-set flags on the window or its children. Either the expand propagation is screwy, or I haven't quite mastered the resizability updates in gtkwindow right. 

Something to look at later...
Comment 44 Matthias Clasen 2010-10-13 15:03:11 UTC
retitling for whats left.
Comment 45 Tristan Van Berkom 2013-04-27 12:04:08 UTC
(In reply to comment #10)
> Created an attachment (id=169640) [details] [review]
> Add horizontal and vertical expand flags, compute_expand() to GtkWidget

Havoc, I think part of this reasoning is wrong.

Some description of the fallout is up in bug 698656.

It seems now that gtk_container_child_set_property() is used to
set the child "expand" property, it's causing gtk_box_compute_expand()
to actually be called hit.

> 
> GtkWidget now has flags for horizontal and vertical expand, and
> a compute_expand() method. compute_expand() is used by containers
> to set a default expand flag. (If a widget has expand set explicitly,
> it always overrides the results of compute_expand.)
> 
> GtkContainer has a default implementation of compute_expand which
> simply walks over all child widgets and sets expand=TRUE
> if any child is expanding.
> 
> The overall effect is that you only have to set expand on
> leaf nodes in the widget tree, while previously you had to
> set expand all the way up the tree as you packed every
> container. Also, now containers need not have their own child
> properties for expand.
> 
> For old containers which do have "expand" child properties,
> they should override compute_expand and include the child
> properties in whether the container is expand=TRUE.

This part I think is wrong.

Application code which calls:
   gtk_box_pack_start (box, child, TRUE, TRUE, 0);

Does not expect that packing a child into the box, will cause the box
itself to expand (nor is the 'expand' child property of GtkBox documented
to have this effect).

> Also, the old container should use
> "child_prop_expand || gtk_widget_get_expand()" everywhere
> it previously used simply "child_prop_expand"

This part makes perfect sense, GtkBox should let children
expand based on their hexpand/vexpand flags at allocation time.

The end result should be that:

  o Adding a widget with hexpand/vexpand TRUE to a GtkBox will
    cause that child to expand inside it's parent _and_ cause
    the GtkBox to expand in _its_ parent.

  o Adding a widget to a GtkBox with the packing 'expand'
    property set to TRUE, should cause the child to expand
    in the box, but certainly not cause the box itself to
    expand in it's parent.

Currently, we have the above desired behaviour because gtk_box_pack_start()
does not call gtk_widget_queue_compute_expand(), so all the code which
expects the traditional behaviour of GtkBox is not broken because the
->compute_expand() of GtkBox is not hit (thankfully, because this
avoids breakage in much existing code, which would otherwise need to
be fixed by explicitly setting h/vexpand = FALSE on any parenting
GtkBox).

The gtk_box_compute_expand() implementation is called as a result of:

  o gtk_container_child_set_property() is called on the box, and then
    only if the child property has changed from it's default

  o gtk_widget_set_[hv]expand() is called on a child _after_ adding
    it to the GtkBox (rather unlikely).

  o gtk_widget_set_parent() is called for a child with an explicit
    hexpand/vexpand property set, this is also unlikely for any
    code calling gtk_box_pack_start().

However it is not called as a result of gtk_box_pack_start() with an
expand property set to TRUE (which is the majority use case of
gtk_box_pack_start()).
Comment 46 Havoc Pennington 2013-04-27 12:55:14 UTC
It's been a few years here, but I believe we encountered something exactly like  bug 698656 when initially landing these changes and may have discussed the issue on the mailing list. I don't see the mail immediately though. But maybe GtkToolbar had this problem at some point? (that it expanded because its children did?) I think the expand stuff may have broken toolbars. Just a faint memory. Maybe the discussion was in bugzilla or IRC, who knows.

If you don't want an expanding child to "propagate" up to make its parents expand, you are supposed to explicitly set expand=FALSE on the parent, right? I think that was the intent.

It is certainly a bug that setting the "expand" child property calls queue_compute_expand but that pack_start does not. So yeah that probably was hiding other issues including potentially that this patch wasn't compatible enough. Those two should be made equivalent one way or another. (Probably pack_start should queue_compute_expand also, but then count_expand_children should either use child->expand or not).

Either way you fix this will probably break *something* at this point...

Sorry if anything above doesn't make sense, it has been a while.
Comment 47 Havoc Pennington 2013-04-27 13:19:34 UTC
Oh, comment 22 through comment 24 talk about toolbars even.

FWIW *ignoring compatibility issues* I think it's correct and was the intent that packing a child with expand=TRUE would propagate up (at least to the next ancestor which explicitly set expand=FALSE). Or if the box itself has expand=FALSE then packing an expandable child in the box should not cause the box to expand.

It looks pretty clear to me that the pack_start not propagating expand up the tree was an unintentional mistake. However, I don't know the extent of the back compat issues that were papered over by this mistake.
Comment 48 Tristan Van Berkom 2013-04-27 13:41:33 UTC
(In reply to comment #46)
> It's been a few years here, but I believe we encountered something exactly like
>  bug 698656 when initially landing these changes and may have discussed the
> issue on the mailing list. I don't see the mail immediately though. But maybe
> GtkToolbar had this problem at some point? (that it expanded because its
> children did?) I think the expand stuff may have broken toolbars. Just a faint
> memory. Maybe the discussion was in bugzilla or IRC, who knows.
> 
> If you don't want an expanding child to "propagate" up to make its parents
> expand, you are supposed to explicitly set expand=FALSE on the parent, right? I
> think that was the intent.
> 
> It is certainly a bug that setting the "expand" child property calls
> queue_compute_expand but that pack_start does not. So yeah that probably was
> hiding other issues including potentially that this patch wasn't compatible
> enough. Those two should be made equivalent one way or another. (Probably
> pack_start should queue_compute_expand also, but then count_expand_children
> should either use child->expand or not).
> 
> Either way you fix this will probably break *something* at this point...
> 
> Sorry if anything above doesn't make sense, it has been a while.

Thanks for your quick reply Havoc.

It makes sense to me, yes, and I agree whichever way you fix it, it will
probably break *something*, I'm pretty convinced that it will break less
things to just remove the ->compute_expand() vfunc from GtkBox, and I also
think that would have been more logical to begin with.

Rationale:

  o The "expand" child property is essentially deprecated in favour of
    "hexpand"/"vexpand" properties on GtkWidget (if not deprecated,
    at least the latter is 'preferred').

    However using the "hexpand"/"vexpand" properties does produce
    the advertised results (both that it effects the parent, and
    the GtkBox takes the [hv]expand attributes into account when
    allocating, very nice).

  o GtkBox "expand" child property is not documented to effect the
    box's expand request, neither is it mentioned anywhere I can see
    in the porting guide[0] (I may have missed it's mention, though).

As it looks to me that we advertised that gtk_box_pack_start() should
be usable in the same way as in GTK+2, I would expect any ported
application code to have the same expectation.

I'm quite sure that more code will suffer by enforcing this original
intent than by removing the intent all together, otherwise we will
find ourselves adding many calls to gtk_widget_set_[hv]expand(box, FALSE)
to many ported applications, but if others strongly believe that we
should "stick to our guns" on this instead, I won't argue the case further.

[0]:https://developer.gnome.org/gtk3/stable/migrating.html
Comment 49 Havoc Pennington 2013-04-27 14:08:54 UTC
I think the section on expand in the porting guide is intended to cover this: https://developer.gnome.org/gtk3/stable/ch25s02.html#idm46912315965200

'If you experience sizing problems with widgets in ported code, carefully check the "expand" and "fill" flags of your boxes.'

But yeah the bottom line is it depends on the back compat. Maybe the most compatible thing is to just leave it all as-is :-/

I don't know how much will really break; you would sort of have to try a fix in either direction and see what breaks in each case.

Maybe this should be a new/separate bug btw ("pack_start and expand child property have inconsistent behavior").
Comment 50 Matthias Clasen 2013-04-28 21:45:48 UTC
I agree that compatibility will have to be deciding factor - which change breaks less is the one we should take.

Either way, we should expand the documentation around expand flags - the documentation of GtkBox::expand should spell out that it does not propagate up, and point to GtkWidget::h/vexpand as an alternative that does.
Comment 51 Matthias Clasen 2013-04-28 21:45:52 UTC
I agree that compatibility will have to be deciding factor - which change breaks less is the one we should take.

Either way, we should expand the documentation around expand flags - the documentation of GtkBox::expand should spell out that it does not propagate up, and point to GtkWidget::h/vexpand as an alternative that does.
Comment 52 Matthias Clasen 2018-02-10 05:17:42 UTC
We're moving to gitlab! As part of this move, we are moving bugs to NEEDINFO if they haven't seen activity in more than a year. If this issue is still important to you and still relevant with GTK+ 3.22 or master, please reopen it and we will migrate it to gitlab.
Comment 53 Matthias Clasen 2018-04-15 00:12:56 UTC
As announced a while ago, we are migrating to gitlab, and bugs that haven't seen activity in the last year or so will be not be migrated, but closed out in bugzilla.

If this bug is still relevant to you, you can open a new issue describing the symptoms and how to reproduce it with gtk 3.22.x or master in gitlab:

https://gitlab.gnome.org/GNOME/gtk/issues/new