[clutter/clutter-1.16] ClutterEvent: add API to query the full keyboard state when the event was generated



commit 59f1e531f9ac0a3e43a7b1aa80019373cf2ac01c
Author: Giovanni Campagna <gcampagn redhat com>
Date:   Wed Sep 4 14:42:56 2013 +0200

    ClutterEvent: add API to query the full keyboard state when the event was generated
    
    When talking to other applications or serializing the modifier
    state (and in particular when implementing a wayland compositor),
    the effective modifier state alone is not sufficient, one needs
    to know the base, latched and locked modifiers.
    
    Previously one could do with backend specific functionality
    such as clutter_device_manager_evdev_get_xkb_state(), but the
    problem is that the internal data structures are updated as
    soon as the events are fetched from the upstream source, but
    the events are reported to the application some time later,
    and thus the two can get out of sync.
    This way, on the other hand, the information is cached in the
    event, and provided to the application with the value that
    was current when the event was generated.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=706494

 clutter/clutter-event-private.h                |    7 +++
 clutter/clutter-event.c                        |   66 +++++++++++++++++++++++-
 clutter/clutter-event.h                        |    7 +++
 clutter/clutter.symbols                        |    1 +
 clutter/evdev/clutter-device-manager-evdev.c   |    9 +--
 clutter/evdev/clutter-xkb-utils.c              |   18 +++++-
 clutter/evdev/clutter-xkb-utils.h              |    3 +
 clutter/wayland/clutter-input-device-wayland.c |    6 +--
 clutter/x11/clutter-device-manager-xi2.c       |   51 +++++++++---------
 clutter/x11/clutter-input-device-xi2.c         |   33 ++++++++----
 clutter/x11/clutter-input-device-xi2.h         |    7 ++-
 11 files changed, 154 insertions(+), 54 deletions(-)
---
diff --git a/clutter/clutter-event-private.h b/clutter/clutter-event-private.h
index eeb1080..955db26 100644
--- a/clutter/clutter-event-private.h
+++ b/clutter/clutter-event-private.h
@@ -19,6 +19,13 @@ void            _clutter_event_set_platform_data        (ClutterEvent       *eve
                                                          gpointer            data);
 gpointer        _clutter_event_get_platform_data        (const ClutterEvent *event);
 
+void            _clutter_event_set_state_full           (ClutterEvent        *event,
+                                                        ClutterModifierType  button_state,
+                                                        ClutterModifierType  base_state,
+                                                        ClutterModifierType  latched_state,
+                                                        ClutterModifierType  locked_state,
+                                                        ClutterModifierType  effective_state);
+
 void            _clutter_event_push                     (const ClutterEvent *event,
                                                          gboolean            do_copy);
 
diff --git a/clutter/clutter-event.c b/clutter/clutter-event.c
index 2547572..2609f8f 100644
--- a/clutter/clutter-event.c
+++ b/clutter/clutter-event.c
@@ -56,6 +56,11 @@ typedef struct _ClutterEventPrivate {
 
   gpointer platform_data;
 
+  ClutterModifierType button_state;
+  ClutterModifierType base_state;
+  ClutterModifierType latched_state;
+  ClutterModifierType locked_state;
+
   guint is_pointer_emulated : 1;
 } ClutterEventPrivate;
 
@@ -178,7 +183,9 @@ clutter_event_set_time (ClutterEvent *event,
  * clutter_event_get_state:
  * @event: a #ClutterEvent
  *
- * Retrieves the modifier state of the event.
+ * Retrieves the modifier state of the event. In case the window system
+ * supports reporting latched and locked modifiers, this function returns
+ * the effective state.
  *
  * Return value: the modifier state parameter, or 0
  *
@@ -265,6 +272,63 @@ clutter_event_set_state (ClutterEvent        *event,
     }
 }
 
+void
+_clutter_event_set_state_full (ClutterEvent        *event,
+                              ClutterModifierType  button_state,
+                              ClutterModifierType  base_state,
+                              ClutterModifierType  latched_state,
+                              ClutterModifierType  locked_state,
+                              ClutterModifierType  effective_state)
+{
+  ClutterEventPrivate *private = (ClutterEventPrivate*) event;
+
+  private->button_state = button_state;
+  private->base_state = base_state;
+  private->latched_state = latched_state;
+  private->locked_state = locked_state;
+
+  clutter_event_set_state (event, effective_state);
+}
+
+/**
+ * clutter_event_get_state_full:
+ * @event: a #ClutterEvent
+ * @button_state: (out) (allow-none): the pressed buttons as a mask
+ * @base_state: (out) (allow-none): the regular pressed modifier keys
+ * @latched_state: (out) (allow-none): the latched modifier keys (currently released but still valid for one 
key press/release)
+ * @locked_state: (out) (allow-none): the locked modifier keys (valid until the lock key is pressed and 
released again)
+ * @effective_state: (out) (allow-none): the logical OR of all the state bits above
+ *
+ * Retrieves the decomposition of the keyboard state into button, base,
+ * latched, locked and effective. This can be used to transmit to other
+ * applications, for example when implementing a wayland compositor.
+ *
+ * Since: 1.16
+ */
+void
+clutter_event_get_state_full (const ClutterEvent  *event,
+                             ClutterModifierType *button_state,
+                             ClutterModifierType *base_state,
+                             ClutterModifierType *latched_state,
+                             ClutterModifierType *locked_state,
+                             ClutterModifierType *effective_state)
+{
+  const ClutterEventPrivate *private = (const ClutterEventPrivate*) event;
+
+  g_return_if_fail (event != NULL);
+
+  if (button_state)
+    *button_state = private->button_state;
+  if (base_state)
+    *base_state = private->base_state;
+  if (latched_state)
+    *latched_state = private->latched_state;
+  if (locked_state)
+    *locked_state = private->locked_state;
+  if (effective_state)
+    *effective_state = clutter_event_get_state (event);
+}
+
 /**
  * clutter_event_get_coords:
  * @event: a #ClutterEvent
diff --git a/clutter/clutter-event.h b/clutter/clutter-event.h
index 65ba151..f83f4ca 100644
--- a/clutter/clutter-event.h
+++ b/clutter/clutter-event.h
@@ -420,6 +420,13 @@ guint32                 clutter_event_get_time                  (const ClutterEv
 void                    clutter_event_set_state                 (ClutterEvent           *event,
                                                                  ClutterModifierType     state);
 ClutterModifierType     clutter_event_get_state                 (const ClutterEvent     *event);
+CLUTTER_AVAILABLE_IN_1_16
+void                    clutter_event_get_state_full            (const ClutterEvent     *event,
+                                                                ClutterModifierType    *button_state,
+                                                                ClutterModifierType    *base_state,
+                                                                ClutterModifierType    *latched_state,
+                                                                ClutterModifierType    *locked_state,
+                                                                ClutterModifierType    *effective_state);
 void                    clutter_event_set_device                (ClutterEvent           *event,
                                                                  ClutterInputDevice     *device);
 ClutterInputDevice *    clutter_event_get_device                (const ClutterEvent     *event);
diff --git a/clutter/clutter.symbols b/clutter/clutter.symbols
index a397d31..7b4bffd 100644
--- a/clutter/clutter.symbols
+++ b/clutter/clutter.symbols
@@ -673,6 +673,7 @@ clutter_event_get_source
 clutter_event_get_source_device
 clutter_event_get_stage
 clutter_event_get_state
+clutter_event_get_state_full
 clutter_event_get_type
 clutter_event_get_time
 clutter_event_get
diff --git a/clutter/evdev/clutter-device-manager-evdev.c b/clutter/evdev/clutter-device-manager-evdev.c
index e8404bc..7f20ae0 100644
--- a/clutter/evdev/clutter-device-manager-evdev.c
+++ b/clutter/evdev/clutter-device-manager-evdev.c
@@ -278,8 +278,7 @@ notify_relative_motion (ClutterEventSource *source,
   event->motion.time = time_;
   event->motion.stage = stage;
   event->motion.device = manager_evdev->priv->core_pointer;
-  event->motion.modifier_state = xkb_state_serialize_mods (manager_evdev->priv->xkb, XKB_STATE_EFFECTIVE);
-  event->motion.modifier_state |= manager_evdev->priv->button_state;
+  _clutter_xkb_translate_state (event, manager_evdev->priv->xkb, manager_evdev->priv->button_state);
   event->motion.x = new_x;
   event->motion.y = new_y;
   clutter_event_set_source_device (event, input_device);
@@ -311,8 +310,7 @@ notify_scroll (ClutterEventSource *source,
   event->scroll.time = time_;
   event->scroll.stage = CLUTTER_STAGE (stage);
   event->scroll.device = manager_evdev->priv->core_pointer;
-  event->motion.modifier_state = xkb_state_serialize_mods (manager_evdev->priv->xkb, XKB_STATE_EFFECTIVE);
-  event->scroll.modifier_state |= manager_evdev->priv->button_state;
+  _clutter_xkb_translate_state (event, manager_evdev->priv->xkb, manager_evdev->priv->button_state);
   event->scroll.direction = value < 0 ? CLUTTER_SCROLL_DOWN : CLUTTER_SCROLL_UP;
   clutter_input_device_get_coords (manager_evdev->priv->core_pointer, NULL, &point);
   event->scroll.x = point.x;
@@ -390,8 +388,7 @@ notify_button (ClutterEventSource *source,
   event->button.time = time_;
   event->button.stage = CLUTTER_STAGE (stage);
   event->button.device = manager_evdev->priv->core_pointer;
-  event->motion.modifier_state = xkb_state_serialize_mods (manager_evdev->priv->xkb, XKB_STATE_EFFECTIVE);
-  event->button.modifier_state |= manager_evdev->priv->button_state;
+  _clutter_xkb_translate_state (event, manager_evdev->priv->xkb, manager_evdev->priv->button_state);
   event->button.button = button_nr;
   clutter_input_device_get_coords (manager_evdev->priv->core_pointer, NULL, &point);
   event->button.x = point.x;
diff --git a/clutter/evdev/clutter-xkb-utils.c b/clutter/evdev/clutter-xkb-utils.c
index 19d4670..eb84bf7 100644
--- a/clutter/evdev/clutter-xkb-utils.c
+++ b/clutter/evdev/clutter-xkb-utils.c
@@ -24,6 +24,7 @@
  */
 
 #include "clutter-keysyms.h"
+#include "clutter-event-private.h"
 #include "clutter-xkb-utils.h"
 
 /*
@@ -76,9 +77,7 @@ _clutter_key_event_new_from_evdev (ClutterInputDevice *device,
   event->key.device = core_device;
   event->key.stage = stage;
   event->key.time = _time;
-  event->key.modifier_state =
-    xkb_state_serialize_mods (xkb_state, XKB_STATE_EFFECTIVE);
-  event->key.modifier_state |= button_state;
+  _clutter_xkb_translate_state (event, xkb_state, button_state);
   event->key.hardware_keycode = key;
   event->key.keyval = sym;
   clutter_event_set_source_device (event, device);
@@ -142,3 +141,16 @@ _clutter_xkb_state_new (const gchar *model,
 
   return state;
 }
+
+void
+_clutter_xkb_translate_state (ClutterEvent     *event,
+                             struct xkb_state *state,
+                             uint32_t          button_state)
+{
+  _clutter_event_set_state_full (event,
+                                button_state,
+                                xkb_state_serialize_mods (state, XKB_STATE_MODS_DEPRESSED),
+                                xkb_state_serialize_mods (state, XKB_STATE_MODS_LATCHED),
+                                xkb_state_serialize_mods (state, XKB_STATE_MODS_LOCKED),
+                                xkb_state_serialize_mods (state, XKB_STATE_MODS_EFFECTIVE) | button_state);
+}
diff --git a/clutter/evdev/clutter-xkb-utils.h b/clutter/evdev/clutter-xkb-utils.h
index dd99b87..ee3a669 100644
--- a/clutter/evdev/clutter-xkb-utils.h
+++ b/clutter/evdev/clutter-xkb-utils.h
@@ -43,5 +43,8 @@ struct xkb_state * _clutter_xkb_state_new           (const gchar *model,
                                                      const gchar *layout,
                                                      const gchar *variant,
                                                      const gchar *options);
+void               _clutter_xkb_translate_state     (ClutterEvent       *event,
+                                                    struct xkb_state   *xkb_state,
+                                                    uint32_t            button_state);
 
 #endif /* __CLUTTER_XKB_UTILS_H__ */
diff --git a/clutter/wayland/clutter-input-device-wayland.c b/clutter/wayland/clutter-input-device-wayland.c
index 0effddf..29c6caa 100644
--- a/clutter/wayland/clutter-input-device-wayland.c
+++ b/clutter/wayland/clutter-input-device-wayland.c
@@ -123,8 +123,7 @@ clutter_wayland_handle_button (void *data,
   event->button.time = _clutter_wayland_get_time();
   event->button.x = device->x;
   event->button.y = device->y;
-  event->button.modifier_state =
-    xkb_state_serialize_mods (device->xkb, XKB_STATE_EFFECTIVE);
+  _clutter_xkb_translate_state (event, device->xkb, 0);
 
   /* evdev button codes */
   switch (button) {
@@ -177,8 +176,7 @@ clutter_wayland_handle_axis (void *data,
     }
   clutter_event_set_scroll_delta (event, delta_x, delta_y);
 
-  event->scroll.modifier_state =
-    xkb_state_serialize_mods(device->xkb, XKB_STATE_EFFECTIVE);
+  _clutter_xkb_translate_state (event, device->xkb, 0);
 
   _clutter_event_push (event, FALSE);
 }
diff --git a/clutter/x11/clutter-device-manager-xi2.c b/clutter/x11/clutter-device-manager-xi2.c
index e5664d8..1ee4fd9 100644
--- a/clutter/x11/clutter-device-manager-xi2.c
+++ b/clutter/x11/clutter-device-manager-xi2.c
@@ -821,8 +821,7 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
 
         event->key.time = xev->time;
         event->key.stage = stage;
-        event->key.modifier_state =
-          _clutter_input_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
+       _clutter_input_device_xi2_translate_state (event, &xev->mods, &xev->buttons, &xev->group);
         event->key.hardware_keycode = xev->detail;
 
           /* keyval is the key ignoring all modifiers ('1' vs. '!') */
@@ -930,10 +929,10 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
             event->scroll.time = xev->time;
             event->scroll.x = xev->event_x;
             event->scroll.y = xev->event_y;
-            event->scroll.modifier_state =
-              _clutter_input_device_xi2_translate_state (&xev->mods,
-                                                         &xev->buttons,
-                                                         &xev->group);
+           _clutter_input_device_xi2_translate_state (event,
+                                                      &xev->mods,
+                                                      &xev->buttons,
+                                                      &xev->group);
 
             clutter_event_set_source_device (event, source_device);
             clutter_event_set_device (event, device);
@@ -979,10 +978,10 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
             event->button.x = xev->event_x;
             event->button.y = xev->event_y;
             event->button.button = xev->detail;
-            event->button.modifier_state =
-              _clutter_input_device_xi2_translate_state (&xev->mods,
-                                                         &xev->buttons,
-                                                         &xev->group);
+           _clutter_input_device_xi2_translate_state (event,
+                                                      &xev->mods,
+                                                      &xev->buttons,
+                                                      &xev->group);
 
             clutter_event_set_source_device (event, source_device);
             clutter_event_set_device (event, device);
@@ -1061,10 +1060,10 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
             event->scroll.time = xev->time;
             event->scroll.x = xev->event_x;
             event->scroll.y = xev->event_y;
-            event->scroll.modifier_state =
-              _clutter_input_device_xi2_translate_state (&xev->mods,
-                                                         &xev->buttons,
-                                                         &xev->group);
+           _clutter_input_device_xi2_translate_state (event,
+                                                      &xev->mods,
+                                                      &xev->buttons,
+                                                      &xev->group);
 
             clutter_event_set_scroll_delta (event, delta_x, delta_y);
             clutter_event_set_source_device (event, source_device);
@@ -1090,10 +1089,10 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
         event->motion.time = xev->time;
         event->motion.x = xev->event_x;
         event->motion.y = xev->event_y;
-        event->motion.modifier_state =
-          _clutter_input_device_xi2_translate_state (&xev->mods,
-                                                     &xev->buttons,
-                                                     &xev->group);
+       _clutter_input_device_xi2_translate_state (event,
+                                                  &xev->mods,
+                                                  &xev->buttons,
+                                                  &xev->group);
 
         clutter_event_set_source_device (event, source_device);
         clutter_event_set_device (event, device);
@@ -1142,10 +1141,10 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
         event->touch.time = xev->time;
         event->touch.x = xev->event_x;
         event->touch.y = xev->event_y;
-        event->touch.modifier_state =
-          _clutter_input_device_xi2_translate_state (&xev->mods,
-                                                     &xev->buttons,
-                                                     &xev->group);
+       _clutter_input_device_xi2_translate_state (event,
+                                                  &xev->mods,
+                                                  &xev->buttons,
+                                                  &xev->group);
 
         clutter_event_set_source_device (event, source_device);
 
@@ -1211,10 +1210,10 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
                                             stage_x11,
                                             &xev->valuators);
 
-        event->touch.modifier_state =
-          _clutter_input_device_xi2_translate_state (&xev->mods,
-                                                     &xev->buttons,
-                                                     &xev->group);
+       _clutter_input_device_xi2_translate_state (event,
+                                                  &xev->mods,
+                                                  &xev->buttons,
+                                                  &xev->group);
         event->touch.modifier_state |= CLUTTER_BUTTON1_MASK;
 
         if (xev->flags & XITouchEmulatingPointer)
diff --git a/clutter/x11/clutter-input-device-xi2.c b/clutter/x11/clutter-input-device-xi2.c
index b9e27a5..20ac71c 100644
--- a/clutter/x11/clutter-input-device-xi2.c
+++ b/clutter/x11/clutter-input-device-xi2.c
@@ -27,6 +27,7 @@
 
 #include "clutter-debug.h"
 #include "clutter-device-manager-private.h"
+#include "clutter-event-private.h"
 #include "clutter-private.h"
 #include "clutter-stage-private.h"
 
@@ -94,15 +95,24 @@ clutter_input_device_xi2_init (ClutterInputDeviceXI2 *self)
 {
 }
 
-guint
-_clutter_input_device_xi2_translate_state (XIModifierState *modifiers_state,
+void
+_clutter_input_device_xi2_translate_state (ClutterEvent    *event,
+                                          XIModifierState *modifiers_state,
                                            XIButtonState   *buttons_state,
                                            XIGroupState    *group_state)
 {
-  guint retval = 0;
+  guint button = 0;
+  guint base = 0;
+  guint latched = 0;
+  guint locked = 0;
+  guint effective;
 
   if (modifiers_state)
-    retval = (guint) modifiers_state->effective;
+    {
+      base = (guint) modifiers_state->base;
+      latched = (guint) modifiers_state->latched;
+      locked = (guint) modifiers_state->locked;
+    }
 
   if (buttons_state)
     {
@@ -118,23 +128,23 @@ _clutter_input_device_xi2_translate_state (XIModifierState *modifiers_state,
           switch (i)
             {
             case 1:
-              retval |= CLUTTER_BUTTON1_MASK;
+              button |= CLUTTER_BUTTON1_MASK;
               break;
 
             case 2:
-              retval |= CLUTTER_BUTTON2_MASK;
+              button |= CLUTTER_BUTTON2_MASK;
               break;
 
             case 3:
-              retval |= CLUTTER_BUTTON3_MASK;
+              button |= CLUTTER_BUTTON3_MASK;
               break;
 
             case 4:
-              retval |= CLUTTER_BUTTON4_MASK;
+              button |= CLUTTER_BUTTON4_MASK;
               break;
 
             case 5:
-              retval |= CLUTTER_BUTTON5_MASK;
+              button |= CLUTTER_BUTTON5_MASK;
               break;
 
             default:
@@ -143,8 +153,9 @@ _clutter_input_device_xi2_translate_state (XIModifierState *modifiers_state,
         }
     }
 
+  effective = button | base | latched | locked;
   if (group_state)
-    retval |= (group_state->effective) << 13;
+    effective |= (group_state->effective) << 13;
 
-  return retval;
+  _clutter_event_set_state_full (event, button, base, latched, locked, effective);
 }
diff --git a/clutter/x11/clutter-input-device-xi2.h b/clutter/x11/clutter-input-device-xi2.h
index b86401f..92dadc9 100644
--- a/clutter/x11/clutter-input-device-xi2.h
+++ b/clutter/x11/clutter-input-device-xi2.h
@@ -37,9 +37,10 @@ typedef struct _ClutterInputDeviceXI2           ClutterInputDeviceXI2;
 
 GType _clutter_input_device_xi2_get_type (void) G_GNUC_CONST;
 
-guint _clutter_input_device_xi2_translate_state (XIModifierState *modifiers_state,
-                                                 XIButtonState   *buttons_state,
-                                                 XIGroupState    *group_state);
+void  _clutter_input_device_xi2_translate_state (ClutterEvent    *event,
+                                                XIModifierState *modifiers_state,
+                                                XIButtonState   *buttons_state,
+                                                XIGroupState    *group_state);
 
 G_END_DECLS
 


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