[gnome-control-center/wip/gbsneto/new-keyboard-panel: 2/8] keyboard: move keyboard management code to custom class
- From: Georges Basile Stavracas Neto <gbsneto src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-control-center/wip/gbsneto/new-keyboard-panel: 2/8] keyboard: move keyboard management code to custom class
- Date: Mon, 25 Jul 2016 00:30:47 +0000 (UTC)
commit f1878ec023a3a88de4c82a6efc8495042941a113
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date: Thu Jul 21 18:38:37 2016 -0300
keyboard: move keyboard management code to custom class
Instead of having CcKeyboardPanel managing both UI and backend code,
factor the backend code to a new CcKeyboardManager class and drop
backend management from the panel itself.
The next patch will move the current code to use the manager class.
https://bugzilla.gnome.org/show_bug.cgi?id=769063
panels/keyboard/Makefile.am | 2 +
panels/keyboard/cc-keyboard-manager.c | 847 +++++++++++++++++++++++++
panels/keyboard/cc-keyboard-manager.h | 51 ++
panels/keyboard/cc-keyboard-panel.c | 847 +------------------------
panels/keyboard/cc-keyboard-shortcut-editor.c | 67 +--
panels/keyboard/cc-keyboard-shortcut-editor.h | 4 +-
6 files changed, 936 insertions(+), 882 deletions(-)
---
diff --git a/panels/keyboard/Makefile.am b/panels/keyboard/Makefile.am
index a2c09ff..6125ad7 100644
--- a/panels/keyboard/Makefile.am
+++ b/panels/keyboard/Makefile.am
@@ -9,6 +9,8 @@ BUILT_SOURCES = \
libkeyboard_la_SOURCES = \
$(BUILT_SOURCES) \
+ cc-keyboard-manager.c \
+ cc-keyboard-manager.h \
cc-keyboard-panel.c \
cc-keyboard-panel.h \
cc-keyboard-item.c \
diff --git a/panels/keyboard/cc-keyboard-manager.c b/panels/keyboard/cc-keyboard-manager.c
new file mode 100644
index 0000000..7837c72
--- /dev/null
+++ b/panels/keyboard/cc-keyboard-manager.c
@@ -0,0 +1,847 @@
+/*
+ * Copyright (C) 2010 Intel, Inc
+ * Copyright (C) 2016 Endless, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Thomas Wood <thomas wood intel com>
+ * Georges Basile Stavracas Neto <georges stavracas gmail com>
+ *
+ */
+
+#include <glib/gi18n.h>
+
+#include "cc-keyboard-manager.h"
+#include "keyboard-shortcuts.h"
+#include "wm-common.h"
+
+#ifdef GDK_WINDOWING_X11
+#include <gdk/gdkx.h>
+#endif
+
+#define BINDINGS_SCHEMA "org.gnome.settings-daemon.plugins.media-keys"
+#define CUSTOM_SHORTCUTS_ID "custom"
+
+struct _CcKeyboardManager
+{
+ GObject parent;
+
+ GtkListStore *shortcuts_model;
+ GtkListStore *sections_store;
+
+ GHashTable *kb_system_sections;
+ GHashTable *kb_apps_sections;
+ GHashTable *kb_user_sections;
+
+ GSettings *binding_settings;
+
+ gpointer wm_changed_id;
+};
+
+G_DEFINE_TYPE (CcKeyboardManager, cc_keyboard_manager, G_TYPE_OBJECT)
+
+enum
+{
+ SHORTCUT_ADDED,
+ SHORTCUT_CHANGED,
+ SHORTCUT_REMOVED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0, };
+
+/*
+ * Auxiliary methos
+ */
+static void
+free_key_array (GPtrArray *keys)
+{
+ if (keys != NULL)
+ {
+ gint i;
+
+ for (i = 0; i < keys->len; i++)
+ {
+ CcKeyboardItem *item;
+
+ item = g_ptr_array_index (keys, i);
+
+ g_object_unref (item);
+ }
+
+ g_ptr_array_free (keys, TRUE);
+ }
+}
+
+static GHashTable*
+get_hash_for_group (CcKeyboardManager *self,
+ BindingGroupType group)
+{
+ GHashTable *hash;
+
+ switch (group)
+ {
+ case BINDING_GROUP_SYSTEM:
+ hash = self->kb_system_sections;
+ break;
+ case BINDING_GROUP_APPS:
+ hash = self->kb_apps_sections;
+ break;
+ case BINDING_GROUP_USER:
+ hash = self->kb_user_sections;
+ break;
+ default:
+ hash = NULL;
+ }
+
+ return hash;
+}
+
+static gboolean
+have_key_for_group (CcKeyboardManager *self,
+ int group,
+ const gchar *name)
+{
+ GHashTableIter iter;
+ GPtrArray *keys;
+ gint i;
+
+ g_hash_table_iter_init (&iter, get_hash_for_group (self, group));
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer*) &keys))
+ {
+ for (i = 0; i < keys->len; i++)
+ {
+ CcKeyboardItem *item = g_ptr_array_index (keys, i);
+
+ if (item->type == CC_KEYBOARD_ITEM_TYPE_GSETTINGS &&
+ g_strcmp0 (name, item->key) == 0)
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+add_shortcuts (CcKeyboardManager *self)
+{
+ GtkTreeModel *sections_model;
+ GtkTreeIter sections_iter;
+ gboolean can_continue;
+
+ sections_model = GTK_TREE_MODEL (self->sections_store);
+ can_continue = gtk_tree_model_get_iter_first (sections_model, §ions_iter);
+
+ while (can_continue)
+ {
+ BindingGroupType group;
+ GPtrArray *keys;
+ gchar *id, *title;
+ gint i;
+
+ gtk_tree_model_get (sections_model,
+ §ions_iter,
+ SECTION_DESCRIPTION_COLUMN, &title,
+ SECTION_GROUP_COLUMN, &group,
+ SECTION_ID_COLUMN, &id,
+ -1);
+
+ /* Ignore separators */
+ if (group == BINDING_GROUP_SEPARATOR)
+ {
+ can_continue = gtk_tree_model_iter_next (sections_model, §ions_iter);
+ continue;
+ }
+
+ keys = g_hash_table_lookup (get_hash_for_group (self, group), id);
+
+ for (i = 0; i < keys->len; i++)
+ {
+ CcKeyboardItem *item = g_ptr_array_index (keys, i);
+
+ if (!cc_keyboard_item_is_hidden (item))
+ {
+ GtkTreeIter new_row;
+
+ gtk_list_store_append (self->shortcuts_model, &new_row);
+ gtk_list_store_set (self->shortcuts_model,
+ &new_row,
+ DETAIL_DESCRIPTION_COLUMN, item->description,
+ DETAIL_KEYENTRY_COLUMN, item,
+ DETAIL_TYPE_COLUMN, SHORTCUT_TYPE_KEY_ENTRY,
+ -1);
+
+ g_signal_emit (self, signals[SHORTCUT_ADDED],
+ 0,
+ item,
+ id,
+ title);
+ }
+ }
+
+ can_continue = gtk_tree_model_iter_next (sections_model, §ions_iter);
+
+ g_free (title);
+ g_free (id);
+ }
+}
+
+static void
+append_section (CcKeyboardManager *self,
+ const gchar *title,
+ const gchar *id,
+ BindingGroupType group,
+ const KeyListEntry *keys_list)
+{
+ GtkTreeModel *shortcut_model;
+ GtkTreeIter iter;
+ GHashTable *reverse_items;
+ GHashTable *hash;
+ GPtrArray *keys_array;
+ gboolean is_new;
+ gint i;
+
+ hash = get_hash_for_group (self, group);
+
+ if (!hash)
+ return;
+
+ shortcut_model = GTK_TREE_MODEL (self->shortcuts_model);
+
+ /* Add all CcKeyboardItems for this section */
+ is_new = FALSE;
+ keys_array = g_hash_table_lookup (hash, id);
+ if (keys_array == NULL)
+ {
+ keys_array = g_ptr_array_new ();
+ is_new = TRUE;
+ }
+
+ reverse_items = g_hash_table_new (g_str_hash, g_str_equal);
+
+ for (i = 0; keys_list != NULL && keys_list[i].name != NULL; i++)
+ {
+ CcKeyboardItem *item;
+ gboolean ret;
+
+ if (have_key_for_group (self, group, keys_list[i].name))
+ continue;
+
+ item = cc_keyboard_item_new (keys_list[i].type);
+
+ switch (keys_list[i].type)
+ {
+ case CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH:
+ ret = cc_keyboard_item_load_from_gsettings_path (item, keys_list[i].name, FALSE);
+ break;
+
+ case CC_KEYBOARD_ITEM_TYPE_GSETTINGS:
+ ret = cc_keyboard_item_load_from_gsettings (item,
+ keys_list[i].description,
+ keys_list[i].schema,
+ keys_list[i].name);
+ if (ret && keys_list[i].reverse_entry != NULL)
+ {
+ CcKeyboardItem *reverse_item;
+ reverse_item = g_hash_table_lookup (reverse_items,
+ keys_list[i].reverse_entry);
+ if (reverse_item != NULL)
+ {
+ cc_keyboard_item_add_reverse_item (item,
+ reverse_item,
+ keys_list[i].is_reversed);
+ }
+ else
+ {
+ g_hash_table_insert (reverse_items,
+ keys_list[i].name,
+ item);
+ }
+ }
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ if (ret == FALSE)
+ {
+ /* We don't actually want to popup a dialog - just skip this one */
+ g_object_unref (item);
+ continue;
+ }
+
+ cc_keyboard_item_set_hidden (item, keys_list[i].hidden);
+ item->model = shortcut_model;
+ item->group = group;
+
+ g_ptr_array_add (keys_array, item);
+ }
+
+ g_hash_table_destroy (reverse_items);
+
+ /* Add the keys to the hash table */
+ if (is_new)
+ {
+ g_hash_table_insert (hash, g_strdup (id), keys_array);
+
+ /* Append the section to the left tree view */
+ gtk_list_store_append (GTK_LIST_STORE (self->sections_store), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (self->sections_store),
+ &iter,
+ SECTION_DESCRIPTION_COLUMN, title,
+ SECTION_ID_COLUMN, id,
+ SECTION_GROUP_COLUMN, group,
+ -1);
+ }
+}
+
+static void
+append_sections_from_file (CcKeyboardManager *self,
+ const gchar *path,
+ const char *datadir,
+ gchar **wm_keybindings)
+{
+ GError *err = NULL;
+ char *buf;
+ gsize buf_len;
+ KeyList *keylist;
+ KeyListEntry *keys;
+ KeyListEntry key = { 0, 0, 0, 0, 0, 0, 0 };
+ const char *title;
+ int group;
+ guint i;
+ GMarkupParseContext *ctx;
+ GMarkupParser parser = { parse_start_tag, NULL, NULL, NULL, NULL };
+
+ /* Parse file */
+ if (!g_file_get_contents (path, &buf, &buf_len, &err))
+ return;
+
+ keylist = g_new0 (KeyList, 1);
+ keylist->entries = g_array_new (FALSE, TRUE, sizeof (KeyListEntry));
+ ctx = g_markup_parse_context_new (&parser, 0, keylist, NULL);
+
+ if (!g_markup_parse_context_parse (ctx, buf, buf_len, &err))
+ {
+ g_warning ("Failed to parse '%s': '%s'", path, err->message);
+ g_error_free (err);
+ g_free (keylist->name);
+ g_free (keylist->package);
+ g_free (keylist->wm_name);
+
+ for (i = 0; i < keylist->entries->len; i++)
+ g_free (((KeyListEntry *) &(keylist->entries->data[i]))->name);
+
+ g_array_free (keylist->entries, TRUE);
+ g_free (keylist);
+ keylist = NULL;
+ }
+
+ g_markup_parse_context_free (ctx);
+ g_free (buf);
+
+ if (keylist == NULL)
+ return;
+
+#define const_strv(s) ((const gchar* const*) s)
+
+ /* If there's no keys to add, or the settings apply to a window manager
+ * that's not the one we're running */
+ if (keylist->entries->len == 0 ||
+ (keylist->wm_name != NULL && !g_strv_contains (const_strv (wm_keybindings), keylist->wm_name)) ||
+ keylist->name == NULL)
+ {
+ g_free (keylist->name);
+ g_free (keylist->package);
+ g_free (keylist->wm_name);
+ g_array_free (keylist->entries, TRUE);
+ g_free (keylist);
+ return;
+ }
+
+#undef const_strv
+
+ /* Empty KeyListEntry to end the array */
+ key.name = NULL;
+ g_array_append_val (keylist->entries, key);
+
+ keys = (KeyListEntry *) g_array_free (keylist->entries, FALSE);
+ if (keylist->package)
+ {
+ char *localedir;
+
+ localedir = g_build_filename (datadir, "locale", NULL);
+ bindtextdomain (keylist->package, localedir);
+ g_free (localedir);
+
+ title = dgettext (keylist->package, keylist->name);
+ } else {
+ title = _(keylist->name);
+ }
+
+ if (keylist->group && strcmp (keylist->group, "system") == 0)
+ group = BINDING_GROUP_SYSTEM;
+ else
+ group = BINDING_GROUP_APPS;
+
+ append_section (self, title, keylist->name, group, keys);
+
+ g_free (keylist->name);
+ g_free (keylist->package);
+ g_free (keylist->wm_name);
+ g_free (keylist->schema);
+ g_free (keylist->group);
+
+ for (i = 0; keys[i].name != NULL; i++)
+ {
+ KeyListEntry *entry = &keys[i];
+ g_free (entry->schema);
+ g_free (entry->description);
+ g_free (entry->name);
+ g_free (entry->reverse_entry);
+ }
+
+ g_free (keylist);
+ g_free (keys);
+}
+
+static void
+append_sections_from_gsettings (CcKeyboardManager *self)
+{
+ char **custom_paths;
+ GArray *entries;
+ KeyListEntry key = { 0, 0, 0, 0, 0, 0, 0 };
+ int i;
+
+ /* load custom shortcuts from GSettings */
+ entries = g_array_new (FALSE, TRUE, sizeof (KeyListEntry));
+
+ custom_paths = g_settings_get_strv (self->binding_settings, "custom-keybindings");
+ for (i = 0; custom_paths[i]; i++)
+ {
+ key.name = g_strdup (custom_paths[i]);
+ if (!have_key_for_group (self, BINDING_GROUP_USER, key.name))
+ {
+ key.type = CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH;
+ g_array_append_val (entries, key);
+ }
+ else
+ g_free (key.name);
+ }
+ g_strfreev (custom_paths);
+
+ if (entries->len > 0)
+ {
+ KeyListEntry *keys;
+ int i;
+
+ /* Empty KeyListEntry to end the array */
+ key.name = NULL;
+ g_array_append_val (entries, key);
+
+ keys = (KeyListEntry *) entries->data;
+ append_section (self, _("Custom Shortcuts"), CUSTOM_SHORTCUTS_ID, BINDING_GROUP_USER, keys);
+ for (i = 0; i < entries->len; ++i)
+ {
+ g_free (keys[i].name);
+ }
+ }
+ else
+ {
+ append_section (self, _("Custom Shortcuts"), CUSTOM_SHORTCUTS_ID, BINDING_GROUP_USER, NULL);
+ }
+
+ g_array_free (entries, TRUE);
+}
+
+static void
+reload_sections (CcKeyboardManager *self)
+{
+ GtkTreeModel *shortcut_model;
+ GHashTable *loaded_files;
+ GDir *dir;
+ gchar *default_wm_keybindings[] = { "Mutter", "GNOME Shell", NULL };
+ gchar **wm_keybindings;
+ const gchar * const * data_dirs;
+ guint i;
+
+ shortcut_model = GTK_TREE_MODEL (self->shortcuts_model);
+
+ /* Clear previous models and hash tables */
+ gtk_list_store_clear (GTK_LIST_STORE (self->sections_store));
+ gtk_list_store_clear (GTK_LIST_STORE (shortcut_model));
+
+ g_clear_pointer (&self->kb_system_sections, g_hash_table_destroy);
+ self->kb_system_sections = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify) free_key_array);
+
+ g_clear_pointer (&self->kb_apps_sections, g_hash_table_destroy);
+ self->kb_apps_sections = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify) free_key_array);
+
+ g_clear_pointer (&self->kb_user_sections, g_hash_table_destroy);
+ self->kb_user_sections = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify) free_key_array);
+
+ /* Load WM keybindings */
+#ifdef GDK_WINDOWING_X11
+ if (GDK_IS_X11_DISPLAY (gdk_display_get_default ()))
+ wm_keybindings = wm_common_get_current_keybindings ();
+ else
+#endif
+ wm_keybindings = g_strdupv (default_wm_keybindings);
+
+ loaded_files = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ data_dirs = g_get_system_data_dirs ();
+ for (i = 0; data_dirs[i] != NULL; i++)
+ {
+ char *dir_path;
+ const gchar *name;
+
+ dir_path = g_build_filename (data_dirs[i], "gnome-control-center", "keybindings", NULL);
+
+ dir = g_dir_open (dir_path, 0, NULL);
+ if (!dir)
+ {
+ g_free (dir_path);
+ continue;
+ }
+
+ for (name = g_dir_read_name (dir) ; name ; name = g_dir_read_name (dir))
+ {
+ gchar *path;
+
+ if (g_str_has_suffix (name, ".xml") == FALSE)
+ continue;
+
+ if (g_hash_table_lookup (loaded_files, name) != NULL)
+ {
+ g_debug ("Not loading %s, it was already loaded from another directory", name);
+ continue;
+ }
+
+ g_hash_table_insert (loaded_files, g_strdup (name), GINT_TO_POINTER (1));
+ path = g_build_filename (dir_path, name, NULL);
+ append_sections_from_file (self, path, data_dirs[i], wm_keybindings);
+ g_free (path);
+ }
+
+ g_free (dir_path);
+ g_dir_close (dir);
+ }
+
+ g_hash_table_destroy (loaded_files);
+ g_strfreev (wm_keybindings);
+
+ /* Load custom keybindings */
+ append_sections_from_gsettings (self);
+}
+
+/*
+ * Callbacks
+ */
+static void
+on_window_manager_change (const char *wm_name,
+ CcKeyboardManager *self)
+{
+ reload_sections (self);
+}
+
+static void
+cc_keyboard_manager_finalize (GObject *object)
+{
+ CcKeyboardManager *self = (CcKeyboardManager *)object;
+
+ g_clear_pointer (&self->kb_system_sections, g_hash_table_destroy);
+ g_clear_pointer (&self->kb_apps_sections, g_hash_table_destroy);
+ g_clear_pointer (&self->kb_user_sections, g_hash_table_destroy);
+ g_clear_object (&self->binding_settings);
+
+ g_clear_pointer (&self->wm_changed_id, wm_common_unregister_window_manager_change);
+
+ G_OBJECT_CLASS (cc_keyboard_manager_parent_class)->finalize (object);
+}
+
+static void
+cc_keyboard_manager_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+}
+
+static void
+cc_keyboard_manager_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+}
+
+static void
+cc_keyboard_manager_class_init (CcKeyboardManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = cc_keyboard_manager_finalize;
+ object_class->get_property = cc_keyboard_manager_get_property;
+ object_class->set_property = cc_keyboard_manager_set_property;
+
+ /**
+ * CcKeyboardManager:shortcut-added:
+ *
+ * Emited when a shortcut is added.
+ */
+ signals[SHORTCUT_ADDED] = g_signal_new ("shortcut-added",
+ CC_TYPE_KEYBOARD_MANAGER,
+ G_SIGNAL_RUN_FIRST,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE,
+ 3,
+ CC_TYPE_KEYBOARD_ITEM,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
+
+ /**
+ * CcKeyboardManager:shortcut-changed:
+ *
+ * Emited when a shortcut is added.
+ */
+ signals[SHORTCUT_CHANGED] = g_signal_new ("shortcut-changed",
+ CC_TYPE_KEYBOARD_MANAGER,
+ G_SIGNAL_RUN_FIRST,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE,
+ 1,
+ CC_TYPE_KEYBOARD_ITEM);
+
+
+ /**
+ * CcKeyboardManager:shortcut-removed:
+ *
+ * Emited when a shortcut is removed.
+ */
+ signals[SHORTCUT_REMOVED] = g_signal_new ("shortcut-removed",
+ CC_TYPE_KEYBOARD_MANAGER,
+ G_SIGNAL_RUN_FIRST,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE,
+ 1,
+ CC_TYPE_KEYBOARD_ITEM);
+}
+
+static void
+cc_keyboard_manager_init (CcKeyboardManager *self)
+{
+ /* Bindings */
+ self->binding_settings = g_settings_new (BINDINGS_SCHEMA);
+
+ /* Setup the section models */
+ self->sections_store = gtk_list_store_new (SECTION_N_COLUMNS,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_INT);
+
+ self->shortcuts_model = gtk_list_store_new (DETAIL_N_COLUMNS,
+ G_TYPE_STRING,
+ G_TYPE_POINTER,
+ G_TYPE_INT);
+
+#ifdef GDK_WINDOWING_X11
+ if (GDK_IS_X11_DISPLAY (gdk_display_get_default ()))
+ self->wm_changed_id = wm_common_register_window_manager_change ((GFunc) on_window_manager_change,
+ self);
+#endif
+}
+
+
+CcKeyboardManager *
+cc_keyboard_manager_new (void)
+{
+ return g_object_new (CC_TYPE_KEYBOARD_MANAGER, NULL);
+}
+
+void
+cc_keyboard_manager_load_shortcuts (CcKeyboardManager *self)
+{
+ g_return_if_fail (CC_IS_KEYBOARD_MANAGER (self));
+
+ reload_sections (self);
+ add_shortcuts (self);
+}
+
+/**
+ * cc_keyboard_manager_create_custom_shortcut:
+ * @self: a #CcKeyboardPanel
+ *
+ * Creates a new temporary keyboard shortcut.
+ *
+ * Returns: (transfer full): a #CcKeyboardItem
+ */
+CcKeyboardItem*
+cc_keyboard_manager_create_custom_shortcut (CcKeyboardManager *self)
+{
+ CcKeyboardItem *item;
+ gchar *settings_path;
+
+ g_return_val_if_fail (CC_IS_KEYBOARD_MANAGER (self), NULL);
+
+ item = cc_keyboard_item_new (CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH);
+
+ settings_path = find_free_settings_path (self->binding_settings);
+ cc_keyboard_item_load_from_gsettings_path (item, settings_path, TRUE);
+ g_free (settings_path);
+
+ item->model = GTK_TREE_MODEL (self->shortcuts_model);
+ item->group = BINDING_GROUP_USER;
+
+ return item;
+}
+
+/**
+ * cc_keyboard_manager_add_custom_shortcut:
+ * @self: a #CcKeyboardPanel
+ * @item: the #CcKeyboardItem to be added
+ *
+ * Effectively adds the custom shortcut.
+ */
+void
+cc_keyboard_manager_add_custom_shortcut (CcKeyboardManager *self,
+ CcKeyboardItem *item)
+{
+ GPtrArray *keys_array;
+ GtkTreeIter iter;
+ GHashTable *hash;
+ GVariantBuilder builder;
+ char **settings_paths;
+ int i;
+
+ g_return_if_fail (CC_IS_KEYBOARD_MANAGER (self));
+
+ hash = get_hash_for_group (self, BINDING_GROUP_USER);
+ keys_array = g_hash_table_lookup (hash, CUSTOM_SHORTCUTS_ID);
+
+ if (keys_array == NULL)
+ {
+ keys_array = g_ptr_array_new ();
+ g_hash_table_insert (hash, g_strdup (CUSTOM_SHORTCUTS_ID), keys_array);
+ }
+
+ g_ptr_array_add (keys_array, item);
+
+ gtk_list_store_append (self->shortcuts_model, &iter);
+ gtk_list_store_set (self->shortcuts_model, &iter, DETAIL_KEYENTRY_COLUMN, item, -1);
+
+ settings_paths = g_settings_get_strv (self->binding_settings, "custom-keybindings");
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
+
+ for (i = 0; settings_paths[i]; i++)
+ g_variant_builder_add (&builder, "s", settings_paths[i]);
+
+ g_variant_builder_add (&builder, "s", item->gsettings_path);
+
+ g_settings_set_value (self->binding_settings, "custom-keybindings", g_variant_builder_end (&builder));
+
+ g_signal_emit (self, signals[SHORTCUT_ADDED],
+ 0,
+ item,
+ CUSTOM_SHORTCUTS_ID,
+ _("Custom Shortcuts"));
+}
+
+/**
+ * cc_keyboard_manager_remove_custom_shortcut:
+ * @self: a #CcKeyboardPanel
+ * @item: the #CcKeyboardItem to be added
+ *
+ * Removed the custom shortcut.
+ */
+void
+cc_keyboard_manager_remove_custom_shortcut (CcKeyboardManager *self,
+ CcKeyboardItem *item)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GPtrArray *keys_array;
+ GVariantBuilder builder;
+ gboolean valid;
+ char **settings_paths;
+ int i;
+
+ g_return_if_fail (CC_IS_KEYBOARD_MANAGER (self));
+
+ model = GTK_TREE_MODEL (self->shortcuts_model);
+ valid = gtk_tree_model_get_iter_first (model, &iter);
+
+ /* Search for the iter */
+ while (valid)
+ {
+ CcKeyboardItem *current_item;
+
+ gtk_tree_model_get (model, &iter,
+ DETAIL_KEYENTRY_COLUMN, ¤t_item,
+ -1);
+
+ if (current_item == item)
+ break;
+
+ valid = gtk_tree_model_iter_next (model, &iter);
+ }
+
+ /* Shortcut not found or not a custom shortcut */
+ g_assert (valid);
+ g_assert (item->type == CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH);
+
+ g_settings_delay (item->settings);
+ g_settings_reset (item->settings, "name");
+ g_settings_reset (item->settings, "command");
+ g_settings_reset (item->settings, "binding");
+ g_settings_apply (item->settings);
+ g_settings_sync ();
+
+ settings_paths = g_settings_get_strv (self->binding_settings, "custom-keybindings");
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
+
+ for (i = 0; settings_paths[i]; i++)
+ if (strcmp (settings_paths[i], item->gsettings_path) != 0)
+ g_variant_builder_add (&builder, "s", settings_paths[i]);
+
+ g_settings_set_value (self->binding_settings,
+ "custom-keybindings",
+ g_variant_builder_end (&builder));
+
+ g_strfreev (settings_paths);
+
+ keys_array = g_hash_table_lookup (get_hash_for_group (self, BINDING_GROUP_USER), CUSTOM_SHORTCUTS_ID);
+ g_ptr_array_remove (keys_array, item);
+
+ gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+
+ g_signal_emit (self, signals[SHORTCUT_REMOVED], 0, item);
+}
diff --git a/panels/keyboard/cc-keyboard-manager.h b/panels/keyboard/cc-keyboard-manager.h
new file mode 100644
index 0000000..ab14d4a
--- /dev/null
+++ b/panels/keyboard/cc-keyboard-manager.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2010 Intel, Inc
+ * Copyright (C) 2016 Endless, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Thomas Wood <thomas wood intel com>
+ * Georges Basile Stavracas Neto <georges stavracas gmail com>
+ *
+ */
+
+#ifndef CC_KEYBOARD_MANAGER_H
+#define CC_KEYBOARD_MANAGER_H
+
+#include <glib-object.h>
+
+#include "cc-keyboard-item.h"
+
+G_BEGIN_DECLS
+
+#define CC_TYPE_KEYBOARD_MANAGER (cc_keyboard_manager_get_type())
+
+G_DECLARE_FINAL_TYPE (CcKeyboardManager, cc_keyboard_manager, CC, KEYBOARD_MANAGER, GObject)
+
+CcKeyboardManager* cc_keyboard_manager_new (void);
+
+void cc_keyboard_manager_load_shortcuts (CcKeyboardManager *self);
+
+CcKeyboardItem* cc_keyboard_manager_create_custom_shortcut (CcKeyboardManager *self);
+
+void cc_keyboard_manager_add_custom_shortcut (CcKeyboardManager *self,
+ CcKeyboardItem *item);
+
+void cc_keyboard_manager_remove_custom_shortcut (CcKeyboardManager *self,
+ CcKeyboardItem *item);
+
+G_END_DECLS
+
+#endif /* CC_KEYBOARD_MANAGER_H */
+
diff --git a/panels/keyboard/cc-keyboard-panel.c b/panels/keyboard/cc-keyboard-panel.c
index 9d59588..aec965c 100644
--- a/panels/keyboard/cc-keyboard-panel.c
+++ b/panels/keyboard/cc-keyboard-panel.c
@@ -23,20 +23,13 @@
#include <glib/gi18n.h>
#include "cc-keyboard-item.h"
+#include "cc-keyboard-manager.h"
#include "cc-keyboard-option.h"
#include "cc-keyboard-panel.h"
#include "cc-keyboard-resources.h"
#include "cc-keyboard-shortcut-editor.h"
#include "keyboard-shortcuts.h"
-#include "wm-common.h"
-
-#ifdef GDK_WINDOWING_X11
-#include <gdk/gdkx.h>
-#endif
-
-#define BINDINGS_SCHEMA "org.gnome.settings-daemon.plugins.media-keys"
-#define CUSTOM_SHORTCUTS_ID "custom"
typedef struct {
CcKeyboardItem *item;
@@ -49,9 +42,6 @@ struct _CcKeyboardPanel
CcPanel parent;
/* Shortcut view */
- GtkListStore *shortcuts_model;
- GtkListStore *sections_store;
- GtkTreeModel *sections_model;
GtkWidget *listbox;
GtkListBoxRow *add_shortcut_row;
GtkSizeGroup *accelerator_sizegroup;
@@ -59,15 +49,9 @@ struct _CcKeyboardPanel
/* Custom shortcut dialog */
GtkWidget *shortcut_editor;
- GHashTable *kb_system_sections;
- GHashTable *kb_apps_sections;
- GHashTable *kb_user_sections;
-
- GSettings *binding_settings;
-
GRegex *pictures_regex;
- gpointer wm_changed_id;
+ CcKeyboardManager *manager;
};
CC_PANEL_REGISTER (CcKeyboardPanel, cc_keyboard_panel)
@@ -310,725 +294,6 @@ header_function (GtkListBoxRow *row,
}
}
-static GHashTable*
-get_hash_for_group (CcKeyboardPanel *self,
- BindingGroupType group)
-{
- GHashTable *hash;
-
- switch (group)
- {
- case BINDING_GROUP_SYSTEM:
- hash = self->kb_system_sections;
- break;
- case BINDING_GROUP_APPS:
- hash = self->kb_apps_sections;
- break;
- case BINDING_GROUP_USER:
- hash = self->kb_user_sections;
- break;
- default:
- hash = NULL;
- }
-
- return hash;
-}
-
-static gboolean
-have_key_for_group (CcKeyboardPanel *self,
- int group,
- const gchar *name)
-{
- GHashTableIter iter;
- GPtrArray *keys;
- gint i;
-
- g_hash_table_iter_init (&iter, get_hash_for_group (self, group));
- while (g_hash_table_iter_next (&iter, NULL, (gpointer*) &keys))
- {
- for (i = 0; i < keys->len; i++)
- {
- CcKeyboardItem *item = g_ptr_array_index (keys, i);
-
- if (item->type == CC_KEYBOARD_ITEM_TYPE_GSETTINGS &&
- g_strcmp0 (name, item->key) == 0)
- {
- return TRUE;
- }
-
- return FALSE;
- }
- }
-
- return FALSE;
-}
-
-static void
-free_key_array (GPtrArray *keys)
-{
- if (keys != NULL)
- {
- gint i;
-
- for (i = 0; i < keys->len; i++)
- {
- CcKeyboardItem *item;
-
- item = g_ptr_array_index (keys, i);
-
- g_object_unref (item);
- }
-
- g_ptr_array_free (keys, TRUE);
- }
-}
-
-static char*
-binding_name (guint keyval,
- guint keycode,
- GdkModifierType mask,
- gboolean translate)
-{
- if (keyval != 0 || keycode != 0)
- {
- return translate ? gtk_accelerator_get_label_with_keycode (NULL, keyval, keycode, mask) :
- gtk_accelerator_name_with_keycode (NULL, keyval, keycode, mask);
- }
- else
- {
- return g_strdup (translate ? _("Disabled") : NULL);
- }
-}
-
-
-static gboolean
-keybinding_key_changed_foreach (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- CcKeyboardItem *item)
-{
- CcKeyboardItem *tmp_item;
-
- gtk_tree_model_get (item->model,
- iter,
- DETAIL_KEYENTRY_COLUMN, &tmp_item,
- -1);
-
- if (item == tmp_item)
- {
- gtk_tree_model_row_changed (item->model, path, iter);
- return TRUE;
- }
-
- return FALSE;
-}
-
-static void
-item_changed (CcKeyboardItem *item,
- GParamSpec *pspec,
- gpointer user_data)
-{
- /* update the model */
- gtk_tree_model_foreach (item->model,
- (GtkTreeModelForeachFunc) keybinding_key_changed_foreach,
- item);
-}
-
-static void
-append_section (CcKeyboardPanel *self,
- const gchar *title,
- const gchar *id,
- BindingGroupType group,
- const KeyListEntry *keys_list)
-{
- GtkTreeModel *shortcut_model;
- GtkTreeIter iter;
- GHashTable *reverse_items;
- GHashTable *hash;
- GPtrArray *keys_array;
- gboolean is_new;
- gint i;
-
- hash = get_hash_for_group (self, group);
-
- if (!hash)
- return;
-
- shortcut_model = GTK_TREE_MODEL (self->shortcuts_model);
-
- /* Add all CcKeyboardItems for this section */
- is_new = FALSE;
- keys_array = g_hash_table_lookup (hash, id);
- if (keys_array == NULL)
- {
- keys_array = g_ptr_array_new ();
- is_new = TRUE;
- }
-
- reverse_items = g_hash_table_new (g_str_hash, g_str_equal);
-
- for (i = 0; keys_list != NULL && keys_list[i].name != NULL; i++)
- {
- CcKeyboardItem *item;
- gboolean ret;
-
- if (have_key_for_group (self, group, keys_list[i].name))
- continue;
-
- item = cc_keyboard_item_new (keys_list[i].type);
- switch (keys_list[i].type)
- {
- case CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH:
- ret = cc_keyboard_item_load_from_gsettings_path (item, keys_list[i].name, FALSE);
- break;
-
- case CC_KEYBOARD_ITEM_TYPE_GSETTINGS:
- ret = cc_keyboard_item_load_from_gsettings (item,
- keys_list[i].description,
- keys_list[i].schema,
- keys_list[i].name);
- if (ret && keys_list[i].reverse_entry != NULL)
- {
- CcKeyboardItem *reverse_item;
- reverse_item = g_hash_table_lookup (reverse_items,
- keys_list[i].reverse_entry);
- if (reverse_item != NULL)
- {
- cc_keyboard_item_add_reverse_item (item,
- reverse_item,
- keys_list[i].is_reversed);
- }
- else
- {
- g_hash_table_insert (reverse_items,
- keys_list[i].name,
- item);
- }
- }
- break;
-
- default:
- g_assert_not_reached ();
- }
-
- if (ret == FALSE)
- {
- /* We don't actually want to popup a dialog - just skip this one */
- g_object_unref (item);
- continue;
- }
-
- cc_keyboard_item_set_hidden (item, keys_list[i].hidden);
- item->model = shortcut_model;
- item->group = group;
-
- g_signal_connect (G_OBJECT (item),
- "notify",
- G_CALLBACK (item_changed),
- NULL);
-
- g_ptr_array_add (keys_array, item);
- }
-
- g_hash_table_destroy (reverse_items);
-
- /* Add the keys to the hash table */
- if (is_new)
- {
- g_hash_table_insert (hash, g_strdup (id), keys_array);
-
- /* Append the section to the left tree view */
- gtk_list_store_append (GTK_LIST_STORE (self->sections_store), &iter);
- gtk_list_store_set (GTK_LIST_STORE (self->sections_store),
- &iter,
- SECTION_DESCRIPTION_COLUMN, title,
- SECTION_ID_COLUMN, id,
- SECTION_GROUP_COLUMN, group,
- -1);
- }
-}
-
-static void
-append_sections_from_file (CcKeyboardPanel *self,
- const gchar *path,
- const char *datadir,
- gchar **wm_keybindings)
-{
- GError *err = NULL;
- char *buf;
- gsize buf_len;
- KeyList *keylist;
- KeyListEntry *keys;
- KeyListEntry key = { 0, 0, 0, 0, 0, 0, 0 };
- const char *title;
- int group;
- guint i;
- GMarkupParseContext *ctx;
- GMarkupParser parser = { parse_start_tag, NULL, NULL, NULL, NULL };
-
- /* Parse file */
- if (!g_file_get_contents (path, &buf, &buf_len, &err))
- return;
-
- keylist = g_new0 (KeyList, 1);
- keylist->entries = g_array_new (FALSE, TRUE, sizeof (KeyListEntry));
- ctx = g_markup_parse_context_new (&parser, 0, keylist, NULL);
-
- if (!g_markup_parse_context_parse (ctx, buf, buf_len, &err))
- {
- g_warning ("Failed to parse '%s': '%s'", path, err->message);
- g_error_free (err);
- g_free (keylist->name);
- g_free (keylist->package);
- g_free (keylist->wm_name);
-
- for (i = 0; i < keylist->entries->len; i++)
- g_free (((KeyListEntry *) &(keylist->entries->data[i]))->name);
-
- g_array_free (keylist->entries, TRUE);
- g_free (keylist);
- keylist = NULL;
- }
- g_markup_parse_context_free (ctx);
- g_free (buf);
-
- if (keylist == NULL)
- return;
-
-#define const_strv(s) ((const gchar* const*) s)
-
- /* If there's no keys to add, or the settings apply to a window manager
- * that's not the one we're running */
- if (keylist->entries->len == 0 ||
- (keylist->wm_name != NULL && !g_strv_contains (const_strv (wm_keybindings), keylist->wm_name)) ||
- keylist->name == NULL)
- {
- g_free (keylist->name);
- g_free (keylist->package);
- g_free (keylist->wm_name);
- g_array_free (keylist->entries, TRUE);
- g_free (keylist);
- return;
- }
-
-#undef const_strv
-
- /* Empty KeyListEntry to end the array */
- key.name = NULL;
- g_array_append_val (keylist->entries, key);
-
- keys = (KeyListEntry *) g_array_free (keylist->entries, FALSE);
- if (keylist->package)
- {
- char *localedir;
-
- localedir = g_build_filename (datadir, "locale", NULL);
- bindtextdomain (keylist->package, localedir);
- g_free (localedir);
-
- title = dgettext (keylist->package, keylist->name);
- } else {
- title = _(keylist->name);
- }
- if (keylist->group && strcmp (keylist->group, "system") == 0)
- group = BINDING_GROUP_SYSTEM;
- else
- group = BINDING_GROUP_APPS;
-
-
-
- append_section (self, title, keylist->name, group, keys);
- g_free (keylist->name);
- g_free (keylist->package);
- g_free (keylist->wm_name);
- g_free (keylist->schema);
- g_free (keylist->group);
-
- for (i = 0; keys[i].name != NULL; i++)
- {
- KeyListEntry *entry = &keys[i];
- g_free (entry->schema);
- g_free (entry->description);
- g_free (entry->name);
- g_free (entry->reverse_entry);
- }
-
- g_free (keylist);
- g_free (keys);
-}
-
-static void
-append_sections_from_gsettings (CcKeyboardPanel *self)
-{
- char **custom_paths;
- GArray *entries;
- KeyListEntry key = { 0, 0, 0, 0, 0, 0, 0 };
- int i;
-
- /* load custom shortcuts from GSettings */
- entries = g_array_new (FALSE, TRUE, sizeof (KeyListEntry));
-
- custom_paths = g_settings_get_strv (self->binding_settings, "custom-keybindings");
- for (i = 0; custom_paths[i]; i++)
- {
- key.name = g_strdup (custom_paths[i]);
- if (!have_key_for_group (self, BINDING_GROUP_USER, key.name))
- {
- key.type = CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH;
- g_array_append_val (entries, key);
- }
- else
- g_free (key.name);
- }
- g_strfreev (custom_paths);
-
- if (entries->len > 0)
- {
- KeyListEntry *keys;
- int i;
-
- /* Empty KeyListEntry to end the array */
- key.name = NULL;
- g_array_append_val (entries, key);
-
- keys = (KeyListEntry *) entries->data;
- append_section (self, _("Custom Shortcuts"), CUSTOM_SHORTCUTS_ID, BINDING_GROUP_USER, keys);
- for (i = 0; i < entries->len; ++i)
- {
- g_free (keys[i].name);
- }
- }
- else
- {
- append_section (self, _("Custom Shortcuts"), CUSTOM_SHORTCUTS_ID, BINDING_GROUP_USER, NULL);
- }
-
- g_array_free (entries, TRUE);
-}
-
-static void
-reload_sections (CcKeyboardPanel *self)
-{
- GtkTreeModel *shortcut_model;
- GHashTable *loaded_files;
- GDir *dir;
- gchar *default_wm_keybindings[] = { "Mutter", "GNOME Shell", NULL };
- gchar **wm_keybindings;
- const gchar * const * data_dirs;
- guint i;
-
- shortcut_model = GTK_TREE_MODEL (self->shortcuts_model);
- /* FIXME: get current selection and keep it after refreshing */
-
- /* Clear previous models and hash tables */
- gtk_list_store_clear (GTK_LIST_STORE (self->sections_store));
- gtk_list_store_clear (GTK_LIST_STORE (shortcut_model));
-
- g_clear_pointer (&self->kb_system_sections, g_hash_table_destroy);
- self->kb_system_sections = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- (GDestroyNotify) free_key_array);
-
- g_clear_pointer (&self->kb_apps_sections, g_hash_table_destroy);
- self->kb_apps_sections = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- (GDestroyNotify) free_key_array);
-
- g_clear_pointer (&self->kb_user_sections, g_hash_table_destroy);
- self->kb_user_sections = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- (GDestroyNotify) free_key_array);
-
- /* Load WM keybindings */
-#ifdef GDK_WINDOWING_X11
- if (GDK_IS_X11_DISPLAY (gdk_display_get_default ()))
- wm_keybindings = wm_common_get_current_keybindings ();
- else
-#endif
- wm_keybindings = g_strdupv (default_wm_keybindings);
-
- loaded_files = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-
- data_dirs = g_get_system_data_dirs ();
- for (i = 0; data_dirs[i] != NULL; i++)
- {
- char *dir_path;
- const gchar *name;
-
- dir_path = g_build_filename (data_dirs[i], "gnome-control-center", "keybindings", NULL);
-
- dir = g_dir_open (dir_path, 0, NULL);
- if (!dir)
- {
- g_free (dir_path);
- continue;
- }
-
- for (name = g_dir_read_name (dir) ; name ; name = g_dir_read_name (dir))
- {
- gchar *path;
-
- if (g_str_has_suffix (name, ".xml") == FALSE)
- continue;
-
- if (g_hash_table_lookup (loaded_files, name) != NULL)
- {
- g_debug ("Not loading %s, it was already loaded from another directory", name);
- continue;
- }
-
- g_hash_table_insert (loaded_files, g_strdup (name), GINT_TO_POINTER (1));
- path = g_build_filename (dir_path, name, NULL);
- append_sections_from_file (self, path, data_dirs[i], wm_keybindings);
- g_free (path);
- }
- g_free (dir_path);
- g_dir_close (dir);
- }
-
- g_hash_table_destroy (loaded_files);
- g_strfreev (wm_keybindings);
-
- /* Load custom keybindings */
- append_sections_from_gsettings (self);
-}
-
-static int
-section_sort_item (GtkTreeModel *model,
- GtkTreeIter *a,
- GtkTreeIter *b,
- gpointer data)
-{
- char *a_desc;
- int a_group;
- char *b_desc;
- int b_group;
- int ret;
-
- gtk_tree_model_get (model, a,
- SECTION_DESCRIPTION_COLUMN, &a_desc,
- SECTION_GROUP_COLUMN, &a_group,
- -1);
- gtk_tree_model_get (model, b,
- SECTION_DESCRIPTION_COLUMN, &b_desc,
- SECTION_GROUP_COLUMN, &b_group,
- -1);
-
- if (a_group == b_group && a_desc && b_desc)
- ret = g_utf8_collate (a_desc, b_desc);
- else
- ret = a_group - b_group;
-
- g_free (a_desc);
- g_free (b_desc);
-
- return ret;
-}
-
-static void
-add_shortcuts (CcKeyboardPanel *self)
-{
- GtkTreeIter sections_iter;
- gboolean can_continue;
-
- can_continue = gtk_tree_model_get_iter_first (self->sections_model, §ions_iter);
-
- while (can_continue)
- {
- BindingGroupType group;
- GPtrArray *keys;
- gchar *id, *title;
- gint i;
-
- gtk_tree_model_get (self->sections_model,
- §ions_iter,
- SECTION_DESCRIPTION_COLUMN, &title,
- SECTION_GROUP_COLUMN, &group,
- SECTION_ID_COLUMN, &id,
- -1);
-
- /* Ignore separators */
- if (group == BINDING_GROUP_SEPARATOR)
- {
- can_continue = gtk_tree_model_iter_next (self->sections_model, §ions_iter);
- continue;
- }
-
- keys = g_hash_table_lookup (get_hash_for_group (self, group), id);
-
- for (i = 0; i < keys->len; i++)
- {
- CcKeyboardItem *item = g_ptr_array_index (keys, i);
-
- if (!cc_keyboard_item_is_hidden (item))
- {
- GtkTreeIter new_row;
-
- gtk_list_store_append (self->shortcuts_model, &new_row);
- gtk_list_store_set (self->shortcuts_model,
- &new_row,
- DETAIL_DESCRIPTION_COLUMN, item->description,
- DETAIL_KEYENTRY_COLUMN, item,
- DETAIL_TYPE_COLUMN, SHORTCUT_TYPE_KEY_ENTRY,
- -1);
-
- add_item (self, item, id, title);
- }
- }
-
- can_continue = gtk_tree_model_iter_next (self->sections_model, §ions_iter);
-
- g_free (title);
- g_free (id);
- }
-}
-
-static void
-shortcut_selection_changed (GtkTreeSelection *selection,
- GtkWidget *button)
-{
- GtkTreeModel *model;
- GtkTreeIter iter;
- gboolean can_remove;
-
- can_remove = FALSE;
-
- if (gtk_tree_selection_get_selected (selection, &model, &iter))
- {
- CcKeyboardItem *item;
- ShortcutType type;
-
- gtk_tree_model_get (model, &iter,
- DETAIL_KEYENTRY_COLUMN, &item,
- DETAIL_TYPE_COLUMN, &type,
- -1);
-
- if (type == SHORTCUT_TYPE_KEY_ENTRY &&
- item &&
- item->command != NULL &&
- item->editable)
- {
- can_remove = TRUE;
- }
- }
-
- gtk_widget_set_sensitive (button, can_remove);
-}
-
-
-static gboolean
-remove_custom_shortcut (CcKeyboardShortcutEditor *editor,
- CcKeyboardItem *item,
- CcKeyboardPanel *self)
-{
- GtkTreeModel *model;
- GtkTreeIter iter;
- GPtrArray *keys_array;
- GVariantBuilder builder;
- gboolean valid;
- char **settings_paths;
- int i;
-
- model = GTK_TREE_MODEL (self->shortcuts_model);
- valid = gtk_tree_model_get_iter_first (model, &iter);
-
- /* Search for the iter */
- while (valid)
- {
- CcKeyboardItem *current_item;
-
- gtk_tree_model_get (model, &iter,
- DETAIL_KEYENTRY_COLUMN, ¤t_item,
- -1);
-
- if (current_item == item)
- break;
-
- valid = gtk_tree_model_iter_next (model, &iter);
-
- g_clear_object (¤t_item);
- }
-
- if (!valid)
- g_error ("Tried to remove a non-existant shortcut");
-
- g_assert (item->type == CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH);
-
- remove_item (self, item);
-
- g_settings_delay (item->settings);
- g_settings_reset (item->settings, "name");
- g_settings_reset (item->settings, "command");
- g_settings_reset (item->settings, "binding");
- g_settings_apply (item->settings);
- g_settings_sync ();
-
- settings_paths = g_settings_get_strv (self->binding_settings, "custom-keybindings");
- g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
-
- for (i = 0; settings_paths[i]; i++)
- if (strcmp (settings_paths[i], item->gsettings_path) != 0)
- g_variant_builder_add (&builder, "s", settings_paths[i]);
-
- g_settings_set_value (self->binding_settings,
- "custom-keybindings",
- g_variant_builder_end (&builder));
-
- g_strfreev (settings_paths);
- g_object_unref (item);
-
- keys_array = g_hash_table_lookup (get_hash_for_group (self, BINDING_GROUP_USER), CUSTOM_SHORTCUTS_ID);
- g_ptr_array_remove (keys_array, item);
-
- gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
-
- return TRUE;
-}
-
-static void
-add_custom_shortcut (CcKeyboardShortcutEditor *editor,
- CcKeyboardItem *item,
- CcKeyboardPanel *self)
-{
- GtkTreePath *path;
- GPtrArray *keys_array;
- GtkTreeIter iter;
- GHashTable *hash;
- GVariantBuilder builder;
- char **settings_paths;
- int i;
-
- hash = get_hash_for_group (self, BINDING_GROUP_USER);
- keys_array = g_hash_table_lookup (hash, CUSTOM_SHORTCUTS_ID);
- if (keys_array == NULL)
- {
- keys_array = g_ptr_array_new ();
- g_hash_table_insert (hash, g_strdup (CUSTOM_SHORTCUTS_ID), keys_array);
- }
-
- g_ptr_array_add (keys_array, item);
-
- gtk_list_store_append (self->shortcuts_model, &iter);
- gtk_list_store_set (self->shortcuts_model, &iter, DETAIL_KEYENTRY_COLUMN, item, -1);
-
- settings_paths = g_settings_get_strv (self->binding_settings, "custom-keybindings");
- g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
- for (i = 0; settings_paths[i]; i++)
- g_variant_builder_add (&builder, "s", settings_paths[i]);
- g_variant_builder_add (&builder, "s", item->gsettings_path);
- g_settings_set_value (self->binding_settings, "custom-keybindings",
- g_variant_builder_end (&builder));
-
- /* make the new shortcut visible */
- path = gtk_tree_model_get_path (GTK_TREE_MODEL (self->shortcuts_model), &iter);
- gtk_tree_path_free (path);
-
- add_item (self, item, CUSTOM_SHORTCUTS_ID, _("Custom Shortcuts"));
-}
-
static void
shortcut_row_activated (GtkWidget *button,
GtkListBoxRow *row,
@@ -1055,34 +320,6 @@ shortcut_row_activated (GtkWidget *button,
}
static void
-setup_tree_views (CcKeyboardPanel *self)
-{
- /* Setup the section treeview */
- self->sections_store = gtk_list_store_new (SECTION_N_COLUMNS,
- G_TYPE_STRING,
- G_TYPE_STRING,
- G_TYPE_INT);
- self->sections_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (self->sections_store));
-
- gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (self->sections_model),
- SECTION_DESCRIPTION_COLUMN,
- section_sort_item,
- self,
- NULL);
-
- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (self->sections_model),
- SECTION_DESCRIPTION_COLUMN,
- GTK_SORT_ASCENDING);
-
- self->shortcuts_model = gtk_list_store_new (DETAIL_N_COLUMNS,
- G_TYPE_STRING,
- G_TYPE_POINTER,
- G_TYPE_INT);
-
- setup_keyboard_options (self->shortcuts_model);
-}
-
-static void
cc_keyboard_panel_set_property (GObject *object,
guint property_id,
const GValue *value,
@@ -1109,16 +346,8 @@ cc_keyboard_panel_finalize (GObject *object)
{
CcKeyboardPanel *self = CC_KEYBOARD_PANEL (object);
- g_clear_pointer (&self->kb_system_sections, g_hash_table_destroy);
- g_clear_pointer (&self->kb_apps_sections, g_hash_table_destroy);
- g_clear_pointer (&self->kb_user_sections, g_hash_table_destroy);
g_clear_pointer (&self->pictures_regex, g_regex_unref);
- g_clear_pointer (&self->wm_changed_id, wm_common_unregister_window_manager_change);
-
g_clear_object (&self->accelerator_sizegroup);
- g_clear_object (&self->binding_settings);
- g_clear_object (&self->sections_store);
- g_clear_object (&self->sections_model);
cc_keyboard_option_clear_all ();
@@ -1126,13 +355,6 @@ cc_keyboard_panel_finalize (GObject *object)
}
static void
-on_window_manager_change (const char *wm_name,
- CcKeyboardPanel *self)
-{
- reload_sections (self);
-}
-
-static void
cc_keyboard_panel_constructed (GObject *object)
{
CcKeyboardPanel *self = CC_KEYBOARD_PANEL (object);
@@ -1143,17 +365,6 @@ cc_keyboard_panel_constructed (GObject *object)
/* Setup the dialog's transient parent */
toplevel = GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (self))));
gtk_window_set_transient_for (GTK_WINDOW (self->shortcut_editor), toplevel);
-
-#ifdef GDK_WINDOWING_X11
- if (GDK_IS_X11_DISPLAY (gdk_display_get_default ()))
- self->wm_changed_id = wm_common_register_window_manager_change ((GFunc) on_window_manager_change,
- self);
-#endif
-
- setup_tree_views (self);
- reload_sections (self);
-
- add_shortcuts (self);
}
static void
@@ -1177,7 +388,6 @@ cc_keyboard_panel_class_init (CcKeyboardPanelClass *klass)
gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, listbox);
gtk_widget_class_bind_template_callback (widget_class, shortcut_row_activated);
- gtk_widget_class_bind_template_callback (widget_class, shortcut_selection_changed);
}
static void
@@ -1187,23 +397,28 @@ cc_keyboard_panel_init (CcKeyboardPanel *self)
gtk_widget_init_template (GTK_WIDGET (self));
- self->binding_settings = g_settings_new (BINDINGS_SCHEMA);
+ self->manager = cc_keyboard_manager_new ();
/* Use a sizegroup to make the accelerator labels the same width */
self->accelerator_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
/* Shortcut editor dialog */
- self->shortcut_editor = cc_keyboard_shortcut_editor_new (self);
+ self->shortcut_editor = cc_keyboard_shortcut_editor_new (self->manager);
+
+ g_signal_connect_swapped (self->manager,
+ "shortcut-added",
+ G_CALLBACK (add_item),
+ self);
- g_signal_connect (self->shortcut_editor,
- "add-custom-shortcut",
- G_CALLBACK (add_custom_shortcut),
- self);
+ g_signal_connect_swapped (self->manager,
+ "shortcut-removed",
+ G_CALLBACK (remove_item),
+ self);
- g_signal_connect (self->shortcut_editor,
- "remove-custom-shortcut",
- G_CALLBACK (remove_custom_shortcut),
- self);
+ cc_keyboard_manager_load_shortcuts (self->manager);
+
+ /* Shortcut editor dialog */
+ self->shortcut_editor = cc_keyboard_shortcut_editor_new (self->manager);
/* Setup the shortcuts listbox */
gtk_list_box_set_sort_func (GTK_LIST_BOX (self->listbox),
@@ -1217,31 +432,3 @@ cc_keyboard_panel_init (CcKeyboardPanel *self)
NULL);
}
-/**
- * cc_keyboard_panel_create_custom_item:
- * @self: a #CcKeyboardPanel
- *
- * Creates a new temporary keyboard shortcut.
- *
- * Returns: (transfer full): a #CcKeyboardItem
- */
-CcKeyboardItem*
-cc_keyboard_panel_create_custom_item (CcKeyboardPanel *self)
-{
- CcKeyboardItem *item;
- gchar *settings_path;
-
- g_return_val_if_fail (CC_IS_KEYBOARD_PANEL (self), NULL);
-
- item = cc_keyboard_item_new (CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH);
-
- settings_path = find_free_settings_path (self->binding_settings);
- cc_keyboard_item_load_from_gsettings_path (item, settings_path, TRUE);
- g_free (settings_path);
-
- item->model = GTK_TREE_MODEL (self->shortcuts_model);
- item->group = BINDING_GROUP_USER;
-
- return item;
-}
-
diff --git a/panels/keyboard/cc-keyboard-shortcut-editor.c b/panels/keyboard/cc-keyboard-shortcut-editor.c
index bd1917e..74b1911 100644
--- a/panels/keyboard/cc-keyboard-shortcut-editor.c
+++ b/panels/keyboard/cc-keyboard-shortcut-editor.c
@@ -55,7 +55,7 @@ struct _CcKeyboardShortcutEditor
GdkDevice *grab_device;
- CcKeyboardPanel *panel;
+ CcKeyboardManager *manager;
CcKeyboardItem *item;
/* Custom shortcuts */
@@ -77,19 +77,11 @@ enum
{
PROP_0,
PROP_KEYBOARD_ITEM,
- PROP_PANEL,
+ PROP_MANAGER,
N_PROPS
};
-enum
-{
- ADD_CUSTOM_SHORTCUT,
- REMOVE_CUSTOM_SHORTCUT,
- LAST_SIGNAL
-};
-
static GParamSpec *properties [N_PROPS] = { NULL, };
-static guint signals[LAST_SIGNAL] = { 0, };
static void
apply_custom_item_fields (CcKeyboardShortcutEditor *self,
@@ -274,7 +266,7 @@ add_button_clicked_cb (CcKeyboardShortcutEditor *self)
{
CcKeyboardItem *item;
- item = cc_keyboard_panel_create_custom_item (self->panel);
+ item = cc_keyboard_manager_create_custom_shortcut (self->manager);
/* Apply the custom shortcut setup at the new item */
apply_custom_item_fields (self, item);
@@ -282,7 +274,7 @@ add_button_clicked_cb (CcKeyboardShortcutEditor *self)
/* Cleanup everything once we're done */
clear_custom_entries (self);
- g_signal_emit (self, signals[ADD_CUSTOM_SHORTCUT], 0, item);
+ cc_keyboard_manager_add_custom_shortcut (self->manager, item);
gtk_widget_hide (GTK_WIDGET (self));
}
@@ -325,7 +317,7 @@ remove_button_clicked_cb (CcKeyboardShortcutEditor *self)
{
gtk_widget_hide (GTK_WIDGET (self));
- g_signal_emit (self, signals[REMOVE_CUSTOM_SHORTCUT], 0, self->item);
+ cc_keyboard_manager_remove_custom_shortcut (self->manager, self->item);
}
static void
@@ -392,7 +384,7 @@ cc_keyboard_shortcut_editor_finalize (GObject *object)
CcKeyboardShortcutEditor *self = (CcKeyboardShortcutEditor *)object;
g_clear_object (&self->item);
- g_clear_object (&self->panel);
+ g_clear_object (&self->manager);
G_OBJECT_CLASS (cc_keyboard_shortcut_editor_parent_class)->finalize (object);
}
@@ -411,8 +403,8 @@ cc_keyboard_shortcut_editor_get_property (GObject *object,
g_value_set_object (value, self->item);
break;
- case PROP_PANEL:
- g_value_set_pointer (value, self->panel);
+ case PROP_MANAGER:
+ g_value_set_object (value, self->manager);
break;
default:
@@ -434,8 +426,8 @@ cc_keyboard_shortcut_editor_set_property (GObject *object,
cc_keyboard_shortcut_editor_set_item (self, g_value_get_object (value));
break;
- case PROP_PANEL:
- g_set_object (&self->panel, g_value_get_pointer (value));
+ case PROP_MANAGER:
+ g_set_object (&self->manager, g_value_get_object (value));
break;
default:
@@ -572,36 +564,11 @@ cc_keyboard_shortcut_editor_class_init (CcKeyboardShortcutEditorClass *klass)
*
* The current keyboard panel.
*/
- properties[PROP_PANEL] = g_param_spec_pointer ("panel",
- "Keyboard panel",
- "The keyboard panel being edited",
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
-
- /**
- * CcKeyboardShortcutEditor:add-custom-shortcut:
- *
- * Emited when the user asks to add a custom shortcut.
- */
- signals[ADD_CUSTOM_SHORTCUT] = g_signal_new ("add-custom-shortcut",
- CC_TYPE_KEYBOARD_SHORTCUT_EDITOR,
- G_SIGNAL_RUN_FIRST,
- 0, NULL, NULL, NULL,
- G_TYPE_NONE,
- 1,
- CC_TYPE_KEYBOARD_ITEM);
-
- /**
- * CcKeyboardShortcutEditor:remove-custom-shortcut:
- *
- * Emited when the user asks to remove a custom shortcut.
- */
- signals[REMOVE_CUSTOM_SHORTCUT] = g_signal_new ("remove-custom-shortcut",
- CC_TYPE_KEYBOARD_SHORTCUT_EDITOR,
- G_SIGNAL_RUN_FIRST,
- 0, NULL, NULL, NULL,
- G_TYPE_NONE,
- 1,
- CC_TYPE_KEYBOARD_ITEM);
+ properties[PROP_MANAGER] = g_param_spec_object ("manager",
+ "Keyboard manager",
+ "The keyboard manager",
+ CC_TYPE_KEYBOARD_MANAGER,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, N_PROPS, properties);
@@ -645,10 +612,10 @@ cc_keyboard_shortcut_editor_init (CcKeyboardShortcutEditor *self)
* Returns: (transfer full): a newly created #CcKeyboardShortcutEditor.
*/
GtkWidget*
-cc_keyboard_shortcut_editor_new (CcKeyboardPanel *panel)
+cc_keyboard_shortcut_editor_new (CcKeyboardManager *manager)
{
return g_object_new (CC_TYPE_KEYBOARD_SHORTCUT_EDITOR,
- "panel", panel,
+ "manager", manager,
"use-header-bar", 1,
NULL);
}
diff --git a/panels/keyboard/cc-keyboard-shortcut-editor.h b/panels/keyboard/cc-keyboard-shortcut-editor.h
index c0fe675..a9455a8 100644
--- a/panels/keyboard/cc-keyboard-shortcut-editor.h
+++ b/panels/keyboard/cc-keyboard-shortcut-editor.h
@@ -24,7 +24,7 @@
#include <gtk/gtk.h>
#include "cc-keyboard-item.h"
-#include "cc-keyboard-panel.h"
+#include "cc-keyboard-manager.h"
G_BEGIN_DECLS
@@ -38,7 +38,7 @@ typedef enum
G_DECLARE_FINAL_TYPE (CcKeyboardShortcutEditor, cc_keyboard_shortcut_editor, CC, KEYBOARD_SHORTCUT_EDITOR,
GtkDialog)
-GtkWidget* cc_keyboard_shortcut_editor_new (CcKeyboardPanel *panel);
+GtkWidget* cc_keyboard_shortcut_editor_new (CcKeyboardManager *manager);
CcKeyboardItem* cc_keyboard_shortcut_editor_get_item (CcKeyboardShortcutEditor *self);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]