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 162980 - focus stealing prevention and window frames (in particular, deletes)
focus stealing prevention and window frames (in particular, deletes)
Status: RESOLVED FIXED
Product: gtk+
Classification: Platform
Component: Backend: X11
2.6.x
Other Linux
: High major
: ---
Assigned To: gtk-bugs
gtk-bugs
Depends on:
Blocks: 149028
 
 
Reported: 2005-01-05 04:12 UTC by Elijah Newren
Modified: 2011-02-04 16:17 UTC
See Also:
GNOME target: 2.10.0
GNOME version: 2.9/2.10


Attachments
Use timestamp from WM_DELETE_WINDOW to update user interaction time (638 bytes, patch)
2005-01-05 04:13 UTC, Elijah Newren
none Details | Review

Description Elijah Newren 2005-01-05 04:12:54 UTC
Sebastien pointed this one out to me in IRC:
1. Open gedit
2. Type some stuff (but don't save your changes)
3. Click on the close button on the upper right of the window frame

Gedit will open a dialog asking whether to save the document; this window will
not be focused.

Reasons for this bug, in excruciating detail:
1. Whenever the user presses keys or clicks in client area, gtk+ updates
   _NET_WM_USER_TIME of window.  Let's say the timestamp of the last keypress
   is x, so that gedit's _NET_WM_USER_TIME is x.
2. Whenever the user clicks on a window (client area or the frame), Metacity
   updates it's user_time variable for the window (reasons: legacy app support
   and because clients don't receive events that occur on the frame, yet they
   really should count as user interaction).
3. Metacity doesn't update the _NET_WM_USER_TIME of gedit (reason: the idea of
   _NET_WM_USER_TIME was so that the window manager would know all the correct
   timestamps, and Metacity already has the timestamp).
4. From (2) and (3), metacity's user_time variable for gedit is y, where y > x.
5. Gedit opens a new window when it receives the delete_event.  Gtk+ default is
   to set the new window's _NET_WM_USER_TIME to the most recent user
   interaction of the user with the app.  As far as gtk+ knows, that time is x.
6. Metacity sees the new window mapped, but with _NET_WM_USER_TIME x, which is
   less than the user_time of the focus window (gedit), i.e. is less than y.

Proposed solution:
gtk+ already gets a WM_DELETE_WINDOW from the window manager that includes a
timestamp, so use it.  (Question: Can an app get a WM_DELETE_WINDOW that doesn't
come from user interaction?  I don't see how, but that might be a problem with
this solution.)

Alternate solutions that seem to have problems:
1) Don't have metacity update it's internal user_time for any clicks if the
   app  is known to support _NET_WM_USER_TIME.  This means that clicking on a
   frame (e.g. to raise a window) doesn't count as user interaction and so
   other windows can take focus when the user doesn't expect it.
2) Have metacity update _NET_WM_USER_TIME x property of the window when it
   receives frame clicks.  Make gtk+ monitor these so that it's variables are
   updated appropriately.  This would introduce a race condition--which
   message gets to the app first; the _NET_WM_USER_TIME update, or the
   WM_DELETE_WINDOW?

I'll attach a one-line patch in a minute that uses the proposed solution and
which I've verified fixes the observed bug.
Comment 1 Elijah Newren 2005-01-05 04:13:39 UTC
Created attachment 35458 [details] [review]
Use timestamp from WM_DELETE_WINDOW to update user interaction time
Comment 2 Matthias Clasen 2005-01-05 04:49:16 UTC
Sounds like a correct analysis and a reasonable fix.
It doesn't seem to solve the fundamental problem that in the 
sequence

1) edit text in gedit
2) fiddle with wm frame
3) gedit opens a dialog without further user interaction

the dialog will not get focus. Correct ?
Comment 3 Matthias Clasen 2005-01-05 04:50:09 UTC
Sounds like a correct analysis and a reasonable fix.
It doesn't seem to solve the fundamental problem that in the 
sequence

1) edit text in gedit
2) fiddle with wm frame
3) gedit opens a dialog without further user interaction

the dialog will not get focus. Correct ?
Comment 4 Elijah Newren 2005-01-05 06:07:11 UTC
Um, I need to split your summary into three cases and discuss each individually,
because the explanation depends a lot on what you mean by "gedit opens a dialog
without further user interaction".

Case 1: gedit opens a dialog not spawned from any user interaction
This is by definition a "surprise popup".  Applications are supposed to mark any
such dialogs with a do-not-focus-on-map request (because focusing surprise
dialogs can result in users accidentally dismissing the window or accidentally
choosing a destructive action without even getting a chance to read and realize
what action they chose).  This case presents no problems

Case 2: gedit opens a dialog due to a user interaction with the frame
I can't think of any user interactions with the frame that will cause an
application to open a window, except, of course, for the close button on the
frame.  Can you?  As far as I can tell, my patch fixes the only problem this
case presents.

Case 3: gedit opens a dialog from a previous interaction with the app
This is much more involved to explain.  However, it is a lot like the following
focus case we have to worry about for browsers:
  a) Open a URL in a web browser for a site which happens to be down
  b) wait for the browser to respond (by loading the page or showing an error)
OR
  a) same as above
  b) open another URL in a different tab while waiting
In the first of these two cases, the error dialog that says "the connection
couldn't be made" should be focused; in the latter, it shouldn't be (the user
has interacted with the application--and may still be interacting with it--after
the event that caused the window to be opened; focusing it could also result in
accidental dismissal)

Now, to make it easier to catch the similarity, let me go back to the gedit case
but introduce a slight change:
  1) The user clicks on Edit->Preferences in order to get a preferences dialog
     to appear.
  2) Pretend this preferences dialog makes Open Office startup look fast, and
     doesn't appear for a long time.
  3) Pretend further that the user has somehow become accustomed to this, and
     just clicks in his document to continue typing while waiting.
  4) the preference dialog finally appears

The correct behavior in this case is to not focus the preference dialog because
the user has continued on with their work.  (Note that they might accidentally
dismiss the dialog or give an erroneous action if you were to focus it.)

Now, clicking on the frame when the application is trying to open a window from
a previous user interaction is just like the above case, meaning that the new
window should not be focused.  This means that this case presents no problems
either.

In summary, I think we only have a problem if a frame interaction can cause the
app to open a window.  The only case I'm aware of that this can happen is when
trying to close the window via clicking on the frame's close button.  My patch
above handles this case.

Now, it's possible in that long list of cases to miss something.  Can anyone see
anything that I missed?
Comment 5 Matthias Clasen 2005-01-05 06:16:16 UTC
No, I think you are right, fiddling with the frame shouldn't trigger app popups,
exect for the one case we are discussing here (WM_DELETE) - unless someone want
to code a "Really accept focus" dialog in response to WM_TAKE_FOCUS...

 I was mainly thinking about dialogs which could come up after a timeout, but I
think you are correct that not focusing the dialog in this case is likely more
correct wm behaviour, and the user can easily correct it by clicking on the
dialog frame in case he really needs the focus in the dialog.
Comment 6 Matthias Clasen 2005-01-05 16:28:02 UTC
2005-01-05  Matthias Clasen  <mclasen@redhat.com>

	* gdk/x11/gdkevents-x11.c (gdk_wm_protocols_filter): Update 
	the user time when receiving a WM_DELETE message.  (#162980, 
	Elijah Newren)