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 "&lt;Control&gt;a" or "&lt;Shift&gt;&lt;Alt&gt;F1". The parser
1017  * is fairly liberal and allows lower or upper case, and also abbreviations
1018  * such as "&lt;Ctl&gt;" and "&lt;Ctrl&gt;". 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