[mutter] keybindings: Add external grab API



commit a39cabfadb1d160b284ca3a17fdbf4f9e7c6d42c
Author: Florian Müllner <fmuellner gnome org>
Date:   Tue Aug 28 15:28:11 2012 +0200

    keybindings: Add external grab API
    
    During compositor grabs, all global keybindings that don't go
    through mutter's keybinding system are blocked. To allow other
    processes to make use of it, gnome-shell will expose a simple
    grab API on DBus; for this, add API to grab key combos directly
    instead of parsing accelerators stored in GSettings.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=643111

 src/core/display-private.h |    3 +
 src/core/display.c         |   18 ++++
 src/core/keybindings.c     |  196 ++++++++++++++++++++++++++++++++++++++++++--
 src/core/util.c            |    6 ++
 src/meta/display.h         |    5 +
 src/meta/util.h            |    2 +
 6 files changed, 223 insertions(+), 7 deletions(-)
---
diff --git a/src/core/display-private.h b/src/core/display-private.h
index c4abbfa..c30d312 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -460,6 +460,9 @@ void meta_display_queue_autoraise_callback  (MetaDisplay *display,
 void meta_display_remove_autoraise_callback (MetaDisplay *display);
 
 void meta_display_overlay_key_activate (MetaDisplay *display);
+void meta_display_accelerator_activate (MetaDisplay *display,
+                                        guint        action,
+                                        guint        deviceid);
 
 /* In above-tab-keycode.c */
 guint meta_display_get_above_tab_keycode (MetaDisplay *display);
diff --git a/src/core/display.c b/src/core/display.c
index b1e6543..e3bf5f6 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -138,6 +138,7 @@ G_DEFINE_TYPE(MetaDisplay, meta_display, G_TYPE_OBJECT);
 enum
 {
   OVERLAY_KEY,
+  ACCELERATOR_ACTIVATED,
   FOCUS_WINDOW,
   WINDOW_CREATED,
   WINDOW_DEMANDS_ATTENTION,
@@ -246,6 +247,14 @@ meta_display_class_init (MetaDisplayClass *klass)
                   NULL, NULL, NULL,
                   G_TYPE_NONE, 0);
 
+  display_signals[ACCELERATOR_ACTIVATED] =
+    g_signal_new ("accelerator-activated",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0,
+                  NULL, NULL, NULL,
+                  G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
+
   display_signals[WINDOW_CREATED] =
     g_signal_new ("window-created",
                   G_TYPE_FROM_CLASS (klass),
@@ -5663,6 +5672,15 @@ meta_display_overlay_key_activate (MetaDisplay *display)
 }
 
 void
+meta_display_accelerator_activate (MetaDisplay *display,
+                                   guint        action,
+                                   guint        deviceid)
+{
+  g_signal_emit (display, display_signals[ACCELERATOR_ACTIVATED],
+                 0, action, deviceid);
+}
+
+void
 meta_display_get_compositor_version (MetaDisplay *display,
                                      int         *major,
                                      int         *minor)
diff --git a/src/core/keybindings.c b/src/core/keybindings.c
index 7f6be7e..b3bb1ce 100644
--- a/src/core/keybindings.c
+++ b/src/core/keybindings.c
@@ -145,6 +145,7 @@ static void regrab_key_bindings         (MetaDisplay *display);
 
 
 static GHashTable *key_handlers;
+static GHashTable *external_grabs;
 
 #define HANDLER(name) g_hash_table_lookup (key_handlers, (name))
 
@@ -157,6 +158,22 @@ key_handler_free (MetaKeyHandler *handler)
   g_free (handler);
 }
 
+typedef struct _MetaKeyGrab MetaKeyGrab;
+struct _MetaKeyGrab {
+  char *name;
+  guint action;
+  MetaKeyCombo *combo;
+};
+
+static void
+meta_key_grab_free (MetaKeyGrab *grab)
+{
+  g_free (grab->name);
+  g_free (grab->combo);
+  g_free (grab);
+}
+
+
 static void
 reload_keymap (MetaDisplay *display)
 {
@@ -390,13 +407,14 @@ static void
 rebuild_binding_table (MetaDisplay     *display,
                        MetaKeyBinding **bindings_p,
                        int             *n_bindings_p,
-                       GList           *prefs)
+                       GList           *prefs,
+                       GList           *grabs)
 {
-  GList *p;
+  GList *p, *g;
   int n_bindings;
   int i;
 
-  n_bindings = count_bindings (prefs);
+  n_bindings = count_bindings (prefs) + g_list_length (grabs);
   g_free (*bindings_p);
   *bindings_p = g_new0 (MetaKeyBinding, n_bindings);
 
@@ -449,6 +467,27 @@ rebuild_binding_table (MetaDisplay     *display,
       p = p->next;
     }
 
+  g = grabs;
+  while (g)
+    {
+      MetaKeyGrab *grab = (MetaKeyGrab*)g->data;
+      if (grab->combo && (grab->combo->keysym != None || grab->combo->keycode != 0))
+        {
+          MetaKeyHandler *handler = HANDLER ("external-grab");
+
+          (*bindings_p)[i].name = grab->name;
+          (*bindings_p)[i].handler = handler;
+          (*bindings_p)[i].keysym = grab->combo->keysym;
+          (*bindings_p)[i].keycode = grab->combo->keycode;
+          (*bindings_p)[i].modifiers = grab->combo->modifiers;
+          (*bindings_p)[i].mask = 0;
+
+          ++i;
+        }
+
+      g = g->next;
+    }
+
   g_assert (i == n_bindings);
 
   *n_bindings_p = i;
@@ -461,17 +500,19 @@ rebuild_binding_table (MetaDisplay     *display,
 static void
 rebuild_key_binding_table (MetaDisplay *display)
 {
-  GList *prefs;
+  GList *prefs, *grabs;
 
   meta_topic (META_DEBUG_KEYBINDINGS,
               "Rebuilding key binding table from preferences\n");
 
   prefs = meta_prefs_get_keybindings ();
+  grabs = g_hash_table_get_values (external_grabs);
   rebuild_binding_table (display,
                          &display->key_bindings,
                          &display->n_key_bindings,
-                         prefs);
+                         prefs, grabs);
   g_list_free (prefs);
+  g_list_free (grabs);
 }
 
 static void
@@ -699,9 +740,17 @@ meta_display_get_keybinding_action (MetaDisplay  *display,
     binding = display_get_keybinding (display, META_KEY_ABOVE_TAB, keycode, mask);
 
   if (binding)
-    return (guint) meta_prefs_get_keybinding_action (binding->name);
+    {
+      MetaKeyGrab *grab = g_hash_table_lookup (external_grabs, binding->name);
+      if (grab)
+        return grab->action;
+      else
+        return (guint) meta_prefs_get_keybinding_action (binding->name);
+    }
   else
-    return META_KEYBINDING_ACTION_NONE;
+    {
+      return META_KEYBINDING_ACTION_NONE;
+    }
 }
 
 void
@@ -1046,6 +1095,128 @@ meta_window_ungrab_keys (MetaWindow  *window)
     }
 }
 
+static void
+handle_external_grab (MetaDisplay    *display,
+                      MetaScreen     *screen,
+                      MetaWindow     *window,
+                      XIDeviceEvent  *event,
+                      MetaKeyBinding *binding,
+                      gpointer        user_data)
+{
+  guint action = meta_display_get_keybinding_action (display,
+                                                     binding->keycode,
+                                                     binding->mask);
+  meta_display_accelerator_activate (display, action, event->deviceid);
+}
+
+
+guint
+meta_display_grab_accelerator (MetaDisplay *display,
+                               const char  *accelerator)
+{
+  MetaKeyGrab *grab;
+  guint keysym = 0;
+  guint keycode = 0;
+  guint mask = 0;
+  MetaVirtualModifier modifiers = 0;
+  GSList *l;
+  int i;
+
+  if (!meta_ui_parse_accelerator (accelerator, &keysym, &keycode, &modifiers))
+    {
+      meta_topic (META_DEBUG_KEYBINDINGS,
+                  "Failed to parse accelerator\n");
+      meta_warning (_("\"%s\" is not a valid accelerator\n"), accelerator);
+
+      return META_KEYBINDING_ACTION_NONE;
+    }
+
+  meta_display_devirtualize_modifiers (display, modifiers, &mask);
+  keycode = keysym_to_keycode (display, keysym);
+
+  if (keycode == 0)
+    return META_KEYBINDING_ACTION_NONE;
+
+  for (i = 0; i < display->n_key_bindings; i++)
+    if (display->key_bindings[i].keycode == keycode &&
+        display->key_bindings[i].mask == mask)
+      return META_KEYBINDING_ACTION_NONE;
+
+  for (l = display->screens; l; l = l->next)
+    {
+      MetaScreen *screen = l->data;
+      meta_grab_key (display, screen->xroot, keysym, keycode, mask);
+    }
+
+  grab = g_new0 (MetaKeyGrab, 1);
+  grab->action = next_dynamic_keybinding_action ();
+  grab->name = meta_external_binding_name_for_action (grab->action);
+  grab->combo = g_malloc0 (sizeof (MetaKeyCombo));
+  grab->combo->keysym = keysym;
+  grab->combo->keycode = keycode;
+  grab->combo->modifiers = modifiers;
+
+  g_hash_table_insert (external_grabs, grab->name, grab);
+
+  display->n_key_bindings++;
+  display->key_bindings = g_renew (MetaKeyBinding,
+                                   display->key_bindings,
+                                   display->n_key_bindings);
+
+  MetaKeyBinding *binding = &display->key_bindings[display->n_key_bindings - 1];
+  binding->name = grab->name;
+  binding->handler = HANDLER ("external-grab");
+  binding->keysym = grab->combo->keysym;
+  binding->keycode = grab->combo->keycode;
+  binding->modifiers = grab->combo->modifiers;
+  binding->mask = mask;
+
+  return grab->action;
+}
+
+gboolean
+meta_display_ungrab_accelerator (MetaDisplay *display,
+                                 guint        action)
+{
+  MetaKeyGrab *grab;
+  char *key;
+  int i;
+
+  g_return_val_if_fail (action != META_KEYBINDING_ACTION_NONE, FALSE);
+
+  key = meta_external_binding_name_for_action (action);
+  grab = g_hash_table_lookup (external_grabs, key);
+  if (!grab)
+    return FALSE;
+
+  for (i = 0; i < display->n_key_bindings; i++)
+    if (display->key_bindings[i].keysym == grab->combo->keysym &&
+        display->key_bindings[i].keycode == grab->combo->keycode &&
+        display->key_bindings[i].modifiers == grab->combo->modifiers)
+      {
+        GSList *l;
+        for (l = display->screens; l; l = l->next)
+          {
+            MetaScreen *screen = l->data;
+            meta_change_keygrab (display, screen->xroot, FALSE,
+                                 display->key_bindings[i].keysym,
+                                 display->key_bindings[i].keycode,
+                                 display->key_bindings[i].mask);
+          }
+
+        display->key_bindings[i].keysym = 0;
+        display->key_bindings[i].keycode = 0;
+        display->key_bindings[i].modifiers = 0;
+        display->key_bindings[i].mask = 0;
+        break;
+      }
+
+  g_hash_table_remove (external_grabs, key);
+  g_free (key);
+
+  return TRUE;
+}
+
 #ifdef WITH_VERBOSE_MODE
 static const char*
 grab_status_to_string (int status)
@@ -4335,6 +4506,17 @@ meta_display_init_keys (MetaDisplay *display)
 
   g_hash_table_insert (key_handlers, g_strdup ("overlay-key"), handler);
 
+  handler = g_new0 (MetaKeyHandler, 1);
+  handler->name = g_strdup ("external-grab");
+  handler->func = handle_external_grab;
+  handler->default_func = handle_external_grab;
+
+  g_hash_table_insert (key_handlers, g_strdup ("external-grab"), handler);
+
+  external_grabs = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                          NULL,
+                                          (GDestroyNotify)meta_key_grab_free);
+
   init_builtin_key_bindings (display);
 
   rebuild_key_binding_table (display);
diff --git a/src/core/util.c b/src/core/util.c
index 0ab87bb..a8da0d2 100644
--- a/src/core/util.c
+++ b/src/core/util.c
@@ -555,6 +555,12 @@ meta_gravity_to_string (int gravity)
     }
 }
 
+char*
+meta_external_binding_name_for_action (guint keybinding_action)
+{
+  return g_strdup_printf ("external-grab-%u", keybinding_action);
+}
+
 static gboolean
 zenity_supports_option (const char *section, const char *option)
 {
diff --git a/src/meta/display.h b/src/meta/display.h
index b922b48..9ac8d20 100644
--- a/src/meta/display.h
+++ b/src/meta/display.h
@@ -139,6 +139,11 @@ guint meta_display_add_keybinding    (MetaDisplay         *display,
 gboolean meta_display_remove_keybinding (MetaDisplay         *display,
                                          const char          *name);
 
+guint    meta_display_grab_accelerator   (MetaDisplay *display,
+                                          const char  *accelerator);
+gboolean meta_display_ungrab_accelerator (MetaDisplay *display,
+                                          guint        action_id);
+
 guint meta_display_get_keybinding_action (MetaDisplay  *display,
                                           unsigned int  keycode,
                                           unsigned long mask);
diff --git a/src/meta/util.h b/src/meta/util.h
index 04bb7bf..b34d935 100644
--- a/src/meta/util.h
+++ b/src/meta/util.h
@@ -93,6 +93,8 @@ guint meta_unsigned_long_hash  (gconstpointer v);
 const char* meta_frame_type_to_string (MetaFrameType type);
 const char* meta_gravity_to_string (int gravity);
 
+char* meta_external_binding_name_for_action (guint keybinding_action);
+
 #include <libintl.h>
 #define _(x) dgettext (GETTEXT_PACKAGE, x)
 #define N_(x) x


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