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 new backend class handles the loading, creation and removal and search of keyboard shortcuts. It also resolves reversible shortcuts when searching. This patch moves the code to this new class, and updates the rest of the Keyboard panel to use it instead. https://bugzilla.gnome.org/show_bug.cgi?id=769063
This commit is contained in:
parent
70bba2bbcd
commit
60b235754e
6 changed files with 906 additions and 851 deletions
|
@ -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 \
|
||||
|
|
817
panels/keyboard/cc-keyboard-manager.c
Normal file
817
panels/keyboard/cc-keyboard-manager.c
Normal file
|
@ -0,0 +1,817 @@
|
|||
/*
|
||||
* 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
51
panels/keyboard/cc-keyboard-manager.h
Normal file
51
panels/keyboard/cc-keyboard-manager.h
Normal file
|
@ -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 */
|
||||
|
|
@ -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 models */
|
||||
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)
|
||||
|
@ -307,694 +291,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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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,
|
||||
|
@ -1020,34 +316,6 @@ shortcut_row_activated (GtkWidget *button,
|
|||
gtk_widget_show (self->shortcut_editor);
|
||||
}
|
||||
|
||||
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,
|
||||
|
@ -1075,30 +343,14 @@ 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->shortcuts_model);
|
||||
g_clear_object (&self->sections_store);
|
||||
g_clear_object (&self->sections_model);
|
||||
|
||||
cc_keyboard_option_clear_all ();
|
||||
|
||||
G_OBJECT_CLASS (cc_keyboard_panel_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
on_window_manager_change (const char *wm_name,
|
||||
CcKeyboardPanel *self)
|
||||
{
|
||||
reload_sections (self);
|
||||
}
|
||||
|
||||
static void
|
||||
cc_keyboard_panel_constructed (GObject *object)
|
||||
{
|
||||
|
@ -1110,17 +362,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
|
||||
|
@ -1144,7 +385,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
|
||||
|
@ -1154,24 +394,29 @@ 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 (self->shortcut_editor,
|
||||
"add-custom-shortcut",
|
||||
G_CALLBACK (add_custom_shortcut),
|
||||
g_signal_connect_swapped (self->manager,
|
||||
"shortcut-added",
|
||||
G_CALLBACK (add_item),
|
||||
self);
|
||||
|
||||
g_signal_connect (self->shortcut_editor,
|
||||
"remove-custom-shortcut",
|
||||
G_CALLBACK (remove_custom_shortcut),
|
||||
g_signal_connect_swapped (self->manager,
|
||||
"shortcut-removed",
|
||||
G_CALLBACK (remove_item),
|
||||
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),
|
||||
sort_function,
|
||||
|
@ -1184,31 +429,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ struct _CcKeyboardShortcutEditor
|
|||
|
||||
GdkDevice *grab_device;
|
||||
|
||||
CcKeyboardPanel *panel;
|
||||
CcKeyboardManager *manager;
|
||||
CcKeyboardItem *item;
|
||||
|
||||
/* Custom shortcuts */
|
||||
|
@ -72,19 +72,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,
|
||||
|
@ -271,7 +263,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);
|
||||
|
@ -279,7 +271,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));
|
||||
}
|
||||
|
@ -322,7 +314,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
|
||||
|
@ -389,6 +381,7 @@ cc_keyboard_shortcut_editor_finalize (GObject *object)
|
|||
CcKeyboardShortcutEditor *self = (CcKeyboardShortcutEditor *)object;
|
||||
|
||||
g_clear_object (&self->item);
|
||||
g_clear_object (&self->manager);
|
||||
|
||||
G_OBJECT_CLASS (cc_keyboard_shortcut_editor_parent_class)->finalize (object);
|
||||
}
|
||||
|
@ -407,8 +400,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:
|
||||
|
@ -430,8 +423,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:
|
||||
self->panel = g_value_get_pointer (value);
|
||||
case PROP_MANAGER:
|
||||
g_set_object (&self->manager, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -562,37 +555,12 @@ 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",
|
||||
properties[PROP_MANAGER] = g_param_spec_object ("manager",
|
||||
"Keyboard manager",
|
||||
"The keyboard manager",
|
||||
CC_TYPE_KEYBOARD_MANAGER,
|
||||
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);
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
|
||||
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/keyboard/shortcut-editor.ui");
|
||||
|
@ -635,10 +603,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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue