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:
parent
db11a37a68
commit
c1303bd642
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user