[metacity] keybindings: store keybindings dynamically



commit 179549b7cf464114bd155e787e96fc375e049386
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Wed Apr 15 14:32:00 2015 +0300

    keybindings: store keybindings dynamically
    
    Rather than defining keybindings in static arrays generated at compile
    time, store them in a hash table initialized in meta_display_init_keys()
    and filled in init_builtin_keybindings().
    
    This is a prerequisite for allowing to add/remove keybindings at runtime.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=663428
    
    Based on mutter, mostly on this commit by Florian:
    https://git.gnome.org/browse/mutter/commit/?id=d42a2a3c2741b8b44b48f83eb79a82fb4fcd5bbd

 src/Makefile.am               |    3 +-
 src/core/keybindings.c        |  859 +++++++++++++++++++++++++++++++++--------
 src/core/keybindings.h        |   31 ++-
 src/core/prefs.c              |  153 ++++----
 src/include/all-keybindings.h |  233 -----------
 src/include/prefs.h           |   74 ++++-
 src/include/types.h           |    2 +
 7 files changed, 881 insertions(+), 474 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 9663990..d1a112a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -109,8 +109,7 @@ libmetacity_private_la_SOURCES=                     \
        ui/theme-parser.h                       \
        ui/theme.c                              \
        ui/theme.h                              \
-       ui/ui.c                                 \
-       include/all-keybindings.h
+       ui/ui.c
 
 libmetacity_private_la_LDFLAGS = -no-undefined -version-info 3:0:0
 libmetacity_private_la_LIBADD  = @METACITY_LIBS@
diff --git a/src/core/keybindings.c b/src/core/keybindings.c
index f06a53c..81b0649 100644
--- a/src/core/keybindings.c
+++ b/src/core/keybindings.c
@@ -45,24 +45,17 @@
 #include <X11/XKBlib.h>
 #endif
 
+#define SCHEMA_COMMON_KEYBINDINGS "org.gnome.desktop.wm.keybindings"
+
 static gboolean all_bindings_disabled = FALSE;
 
-typedef void (* MetaKeyHandlerFunc) (MetaDisplay    *display,
-                                     MetaScreen     *screen,
-                                     MetaWindow     *window,
-                                     XEvent         *event,
-                                     MetaKeyBinding *binding);
-
-/* Prototypes for handlers */
-#define keybind(name, handler, param, flags) \
-static void \
-handler (MetaDisplay    *display,\
-         MetaScreen     *screen,\
-         MetaWindow     *window,\
-         XEvent         *event,\
-         MetaKeyBinding *binding);
-#include "all-keybindings.h"
-#undef keybind
+static gboolean add_builtin_keybinding (MetaDisplay          *display,
+                                        const char           *name,
+                                        const char           *schema,
+                                        MetaKeyBindingFlags   flags,
+                                        MetaKeyBindingAction  action,
+                                        MetaKeyHandlerFunc    handler,
+                                        int                   handler_arg);
 
 /* These can't be bound to anything, but they are used to handle
  * various other events.  TODO: Possibly we should include them as event
@@ -105,30 +98,18 @@ static gboolean process_workspace_switch_grab (MetaDisplay *display,
 
 static void regrab_key_bindings         (MetaDisplay *display);
 
-typedef struct
-{
-  const char *name;
-  MetaKeyHandlerFunc func;
-  gint data, flags;
-} MetaKeyHandler;
+static GHashTable *key_handlers;
 
-struct _MetaKeyBinding
+#define HANDLER(name) g_hash_table_lookup (key_handlers, (name))
+
+static void
+key_handler_free (MetaKeyHandler *handler)
 {
-  const char *name;
-  KeySym keysym;
-  KeyCode keycode;
-  unsigned int mask;
-  MetaVirtualModifier modifiers;
-  const MetaKeyHandler *handler;
-};
-
-#define keybind(name, handler, param, flags) \
-   { #name, handler, param, flags },
-static const MetaKeyHandler key_handlers[] = {
-#include "all-keybindings.h"
-   { NULL, NULL, 0, 0 }
-};
-#undef keybind
+  g_free (handler->name);
+  if (handler->user_data_free_func && handler->user_data)
+    handler->user_data_free_func (handler->user_data);
+  g_free (handler);
+}
 
 static void
 reload_keymap (MetaDisplay *display)
@@ -343,19 +324,18 @@ reload_modifiers (MetaDisplay *display)
     }
 }
 
-
 static int
-count_bindings (const MetaKeyPref *prefs,
-                int                n_prefs)
+count_bindings (GList *prefs)
 {
-  int i;
+  GList *p;
   int count;
 
   count = 0;
-  i = 0;
-  while (i < n_prefs)
+  p = prefs;
+  while (p)
     {
-      GSList *tmp = prefs[i].bindings;
+      MetaKeyPref *pref = (MetaKeyPref*) p->data;
+      GSList *tmp = pref->bindings;
 
       while (tmp)
         {
@@ -365,58 +345,39 @@ count_bindings (const MetaKeyPref *prefs,
             {
               count += 1;
 
-              if (prefs[i].add_shift &&
-                  (combo->modifiers & META_VIRTUAL_SHIFT_MASK) == 0)
+              if (pref->add_shift && (combo->modifiers & META_VIRTUAL_SHIFT_MASK) == 0)
                 count += 1;
             }
 
           tmp = tmp->next;
         }
 
-      ++i;
+      p = p->next;
     }
 
   return count;
 }
 
-/* FIXME: replace this with a temporary hash */
-static const MetaKeyHandler*
-find_handler (const MetaKeyHandler *handlers,
-              const char           *name)
-{
-  const MetaKeyHandler *iter;
-
-  iter = handlers;
-  while (iter->name)
-    {
-      if (strcmp (iter->name, name) == 0)
-        return iter;
-
-      ++iter;
-    }
-
-  return NULL;
-}
-
 static void
-rebuild_binding_table (MetaDisplay        *display,
-                       MetaKeyBinding    **bindings_p,
-                       int                *n_bindings_p,
-                       const MetaKeyPref  *prefs,
-                       int                 n_prefs)
+rebuild_binding_table (MetaDisplay     *display,
+                       MetaKeyBinding **bindings_p,
+                       int             *n_bindings_p,
+                       GList           *prefs)
 {
+  GList *p;
   int n_bindings;
-  int src, dest;
+  int i;
 
-  n_bindings = count_bindings (prefs, n_prefs);
+  n_bindings = count_bindings (prefs);
   g_free (*bindings_p);
   *bindings_p = g_new0 (MetaKeyBinding, n_bindings);
 
-  src = 0;
-  dest = 0;
-  while (src < n_prefs)
+  i = 0;
+  p = prefs;
+  while (p)
     {
-      GSList *tmp = prefs[src].bindings;
+      MetaKeyPref *pref = (MetaKeyPref*) p->data;
+      GSList *tmp = pref->bindings;
 
       while (tmp)
         {
@@ -424,45 +385,43 @@ rebuild_binding_table (MetaDisplay        *display,
 
           if (combo && (combo->keysym != None || combo->keycode != 0))
             {
-              const MetaKeyHandler *handler = find_handler (key_handlers, prefs[src].name);
+              MetaKeyHandler *handler = HANDLER (pref->name);
 
-              (*bindings_p)[dest].name = prefs[src].name;
-              (*bindings_p)[dest].handler = handler;
-              (*bindings_p)[dest].keysym = combo->keysym;
-              (*bindings_p)[dest].keycode = combo->keycode;
-              (*bindings_p)[dest].modifiers = combo->modifiers;
-              (*bindings_p)[dest].mask = 0;
+              (*bindings_p)[i].name = pref->name;
+              (*bindings_p)[i].handler = handler;
+              (*bindings_p)[i].keysym = combo->keysym;
+              (*bindings_p)[i].keycode = combo->keycode;
+              (*bindings_p)[i].modifiers = combo->modifiers;
+              (*bindings_p)[i].mask = 0;
 
-              ++dest;
+              ++i;
 
-              if (prefs[src].add_shift &&
-                  (combo->modifiers & META_VIRTUAL_SHIFT_MASK) == 0)
+              if (pref->add_shift && (combo->modifiers & META_VIRTUAL_SHIFT_MASK) == 0)
                 {
                   meta_topic (META_DEBUG_KEYBINDINGS,
                               "Binding %s also needs Shift grabbed\n",
-                               prefs[src].name);
+                               pref->name);
 
-                  (*bindings_p)[dest].name = prefs[src].name;
-                  (*bindings_p)[dest].handler = handler;
-                  (*bindings_p)[dest].keysym = combo->keysym;
-                  (*bindings_p)[dest].keycode = combo->keycode;
-                  (*bindings_p)[dest].modifiers = combo->modifiers |
-                    META_VIRTUAL_SHIFT_MASK;
-                  (*bindings_p)[dest].mask = 0;
+                  (*bindings_p)[i].name = pref->name;
+                  (*bindings_p)[i].handler = handler;
+                  (*bindings_p)[i].keysym = combo->keysym;
+                  (*bindings_p)[i].keycode = combo->keycode;
+                  (*bindings_p)[i].modifiers = combo->modifiers | META_VIRTUAL_SHIFT_MASK;
+                  (*bindings_p)[i].mask = 0;
 
-                  ++dest;
+                  ++i;
                 }
             }
 
           tmp = tmp->next;
         }
 
-      ++src;
+      p = p->next;
     }
 
-  g_assert (dest == n_bindings);
+  g_assert (i == n_bindings);
 
-  *n_bindings_p = dest;
+  *n_bindings_p = i;
 
   meta_topic (META_DEBUG_KEYBINDINGS,
               " %d bindings in table\n",
@@ -472,17 +431,17 @@ rebuild_binding_table (MetaDisplay        *display,
 static void
 rebuild_key_binding_table (MetaDisplay *display)
 {
-  const MetaKeyPref *prefs;
-  int n_prefs;
+  GList *prefs;
 
   meta_topic (META_DEBUG_KEYBINDINGS,
               "Rebuilding key binding table from preferences\n");
 
-  meta_prefs_get_key_bindings (&prefs, &n_prefs);
+  prefs = meta_prefs_get_keybindings ();
   rebuild_binding_table (display,
                          &display->key_bindings,
                          &display->n_key_bindings,
-                         prefs, n_prefs);
+                         prefs);
+  g_list_free (prefs);
 }
 
 static void
@@ -520,6 +479,32 @@ regrab_key_bindings (MetaDisplay *display)
   g_slist_free (windows);
 }
 
+static gboolean
+add_builtin_keybinding (MetaDisplay          *display,
+                        const char           *name,
+                        const char           *schema,
+                        MetaKeyBindingFlags   flags,
+                        MetaKeyBindingAction  action,
+                        MetaKeyHandlerFunc    func,
+                        int                   data)
+{
+  MetaKeyHandler *handler;
+
+  if (!meta_prefs_add_keybinding (name, schema, action, flags))
+    return FALSE;
+
+  handler = g_new0 (MetaKeyHandler, 1);
+  handler->name = g_strdup (name);
+  handler->func = func;
+  handler->default_func = func;
+  handler->data = data;
+  handler->flags = flags;
+
+  g_hash_table_insert (key_handlers, g_strdup (name), handler);
+
+  return TRUE;
+}
+
 static MetaKeyBindingAction
 display_get_keybinding_action (MetaDisplay  *display,
                                unsigned int  keysym,
@@ -619,55 +604,6 @@ bindings_changed_callback (MetaPreference pref,
     }
 }
 
-
-void
-meta_display_init_keys (MetaDisplay *display)
-{
-  /* Keybindings */
-  display->keymap = NULL;
-  display->keysyms_per_keycode = 0;
-  display->modmap = NULL;
-  display->min_keycode = 0;
-  display->max_keycode = 0;
-  display->ignored_modifier_mask = 0;
-  display->num_lock_mask = 0;
-  display->scroll_lock_mask = 0;
-  display->hyper_mask = 0;
-  display->super_mask = 0;
-  display->meta_mask = 0;
-  display->key_bindings = NULL;
-  display->n_key_bindings = 0;
-
-  XDisplayKeycodes (display->xdisplay,
-                    &display->min_keycode,
-                    &display->max_keycode);
-
-  meta_topic (META_DEBUG_KEYBINDINGS,
-              "Display has keycode range %d to %d\n",
-              display->min_keycode,
-              display->max_keycode);
-
-  reload_keymap (display);
-  reload_modmap (display);
-
-  rebuild_key_binding_table (display);
-
-  reload_keycodes (display);
-  reload_modifiers (display);
-
-  /* Keys are actually grabbed in meta_screen_grab_keys() */
-
-  meta_prefs_add_listener (bindings_changed_callback, display);
-
-#ifdef HAVE_XKB
-  /* meta_display_init_keys() should have already called XkbQueryExtension() */
-  if (display->xkb_base_event_type != -1)
-    XkbSelectEvents (display->xdisplay, XkbUseCoreKbd,
-                     XkbNewKeyboardNotifyMask | XkbMapNotifyMask,
-                     XkbNewKeyboardNotifyMask | XkbMapNotifyMask);
-#endif
-}
-
 void
 meta_display_shutdown_keys (MetaDisplay *display)
 {
@@ -792,7 +728,7 @@ grab_keys (MetaKeyBinding *bindings,
   while (i < n_bindings)
     {
       if (!!binding_per_window ==
-          !!(bindings[i].handler->flags & BINDING_PER_WINDOW) &&
+          !!(bindings[i].handler->flags & META_KEY_BINDING_PER_WINDOW) &&
           bindings[i].keycode != 0)
         {
           meta_grab_key (display, xwindow,
@@ -1264,7 +1200,7 @@ process_event (MetaKeyBinding       *bindings,
     {
       const MetaKeyHandler *handler = bindings[i].handler;
 
-      if ((!on_window && handler->flags & BINDING_PER_WINDOW) ||
+      if ((!on_window && handler->flags & META_KEY_BINDING_PER_WINDOW) ||
           event->type != KeyPress ||
           bindings[i].keycode != event->xkey.keycode ||
           ((event->xkey.state & 0xff & ~(display->ignored_modifier_mask)) !=
@@ -1274,7 +1210,7 @@ process_event (MetaKeyBinding       *bindings,
       /*
        * window must be non-NULL for on_window to be true,
        * and so also window must be non-NULL if we get here and
-       * this is a BINDING_PER_WINDOW binding.
+       * this is a META_KEY_BINDING_PER_WINDOW binding.
        */
 
       meta_topic (META_DEBUG_KEYBINDINGS,
@@ -1296,9 +1232,10 @@ process_event (MetaKeyBinding       *bindings,
       display->allow_terminal_deactivation = TRUE;
 
       (* handler->func) (display, screen,
-                         bindings[i].handler->flags & BINDING_PER_WINDOW? window: NULL,
+                         bindings[i].handler->flags & META_KEY_BINDING_PER_WINDOW ? window: NULL,
                          event,
-                         &bindings[i]);
+                         &bindings[i],
+                         NULL);
       return TRUE;
     }
 
@@ -2898,7 +2835,7 @@ handle_switch (MetaDisplay    *display,
                     XEvent         *event,
                     MetaKeyBinding *binding)
 {
-  gint backwards = binding->handler->flags & BINDING_IS_REVERSED;
+  gint backwards = (binding->handler->flags & META_KEY_BINDING_IS_REVERSED) != 0;
 
   do_choose_window (display, screen, event_window, event, binding,
                     backwards, TRUE);
@@ -2911,7 +2848,7 @@ handle_cycle (MetaDisplay    *display,
                     XEvent         *event,
                     MetaKeyBinding *binding)
 {
-  gint backwards = binding->handler->flags & BINDING_IS_REVERSED;
+  gint backwards = (binding->handler->flags & META_KEY_BINDING_IS_REVERSED) != 0;
 
   do_choose_window (display, screen, event_window, event, binding,
                     backwards, FALSE);
@@ -3272,3 +3209,605 @@ meta_set_keybindings_disabled (MetaDisplay *display,
   meta_topic (META_DEBUG_KEYBINDINGS,
               "Keybindings %s\n", all_bindings_disabled ? "disabled" : "enabled");
 }
+
+static void
+init_builtin_key_bindings (MetaDisplay *display)
+{
+#define REVERSES_AND_REVERSED (META_KEY_BINDING_REVERSES | \
+                               META_KEY_BINDING_IS_REVERSED)
+
+  add_builtin_keybinding (display,
+                          "switch-to-workspace-1",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_NONE,
+                          META_KEYBINDING_ACTION_WORKSPACE_1,
+                          (MetaKeyHandlerFunc) handle_switch_to_workspace, 0);
+  add_builtin_keybinding (display,
+                          "switch-to-workspace-2",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_NONE,
+                          META_KEYBINDING_ACTION_WORKSPACE_2,
+                          (MetaKeyHandlerFunc) handle_switch_to_workspace, 1);
+  add_builtin_keybinding (display,
+                          "switch-to-workspace-3",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_NONE,
+                          META_KEYBINDING_ACTION_WORKSPACE_3,
+                          (MetaKeyHandlerFunc) handle_switch_to_workspace, 2);
+  add_builtin_keybinding (display,
+                          "switch-to-workspace-4",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_NONE,
+                          META_KEYBINDING_ACTION_WORKSPACE_4,
+                          (MetaKeyHandlerFunc) handle_switch_to_workspace, 3);
+  add_builtin_keybinding (display,
+                          "switch-to-workspace-5",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_NONE,
+                          META_KEYBINDING_ACTION_WORKSPACE_5,
+                          (MetaKeyHandlerFunc) handle_switch_to_workspace, 4);
+  add_builtin_keybinding (display,
+                          "switch-to-workspace-6",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_NONE,
+                          META_KEYBINDING_ACTION_WORKSPACE_6,
+                          (MetaKeyHandlerFunc) handle_switch_to_workspace, 5);
+  add_builtin_keybinding (display,
+                          "switch-to-workspace-7",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_NONE,
+                          META_KEYBINDING_ACTION_WORKSPACE_7,
+                          (MetaKeyHandlerFunc) handle_switch_to_workspace, 6);
+  add_builtin_keybinding (display,
+                          "switch-to-workspace-8",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_NONE,
+                          META_KEYBINDING_ACTION_WORKSPACE_8,
+                          (MetaKeyHandlerFunc) handle_switch_to_workspace, 7);
+  add_builtin_keybinding (display,
+                          "switch-to-workspace-9",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_NONE,
+                          META_KEYBINDING_ACTION_WORKSPACE_9,
+                          (MetaKeyHandlerFunc) handle_switch_to_workspace, 8);
+  add_builtin_keybinding (display,
+                          "switch-to-workspace-10",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_NONE,
+                          META_KEYBINDING_ACTION_WORKSPACE_10,
+                          (MetaKeyHandlerFunc) handle_switch_to_workspace, 9);
+  add_builtin_keybinding (display,
+                          "switch-to-workspace-11",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_NONE,
+                          META_KEYBINDING_ACTION_WORKSPACE_11,
+                          (MetaKeyHandlerFunc) handle_switch_to_workspace, 10);
+  add_builtin_keybinding (display,
+                          "switch-to-workspace-12",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_NONE,
+                          META_KEYBINDING_ACTION_WORKSPACE_12,
+                          (MetaKeyHandlerFunc) handle_switch_to_workspace, 11);
+
+  add_builtin_keybinding (display,
+                          "switch-to-workspace-left",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_NONE,
+                          META_KEYBINDING_ACTION_WORKSPACE_LEFT,
+                          (MetaKeyHandlerFunc) handle_switch_to_workspace, META_MOTION_LEFT);
+
+  add_builtin_keybinding (display,
+                          "switch-to-workspace-right",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_NONE,
+                          META_KEYBINDING_ACTION_WORKSPACE_RIGHT,
+                          (MetaKeyHandlerFunc) handle_switch_to_workspace, META_MOTION_RIGHT);
+
+  add_builtin_keybinding (display,
+                          "switch-to-workspace-up",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_NONE,
+                          META_KEYBINDING_ACTION_WORKSPACE_UP,
+                          (MetaKeyHandlerFunc) handle_switch_to_workspace, META_MOTION_UP);
+
+  add_builtin_keybinding (display,
+                          "switch-to-workspace-down",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_NONE,
+                          META_KEYBINDING_ACTION_WORKSPACE_DOWN,
+                          (MetaKeyHandlerFunc) handle_switch_to_workspace, META_MOTION_DOWN);
+
+
+  /* The ones which have inverses.  These can't be bound to any keystroke
+   * containing Shift because Shift will invert their "backward" state.
+   *
+   * TODO: "NORMAL" and "DOCKS" should be renamed to the same name as their
+   * action, for obviousness.
+   *
+   * TODO: handle_switch and handle_cycle should probably really be the
+   * same function checking a bit in the parameter for difference.
+   */
+
+  add_builtin_keybinding (display,
+                          "switch-applications",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_REVERSES,
+                          META_KEYBINDING_ACTION_SWITCH_APPLICATIONS,
+                          (MetaKeyHandlerFunc) handle_switch, META_TAB_LIST_NORMAL);
+
+  add_builtin_keybinding (display,
+                          "switch-applications-backward",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          REVERSES_AND_REVERSED,
+                          META_KEYBINDING_ACTION_SWITCH_APPLICATIONS_BACKWARD,
+                          (MetaKeyHandlerFunc) handle_switch, META_TAB_LIST_NORMAL);
+
+  add_builtin_keybinding (display,
+                          "switch-group",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_REVERSES,
+                          META_KEYBINDING_ACTION_SWITCH_GROUP,
+                          (MetaKeyHandlerFunc) handle_switch, META_TAB_LIST_GROUP);
+
+  add_builtin_keybinding (display,
+                          "switch-group-backward",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          REVERSES_AND_REVERSED,
+                          META_KEYBINDING_ACTION_SWITCH_GROUP_BACKWARD,
+                          (MetaKeyHandlerFunc) handle_switch, META_TAB_LIST_GROUP);
+
+  add_builtin_keybinding (display,
+                          "switch-windows",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_REVERSES,
+                          META_KEYBINDING_ACTION_SWITCH_WINDOWS,
+                          (MetaKeyHandlerFunc) handle_switch, META_TAB_LIST_NORMAL);
+
+  add_builtin_keybinding (display,
+                          "switch-windows-backward",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          REVERSES_AND_REVERSED,
+                          META_KEYBINDING_ACTION_SWITCH_WINDOWS_BACKWARD,
+                          (MetaKeyHandlerFunc) handle_switch, META_TAB_LIST_NORMAL);
+
+  add_builtin_keybinding (display,
+                          "switch-panels",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_REVERSES,
+                          META_KEYBINDING_ACTION_SWITCH_PANELS,
+                          (MetaKeyHandlerFunc) handle_switch, META_TAB_LIST_DOCKS);
+
+  add_builtin_keybinding (display,
+                          "switch-panels-backward",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          REVERSES_AND_REVERSED,
+                          META_KEYBINDING_ACTION_SWITCH_PANELS_BACKWARD,
+                          (MetaKeyHandlerFunc) handle_switch, META_TAB_LIST_DOCKS);
+
+  add_builtin_keybinding (display,
+                          "cycle-group",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_REVERSES,
+                          META_KEYBINDING_ACTION_CYCLE_GROUP,
+                          (MetaKeyHandlerFunc) handle_cycle, META_TAB_LIST_GROUP);
+
+  add_builtin_keybinding (display,
+                          "cycle-group-backward",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          REVERSES_AND_REVERSED,
+                          META_KEYBINDING_ACTION_CYCLE_GROUP_BACKWARD,
+                          (MetaKeyHandlerFunc) handle_cycle, META_TAB_LIST_GROUP);
+
+  add_builtin_keybinding (display,
+                          "cycle-windows",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_REVERSES,
+                          META_KEYBINDING_ACTION_CYCLE_WINDOWS,
+                          (MetaKeyHandlerFunc) handle_cycle, META_TAB_LIST_NORMAL);
+
+  add_builtin_keybinding (display,
+                          "cycle-windows-backward",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          REVERSES_AND_REVERSED,
+                          META_KEYBINDING_ACTION_CYCLE_WINDOWS_BACKWARD,
+                          (MetaKeyHandlerFunc) handle_cycle, META_TAB_LIST_NORMAL);
+
+  add_builtin_keybinding (display,
+                          "cycle-panels",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_REVERSES,
+                          META_KEYBINDING_ACTION_CYCLE_PANELS,
+                          (MetaKeyHandlerFunc) handle_cycle, META_TAB_LIST_DOCKS);
+
+  add_builtin_keybinding (display,
+                          "cycle-panels-backward",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          REVERSES_AND_REVERSED,
+                          META_KEYBINDING_ACTION_CYCLE_PANELS_BACKWARD,
+                          (MetaKeyHandlerFunc) handle_cycle, META_TAB_LIST_DOCKS);
+
+
+/***********************************/
+
+  add_builtin_keybinding (display,
+                          "show-desktop",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_NONE,
+                          META_KEYBINDING_ACTION_SHOW_DESKTOP,
+                          (MetaKeyHandlerFunc) handle_show_desktop, 0);
+
+  add_builtin_keybinding (display,
+                          "panel-main-menu",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_NONE,
+                          META_KEYBINDING_ACTION_PANEL_MAIN_MENU,
+                          (MetaKeyHandlerFunc) handle_panel, META_KEYBINDING_ACTION_PANEL_MAIN_MENU);
+
+  add_builtin_keybinding (display,
+                          "panel-run-dialog",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_NONE,
+                          META_KEYBINDING_ACTION_PANEL_RUN_DIALOG,
+                          (MetaKeyHandlerFunc) handle_panel, META_KEYBINDING_ACTION_PANEL_RUN_DIALOG);
+
+  add_builtin_keybinding (display,
+                          "set-spew-mark",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_NONE,
+                          META_KEYBINDING_ACTION_SET_SPEW_MARK,
+                          (MetaKeyHandlerFunc) handle_set_spew_mark, 0);
+
+#undef REVERSES_AND_REVERSED
+
+/************************ PER WINDOW BINDINGS ************************/
+
+/* These take a window as an extra parameter; they have no effect
+ * if no window is active.
+ */
+
+  add_builtin_keybinding (display,
+                          "activate-window-menu",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_ACTIVATE_WINDOW_MENU,
+                          (MetaKeyHandlerFunc) handle_activate_window_menu, 0);
+
+  add_builtin_keybinding (display,
+                          "toggle-fullscreen",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_TOGGLE_FULLSCREEN,
+                          (MetaKeyHandlerFunc) handle_toggle_fullscreen, 0);
+
+  add_builtin_keybinding (display,
+                          "toggle-maximized",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_TOGGLE_MAXIMIZED,
+                          (MetaKeyHandlerFunc) handle_toggle_maximized, 0);
+
+  add_builtin_keybinding (display,
+                          "toggle-above",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_TOGGLE_ABOVE,
+                          (MetaKeyHandlerFunc) handle_toggle_above, 0);
+
+  add_builtin_keybinding (display,
+                          "maximize",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MAXIMIZE,
+                          (MetaKeyHandlerFunc) handle_maximize, 0);
+
+  add_builtin_keybinding (display,
+                          "unmaximize",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_UNMAXIMIZE,
+                          (MetaKeyHandlerFunc) handle_unmaximize, 0);
+
+  add_builtin_keybinding (display,
+                          "toggle-shaded",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_TOGGLE_SHADED,
+                          (MetaKeyHandlerFunc) handle_toggle_shaded, 0);
+
+  add_builtin_keybinding (display,
+                          "minimize",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MINIMIZE,
+                          (MetaKeyHandlerFunc) handle_minimize, 0);
+
+  add_builtin_keybinding (display,
+                          "close",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_CLOSE,
+                          (MetaKeyHandlerFunc) handle_close, 0);
+
+  add_builtin_keybinding (display,
+                          "begin-move",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_BEGIN_MOVE,
+                          (MetaKeyHandlerFunc) handle_begin_move, 0);
+
+  add_builtin_keybinding (display,
+                          "begin-resize",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_BEGIN_RESIZE,
+                          (MetaKeyHandlerFunc) handle_begin_resize, 0);
+
+  add_builtin_keybinding (display,
+                          "toggle-on-all-workspaces",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_TOGGLE_ON_ALL_WORKSPACES,
+                          (MetaKeyHandlerFunc) handle_toggle_on_all_workspaces, 0);
+
+  add_builtin_keybinding (display,
+                          "move-to-workspace-1",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_1,
+                          (MetaKeyHandlerFunc) handle_move_to_workspace, 0);
+
+  add_builtin_keybinding (display,
+                          "move-to-workspace-2",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_2,
+                          (MetaKeyHandlerFunc) handle_move_to_workspace, 1);
+
+  add_builtin_keybinding (display,
+                          "move-to-workspace-3",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_3,
+                          (MetaKeyHandlerFunc) handle_move_to_workspace, 2);
+
+  add_builtin_keybinding (display,
+                          "move-to-workspace-4",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_4,
+                          (MetaKeyHandlerFunc) handle_move_to_workspace, 3);
+
+  add_builtin_keybinding (display,
+                          "move-to-workspace-5",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_5,
+                          (MetaKeyHandlerFunc) handle_move_to_workspace, 4);
+
+  add_builtin_keybinding (display,
+                          "move-to-workspace-6",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_6,
+                          (MetaKeyHandlerFunc) handle_move_to_workspace, 5);
+
+  add_builtin_keybinding (display,
+                          "move-to-workspace-7",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_7,
+                          (MetaKeyHandlerFunc) handle_move_to_workspace, 6);
+
+  add_builtin_keybinding (display,
+                          "move-to-workspace-8",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_8,
+                          (MetaKeyHandlerFunc) handle_move_to_workspace, 7);
+
+  add_builtin_keybinding (display,
+                          "move-to-workspace-9",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_9,
+                          (MetaKeyHandlerFunc) handle_move_to_workspace, 8);
+
+  add_builtin_keybinding (display,
+                          "move-to-workspace-10",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_10,
+                          (MetaKeyHandlerFunc) handle_move_to_workspace, 9);
+
+  add_builtin_keybinding (display,
+                          "move-to-workspace-11",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_11,
+                          (MetaKeyHandlerFunc) handle_move_to_workspace, 10);
+
+  add_builtin_keybinding (display,
+                          "move-to-workspace-12",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_12,
+                          (MetaKeyHandlerFunc) handle_move_to_workspace, 11);
+
+  add_builtin_keybinding (display,
+                          "move-to-workspace-left",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_LEFT,
+                          (MetaKeyHandlerFunc) handle_move_to_workspace, META_MOTION_LEFT);
+
+  add_builtin_keybinding (display,
+                          "move-to-workspace-right",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_RIGHT,
+                          (MetaKeyHandlerFunc) handle_move_to_workspace, META_MOTION_RIGHT);
+
+  add_builtin_keybinding (display,
+                          "move-to-workspace-up",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_UP,
+                          (MetaKeyHandlerFunc) handle_move_to_workspace, META_MOTION_UP);
+
+  add_builtin_keybinding (display,
+                          "move-to-workspace-down",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_DOWN,
+                          (MetaKeyHandlerFunc) handle_move_to_workspace, META_MOTION_DOWN);
+
+  add_builtin_keybinding (display,
+                          "raise-or-lower",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_RAISE_OR_LOWER,
+                          (MetaKeyHandlerFunc) handle_raise_or_lower, 0);
+
+  add_builtin_keybinding (display,
+                          "raise",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_RAISE,
+                          (MetaKeyHandlerFunc) handle_raise, 0);
+
+  add_builtin_keybinding (display,
+                          "lower",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_LOWER,
+                          (MetaKeyHandlerFunc) handle_lower, 0);
+
+  add_builtin_keybinding (display,
+                          "maximize-vertically",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MAXIMIZE_VERTICALLY,
+                          (MetaKeyHandlerFunc) handle_maximize_vertically, 0);
+
+  add_builtin_keybinding (display,
+                          "maximize-horizontally",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MAXIMIZE_HORIZONTALLY,
+                          (MetaKeyHandlerFunc) handle_maximize_horizontally, 0);
+
+  add_builtin_keybinding (display,
+                          "move-to-corner-nw",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_CORNER_NW,
+                          (MetaKeyHandlerFunc) handle_move_to_corner_nw, 0);
+
+  add_builtin_keybinding (display,
+                          "move-to-corner-ne",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_CORNER_NE,
+                          (MetaKeyHandlerFunc) handle_move_to_corner_ne, 0);
+
+  add_builtin_keybinding (display,
+                          "move-to-corner-sw",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_CORNER_SW,
+                          (MetaKeyHandlerFunc) handle_move_to_corner_sw, 0);
+
+  add_builtin_keybinding (display,
+                          "move-to-corner-se",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_CORNER_SE,
+                          (MetaKeyHandlerFunc) handle_move_to_corner_se, 0);
+
+  add_builtin_keybinding (display,
+                          "move-to-side-n",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_SIDE_N,
+                          (MetaKeyHandlerFunc) handle_move_to_side_n, 0);
+
+  add_builtin_keybinding (display,
+                          "move-to-side-s",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_SIDE_S,
+                          (MetaKeyHandlerFunc) handle_move_to_side_s, 0);
+
+  add_builtin_keybinding (display,
+                          "move-to-side-e",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_SIDE_E,
+                          (MetaKeyHandlerFunc) handle_move_to_side_e, 0);
+
+  add_builtin_keybinding (display,
+                          "move-to-side-w",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_SIDE_W,
+                          (MetaKeyHandlerFunc) handle_move_to_side_w, 0);
+
+  add_builtin_keybinding (display,
+                          "move-to-center",
+                          SCHEMA_COMMON_KEYBINDINGS,
+                          META_KEY_BINDING_PER_WINDOW,
+                          META_KEYBINDING_ACTION_MOVE_TO_CENTER,
+                          (MetaKeyHandlerFunc) handle_move_to_center, 0);
+}
+
+void
+meta_display_init_keys (MetaDisplay *display)
+{
+  /* Keybindings */
+  display->keymap = NULL;
+  display->keysyms_per_keycode = 0;
+  display->modmap = NULL;
+  display->min_keycode = 0;
+  display->max_keycode = 0;
+  display->ignored_modifier_mask = 0;
+  display->num_lock_mask = 0;
+  display->scroll_lock_mask = 0;
+  display->hyper_mask = 0;
+  display->super_mask = 0;
+  display->meta_mask = 0;
+  display->key_bindings = NULL;
+  display->n_key_bindings = 0;
+
+  XDisplayKeycodes (display->xdisplay,
+                    &display->min_keycode,
+                    &display->max_keycode);
+
+  meta_topic (META_DEBUG_KEYBINDINGS,
+              "Display has keycode range %d to %d\n",
+              display->min_keycode,
+              display->max_keycode);
+
+  reload_keymap (display);
+  reload_modmap (display);
+
+  key_handlers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
+                                        (GDestroyNotify) key_handler_free);
+  init_builtin_key_bindings (display);
+
+  rebuild_key_binding_table (display);
+
+  reload_keycodes (display);
+  reload_modifiers (display);
+
+  /* Keys are actually grabbed in meta_screen_grab_keys() */
+
+  meta_prefs_add_listener (bindings_changed_callback, display);
+
+#ifdef HAVE_XKB
+  /* meta_display_init_keys() should have already called XkbQueryExtension() */
+  if (display->xkb_base_event_type != -1)
+    XkbSelectEvents (display->xdisplay, XkbUseCoreKbd,
+                     XkbNewKeyboardNotifyMask | XkbMapNotifyMask,
+                     XkbNewKeyboardNotifyMask | XkbMapNotifyMask);
+#endif
+}
diff --git a/src/core/keybindings.h b/src/core/keybindings.h
index d1078bd..5e38af5 100644
--- a/src/core/keybindings.h
+++ b/src/core/keybindings.h
@@ -29,6 +29,28 @@
 
 #include "display-private.h"
 #include "window.h"
+#include "prefs.h"
+
+struct _MetaKeyHandler
+{
+  char               *name;
+  MetaKeyHandlerFunc  func;
+  MetaKeyHandlerFunc  default_func;
+  gint                data;
+  gint                flags;
+  gpointer            user_data;
+  GDestroyNotify      user_data_free_func;
+};
+
+struct _MetaKeyBinding
+{
+  const char          *name;
+  KeySym               keysym;
+  KeyCode              keycode;
+  unsigned int         mask;
+  MetaVirtualModifier  modifiers;
+  MetaKeyHandler      *handler;
+};
 
 void     meta_display_init_keys             (MetaDisplay *display);
 void     meta_display_shutdown_keys         (MetaDisplay *display);
@@ -52,8 +74,9 @@ void     meta_set_keybindings_disabled      (MetaDisplay *display,
 void     meta_display_process_mapping_event (MetaDisplay *display,
                                              XEvent      *event);
 
-#endif
-
-
-
+gboolean meta_prefs_add_keybinding          (const char           *name,
+                                             const char           *schema,
+                                             MetaKeyBindingAction  action,
+                                             MetaKeyBindingFlags   flags);
 
+#endif
diff --git a/src/core/prefs.c b/src/core/prefs.c
index e95249d..bad0418 100644
--- a/src/core/prefs.c
+++ b/src/core/prefs.c
@@ -30,6 +30,7 @@
 #include <gio/gio.h>
 #include <string.h>
 #include <stdlib.h>
+#include "keybindings.h"
 
 /* If you add a key, it needs updating in init() and in the gsettings
  * notify listener and of course in the .schemas file.
@@ -55,7 +56,6 @@
 #define SCHEMA_GENERAL         "org.gnome.desktop.wm.preferences"
 #define SCHEMA_METACITY        "org.gnome.metacity"
 #define SCHEMA_INTERFACE       "org.gnome.desktop.interface"
-#define SCHEMA_BINDINGS        "org.gnome.desktop.wm.keybindings"
 
 #define SETTINGS(s) g_hash_table_lookup (settings_schemas, (s))
 
@@ -791,15 +791,7 @@ meta_prefs_init (void)
                     G_CALLBACK (settings_changed), NULL);
   g_hash_table_insert (settings_schemas, SCHEMA_INTERFACE, settings);
 
-  /* Bindings have a separate handler, since they are in separate schemas
-   * and work differently */
-  settings = g_settings_new (SCHEMA_BINDINGS);
-  g_signal_connect (settings, "changed", G_CALLBACK (bindings_changed), NULL);
-  g_hash_table_insert (settings_schemas, SCHEMA_BINDINGS, settings);
-
-
   /* Pick up initial values. */
-
   handle_preference_init_enum ();
   handle_preference_init_bool ();
   handle_preference_init_string ();
@@ -1449,29 +1441,24 @@ meta_prefs_set_num_workspaces (int n_workspaces)
                       n_workspaces);
 }
 
-#define keybind(name, handler, param, flags) \
-  { #name, NULL, !!(flags & BINDING_REVERSES), !!(flags & BINDING_PER_WINDOW) },
-static MetaKeyPref key_bindings[] = {
-#include "all-keybindings.h"
-  { NULL, NULL, FALSE }
-};
-#undef keybind
-
+static GHashTable *key_bindings;
 
 static void
-init_bindings (void)
+meta_key_pref_free (MetaKeyPref *pref)
 {
-  int i;
-  gchar **strokes;
+  update_binding (pref, NULL);
 
-  for (i = 0; key_bindings[i].name; i++)
-    {
-      strokes = g_settings_get_strv (SETTINGS (SCHEMA_BINDINGS),
-                                     key_bindings[i].name);
-      update_key_binding (key_bindings[i].name, strokes);
+  g_free (pref->name);
+  g_free (pref->schema);
 
-      g_strfreev (strokes);
-    }
+  g_free (pref);
+}
+
+static void
+init_bindings (void)
+{
+  key_bindings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
+                                        (GDestroyNotify) meta_key_pref_free);
 }
 
 static void
@@ -1558,15 +1545,10 @@ static gboolean
 update_key_binding (const char *key,
                     gchar     **strokes)
 {
-  int i;
-
-  i = 0;
-  while (key_bindings[i].name &&
-         strcmp (key, key_bindings[i].name) != 0)
-    i++;
+  MetaKeyPref *pref = g_hash_table_lookup (key_bindings, key);
 
-  if (key_bindings[i].name)
-    return update_binding (&key_bindings[i], strokes);
+  if (pref)
+    return update_binding (pref, strokes);
   else
     return FALSE;
 }
@@ -1703,13 +1685,56 @@ meta_prefs_get_visual_bell_type (void)
   return visual_bell_type;
 }
 
-void
-meta_prefs_get_key_bindings (const MetaKeyPref **bindings,
-                                int                *n_bindings)
+gboolean
+meta_prefs_add_keybinding (const char           *name,
+                           const char           *schema,
+                           MetaKeyBindingAction  action,
+                           MetaKeyBindingFlags   flags)
 {
+  MetaKeyPref  *pref;
+  GSettings    *settings;
+  char        **strokes;
 
-  *bindings = key_bindings;
-  *n_bindings = (int) G_N_ELEMENTS (key_bindings) - 1;
+  if (g_hash_table_lookup (key_bindings, name))
+    {
+      meta_warning ("Trying to re-add keybinding \"%s\".\n", name);
+      return FALSE;
+    }
+
+  settings = SETTINGS (schema);
+  if (settings == NULL)
+    {
+      settings = g_settings_new (schema);
+      g_signal_connect (settings, "changed",
+                        G_CALLBACK (bindings_changed), NULL);
+      g_hash_table_insert (settings_schemas, g_strdup (schema), settings);
+    }
+
+  pref = g_new0 (MetaKeyPref, 1);
+  pref->name = g_strdup (name);
+  pref->schema = g_strdup (schema);
+  pref->action = action;
+  pref->bindings = NULL;
+  pref->add_shift = (flags & META_KEY_BINDING_REVERSES) != 0;
+  pref->per_window = (flags & META_KEY_BINDING_PER_WINDOW) != 0;
+
+  strokes = g_settings_get_strv (settings, name);
+  update_binding (pref, strokes);
+  g_strfreev (strokes);
+
+  g_hash_table_insert (key_bindings, g_strdup (name), pref);
+
+  return TRUE;
+}
+
+/**
+ * meta_prefs_get_keybindings: (skip)
+ * Return: (element-type MetaKeyPref) (transfer container):
+ */
+GList *
+meta_prefs_get_keybindings ()
+{
+  return g_hash_table_get_values (key_bindings);
 }
 
 GDesktopTitlebarAction
@@ -1769,18 +1794,9 @@ meta_prefs_get_edge_tiling ()
 MetaKeyBindingAction
 meta_prefs_get_keybinding_action (const char *name)
 {
-  int i;
+  MetaKeyPref *pref = g_hash_table_lookup (key_bindings, name);
 
-  i = G_N_ELEMENTS (key_bindings) - 2; /* -2 for dummy entry at end */
-  while (i >= 0)
-    {
-      if (strcmp (key_bindings[i].name, name) == 0)
-        return (MetaKeyBindingAction) i;
-
-      --i;
-    }
-
-  return META_KEYBINDING_ACTION_NONE;
+  return pref ? pref->action : META_KEYBINDING_ACTION_NONE;
 }
 
 /* This is used by the menu system to decide what key binding
@@ -1792,36 +1808,29 @@ meta_prefs_get_window_binding (const char          *name,
                                unsigned int        *keysym,
                                MetaVirtualModifier *modifiers)
 {
-  int i;
+  MetaKeyPref *pref = g_hash_table_lookup (key_bindings, name);
 
-  i = G_N_ELEMENTS (key_bindings) - 2; /* -2 for dummy entry at end */
-  while (i >= 0)
+  if (pref->per_window)
     {
-      if (key_bindings[i].per_window &&
-          strcmp (key_bindings[i].name, name) == 0)
+      GSList *s = pref->bindings;
+
+      while (s)
         {
-          GSList *s = key_bindings[i].bindings;
+          MetaKeyCombo *c = s->data;
 
-          while (s)
+          if (c->keysym != 0 || c->modifiers != 0)
             {
-              MetaKeyCombo *c = s->data;
-
-              if (c->keysym!=0 || c->modifiers!=0)
-                {
-                  *keysym = c->keysym;
-                  *modifiers = c->modifiers;
-                  return;
-                }
-
-              s = s->next;
+              *keysym = c->keysym;
+              *modifiers = c->modifiers;
+              return;
             }
 
-          /* Not found; return the disabled value */
-          *keysym = *modifiers = 0;
-          return;
+          s = s->next;
         }
 
-      --i;
+      /* Not found; return the disabled value */
+      *keysym = *modifiers = 0;
+      return;
     }
 
   g_assert_not_reached ();
diff --git a/src/include/prefs.h b/src/include/prefs.h
index b03557e..6ce6fd3 100644
--- a/src/include/prefs.h
+++ b/src/include/prefs.h
@@ -25,6 +25,7 @@
 
 /* This header is a "common" one between the UI and core side */
 #include "common.h"
+#include "types.h"
 #include <pango/pango-font.h>
 #include <gdesktop-enums.h>
 
@@ -181,8 +182,59 @@ typedef enum _MetaKeyBindingAction
   META_KEYBINDING_ACTION_SHOW_DESKTOP,
   META_KEYBINDING_ACTION_PANEL_MAIN_MENU,
   META_KEYBINDING_ACTION_PANEL_RUN_DIALOG,
+  META_KEYBINDING_ACTION_SET_SPEW_MARK,
+  META_KEYBINDING_ACTION_ACTIVATE_WINDOW_MENU,
+  META_KEYBINDING_ACTION_TOGGLE_FULLSCREEN,
+  META_KEYBINDING_ACTION_TOGGLE_MAXIMIZED,
+  META_KEYBINDING_ACTION_TOGGLE_ABOVE,
+  META_KEYBINDING_ACTION_MAXIMIZE,
+  META_KEYBINDING_ACTION_UNMAXIMIZE,
+  META_KEYBINDING_ACTION_TOGGLE_SHADED,
+  META_KEYBINDING_ACTION_MINIMIZE,
+  META_KEYBINDING_ACTION_CLOSE,
+  META_KEYBINDING_ACTION_BEGIN_MOVE,
+  META_KEYBINDING_ACTION_BEGIN_RESIZE,
+  META_KEYBINDING_ACTION_TOGGLE_ON_ALL_WORKSPACES,
+  META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_1,
+  META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_2,
+  META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_3,
+  META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_4,
+  META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_5,
+  META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_6,
+  META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_7,
+  META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_8,
+  META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_9,
+  META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_10,
+  META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_11,
+  META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_12,
+  META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_LEFT,
+  META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_RIGHT,
+  META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_UP,
+  META_KEYBINDING_ACTION_MOVE_TO_WORKSPACE_DOWN,
+  META_KEYBINDING_ACTION_RAISE_OR_LOWER,
+  META_KEYBINDING_ACTION_RAISE,
+  META_KEYBINDING_ACTION_LOWER,
+  META_KEYBINDING_ACTION_MAXIMIZE_VERTICALLY,
+  META_KEYBINDING_ACTION_MAXIMIZE_HORIZONTALLY,
+  META_KEYBINDING_ACTION_MOVE_TO_CORNER_NW,
+  META_KEYBINDING_ACTION_MOVE_TO_CORNER_NE,
+  META_KEYBINDING_ACTION_MOVE_TO_CORNER_SW,
+  META_KEYBINDING_ACTION_MOVE_TO_CORNER_SE,
+  META_KEYBINDING_ACTION_MOVE_TO_SIDE_N,
+  META_KEYBINDING_ACTION_MOVE_TO_SIDE_S,
+  META_KEYBINDING_ACTION_MOVE_TO_SIDE_E,
+  META_KEYBINDING_ACTION_MOVE_TO_SIDE_W,
+  META_KEYBINDING_ACTION_MOVE_TO_CENTER,
 } MetaKeyBindingAction;
 
+typedef enum
+{
+  META_KEY_BINDING_NONE,
+  META_KEY_BINDING_PER_WINDOW  = 1 << 0,
+  META_KEY_BINDING_REVERSES    = 1 << 1,
+  META_KEY_BINDING_IS_REVERSED = 1 << 2
+} MetaKeyBindingFlags;
+
 typedef struct
 {
   unsigned int keysym;
@@ -190,9 +242,26 @@ typedef struct
   MetaVirtualModifier modifiers;
 } MetaKeyCombo;
 
+/**
+ * MetaKeyHandlerFunc: (skip)
+ *
+ */
+typedef void (* MetaKeyHandlerFunc) (MetaDisplay    *display,
+                                     MetaScreen     *screen,
+                                     MetaWindow     *window,
+                                     XEvent         *event,
+                                     MetaKeyBinding *binding,
+                                     gpointer        user_data);
+
+typedef struct _MetaKeyHandler MetaKeyHandler;
+
 typedef struct
 {
-  const char   *name;
+  char *name;
+  char *schema;
+
+  MetaKeyBindingAction action;
+
   /**
    * A list of MetaKeyCombos. Each of them is bound to
    * this keypref. If one has keysym==modifiers==0, it is
@@ -209,8 +278,7 @@ typedef struct
   gboolean      per_window:1;
 } MetaKeyPref;
 
-void meta_prefs_get_key_bindings (const MetaKeyPref **bindings,
-                                  int                *n_bindings);
+GList *meta_prefs_get_keybindings (void);
 
 MetaKeyBindingAction meta_prefs_get_keybinding_action (const char *name);
 
diff --git a/src/include/types.h b/src/include/types.h
index 738521a..a779a1f 100644
--- a/src/include/types.h
+++ b/src/include/types.h
@@ -26,4 +26,6 @@ typedef struct _MetaFrame       MetaFrame;
 typedef struct _MetaScreen      MetaScreen;
 typedef struct _MetaWindow      MetaWindow;
 
+typedef struct _MetaKeyBinding  MetaKeyBinding;
+
 #endif


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]