~ubuntu-branches/ubuntu/precise/gnome-control-center/precise-updates

« back to all changes in this revision

Viewing changes to .pc/revert_git_keyboard_gsettings.patch/panels/keyboard/keyboard-shortcuts.c

  • Committer: Package Import Robot
  • Author(s): Sebastien Bacher, Jeremy Bicha, Ken VanDine
  • Date: 2012-02-15 23:16:31 UTC
  • mfrom: (1.1.56)
  • Revision ID: package-import@ubuntu.com-20120215231631-vk7me0mhofpsq0hp
Tags: 1:3.3.5-0ubuntu1
* Upload the new serie, that will bring in quite some fixes, we revert
  some problematic or risky changes as well
* The new version includes those fixes:
  - "Change Password in User Accounts panel focuses "New password" field, 
     skipping "Current password"" (lp: #821759)
  - The dialog to add online accounts should have a title 
    (lp: #822380)
  - "Remove Profile" button clickable in Color panel when 
     no profile selected (lp: #869603)
  - Move Removable Media into System Info (lp: #835880)
  - Sound preferences: mouse scrolling balance only works for right.
    (lp: #918017)
  - gnome-control-center SIGSEGV in actualize_printers_list() 
    (lp: #903009)
  - selecting preffered applications is not an info (lp: #890143)
  - Add a keyboard shortcut by default for take screenshot of a selection"
    (lp: #625518)
* debian/patches/revert_git_datetime_port.patch:
  - revert use of datetimed, we don't use systemd and ubuntu-system-service 
    doesn't support it yet
* debian/patches/revert_git_drop_library.patch:
  - consolidate "01_allow_external_panels.patch", don't drop the library
    we use it from other components on ubuntu, the patch will be improved
    later to not use a copy of files like it does in that version
* debian/patches/revert_git_stop_using_gconf.patch,
  debian/patches/revert_ua_gsettings.patch,
  debian/patches/revert_git_keyboard_gsettings.patch:
  - revert keyboard porting to gsettings, compiz still use gconf and we
    didn't update gnome-shell to the new serie (yet)

[ Jeremy Bicha ]
* New upstream release (Thanks Rico Tzchichholz!)
* debian/control.in:
  - Bump minimum dependency versions and add libwacom dependency
* debian/rules: Build without -Wl,-z,defs
* debian/watch: Watch for unstable releases
* Refreshed patches:
  - 01_allow_external_panels.patch
  - 04_add_theme_selection.patch
  - 50_ubuntu_systemwide_prefs.patch
  - 58_ubuntu_icon_views_redesign.patch
  - 59_install_gcm_components_on_demand.patch
  - 91_configure_cheese.patch
* Dropped upstream patches:
  - 00git_handle_media_dialog_close.patch
  - 03_show_wacom_under_unity.patch
  - 90_git_sound_tab_order.patch
  - 91_git_build_use_fontconfig.patch
  - 92_git_minimal_output_height.patch
  - 93_change_window_role_on_panel_change.patch
  - 94_git_adding_shortcuts.patch
  - 95_git_ctrlw_shortcut.patch
  - git_extra_keywords.patch

[ Ken VanDine ]
* debian/patches/96_sound_nua_panel.patch
  - refreshed with latest changes from ronoc

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2010 Intel, Inc
 
3
 *
 
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.
 
8
 *
 
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.
 
13
 *
 
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.
 
17
 *
 
18
 * Authors: Thomas Wood <thomas.wood@intel.com>
 
19
 *          Rodrigo Moya <rodrigo@gnome.org>
 
20
 */
 
21
 
 
22
#include <config.h>
 
23
 
 
24
#include <glib/gi18n.h>
 
25
#include "keyboard-shortcuts.h"
 
26
#include "cc-keyboard-item.h"
 
27
#include "wm-common.h"
 
28
 
 
29
#define BINDINGS_SCHEMA "org.gnome.settings-daemon.plugins.media-keys"
 
30
#define CUSTOM_KEYS_BASENAME "/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings"
 
31
#define WID(builder, name) (GTK_WIDGET (gtk_builder_get_object (builder, name)))
 
32
 
 
33
typedef struct {
 
34
  char *name;
 
35
  /* The group of keybindings (system or application) */
 
36
  char *group;
 
37
  /* The gettext package to use to translate the section title */
 
38
  char *package;
 
39
  /* Name of the window manager the keys would apply to */
 
40
  char *wm_name;
 
41
  /* The GSettings schema for the whole file, if any */
 
42
  char *schema;
 
43
  /* an array of KeyListEntry */
 
44
  GArray *entries;
 
45
} KeyList;
 
46
 
 
47
typedef struct
 
48
{
 
49
  CcKeyboardItemType type;
 
50
  char *schema; /* GSettings schema name, if any */
 
51
  char *description; /* description for GSettings types */
 
52
  char *gettext_package;
 
53
  char *name; /* GSettings schema path, or GSettings key name depending on type */
 
54
} KeyListEntry;
 
55
 
 
56
enum
 
57
{
 
58
  DETAIL_DESCRIPTION_COLUMN,
 
59
  DETAIL_KEYENTRY_COLUMN,
 
60
  DETAIL_N_COLUMNS
 
61
};
 
62
 
 
63
enum
 
64
{
 
65
  SECTION_DESCRIPTION_COLUMN,
 
66
  SECTION_GROUP_COLUMN,
 
67
  SECTION_N_COLUMNS
 
68
};
 
69
 
 
70
static guint maybe_block_accels_id = 0;
 
71
static gboolean block_accels = FALSE;
 
72
static GSettings *settings = NULL;
 
73
static GtkWidget *custom_shortcut_dialog = NULL;
 
74
static GtkWidget *custom_shortcut_name_entry = NULL;
 
75
static GtkWidget *custom_shortcut_command_entry = NULL;
 
76
static GHashTable *kb_system_sections = NULL;
 
77
static GHashTable *kb_apps_sections = NULL;
 
78
static GHashTable *kb_user_sections = NULL;
 
79
 
 
80
static void
 
81
free_key_array (GPtrArray *keys)
 
82
{
 
83
  if (keys != NULL)
 
84
    {
 
85
      gint i;
 
86
 
 
87
      for (i = 0; i < keys->len; i++)
 
88
        {
 
89
          CcKeyboardItem *item;
 
90
 
 
91
          item = g_ptr_array_index (keys, i);
 
92
 
 
93
          g_object_unref (item);
 
94
        }
 
95
 
 
96
      g_ptr_array_free (keys, TRUE);
 
97
    }
 
98
}
 
99
 
 
100
static GHashTable *
 
101
get_hash_for_group (BindingGroupType group)
 
102
{
 
103
  GHashTable *hash;
 
104
 
 
105
  switch (group)
 
106
    {
 
107
    case BINDING_GROUP_SYSTEM:
 
108
      hash = kb_system_sections;
 
109
      break;
 
110
    case BINDING_GROUP_APPS:
 
111
      hash = kb_apps_sections;
 
112
      break;
 
113
    case BINDING_GROUP_USER:
 
114
      hash = kb_user_sections;
 
115
      break;
 
116
    default:
 
117
      g_assert_not_reached ();
 
118
    }
 
119
  return hash;
 
120
}
 
121
 
 
122
static gboolean
 
123
have_key_for_group (int group, const gchar *name)
 
124
{
 
125
  GHashTableIter iter;
 
126
  GPtrArray *keys;
 
127
  gint i;
 
128
 
 
129
  g_hash_table_iter_init (&iter, get_hash_for_group (group));
 
130
  while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&keys))
 
131
    {
 
132
      for (i = 0; i < keys->len; i++)
 
133
        {
 
134
          CcKeyboardItem *item = g_ptr_array_index (keys, i);
 
135
 
 
136
          if (item->type == CC_KEYBOARD_ITEM_TYPE_GSETTINGS &&
 
137
              g_strcmp0 (name, item->key) == 0)
 
138
            {
 
139
                  return TRUE;
 
140
            }
 
141
 
 
142
          return FALSE;
 
143
        }
 
144
    }
 
145
 
 
146
  return FALSE;
 
147
}
 
148
 
 
149
static gboolean
 
150
keybinding_key_changed_foreach (GtkTreeModel   *model,
 
151
                                GtkTreePath    *path,
 
152
                                GtkTreeIter    *iter,
 
153
                                CcKeyboardItem *item)
 
154
{
 
155
  CcKeyboardItem *tmp_item;
 
156
 
 
157
  gtk_tree_model_get (item->model, iter,
 
158
                      DETAIL_KEYENTRY_COLUMN, &tmp_item,
 
159
                      -1);
 
160
 
 
161
  if (item == tmp_item)
 
162
    {
 
163
      gtk_tree_model_row_changed (item->model, path, iter);
 
164
      return TRUE;
 
165
    }
 
166
  return FALSE;
 
167
}
 
168
 
 
169
static void
 
170
item_changed (CcKeyboardItem *item,
 
171
              GParamSpec     *pspec,
 
172
              gpointer        user_data)
 
173
{
 
174
  /* update the model */
 
175
  gtk_tree_model_foreach (item->model, (GtkTreeModelForeachFunc) keybinding_key_changed_foreach, item);
 
176
}
 
177
 
 
178
 
 
179
static void
 
180
append_section (GtkBuilder         *builder,
 
181
                const gchar        *title,
 
182
                BindingGroupType    group,
 
183
                const KeyListEntry *keys_list)
 
184
{
 
185
  GPtrArray *keys_array;
 
186
  GtkTreeModel *sort_model;
 
187
  GtkTreeModel *model, *shortcut_model;
 
188
  GtkTreeIter iter;
 
189
  gint i;
 
190
  GHashTable *hash;
 
191
  gboolean is_new;
 
192
 
 
193
  hash = get_hash_for_group (group);
 
194
 
 
195
  sort_model = gtk_tree_view_get_model (GTK_TREE_VIEW (gtk_builder_get_object (builder, "section_treeview")));
 
196
  model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (sort_model));
 
197
 
 
198
  shortcut_model = gtk_tree_view_get_model (GTK_TREE_VIEW (gtk_builder_get_object (builder, "shortcut_treeview")));
 
199
 
 
200
  /* Add all CcKeyboardItems for this section */
 
201
  is_new = FALSE;
 
202
  keys_array = g_hash_table_lookup (hash, title);
 
203
  if (keys_array == NULL)
 
204
    {
 
205
      keys_array = g_ptr_array_new ();
 
206
      is_new = TRUE;
 
207
    }
 
208
 
 
209
  for (i = 0; keys_list != NULL && keys_list[i].name != NULL; i++)
 
210
    {
 
211
      CcKeyboardItem *item;
 
212
      gboolean ret;
 
213
 
 
214
      if (have_key_for_group (group, keys_list[i].name))
 
215
        continue;
 
216
 
 
217
      item = cc_keyboard_item_new (keys_list[i].type);
 
218
      switch (keys_list[i].type)
 
219
        {
 
220
        case CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH:
 
221
          ret = cc_keyboard_item_load_from_gsettings_path (item, keys_list[i].name, FALSE);
 
222
          break;
 
223
        case CC_KEYBOARD_ITEM_TYPE_GSETTINGS:
 
224
          ret = cc_keyboard_item_load_from_gsettings (item,
 
225
                                                      keys_list[i].description,
 
226
                                                      keys_list[i].schema,
 
227
                                                      keys_list[i].name);
 
228
          break;
 
229
        default:
 
230
          g_assert_not_reached ();
 
231
        }
 
232
 
 
233
      if (ret == FALSE)
 
234
        {
 
235
          /* We don't actually want to popup a dialog - just skip this one */
 
236
          g_object_unref (item);
 
237
          continue;
 
238
        }
 
239
 
 
240
      item->model = shortcut_model;
 
241
      item->group = group;
 
242
 
 
243
      g_signal_connect (G_OBJECT (item), "notify",
 
244
                        G_CALLBACK (item_changed), NULL);
 
245
 
 
246
      g_ptr_array_add (keys_array, item);
 
247
    }
 
248
 
 
249
  /* Add the keys to the hash table */
 
250
  if (is_new)
 
251
    {
 
252
      static gboolean have_sep = FALSE;
 
253
 
 
254
      g_hash_table_insert (hash, g_strdup (title), keys_array);
 
255
 
 
256
      /* Append the section to the left tree view */
 
257
      gtk_list_store_append (GTK_LIST_STORE (model), &iter);
 
258
      gtk_list_store_set (GTK_LIST_STORE (model), &iter,
 
259
                          SECTION_DESCRIPTION_COLUMN, title,
 
260
                          SECTION_GROUP_COLUMN, group,
 
261
                          -1);
 
262
      if (!have_sep && group != BINDING_GROUP_SYSTEM)
 
263
        {
 
264
          have_sep = TRUE;
 
265
          /* Append the section to the left tree view */
 
266
          gtk_list_store_append (GTK_LIST_STORE (model), &iter);
 
267
          gtk_list_store_set (GTK_LIST_STORE (model), &iter,
 
268
                              SECTION_DESCRIPTION_COLUMN, NULL,
 
269
                              SECTION_GROUP_COLUMN, BINDING_GROUP_SYSTEM,
 
270
                              -1);
 
271
        }
 
272
    }
 
273
}
 
274
 
 
275
static void
 
276
parse_start_tag (GMarkupParseContext *ctx,
 
277
                 const gchar         *element_name,
 
278
                 const gchar        **attr_names,
 
279
                 const gchar        **attr_values,
 
280
                 gpointer             user_data,
 
281
                 GError             **error)
 
282
{
 
283
  KeyList *keylist = (KeyList *) user_data;
 
284
  KeyListEntry key;
 
285
  const char *name, *schema, *description, *package;
 
286
 
 
287
  name = NULL;
 
288
  schema = NULL;
 
289
  package = NULL;
 
290
 
 
291
  /* The top-level element, names the section in the tree */
 
292
  if (g_str_equal (element_name, "KeyListEntries"))
 
293
    {
 
294
      const char *wm_name = NULL;
 
295
      const char *group = NULL;
 
296
 
 
297
      while (*attr_names && *attr_values)
 
298
        {
 
299
          if (g_str_equal (*attr_names, "name"))
 
300
            {
 
301
              if (**attr_values)
 
302
                name = *attr_values;
 
303
            } else if (g_str_equal (*attr_names, "group")) {
 
304
              if (**attr_values)
 
305
                group = *attr_values;
 
306
            } else if (g_str_equal (*attr_names, "wm_name")) {
 
307
              if (**attr_values)
 
308
                wm_name = *attr_values;
 
309
            } else if (g_str_equal (*attr_names, "schema")) {
 
310
              if (**attr_values)
 
311
                schema = *attr_values;
 
312
            } else if (g_str_equal (*attr_names, "package")) {
 
313
              if (**attr_values)
 
314
                package = *attr_values;
 
315
            }
 
316
          ++attr_names;
 
317
          ++attr_values;
 
318
        }
 
319
 
 
320
      if (name)
 
321
        {
 
322
          if (keylist->name)
 
323
            g_warning ("Duplicate section name");
 
324
          g_free (keylist->name);
 
325
          keylist->name = g_strdup (name);
 
326
        }
 
327
      if (wm_name)
 
328
        {
 
329
          if (keylist->wm_name)
 
330
            g_warning ("Duplicate window manager name");
 
331
          g_free (keylist->wm_name);
 
332
          keylist->wm_name = g_strdup (wm_name);
 
333
        }
 
334
      if (package)
 
335
        {
 
336
          if (keylist->package)
 
337
            g_warning ("Duplicate gettext package name");
 
338
          g_free (keylist->package);
 
339
          keylist->package = g_strdup (package);
 
340
          bind_textdomain_codeset (keylist->package, "UTF-8");
 
341
        }
 
342
      if (group)
 
343
        {
 
344
          if (keylist->group)
 
345
            g_warning ("Duplicate group");
 
346
          g_free (keylist->group);
 
347
          keylist->group = g_strdup (group);
 
348
        }
 
349
      if (schema)
 
350
        {
 
351
          if (keylist->schema)
 
352
            g_warning ("Duplicate schema");
 
353
          g_free (keylist->schema);
 
354
          keylist->schema = g_strdup (schema);
 
355
        }
 
356
      return;
 
357
    }
 
358
 
 
359
  if (!g_str_equal (element_name, "KeyListEntry")
 
360
      || attr_names == NULL
 
361
      || attr_values == NULL)
 
362
    return;
 
363
 
 
364
  schema = NULL;
 
365
  description = NULL;
 
366
 
 
367
  while (*attr_names && *attr_values)
 
368
    {
 
369
      if (g_str_equal (*attr_names, "name"))
 
370
        {
 
371
          /* skip if empty */
 
372
          if (**attr_values)
 
373
            name = *attr_values;
 
374
        } else if (g_str_equal (*attr_names, "schema")) {
 
375
          if (**attr_values) {
 
376
           schema = *attr_values;
 
377
          }
 
378
        } else if (g_str_equal (*attr_names, "description")) {
 
379
          if (**attr_values) {
 
380
            if (keylist->package)
 
381
              {
 
382
                description = dgettext (keylist->package, *attr_values);
 
383
              }
 
384
            else
 
385
              {
 
386
                description = _(*attr_values);
 
387
              }
 
388
          }
 
389
        }
 
390
 
 
391
      ++attr_names;
 
392
      ++attr_values;
 
393
    }
 
394
 
 
395
  if (name == NULL)
 
396
    return;
 
397
 
 
398
  if (schema == NULL &&
 
399
      keylist->schema == NULL) {
 
400
    g_debug ("Ignored GConf keyboard shortcut '%s'", name);
 
401
    return;
 
402
  }
 
403
 
 
404
  key.name = g_strdup (name);
 
405
  key.type = CC_KEYBOARD_ITEM_TYPE_GSETTINGS;
 
406
  key.description = g_strdup (description);
 
407
  key.gettext_package = g_strdup (keylist->package);
 
408
  key.schema = schema ? g_strdup (schema) : g_strdup (keylist->schema);
 
409
  g_array_append_val (keylist->entries, key);
 
410
}
 
411
 
 
412
static gboolean
 
413
strv_contains (char **strv,
 
414
               char  *str)
 
415
{
 
416
  char **p = strv;
 
417
  for (p = strv; *p; p++)
 
418
    if (strcmp (*p, str) == 0)
 
419
      return TRUE;
 
420
 
 
421
  return FALSE;
 
422
}
 
423
 
 
424
static void
 
425
append_sections_from_file (GtkBuilder *builder, const gchar *path, const char *datadir, gchar **wm_keybindings)
 
426
{
 
427
  GError *err = NULL;
 
428
  char *buf;
 
429
  gsize buf_len;
 
430
  KeyList *keylist;
 
431
  KeyListEntry key, *keys;
 
432
  const char *title;
 
433
  int group;
 
434
  guint i;
 
435
  GMarkupParseContext *ctx;
 
436
  GMarkupParser parser = { parse_start_tag, NULL, NULL, NULL, NULL };
 
437
 
 
438
  /* Parse file */
 
439
  if (!g_file_get_contents (path, &buf, &buf_len, &err))
 
440
    return;
 
441
 
 
442
  keylist = g_new0 (KeyList, 1);
 
443
  keylist->entries = g_array_new (FALSE, TRUE, sizeof (KeyListEntry));
 
444
  ctx = g_markup_parse_context_new (&parser, 0, keylist, NULL);
 
445
 
 
446
  if (!g_markup_parse_context_parse (ctx, buf, buf_len, &err))
 
447
    {
 
448
      g_warning ("Failed to parse '%s': '%s'", path, err->message);
 
449
      g_error_free (err);
 
450
      g_free (keylist->name);
 
451
      g_free (keylist->package);
 
452
      g_free (keylist->wm_name);
 
453
      for (i = 0; i < keylist->entries->len; i++)
 
454
        g_free (((KeyListEntry *) &(keylist->entries->data[i]))->name);
 
455
      g_array_free (keylist->entries, TRUE);
 
456
      g_free (keylist);
 
457
      keylist = NULL;
 
458
    }
 
459
  g_markup_parse_context_free (ctx);
 
460
  g_free (buf);
 
461
 
 
462
  if (keylist == NULL)
 
463
    return;
 
464
 
 
465
  /* If there's no keys to add, or the settings apply to a window manager
 
466
   * that's not the one we're running */
 
467
  if (keylist->entries->len == 0
 
468
      || (keylist->wm_name != NULL && !strv_contains (wm_keybindings, keylist->wm_name))
 
469
      || keylist->name == NULL)
 
470
    {
 
471
      g_free (keylist->name);
 
472
      g_free (keylist->package);
 
473
      g_free (keylist->wm_name);
 
474
      g_array_free (keylist->entries, TRUE);
 
475
      g_free (keylist);
 
476
      return;
 
477
    }
 
478
 
 
479
  /* Empty KeyListEntry to end the array */
 
480
  key.name = NULL;
 
481
  g_array_append_val (keylist->entries, key);
 
482
 
 
483
  keys = (KeyListEntry *) g_array_free (keylist->entries, FALSE);
 
484
  if (keylist->package)
 
485
    {
 
486
      char *localedir;
 
487
 
 
488
      localedir = g_build_filename (datadir, "locale", NULL);
 
489
      bindtextdomain (keylist->package, localedir);
 
490
      g_free (localedir);
 
491
 
 
492
      title = dgettext (keylist->package, keylist->name);
 
493
    } else {
 
494
      title = _(keylist->name);
 
495
    }
 
496
  if (keylist->group && strcmp (keylist->group, "system") == 0)
 
497
    group = BINDING_GROUP_SYSTEM;
 
498
  else
 
499
    group = BINDING_GROUP_APPS;
 
500
 
 
501
  append_section (builder, title, group, keys);
 
502
 
 
503
  g_free (keylist->name);
 
504
  g_free (keylist->package);
 
505
  g_free (keylist->wm_name);
 
506
  g_free (keylist->schema);
 
507
  g_free (keylist->group);
 
508
 
 
509
  for (i = 0; keys[i].name != NULL; i++) {
 
510
    KeyListEntry *entry = &keys[i];
 
511
    g_free (entry->schema);
 
512
    g_free (entry->description);
 
513
    g_free (entry->gettext_package);
 
514
    g_free (entry->name);
 
515
  }
 
516
 
 
517
  g_free (keylist);
 
518
}
 
519
 
 
520
static void
 
521
append_sections_from_gsettings (GtkBuilder *builder)
 
522
{
 
523
  char **custom_paths;
 
524
  GArray *entries;
 
525
  KeyListEntry key;
 
526
  int i;
 
527
 
 
528
  /* load custom shortcuts from GSettings */
 
529
  entries = g_array_new (FALSE, TRUE, sizeof (KeyListEntry));
 
530
 
 
531
  custom_paths = g_settings_get_strv (settings, "custom-keybindings");
 
532
  for (i = 0; custom_paths[i]; i++)
 
533
    {
 
534
      key.name = g_strdup (custom_paths[i]);
 
535
      if (!have_key_for_group (BINDING_GROUP_USER, key.name))
 
536
        {
 
537
          key.type = CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH;
 
538
          g_array_append_val (entries, key);
 
539
        }
 
540
      else
 
541
        g_free (key.name);
 
542
    }
 
543
  g_strfreev (custom_paths);
 
544
 
 
545
  if (entries->len > 0)
 
546
    {
 
547
      KeyListEntry *keys;
 
548
      int i;
 
549
 
 
550
      /* Empty KeyListEntry to end the array */
 
551
      key.name = NULL;
 
552
      g_array_append_val (entries, key);
 
553
 
 
554
      keys = (KeyListEntry *) entries->data;
 
555
      append_section (builder, _("Custom Shortcuts"), BINDING_GROUP_USER, keys);
 
556
      for (i = 0; i < entries->len; ++i)
 
557
        {
 
558
          g_free (keys[i].name);
 
559
        }
 
560
    }
 
561
  else
 
562
    {
 
563
      append_section (builder, _("Custom Shortcuts"), BINDING_GROUP_USER, NULL);
 
564
    }
 
565
 
 
566
  g_array_free (entries, TRUE);
 
567
}
 
568
 
 
569
static void
 
570
reload_sections (GtkBuilder *builder)
 
571
{
 
572
  gchar **wm_keybindings;
 
573
  GDir *dir;
 
574
  GtkTreeModel *sort_model;
 
575
  GtkTreeModel *section_model;
 
576
  GtkTreeModel *shortcut_model;
 
577
  const gchar * const * data_dirs;
 
578
  guint i;
 
579
  GtkTreeView *section_treeview;
 
580
  GtkTreeSelection *selection;
 
581
  GtkTreeIter iter;
 
582
  GHashTable *loaded_files;
 
583
 
 
584
  section_treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "section_treeview"));
 
585
  sort_model = gtk_tree_view_get_model (section_treeview);
 
586
  section_model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (sort_model));
 
587
 
 
588
  shortcut_model = gtk_tree_view_get_model (GTK_TREE_VIEW (gtk_builder_get_object (builder, "shortcut_treeview")));
 
589
  /* FIXME: get current selection and keep it after refreshing */
 
590
 
 
591
  /* Clear previous models and hash tables */
 
592
  gtk_list_store_clear (GTK_LIST_STORE (section_model));
 
593
  gtk_list_store_clear (GTK_LIST_STORE (shortcut_model));
 
594
  if (kb_system_sections != NULL)
 
595
    g_hash_table_destroy (kb_system_sections);
 
596
  kb_system_sections = g_hash_table_new_full (g_str_hash,
 
597
                                              g_str_equal,
 
598
                                              g_free,
 
599
                                              (GDestroyNotify) free_key_array);
 
600
 
 
601
  if (kb_apps_sections != NULL)
 
602
    g_hash_table_destroy (kb_apps_sections);
 
603
  kb_apps_sections = g_hash_table_new_full (g_str_hash,
 
604
                                            g_str_equal,
 
605
                                            g_free,
 
606
                                            (GDestroyNotify) free_key_array);
 
607
 
 
608
  if (kb_user_sections != NULL)
 
609
    g_hash_table_destroy (kb_user_sections);
 
610
  kb_user_sections = g_hash_table_new_full (g_str_hash,
 
611
                                            g_str_equal,
 
612
                                            g_free,
 
613
                                            (GDestroyNotify) free_key_array);
 
614
 
 
615
  /* Load WM keybindings */
 
616
  wm_keybindings = wm_common_get_current_keybindings ();
 
617
 
 
618
  loaded_files = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
619
 
 
620
  data_dirs = g_get_system_data_dirs ();
 
621
  for (i = 0; data_dirs[i] != NULL; i++)
 
622
    {
 
623
      char *dir_path;
 
624
      const gchar *name;
 
625
 
 
626
      dir_path = g_build_filename (data_dirs[i], "gnome-control-center", "keybindings", NULL);
 
627
 
 
628
      dir = g_dir_open (dir_path, 0, NULL);
 
629
      if (!dir)
 
630
        {
 
631
          g_free (dir_path);
 
632
          continue;
 
633
        }
 
634
 
 
635
      for (name = g_dir_read_name (dir) ; name ; name = g_dir_read_name (dir))
 
636
        {
 
637
          gchar *path;
 
638
 
 
639
          if (g_str_has_suffix (name, ".xml") == FALSE)
 
640
            continue;
 
641
 
 
642
          if (g_hash_table_lookup (loaded_files, name) != NULL)
 
643
            {
 
644
              g_debug ("Not loading %s, it was already loaded from another directory", name);
 
645
              continue;
 
646
            }
 
647
 
 
648
          g_hash_table_insert (loaded_files, g_strdup (name), GINT_TO_POINTER (1));
 
649
          path = g_build_filename (dir_path, name, NULL);
 
650
          append_sections_from_file (builder, path, data_dirs[i], wm_keybindings);
 
651
          g_free (path);
 
652
        }
 
653
      g_free (dir_path);
 
654
      g_dir_close (dir);
 
655
    }
 
656
 
 
657
  g_hash_table_destroy (loaded_files);
 
658
  g_strfreev (wm_keybindings);
 
659
 
 
660
  /* Load custom keybindings */
 
661
  append_sections_from_gsettings (builder);
 
662
 
 
663
  /* Select the first item */
 
664
  gtk_tree_model_get_iter_first (sort_model, &iter);
 
665
  selection = gtk_tree_view_get_selection (section_treeview);
 
666
  gtk_tree_selection_select_iter (selection, &iter);
 
667
}
 
668
 
 
669
static void
 
670
accel_set_func (GtkTreeViewColumn *tree_column,
 
671
                GtkCellRenderer   *cell,
 
672
                GtkTreeModel      *model,
 
673
                GtkTreeIter       *iter,
 
674
                gpointer           data)
 
675
{
 
676
  CcKeyboardItem *item;
 
677
 
 
678
  gtk_tree_model_get (model, iter,
 
679
                      DETAIL_KEYENTRY_COLUMN, &item,
 
680
                      -1);
 
681
 
 
682
  if (item == NULL)
 
683
    g_object_set (cell,
 
684
                  "visible", FALSE,
 
685
                  NULL);
 
686
  else if (! item->editable)
 
687
    g_object_set (cell,
 
688
                  "visible", TRUE,
 
689
                  "editable", FALSE,
 
690
                  "accel-key", item->keyval,
 
691
                  "accel-mods", item->mask,
 
692
                  "keycode", item->keycode,
 
693
                  "style", PANGO_STYLE_ITALIC,
 
694
                  NULL);
 
695
  else
 
696
    g_object_set (cell,
 
697
                  "visible", TRUE,
 
698
                  "editable", TRUE,
 
699
                  "accel-key", item->keyval,
 
700
                  "accel-mods", item->mask,
 
701
                  "keycode", item->keycode,
 
702
                  "style", PANGO_STYLE_NORMAL,
 
703
                  NULL);
 
704
}
 
705
 
 
706
static void
 
707
description_set_func (GtkTreeViewColumn *tree_column,
 
708
                      GtkCellRenderer   *cell,
 
709
                      GtkTreeModel      *model,
 
710
                      GtkTreeIter       *iter,
 
711
                      gpointer           data)
 
712
{
 
713
  CcKeyboardItem *item;
 
714
 
 
715
  gtk_tree_model_get (model, iter,
 
716
                      DETAIL_KEYENTRY_COLUMN, &item,
 
717
                      -1);
 
718
 
 
719
  if (item != NULL)
 
720
    g_object_set (cell,
 
721
                  "editable", FALSE,
 
722
                  "text", item->description != NULL ?
 
723
                          item->description : _("<Unknown Action>"),
 
724
                  NULL);
 
725
  else
 
726
    g_object_set (cell,
 
727
                  "editable", FALSE, NULL);
 
728
}
 
729
 
 
730
static void
 
731
shortcut_selection_changed (GtkTreeSelection *selection, gpointer data)
 
732
{
 
733
  GtkWidget *button = data;
 
734
  GtkTreeModel *model;
 
735
  GtkTreeIter iter;
 
736
  CcKeyboardItem *item;
 
737
  gboolean can_remove;
 
738
 
 
739
  can_remove = FALSE;
 
740
  if (gtk_tree_selection_get_selected (selection, &model, &iter))
 
741
    {
 
742
      gtk_tree_model_get (model, &iter, DETAIL_KEYENTRY_COLUMN, &item, -1);
 
743
      if (item && item->command != NULL && item->editable)
 
744
        can_remove = TRUE;
 
745
    }
 
746
 
 
747
  gtk_widget_set_sensitive (button, can_remove);
 
748
}
 
749
 
 
750
static void
 
751
section_selection_changed (GtkTreeSelection *selection, gpointer data)
 
752
{
 
753
  GtkTreeIter iter;
 
754
  GtkTreeModel *model;
 
755
  GtkBuilder *builder = GTK_BUILDER (data);
 
756
 
 
757
  if (gtk_tree_selection_get_selected (selection, &model, &iter))
 
758
    {
 
759
      GPtrArray *keys;
 
760
      GtkWidget *shortcut_treeview;
 
761
      GtkTreeModel *shortcut_model;
 
762
      gchar *description;
 
763
      BindingGroupType group;
 
764
      gint i;
 
765
 
 
766
      gtk_tree_model_get (model, &iter,
 
767
                          SECTION_DESCRIPTION_COLUMN, &description,
 
768
                          SECTION_GROUP_COLUMN, &group, -1);
 
769
 
 
770
      keys = g_hash_table_lookup (get_hash_for_group (group), description);
 
771
      if (keys == NULL)
 
772
        {
 
773
          g_warning ("Can't find section %s in sections hash table!!!", description);
 
774
          return;
 
775
        }
 
776
 
 
777
      gtk_widget_set_sensitive (WID (builder, "remove-toolbutton"), FALSE);
 
778
 
 
779
      /* Fill the shortcut treeview with the keys for the selected section */
 
780
      shortcut_treeview = GTK_WIDGET (gtk_builder_get_object (builder, "shortcut_treeview"));
 
781
      shortcut_model = gtk_tree_view_get_model (GTK_TREE_VIEW (shortcut_treeview));
 
782
      gtk_list_store_clear (GTK_LIST_STORE (shortcut_model));
 
783
 
 
784
      for (i = 0; i < keys->len; i++)
 
785
        {
 
786
          GtkTreeIter new_row;
 
787
          CcKeyboardItem *item = g_ptr_array_index (keys, i);
 
788
 
 
789
          gtk_list_store_append (GTK_LIST_STORE (shortcut_model), &new_row);
 
790
          gtk_list_store_set (GTK_LIST_STORE (shortcut_model), &new_row,
 
791
                              DETAIL_DESCRIPTION_COLUMN, item->description,
 
792
                              DETAIL_KEYENTRY_COLUMN, item,
 
793
                              -1);
 
794
        }
 
795
    }
 
796
}
 
797
 
 
798
typedef struct
 
799
{
 
800
  GtkTreeView *tree_view;
 
801
  GtkTreePath *path;
 
802
  GtkTreeViewColumn *column;
 
803
} IdleData;
 
804
 
 
805
static gboolean
 
806
edit_custom_shortcut (CcKeyboardItem *item)
 
807
{
 
808
  gint result;
 
809
  gboolean ret;
 
810
  GSettings *settings;
 
811
 
 
812
  settings = g_settings_new_with_path (item->schema, item->gsettings_path);
 
813
 
 
814
  g_settings_bind (settings, "name",
 
815
                   G_OBJECT (custom_shortcut_name_entry), "text",
 
816
                   G_SETTINGS_BIND_DEFAULT);
 
817
  gtk_widget_grab_focus (custom_shortcut_name_entry);
 
818
 
 
819
  g_settings_bind (settings, "command",
 
820
                   G_OBJECT (custom_shortcut_command_entry), "text",
 
821
                   G_SETTINGS_BIND_DEFAULT);
 
822
 
 
823
  g_settings_delay (settings);
 
824
 
 
825
  gtk_window_present (GTK_WINDOW (custom_shortcut_dialog));
 
826
  result = gtk_dialog_run (GTK_DIALOG (custom_shortcut_dialog));
 
827
  switch (result)
 
828
    {
 
829
    case GTK_RESPONSE_OK:
 
830
      g_settings_apply (settings);
 
831
      ret = TRUE;
 
832
      break;
 
833
    default:
 
834
      g_settings_revert (settings);
 
835
      ret = FALSE;
 
836
      break;
 
837
    }
 
838
 
 
839
  g_settings_unbind (G_OBJECT (custom_shortcut_name_entry), "text");
 
840
  g_settings_unbind (G_OBJECT (custom_shortcut_command_entry), "text");
 
841
 
 
842
  g_object_unref (settings);
 
843
 
 
844
  gtk_widget_hide (custom_shortcut_dialog);
 
845
 
 
846
  return ret;
 
847
}
 
848
 
 
849
static gboolean
 
850
remove_custom_shortcut (GtkTreeModel *model, GtkTreeIter *iter)
 
851
{
 
852
  CcKeyboardItem *item;
 
853
  GPtrArray *keys_array;
 
854
  GVariantBuilder builder;
 
855
  char **settings_paths;
 
856
  int i;
 
857
 
 
858
  gtk_tree_model_get (model, iter,
 
859
                      DETAIL_KEYENTRY_COLUMN, &item,
 
860
                      -1);
 
861
 
 
862
  /* not a custom shortcut */
 
863
  g_assert (item->type == CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH);
 
864
 
 
865
  g_settings_delay (item->settings);
 
866
  g_settings_reset (item->settings, "name");
 
867
  g_settings_reset (item->settings, "command");
 
868
  g_settings_reset (item->settings, "binding");
 
869
  g_settings_apply (item->settings);
 
870
  g_settings_sync ();
 
871
 
 
872
  settings_paths = g_settings_get_strv (settings, "custom-keybindings");
 
873
  g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
 
874
  for (i = 0; settings_paths[i]; i++)
 
875
    if (strcmp (settings_paths[i], item->gsettings_path) != 0)
 
876
      g_variant_builder_add (&builder, "s", settings_paths[i]);
 
877
  g_settings_set_value (settings,
 
878
                        "custom-keybindings", g_variant_builder_end (&builder));
 
879
  g_strfreev (settings_paths);
 
880
  g_object_unref (item);
 
881
 
 
882
  keys_array = g_hash_table_lookup (get_hash_for_group (BINDING_GROUP_USER), _("Custom Shortcuts"));
 
883
  g_ptr_array_remove (keys_array, item);
 
884
 
 
885
  gtk_list_store_remove (GTK_LIST_STORE (model), iter);
 
886
 
 
887
  return TRUE;
 
888
}
 
889
 
 
890
static void
 
891
update_custom_shortcut (GtkTreeModel *model, GtkTreeIter *iter)
 
892
{
 
893
  CcKeyboardItem *item;
 
894
 
 
895
  gtk_tree_model_get (model, iter,
 
896
                      DETAIL_KEYENTRY_COLUMN, &item,
 
897
                      -1);
 
898
 
 
899
  g_assert (item->type == CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH);
 
900
 
 
901
  edit_custom_shortcut (item);
 
902
  if (item->command == NULL || item->command[0] == '\0')
 
903
    {
 
904
      remove_custom_shortcut (model, iter);
 
905
    }
 
906
  else
 
907
    {
 
908
      gtk_list_store_set (GTK_LIST_STORE (model), iter,
 
909
                          DETAIL_KEYENTRY_COLUMN, item, -1);
 
910
    }
 
911
}
 
912
 
 
913
static gboolean
 
914
real_start_editing_cb (IdleData *idle_data)
 
915
{
 
916
  gtk_widget_grab_focus (GTK_WIDGET (idle_data->tree_view));
 
917
  gtk_tree_view_set_cursor (idle_data->tree_view,
 
918
                            idle_data->path,
 
919
                            idle_data->column,
 
920
                            TRUE);
 
921
  gtk_tree_path_free (idle_data->path);
 
922
  g_free (idle_data);
 
923
  return FALSE;
 
924
}
 
925
 
 
926
static gboolean
 
927
start_editing_cb (GtkTreeView    *tree_view,
 
928
                  GdkEventButton *event,
 
929
                  gpointer        user_data)
 
930
{
 
931
  GtkTreePath *path;
 
932
  GtkTreeViewColumn *column;
 
933
 
 
934
  if (event->window != gtk_tree_view_get_bin_window (tree_view))
 
935
    return FALSE;
 
936
 
 
937
  if (gtk_tree_view_get_path_at_pos (tree_view,
 
938
                                     (gint) event->x,
 
939
                                     (gint) event->y,
 
940
                                     &path, &column,
 
941
                                     NULL, NULL))
 
942
    {
 
943
      IdleData *idle_data;
 
944
      GtkTreeModel *model;
 
945
      GtkTreeIter iter;
 
946
      CcKeyboardItem *item;
 
947
 
 
948
      if (gtk_tree_path_get_depth (path) == 1)
 
949
        {
 
950
          gtk_tree_path_free (path);
 
951
          return FALSE;
 
952
        }
 
953
 
 
954
      model = gtk_tree_view_get_model (tree_view);
 
955
      gtk_tree_model_get_iter (model, &iter, path);
 
956
      gtk_tree_model_get (model, &iter,
 
957
                          DETAIL_KEYENTRY_COLUMN, &item,
 
958
                         -1);
 
959
 
 
960
      /* if only the accel can be edited on the selected row
 
961
       * always select the accel column */
 
962
      if (item->desc_editable &&
 
963
          column == gtk_tree_view_get_column (tree_view, 0))
 
964
        {
 
965
          gtk_widget_grab_focus (GTK_WIDGET (tree_view));
 
966
          gtk_tree_view_set_cursor (tree_view, path,
 
967
                                    gtk_tree_view_get_column (tree_view, 0),
 
968
                                    FALSE);
 
969
          update_custom_shortcut (model, &iter);
 
970
        }
 
971
      else
 
972
        {
 
973
          idle_data = g_new (IdleData, 1);
 
974
          idle_data->tree_view = tree_view;
 
975
          idle_data->path = path;
 
976
          idle_data->column = item->desc_editable ? column :
 
977
                              gtk_tree_view_get_column (tree_view, 1);
 
978
          g_idle_add ((GSourceFunc) real_start_editing_cb, idle_data);
 
979
          block_accels = TRUE;
 
980
        }
 
981
      g_signal_stop_emission_by_name (tree_view, "button_press_event");
 
982
    }
 
983
  return TRUE;
 
984
}
 
985
 
 
986
static void
 
987
start_editing_kb_cb (GtkTreeView *treeview,
 
988
                          GtkTreePath *path,
 
989
                          GtkTreeViewColumn *column,
 
990
                          gpointer user_data)
 
991
{
 
992
  GtkTreeModel *model;
 
993
  GtkTreeIter iter;
 
994
  CcKeyboardItem *item;
 
995
 
 
996
  model = gtk_tree_view_get_model (treeview);
 
997
  gtk_tree_model_get_iter (model, &iter, path);
 
998
  gtk_tree_model_get (model, &iter,
 
999
                      DETAIL_KEYENTRY_COLUMN, &item,
 
1000
                      -1);
 
1001
 
 
1002
  if (item == NULL)
 
1003
    {
 
1004
      /* This is a section heading - expand or collapse */
 
1005
      if (gtk_tree_view_row_expanded (treeview, path))
 
1006
        gtk_tree_view_collapse_row (treeview, path);
 
1007
      else
 
1008
        gtk_tree_view_expand_row (treeview, path, FALSE);
 
1009
      return;
 
1010
    }
 
1011
 
 
1012
  /* if only the accel can be edited on the selected row
 
1013
   * always select the accel column */
 
1014
  if (item->desc_editable &&
 
1015
      column == gtk_tree_view_get_column (treeview, 0))
 
1016
    {
 
1017
      gtk_widget_grab_focus (GTK_WIDGET (treeview));
 
1018
      gtk_tree_view_set_cursor (treeview, path,
 
1019
                                gtk_tree_view_get_column (treeview, 0),
 
1020
                                FALSE);
 
1021
      update_custom_shortcut (model, &iter);
 
1022
    }
 
1023
  else
 
1024
    {
 
1025
       gtk_widget_grab_focus (GTK_WIDGET (treeview));
 
1026
       gtk_tree_view_set_cursor (treeview,
 
1027
                                 path,
 
1028
                                 gtk_tree_view_get_column (treeview, 1),
 
1029
                                 TRUE);
 
1030
    }
 
1031
}
 
1032
 
 
1033
static const guint forbidden_keyvals[] = {
 
1034
  /* Navigation keys */
 
1035
  GDK_KEY_Home,
 
1036
  GDK_KEY_Left,
 
1037
  GDK_KEY_Up,
 
1038
  GDK_KEY_Right,
 
1039
  GDK_KEY_Down,
 
1040
  GDK_KEY_Page_Up,
 
1041
  GDK_KEY_Page_Down,
 
1042
  GDK_KEY_End,
 
1043
  GDK_KEY_Tab,
 
1044
 
 
1045
  /* Return */
 
1046
  GDK_KEY_KP_Enter,
 
1047
  GDK_KEY_Return,
 
1048
 
 
1049
  GDK_KEY_space,
 
1050
  GDK_KEY_Mode_switch
 
1051
};
 
1052
 
 
1053
static char*
 
1054
binding_name (guint                   keyval,
 
1055
              guint                   keycode,
 
1056
              GdkModifierType         mask,
 
1057
              gboolean                translate)
 
1058
{
 
1059
  if (keyval != 0 || keycode != 0)
 
1060
    return translate ?
 
1061
        gtk_accelerator_get_label_with_keycode (NULL, keyval, keycode, mask) :
 
1062
        gtk_accelerator_name_with_keycode (NULL, keyval, keycode, mask);
 
1063
  else
 
1064
    return g_strdup (translate ? _("Disabled") : "");
 
1065
}
 
1066
 
 
1067
static gboolean
 
1068
keyval_is_forbidden (guint keyval)
 
1069
{
 
1070
  guint i;
 
1071
 
 
1072
  for (i = 0; i < G_N_ELEMENTS(forbidden_keyvals); i++) {
 
1073
    if (keyval == forbidden_keyvals[i])
 
1074
      return TRUE;
 
1075
  }
 
1076
 
 
1077
  return FALSE;
 
1078
}
 
1079
 
 
1080
typedef struct {
 
1081
  CcKeyboardItem *orig_item;
 
1082
  CcKeyboardItem *conflict_item;
 
1083
  guint new_keyval;
 
1084
  GdkModifierType new_mask;
 
1085
  guint new_keycode;
 
1086
} CcUniquenessData;
 
1087
 
 
1088
static gboolean
 
1089
compare_keys_for_uniqueness (CcKeyboardItem   *element,
 
1090
                             CcUniquenessData *data)
 
1091
{
 
1092
  CcKeyboardItem *orig_item;
 
1093
 
 
1094
  orig_item = data->orig_item;
 
1095
 
 
1096
  /* no conflict for : blanks, different modifiers, or ourselves */
 
1097
  if (element == NULL || data->new_mask != element->mask ||
 
1098
      cc_keyboard_item_equal (orig_item, element))
 
1099
    return FALSE;
 
1100
 
 
1101
  if (data->new_keyval != 0) {
 
1102
      if (data->new_keyval != element->keyval)
 
1103
          return FALSE;
 
1104
  } else if (element->keyval != 0 || data->new_keycode != element->keycode)
 
1105
    return FALSE;
 
1106
 
 
1107
  data->conflict_item = element;
 
1108
 
 
1109
  return TRUE;
 
1110
}
 
1111
 
 
1112
static gboolean
 
1113
cb_check_for_uniqueness (gpointer          key,
 
1114
                         GPtrArray        *keys_array,
 
1115
                         CcUniquenessData *data)
 
1116
{
 
1117
  guint i;
 
1118
 
 
1119
  for (i = 0; i < keys_array->len; i++)
 
1120
    {
 
1121
      CcKeyboardItem *item;
 
1122
 
 
1123
      item = keys_array->pdata[i];
 
1124
      if (compare_keys_for_uniqueness (item, data))
 
1125
        return TRUE;
 
1126
    }
 
1127
  return FALSE;
 
1128
}
 
1129
 
 
1130
static void
 
1131
accel_edited_callback (GtkCellRendererText   *cell,
 
1132
                       const char            *path_string,
 
1133
                       guint                  keyval,
 
1134
                       GdkModifierType        mask,
 
1135
                       guint                  keycode,
 
1136
                       GtkTreeView           *view)
 
1137
{
 
1138
  GtkTreeModel *model;
 
1139
  GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
 
1140
  GtkTreeIter iter;
 
1141
  CcUniquenessData data;
 
1142
  CcKeyboardItem *item;
 
1143
  char *str;
 
1144
 
 
1145
  block_accels = FALSE;
 
1146
 
 
1147
  model = gtk_tree_view_get_model (view);
 
1148
  gtk_tree_model_get_iter (model, &iter, path);
 
1149
  gtk_tree_path_free (path);
 
1150
  gtk_tree_model_get (model, &iter,
 
1151
                      DETAIL_KEYENTRY_COLUMN, &item,
 
1152
                      -1);
 
1153
 
 
1154
  /* sanity check */
 
1155
  if (item == NULL)
 
1156
    return;
 
1157
 
 
1158
  /* CapsLock isn't supported as a keybinding modifier, so keep it from confusing us */
 
1159
  mask &= ~GDK_LOCK_MASK;
 
1160
 
 
1161
  data.orig_item = item;
 
1162
  data.new_keyval = keyval;
 
1163
  data.new_mask = mask;
 
1164
  data.new_keycode = keycode;
 
1165
  data.conflict_item = NULL;
 
1166
 
 
1167
  if (keyval != 0 || keycode != 0) /* any number of shortcuts can be disabled */
 
1168
    {
 
1169
      BindingGroupType i;
 
1170
 
 
1171
      for (i = BINDING_GROUP_SYSTEM; i <= BINDING_GROUP_USER && data.conflict_item == NULL; i++)
 
1172
        {
 
1173
          GHashTable *table;
 
1174
 
 
1175
          table = get_hash_for_group (i);
 
1176
          g_hash_table_find (table, (GHRFunc) cb_check_for_uniqueness, &data);
 
1177
        }
 
1178
    }
 
1179
 
 
1180
  /* Check for unmodified keys */
 
1181
  if (mask == 0 && keycode != 0)
 
1182
    {
 
1183
      if ((keyval >= GDK_KEY_a && keyval <= GDK_KEY_z)
 
1184
           || (keyval >= GDK_KEY_A && keyval <= GDK_KEY_Z)
 
1185
           || (keyval >= GDK_KEY_0 && keyval <= GDK_KEY_9)
 
1186
           || (keyval >= GDK_KEY_kana_fullstop && keyval <= GDK_KEY_semivoicedsound)
 
1187
           || (keyval >= GDK_KEY_Arabic_comma && keyval <= GDK_KEY_Arabic_sukun)
 
1188
           || (keyval >= GDK_KEY_Serbian_dje && keyval <= GDK_KEY_Cyrillic_HARDSIGN)
 
1189
           || (keyval >= GDK_KEY_Greek_ALPHAaccent && keyval <= GDK_KEY_Greek_omega)
 
1190
           || (keyval >= GDK_KEY_hebrew_doublelowline && keyval <= GDK_KEY_hebrew_taf)
 
1191
           || (keyval >= GDK_KEY_Thai_kokai && keyval <= GDK_KEY_Thai_lekkao)
 
1192
           || (keyval >= GDK_KEY_Hangul && keyval <= GDK_KEY_Hangul_Special)
 
1193
           || (keyval >= GDK_KEY_Hangul_Kiyeog && keyval <= GDK_KEY_Hangul_J_YeorinHieuh)
 
1194
           || keyval_is_forbidden (keyval)) {
 
1195
        GtkWidget *dialog;
 
1196
        char *name;
 
1197
 
 
1198
        name = binding_name (keyval, keycode, mask, TRUE);
 
1199
 
 
1200
        dialog =
 
1201
          gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
 
1202
                                  GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
 
1203
                                  GTK_MESSAGE_WARNING,
 
1204
                                  GTK_BUTTONS_CANCEL,
 
1205
                                  _("The shortcut \"%s\" cannot be used because it will become impossible to type using this key.\n"
 
1206
                                  "Please try with a key such as Control, Alt or Shift at the same time."),
 
1207
                                  name);
 
1208
 
 
1209
        g_free (name);
 
1210
        gtk_dialog_run (GTK_DIALOG (dialog));
 
1211
        gtk_widget_destroy (dialog);
 
1212
 
 
1213
        /* set it back to its previous value. */
 
1214
        g_object_set (G_OBJECT (cell),
 
1215
                      "accel-key", item->keyval,
 
1216
                      "keycode", item->keycode,
 
1217
                      "accel-mods", item->mask,
 
1218
                      NULL);
 
1219
        return;
 
1220
      }
 
1221
    }
 
1222
 
 
1223
  /* flag to see if the new accelerator was in use by something */
 
1224
  if (data.conflict_item != NULL)
 
1225
    {
 
1226
      GtkWidget *dialog;
 
1227
      char *name;
 
1228
      int response;
 
1229
 
 
1230
      name = binding_name (keyval, keycode, mask, TRUE);
 
1231
 
 
1232
      dialog =
 
1233
        gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
 
1234
                                GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
 
1235
                                GTK_MESSAGE_WARNING,
 
1236
                                GTK_BUTTONS_CANCEL,
 
1237
                                _("The shortcut \"%s\" is already used for\n\"%s\""),
 
1238
                                name, data.conflict_item->description);
 
1239
      g_free (name);
 
1240
 
 
1241
      gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
 
1242
          _("If you reassign the shortcut to \"%s\", the \"%s\" shortcut "
 
1243
            "will be disabled."),
 
1244
          item->description,
 
1245
          data.conflict_item->description);
 
1246
 
 
1247
      gtk_dialog_add_button (GTK_DIALOG (dialog),
 
1248
                             _("_Reassign"),
 
1249
                             GTK_RESPONSE_ACCEPT);
 
1250
 
 
1251
      gtk_dialog_set_default_response (GTK_DIALOG (dialog),
 
1252
                                       GTK_RESPONSE_ACCEPT);
 
1253
 
 
1254
      response = gtk_dialog_run (GTK_DIALOG (dialog));
 
1255
      gtk_widget_destroy (dialog);
 
1256
 
 
1257
      if (response == GTK_RESPONSE_ACCEPT)
 
1258
        {
 
1259
          g_object_set (G_OBJECT (data.conflict_item), "binding", "", NULL);
 
1260
 
 
1261
          str = binding_name (keyval, keycode, mask, FALSE);
 
1262
          g_object_set (G_OBJECT (item), "binding", str, NULL);
 
1263
 
 
1264
          g_free (str);
 
1265
        }
 
1266
      else
 
1267
        {
 
1268
          /* set it back to its previous value. */
 
1269
        g_object_set (G_OBJECT (cell),
 
1270
                      "accel-key", item->keyval,
 
1271
                      "keycode", item->keycode,
 
1272
                      "accel-mods", item->mask,
 
1273
                      NULL);
 
1274
        }
 
1275
 
 
1276
      return;
 
1277
    }
 
1278
 
 
1279
  str = binding_name (keyval, keycode, mask, FALSE);
 
1280
  g_object_set (G_OBJECT (item), "binding", str, NULL);
 
1281
 
 
1282
  g_free (str);
 
1283
}
 
1284
 
 
1285
static void
 
1286
accel_cleared_callback (GtkCellRendererText *cell,
 
1287
                        const char          *path_string,
 
1288
                        gpointer             data)
 
1289
{
 
1290
  GtkTreeView *view = (GtkTreeView *) data;
 
1291
  GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
 
1292
  CcKeyboardItem *item;
 
1293
  GtkTreeIter iter;
 
1294
  GtkTreeModel *model;
 
1295
 
 
1296
  block_accels = FALSE;
 
1297
 
 
1298
  model = gtk_tree_view_get_model (view);
 
1299
  gtk_tree_model_get_iter (model, &iter, path);
 
1300
  gtk_tree_path_free (path);
 
1301
  gtk_tree_model_get (model, &iter,
 
1302
                      DETAIL_KEYENTRY_COLUMN, &item,
 
1303
                      -1);
 
1304
 
 
1305
  /* sanity check */
 
1306
  if (item == NULL)
 
1307
    return;
 
1308
 
 
1309
  /* Unset the key */
 
1310
  g_object_set (G_OBJECT (item), "binding", "", NULL);
 
1311
}
 
1312
 
 
1313
/* this handler is used to keep accels from activating while the user
 
1314
 * is assigning a new shortcut so that he won't accidentally trigger one
 
1315
 * of the widgets */
 
1316
static gboolean
 
1317
maybe_block_accels (GtkWidget *widget,
 
1318
                    GdkEventKey *event,
 
1319
                    gpointer user_data)
 
1320
{
 
1321
  if (block_accels)
 
1322
  {
 
1323
    return gtk_window_propagate_key_event (GTK_WINDOW (widget), event);
 
1324
  }
 
1325
  return FALSE;
 
1326
}
 
1327
 
 
1328
static gchar *
 
1329
find_free_settings_path ()
 
1330
{
 
1331
  char **used_names;
 
1332
  char *dir = NULL;
 
1333
  int i, num, n_names;
 
1334
 
 
1335
  used_names = g_settings_get_strv (settings, "custom-keybindings");
 
1336
  n_names = g_strv_length (used_names);
 
1337
 
 
1338
  for (num = 0; dir == NULL; num++)
 
1339
    {
 
1340
      char *tmp;
 
1341
      gboolean found = FALSE;
 
1342
 
 
1343
      tmp = g_strdup_printf ("%s/custom%d/", CUSTOM_KEYS_BASENAME, num);
 
1344
      for (i = 0; i < n_names && !found; i++)
 
1345
        found = strcmp (used_names[i], tmp) == 0;
 
1346
 
 
1347
      if (!found)
 
1348
        dir = tmp;
 
1349
      else
 
1350
        g_free (tmp);
 
1351
    }
 
1352
 
 
1353
  return dir;
 
1354
}
 
1355
 
 
1356
static void
 
1357
add_custom_shortcut (GtkTreeView  *tree_view,
 
1358
                     GtkTreeModel *model)
 
1359
{
 
1360
  CcKeyboardItem *item;
 
1361
  GtkTreePath *path;
 
1362
  gchar *settings_path;
 
1363
 
 
1364
  item = cc_keyboard_item_new (CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH);
 
1365
 
 
1366
  settings_path = find_free_settings_path ();
 
1367
  cc_keyboard_item_load_from_gsettings_path (item, settings_path, TRUE);
 
1368
  g_free (settings_path);
 
1369
 
 
1370
  item->model = model;
 
1371
 
 
1372
  if (edit_custom_shortcut (item) &&
 
1373
      item->command && item->command[0])
 
1374
    {
 
1375
      GPtrArray *keys_array;
 
1376
      GtkTreeIter iter;
 
1377
      GHashTable *hash;
 
1378
      GVariantBuilder builder;
 
1379
      char **settings_paths;
 
1380
      int i;
 
1381
 
 
1382
      hash = get_hash_for_group (BINDING_GROUP_USER);
 
1383
      keys_array = g_hash_table_lookup (hash, _("Custom Shortcuts"));
 
1384
      if (keys_array == NULL)
 
1385
        {
 
1386
          keys_array = g_ptr_array_new ();
 
1387
          g_hash_table_insert (hash, g_strdup (_("Custom Shortcuts")), keys_array);
 
1388
        }
 
1389
 
 
1390
      g_ptr_array_add (keys_array, item);
 
1391
 
 
1392
      gtk_list_store_append (GTK_LIST_STORE (model), &iter);
 
1393
      gtk_list_store_set (GTK_LIST_STORE (model), &iter, DETAIL_KEYENTRY_COLUMN, item, -1);
 
1394
 
 
1395
      settings_paths = g_settings_get_strv (settings, "custom-keybindings");
 
1396
      g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
 
1397
      for (i = 0; settings_paths[i]; i++)
 
1398
        g_variant_builder_add (&builder, "s", settings_paths[i]);
 
1399
      g_variant_builder_add (&builder, "s", item->gsettings_path);
 
1400
      g_settings_set_value (settings, "custom-keybindings",
 
1401
                            g_variant_builder_end (&builder));
 
1402
 
 
1403
      /* make the new shortcut visible */
 
1404
      path = gtk_tree_model_get_path (model, &iter);
 
1405
      gtk_tree_view_expand_to_path (tree_view, path);
 
1406
      gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0, 0);
 
1407
      gtk_tree_path_free (path);
 
1408
    }
 
1409
  else
 
1410
    {
 
1411
      g_object_unref (item);
 
1412
    }
 
1413
}
 
1414
 
 
1415
static void
 
1416
add_button_clicked (GtkWidget  *button,
 
1417
                    GtkBuilder *builder)
 
1418
{
 
1419
  GtkTreeView *treeview;
 
1420
  GtkTreeModel *model;
 
1421
  GtkTreeModel *section_model;
 
1422
  GtkTreeIter iter;
 
1423
  gboolean found, cont;
 
1424
 
 
1425
  treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder,
 
1426
                                                    "shortcut_treeview"));
 
1427
  model = gtk_tree_view_get_model (treeview);
 
1428
 
 
1429
  /* Select the Custom Shortcuts section
 
1430
   * before adding the shortcut itself */
 
1431
  section_model = gtk_tree_view_get_model (GTK_TREE_VIEW (WID (builder, "section_treeview")));
 
1432
  cont = gtk_tree_model_get_iter_first (section_model, &iter);
 
1433
  found = FALSE;
 
1434
  while (cont)
 
1435
    {
 
1436
      BindingGroupType group;
 
1437
 
 
1438
      gtk_tree_model_get (section_model, &iter,
 
1439
                          SECTION_GROUP_COLUMN, &group,
 
1440
                          -1);
 
1441
 
 
1442
      if (group == BINDING_GROUP_USER)
 
1443
        {
 
1444
          found = TRUE;
 
1445
          break;
 
1446
        }
 
1447
      cont = gtk_tree_model_iter_next (section_model, &iter);
 
1448
    }
 
1449
  if (found)
 
1450
    {
 
1451
      GtkTreeSelection *selection;
 
1452
 
 
1453
      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (WID (builder, "section_treeview")));
 
1454
      gtk_tree_selection_select_iter (selection, &iter);
 
1455
    }
 
1456
 
 
1457
  /* And add the shortcut */
 
1458
  add_custom_shortcut (treeview, model);
 
1459
}
 
1460
 
 
1461
static void
 
1462
remove_button_clicked (GtkWidget  *button,
 
1463
                       GtkBuilder *builder)
 
1464
{
 
1465
  GtkTreeView *treeview;
 
1466
  GtkTreeModel *model;
 
1467
  GtkTreeSelection *selection;
 
1468
  GtkTreeIter iter;
 
1469
 
 
1470
  treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder,
 
1471
                                                    "shortcut_treeview"));
 
1472
  model = gtk_tree_view_get_model (treeview);
 
1473
 
 
1474
  selection = gtk_tree_view_get_selection (treeview);
 
1475
  if (gtk_tree_selection_get_selected (selection, NULL, &iter))
 
1476
    {
 
1477
      remove_custom_shortcut (model, &iter);
 
1478
    }
 
1479
}
 
1480
 
 
1481
static int
 
1482
keyentry_sort_func (GtkTreeModel *model,
 
1483
                    GtkTreeIter  *a,
 
1484
                    GtkTreeIter  *b,
 
1485
                    gpointer      user_data)
 
1486
{
 
1487
  CcKeyboardItem *item_a;
 
1488
  CcKeyboardItem *item_b;
 
1489
  int retval;
 
1490
 
 
1491
  item_a = NULL;
 
1492
  gtk_tree_model_get (model, a,
 
1493
                      DETAIL_KEYENTRY_COLUMN, &item_a,
 
1494
                      -1);
 
1495
 
 
1496
  item_b = NULL;
 
1497
  gtk_tree_model_get (model, b,
 
1498
                      DETAIL_KEYENTRY_COLUMN, &item_b,
 
1499
                      -1);
 
1500
 
 
1501
  if (item_a && item_b)
 
1502
    {
 
1503
      if ((item_a->keyval || item_a->keycode) &&
 
1504
          (item_b->keyval || item_b->keycode))
 
1505
        {
 
1506
          gchar *name_a, *name_b;
 
1507
 
 
1508
          name_a = binding_name (item_a->keyval,
 
1509
                                 item_a->keycode,
 
1510
                                 item_a->mask,
 
1511
                                 TRUE);
 
1512
 
 
1513
          name_b = binding_name (item_b->keyval,
 
1514
                                 item_b->keycode,
 
1515
                                 item_b->mask,
 
1516
                                 TRUE);
 
1517
 
 
1518
          retval = g_utf8_collate (name_a, name_b);
 
1519
 
 
1520
          g_free (name_a);
 
1521
          g_free (name_b);
 
1522
        }
 
1523
      else if (item_a->keyval || item_a->keycode)
 
1524
        retval = -1;
 
1525
      else if (item_b->keyval || item_b->keycode)
 
1526
        retval = 1;
 
1527
      else
 
1528
        retval = 0;
 
1529
    }
 
1530
  else if (item_a)
 
1531
    retval = -1;
 
1532
  else if (item_b)
 
1533
    retval = 1;
 
1534
  else
 
1535
    retval = 0;
 
1536
 
 
1537
  return retval;
 
1538
}
 
1539
 
 
1540
static int
 
1541
section_sort_item  (GtkTreeModel *model,
 
1542
                    GtkTreeIter  *a,
 
1543
                    GtkTreeIter  *b,
 
1544
                    gpointer      data)
 
1545
{
 
1546
  char *a_desc;
 
1547
  int   a_group;
 
1548
  char *b_desc;
 
1549
  int   b_group;
 
1550
  int   ret;
 
1551
 
 
1552
  gtk_tree_model_get (model, a,
 
1553
                      SECTION_DESCRIPTION_COLUMN, &a_desc,
 
1554
                      SECTION_GROUP_COLUMN, &a_group,
 
1555
                      -1);
 
1556
  gtk_tree_model_get (model, b,
 
1557
                      SECTION_DESCRIPTION_COLUMN, &b_desc,
 
1558
                      SECTION_GROUP_COLUMN, &b_group,
 
1559
                      -1);
 
1560
 
 
1561
  if (a_group == b_group)
 
1562
    {
 
1563
      /* separators go after the section */
 
1564
      if (a_desc == NULL)
 
1565
        ret = 1;
 
1566
      else if (b_desc == NULL)
 
1567
        ret = -1;
 
1568
      else
 
1569
        ret = g_utf8_collate (a_desc, b_desc);
 
1570
    }
 
1571
  else
 
1572
    {
 
1573
      if (a_group < b_group)
 
1574
        ret = -1;
 
1575
      else
 
1576
        ret = 1;
 
1577
    }
 
1578
 
 
1579
  g_free (a_desc);
 
1580
  g_free (b_desc);
 
1581
 
 
1582
  return ret;
 
1583
}
 
1584
 
 
1585
static gboolean
 
1586
sections_separator_func (GtkTreeModel *model,
 
1587
                         GtkTreeIter  *iter,
 
1588
                         gpointer      data)
 
1589
{
 
1590
  char    *description;
 
1591
  gboolean is_separator;
 
1592
 
 
1593
  description = NULL;
 
1594
  is_separator = FALSE;
 
1595
 
 
1596
  gtk_tree_model_get (model, iter, SECTION_DESCRIPTION_COLUMN, &description, -1);
 
1597
  if (description == NULL)
 
1598
    is_separator = TRUE;
 
1599
  g_free (description);
 
1600
 
 
1601
  return is_separator;
 
1602
}
 
1603
 
 
1604
static void
 
1605
setup_dialog (CcPanel *panel, GtkBuilder *builder)
 
1606
{
 
1607
  GtkCellRenderer *renderer;
 
1608
  GtkTreeViewColumn *column;
 
1609
  GtkWidget *widget;
 
1610
  GtkTreeView *treeview;
 
1611
  GtkTreeSelection *selection;
 
1612
  CcShell *shell;
 
1613
  GtkListStore *model;
 
1614
  GtkTreeModelSort *sort_model;
 
1615
  GtkStyleContext *context;
 
1616
 
 
1617
  gtk_widget_set_size_request (GTK_WIDGET (panel), -1, 400);
 
1618
 
 
1619
  /* Setup the section treeview */
 
1620
  treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "section_treeview"));
 
1621
  gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (treeview),
 
1622
                                        sections_separator_func,
 
1623
                                        panel,
 
1624
                                        NULL);
 
1625
 
 
1626
  renderer = gtk_cell_renderer_text_new ();
 
1627
  column = gtk_tree_view_column_new_with_attributes (_("Section"),
 
1628
                                                     renderer,
 
1629
                                                     "text", SECTION_DESCRIPTION_COLUMN,
 
1630
                                                     NULL);
 
1631
  g_object_set (renderer,
 
1632
                "width-chars", 20,
 
1633
                "ellipsize", PANGO_ELLIPSIZE_END,
 
1634
                NULL);
 
1635
 
 
1636
  gtk_tree_view_append_column (treeview, column);
 
1637
 
 
1638
  model = gtk_list_store_new (SECTION_N_COLUMNS, G_TYPE_STRING, G_TYPE_INT);
 
1639
  sort_model = GTK_TREE_MODEL_SORT (gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (model)));
 
1640
  gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (sort_model));
 
1641
  g_object_unref (model);
 
1642
 
 
1643
  gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sort_model),
 
1644
                                   SECTION_DESCRIPTION_COLUMN,
 
1645
                                   section_sort_item,
 
1646
                                   panel,
 
1647
                                   NULL);
 
1648
 
 
1649
  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
 
1650
                                        SECTION_DESCRIPTION_COLUMN,
 
1651
                                        GTK_SORT_ASCENDING);
 
1652
  g_object_unref (sort_model);
 
1653
 
 
1654
  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
 
1655
 
 
1656
  gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
 
1657
 
 
1658
  g_signal_connect (selection, "changed",
 
1659
                    G_CALLBACK (section_selection_changed), builder);
 
1660
  section_selection_changed (selection, builder);
 
1661
 
 
1662
  /* Setup the shortcut treeview */
 
1663
  treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder,
 
1664
                                                    "shortcut_treeview"));
 
1665
 
 
1666
  settings = g_settings_new (BINDINGS_SCHEMA);
 
1667
 
 
1668
  g_signal_connect (treeview, "button_press_event",
 
1669
                    G_CALLBACK (start_editing_cb), builder);
 
1670
  g_signal_connect (treeview, "row-activated",
 
1671
                    G_CALLBACK (start_editing_kb_cb), NULL);
 
1672
 
 
1673
  renderer = gtk_cell_renderer_text_new ();
 
1674
  g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
 
1675
 
 
1676
  column = gtk_tree_view_column_new_with_attributes (_("Action"),
 
1677
                                                     renderer,
 
1678
                                                     "text", DETAIL_DESCRIPTION_COLUMN,
 
1679
                                                     NULL);
 
1680
  gtk_tree_view_column_set_cell_data_func (column, renderer, description_set_func, NULL, NULL);
 
1681
  gtk_tree_view_column_set_resizable (column, FALSE);
 
1682
  gtk_tree_view_column_set_expand (column, TRUE);
 
1683
 
 
1684
  gtk_tree_view_append_column (treeview, column);
 
1685
  gtk_tree_view_column_set_sort_column_id (column, DETAIL_DESCRIPTION_COLUMN);
 
1686
 
 
1687
  renderer = (GtkCellRenderer *) g_object_new (GTK_TYPE_CELL_RENDERER_ACCEL,
 
1688
                                               "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
 
1689
                                               NULL);
 
1690
 
 
1691
  g_signal_connect (renderer, "accel_edited",
 
1692
                    G_CALLBACK (accel_edited_callback),
 
1693
                    treeview);
 
1694
 
 
1695
  g_signal_connect (renderer, "accel_cleared",
 
1696
                    G_CALLBACK (accel_cleared_callback),
 
1697
                    treeview);
 
1698
 
 
1699
  column = gtk_tree_view_column_new_with_attributes (_("Shortcut"), renderer, NULL);
 
1700
  gtk_tree_view_column_set_cell_data_func (column, renderer, accel_set_func, NULL, NULL);
 
1701
  gtk_tree_view_column_set_resizable (column, FALSE);
 
1702
  gtk_tree_view_column_set_expand (column, FALSE);
 
1703
 
 
1704
  gtk_tree_view_append_column (treeview, column);
 
1705
  gtk_tree_view_column_set_sort_column_id (column, DETAIL_KEYENTRY_COLUMN);
 
1706
 
 
1707
  model = gtk_list_store_new (DETAIL_N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER);
 
1708
  gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (model),
 
1709
                                   DETAIL_KEYENTRY_COLUMN,
 
1710
                                   keyentry_sort_func,
 
1711
                                   NULL, NULL);
 
1712
  gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (model));
 
1713
  g_object_unref (model);
 
1714
 
 
1715
  widget = GTK_WIDGET (gtk_builder_get_object (builder, "actions_swindow"));
 
1716
  context = gtk_widget_get_style_context (widget);
 
1717
  gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);
 
1718
  widget = GTK_WIDGET (gtk_builder_get_object (builder, "shortcut-toolbar"));
 
1719
  context = gtk_widget_get_style_context (widget);
 
1720
  gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
 
1721
 
 
1722
  /* set up the dialog */
 
1723
  shell = cc_panel_get_shell (CC_PANEL (panel));
 
1724
  widget = cc_shell_get_toplevel (shell);
 
1725
 
 
1726
  maybe_block_accels_id = g_signal_connect (widget, "key_press_event",
 
1727
                                            G_CALLBACK (maybe_block_accels), NULL);
 
1728
 
 
1729
  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
 
1730
  g_signal_connect (selection, "changed",
 
1731
                    G_CALLBACK (shortcut_selection_changed),
 
1732
                    WID (builder, "remove-toolbutton"));
 
1733
 
 
1734
  /* setup the custom shortcut dialog */
 
1735
  custom_shortcut_dialog = WID (builder,
 
1736
                                "custom-shortcut-dialog");
 
1737
  custom_shortcut_name_entry = WID (builder,
 
1738
                                    "custom-shortcut-name-entry");
 
1739
  custom_shortcut_command_entry = WID (builder,
 
1740
                                       "custom-shortcut-command-entry");
 
1741
  g_signal_connect (WID (builder, "add-toolbutton"),
 
1742
                    "clicked", G_CALLBACK (add_button_clicked), builder);
 
1743
  g_signal_connect (WID (builder, "remove-toolbutton"),
 
1744
                    "clicked", G_CALLBACK (remove_button_clicked), builder);
 
1745
 
 
1746
  gtk_dialog_set_default_response (GTK_DIALOG (custom_shortcut_dialog),
 
1747
                                   GTK_RESPONSE_OK);
 
1748
 
 
1749
  gtk_window_set_transient_for (GTK_WINDOW (custom_shortcut_dialog),
 
1750
                                GTK_WINDOW (widget));
 
1751
 
 
1752
  gtk_window_set_resizable (GTK_WINDOW (custom_shortcut_dialog), FALSE);
 
1753
}
 
1754
 
 
1755
static void
 
1756
on_window_manager_change (const char *wm_name, GtkBuilder *builder)
 
1757
{
 
1758
  reload_sections (builder);
 
1759
}
 
1760
 
 
1761
void
 
1762
keyboard_shortcuts_init (CcPanel *panel, GtkBuilder *builder)
 
1763
{
 
1764
  wm_common_register_window_manager_change ((GFunc) on_window_manager_change,
 
1765
                                            builder);
 
1766
  setup_dialog (panel, builder);
 
1767
  reload_sections (builder);
 
1768
}
 
1769
 
 
1770
void
 
1771
keyboard_shortcuts_dispose (CcPanel *panel)
 
1772
{
 
1773
  if (maybe_block_accels_id != 0)
 
1774
    {
 
1775
      CcShell *shell;
 
1776
      GtkWidget *toplevel;
 
1777
 
 
1778
      shell = cc_panel_get_shell (CC_PANEL (panel));
 
1779
      toplevel = cc_shell_get_toplevel (shell);
 
1780
 
 
1781
      g_signal_handler_disconnect (toplevel, maybe_block_accels_id);
 
1782
      maybe_block_accels_id = 0;
 
1783
 
 
1784
      if (kb_system_sections != NULL)
 
1785
        {
 
1786
          g_hash_table_destroy (kb_system_sections);
 
1787
          kb_system_sections = NULL;
 
1788
        }
 
1789
      if (kb_apps_sections != NULL)
 
1790
        {
 
1791
          g_hash_table_destroy (kb_apps_sections);
 
1792
          kb_apps_sections = NULL;
 
1793
        }
 
1794
      if (kb_user_sections != NULL)
 
1795
        {
 
1796
          g_hash_table_destroy (kb_user_sections);
 
1797
          kb_user_sections = NULL;
 
1798
        }
 
1799
    }
 
1800
}