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 |
|