Commit 44f53c64 authored by Benjamin Berg's avatar Benjamin Berg

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.
parent 7202d689
<?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>
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment