2
** cairo-dock-keybinder.c
3
** Login : <ctaf42@localhost.localdomain>
4
** Started on Thu Jan 31 03:57:17 2008 Cedric GESTES
8
** - Cedric GESTES <ctaf42@gmail.com>
12
** Copyright (C) 2008 Cedric GESTES
13
** This program is free software; you can redistribute it and/or modify
14
** it under the terms of the GNU General Public License as published by
15
** the Free Software Foundation; either version 3 of the License, or
16
** (at your option) any later version.
18
** This program is distributed in the hope that it will be useful,
19
** but WITHOUT ANY WARRANTY; without even the implied warranty of
20
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
** GNU General Public License for more details.
23
** You should have received a copy of the GNU General Public License
24
** along with this program; if not, write to the Free Software
25
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27
* imported from tomboy_keybinder.c
31
#include <sys/types.h>
33
#include <gdk/gdkwindow.h>
36
#include "../config.h"
38
#include <X11/extensions/XTest.h>
41
#include "eggaccelerators.h"
42
#include "cairo-dock-log.h"
43
#include "cairo-dock-X-utilities.h"
44
#include "cairo-dock-keybinder.h"
46
typedef unsigned int uint;
47
typedef struct _Binding {
48
CDBindkeyHandler handler;
55
static GSList *bindings = NULL;
56
static guint32 last_event_time = 0;
57
static gboolean processing_event = FALSE;
59
static guint num_lock_mask=0, caps_lock_mask=0, scroll_lock_mask=0;
62
lookup_ignorable_modifiers (GdkKeymap *keymap)
64
egg_keymap_resolve_virtual_modifiers (keymap,
65
EGG_VIRTUAL_LOCK_MASK,
68
egg_keymap_resolve_virtual_modifiers (keymap,
69
EGG_VIRTUAL_NUM_LOCK_MASK,
72
egg_keymap_resolve_virtual_modifiers (keymap,
73
EGG_VIRTUAL_SCROLL_LOCK_MASK,
78
grab_ungrab_with_ignorable_modifiers (GdkWindow *rootwin,
82
guint mod_masks [] = {
83
0, /* modifier only */
87
num_lock_mask | caps_lock_mask,
88
num_lock_mask | scroll_lock_mask,
89
caps_lock_mask | scroll_lock_mask,
90
num_lock_mask | caps_lock_mask | scroll_lock_mask,
94
for (i = 0; i < G_N_ELEMENTS (mod_masks); i++) {
96
XGrabKey (GDK_WINDOW_XDISPLAY (rootwin),
98
binding->modifiers | mod_masks [i],
99
GDK_WINDOW_XWINDOW (rootwin),
104
XUngrabKey (GDK_WINDOW_XDISPLAY (rootwin),
106
binding->modifiers | mod_masks [i],
107
GDK_WINDOW_XWINDOW (rootwin));
113
do_grab_key (Binding *binding)
115
GdkKeymap *keymap = gdk_keymap_get_default ();
116
GdkWindow *rootwin = gdk_get_default_root_window ();
118
EggVirtualModifierType virtual_mods = 0;
121
if (keymap == NULL || rootwin == NULL)
124
if (!egg_accelerator_parse_virtual (binding->keystring,
129
cd_debug ("Got accel %d, %d", keysym, virtual_mods);
131
binding->keycode = XKeysymToKeycode (GDK_WINDOW_XDISPLAY (rootwin),
133
if (binding->keycode == 0)
136
cd_debug ("Got keycode %d", binding->keycode);
138
egg_keymap_resolve_virtual_modifiers (keymap,
140
&binding->modifiers);
142
cd_debug ("Got modmask %d", binding->modifiers);
144
gdk_error_trap_push ();
146
grab_ungrab_with_ignorable_modifiers (rootwin,
152
if (gdk_error_trap_pop ()) {
153
g_warning ("Binding '%s' failed!", binding->keystring);
161
do_ungrab_key (Binding *binding)
163
GdkWindow *rootwin = gdk_get_default_root_window ();
165
cd_debug ("Removing grab for '%s'", binding->keystring);
167
grab_ungrab_with_ignorable_modifiers (rootwin,
174
static GdkFilterReturn
175
filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
177
GdkFilterReturn return_val = GDK_FILTER_CONTINUE;
178
XEvent *xevent = (XEvent *) gdk_xevent;
182
cd_debug ("Got Event! %d, %d", xevent->type, event->type);
184
switch (xevent->type) {
186
cd_debug ("Got KeyPress! keycode: %d, modifiers: %d",
187
xevent->xkey.keycode,
191
* Set the last event time for use when showing
192
* windows to avoid anti-focus-stealing code.
194
processing_event = TRUE;
195
last_event_time = xevent->xkey.time;
197
event_mods = xevent->xkey.state & ~(num_lock_mask |
201
for (iter = bindings; iter != NULL; iter = iter->next) {
202
Binding *binding = (Binding *) iter->data;
204
if (binding->keycode == xevent->xkey.keycode &&
205
binding->modifiers == event_mods) {
207
cd_debug ("Calling handler for '%s'...",
210
(binding->handler) (binding->keystring,
215
processing_event = FALSE;
218
cd_debug ("Got KeyRelease! ");
226
keymap_changed (GdkKeymap *map)
228
GdkKeymap *keymap = gdk_keymap_get_default ();
231
cd_debug ("Keymap changed! Regrabbing keys...");
233
for (iter = bindings; iter != NULL; iter = iter->next) {
234
Binding *binding = (Binding *) iter->data;
235
do_ungrab_key (binding);
238
lookup_ignorable_modifiers (keymap);
240
for (iter = bindings; iter != NULL; iter = iter->next) {
241
Binding *binding = (Binding *) iter->data;
242
do_grab_key (binding);
247
cd_keybinder_init (void)
249
GdkKeymap *keymap = gdk_keymap_get_default ();
250
GdkWindow *rootwin = gdk_get_default_root_window ();
252
lookup_ignorable_modifiers (keymap);
254
gdk_window_add_filter (rootwin,
258
g_signal_connect (keymap,
260
G_CALLBACK (keymap_changed),
265
cd_keybinder_stop (void)
267
GdkKeymap *keymap = gdk_keymap_get_default ();
268
GdkWindow *rootwin = gdk_get_default_root_window ();
270
num_lock_mask=0, caps_lock_mask=0, scroll_lock_mask=0;
272
g_signal_handlers_disconnect_by_func (keymap,
273
G_CALLBACK (keymap_changed),
276
gdk_window_remove_filter (rootwin,
283
cd_keybinder_bind (const char *keystring,
284
CDBindkeyHandler handler,
290
cd_debug ("%s (%s)", __func__, keystring);
293
binding = g_new0 (Binding, 1);
294
binding->keystring = g_strdup (keystring);
295
binding->handler = handler;
296
binding->user_data = user_data;
298
/* Sets the binding's keycode and modifiers */
299
success = do_grab_key (binding);
302
bindings = g_slist_prepend (bindings, binding);
304
cd_warning ("Couldn't bind %s\n This shortkey is probably already used by another applet or another application", keystring);
305
g_free (binding->keystring);
313
cd_keybinder_unbind (const char *keystring,
314
CDBindkeyHandler handler)
316
cd_debug ("%s (%s)", __func__, keystring);
321
for (iter = bindings; iter != NULL; iter = iter->next) {
322
Binding *binding = (Binding *) iter->data;
324
if (strcmp (keystring, binding->keystring) != 0 ||
325
handler != binding->handler)
328
do_ungrab_key (binding);
330
bindings = g_slist_remove (bindings, binding);
332
cd_debug (" --- remove key binding '%s'\n", binding->keystring);
333
g_free (binding->keystring);
340
* From eggcellrenderkeys.c.
343
cd_keybinder_is_modifier (guint keycode)
347
XModifierKeymap *mod_keymap;
348
gboolean retval = FALSE;
350
mod_keymap = XGetModifierMapping (gdk_display);
352
map_size = 8 * mod_keymap->max_keypermod;
355
while (i < map_size) {
356
if (keycode == mod_keymap->modifiermap[i]) {
363
XFreeModifiermap (mod_keymap);
369
cd_keybinder_get_current_event_time (void)
371
if (processing_event)
372
return last_event_time;
374
return GDK_CURRENT_TIME;
378
gboolean cairo_dock_simulate_key_sequence (gchar *cKeyString) // the idea was taken from xdo.
381
g_return_val_if_fail (cairo_dock_xtest_is_available (), FALSE);
382
g_return_val_if_fail (cKeyString != NULL, FALSE);
383
cd_message ("%s (%s)", __func__, cKeyString);
386
int *pKeySyms = egg_keystring_to_keysyms (cKeyString, &iNbKeys);
390
Display *dpy = cairo_dock_get_Xdisplay ();
391
for (i = 0; i < iNbKeys; i ++)
393
keycode = XKeysymToKeycode (dpy, pKeySyms[i]);
394
XTestFakeKeyEvent (dpy, keycode, TRUE, CurrentTime); // TRUE <=> presse.
397
for (i = iNbKeys-1; i >=0; i --)
399
keycode = XKeysymToKeycode (dpy, pKeySyms[i]);
400
XTestFakeKeyEvent (dpy, keycode, FALSE, CurrentTime); // TRUE <=> presse.
407
cd_warning ("The dock was not compiled with the support of XTest.");