From 7c1e0e71899d13f75fe4177454656049d3f35d54 Mon Sep 17 00:00:00 2001 From: Jan Ziak <0xe2.0x9a.0x9b@gmail.com> Date: Mon, 4 Jan 2021 17:01:04 +0100 Subject: [PATCH 1/5] shortcuts-grabber: Record xkb state group (Bug #33) XkbGroupForCoreState(xevent->xkey.state) returns 0 even after a keyboard layout switch. Instead of using the XkbGroupForCoreState() function, this patch watches for XkbStateNotify events from which it obtains the xkb state group. Closes: https://gitlab.xfce.org/xfce/libxfce4ui/-/issues/33 See also: https://gitlab.xfce.org/xfce/libxfce4ui/-/merge_requests/33 --- libxfce4kbd-private/xfce-shortcuts-grabber.c | 38 ++++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/libxfce4kbd-private/xfce-shortcuts-grabber.c b/libxfce4kbd-private/xfce-shortcuts-grabber.c index 60ddfd7..9df45c3 100644 --- libxfce4kbd-private/xfce-shortcuts-grabber.c +++ libxfce4kbd-private/xfce-shortcuts-grabber.c @@ -61,13 +61,14 @@ static void xfce_shortcuts_grabber_grab (XfceShortcutsGra gboolean grab); static GdkFilterReturn xfce_shortcuts_grabber_event_filter (GdkXEvent *gdk_xevent, GdkEvent *event, - XfceShortcutsGrabber *grabber); + gpointer data); struct _XfceShortcutsGrabberPrivate { GHashTable *keys; + gint xkbEventType, xkbStateGroup; }; typedef enum @@ -141,20 +142,26 @@ static void xfce_shortcuts_grabber_constructed (GObject *object) { GdkDisplay *display; + Display *xdisplay; GdkKeymap *keymap; XfceShortcutsGrabber *grabber = XFCE_SHORTCUTS_GRABBER (object); display = gdk_display_get_default (); + xdisplay = GDK_DISPLAY_XDISPLAY (display); keymap = gdk_keymap_get_for_display (display); g_signal_connect (keymap, "keys-changed", G_CALLBACK (xfce_shortcuts_grabber_keys_changed), grabber); + if (G_UNLIKELY (!XkbQueryExtension (xdisplay, 0, &grabber->priv->xkbEventType, 0, 0, 0))) + grabber->priv->xkbEventType = -1; + grabber->priv->xkbStateGroup = -1; + /* Flush events before adding the event filter */ - XAllowEvents (GDK_DISPLAY_XDISPLAY (display), AsyncBoth, CurrentTime); + XAllowEvents (xdisplay, AsyncBoth, CurrentTime); /* Add event filter */ - gdk_window_add_filter (NULL, (GdkFilterFunc) xfce_shortcuts_grabber_event_filter, grabber); + gdk_window_add_filter (NULL, xfce_shortcuts_grabber_event_filter, grabber); } @@ -417,10 +424,11 @@ find_event_key (const gchar *shortcut, static GdkFilterReturn -xfce_shortcuts_grabber_event_filter (GdkXEvent *gdk_xevent, - GdkEvent *event, - XfceShortcutsGrabber *grabber) +xfce_shortcuts_grabber_event_filter (GdkXEvent *gdk_xevent, + GdkEvent *event, + gpointer data) { + XfceShortcutsGrabber *const grabber = data; struct EventKeyFindContext context; GdkKeymap *keymap; GdkModifierType consumed, modifiers; @@ -434,6 +442,22 @@ xfce_shortcuts_grabber_event_filter (GdkXEvent *gdk_xevent, xevent = (XEvent *) gdk_xevent; + if (xevent->type == grabber->priv->xkbEventType) + { + const XkbEvent *e = (const XkbEvent*) xevent; + TRACE ("xkb event: any.xkb_type=%d", e->any.xkb_type); + if (e->any.xkb_type == XkbStateNotify) + { + TRACE ("xkb event: any.xkb_type=XkbStateNotify, state.group=%d", e->state.group); + if (grabber->priv->xkbStateGroup != e->state.group) + { + grabber->priv->xkbStateGroup = e->state.group; + xfce_shortcuts_grabber_ungrab_all (grabber); + xfce_shortcuts_grabber_grab_all (grabber); + } + } + } + if (xevent->type != KeyPress) return GDK_FILTER_CONTINUE; @@ -450,7 +474,7 @@ xfce_shortcuts_grabber_event_filter (GdkXEvent *gdk_xevent, gdk_keymap_translate_keyboard_state (keymap, xevent->xkey.keycode, modifiers, - XkbGroupForCoreState (xevent->xkey.state), + grabber->priv->xkbStateGroup, &keyval, NULL, NULL, &consumed); /* We want Alt + Print to be Alt + Print not SysReq. See bug #7897 */ -- GitLab From 5d34aac693e160de3d22d1700b89664dcac12394 Mon Sep 17 00:00:00 2001 From: Jan Ziak <0xe2.0x9a.0x9b@gmail.com> Date: Fri, 26 Feb 2021 05:27:16 +0100 Subject: [PATCH 2/5] shortcuts: Fix a memory leak --- libxfce4kbd-private/xfce-shortcuts-provider.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libxfce4kbd-private/xfce-shortcuts-provider.c b/libxfce4kbd-private/xfce-shortcuts-provider.c index b7f7a47..83ab6c0 100644 --- libxfce4kbd-private/xfce-shortcuts-provider.c +++ libxfce4kbd-private/xfce-shortcuts-provider.c @@ -711,6 +711,7 @@ void xfce_shortcuts_free (GList *shortcuts) { g_list_foreach (shortcuts, (GFunc) (void (*)(void)) xfce_shortcut_free, NULL); + g_list_free (shortcuts); } -- GitLab From c18f068ab2bd69647af6519e389d76728c1f924e Mon Sep 17 00:00:00 2001 From: Jan Ziak <0xe2.0x9a.0x9b@gmail.com> Date: Fri, 26 Feb 2021 05:57:42 +0100 Subject: [PATCH 3/5] shortcuts-grabber: Stop search when the first match is found --- libxfce4kbd-private/xfce-shortcuts-grabber.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/libxfce4kbd-private/xfce-shortcuts-grabber.c b/libxfce4kbd-private/xfce-shortcuts-grabber.c index 9df45c3..61f8ef8 100644 --- libxfce4kbd-private/xfce-shortcuts-grabber.c +++ libxfce4kbd-private/xfce-shortcuts-grabber.c @@ -391,10 +391,9 @@ xfce_shortcuts_grabber_grab (XfceShortcutsGrabber *grabber, struct EventKeyFindContext { - XfceShortcutsGrabber *grabber; - GdkModifierType modifiers; - guint keyval; - const gchar *result; + GdkModifierType modifiers; + guint keyval; + const gchar *result; }; @@ -461,7 +460,6 @@ xfce_shortcuts_grabber_event_filter (GdkXEvent *gdk_xevent, if (xevent->type != KeyPress) return GDK_FILTER_CONTINUE; - context.grabber = grabber; context.result = NULL; timestamp = xevent->xkey.time; @@ -520,9 +518,9 @@ xfce_shortcuts_grabber_event_filter (GdkXEvent *gdk_xevent, TRACE ("Looking for %s", raw_shortcut_name); g_free (raw_shortcut_name); - g_hash_table_foreach (grabber->priv->keys, - (GHFunc) (void (*)(void)) find_event_key, - &context); + g_hash_table_find (grabber->priv->keys, + (GHRFunc) (void (*)(void)) find_event_key, + &context); if (G_LIKELY (context.result != NULL)) /* We had a positive match */ -- GitLab From 51deff8231b94f040060f663bcdb1c65d090884e Mon Sep 17 00:00:00 2001 From: Jan Ziak <0xe2.0x9a.0x9b@gmail.com> Date: Fri, 26 Feb 2021 06:52:04 +0100 Subject: [PATCH 4/5] shortcuts-grabber: Redesign shortcut regrabbing (Bug #33) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch hopes to fix shortcut grabbing issues related to keyboard layouts while maintaining high performance. The implementation uses a new hash-table for tracking the keycodes grabbed from the X server. The grabbed X11/Xorg keys are reference counted: X11 XGrabKey() is called once per a keycode+modifiers combination and X11 XUngrabKey() is called when the reference count of the combination drops to zero. It is common for the reference counts to, for example, reach the value of 4 if the user is using 4 keyboard layouts, in which case the new implementation will use a single XGrabKey() call compared to 4 such calls in previous implementations. The grab_all() function has been removed and has been replaced by an optimized regrab_all() function which is more efficient than the sequence ungrab_all()+grab_all(). Tested keyboard layouts: - English - English (Colemak) - French (BÉPO) - Slovak (QWERTY) Test environments: - Arch Linux (FR-BÉPO) - FreeBSD (basic testing) - Gentoo Linux (EN, EN-Colemak, SK-QWERTY) - Xubuntu (basic testing) Closes: https://gitlab.xfce.org/xfce/libxfce4ui/-/issues/33 --- libxfce4kbd-private/xfce-shortcuts-grabber.c | 598 ++++++++++++++----- 1 file changed, 449 insertions(+), 149 deletions(-) diff --git a/libxfce4kbd-private/xfce-shortcuts-grabber.c b/libxfce4kbd-private/xfce-shortcuts-grabber.c index 61f8ef8..1de5929 100644 --- libxfce4kbd-private/xfce-shortcuts-grabber.c +++ libxfce4kbd-private/xfce-shortcuts-grabber.c @@ -54,11 +54,13 @@ static void xfce_shortcuts_grabber_constructed (GObject static void xfce_shortcuts_grabber_finalize (GObject *object); static void xfce_shortcuts_grabber_keys_changed (GdkKeymap *keymap, XfceShortcutsGrabber *grabber); -static void xfce_shortcuts_grabber_grab_all (XfceShortcutsGrabber *grabber); +static void xfce_shortcuts_grabber_regrab_all (XfceShortcutsGrabber *grabber); static void xfce_shortcuts_grabber_ungrab_all (XfceShortcutsGrabber *grabber); static void xfce_shortcuts_grabber_grab (XfceShortcutsGrabber *grabber, + XfceKey *key); +static void xfce_shortcuts_grabber_ungrab (XfceShortcutsGrabber *grabber, XfceKey *key, - gboolean grab); + gboolean trace); static GdkFilterReturn xfce_shortcuts_grabber_event_filter (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data); @@ -67,25 +69,37 @@ static GdkFilterReturn xfce_shortcuts_grabber_event_filter (GdkXEvent struct _XfceShortcutsGrabberPrivate { + /* Maps a shortcut string to a pointer to XfceKey */ GHashTable *keys; - gint xkbEventType, xkbStateGroup; -}; -typedef enum -{ - UNDEFINED_GRAB_STATE = 0, /* Initial value after g_new0(XfceKey) */ - NOT_GRABBED, - GRABBED, -} XfceKeyGrabState; + /* Maps an XfceXGrab to a reference count. + * The reference count tracks the number of shortcuts that grab the XfceXGrab. */ + GHashTable *grabbed_keycodes; + + gint xkbEventType, xkbStateGroup; +}; struct _XfceKey { guint keyval; - guint modifiers; - GArray *keycodes; - XfceKeyGrabState grab_state; + GdkModifierType modifiers; + + /* Information about how the key has been grabbed */ + guint n_keys; /* Equals 0 if the key isn't grabbed */ + GdkKeymapKey *keys; + GdkModifierType non_virtual_modifiers; + guint numlock_modifier; }; +typedef struct +{ + guint keycode; + GdkModifierType non_virtual_modifiers; + guint numlock_modifier; +} XfceXGrab; + +typedef guint XfceXGrabRefcount; + G_DEFINE_TYPE (XfceShortcutsGrabber, xfce_shortcuts_grabber, G_TYPE_OBJECT) @@ -117,6 +131,45 @@ xfce_shortcuts_grabber_class_init (XfceShortcutsGrabberClass *klass) +static void +free_key (gpointer data) +{ + XfceKey *key = data; + g_free (key->keys); + g_free (key); +} + +static gboolean +xgrab_equal (gconstpointer data1, gconstpointer data2) +{ + const XfceXGrab *a = data1; + const XfceXGrab *b = data2; + + if (a == b) + return TRUE; + + return a->keycode == b->keycode && + a->non_virtual_modifiers == b->non_virtual_modifiers && + a->numlock_modifier == b->numlock_modifier; +} + +static void +xgrab_free (gpointer data) +{ + XfceXGrab *g = data; + g_free (g); +} + +static guint +xgrab_hash (gconstpointer data) +{ + const XfceXGrab *g = data; + return g->keycode ^ g->non_virtual_modifiers ^ g->numlock_modifier; +} + + + + static void xfce_shortcuts_grabber_init (XfceShortcutsGrabber *grabber) { @@ -124,7 +177,8 @@ xfce_shortcuts_grabber_init (XfceShortcutsGrabber *grabber) GdkKeymap *keymap; grabber->priv = XFCE_SHORTCUTS_GRABBER_GET_PRIVATE (grabber); - grabber->priv->keys = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + grabber->priv->keys = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, free_key); + grabber->priv->grabbed_keycodes = g_hash_table_new_full (xgrab_hash, xgrab_equal, xgrab_free, g_free); /* Workaround: Make sure modmap is up to date * There is possibly a bug in GTK+ where virtual modifiers are not @@ -173,6 +227,7 @@ xfce_shortcuts_grabber_finalize (GObject *object) xfce_shortcuts_grabber_ungrab_all (grabber); g_hash_table_unref (grabber->priv->keys); + g_hash_table_unref (grabber->priv->grabbed_keycodes); (*G_OBJECT_CLASS (xfce_shortcuts_grabber_parent_class)->finalize) (object); } @@ -187,29 +242,73 @@ xfce_shortcuts_grabber_keys_changed (GdkKeymap *keymap, TRACE ("Keys changed, regrabbing"); - xfce_shortcuts_grabber_grab_all (grabber); + xfce_shortcuts_grabber_regrab_all (grabber); } static gboolean -grab_key (const gchar *shortcut, - XfceKey *key, - XfceShortcutsGrabber *grabber) +xfce_shortcuts_grabber_xgrab (XfceXGrab g, gboolean grab) { - xfce_shortcuts_grabber_grab (grabber, key, TRUE); - return FALSE; -} + GdkDisplay *display = gdk_display_get_default (); + Display *xdisplay = GDK_DISPLAY_XDISPLAY (display); + Window root_window; + guint k; + gboolean success = TRUE; + + /* Ignorable modifiers */ + const guint mod_masks [] = { + 0, + GDK_MOD2_MASK, + g.numlock_modifier | GDK_MOD2_MASK, + GDK_LOCK_MASK, + g.numlock_modifier | GDK_LOCK_MASK, + GDK_MOD5_MASK, + g.numlock_modifier | GDK_MOD5_MASK, + GDK_MOD2_MASK | GDK_LOCK_MASK, + g.numlock_modifier | GDK_MOD2_MASK | GDK_LOCK_MASK, + GDK_MOD2_MASK | GDK_MOD5_MASK, + g.numlock_modifier | GDK_MOD2_MASK | GDK_MOD5_MASK, + GDK_LOCK_MASK | GDK_MOD5_MASK, + g.numlock_modifier | GDK_LOCK_MASK | GDK_MOD5_MASK, + GDK_MOD2_MASK | GDK_LOCK_MASK | GDK_MOD5_MASK, + g.numlock_modifier | GDK_MOD2_MASK | GDK_LOCK_MASK | GDK_MOD5_MASK, + }; + + /* Retrieve the root window of the screen */ + root_window = GDK_WINDOW_XID (gdk_screen_get_root_window (gdk_display_get_default_screen (display))); + + TRACE ("%s keycode %u, non_virtual_modifiers 0x%x", + grab ? "Grabbing" : "Ungrabbing", + g.keycode, g.non_virtual_modifiers); + gdk_x11_display_error_trap_push (display); + for (k = 0; k < G_N_ELEMENTS (mod_masks); k++) + { + /* Take ignorable modifiers into account when grabbing/ungrabbing */ + if (grab) + XGrabKey (xdisplay, + g.keycode, + g.non_virtual_modifiers | mod_masks [k], + root_window, + False, GrabModeAsync, GrabModeAsync); + else + XUngrabKey (xdisplay, + g.keycode, + g.non_virtual_modifiers | mod_masks [k], + root_window); + } -static void -xfce_shortcuts_grabber_grab_all (XfceShortcutsGrabber *grabber) -{ - g_return_if_fail (XFCE_IS_SHORTCUTS_GRABBER (grabber)); - g_hash_table_foreach (grabber->priv->keys, - (GHFunc) (void (*)(void)) grab_key, - grabber); + gdk_display_flush (display); + if (gdk_x11_display_error_trap_pop (display)) + { + g_warning ("Failed to %s keycode %u", + grab ? "grab" : "ungrab", g.keycode); + success = FALSE; + } + + return success; } @@ -219,7 +318,7 @@ ungrab_key (const gchar *shortcut, XfceKey *key, XfceShortcutsGrabber *grabber) { - xfce_shortcuts_grabber_grab (grabber, key, FALSE); + xfce_shortcuts_grabber_ungrab (grabber, key, TRUE); return FALSE; } @@ -236,155 +335,358 @@ xfce_shortcuts_grabber_ungrab_all (XfceShortcutsGrabber *grabber) +static gboolean +get_entries_for_keyval (GdkKeymap *keymap, + guint keyval, + GdkKeymapKey **keys, + gint *n_keys) +{ + /* Get all keys generating keyval */ + if (!gdk_keymap_get_entries_for_keyval (keymap, keyval, keys, n_keys)) + { + TRACE ("Got no keys for keyval"); + return FALSE; + } + + if (G_UNLIKELY (*n_keys <= 0)) + { + g_free (*keys); + return FALSE; + } + + return TRUE; +} + + + +static gboolean +map_virtual_modifiers (GdkKeymap *keymap, + GdkModifierType virtual_modifiers, + GdkModifierType *non_virtual_modifiers) +{ + /* Map virtual modifiers to non-virtual modifiers */ + GdkModifierType non_virtual = virtual_modifiers; + if (!gdk_keymap_map_virtual_modifiers (keymap, &non_virtual)) + return FALSE; + + if (non_virtual == virtual_modifiers && + (GDK_SUPER_MASK | GDK_HYPER_MASK | GDK_META_MASK) & non_virtual) + { + TRACE ("Failed to map virtual modifiers"); + return FALSE; + } + + *non_virtual_modifiers = non_virtual; + return TRUE; +} + + + + static void -xfce_shortcuts_grabber_grab (XfceShortcutsGrabber *grabber, - XfceKey *key, - gboolean grab) +xfce_shortcuts_grabber_regrab_all (XfceShortcutsGrabber *grabber) { - GdkModifierType numlock_modifier; - GdkKeymapKey *keys; - GdkDisplay *display; - GdkKeymap *keymap; - gchar *shortcut_name; - guint modifiers; - guint k; - gint i; - gint j; - gint n_keys; - gint screens; + GdkDisplay *display; + Display *xdisplay; + GdkKeymap *keymap; + guint numlock_modifier; + GHashTable *grabbed_keycodes; + GHashTableIter iter; + gpointer hash_value; + guint n_already_grabbed = 0; + guint n_regrab = 0; + XfceKey **regrab; /* list of keys to re-grab */ + guint i; g_return_if_fail (XFCE_IS_SHORTCUTS_GRABBER (grabber)); - g_return_if_fail (key != NULL); - - if (key->grab_state == (grab ? GRABBED : NOT_GRABBED)) { - TRACE (grab ? "Key already grabbed" : "Key already ungrabbed"); - return; - } - key->grab_state = UNDEFINED_GRAB_STATE; display = gdk_display_get_default (); - screens = 1; + xdisplay = GDK_DISPLAY_XDISPLAY (display); keymap = gdk_keymap_get_for_display (display); + numlock_modifier = XkbKeysymToModifiers (xdisplay, GDK_KEY_Num_Lock); + grabbed_keycodes = grabber->priv->grabbed_keycodes; + + regrab = g_malloc (g_hash_table_size (grabber->priv->keys) * sizeof (*regrab)); + + /* Phase 1: Ungrab all keys that need to be re-grabbed + * and collect them into the 'regrab' list */ + g_hash_table_iter_init (&iter, grabber->priv->keys); + while (g_hash_table_iter_next (&iter, NULL, &hash_value)) + { + XfceKey *const key = hash_value; + GdkKeymapKey *keys; + GdkModifierType non_virtual_modifiers; + gint n_keys; + gboolean already_grabbed; + + if (!map_virtual_modifiers (keymap, key->modifiers, &non_virtual_modifiers)) + continue; + if (!get_entries_for_keyval (keymap, key->keyval, &keys, &n_keys)) + continue; + + already_grabbed = TRUE; + if (key->n_keys == (guint) n_keys && + key->non_virtual_modifiers == non_virtual_modifiers && + key->numlock_modifier == numlock_modifier) + { + gint j; + for (j = 0; j < n_keys; j++) + if (memcmp (&key->keys[j], &keys[j], sizeof(*keys)) != 0) + { + already_grabbed = FALSE; + break; + } + } + else + already_grabbed = FALSE; + + if (already_grabbed) + { + n_already_grabbed++; + g_free (keys); + } + else + { + /* Undo current X11 grabs of the key */ + xfce_shortcuts_grabber_ungrab (grabber, key, FALSE); + + /* Set key->keys to the keycodes that need to be grabbed in phase 2 */ + if (G_UNLIKELY (key->keys)) + { + g_free (key->keys); + key->keys = NULL; + } + key->n_keys = n_keys; + if (n_keys != 0) + key->keys = keys; + else + g_free (keys); + key->non_virtual_modifiers = non_virtual_modifiers; + key->numlock_modifier = numlock_modifier; + + /* Remember to grab the key in phase 2 */ + regrab[n_regrab++] = key; + } + } - /* Map virtual modifiers to non-virtual modifiers */ - modifiers = key->modifiers; - gdk_keymap_map_virtual_modifiers (keymap, &modifiers); + TRACE ("n_already_grabbed=%u, n_regrab=%u", n_already_grabbed, n_regrab); + + /* Phase 2: Grab all keys that have been stored in the 'regrab' list */ + for (i = 0; i < n_regrab; i++) + { + XfceKey *const key = regrab[i]; + guint j; + +#ifdef DEBUG_TRACE + gchar *shortcut_name = gtk_accelerator_name (key->keyval, key->non_virtual_modifiers); + TRACE (key->n_keys==0 ? "Grabbing %s" : "Regrabbing %s", shortcut_name); + TRACE (" key->keyval: %d", key->keyval); + TRACE (" key->modifiers: 0x%x", key->modifiers); + TRACE (" key->non_virtual_modifiers: 0x%x", key->non_virtual_modifiers); + TRACE (" key->n_keys: %d", key->n_keys); + g_free (shortcut_name); + shortcut_name = NULL; +#endif - /* Debugging information */ - shortcut_name = gtk_accelerator_name (key->keyval, modifiers); + /* Grab all hardware keys generating keyval */ + for (j = 0; j < key->n_keys;) + { + XfceXGrab g; + gpointer refcount; + + g.keycode = key->keys[j].keycode; + g.non_virtual_modifiers = key->non_virtual_modifiers; + g.numlock_modifier = key->numlock_modifier; + if (!g_hash_table_lookup_extended (grabbed_keycodes, &g, NULL, &refcount)) + { + if (xfce_shortcuts_grabber_xgrab (g, TRUE)) + { + XfceXGrab *g1 = g_new (XfceXGrab, 1); + XfceXGrabRefcount *refcount1 = g_new (XfceXGrabRefcount, 1); + *g1 = g; + *refcount1 = 1; + g_hash_table_insert (grabbed_keycodes, g1, refcount1); + j++; + } + else + /* Failed to grab key->keys[j], remove it from key->keys */ + key->keys[j] = key->keys[--key->n_keys]; + } + else + { + // 'g' has already been grabbed, increment its refcount only + XfceXGrabRefcount *refcount1 = refcount; + (*refcount1)++; + TRACE ("keycode %u, non_virtual_modifiers 0x%x: ++refcount = %u", + g.keycode, g.non_virtual_modifiers, *refcount1); + j++; + } + } + + if (key->n_keys == 0 && key->keys != NULL) + { + g_free (key->keys); + key->keys = NULL; + } + } - TRACE (grab ? "Grabbing %s" : "Ungrabbing %s", shortcut_name); - TRACE ("Keyval: %d", key->keyval); - TRACE ("Modifiers: 0x%x", modifiers); + g_free (regrab); +} + + +static void +xfce_shortcuts_grabber_grab (XfceShortcutsGrabber *grabber, XfceKey *key) +{ + GdkDisplay *display; + Display *xdisplay; + GdkKeymap *keymap; + guint numlock_modifier; + GHashTable *grabbed_keycodes; + GdkKeymapKey *keys; + GdkModifierType non_virtual_modifiers; + gint i, n_keys; +#ifdef DEBUG_TRACE + gchar *shortcut_name; +#endif + + display = gdk_display_get_default (); + xdisplay = GDK_DISPLAY_XDISPLAY (display); + keymap = gdk_keymap_get_for_display (display); + numlock_modifier = XkbKeysymToModifiers (xdisplay, GDK_KEY_Num_Lock); + grabbed_keycodes = grabber->priv->grabbed_keycodes; + + if (!map_virtual_modifiers (keymap, key->modifiers, &non_virtual_modifiers)) + return; + if (!get_entries_for_keyval (keymap, key->keyval, &keys, &n_keys)) + return; + +#ifdef DEBUG_TRACE + shortcut_name = gtk_accelerator_name (key->keyval, non_virtual_modifiers); + TRACE (key->n_keys==0 ? "Grabbing %s" : "Regrabbing %s", shortcut_name); + TRACE (" key->keyval: %d", key->keyval); + TRACE (" key->modifiers: 0x%x", key->modifiers); + TRACE (" non_virtual_modifiers: 0x%x", non_virtual_modifiers); + TRACE (" n_keys: %d", n_keys); g_free (shortcut_name); + shortcut_name = NULL; +#endif - if (modifiers == key->modifiers && - (GDK_SUPER_MASK | GDK_HYPER_MASK | GDK_META_MASK) & modifiers) + /* Undo old grabs (just in case there are some old grabs) */ + if (G_UNLIKELY (key->n_keys != 0)) { - TRACE ("Failed to map virtual modifiers"); - return; + g_warning ("keyval %u already grabbed", key->keyval); + xfce_shortcuts_grabber_ungrab (grabber, key, TRUE); } - /* Get all keys generating keyval */ - if (!gdk_keymap_get_entries_for_keyval (keymap,key->keyval, - &keys, &n_keys)) + /* Grab all hardware keys generating keyval */ + for (i = 0; i < n_keys;) { - TRACE ("Got no keys for keyval"); - return; + XfceXGrab g; + gpointer refcount; + + g.keycode = keys[i].keycode; + g.non_virtual_modifiers = non_virtual_modifiers; + g.numlock_modifier = numlock_modifier; + if (!g_hash_table_lookup_extended (grabbed_keycodes, &g, NULL, &refcount)) + { + if (xfce_shortcuts_grabber_xgrab (g, TRUE)) + { + XfceXGrab *g1 = g_new (XfceXGrab, 1); + XfceXGrabRefcount *refcount1 = g_new (XfceXGrabRefcount, 1); + *g1 = g; + *refcount1 = 1; + g_hash_table_insert (grabbed_keycodes, g1, refcount1); + TRACE ("[group %d] keycode %u, non_virtual_modifiers 0x%x: refcount := %u", + keys[i].group, g.keycode, g.non_virtual_modifiers, *refcount1); + i++; + } + else + /* Failed to grab keys[i], remove it from keys */ + keys[i] = keys[--n_keys]; + } + else + { + // 'g' has already been grabbed, increment its refcount only + XfceXGrabRefcount *refcount1 = refcount; + (*refcount1)++; + TRACE ("[group %d] keycode %u, non_virtual_modifiers 0x%x: ++refcount = %u", + keys[i].group, g.keycode, g.non_virtual_modifiers, *refcount1); + i++; + } } - if (n_keys == 0) - { - g_free (keys); + /* Set key->keys to the list of keys that been succesfully grabbed */ + g_free (key->keys); + key->keys = NULL; + key->n_keys = n_keys; + if (n_keys != 0) + key->keys = keys; + else + g_free (keys); + key->non_virtual_modifiers = non_virtual_modifiers; + key->numlock_modifier = numlock_modifier; +} - TRACE ("Got 0 keys for keyval"); - return; - } +static void +xfce_shortcuts_grabber_ungrab (XfceShortcutsGrabber *grabber, XfceKey *key, + gboolean trace) +{ + GHashTable *grabbed_keycodes; + guint i; - numlock_modifier = - XkbKeysymToModifiers (GDK_DISPLAY_XDISPLAY (display), GDK_KEY_Num_Lock); + grabbed_keycodes = grabber->priv->grabbed_keycodes; - key->grab_state = (grab ? GRABBED : NOT_GRABBED); - for (i = 0; i < n_keys; i ++) + if (trace) { - /* Grab all hardware keys generating keyval */ + gchar *shortcut_name = gtk_accelerator_name (key->keyval, key->non_virtual_modifiers); + TRACE ("Ungrabbing %s", shortcut_name); + TRACE (" key->keyval: %d", key->keyval); + TRACE (" key->modifiers: 0x%x", key->modifiers); + TRACE (" key->non_virtual_modifiers: 0x%x", key->non_virtual_modifiers); + TRACE (" key->n_keys: %u", key->n_keys); + g_free (shortcut_name); + } - TRACE ("Keycode: %d", keys[i].keycode); + for (i = 0; i < key->n_keys; i++) + { + XfceXGrab g; + gpointer refcount; - for (j = 0; j < screens; j++) + g.keycode = key->keys[i].keycode; + g.non_virtual_modifiers = key->non_virtual_modifiers; + g.numlock_modifier = key->numlock_modifier; + if (G_LIKELY (g_hash_table_lookup_extended (grabbed_keycodes, &g, NULL, &refcount))) { - /* Do the grab on all screens */ - Window root_window; - - /* Ignorable modifiers */ - guint mod_masks [] = { - 0, - GDK_MOD2_MASK, - numlock_modifier | GDK_MOD2_MASK, - GDK_LOCK_MASK, - numlock_modifier | GDK_LOCK_MASK, - GDK_MOD5_MASK, - numlock_modifier | GDK_MOD5_MASK, - GDK_MOD2_MASK | GDK_LOCK_MASK, - numlock_modifier | GDK_MOD2_MASK | GDK_LOCK_MASK, - GDK_MOD2_MASK | GDK_MOD5_MASK, - numlock_modifier | GDK_MOD2_MASK | GDK_MOD5_MASK, - GDK_LOCK_MASK | GDK_MOD5_MASK, - numlock_modifier | GDK_LOCK_MASK | GDK_MOD5_MASK, - GDK_MOD2_MASK | GDK_LOCK_MASK | GDK_MOD5_MASK, - numlock_modifier | GDK_MOD2_MASK | GDK_LOCK_MASK | GDK_MOD5_MASK, - }; - - /* Retrieve the root window of the screen */ - root_window = GDK_WINDOW_XID (gdk_screen_get_root_window (gdk_display_get_default_screen (display))); - gdk_x11_display_error_trap_push (display); - - for (k = 0; k < G_N_ELEMENTS (mod_masks); k++) + XfceXGrabRefcount *refcount1 = refcount; + if (G_LIKELY (*refcount1 != 0)) { - /* Take ignorable modifiers into account when grabbing */ - if (grab) - XGrabKey (GDK_DISPLAY_XDISPLAY (display), - keys[i].keycode, - modifiers | mod_masks [k], - root_window, - False, - GrabModeAsync, - GrabModeAsync); - else + (*refcount1)--; + if (trace) + TRACE ("[group %d] keycode %u, non_virtual_modifiers 0x%x: --refcount = %u", + key->keys[i].group, g.keycode, g.non_virtual_modifiers, *refcount1); + if(*refcount1 == 0) { - if (i >= (gint) key->keycodes->len) - break; - XUngrabKey (GDK_DISPLAY_XDISPLAY (display), - g_array_index (key->keycodes, guint, i), - modifiers | mod_masks [k], - root_window); + xfce_shortcuts_grabber_xgrab (g, FALSE); + g_hash_table_remove (grabbed_keycodes, &g); } } - - gdk_display_flush (display); - - if (gdk_x11_display_error_trap_pop (display)) + else { - TRACE (grab ? "Failed to grab" : "Failed to ungrab"); - key->grab_state = UNDEFINED_GRAB_STATE; + g_warning ("corrupted refcount"); } } - /* Remember the old keycode, as we need it to ungrab. */ - if (grab) - g_array_append_val (key->keycodes, keys[i].keycode); else - g_array_index (key->keycodes, guint, i) = UINT_MAX; - } - - /* Cleanup elements containing UINT_MAX from the key->keycodes array */ - for (i = key->keycodes->len - 1; i >= 0; i --) - { - if (g_array_index (key->keycodes, guint, i) == UINT_MAX) - g_array_remove_index_fast (key->keycodes, i); + { + g_warning ("corrupted hashtable"); + } } - g_free (keys); + g_free (key->keys); + key->keys = NULL; + key->n_keys = 0; + key->non_virtual_modifiers = 0; + key->numlock_modifier = 0; } @@ -451,8 +753,7 @@ xfce_shortcuts_grabber_event_filter (GdkXEvent *gdk_xevent, if (grabber->priv->xkbStateGroup != e->state.group) { grabber->priv->xkbStateGroup = e->state.group; - xfce_shortcuts_grabber_ungrab_all (grabber); - xfce_shortcuts_grabber_grab_all (grabber); + xfce_shortcuts_grabber_regrab_all (grabber); } } } @@ -553,19 +854,18 @@ xfce_shortcuts_grabber_add (XfceShortcutsGrabber *grabber, g_return_if_fail (shortcut != NULL); key = g_new0 (XfceKey, 1); - key->keycodes = g_array_new (FALSE, TRUE, sizeof (guint)); gtk_accelerator_parse (shortcut, &key->keyval, &key->modifiers); + TRACE ("parse %s -> keyval=0x%x, modifiers=0x%x", shortcut, key->keyval, key->modifiers); if (G_LIKELY (key->keyval != 0)) { - xfce_shortcuts_grabber_grab (grabber, key, TRUE); + xfce_shortcuts_grabber_grab (grabber, key); g_hash_table_insert (grabber->priv->keys, g_strdup (shortcut), key); } else { - g_array_free (key->keycodes, TRUE); - g_free (key); + free_key (key); } } @@ -584,7 +884,7 @@ xfce_shortcuts_grabber_remove (XfceShortcutsGrabber *grabber, if (G_LIKELY (key != NULL)) { - xfce_shortcuts_grabber_grab (grabber, key, FALSE); + xfce_shortcuts_grabber_ungrab (grabber, key, TRUE); g_hash_table_remove (grabber->priv->keys, shortcut); } } -- GitLab From 609b60be1ea7db9140a1d96ad4dccf7d9512b7fd Mon Sep 17 00:00:00 2001 From: Jan Ziak <0xe2.0x9a.0x9b@gmail.com> Date: Sat, 27 Feb 2021 17:34:41 +0100 Subject: [PATCH 5/5] shortcuts-grabber: Filter grabbing by key group Closes: https://gitlab.xfce.org/xfce/libxfce4ui/-/issues/33 --- libxfce4kbd-private/xfce-shortcuts-grabber.c | 162 ++++++++++++------- 1 file changed, 106 insertions(+), 56 deletions(-) diff --git a/libxfce4kbd-private/xfce-shortcuts-grabber.c b/libxfce4kbd-private/xfce-shortcuts-grabber.c index 1de5929..4d21e4a 100644 --- libxfce4kbd-private/xfce-shortcuts-grabber.c +++ libxfce4kbd-private/xfce-shortcuts-grabber.c @@ -59,8 +59,7 @@ static void xfce_shortcuts_grabber_ungrab_all (XfceShortcutsGra static void xfce_shortcuts_grabber_grab (XfceShortcutsGrabber *grabber, XfceKey *key); static void xfce_shortcuts_grabber_ungrab (XfceShortcutsGrabber *grabber, - XfceKey *key, - gboolean trace); + XfceKey *key); static GdkFilterReturn xfce_shortcuts_grabber_event_filter (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data); @@ -318,7 +317,7 @@ ungrab_key (const gchar *shortcut, XfceKey *key, XfceShortcutsGrabber *grabber) { - xfce_shortcuts_grabber_ungrab (grabber, key, TRUE); + xfce_shortcuts_grabber_ungrab (grabber, key); return FALSE; } @@ -337,23 +336,67 @@ xfce_shortcuts_grabber_ungrab_all (XfceShortcutsGrabber *grabber) static gboolean get_entries_for_keyval (GdkKeymap *keymap, + gint group, guint keyval, GdkKeymapKey **keys, - gint *n_keys) + guint *n_keys) { - /* Get all keys generating keyval */ - if (!gdk_keymap_get_entries_for_keyval (keymap, keyval, keys, n_keys)) + GdkKeymapKey *keys1; + gint n_keys1; + + *keys = NULL; + *n_keys = 0; + + /* Get all keys generating keyval */ + if (!gdk_keymap_get_entries_for_keyval (keymap, keyval, &keys1, &n_keys1)) { TRACE ("Got no keys for keyval"); return FALSE; } - if (G_UNLIKELY (*n_keys <= 0)) + if (G_UNLIKELY (n_keys1 <= 0)) { - g_free (*keys); + g_free (keys1); return FALSE; } + /* Filter keys by group */ + { + gboolean group0_only; + gint i, n_matches; + + /* For keys such as F12: + * keys1[i].group is always 0 (even if n_keys1 >= 2) + * and thus n_matches will be zero if group != 0 */ + + group0_only = TRUE; + n_matches = 0; + for (i = 0; i < n_keys1; i++) + { + group0_only &= (keys1[i].group == 0) ? TRUE : FALSE; + if (keys1[i].group == group) + n_matches++; + } + + if (!group0_only || n_matches != 0) + { + /* Remove keys that do not match the group*/ + for (i = 0; i < n_keys1;) + if (keys1[i].group == group) + i++; + else + keys1[i] = keys1[--n_keys1]; + } + } + + if (G_UNLIKELY (n_keys1 == 0)) + { + g_free (keys1); + keys1 = NULL; + } + + *keys = keys1; + *n_keys = n_keys1; return TRUE; } @@ -397,6 +440,7 @@ xfce_shortcuts_grabber_regrab_all (XfceShortcutsGrabber *grabber) guint n_regrab = 0; XfceKey **regrab; /* list of keys to re-grab */ guint i; + gint group; g_return_if_fail (XFCE_IS_SHORTCUTS_GRABBER (grabber)); @@ -405,6 +449,9 @@ xfce_shortcuts_grabber_regrab_all (XfceShortcutsGrabber *grabber) keymap = gdk_keymap_get_for_display (display); numlock_modifier = XkbKeysymToModifiers (xdisplay, GDK_KEY_Num_Lock); grabbed_keycodes = grabber->priv->grabbed_keycodes; + group = grabber->priv->xkbStateGroup; + if (G_UNLIKELY (group == -1)) + group = 0; regrab = g_malloc (g_hash_table_size (grabber->priv->keys) * sizeof (*regrab)); @@ -416,20 +463,20 @@ xfce_shortcuts_grabber_regrab_all (XfceShortcutsGrabber *grabber) XfceKey *const key = hash_value; GdkKeymapKey *keys; GdkModifierType non_virtual_modifiers; - gint n_keys; + guint n_keys; gboolean already_grabbed; if (!map_virtual_modifiers (keymap, key->modifiers, &non_virtual_modifiers)) continue; - if (!get_entries_for_keyval (keymap, key->keyval, &keys, &n_keys)) + if (!get_entries_for_keyval (keymap, group, key->keyval, &keys, &n_keys)) continue; already_grabbed = TRUE; - if (key->n_keys == (guint) n_keys && + if (key->n_keys == n_keys && key->non_virtual_modifiers == non_virtual_modifiers && key->numlock_modifier == numlock_modifier) { - gint j; + guint j; for (j = 0; j < n_keys; j++) if (memcmp (&key->keys[j], &keys[j], sizeof(*keys)) != 0) { @@ -448,7 +495,8 @@ xfce_shortcuts_grabber_regrab_all (XfceShortcutsGrabber *grabber) else { /* Undo current X11 grabs of the key */ - xfce_shortcuts_grabber_ungrab (grabber, key, FALSE); + if (key->n_keys != 0) + xfce_shortcuts_grabber_ungrab (grabber, key); /* Set key->keys to the keycodes that need to be grabbed in phase 2 */ if (G_UNLIKELY (key->keys)) @@ -465,7 +513,8 @@ xfce_shortcuts_grabber_regrab_all (XfceShortcutsGrabber *grabber) key->numlock_modifier = numlock_modifier; /* Remember to grab the key in phase 2 */ - regrab[n_regrab++] = key; + if (n_keys != 0) + regrab[n_regrab++] = key; } } @@ -478,14 +527,15 @@ xfce_shortcuts_grabber_regrab_all (XfceShortcutsGrabber *grabber) guint j; #ifdef DEBUG_TRACE - gchar *shortcut_name = gtk_accelerator_name (key->keyval, key->non_virtual_modifiers); - TRACE (key->n_keys==0 ? "Grabbing %s" : "Regrabbing %s", shortcut_name); - TRACE (" key->keyval: %d", key->keyval); - TRACE (" key->modifiers: 0x%x", key->modifiers); - TRACE (" key->non_virtual_modifiers: 0x%x", key->non_virtual_modifiers); - TRACE (" key->n_keys: %d", key->n_keys); - g_free (shortcut_name); - shortcut_name = NULL; + { + gchar *shortcut_name = gtk_accelerator_name (key->keyval, key->non_virtual_modifiers); + TRACE (key->n_keys==0 ? "Grabbing %s" : "Regrabbing %s", shortcut_name); + TRACE (" key->keyval: %d", key->keyval); + TRACE (" key->modifiers: 0x%x", key->modifiers); + TRACE (" key->non_virtual_modifiers: 0x%x", key->non_virtual_modifiers); + TRACE (" key->n_keys: %u", key->n_keys); + g_free (shortcut_name); + } #endif /* Grab all hardware keys generating keyval */ @@ -545,38 +595,40 @@ xfce_shortcuts_grabber_grab (XfceShortcutsGrabber *grabber, XfceKey *key) GHashTable *grabbed_keycodes; GdkKeymapKey *keys; GdkModifierType non_virtual_modifiers; - gint i, n_keys; -#ifdef DEBUG_TRACE - gchar *shortcut_name; -#endif + guint i, n_keys; + gint group; display = gdk_display_get_default (); xdisplay = GDK_DISPLAY_XDISPLAY (display); keymap = gdk_keymap_get_for_display (display); numlock_modifier = XkbKeysymToModifiers (xdisplay, GDK_KEY_Num_Lock); grabbed_keycodes = grabber->priv->grabbed_keycodes; + group = grabber->priv->xkbStateGroup; + if (G_UNLIKELY (group == -1)) + group = 0; if (!map_virtual_modifiers (keymap, key->modifiers, &non_virtual_modifiers)) return; - if (!get_entries_for_keyval (keymap, key->keyval, &keys, &n_keys)) + if (!get_entries_for_keyval (keymap, group, key->keyval, &keys, &n_keys)) return; #ifdef DEBUG_TRACE - shortcut_name = gtk_accelerator_name (key->keyval, non_virtual_modifiers); - TRACE (key->n_keys==0 ? "Grabbing %s" : "Regrabbing %s", shortcut_name); - TRACE (" key->keyval: %d", key->keyval); - TRACE (" key->modifiers: 0x%x", key->modifiers); - TRACE (" non_virtual_modifiers: 0x%x", non_virtual_modifiers); - TRACE (" n_keys: %d", n_keys); - g_free (shortcut_name); - shortcut_name = NULL; + { + char *shortcut_name = gtk_accelerator_name (key->keyval, non_virtual_modifiers); + TRACE (key->n_keys==0 ? "Grabbing %s" : "Regrabbing %s", shortcut_name); + TRACE (" key->keyval: %d", key->keyval); + TRACE (" key->modifiers: 0x%x", key->modifiers); + TRACE (" non_virtual_modifiers: 0x%x", non_virtual_modifiers); + TRACE (" n_keys: %u", n_keys); + g_free (shortcut_name); + } #endif /* Undo old grabs (just in case there are some old grabs) */ if (G_UNLIKELY (key->n_keys != 0)) { g_warning ("keyval %u already grabbed", key->keyval); - xfce_shortcuts_grabber_ungrab (grabber, key, TRUE); + xfce_shortcuts_grabber_ungrab (grabber, key); } /* Grab all hardware keys generating keyval */ @@ -597,7 +649,7 @@ xfce_shortcuts_grabber_grab (XfceShortcutsGrabber *grabber, XfceKey *key) *g1 = g; *refcount1 = 1; g_hash_table_insert (grabbed_keycodes, g1, refcount1); - TRACE ("[group %d] keycode %u, non_virtual_modifiers 0x%x: refcount := %u", + TRACE ("group %d, keycode %u, non_virtual_modifiers 0x%x: refcount := %u", keys[i].group, g.keycode, g.non_virtual_modifiers, *refcount1); i++; } @@ -610,7 +662,7 @@ xfce_shortcuts_grabber_grab (XfceShortcutsGrabber *grabber, XfceKey *key) // 'g' has already been grabbed, increment its refcount only XfceXGrabRefcount *refcount1 = refcount; (*refcount1)++; - TRACE ("[group %d] keycode %u, non_virtual_modifiers 0x%x: ++refcount = %u", + TRACE ("group %d, keycode %u, non_virtual_modifiers 0x%x: ++refcount = %u", keys[i].group, g.keycode, g.non_virtual_modifiers, *refcount1); i++; } @@ -629,24 +681,24 @@ xfce_shortcuts_grabber_grab (XfceShortcutsGrabber *grabber, XfceKey *key) } static void -xfce_shortcuts_grabber_ungrab (XfceShortcutsGrabber *grabber, XfceKey *key, - gboolean trace) +xfce_shortcuts_grabber_ungrab (XfceShortcutsGrabber *grabber, XfceKey *key) { GHashTable *grabbed_keycodes; guint i; grabbed_keycodes = grabber->priv->grabbed_keycodes; - if (trace) - { - gchar *shortcut_name = gtk_accelerator_name (key->keyval, key->non_virtual_modifiers); - TRACE ("Ungrabbing %s", shortcut_name); - TRACE (" key->keyval: %d", key->keyval); - TRACE (" key->modifiers: 0x%x", key->modifiers); - TRACE (" key->non_virtual_modifiers: 0x%x", key->non_virtual_modifiers); - TRACE (" key->n_keys: %u", key->n_keys); - g_free (shortcut_name); - } +#ifdef DEBUG_TRACE + { + gchar *shortcut_name = gtk_accelerator_name (key->keyval, key->non_virtual_modifiers); + TRACE ("Ungrabbing %s", shortcut_name); + TRACE (" key->keyval: %d", key->keyval); + TRACE (" key->modifiers: 0x%x", key->modifiers); + TRACE (" key->non_virtual_modifiers: 0x%x", key->non_virtual_modifiers); + TRACE (" key->n_keys: %u", key->n_keys); + g_free (shortcut_name); + } +#endif for (i = 0; i < key->n_keys; i++) { @@ -662,9 +714,8 @@ xfce_shortcuts_grabber_ungrab (XfceShortcutsGrabber *grabber, XfceKey *key, if (G_LIKELY (*refcount1 != 0)) { (*refcount1)--; - if (trace) - TRACE ("[group %d] keycode %u, non_virtual_modifiers 0x%x: --refcount = %u", - key->keys[i].group, g.keycode, g.non_virtual_modifiers, *refcount1); + TRACE ("group %d, keycode %u, non_virtual_modifiers 0x%x: --refcount = %u", + key->keys[i].group, g.keycode, g.non_virtual_modifiers, *refcount1); if(*refcount1 == 0) { xfce_shortcuts_grabber_xgrab (g, FALSE); @@ -746,12 +797,11 @@ xfce_shortcuts_grabber_event_filter (GdkXEvent *gdk_xevent, if (xevent->type == grabber->priv->xkbEventType) { const XkbEvent *e = (const XkbEvent*) xevent; - TRACE ("xkb event: any.xkb_type=%d", e->any.xkb_type); if (e->any.xkb_type == XkbStateNotify) { - TRACE ("xkb event: any.xkb_type=XkbStateNotify, state.group=%d", e->state.group); if (grabber->priv->xkbStateGroup != e->state.group) { + TRACE ("xkb event: any.xkb_type=XkbStateNotify, state.group=%d", e->state.group); grabber->priv->xkbStateGroup = e->state.group; xfce_shortcuts_grabber_regrab_all (grabber); } @@ -884,7 +934,7 @@ xfce_shortcuts_grabber_remove (XfceShortcutsGrabber *grabber, if (G_LIKELY (key != NULL)) { - xfce_shortcuts_grabber_ungrab (grabber, key, TRUE); + xfce_shortcuts_grabber_ungrab (grabber, key); g_hash_table_remove (grabber->priv->keys, shortcut); } } -- GitLab