GNOME Bugzilla – Bug 769635
Using gtk_event_box_set_above_child() can result in spurious grab-broken events
Last modified: 2016-08-09 10:04:45 UTC
In spice-gtk, we use a GtkEventBox along with gtk_event_box_set_above_child(). On a button-press-event, we are calling gdk_pointer_grab() on the event box. After doing that, we get a grab-broken event where event->grab_window is the event box we passed to gdk_pointer_grab(). This is unexpected, and is currently causing spice-gtk to fail grabbing the mouse.
Created attachment 332947 [details] small reproducer This small test program exhibits the bug described in this bug report.
I think this works as intended... bear in mind that gtk_widget_get_window() won't return the GdkWindow that GtkEventBox places above as per your request. In this case, GtkEventBox has 2 windows: a I/O window set as the widget window (the one you get and grab on) and a input-only window placed right above. When you click, the latter gets the events, yet you immediately force a grab on the first one. So gdk sends a GdkEventGrabBroken with event->window being the window it's delivered to (the input-only window), and event->grab_window being the window that's taking over the grab (the I/O window below the child widget). This "works" in the !above_child case, because gtk_widget_get_window() and the "event window" are the same. I see two options to handle this on your side: - Check whether event->grab_broken.window and event->grab_broken.grab_window belong to the same widget - Actually grab on the input-only window, although GtkEventBox doesn't offer getters for it.
An idea to bypass the shortcoming in the second option: grab on event->button.window, that will be the input-only window that's meant to be handling input events here.
(In reply to Carlos Garnacho from comment #2) > I think this works as intended... Oh, could very well be, I'm not familiar with grabs in general, and this was unexpected behaviour for me, so I thought I'd file a bug. At the same time, I was expecting it to end up being closed as NOTABUG or WONTFIX :) Thanks for the detailed explanation! > bear in mind that gtk_widget_get_window() > won't return the GdkWindow that GtkEventBox places above as per your request. > > In this case, GtkEventBox has 2 windows: a I/O window set as the widget > window (the one you get and grab on) and a input-only window placed right > above. When you click, the latter gets the events, yet you immediately force > a grab on the first one. So gdk sends a GdkEventGrabBroken with > event->window being the window it's delivered to (the input-only window), > and event->grab_window being the window that's taking over the grab (the I/O > window below the child widget). > > This "works" in the !above_child case, because gtk_widget_get_window() and > the "event window" are the same. Hmm, yup, makes sense, this was quite confusing for me as the input-only window is some hidden implementation detail, so it was not very clear what was this window that had the grab. Add to that that GtkEventBox has 2 GdkWindow and we get a grab-broken for the grab moving from one window to the other, and I was not sure which behaviour to expect ;) > > I see two options to handle this on your side: > - Check whether event->grab_broken.window and event->grab_broken.grab_window > belong to the same widget Yup, this is what I've proposed on the mailing list ( https://lists.freedesktop.org/archives/spice-devel/2016-August/031150.html ), but I'll try your other suggestion. Thanks! > - Actually grab on the input-only window, although GtkEventBox doesn't offer > getters for it.
(In reply to Christophe Fergeau from comment #4) > (In reply to Carlos Garnacho from comment #2) > > I think this works as intended... > > Oh, could very well be, I'm not familiar with grabs in general, and this was > unexpected behaviour for me, so I thought I'd file a bug. At the same time, > I was expecting it to end up being closed as NOTABUG or WONTFIX :) Thanks > for the detailed explanation! > > > bear in mind that gtk_widget_get_window() > > won't return the GdkWindow that GtkEventBox places above as per your request. > > > > In this case, GtkEventBox has 2 windows: a I/O window set as the widget > > window (the one you get and grab on) and a input-only window placed right > > above. When you click, the latter gets the events, yet you immediately force > > a grab on the first one. So gdk sends a GdkEventGrabBroken with > > event->window being the window it's delivered to (the input-only window), > > and event->grab_window being the window that's taking over the grab (the I/O > > window below the child widget). > > > > This "works" in the !above_child case, because gtk_widget_get_window() and > > the "event window" are the same. > > Hmm, yup, makes sense, this was quite confusing for me as the input-only > window is some hidden implementation detail, so it was not very clear what > was this window that had the grab. Add to that that GtkEventBox has 2 > GdkWindow and we get a grab-broken for the grab moving from one window to > the other, and I was not sure which behaviour to expect ;) I agree this is kinda confusing :), events are coherent at the gdk level, but this one sends a kind of mixed message when both windows belong to the same widget above gdk. I would be at the same time afraid to just silence it at the gtk level because we drop this event coherence. I expect this to get better in the future when we manage to eliminate/hide non-toplevel GdkWindows from API, and widgets become the surface unit. Till then... this works as designed, thus NOTABUG :)