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
This commit is contained in:
Olivier Fourdan 2019-03-14 14:12:34 +01:00
parent db11a37a68
commit c1303bd642
3 changed files with 157 additions and 1 deletions

View File

@ -30,6 +30,7 @@
#include "clutter-backend-x11.h" #include "clutter-backend-x11.h"
#include "clutter-input-device-xi2.h" #include "clutter-input-device-xi2.h"
#include "clutter-input-device-tool-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-virtual-input-device-x11.h"
#include "clutter-stage-x11.h" #include "clutter-stage-x11.h"
@ -1273,6 +1274,60 @@ translate_pad_event (ClutterEvent *event,
return TRUE; 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 static ClutterTranslateReturn
clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator, clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
gpointer native, gpointer native,
@ -1303,6 +1358,14 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
if (!xi_event) if (!xi_event)
return CLUTTER_TRANSLATE_REMOVE; 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 || if (!(xi_event->evtype == XI_HierarchyChanged ||
xi_event->evtype == XI_DeviceChanged || xi_event->evtype == XI_DeviceChanged ||
xi_event->evtype == XI_PropertyEvent)) xi_event->evtype == XI_PropertyEvent))
@ -2031,7 +2094,7 @@ clutter_device_manager_xi2_constructed (GObject *gobject)
GHashTable *masters, *slaves; GHashTable *masters, *slaves;
XIDeviceInfo *info; XIDeviceInfo *info;
XIEventMask event_mask; XIEventMask event_mask;
unsigned char mask[2] = { 0, }; unsigned char mask[(XI_LASTEVENT + 7) / 8] = { 0, };
int n_devices, i; int n_devices, i;
backend_x11 = backend_x11 =
@ -2083,6 +2146,19 @@ clutter_device_manager_xi2_constructed (GObject *gobject)
event_mask.mask_len = sizeof (mask); event_mask.mask_len = sizeof (mask);
event_mask.mask = 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_device_manager_xi2_select_events (manager,
clutter_x11_get_root_window (), clutter_x11_get_root_window (),
&event_mask); &event_mask);

View File

@ -46,6 +46,11 @@ struct _ClutterInputDeviceXI2
gint device_id; gint device_id;
ClutterInputDeviceTool *current_tool; ClutterInputDeviceTool *current_tool;
guint inhibit_pointer_query_timer;
gboolean query_status;
float current_x;
float current_y;
#ifdef HAVE_LIBWACOM #ifdef HAVE_LIBWACOM
WacomDevice *wacom_device; WacomDevice *wacom_device;
GArray *group_modes; GArray *group_modes;
@ -114,6 +119,9 @@ clutter_input_device_xi2_finalize (GObject *object)
g_array_unref (device_xi2->group_modes); g_array_unref (device_xi2->group_modes);
#endif #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); 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; 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 #ifdef HAVE_LIBWACOM
void void
clutter_input_device_xi2_ensure_wacom_info (ClutterInputDevice *device, clutter_input_device_xi2_ensure_wacom_info (ClutterInputDevice *device,

View File

@ -48,6 +48,9 @@ void _clutter_input_device_xi2_translate_state (ClutterEvent *event,
void clutter_input_device_xi2_update_tool (ClutterInputDevice *device, void clutter_input_device_xi2_update_tool (ClutterInputDevice *device,
ClutterInputDeviceTool *tool); ClutterInputDeviceTool *tool);
ClutterInputDeviceTool * clutter_input_device_xi2_get_current_tool (ClutterInputDevice *device); 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 #ifdef HAVE_LIBWACOM
void clutter_input_device_xi2_ensure_wacom_info (ClutterInputDevice *device, void clutter_input_device_xi2_ensure_wacom_info (ClutterInputDevice *device,