From 7eb4bfbea3705bd46b24f83a7b899aef863d68aa Mon Sep 17 00:00:00 2001 From: Giovanni Campagna Date: Tue, 13 Aug 2013 16:51:33 +0200 Subject: [PATCH] wayland: implement support for plugin modality Calling XIGrabDevice has no effect under wayland, because the xserver is getting events from us. Instead, we need to use our own interfaces for grabs. At the same time, we can simplify the public API, as plugins should always listen for events using clutter. https://bugzilla.gnome.org/show_bug.cgi?id=705917 --- src/compositor/compositor.c | 139 ++++++++++++++++++++-------- src/wayland/meta-wayland-keyboard.c | 122 ++++++++++++++++++++++-- src/wayland/meta-wayland-keyboard.h | 7 ++ src/wayland/meta-wayland-pointer.c | 62 +++++++++++++ src/wayland/meta-wayland-pointer.h | 5 + 5 files changed, 291 insertions(+), 44 deletions(-) diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c index 215645265..866089861 100644 --- a/src/compositor/compositor.c +++ b/src/compositor/compositor.c @@ -85,6 +85,8 @@ #include "window-private.h" /* to check window->hidden */ #include "display-private.h" /* for meta_display_lookup_x_window() */ #include "meta-wayland-private.h" +#include "meta-wayland-pointer.h" +#include "meta-wayland-keyboard.h" #include #include @@ -424,34 +426,20 @@ meta_stage_is_focused (MetaScreen *screen) return (screen->display->focus_type == META_FOCUS_STAGE); } -gboolean -meta_begin_modal_for_plugin (MetaScreen *screen, - MetaPlugin *plugin, - MetaModalOptions options, - guint32 timestamp) +static gboolean +begin_modal_x11 (MetaScreen *screen, + MetaPlugin *plugin, + MetaModalOptions options, + guint32 timestamp) { - /* To some extent this duplicates code in meta_display_begin_grab_op(), but there - * are significant differences in how we handle grabs that make it difficult to - * merge the two. - */ - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdpy = meta_display_get_xdisplay (display); - MetaCompositor *compositor = display->compositor; - ClutterStage *stage; - Window grab_window; - Cursor cursor = None; - gboolean pointer_grabbed = FALSE; - gboolean keyboard_grabbed = FALSE; - int result; - - stage = CLUTTER_STAGE (meta_get_stage_for_screen (screen)); - if (!stage) - return FALSE; - - grab_window = clutter_x11_get_stage_window (stage); - - if (compositor->modal_plugin != NULL || display->grab_op != META_GRAB_OP_NONE) - return FALSE; + MetaDisplay *display = meta_screen_get_display (screen); + Display *xdpy = meta_display_get_xdisplay (display); + MetaCompScreen *info = meta_screen_get_compositor_data (screen); + Window grab_window = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage)); + Cursor cursor = None; + int result; + gboolean pointer_grabbed = FALSE; + gboolean keyboard_grabbed = FALSE; if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0) { @@ -501,14 +489,6 @@ meta_begin_modal_for_plugin (MetaScreen *screen, keyboard_grabbed = TRUE; } - display->grab_op = META_GRAB_OP_COMPOSITOR; - display->grab_window = NULL; - display->grab_screen = screen; - display->grab_have_pointer = TRUE; - display->grab_have_keyboard = TRUE; - - compositor->modal_plugin = plugin; - return TRUE; fail: @@ -520,6 +500,80 @@ meta_begin_modal_for_plugin (MetaScreen *screen, return FALSE; } +static gboolean +begin_modal_wayland (MetaScreen *screen, + MetaPlugin *plugin, + MetaModalOptions options, + guint32 timestamp) +{ + MetaWaylandCompositor *compositor; + gboolean pointer_grabbed = FALSE; + gboolean keyboard_grabbed = FALSE; + + compositor = meta_wayland_compositor_get_default (); + + if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0) + { + if (!meta_wayland_pointer_begin_modal (&compositor->seat->pointer)) + goto fail; + + pointer_grabbed = TRUE; + } + if ((options & META_MODAL_KEYBOARD_ALREADY_GRABBED) == 0) + { + if (!meta_wayland_keyboard_begin_modal (&compositor->seat->keyboard, + timestamp)) + goto fail; + + keyboard_grabbed = TRUE; + } + + return TRUE; + + fail: + if (pointer_grabbed) + meta_wayland_pointer_end_modal (&compositor->seat->pointer); + if (keyboard_grabbed) + meta_wayland_keyboard_end_modal (&compositor->seat->keyboard, timestamp); + + return FALSE; +} + +gboolean +meta_begin_modal_for_plugin (MetaScreen *screen, + MetaPlugin *plugin, + MetaModalOptions options, + guint32 timestamp) +{ + /* To some extent this duplicates code in meta_display_begin_grab_op(), but there + * are significant differences in how we handle grabs that make it difficult to + * merge the two. + */ + MetaDisplay *display = meta_screen_get_display (screen); + MetaCompositor *compositor = display->compositor; + gboolean ok; + + if (compositor->modal_plugin != NULL || display->grab_op != META_GRAB_OP_NONE) + return FALSE; + + if (meta_is_wayland_compositor ()) + ok = begin_modal_wayland (screen, plugin, options, timestamp); + else + ok = begin_modal_x11 (screen, plugin, options, timestamp); + if (!ok) + return FALSE; + + display->grab_op = META_GRAB_OP_COMPOSITOR; + display->grab_window = NULL; + display->grab_screen = screen; + display->grab_have_pointer = TRUE; + display->grab_have_keyboard = TRUE; + + compositor->modal_plugin = plugin; + + return TRUE; +} + void meta_end_modal_for_plugin (MetaScreen *screen, MetaPlugin *plugin, @@ -531,8 +585,19 @@ meta_end_modal_for_plugin (MetaScreen *screen, g_return_if_fail (compositor->modal_plugin == plugin); - XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp); - XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp); + if (meta_is_wayland_compositor ()) + { + MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); + + meta_wayland_pointer_end_modal (&compositor->seat->pointer); + meta_wayland_keyboard_end_modal (&compositor->seat->keyboard, + timestamp); + } + else + { + XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp); + XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp); + } display->grab_op = META_GRAB_OP_NONE; display->grab_window = NULL; diff --git a/src/wayland/meta-wayland-keyboard.c b/src/wayland/meta-wayland-keyboard.c index 70d29b261..ef7c2071f 100644 --- a/src/wayland/meta-wayland-keyboard.c +++ b/src/wayland/meta-wayland-keyboard.c @@ -274,6 +274,29 @@ static const MetaWaylandKeyboardGrabInterface default_grab_modifiers, }; +static void +modal_key (MetaWaylandKeyboardGrab *grab, + uint32_t time, + uint32_t key, + uint32_t state) +{ +} + +static void +modal_modifiers (MetaWaylandKeyboardGrab *grab, + uint32_t serial, + uint32_t mods_depressed, + uint32_t mods_latched, + uint32_t mods_locked, + uint32_t group) +{ +} + +static MetaWaylandKeyboardGrabInterface modal_grab = { + modal_key, + modal_modifiers, +}; + gboolean meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard, struct wl_display *display, @@ -515,13 +538,29 @@ meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard, display = wl_client_get_display (client); serial = wl_display_next_serial (display); - wl_keyboard_send_modifiers (resource, serial, - keyboard->modifier_state.mods_depressed, - keyboard->modifier_state.mods_latched, - keyboard->modifier_state.mods_locked, - keyboard->modifier_state.group); - wl_keyboard_send_enter (resource, serial, surface->resource, - &keyboard->keys); + + /* If we're in a modal grab, the client is focused but doesn't see + modifiers or pressed keys (and fix that up when we exit the modal) */ + if (keyboard->grab->interface == &modal_grab) + { + struct wl_array empty; + wl_array_init (&empty); + + wl_keyboard_send_modifiers (resource, serial, + 0, 0, 0, 0); + wl_keyboard_send_enter (resource, serial, surface->resource, + &empty); + } + else + { + wl_keyboard_send_modifiers (resource, serial, + keyboard->modifier_state.mods_depressed, + keyboard->modifier_state.mods_latched, + keyboard->modifier_state.mods_locked, + keyboard->modifier_state.group); + wl_keyboard_send_enter (resource, serial, surface->resource, + &keyboard->keys); + } wl_resource_add_destroy_listener (resource, &keyboard->focus_listener); keyboard->focus_serial = serial; } @@ -565,3 +604,72 @@ meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard) wl_list_remove (&keyboard->focus_listener.link); wl_array_release (&keyboard->keys); } + +gboolean +meta_wayland_keyboard_begin_modal (MetaWaylandKeyboard *keyboard, + guint32 timestamp) +{ + MetaWaylandKeyboardGrab *grab; + uint32_t *end = (void *) ((char *) keyboard->keys.data + + keyboard->keys.size); + uint32_t *k; + uint32_t serial; + + if (keyboard->grab != &keyboard->default_grab) + return FALSE; + + if (keyboard->focus) + { + /* Fake key release events for the focused app */ + serial = wl_display_next_serial (keyboard->display); + keyboard->grab->interface->modifiers (keyboard->grab, + serial, + 0, 0, 0, 0); + + for (k = keyboard->keys.data; k < end; k++) + keyboard->grab->interface->key (keyboard->grab, + timestamp, + *k, 0); + } + + grab = g_slice_new0 (MetaWaylandKeyboardGrab); + grab->interface = &modal_grab; + meta_wayland_keyboard_start_grab (keyboard, grab); + + return TRUE; +} + +void +meta_wayland_keyboard_end_modal (MetaWaylandKeyboard *keyboard, + guint32 timestamp) +{ + MetaWaylandKeyboardGrab *grab; + uint32_t *end = (void *) ((char *) keyboard->keys.data + + keyboard->keys.size); + uint32_t *k; + uint32_t serial; + + grab = keyboard->grab; + + g_assert (grab->interface == &modal_grab); + + meta_wayland_keyboard_end_grab (keyboard); + g_slice_free (MetaWaylandKeyboardGrab, grab); + + if (keyboard->focus) + { + /* Fake key press events for the focused app */ + serial = wl_display_next_serial (keyboard->display); + keyboard->grab->interface->modifiers (keyboard->grab, + serial, + keyboard->modifier_state.mods_depressed, + keyboard->modifier_state.mods_latched, + keyboard->modifier_state.mods_locked, + keyboard->modifier_state.group); + + for (k = keyboard->keys.data; k < end; k++) + keyboard->grab->interface->key (keyboard->grab, + timestamp, + *k, 1); + } +} diff --git a/src/wayland/meta-wayland-keyboard.h b/src/wayland/meta-wayland-keyboard.h index e092366b9..57d7a878b 100644 --- a/src/wayland/meta-wayland-keyboard.h +++ b/src/wayland/meta-wayland-keyboard.h @@ -70,6 +70,13 @@ meta_wayland_keyboard_start_grab (MetaWaylandKeyboard *device, void meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard); +gboolean +meta_wayland_keyboard_begin_modal (MetaWaylandKeyboard *keyboard, + guint32 timestamp); +void +meta_wayland_keyboard_end_modal (MetaWaylandKeyboard *keyboard, + guint32 timestamp); + void meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard); diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c index 49ac2ec98..758d60a85 100644 --- a/src/wayland/meta-wayland-pointer.c +++ b/src/wayland/meta-wayland-pointer.c @@ -262,3 +262,65 @@ meta_wayland_pointer_set_current (MetaWaylandPointer *pointer, &pointer->current_listener); pointer->current_listener.notify = current_surface_destroy; } + +static void +modal_focus (MetaWaylandPointerGrab *grab, + MetaWaylandSurface *surface, + wl_fixed_t x, + wl_fixed_t y) +{ +} + +static void +modal_motion (MetaWaylandPointerGrab *grab, + uint32_t time, + wl_fixed_t x, + wl_fixed_t y) +{ +} + +static void +modal_button (MetaWaylandPointerGrab *grab, + uint32_t time, + uint32_t button, + uint32_t state) +{ +} + +static MetaWaylandPointerGrabInterface modal_grab = { + modal_focus, + modal_motion, + modal_button +}; + +gboolean +meta_wayland_pointer_begin_modal (MetaWaylandPointer *pointer) +{ + MetaWaylandPointerGrab *grab; + + if (pointer->grab != &pointer->default_grab) + return FALSE; + + meta_wayland_pointer_set_focus (pointer, NULL, + wl_fixed_from_int (0), + wl_fixed_from_int (0)); + + grab = g_slice_new0 (MetaWaylandPointerGrab); + grab->interface = &modal_grab; + meta_wayland_pointer_start_grab (pointer, grab); + + return TRUE; +} + +void +meta_wayland_pointer_end_modal (MetaWaylandPointer *pointer) +{ + MetaWaylandPointerGrab *grab; + + grab = pointer->grab; + + g_assert (grab->interface == &modal_grab); + + meta_wayland_pointer_end_grab (pointer); + g_slice_free (MetaWaylandPointerGrab, grab); +} diff --git a/src/wayland/meta-wayland-pointer.h b/src/wayland/meta-wayland-pointer.h index a1e5f3854..db6d3bf9b 100644 --- a/src/wayland/meta-wayland-pointer.h +++ b/src/wayland/meta-wayland-pointer.h @@ -42,6 +42,11 @@ meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer, void meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer); +gboolean +meta_wayland_pointer_begin_modal (MetaWaylandPointer *pointer); +void +meta_wayland_pointer_end_modal (MetaWaylandPointer *pointer); + void meta_wayland_pointer_set_current (MetaWaylandPointer *pointer, MetaWaylandSurface *surface);