aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuido Falsi <madpilot@FreeBSD.org>2021-03-11 09:05:59 +0000
committerGuido Falsi <madpilot@FreeBSD.org>2021-03-11 09:05:59 +0000
commitfe97c820762a53057849d4ed21ac171c8ffb83e3 (patch)
tree51f1122d10da19be8d362a19791417baa99c26b5
parentf48d9d063fff020523092cd5e6e9ed34e095613e (diff)
downloadports-fe97c820762a53057849d4ed21ac171c8ffb83e3.tar.gz
ports-fe97c820762a53057849d4ed21ac171c8ffb83e3.zip
MFH: r566943
Import patch from upstream to fix key grabbing issues. This replaces previous homegroown patch. PR: 244290 Submitted by: aryeh.friedman@gmail.com Tested by: Jethro Nederhof <jethro@jethron.id.au> Obtained from: https://gitlab.xfce.org/xfce/libxfce4ui/-/merge_requests/27
Notes
Notes: svn path=/branches/2021Q1/; revision=568071
-rw-r--r--x11/libxfce4menu/Makefile2
-rw-r--r--x11/libxfce4menu/files/patch-libxfce4kbd-private_xfce-shortcuts-grabber.c21
-rw-r--r--x11/libxfce4menu/files/patch-shortcuts-grabber-fix-PR271324
3 files changed, 1325 insertions, 22 deletions
diff --git a/x11/libxfce4menu/Makefile b/x11/libxfce4menu/Makefile
index dc197d620fda..4d88868a48b6 100644
--- a/x11/libxfce4menu/Makefile
+++ b/x11/libxfce4menu/Makefile
@@ -3,7 +3,7 @@
PORTNAME= libxfce4menu
PORTVERSION= 4.16.0
-PORTREVISION= 1
+PORTREVISION= 2
CATEGORIES= x11 xfce
MASTER_SITES= XFCE
DISTNAME= libxfce4ui-${DISTVERSIONFULL}
diff --git a/x11/libxfce4menu/files/patch-libxfce4kbd-private_xfce-shortcuts-grabber.c b/x11/libxfce4menu/files/patch-libxfce4kbd-private_xfce-shortcuts-grabber.c
deleted file mode 100644
index c9bf1bdecff8..000000000000
--- a/x11/libxfce4menu/files/patch-libxfce4kbd-private_xfce-shortcuts-grabber.c
+++ /dev/null
@@ -1,21 +0,0 @@
---- libxfce4kbd-private/xfce-shortcuts-grabber.c.orig 2020-11-23 10:16:17 UTC
-+++ libxfce4kbd-private/xfce-shortcuts-grabber.c
-@@ -22,6 +22,8 @@
- #include <config.h>
- #endif
-
-+#include <sys/param.h>
-+
- #include <glib.h>
- #include <glib-object.h>
-
-@@ -180,6 +182,9 @@ xfce_shortcuts_grabber_keys_changed (GdkKeymap
-
- TRACE ("Keys changed, regrabbing");
-
-+#ifdef __FreeBSD__
-+ xfce_shortcuts_grabber_ungrab_all (grabber);
-+#endif
- xfce_shortcuts_grabber_grab_all (grabber);
- }
-
diff --git a/x11/libxfce4menu/files/patch-shortcuts-grabber-fix-PR27 b/x11/libxfce4menu/files/patch-shortcuts-grabber-fix-PR27
new file mode 100644
index 000000000000..c50922d4a68a
--- /dev/null
+++ b/x11/libxfce4menu/files/patch-shortcuts-grabber-fix-PR27
@@ -0,0 +1,1324 @@
+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
+