[gnome-settings-daemon/wip/benzea/multiple-keybindings: 10/15] media-keys: Make internal keybindings to be lists



commit 44f53c64c5a2514d2c022bcb1596a9e46f1df51c
Author: Benjamin Berg <bberg redhat com>
Date:   Wed Feb 6 16:57:20 2019 +0100

    media-keys: Make internal keybindings to be lists
    
    This will allow us moving all the keybindings into gsettings and also
    allows users to override keybindings when desired.
    
    If a keybinding is for a "hardware" key, then we add a dummy first
    entry. This allows users to define a further keybinding in g-c-c while
    keeping the hardware key functional.
    
    Note that we are not allowing multiple keybindings for custom
    keybindings for now.
    
    When migrating, any overriden keybinding is inserted into the first
    slot of the default value. This means that for e.g. the audio keys we
    are re-adding the hardware button. This could potentially create
    collisions if the user changed the default binding *and* assigned the
    hardware button to another purpose. Unfortunately, users will need to
    correct this manually.

 ...ttings-daemon.plugins.media-keys.gschema.xml.in | 190 ++++++++++++++++++++-
 plugins/media-keys/gsd-media-keys-manager.c        | 151 +++++++++++++---
 2 files changed, 315 insertions(+), 26 deletions(-)
---
diff --git a/data/org.gnome.settings-daemon.plugins.media-keys.gschema.xml.in 
b/data/org.gnome.settings-daemon.plugins.media-keys.gschema.xml.in
index 089b8610..619cdd40 100644
--- a/data/org.gnome.settings-daemon.plugins.media-keys.gschema.xml.in
+++ b/data/org.gnome.settings-daemon.plugins.media-keys.gschema.xml.in
@@ -1,11 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <schemalist>
-  <schema gettext-domain="@GETTEXT_PACKAGE@" id="org.gnome.settings-daemon.plugins.media-keys" 
path="/org/gnome/settings-daemon/plugins/media-keys/">
-    <key name="custom-keybindings" type="as">
-      <default>[]</default>
-      <summary>Custom keybindings</summary>
-      <description>List of custom keybindings</description>
-    </key>
+  <schema gettext-domain="@GETTEXT_PACKAGE@" id="org.gnome.settings-daemon.plugins.media-keys.deprecated">
     <key name="calculator" type="s">
       <default>'XF86Calculator'</default>
       <summary>Launch calculator</summary>
@@ -181,6 +176,189 @@
       <summary>Magnifier zoom out</summary>
       <description>Binding for the magnifier to zoom out</description>
     </key>
+  </schema>
+
+  <schema gettext-domain="@GETTEXT_PACKAGE@" id="org.gnome.settings-daemon.plugins.media-keys" 
path="/org/gnome/settings-daemon/plugins/media-keys/">
+    <key name="custom-keybindings" type="as">
+      <default>[]</default>
+      <summary>Custom keybindings</summary>
+      <description>List of custom keybindings</description>
+    </key>
+    <key name="calculator" type="as">
+      <default>['', 'XF86Calculator']</default>
+      <summary>Launch calculator</summary>
+      <description>Binding to launch the calculator.</description>
+    </key>
+    <key name="control-center" type="as">
+      <default>['', 'XF86Tools']</default>
+      <summary>Launch settings</summary>
+      <description>Binding to launch GNOME settings.</description>
+    </key>
+    <key name="email" type="as">
+      <default>['', 'XF86Mail']</default>
+      <summary>Launch email client</summary>
+      <description>Binding to launch the email client.</description>
+    </key>
+    <key name="eject" type="as">
+      <default>['', 'XF86Eject']</default>
+      <summary>Eject</summary>
+      <description>Binding to eject an optical disc.</description>
+    </key>
+    <key name="help" type="as">
+      <default>['']</default>
+      <summary>Launch help browser</summary>
+      <description>Binding to launch the help browser.</description>
+    </key>
+    <key name="home" type="as">
+      <default>['', 'XF86Explorer']</default>
+      <summary>Home folder</summary>
+      <description>Binding to open the Home folder.</description>
+    </key>
+    <key name="media" type="as">
+      <default>['', 'XF86AudioMedia']</default>
+      <summary>Launch media player</summary>
+      <description>Binding to launch the media player.</description>
+    </key>
+    <key name="next" type="as">
+      <default>['', 'XF86AudioNext']</default>
+      <summary>Next track</summary>
+      <description>Binding to skip to next track.</description>
+    </key>
+    <key name="pause" type="as">
+      <default>['', 'XF86AudioPause']</default>
+      <summary>Pause playback</summary>
+      <description>Binding to pause playback.</description>
+    </key>
+    <key name="play" type="as">
+      <default>['', 'XF86AudioPlay']</default>
+      <summary>Play (or play/pause)</summary>
+      <description>Binding to start playback (or toggle play/pause).</description>
+    </key>
+    <key name="logout" type="as">
+      <default>['&lt;Control&gt;&lt;Alt&gt;Delete']</default>
+      <summary>Log out</summary>
+      <description>Binding to log out.</description>
+    </key>
+    <key name="previous" type="as">
+      <default>['', 'XF86AudioPrev']</default>
+      <summary>Previous track</summary>
+      <description>Binding to skip to previous track.</description>
+    </key>
+    <key name="screensaver" type="as">
+      <default>['&lt;Super&gt;l']</default>
+      <summary>Lock screen</summary>
+      <description>Binding to lock the screen.</description>
+    </key>
+    <key name="search" type="as">
+      <default>['XF86Search']</default>
+      <summary>Search</summary>
+      <description>Binding to launch the search tool.</description>
+    </key>
+    <key name="stop" type="as">
+      <default>['', 'XF86AudioStop']</default>
+      <summary>Stop playback</summary>
+      <description>Binding to stop playback.</description>
+    </key>
+    <key name="volume-down" type="as">
+      <default>['', 'XF86AudioLowerVolume']</default>
+      <summary>Volume down</summary>
+      <description>Binding to lower the volume.</description>
+    </key>
+    <key name="volume-mute" type="as">
+      <default>['', 'XF86AudioMute']</default>
+      <summary>Volume mute/unmute</summary>
+      <description>Binding to mute/unmute the volume.</description>
+    </key>
+    <key name="volume-up" type="as">
+      <default>['', 'XF86AudioRaiseVolume']</default>
+      <summary>Volume up</summary>
+      <description>Binding to raise the volume.</description>
+    </key>
+    <key name="mic-mute" type="as">
+      <default>['', 'XF86AudioMicMute']</default>
+      <summary>Microphone mute/unmute</summary>
+      <description>Binding to mute/unmute the microphone.</description>
+    </key>
+    <key name="screenshot" type="as">
+      <default>['Print']</default>
+      <summary>Take a screenshot</summary>
+      <description>Binding to take a screenshot.</description>
+    </key>
+    <key name="window-screenshot" type="as">
+      <default>['&lt;Alt&gt;Print']</default>
+      <summary>Take a screenshot of a window</summary>
+      <description>Binding to take a screenshot of a window.</description>
+    </key>
+    <key name="area-screenshot" type="as">
+      <default>['&lt;Shift&gt;Print']</default>
+      <summary>Take a screenshot of an area</summary>
+      <description>Binding to take a screenshot of an area.</description>
+    </key>
+    <key name="screenshot-clip" type="as">
+      <default>['&lt;Ctrl&gt;Print']</default>
+      <summary>Copy a screenshot to clipboard</summary>
+      <description>Binding to copy a screenshot to clipboard.</description>
+    </key>
+    <key name="window-screenshot-clip" type="as">
+      <default>['&lt;Ctrl&gt;&lt;Alt&gt;Print']</default>
+      <summary>Copy a screenshot of a window to clipboard</summary>
+      <description>Binding to copy a screenshot of a window to clipboard.</description>
+    </key>
+    <key name="area-screenshot-clip" type="as">
+      <default>['&lt;Ctrl&gt;&lt;Shift&gt;Print']</default>
+      <summary>Copy a screenshot of an area to clipboard</summary>
+      <description>Binding to copy a screenshot of an area to clipboard.</description>
+    </key>
+    <key name="screencast" type="as">
+      <default>['&lt;Ctrl&gt;&lt;Shift&gt;&lt;Alt&gt;R']</default>
+      <summary>Record a short video of the screen</summary>
+      <description>Binding to record a short video of the screen</description>
+    </key>
+    <key name="www" type="as">
+      <default>['', 'XF86WWW']</default>
+      <summary>Launch web browser</summary>
+      <description>Binding to launch the web browser.</description>
+    </key>
+    <key name="magnifier" type="as">
+      <default>['&lt;Alt&gt;&lt;Super&gt;8']</default>
+      <summary>Toggle magnifier</summary>
+      <description>Binding to show the screen magnifier</description>
+    </key>
+    <key name="screenreader" type="as">
+      <default>['&lt;Alt&gt;&lt;Super&gt;s']</default>
+      <summary>Toggle screen reader</summary>
+      <description>Binding to start the screen reader</description>
+    </key>
+    <key name="on-screen-keyboard" type="as">
+      <default>['']</default>
+      <summary>Toggle on-screen keyboard</summary>
+      <description>Binding to show the on-screen keyboard</description>
+    </key>
+    <key name="increase-text-size" type="as">
+      <default>['']</default>
+      <summary>Increase text size</summary>
+      <description>Binding to increase the text size</description>
+    </key>
+    <key name="decrease-text-size" type="as">
+      <default>['']</default>
+      <summary>Decrease text size</summary>
+      <description>Binding to decrease the text size</description>
+    </key>
+    <key name="toggle-contrast" type="as">
+      <default>['']</default>
+      <summary>Toggle contrast</summary>
+      <description>Binding to toggle the interface contrast</description>
+    </key>
+    <key name="magnifier-zoom-in" type="as">
+      <default>['&lt;Alt&gt;&lt;Super&gt;equal']</default>
+      <summary>Magnifier zoom in</summary>
+      <description>Binding for the magnifier to zoom in</description>
+    </key>
+    <key name="magnifier-zoom-out" type="as">
+      <default>['&lt;Alt&gt;&lt;Super&gt;minus']</default>
+      <summary>Magnifier zoom out</summary>
+      <description>Binding for the magnifier to zoom out</description>
+    </key>
     <key name="max-screencast-length" type="u">
       <default>30</default>
       <summary>Maximum length of screen recordings</summary>
diff --git a/plugins/media-keys/gsd-media-keys-manager.c b/plugins/media-keys/gsd-media-keys-manager.c
index 5193527a..9eb1bc7d 100644
--- a/plugins/media-keys/gsd-media-keys-manager.c
+++ b/plugins/media-keys/gsd-media-keys-manager.c
@@ -46,6 +46,8 @@
 #include <gudev/gudev.h>
 #endif
 
+#include "gsd-settings-migrate.h"
+
 #include "mpris-controller.h"
 #include "gnome-settings-bus.h"
 #include "gnome-settings-profile.h"
@@ -146,7 +148,7 @@ typedef struct {
         const char *hard_coded;
         char *custom_path;
         char *custom_command;
-        guint accel_id;
+        GArray *accel_ids;
 } MediaKey;
 
 typedef struct {
@@ -270,6 +272,7 @@ media_key_unref (MediaKey *key)
                 return;
         if (!g_atomic_int_dec_and_test (&key->ref_count))
                 return;
+        g_clear_pointer (&key->accel_ids, g_array_unref);
         g_free (key->custom_path);
         g_free (key->custom_command);
         g_free (key);
@@ -286,6 +289,9 @@ static MediaKey *
 media_key_new (void)
 {
         MediaKey *key = g_new0 (MediaKey, 1);
+
+        key->accel_ids = g_array_new (FALSE, TRUE, sizeof(guint));
+
         return media_key_ref (key);
 }
 
@@ -373,24 +379,33 @@ get_key_string (MediaKey *key)
                g_assert_not_reached ();
 }
 
-static char *
-get_binding (GsdMediaKeysManager *manager,
-            MediaKey            *key)
+static GStrv
+get_bindings (GsdMediaKeysManager *manager,
+             MediaKey            *key)
 {
        GsdMediaKeysManagerPrivate *priv = GSD_MEDIA_KEYS_MANAGER_GET_PRIVATE (manager);
+       GPtrArray *array;
+       gchar *binding;
 
        if (key->settings_key != NULL)
-               return g_settings_get_string (priv->settings, key->settings_key);
-       else if (key->hard_coded != NULL)
-               return g_strdup (key->hard_coded);
+               return g_settings_get_strv (priv->settings, key->settings_key);
+
+       if (key->hard_coded != NULL)
+               binding = g_strdup (key->hard_coded);
        else if (key->custom_path != NULL) {
                 GSettings *settings;
 
                 settings = g_hash_table_lookup (priv->custom_settings,
                                                 key->custom_path);
-               return g_settings_get_string (settings, "binding");
+               binding = g_settings_get_string (settings, "binding");
        } else
                g_assert_not_reached ();
+
+        array = g_ptr_array_new ();
+        g_ptr_array_add (array, binding);
+        g_ptr_array_add (array, NULL);
+
+        return (GStrv) g_ptr_array_free (array, FALSE);
 }
 
 static void
@@ -500,7 +515,7 @@ ungrab_accelerators_complete (GObject      *object,
                 key = g_ptr_array_index (data->keys, i);
 
                 /* Always clear, as it would just fail again the next time. */
-                key->accel_id = 0;
+                g_array_set_size (key->accel_ids, 0);
         }
 
         /* Nothing left to do if the operation was cancelled */
@@ -556,12 +571,17 @@ grab_accelerators_complete (GObject      *object,
         }
 
         /* We need to stow away the accel_ids that have been registered successfully. */
+        for (i = 0; i < data->keys->len; i++) {
+                MediaKey *key;
+
+                key = g_ptr_array_index (data->keys, i);
+                g_assert (key->accel_ids->len == 0);
+        }
         for (i = 0; i < data->keys->len; i++) {
                 MediaKey *key;
                 guint accel_id;
 
                 key = g_ptr_array_index (data->keys, i);
-                g_assert (key->accel_id == 0);
 
                 g_variant_get_child (actions, i, "u", &accel_id);
                 if (accel_id == 0) {
@@ -569,7 +589,7 @@ grab_accelerators_complete (GObject      *object,
                         tmp = get_key_string (key);
                         g_warning ("Failed to grab accelerator for keybinding %s", tmp);
                 } else {
-                        key->accel_id = accel_id;
+                        g_array_append_val (key->accel_ids, accel_id);
                 }
         }
 
@@ -606,10 +626,12 @@ keys_sync_continue (GsdMediaKeysManager *manager)
 
         g_hash_table_iter_init (&iter, priv->keys_to_sync);
         while (g_hash_table_iter_next (&iter, (gpointer*) &key, NULL)) {
-                g_autofree gchar *tmp = NULL;
+                g_auto(GStrv) bindings = NULL;
+                gchar **pos = NULL;
+                gint i;
 
-                if (key->accel_id > 0) {
-                        g_variant_builder_add (&ungrab_builder, "u", key->accel_id);
+                for (i = 0; i < key->accel_ids->len; i++) {
+                        g_variant_builder_add (&ungrab_builder, "u", g_array_index (key->accel_ids, guint, 
i));
                         g_ptr_array_add (keys_being_ungrabbed, media_key_ref (key));
 
                         need_ungrab = TRUE;
@@ -619,11 +641,15 @@ keys_sync_continue (GsdMediaKeysManager *manager)
                 if (!g_ptr_array_find (priv->keys, key, NULL))
                         continue;
 
-                tmp = get_binding (manager, key);
-                /* The key might not have a keybinding. */
-                if (tmp && strlen (tmp) > 0) {
-                        g_variant_builder_add (&grab_builder, "(suu)", tmp, key->modes, key->grab_flags);
-                        g_ptr_array_add (keys_being_grabbed, media_key_ref (key));
+                bindings = get_bindings (manager, key);
+                pos = bindings;
+                while (*pos) {
+                        /* Do not try to register empty keybindings. */
+                        if (strlen (*pos) > 0) {
+                                g_variant_builder_add (&grab_builder, "(suu)", *pos, key->modes, 
key->grab_flags);
+                                g_ptr_array_add (keys_being_grabbed, media_key_ref (key));
+                        }
+                        pos++;
                 }
         }
 
@@ -2731,10 +2757,15 @@ on_accelerator_activated (ShellKeyGrabber     *grabber,
 
         for (i = 0; i < priv->keys->len; i++) {
                 MediaKey *key;
+                guint j;
 
                 key = g_ptr_array_index (priv->keys, i);
 
-                if (key->accel_id != accel_id)
+                for (j = 0; j < key->accel_ids->len; j++) {
+                        if (g_array_index (key->accel_ids, guint, j) == accel_id)
+                                break;
+                }
+                if (j >= key->accel_ids->len)
                         continue;
 
                 if (key->key_type == CUSTOM_KEY)
@@ -3144,6 +3175,84 @@ start_media_keys_idle_cb (GsdMediaKeysManager *manager)
         return FALSE;
 }
 
+static GVariant *
+map_keybinding (GVariant *variant, GVariant *new_default)
+{
+        g_autoptr(GPtrArray) array = g_ptr_array_new ();
+        g_autofree const gchar **defaults = NULL;
+        const gchar **pos;
+        const gchar *value;
+
+        defaults = g_variant_get_strv (new_default, NULL);
+        pos = defaults;
+
+        value = g_variant_get_string (variant, NULL);
+
+        /* If the user has a custom value that is not in the list, then
+         * insert it instead of the first default entry. */
+        if (!g_strv_contains (defaults, value)) {
+                g_ptr_array_add (array, (gpointer) value);
+                if (*pos)
+                        pos++;
+        }
+
+        /* Add all remaining default values */
+        while (*pos)
+              g_ptr_array_add (array, (gpointer) *pos);
+
+        g_ptr_array_add (array, NULL);
+
+        return g_variant_new_strv ((const gchar * const *) array->pdata, -1);
+}
+
+static void
+migrate_keybinding_settings (void)
+{
+        GsdSettingsMigrateEntry binding_entries[] = {
+                { "calculator",                 "calculator",                   map_keybinding },
+                { "control-center",             "control-center",               map_keybinding },
+                { "email",                      "email",                        map_keybinding },
+                { "eject",                      "eject",                        map_keybinding },
+                { "help",                       "help",                         map_keybinding },
+                { "home",                       "home",                         map_keybinding },
+                { "media",                      "media",                        map_keybinding },
+                { "next",                       "next",                         map_keybinding },
+                { "pause",                      "pause",                        map_keybinding },
+                { "play",                       "play",                         map_keybinding },
+                { "logout",                     "logout",                       map_keybinding },
+                { "previous",                   "previous",                     map_keybinding },
+                { "screensaver",                "screensaver",                  map_keybinding },
+                { "search",                     "search",                       map_keybinding },
+                { "stop",                       "stop",                         map_keybinding },
+                { "volume-down",                "volume-down",                  map_keybinding },
+                { "volume-mute",                "volume-mute",                  map_keybinding },
+                { "volume-up",                  "volume-up",                    map_keybinding },
+                { "mic-mute",                   "mic-mute",                     map_keybinding },
+                { "screenshot",                 "screenshot",                   map_keybinding },
+                { "window-screenshot",          "window-screenshot",            map_keybinding },
+                { "area-screenshot",            "area-screenshot",              map_keybinding },
+                { "screenshot-clip",            "screenshot-clip",              map_keybinding },
+                { "window-screenshot-clip",     "window-screenshot-clip",       map_keybinding },
+                { "area-screenshot-clip",       "area-screenshot-clip",         map_keybinding },
+                { "screencast",                 "screencast",                   map_keybinding },
+                { "www",                        "www",                          map_keybinding },
+                { "magnifier",                  "magnifier",                    map_keybinding },
+                { "screenreader",               "screenreader",                 map_keybinding },
+                { "on-screen-keyboard",         "on-screen-keyboard",           map_keybinding },
+                { "increase-text-size",         "increase-text-size",           map_keybinding },
+                { "decrease-text-size",         "decrease-text-size",           map_keybinding },
+                { "toggle-contrast",            "toggle-contrast",              map_keybinding },
+                { "magnifier-zoom-in",          "magnifier-zoom-in",            map_keybinding },
+                { "magnifier-zoom-out",         "magnifier-zoom-out",           map_keybinding },
+        };
+
+        gsd_settings_migrate_check ("org.gnome.settings-daemon.plugins.media-keys.deprecated",
+                                    "/org/gnome/settings-daemon/plugins/media-keys/",
+                                    "org.gnome.settings-daemon.plugins.media-keys",
+                                    "/org/gnome/settings-daemon/plugins/media-keys/",
+                                    binding_entries, G_N_ELEMENTS (binding_entries));
+}
+
 gboolean
 gsd_media_keys_manager_start (GsdMediaKeysManager *manager,
                               GError             **error)
@@ -3153,6 +3262,8 @@ gsd_media_keys_manager_start (GsdMediaKeysManager *manager,
 
         gnome_settings_profile_start (NULL);
 
+        migrate_keybinding_settings ();
+
 #if HAVE_GUDEV
         priv->streams = g_hash_table_new (g_direct_hash, g_direct_equal);
         priv->udev_client = g_udev_client_new (subsystems);


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