1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3 /* Mutter Keybindings */
4 /*
5 * Copyright (C) 2001 Havoc Pennington
6 * Copyright (C) 2002 Red Hat Inc.
7 * Copyright (C) 2003 Rob Adams
8 * Copyright (C) 2004-2006 Elijah Newren
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of the
13 * License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 */
23
24 /**
25 * SECTION:keybindings
26 * @Title: MetaKeybinding
27 * @Short_Description: Key bindings
28 */
29
30 #include "config.h"
31
32 #include "backends/meta-backend-private.h"
33 #include "backends/meta-keymap-utils.h"
34 #include "backends/meta-logical-monitor.h"
35 #include "backends/meta-monitor-manager-private.h"
36 #include "backends/x11/meta-backend-x11.h"
37 #include "backends/x11/meta-input-device-x11.h"
38 #include "compositor/compositor-private.h"
39 #include "core/edge-resistance.h"
40 #include "core/frame.h"
41 #include "core/keybindings-private.h"
42 #include "core/meta-accel-parse.h"
43 #include "core/meta-workspace-manager-private.h"
44 #include "core/workspace-private.h"
45 #include "meta/compositor.h"
46 #include "meta/meta-x11-errors.h"
47 #include "meta/prefs.h"
48 #include "x11/meta-x11-display-private.h"
49 #include "x11/window-x11.h"
50
51 #ifdef HAVE_NATIVE_BACKEND
52 #include "backends/native/meta-backend-native.h"
53 #endif
54
55 #ifdef __linux__
56 #include <linux/input.h>
57 #elif !defined KEY_GRAVE
58 #define KEY_GRAVE 0x29 /* assume the use of xf86-input-keyboard */
59 #endif
60
61 #define SCHEMA_COMMON_KEYBINDINGS "org.gnome.desktop.wm.keybindings"
62 #define SCHEMA_MUTTER_KEYBINDINGS "org.gnome.mutter.keybindings"
63 #define SCHEMA_MUTTER_WAYLAND_KEYBINDINGS "org.gnome.mutter.wayland.keybindings"
64
65 #define META_KEY_BINDING_PRIMARY_LAYOUT 0
66 #define META_KEY_BINDING_SECONDARY_LAYOUT 1
67
68 /* Only for special modifier keys */
69 #define IGNORED_MODIFIERS (CLUTTER_LOCK_MASK | \
70 CLUTTER_MOD2_MASK | \
71 CLUTTER_BUTTON1_MASK | \
72 CLUTTER_BUTTON2_MASK | \
73 CLUTTER_BUTTON3_MASK | \
74 CLUTTER_BUTTON4_MASK | \
75 CLUTTER_BUTTON5_MASK)
76
77 static gboolean add_builtin_keybinding (MetaDisplay *display,
78 const char *name,
79 GSettings *settings,
80 MetaKeyBindingFlags flags,
81 MetaKeyBindingAction action,
82 MetaKeyHandlerFunc handler,
83 int handler_arg);
84
85 static void
resolved_key_combo_reset(MetaResolvedKeyCombo * resolved_combo)86 resolved_key_combo_reset (MetaResolvedKeyCombo *resolved_combo)
87 {
88 g_free (resolved_combo->keycodes);
89 resolved_combo->len = 0;
90 resolved_combo->keycodes = NULL;
91 }
92
93 static void
resolved_key_combo_copy(MetaResolvedKeyCombo * from,MetaResolvedKeyCombo * to)94 resolved_key_combo_copy (MetaResolvedKeyCombo *from,
95 MetaResolvedKeyCombo *to)
96 {
97 to->len = from->len;
98 to->keycodes = g_memdup2 (from->keycodes,
99 from->len * sizeof (xkb_keycode_t));
100 }
101
102 static gboolean
resolved_key_combo_has_keycode(MetaResolvedKeyCombo * resolved_combo,int keycode)103 resolved_key_combo_has_keycode (MetaResolvedKeyCombo *resolved_combo,
104 int keycode)
105 {
106 int i;
107
108 for (i = 0; i < resolved_combo->len; i++)
109 if ((int) resolved_combo->keycodes[i] == keycode)
110 return TRUE;
111
112 return FALSE;
113 }
114
115 static gboolean
resolved_key_combo_intersect(MetaResolvedKeyCombo * a,MetaResolvedKeyCombo * b)116 resolved_key_combo_intersect (MetaResolvedKeyCombo *a,
117 MetaResolvedKeyCombo *b)
118 {
119 int i;
120
121 for (i = 0; i < a->len; i++)
122 if (resolved_key_combo_has_keycode (b, a->keycodes[i]))
123 return TRUE;
124
125 return FALSE;
126 }
127
128 static void
meta_key_binding_free(MetaKeyBinding * binding)129 meta_key_binding_free (MetaKeyBinding *binding)
130 {
131 resolved_key_combo_reset (&binding->resolved_combo);
132 g_free (binding);
133 }
134
135 static MetaKeyBinding *
meta_key_binding_copy(MetaKeyBinding * binding)136 meta_key_binding_copy (MetaKeyBinding *binding)
137 {
138 MetaKeyBinding *clone = g_memdup2 (binding, sizeof (MetaKeyBinding));
139 resolved_key_combo_copy (&binding->resolved_combo,
140 &clone->resolved_combo);
141 return clone;
142 }
143
G_DEFINE_BOXED_TYPE(MetaKeyBinding,meta_key_binding,meta_key_binding_copy,meta_key_binding_free)144 G_DEFINE_BOXED_TYPE(MetaKeyBinding,
145 meta_key_binding,
146 meta_key_binding_copy,
147 meta_key_binding_free)
148
149 const char *
150 meta_key_binding_get_name (MetaKeyBinding *binding)
151 {
152 return binding->name;
153 }
154
155 MetaVirtualModifier
meta_key_binding_get_modifiers(MetaKeyBinding * binding)156 meta_key_binding_get_modifiers (MetaKeyBinding *binding)
157 {
158 return binding->combo.modifiers;
159 }
160
161 gboolean
meta_key_binding_is_reversed(MetaKeyBinding * binding)162 meta_key_binding_is_reversed (MetaKeyBinding *binding)
163 {
164 return (binding->handler->flags & META_KEY_BINDING_IS_REVERSED) != 0;
165 }
166
167 guint
meta_key_binding_get_mask(MetaKeyBinding * binding)168 meta_key_binding_get_mask (MetaKeyBinding *binding)
169 {
170 return binding->resolved_combo.mask;
171 }
172
173 gboolean
meta_key_binding_is_builtin(MetaKeyBinding * binding)174 meta_key_binding_is_builtin (MetaKeyBinding *binding)
175 {
176 return binding->handler->flags & META_KEY_BINDING_BUILTIN;
177 }
178
179 /* These can't be bound to anything, but they are used to handle
180 * various other events. TODO: Possibly we should include them as event
181 * handler functions and have some kind of flag to say they're unbindable.
182 */
183
184 static gboolean process_mouse_move_resize_grab (MetaDisplay *display,
185 MetaWindow *window,
186 ClutterKeyEvent *event);
187
188 static gboolean process_keyboard_move_grab (MetaDisplay *display,
189 MetaWindow *window,
190 ClutterKeyEvent *event);
191
192 static gboolean process_keyboard_resize_grab (MetaDisplay *display,
193 MetaWindow *window,
194 ClutterKeyEvent *event);
195
196 static void maybe_update_locate_pointer_keygrab (MetaDisplay *display,
197 gboolean grab);
198
199 static GHashTable *key_handlers;
200 static GHashTable *external_grabs;
201
202 #define HANDLER(name) g_hash_table_lookup (key_handlers, (name))
203
204 static void
key_handler_free(MetaKeyHandler * handler)205 key_handler_free (MetaKeyHandler *handler)
206 {
207 g_free (handler->name);
208 if (handler->user_data_free_func && handler->user_data)
209 handler->user_data_free_func (handler->user_data);
210 g_free (handler);
211 }
212
213 typedef struct _MetaKeyGrab MetaKeyGrab;
214 struct _MetaKeyGrab {
215 char *name;
216 guint action;
217 MetaKeyCombo combo;
218 gint flags;
219 };
220
221 static void
meta_key_grab_free(MetaKeyGrab * grab)222 meta_key_grab_free (MetaKeyGrab *grab)
223 {
224 g_free (grab->name);
225 g_free (grab);
226 }
227
228 static guint32
key_combo_key(MetaResolvedKeyCombo * resolved_combo,int i)229 key_combo_key (MetaResolvedKeyCombo *resolved_combo,
230 int i)
231 {
232 /* On X, keycodes are only 8 bits while libxkbcommon supports 32 bit
233 keycodes, but since we're using the same XKB keymaps that X uses,
234 we won't find keycodes bigger than 8 bits in practice. The bits
235 that mutter cares about in the modifier mask are also all in the
236 lower 8 bits both on X and clutter key events. This means that we
237 can use a 32 bit integer to safely concatenate both keycode and
238 mask and thus making it easy to use them as an index in a
239 GHashTable. */
240 guint32 key = resolved_combo->keycodes[i] & 0xffff;
241 return (key << 16) | (resolved_combo->mask & 0xffff);
242 }
243
244 static void
reload_modmap(MetaKeyBindingManager * keys)245 reload_modmap (MetaKeyBindingManager *keys)
246 {
247 struct xkb_keymap *keymap = meta_backend_get_keymap (keys->backend);
248 struct xkb_state *scratch_state;
249 xkb_mod_mask_t scroll_lock_mask;
250 xkb_mod_mask_t dummy_mask;
251
252 /* Modifiers to find. */
253 struct {
254 const char *name;
255 xkb_mod_mask_t *mask_p;
256 xkb_mod_mask_t *virtual_mask_p;
257 } mods[] = {
258 { "ScrollLock", &scroll_lock_mask, &dummy_mask },
259 { "Meta", &keys->meta_mask, &keys->virtual_meta_mask },
260 { "Hyper", &keys->hyper_mask, &keys->virtual_hyper_mask },
261 { "Super", &keys->super_mask, &keys->virtual_super_mask },
262 };
263
264 scratch_state = xkb_state_new (keymap);
265
266 gsize i;
267 for (i = 0; i < G_N_ELEMENTS (mods); i++)
268 {
269 xkb_mod_mask_t *mask_p = mods[i].mask_p;
270 xkb_mod_mask_t *virtual_mask_p = mods[i].virtual_mask_p;
271 xkb_mod_index_t idx = xkb_keymap_mod_get_index (keymap, mods[i].name);
272
273 if (idx != XKB_MOD_INVALID)
274 {
275 xkb_mod_mask_t vmodmask = (1 << idx);
276 xkb_state_update_mask (scratch_state, vmodmask, 0, 0, 0, 0, 0);
277 *mask_p = xkb_state_serialize_mods (scratch_state, XKB_STATE_MODS_DEPRESSED) & ~vmodmask;
278 *virtual_mask_p = vmodmask;
279 }
280 else
281 {
282 *mask_p = 0;
283 *virtual_mask_p = 0;
284 }
285 }
286
287 xkb_state_unref (scratch_state);
288
289 keys->ignored_modifier_mask = (scroll_lock_mask | Mod2Mask | LockMask);
290
291 meta_topic (META_DEBUG_KEYBINDINGS,
292 "Ignoring modmask 0x%x scroll lock 0x%x hyper 0x%x super 0x%x meta 0x%x",
293 keys->ignored_modifier_mask,
294 scroll_lock_mask,
295 keys->hyper_mask,
296 keys->super_mask,
297 keys->meta_mask);
298 }
299
300 static gboolean
is_keycode_for_keysym(struct xkb_keymap * keymap,xkb_layout_index_t layout,xkb_level_index_t level,xkb_keycode_t keycode,xkb_keysym_t keysym)301 is_keycode_for_keysym (struct xkb_keymap *keymap,
302 xkb_layout_index_t layout,
303 xkb_level_index_t level,
304 xkb_keycode_t keycode,
305 xkb_keysym_t keysym)
306 {
307 const xkb_keysym_t *syms;
308 int num_syms, k;
309
310 num_syms = xkb_keymap_key_get_syms_by_level (keymap, keycode, layout, level, &syms);
311 for (k = 0; k < num_syms; k++)
312 {
313 if (syms[k] == keysym)
314 return TRUE;
315 }
316
317 return FALSE;
318 }
319
320 typedef struct
321 {
322 GArray *keycodes;
323 xkb_keysym_t keysym;
324 xkb_layout_index_t layout;
325 xkb_level_index_t level;
326 } FindKeysymData;
327
328 static void
get_keycodes_for_keysym_iter(struct xkb_keymap * keymap,xkb_keycode_t keycode,void * data)329 get_keycodes_for_keysym_iter (struct xkb_keymap *keymap,
330 xkb_keycode_t keycode,
331 void *data)
332 {
333 FindKeysymData *search_data = data;
334 GArray *keycodes = search_data->keycodes;
335 xkb_keysym_t keysym = search_data->keysym;
336 xkb_layout_index_t layout = search_data->layout;
337 xkb_level_index_t level = search_data->level;
338
339 if (is_keycode_for_keysym (keymap, layout, level, keycode, keysym))
340 {
341 guint i;
342 gboolean missing = TRUE;
343
344 /* duplicate keycode detection */
345 for (i = 0; i < keycodes->len; i++)
346 if (g_array_index (keycodes, xkb_keysym_t, i) == keycode)
347 {
348 missing = FALSE;
349 break;
350 }
351
352 if (missing)
353 g_array_append_val (keycodes, keycode);
354 }
355 }
356
357 static void
add_keysym_keycodes_from_layout(int keysym,MetaKeyBindingKeyboardLayout * layout,GArray * keycodes)358 add_keysym_keycodes_from_layout (int keysym,
359 MetaKeyBindingKeyboardLayout *layout,
360 GArray *keycodes)
361 {
362 xkb_level_index_t layout_level;
363
364 for (layout_level = 0;
365 layout_level < layout->n_levels && keycodes->len == 0;
366 layout_level++)
367 {
368 FindKeysymData search_data = (FindKeysymData) {
369 .keycodes = keycodes,
370 .keysym = keysym,
371 .layout = layout->index,
372 .level = layout_level
373 };
374 xkb_keymap_key_for_each (layout->keymap,
375 get_keycodes_for_keysym_iter,
376 &search_data);
377 }
378 }
379
380 /* Original code from gdk_x11_keymap_get_entries_for_keyval() in
381 * gdkkeys-x11.c */
382 static void
get_keycodes_for_keysym(MetaKeyBindingManager * keys,int keysym,MetaResolvedKeyCombo * resolved_combo)383 get_keycodes_for_keysym (MetaKeyBindingManager *keys,
384 int keysym,
385 MetaResolvedKeyCombo *resolved_combo)
386 {
387 unsigned int i;
388 GArray *keycodes;
389 int keycode;
390
391 keycodes = g_array_new (FALSE, FALSE, sizeof (xkb_keysym_t));
392
393 /* Special-case: Fake mutter keysym */
394 if (keysym == META_KEY_ABOVE_TAB)
395 {
396 keycode = KEY_GRAVE + 8;
397 g_array_append_val (keycodes, keycode);
398 goto out;
399 }
400
401 for (i = 0; i < G_N_ELEMENTS (keys->active_layouts); i++)
402 {
403 MetaKeyBindingKeyboardLayout *layout = &keys->active_layouts[i];
404
405 if (!layout->keymap)
406 continue;
407
408 add_keysym_keycodes_from_layout (keysym, layout, keycodes);
409 }
410
411 out:
412 resolved_combo->len = keycodes->len;
413 resolved_combo->keycodes =
414 (xkb_keycode_t *) g_array_free (keycodes,
415 keycodes->len == 0 ? TRUE : FALSE);
416 }
417
418 typedef struct _CalculateLayoutLevelsState
419 {
420 struct xkb_keymap *keymap;
421 xkb_layout_index_t layout_index;
422
423 xkb_level_index_t out_n_levels;
424 } CalculateLayoutLevelState;
425
426 static void
calculate_n_layout_levels_iter(struct xkb_keymap * keymap,xkb_keycode_t keycode,void * data)427 calculate_n_layout_levels_iter (struct xkb_keymap *keymap,
428 xkb_keycode_t keycode,
429 void *data)
430 {
431 CalculateLayoutLevelState *state = data;
432 xkb_level_index_t n_levels;
433
434 n_levels = xkb_keymap_num_levels_for_key (keymap,
435 keycode,
436 state->layout_index);
437
438 state->out_n_levels = MAX (n_levels, state->out_n_levels);
439 }
440
441 static xkb_level_index_t
calculate_n_layout_levels(struct xkb_keymap * keymap,xkb_layout_index_t layout_index)442 calculate_n_layout_levels (struct xkb_keymap *keymap,
443 xkb_layout_index_t layout_index)
444
445 {
446 CalculateLayoutLevelState state = {
447 .keymap = keymap,
448 .layout_index = layout_index,
449
450 .out_n_levels = 0
451 };
452
453 xkb_keymap_key_for_each (keymap, calculate_n_layout_levels_iter, &state);
454
455 return state.out_n_levels;
456 }
457
458 static void
reload_iso_next_group_combos(MetaKeyBindingManager * keys)459 reload_iso_next_group_combos (MetaKeyBindingManager *keys)
460 {
461 const char *iso_next_group_option;
462 int i;
463
464 for (i = 0; i < keys->n_iso_next_group_combos; i++)
465 resolved_key_combo_reset (&keys->iso_next_group_combo[i]);
466
467 keys->n_iso_next_group_combos = 0;
468
469 iso_next_group_option = meta_prefs_get_iso_next_group_option ();
470 if (iso_next_group_option == NULL)
471 return;
472
473 get_keycodes_for_keysym (keys, XKB_KEY_ISO_Next_Group, keys->iso_next_group_combo);
474
475 if (keys->iso_next_group_combo[0].len == 0)
476 return;
477
478 keys->n_iso_next_group_combos = 1;
479
480 if (g_str_equal (iso_next_group_option, "toggle") ||
481 g_str_equal (iso_next_group_option, "lalt_toggle") ||
482 g_str_equal (iso_next_group_option, "lwin_toggle") ||
483 g_str_equal (iso_next_group_option, "rwin_toggle") ||
484 g_str_equal (iso_next_group_option, "lshift_toggle") ||
485 g_str_equal (iso_next_group_option, "rshift_toggle") ||
486 g_str_equal (iso_next_group_option, "lctrl_toggle") ||
487 g_str_equal (iso_next_group_option, "rctrl_toggle") ||
488 g_str_equal (iso_next_group_option, "sclk_toggle") ||
489 g_str_equal (iso_next_group_option, "menu_toggle") ||
490 g_str_equal (iso_next_group_option, "caps_toggle"))
491 {
492 keys->iso_next_group_combo[0].mask = 0;
493 }
494 else if (g_str_equal (iso_next_group_option, "shift_caps_toggle") ||
495 g_str_equal (iso_next_group_option, "shifts_toggle"))
496 {
497 keys->iso_next_group_combo[0].mask = ShiftMask;
498 }
499 else if (g_str_equal (iso_next_group_option, "alt_caps_toggle") ||
500 g_str_equal (iso_next_group_option, "alt_space_toggle"))
501 {
502 keys->iso_next_group_combo[0].mask = Mod1Mask;
503 }
504 else if (g_str_equal (iso_next_group_option, "ctrl_shift_toggle") ||
505 g_str_equal (iso_next_group_option, "lctrl_lshift_toggle") ||
506 g_str_equal (iso_next_group_option, "rctrl_rshift_toggle"))
507 {
508 resolved_key_combo_copy (&keys->iso_next_group_combo[0],
509 &keys->iso_next_group_combo[1]);
510
511 keys->iso_next_group_combo[0].mask = ShiftMask;
512 keys->iso_next_group_combo[1].mask = ControlMask;
513 keys->n_iso_next_group_combos = 2;
514 }
515 else if (g_str_equal (iso_next_group_option, "ctrl_alt_toggle"))
516 {
517 resolved_key_combo_copy (&keys->iso_next_group_combo[0],
518 &keys->iso_next_group_combo[1]);
519
520 keys->iso_next_group_combo[0].mask = Mod1Mask;
521 keys->iso_next_group_combo[1].mask = ControlMask;
522 keys->n_iso_next_group_combos = 2;
523 }
524 else if (g_str_equal (iso_next_group_option, "alt_shift_toggle") ||
525 g_str_equal (iso_next_group_option, "lalt_lshift_toggle"))
526 {
527 resolved_key_combo_copy (&keys->iso_next_group_combo[0],
528 &keys->iso_next_group_combo[1]);
529
530 keys->iso_next_group_combo[0].mask = Mod1Mask;
531 keys->iso_next_group_combo[1].mask = ShiftMask;
532 keys->n_iso_next_group_combos = 2;
533 }
534 else
535 {
536 resolved_key_combo_reset (keys->iso_next_group_combo);
537 keys->n_iso_next_group_combos = 0;
538 }
539 }
540
541 static void
devirtualize_modifiers(MetaKeyBindingManager * keys,MetaVirtualModifier modifiers,unsigned int * mask)542 devirtualize_modifiers (MetaKeyBindingManager *keys,
543 MetaVirtualModifier modifiers,
544 unsigned int *mask)
545 {
546 *mask = 0;
547
548 if (modifiers & META_VIRTUAL_SHIFT_MASK)
549 *mask |= ShiftMask;
550 if (modifiers & META_VIRTUAL_CONTROL_MASK)
551 *mask |= ControlMask;
552 if (modifiers & META_VIRTUAL_ALT_MASK)
553 *mask |= Mod1Mask;
554 if (modifiers & META_VIRTUAL_META_MASK)
555 *mask |= keys->meta_mask;
556 if (modifiers & META_VIRTUAL_HYPER_MASK)
557 *mask |= keys->hyper_mask;
558 if (modifiers & META_VIRTUAL_SUPER_MASK)
559 *mask |= keys->super_mask;
560 if (modifiers & META_VIRTUAL_MOD2_MASK)
561 *mask |= Mod2Mask;
562 if (modifiers & META_VIRTUAL_MOD3_MASK)
563 *mask |= Mod3Mask;
564 if (modifiers & META_VIRTUAL_MOD4_MASK)
565 *mask |= Mod4Mask;
566 if (modifiers & META_VIRTUAL_MOD5_MASK)
567 *mask |= Mod5Mask;
568 }
569
570 static void
index_binding(MetaKeyBindingManager * keys,MetaKeyBinding * binding)571 index_binding (MetaKeyBindingManager *keys,
572 MetaKeyBinding *binding)
573 {
574 int i;
575
576 for (i = 0; i < binding->resolved_combo.len; i++)
577 {
578 MetaKeyBinding *existing;
579 guint32 index_key;
580
581 index_key = key_combo_key (&binding->resolved_combo, i);
582
583 existing = g_hash_table_lookup (keys->key_bindings_index,
584 GINT_TO_POINTER (index_key));
585 if (existing != NULL)
586 {
587 /* Overwrite already indexed keycodes only for the first
588 * keycode, i.e. we give those primary keycodes precedence
589 * over non-first ones. */
590 if (i > 0)
591 continue;
592
593 meta_warning ("Overwriting existing binding of keysym %x"
594 " with keysym %x (keycode %x).",
595 binding->combo.keysym,
596 existing->combo.keysym,
597 binding->resolved_combo.keycodes[i]);
598 }
599
600 g_hash_table_replace (keys->key_bindings_index,
601 GINT_TO_POINTER (index_key), binding);
602 }
603 }
604
605 static void
resolve_key_combo(MetaKeyBindingManager * keys,MetaKeyCombo * combo,MetaResolvedKeyCombo * resolved_combo)606 resolve_key_combo (MetaKeyBindingManager *keys,
607 MetaKeyCombo *combo,
608 MetaResolvedKeyCombo *resolved_combo)
609 {
610
611 resolved_key_combo_reset (resolved_combo);
612
613 if (combo->keysym != 0)
614 {
615 get_keycodes_for_keysym (keys, combo->keysym, resolved_combo);
616 }
617 else if (combo->keycode != 0)
618 {
619 resolved_combo->keycodes = g_new0 (xkb_keycode_t, 1);
620 resolved_combo->keycodes[0] = combo->keycode;
621 resolved_combo->len = 1;
622 }
623
624 devirtualize_modifiers (keys, combo->modifiers, &resolved_combo->mask);
625 }
626
627 static void
binding_reload_combos_foreach(gpointer key,gpointer value,gpointer data)628 binding_reload_combos_foreach (gpointer key,
629 gpointer value,
630 gpointer data)
631 {
632 MetaKeyBindingManager *keys = data;
633 MetaKeyBinding *binding = value;
634
635 resolve_key_combo (keys, &binding->combo, &binding->resolved_combo);
636 index_binding (keys, binding);
637 }
638
639 typedef struct _FindLatinKeysymsState
640 {
641 MetaKeyBindingKeyboardLayout *layout;
642 gboolean *required_keysyms_found;
643 int n_required_keysyms;
644 } FindLatinKeysymsState;
645
646 static void
find_latin_keysym(struct xkb_keymap * keymap,xkb_keycode_t key,void * data)647 find_latin_keysym (struct xkb_keymap *keymap,
648 xkb_keycode_t key,
649 void *data)
650 {
651 FindLatinKeysymsState *state = data;
652 int n_keysyms, i;
653 const xkb_keysym_t *keysyms;
654
655 n_keysyms = xkb_keymap_key_get_syms_by_level (state->layout->keymap,
656 key,
657 state->layout->index,
658 0,
659 &keysyms);
660 for (i = 0; i < n_keysyms; i++)
661 {
662 xkb_keysym_t keysym = keysyms[i];
663
664 if (keysym >= XKB_KEY_a && keysym <= XKB_KEY_z)
665 {
666 unsigned int keysym_index = keysym - XKB_KEY_a;
667
668 if (!state->required_keysyms_found[keysym_index])
669 {
670 state->required_keysyms_found[keysym_index] = TRUE;
671 state->n_required_keysyms--;
672 }
673 }
674 }
675 }
676
677 static gboolean
needs_secondary_layout(MetaKeyBindingKeyboardLayout * layout)678 needs_secondary_layout (MetaKeyBindingKeyboardLayout *layout)
679 {
680 gboolean required_keysyms_found[] = {
681 FALSE, /* XKB_KEY_a */
682 FALSE, /* XKB_KEY_b */
683 FALSE, /* XKB_KEY_c */
684 FALSE, /* XKB_KEY_d */
685 FALSE, /* XKB_KEY_e */
686 FALSE, /* XKB_KEY_f */
687 FALSE, /* XKB_KEY_g */
688 FALSE, /* XKB_KEY_h */
689 FALSE, /* XKB_KEY_i */
690 FALSE, /* XKB_KEY_j */
691 FALSE, /* XKB_KEY_k */
692 FALSE, /* XKB_KEY_l */
693 FALSE, /* XKB_KEY_m */
694 FALSE, /* XKB_KEY_n */
695 FALSE, /* XKB_KEY_o */
696 FALSE, /* XKB_KEY_p */
697 FALSE, /* XKB_KEY_q */
698 FALSE, /* XKB_KEY_r */
699 FALSE, /* XKB_KEY_s */
700 FALSE, /* XKB_KEY_t */
701 FALSE, /* XKB_KEY_u */
702 FALSE, /* XKB_KEY_v */
703 FALSE, /* XKB_KEY_w */
704 FALSE, /* XKB_KEY_x */
705 FALSE, /* XKB_KEY_y */
706 FALSE, /* XKB_KEY_z */
707 };
708 FindLatinKeysymsState state = {
709 .layout = layout,
710 .required_keysyms_found = required_keysyms_found,
711 .n_required_keysyms = G_N_ELEMENTS (required_keysyms_found),
712 };
713
714 xkb_keymap_key_for_each (layout->keymap, find_latin_keysym, &state);
715
716 return state.n_required_keysyms != 0;
717 }
718
719 static void
clear_active_keyboard_layouts(MetaKeyBindingManager * keys)720 clear_active_keyboard_layouts (MetaKeyBindingManager *keys)
721 {
722 unsigned int i;
723
724 for (i = 0; i < G_N_ELEMENTS (keys->active_layouts); i++)
725 {
726 MetaKeyBindingKeyboardLayout *layout = &keys->active_layouts[i];
727
728 g_clear_pointer (&layout->keymap, xkb_keymap_unref);
729 *layout = (MetaKeyBindingKeyboardLayout) { 0 };
730 }
731 }
732
733 static MetaKeyBindingKeyboardLayout
create_us_layout(void)734 create_us_layout (void)
735 {
736 struct xkb_rule_names names;
737 struct xkb_keymap *keymap;
738 struct xkb_context *context;
739
740 names.rules = DEFAULT_XKB_RULES_FILE;
741 names.model = DEFAULT_XKB_MODEL;
742 names.layout = "us";
743 names.variant = "";
744 names.options = "";
745
746 context = meta_create_xkb_context ();
747 keymap = xkb_keymap_new_from_names (context, &names, XKB_KEYMAP_COMPILE_NO_FLAGS);
748 xkb_context_unref (context);
749
750 return (MetaKeyBindingKeyboardLayout) {
751 .keymap = keymap,
752 .n_levels = calculate_n_layout_levels (keymap, 0),
753 };
754 }
755
756 static void
reload_active_keyboard_layouts(MetaKeyBindingManager * keys)757 reload_active_keyboard_layouts (MetaKeyBindingManager *keys)
758 {
759 struct xkb_keymap *keymap;
760 xkb_layout_index_t layout_index;
761 MetaKeyBindingKeyboardLayout primary_layout;
762
763 clear_active_keyboard_layouts (keys);
764
765 keymap = meta_backend_get_keymap (keys->backend);
766 layout_index = meta_backend_get_keymap_layout_group (keys->backend);
767 primary_layout = (MetaKeyBindingKeyboardLayout) {
768 .keymap = xkb_keymap_ref (keymap),
769 .index = layout_index,
770 .n_levels = calculate_n_layout_levels (keymap, layout_index),
771 };
772
773 keys->active_layouts[META_KEY_BINDING_PRIMARY_LAYOUT] = primary_layout;
774
775 if (needs_secondary_layout (&primary_layout))
776 {
777 MetaKeyBindingKeyboardLayout us_layout;
778
779 us_layout = create_us_layout ();
780 keys->active_layouts[META_KEY_BINDING_SECONDARY_LAYOUT] = us_layout;
781 }
782 }
783
784 static void
reload_combos(MetaKeyBindingManager * keys)785 reload_combos (MetaKeyBindingManager *keys)
786 {
787 g_hash_table_remove_all (keys->key_bindings_index);
788
789 reload_active_keyboard_layouts (keys);
790
791 resolve_key_combo (keys,
792 &keys->overlay_key_combo,
793 &keys->overlay_resolved_key_combo);
794
795 resolve_key_combo (keys,
796 &keys->locate_pointer_key_combo,
797 &keys->locate_pointer_resolved_key_combo);
798
799 reload_iso_next_group_combos (keys);
800
801 g_hash_table_foreach (keys->key_bindings, binding_reload_combos_foreach, keys);
802 }
803
804 static void
rebuild_binding_table(MetaKeyBindingManager * keys,GList * prefs,GList * grabs)805 rebuild_binding_table (MetaKeyBindingManager *keys,
806 GList *prefs,
807 GList *grabs)
808 {
809 MetaKeyBinding *b;
810 GList *p, *g;
811
812 g_hash_table_remove_all (keys->key_bindings);
813
814 p = prefs;
815 while (p)
816 {
817 MetaKeyPref *pref = (MetaKeyPref*)p->data;
818 GSList *tmp = pref->combos;
819
820 while (tmp)
821 {
822 MetaKeyCombo *combo = tmp->data;
823
824 if (combo && (combo->keysym != None || combo->keycode != 0))
825 {
826 MetaKeyHandler *handler = HANDLER (pref->name);
827
828 b = g_new0 (MetaKeyBinding, 1);
829 b->name = pref->name;
830 b->handler = handler;
831 b->flags = handler->flags;
832 b->combo = *combo;
833
834 g_hash_table_add (keys->key_bindings, b);
835 }
836
837 tmp = tmp->next;
838 }
839
840 p = p->next;
841 }
842
843 g = grabs;
844 while (g)
845 {
846 MetaKeyGrab *grab = (MetaKeyGrab*)g->data;
847 if (grab->combo.keysym != None || grab->combo.keycode != 0)
848 {
849 MetaKeyHandler *handler = HANDLER ("external-grab");
850
851 b = g_new0 (MetaKeyBinding, 1);
852 b->name = grab->name;
853 b->handler = handler;
854 b->flags = grab->flags;
855 b->combo = grab->combo;
856
857 g_hash_table_add (keys->key_bindings, b);
858 }
859
860 g = g->next;
861 }
862
863 meta_topic (META_DEBUG_KEYBINDINGS,
864 " %d bindings in table",
865 g_hash_table_size (keys->key_bindings));
866 }
867
868 static void
rebuild_key_binding_table(MetaKeyBindingManager * keys)869 rebuild_key_binding_table (MetaKeyBindingManager *keys)
870 {
871 GList *prefs, *grabs;
872
873 meta_topic (META_DEBUG_KEYBINDINGS,
874 "Rebuilding key binding table from preferences");
875
876 prefs = meta_prefs_get_keybindings ();
877 grabs = g_hash_table_get_values (external_grabs);
878 rebuild_binding_table (keys, prefs, grabs);
879 g_list_free (prefs);
880 g_list_free (grabs);
881 }
882
883 static void
rebuild_special_bindings(MetaKeyBindingManager * keys)884 rebuild_special_bindings (MetaKeyBindingManager *keys)
885 {
886 MetaKeyCombo combo;
887
888 meta_prefs_get_overlay_binding (&combo);
889 keys->overlay_key_combo = combo;
890
891 meta_prefs_get_locate_pointer_binding (&combo);
892 keys->locate_pointer_key_combo = combo;
893 }
894
895 static void
ungrab_key_bindings(MetaDisplay * display)896 ungrab_key_bindings (MetaDisplay *display)
897 {
898 GSList *windows, *l;
899
900 if (display->x11_display)
901 meta_x11_display_ungrab_keys (display->x11_display);
902
903 windows = meta_display_list_windows (display, META_LIST_DEFAULT);
904 for (l = windows; l; l = l->next)
905 {
906 MetaWindow *w = l->data;
907 meta_window_ungrab_keys (w);
908 }
909
910 g_slist_free (windows);
911 }
912
913 static void
grab_key_bindings(MetaDisplay * display)914 grab_key_bindings (MetaDisplay *display)
915 {
916 GSList *windows, *l;
917
918 if (display->x11_display)
919 meta_x11_display_grab_keys (display->x11_display);
920
921 windows = meta_display_list_windows (display, META_LIST_DEFAULT);
922 for (l = windows; l; l = l->next)
923 {
924 MetaWindow *w = l->data;
925 meta_window_grab_keys (w);
926 }
927
928 g_slist_free (windows);
929 }
930
931 static MetaKeyBinding *
get_keybinding(MetaKeyBindingManager * keys,MetaResolvedKeyCombo * resolved_combo)932 get_keybinding (MetaKeyBindingManager *keys,
933 MetaResolvedKeyCombo *resolved_combo)
934 {
935 MetaKeyBinding *binding = NULL;
936 int i;
937
938 for (i = 0; i < resolved_combo->len; i++)
939 {
940 guint32 key;
941
942 key = key_combo_key (resolved_combo, i);
943 binding = g_hash_table_lookup (keys->key_bindings_index,
944 GINT_TO_POINTER (key));
945
946 if (binding != NULL)
947 break;
948 }
949
950 return binding;
951 }
952
953 static guint
next_dynamic_keybinding_action(void)954 next_dynamic_keybinding_action (void)
955 {
956 static guint num_dynamic_bindings = 0;
957 return META_KEYBINDING_ACTION_LAST + (++num_dynamic_bindings);
958 }
959
960 static gboolean
add_keybinding_internal(MetaDisplay * display,const char * name,GSettings * settings,MetaKeyBindingFlags flags,MetaKeyBindingAction action,MetaKeyHandlerFunc func,int data,gpointer user_data,GDestroyNotify free_data)961 add_keybinding_internal (MetaDisplay *display,
962 const char *name,
963 GSettings *settings,
964 MetaKeyBindingFlags flags,
965 MetaKeyBindingAction action,
966 MetaKeyHandlerFunc func,
967 int data,
968 gpointer user_data,
969 GDestroyNotify free_data)
970 {
971 MetaKeyHandler *handler;
972
973 if (!meta_prefs_add_keybinding (name, settings, action, flags))
974 return FALSE;
975
976 handler = g_new0 (MetaKeyHandler, 1);
977 handler->name = g_strdup (name);
978 handler->func = func;
979 handler->default_func = func;
980 handler->data = data;
981 handler->flags = flags;
982 handler->user_data = user_data;
983 handler->user_data_free_func = free_data;
984
985 g_hash_table_insert (key_handlers, g_strdup (name), handler);
986
987 return TRUE;
988 }
989
990 static gboolean
add_builtin_keybinding(MetaDisplay * display,const char * name,GSettings * settings,MetaKeyBindingFlags flags,MetaKeyBindingAction action,MetaKeyHandlerFunc handler,int handler_arg)991 add_builtin_keybinding (MetaDisplay *display,
992 const char *name,
993 GSettings *settings,
994 MetaKeyBindingFlags flags,
995 MetaKeyBindingAction action,
996 MetaKeyHandlerFunc handler,
997 int handler_arg)
998 {
999 return add_keybinding_internal (display, name, settings,
1000 flags | META_KEY_BINDING_BUILTIN,
1001 action, handler, handler_arg, NULL, NULL);
1002 }
1003
1004 /**
1005 * meta_display_add_keybinding:
1006 * @display: a #MetaDisplay
1007 * @name: the binding's name
1008 * @settings: the #GSettings object where @name is stored
1009 * @flags: flags to specify binding details
1010 * @handler: function to run when the keybinding is invoked
1011 * @user_data: the data to pass to @handler
1012 * @free_data: function to free @user_data
1013 *
1014 * Add a keybinding at runtime. The key @name in @schema needs to be of
1015 * type %G_VARIANT_TYPE_STRING_ARRAY, with each string describing a
1016 * keybinding in the form of "<Control>a" or "<Shift><Alt>F1". The parser
1017 * is fairly liberal and allows lower or upper case, and also abbreviations
1018 * such as "<Ctl>" and "<Ctrl>". If the key is set to the empty list or a
1019 * list with a single element of either "" or "disabled", the keybinding is
1020 * disabled.
1021 *
1022 * Use meta_display_remove_keybinding() to remove the binding.
1023 *
1024 * Returns: the corresponding keybinding action if the keybinding was
1025 * added successfully, otherwise %META_KEYBINDING_ACTION_NONE
1026 */
1027 guint
meta_display_add_keybinding(MetaDisplay * display,const char * name,GSettings * settings,MetaKeyBindingFlags flags,MetaKeyHandlerFunc handler,gpointer user_data,GDestroyNotify free_data)1028 meta_display_add_keybinding (MetaDisplay *display,
1029 const char *name,
1030 GSettings *settings,
1031 MetaKeyBindingFlags flags,
1032 MetaKeyHandlerFunc handler,
1033 gpointer user_data,
1034 GDestroyNotify free_data)
1035 {
1036 guint new_action = next_dynamic_keybinding_action ();
1037
1038 if (!add_keybinding_internal (display, name, settings, flags, new_action,
1039 handler, 0, user_data, free_data))
1040 return META_KEYBINDING_ACTION_NONE;
1041
1042 return new_action;
1043 }
1044
1045 /**
1046 * meta_display_remove_keybinding:
1047 * @display: the #MetaDisplay
1048 * @name: name of the keybinding to remove
1049 *
1050 * Remove keybinding @name; the function will fail if @name is not a known
1051 * keybinding or has not been added with meta_display_add_keybinding().
1052 *
1053 * Returns: %TRUE if the binding has been removed successfully,
1054 * otherwise %FALSE
1055 */
1056 gboolean
meta_display_remove_keybinding(MetaDisplay * display,const char * name)1057 meta_display_remove_keybinding (MetaDisplay *display,
1058 const char *name)
1059 {
1060 if (!meta_prefs_remove_keybinding (name))
1061 return FALSE;
1062
1063 g_hash_table_remove (key_handlers, name);
1064
1065 return TRUE;
1066 }
1067
1068 static guint
get_keybinding_action(MetaKeyBindingManager * keys,MetaResolvedKeyCombo * resolved_combo)1069 get_keybinding_action (MetaKeyBindingManager *keys,
1070 MetaResolvedKeyCombo *resolved_combo)
1071 {
1072 MetaKeyBinding *binding;
1073
1074 /* This is much more vague than the MetaDisplay::overlay-key signal,
1075 * which is only emitted if the overlay-key is the only key pressed;
1076 * as this method is primarily intended for plugins to allow processing
1077 * of mutter keybindings while holding a grab, the overlay-key-only-pressed
1078 * tracking is left to the plugin here.
1079 */
1080 if (resolved_key_combo_intersect (resolved_combo,
1081 &keys->overlay_resolved_key_combo))
1082 return META_KEYBINDING_ACTION_OVERLAY_KEY;
1083
1084 if (resolved_key_combo_intersect (resolved_combo,
1085 &keys->locate_pointer_resolved_key_combo))
1086 return META_KEYBINDING_ACTION_LOCATE_POINTER_KEY;
1087
1088 binding = get_keybinding (keys, resolved_combo);
1089 if (binding)
1090 {
1091 MetaKeyGrab *grab = g_hash_table_lookup (external_grabs, binding->name);
1092 if (grab)
1093 return grab->action;
1094 else
1095 return (guint) meta_prefs_get_keybinding_action (binding->name);
1096 }
1097 else
1098 {
1099 return META_KEYBINDING_ACTION_NONE;
1100 }
1101 }
1102
1103 static xkb_mod_mask_t
mask_from_event_params(MetaKeyBindingManager * keys,unsigned long mask)1104 mask_from_event_params (MetaKeyBindingManager *keys,
1105 unsigned long mask)
1106 {
1107 return mask & 0xff & ~keys->ignored_modifier_mask;
1108 }
1109
1110 /**
1111 * meta_display_get_keybinding_action:
1112 * @display: A #MetaDisplay
1113 * @keycode: Raw keycode
1114 * @mask: Event mask
1115 *
1116 * Get the keybinding action bound to @keycode. Builtin keybindings
1117 * have a fixed associated #MetaKeyBindingAction, for bindings added
1118 * dynamically the function will return the keybinding action
1119 * meta_display_add_keybinding() returns on registration.
1120 *
1121 * Returns: The action that should be taken for the given key, or
1122 * %META_KEYBINDING_ACTION_NONE.
1123 */
1124 guint
meta_display_get_keybinding_action(MetaDisplay * display,unsigned int keycode,unsigned long mask)1125 meta_display_get_keybinding_action (MetaDisplay *display,
1126 unsigned int keycode,
1127 unsigned long mask)
1128 {
1129 MetaKeyBindingManager *keys = &display->key_binding_manager;
1130 xkb_keycode_t code = (xkb_keycode_t) keycode;
1131 MetaResolvedKeyCombo resolved_combo = { &code, 1 };
1132
1133 resolved_combo.mask = mask_from_event_params (keys, mask);
1134 return get_keybinding_action (keys, &resolved_combo);
1135 }
1136
1137 static void
reload_keybindings(MetaDisplay * display)1138 reload_keybindings (MetaDisplay *display)
1139 {
1140 MetaKeyBindingManager *keys = &display->key_binding_manager;
1141
1142 ungrab_key_bindings (display);
1143
1144 /* Deciphering the modmap depends on the loaded keysyms to find out
1145 * what modifiers is Super and so forth, so we need to reload it
1146 * even when only the keymap changes */
1147 reload_modmap (keys);
1148
1149 reload_combos (keys);
1150
1151 grab_key_bindings (display);
1152 }
1153
1154 static GArray *
calc_grab_modifiers(MetaKeyBindingManager * keys,unsigned int modmask)1155 calc_grab_modifiers (MetaKeyBindingManager *keys,
1156 unsigned int modmask)
1157 {
1158 unsigned int ignored_mask;
1159 XIGrabModifiers mods;
1160 GArray *mods_array = g_array_new (FALSE, TRUE, sizeof (XIGrabModifiers));
1161
1162 /* The X server crashes if XIAnyModifier gets passed in with any
1163 other bits. It doesn't make sense to ask for a grab of
1164 XIAnyModifier plus other bits anyway so we avoid that. */
1165 if (modmask & XIAnyModifier)
1166 {
1167 mods = (XIGrabModifiers) { XIAnyModifier, 0 };
1168 g_array_append_val (mods_array, mods);
1169 return mods_array;
1170 }
1171
1172 mods = (XIGrabModifiers) { modmask, 0 };
1173 g_array_append_val (mods_array, mods);
1174
1175 for (ignored_mask = 1;
1176 ignored_mask <= keys->ignored_modifier_mask;
1177 ++ignored_mask)
1178 {
1179 if (ignored_mask & keys->ignored_modifier_mask)
1180 {
1181 mods = (XIGrabModifiers) { modmask | ignored_mask, 0 };
1182 g_array_append_val (mods_array, mods);
1183 }
1184 }
1185
1186 return mods_array;
1187 }
1188
1189 static void
meta_change_button_grab(MetaKeyBindingManager * keys,Window xwindow,gboolean grab,gboolean sync,int button,int modmask)1190 meta_change_button_grab (MetaKeyBindingManager *keys,
1191 Window xwindow,
1192 gboolean grab,
1193 gboolean sync,
1194 int button,
1195 int modmask)
1196 {
1197 if (meta_is_wayland_compositor ())
1198 return;
1199
1200 MetaBackendX11 *backend = META_BACKEND_X11 (keys->backend);
1201 Display *xdisplay = meta_backend_x11_get_xdisplay (backend);
1202
1203 unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
1204 XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
1205 GArray *mods;
1206
1207 XISetMask (mask.mask, XI_ButtonPress);
1208 XISetMask (mask.mask, XI_ButtonRelease);
1209 XISetMask (mask.mask, XI_Motion);
1210
1211 mods = calc_grab_modifiers (keys, modmask);
1212
1213 /* GrabModeSync means freeze until XAllowEvents */
1214 if (grab)
1215 XIGrabButton (xdisplay,
1216 META_VIRTUAL_CORE_POINTER_ID,
1217 button, xwindow, None,
1218 sync ? XIGrabModeSync : XIGrabModeAsync,
1219 XIGrabModeAsync, False,
1220 &mask, mods->len, (XIGrabModifiers *)mods->data);
1221 else
1222 XIUngrabButton (xdisplay,
1223 META_VIRTUAL_CORE_POINTER_ID,
1224 button, xwindow, mods->len, (XIGrabModifiers *)mods->data);
1225
1226 g_array_free (mods, TRUE);
1227 }
1228
1229 ClutterModifierType
meta_display_get_compositor_modifiers(MetaDisplay * display)1230 meta_display_get_compositor_modifiers (MetaDisplay *display)
1231 {
1232 MetaKeyBindingManager *keys = &display->key_binding_manager;
1233 return keys->window_grab_modifiers;
1234 }
1235
1236 static void
meta_change_buttons_grab(MetaKeyBindingManager * keys,Window xwindow,gboolean grab,gboolean sync,int modmask)1237 meta_change_buttons_grab (MetaKeyBindingManager *keys,
1238 Window xwindow,
1239 gboolean grab,
1240 gboolean sync,
1241 int modmask)
1242 {
1243 #define MAX_BUTTON 3
1244
1245 int i;
1246 for (i = 1; i <= MAX_BUTTON; i++)
1247 meta_change_button_grab (keys, xwindow, grab, sync, i, modmask);
1248 }
1249
1250 void
meta_display_grab_window_buttons(MetaDisplay * display,Window xwindow)1251 meta_display_grab_window_buttons (MetaDisplay *display,
1252 Window xwindow)
1253 {
1254 MetaKeyBindingManager *keys = &display->key_binding_manager;
1255
1256 /* Grab Alt + button1 for moving window.
1257 * Grab Alt + button2 for resizing window.
1258 * Grab Alt + button3 for popping up window menu.
1259 * Grab Alt + Shift + button1 for snap-moving window.
1260 */
1261 meta_verbose ("Grabbing window buttons for 0x%lx", xwindow);
1262
1263 /* FIXME If we ignored errors here instead of spewing, we could
1264 * put one big error trap around the loop and avoid a bunch of
1265 * XSync()
1266 */
1267
1268 if (keys->window_grab_modifiers != 0)
1269 {
1270 meta_change_buttons_grab (keys, xwindow, TRUE, FALSE,
1271 keys->window_grab_modifiers);
1272
1273 /* In addition to grabbing Alt+Button1 for moving the window,
1274 * grab Alt+Shift+Button1 for snap-moving the window. See bug
1275 * 112478. Unfortunately, this doesn't work with
1276 * Shift+Alt+Button1 for some reason; so at least part of the
1277 * order still matters, which sucks (please FIXME).
1278 */
1279 meta_change_button_grab (keys, xwindow,
1280 TRUE,
1281 FALSE,
1282 1, keys->window_grab_modifiers | ShiftMask);
1283 }
1284 }
1285
1286 void
meta_display_ungrab_window_buttons(MetaDisplay * display,Window xwindow)1287 meta_display_ungrab_window_buttons (MetaDisplay *display,
1288 Window xwindow)
1289 {
1290 MetaKeyBindingManager *keys = &display->key_binding_manager;
1291
1292 if (keys->window_grab_modifiers == 0)
1293 return;
1294
1295 meta_change_buttons_grab (keys, xwindow, FALSE, FALSE,
1296 keys->window_grab_modifiers);
1297 }
1298
1299 static void
update_window_grab_modifiers(MetaDisplay * display)1300 update_window_grab_modifiers (MetaDisplay *display)
1301 {
1302 MetaKeyBindingManager *keys = &display->key_binding_manager;
1303 MetaVirtualModifier virtual_mods;
1304 unsigned int mods;
1305
1306 virtual_mods = meta_prefs_get_mouse_button_mods ();
1307 devirtualize_modifiers (keys, virtual_mods, &mods);
1308
1309 if (keys->window_grab_modifiers != mods)
1310 {
1311 keys->window_grab_modifiers = mods;
1312 g_object_notify (G_OBJECT (display), "compositor-modifiers");
1313 }
1314 }
1315
1316 void
meta_display_grab_focus_window_button(MetaDisplay * display,MetaWindow * window)1317 meta_display_grab_focus_window_button (MetaDisplay *display,
1318 MetaWindow *window)
1319 {
1320 MetaKeyBindingManager *keys = &display->key_binding_manager;
1321
1322 /* Grab button 1 for activating unfocused windows */
1323 meta_verbose ("Grabbing unfocused window buttons for %s", window->desc);
1324
1325 if (window->have_focus_click_grab)
1326 {
1327 meta_verbose (" (well, not grabbing since we already have the grab)");
1328 return;
1329 }
1330
1331 /* FIXME If we ignored errors here instead of spewing, we could
1332 * put one big error trap around the loop and avoid a bunch of
1333 * XSync()
1334 */
1335
1336 meta_change_buttons_grab (keys, window->xwindow, TRUE, TRUE, XIAnyModifier);
1337 window->have_focus_click_grab = TRUE;
1338 }
1339
1340 void
meta_display_ungrab_focus_window_button(MetaDisplay * display,MetaWindow * window)1341 meta_display_ungrab_focus_window_button (MetaDisplay *display,
1342 MetaWindow *window)
1343 {
1344 MetaKeyBindingManager *keys = &display->key_binding_manager;
1345
1346 meta_verbose ("Ungrabbing unfocused window buttons for %s", window->desc);
1347
1348 if (!window->have_focus_click_grab)
1349 return;
1350
1351 meta_change_buttons_grab (keys, window->xwindow, FALSE, FALSE, XIAnyModifier);
1352 window->have_focus_click_grab = FALSE;
1353 }
1354
1355 static void
prefs_changed_callback(MetaPreference pref,void * data)1356 prefs_changed_callback (MetaPreference pref,
1357 void *data)
1358 {
1359 MetaDisplay *display = data;
1360 MetaKeyBindingManager *keys = &display->key_binding_manager;
1361
1362 switch (pref)
1363 {
1364 case META_PREF_LOCATE_POINTER:
1365 maybe_update_locate_pointer_keygrab (display,
1366 meta_prefs_is_locate_pointer_enabled());
1367 break;
1368 case META_PREF_KEYBINDINGS:
1369 ungrab_key_bindings (display);
1370 rebuild_key_binding_table (keys);
1371 rebuild_special_bindings (keys);
1372 reload_combos (keys);
1373 grab_key_bindings (display);
1374 break;
1375 case META_PREF_MOUSE_BUTTON_MODS:
1376 {
1377 GSList *windows, *l;
1378 windows = meta_display_list_windows (display, META_LIST_DEFAULT);
1379
1380 for (l = windows; l; l = l->next)
1381 {
1382 MetaWindow *w = l->data;
1383 meta_display_ungrab_window_buttons (display, w->xwindow);
1384 }
1385
1386 update_window_grab_modifiers (display);
1387
1388 for (l = windows; l; l = l->next)
1389 {
1390 MetaWindow *w = l->data;
1391 if (w->type != META_WINDOW_DOCK)
1392 meta_display_grab_window_buttons (display, w->xwindow);
1393 }
1394
1395 g_slist_free (windows);
1396 }
1397 default:
1398 break;
1399 }
1400 }
1401
1402
1403 void
meta_display_shutdown_keys(MetaDisplay * display)1404 meta_display_shutdown_keys (MetaDisplay *display)
1405 {
1406 MetaKeyBindingManager *keys = &display->key_binding_manager;
1407
1408 meta_prefs_remove_listener (prefs_changed_callback, display);
1409
1410 g_hash_table_destroy (keys->key_bindings_index);
1411 g_hash_table_destroy (keys->key_bindings);
1412
1413 clear_active_keyboard_layouts (keys);
1414 }
1415
1416 /* Grab/ungrab, ignoring all annoying modifiers like NumLock etc. */
1417 static void
meta_change_keygrab(MetaKeyBindingManager * keys,Window xwindow,gboolean grab,MetaResolvedKeyCombo * resolved_combo)1418 meta_change_keygrab (MetaKeyBindingManager *keys,
1419 Window xwindow,
1420 gboolean grab,
1421 MetaResolvedKeyCombo *resolved_combo)
1422 {
1423 unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
1424 XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
1425
1426 XISetMask (mask.mask, XI_KeyPress);
1427 XISetMask (mask.mask, XI_KeyRelease);
1428
1429 if (meta_is_wayland_compositor ())
1430 return;
1431
1432 MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ());
1433 Display *xdisplay = meta_backend_x11_get_xdisplay (backend);
1434 GArray *mods;
1435 int i;
1436
1437 /* Grab keycode/modmask, together with
1438 * all combinations of ignored modifiers.
1439 * X provides no better way to do this.
1440 */
1441
1442 mods = calc_grab_modifiers (keys, resolved_combo->mask);
1443
1444 for (i = 0; i < resolved_combo->len; i++)
1445 {
1446 xkb_keycode_t keycode = resolved_combo->keycodes[i];
1447
1448 meta_topic (META_DEBUG_KEYBINDINGS,
1449 "%s keybinding keycode %d mask 0x%x on 0x%lx",
1450 grab ? "Grabbing" : "Ungrabbing",
1451 keycode, resolved_combo->mask, xwindow);
1452
1453 if (grab)
1454 XIGrabKeycode (xdisplay,
1455 META_VIRTUAL_CORE_KEYBOARD_ID,
1456 keycode, xwindow,
1457 XIGrabModeSync, XIGrabModeAsync,
1458 False, &mask, mods->len, (XIGrabModifiers *)mods->data);
1459 else
1460 XIUngrabKeycode (xdisplay,
1461 META_VIRTUAL_CORE_KEYBOARD_ID,
1462 keycode, xwindow,
1463 mods->len, (XIGrabModifiers *)mods->data);
1464 }
1465
1466 g_array_free (mods, TRUE);
1467 }
1468
1469 typedef struct
1470 {
1471 MetaKeyBindingManager *keys;
1472 Window xwindow;
1473 gboolean only_per_window;
1474 gboolean grab;
1475 } ChangeKeygrabData;
1476
1477 static void
change_keygrab_foreach(gpointer key,gpointer value,gpointer user_data)1478 change_keygrab_foreach (gpointer key,
1479 gpointer value,
1480 gpointer user_data)
1481 {
1482 ChangeKeygrabData *data = user_data;
1483 MetaKeyBinding *binding = value;
1484 gboolean binding_is_per_window = (binding->flags & META_KEY_BINDING_PER_WINDOW) != 0;
1485
1486 if (data->only_per_window != binding_is_per_window)
1487 return;
1488
1489 /* Ignore the key bindings marked as META_KEY_BINDING_NO_AUTO_GRAB,
1490 * those are handled separately
1491 */
1492 if (binding->flags & META_KEY_BINDING_NO_AUTO_GRAB)
1493 return;
1494
1495 if (binding->resolved_combo.len == 0)
1496 return;
1497
1498 meta_change_keygrab (data->keys, data->xwindow, data->grab, &binding->resolved_combo);
1499 }
1500
1501 static void
change_binding_keygrabs(MetaKeyBindingManager * keys,Window xwindow,gboolean only_per_window,gboolean grab)1502 change_binding_keygrabs (MetaKeyBindingManager *keys,
1503 Window xwindow,
1504 gboolean only_per_window,
1505 gboolean grab)
1506 {
1507 ChangeKeygrabData data;
1508
1509 data.keys = keys;
1510 data.xwindow = xwindow;
1511 data.only_per_window = only_per_window;
1512 data.grab = grab;
1513
1514 g_hash_table_foreach (keys->key_bindings, change_keygrab_foreach, &data);
1515 }
1516
1517 static void
maybe_update_locate_pointer_keygrab(MetaDisplay * display,gboolean grab)1518 maybe_update_locate_pointer_keygrab (MetaDisplay *display,
1519 gboolean grab)
1520 {
1521 MetaKeyBindingManager *keys = &display->key_binding_manager;
1522
1523 if (!display->x11_display)
1524 return;
1525
1526 if (keys->locate_pointer_resolved_key_combo.len != 0)
1527 meta_change_keygrab (keys, display->x11_display->xroot,
1528 (!!grab & !!meta_prefs_is_locate_pointer_enabled()),
1529 &keys->locate_pointer_resolved_key_combo);
1530 }
1531
1532 static void
meta_x11_display_change_keygrabs(MetaX11Display * x11_display,gboolean grab)1533 meta_x11_display_change_keygrabs (MetaX11Display *x11_display,
1534 gboolean grab)
1535 {
1536 MetaKeyBindingManager *keys = &x11_display->display->key_binding_manager;
1537 int i;
1538
1539 if (keys->overlay_resolved_key_combo.len != 0)
1540 meta_change_keygrab (keys, x11_display->xroot,
1541 grab, &keys->overlay_resolved_key_combo);
1542
1543 maybe_update_locate_pointer_keygrab (x11_display->display, grab);
1544
1545 for (i = 0; i < keys->n_iso_next_group_combos; i++)
1546 meta_change_keygrab (keys, x11_display->xroot,
1547 grab, &keys->iso_next_group_combo[i]);
1548
1549 change_binding_keygrabs (keys, x11_display->xroot,
1550 FALSE, grab);
1551 }
1552
1553 void
meta_x11_display_grab_keys(MetaX11Display * x11_display)1554 meta_x11_display_grab_keys (MetaX11Display *x11_display)
1555 {
1556 if (x11_display->keys_grabbed)
1557 return;
1558
1559 meta_x11_display_change_keygrabs (x11_display, TRUE);
1560
1561 x11_display->keys_grabbed = TRUE;
1562 }
1563
1564 void
meta_x11_display_ungrab_keys(MetaX11Display * x11_display)1565 meta_x11_display_ungrab_keys (MetaX11Display *x11_display)
1566 {
1567 if (!x11_display->keys_grabbed)
1568 return;
1569
1570 meta_x11_display_change_keygrabs (x11_display, FALSE);
1571
1572 x11_display->keys_grabbed = FALSE;
1573 }
1574
1575 static void
change_window_keygrabs(MetaKeyBindingManager * keys,Window xwindow,gboolean grab)1576 change_window_keygrabs (MetaKeyBindingManager *keys,
1577 Window xwindow,
1578 gboolean grab)
1579 {
1580 change_binding_keygrabs (keys, xwindow, TRUE, grab);
1581 }
1582
1583 void
meta_window_grab_keys(MetaWindow * window)1584 meta_window_grab_keys (MetaWindow *window)
1585 {
1586 MetaDisplay *display = window->display;
1587 MetaKeyBindingManager *keys = &display->key_binding_manager;
1588
1589 if (meta_is_wayland_compositor ())
1590 return;
1591 if (window->all_keys_grabbed)
1592 return;
1593
1594 if (window->type == META_WINDOW_DOCK
1595 || window->override_redirect)
1596 {
1597 if (window->keys_grabbed)
1598 change_window_keygrabs (keys, window->xwindow, FALSE);
1599 window->keys_grabbed = FALSE;
1600 return;
1601 }
1602
1603 if (window->keys_grabbed)
1604 {
1605 if (window->frame && !window->grab_on_frame)
1606 change_window_keygrabs (keys, window->xwindow, FALSE);
1607 else if (window->frame == NULL &&
1608 window->grab_on_frame)
1609 ; /* continue to regrab on client window */
1610 else
1611 return; /* already all good */
1612 }
1613
1614 change_window_keygrabs (keys,
1615 meta_window_x11_get_toplevel_xwindow (window),
1616 TRUE);
1617
1618 window->keys_grabbed = TRUE;
1619 window->grab_on_frame = window->frame != NULL;
1620 }
1621
1622 void
meta_window_ungrab_keys(MetaWindow * window)1623 meta_window_ungrab_keys (MetaWindow *window)
1624 {
1625 if (!meta_is_wayland_compositor () && window->keys_grabbed)
1626 {
1627 MetaDisplay *display = window->display;
1628 MetaKeyBindingManager *keys = &display->key_binding_manager;
1629
1630 if (window->grab_on_frame &&
1631 window->frame != NULL)
1632 change_window_keygrabs (keys, window->frame->xwindow, FALSE);
1633 else if (!window->grab_on_frame)
1634 change_window_keygrabs (keys, window->xwindow, FALSE);
1635
1636 window->keys_grabbed = FALSE;
1637 }
1638 }
1639
1640 static void
handle_external_grab(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer user_data)1641 handle_external_grab (MetaDisplay *display,
1642 MetaWindow *window,
1643 ClutterKeyEvent *event,
1644 MetaKeyBinding *binding,
1645 gpointer user_data)
1646 {
1647 MetaKeyBindingManager *keys = &display->key_binding_manager;
1648 guint action = get_keybinding_action (keys, &binding->resolved_combo);
1649 meta_display_accelerator_activate (display, action, event);
1650 }
1651
1652
1653 guint
meta_display_grab_accelerator(MetaDisplay * display,const char * accelerator,MetaKeyBindingFlags flags)1654 meta_display_grab_accelerator (MetaDisplay *display,
1655 const char *accelerator,
1656 MetaKeyBindingFlags flags)
1657 {
1658 MetaKeyBindingManager *keys = &display->key_binding_manager;
1659 MetaKeyBinding *binding;
1660 MetaKeyGrab *grab;
1661 MetaKeyCombo combo = { 0 };
1662 MetaResolvedKeyCombo resolved_combo = { NULL, 0 };
1663
1664 if (!meta_parse_accelerator (accelerator, &combo))
1665 {
1666 meta_topic (META_DEBUG_KEYBINDINGS,
1667 "Failed to parse accelerator");
1668 meta_warning ("\"%s\" is not a valid accelerator", accelerator);
1669
1670 return META_KEYBINDING_ACTION_NONE;
1671 }
1672
1673 resolve_key_combo (keys, &combo, &resolved_combo);
1674
1675 if (resolved_combo.len == 0)
1676 return META_KEYBINDING_ACTION_NONE;
1677
1678 if (get_keybinding (keys, &resolved_combo))
1679 {
1680 resolved_key_combo_reset (&resolved_combo);
1681 return META_KEYBINDING_ACTION_NONE;
1682 }
1683
1684 if (!meta_is_wayland_compositor ())
1685 {
1686 meta_change_keygrab (keys, display->x11_display->xroot,
1687 TRUE, &resolved_combo);
1688 }
1689
1690 grab = g_new0 (MetaKeyGrab, 1);
1691 grab->action = next_dynamic_keybinding_action ();
1692 grab->name = meta_external_binding_name_for_action (grab->action);
1693 grab->combo = combo;
1694 grab->flags = flags;
1695
1696 g_hash_table_insert (external_grabs, grab->name, grab);
1697
1698 binding = g_new0 (MetaKeyBinding, 1);
1699 binding->name = grab->name;
1700 binding->handler = HANDLER ("external-grab");
1701 binding->combo = combo;
1702 binding->resolved_combo = resolved_combo;
1703 binding->flags = flags;
1704
1705 g_hash_table_add (keys->key_bindings, binding);
1706 index_binding (keys, binding);
1707
1708 return grab->action;
1709 }
1710
1711 gboolean
meta_display_ungrab_accelerator(MetaDisplay * display,guint action)1712 meta_display_ungrab_accelerator (MetaDisplay *display,
1713 guint action)
1714 {
1715 MetaKeyBindingManager *keys = &display->key_binding_manager;
1716 MetaKeyBinding *binding;
1717 MetaKeyGrab *grab;
1718 g_autofree char *key = NULL;
1719 MetaResolvedKeyCombo resolved_combo = { NULL, 0 };
1720
1721 g_return_val_if_fail (action != META_KEYBINDING_ACTION_NONE, FALSE);
1722
1723 key = meta_external_binding_name_for_action (action);
1724 grab = g_hash_table_lookup (external_grabs, key);
1725 if (!grab)
1726 return FALSE;
1727
1728 resolve_key_combo (keys, &grab->combo, &resolved_combo);
1729 binding = get_keybinding (keys, &resolved_combo);
1730 if (binding)
1731 {
1732 int i;
1733
1734 if (!meta_is_wayland_compositor ())
1735 {
1736 meta_change_keygrab (keys, display->x11_display->xroot,
1737 FALSE, &binding->resolved_combo);
1738 }
1739
1740 for (i = 0; i < binding->resolved_combo.len; i++)
1741 {
1742 guint32 index_key = key_combo_key (&binding->resolved_combo, i);
1743 g_hash_table_remove (keys->key_bindings_index, GINT_TO_POINTER (index_key));
1744 }
1745
1746 g_hash_table_remove (keys->key_bindings, binding);
1747 }
1748
1749 g_hash_table_remove (external_grabs, key);
1750 resolved_key_combo_reset (&resolved_combo);
1751
1752 return TRUE;
1753 }
1754
1755 static gboolean
grab_keyboard(Window xwindow,guint32 timestamp,int grab_mode)1756 grab_keyboard (Window xwindow,
1757 guint32 timestamp,
1758 int grab_mode)
1759 {
1760 int grab_status;
1761
1762 unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
1763 XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
1764
1765 XISetMask (mask.mask, XI_KeyPress);
1766 XISetMask (mask.mask, XI_KeyRelease);
1767
1768 if (meta_is_wayland_compositor ())
1769 return TRUE;
1770
1771 /* Grab the keyboard, so we get key releases and all key
1772 * presses
1773 */
1774
1775 MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ());
1776 Display *xdisplay = meta_backend_x11_get_xdisplay (backend);
1777
1778 /* Strictly, we only need to set grab_mode on the keyboard device
1779 * while the pointer should always be XIGrabModeAsync. Unfortunately
1780 * there is a bug in the X server, only fixed (link below) in 1.15,
1781 * which swaps these arguments for keyboard devices. As such, we set
1782 * both the device and the paired device mode which works around
1783 * that bug and also works on fixed X servers.
1784 *
1785 * http://cgit.freedesktop.org/xorg/xserver/commit/?id=9003399708936481083424b4ff8f18a16b88b7b3
1786 */
1787 grab_status = XIGrabDevice (xdisplay,
1788 META_VIRTUAL_CORE_KEYBOARD_ID,
1789 xwindow,
1790 timestamp,
1791 None,
1792 grab_mode, grab_mode,
1793 False, /* owner_events */
1794 &mask);
1795
1796 return (grab_status == Success);
1797 }
1798
1799 static void
ungrab_keyboard(guint32 timestamp)1800 ungrab_keyboard (guint32 timestamp)
1801 {
1802 if (meta_is_wayland_compositor ())
1803 return;
1804
1805 MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ());
1806 Display *xdisplay = meta_backend_x11_get_xdisplay (backend);
1807
1808 XIUngrabDevice (xdisplay, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp);
1809 }
1810
1811 gboolean
meta_window_grab_all_keys(MetaWindow * window,guint32 timestamp)1812 meta_window_grab_all_keys (MetaWindow *window,
1813 guint32 timestamp)
1814 {
1815 Window grabwindow;
1816 gboolean retval = TRUE;
1817
1818 if (window->all_keys_grabbed)
1819 return FALSE;
1820
1821 if (window->keys_grabbed)
1822 meta_window_ungrab_keys (window);
1823
1824 /* Make sure the window is focused, otherwise the grab
1825 * won't do a lot of good.
1826 */
1827 meta_topic (META_DEBUG_FOCUS,
1828 "Focusing %s because we're grabbing all its keys",
1829 window->desc);
1830 meta_window_focus (window, timestamp);
1831
1832 if (!meta_is_wayland_compositor ())
1833 {
1834 grabwindow = meta_window_x11_get_toplevel_xwindow (window);
1835
1836 meta_topic (META_DEBUG_KEYBINDINGS,
1837 "Grabbing all keys on window %s", window->desc);
1838 retval = grab_keyboard (grabwindow, timestamp, XIGrabModeAsync);
1839 }
1840 if (retval)
1841 {
1842 window->keys_grabbed = FALSE;
1843 window->all_keys_grabbed = TRUE;
1844 window->grab_on_frame = window->frame != NULL;
1845 }
1846
1847 return retval;
1848 }
1849
1850 void
meta_window_ungrab_all_keys(MetaWindow * window,guint32 timestamp)1851 meta_window_ungrab_all_keys (MetaWindow *window,
1852 guint32 timestamp)
1853 {
1854 if (window->all_keys_grabbed)
1855 {
1856 if (!meta_is_wayland_compositor())
1857 ungrab_keyboard (timestamp);
1858
1859 window->grab_on_frame = FALSE;
1860 window->all_keys_grabbed = FALSE;
1861 window->keys_grabbed = FALSE;
1862
1863 /* Re-establish our standard bindings */
1864 meta_window_grab_keys (window);
1865 }
1866 }
1867
1868 void
meta_display_freeze_keyboard(MetaDisplay * display,guint32 timestamp)1869 meta_display_freeze_keyboard (MetaDisplay *display, guint32 timestamp)
1870 {
1871 MetaBackend *backend = meta_get_backend ();
1872
1873 if (!META_IS_BACKEND_X11 (backend))
1874 return;
1875
1876 Window window = meta_backend_x11_get_xwindow (META_BACKEND_X11 (backend));
1877 grab_keyboard (window, timestamp, XIGrabModeSync);
1878 }
1879
1880 void
meta_display_ungrab_keyboard(MetaDisplay * display,guint32 timestamp)1881 meta_display_ungrab_keyboard (MetaDisplay *display, guint32 timestamp)
1882 {
1883 ungrab_keyboard (timestamp);
1884 }
1885
1886 void
meta_display_unfreeze_keyboard(MetaDisplay * display,guint32 timestamp)1887 meta_display_unfreeze_keyboard (MetaDisplay *display, guint32 timestamp)
1888 {
1889 MetaBackend *backend = meta_get_backend ();
1890
1891 if (!META_IS_BACKEND_X11 (backend))
1892 return;
1893
1894 Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
1895
1896 XIAllowEvents (xdisplay, META_VIRTUAL_CORE_KEYBOARD_ID,
1897 XIAsyncDevice, timestamp);
1898 /* We shouldn't need to unfreeze the pointer device here, however we
1899 * have to, due to the workaround we do in grab_keyboard().
1900 */
1901 XIAllowEvents (xdisplay, META_VIRTUAL_CORE_POINTER_ID,
1902 XIAsyncDevice, timestamp);
1903 }
1904
1905 static gboolean
is_modifier(xkb_keysym_t keysym)1906 is_modifier (xkb_keysym_t keysym)
1907 {
1908 switch (keysym)
1909 {
1910 case XKB_KEY_Shift_L:
1911 case XKB_KEY_Shift_R:
1912 case XKB_KEY_Control_L:
1913 case XKB_KEY_Control_R:
1914 case XKB_KEY_Caps_Lock:
1915 case XKB_KEY_Shift_Lock:
1916 case XKB_KEY_Meta_L:
1917 case XKB_KEY_Meta_R:
1918 case XKB_KEY_Alt_L:
1919 case XKB_KEY_Alt_R:
1920 case XKB_KEY_Super_L:
1921 case XKB_KEY_Super_R:
1922 case XKB_KEY_Hyper_L:
1923 case XKB_KEY_Hyper_R:
1924 return TRUE;
1925 default:
1926 return FALSE;
1927 }
1928 }
1929
1930 static void
invoke_handler(MetaDisplay * display,MetaKeyHandler * handler,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding)1931 invoke_handler (MetaDisplay *display,
1932 MetaKeyHandler *handler,
1933 MetaWindow *window,
1934 ClutterKeyEvent *event,
1935 MetaKeyBinding *binding)
1936 {
1937 if (handler->func)
1938 (* handler->func) (display,
1939 handler->flags & META_KEY_BINDING_PER_WINDOW ?
1940 window : NULL,
1941 event,
1942 binding,
1943 handler->user_data);
1944 else
1945 (* handler->default_func) (display,
1946 handler->flags & META_KEY_BINDING_PER_WINDOW ?
1947 window: NULL,
1948 event,
1949 binding,
1950 NULL);
1951 }
1952
1953 static gboolean
meta_key_binding_has_handler_func(MetaKeyBinding * binding)1954 meta_key_binding_has_handler_func (MetaKeyBinding *binding)
1955 {
1956 return (!!binding->handler->func || !!binding->handler->default_func);
1957 }
1958
1959 static gboolean
process_event(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event)1960 process_event (MetaDisplay *display,
1961 MetaWindow *window,
1962 ClutterKeyEvent *event)
1963 {
1964 MetaKeyBindingManager *keys = &display->key_binding_manager;
1965 xkb_keycode_t keycode = (xkb_keycode_t) event->hardware_keycode;
1966 MetaResolvedKeyCombo resolved_combo = { &keycode, 1 };
1967 MetaKeyBinding *binding;
1968
1969 /* we used to have release-based bindings but no longer. */
1970 if (event->type == CLUTTER_KEY_RELEASE)
1971 return FALSE;
1972
1973 resolved_combo.mask = mask_from_event_params (keys, event->modifier_state);
1974
1975 binding = get_keybinding (keys, &resolved_combo);
1976
1977 if (!binding ||
1978 (!window && binding->flags & META_KEY_BINDING_PER_WINDOW))
1979 goto not_found;
1980
1981 if (binding->handler == NULL)
1982 meta_bug ("Binding %s has no handler", binding->name);
1983
1984 if (!meta_key_binding_has_handler_func (binding))
1985 goto not_found;
1986
1987 if (display->focus_window &&
1988 !(binding->handler->flags & META_KEY_BINDING_NON_MASKABLE))
1989 {
1990 ClutterInputDevice *source;
1991
1992 source = clutter_event_get_source_device ((ClutterEvent *) event);
1993 if (meta_window_shortcuts_inhibited (display->focus_window, source))
1994 goto not_found;
1995 }
1996
1997 /* If the compositor filtered out the keybindings, that
1998 * means they don't want the binding to trigger, so we do
1999 * the same thing as if the binding didn't exist. */
2000 if (meta_compositor_filter_keybinding (display->compositor, binding))
2001 goto not_found;
2002
2003 if (event->flags & CLUTTER_EVENT_FLAG_REPEATED &&
2004 binding->flags & META_KEY_BINDING_IGNORE_AUTOREPEAT)
2005 {
2006 meta_topic (META_DEBUG_KEYBINDINGS,
2007 "Ignore autorepeat for handler %s",
2008 binding->name);
2009 return TRUE;
2010 }
2011
2012 meta_topic (META_DEBUG_KEYBINDINGS,
2013 "Running handler for %s",
2014 binding->name);
2015
2016 /* Global keybindings count as a let-the-terminal-lose-focus
2017 * due to new window mapping until the user starts
2018 * interacting with the terminal again.
2019 */
2020 display->allow_terminal_deactivation = TRUE;
2021
2022 invoke_handler (display, binding->handler, window, event, binding);
2023
2024 return TRUE;
2025
2026 not_found:
2027 meta_topic (META_DEBUG_KEYBINDINGS,
2028 "No handler found for this event in this binding table");
2029 return FALSE;
2030 }
2031
2032 static gboolean
process_special_modifier_key(MetaDisplay * display,ClutterKeyEvent * event,MetaWindow * window,gboolean * modifier_press_only,MetaResolvedKeyCombo * resolved_key_combo,GFunc trigger_callback)2033 process_special_modifier_key (MetaDisplay *display,
2034 ClutterKeyEvent *event,
2035 MetaWindow *window,
2036 gboolean *modifier_press_only,
2037 MetaResolvedKeyCombo *resolved_key_combo,
2038 GFunc trigger_callback)
2039 {
2040 MetaKeyBindingManager *keys = &display->key_binding_manager;
2041 MetaBackend *backend = keys->backend;
2042 Display *xdisplay;
2043
2044 if (META_IS_BACKEND_X11 (backend))
2045 xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
2046 else
2047 xdisplay = NULL;
2048
2049 if (*modifier_press_only)
2050 {
2051 if (! resolved_key_combo_has_keycode (resolved_key_combo,
2052 event->hardware_keycode))
2053 {
2054 *modifier_press_only = FALSE;
2055
2056 /* If this is a wayland session, we can avoid the shenanigans
2057 * about passive grabs below, and let the event continue to
2058 * be processed through the regular paths.
2059 */
2060 if (!xdisplay)
2061 return FALSE;
2062
2063 /* OK, the user hit modifier+key rather than pressing and
2064 * releasing the modifier key alone. We want to handle the key
2065 * sequence "normally". Unfortunately, using
2066 * XAllowEvents(..., ReplayKeyboard, ...) doesn't quite
2067 * work, since global keybindings won't be activated ("this
2068 * time, however, the function ignores any passive grabs at
2069 * above (toward the root of) the grab_window of the grab
2070 * just released.") So, we first explicitly check for one of
2071 * our global keybindings, and if not found, we then replay
2072 * the event. Other clients with global grabs will be out of
2073 * luck.
2074 */
2075 if (process_event (display, window, event))
2076 {
2077 /* As normally, after we've handled a global key
2078 * binding, we unfreeze the keyboard but keep the grab
2079 * (this is important for something like cycling
2080 * windows */
2081
2082 if (xdisplay)
2083 XIAllowEvents (xdisplay,
2084 meta_input_device_x11_get_device_id (event->device),
2085 XIAsyncDevice, event->time);
2086 }
2087 else
2088 {
2089 /* Replay the event so it gets delivered to our
2090 * per-window key bindings or to the application */
2091 if (xdisplay)
2092 XIAllowEvents (xdisplay,
2093 meta_input_device_x11_get_device_id (event->device),
2094 XIReplayDevice, event->time);
2095 }
2096 }
2097 else if (event->type == CLUTTER_KEY_RELEASE)
2098 {
2099 MetaKeyBinding *binding;
2100
2101 *modifier_press_only = FALSE;
2102
2103 /* We want to unfreeze events, but keep the grab so that if the user
2104 * starts typing into the overlay we get all the keys */
2105 if (xdisplay)
2106 XIAllowEvents (xdisplay,
2107 meta_input_device_x11_get_device_id (event->device),
2108 XIAsyncDevice, event->time);
2109
2110 binding = get_keybinding (keys, resolved_key_combo);
2111 if (binding &&
2112 meta_compositor_filter_keybinding (display->compositor, binding))
2113 return TRUE;
2114 trigger_callback (display, NULL);
2115 }
2116 else
2117 {
2118 /* In some rare race condition, mutter might not receive the Super_L
2119 * KeyRelease event because:
2120 * - the compositor might end the modal mode and call XIUngrabDevice
2121 * while the key is still down
2122 * - passive grabs are only activated on KeyPress and not KeyRelease.
2123 *
2124 * In this case, modifier_press_only might be wrong.
2125 * Mutter still ought to acknowledge events, otherwise the X server
2126 * will not send the next events.
2127 *
2128 * https://bugzilla.gnome.org/show_bug.cgi?id=666101
2129 */
2130 if (xdisplay)
2131 XIAllowEvents (xdisplay,
2132 meta_input_device_x11_get_device_id (event->device),
2133 XIAsyncDevice, event->time);
2134 }
2135
2136 return TRUE;
2137 }
2138 else if (event->type == CLUTTER_KEY_PRESS &&
2139 ((event->modifier_state & ~(IGNORED_MODIFIERS)) & CLUTTER_MODIFIER_MASK) == 0 &&
2140 resolved_key_combo_has_keycode (resolved_key_combo,
2141 event->hardware_keycode))
2142 {
2143 *modifier_press_only = TRUE;
2144 /* We keep the keyboard frozen - this allows us to use ReplayKeyboard
2145 * on the next event if it's not the release of the modifier key */
2146 if (xdisplay)
2147 XIAllowEvents (xdisplay,
2148 meta_input_device_x11_get_device_id (event->device),
2149 XISyncDevice, event->time);
2150
2151 return TRUE;
2152 }
2153 else
2154 return FALSE;
2155 }
2156
2157
2158 static gboolean
process_overlay_key(MetaDisplay * display,ClutterKeyEvent * event,MetaWindow * window)2159 process_overlay_key (MetaDisplay *display,
2160 ClutterKeyEvent *event,
2161 MetaWindow *window)
2162 {
2163 MetaKeyBindingManager *keys = &display->key_binding_manager;
2164
2165 if (display->focus_window && !keys->overlay_key_only_pressed)
2166 {
2167 ClutterInputDevice *source;
2168
2169 source = clutter_event_get_source_device ((ClutterEvent *) event);
2170 if (meta_window_shortcuts_inhibited (display->focus_window, source))
2171 return FALSE;
2172 }
2173
2174 return process_special_modifier_key (display,
2175 event,
2176 window,
2177 &keys->overlay_key_only_pressed,
2178 &keys->overlay_resolved_key_combo,
2179 (GFunc) meta_display_overlay_key_activate);
2180 }
2181
2182 static void
handle_locate_pointer(MetaDisplay * display)2183 handle_locate_pointer (MetaDisplay *display)
2184 {
2185 meta_compositor_locate_pointer (display->compositor);
2186 }
2187
2188 static gboolean
process_locate_pointer_key(MetaDisplay * display,ClutterKeyEvent * event,MetaWindow * window)2189 process_locate_pointer_key (MetaDisplay *display,
2190 ClutterKeyEvent *event,
2191 MetaWindow *window)
2192 {
2193 MetaKeyBindingManager *keys = &display->key_binding_manager;
2194
2195 return process_special_modifier_key (display,
2196 event,
2197 window,
2198 &keys->locate_pointer_key_only_pressed,
2199 &keys->locate_pointer_resolved_key_combo,
2200 (GFunc) handle_locate_pointer);
2201 }
2202
2203 static gboolean
process_iso_next_group(MetaDisplay * display,ClutterKeyEvent * event)2204 process_iso_next_group (MetaDisplay *display,
2205 ClutterKeyEvent *event)
2206 {
2207 MetaKeyBindingManager *keys = &display->key_binding_manager;
2208 gboolean activate;
2209 xkb_keycode_t keycode = (xkb_keycode_t) event->hardware_keycode;
2210 xkb_mod_mask_t mask;
2211 int i, j;
2212
2213 if (event->type == CLUTTER_KEY_RELEASE)
2214 return FALSE;
2215
2216 activate = FALSE;
2217 mask = mask_from_event_params (keys, event->modifier_state);
2218
2219 for (i = 0; i < keys->n_iso_next_group_combos; ++i)
2220 {
2221 for (j = 0; j < keys->iso_next_group_combo[i].len; ++j)
2222 {
2223 if (keycode == keys->iso_next_group_combo[i].keycodes[j] &&
2224 mask == keys->iso_next_group_combo[i].mask)
2225 {
2226 /* If the signal handler returns TRUE the keyboard will
2227 remain frozen. It's the signal handler's responsibility
2228 to unfreeze it. */
2229 if (!meta_display_modifiers_accelerator_activate (display))
2230 meta_display_unfreeze_keyboard (display, event->time);
2231 activate = TRUE;
2232 break;
2233 }
2234 }
2235 }
2236
2237 return activate;
2238 }
2239
2240 static gboolean
process_key_event(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event)2241 process_key_event (MetaDisplay *display,
2242 MetaWindow *window,
2243 ClutterKeyEvent *event)
2244 {
2245 gboolean keep_grab;
2246 gboolean all_keys_grabbed;
2247
2248 all_keys_grabbed = window ? window->all_keys_grabbed : FALSE;
2249 if (!all_keys_grabbed)
2250 {
2251 if (process_overlay_key (display, event, window))
2252 return TRUE;
2253
2254 if (process_locate_pointer_key (display, event, window))
2255 return FALSE; /* Continue with the event even if handled */
2256
2257 if (process_iso_next_group (display, event))
2258 return TRUE;
2259 }
2260
2261 {
2262 MetaBackend *backend = meta_get_backend ();
2263 if (META_IS_BACKEND_X11 (backend))
2264 {
2265 Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
2266 XIAllowEvents (xdisplay,
2267 meta_input_device_x11_get_device_id (event->device),
2268 XIAsyncDevice, event->time);
2269 }
2270 }
2271
2272 keep_grab = TRUE;
2273 if (all_keys_grabbed)
2274 {
2275 if (display->grab_op == META_GRAB_OP_NONE)
2276 return TRUE;
2277
2278 /* If we get here we have a global grab, because
2279 * we're in some special keyboard mode such as window move
2280 * mode.
2281 */
2282 if (window == display->grab_window)
2283 {
2284 if (display->grab_op & META_GRAB_OP_WINDOW_FLAG_KEYBOARD)
2285 {
2286 if (display->grab_op == META_GRAB_OP_KEYBOARD_MOVING)
2287 {
2288 meta_topic (META_DEBUG_KEYBINDINGS,
2289 "Processing event for keyboard move");
2290 keep_grab = process_keyboard_move_grab (display, window, event);
2291 }
2292 else
2293 {
2294 meta_topic (META_DEBUG_KEYBINDINGS,
2295 "Processing event for keyboard resize");
2296 keep_grab = process_keyboard_resize_grab (display, window, event);
2297 }
2298 }
2299 else
2300 {
2301 meta_topic (META_DEBUG_KEYBINDINGS,
2302 "Processing event for mouse-only move/resize");
2303 keep_grab = process_mouse_move_resize_grab (display, window, event);
2304 }
2305 }
2306 if (!keep_grab)
2307 meta_display_end_grab_op (display, event->time);
2308
2309 return TRUE;
2310 }
2311
2312 /* Do the normal keybindings */
2313 return process_event (display, window, event);
2314 }
2315
2316 /* Handle a key event. May be called recursively: some key events cause
2317 * grabs to be ended and then need to be processed again in their own
2318 * right. This cannot cause infinite recursion because we never call
2319 * ourselves when there wasn't a grab, and we always clear the grab
2320 * first; the invariant is enforced using an assertion. See #112560.
2321 *
2322 * The return value is whether we handled the key event.
2323 *
2324 * FIXME: We need to prove there are no race conditions here.
2325 * FIXME: Does it correctly handle alt-Tab being followed by another
2326 * grabbing keypress without letting go of alt?
2327 * FIXME: An iterative solution would probably be simpler to understand
2328 * (and help us solve the other fixmes).
2329 */
2330 gboolean
meta_keybindings_process_event(MetaDisplay * display,MetaWindow * window,const ClutterEvent * event)2331 meta_keybindings_process_event (MetaDisplay *display,
2332 MetaWindow *window,
2333 const ClutterEvent *event)
2334 {
2335 MetaKeyBindingManager *keys = &display->key_binding_manager;
2336
2337 switch (event->type)
2338 {
2339 case CLUTTER_BUTTON_PRESS:
2340 case CLUTTER_BUTTON_RELEASE:
2341 case CLUTTER_TOUCH_BEGIN:
2342 case CLUTTER_TOUCH_END:
2343 case CLUTTER_SCROLL:
2344 keys->overlay_key_only_pressed = FALSE;
2345 keys->locate_pointer_key_only_pressed = FALSE;
2346 return FALSE;
2347
2348 case CLUTTER_KEY_PRESS:
2349 case CLUTTER_KEY_RELEASE:
2350 return process_key_event (display, window, (ClutterKeyEvent *) event);
2351
2352 default:
2353 return FALSE;
2354 }
2355 }
2356
2357 static gboolean
process_mouse_move_resize_grab(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event)2358 process_mouse_move_resize_grab (MetaDisplay *display,
2359 MetaWindow *window,
2360 ClutterKeyEvent *event)
2361 {
2362 /* don't care about releases, but eat them, don't end grab */
2363 if (event->type == CLUTTER_KEY_RELEASE)
2364 return TRUE;
2365
2366 if (event->keyval == CLUTTER_KEY_Escape)
2367 {
2368 MetaTileMode tile_mode;
2369
2370 /* Hide the tiling preview if necessary */
2371 if (display->preview_tile_mode != META_TILE_NONE)
2372 meta_display_hide_tile_preview (display);
2373
2374 /* Restore the original tile mode */
2375 tile_mode = display->grab_tile_mode;
2376 window->tile_monitor_number = display->grab_tile_monitor_number;
2377
2378 /* End move or resize and restore to original state. If the
2379 * window was a maximized window that had been "shaken loose" we
2380 * need to remaximize it. In normal cases, we need to do a
2381 * moveresize now to get the position back to the original.
2382 */
2383 if (window->shaken_loose || tile_mode == META_TILE_MAXIMIZED)
2384 meta_window_maximize (window, META_MAXIMIZE_BOTH);
2385 else if (tile_mode != META_TILE_NONE)
2386 meta_window_restore_tile (window,
2387 tile_mode,
2388 display->grab_initial_window_pos.width,
2389 display->grab_initial_window_pos.height);
2390 else
2391 meta_window_move_resize_frame (display->grab_window,
2392 TRUE,
2393 display->grab_initial_window_pos.x,
2394 display->grab_initial_window_pos.y,
2395 display->grab_initial_window_pos.width,
2396 display->grab_initial_window_pos.height);
2397
2398 /* End grab */
2399 return FALSE;
2400 }
2401
2402 return TRUE;
2403 }
2404
2405 static gboolean
process_keyboard_move_grab(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event)2406 process_keyboard_move_grab (MetaDisplay *display,
2407 MetaWindow *window,
2408 ClutterKeyEvent *event)
2409 {
2410 MetaEdgeResistanceFlags flags;
2411 gboolean handled;
2412 MetaRectangle frame_rect;
2413 int x, y;
2414 int incr;
2415
2416 handled = FALSE;
2417
2418 /* don't care about releases, but eat them, don't end grab */
2419 if (event->type == CLUTTER_KEY_RELEASE)
2420 return TRUE;
2421
2422 /* don't end grab on modifier key presses */
2423 if (is_modifier (event->keyval))
2424 return TRUE;
2425
2426 meta_window_get_frame_rect (window, &frame_rect);
2427 x = frame_rect.x;
2428 y = frame_rect.y;
2429
2430 flags = META_EDGE_RESISTANCE_KEYBOARD_OP | META_EDGE_RESISTANCE_WINDOWS;
2431
2432 if ((event->modifier_state & CLUTTER_SHIFT_MASK) != 0)
2433 flags |= META_EDGE_RESISTANCE_SNAP;
2434
2435 #define SMALL_INCREMENT 1
2436 #define NORMAL_INCREMENT 10
2437
2438 if (flags & META_EDGE_RESISTANCE_SNAP)
2439 incr = 1;
2440 else if (event->modifier_state & CLUTTER_CONTROL_MASK)
2441 incr = SMALL_INCREMENT;
2442 else
2443 incr = NORMAL_INCREMENT;
2444
2445 if (event->keyval == CLUTTER_KEY_Escape)
2446 {
2447 /* End move and restore to original state. If the window was a
2448 * maximized window that had been "shaken loose" we need to
2449 * remaximize it. In normal cases, we need to do a moveresize
2450 * now to get the position back to the original.
2451 */
2452 if (window->shaken_loose)
2453 meta_window_maximize (window, META_MAXIMIZE_BOTH);
2454 else
2455 meta_window_move_resize_frame (display->grab_window,
2456 TRUE,
2457 display->grab_initial_window_pos.x,
2458 display->grab_initial_window_pos.y,
2459 display->grab_initial_window_pos.width,
2460 display->grab_initial_window_pos.height);
2461 }
2462
2463 /* When moving by increments, we still snap to edges if the move
2464 * to the edge is smaller than the increment. This is because
2465 * Shift + arrow to snap is sort of a hidden feature. This way
2466 * people using just arrows shouldn't get too frustrated.
2467 */
2468 switch (event->keyval)
2469 {
2470 case CLUTTER_KEY_KP_Home:
2471 case CLUTTER_KEY_KP_Prior:
2472 case CLUTTER_KEY_Up:
2473 case CLUTTER_KEY_KP_Up:
2474 y -= incr;
2475 handled = TRUE;
2476 break;
2477 case CLUTTER_KEY_KP_End:
2478 case CLUTTER_KEY_KP_Next:
2479 case CLUTTER_KEY_Down:
2480 case CLUTTER_KEY_KP_Down:
2481 y += incr;
2482 handled = TRUE;
2483 break;
2484 }
2485
2486 switch (event->keyval)
2487 {
2488 case CLUTTER_KEY_KP_Home:
2489 case CLUTTER_KEY_KP_End:
2490 case CLUTTER_KEY_Left:
2491 case CLUTTER_KEY_KP_Left:
2492 x -= incr;
2493 handled = TRUE;
2494 break;
2495 case CLUTTER_KEY_KP_Prior:
2496 case CLUTTER_KEY_KP_Next:
2497 case CLUTTER_KEY_Right:
2498 case CLUTTER_KEY_KP_Right:
2499 x += incr;
2500 handled = TRUE;
2501 break;
2502 }
2503
2504 if (handled)
2505 {
2506 meta_topic (META_DEBUG_KEYBINDINGS,
2507 "Computed new window location %d,%d due to keypress",
2508 x, y);
2509
2510 meta_window_edge_resistance_for_move (window,
2511 &x,
2512 &y,
2513 NULL,
2514 flags);
2515
2516 meta_window_move_frame (window, TRUE, x, y);
2517 meta_window_update_keyboard_move (window);
2518 }
2519
2520 return handled;
2521 }
2522
2523 static gboolean
process_keyboard_resize_grab_op_change(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event)2524 process_keyboard_resize_grab_op_change (MetaDisplay *display,
2525 MetaWindow *window,
2526 ClutterKeyEvent *event)
2527 {
2528 gboolean handled;
2529
2530 handled = FALSE;
2531 switch (display->grab_op)
2532 {
2533 case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN:
2534 switch (event->keyval)
2535 {
2536 case CLUTTER_KEY_Up:
2537 case CLUTTER_KEY_KP_Up:
2538 display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_N;
2539 handled = TRUE;
2540 break;
2541 case CLUTTER_KEY_Down:
2542 case CLUTTER_KEY_KP_Down:
2543 display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_S;
2544 handled = TRUE;
2545 break;
2546 case CLUTTER_KEY_Left:
2547 case CLUTTER_KEY_KP_Left:
2548 display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_W;
2549 handled = TRUE;
2550 break;
2551 case CLUTTER_KEY_Right:
2552 case CLUTTER_KEY_KP_Right:
2553 display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_E;
2554 handled = TRUE;
2555 break;
2556 }
2557 break;
2558
2559 case META_GRAB_OP_KEYBOARD_RESIZING_S:
2560 switch (event->keyval)
2561 {
2562 case CLUTTER_KEY_Left:
2563 case CLUTTER_KEY_KP_Left:
2564 display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_W;
2565 handled = TRUE;
2566 break;
2567 case CLUTTER_KEY_Right:
2568 case CLUTTER_KEY_KP_Right:
2569 display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_E;
2570 handled = TRUE;
2571 break;
2572 }
2573 break;
2574
2575 case META_GRAB_OP_KEYBOARD_RESIZING_N:
2576 switch (event->keyval)
2577 {
2578 case CLUTTER_KEY_Left:
2579 case CLUTTER_KEY_KP_Left:
2580 display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_W;
2581 handled = TRUE;
2582 break;
2583 case CLUTTER_KEY_Right:
2584 case CLUTTER_KEY_KP_Right:
2585 display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_E;
2586 handled = TRUE;
2587 break;
2588 }
2589 break;
2590
2591 case META_GRAB_OP_KEYBOARD_RESIZING_W:
2592 switch (event->keyval)
2593 {
2594 case CLUTTER_KEY_Up:
2595 case CLUTTER_KEY_KP_Up:
2596 display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_N;
2597 handled = TRUE;
2598 break;
2599 case CLUTTER_KEY_Down:
2600 case CLUTTER_KEY_KP_Down:
2601 display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_S;
2602 handled = TRUE;
2603 break;
2604 }
2605 break;
2606
2607 case META_GRAB_OP_KEYBOARD_RESIZING_E:
2608 switch (event->keyval)
2609 {
2610 case CLUTTER_KEY_Up:
2611 case CLUTTER_KEY_KP_Up:
2612 display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_N;
2613 handled = TRUE;
2614 break;
2615 case CLUTTER_KEY_Down:
2616 case CLUTTER_KEY_KP_Down:
2617 display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_S;
2618 handled = TRUE;
2619 break;
2620 }
2621 break;
2622
2623 case META_GRAB_OP_KEYBOARD_RESIZING_SE:
2624 case META_GRAB_OP_KEYBOARD_RESIZING_NE:
2625 case META_GRAB_OP_KEYBOARD_RESIZING_SW:
2626 case META_GRAB_OP_KEYBOARD_RESIZING_NW:
2627 break;
2628
2629 default:
2630 g_assert_not_reached ();
2631 break;
2632 }
2633
2634 if (handled)
2635 {
2636 meta_window_update_keyboard_resize (window, TRUE);
2637 return TRUE;
2638 }
2639
2640 return FALSE;
2641 }
2642
2643 static gboolean
process_keyboard_resize_grab(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event)2644 process_keyboard_resize_grab (MetaDisplay *display,
2645 MetaWindow *window,
2646 ClutterKeyEvent *event)
2647 {
2648 MetaRectangle frame_rect;
2649 gboolean handled;
2650 int height_inc;
2651 int width_inc;
2652 int width, height;
2653 MetaEdgeResistanceFlags flags;
2654 MetaGravity gravity;
2655
2656 handled = FALSE;
2657
2658 /* don't care about releases, but eat them, don't end grab */
2659 if (event->type == CLUTTER_KEY_RELEASE)
2660 return TRUE;
2661
2662 /* don't end grab on modifier key presses */
2663 if (is_modifier (event->keyval))
2664 return TRUE;
2665
2666 if (event->keyval == CLUTTER_KEY_Escape)
2667 {
2668 /* End resize and restore to original state. */
2669 meta_window_move_resize_frame (display->grab_window,
2670 TRUE,
2671 display->grab_initial_window_pos.x,
2672 display->grab_initial_window_pos.y,
2673 display->grab_initial_window_pos.width,
2674 display->grab_initial_window_pos.height);
2675
2676 return FALSE;
2677 }
2678
2679 if (process_keyboard_resize_grab_op_change (display, window, event))
2680 return TRUE;
2681
2682 width = window->rect.width;
2683 height = window->rect.height;
2684
2685 meta_window_get_frame_rect (window, &frame_rect);
2686 width = frame_rect.width;
2687 height = frame_rect.height;
2688
2689 gravity = meta_resize_gravity_from_grab_op (display->grab_op);
2690
2691 flags = META_EDGE_RESISTANCE_KEYBOARD_OP;
2692
2693 if ((event->modifier_state & CLUTTER_SHIFT_MASK) != 0)
2694 flags |= META_EDGE_RESISTANCE_SNAP;
2695
2696 #define SMALL_INCREMENT 1
2697 #define NORMAL_INCREMENT 10
2698
2699 if (flags & META_EDGE_RESISTANCE_SNAP)
2700 {
2701 height_inc = 1;
2702 width_inc = 1;
2703 }
2704 else if (event->modifier_state & CLUTTER_CONTROL_MASK)
2705 {
2706 width_inc = SMALL_INCREMENT;
2707 height_inc = SMALL_INCREMENT;
2708 }
2709 else
2710 {
2711 width_inc = NORMAL_INCREMENT;
2712 height_inc = NORMAL_INCREMENT;
2713 }
2714
2715 /* If this is a resize increment window, make the amount we resize
2716 * the window by match that amount (well, unless snap resizing...)
2717 */
2718 if (window->size_hints.width_inc > 1)
2719 width_inc = window->size_hints.width_inc;
2720 if (window->size_hints.height_inc > 1)
2721 height_inc = window->size_hints.height_inc;
2722
2723 switch (event->keyval)
2724 {
2725 case CLUTTER_KEY_Up:
2726 case CLUTTER_KEY_KP_Up:
2727 switch (gravity)
2728 {
2729 case META_GRAVITY_NORTH:
2730 case META_GRAVITY_NORTH_WEST:
2731 case META_GRAVITY_NORTH_EAST:
2732 /* Move bottom edge up */
2733 height -= height_inc;
2734 break;
2735
2736 case META_GRAVITY_SOUTH:
2737 case META_GRAVITY_SOUTH_WEST:
2738 case META_GRAVITY_SOUTH_EAST:
2739 /* Move top edge up */
2740 height += height_inc;
2741 break;
2742
2743 case META_GRAVITY_EAST:
2744 case META_GRAVITY_WEST:
2745 case META_GRAVITY_CENTER:
2746 case META_GRAVITY_NONE:
2747 case META_GRAVITY_STATIC:
2748 g_assert_not_reached ();
2749 break;
2750 }
2751
2752 handled = TRUE;
2753 break;
2754
2755 case CLUTTER_KEY_Down:
2756 case CLUTTER_KEY_KP_Down:
2757 switch (gravity)
2758 {
2759 case META_GRAVITY_NORTH:
2760 case META_GRAVITY_NORTH_WEST:
2761 case META_GRAVITY_NORTH_EAST:
2762 /* Move bottom edge down */
2763 height += height_inc;
2764 break;
2765
2766 case META_GRAVITY_SOUTH:
2767 case META_GRAVITY_SOUTH_WEST:
2768 case META_GRAVITY_SOUTH_EAST:
2769 /* Move top edge down */
2770 height -= height_inc;
2771 break;
2772
2773 case META_GRAVITY_EAST:
2774 case META_GRAVITY_WEST:
2775 case META_GRAVITY_CENTER:
2776 case META_GRAVITY_NONE:
2777 case META_GRAVITY_STATIC:
2778 g_assert_not_reached ();
2779 break;
2780 }
2781
2782 handled = TRUE;
2783 break;
2784
2785 case CLUTTER_KEY_Left:
2786 case CLUTTER_KEY_KP_Left:
2787 switch (gravity)
2788 {
2789 case META_GRAVITY_EAST:
2790 case META_GRAVITY_SOUTH_EAST:
2791 case META_GRAVITY_NORTH_EAST:
2792 /* Move left edge left */
2793 width += width_inc;
2794 break;
2795
2796 case META_GRAVITY_WEST:
2797 case META_GRAVITY_SOUTH_WEST:
2798 case META_GRAVITY_NORTH_WEST:
2799 /* Move right edge left */
2800 width -= width_inc;
2801 break;
2802
2803 case META_GRAVITY_NORTH:
2804 case META_GRAVITY_SOUTH:
2805 case META_GRAVITY_CENTER:
2806 case META_GRAVITY_NONE:
2807 case META_GRAVITY_STATIC:
2808 g_assert_not_reached ();
2809 break;
2810 }
2811
2812 handled = TRUE;
2813 break;
2814
2815 case CLUTTER_KEY_Right:
2816 case CLUTTER_KEY_KP_Right:
2817 switch (gravity)
2818 {
2819 case META_GRAVITY_EAST:
2820 case META_GRAVITY_SOUTH_EAST:
2821 case META_GRAVITY_NORTH_EAST:
2822 /* Move left edge right */
2823 width -= width_inc;
2824 break;
2825
2826 case META_GRAVITY_WEST:
2827 case META_GRAVITY_SOUTH_WEST:
2828 case META_GRAVITY_NORTH_WEST:
2829 /* Move right edge right */
2830 width += width_inc;
2831 break;
2832
2833 case META_GRAVITY_NORTH:
2834 case META_GRAVITY_SOUTH:
2835 case META_GRAVITY_CENTER:
2836 case META_GRAVITY_NONE:
2837 case META_GRAVITY_STATIC:
2838 g_assert_not_reached ();
2839 break;
2840 }
2841
2842 handled = TRUE;
2843 break;
2844
2845 default:
2846 break;
2847 }
2848
2849 /* fixup hack (just paranoia, not sure it's required) */
2850 if (height < 1)
2851 height = 1;
2852 if (width < 1)
2853 width = 1;
2854
2855 if (handled)
2856 {
2857 meta_topic (META_DEBUG_KEYBINDINGS,
2858 "Computed new window size due to keypress: "
2859 "%dx%d, gravity %s",
2860 width, height, meta_gravity_to_string (gravity));
2861
2862 /* Do any edge resistance/snapping */
2863 meta_window_edge_resistance_for_resize (window,
2864 &width,
2865 &height,
2866 gravity,
2867 NULL,
2868 flags);
2869
2870 meta_window_resize_frame_with_gravity (window,
2871 TRUE,
2872 width,
2873 height,
2874 gravity);
2875
2876 meta_window_update_keyboard_resize (window, FALSE);
2877 }
2878
2879 return handled;
2880 }
2881
2882 static void
handle_switch_to_last_workspace(MetaDisplay * display,MetaWindow * event_window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)2883 handle_switch_to_last_workspace (MetaDisplay *display,
2884 MetaWindow *event_window,
2885 ClutterKeyEvent *event,
2886 MetaKeyBinding *binding,
2887 gpointer dummy)
2888 {
2889 MetaWorkspaceManager *workspace_manager = display->workspace_manager;
2890 gint target = meta_workspace_manager_get_n_workspaces (workspace_manager) - 1;
2891 MetaWorkspace *workspace = meta_workspace_manager_get_workspace_by_index (workspace_manager, target);
2892 meta_workspace_activate (workspace, event->time);
2893 }
2894
2895 static void
handle_switch_to_workspace(MetaDisplay * display,MetaWindow * event_window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)2896 handle_switch_to_workspace (MetaDisplay *display,
2897 MetaWindow *event_window,
2898 ClutterKeyEvent *event,
2899 MetaKeyBinding *binding,
2900 gpointer dummy)
2901 {
2902 gint which = binding->handler->data;
2903 MetaWorkspaceManager *workspace_manager = display->workspace_manager;
2904 MetaWorkspace *workspace;
2905
2906 if (which < 0)
2907 {
2908 /* Negative workspace numbers are directions with respect to the
2909 * current workspace.
2910 */
2911
2912 workspace = meta_workspace_get_neighbor (workspace_manager->active_workspace,
2913 which);
2914 }
2915 else
2916 {
2917 workspace = meta_workspace_manager_get_workspace_by_index (workspace_manager, which);
2918 }
2919
2920 if (workspace)
2921 {
2922 meta_workspace_activate (workspace, event->time);
2923 }
2924 else
2925 {
2926 /* We could offer to create it I suppose */
2927 }
2928 }
2929
2930
2931 static void
handle_maximize_vertically(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)2932 handle_maximize_vertically (MetaDisplay *display,
2933 MetaWindow *window,
2934 ClutterKeyEvent *event,
2935 MetaKeyBinding *binding,
2936 gpointer dummy)
2937 {
2938 if (window->has_resize_func)
2939 {
2940 if (window->maximized_vertically)
2941 meta_window_unmaximize (window, META_MAXIMIZE_VERTICAL);
2942 else
2943 meta_window_maximize (window, META_MAXIMIZE_VERTICAL);
2944 }
2945 }
2946
2947 static void
handle_maximize_horizontally(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)2948 handle_maximize_horizontally (MetaDisplay *display,
2949 MetaWindow *window,
2950 ClutterKeyEvent *event,
2951 MetaKeyBinding *binding,
2952 gpointer dummy)
2953 {
2954 if (window->has_resize_func)
2955 {
2956 if (window->maximized_horizontally)
2957 meta_window_unmaximize (window, META_MAXIMIZE_HORIZONTAL);
2958 else
2959 meta_window_maximize (window, META_MAXIMIZE_HORIZONTAL);
2960 }
2961 }
2962
2963 static void
handle_always_on_top(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)2964 handle_always_on_top (MetaDisplay *display,
2965 MetaWindow *window,
2966 ClutterKeyEvent *event,
2967 MetaKeyBinding *binding,
2968 gpointer dummy)
2969 {
2970 if (window->wm_state_above == FALSE)
2971 meta_window_make_above (window);
2972 else
2973 meta_window_unmake_above (window);
2974 }
2975
2976 static void
handle_move_to_corner_backend(MetaDisplay * display,MetaWindow * window,MetaGravity gravity)2977 handle_move_to_corner_backend (MetaDisplay *display,
2978 MetaWindow *window,
2979 MetaGravity gravity)
2980 {
2981 MetaRectangle work_area;
2982 MetaRectangle frame_rect;
2983 int new_x, new_y;
2984
2985 if (!window->monitor)
2986 return;
2987
2988 meta_window_get_work_area_current_monitor (window, &work_area);
2989 meta_window_get_frame_rect (window, &frame_rect);
2990
2991 switch (gravity)
2992 {
2993 case META_GRAVITY_NORTH_WEST:
2994 case META_GRAVITY_WEST:
2995 case META_GRAVITY_SOUTH_WEST:
2996 new_x = work_area.x;
2997 break;
2998 case META_GRAVITY_NORTH:
2999 case META_GRAVITY_SOUTH:
3000 new_x = frame_rect.x;
3001 break;
3002 case META_GRAVITY_NORTH_EAST:
3003 case META_GRAVITY_EAST:
3004 case META_GRAVITY_SOUTH_EAST:
3005 new_x = work_area.x + work_area.width - frame_rect.width;
3006 break;
3007 default:
3008 g_assert_not_reached ();
3009 }
3010
3011 switch (gravity)
3012 {
3013 case META_GRAVITY_NORTH_WEST:
3014 case META_GRAVITY_NORTH:
3015 case META_GRAVITY_NORTH_EAST:
3016 new_y = work_area.y;
3017 break;
3018 case META_GRAVITY_WEST:
3019 case META_GRAVITY_EAST:
3020 new_y = frame_rect.y;
3021 break;
3022 case META_GRAVITY_SOUTH_WEST:
3023 case META_GRAVITY_SOUTH:
3024 case META_GRAVITY_SOUTH_EAST:
3025 new_y = work_area.y + work_area.height - frame_rect.height;
3026 break;
3027 default:
3028 g_assert_not_reached ();
3029 }
3030
3031 meta_window_move_frame (window,
3032 TRUE,
3033 new_x,
3034 new_y);
3035 }
3036
3037 static void
handle_move_to_corner_nw(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3038 handle_move_to_corner_nw (MetaDisplay *display,
3039 MetaWindow *window,
3040 ClutterKeyEvent *event,
3041 MetaKeyBinding *binding,
3042 gpointer dummy)
3043 {
3044 handle_move_to_corner_backend (display, window, META_GRAVITY_NORTH_WEST);
3045 }
3046
3047 static void
handle_move_to_corner_ne(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3048 handle_move_to_corner_ne (MetaDisplay *display,
3049 MetaWindow *window,
3050 ClutterKeyEvent *event,
3051 MetaKeyBinding *binding,
3052 gpointer dummy)
3053 {
3054 handle_move_to_corner_backend (display, window, META_GRAVITY_NORTH_EAST);
3055 }
3056
3057 static void
handle_move_to_corner_sw(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3058 handle_move_to_corner_sw (MetaDisplay *display,
3059 MetaWindow *window,
3060 ClutterKeyEvent *event,
3061 MetaKeyBinding *binding,
3062 gpointer dummy)
3063 {
3064 handle_move_to_corner_backend (display, window, META_GRAVITY_SOUTH_WEST);
3065 }
3066
3067 static void
handle_move_to_corner_se(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3068 handle_move_to_corner_se (MetaDisplay *display,
3069 MetaWindow *window,
3070 ClutterKeyEvent *event,
3071 MetaKeyBinding *binding,
3072 gpointer dummy)
3073 {
3074 handle_move_to_corner_backend (display, window, META_GRAVITY_SOUTH_EAST);
3075 }
3076
3077 static void
handle_move_to_side_n(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3078 handle_move_to_side_n (MetaDisplay *display,
3079 MetaWindow *window,
3080 ClutterKeyEvent *event,
3081 MetaKeyBinding *binding,
3082 gpointer dummy)
3083 {
3084 handle_move_to_corner_backend (display, window, META_GRAVITY_NORTH);
3085 }
3086
3087 static void
handle_move_to_side_s(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3088 handle_move_to_side_s (MetaDisplay *display,
3089 MetaWindow *window,
3090 ClutterKeyEvent *event,
3091 MetaKeyBinding *binding,
3092 gpointer dummy)
3093 {
3094 handle_move_to_corner_backend (display, window, META_GRAVITY_SOUTH);
3095 }
3096
3097 static void
handle_move_to_side_e(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3098 handle_move_to_side_e (MetaDisplay *display,
3099 MetaWindow *window,
3100 ClutterKeyEvent *event,
3101 MetaKeyBinding *binding,
3102 gpointer dummy)
3103 {
3104 handle_move_to_corner_backend (display, window, META_GRAVITY_EAST);
3105 }
3106
3107 static void
handle_move_to_side_w(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3108 handle_move_to_side_w (MetaDisplay *display,
3109 MetaWindow *window,
3110 ClutterKeyEvent *event,
3111 MetaKeyBinding *binding,
3112 gpointer dummy)
3113 {
3114 handle_move_to_corner_backend (display, window, META_GRAVITY_WEST);
3115 }
3116
3117 static void
handle_move_to_center(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3118 handle_move_to_center (MetaDisplay *display,
3119 MetaWindow *window,
3120 ClutterKeyEvent *event,
3121 MetaKeyBinding *binding,
3122 gpointer dummy)
3123 {
3124 MetaRectangle work_area;
3125 MetaRectangle frame_rect;
3126
3127 meta_window_get_work_area_current_monitor (window, &work_area);
3128 meta_window_get_frame_rect (window, &frame_rect);
3129
3130 meta_window_move_frame (window,
3131 TRUE,
3132 work_area.x + (work_area.width - frame_rect.width ) / 2,
3133 work_area.y + (work_area.height - frame_rect.height) / 2);
3134 }
3135
3136 static void
handle_show_desktop(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3137 handle_show_desktop (MetaDisplay *display,
3138 MetaWindow *window,
3139 ClutterKeyEvent *event,
3140 MetaKeyBinding *binding,
3141 gpointer dummy)
3142 {
3143 MetaWorkspaceManager *workspace_manager = display->workspace_manager;
3144
3145 if (workspace_manager->active_workspace->showing_desktop)
3146 {
3147 meta_workspace_manager_unshow_desktop (workspace_manager);
3148 meta_workspace_focus_default_window (workspace_manager->active_workspace,
3149 NULL,
3150 event->time);
3151 }
3152 else
3153 meta_workspace_manager_show_desktop (workspace_manager, event->time);
3154 }
3155
3156 static void
handle_activate_window_menu(MetaDisplay * display,MetaWindow * event_window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3157 handle_activate_window_menu (MetaDisplay *display,
3158 MetaWindow *event_window,
3159 ClutterKeyEvent *event,
3160 MetaKeyBinding *binding,
3161 gpointer dummy)
3162 {
3163 if (display->focus_window)
3164 {
3165 int x, y;
3166 MetaRectangle frame_rect;
3167 cairo_rectangle_int_t child_rect;
3168
3169 meta_window_get_frame_rect (display->focus_window, &frame_rect);
3170 meta_window_get_client_area_rect (display->focus_window, &child_rect);
3171
3172 x = frame_rect.x + child_rect.x;
3173 if (meta_get_locale_direction () == META_LOCALE_DIRECTION_RTL)
3174 x += child_rect.width;
3175
3176 y = frame_rect.y + child_rect.y;
3177 meta_window_show_menu (display->focus_window, META_WINDOW_MENU_WM, x, y);
3178 }
3179 }
3180
3181 static void
do_choose_window(MetaDisplay * display,MetaWindow * event_window,ClutterKeyEvent * event,MetaKeyBinding * binding,gboolean backward)3182 do_choose_window (MetaDisplay *display,
3183 MetaWindow *event_window,
3184 ClutterKeyEvent *event,
3185 MetaKeyBinding *binding,
3186 gboolean backward)
3187 {
3188 MetaWorkspaceManager *workspace_manager = display->workspace_manager;
3189 MetaTabList type = binding->handler->data;
3190 MetaWindow *window;
3191
3192 meta_topic (META_DEBUG_KEYBINDINGS,
3193 "Tab list = %u", type);
3194
3195 window = meta_display_get_tab_next (display,
3196 type,
3197 workspace_manager->active_workspace,
3198 NULL,
3199 backward);
3200
3201 if (window)
3202 meta_window_activate (window, event->time);
3203 }
3204
3205 static void
handle_switch(MetaDisplay * display,MetaWindow * event_window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3206 handle_switch (MetaDisplay *display,
3207 MetaWindow *event_window,
3208 ClutterKeyEvent *event,
3209 MetaKeyBinding *binding,
3210 gpointer dummy)
3211 {
3212 gboolean backwards = meta_key_binding_is_reversed (binding);
3213 do_choose_window (display, event_window, event, binding, backwards);
3214 }
3215
3216 static void
handle_cycle(MetaDisplay * display,MetaWindow * event_window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3217 handle_cycle (MetaDisplay *display,
3218 MetaWindow *event_window,
3219 ClutterKeyEvent *event,
3220 MetaKeyBinding *binding,
3221 gpointer dummy)
3222 {
3223 gboolean backwards = meta_key_binding_is_reversed (binding);
3224 do_choose_window (display, event_window, event, binding, backwards);
3225 }
3226
3227 static void
handle_toggle_fullscreen(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3228 handle_toggle_fullscreen (MetaDisplay *display,
3229 MetaWindow *window,
3230 ClutterKeyEvent *event,
3231 MetaKeyBinding *binding,
3232 gpointer dummy)
3233 {
3234 if (window->fullscreen)
3235 meta_window_unmake_fullscreen (window);
3236 else if (window->has_fullscreen_func)
3237 meta_window_make_fullscreen (window);
3238 }
3239
3240 static void
handle_toggle_above(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3241 handle_toggle_above (MetaDisplay *display,
3242 MetaWindow *window,
3243 ClutterKeyEvent *event,
3244 MetaKeyBinding *binding,
3245 gpointer dummy)
3246 {
3247 if (window->wm_state_above)
3248 meta_window_unmake_above (window);
3249 else
3250 meta_window_make_above (window);
3251 }
3252
3253 static void
handle_toggle_tiled(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3254 handle_toggle_tiled (MetaDisplay *display,
3255 MetaWindow *window,
3256 ClutterKeyEvent *event,
3257 MetaKeyBinding *binding,
3258 gpointer dummy)
3259 {
3260 MetaTileMode mode = binding->handler->data;
3261
3262 if ((META_WINDOW_TILED_LEFT (window) && mode == META_TILE_LEFT) ||
3263 (META_WINDOW_TILED_RIGHT (window) && mode == META_TILE_RIGHT))
3264 {
3265 meta_window_untile (window);
3266 }
3267 else if (meta_window_can_tile_side_by_side (window))
3268 {
3269 window->tile_monitor_number = window->monitor->number;
3270 /* Maximization constraints beat tiling constraints, so if the window
3271 * is maximized, tiling won't have any effect unless we unmaximize it
3272 * horizontally first; rather than calling meta_window_unmaximize(),
3273 * we just set the flag and rely on meta_window_tile() syncing it to
3274 * save an additional roundtrip.
3275 */
3276 window->maximized_horizontally = FALSE;
3277 meta_window_tile (window, mode);
3278 }
3279 }
3280
3281 static void
handle_toggle_maximized(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3282 handle_toggle_maximized (MetaDisplay *display,
3283 MetaWindow *window,
3284 ClutterKeyEvent *event,
3285 MetaKeyBinding *binding,
3286 gpointer dummy)
3287 {
3288 if (META_WINDOW_MAXIMIZED (window))
3289 meta_window_unmaximize (window, META_MAXIMIZE_BOTH);
3290 else if (window->has_maximize_func)
3291 meta_window_maximize (window, META_MAXIMIZE_BOTH);
3292 }
3293
3294 static void
handle_maximize(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3295 handle_maximize (MetaDisplay *display,
3296 MetaWindow *window,
3297 ClutterKeyEvent *event,
3298 MetaKeyBinding *binding,
3299 gpointer dummy)
3300 {
3301 if (window->has_maximize_func)
3302 meta_window_maximize (window, META_MAXIMIZE_BOTH);
3303 }
3304
3305 static void
handle_unmaximize(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3306 handle_unmaximize (MetaDisplay *display,
3307 MetaWindow *window,
3308 ClutterKeyEvent *event,
3309 MetaKeyBinding *binding,
3310 gpointer dummy)
3311 {
3312 if (window->maximized_vertically || window->maximized_horizontally)
3313 meta_window_unmaximize (window, META_MAXIMIZE_BOTH);
3314 }
3315
3316 static void
handle_toggle_shaded(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3317 handle_toggle_shaded (MetaDisplay *display,
3318 MetaWindow *window,
3319 ClutterKeyEvent *event,
3320 MetaKeyBinding *binding,
3321 gpointer dummy)
3322 {
3323 if (window->shaded)
3324 meta_window_unshade (window, event->time);
3325 else if (window->has_shade_func)
3326 meta_window_shade (window, event->time);
3327 }
3328
3329 static void
handle_close(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3330 handle_close (MetaDisplay *display,
3331 MetaWindow *window,
3332 ClutterKeyEvent *event,
3333 MetaKeyBinding *binding,
3334 gpointer dummy)
3335 {
3336 if (window->has_close_func)
3337 meta_window_delete (window, event->time);
3338 }
3339
3340 static void
handle_minimize(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3341 handle_minimize (MetaDisplay *display,
3342 MetaWindow *window,
3343 ClutterKeyEvent *event,
3344 MetaKeyBinding *binding,
3345 gpointer dummy)
3346 {
3347 if (window->has_minimize_func)
3348 meta_window_minimize (window);
3349 }
3350
3351 static void
handle_begin_move(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3352 handle_begin_move (MetaDisplay *display,
3353 MetaWindow *window,
3354 ClutterKeyEvent *event,
3355 MetaKeyBinding *binding,
3356 gpointer dummy)
3357 {
3358 if (window->has_move_func)
3359 {
3360 meta_window_begin_grab_op (window,
3361 META_GRAB_OP_KEYBOARD_MOVING,
3362 FALSE,
3363 event->time);
3364 }
3365 }
3366
3367 static void
handle_begin_resize(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3368 handle_begin_resize (MetaDisplay *display,
3369 MetaWindow *window,
3370 ClutterKeyEvent *event,
3371 MetaKeyBinding *binding,
3372 gpointer dummy)
3373 {
3374 if (window->has_resize_func)
3375 {
3376 meta_window_begin_grab_op (window,
3377 META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN,
3378 FALSE,
3379 event->time);
3380 }
3381 }
3382
3383 static void
handle_toggle_on_all_workspaces(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3384 handle_toggle_on_all_workspaces (MetaDisplay *display,
3385 MetaWindow *window,
3386 ClutterKeyEvent *event,
3387 MetaKeyBinding *binding,
3388 gpointer dummy)
3389 {
3390 if (window->on_all_workspaces_requested)
3391 meta_window_unstick (window);
3392 else
3393 meta_window_stick (window);
3394 }
3395
3396 static void
handle_move_to_workspace_last(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3397 handle_move_to_workspace_last (MetaDisplay *display,
3398 MetaWindow *window,
3399 ClutterKeyEvent *event,
3400 MetaKeyBinding *binding,
3401 gpointer dummy)
3402 {
3403 MetaWorkspaceManager *workspace_manager = display->workspace_manager;
3404 gint which;
3405 MetaWorkspace *workspace;
3406
3407 if (window->always_sticky)
3408 return;
3409
3410 which = meta_workspace_manager_get_n_workspaces (workspace_manager) - 1;
3411 workspace = meta_workspace_manager_get_workspace_by_index (workspace_manager, which);
3412 meta_window_change_workspace (window, workspace);
3413 }
3414
3415
3416 static void
handle_move_to_workspace(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3417 handle_move_to_workspace (MetaDisplay *display,
3418 MetaWindow *window,
3419 ClutterKeyEvent *event,
3420 MetaKeyBinding *binding,
3421 gpointer dummy)
3422 {
3423 MetaWorkspaceManager *workspace_manager = display->workspace_manager;
3424 gint which = binding->handler->data;
3425 gboolean flip = (which < 0);
3426 MetaWorkspace *workspace;
3427
3428 /* If which is zero or positive, it's a workspace number, and the window
3429 * should move to the workspace with that number.
3430 *
3431 * However, if it's negative, it's a direction with respect to the current
3432 * position; it's expressed as a member of the MetaMotionDirection enum,
3433 * all of whose members are negative. Such a change is called a flip.
3434 */
3435
3436 if (window->always_sticky)
3437 return;
3438
3439 workspace = NULL;
3440 if (flip)
3441 {
3442 workspace = meta_workspace_get_neighbor (workspace_manager->active_workspace,
3443 which);
3444 }
3445 else
3446 {
3447 workspace = meta_workspace_manager_get_workspace_by_index (workspace_manager, which);
3448 }
3449
3450 if (workspace)
3451 {
3452 /* Activate second, so the window is never unmapped */
3453 meta_window_change_workspace (window, workspace);
3454 if (flip)
3455 {
3456 meta_topic (META_DEBUG_FOCUS,
3457 "Resetting mouse_mode to FALSE due to "
3458 "handle_move_to_workspace() call with flip set.");
3459 meta_display_clear_mouse_mode (workspace->display);
3460 meta_workspace_activate_with_focus (workspace,
3461 window,
3462 event->time);
3463 }
3464 }
3465 else
3466 {
3467 /* We could offer to create it I suppose */
3468 }
3469 }
3470
3471 static void
handle_move_to_monitor(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3472 handle_move_to_monitor (MetaDisplay *display,
3473 MetaWindow *window,
3474 ClutterKeyEvent *event,
3475 MetaKeyBinding *binding,
3476 gpointer dummy)
3477 {
3478 MetaBackend *backend = meta_get_backend ();
3479 MetaMonitorManager *monitor_manager =
3480 meta_backend_get_monitor_manager (backend);
3481 gint which = binding->handler->data;
3482 MetaLogicalMonitor *current, *new;
3483
3484 current = window->monitor;
3485 new = meta_monitor_manager_get_logical_monitor_neighbor (monitor_manager,
3486 current, which);
3487
3488 if (new == NULL)
3489 return;
3490
3491 meta_window_move_to_monitor (window, new->number);
3492 }
3493
3494 static void
handle_raise_or_lower(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3495 handle_raise_or_lower (MetaDisplay *display,
3496 MetaWindow *window,
3497 ClutterKeyEvent *event,
3498 MetaKeyBinding *binding,
3499 gpointer dummy)
3500 {
3501 /* Get window at pointer */
3502
3503 MetaWindow *above = NULL;
3504
3505 /* Check if top */
3506 if (meta_stack_get_top (window->display->stack) == window)
3507 {
3508 meta_window_lower (window);
3509 return;
3510 }
3511
3512 /* else check if windows in same layer are intersecting it */
3513
3514 above = meta_stack_get_above (window->display->stack, window, TRUE);
3515
3516 while (above)
3517 {
3518 MetaRectangle tmp, win_rect, above_rect;
3519
3520 if (above->mapped && meta_window_should_be_showing (above))
3521 {
3522 meta_window_get_frame_rect (window, &win_rect);
3523 meta_window_get_frame_rect (above, &above_rect);
3524
3525 /* Check if obscured */
3526 if (meta_rectangle_intersect (&win_rect, &above_rect, &tmp))
3527 {
3528 meta_window_raise (window);
3529 return;
3530 }
3531 }
3532
3533 above = meta_stack_get_above (window->display->stack, above, TRUE);
3534 }
3535
3536 /* window is not obscured */
3537 meta_window_lower (window);
3538 }
3539
3540 static void
handle_raise(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3541 handle_raise (MetaDisplay *display,
3542 MetaWindow *window,
3543 ClutterKeyEvent *event,
3544 MetaKeyBinding *binding,
3545 gpointer dummy)
3546 {
3547 meta_window_raise (window);
3548 }
3549
3550 static void
handle_lower(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3551 handle_lower (MetaDisplay *display,
3552 MetaWindow *window,
3553 ClutterKeyEvent *event,
3554 MetaKeyBinding *binding,
3555 gpointer dummy)
3556 {
3557 meta_window_lower (window);
3558 }
3559
3560 static void
handle_set_spew_mark(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3561 handle_set_spew_mark (MetaDisplay *display,
3562 MetaWindow *window,
3563 ClutterKeyEvent *event,
3564 MetaKeyBinding *binding,
3565 gpointer dummy)
3566 {
3567 meta_verbose ("-- MARK MARK MARK MARK --");
3568 }
3569
3570 #ifdef HAVE_NATIVE_BACKEND
3571 static void
handle_switch_vt(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3572 handle_switch_vt (MetaDisplay *display,
3573 MetaWindow *window,
3574 ClutterKeyEvent *event,
3575 MetaKeyBinding *binding,
3576 gpointer dummy)
3577 {
3578 gint vt = binding->handler->data;
3579 GError *error = NULL;
3580
3581 if (!meta_activate_vt (vt, &error))
3582 {
3583 g_warning ("Failed to switch VT: %s", error->message);
3584 g_error_free (error);
3585 }
3586 }
3587 #endif /* HAVE_NATIVE_BACKEND */
3588
3589 static void
handle_switch_monitor(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3590 handle_switch_monitor (MetaDisplay *display,
3591 MetaWindow *window,
3592 ClutterKeyEvent *event,
3593 MetaKeyBinding *binding,
3594 gpointer dummy)
3595 {
3596 MetaBackend *backend = meta_get_backend ();
3597 MetaMonitorManager *monitor_manager =
3598 meta_backend_get_monitor_manager (backend);
3599 MetaMonitorSwitchConfigType config_type =
3600 meta_monitor_manager_get_switch_config (monitor_manager);
3601
3602 if (!meta_monitor_manager_can_switch_config (monitor_manager))
3603 return;
3604
3605 config_type = (config_type + 1) % (META_MONITOR_SWITCH_CONFIG_UNKNOWN);
3606 meta_monitor_manager_switch_config (monitor_manager, config_type);
3607 }
3608
3609 static void
handle_rotate_monitor(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3610 handle_rotate_monitor (MetaDisplay *display,
3611 MetaWindow *window,
3612 ClutterKeyEvent *event,
3613 MetaKeyBinding *binding,
3614 gpointer dummy)
3615 {
3616 MetaBackend *backend = meta_get_backend ();
3617 MetaMonitorManager *monitor_manager =
3618 meta_backend_get_monitor_manager (backend);
3619
3620 meta_monitor_manager_rotate_monitor (monitor_manager);
3621 }
3622
3623 static void
handle_restore_shortcuts(MetaDisplay * display,MetaWindow * window,ClutterKeyEvent * event,MetaKeyBinding * binding,gpointer dummy)3624 handle_restore_shortcuts (MetaDisplay *display,
3625 MetaWindow *window,
3626 ClutterKeyEvent *event,
3627 MetaKeyBinding *binding,
3628 gpointer dummy)
3629 {
3630 ClutterInputDevice *source;
3631
3632 if (!display->focus_window)
3633 return;
3634
3635 source = clutter_event_get_source_device ((ClutterEvent *) event);
3636
3637 meta_topic (META_DEBUG_KEYBINDINGS, "Restoring normal keyboard shortcuts");
3638
3639 meta_window_force_restore_shortcuts (display->focus_window, source);
3640 }
3641
3642 /**
3643 * meta_keybindings_set_custom_handler:
3644 * @name: The name of the keybinding to set
3645 * @handler: (nullable): The new handler function
3646 * @user_data: User data to pass to the callback
3647 * @free_data: Will be called when this handler is overridden.
3648 *
3649 * Allows users to register a custom handler for a
3650 * builtin key binding.
3651 *
3652 * Returns: %TRUE if the binding known as @name was found,
3653 * %FALSE otherwise.
3654 */
3655 gboolean
meta_keybindings_set_custom_handler(const gchar * name,MetaKeyHandlerFunc handler,gpointer user_data,GDestroyNotify free_data)3656 meta_keybindings_set_custom_handler (const gchar *name,
3657 MetaKeyHandlerFunc handler,
3658 gpointer user_data,
3659 GDestroyNotify free_data)
3660 {
3661 MetaKeyHandler *key_handler = HANDLER (name);
3662
3663 if (!key_handler)
3664 return FALSE;
3665
3666 if (key_handler->user_data_free_func && key_handler->user_data)
3667 key_handler->user_data_free_func (key_handler->user_data);
3668
3669 key_handler->func = handler;
3670 key_handler->user_data = user_data;
3671 key_handler->user_data_free_func = free_data;
3672
3673 return TRUE;
3674 }
3675
3676 static void
init_builtin_key_bindings(MetaDisplay * display)3677 init_builtin_key_bindings (MetaDisplay *display)
3678 {
3679 GSettings *common_keybindings = g_settings_new (SCHEMA_COMMON_KEYBINDINGS);
3680 GSettings *mutter_keybindings = g_settings_new (SCHEMA_MUTTER_KEYBINDINGS);
3681 GSettings *mutter_wayland_keybindings = g_settings_new (SCHEMA_MUTTER_WAYLAND_KEYBINDINGS);
3682
3683 add_builtin_keybinding (display,
3684 "switch-to-workspace-1",
3685 common_keybindings,
3686 META_KEY_BINDING_NONE |
3687 META_KEY_BINDING_IGNORE_AUTOREPEAT,
3688 META_KEYBINDING_ACTION_WORKSPACE_1,
3689 handle_switch_to_workspace, 0);
3690 add_builtin_keybinding (display,
3691 "switch-to-workspace-2",
3692 common_keybindings,
3693 META_KEY_BINDING_NONE |
3694 META_KEY_BINDING_IGNORE_AUTOREPEAT,
3695 META_KEYBINDING_ACTION_WORKSPACE_2,
3696 handle_switch_to_workspace, 1);
3697 add_builtin_keybinding (display,
3698 "switch-to-workspace-3",
3699 common_keybindings,
3700 META_KEY_BINDING_NONE |
3701 META_KEY_BINDING_IGNORE_AUTOREPEAT,
3702 META_KEYBINDING_ACTION_WORKSPACE_3,
3703 handle_switch_to_workspace, 2);
3704 add_builtin_keybinding (display,
3705 "switch-to-workspace-4",
3706 common_keybindings,
3707 META_KEY_BINDING_NONE |
3708 META_KEY_BINDING_IGNORE_AUTOREPEAT,
3709 META_KEYBINDING_ACTION_WORKSPACE_4,
3710 handle_switch_to_workspace, 3);
3711 add_builtin_keybinding (display,
3712 "switch-to-workspace-5",
3713 common_keybindings,
3714 META_KEY_BINDING_NONE |
3715 META_KEY_BINDING_IGNORE_AUTOREPEAT,
3716 META_KEYBINDING_ACTION_WORKSPACE_5,
3717 handle_switch_to_workspace, 4);
3718 add_builtin_keybinding (display,
3719 "switch-to-workspace-6",
3720 common_keybindings,
3721 META_KEY_BINDING_NONE |
3722 META_KEY_BINDING_IGNORE_AUTOREPEAT,
3723 META_KEYBINDING_ACTION_WORKSPACE_6,
3724 handle_switch_to_workspace, 5);
3725 add_builtin_keybinding (display,
3726 "switch-to-workspace-7",
3727 common_keybindings,
3728 META_KEY_BINDING_NONE |
3729 META_KEY_BINDING_IGNORE_AUTOREPEAT,
3730 META_KEYBINDING_ACTION_WORKSPACE_7,
3731 handle_switch_to_workspace, 6);
3732 add_builtin_keybinding (display,
3733 "switch-to-workspace-8",
3734 common_keybindings,
3735 META_KEY_BINDING_NONE |
3736 META_KEY_BINDING_IGNORE_AUTOREPEAT,
3737 META_KEYBINDING_ACTION_WORKSPACE_8,
3738 handle_switch_to_workspace, 7);
3739 add_builtin_keybinding (display,
3740 "switch-to-workspace-9",
3741 common_keybindings,
3742 META_KEY_BINDING_NONE |
3743 META_KEY_BINDING_IGNORE_AUTOREPEAT,
3744 META_KEYBINDING_ACTION_WORKSPACE_9,
3745 handle_switch_to_workspace, 8);
3746 add_builtin_keybinding (display,
3747 "switch-to-workspace-10",
3748 common_keybindings,
3749 META_KEY_BINDING_NONE |
3750 META_KEY_BINDING_IGNORE_AUTOREPEAT,
3751 META_KEYBINDING_ACTION_WORKSPACE_10,
3752 handle_switch_to_workspace, 9);
3753 add_builtin_keybinding (display,
3754 "switch-to-workspace-11",
3755 common_keybindings,
3756 META_KEY_BINDING_NONE |
3757 META_KEY_BINDING_IGNORE_AUTOREPEAT,
3758 META_KEYBINDING_ACTION_WORKSPACE_11,
3759 handle_switch_to_workspace, 10);
3760 add_builtin_keybinding (display,
3761 "switch-to-workspace-12",
3762 common_keybindings,
3763 META_KEY_BINDING_NONE |
3764 META_KEY_BINDING_IGNORE_AUTOREPEAT,
3765 META_KEYBINDING_ACTION_WORKSPACE_12,
3766 handle_switch_to_workspace, 11);
3767
3768 add_builtin_keybinding (display,
3769 "switch-to-workspace-left",
3770 common_keybindings,
3771 META_KEY_BINDING_NONE,
3772 META_KEYBINDING_ACTION_WORKSPACE_LEFT,
3773 handle_switch_to_workspace, META_MOTION_LEFT);
3774
3775 add_builtin_keybinding (display,
3776 "switch-to-workspace-right",
3777 common_keybindings,
3778 META_KEY_BINDING_NONE,
3779 META_KEYBINDING_ACTION_WORKSPACE_RIGHT,
3780 handle_switch_to_workspace, META_MOTION_RIGHT);
3781
3782 add_builtin_keybinding (display,
3783 "switch-to-workspace-up",
3784 common_keybindings,
3785 META_KEY_BINDING_NONE,
3786 META_KEYBINDING_ACTION_WORKSPACE_UP,
3787 handle_switch_to_workspace, META_MOTION_UP);
3788
3789 add_builtin_keybinding (display,
3790 "switch-to-workspace-down",
3791 common_keybindings,
3792 META_KEY_BINDING_NONE,
3793 META_KEYBINDING_ACTION_WORKSPACE_DOWN,
3794 handle_switch_to_workspace, META_MOTION_DOWN);
3795
3796 add_builtin_keybinding (display,
3797 "switch-to-workspace-last",
3798 common_keybindings,
3799 META_KEY_BINDING_NONE,
3800 META_KEYBINDING_ACTION_WORKSPACE_LAST,
3801 handle_switch_to_last_workspace, 0);
3802
3803
3804
3805 /* The ones which have inverses. These can't be bound to any keystroke
3806 * containing Shift because Shift will invert their "backward" state.
3807 *
3808 * TODO: "NORMAL" and "DOCKS" should be renamed to the same name as their
3809 * action, for obviousness.
3810 *
3811 * TODO: handle_switch and handle_cycle should probably really be the
3812 * same function checking a bit in the parameter for difference.
3813 */
3814
3815 add_builtin_keybinding (display,
3816 "switch-group",
3817 common_keybindings,
3818 META_KEY_BINDING_NONE,
3819 META_KEYBINDING_ACTION_SWITCH_GROUP,
3820 handle_switch, META_TAB_LIST_GROUP);
3821
3822 add_builtin_keybinding (display,
3823 "switch-group-backward",
3824 common_keybindings,
3825 META_KEY_BINDING_IS_REVERSED,
3826 META_KEYBINDING_ACTION_SWITCH_GROUP_BACKWARD,
3827 handle_switch, META_TAB_LIST_GROUP);
3828
3829 add_builtin_keybinding (display,
3830 "switch-applications",
3831 common_keybindings,
3832 META_KEY_BINDING_NONE,
3833 META_KEYBINDING_ACTION_SWITCH_APPLICATIONS,
3834 handle_switch, META_TAB_LIST_NORMAL);
3835
3836 add_builtin_keybinding (display,
3837 "switch-applications-backward",
3838 common_keybindings,
3839 META_KEY_BINDING_IS_REVERSED,
3840 META_KEYBINDING_ACTION_SWITCH_APPLICATIONS_BACKWARD,
3841 handle_switch, META_TAB_LIST_NORMAL);
3842
3843 add_builtin_keybinding (display,
3844 "switch-windows",
3845 common_keybindings,
3846 META_KEY_BINDING_NONE,
3847 META_KEYBINDING_ACTION_SWITCH_WINDOWS,
3848 handle_switch, META_TAB_LIST_NORMAL);
3849
3850 add_builtin_keybinding (display,
3851 "switch-windows-backward",
3852 common_keybindings,
3853 META_KEY_BINDING_IS_REVERSED,
3854 META_KEYBINDING_ACTION_SWITCH_WINDOWS_BACKWARD,
3855 handle_switch, META_TAB_LIST_NORMAL);
3856
3857 add_builtin_keybinding (display,
3858 "switch-panels",
3859 common_keybindings,
3860 META_KEY_BINDING_NONE,
3861 META_KEYBINDING_ACTION_SWITCH_PANELS,
3862 handle_switch, META_TAB_LIST_DOCKS);
3863
3864 add_builtin_keybinding (display,
3865 "switch-panels-backward",
3866 common_keybindings,
3867 META_KEY_BINDING_IS_REVERSED,
3868 META_KEYBINDING_ACTION_SWITCH_PANELS_BACKWARD,
3869 handle_switch, META_TAB_LIST_DOCKS);
3870
3871 add_builtin_keybinding (display,
3872 "cycle-group",
3873 common_keybindings,
3874 META_KEY_BINDING_NONE,
3875 META_KEYBINDING_ACTION_CYCLE_GROUP,
3876 handle_cycle, META_TAB_LIST_GROUP);
3877
3878 add_builtin_keybinding (display,
3879 "cycle-group-backward",
3880 common_keybindings,
3881 META_KEY_BINDING_IS_REVERSED,
3882 META_KEYBINDING_ACTION_CYCLE_GROUP_BACKWARD,
3883 handle_cycle, META_TAB_LIST_GROUP);
3884
3885 add_builtin_keybinding (display,
3886 "cycle-windows",
3887 common_keybindings,
3888 META_KEY_BINDING_NONE,
3889 META_KEYBINDING_ACTION_CYCLE_WINDOWS,
3890 handle_cycle, META_TAB_LIST_NORMAL);
3891
3892 add_builtin_keybinding (display,
3893 "cycle-windows-backward",
3894 common_keybindings,
3895 META_KEY_BINDING_IS_REVERSED,
3896 META_KEYBINDING_ACTION_CYCLE_WINDOWS_BACKWARD,
3897 handle_cycle, META_TAB_LIST_NORMAL);
3898
3899 add_builtin_keybinding (display,
3900 "cycle-panels",
3901 common_keybindings,
3902 META_KEY_BINDING_NONE,
3903 META_KEYBINDING_ACTION_CYCLE_PANELS,
3904 handle_cycle, META_TAB_LIST_DOCKS);
3905
3906 add_builtin_keybinding (display,
3907 "cycle-panels-backward",
3908 common_keybindings,
3909 META_KEY_BINDING_IS_REVERSED,
3910 META_KEYBINDING_ACTION_CYCLE_PANELS_BACKWARD,
3911 handle_cycle, META_TAB_LIST_DOCKS);
3912
3913 /***********************************/
3914
3915 add_builtin_keybinding (display,
3916 "show-desktop",
3917 common_keybindings,
3918 META_KEY_BINDING_NONE,
3919 META_KEYBINDING_ACTION_SHOW_DESKTOP,
3920 handle_show_desktop, 0);
3921
3922 add_builtin_keybinding (display,
3923 "panel-run-dialog",
3924 common_keybindings,
3925 META_KEY_BINDING_NONE,
3926 META_KEYBINDING_ACTION_PANEL_RUN_DIALOG,
3927 NULL, META_KEYBINDING_ACTION_PANEL_RUN_DIALOG);
3928
3929 add_builtin_keybinding (display,
3930 "set-spew-mark",
3931 common_keybindings,
3932 META_KEY_BINDING_NONE,
3933 META_KEYBINDING_ACTION_SET_SPEW_MARK,
3934 handle_set_spew_mark, 0);
3935
3936 add_builtin_keybinding (display,
3937 "switch-monitor",
3938 mutter_keybindings,
3939 META_KEY_BINDING_NONE,
3940 META_KEYBINDING_ACTION_SWITCH_MONITOR,
3941 handle_switch_monitor, 0);
3942
3943 add_builtin_keybinding (display,
3944 "rotate-monitor",
3945 mutter_keybindings,
3946 META_KEY_BINDING_NONE,
3947 META_KEYBINDING_ACTION_ROTATE_MONITOR,
3948 handle_rotate_monitor, 0);
3949
3950 #ifdef HAVE_NATIVE_BACKEND
3951 MetaBackend *backend = meta_get_backend ();
3952 if (META_IS_BACKEND_NATIVE (backend))
3953 {
3954 add_builtin_keybinding (display,
3955 "switch-to-session-1",
3956 mutter_wayland_keybindings,
3957 META_KEY_BINDING_NON_MASKABLE,
3958 META_KEYBINDING_ACTION_NONE,
3959 handle_switch_vt, 1);
3960
3961 add_builtin_keybinding (display,
3962 "switch-to-session-2",
3963 mutter_wayland_keybindings,
3964 META_KEY_BINDING_NON_MASKABLE,
3965 META_KEYBINDING_ACTION_NONE,
3966 handle_switch_vt, 2);
3967
3968 add_builtin_keybinding (display,
3969 "switch-to-session-3",
3970 mutter_wayland_keybindings,
3971 META_KEY_BINDING_NON_MASKABLE,
3972 META_KEYBINDING_ACTION_NONE,
3973 handle_switch_vt, 3);
3974
3975 add_builtin_keybinding (display,
3976 "switch-to-session-4",
3977 mutter_wayland_keybindings,
3978 META_KEY_BINDING_NON_MASKABLE,
3979 META_KEYBINDING_ACTION_NONE,
3980 handle_switch_vt, 4);
3981
3982 add_builtin_keybinding (display,
3983 "switch-to-session-5",
3984 mutter_wayland_keybindings,
3985 META_KEY_BINDING_NON_MASKABLE,
3986 META_KEYBINDING_ACTION_NONE,
3987 handle_switch_vt, 5);
3988
3989 add_builtin_keybinding (display,
3990 "switch-to-session-6",
3991 mutter_wayland_keybindings,
3992 META_KEY_BINDING_NON_MASKABLE,
3993 META_KEYBINDING_ACTION_NONE,
3994 handle_switch_vt, 6);
3995
3996 add_builtin_keybinding (display,
3997 "switch-to-session-7",
3998 mutter_wayland_keybindings,
3999 META_KEY_BINDING_NON_MASKABLE,
4000 META_KEYBINDING_ACTION_NONE,
4001 handle_switch_vt, 7);
4002
4003 add_builtin_keybinding (display,
4004 "switch-to-session-8",
4005 mutter_wayland_keybindings,
4006 META_KEY_BINDING_NON_MASKABLE,
4007 META_KEYBINDING_ACTION_NONE,
4008 handle_switch_vt, 8);
4009
4010 add_builtin_keybinding (display,
4011 "switch-to-session-9",
4012 mutter_wayland_keybindings,
4013 META_KEY_BINDING_NON_MASKABLE,
4014 META_KEYBINDING_ACTION_NONE,
4015 handle_switch_vt, 9);
4016
4017 add_builtin_keybinding (display,
4018 "switch-to-session-10",
4019 mutter_wayland_keybindings,
4020 META_KEY_BINDING_NON_MASKABLE,
4021 META_KEYBINDING_ACTION_NONE,
4022 handle_switch_vt, 10);
4023
4024 add_builtin_keybinding (display,
4025 "switch-to-session-11",
4026 mutter_wayland_keybindings,
4027 META_KEY_BINDING_NON_MASKABLE,
4028 META_KEYBINDING_ACTION_NONE,
4029 handle_switch_vt, 11);
4030
4031 add_builtin_keybinding (display,
4032 "switch-to-session-12",
4033 mutter_wayland_keybindings,
4034 META_KEY_BINDING_NON_MASKABLE,
4035 META_KEYBINDING_ACTION_NONE,
4036 handle_switch_vt, 12);
4037 }
4038 #endif /* HAVE_NATIVE_BACKEND */
4039
4040 add_builtin_keybinding (display,
4041 "restore-shortcuts",
4042 mutter_wayland_keybindings,
4043 META_KEY_BINDING_NON_MASKABLE,
4044 META_KEYBINDING_ACTION_NONE,
4045 handle_restore_shortcuts, 0);
4046
4047 /************************ PER WINDOW BINDINGS ************************/
4048
4049 /* These take a window as an extra parameter; they have no effect
4050 * if no window is active.
4051 */
4052
4053 add_builtin_keybinding (display,
4054 "activate-window-menu",
4055 common_keybindings,
4056 META_KEY_BINDING_PER_WINDOW |
4057 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4058 META_KEYBINDING_ACTION_ACTIVATE_WINDOW_MENU,
4059 handle_activate_window_menu, 0);
4060
4061 add_builtin_keybinding (display,
4062 "toggle-fullscreen",
4063 common_keybindings,
4064 META_KEY_BINDING_PER_WINDOW |
4065 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4066 META_KEYBINDING_ACTION_TOGGLE_FULLSCREEN,
4067 handle_toggle_fullscreen, 0);
4068
4069 add_builtin_keybinding (display,
4070 "toggle-maximized",
4071 common_keybindings,
4072 META_KEY_BINDING_PER_WINDOW |
4073 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4074 META_KEYBINDING_ACTION_TOGGLE_MAXIMIZED,
4075 handle_toggle_maximized, 0);
4076
4077 add_builtin_keybinding (display,
4078 "toggle-tiled-left",
4079 mutter_keybindings,
4080 META_KEY_BINDING_PER_WINDOW |
4081 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4082 META_KEYBINDING_ACTION_TOGGLE_TILED_LEFT,
4083 handle_toggle_tiled, META_TILE_LEFT);
4084
4085 add_builtin_keybinding (display,
4086 "toggle-tiled-right",
4087 mutter_keybindings,
4088 META_KEY_BINDING_PER_WINDOW |
4089 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4090 META_KEYBINDING_ACTION_TOGGLE_TILED_RIGHT,
4091 handle_toggle_tiled, META_TILE_RIGHT);
4092
4093 add_builtin_keybinding (display,
4094 "toggle-above",
4095 common_keybindings,
4096 META_KEY_BINDING_PER_WINDOW |
4097 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4098 META_KEYBINDING_ACTION_TOGGLE_ABOVE,
4099 handle_toggle_above, 0);
4100
4101 add_builtin_keybinding (display,
4102 "maximize",
4103 common_keybindings,
4104 META_KEY_BINDING_PER_WINDOW |
4105 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4106 META_KEYBINDING_ACTION_MAXIMIZE,
4107 handle_maximize, 0);
4108
4109 add_builtin_keybinding (display,
4110 "unmaximize",
4111 common_keybindings,
4112 META_KEY_BINDING_PER_WINDOW |
4113 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4114 META_KEYBINDING_ACTION_UNMAXIMIZE,
4115 handle_unmaximize, 0);
4116
4117 add_builtin_keybinding (display,
4118 "toggle-shaded",
4119 common_keybindings,
4120 META_KEY_BINDING_PER_WINDOW |
4121 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4122 META_KEYBINDING_ACTION_TOGGLE_SHADED,
4123 handle_toggle_shaded, 0);
4124
4125 add_builtin_keybinding (display,
4126 "minimize",
4127 common_keybindings,
4128 META_KEY_BINDING_PER_WINDOW |
4129 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4130 META_KEYBINDING_ACTION_MINIMIZE,
4131 handle_minimize, 0);
4132
4133 add_builtin_keybinding (display,
4134 "close",
4135 common_keybindings,
4136 META_KEY_BINDING_PER_WINDOW |
4137 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4138 META_KEYBINDING_ACTION_CLOSE,
4139 handle_close, 0);
4140
4141 add_builtin_keybinding (display,
4142 "begin-move",
4143 common_keybindings,
4144 META_KEY_BINDING_PER_WINDOW |
4145 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4146 META_KEYBINDING_ACTION_BEGIN_MOVE,
4147 handle_begin_move, 0);
4148
4149 add_builtin_keybinding (display,
4150 "begin-resize",
4151 common_keybindings,
4152 META_KEY_BINDING_PER_WINDOW |
4153 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4154 META_KEYBINDING_ACTION_BEGIN_RESIZE,
4155 handle_begin_resize, 0);
4156
4157 add_builtin_keybinding (display,
4158 "toggle-on-all-workspaces",
4159 common_keybindings,
4160 META_KEY_BINDING_PER_WINDOW |
4161 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4162 META_KEYBINDING_ACTION_TOGGLE_ON_ALL_WORKSPACES,
4163 handle_toggle_on_all_workspaces, 0);
4164
4165 add_builtin_keybinding (display,
4166 "move-to-workspace-1",
4167 common_keybindings,
4168 META_KEY_BINDING_PER_WINDOW |
4169 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4170 META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_1,
4171 handle_move_to_workspace, 0);
4172
4173 add_builtin_keybinding (display,
4174 "move-to-workspace-2",
4175 common_keybindings,
4176 META_KEY_BINDING_PER_WINDOW |
4177 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4178 META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_2,
4179 handle_move_to_workspace, 1);
4180
4181 add_builtin_keybinding (display,
4182 "move-to-workspace-3",
4183 common_keybindings,
4184 META_KEY_BINDING_PER_WINDOW |
4185 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4186 META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_3,
4187 handle_move_to_workspace, 2);
4188
4189 add_builtin_keybinding (display,
4190 "move-to-workspace-4",
4191 common_keybindings,
4192 META_KEY_BINDING_PER_WINDOW |
4193 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4194 META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_4,
4195 handle_move_to_workspace, 3);
4196
4197 add_builtin_keybinding (display,
4198 "move-to-workspace-5",
4199 common_keybindings,
4200 META_KEY_BINDING_PER_WINDOW |
4201 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4202 META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_5,
4203 handle_move_to_workspace, 4);
4204
4205 add_builtin_keybinding (display,
4206 "move-to-workspace-6",
4207 common_keybindings,
4208 META_KEY_BINDING_PER_WINDOW |
4209 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4210 META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_6,
4211 handle_move_to_workspace, 5);
4212
4213 add_builtin_keybinding (display,
4214 "move-to-workspace-7",
4215 common_keybindings,
4216 META_KEY_BINDING_PER_WINDOW |
4217 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4218 META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_7,
4219 handle_move_to_workspace, 6);
4220
4221 add_builtin_keybinding (display,
4222 "move-to-workspace-8",
4223 common_keybindings,
4224 META_KEY_BINDING_PER_WINDOW |
4225 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4226 META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_8,
4227 handle_move_to_workspace, 7);
4228
4229 add_builtin_keybinding (display,
4230 "move-to-workspace-9",
4231 common_keybindings,
4232 META_KEY_BINDING_PER_WINDOW |
4233 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4234 META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_9,
4235 handle_move_to_workspace, 8);
4236
4237 add_builtin_keybinding (display,
4238 "move-to-workspace-10",
4239 common_keybindings,
4240 META_KEY_BINDING_PER_WINDOW |
4241 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4242 META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_10,
4243 handle_move_to_workspace, 9);
4244
4245 add_builtin_keybinding (display,
4246 "move-to-workspace-11",
4247 common_keybindings,
4248 META_KEY_BINDING_PER_WINDOW |
4249 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4250 META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_11,
4251 handle_move_to_workspace, 10);
4252
4253 add_builtin_keybinding (display,
4254 "move-to-workspace-12",
4255 common_keybindings,
4256 META_KEY_BINDING_PER_WINDOW |
4257 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4258 META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_12,
4259 handle_move_to_workspace, 11);
4260
4261 add_builtin_keybinding (display,
4262 "move-to-workspace-last",
4263 common_keybindings,
4264 META_KEY_BINDING_PER_WINDOW |
4265 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4266 META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_LAST,
4267 handle_move_to_workspace_last, 0);
4268
4269 add_builtin_keybinding (display,
4270 "move-to-workspace-left",
4271 common_keybindings,
4272 META_KEY_BINDING_PER_WINDOW,
4273 META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_LEFT,
4274 handle_move_to_workspace, META_MOTION_LEFT);
4275
4276 add_builtin_keybinding (display,
4277 "move-to-workspace-right",
4278 common_keybindings,
4279 META_KEY_BINDING_PER_WINDOW,
4280 META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_RIGHT,
4281 handle_move_to_workspace, META_MOTION_RIGHT);
4282
4283 add_builtin_keybinding (display,
4284 "move-to-workspace-up",
4285 common_keybindings,
4286 META_KEY_BINDING_PER_WINDOW,
4287 META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_UP,
4288 handle_move_to_workspace, META_MOTION_UP);
4289
4290 add_builtin_keybinding (display,
4291 "move-to-workspace-down",
4292 common_keybindings,
4293 META_KEY_BINDING_PER_WINDOW,
4294 META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_DOWN,
4295 handle_move_to_workspace, META_MOTION_DOWN);
4296
4297 add_builtin_keybinding (display,
4298 "move-to-monitor-left",
4299 common_keybindings,
4300 META_KEY_BINDING_PER_WINDOW,
4301 META_KEYBINDING_ACTION_MOVE_TO_MONITOR_LEFT,
4302 handle_move_to_monitor, META_DISPLAY_LEFT);
4303
4304 add_builtin_keybinding (display,
4305 "move-to-monitor-right",
4306 common_keybindings,
4307 META_KEY_BINDING_PER_WINDOW,
4308 META_KEYBINDING_ACTION_MOVE_TO_MONITOR_RIGHT,
4309 handle_move_to_monitor, META_DISPLAY_RIGHT);
4310
4311 add_builtin_keybinding (display,
4312 "move-to-monitor-down",
4313 common_keybindings,
4314 META_KEY_BINDING_PER_WINDOW,
4315 META_KEYBINDING_ACTION_MOVE_TO_MONITOR_DOWN,
4316 handle_move_to_monitor, META_DISPLAY_DOWN);
4317
4318 add_builtin_keybinding (display,
4319 "move-to-monitor-up",
4320 common_keybindings,
4321 META_KEY_BINDING_PER_WINDOW,
4322 META_KEYBINDING_ACTION_MOVE_TO_MONITOR_UP,
4323 handle_move_to_monitor, META_DISPLAY_UP);
4324
4325 add_builtin_keybinding (display,
4326 "raise-or-lower",
4327 common_keybindings,
4328 META_KEY_BINDING_PER_WINDOW |
4329 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4330 META_KEYBINDING_ACTION_RAISE_OR_LOWER,
4331 handle_raise_or_lower, 0);
4332
4333 add_builtin_keybinding (display,
4334 "raise",
4335 common_keybindings,
4336 META_KEY_BINDING_PER_WINDOW |
4337 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4338 META_KEYBINDING_ACTION_RAISE,
4339 handle_raise, 0);
4340
4341 add_builtin_keybinding (display,
4342 "lower",
4343 common_keybindings,
4344 META_KEY_BINDING_PER_WINDOW |
4345 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4346 META_KEYBINDING_ACTION_LOWER,
4347 handle_lower, 0);
4348
4349 add_builtin_keybinding (display,
4350 "maximize-vertically",
4351 common_keybindings,
4352 META_KEY_BINDING_PER_WINDOW |
4353 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4354 META_KEYBINDING_ACTION_MAXIMIZE_VERTICALLY,
4355 handle_maximize_vertically, 0);
4356
4357 add_builtin_keybinding (display,
4358 "maximize-horizontally",
4359 common_keybindings,
4360 META_KEY_BINDING_PER_WINDOW |
4361 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4362 META_KEYBINDING_ACTION_MAXIMIZE_HORIZONTALLY,
4363 handle_maximize_horizontally, 0);
4364
4365 add_builtin_keybinding (display,
4366 "always-on-top",
4367 common_keybindings,
4368 META_KEY_BINDING_PER_WINDOW |
4369 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4370 META_KEYBINDING_ACTION_ALWAYS_ON_TOP,
4371 handle_always_on_top, 0);
4372
4373 add_builtin_keybinding (display,
4374 "move-to-corner-nw",
4375 common_keybindings,
4376 META_KEY_BINDING_PER_WINDOW |
4377 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4378 META_KEYBINDING_ACTION_MOVE_TO_CORNER_NW,
4379 handle_move_to_corner_nw, 0);
4380
4381 add_builtin_keybinding (display,
4382 "move-to-corner-ne",
4383 common_keybindings,
4384 META_KEY_BINDING_PER_WINDOW |
4385 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4386 META_KEYBINDING_ACTION_MOVE_TO_CORNER_NE,
4387 handle_move_to_corner_ne, 0);
4388
4389 add_builtin_keybinding (display,
4390 "move-to-corner-sw",
4391 common_keybindings,
4392 META_KEY_BINDING_PER_WINDOW |
4393 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4394 META_KEYBINDING_ACTION_MOVE_TO_CORNER_SW,
4395 handle_move_to_corner_sw, 0);
4396
4397 add_builtin_keybinding (display,
4398 "move-to-corner-se",
4399 common_keybindings,
4400 META_KEY_BINDING_PER_WINDOW |
4401 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4402 META_KEYBINDING_ACTION_MOVE_TO_CORNER_SE,
4403 handle_move_to_corner_se, 0);
4404
4405 add_builtin_keybinding (display,
4406 "move-to-side-n",
4407 common_keybindings,
4408 META_KEY_BINDING_PER_WINDOW |
4409 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4410 META_KEYBINDING_ACTION_MOVE_TO_SIDE_N,
4411 handle_move_to_side_n, 0);
4412
4413 add_builtin_keybinding (display,
4414 "move-to-side-s",
4415 common_keybindings,
4416 META_KEY_BINDING_PER_WINDOW |
4417 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4418 META_KEYBINDING_ACTION_MOVE_TO_SIDE_S,
4419 handle_move_to_side_s, 0);
4420
4421 add_builtin_keybinding (display,
4422 "move-to-side-e",
4423 common_keybindings,
4424 META_KEY_BINDING_PER_WINDOW |
4425 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4426 META_KEYBINDING_ACTION_MOVE_TO_SIDE_E,
4427 handle_move_to_side_e, 0);
4428
4429 add_builtin_keybinding (display,
4430 "move-to-side-w",
4431 common_keybindings,
4432 META_KEY_BINDING_PER_WINDOW |
4433 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4434 META_KEYBINDING_ACTION_MOVE_TO_SIDE_W,
4435 handle_move_to_side_w, 0);
4436
4437 add_builtin_keybinding (display,
4438 "move-to-center",
4439 common_keybindings,
4440 META_KEY_BINDING_PER_WINDOW |
4441 META_KEY_BINDING_IGNORE_AUTOREPEAT,
4442 META_KEYBINDING_ACTION_MOVE_TO_CENTER,
4443 handle_move_to_center, 0);
4444
4445 g_object_unref (common_keybindings);
4446 g_object_unref (mutter_keybindings);
4447 g_object_unref (mutter_wayland_keybindings);
4448 }
4449
4450 void
meta_display_init_keys(MetaDisplay * display)4451 meta_display_init_keys (MetaDisplay *display)
4452 {
4453 MetaKeyBindingManager *keys = &display->key_binding_manager;
4454 MetaBackend *backend = meta_get_backend ();
4455 MetaKeyHandler *handler;
4456
4457 keys->backend = backend;
4458
4459 /* Keybindings */
4460 keys->ignored_modifier_mask = 0;
4461 keys->hyper_mask = 0;
4462 keys->super_mask = 0;
4463 keys->meta_mask = 0;
4464
4465 keys->key_bindings = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) meta_key_binding_free);
4466 keys->key_bindings_index = g_hash_table_new (NULL, NULL);
4467
4468 reload_modmap (keys);
4469
4470 key_handlers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
4471 (GDestroyNotify) key_handler_free);
4472
4473 handler = g_new0 (MetaKeyHandler, 1);
4474 handler->name = g_strdup ("overlay-key");
4475 handler->flags = META_KEY_BINDING_BUILTIN | META_KEY_BINDING_NO_AUTO_GRAB;
4476
4477 g_hash_table_insert (key_handlers, g_strdup (handler->name), handler);
4478
4479 handler = g_new0 (MetaKeyHandler, 1);
4480 handler->name = g_strdup ("locate-pointer-key");
4481 handler->flags = META_KEY_BINDING_BUILTIN | META_KEY_BINDING_NO_AUTO_GRAB;
4482
4483 g_hash_table_insert (key_handlers, g_strdup (handler->name), handler);
4484
4485 handler = g_new0 (MetaKeyHandler, 1);
4486 handler->name = g_strdup ("iso-next-group");
4487 handler->flags = META_KEY_BINDING_BUILTIN;
4488
4489 g_hash_table_insert (key_handlers, g_strdup (handler->name), handler);
4490
4491 handler = g_new0 (MetaKeyHandler, 1);
4492 handler->name = g_strdup ("external-grab");
4493 handler->func = handle_external_grab;
4494 handler->default_func = handle_external_grab;
4495
4496 g_hash_table_insert (key_handlers, g_strdup (handler->name), handler);
4497
4498 external_grabs = g_hash_table_new_full (g_str_hash, g_str_equal,
4499 NULL,
4500 (GDestroyNotify)meta_key_grab_free);
4501
4502 init_builtin_key_bindings (display);
4503
4504 rebuild_key_binding_table (keys);
4505 rebuild_special_bindings (keys);
4506
4507 reload_combos (keys);
4508
4509 update_window_grab_modifiers (display);
4510
4511 /* Keys are actually grabbed in meta_screen_grab_keys() */
4512
4513 meta_prefs_add_listener (prefs_changed_callback, display);
4514
4515 g_signal_connect_swapped (backend, "keymap-changed",
4516 G_CALLBACK (reload_keybindings), display);
4517 g_signal_connect_swapped (backend, "keymap-layout-group-changed",
4518 G_CALLBACK (reload_keybindings), display);
4519 }
4520