[mutter] clutter/x11: Hook up pointer accessibility



commit c1303bd642e57d53ccbc8f6eb450c2a45bf4d3ef
Author: Olivier Fourdan <ofourdan redhat com>
Date:   Thu Mar 14 14:12:34 2019 +0100

    clutter/x11: Hook up pointer accessibility
    
    Pointer accessibility features requires to receive all pointer events
    regardless of X11 grabs.
    
    Add XI2 raw events mask and hook up the pointer accessibility handlers
    to the raw motion and button press/release events.
    
    https://gitlab.gnome.org/GNOME/mutter/merge_requests/512

 clutter/clutter/x11/clutter-device-manager-xi2.c | 78 +++++++++++++++++++++++-
 clutter/clutter/x11/clutter-input-device-xi2.c   | 77 +++++++++++++++++++++++
 clutter/clutter/x11/clutter-input-device-xi2.h   |  3 +
 3 files changed, 157 insertions(+), 1 deletion(-)
---
diff --git a/clutter/clutter/x11/clutter-device-manager-xi2.c 
b/clutter/clutter/x11/clutter-device-manager-xi2.c
index 87da4b050..6d63ed9bd 100644
--- a/clutter/clutter/x11/clutter-device-manager-xi2.c
+++ b/clutter/clutter/x11/clutter-device-manager-xi2.c
@@ -30,6 +30,7 @@
 #include "clutter-backend-x11.h"
 #include "clutter-input-device-xi2.h"
 #include "clutter-input-device-tool-xi2.h"
+#include "clutter-input-pointer-a11y-private.h"
 #include "clutter-virtual-input-device-x11.h"
 #include "clutter-stage-x11.h"
 
@@ -1273,6 +1274,60 @@ translate_pad_event (ClutterEvent       *event,
   return TRUE;
 }
 
+static void
+handle_raw_event (ClutterDeviceManagerXI2 *manager_xi2,
+                  XEvent                  *xevent)
+{
+  ClutterInputDevice *device;
+  XGenericEventCookie *cookie;
+  XIEvent *xi_event;
+  XIRawEvent *xev;
+  float x,y;
+
+  cookie = &xevent->xcookie;
+  xi_event = (XIEvent *) cookie->data;
+  xev = (XIRawEvent *) xi_event;
+
+  device = g_hash_table_lookup (manager_xi2->devices_by_id,
+                                GINT_TO_POINTER (xev->deviceid));
+  if (device == NULL)
+    return;
+
+  if (!_clutter_is_input_pointer_a11y_enabled (device))
+    return;
+
+  switch (cookie->evtype)
+    {
+    case XI_RawMotion:
+      CLUTTER_NOTE (EVENT,
+                    "raw motion: device:%d '%s'",
+                    device->id,
+                    device->device_name);
+      /* We don't get actual pointer location with raw events, and we cannot
+       * rely on `clutter_input_device_get_coords()` either because of
+       * unreparented toplevels (like all client-side decoration windows),
+       * so we need to explicitely query the pointer here...
+       */
+      if (clutter_input_device_xi2_get_pointer_location (device, &x, &y))
+        _clutter_input_pointer_a11y_on_motion_event (device, x, y);
+      break;
+    case XI_RawButtonPress:
+    case XI_RawButtonRelease:
+      CLUTTER_NOTE (EVENT,
+                    "raw button %s: device:%d '%s' button %i",
+                    cookie->evtype == XI_RawButtonPress
+                      ? "press  "
+                      : "release",
+                    device->id,
+                    device->device_name,
+                    xev->detail);
+      _clutter_input_pointer_a11y_on_button_event (device,
+                                                  xev->detail,
+                                                  (cookie->evtype == XI_RawButtonPress));
+      break;
+    }
+}
+
 static ClutterTranslateReturn
 clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
                                             gpointer                native,
@@ -1303,6 +1358,14 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
   if (!xi_event)
     return CLUTTER_TRANSLATE_REMOVE;
 
+  if (cookie->evtype == XI_RawMotion ||
+      cookie->evtype == XI_RawButtonPress ||
+      cookie->evtype == XI_RawButtonRelease)
+    {
+      handle_raw_event (manager_xi2, xevent);
+      return CLUTTER_TRANSLATE_REMOVE;
+    }
+
   if (!(xi_event->evtype == XI_HierarchyChanged ||
         xi_event->evtype == XI_DeviceChanged ||
         xi_event->evtype == XI_PropertyEvent))
@@ -2031,7 +2094,7 @@ clutter_device_manager_xi2_constructed (GObject *gobject)
   GHashTable *masters, *slaves;
   XIDeviceInfo *info;
   XIEventMask event_mask;
-  unsigned char mask[2] = { 0, };
+  unsigned char mask[(XI_LASTEVENT + 7) / 8] = { 0, };
   int n_devices, i;
 
   backend_x11 =
@@ -2083,6 +2146,19 @@ clutter_device_manager_xi2_constructed (GObject *gobject)
   event_mask.mask_len = sizeof (mask);
   event_mask.mask = mask;
 
+  clutter_device_manager_xi2_select_events (manager,
+                                            clutter_x11_get_root_window (),
+                                            &event_mask);
+
+  memset(mask, 0, sizeof (mask));
+  XISetMask (mask, XI_RawMotion);
+  XISetMask (mask, XI_RawButtonPress);
+  XISetMask (mask, XI_RawButtonRelease);
+
+  event_mask.deviceid = XIAllMasterDevices;
+  event_mask.mask_len = sizeof (mask);
+  event_mask.mask = mask;
+
   clutter_device_manager_xi2_select_events (manager,
                                             clutter_x11_get_root_window (),
                                             &event_mask);
diff --git a/clutter/clutter/x11/clutter-input-device-xi2.c b/clutter/clutter/x11/clutter-input-device-xi2.c
index 1254aca3a..0033166c5 100644
--- a/clutter/clutter/x11/clutter-input-device-xi2.c
+++ b/clutter/clutter/x11/clutter-input-device-xi2.c
@@ -46,6 +46,11 @@ struct _ClutterInputDeviceXI2
   gint device_id;
   ClutterInputDeviceTool *current_tool;
 
+  guint inhibit_pointer_query_timer;
+  gboolean query_status;
+  float current_x;
+  float current_y;
+
 #ifdef HAVE_LIBWACOM
   WacomDevice *wacom_device;
   GArray *group_modes;
@@ -114,6 +119,9 @@ clutter_input_device_xi2_finalize (GObject *object)
     g_array_unref (device_xi2->group_modes);
 #endif
 
+  if (device_xi2->inhibit_pointer_query_timer)
+    g_source_remove (device_xi2->inhibit_pointer_query_timer);
+
   G_OBJECT_CLASS (clutter_input_device_xi2_parent_class)->finalize (object);
 }
 
@@ -293,6 +301,75 @@ clutter_input_device_xi2_get_current_tool (ClutterInputDevice *device)
   return device_xi2->current_tool;
 }
 
+static gboolean
+clutter_input_device_xi2_query_pointer_location (ClutterInputDeviceXI2 *device_xi2)
+{
+  Window xroot_window, xchild_window;
+  double xroot_x, xroot_y, xwin_x, xwin_y;
+  XIButtonState button_state;
+  XIModifierState mod_state;
+  XIGroupState group_state;
+  int result;
+
+  clutter_x11_trap_x_errors ();
+  result = XIQueryPointer (clutter_x11_get_default_display (),
+                           device_xi2->device_id,
+                           clutter_x11_get_root_window (),
+                           &xroot_window,
+                           &xchild_window,
+                           &xroot_x, &xroot_y,
+                           &xwin_x, &xwin_y,
+                           &button_state,
+                           &mod_state,
+                           &group_state);
+  clutter_x11_untrap_x_errors ();
+
+  if (!result)
+    return FALSE;
+
+  device_xi2->current_x = (float) xroot_x;
+  device_xi2->current_y = (float) xroot_y;
+
+  return TRUE;
+}
+
+static gboolean
+clear_inhibit_pointer_query_cb (gpointer data)
+{
+  ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (data);
+
+  device_xi2->inhibit_pointer_query_timer = 0;
+
+  return G_SOURCE_REMOVE;
+}
+
+gboolean
+clutter_input_device_xi2_get_pointer_location (ClutterInputDevice *device,
+                                               float              *x,
+                                               float              *y)
+
+{
+  ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (device);
+
+  g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
+  g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE_XI2 (device_xi2), FALSE);
+  g_return_val_if_fail (device->device_type == CLUTTER_POINTER_DEVICE, FALSE);
+
+  /* Throttle XServer queries and roundtrips using an idle timeout */
+  if (device_xi2->inhibit_pointer_query_timer == 0)
+    {
+      device_xi2->query_status =
+        clutter_input_device_xi2_query_pointer_location (device_xi2);
+      device_xi2->inhibit_pointer_query_timer =
+        clutter_threads_add_idle (clear_inhibit_pointer_query_cb, device_xi2);
+    }
+
+  *x = device_xi2->current_x;
+  *y = device_xi2->current_y;
+
+  return device_xi2->query_status;
+}
+
 #ifdef HAVE_LIBWACOM
 void
 clutter_input_device_xi2_ensure_wacom_info (ClutterInputDevice  *device,
diff --git a/clutter/clutter/x11/clutter-input-device-xi2.h b/clutter/clutter/x11/clutter-input-device-xi2.h
index 2194e1ba2..8ec709a2e 100644
--- a/clutter/clutter/x11/clutter-input-device-xi2.h
+++ b/clutter/clutter/x11/clutter-input-device-xi2.h
@@ -48,6 +48,9 @@ void  _clutter_input_device_xi2_translate_state (ClutterEvent    *event,
 void  clutter_input_device_xi2_update_tool      (ClutterInputDevice     *device,
                                                  ClutterInputDeviceTool *tool);
 ClutterInputDeviceTool * clutter_input_device_xi2_get_current_tool (ClutterInputDevice *device);
+gboolean clutter_input_device_xi2_get_pointer_location (ClutterInputDevice *device,
+                                                        float              *x,
+                                                        float              *y);
 
 #ifdef HAVE_LIBWACOM
 void clutter_input_device_xi2_ensure_wacom_info (ClutterInputDevice  *device,


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