diff options
author | Mike Gorse <mgorse@suse.com> | 2023-01-06 12:22:22 -0600 |
---|---|---|
committer | Mike Gorse <mgorse@suse.com> | 2023-01-06 12:22:22 -0600 |
commit | 12e789776f7d8eaeace7d2542297c6f4435f37ad (patch) | |
tree | d9b68ba0ddccd10a5ae3666f89a10f1db19ba5e2 /atspi/atspi-device-x11.c | |
parent | a429153c75857e7f78929fc0418a9d2785286df1 (diff) | |
download | at-spi2-core-12e789776f7d8eaeace7d2542297c6f4435f37ad.tar.gz |
x11: Register key grabs using the currently-focused window
Previously, the root window was being passed to XIGrabKeycode. This had the
annoying side effect of briefly taking focus from the window when one of our
key grabs was used, leading to a window:deactive event that would confuse
orca.
The challenge with the new approach is that we need to reset any active grabs
when the focus changes. Now the X event watcher will listen for FocusIn
events and refresh the key grabs when it sees one. As a backup, we also
listen for window:activate and window:deactivate events and also refresh the
key grabs when we see one.
Fixes #101
Diffstat (limited to 'atspi/atspi-device-x11.c')
-rw-r--r-- | atspi/atspi-device-x11.c | 79 |
1 files changed, 57 insertions, 22 deletions
diff --git a/atspi/atspi-device-x11.c b/atspi/atspi-device-x11.c index fccaba8c..46aecc29 100644 --- a/atspi/atspi-device-x11.c +++ b/atspi/atspi-device-x11.c @@ -34,7 +34,8 @@ typedef struct _AtspiDeviceX11Private AtspiDeviceX11Private; struct _AtspiDeviceX11Private { Display *display; - Window window; + Window root_window; + Window focused_window; GSource *source; int xi_opcode; int device_id; @@ -44,6 +45,7 @@ struct _AtspiDeviceX11Private guint virtual_mods_enabled; gboolean keyboard_grabbed; unsigned int numlock_physical_mask; + AtspiEventListener *event_listener; }; GObjectClass *device_x11_parent_class; @@ -66,6 +68,7 @@ typedef struct { AtspiKeyDefinition *kd; gboolean enabled; + Window window; } AtspiX11KeyGrab; static gboolean @@ -173,7 +176,7 @@ grab_has_active_duplicate (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab) } static void -grab_key_aux (AtspiDeviceX11 *x11_device, int keycode, int modmask) +grab_key_aux (AtspiDeviceX11 *x11_device, Window window, int keycode, int modmask) { AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); XIGrabModifiers xi_modifiers; @@ -190,22 +193,22 @@ grab_key_aux (AtspiDeviceX11 *x11_device, int keycode, int modmask) XISetMask (mask, XI_KeyPress); XISetMask (mask, XI_KeyRelease); - XIGrabKeycode (priv->display, XIAllMasterDevices, keycode, priv->window, XIGrabModeSync, XIGrabModeAsync, False, &eventmask, 1, &xi_modifiers); + XIGrabKeycode (priv->display, XIAllMasterDevices, keycode, window, XIGrabModeSync, XIGrabModeAsync, False, &eventmask, 1, &xi_modifiers); } static void -grab_key (AtspiDeviceX11 *x11_device, int keycode, int modmask) +grab_key (AtspiDeviceX11 *x11_device, Window window, int keycode, int modmask) { AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); - grab_key_aux (x11_device, keycode, modmask); + grab_key_aux (x11_device, window, keycode, modmask); if (!(modmask & LockMask)) - grab_key_aux (x11_device, keycode, modmask | LockMask); + grab_key_aux (x11_device, window, keycode, modmask | LockMask); if (!(modmask & priv->numlock_physical_mask)) { - grab_key_aux (x11_device, keycode, modmask | priv->numlock_physical_mask); + grab_key_aux (x11_device, window, keycode, modmask | priv->numlock_physical_mask); if (!(modmask & LockMask)) - grab_key_aux (x11_device, keycode, modmask | LockMask | priv->numlock_physical_mask); + grab_key_aux (x11_device, window, keycode, modmask | LockMask | priv->numlock_physical_mask); } } @@ -217,12 +220,13 @@ enable_key_grab (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab) g_return_if_fail (priv->display != NULL); if (!grab_has_active_duplicate (x11_device, grab)) - grab_key (x11_device, grab->kd->keycode, grab->kd->modifiers & ~ATSPI_VIRTUAL_MODIFIER_MASK); + grab_key (x11_device, priv->focused_window, grab->kd->keycode, grab->kd->modifiers & ~ATSPI_VIRTUAL_MODIFIER_MASK); grab->enabled = TRUE; + grab->window = priv->focused_window; } static void -ungrab_key_aux (AtspiDeviceX11 *x11_device, int keycode, int modmask) +ungrab_key_aux (AtspiDeviceX11 *x11_device, Window window, int keycode, int modmask) { AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); XIGrabModifiers xi_modifiers; @@ -230,22 +234,22 @@ ungrab_key_aux (AtspiDeviceX11 *x11_device, int keycode, int modmask) xi_modifiers.modifiers = modmask; xi_modifiers.status = 0; - XIUngrabKeycode (priv->display, XIAllMasterDevices, keycode, priv->window, sizeof (xi_modifiers), &xi_modifiers); + XIUngrabKeycode (priv->display, XIAllMasterDevices, keycode, window, sizeof (xi_modifiers), &xi_modifiers); } static void -ungrab_key (AtspiDeviceX11 *x11_device, int keycode, int modmask) +ungrab_key (AtspiDeviceX11 *x11_device, Window window, int keycode, int modmask) { AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); - ungrab_key_aux (x11_device, keycode, modmask); + ungrab_key_aux (x11_device, window, keycode, modmask); if (!(modmask & LockMask)) - ungrab_key_aux (x11_device, keycode, modmask | LockMask); + ungrab_key_aux (x11_device, window, keycode, modmask | LockMask); if (!(modmask & priv->numlock_physical_mask)) { - ungrab_key_aux (x11_device, keycode, modmask | priv->numlock_physical_mask); + ungrab_key_aux (x11_device, window, keycode, modmask | priv->numlock_physical_mask); if (!(modmask & LockMask)) - ungrab_key_aux (x11_device, keycode, modmask | LockMask | priv->numlock_physical_mask); + ungrab_key_aux (x11_device, window, keycode, modmask | LockMask | priv->numlock_physical_mask); } } @@ -264,7 +268,7 @@ disable_key_grab (AtspiDeviceX11 *x11_device, AtspiX11KeyGrab *grab) if (grab_has_active_duplicate (x11_device, grab)) return; - ungrab_key (x11_device, grab->kd->keycode, grab->kd->modifiers & ~ATSPI_VIRTUAL_MODIFIER_MASK); + ungrab_key (x11_device, grab->window, grab->kd->keycode, grab->kd->modifiers & ~ATSPI_VIRTUAL_MODIFIER_MASK); } static void @@ -272,11 +276,16 @@ refresh_key_grabs (AtspiDeviceX11 *x11_device) { AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (x11_device); GSList *l; + int focus_revert; + + XGetInputFocus (priv->display, &priv->focused_window, &focus_revert); for (l = priv->key_grabs; l; l = l->next) { AtspiX11KeyGrab *grab = l->data; gboolean new_enabled = grab_should_be_enabled (x11_device, grab); + if (grab->window != priv->focused_window) + disable_key_grab (x11_device, grab); if (new_enabled && !grab->enabled) enable_key_grab (x11_device, grab); else if (grab->enabled && !new_enabled) @@ -339,6 +348,9 @@ do_event_dispatch (gpointer user_data) } atspi_device_notify_key (ATSPI_DEVICE (device), (xevent.type == KeyPress), xevent.xkey.keycode, keysym, modifiers, text); break; + case FocusIn: + refresh_key_grabs (device); + break; case GenericEvent: if (xevent.xcookie.extension == priv->xi_opcode) { @@ -370,6 +382,9 @@ do_event_dispatch (gpointer user_data) /* otherwise it's probably a duplicate event from a key grab */ XFreeEventData (priv->display, &xevent.xcookie); break; + case FocusIn: + refresh_key_grabs (device); + break; } } default: @@ -545,14 +560,24 @@ atspi_device_x11_get_modifier (AtspiDevice *device, gint keycode) } static void +event_listener_cb (AtspiEvent *event, void *user_data) +{ + AtspiDeviceX11 *x11_device = user_data; + + refresh_key_grabs (x11_device); +} + +static void atspi_device_x11_init (AtspiDeviceX11 *device) { AtspiDeviceX11Private *priv = atspi_device_x11_get_instance_private (device); int first_event, first_error; + int focus_revert; priv->display = XOpenDisplay (""); g_return_if_fail (priv->display != NULL); - priv->window = DefaultRootWindow (priv->display); + priv->root_window = DefaultRootWindow (priv->display); + XGetInputFocus (priv->display, &priv->focused_window, &focus_revert); if (XQueryExtension (priv->display, "XInputExtension", &priv->xi_opcode, &first_event, &first_error)) { @@ -572,13 +597,18 @@ atspi_device_x11_init (AtspiDeviceX11 *device) XISetMask (mask, XI_ButtonPress); XISetMask (mask, XI_ButtonRelease); XISetMask (mask, XI_Motion); - XISelectEvents (priv->display, priv->window, &eventmask, 1); + XISelectEvents (priv->display, priv->root_window, &eventmask, 1); + XSelectInput (priv->display, priv->root_window, FocusChangeMask); create_event_source (device); } } priv->numlock_physical_mask = XkbKeysymToModifiers (priv->display, XK_Num_Lock); + + priv->event_listener = atspi_event_listener_new (event_listener_cb, device, NULL); + atspi_event_listener_register (priv->event_listener, "window:activate", NULL); + atspi_event_listener_register (priv->event_listener, "window:deactivate", NULL); } static void @@ -608,6 +638,11 @@ atspi_device_x11_finalize (GObject *object) priv->source = NULL; } + /* TODO: deregister event listeners automatically when the listener is finalized */ + atspi_event_listener_deregister (priv->event_listener, "window:deactivate", NULL); + atspi_event_listener_deregister (priv->event_listener, "window:activate", NULL); + g_object_unref (priv->event_listener); + device_x11_parent_class->finalize (object); } @@ -683,7 +718,7 @@ atspi_device_x11_grab_keyboard (AtspiDevice *device) g_return_val_if_fail (priv->display != NULL, FALSE); #if 0 /* THis seems like the right thing to do, but it fails for me */ - return (XGrabKeyboard (priv->display, priv->window, TRUE, GrabModeAsync, GrabModeSync, CurrentTime)) == 0; + return (XGrabKeyboard (priv->display, priv->focused_window, TRUE, GrabModeAsync, GrabModeSync, CurrentTime)) == 0; #else if (priv->keyboard_grabbed) return TRUE; @@ -692,7 +727,7 @@ atspi_device_x11_grab_keyboard (AtspiDevice *device) get_keycode_range (x11_device, &min, &max); for (i = min; i < max; i++) - grab_key (x11_device, i, 0); + grab_key (x11_device, priv->focused_window, i, 0); return TRUE; #endif } @@ -715,7 +750,7 @@ atspi_device_x11_ungrab_keyboard (AtspiDevice *device) get_keycode_range (x11_device, &min, &max); for (i = min; i < max; i++) - ungrab_key (x11_device, i, 0); + ungrab_key (x11_device, priv->focused_window, i, 0); refresh_key_grabs (x11_device); #endif |