2
* Copyright (C) 2010 Intel, Inc
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
* Authors: Thomas Wood <thomas.wood@intel.com>
19
* Rodrigo Moya <rodrigo@gnome.org>
24
#include <glib/gi18n.h>
25
#include <gconf/gconf-client.h>
26
#include "eggcellrendererkeys.h"
27
#include "keyboard-shortcuts.h"
28
#include "cc-keyboard-item.h"
29
#include "wm-common.h"
31
#define MAX_CUSTOM_SHORTCUTS 1000
32
#define GCONF_BINDING_DIR "/desktop/gnome/keybindings"
33
#define WID(builder, name) (GTK_WIDGET (gtk_builder_get_object (builder, name)))
37
/* The group of keybindings (system or application) */
39
/* The gettext package to use to translate the section title */
41
/* Name of the window manager the keys would apply to */
43
/* The GSettings schema for the whole file, if any */
45
/* an array of KeyListEntry */
58
CcKeyboardItemType type;
59
char *schema; /* GSettings schema name, if any */
60
char *description; /* description for GSettings types */
61
char *gettext_package; /* used for GConf type */
62
char *name; /* GConf key, GConf directory, or GSettings key name depending on type */
63
int value; /* Value for comparison */
64
char *key; /* GConf key name for the comparison */
65
Comparison comparison;
70
DETAIL_DESCRIPTION_COLUMN,
71
DETAIL_KEYENTRY_COLUMN,
77
SECTION_DESCRIPTION_COLUMN,
82
static guint maybe_block_accels_id = 0;
83
static gboolean block_accels = FALSE;
84
static GtkWidget *custom_shortcut_dialog = NULL;
85
static GtkWidget *custom_shortcut_name_entry = NULL;
86
static GtkWidget *custom_shortcut_command_entry = NULL;
87
static GHashTable *kb_system_sections = NULL;
88
static GHashTable *kb_apps_sections = NULL;
89
static GHashTable *kb_user_sections = NULL;
90
static guint workspace_num_notify_id = 0;
93
free_key_array (GPtrArray *keys)
99
for (i = 0; i < keys->len; i++)
101
CcKeyboardItem *item;
103
item = g_ptr_array_index (keys, i);
105
g_object_unref (item);
108
g_ptr_array_free (keys, TRUE);
113
get_hash_for_group (BindingGroupType group)
119
case BINDING_GROUP_SYSTEM:
120
hash = kb_system_sections;
122
case BINDING_GROUP_APPS:
123
hash = kb_apps_sections;
125
case BINDING_GROUP_USER:
126
hash = kb_user_sections;
129
g_assert_not_reached ();
135
have_key_for_group (int group, const gchar *name)
141
g_hash_table_iter_init (&iter, get_hash_for_group (group));
142
while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&keys))
144
for (i = 0; i < keys->len; i++)
146
CcKeyboardItem *item = g_ptr_array_index (keys, i);
148
if (g_strcmp0 (name, item->gconf_key) == 0)
157
should_show_key (const KeyListEntry *entry)
162
if (entry->comparison == COMPARISON_NONE)
165
g_return_val_if_fail (entry->key != NULL, FALSE);
167
/* FIXME: We'll need to change that when metacity/mutter
169
g_assert (entry->type == CC_KEYBOARD_ITEM_TYPE_GCONF);
171
client = gconf_client_get_default();
172
value = gconf_client_get_int (client, entry->key, NULL);
173
g_object_unref (client);
175
switch (entry->comparison) {
176
case COMPARISON_NONE:
177
/* For compiler warnings */
178
g_assert_not_reached ();
181
if (value > entry->value)
185
if (value < entry->value)
189
if (value == entry->value)
198
keybinding_key_changed_foreach (GtkTreeModel *model,
201
CcKeyboardItem *item)
203
CcKeyboardItem *tmp_item;
205
gtk_tree_model_get (item->model, iter,
206
DETAIL_KEYENTRY_COLUMN, &tmp_item,
209
if (item == tmp_item)
211
gtk_tree_model_row_changed (item->model, path, iter);
218
item_changed (CcKeyboardItem *item,
222
/* update the model */
223
gtk_tree_model_foreach (item->model, (GtkTreeModelForeachFunc) keybinding_key_changed_foreach, item);
227
append_section (GtkBuilder *builder,
229
BindingGroupType group,
230
const KeyListEntry *keys_list)
232
GPtrArray *keys_array;
233
GtkTreeModel *sort_model;
234
GtkTreeModel *model, *shortcut_model;
240
hash = get_hash_for_group (group);
242
sort_model = gtk_tree_view_get_model (GTK_TREE_VIEW (gtk_builder_get_object (builder, "section_treeview")));
243
model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (sort_model));
245
shortcut_model = gtk_tree_view_get_model (GTK_TREE_VIEW (gtk_builder_get_object (builder, "shortcut_treeview")));
247
/* Add all CcKeyboardItems for this section */
249
keys_array = g_hash_table_lookup (hash, title);
250
if (keys_array == NULL)
252
keys_array = g_ptr_array_new ();
256
for (i = 0; keys_list != NULL && keys_list[i].name != NULL; i++)
258
CcKeyboardItem *item;
261
if (!should_show_key (&keys_list[i]))
264
if (have_key_for_group (group, keys_list[i].name)) /* FIXME broken for GSettings */
267
item = cc_keyboard_item_new (keys_list[i].type);
268
switch (keys_list[i].type)
270
case CC_KEYBOARD_ITEM_TYPE_GCONF:
271
ret = cc_keyboard_item_load_from_gconf (item, keys_list[i].gettext_package, keys_list[i].name);
273
case CC_KEYBOARD_ITEM_TYPE_GCONF_DIR:
274
ret = cc_keyboard_item_load_from_gconf_dir (item, keys_list[i].name);
276
case CC_KEYBOARD_ITEM_TYPE_GSETTINGS:
277
ret = cc_keyboard_item_load_from_gsettings (item,
278
keys_list[i].description,
283
g_assert_not_reached ();
288
/* We don't actually want to popup a dialog - just skip this one */
289
g_object_unref (item);
293
item->model = shortcut_model;
296
g_signal_connect (G_OBJECT (item), "notify",
297
G_CALLBACK (item_changed), NULL);
299
g_ptr_array_add (keys_array, item);
302
/* Add the keys to the hash table */
305
static gboolean have_sep = FALSE;
307
g_hash_table_insert (hash, g_strdup (title), keys_array);
309
/* Append the section to the left tree view */
310
gtk_list_store_append (GTK_LIST_STORE (model), &iter);
311
gtk_list_store_set (GTK_LIST_STORE (model), &iter,
312
SECTION_DESCRIPTION_COLUMN, title,
313
SECTION_GROUP_COLUMN, group,
315
if (!have_sep && group != BINDING_GROUP_SYSTEM)
318
/* Append the section to the left tree view */
319
gtk_list_store_append (GTK_LIST_STORE (model), &iter);
320
gtk_list_store_set (GTK_LIST_STORE (model), &iter,
321
SECTION_DESCRIPTION_COLUMN, NULL,
322
SECTION_GROUP_COLUMN, BINDING_GROUP_SYSTEM,
329
parse_start_tag (GMarkupParseContext *ctx,
330
const gchar *element_name,
331
const gchar **attr_names,
332
const gchar **attr_values,
336
KeyList *keylist = (KeyList *) user_data;
338
const char *name, *gconf_key, *schema, *description, *package;
340
Comparison comparison;
346
/* The top-level element, names the section in the tree */
347
if (g_str_equal (element_name, "KeyListEntries"))
349
const char *wm_name = NULL;
350
const char *group = NULL;
352
while (*attr_names && *attr_values)
354
if (g_str_equal (*attr_names, "name"))
358
} else if (g_str_equal (*attr_names, "group")) {
360
group = *attr_values;
361
} else if (g_str_equal (*attr_names, "wm_name")) {
363
wm_name = *attr_values;
364
} else if (g_str_equal (*attr_names, "schema")) {
366
schema = *attr_values;
367
} else if (g_str_equal (*attr_names, "package")) {
369
package = *attr_values;
378
g_warning ("Duplicate section name");
379
g_free (keylist->name);
380
keylist->name = g_strdup (name);
384
if (keylist->wm_name)
385
g_warning ("Duplicate window manager name");
386
g_free (keylist->wm_name);
387
keylist->wm_name = g_strdup (wm_name);
391
if (keylist->package)
392
g_warning ("Duplicate gettext package name");
393
g_free (keylist->package);
394
keylist->package = g_strdup (package);
395
bind_textdomain_codeset (keylist->package, "UTF-8");
400
g_warning ("Duplicate group");
401
g_free (keylist->group);
402
keylist->group = g_strdup (group);
407
g_warning ("Duplicate schema");
408
g_free (keylist->schema);
409
keylist->schema = g_strdup (schema);
414
if (!g_str_equal (element_name, "KeyListEntry")
415
|| attr_names == NULL
416
|| attr_values == NULL)
420
comparison = COMPARISON_NONE;
425
while (*attr_names && *attr_values)
427
if (g_str_equal (*attr_names, "name"))
432
} else if (g_str_equal (*attr_names, "value")) {
434
value = (int) g_ascii_strtoull (*attr_values, NULL, 0);
436
} else if (g_str_equal (*attr_names, "key")) {
438
gconf_key = *attr_values;
440
} else if (g_str_equal (*attr_names, "schema")) {
442
schema = *attr_values;
444
} else if (g_str_equal (*attr_names, "description")) {
446
if (keylist->package)
448
description = dgettext (keylist->package, *attr_values);
452
description = _(*attr_values);
455
} else if (g_str_equal (*attr_names, "comparison")) {
457
if (g_str_equal (*attr_values, "gt")) {
458
comparison = COMPARISON_GT;
459
} else if (g_str_equal (*attr_values, "lt")) {
460
comparison = COMPARISON_LT;
461
} else if (g_str_equal (*attr_values, "eq")) {
462
comparison = COMPARISON_EQ;
474
key.name = g_strdup (name);
475
if (schema != NULL ||
476
keylist->schema != NULL)
477
key.type = CC_KEYBOARD_ITEM_TYPE_GSETTINGS;
479
key.type = CC_KEYBOARD_ITEM_TYPE_GCONF;
481
key.key = g_strdup (gconf_key);
482
key.description = g_strdup (description);
483
key.gettext_package = g_strdup (keylist->package);
484
key.schema = schema ? g_strdup (schema) : g_strdup (keylist->schema);
485
key.comparison = comparison;
486
g_array_append_val (keylist->entries, key);
490
strv_contains (char **strv,
494
for (p = strv; *p; p++)
495
if (strcmp (*p, str) == 0)
502
append_sections_from_file (GtkBuilder *builder, const gchar *path, const char *datadir, gchar **wm_keybindings)
508
KeyListEntry key, *keys;
512
GMarkupParseContext *ctx;
513
GMarkupParser parser = { parse_start_tag, NULL, NULL, NULL, NULL };
516
if (!g_file_get_contents (path, &buf, &buf_len, &err))
519
keylist = g_new0 (KeyList, 1);
520
keylist->entries = g_array_new (FALSE, TRUE, sizeof (KeyListEntry));
521
ctx = g_markup_parse_context_new (&parser, 0, keylist, NULL);
523
if (!g_markup_parse_context_parse (ctx, buf, buf_len, &err))
525
g_warning ("Failed to parse '%s': '%s'", path, err->message);
527
g_free (keylist->name);
528
g_free (keylist->package);
529
g_free (keylist->wm_name);
530
for (i = 0; i < keylist->entries->len; i++)
531
g_free (((KeyListEntry *) &(keylist->entries->data[i]))->name);
532
g_array_free (keylist->entries, TRUE);
536
g_markup_parse_context_free (ctx);
542
/* If there's no keys to add, or the settings apply to a window manager
543
* that's not the one we're running */
544
if (keylist->entries->len == 0
545
|| (keylist->wm_name != NULL && !strv_contains (wm_keybindings, keylist->wm_name))
546
|| keylist->name == NULL)
548
g_free (keylist->name);
549
g_free (keylist->package);
550
g_free (keylist->wm_name);
551
g_array_free (keylist->entries, TRUE);
556
/* Empty KeyListEntry to end the array */
560
key.comparison = COMPARISON_NONE;
561
g_array_append_val (keylist->entries, key);
563
keys = (KeyListEntry *) g_array_free (keylist->entries, FALSE);
564
if (keylist->package)
568
localedir = g_build_filename (datadir, "locale", NULL);
569
bindtextdomain (keylist->package, localedir);
572
title = dgettext (keylist->package, keylist->name);
574
title = _(keylist->name);
576
if (keylist->group && strcmp (keylist->group, "system") == 0)
577
group = BINDING_GROUP_SYSTEM;
579
group = BINDING_GROUP_APPS;
581
append_section (builder, title, group, keys);
583
g_free (keylist->name);
584
g_free (keylist->package);
585
g_free (keylist->wm_name);
586
g_free (keylist->schema);
587
g_free (keylist->group);
589
for (i = 0; keys[i].name != NULL; i++) {
590
KeyListEntry *entry = &keys[i];
591
g_free (entry->schema);
592
g_free (entry->description);
593
g_free (entry->gettext_package);
594
g_free (entry->name);
602
append_sections_from_gconf (GtkBuilder *builder, const gchar *gconf_path)
605
GSList *custom_list, *l;
609
/* load custom shortcuts from GConf */
610
entries = g_array_new (FALSE, TRUE, sizeof (KeyListEntry));
614
key.comparison = COMPARISON_NONE;
616
client = gconf_client_get_default ();
617
custom_list = gconf_client_all_dirs (client, gconf_path, NULL);
619
for (l = custom_list; l != NULL; l = l->next)
621
key.name = g_strdup (l->data);
622
if (!have_key_for_group (BINDING_GROUP_USER, key.name))
624
key.type = CC_KEYBOARD_ITEM_TYPE_GCONF_DIR;
625
g_array_append_val (entries, key);
633
g_slist_free (custom_list);
634
g_object_unref (client);
636
if (entries->len > 0)
641
/* Empty KeyListEntry to end the array */
643
g_array_append_val (entries, key);
645
keys = (KeyListEntry *) entries->data;
646
append_section (builder, _("Custom Shortcuts"), BINDING_GROUP_USER, keys);
647
for (i = 0; i < entries->len; ++i)
649
g_free (keys[i].name);
654
append_section (builder, _("Custom Shortcuts"), BINDING_GROUP_USER, NULL);
657
g_array_free (entries, TRUE);
661
reload_sections (GtkBuilder *builder)
663
gchar **wm_keybindings;
666
GtkTreeModel *sort_model;
667
GtkTreeModel *section_model;
668
GtkTreeModel *shortcut_model;
669
const gchar * const * data_dirs;
671
GtkTreeView *section_treeview;
672
GtkTreeSelection *selection;
675
section_treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "section_treeview"));
676
sort_model = gtk_tree_view_get_model (section_treeview);
677
section_model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (sort_model));
679
shortcut_model = gtk_tree_view_get_model (GTK_TREE_VIEW (gtk_builder_get_object (builder, "shortcut_treeview")));
680
/* FIXME: get current selection and keep it after refreshing */
682
/* Clear previous models and hash tables */
683
gtk_list_store_clear (GTK_LIST_STORE (section_model));
684
gtk_list_store_clear (GTK_LIST_STORE (shortcut_model));
685
if (kb_system_sections != NULL)
686
g_hash_table_destroy (kb_system_sections);
687
kb_system_sections = g_hash_table_new_full (g_str_hash,
690
(GDestroyNotify) free_key_array);
692
if (kb_apps_sections != NULL)
693
g_hash_table_destroy (kb_apps_sections);
694
kb_apps_sections = g_hash_table_new_full (g_str_hash,
697
(GDestroyNotify) free_key_array);
699
if (kb_user_sections != NULL)
700
g_hash_table_destroy (kb_user_sections);
701
kb_user_sections = g_hash_table_new_full (g_str_hash,
704
(GDestroyNotify) free_key_array);
706
/* Load WM keybindings */
707
wm_keybindings = wm_common_get_current_keybindings ();
709
data_dirs = g_get_system_data_dirs ();
710
for (i = 0; data_dirs[i] != NULL; i++)
714
dir_path = g_build_filename (data_dirs[i], "gnome-control-center", "keybindings", NULL);
716
dir = g_dir_open (dir_path, 0, NULL);
723
for (name = g_dir_read_name (dir) ; name ; name = g_dir_read_name (dir))
725
if (g_str_has_suffix (name, ".xml"))
729
path = g_build_filename (dir_path, name, NULL);
730
append_sections_from_file (builder, path, data_dirs[i], wm_keybindings);
739
g_strfreev (wm_keybindings);
741
/* Load custom keybindings */
742
append_sections_from_gconf (builder, GCONF_BINDING_DIR);
744
/* Select the first item */
745
gtk_tree_model_get_iter_first (sort_model, &iter);
746
selection = gtk_tree_view_get_selection (section_treeview);
747
gtk_tree_selection_select_iter (selection, &iter);
751
accel_set_func (GtkTreeViewColumn *tree_column,
752
GtkCellRenderer *cell,
757
CcKeyboardItem *item;
759
gtk_tree_model_get (model, iter,
760
DETAIL_KEYENTRY_COLUMN, &item,
767
else if (! item->editable)
771
"accel_key", item->keyval,
772
"accel_mask", item->mask,
773
"keycode", item->keycode,
774
"style", PANGO_STYLE_ITALIC,
780
"accel_key", item->keyval,
781
"accel_mask", item->mask,
782
"keycode", item->keycode,
783
"style", PANGO_STYLE_NORMAL,
788
description_set_func (GtkTreeViewColumn *tree_column,
789
GtkCellRenderer *cell,
794
CcKeyboardItem *item;
796
gtk_tree_model_get (model, iter,
797
DETAIL_KEYENTRY_COLUMN, &item,
803
"text", item->description != NULL ?
804
item->description : _("<Unknown Action>"),
808
"editable", FALSE, NULL);
812
shortcut_selection_changed (GtkTreeSelection *selection, gpointer data)
814
GtkWidget *button = data;
817
CcKeyboardItem *item;
821
if (gtk_tree_selection_get_selected (selection, &model, &iter))
823
gtk_tree_model_get (model, &iter, DETAIL_KEYENTRY_COLUMN, &item, -1);
824
if (item && item->command != NULL && item->editable)
828
gtk_widget_set_sensitive (button, can_remove);
832
section_selection_changed (GtkTreeSelection *selection, gpointer data)
836
GtkBuilder *builder = GTK_BUILDER (data);
838
if (gtk_tree_selection_get_selected (selection, &model, &iter))
841
GtkWidget *shortcut_treeview;
842
GtkTreeModel *shortcut_model;
844
BindingGroupType group;
847
gtk_tree_model_get (model, &iter,
848
SECTION_DESCRIPTION_COLUMN, &description,
849
SECTION_GROUP_COLUMN, &group, -1);
851
keys = g_hash_table_lookup (get_hash_for_group (group), description);
854
g_warning ("Can't find section %s in sections hash table!!!", description);
858
gtk_widget_set_sensitive (WID (builder, "add-toolbutton"),
859
group == BINDING_GROUP_USER);
860
gtk_widget_set_sensitive (WID (builder, "remove-toolbutton"), FALSE);
862
/* Fill the shortcut treeview with the keys for the selected section */
863
shortcut_treeview = GTK_WIDGET (gtk_builder_get_object (builder, "shortcut_treeview"));
864
shortcut_model = gtk_tree_view_get_model (GTK_TREE_VIEW (shortcut_treeview));
865
gtk_list_store_clear (GTK_LIST_STORE (shortcut_model));
867
for (i = 0; i < keys->len; i++)
870
CcKeyboardItem *item = g_ptr_array_index (keys, i);
872
gtk_list_store_append (GTK_LIST_STORE (shortcut_model), &new_row);
873
gtk_list_store_set (GTK_LIST_STORE (shortcut_model), &new_row,
874
DETAIL_DESCRIPTION_COLUMN, item->description,
875
DETAIL_KEYENTRY_COLUMN, item,
883
GtkTreeView *tree_view;
885
GtkTreeViewColumn *column;
889
edit_custom_shortcut (CcKeyboardItem *item)
892
const gchar *description, *command;
895
gtk_entry_set_text (GTK_ENTRY (custom_shortcut_name_entry), item->description ? item->description : "");
896
gtk_widget_set_sensitive (custom_shortcut_name_entry, item->desc_editable);
897
gtk_widget_grab_focus (custom_shortcut_name_entry);
898
gtk_entry_set_text (GTK_ENTRY (custom_shortcut_command_entry), item->command ? item->command : "");
899
gtk_widget_set_sensitive (custom_shortcut_command_entry, item->cmd_editable);
901
gtk_window_present (GTK_WINDOW (custom_shortcut_dialog));
902
result = gtk_dialog_run (GTK_DIALOG (custom_shortcut_dialog));
905
case GTK_RESPONSE_OK:
906
description = gtk_entry_get_text (GTK_ENTRY (custom_shortcut_name_entry));
907
command = gtk_entry_get_text (GTK_ENTRY (custom_shortcut_command_entry));
908
g_object_set (G_OBJECT (item),
909
"description", description,
919
gtk_widget_hide (custom_shortcut_dialog);
925
remove_custom_shortcut (GtkTreeModel *model, GtkTreeIter *iter)
929
CcKeyboardItem *item;
930
GPtrArray *keys_array;
933
gtk_tree_model_get (model, iter,
934
DETAIL_KEYENTRY_COLUMN, &item,
937
/* not a custom shortcut */
938
g_assert (item->type == CC_KEYBOARD_ITEM_TYPE_GCONF_DIR);
940
client = gconf_client_get_default ();
942
base = g_strdup (item->gconf_key_dir);
943
g_object_unref (item);
945
if (gconf_client_recursive_unset (client, base, 0, &err) == FALSE)
947
g_warning ("Failed to unset GConf directory '%s': %s", base, err->message);
952
/* suggest sync now so the unset directory actually gets dropped;
953
* if we don't do this we may end up with 'zombie' shortcuts when
954
* restarting the app */
955
gconf_client_suggest_sync (client, NULL);
956
g_object_unref (client);
958
keys_array = g_hash_table_lookup (get_hash_for_group (BINDING_GROUP_USER), _("Custom Shortcuts"));
959
g_ptr_array_remove (keys_array, item);
961
gtk_list_store_remove (GTK_LIST_STORE (model), iter);
967
update_custom_shortcut (GtkTreeModel *model, GtkTreeIter *iter)
969
CcKeyboardItem *item;
971
gtk_tree_model_get (model, iter,
972
DETAIL_KEYENTRY_COLUMN, &item,
975
g_assert (item->type == CC_KEYBOARD_ITEM_TYPE_GCONF_DIR);
977
edit_custom_shortcut (item);
978
if (item->command == NULL || item->command[0] == '\0')
980
remove_custom_shortcut (model, iter);
986
gtk_list_store_set (GTK_LIST_STORE (model), iter,
987
DETAIL_KEYENTRY_COLUMN, item, -1);
988
client = gconf_client_get_default ();
989
if (item->description != NULL)
990
gconf_client_set_string (client, item->desc_gconf_key, item->description, NULL);
992
gconf_client_unset (client, item->desc_gconf_key, NULL);
993
gconf_client_set_string (client, item->cmd_gconf_key, item->command, NULL);
994
g_object_unref (client);
999
real_start_editing_cb (IdleData *idle_data)
1001
gtk_widget_grab_focus (GTK_WIDGET (idle_data->tree_view));
1002
gtk_tree_view_set_cursor (idle_data->tree_view,
1006
gtk_tree_path_free (idle_data->path);
1012
start_editing_cb (GtkTreeView *tree_view,
1013
GdkEventButton *event,
1017
GtkTreeViewColumn *column;
1019
if (event->window != gtk_tree_view_get_bin_window (tree_view))
1022
if (gtk_tree_view_get_path_at_pos (tree_view,
1028
IdleData *idle_data;
1029
GtkTreeModel *model;
1031
CcKeyboardItem *item;
1033
if (gtk_tree_path_get_depth (path) == 1)
1035
gtk_tree_path_free (path);
1039
model = gtk_tree_view_get_model (tree_view);
1040
gtk_tree_model_get_iter (model, &iter, path);
1041
gtk_tree_model_get (model, &iter,
1042
DETAIL_KEYENTRY_COLUMN, &item,
1045
/* if only the accel can be edited on the selected row
1046
* always select the accel column */
1047
if (item->desc_editable &&
1048
column == gtk_tree_view_get_column (tree_view, 0))
1050
gtk_widget_grab_focus (GTK_WIDGET (tree_view));
1051
gtk_tree_view_set_cursor (tree_view, path,
1052
gtk_tree_view_get_column (tree_view, 0),
1054
update_custom_shortcut (model, &iter);
1058
idle_data = g_new (IdleData, 1);
1059
idle_data->tree_view = tree_view;
1060
idle_data->path = path;
1061
idle_data->column = item->desc_editable ? column :
1062
gtk_tree_view_get_column (tree_view, 1);
1063
g_idle_add ((GSourceFunc) real_start_editing_cb, idle_data);
1064
block_accels = TRUE;
1066
g_signal_stop_emission_by_name (tree_view, "button_press_event");
1072
start_editing_kb_cb (GtkTreeView *treeview,
1074
GtkTreeViewColumn *column,
1077
GtkTreeModel *model;
1079
CcKeyboardItem *item;
1081
model = gtk_tree_view_get_model (treeview);
1082
gtk_tree_model_get_iter (model, &iter, path);
1083
gtk_tree_model_get (model, &iter,
1084
DETAIL_KEYENTRY_COLUMN, &item,
1089
/* This is a section heading - expand or collapse */
1090
if (gtk_tree_view_row_expanded (treeview, path))
1091
gtk_tree_view_collapse_row (treeview, path);
1093
gtk_tree_view_expand_row (treeview, path, FALSE);
1097
/* if only the accel can be edited on the selected row
1098
* always select the accel column */
1099
if (item->desc_editable &&
1100
column == gtk_tree_view_get_column (treeview, 0))
1102
gtk_widget_grab_focus (GTK_WIDGET (treeview));
1103
gtk_tree_view_set_cursor (treeview, path,
1104
gtk_tree_view_get_column (treeview, 0),
1106
update_custom_shortcut (model, &iter);
1110
gtk_widget_grab_focus (GTK_WIDGET (treeview));
1111
gtk_tree_view_set_cursor (treeview,
1113
gtk_tree_view_get_column (treeview, 1),
1119
description_edited_callback (GtkCellRendererText *renderer,
1124
GConfClient *client;
1125
GtkTreeView *view = GTK_TREE_VIEW (user_data);
1126
GtkTreeModel *model;
1127
GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
1129
CcKeyboardItem *item;
1131
model = gtk_tree_view_get_model (view);
1132
gtk_tree_model_get_iter (model, &iter, path);
1133
gtk_tree_path_free (path);
1135
gtk_tree_model_get (model, &iter,
1136
DETAIL_KEYENTRY_COLUMN, &item,
1140
if (item == NULL || item->desc_gconf_key == NULL)
1143
g_assert (item->type == CC_KEYBOARD_ITEM_TYPE_GCONF_DIR);
1145
client = gconf_client_get_default ();
1146
if (!gconf_client_set_string (client, item->desc_gconf_key, new_text, NULL))
1147
item->desc_editable = FALSE;
1149
g_object_unref (client);
1152
static const guint forbidden_keyvals[] = {
1153
/* Navigation keys */
1173
binding_name (guint keyval,
1175
EggVirtualModifierType mask,
1178
if (keyval != 0 || keycode != 0)
1180
egg_virtual_accelerator_label (keyval, keycode, mask) :
1181
egg_virtual_accelerator_name (keyval, keycode, mask);
1183
return g_strdup (translate ? _("Disabled") : "");
1187
keyval_is_forbidden (guint keyval)
1191
for (i = 0; i < G_N_ELEMENTS(forbidden_keyvals); i++) {
1192
if (keyval == forbidden_keyvals[i])
1200
show_error (GtkWindow *parent,
1205
dialog = gtk_message_dialog_new (parent,
1206
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
1207
GTK_MESSAGE_WARNING,
1209
_("Error saving the new shortcut"));
1211
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1212
"%s", err->message);
1213
gtk_dialog_run (GTK_DIALOG (dialog));
1214
gtk_widget_destroy (dialog);
1218
CcKeyboardItem *orig_item;
1219
CcKeyboardItem *conflict_item;
1221
EggVirtualModifierType new_mask;
1226
compare_keys_for_uniqueness (CcKeyboardItem *element,
1227
CcUniquenessData *data)
1229
CcKeyboardItem *orig_item;
1231
orig_item = data->orig_item;
1233
/* no conflict for : blanks, different modifiers, or ourselves */
1234
if (element == NULL || data->new_mask != element->mask ||
1235
cc_keyboard_item_equal (orig_item, element))
1238
if (data->new_keyval != 0) {
1239
if (data->new_keyval != element->keyval)
1241
} else if (element->keyval != 0 || data->new_keycode != element->keycode)
1244
data->conflict_item = element;
1250
cb_check_for_uniqueness (gpointer key,
1251
GPtrArray *keys_array,
1252
CcUniquenessData *data)
1256
for (i = 0; i < keys_array->len; i++)
1258
CcKeyboardItem *item;
1260
item = keys_array->pdata[i];
1261
if (compare_keys_for_uniqueness (item, data))
1268
accel_edited_callback (GtkCellRendererText *cell,
1269
const char *path_string,
1271
EggVirtualModifierType mask,
1275
GtkTreeModel *model;
1276
GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
1278
CcUniquenessData data;
1279
CcKeyboardItem *item;
1282
block_accels = FALSE;
1284
model = gtk_tree_view_get_model (view);
1285
gtk_tree_model_get_iter (model, &iter, path);
1286
gtk_tree_path_free (path);
1287
gtk_tree_model_get (model, &iter,
1288
DETAIL_KEYENTRY_COLUMN, &item,
1295
/* CapsLock isn't supported as a keybinding modifier, so keep it from confusing us */
1296
mask &= ~EGG_VIRTUAL_LOCK_MASK;
1298
data.orig_item = item;
1299
data.new_keyval = keyval;
1300
data.new_mask = mask;
1301
data.new_keycode = keycode;
1302
data.conflict_item = NULL;
1304
if (keyval != 0 || keycode != 0) /* any number of shortcuts can be disabled */
1308
for (i = BINDING_GROUP_SYSTEM; i <= BINDING_GROUP_USER && data.conflict_item == NULL; i++)
1312
table = get_hash_for_group (i);
1313
g_hash_table_find (table, (GHRFunc) cb_check_for_uniqueness, &data);
1317
/* Check for unmodified keys */
1318
if (mask == 0 && keycode != 0)
1320
if ((keyval >= GDK_KEY_a && keyval <= GDK_KEY_z)
1321
|| (keyval >= GDK_KEY_A && keyval <= GDK_KEY_Z)
1322
|| (keyval >= GDK_KEY_0 && keyval <= GDK_KEY_9)
1323
|| (keyval >= GDK_KEY_kana_fullstop && keyval <= GDK_KEY_semivoicedsound)
1324
|| (keyval >= GDK_KEY_Arabic_comma && keyval <= GDK_KEY_Arabic_sukun)
1325
|| (keyval >= GDK_KEY_Serbian_dje && keyval <= GDK_KEY_Cyrillic_HARDSIGN)
1326
|| (keyval >= GDK_KEY_Greek_ALPHAaccent && keyval <= GDK_KEY_Greek_omega)
1327
|| (keyval >= GDK_KEY_hebrew_doublelowline && keyval <= GDK_KEY_hebrew_taf)
1328
|| (keyval >= GDK_KEY_Thai_kokai && keyval <= GDK_KEY_Thai_lekkao)
1329
|| (keyval >= GDK_KEY_Hangul && keyval <= GDK_KEY_Hangul_Special)
1330
|| (keyval >= GDK_KEY_Hangul_Kiyeog && keyval <= GDK_KEY_Hangul_J_YeorinHieuh)
1331
|| keyval_is_forbidden (keyval)) {
1335
name = binding_name (keyval, keycode, mask, TRUE);
1338
gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
1339
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
1340
GTK_MESSAGE_WARNING,
1342
_("The shortcut \"%s\" cannot be used because it will become impossible to type using this key.\n"
1343
"Please try with a key such as Control, Alt or Shift at the same time."),
1347
gtk_dialog_run (GTK_DIALOG (dialog));
1348
gtk_widget_destroy (dialog);
1350
/* set it back to its previous value. */
1351
egg_cell_renderer_keys_set_accelerator
1352
(EGG_CELL_RENDERER_KEYS (cell),
1353
item->keyval, item->keycode, item->mask);
1358
/* flag to see if the new accelerator was in use by something */
1359
if (data.conflict_item != NULL)
1365
name = binding_name (keyval, keycode, mask, TRUE);
1368
gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
1369
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
1370
GTK_MESSAGE_WARNING,
1372
_("The shortcut \"%s\" is already used for\n\"%s\""),
1373
name, data.conflict_item->description);
1376
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1377
_("If you reassign the shortcut to \"%s\", the \"%s\" shortcut "
1378
"will be disabled."),
1380
data.conflict_item->description);
1382
gtk_dialog_add_button (GTK_DIALOG (dialog),
1384
GTK_RESPONSE_ACCEPT);
1386
gtk_dialog_set_default_response (GTK_DIALOG (dialog),
1387
GTK_RESPONSE_ACCEPT);
1389
response = gtk_dialog_run (GTK_DIALOG (dialog));
1390
gtk_widget_destroy (dialog);
1392
if (response == GTK_RESPONSE_ACCEPT)
1394
g_object_set (G_OBJECT (data.conflict_item), "binding", "", NULL);
1396
str = binding_name (keyval, keycode, mask, FALSE);
1397
g_object_set (G_OBJECT (item), "binding", str, NULL);
1403
/* set it back to its previous value. */
1404
egg_cell_renderer_keys_set_accelerator (EGG_CELL_RENDERER_KEYS (cell),
1413
str = binding_name (keyval, keycode, mask, FALSE);
1414
g_object_set (G_OBJECT (item), "binding", str, NULL);
1420
accel_cleared_callback (GtkCellRendererText *cell,
1421
const char *path_string,
1424
GtkTreeView *view = (GtkTreeView *) data;
1425
GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
1426
CcKeyboardItem *item;
1428
GtkTreeModel *model;
1430
block_accels = FALSE;
1432
model = gtk_tree_view_get_model (view);
1433
gtk_tree_model_get_iter (model, &iter, path);
1434
gtk_tree_path_free (path);
1435
gtk_tree_model_get (model, &iter,
1436
DETAIL_KEYENTRY_COLUMN, &item,
1444
g_object_set (G_OBJECT (item), "binding", "", NULL);
1448
key_entry_controlling_key_changed (GConfClient *client,
1453
reload_sections (user_data);
1456
/* this handler is used to keep accels from activating while the user
1457
* is assigning a new shortcut so that he won't accidentally trigger one
1460
maybe_block_accels (GtkWidget *widget,
1466
return gtk_window_propagate_key_event (GTK_WINDOW (widget), event);
1472
find_free_gconf_key (GError **error)
1474
GConfClient *client;
1479
client = gconf_client_get_default ();
1481
for (i = 0; i < MAX_CUSTOM_SHORTCUTS; i++)
1483
dir = g_strdup_printf ("%s/custom%d", GCONF_BINDING_DIR, i);
1484
if (!gconf_client_dir_exists (client, dir, NULL))
1489
if (i == MAX_CUSTOM_SHORTCUTS)
1492
g_set_error_literal (error,
1493
g_quark_from_string ("Keyboard Shortcuts"),
1495
_("Too many custom shortcuts"));
1498
g_object_unref (client);
1504
add_custom_shortcut (GtkTreeView *tree_view,
1505
GtkTreeModel *model)
1507
CcKeyboardItem *item;
1513
dir = find_free_gconf_key (&error);
1516
show_error (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (tree_view))), error);
1518
g_error_free (error);
1522
/* FIXME this is way ugly */
1523
item = cc_keyboard_item_new (CC_KEYBOARD_ITEM_TYPE_GCONF_DIR);
1524
item->gconf_key_dir = g_strdup (dir);
1525
item->gconf_key = g_strconcat (dir, "/binding", NULL);
1526
item->editable = TRUE;
1527
item->model = model;
1528
item->desc_gconf_key = g_strconcat (dir, "/name", NULL);
1529
item->description = g_strdup ("");
1530
item->desc_editable = TRUE;
1531
item->cmd_gconf_key = g_strconcat (dir, "/action", NULL);
1532
item->command = g_strdup ("");
1533
item->cmd_editable = TRUE;
1535
if (edit_custom_shortcut (item) &&
1536
item->command && item->command[0])
1538
GPtrArray *keys_array;
1541
GConfClient *client;
1543
/* store in gconf */
1544
client = gconf_client_get_default ();
1545
gconf_client_set_string (client, item->gconf_key, "", NULL);
1546
gconf_client_set_string (client, item->desc_gconf_key, item->description, NULL);
1547
gconf_client_set_string (client, item->cmd_gconf_key, item->command, NULL);
1548
g_object_unref (client);
1549
g_object_unref (item);
1551
/* Now setup the actual item we'll be adding */
1552
item = cc_keyboard_item_new (CC_KEYBOARD_ITEM_TYPE_GCONF_DIR);
1553
cc_keyboard_item_load_from_gconf_dir (item, dir);
1555
hash = get_hash_for_group (BINDING_GROUP_USER);
1556
keys_array = g_hash_table_lookup (hash, _("Custom Shortcuts"));
1557
if (keys_array == NULL)
1559
keys_array = g_ptr_array_new ();
1560
g_hash_table_insert (hash, g_strdup (_("Custom Shortcuts")), keys_array);
1563
g_ptr_array_add (keys_array, item);
1565
gtk_list_store_append (GTK_LIST_STORE (model), &iter);
1566
gtk_list_store_set (GTK_LIST_STORE (model), &iter, DETAIL_KEYENTRY_COLUMN, item, -1);
1568
/* make the new shortcut visible */
1569
path = gtk_tree_model_get_path (model, &iter);
1570
gtk_tree_view_expand_to_path (tree_view, path);
1571
gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0, 0);
1572
gtk_tree_path_free (path);
1576
g_object_unref (item);
1581
add_button_clicked (GtkWidget *button,
1582
GtkBuilder *builder)
1584
GtkTreeView *treeview;
1585
GtkTreeModel *model;
1587
treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder,
1588
"shortcut_treeview"));
1589
model = gtk_tree_view_get_model (treeview);
1591
add_custom_shortcut (treeview, model);
1595
remove_button_clicked (GtkWidget *button,
1596
GtkBuilder *builder)
1598
GtkTreeView *treeview;
1599
GtkTreeModel *model;
1600
GtkTreeSelection *selection;
1603
treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder,
1604
"shortcut_treeview"));
1605
model = gtk_tree_view_get_model (treeview);
1607
selection = gtk_tree_view_get_selection (treeview);
1608
if (gtk_tree_selection_get_selected (selection, NULL, &iter))
1610
remove_custom_shortcut (model, &iter);
1615
keyentry_sort_func (GtkTreeModel *model,
1620
CcKeyboardItem *item_a;
1621
CcKeyboardItem *item_b;
1625
gtk_tree_model_get (model, a,
1626
DETAIL_KEYENTRY_COLUMN, &item_a,
1630
gtk_tree_model_get (model, b,
1631
DETAIL_KEYENTRY_COLUMN, &item_b,
1634
if (item_a && item_b)
1636
if ((item_a->keyval || item_a->keycode) &&
1637
(item_b->keyval || item_b->keycode))
1639
gchar *name_a, *name_b;
1641
name_a = binding_name (item_a->keyval,
1646
name_b = binding_name (item_b->keyval,
1651
retval = g_utf8_collate (name_a, name_b);
1656
else if (item_a->keyval || item_a->keycode)
1658
else if (item_b->keyval || item_b->keycode)
1674
section_sort_item (GtkTreeModel *model,
1685
gtk_tree_model_get (model, a,
1686
SECTION_DESCRIPTION_COLUMN, &a_desc,
1687
SECTION_GROUP_COLUMN, &a_group,
1689
gtk_tree_model_get (model, b,
1690
SECTION_DESCRIPTION_COLUMN, &b_desc,
1691
SECTION_GROUP_COLUMN, &b_group,
1694
if (a_group == b_group)
1696
/* separators go after the section */
1699
else if (b_desc == NULL)
1702
ret = g_utf8_collate (a_desc, b_desc);
1706
if (a_group < b_group)
1719
sections_separator_func (GtkTreeModel *model,
1724
gboolean is_separator;
1727
is_separator = FALSE;
1729
gtk_tree_model_get (model, iter, SECTION_DESCRIPTION_COLUMN, &description, -1);
1730
if (description == NULL)
1731
is_separator = TRUE;
1732
g_free (description);
1734
return is_separator;
1738
setup_dialog (CcPanel *panel, GtkBuilder *builder)
1740
GConfClient *client;
1741
GtkCellRenderer *renderer;
1742
GtkTreeViewColumn *column;
1744
GtkTreeView *treeview;
1745
GtkTreeSelection *selection;
1746
GSList *allowed_keys;
1748
GtkListStore *model;
1749
GtkTreeModelSort *sort_model;
1750
GtkStyleContext *context;
1752
gtk_widget_set_size_request (GTK_WIDGET (panel), -1, 400);
1754
/* Setup the section treeview */
1755
treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "section_treeview"));
1756
gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (treeview),
1757
sections_separator_func,
1761
renderer = gtk_cell_renderer_text_new ();
1762
column = gtk_tree_view_column_new_with_attributes (_("Section"),
1764
"text", SECTION_DESCRIPTION_COLUMN,
1766
g_object_set (renderer,
1768
"ellipsize", PANGO_ELLIPSIZE_END,
1771
gtk_tree_view_append_column (treeview, column);
1773
model = gtk_list_store_new (SECTION_N_COLUMNS, G_TYPE_STRING, G_TYPE_INT);
1774
sort_model = GTK_TREE_MODEL_SORT (gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (model)));
1775
gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (sort_model));
1776
g_object_unref (model);
1778
gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sort_model),
1779
SECTION_DESCRIPTION_COLUMN,
1784
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
1785
SECTION_DESCRIPTION_COLUMN,
1786
GTK_SORT_ASCENDING);
1787
g_object_unref (sort_model);
1789
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
1791
gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
1793
g_signal_connect (selection, "changed",
1794
G_CALLBACK (section_selection_changed), builder);
1795
section_selection_changed (selection, builder);
1797
/* Setup the shortcut treeview */
1798
treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder,
1799
"shortcut_treeview"));
1801
client = gconf_client_get_default ();
1803
g_signal_connect (treeview, "button_press_event",
1804
G_CALLBACK (start_editing_cb), builder);
1805
g_signal_connect (treeview, "row-activated",
1806
G_CALLBACK (start_editing_kb_cb), NULL);
1808
renderer = gtk_cell_renderer_text_new ();
1809
g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
1811
g_signal_connect (renderer, "edited",
1812
G_CALLBACK (description_edited_callback),
1815
column = gtk_tree_view_column_new_with_attributes (_("Action"),
1817
"text", DETAIL_DESCRIPTION_COLUMN,
1819
gtk_tree_view_column_set_cell_data_func (column, renderer, description_set_func, NULL, NULL);
1820
gtk_tree_view_column_set_resizable (column, FALSE);
1821
gtk_tree_view_column_set_expand (column, TRUE);
1823
gtk_tree_view_append_column (treeview, column);
1824
gtk_tree_view_column_set_sort_column_id (column, DETAIL_DESCRIPTION_COLUMN);
1826
renderer = (GtkCellRenderer *) g_object_new (EGG_TYPE_CELL_RENDERER_KEYS,
1827
"accel_mode", EGG_CELL_RENDERER_KEYS_MODE_X,
1830
g_signal_connect (renderer, "accel_edited",
1831
G_CALLBACK (accel_edited_callback),
1834
g_signal_connect (renderer, "accel_cleared",
1835
G_CALLBACK (accel_cleared_callback),
1838
column = gtk_tree_view_column_new_with_attributes (_("Shortcut"), renderer, NULL);
1839
gtk_tree_view_column_set_cell_data_func (column, renderer, accel_set_func, NULL, NULL);
1840
gtk_tree_view_column_set_resizable (column, FALSE);
1841
gtk_tree_view_column_set_expand (column, FALSE);
1843
gtk_tree_view_append_column (treeview, column);
1844
gtk_tree_view_column_set_sort_column_id (column, DETAIL_KEYENTRY_COLUMN);
1846
gconf_client_add_dir (client, GCONF_BINDING_DIR, GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
1847
gconf_client_add_dir (client, "/apps/metacity/general", GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
1848
workspace_num_notify_id = gconf_client_notify_add (client,
1849
"/apps/metacity/general/num_workspaces",
1850
(GConfClientNotifyFunc) key_entry_controlling_key_changed,
1851
builder, NULL, NULL);
1853
model = gtk_list_store_new (DETAIL_N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER);
1854
gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (model),
1855
DETAIL_KEYENTRY_COLUMN,
1858
gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (model));
1859
g_object_unref (model);
1861
widget = GTK_WIDGET (gtk_builder_get_object (builder, "actions_swindow"));
1862
context = gtk_widget_get_style_context (widget);
1863
gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);
1864
widget = GTK_WIDGET (gtk_builder_get_object (builder, "shortcut-toolbar"));
1865
context = gtk_widget_get_style_context (widget);
1866
gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
1868
/* set up the dialog */
1869
shell = cc_panel_get_shell (CC_PANEL (panel));
1870
widget = cc_shell_get_toplevel (shell);
1872
maybe_block_accels_id = g_signal_connect (widget, "key_press_event",
1873
G_CALLBACK (maybe_block_accels), NULL);
1875
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
1876
g_signal_connect (selection, "changed",
1877
G_CALLBACK (shortcut_selection_changed),
1878
WID (builder, "remove-toolbutton"));
1880
/* FIXME those use GSettings now */
1881
allowed_keys = gconf_client_get_list (client,
1882
GCONF_BINDING_DIR "/allowed_keys",
1885
if (allowed_keys != NULL)
1887
g_slist_foreach (allowed_keys, (GFunc)g_free, NULL);
1888
g_slist_free (allowed_keys);
1889
gtk_widget_set_sensitive (WID (builder, "add-toolbutton"),
1893
g_object_unref (client);
1895
/* setup the custom shortcut dialog */
1896
custom_shortcut_dialog = WID (builder,
1897
"custom-shortcut-dialog");
1898
custom_shortcut_name_entry = WID (builder,
1899
"custom-shortcut-name-entry");
1900
custom_shortcut_command_entry = WID (builder,
1901
"custom-shortcut-command-entry");
1902
g_signal_connect (WID (builder, "add-toolbutton"),
1903
"clicked", G_CALLBACK (add_button_clicked), builder);
1904
g_signal_connect (WID (builder, "remove-toolbutton"),
1905
"clicked", G_CALLBACK (remove_button_clicked), builder);
1907
gtk_dialog_set_default_response (GTK_DIALOG (custom_shortcut_dialog),
1910
gtk_window_set_transient_for (GTK_WINDOW (custom_shortcut_dialog),
1911
GTK_WINDOW (widget));
1913
gtk_window_set_resizable (GTK_WINDOW (custom_shortcut_dialog), FALSE);
1917
on_window_manager_change (const char *wm_name, GtkBuilder *builder)
1919
reload_sections (builder);
1923
keyboard_shortcuts_init (CcPanel *panel, GtkBuilder *builder)
1925
wm_common_register_window_manager_change ((GFunc) on_window_manager_change,
1927
setup_dialog (panel, builder);
1928
reload_sections (builder);
1932
keyboard_shortcuts_dispose (CcPanel *panel)
1934
if (maybe_block_accels_id != 0)
1937
GtkWidget *toplevel;
1939
shell = cc_panel_get_shell (CC_PANEL (panel));
1940
toplevel = cc_shell_get_toplevel (shell);
1942
g_signal_handler_disconnect (toplevel, maybe_block_accels_id);
1943
maybe_block_accels_id = 0;
1945
if (kb_system_sections != NULL)
1947
g_hash_table_destroy (kb_system_sections);
1948
kb_system_sections = NULL;
1950
if (kb_apps_sections != NULL)
1952
g_hash_table_destroy (kb_apps_sections);
1953
kb_apps_sections = NULL;
1955
if (kb_user_sections != NULL)
1957
g_hash_table_destroy (kb_user_sections);
1958
kb_user_sections = NULL;
1960
if (workspace_num_notify_id != 0)
1962
GConfClient *client;
1963
client = gconf_client_get_default ();
1964
gconf_client_notify_remove (client, workspace_num_notify_id);
1965
workspace_num_notify_id = 0;
1966
g_object_unref (client);