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 701017 - display: Ensure that we ignore our own focus events for focus predictions
display: Ensure that we ignore our own focus events for focus predictions
Status: RESOLVED FIXED
Product: mutter
Classification: Core
Component: general
unspecified
Other All
: Normal normal
: ---
Assigned To: mutter-maint
mutter-maint
Depends on:
Blocks:
 
 
Reported: 2013-05-25 20:20 UTC by Jasper St. Pierre (not reading bugmail)
Modified: 2013-10-16 16:48 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
display: Ensure that we ignore our own focus events for focus predictions (3.75 KB, patch)
2013-05-25 20:20 UTC, Jasper St. Pierre (not reading bugmail)
needs-work Details | Review
display: Ensure that we ignore our own focus events for focus predictions (3.64 KB, patch)
2013-05-28 19:05 UTC, Jasper St. Pierre (not reading bugmail)
needs-work Details | Review
display: Ensure that we ignore our own focus events for focus predictions (4.73 KB, patch)
2013-05-30 04:06 UTC, Jasper St. Pierre (not reading bugmail)
needs-work Details | Review
display: Ensure that we ignore our own focus events for focus predictions (5.51 KB, patch)
2013-06-03 02:16 UTC, Jasper St. Pierre (not reading bugmail)
committed Details | Review

Description Jasper St. Pierre (not reading bugmail) 2013-05-25 20:20:35 UTC
See patch. This came up during the gnome-shell focus rework patch set, as
changes to the focus_window now matter a lot more to gnome-shell.
Comment 1 Jasper St. Pierre (not reading bugmail) 2013-05-25 20:20:37 UTC
Created attachment 245309 [details] [review]
display: Ensure that we ignore our own focus events for focus predictions

When we set the input focus, we first set the predicted window,
and then try to process focus events. But as XI_FocusOut on the
existing window comes before XI_FocusIn on the new window, we'll
see the focus out on the old window and think the focus is going
to nothing, which makes mutter think the prediction failed.

This didn't really matter as nothing paid attention to the focus
window changing, but with gnome-shell's focus rework, we'll try
and drop keyboard focus in events like these.

Fix this by making sure that we ignore focus window changes of our
own cause when updating the focus window field, by ignoring all
focus events that have a serial the same as the focus request or
lower. Note that if mutter doens't make any requests after the
focus request, this could be racy, as another client could steal
the focus, but mutter would ignore it as the serial was the same.
Bump the serial by making a dummy ChangeProperty request to the
root window in this case.
Comment 2 Owen Taylor 2013-05-28 18:05:05 UTC
Review of attachment 245309 [details] [review]:

To simply get a newer serial, there's no need for the ChangeProperty - the UngrabServer request itself will bump the serial.

It should be noted tthat we get a new serial from the UngrabServer alone. I suggested ChangeProperty because:

 * I didn't think of the fact that we could just use the UngrabServer as the request, so I thought we needed *some* request

 * The event we get in return could be useful. In particular if we fail to change the focus (which basically means someone else got the focus with a newer timestamp), then ""Earlier attempt to focus %s failed" code in event_callback() will run immediately rather than waiting for the next event we get. Doesn't matter a lot since we'll get an event soon enough - damage, user time notify, something, but it's a little nicer.

The code needs to use meta_display_grab()/meta_display_ungrab() which handles two details:

 * It is necessary to XFlush() after ungrabbing the server, to prevent the case where someone is stepping through the calling code in gdb without actually stepping into the grab, and the XGrabServer() gets flushed, but the XUngrabServer() doesn't. [Obviously less important for mutter than for other uses of Xlib, since you can't meaningfully gdb Mutter from within the same session, but good hygiene in any case]
 * If this code is called with the server already grabbed, it doesn't ungrab the outer grab. Hmm - but that means that we *can't* count on XUngrabServer() to increment the serial - so we *do* need something.

::: src/core/display.c
@@ +1965,3 @@
+    unsigned long data[1];
+
+    data[0] = meta_display_get_current_time (display);

This is a weird choice... it could be 0. If you want to always change, use the serial, or your own incrementing counter. But note

 "This event is reported to clients selecting PropertyChange on the window and is generated with state NewValue when a property of the window is changed using ChangeProperty or RotateProperties, even when adding zero-length data using ChangeProperty and when replacing all or part of a property with identical data using ChangeProperty or RotateProperties."

So there's no need to make it change. See meta_display_get_current_time_roundtrip().

@@ +1967,3 @@
+    data[0] = meta_display_get_current_time (display);
+
+    XChangeProperty (display->xdisplay, screen->xroot,

I'd rather you used display->timestamp_pinging_window - it's always better to have events generated on a private window than a root window when we can - other clients may be selecting on the root window and will be woken up to have an event delivered. You are going to have switch get_current_time_roundtrip() to use XIfEvent and check for an event with the right serial since the events we generate on the timestamp pinging window would break the use of XWindowEvent() (ugh), but on balance I still prefer that to using the root window or some other random window.
Comment 3 Jasper St. Pierre (not reading bugmail) 2013-05-28 19:05:35 UTC
Created attachment 245482 [details] [review]
display: Ensure that we ignore our own focus events for focus predictions

When we set the input focus, we first set the predicted window,
and then try to process focus events. But as XI_FocusOut on the
existing window comes before XI_FocusIn on the new window, we'll
see the focus out on the old window and think the focus is going
to nothing, which makes mutter think the prediction failed.

This didn't really matter as nothing paid attention to the focus
window changing, but with gnome-shell's focus rework, we'll try
and drop keyboard focus in events like these.

Fix this by making sure that we ignore focus window changes of our
own cause when updating the focus window field, by ignoring all
focus events that have a serial the same as the focus request or
lower. Note that if mutter doens't make any requests after the
focus request, this could be racy, as another client could steal
the focus, but mutter would ignore it as the serial was the same.
Bump the serial by making a dummy ChangeProperty request to the
root window in this case.
Comment 4 Owen Taylor 2013-05-29 20:30:54 UTC
Review of attachment 245482 [details] [review]:

In the commit message:

> Bump the serial by making a dummy ChangeProperty request to the
> root window in this case.

"root window"

::: src/core/display.c
@@ +1977,3 @@
                   timestamp);
+
+  serial = XNextRequest (display->xdisplay);

You want the serial of the SetInputFocus, right?

@@ +1982,3 @@
+    unsigned long data[1] = { 0 };
+
+    XChangeProperty (display->xdisplay, display->timestamp_pinging_window,

As I mentioned in my last review, using timsetamp_pinging_window is going to require adaption of the code to get roundtrip server time - that currently assumes that the *first* PropertyNotify on the pinging window is the one it looks for.
Comment 5 Jasper St. Pierre (not reading bugmail) 2013-05-29 20:35:05 UTC
(In reply to comment #4)
> Review of attachment 245482 [details] [review]:
> 
> In the commit message:
> 
> > Bump the serial by making a dummy ChangeProperty request to the
> > root window in this case.
> 
> "root window"
> 
> ::: src/core/display.c
> @@ +1977,3 @@
>                    timestamp);
> +
> +  serial = XNextRequest (display->xdisplay);
> 
> You want the serial of the SetInputFocus, right?

No? The code is:

  if (display->server_focus_serial >= display->focus_serial)

So we want to make sure that we ignore FocusOut events that come from that serial. Either the serial is of the ChangeProperty (the serial after the SetInputFocus), *or* we change this to a >.

I'm fine with either, but wouldn't making the serial the same as before keep the bug alive?
Comment 6 Jasper St. Pierre (not reading bugmail) 2013-05-30 04:06:50 UTC
Created attachment 245609 [details] [review]
display: Ensure that we ignore our own focus events for focus predictions

When we set the input focus, we first set the predicted window,
and then try to process focus events. But as XI_FocusOut on the
existing window comes before XI_FocusIn on the new window, we'll
see the focus out on the old window and think the focus is going
to nothing, which makes mutter think the prediction failed.

This didn't really matter as nothing paid attention to the focus
window changing, but with gnome-shell's focus rework, we'll try
and drop keyboard focus in events like these.

Fix this by making sure that we ignore focus window changes of our
own cause when updating the focus window field, by ignoring all
focus events that have a serial the same as the focus request or
lower. Note that if mutter doens't make any requests after the
focus request, this could be racy, as another client could steal
the focus, but mutter would ignore it as the serial was the same.
Bump the serial by making a dummy ChangeProperty request to a
mutter-controlled window in this case.
Comment 7 Owen Taylor 2013-05-30 18:10:14 UTC
(In reply to comment #5)

> > ::: src/core/display.c
> > @@ +1977,3 @@
> >                    timestamp);
> > +
> > +  serial = XNextRequest (display->xdisplay);
> > 
> > You want the serial of the SetInputFocus, right?
> 
> No? The code is:
> 
>   if (display->server_focus_serial >= display->focus_serial)

True for that code. But we also have:

  if (event->xany.serial > display->focus_serial &&
      display->focus_window &&
      display->focus_window->xwindow != display->server_focus_window)
    {
      meta_topic (META_DEBUG_FOCUS, "Earlier attempt to focus %s failed\n",
                  display->focus_window->desc);

And that definitely wants display->focus_serial to be the serial of the request to change the focus. I think it's also confusion strange if when we get the focus event back for a change we make, we set display->server_focus_serial to display->focus_serial - 1.

So I think we want to change the check to be >, rather than using the higher serial.
Comment 8 Owen Taylor 2013-05-30 18:13:46 UTC
Review of attachment 245609 [details] [review]:

I think it's pretty bizarre to change properties on the pinging window in two places, and in one place do:

      /* Using the property XA_PRIMARY because it's safe; nothing
       * would use it as a property. The type doesn't matter.
       */

And in the other place add a new _MUTTER_FOCUS_SET atom. I'm fine with any of three things:

 * Use XA_PRIMARY for one, and, say, XA_SECONDARY for the other
 * Use a special atom for both
 * Use XA_PRIMARY (or a special atom) for both, and check the serial in the XIfEvent call to find the event we are looking for

That, and the choice of the serial are the only remaining problems I see here.
Comment 9 Jasper St. Pierre (not reading bugmail) 2013-06-03 02:16:17 UTC
Created attachment 245887 [details] [review]
display: Ensure that we ignore our own focus events for focus predictions

When we set the input focus, we first set the predicted window,
and then try to process focus events. But as XI_FocusOut on the
existing window comes before XI_FocusIn on the new window, we'll
see the focus out on the old window and think the focus is going
to nothing, which makes mutter think the prediction failed.

This didn't really matter as nothing paid attention to the focus
window changing, but with gnome-shell's focus rework, we'll try
and drop keyboard focus in events like these.

Fix this by making sure that we ignore focus window changes of our
own cause when updating the focus window field, by ignoring all
focus events that have a serial the same as the focus request or
lower. Note that if mutter doens't make any requests after the
focus request, this could be racy, as another client could steal
the focus, but mutter would ignore it as the serial was the same.
Bump the serial by making a dummy ChangeProperty request to a
mutter-controlled window in this case.
Comment 10 Owen Taylor 2013-06-03 17:01:27 UTC
Review of attachment 245887 [details] [review]:

Looks good
Comment 11 Jasper St. Pierre (not reading bugmail) 2013-06-20 21:23:29 UTC
Attachment 245887 [details] pushed as 7fdfbad - display: Ensure that we ignore our own focus events for focus predictions