GNOME Bugzilla – Bug 66754
setting state hints on second map
Last modified: 2011-02-04 16:11:52 UTC
If you: a) Call gdk_window_maximize b) Show the window c) withdraw the window d) call gdk_window_unmaximize e) Show the window again I believe that the window will come up maximized, since gdkwindow-x11.c:set_initial_hints() doesn't change the property if no state flags are set. I think set_initial_hints() needs to delete the property if no state flags are set.
This is pretty much completely hidden by the gtkwindow.c maximization (etc.) code ... you really can't mix that that with gdk_window_maximation(). But the gtk_window_maximize code seems broken over repeated show/hide cycles. gtk_window_maximize(window) [ user unmaximizes ] gtk_widget_hide (window) gtk_widget_show (window) Will leave the window shown since the maximize_initially flag is never cleared.
I wonder if the window manager shouldn't clear _NET_WM_STATE when a window is withdrawn. That would resolve the GDK issue. If not yeah the properties need deleting if the window has ever been mapped. The point about GtkWindow is probably pretty easy to fix (does the invariant that "if (mapped) assert (maximized_initially == FALSE)" fix it? this is essentially the same invariant that we have for gtk_window_set_default_size)
Shouldn't the maximization state be preserved over withdraw/show unless the client specifically intervenes? That won't happen if you clear the maximized flag, and I think worse, the window will come up big as the screen but not maximized. In gtk_window_map(), we have: if (window->maximize_initially) gdk_window_maximize (toplevel); else gdk_window_unmaximize (toplevel); So I don't think just clearing maximize_initially works.
Good point. Perhaps we need to save last-received state_changed event state, and set maximize_initially etc. based on that? Perhaps a better fix is that once we've mapped a window once, we only touch _NET_WM_STATE again if the app explicitly calls gtk_window_maximize(). Another issue here is that we should leave _NET_WM_STATE fields we don't understand in-place, which of course can't be done without races unless we grab the server... though it should be safe for withdrawn windows.
A lot of confusing issues here. I don't think that the current behavior is conceivably "right" enough that people would come to rely on it so I think we can deal with this for 2.0.1.
Moving non-critical or hard to fix bugs to 2.0.2
Move open bugs from milestones 2.0.[012] -- > 2.0.3, since 2.0.2 is already out.
I think Havocs plan is right. The actions taken in gtk_window_map based on the various _initially flags are only appropriate before the first map. If a window has already gone through a show-hide cycle, the _NET_WM_STATE property will contain the WMs view of the windows state before it died (from the wms perspective, a withdrawn toplevel is dead and mapping it again will create a fresh toplevel). If we leave _NET_WM_STATE untouched during the second map, the WM will initiate the state of the new toplevel based on it. There should be no races involved in keeping unknown _NET_WM_STATE fields, unless there is a bug in the EWMH. There is always exactly one possible writer: The WM may write it on mapped toplevels, the client may write it on unmapped toplevels.
...provided that WMs do *not* clear _NET_WM_STATE on withdrawal, of course. To defend against WMs that do so, we would indeed have to transfer the last known state into the various ..._initially variables.
Wasn't the outcome of discussion on wm-spec-list that we were supposed to clear _NET_WM_STATE on withdrawal? I don't remember all the details but I thought that was the conclusion.
Here is a minimal patch which seems to work. I have tested it using sawfish and a little cleaner which I used to delete the _NET_WM properties on withdrawn windows.
Created attachment 8197 [details] [review] the patch
Created attachment 8198 [details] the cleaner
Created attachment 8199 [details] [review] the patch
Forgot to mention that the patch won't work unless you also apply the patch for #79248, since it relies on the gdk window state being uptodate.
I guess I'm still confused on the difference between: - "An app that wants to reuse a dialog" that has been referred to in wm-spec-list discussions - A GTK+ app that calls gtk_widget_hide(window) followed by gtk_widget_show(window)
The difference I see is that there are two different things to do with a withdrawn window: 1) Reuse it as if it was a fresh window. In this case, the clients doesn't want to have any "hidden" wm state sticking to the withdrawn window. I think this is what the ICCCM alludes to in section 4.1.4(and this is how the ICCCM already treats the Withdrawn state: the wm has to remove WM_STATE upon withdrawal) 2) Bring the window back from the Withdrawn state as if it had only been iconfied. In this case, the clients want to keep any "hidden" wm state. I think this is the expected behaviour for gtk_widget_hide(window) followed by gtk_widget_show(window). If we clearify the EWMH by extending the ICCCM behaviour of cleaning wm state upon withdrawal, clients can get both. 1) is free, for 2) they have to maintain the wm state of withdrawn windows - which gtk already does anyway.
Looks like the gtkwindow.c patch got accidentally committed in May. (ChangeLog entry: * gtk/gtkwindow.c (gtk_window_move): Markup fixes ). That's fine since I was about to say to go ahead and apply it :-) Since i don't think window managers reliably clean the _NET_WM_STATE hint, I think we also need the small change to set_initial_hints mentioned at the top of this mail- if no state hints are being set, delete the current property.
Oh, sorry, I should be more careful when operating in a single tree ...well, at least it got some field testing... I'll look into providing a patch for set_initial_hints.
Created attachment 12909 [details] [review] patch (untested)
Patch looks fine to me. (Noticing that function could really use a: GdkDisplay *display = GDK_WINDOW_DISPLAY (window); Display *xdisplay = GDK_DISPLAY_XDISPLAY (display); Window xwindow = GDK_WINDOW_XID (window); At that top.)
Committed with the proposed locals.