~robertcarr/bamf/ignore-shell-windows

« back to all changes in this revision

Viewing changes to WindowSwitcher/libwsbind/keybinder.c

  • Committer: Jason Smith
  • Date: 2009-11-06 14:51:10 UTC
  • Revision ID: jason@t500-20091106145110-ogw9i0dz02vgf4p9
Kill window switcher

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//
2
 
// This file comes from the Tomboy project.
3
 
// http://www.gnome.org/projects/tomboy/
4
 
//
5
 
/*
6
 
 * Copyright (C) 2004-2007  Alex Graveley
7
 
 *
8
 
 * This library is free software; you can redistribute it and/or
9
 
 * modify it under the terms of the GNU Library General Public
10
 
 * License as published by the Free Software Foundation; either
11
 
 * version 2 of the License, or (at your option) any later version.
12
 
 *
13
 
 * This library is distributed in the hope that it will be useful,
14
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 
 * Library General Public License for more details.
17
 
 *
18
 
 * You should have received a copy of the GNU Library General Public
19
 
 * License along with this library; if not, write to the
20
 
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21
 
 * Boston, MA 02111-1307, USA.
22
 
 */
23
 
 
24
 
#include <string.h>
25
 
 
26
 
#include <gdk/gdk.h>
27
 
#include <gdk/gdkwindow.h>
28
 
#include <gdk/gdkx.h>
29
 
#include <X11/Xlib.h>
30
 
 
31
 
#include "eggaccelerators.h"
32
 
#include "keybinder.h"
33
 
 
34
 
/* Uncomment the next line to print a debug trace. */
35
 
/* #define DEBUG */
36
 
 
37
 
#ifdef DEBUG
38
 
#  define TRACE(x) x
39
 
#else
40
 
#  define TRACE(x) do {} while (FALSE);
41
 
#endif
42
 
 
43
 
typedef struct _Binding {
44
 
        GnomeDoBindkeyHandler  handler;
45
 
        gpointer              user_data;
46
 
        char                 *keystring;
47
 
        uint                  keycode;
48
 
        uint                  modifiers;
49
 
} Binding;
50
 
 
51
 
static GSList *bindings = NULL;
52
 
static guint32 last_event_time = 0;
53
 
static gboolean processing_event = FALSE;
54
 
 
55
 
static guint num_lock_mask, caps_lock_mask, scroll_lock_mask;
56
 
 
57
 
static void
58
 
lookup_ignorable_modifiers (GdkKeymap *keymap)
59
 
{
60
 
        egg_keymap_resolve_virtual_modifiers (keymap, 
61
 
                                              EGG_VIRTUAL_LOCK_MASK,
62
 
                                              &caps_lock_mask);
63
 
 
64
 
        egg_keymap_resolve_virtual_modifiers (keymap, 
65
 
                                              EGG_VIRTUAL_NUM_LOCK_MASK,
66
 
                                              &num_lock_mask);
67
 
 
68
 
        egg_keymap_resolve_virtual_modifiers (keymap, 
69
 
                                              EGG_VIRTUAL_SCROLL_LOCK_MASK,
70
 
                                              &scroll_lock_mask);
71
 
}
72
 
 
73
 
static void
74
 
grab_ungrab_with_ignorable_modifiers (GdkWindow *rootwin, 
75
 
                                      Binding   *binding,
76
 
                                      gboolean   grab)
77
 
{
78
 
        guint mod_masks [] = {
79
 
                0, /* modifier only */
80
 
                num_lock_mask,
81
 
                caps_lock_mask,
82
 
                scroll_lock_mask,
83
 
                num_lock_mask  | caps_lock_mask,
84
 
                num_lock_mask  | scroll_lock_mask,
85
 
                caps_lock_mask | scroll_lock_mask,
86
 
                num_lock_mask  | caps_lock_mask | scroll_lock_mask,
87
 
        };
88
 
        int i;
89
 
 
90
 
        for (i = 0; i < G_N_ELEMENTS (mod_masks); i++) {
91
 
                if (grab) {
92
 
                        XGrabKey (GDK_WINDOW_XDISPLAY (rootwin), 
93
 
                                  binding->keycode, 
94
 
                                  binding->modifiers | mod_masks [i], 
95
 
                                  GDK_WINDOW_XWINDOW (rootwin), 
96
 
                                  False, 
97
 
                                  GrabModeSync,
98
 
                                  GrabModeSync);
99
 
                } else {
100
 
                        XUngrabKey (GDK_WINDOW_XDISPLAY (rootwin),
101
 
                                    binding->keycode,
102
 
                                    binding->modifiers | mod_masks [i], 
103
 
                                    GDK_WINDOW_XWINDOW (rootwin));
104
 
                }
105
 
        }
106
 
}
107
 
 
108
 
static gboolean 
109
 
do_grab_key (Binding *binding)
110
 
{
111
 
        GdkKeymap *keymap = gdk_keymap_get_default ();
112
 
        GdkWindow *rootwin = gdk_get_default_root_window ();
113
 
 
114
 
        EggVirtualModifierType virtual_mods = 0;
115
 
        guint keysym = 0;
116
 
 
117
 
        if (keymap == NULL || rootwin == NULL)
118
 
                return FALSE;
119
 
 
120
 
        if (!egg_accelerator_parse_virtual (binding->keystring, 
121
 
                                            &keysym, 
122
 
                                            &virtual_mods))
123
 
                return FALSE;
124
 
 
125
 
        TRACE (g_print ("Got accel %d, %d\n", keysym, virtual_mods));
126
 
 
127
 
        binding->keycode = XKeysymToKeycode (GDK_WINDOW_XDISPLAY (rootwin), 
128
 
                                             keysym);
129
 
        if (binding->keycode == 0)
130
 
                return FALSE;
131
 
 
132
 
        TRACE (g_print ("Got keycode %d\n", binding->keycode));
133
 
 
134
 
        egg_keymap_resolve_virtual_modifiers (keymap,
135
 
                                              virtual_mods,
136
 
                                              &binding->modifiers);
137
 
 
138
 
        TRACE (g_print ("Got modmask %d\n", binding->modifiers));
139
 
 
140
 
        gdk_error_trap_push ();
141
 
 
142
 
        grab_ungrab_with_ignorable_modifiers (rootwin, 
143
 
                                              binding, 
144
 
                                              TRUE /* grab */);
145
 
 
146
 
        gdk_flush ();
147
 
 
148
 
        if (gdk_error_trap_pop ()) {
149
 
           g_warning ("Binding '%s' failed!\n", binding->keystring);
150
 
           return FALSE;
151
 
        }
152
 
 
153
 
        return TRUE;
154
 
}
155
 
 
156
 
static gboolean 
157
 
do_ungrab_key (Binding *binding)
158
 
{
159
 
        GdkWindow *rootwin = gdk_get_default_root_window ();
160
 
 
161
 
        TRACE (g_print ("Removing grab for '%s'\n", binding->keystring));
162
 
 
163
 
        grab_ungrab_with_ignorable_modifiers (rootwin, 
164
 
                                              binding, 
165
 
                                              FALSE /* ungrab */);
166
 
 
167
 
        return TRUE;
168
 
}
169
 
 
170
 
static GdkFilterReturn
171
 
filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
172
 
{
173
 
        GdkFilterReturn return_val = GDK_FILTER_CONTINUE;
174
 
        XEvent *xevent = (XEvent *) gdk_xevent;
175
 
        guint event_mods;
176
 
        GSList *iter;
177
 
 
178
 
        TRACE (g_print ("Got Event! %d, %d\n", xevent->type, event->type));
179
 
 
180
 
        switch (xevent->type) {
181
 
        case KeyPress:
182
 
                TRACE (g_print ("Got KeyPress! keycode: %d, modifiers: %d\n", 
183
 
                                xevent->xkey.keycode, 
184
 
                                xevent->xkey.state));
185
 
 
186
 
                /* 
187
 
                 * Set the last event time for use when showing
188
 
                 * windows to avoid anti-focus-stealing code.
189
 
                 */
190
 
                processing_event = TRUE;
191
 
                last_event_time = xevent->xkey.time;
192
 
 
193
 
                event_mods = xevent->xkey.state & ~(num_lock_mask  | 
194
 
                                                    caps_lock_mask | 
195
 
                                                    scroll_lock_mask);
196
 
 
197
 
                for (iter = bindings; iter != NULL; iter = iter->next) {
198
 
                        Binding *binding = (Binding *) iter->data;
199
 
                                                       
200
 
                        if (binding->keycode == xevent->xkey.keycode &&
201
 
                            binding->modifiers == event_mods) {
202
 
 
203
 
                                TRACE (g_print ("Calling handler for '%s'...\n", 
204
 
                                                binding->keystring));
205
 
 
206
 
                                (binding->handler) (binding->keystring, 
207
 
                                                    binding->user_data);
208
 
                        }
209
 
                }
210
 
 
211
 
                processing_event = FALSE;
212
 
                break;
213
 
        case KeyRelease:
214
 
                TRACE (g_print ("Got KeyRelease! \n"));
215
 
                break;
216
 
        }
217
 
 
218
 
        return return_val;
219
 
}
220
 
 
221
 
static void 
222
 
keymap_changed (GdkKeymap *map)
223
 
{
224
 
        GdkKeymap *keymap = gdk_keymap_get_default ();
225
 
        GSList *iter;
226
 
 
227
 
        TRACE (g_print ("Keymap changed! Regrabbing keys..."));
228
 
 
229
 
        for (iter = bindings; iter != NULL; iter = iter->next) {
230
 
                Binding *binding = (Binding *) iter->data;
231
 
                do_ungrab_key (binding);
232
 
        }
233
 
 
234
 
        lookup_ignorable_modifiers (keymap);
235
 
 
236
 
        for (iter = bindings; iter != NULL; iter = iter->next) {
237
 
                Binding *binding = (Binding *) iter->data;
238
 
                do_grab_key (binding);
239
 
        }
240
 
}
241
 
 
242
 
void 
243
 
wsbind_keybinder_init (void)
244
 
{
245
 
        GdkKeymap *keymap = gdk_keymap_get_default ();
246
 
        GdkWindow *rootwin = gdk_get_default_root_window ();
247
 
 
248
 
        lookup_ignorable_modifiers (keymap);
249
 
 
250
 
        gdk_window_add_filter (rootwin, 
251
 
                               filter_func, 
252
 
                               NULL);
253
 
 
254
 
        g_signal_connect (keymap, 
255
 
                          "keys_changed",
256
 
                          G_CALLBACK (keymap_changed),
257
 
                          NULL);
258
 
}
259
 
 
260
 
void 
261
 
wsbind_keybinder_bind (const char           *keystring,
262
 
                       GnomeDoBindkeyHandler  handler,
263
 
                       gpointer              user_data)
264
 
{
265
 
        Binding *binding;
266
 
        gboolean success;
267
 
 
268
 
        binding = g_new0 (Binding, 1);
269
 
        binding->keystring = g_strdup (keystring);
270
 
        binding->handler = handler;
271
 
        binding->user_data = user_data;
272
 
 
273
 
        /* Sets the binding's keycode and modifiers */
274
 
        success = do_grab_key (binding);
275
 
 
276
 
        if (success) {
277
 
                bindings = g_slist_prepend (bindings, binding);
278
 
        } else {
279
 
                g_free (binding->keystring);
280
 
                g_free (binding);
281
 
        }
282
 
}
283
 
 
284
 
void
285
 
wsbind_keybinder_unbind (const char           *keystring, 
286
 
                         GnomeDoBindkeyHandler  handler)
287
 
{
288
 
        GSList *iter;
289
 
 
290
 
        for (iter = bindings; iter != NULL; iter = iter->next) {
291
 
                Binding *binding = (Binding *) iter->data;
292
 
 
293
 
                if (strcmp (keystring, binding->keystring) != 0 ||
294
 
                    handler != binding->handler) 
295
 
                        continue;
296
 
 
297
 
                do_ungrab_key (binding);
298
 
 
299
 
                bindings = g_slist_remove (bindings, binding);
300
 
 
301
 
                g_free (binding->keystring);
302
 
                g_free (binding);
303
 
                break;
304
 
        }
305
 
}
306
 
 
307
 
/* 
308
 
 * From eggcellrenderkeys.c.
309
 
 */
310
 
gboolean
311
 
wsbind_keybinder_is_modifier (guint keycode)
312
 
{
313
 
        gint i;
314
 
        gint map_size;
315
 
        XModifierKeymap *mod_keymap;
316
 
        gboolean retval = FALSE;
317
 
 
318
 
        mod_keymap = XGetModifierMapping (gdk_display);
319
 
 
320
 
        map_size = 8 * mod_keymap->max_keypermod;
321
 
 
322
 
        i = 0;
323
 
        while (i < map_size) {
324
 
                if (keycode == mod_keymap->modifiermap[i]) {
325
 
                        retval = TRUE;
326
 
                        break;
327
 
                }
328
 
                ++i;
329
 
        }
330
 
 
331
 
        XFreeModifiermap (mod_keymap);
332
 
 
333
 
        return retval;
334
 
}
335
 
 
336
 
guint32
337
 
wsbind_keybinder_get_current_event_time (void)
338
 
{
339
 
        if (processing_event) 
340
 
                return last_event_time;
341
 
        else
342
 
                return GDK_CURRENT_TIME;
343
 
}