diff options
Diffstat (limited to 'panels/keyboard/cc-keyboard-manager.c')
-rw-r--r-- | panels/keyboard/cc-keyboard-manager.c | 923 |
1 files changed, 923 insertions, 0 deletions
diff --git a/panels/keyboard/cc-keyboard-manager.c b/panels/keyboard/cc-keyboard-manager.c new file mode 100644 index 0000000..55ae3af --- /dev/null +++ b/panels/keyboard/cc-keyboard-manager.c @@ -0,0 +1,923 @@ +/* + * 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 *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 gboolean +find_conflict (CcUniquenessData *data, + CcKeyboardItem *item) +{ + GList *l; + gboolean is_conflict = FALSE; + + if (data->orig_item && cc_keyboard_item_equal (data->orig_item, item)) + return FALSE; + + for (l = cc_keyboard_item_get_key_combos (item); l; l = l->next) + { + CcKeyCombo *combo = l->data; + + if (data->new_mask != combo->mask) + continue; + + if (data->new_keyval != 0) + is_conflict = data->new_keyval == combo->keyval; + else + is_conflict = combo->keyval == 0 && data->new_keycode == combo->keycode; + + if (is_conflict) + break; + } + + if (is_conflict) + data->conflict_item = item; + + return is_conflict; +} + +static gboolean +compare_keys_for_uniqueness (CcKeyboardItem *current_item, + CcUniquenessData *data) +{ + CcKeyboardItem *reverse_item; + + /* No conflict for: blanks or ourselves */ + if (!current_item || data->orig_item == current_item) + return FALSE; + + reverse_item = cc_keyboard_item_get_reverse_item (current_item); + + /* When the current item is the reversed shortcut of a main item, simply ignore it */ + if (reverse_item && cc_keyboard_item_is_hidden (current_item)) + return FALSE; + + if (find_conflict (data, current_item)) + return TRUE; + + /* Also check for the reverse item if any */ + if (reverse_item && find_conflict (data, reverse_item)) + return TRUE; + + return FALSE; +} + +static gboolean +check_for_uniqueness (gpointer key, + GPtrArray *keys_array, + CcUniquenessData *data) +{ + guint i; + + for (i = 0; i < keys_array->len; i++) + { + CcKeyboardItem *item; + + item = keys_array->pdata[i]; + + if (compare_keys_for_uniqueness (item, data)) + return TRUE; + } + + return FALSE; +} + + +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 (cc_keyboard_item_get_item_type (item) == CC_KEYBOARD_ITEM_TYPE_GSETTINGS && + g_strcmp0 (name, cc_keyboard_item_get_key (item)) == 0) + { + return TRUE; + } + } + } + + 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; + g_autofree gchar *id = NULL; + g_autofree gchar *title = NULL; + 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)) + { + g_signal_emit (self, signals[SHORTCUT_ADDED], + 0, + item, + id, + title); + } + } + + can_continue = gtk_tree_model_iter_next (sections_model, §ions_iter); + } +} + +static void +append_section (CcKeyboardManager *self, + const gchar *title, + const gchar *id, + BindingGroupType group, + const KeyListEntry *keys_list) +{ + 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; + + /* 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); + + 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) +{ + KeyList *keylist; + KeyListEntry *keys; + KeyListEntry key = { 0, 0, 0, 0, 0, 0, 0 }; + const char *title; + int group; + guint i; + + keylist = parse_keylist_from_file (path); + + 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) + { + g_autofree gchar *localedir = NULL; + + localedir = g_build_filename (datadir, "locale", NULL); + bindtextdomain (keylist->package, 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) +{ + g_auto(GStrv) custom_paths = NULL; + 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); + } + + 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) +{ + GHashTable *loaded_files; + GDir *dir; + gchar *default_wm_keybindings[] = { "Mutter", "GNOME Shell", NULL }; + g_auto(GStrv) wm_keybindings = NULL; + const gchar * const * data_dirs; + guint i; + + /* Clear previous models and hash tables */ + gtk_list_store_clear (GTK_LIST_STORE (self->sections_store)); + + 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++) + { + g_autofree gchar *dir_path = NULL; + 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) + continue; + + for (name = g_dir_read_name (dir) ; name ; name = g_dir_read_name (dir)) + { + g_autofree gchar *path = NULL; + + 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_dir_close (dir); + } + + g_hash_table_destroy (loaded_files); + + /* 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: + * + * Emitted 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: + * + * Emitted 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: + * + * Emitted 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); + +#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; + g_autofree gchar *settings_path = NULL; + + 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); + + 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; + 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); + + 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", cc_keyboard_item_get_gsettings_path (item)); + + 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) +{ + GPtrArray *keys_array; + GVariantBuilder builder; + GSettings *settings; + char **settings_paths; + int i; + + g_return_if_fail (CC_IS_KEYBOARD_MANAGER (self)); + + /* Shortcut not a custom shortcut */ + g_assert (cc_keyboard_item_get_item_type (item) == CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH); + + settings = cc_keyboard_item_get_settings (item); + g_settings_delay (settings); + g_settings_reset (settings, "name"); + g_settings_reset (settings, "command"); + g_settings_reset (settings, "binding"); + g_settings_apply (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], cc_keyboard_item_get_gsettings_path (item)) != 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); + + g_signal_emit (self, signals[SHORTCUT_REMOVED], 0, item); +} + +/** + * cc_keyboard_manager_get_collision: + * @self: a #CcKeyboardManager + * @item: (nullable): a keyboard shortcut + * @combo: a #CcKeyCombo + * + * Retrieves the collision item for the given shortcut. + * + * Returns: (transfer none)(nullable): the collisioned shortcut + */ +CcKeyboardItem* +cc_keyboard_manager_get_collision (CcKeyboardManager *self, + CcKeyboardItem *item, + CcKeyCombo *combo) +{ + CcUniquenessData data; + BindingGroupType i; + + g_return_val_if_fail (CC_IS_KEYBOARD_MANAGER (self), NULL); + + data.orig_item = item; + data.new_keyval = combo->keyval; + data.new_mask = combo->mask; + data.new_keycode = combo->keycode; + data.conflict_item = NULL; + + if (combo->keyval == 0 && combo->keycode == 0) + return NULL; + + /* Any number of shortcuts can be disabled */ + for (i = BINDING_GROUP_SYSTEM; i <= BINDING_GROUP_USER && !data.conflict_item; i++) + { + GHashTable *table; + + table = get_hash_for_group (self, i); + + if (!table) + continue; + + g_hash_table_find (table, (GHRFunc) check_for_uniqueness, &data); + } + + return data.conflict_item; +} + +/** + * cc_keyboard_manager_disable_shortcut: + * @self: a #CcKeyboardManager + * @item: a @CcKeyboardItem + * + * Disables the given keyboard shortcut. + */ +void +cc_keyboard_manager_disable_shortcut (CcKeyboardManager *self, + CcKeyboardItem *item) +{ + g_return_if_fail (CC_IS_KEYBOARD_MANAGER (self)); + + g_object_set (item, "binding", NULL, NULL); +} + +/** + * cc_keyboard_manager_reset_shortcut: + * @self: a #CcKeyboardManager + * @item: a #CcKeyboardItem + * + * Resets the keyboard shortcut managed by @item, and eventually + * disables any shortcut that conflicts with the new shortcut's + * value. + */ +void +cc_keyboard_manager_reset_shortcut (CcKeyboardManager *self, + CcKeyboardItem *item) +{ + GList *l; + + g_return_if_fail (CC_IS_KEYBOARD_MANAGER (self)); + g_return_if_fail (CC_IS_KEYBOARD_ITEM (item)); + + /* Disables any shortcut that conflicts with the new shortcut's value */ + for (l = cc_keyboard_item_get_default_combos (item); l; l = l->next) + { + CcKeyCombo *combo = l->data; + CcKeyboardItem *collision; + + collision = cc_keyboard_manager_get_collision (self, NULL, combo); + if (collision) + cc_keyboard_manager_disable_shortcut (self, collision); + } + + /* Resets the current item */ + cc_keyboard_item_reset (item); +} |