View | Details | Raw Unified | Return to bug 244290 | Differences between
and this patch

Collapse All | Expand All

(-)Makefile (-1 / +1 lines)
Lines 3-9 Link Here
3
3
4
PORTNAME=	libxfce4menu
4
PORTNAME=	libxfce4menu
5
PORTVERSION=	4.16.0
5
PORTVERSION=	4.16.0
6
PORTREVISION=	1
6
PORTREVISION=	2
7
CATEGORIES=	x11 xfce
7
CATEGORIES=	x11 xfce
8
MASTER_SITES=	XFCE
8
MASTER_SITES=	XFCE
9
DISTNAME=	libxfce4ui-${DISTVERSIONFULL}
9
DISTNAME=	libxfce4ui-${DISTVERSIONFULL}
(-)files/patch-libxfce4kbd-private_xfce-shortcuts-grabber.c (-21 lines)
Lines 1-21 Link Here
1
--- libxfce4kbd-private/xfce-shortcuts-grabber.c.orig	2020-11-23 10:16:17 UTC
2
+++ libxfce4kbd-private/xfce-shortcuts-grabber.c
3
@@ -22,6 +22,8 @@
4
 #include <config.h>
5
 #endif
6
 
7
+#include <sys/param.h>
8
+
9
 #include <glib.h>
10
 #include <glib-object.h>
11
 
12
@@ -180,6 +182,9 @@ xfce_shortcuts_grabber_keys_changed (GdkKeymap        
13
 
14
   TRACE ("Keys changed, regrabbing");
15
 
16
+#ifdef __FreeBSD__
17
+  xfce_shortcuts_grabber_ungrab_all (grabber);
18
+#endif
19
   xfce_shortcuts_grabber_grab_all (grabber);
20
 }
21
 
(-)files/patch-shortcuts-grabber-fix-PR27 (-11 / +1314 lines)
Lines 1-21 Link Here
1
--- libxfce4kbd-private/xfce-shortcuts-grabber.c.orig	2020-11-23 10:16:17 UTC
1
From 7c1e0e71899d13f75fe4177454656049d3f35d54 Mon Sep 17 00:00:00 2001
2
From: Jan Ziak <0xe2.0x9a.0x9b@gmail.com>
3
Date: Mon, 4 Jan 2021 17:01:04 +0100
4
Subject: [PATCH 1/5] shortcuts-grabber: Record xkb state group (Bug #33)
5
6
XkbGroupForCoreState(xevent->xkey.state) returns 0 even after a keyboard
7
layout switch. Instead of using the XkbGroupForCoreState() function, this
8
patch watches for XkbStateNotify events from which it obtains the xkb state
9
group.
10
11
Closes: https://gitlab.xfce.org/xfce/libxfce4ui/-/issues/33
12
See also: https://gitlab.xfce.org/xfce/libxfce4ui/-/merge_requests/33
13
---
14
 libxfce4kbd-private/xfce-shortcuts-grabber.c | 38 ++++++++++++++++----
15
 1 file changed, 31 insertions(+), 7 deletions(-)
16
17
diff --git a/libxfce4kbd-private/xfce-shortcuts-grabber.c b/libxfce4kbd-private/xfce-shortcuts-grabber.c
18
index 60ddfd7..9df45c3 100644
19
--- libxfce4kbd-private/xfce-shortcuts-grabber.c
2
+++ libxfce4kbd-private/xfce-shortcuts-grabber.c
20
+++ libxfce4kbd-private/xfce-shortcuts-grabber.c
3
@@ -22,6 +22,8 @@
21
@@ -61,13 +61,14 @@ static void            xfce_shortcuts_grabber_grab             (XfceShortcutsGra
4
 #include <config.h>
22
                                                                 gboolean                   grab);
5
 #endif
23
 static GdkFilterReturn xfce_shortcuts_grabber_event_filter     (GdkXEvent                 *gdk_xevent,
24
                                                                 GdkEvent                  *event,
25
-                                                                XfceShortcutsGrabber      *grabber);
26
+                                                                gpointer                   data);
6
 
27
 
7
+#include <sys/param.h>
28
 
29
 
30
 struct _XfceShortcutsGrabberPrivate
31
 {
32
   GHashTable *keys;
33
+  gint        xkbEventType, xkbStateGroup;
34
 };
35
 
36
 typedef enum
37
@@ -141,20 +142,26 @@ static void
38
 xfce_shortcuts_grabber_constructed (GObject *object)
39
 {
40
   GdkDisplay *display;
41
+  Display    *xdisplay;
42
   GdkKeymap  *keymap;
43
 
44
   XfceShortcutsGrabber *grabber = XFCE_SHORTCUTS_GRABBER (object);
45
 
46
   display = gdk_display_get_default ();
47
+  xdisplay = GDK_DISPLAY_XDISPLAY (display);
48
   keymap = gdk_keymap_get_for_display (display);
49
   g_signal_connect (keymap, "keys-changed", G_CALLBACK (xfce_shortcuts_grabber_keys_changed),
50
                     grabber);
51
 
52
+  if (G_UNLIKELY (!XkbQueryExtension (xdisplay, 0, &grabber->priv->xkbEventType, 0, 0, 0)))
53
+    grabber->priv->xkbEventType = -1;
54
+  grabber->priv->xkbStateGroup = -1;
8
+
55
+
9
 #include <glib.h>
56
   /* Flush events before adding the event filter */
10
 #include <glib-object.h>
57
-  XAllowEvents (GDK_DISPLAY_XDISPLAY (display), AsyncBoth, CurrentTime);
58
+  XAllowEvents (xdisplay, AsyncBoth, CurrentTime);
11
 
59
 
12
@@ -180,6 +182,9 @@ xfce_shortcuts_grabber_keys_changed (GdkKeymap        
60
   /* Add event filter */
61
-  gdk_window_add_filter (NULL, (GdkFilterFunc) xfce_shortcuts_grabber_event_filter, grabber);
62
+  gdk_window_add_filter (NULL, xfce_shortcuts_grabber_event_filter, grabber);
63
 }
13
 
64
 
65
 
66
@@ -417,10 +424,11 @@ find_event_key (const gchar                *shortcut,
67
 
68
 
69
 static GdkFilterReturn
70
-xfce_shortcuts_grabber_event_filter (GdkXEvent            *gdk_xevent,
71
-                                     GdkEvent             *event,
72
-                                     XfceShortcutsGrabber *grabber)
73
+xfce_shortcuts_grabber_event_filter (GdkXEvent *gdk_xevent,
74
+                                     GdkEvent  *event,
75
+                                     gpointer   data)
76
 {
77
+  XfceShortcutsGrabber       *const grabber = data;
78
   struct EventKeyFindContext  context;
79
   GdkKeymap                  *keymap;
80
   GdkModifierType             consumed, modifiers;
81
@@ -434,6 +442,22 @@ xfce_shortcuts_grabber_event_filter (GdkXEvent            *gdk_xevent,
82
 
83
   xevent = (XEvent *) gdk_xevent;
84
 
85
+  if (xevent->type == grabber->priv->xkbEventType)
86
+    {
87
+      const XkbEvent *e = (const XkbEvent*) xevent;
88
+      TRACE ("xkb event: any.xkb_type=%d", e->any.xkb_type);
89
+      if (e->any.xkb_type == XkbStateNotify)
90
+        {
91
+          TRACE ("xkb event: any.xkb_type=XkbStateNotify, state.group=%d", e->state.group);
92
+          if (grabber->priv->xkbStateGroup != e->state.group)
93
+            {
94
+              grabber->priv->xkbStateGroup = e->state.group;
95
+              xfce_shortcuts_grabber_ungrab_all (grabber);
96
+              xfce_shortcuts_grabber_grab_all (grabber);
97
+            }
98
+        }
99
+    }
100
+
101
   if (xevent->type != KeyPress)
102
     return GDK_FILTER_CONTINUE;
103
 
104
@@ -450,7 +474,7 @@ xfce_shortcuts_grabber_event_filter (GdkXEvent            *gdk_xevent,
105
 
106
   gdk_keymap_translate_keyboard_state (keymap, xevent->xkey.keycode,
107
                                        modifiers,
108
-                                       XkbGroupForCoreState (xevent->xkey.state),
109
+                                       grabber->priv->xkbStateGroup,
110
                                        &keyval, NULL, NULL, &consumed);
111
 
112
   /* We want Alt + Print to be Alt + Print not SysReq. See bug #7897 */
113
-- 
114
GitLab
115
116
117
From 5d34aac693e160de3d22d1700b89664dcac12394 Mon Sep 17 00:00:00 2001
118
From: Jan Ziak <0xe2.0x9a.0x9b@gmail.com>
119
Date: Fri, 26 Feb 2021 05:27:16 +0100
120
Subject: [PATCH 2/5] shortcuts: Fix a memory leak
121
122
---
123
 libxfce4kbd-private/xfce-shortcuts-provider.c | 1 +
124
 1 file changed, 1 insertion(+)
125
126
diff --git a/libxfce4kbd-private/xfce-shortcuts-provider.c b/libxfce4kbd-private/xfce-shortcuts-provider.c
127
index b7f7a47..83ab6c0 100644
128
--- libxfce4kbd-private/xfce-shortcuts-provider.c
129
+++ libxfce4kbd-private/xfce-shortcuts-provider.c
130
@@ -711,6 +711,7 @@ void
131
 xfce_shortcuts_free (GList *shortcuts)
132
 {
133
   g_list_foreach (shortcuts, (GFunc) (void (*)(void)) xfce_shortcut_free, NULL);
134
+  g_list_free (shortcuts);
135
 }
136
 
137
 
138
-- 
139
GitLab
140
141
142
From c18f068ab2bd69647af6519e389d76728c1f924e Mon Sep 17 00:00:00 2001
143
From: Jan Ziak <0xe2.0x9a.0x9b@gmail.com>
144
Date: Fri, 26 Feb 2021 05:57:42 +0100
145
Subject: [PATCH 3/5] shortcuts-grabber: Stop search when the first match is
146
 found
147
148
---
149
 libxfce4kbd-private/xfce-shortcuts-grabber.c | 14 ++++++--------
150
 1 file changed, 6 insertions(+), 8 deletions(-)
151
152
diff --git a/libxfce4kbd-private/xfce-shortcuts-grabber.c b/libxfce4kbd-private/xfce-shortcuts-grabber.c
153
index 9df45c3..61f8ef8 100644
154
--- libxfce4kbd-private/xfce-shortcuts-grabber.c
155
+++ libxfce4kbd-private/xfce-shortcuts-grabber.c
156
@@ -391,10 +391,9 @@ xfce_shortcuts_grabber_grab (XfceShortcutsGrabber *grabber,
157
 
158
 struct EventKeyFindContext
159
 {
160
-  XfceShortcutsGrabber *grabber;
161
-  GdkModifierType       modifiers;
162
-  guint                 keyval;
163
-  const gchar          *result;
164
+  GdkModifierType modifiers;
165
+  guint           keyval;
166
+  const gchar    *result;
167
 };
168
 
169
 
170
@@ -461,7 +460,6 @@ xfce_shortcuts_grabber_event_filter (GdkXEvent *gdk_xevent,
171
   if (xevent->type != KeyPress)
172
     return GDK_FILTER_CONTINUE;
173
 
174
-  context.grabber = grabber;
175
   context.result = NULL;
176
   timestamp = xevent->xkey.time;
177
 
178
@@ -520,9 +518,9 @@ xfce_shortcuts_grabber_event_filter (GdkXEvent *gdk_xevent,
179
   TRACE ("Looking for %s", raw_shortcut_name);
180
   g_free (raw_shortcut_name);
181
 
182
-  g_hash_table_foreach (grabber->priv->keys,
183
-                        (GHFunc) (void (*)(void)) find_event_key,
184
-                        &context);
185
+  g_hash_table_find (grabber->priv->keys,
186
+                     (GHRFunc) (void (*)(void)) find_event_key,
187
+                     &context);
188
 
189
   if (G_LIKELY (context.result != NULL))
190
     /* We had a positive match */
191
-- 
192
GitLab
193
194
195
From 51deff8231b94f040060f663bcdb1c65d090884e Mon Sep 17 00:00:00 2001
196
From: Jan Ziak <0xe2.0x9a.0x9b@gmail.com>
197
Date: Fri, 26 Feb 2021 06:52:04 +0100
198
Subject: [PATCH 4/5] shortcuts-grabber: Redesign shortcut regrabbing (Bug #33)
199
MIME-Version: 1.0
200
Content-Type: text/plain; charset=UTF-8
201
Content-Transfer-Encoding: 8bit
202
203
This patch hopes to fix shortcut grabbing issues related to keyboard
204
layouts while maintaining high performance.
205
206
The implementation uses a new hash-table for tracking the keycodes grabbed
207
from the X server. The grabbed X11/Xorg keys are reference counted:
208
X11 XGrabKey() is called once per a keycode+modifiers combination and
209
X11 XUngrabKey() is called when the reference count of the combination
210
drops to zero. It is common for the reference counts to, for example,
211
reach the value of 4 if the user is using 4 keyboard layouts, in which
212
case the new implementation will use a single XGrabKey() call compared
213
to 4 such calls in previous implementations.
214
215
The grab_all() function has been removed and has been replaced by an
216
optimized regrab_all() function which is more efficient than the sequence
217
ungrab_all()+grab_all().
218
219
Tested keyboard layouts:
220
 - English
221
 - English (Colemak)
222
 - French (BÉPO)
223
 - Slovak (QWERTY)
224
225
Test environments:
226
 - Arch Linux (FR-BÉPO)
227
 - FreeBSD (basic testing)
228
 - Gentoo Linux (EN, EN-Colemak, SK-QWERTY)
229
 - Xubuntu (basic testing)
230
231
Closes: https://gitlab.xfce.org/xfce/libxfce4ui/-/issues/33
232
---
233
 libxfce4kbd-private/xfce-shortcuts-grabber.c | 598 ++++++++++++++-----
234
 1 file changed, 449 insertions(+), 149 deletions(-)
235
236
diff --git a/libxfce4kbd-private/xfce-shortcuts-grabber.c b/libxfce4kbd-private/xfce-shortcuts-grabber.c
237
index 61f8ef8..1de5929 100644
238
--- libxfce4kbd-private/xfce-shortcuts-grabber.c
239
+++ libxfce4kbd-private/xfce-shortcuts-grabber.c
240
@@ -54,11 +54,13 @@ static void            xfce_shortcuts_grabber_constructed      (GObject
241
 static void            xfce_shortcuts_grabber_finalize         (GObject                   *object);
242
 static void            xfce_shortcuts_grabber_keys_changed     (GdkKeymap                 *keymap,
243
                                                                 XfceShortcutsGrabber      *grabber);
244
-static void            xfce_shortcuts_grabber_grab_all         (XfceShortcutsGrabber      *grabber);
245
+static void            xfce_shortcuts_grabber_regrab_all       (XfceShortcutsGrabber      *grabber);
246
 static void            xfce_shortcuts_grabber_ungrab_all       (XfceShortcutsGrabber      *grabber);
247
 static void            xfce_shortcuts_grabber_grab             (XfceShortcutsGrabber      *grabber,
248
+                                                                XfceKey                   *key);
249
+static void            xfce_shortcuts_grabber_ungrab           (XfceShortcutsGrabber      *grabber,
250
                                                                 XfceKey                   *key,
251
-                                                                gboolean                   grab);
252
+                                                                gboolean                   trace);
253
 static GdkFilterReturn xfce_shortcuts_grabber_event_filter     (GdkXEvent                 *gdk_xevent,
254
                                                                 GdkEvent                  *event,
255
                                                                 gpointer                   data);
256
@@ -67,25 +69,37 @@ static GdkFilterReturn xfce_shortcuts_grabber_event_filter     (GdkXEvent
257
 
258
 struct _XfceShortcutsGrabberPrivate
259
 {
260
+  /* Maps a shortcut string to a pointer to XfceKey */
261
   GHashTable *keys;
262
-  gint        xkbEventType, xkbStateGroup;
263
-};
264
 
265
-typedef enum
266
-{
267
-  UNDEFINED_GRAB_STATE = 0, /* Initial value after g_new0(XfceKey) */
268
-  NOT_GRABBED,
269
-  GRABBED,
270
-} XfceKeyGrabState;
271
+  /* Maps an XfceXGrab to a reference count.
272
+   * The reference count tracks the number of shortcuts that grab the XfceXGrab. */
273
+  GHashTable *grabbed_keycodes;
274
+
275
+  gint xkbEventType, xkbStateGroup;
276
+};
277
 
278
 struct _XfceKey
279
 {
280
   guint            keyval;
281
-  guint            modifiers;
282
-  GArray          *keycodes;
283
-  XfceKeyGrabState grab_state;
284
+  GdkModifierType  modifiers;
285
+
286
+  /* Information about how the key has been grabbed */
287
+  guint            n_keys;  /* Equals 0 if the key isn't grabbed */
288
+  GdkKeymapKey    *keys;
289
+  GdkModifierType  non_virtual_modifiers;
290
+  guint            numlock_modifier;
291
 };
292
 
293
+typedef struct
294
+{
295
+  guint            keycode;
296
+  GdkModifierType  non_virtual_modifiers;
297
+  guint            numlock_modifier;
298
+} XfceXGrab;
299
+
300
+typedef guint XfceXGrabRefcount;
301
+
302
 
303
 
304
 G_DEFINE_TYPE (XfceShortcutsGrabber, xfce_shortcuts_grabber, G_TYPE_OBJECT)
305
@@ -117,6 +131,45 @@ xfce_shortcuts_grabber_class_init (XfceShortcutsGrabberClass *klass)
306
 
307
 
308
 
309
+static void
310
+free_key (gpointer data)
311
+{
312
+  XfceKey *key = data;
313
+  g_free (key->keys);
314
+  g_free (key);
315
+}
316
+
317
+static gboolean
318
+xgrab_equal (gconstpointer data1, gconstpointer data2)
319
+{
320
+  const XfceXGrab *a = data1;
321
+  const XfceXGrab *b = data2;
322
+
323
+  if (a == b)
324
+    return TRUE;
325
+
326
+  return a->keycode == b->keycode &&
327
+         a->non_virtual_modifiers == b->non_virtual_modifiers &&
328
+         a->numlock_modifier == b->numlock_modifier;
329
+}
330
+
331
+static void
332
+xgrab_free (gpointer data)
333
+{
334
+  XfceXGrab *g = data;
335
+  g_free (g);
336
+}
337
+
338
+static guint
339
+xgrab_hash (gconstpointer data)
340
+{
341
+  const XfceXGrab *g = data;
342
+  return g->keycode ^ g->non_virtual_modifiers ^ g->numlock_modifier;
343
+}
344
+
345
+
346
+
347
+
348
 static void
349
 xfce_shortcuts_grabber_init (XfceShortcutsGrabber *grabber)
350
 {
351
@@ -124,7 +177,8 @@ xfce_shortcuts_grabber_init (XfceShortcutsGrabber *grabber)
352
   GdkKeymap       *keymap;
353
 
354
   grabber->priv = XFCE_SHORTCUTS_GRABBER_GET_PRIVATE (grabber);
355
-  grabber->priv->keys = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
356
+  grabber->priv->keys = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, free_key);
357
+  grabber->priv->grabbed_keycodes = g_hash_table_new_full (xgrab_hash, xgrab_equal, xgrab_free, g_free);
358
 
359
   /* Workaround: Make sure modmap is up to date
360
    * There is possibly a bug in GTK+ where virtual modifiers are not
361
@@ -173,6 +227,7 @@ xfce_shortcuts_grabber_finalize (GObject *object)
362
 
363
   xfce_shortcuts_grabber_ungrab_all (grabber);
364
   g_hash_table_unref (grabber->priv->keys);
365
+  g_hash_table_unref (grabber->priv->grabbed_keycodes);
366
 
367
   (*G_OBJECT_CLASS (xfce_shortcuts_grabber_parent_class)->finalize) (object);
368
 }
369
@@ -187,29 +242,73 @@ xfce_shortcuts_grabber_keys_changed (GdkKeymap            *keymap,
370
 
14
   TRACE ("Keys changed, regrabbing");
371
   TRACE ("Keys changed, regrabbing");
15
 
372
 
16
+#ifdef __FreeBSD__
373
-  xfce_shortcuts_grabber_grab_all (grabber);
17
+  xfce_shortcuts_grabber_ungrab_all (grabber);
374
+  xfce_shortcuts_grabber_regrab_all (grabber);
375
 }
376
 
377
 
378
 
379
 static gboolean
380
-grab_key (const gchar          *shortcut,
381
-          XfceKey              *key,
382
-          XfceShortcutsGrabber *grabber)
383
+xfce_shortcuts_grabber_xgrab (XfceXGrab g, gboolean grab)
384
 {
385
-  xfce_shortcuts_grabber_grab (grabber, key, TRUE);
386
-  return FALSE;
387
-}
388
+  GdkDisplay *display = gdk_display_get_default ();
389
+  Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
390
+  Window root_window;
391
+  guint k;
392
+  gboolean success = TRUE;
393
+
394
+  /* Ignorable modifiers */
395
+  const guint mod_masks [] = {
396
+    0,
397
+    GDK_MOD2_MASK,
398
+    g.numlock_modifier | GDK_MOD2_MASK,
399
+    GDK_LOCK_MASK,
400
+    g.numlock_modifier | GDK_LOCK_MASK,
401
+    GDK_MOD5_MASK,
402
+    g.numlock_modifier | GDK_MOD5_MASK,
403
+    GDK_MOD2_MASK | GDK_LOCK_MASK,
404
+    g.numlock_modifier | GDK_MOD2_MASK | GDK_LOCK_MASK,
405
+    GDK_MOD2_MASK | GDK_MOD5_MASK,
406
+    g.numlock_modifier | GDK_MOD2_MASK | GDK_MOD5_MASK,
407
+    GDK_LOCK_MASK | GDK_MOD5_MASK,
408
+    g.numlock_modifier | GDK_LOCK_MASK | GDK_MOD5_MASK,
409
+    GDK_MOD2_MASK | GDK_LOCK_MASK | GDK_MOD5_MASK,
410
+    g.numlock_modifier | GDK_MOD2_MASK | GDK_LOCK_MASK | GDK_MOD5_MASK,
411
+  };
412
+
413
+  /* Retrieve the root window of the screen */
414
+  root_window = GDK_WINDOW_XID (gdk_screen_get_root_window (gdk_display_get_default_screen (display)));
415
+
416
+  TRACE ("%s keycode %u, non_virtual_modifiers 0x%x",
417
+         grab ? "Grabbing" : "Ungrabbing",
418
+         g.keycode, g.non_virtual_modifiers);
419
 
420
+  gdk_x11_display_error_trap_push (display);
421
 
422
+  for (k = 0; k < G_N_ELEMENTS (mod_masks); k++)
423
+    {
424
+      /* Take ignorable modifiers into account when grabbing/ungrabbing */
425
+      if (grab)
426
+        XGrabKey (xdisplay,
427
+                  g.keycode,
428
+                  g.non_virtual_modifiers | mod_masks [k],
429
+                  root_window,
430
+                  False, GrabModeAsync, GrabModeAsync);
431
+      else
432
+        XUngrabKey (xdisplay,
433
+                    g.keycode,
434
+                    g.non_virtual_modifiers | mod_masks [k],
435
+                    root_window);
436
+    }
437
 
438
-static void
439
-xfce_shortcuts_grabber_grab_all (XfceShortcutsGrabber *grabber)
440
-{
441
-  g_return_if_fail (XFCE_IS_SHORTCUTS_GRABBER (grabber));
442
-  g_hash_table_foreach (grabber->priv->keys,
443
-                        (GHFunc) (void (*)(void)) grab_key,
444
-                        grabber);
445
+  gdk_display_flush (display);
446
+  if (gdk_x11_display_error_trap_pop (display))
447
+    {
448
+      g_warning ("Failed to %s keycode %u",
449
+                 grab ? "grab" : "ungrab", g.keycode);
450
+      success = FALSE;
451
+    }
452
+
453
+  return success;
454
 }
455
 
456
 
457
@@ -219,7 +318,7 @@ ungrab_key (const gchar          *shortcut,
458
             XfceKey              *key,
459
             XfceShortcutsGrabber *grabber)
460
 {
461
-  xfce_shortcuts_grabber_grab (grabber, key, FALSE);
462
+  xfce_shortcuts_grabber_ungrab (grabber, key, TRUE);
463
   return FALSE;
464
 }
465
 
466
@@ -236,155 +335,358 @@ xfce_shortcuts_grabber_ungrab_all (XfceShortcutsGrabber *grabber)
467
 
468
 
469
 
470
+static gboolean
471
+get_entries_for_keyval (GdkKeymap     *keymap,
472
+                        guint          keyval,
473
+                        GdkKeymapKey **keys,
474
+                        gint          *n_keys)
475
+{
476
+  /* Get all keys generating keyval */
477
+  if (!gdk_keymap_get_entries_for_keyval (keymap, keyval, keys, n_keys))
478
+    {
479
+      TRACE ("Got no keys for keyval");
480
+      return FALSE;
481
+    }
482
+
483
+  if (G_UNLIKELY (*n_keys <= 0))
484
+    {
485
+      g_free (*keys);
486
+      return FALSE;
487
+    }
488
+
489
+  return TRUE;
490
+}
491
+
492
+
493
+
494
+static gboolean
495
+map_virtual_modifiers (GdkKeymap       *keymap,
496
+                       GdkModifierType  virtual_modifiers,
497
+                       GdkModifierType *non_virtual_modifiers)
498
+{
499
+  /* Map virtual modifiers to non-virtual modifiers */
500
+  GdkModifierType non_virtual = virtual_modifiers;
501
+  if (!gdk_keymap_map_virtual_modifiers (keymap, &non_virtual))
502
+    return FALSE;
503
+
504
+  if (non_virtual == virtual_modifiers &&
505
+      (GDK_SUPER_MASK | GDK_HYPER_MASK | GDK_META_MASK) & non_virtual)
506
+    {
507
+      TRACE ("Failed to map virtual modifiers");
508
+      return FALSE;
509
+    }
510
+
511
+  *non_virtual_modifiers = non_virtual;
512
+  return TRUE;
513
+}
514
+
515
+
516
+
517
+
518
 static void
519
-xfce_shortcuts_grabber_grab (XfceShortcutsGrabber *grabber,
520
-                             XfceKey              *key,
521
-                             gboolean              grab)
522
+xfce_shortcuts_grabber_regrab_all (XfceShortcutsGrabber *grabber)
523
 {
524
-  GdkModifierType  numlock_modifier;
525
-  GdkKeymapKey    *keys;
526
-  GdkDisplay      *display;
527
-  GdkKeymap       *keymap;
528
-  gchar           *shortcut_name;
529
-  guint            modifiers;
530
-  guint            k;
531
-  gint             i;
532
-  gint             j;
533
-  gint             n_keys;
534
-  gint             screens;
535
+  GdkDisplay     *display;
536
+  Display        *xdisplay;
537
+  GdkKeymap      *keymap;
538
+  guint           numlock_modifier;
539
+  GHashTable     *grabbed_keycodes;
540
+  GHashTableIter  iter;
541
+  gpointer        hash_value;
542
+  guint           n_already_grabbed = 0;
543
+  guint           n_regrab = 0;
544
+  XfceKey       **regrab; /* list of keys to re-grab */
545
+  guint           i;
546
 
547
   g_return_if_fail (XFCE_IS_SHORTCUTS_GRABBER (grabber));
548
-  g_return_if_fail (key != NULL);
549
-
550
-  if (key->grab_state == (grab ? GRABBED : NOT_GRABBED)) {
551
-    TRACE (grab ? "Key already grabbed" : "Key already ungrabbed");
552
-    return;
553
-  }
554
-  key->grab_state = UNDEFINED_GRAB_STATE;
555
 
556
   display = gdk_display_get_default ();
557
-  screens = 1;
558
+  xdisplay = GDK_DISPLAY_XDISPLAY (display);
559
   keymap = gdk_keymap_get_for_display (display);
560
+  numlock_modifier = XkbKeysymToModifiers (xdisplay, GDK_KEY_Num_Lock);
561
+  grabbed_keycodes = grabber->priv->grabbed_keycodes;
562
+
563
+  regrab = g_malloc (g_hash_table_size (grabber->priv->keys) * sizeof (*regrab));
564
+
565
+  /* Phase 1: Ungrab all keys that need to be re-grabbed
566
+   *          and collect them into the 'regrab' list */
567
+  g_hash_table_iter_init (&iter, grabber->priv->keys);
568
+  while (g_hash_table_iter_next (&iter, NULL, &hash_value))
569
+  {
570
+    XfceKey         *const key = hash_value;
571
+    GdkKeymapKey    *keys;
572
+    GdkModifierType  non_virtual_modifiers;
573
+    gint             n_keys;
574
+    gboolean         already_grabbed;
575
+
576
+    if (!map_virtual_modifiers (keymap, key->modifiers, &non_virtual_modifiers))
577
+      continue;
578
+    if (!get_entries_for_keyval (keymap, key->keyval, &keys, &n_keys))
579
+      continue;
580
+
581
+    already_grabbed = TRUE;
582
+    if (key->n_keys == (guint) n_keys &&
583
+        key->non_virtual_modifiers == non_virtual_modifiers &&
584
+        key->numlock_modifier == numlock_modifier)
585
+      {
586
+        gint j;
587
+        for (j = 0; j < n_keys; j++)
588
+          if (memcmp (&key->keys[j], &keys[j], sizeof(*keys)) != 0)
589
+            {
590
+              already_grabbed = FALSE;
591
+              break;
592
+            }
593
+      }
594
+    else
595
+      already_grabbed = FALSE;
596
+
597
+    if (already_grabbed)
598
+      {
599
+        n_already_grabbed++;
600
+        g_free (keys);
601
+      }
602
+    else
603
+      {
604
+        /* Undo current X11 grabs of the key */
605
+        xfce_shortcuts_grabber_ungrab (grabber, key, FALSE);
606
+
607
+        /* Set key->keys to the keycodes that need to be grabbed in phase 2 */
608
+        if (G_UNLIKELY (key->keys))
609
+        {
610
+          g_free (key->keys);
611
+          key->keys = NULL;
612
+        }
613
+        key->n_keys = n_keys;
614
+        if (n_keys != 0)
615
+          key->keys = keys;
616
+        else
617
+          g_free (keys);
618
+        key->non_virtual_modifiers = non_virtual_modifiers;
619
+        key->numlock_modifier = numlock_modifier;
620
+
621
+        /* Remember to grab the key in phase 2 */
622
+        regrab[n_regrab++] = key;
623
+      }
624
+  }
625
 
626
-  /* Map virtual modifiers to non-virtual modifiers */
627
-  modifiers = key->modifiers;
628
-  gdk_keymap_map_virtual_modifiers (keymap, &modifiers);
629
+  TRACE ("n_already_grabbed=%u, n_regrab=%u", n_already_grabbed, n_regrab);
630
+
631
+  /* Phase 2: Grab all keys that have been stored in the 'regrab' list */
632
+  for (i = 0; i < n_regrab; i++)
633
+  {
634
+    XfceKey *const key = regrab[i];
635
+    guint    j;
636
+
637
+#ifdef DEBUG_TRACE
638
+    gchar *shortcut_name = gtk_accelerator_name (key->keyval, key->non_virtual_modifiers);
639
+    TRACE (key->n_keys==0 ? "Grabbing %s" : "Regrabbing %s", shortcut_name);
640
+    TRACE ("  key->keyval: %d", key->keyval);
641
+    TRACE ("  key->modifiers: 0x%x", key->modifiers);
642
+    TRACE ("  key->non_virtual_modifiers: 0x%x", key->non_virtual_modifiers);
643
+    TRACE ("  key->n_keys: %d", key->n_keys);
644
+    g_free (shortcut_name);
645
+    shortcut_name = NULL;
18
+#endif
646
+#endif
19
   xfce_shortcuts_grabber_grab_all (grabber);
647
 
648
-  /* Debugging information */
649
-  shortcut_name = gtk_accelerator_name (key->keyval, modifiers);
650
+    /* Grab all hardware keys generating keyval */
651
+    for (j = 0; j < key->n_keys;)
652
+      {
653
+        XfceXGrab g;
654
+        gpointer  refcount;
655
+
656
+        g.keycode = key->keys[j].keycode;
657
+        g.non_virtual_modifiers = key->non_virtual_modifiers;
658
+        g.numlock_modifier = key->numlock_modifier;
659
+        if (!g_hash_table_lookup_extended (grabbed_keycodes, &g, NULL, &refcount))
660
+          {
661
+            if (xfce_shortcuts_grabber_xgrab (g, TRUE))
662
+              {
663
+                XfceXGrab *g1 = g_new (XfceXGrab, 1);
664
+                XfceXGrabRefcount *refcount1 = g_new (XfceXGrabRefcount, 1);
665
+                *g1 = g;
666
+                *refcount1 = 1;
667
+                g_hash_table_insert (grabbed_keycodes, g1, refcount1);
668
+                j++;
669
+              }
670
+            else
671
+              /* Failed to grab key->keys[j], remove it from key->keys */
672
+              key->keys[j] = key->keys[--key->n_keys];
673
+          }
674
+        else
675
+          {
676
+            // 'g' has already been grabbed, increment its refcount only
677
+            XfceXGrabRefcount *refcount1 = refcount;
678
+            (*refcount1)++;
679
+            TRACE ("keycode %u, non_virtual_modifiers 0x%x: ++refcount = %u",
680
+                   g.keycode, g.non_virtual_modifiers, *refcount1);
681
+            j++;
682
+          }
683
+      }
684
+
685
+    if (key->n_keys == 0 && key->keys != NULL)
686
+      {
687
+        g_free (key->keys);
688
+        key->keys = NULL;
689
+      }
690
+  }
691
 
692
-  TRACE (grab ? "Grabbing %s" : "Ungrabbing %s", shortcut_name);
693
-  TRACE ("Keyval: %d", key->keyval);
694
-  TRACE ("Modifiers: 0x%x", modifiers);
695
+  g_free (regrab);
696
+}
697
 
698
+
699
+
700
+static void
701
+xfce_shortcuts_grabber_grab (XfceShortcutsGrabber *grabber, XfceKey *key)
702
+{
703
+  GdkDisplay      *display;
704
+  Display         *xdisplay;
705
+  GdkKeymap       *keymap;
706
+  guint            numlock_modifier;
707
+  GHashTable      *grabbed_keycodes;
708
+  GdkKeymapKey    *keys;
709
+  GdkModifierType  non_virtual_modifiers;
710
+  gint             i, n_keys;
711
+#ifdef DEBUG_TRACE
712
+  gchar           *shortcut_name;
713
+#endif
714
+
715
+  display = gdk_display_get_default ();
716
+  xdisplay = GDK_DISPLAY_XDISPLAY (display);
717
+  keymap = gdk_keymap_get_for_display (display);
718
+  numlock_modifier = XkbKeysymToModifiers (xdisplay, GDK_KEY_Num_Lock);
719
+  grabbed_keycodes = grabber->priv->grabbed_keycodes;
720
+
721
+  if (!map_virtual_modifiers (keymap, key->modifiers, &non_virtual_modifiers))
722
+    return;
723
+  if (!get_entries_for_keyval (keymap, key->keyval, &keys, &n_keys))
724
+    return;
725
+
726
+#ifdef DEBUG_TRACE
727
+  shortcut_name = gtk_accelerator_name (key->keyval, non_virtual_modifiers);
728
+  TRACE (key->n_keys==0 ? "Grabbing %s" : "Regrabbing %s", shortcut_name);
729
+  TRACE ("  key->keyval: %d", key->keyval);
730
+  TRACE ("  key->modifiers: 0x%x", key->modifiers);
731
+  TRACE ("  non_virtual_modifiers: 0x%x", non_virtual_modifiers);
732
+  TRACE ("  n_keys: %d", n_keys);
733
   g_free (shortcut_name);
734
+  shortcut_name = NULL;
735
+#endif
736
 
737
-  if (modifiers == key->modifiers &&
738
-      (GDK_SUPER_MASK | GDK_HYPER_MASK | GDK_META_MASK) & modifiers)
739
+  /* Undo old grabs (just in case there are some old grabs) */
740
+  if (G_UNLIKELY (key->n_keys != 0))
741
     {
742
-      TRACE ("Failed to map virtual modifiers");
743
-      return;
744
+      g_warning ("keyval %u already grabbed", key->keyval);
745
+      xfce_shortcuts_grabber_ungrab (grabber, key, TRUE);
746
     }
747
 
748
-  /* Get all keys generating keyval */
749
-  if (!gdk_keymap_get_entries_for_keyval (keymap,key->keyval,
750
-                                          &keys, &n_keys))
751
+  /* Grab all hardware keys generating keyval */
752
+  for (i = 0; i < n_keys;)
753
     {
754
-      TRACE ("Got no keys for keyval");
755
-      return;
756
+      XfceXGrab g;
757
+      gpointer  refcount;
758
+
759
+      g.keycode = keys[i].keycode;
760
+      g.non_virtual_modifiers = non_virtual_modifiers;
761
+      g.numlock_modifier = numlock_modifier;
762
+      if (!g_hash_table_lookup_extended (grabbed_keycodes, &g, NULL, &refcount))
763
+        {
764
+          if (xfce_shortcuts_grabber_xgrab (g, TRUE))
765
+            {
766
+              XfceXGrab *g1 = g_new (XfceXGrab, 1);
767
+              XfceXGrabRefcount *refcount1 = g_new (XfceXGrabRefcount, 1);
768
+              *g1 = g;
769
+              *refcount1 = 1;
770
+              g_hash_table_insert (grabbed_keycodes, g1, refcount1);
771
+              TRACE ("[group %d] keycode %u, non_virtual_modifiers 0x%x: refcount := %u",
772
+                     keys[i].group, g.keycode, g.non_virtual_modifiers, *refcount1);
773
+              i++;
774
+            }
775
+          else
776
+            /* Failed to grab keys[i], remove it from keys */
777
+            keys[i] = keys[--n_keys];
778
+        }
779
+      else
780
+        {
781
+          // 'g' has already been grabbed, increment its refcount only
782
+          XfceXGrabRefcount *refcount1 = refcount;
783
+          (*refcount1)++;
784
+          TRACE ("[group %d] keycode %u, non_virtual_modifiers 0x%x: ++refcount = %u",
785
+                 keys[i].group, g.keycode, g.non_virtual_modifiers, *refcount1);
786
+          i++;
787
+        }
788
     }
789
 
790
-  if (n_keys == 0)
791
-    {
792
-      g_free (keys);
793
+  /* Set key->keys to the list of keys that been succesfully grabbed */
794
+  g_free (key->keys);
795
+  key->keys = NULL;
796
+  key->n_keys = n_keys;
797
+  if (n_keys != 0)
798
+    key->keys = keys;
799
+  else
800
+    g_free (keys);
801
+  key->non_virtual_modifiers = non_virtual_modifiers;
802
+  key->numlock_modifier = numlock_modifier;
803
+}
804
 
805
-      TRACE ("Got 0 keys for keyval");
806
-      return;
807
-    }
808
+static void
809
+xfce_shortcuts_grabber_ungrab (XfceShortcutsGrabber *grabber, XfceKey *key,
810
+                               gboolean trace)
811
+{
812
+  GHashTable *grabbed_keycodes;
813
+  guint       i;
814
 
815
-  numlock_modifier =
816
-    XkbKeysymToModifiers (GDK_DISPLAY_XDISPLAY (display), GDK_KEY_Num_Lock);
817
+  grabbed_keycodes = grabber->priv->grabbed_keycodes;
818
 
819
-  key->grab_state = (grab ? GRABBED : NOT_GRABBED);
820
-  for (i = 0; i < n_keys; i ++)
821
+  if (trace)
822
     {
823
-      /* Grab all hardware keys generating keyval */
824
+      gchar *shortcut_name = gtk_accelerator_name (key->keyval, key->non_virtual_modifiers);
825
+      TRACE ("Ungrabbing %s", shortcut_name);
826
+      TRACE ("  key->keyval: %d", key->keyval);
827
+      TRACE ("  key->modifiers: 0x%x", key->modifiers);
828
+      TRACE ("  key->non_virtual_modifiers: 0x%x", key->non_virtual_modifiers);
829
+      TRACE ("  key->n_keys: %u", key->n_keys);
830
+      g_free (shortcut_name);
831
+    }
832
 
833
-      TRACE ("Keycode: %d", keys[i].keycode);
834
+  for (i = 0; i < key->n_keys; i++)
835
+    {
836
+      XfceXGrab g;
837
+      gpointer  refcount;
838
 
839
-      for (j = 0; j < screens; j++)
840
+      g.keycode = key->keys[i].keycode;
841
+      g.non_virtual_modifiers = key->non_virtual_modifiers;
842
+      g.numlock_modifier = key->numlock_modifier;
843
+      if (G_LIKELY (g_hash_table_lookup_extended (grabbed_keycodes, &g, NULL, &refcount)))
844
         {
845
-          /* Do the grab on all screens */
846
-          Window root_window;
847
-
848
-          /* Ignorable modifiers */
849
-          guint mod_masks [] = {
850
-            0,
851
-            GDK_MOD2_MASK,
852
-            numlock_modifier | GDK_MOD2_MASK,
853
-            GDK_LOCK_MASK,
854
-            numlock_modifier | GDK_LOCK_MASK,
855
-            GDK_MOD5_MASK,
856
-            numlock_modifier | GDK_MOD5_MASK,
857
-            GDK_MOD2_MASK | GDK_LOCK_MASK,
858
-            numlock_modifier | GDK_MOD2_MASK | GDK_LOCK_MASK,
859
-            GDK_MOD2_MASK | GDK_MOD5_MASK,
860
-            numlock_modifier | GDK_MOD2_MASK | GDK_MOD5_MASK,
861
-            GDK_LOCK_MASK | GDK_MOD5_MASK,
862
-            numlock_modifier | GDK_LOCK_MASK | GDK_MOD5_MASK,
863
-            GDK_MOD2_MASK | GDK_LOCK_MASK | GDK_MOD5_MASK,
864
-            numlock_modifier | GDK_MOD2_MASK | GDK_LOCK_MASK | GDK_MOD5_MASK,
865
-          };
866
-
867
-          /* Retrieve the root window of the screen */
868
-          root_window = GDK_WINDOW_XID (gdk_screen_get_root_window (gdk_display_get_default_screen (display)));
869
-          gdk_x11_display_error_trap_push (display);
870
-
871
-          for (k = 0; k < G_N_ELEMENTS (mod_masks); k++)
872
+          XfceXGrabRefcount *refcount1 = refcount;
873
+          if (G_LIKELY (*refcount1 != 0))
874
             {
875
-              /* Take ignorable modifiers into account when grabbing */
876
-              if (grab)
877
-                XGrabKey (GDK_DISPLAY_XDISPLAY (display),
878
-                          keys[i].keycode,
879
-                          modifiers | mod_masks [k],
880
-                          root_window,
881
-                          False,
882
-                          GrabModeAsync,
883
-                          GrabModeAsync);
884
-              else
885
+              (*refcount1)--;
886
+              if (trace)
887
+                TRACE ("[group %d] keycode %u, non_virtual_modifiers 0x%x: --refcount = %u",
888
+                       key->keys[i].group, g.keycode, g.non_virtual_modifiers, *refcount1);
889
+              if(*refcount1 == 0)
890
                 {
891
-                  if (i >= (gint) key->keycodes->len)
892
-                    break;
893
-                  XUngrabKey (GDK_DISPLAY_XDISPLAY (display),
894
-                              g_array_index (key->keycodes, guint, i),
895
-                              modifiers | mod_masks [k],
896
-                              root_window);
897
+                  xfce_shortcuts_grabber_xgrab (g, FALSE);
898
+                  g_hash_table_remove (grabbed_keycodes, &g);
899
                 }
900
             }
901
-
902
-          gdk_display_flush (display);
903
-
904
-          if (gdk_x11_display_error_trap_pop (display))
905
+          else
906
             {
907
-              TRACE (grab ? "Failed to grab" : "Failed to ungrab");
908
-              key->grab_state = UNDEFINED_GRAB_STATE;
909
+              g_warning ("corrupted refcount");
910
             }
911
         }
912
-      /* Remember the old keycode, as we need it to ungrab. */
913
-      if (grab)
914
-        g_array_append_val (key->keycodes, keys[i].keycode);
915
       else
916
-        g_array_index (key->keycodes, guint, i) = UINT_MAX;
917
-    }
918
-
919
-  /* Cleanup elements containing UINT_MAX from the key->keycodes array */
920
-  for (i = key->keycodes->len - 1; i >= 0; i --)
921
-    {
922
-      if (g_array_index (key->keycodes, guint, i) == UINT_MAX)
923
-        g_array_remove_index_fast (key->keycodes, i);
924
+        {
925
+          g_warning ("corrupted hashtable");
926
+        }
927
     }
928
 
929
-  g_free (keys);
930
+  g_free (key->keys);
931
+  key->keys = NULL;
932
+  key->n_keys = 0;
933
+  key->non_virtual_modifiers = 0;
934
+  key->numlock_modifier = 0;
20
 }
935
 }
21
 
936
 
937
 
938
@@ -451,8 +753,7 @@ xfce_shortcuts_grabber_event_filter (GdkXEvent *gdk_xevent,
939
           if (grabber->priv->xkbStateGroup != e->state.group)
940
             {
941
               grabber->priv->xkbStateGroup = e->state.group;
942
-              xfce_shortcuts_grabber_ungrab_all (grabber);
943
-              xfce_shortcuts_grabber_grab_all (grabber);
944
+              xfce_shortcuts_grabber_regrab_all (grabber);
945
             }
946
         }
947
     }
948
@@ -553,19 +854,18 @@ xfce_shortcuts_grabber_add (XfceShortcutsGrabber *grabber,
949
   g_return_if_fail (shortcut != NULL);
950
 
951
   key = g_new0 (XfceKey, 1);
952
-  key->keycodes = g_array_new (FALSE, TRUE, sizeof (guint));
953
 
954
   gtk_accelerator_parse (shortcut, &key->keyval, &key->modifiers);
955
+  TRACE ("parse %s -> keyval=0x%x, modifiers=0x%x", shortcut, key->keyval, key->modifiers);
956
 
957
   if (G_LIKELY (key->keyval != 0))
958
     {
959
-      xfce_shortcuts_grabber_grab (grabber, key, TRUE);
960
+      xfce_shortcuts_grabber_grab (grabber, key);
961
       g_hash_table_insert (grabber->priv->keys, g_strdup (shortcut), key);
962
     }
963
   else
964
     {
965
-      g_array_free (key->keycodes, TRUE);
966
-      g_free (key);
967
+      free_key (key);
968
     }
969
 }
970
 
971
@@ -584,7 +884,7 @@ xfce_shortcuts_grabber_remove (XfceShortcutsGrabber *grabber,
972
 
973
   if (G_LIKELY (key != NULL))
974
     {
975
-      xfce_shortcuts_grabber_grab (grabber, key, FALSE);
976
+      xfce_shortcuts_grabber_ungrab (grabber, key, TRUE);
977
       g_hash_table_remove (grabber->priv->keys, shortcut);
978
     }
979
 }
980
-- 
981
GitLab
982
983
984
From 609b60be1ea7db9140a1d96ad4dccf7d9512b7fd Mon Sep 17 00:00:00 2001
985
From: Jan Ziak <0xe2.0x9a.0x9b@gmail.com>
986
Date: Sat, 27 Feb 2021 17:34:41 +0100
987
Subject: [PATCH 5/5] shortcuts-grabber: Filter grabbing by key group
988
989
Closes: https://gitlab.xfce.org/xfce/libxfce4ui/-/issues/33
990
---
991
 libxfce4kbd-private/xfce-shortcuts-grabber.c | 162 ++++++++++++-------
992
 1 file changed, 106 insertions(+), 56 deletions(-)
993
994
diff --git a/libxfce4kbd-private/xfce-shortcuts-grabber.c b/libxfce4kbd-private/xfce-shortcuts-grabber.c
995
index 1de5929..4d21e4a 100644
996
--- libxfce4kbd-private/xfce-shortcuts-grabber.c
997
+++ libxfce4kbd-private/xfce-shortcuts-grabber.c
998
@@ -59,8 +59,7 @@ static void            xfce_shortcuts_grabber_ungrab_all       (XfceShortcutsGra
999
 static void            xfce_shortcuts_grabber_grab             (XfceShortcutsGrabber      *grabber,
1000
                                                                 XfceKey                   *key);
1001
 static void            xfce_shortcuts_grabber_ungrab           (XfceShortcutsGrabber      *grabber,
1002
-                                                                XfceKey                   *key,
1003
-                                                                gboolean                   trace);
1004
+                                                                XfceKey                   *key);
1005
 static GdkFilterReturn xfce_shortcuts_grabber_event_filter     (GdkXEvent                 *gdk_xevent,
1006
                                                                 GdkEvent                  *event,
1007
                                                                 gpointer                   data);
1008
@@ -318,7 +317,7 @@ ungrab_key (const gchar          *shortcut,
1009
             XfceKey              *key,
1010
             XfceShortcutsGrabber *grabber)
1011
 {
1012
-  xfce_shortcuts_grabber_ungrab (grabber, key, TRUE);
1013
+  xfce_shortcuts_grabber_ungrab (grabber, key);
1014
   return FALSE;
1015
 }
1016
 
1017
@@ -337,23 +336,67 @@ xfce_shortcuts_grabber_ungrab_all (XfceShortcutsGrabber *grabber)
1018
 
1019
 static gboolean
1020
 get_entries_for_keyval (GdkKeymap     *keymap,
1021
+                        gint           group,
1022
                         guint          keyval,
1023
                         GdkKeymapKey **keys,
1024
-                        gint          *n_keys)
1025
+                        guint         *n_keys)
1026
 {
1027
-  /* Get all keys generating keyval */
1028
-  if (!gdk_keymap_get_entries_for_keyval (keymap, keyval, keys, n_keys))
1029
+  GdkKeymapKey *keys1;
1030
+  gint n_keys1;
1031
+
1032
+  *keys = NULL;
1033
+  *n_keys = 0;
1034
+
1035
+   /* Get all keys generating keyval */
1036
+  if (!gdk_keymap_get_entries_for_keyval (keymap, keyval, &keys1, &n_keys1))
1037
     {
1038
       TRACE ("Got no keys for keyval");
1039
       return FALSE;
1040
     }
1041
 
1042
-  if (G_UNLIKELY (*n_keys <= 0))
1043
+  if (G_UNLIKELY (n_keys1 <= 0))
1044
     {
1045
-      g_free (*keys);
1046
+      g_free (keys1);
1047
       return FALSE;
1048
     }
1049
 
1050
+  /* Filter keys by group */
1051
+  {
1052
+    gboolean group0_only;
1053
+    gint i, n_matches;
1054
+
1055
+    /* For keys such as F12:
1056
+     *   keys1[i].group is always 0 (even if n_keys1 >= 2)
1057
+     *   and thus n_matches will be zero if group != 0 */
1058
+
1059
+    group0_only = TRUE;
1060
+    n_matches = 0;
1061
+    for (i = 0; i < n_keys1; i++)
1062
+      {
1063
+        group0_only &= (keys1[i].group == 0) ? TRUE : FALSE;
1064
+        if (keys1[i].group == group)
1065
+          n_matches++;
1066
+      }
1067
+
1068
+    if (!group0_only || n_matches != 0)
1069
+      {
1070
+        /* Remove keys that do not match the group*/
1071
+        for (i = 0; i < n_keys1;)
1072
+          if (keys1[i].group == group)
1073
+            i++;
1074
+          else
1075
+            keys1[i] = keys1[--n_keys1];
1076
+      }
1077
+  }
1078
+
1079
+  if (G_UNLIKELY (n_keys1 == 0))
1080
+    {
1081
+      g_free (keys1);
1082
+      keys1 = NULL;
1083
+    }
1084
+
1085
+  *keys = keys1;
1086
+  *n_keys = n_keys1;
1087
   return TRUE;
1088
 }
1089
 
1090
@@ -397,6 +440,7 @@ xfce_shortcuts_grabber_regrab_all (XfceShortcutsGrabber *grabber)
1091
   guint           n_regrab = 0;
1092
   XfceKey       **regrab; /* list of keys to re-grab */
1093
   guint           i;
1094
+  gint            group;
1095
 
1096
   g_return_if_fail (XFCE_IS_SHORTCUTS_GRABBER (grabber));
1097
 
1098
@@ -405,6 +449,9 @@ xfce_shortcuts_grabber_regrab_all (XfceShortcutsGrabber *grabber)
1099
   keymap = gdk_keymap_get_for_display (display);
1100
   numlock_modifier = XkbKeysymToModifiers (xdisplay, GDK_KEY_Num_Lock);
1101
   grabbed_keycodes = grabber->priv->grabbed_keycodes;
1102
+  group = grabber->priv->xkbStateGroup;
1103
+  if (G_UNLIKELY (group == -1))
1104
+    group = 0;
1105
 
1106
   regrab = g_malloc (g_hash_table_size (grabber->priv->keys) * sizeof (*regrab));
1107
 
1108
@@ -416,20 +463,20 @@ xfce_shortcuts_grabber_regrab_all (XfceShortcutsGrabber *grabber)
1109
     XfceKey         *const key = hash_value;
1110
     GdkKeymapKey    *keys;
1111
     GdkModifierType  non_virtual_modifiers;
1112
-    gint             n_keys;
1113
+    guint            n_keys;
1114
     gboolean         already_grabbed;
1115
 
1116
     if (!map_virtual_modifiers (keymap, key->modifiers, &non_virtual_modifiers))
1117
       continue;
1118
-    if (!get_entries_for_keyval (keymap, key->keyval, &keys, &n_keys))
1119
+    if (!get_entries_for_keyval (keymap, group, key->keyval, &keys, &n_keys))
1120
       continue;
1121
 
1122
     already_grabbed = TRUE;
1123
-    if (key->n_keys == (guint) n_keys &&
1124
+    if (key->n_keys == n_keys &&
1125
         key->non_virtual_modifiers == non_virtual_modifiers &&
1126
         key->numlock_modifier == numlock_modifier)
1127
       {
1128
-        gint j;
1129
+        guint j;
1130
         for (j = 0; j < n_keys; j++)
1131
           if (memcmp (&key->keys[j], &keys[j], sizeof(*keys)) != 0)
1132
             {
1133
@@ -448,7 +495,8 @@ xfce_shortcuts_grabber_regrab_all (XfceShortcutsGrabber *grabber)
1134
     else
1135
       {
1136
         /* Undo current X11 grabs of the key */
1137
-        xfce_shortcuts_grabber_ungrab (grabber, key, FALSE);
1138
+        if (key->n_keys != 0)
1139
+          xfce_shortcuts_grabber_ungrab (grabber, key);
1140
 
1141
         /* Set key->keys to the keycodes that need to be grabbed in phase 2 */
1142
         if (G_UNLIKELY (key->keys))
1143
@@ -465,7 +513,8 @@ xfce_shortcuts_grabber_regrab_all (XfceShortcutsGrabber *grabber)
1144
         key->numlock_modifier = numlock_modifier;
1145
 
1146
         /* Remember to grab the key in phase 2 */
1147
-        regrab[n_regrab++] = key;
1148
+        if (n_keys != 0)
1149
+          regrab[n_regrab++] = key;
1150
       }
1151
   }
1152
 
1153
@@ -478,14 +527,15 @@ xfce_shortcuts_grabber_regrab_all (XfceShortcutsGrabber *grabber)
1154
     guint    j;
1155
 
1156
 #ifdef DEBUG_TRACE
1157
-    gchar *shortcut_name = gtk_accelerator_name (key->keyval, key->non_virtual_modifiers);
1158
-    TRACE (key->n_keys==0 ? "Grabbing %s" : "Regrabbing %s", shortcut_name);
1159
-    TRACE ("  key->keyval: %d", key->keyval);
1160
-    TRACE ("  key->modifiers: 0x%x", key->modifiers);
1161
-    TRACE ("  key->non_virtual_modifiers: 0x%x", key->non_virtual_modifiers);
1162
-    TRACE ("  key->n_keys: %d", key->n_keys);
1163
-    g_free (shortcut_name);
1164
-    shortcut_name = NULL;
1165
+    {
1166
+      gchar *shortcut_name = gtk_accelerator_name (key->keyval, key->non_virtual_modifiers);
1167
+      TRACE (key->n_keys==0 ? "Grabbing %s" : "Regrabbing %s", shortcut_name);
1168
+      TRACE ("  key->keyval: %d", key->keyval);
1169
+      TRACE ("  key->modifiers: 0x%x", key->modifiers);
1170
+      TRACE ("  key->non_virtual_modifiers: 0x%x", key->non_virtual_modifiers);
1171
+      TRACE ("  key->n_keys: %u", key->n_keys);
1172
+      g_free (shortcut_name);
1173
+    }
1174
 #endif
1175
 
1176
     /* Grab all hardware keys generating keyval */
1177
@@ -545,38 +595,40 @@ xfce_shortcuts_grabber_grab (XfceShortcutsGrabber *grabber, XfceKey *key)
1178
   GHashTable      *grabbed_keycodes;
1179
   GdkKeymapKey    *keys;
1180
   GdkModifierType  non_virtual_modifiers;
1181
-  gint             i, n_keys;
1182
-#ifdef DEBUG_TRACE
1183
-  gchar           *shortcut_name;
1184
-#endif
1185
+  guint            i, n_keys;
1186
+  gint             group;
1187
 
1188
   display = gdk_display_get_default ();
1189
   xdisplay = GDK_DISPLAY_XDISPLAY (display);
1190
   keymap = gdk_keymap_get_for_display (display);
1191
   numlock_modifier = XkbKeysymToModifiers (xdisplay, GDK_KEY_Num_Lock);
1192
   grabbed_keycodes = grabber->priv->grabbed_keycodes;
1193
+  group = grabber->priv->xkbStateGroup;
1194
+  if (G_UNLIKELY (group == -1))
1195
+    group = 0;
1196
 
1197
   if (!map_virtual_modifiers (keymap, key->modifiers, &non_virtual_modifiers))
1198
     return;
1199
-  if (!get_entries_for_keyval (keymap, key->keyval, &keys, &n_keys))
1200
+  if (!get_entries_for_keyval (keymap, group, key->keyval, &keys, &n_keys))
1201
     return;
1202
 
1203
 #ifdef DEBUG_TRACE
1204
-  shortcut_name = gtk_accelerator_name (key->keyval, non_virtual_modifiers);
1205
-  TRACE (key->n_keys==0 ? "Grabbing %s" : "Regrabbing %s", shortcut_name);
1206
-  TRACE ("  key->keyval: %d", key->keyval);
1207
-  TRACE ("  key->modifiers: 0x%x", key->modifiers);
1208
-  TRACE ("  non_virtual_modifiers: 0x%x", non_virtual_modifiers);
1209
-  TRACE ("  n_keys: %d", n_keys);
1210
-  g_free (shortcut_name);
1211
-  shortcut_name = NULL;
1212
+  {
1213
+    char *shortcut_name = gtk_accelerator_name (key->keyval, non_virtual_modifiers);
1214
+    TRACE (key->n_keys==0 ? "Grabbing %s" : "Regrabbing %s", shortcut_name);
1215
+    TRACE ("  key->keyval: %d", key->keyval);
1216
+    TRACE ("  key->modifiers: 0x%x", key->modifiers);
1217
+    TRACE ("  non_virtual_modifiers: 0x%x", non_virtual_modifiers);
1218
+    TRACE ("  n_keys: %u", n_keys);
1219
+    g_free (shortcut_name);
1220
+  }
1221
 #endif
1222
 
1223
   /* Undo old grabs (just in case there are some old grabs) */
1224
   if (G_UNLIKELY (key->n_keys != 0))
1225
     {
1226
       g_warning ("keyval %u already grabbed", key->keyval);
1227
-      xfce_shortcuts_grabber_ungrab (grabber, key, TRUE);
1228
+      xfce_shortcuts_grabber_ungrab (grabber, key);
1229
     }
1230
 
1231
   /* Grab all hardware keys generating keyval */
1232
@@ -597,7 +649,7 @@ xfce_shortcuts_grabber_grab (XfceShortcutsGrabber *grabber, XfceKey *key)
1233
               *g1 = g;
1234
               *refcount1 = 1;
1235
               g_hash_table_insert (grabbed_keycodes, g1, refcount1);
1236
-              TRACE ("[group %d] keycode %u, non_virtual_modifiers 0x%x: refcount := %u",
1237
+              TRACE ("group %d, keycode %u, non_virtual_modifiers 0x%x: refcount := %u",
1238
                      keys[i].group, g.keycode, g.non_virtual_modifiers, *refcount1);
1239
               i++;
1240
             }
1241
@@ -610,7 +662,7 @@ xfce_shortcuts_grabber_grab (XfceShortcutsGrabber *grabber, XfceKey *key)
1242
           // 'g' has already been grabbed, increment its refcount only
1243
           XfceXGrabRefcount *refcount1 = refcount;
1244
           (*refcount1)++;
1245
-          TRACE ("[group %d] keycode %u, non_virtual_modifiers 0x%x: ++refcount = %u",
1246
+          TRACE ("group %d, keycode %u, non_virtual_modifiers 0x%x: ++refcount = %u",
1247
                  keys[i].group, g.keycode, g.non_virtual_modifiers, *refcount1);
1248
           i++;
1249
         }
1250
@@ -629,24 +681,24 @@ xfce_shortcuts_grabber_grab (XfceShortcutsGrabber *grabber, XfceKey *key)
1251
 }
1252
 
1253
 static void
1254
-xfce_shortcuts_grabber_ungrab (XfceShortcutsGrabber *grabber, XfceKey *key,
1255
-                               gboolean trace)
1256
+xfce_shortcuts_grabber_ungrab (XfceShortcutsGrabber *grabber, XfceKey *key)
1257
 {
1258
   GHashTable *grabbed_keycodes;
1259
   guint       i;
1260
 
1261
   grabbed_keycodes = grabber->priv->grabbed_keycodes;
1262
 
1263
-  if (trace)
1264
-    {
1265
-      gchar *shortcut_name = gtk_accelerator_name (key->keyval, key->non_virtual_modifiers);
1266
-      TRACE ("Ungrabbing %s", shortcut_name);
1267
-      TRACE ("  key->keyval: %d", key->keyval);
1268
-      TRACE ("  key->modifiers: 0x%x", key->modifiers);
1269
-      TRACE ("  key->non_virtual_modifiers: 0x%x", key->non_virtual_modifiers);
1270
-      TRACE ("  key->n_keys: %u", key->n_keys);
1271
-      g_free (shortcut_name);
1272
-    }
1273
+#ifdef DEBUG_TRACE
1274
+  {
1275
+    gchar *shortcut_name = gtk_accelerator_name (key->keyval, key->non_virtual_modifiers);
1276
+    TRACE ("Ungrabbing %s", shortcut_name);
1277
+    TRACE ("  key->keyval: %d", key->keyval);
1278
+    TRACE ("  key->modifiers: 0x%x", key->modifiers);
1279
+    TRACE ("  key->non_virtual_modifiers: 0x%x", key->non_virtual_modifiers);
1280
+    TRACE ("  key->n_keys: %u", key->n_keys);
1281
+    g_free (shortcut_name);
1282
+  }
1283
+#endif
1284
 
1285
   for (i = 0; i < key->n_keys; i++)
1286
     {
1287
@@ -662,9 +714,8 @@ xfce_shortcuts_grabber_ungrab (XfceShortcutsGrabber *grabber, XfceKey *key,
1288
           if (G_LIKELY (*refcount1 != 0))
1289
             {
1290
               (*refcount1)--;
1291
-              if (trace)
1292
-                TRACE ("[group %d] keycode %u, non_virtual_modifiers 0x%x: --refcount = %u",
1293
-                       key->keys[i].group, g.keycode, g.non_virtual_modifiers, *refcount1);
1294
+              TRACE ("group %d, keycode %u, non_virtual_modifiers 0x%x: --refcount = %u",
1295
+                     key->keys[i].group, g.keycode, g.non_virtual_modifiers, *refcount1);
1296
               if(*refcount1 == 0)
1297
                 {
1298
                   xfce_shortcuts_grabber_xgrab (g, FALSE);
1299
@@ -746,12 +797,11 @@ xfce_shortcuts_grabber_event_filter (GdkXEvent *gdk_xevent,
1300
   if (xevent->type == grabber->priv->xkbEventType)
1301
     {
1302
       const XkbEvent *e = (const XkbEvent*) xevent;
1303
-      TRACE ("xkb event: any.xkb_type=%d", e->any.xkb_type);
1304
       if (e->any.xkb_type == XkbStateNotify)
1305
         {
1306
-          TRACE ("xkb event: any.xkb_type=XkbStateNotify, state.group=%d", e->state.group);
1307
           if (grabber->priv->xkbStateGroup != e->state.group)
1308
             {
1309
+              TRACE ("xkb event: any.xkb_type=XkbStateNotify, state.group=%d", e->state.group);
1310
               grabber->priv->xkbStateGroup = e->state.group;
1311
               xfce_shortcuts_grabber_regrab_all (grabber);
1312
             }
1313
@@ -884,7 +934,7 @@ xfce_shortcuts_grabber_remove (XfceShortcutsGrabber *grabber,
1314
 
1315
   if (G_LIKELY (key != NULL))
1316
     {
1317
-      xfce_shortcuts_grabber_ungrab (grabber, key, TRUE);
1318
+      xfce_shortcuts_grabber_ungrab (grabber, key);
1319
       g_hash_table_remove (grabber->priv->keys, shortcut);
1320
     }
1321
 }
1322
-- 
1323
GitLab
1324

Return to bug 244290