[mutter/wayland] wayland: implement support for plugin modality



commit 7eb4bfbea3705bd46b24f83a7b899aef863d68aa
Author: Giovanni Campagna <gcampagn redhat com>
Date:   Tue Aug 13 16:51:33 2013 +0200

    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 2156452..8660898 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 <X11/extensions/shape.h>
 #include <X11/extensions/Xcomposite.h>
 
@@ -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 70d29b2..ef7c207 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 e092366..57d7a87 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 49ac2ec..758d60a 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 a1e5f38..db6d3bf 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);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]