[mutter/wip/wayland-work: 36/42] wayland: implement global and window keybindings



commit 21402ad3c505fbd551237dc28eaf7d61f448275d
Author: Giovanni Campagna <gcampagn redhat com>
Date:   Thu Aug 15 18:58:48 2013 +0200

    wayland: implement global and window keybindings
    
    Synthetize XInput events from ClutterEvents in MetaWaylandKeyboard,
    and pass them to the keybindings infrastructure for early handling,
    so that we can activate them even if the currently focused window
    is not an X11 one (or if there is no focused window, or we're
    modal)
    
    https://bugzilla.gnome.org/show_bug.cgi?id=706963

 src/core/display.c                  |    4 +-
 src/core/keybindings.c              |   46 ++++++++++++--------
 src/wayland/meta-wayland-keyboard.c |   81 +++++++++++++++++++++++++++++++++++
 3 files changed, 112 insertions(+), 19 deletions(-)
---
diff --git a/src/core/display.c b/src/core/display.c
index 6f47023..85e7f34 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -3197,7 +3197,9 @@ event_callback (XEvent  *event,
      translation altogether by directly using the Clutter events */
   if (meta_is_wayland_compositor () &&
       event->type == GenericEvent &&
-      event->xcookie.evtype == XI_Motion)
+      (event->xcookie.evtype == XI_Motion ||
+       event->xcookie.evtype == XI_KeyPress ||
+       event->xcookie.evtype == XI_KeyRelease))
     return FALSE;
 
   return meta_display_handle_event (display, event);
diff --git a/src/core/keybindings.c b/src/core/keybindings.c
index c95470e..9c2de29 100644
--- a/src/core/keybindings.c
+++ b/src/core/keybindings.c
@@ -2065,22 +2065,22 @@ meta_display_process_key_event (MetaDisplay   *display,
   gboolean handled;
   const char *str;
   MetaScreen *screen;
+  gboolean was_current_time;
 
-  /* if key event was on root window, we have a shortcut */
-  screen = meta_display_screen_for_root (display, event->event);
-
-  /* else round-trip to server */
-  if (screen == NULL)
-    screen = meta_display_screen_for_xwindow (display, event->event);
-
-  if (screen == NULL)
-    return FALSE; /* event window is destroyed */
+  /* We only ever have one screen */
+  screen = display->screens->data;
 
   /* ignore key events on popup menus and such. */
   if (meta_ui_window_is_widget (screen->ui, event->event))
     return FALSE;
 
-  /* window may be NULL */
+  if (display->current_time == CurrentTime)
+    {
+      display->current_time = event->time;
+      was_current_time = TRUE;
+    }
+  else
+    was_current_time = FALSE;
 
   keysym = XKeycodeToKeysym (display->xdisplay, event->detail, 0);
 
@@ -2098,11 +2098,11 @@ meta_display_process_key_event (MetaDisplay   *display,
     {
       handled = process_overlay_key (display, screen, event, keysym);
       if (handled)
-        return TRUE;
+        goto out;
 
       handled = process_iso_next_group (display, screen, event, keysym);
       if (handled)
-        return TRUE;
+        goto out;
     }
 
   XIAllowEvents (display->xdisplay, event->deviceid,
@@ -2112,7 +2112,11 @@ meta_display_process_key_event (MetaDisplay   *display,
   if (all_keys_grabbed)
     {
       if (display->grab_op == META_GRAB_OP_NONE)
-        return TRUE;
+        {
+          handled = TRUE;
+          goto out;
+        }
+
       /* If we get here we have a global grab, because
        * we're in some special keyboard mode such as window move
        * mode.
@@ -2191,14 +2195,20 @@ meta_display_process_key_event (MetaDisplay   *display,
           meta_display_end_grab_op (display, event->time);
         }
 
-      return TRUE;
+      handled = TRUE;
+      goto out;
     }
 
   /* Do the normal keybindings */
-  return process_event (display->key_bindings,
-                        display->n_key_bindings,
-                        display, screen, window, event, keysym,
-                        !all_keys_grabbed && window);
+  handled = process_event (display->key_bindings,
+                           display->n_key_bindings,
+                           display, screen, window, event, keysym,
+                           !all_keys_grabbed && window);
+
+ out:
+  if (was_current_time)
+    display->current_time = CurrentTime;
+  return handled;
 }
 
 static gboolean
diff --git a/src/wayland/meta-wayland-keyboard.c b/src/wayland/meta-wayland-keyboard.c
index 944a2fb..5891863 100644
--- a/src/wayland/meta-wayland-keyboard.c
+++ b/src/wayland/meta-wayland-keyboard.c
@@ -388,6 +388,83 @@ set_modifiers (MetaWaylandKeyboard *keyboard,
                               new_state.group);
 }
 
+#define N_BUTTONS 5
+
+static gboolean
+process_keybinding (MetaWaylandKeyboard   *keyboard,
+                   const ClutterEvent    *event)
+{
+  MetaWaylandSurface *surface;
+  XGenericEventCookie generic_event;
+  XIDeviceEvent device_event;
+  unsigned char button_mask[(N_BUTTONS + 7) / 8] = { 0 };
+  MetaDisplay *display = meta_get_display ();
+  ClutterModifierType button_state;
+  int i;
+
+  if (!display) /* not initialized yet */
+    return FALSE;
+
+  generic_event.type = GenericEvent;
+  generic_event.serial = 0;
+  generic_event.send_event = False;
+  generic_event.display = display->xdisplay;
+  generic_event.extension = display->xinput_opcode;
+  if (clutter_event_type (event) == CLUTTER_KEY_PRESS)
+    generic_event.evtype = XI_KeyPress;
+  else
+    generic_event.evtype = XI_KeyRelease;
+  /* Mutter assumes the data for the event is already retrieved by GDK
+   * so we don't need the cookie */
+  generic_event.cookie = 0;
+  generic_event.data = &device_event;
+
+  memcpy (&device_event, &generic_event, sizeof (XGenericEvent));
+
+  /* Can't use clutter_event_get_time() here, because evdev timestamps
+     have nothing to do with X timestamps */
+  device_event.time = meta_display_get_current_time_roundtrip (display);
+  device_event.deviceid = clutter_event_get_device_id (event);
+  device_event.sourceid = 0; /* not used, not sure what this should be */
+  device_event.detail = clutter_event_get_key_code (event);
+  device_event.root = DefaultRootWindow (display->xdisplay);
+  device_event.flags = 0;
+
+  surface = keyboard->focus;
+  if (surface)
+    device_event.event = surface->window ? surface->window->xwindow : device_event.root;
+  else
+    device_event.event = device_event.root;
+
+  /* Mutter doesn't really know about the sub-windows. This assumes it
+     doesn't care either */
+  device_event.child = device_event.event;
+  device_event.root_x = 0;
+  device_event.root_y = 0;
+
+  clutter_event_get_state_full (event,
+                               &button_state,
+                               (ClutterModifierType*)&device_event.mods.base,
+                               (ClutterModifierType*)&device_event.mods.latched,
+                               (ClutterModifierType*)&device_event.mods.locked,
+                               (ClutterModifierType*)&device_event.mods.effective);
+  device_event.mods.effective &= ~button_state;
+  memset (&device_event.group, 0, sizeof (device_event.group));
+  device_event.group.effective = (device_event.mods.effective >> 13) & 0x3;
+
+  for (i = 0; i < N_BUTTONS; i++)
+    if ((button_state & (CLUTTER_BUTTON1_MASK << i)))
+      XISetMask (button_mask, i + 1);
+  device_event.buttons.mask_len = N_BUTTONS + 1;
+  device_event.buttons.mask = button_mask;
+
+  device_event.valuators.mask_len = 0;
+  device_event.valuators.mask = NULL;
+  device_event.valuators.values = NULL;
+
+  return meta_display_process_key_event (display, surface ? surface->window : NULL, &device_event);
+}
+
 static gboolean
 update_pressed_keys (MetaWaylandKeyboard   *keyboard,
                     uint32_t               evdev_code,
@@ -460,6 +537,10 @@ meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
                autorepeat ? " (autorepeat)" : "",
                xkb_keycode);
 
+  /* Give a chance to process keybindings */
+  if (process_keybinding (keyboard, (ClutterEvent*) event))
+    return TRUE;
+
   if (autorepeat)
     return FALSE;
 


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