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);