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 726123 - wayland: Set/unset wayland focus on mutter grab/ungrab operations
wayland: Set/unset wayland focus on mutter grab/ungrab operations
Status: RESOLVED FIXED
Product: mutter
Classification: Core
Component: wayland
unspecified
Other All
: Normal normal
: ---
Assigned To: mutter-maint
mutter-maint
Depends on:
Blocks:
 
 
Reported: 2014-03-11 17:58 UTC by Rui Matos
Modified: 2014-03-20 16:18 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
wayland: Set/unset wayland focus on mutter grab/ungrab operations (5.93 KB, patch)
2014-03-11 17:58 UTC, Rui Matos
reviewed Details | Review
wayland-pointer: Drop unused arg from focus grab interface method (3.28 KB, patch)
2014-03-16 16:00 UTC, Rui Matos
accepted-commit_now Details | Review
wayland: Set/unset wayland focus on mutter grab/ungrab operations (8.52 KB, patch)
2014-03-16 16:01 UTC, Rui Matos
reviewed Details | Review
wayland-pointer: Drop unused arg from focus grab interface method (4.32 KB, patch)
2014-03-16 16:04 UTC, Rui Matos
committed Details | Review
wayland: Set/unset wayland focus on mutter grab/ungrab operations (6.37 KB, patch)
2014-03-16 19:32 UTC, Rui Matos
committed Details | Review
wayland-seat: Don't send pointer enter/leave events during a GRAB_OP (1.04 KB, patch)
2014-03-16 19:37 UTC, Rui Matos
reviewed Details | Review
wayland-seat: Don't send pointer enter/leave events during a GRAB_OP (3.05 KB, patch)
2014-03-17 19:15 UTC, Rui Matos
committed Details | Review
wayland: Exempt CLICKING grab ops when syncing wayland input focus (5.21 KB, patch)
2014-03-17 20:04 UTC, Rui Matos
committed Details | Review

Description Rui Matos 2014-03-11 17:58:39 UTC
This one puzzled me for a while, see the commit msg.
Comment 1 Rui Matos 2014-03-11 17:58:41 UTC
Created attachment 271542 [details] [review]
wayland: Set/unset wayland focus on mutter grab/ungrab operations

This ensures that we send the proper leave and enter events to wayland
clients.

Particularly, this solves a bug in SSD xwayland windows where clicking
and dragging on the title bar to move the window only works on the odd
turn (unless the pointer moves away from the title bar between
tries). This happens because xwayland gets a button press but doesn't
see the release so when it gets the next button press it discards it
because its pointer button tracking logic says that the button is
already pressed. Sending the proper wayland pointer leave event fixes
it since wayland clients must forget about button state at that point.
Comment 2 Jasper St. Pierre (not reading bugmail) 2014-03-11 18:50:54 UTC
Review of attachment 271542 [details] [review]:

::: src/core/display.c
@@ +1751,3 @@
+{
+  MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
+

I feel like the code to set it to NULL if we have a grab should be in here.

  MetaWindow *focus_window;

  if (display->grab_op == META_GRAB_OP_NONE)
    focus_window = NULL;
  else if (meta_display_xwindow_is_a_no_focus_window (display, display->focus_xwindow))
    focus_window = NULL;
  else if (...)
    focus_window = display->focus_window;

  meta_wayland_compositor_set_input_focus (compositor, display->focus_window);

But that doesn't help us for pointer focus. I'm undecided about that. I really don't like how it's split across multiple places. Perhaps we should hack in some code to repick() to make it focus NULL if we have a non-NULL grab op, since that's what we do here.

@@ +1754,3 @@
+  if (meta_display_xwindow_is_a_no_focus_window (display, display->focus_xwindow))
+    meta_wayland_compositor_set_input_focus (compositor, NULL);
+  else if (display->focus_window && display->focus_window->surface)

Theoretically, if we always only call this when we're a Wayland compositor, this should *never* be false, but this is a separate cleanup.
Comment 3 Giovanni Campagna 2014-03-11 22:00:14 UTC
Wait a minute, is this for keyboard or pointer? The keyboard focus must not move when we grab, otherwise entering and exiting the overview would unfocus the active window or focus a different one.
Comment 4 Jasper St. Pierre (not reading bugmail) 2014-03-11 22:20:58 UTC
Uh, why would sending leave events and setting the Wayland keyboard focus to NULL change how the overview behaves?
Comment 5 Giovanni Campagna 2014-03-11 22:29:36 UTC
Because if go the overview in x11 the app is not unfocused (does not go to backdrop state), and because if we don't have a focused window we call focus_default_window () on exit which is not necessary right.
Setting the pointer focus is fine, setting keyboard is not, just like we don't call XSetInputFocus under X11
Comment 6 Jasper St. Pierre (not reading bugmail) 2014-03-11 23:27:32 UTC
We don't modify display->focus_window which is what gnome-shell tracks, only the Wayland focus (which is what's used to deliver enter/leave and that's it).

Decorations being focused is driven by the appears-focused property, and that's driven by display->focus_window as well.
Comment 7 Jasper St. Pierre (not reading bugmail) 2014-03-11 23:27:57 UTC
Well, it's also used to deliver key events, but that obviously doesn't have any role when grabbed/modal in the overview.
Comment 8 Giovanni Campagna 2014-03-12 09:57:29 UTC
No decorations being focused is driven by the app getting wl_keyboard.enter/leave, because decorations are client side.
Comment 9 Rui Matos 2014-03-12 10:21:22 UTC
(In reply to comment #8)
> No decorations being focused is driven by the app getting
> wl_keyboard.enter/leave, because decorations are client side.

For gtk+ this is driven by xdg_surface.activated/deactivated, not by wl_keyboard.enter/leave.
Comment 10 Rui Matos 2014-03-16 16:00:53 UTC
Created attachment 272066 [details] [review]
wayland-pointer: Drop unused arg from focus grab interface method
Comment 11 Rui Matos 2014-03-16 16:01:03 UTC
Created attachment 272067 [details] [review]
wayland: Set/unset wayland focus on mutter grab/ungrab operations

This ensures that we send the proper leave and enter events to wayland
clients.

Particularly, this solves a bug in SSD xwayland windows where clicking
and dragging on the title bar to move the window only works on the odd
turn (unless the pointer moves away from the title bar between
tries). This happens because xwayland gets a button press but doesn't
see the release so when it gets the next button press it discards it
because its pointer button tracking logic says that the button is
already pressed. Sending the proper wayland pointer leave event fixes
it since wayland clients must forget about button state at that point.
Comment 12 Rui Matos 2014-03-16 16:04:07 UTC
Created attachment 272069 [details] [review]
wayland-pointer: Drop unused arg from focus grab interface method
Comment 13 Jasper St. Pierre (not reading bugmail) 2014-03-16 17:22:42 UTC
Review of attachment 272066 [details] [review]:

OK.
Comment 14 Jasper St. Pierre (not reading bugmail) 2014-03-16 17:59:25 UTC
Review of attachment 272067 [details] [review]:

Hm, could we somehow get a repick while grabbed? I'm a bit worried about a situation like that.
Comment 15 Jasper St. Pierre (not reading bugmail) 2014-03-16 17:59:49 UTC
Review of attachment 272069 [details] [review]:

Uh, OK.
Comment 16 Rui Matos 2014-03-16 19:32:28 UTC
Created attachment 272089 [details] [review]
wayland: Set/unset wayland focus on mutter grab/ungrab operations

--

The previous patch didn't actually work right. Going through
default_grab_focus() doesn't work here because that function is a nop
if button_count > 0. Instead I changed it back to calling
meta_wayland_pointer_set_focus(pointer, NULL) directly. This means we don't
update pointer->current in this case but it shouldn't matter since we
do this when beggining a GRAB_OP and thus there won't be pointer events being
delivered to wayland clients until the GRAP_OP ends and at that point
we do a seat_repick() which takes care of updating pointer->current.
Comment 17 Rui Matos 2014-03-16 19:37:32 UTC
Created attachment 272090 [details] [review]
wayland-seat: Don't send pointer enter/leave events during a GRAB_OP

meta_wayland_seat_repick() can be called in various cases while mutter
has a GRAB_OP ongoing which means we could be sending wrong pointer
enter/leave events.
--

(In reply to comment #14)
> Hm, could we somehow get a repick while grabbed? I'm a bit worried
> about a situation like that.

Indeed it looks like it could happen. How about this?
Comment 18 Rui Matos 2014-03-17 10:32:54 UTC
Comment on attachment 272069 [details] [review]
wayland-pointer: Drop unused arg from focus grab interface method

Attachment 272069 [details] pushed as 62e45b6 - wayland-pointer: Drop unused arg from focus grab interface method
Comment 19 Jasper St. Pierre (not reading bugmail) 2014-03-17 15:04:39 UTC
Review of attachment 272090 [details] [review]:

Similar to how we did sync_input_focus, is there anything wrong with:

    if (display->grab_op != META_GRAB_OP_NONE)
      surface = NULL;
    else
      {
        if (for_event)
          ...
      }

?
Comment 20 Giovanni Campagna 2014-03-17 15:25:34 UTC
Mh... one thing that pops into my mind now... What about gtk+ grab ops (the CLICKING_* stuff)?
For those, we need to send events to wayland, so that they're forwarded to XWayland and from there to gtk+.
Or we need to forge events to gtk+ from clutter events...
Comment 21 Rui Matos 2014-03-17 19:15:12 UTC
Created attachment 272199 [details] [review]
wayland-seat: Don't send pointer enter/leave events during a GRAB_OP

--
(In reply to comment #19)

> Similar to how we did sync_input_focus, is there anything wrong
> with:

Like this? If sync_input_focus() is being called from all the correct
places this should be nop but yeah, seems safer.
Comment 22 Jasper St. Pierre (not reading bugmail) 2014-03-17 19:29:33 UTC
Review of attachment 272199 [details] [review]:

::: src/wayland/meta-wayland-pointer.c
@@ +587,3 @@
+void
+meta_wayland_pointer_update_current_focus (MetaWaylandPointer *pointer,
+                                           MetaWaylandSurface *surface)

I don't need the need for the separate function anymore, but it can't hurt. We probably should be moving stuff like repick to MetaWaylandPointer anyway.
Comment 23 Jasper St. Pierre (not reading bugmail) 2014-03-17 19:30:13 UTC
Review of attachment 272089 [details] [review]:

Looks good.
Comment 24 Rui Matos 2014-03-17 20:04:17 UTC
Created attachment 272201 [details] [review]
wayland: Exempt CLICKING grab ops when syncing wayland input focus

If we have a CLICKING grab op we still need to send events to xwayland
so that we get them back for gtk+ to process thus we can't steer
wayland input focus away from it.
--

(In reply to comment #20)
> Mh... one thing that pops into my mind now... What about gtk+ grab
> ops (the CLICKING_* stuff)?  For those, we need to send events to
> wayland, so that they're forwarded to XWayland and from there to
> gtk+.  Or we need to forge events to gtk+ from clutter events...

Indeed, good catch. This patch fixes it but this stuff is getting
ugly. Also, I don't like the function name here but I can't think of
anything short that conveys what this is about...
Comment 25 Jasper St. Pierre (not reading bugmail) 2014-03-17 20:52:44 UTC
Review of attachment 272201 [details] [review]:

OK, we have a bunch of different "types" of grab operations:

  * "Normal" mode. Pointer and keyboard get sent to clients. Keybindings are OK.

  * User grab operations where we basically want to change the behavior of pointer and keyboard. These are the standard move / resize grabs. These should take over the normal behavior of pointer / keyboard, as far as I'm aware. We don't play events to clients, and keybindings don't activate. The keybindings.c explicitly special-cases this, to add support for the "Escape" key when doing a mouse move/resize, and to add arrow keys when doing a keyboard move/resize.

  * Frame button operations. These are used as state tracking, so we know what button we clicked on, since we can't use a widget system like GtkButton. Under X11, at least, normal events and keybindings activate normally (e.g. click and hold on the close button and press Alt+F10, and the window will be maximized). I don't think it particularly matters whether we keep this behavior. I also think that we don't particularly need this to be part of a grab op. We could track this in a separate field. At the very least, we should probably have META_GRAB_OP_CLICKING_FRAME_CONTROL and then have a separate field.

  * Compositor grab. Keybindings should act like "normal mode", and we shouldn't filter out events from the compositor, but we should not replay them to clients. We take a keyboard/pointer grab to ensure this under X11, and simply test against GRAB_OP_NONE under Wayland/XWayland.

  * Wayland pointer grab. This was a new addition from me, and refers to the type of grab that we use for Wayland popups. The only rule is that all Wayland events must go to the grabbed client, in owner-events mode. As far as I'm aware, we're allowed to make our own rules about keybindings activating and other behaviors.

So, we have a number of different policies based on the current grab op:

  Q: Should we "react" to mouse operations? e.g. if we click on a window while we have a grab, should we raise and focus it? Same for enter/leave events in a mouse focus mode.
  A: Right now, we react in all modes but a compositor grab and a Wayland popup grab. This is currently handled with the grab_op_should_block_mouse_events function in display.c, along with code that checks it in meta_display_handle_event.

  Q: Should we send events to the compositor?
  A: Right now the policy is a bit complicated. We always route events to the compositor if we have a compositor grab, of course, but not if we have a Wayland popup grab, and if we handle something inside mutter, like a mouse op / keybinding, we also skip the compositor. This is implemented with the bypass_clutter variable in meta_display_handle_event.

  Q: Should we send events to clients? Either Wayland or XWayland?
  A: If somebody (either an X client or a Wayland client) has a grab, always deliver events to them. "Yes" in normal mode as well. "No" in move/resize, though some may disagree. "No" in compositor grab mode. Frame control clicking is a bit complicated, since we have to route through XWayland for them. This is implemented with the bypass_wayland variable in meta_display_handle_event.

  Q: Should keybindings be allowed?
  A: I'm not sure what the policy should be here. Obviously in normal mode or compositor grab mode, we should always activate keybindings, but what about resizing / frame controls / Wayland grabs? I think we have to decide our own policy here. This is implemented with a variety of fancy custom code in keybindings.c, along with Florian's filter_keybinding plugin vfunc, although that's somewhat orthogonal.

Ideally, this would all be managed centrally in a place like display.c, instead of split between compositor.c and meta-wayland-surface.c, but I understand that we have various silly architectural issues like "core/ isn't supposed to know that Clutter exists at all, and has no idea what a ClutterStage is".

There's also lots of code that checks meta_op_is_moving to implement that whole state machine. Again, ideally, grab_op would simply be used to route events instead of also drive an state machine about moving/resizing.

So, instead of meta_grab_op_is_wayland / meta_grab_op_is_clicking, I'd prefer to see something based in terms of these policies. Something along the lines of grab_op_should_block_mouse_events (which is also a bad name for what it does, I admit).
Comment 26 Rui Matos 2014-03-20 16:17:51 UTC
Pushing for now as discussed on IRC. Jasper has a WIP patch to address
comment 25.

Attachment 272089 [details] pushed as 1b29113 - wayland: Set/unset wayland focus on mutter grab/ungrab operations
Attachment 272199 [details] pushed as 8968501 - wayland-seat: Don't send pointer enter/leave events during a GRAB_OP
Attachment 272201 [details] pushed as 76dc0ca - wayland: Exempt CLICKING grab ops when syncing wayland input focus