[mutter/wip/wayland-work: 13/20] wayland: reimplement keyboard state handling properly



commit c66bf93ccae65578ef58fd95f6ed393ed44bdf32
Author: Giovanni Campagna <gcampagn redhat com>
Date:   Wed Sep 4 15:01:11 2013 +0200

    wayland: reimplement keyboard state handling properly
    
    We can't rely on clutter's xkb_state, because that's updated
    when events are pulled from the kernel, not when we see them.
    Instead, use the new clutter API to get the full modifier state
    from the event (which, as a side effect, also works when clutter
    is using the X11 backend for running nested).
    
    https://bugzilla.gnome.org/show_bug.cgi?id=706963

 src/wayland/meta-wayland-keyboard.c |  223 ++++++++++++++++-------------------
 src/wayland/meta-wayland-keyboard.h |    6 +-
 src/wayland/meta-wayland.c          |   22 ++--
 3 files changed, 114 insertions(+), 137 deletions(-)
---
diff --git a/src/wayland/meta-wayland-keyboard.c b/src/wayland/meta-wayland-keyboard.c
index 90182ed..494d9f8 100644
--- a/src/wayland/meta-wayland-keyboard.c
+++ b/src/wayland/meta-wayland-keyboard.c
@@ -202,7 +202,7 @@ lose_keyboard_focus (struct wl_listener *listener, void *data)
   keyboard->focus_resource = NULL;
 }
 
-static void
+static gboolean
 default_grab_key (MetaWaylandKeyboardGrab *grab,
                   uint32_t time, uint32_t key, uint32_t state)
 {
@@ -218,6 +218,8 @@ default_grab_key (MetaWaylandKeyboardGrab *grab,
       serial = wl_display_next_serial (display);
       wl_keyboard_send_key (resource, serial, time, key, state);
     }
+
+  return resource != NULL;
 }
 
 static struct wl_resource *
@@ -274,12 +276,14 @@ static const MetaWaylandKeyboardGrabInterface
   default_grab_modifiers,
 };
 
-static void
+static gboolean
 modal_key (MetaWaylandKeyboardGrab *grab,
           uint32_t                 time,
           uint32_t                 key,
           uint32_t                 state)
 {
+  /* FALSE means: let the event through to clutter */
+  return FALSE;
 }
 
 static void
@@ -328,12 +332,6 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
       manager = clutter_device_manager_get_default ();
 
       clutter_evdev_set_keyboard_map (manager, keyboard->xkb_info.keymap);
-      keyboard->xkb_state = clutter_evdev_get_keyboard_state (manager);
-      xkb_state_ref (keyboard->xkb_state);
-    }
-  else
-    {
-      keyboard->xkb_state = xkb_state_new (keyboard->xkb_info.keymap);
     }
 
   return TRUE;
@@ -351,52 +349,6 @@ meta_wayland_xkb_info_destroy (MetaWaylandXkbInfo *xkb_info)
     close (xkb_info->keymap_fd);
 }
 
-static void
-update_state_from_clutter (MetaWaylandKeyboard *keyboard,
-                          ClutterModifierType  modifier_state)
-{
-  uint32_t depressed_mods = 0;
-  uint32_t locked_mods = 0;
-
-  if ((modifier_state & CLUTTER_SHIFT_MASK) &&
-      keyboard->xkb_info.shift_mod != XKB_MOD_INVALID)
-    depressed_mods |= (1 << keyboard->xkb_info.shift_mod);
-
-  if ((modifier_state & CLUTTER_LOCK_MASK) &&
-      keyboard->xkb_info.caps_mod != XKB_MOD_INVALID)
-    locked_mods |= (1 << keyboard->xkb_info.caps_mod);
-
-  if ((modifier_state & CLUTTER_CONTROL_MASK) &&
-      keyboard->xkb_info.ctrl_mod != XKB_MOD_INVALID)
-    depressed_mods |= (1 << keyboard->xkb_info.ctrl_mod);
-
-  if ((modifier_state & CLUTTER_MOD1_MASK) &&
-      keyboard->xkb_info.alt_mod != XKB_MOD_INVALID)
-    depressed_mods |= (1 << keyboard->xkb_info.alt_mod);
-
-  if ((modifier_state & CLUTTER_MOD2_MASK) &&
-      keyboard->xkb_info.mod2_mod != XKB_MOD_INVALID)
-    depressed_mods |= (1 << keyboard->xkb_info.mod2_mod);
-
-  if ((modifier_state & CLUTTER_MOD3_MASK) &&
-      keyboard->xkb_info.mod3_mod != XKB_MOD_INVALID)
-    depressed_mods |= (1 << keyboard->xkb_info.mod3_mod);
-
-  if ((modifier_state & CLUTTER_SUPER_MASK) &&
-      keyboard->xkb_info.super_mod != XKB_MOD_INVALID)
-    depressed_mods |= (1 << keyboard->xkb_info.super_mod);
-
-  if ((modifier_state & CLUTTER_MOD5_MASK) &&
-      keyboard->xkb_info.mod5_mod != XKB_MOD_INVALID)
-    depressed_mods |= (1 << keyboard->xkb_info.mod5_mod);
-
-  xkb_state_update_mask (keyboard->xkb_state,
-                        depressed_mods,
-                        0,
-                        locked_mods,
-                        0, 0, 0);
-}
-
 static gboolean
 state_equal (MetaWaylandXkbState *one,
             MetaWaylandXkbState *two)
@@ -409,25 +361,20 @@ state_equal (MetaWaylandXkbState *one,
 
 static void
 set_modifiers (MetaWaylandKeyboard *keyboard,
-               guint32 serial,
-               ClutterModifierType modifier_state)
+               guint32              serial,
+               ClutterEvent        *event)
 {
   MetaWaylandKeyboardGrab *grab = keyboard->grab;
   MetaWaylandXkbState new_state;
+  guint effective_state;
 
-  /* In the evdev case, the state is shared with the clutter backend, so
-     we don't need to update it */
-  if (!keyboard->is_evdev)
-    update_state_from_clutter (keyboard, modifier_state);
-
-  new_state.mods_depressed = xkb_state_serialize_mods (keyboard->xkb_state,
-                                                      XKB_STATE_MODS_DEPRESSED);
-  new_state.mods_latched = xkb_state_serialize_mods (keyboard->xkb_state,
-                                                    XKB_STATE_MODS_LATCHED);
-  new_state.mods_locked = xkb_state_serialize_mods (keyboard->xkb_state,
-                                                   XKB_STATE_MODS_LOCKED);
-  new_state.group = xkb_state_serialize_layout (keyboard->xkb_state,
-                                               XKB_STATE_LAYOUT_EFFECTIVE);
+  clutter_event_get_state_full (event,
+                               NULL,
+                               &new_state.mods_depressed,
+                               &new_state.mods_latched,
+                               &new_state.mods_locked,
+                               &effective_state);
+  new_state.group = (effective_state >> 13) & 0x3;
 
   if (state_equal (&keyboard->modifier_state, &new_state))
     return;
@@ -453,7 +400,7 @@ process_keybinding (MetaWaylandKeyboard   *keyboard,
   XIDeviceEvent device_event;
   unsigned char button_mask[(N_BUTTONS + 7) / 8] = { 0 };
   MetaDisplay *display = meta_get_display ();
-  ClutterModifierType state;
+  ClutterModifierType button_state;
   int i;
 
   if (!display) /* not initialized yet */
@@ -496,10 +443,18 @@ process_keybinding (MetaWaylandKeyboard   *keyboard,
   device_event.root_x = 0;
   device_event.root_y = 0;
 
-  state = clutter_event_get_state (event);
+  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 ((state & (CLUTTER_BUTTON1_MASK << 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;
@@ -508,53 +463,27 @@ process_keybinding (MetaWaylandKeyboard   *keyboard,
   device_event.valuators.mask = NULL;
   device_event.valuators.values = NULL;
 
-  device_event.mods.base = xkb_state_serialize_mods (keyboard->xkb_state,
-                                                      XKB_STATE_MODS_DEPRESSED);
-  device_event.mods.latched = xkb_state_serialize_mods (keyboard->xkb_state,
-                                                       XKB_STATE_MODS_LATCHED);
-  device_event.mods.locked = xkb_state_serialize_mods (keyboard->xkb_state,
-                                                      XKB_STATE_MODS_LOCKED);
-  device_event.mods.effective = xkb_state_serialize_mods (keyboard->xkb_state,
-                                                         XKB_STATE_MODS_EFFECTIVE);
-  memset (&device_event.group, 0, sizeof (device_event.group));
-
   return meta_display_process_key_event (display, surface ? surface->window : NULL, &device_event);
 }
 
-gboolean
-meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
-                                    const ClutterKeyEvent *event)
+static gboolean
+update_pressed_keys (MetaWaylandKeyboard   *keyboard,
+                    uint32_t               evdev_code,
+                    gboolean               is_press)
 {
-  gboolean state = event->type == CLUTTER_KEY_PRESS;
-  guint evdev_code;
-  uint32_t serial;
-
-  /* We can't do anything with the event if we can't get an evdev
-     keycode for it */
-  if (event->device == NULL ||
-      !clutter_input_device_keycode_to_evdev (event->device,
-                                              event->hardware_keycode,
-                                              &evdev_code))
-    return FALSE;
-
-  /* Give a chance to process keybindings */
-  if (process_keybinding (keyboard, (ClutterEvent*) event))
-    return TRUE;
-
-  /* We want to ignore events that are sent because of auto-repeat. In
-     the Clutter event stream these appear as a single key press
-     event. We can detect that because the key will already have been
-     pressed */
-  if (state)
+  if (is_press)
     {
       uint32_t *end = (void *) ((char *) keyboard->keys.data +
                                 keyboard->keys.size);
       uint32_t *k;
 
-      /* Ignore the event if the key is already down */
+      /* We want to ignore events that are sent because of auto-repeat. In
+        the Clutter event stream these appear as a single key press
+        event. We can detect that because the key will already have been
+        pressed */
       for (k = keyboard->keys.data; k < end; k++)
         if (*k == evdev_code)
-          return FALSE;
+          return TRUE;
 
       /* Otherwise add the key to the list of pressed keys */
       k = wl_array_add (&keyboard->keys, sizeof (*k));
@@ -577,20 +506,61 @@ meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
           }
 
       g_warning ("unexpected key release event for key 0x%x", evdev_code);
+      return FALSE;
 
     found:
       (void) 0;
     }
 
+  return FALSE;
+}
+gboolean
+meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
+                                    const ClutterKeyEvent *event)
+{
+  gboolean is_press = event->type == CLUTTER_KEY_PRESS;
+  guint xkb_keycode, evdev_code;
+  uint32_t serial;
+  gboolean autorepeat;
+  gboolean handled;
+
+  xkb_keycode = event->hardware_keycode;
+  if (event->device == NULL ||
+      !clutter_input_device_keycode_to_evdev (event->device,
+                                             xkb_keycode, &evdev_code))
+    evdev_code = xkb_keycode - 8; /* What everyone is doing in practice... */
+
+  autorepeat = update_pressed_keys (keyboard, evdev_code, is_press);
+
+  meta_verbose ("Handling key %s%s event code %d\n",
+               is_press ? "press" : "release",
+               autorepeat ? " (autorepeat)" : "",
+               xkb_keycode);
+
+  /* Give a chance to process keybindings */
+  if (process_keybinding (keyboard, (ClutterEvent*) event))
+    return TRUE;
+
+  meta_verbose ("Keybindings ignored the previous event\n");
+
+  if (autorepeat)
+    return FALSE;
+
   serial = wl_display_next_serial (keyboard->display);
 
-  set_modifiers (keyboard, serial, event->modifier_state);
+  set_modifiers (keyboard, serial, (ClutterEvent*)event);
 
-  keyboard->grab->interface->key (keyboard->grab,
-                                  event->time,
-                                  evdev_code,
-                                  state);
-  return FALSE;
+  handled = keyboard->grab->interface->key (keyboard->grab,
+                                           event->time,
+                                           evdev_code,
+                                           is_press);
+
+  if (handled)
+    meta_verbose ("Sent event to wayland client\n");
+  else
+    meta_verbose ("No wayland surface is focused, continuing normal operation\n");
+
+  return handled;
 }
 
 void
@@ -681,7 +651,6 @@ meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard)
 
   meta_wayland_xkb_info_destroy (&keyboard->xkb_info);
   xkb_context_unref (keyboard->xkb_context);
-  xkb_state_unref (keyboard->xkb_state);
 
   /* XXX: What about keyboard->resource_list? */
   if (keyboard->focus_resource)
@@ -699,8 +668,10 @@ meta_wayland_keyboard_begin_modal (MetaWaylandKeyboard *keyboard,
   uint32_t *k;
   uint32_t serial;
 
+  meta_verbose ("Asked to acquire modal keyboard grab, timestamp %d\n", timestamp);
+
   if (keyboard->grab != &keyboard->default_grab)
-    return FALSE; 
+    return FALSE;
 
   if (keyboard->focus)
     {
@@ -711,15 +682,19 @@ meta_wayland_keyboard_begin_modal (MetaWaylandKeyboard *keyboard,
                                            0, 0, 0, 0);
 
       for (k = keyboard->keys.data; k < end; k++)
-       keyboard->grab->interface->key (keyboard->grab,
-                                       timestamp,
-                                       *k, 0);
+       {
+         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);
 
+  meta_verbose ("Acquired modal keyboard grab, timestamp %d\n", timestamp);
+
   return TRUE;
 }
 
@@ -752,8 +727,12 @@ meta_wayland_keyboard_end_modal (MetaWaylandKeyboard *keyboard,
                                            keyboard->modifier_state.group);
 
       for (k = keyboard->keys.data; k < end; k++)
-       keyboard->grab->interface->key (keyboard->grab,
-                                       timestamp,
-                                       *k, 1);
+       {
+         keyboard->grab->interface->key (keyboard->grab,
+                                         timestamp,
+                                         *k, 1);
+       }
     }
+
+  meta_verbose ("Released modal keyboard grab, timestamp %d\n", timestamp);
 }
diff --git a/src/wayland/meta-wayland-keyboard.h b/src/wayland/meta-wayland-keyboard.h
index 7c2a7b7..110363d 100644
--- a/src/wayland/meta-wayland-keyboard.h
+++ b/src/wayland/meta-wayland-keyboard.h
@@ -50,8 +50,8 @@
 
 struct _MetaWaylandKeyboardGrabInterface
 {
-  void (*key) (MetaWaylandKeyboardGrab * grab, uint32_t time,
-               uint32_t key, uint32_t state);
+  gboolean (*key) (MetaWaylandKeyboardGrab * grab, uint32_t time,
+                  uint32_t key, uint32_t state);
   void (*modifiers) (MetaWaylandKeyboardGrab * grab, uint32_t serial,
                      uint32_t mods_depressed, uint32_t mods_latched,
                      uint32_t mods_locked, uint32_t group);
@@ -111,9 +111,7 @@ struct _MetaWaylandKeyboard
   struct wl_display *display;
 
   struct xkb_context *xkb_context;
-  struct xkb_state *xkb_state;
   gboolean is_evdev;
-
   MetaWaylandXkbInfo xkb_info;
   struct xkb_rule_names xkb_names;
 
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index f558900..e95250d 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -548,7 +548,7 @@ synthesize_motion_event (MetaWaylandCompositor *compositor,
   XIDeviceEvent device_event;
   unsigned char button_mask[(N_BUTTONS + 7) / 8] = { 0 };
   MetaDisplay *display = meta_get_display ();
-  ClutterModifierType state;
+  ClutterModifierType button_state;
   int i;
 
   generic_event.type = GenericEvent;
@@ -621,10 +621,18 @@ synthesize_motion_event (MetaWaylandCompositor *compositor,
   device_event.root_x = wl_fixed_to_double (pointer->x);
   device_event.root_y = wl_fixed_to_double (pointer->y);
 
-  state = clutter_event_get_state (event);
+  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 ((state & (CLUTTER_BUTTON1_MASK << 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;
@@ -633,14 +641,6 @@ synthesize_motion_event (MetaWaylandCompositor *compositor,
   device_event.valuators.mask = NULL;
   device_event.valuators.values = NULL;
 
-  memset (&device_event.mods, 0, sizeof (device_event.mods));
-  device_event.mods.effective =
-    state & (CLUTTER_MODIFIER_MASK &
-             ~(((CLUTTER_BUTTON1_MASK << N_BUTTONS) - 1) ^
-               (CLUTTER_BUTTON1_MASK - 1)));
-
-  memset (&device_event.group, 0, sizeof (device_event.group));
-
   meta_display_handle_event (display, (XEvent *) &generic_event);
 }
 


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