Comment 7 for bug 1165649

Revision history for this message
In , Josh Triplett (joshtriplett) wrote :

OK, after further exploration and some discussion on #xorg-devel, it turns out that this bug really does need fixing in Firefox, not in gnome-settings-daemon and similar programs that listen for keys.

The FocusOut event occurs as an inherent part of grabbing a keyboard key. gnome-settings-daemon or anything else listening to specific keys such as the hardware volume/brightness keys has to register a passive grab on those keys. A passive grab causes X to start an active grab when the grabbed key occurs. That active grab generates a FocusOut event to the currently focused window, and then the end of the grab generates a FocusIn event.

However, the FocusOut event actually indicates the nature of the lost focus, in the .mode field. When a grab occurs, the FocusOut event will have NotifyGrab set. Other types of FocusOut events have NotifyNormal (a normal focus change) or NotifyWhileGrabbed (focus changed while under a grab, so the window won't get it back when the grab ends; occurs in Alt-Tab for instance).

xterm, as usual, gets this right. It shows its cursor as hollow when it loses focus, and solid when it has focus. Hitting a grabbed key such as the hardware volume/brightness keys or Alt-Tab does not cause xterm to show the hollow cursor, but actually switching to another window (with Alt-Tab or by clicking on the other window) does. Looking at the source to xterm, in misc.c, in the FocusOut case of HandleFocusChange:

 /*
  * XGrabKeyboard() will generate NotifyGrab event that we want to
  * ignore.
  */
 if (event->mode != NotifyGrab) {
     unselectwindow(screen,
      ((event->detail == NotifyPointer)
       ? INWINDOW
       : FOCUS));
 }

I think Firefox needs to apply the same logic: ignore FocusOut events if they have NotifyGrab set. Any actual focus change that Firefox cares about will occur with one of the other flags set. NotifyGrab just means some other program just captured a magic hotkey that Firefox shouldn't care about; that shouldn't cause un-fullscreening.

Unfortunately, GDK doesn't currently expose the .mode field of FocusOut events in its GdkEventFocus structure. So, handling this case requires touching the X event directly. Firefox already does this for several other types of events. The simplest fix seems a GDK event filter (gdk_window_add_filter) which returns GDK_FILTER_REMOVE for any FocusOut with mode NotifyGrab.

I've discussed this issue with people in the Xorg and GTK+ communities, who also plan to look into the broader issue with other GTK+ applications getting this wrong; for instance, unlike xterm, gnome-terminal shows its hollow not-focused cursor momentarily when pressing grabbed keys. A future GDK may start translating the .mode field of the FocusOut event as part of GdkEventFocus, and GTK+ may change its generation of focus-out-event to handle NotifyGrab differently. However, I still think it makes sense to go ahead and fix this in Firefox.