[gnome-control-center] keyboard: Match with previous functionality
- From: Rodrigo Moya <rodrigo src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-control-center] keyboard: Match with previous functionality
- Date: Thu, 9 Dec 2010 16:05:27 +0000 (UTC)
commit cc15b73336f4d01aa6997a31accf9644b36e4759
Author: Rodrigo Moya <rodrigo gnome-db org>
Date: Thu Dec 9 14:27:54 2010 +0100
keyboard: Match with previous functionality
panels/keyboard/gnome-keyboard-panel.c | 1138 --------------------------------
panels/keyboard/keyboard-shortcuts.c | 1072 ++++++++++++++++++++++++++++--
2 files changed, 1024 insertions(+), 1186 deletions(-)
---
diff --git a/panels/keyboard/gnome-keyboard-panel.c b/panels/keyboard/gnome-keyboard-panel.c
index ac5c383..bf6aa2a 100644
--- a/panels/keyboard/gnome-keyboard-panel.c
+++ b/panels/keyboard/gnome-keyboard-panel.c
@@ -15,239 +15,9 @@
#include "gnome-keyboard-panel.h"
#define MAX_ELEMENTS_BEFORE_SCROLLING 10
-#define MAX_CUSTOM_SHORTCUTS 1000
#define RESPONSE_ADD 0
#define RESPONSE_REMOVE 1
-static gboolean block_accels = FALSE;
-static GHashTable *keyb_sections = NULL;
-
-static char*
-binding_name (guint keyval,
- guint keycode,
- EggVirtualModifierType mask,
- gboolean translate)
-{
- if (keyval != 0 || keycode != 0)
- return translate ?
- egg_virtual_accelerator_label (keyval, keycode, mask) :
- egg_virtual_accelerator_name (keyval, keycode, mask);
- else
- return g_strdup (translate ? _("Disabled") : "");
-}
-
-static gboolean
-keybinding_key_changed_foreach (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gpointer user_data)
-{
- KeyEntry *key_entry;
- KeyEntry *tmp_key_entry;
-
- key_entry = (KeyEntry *)user_data;
- gtk_tree_model_get (key_entry->model, iter,
- KEYENTRY_COLUMN, &tmp_key_entry,
- -1);
-
- if (key_entry == tmp_key_entry)
- {
- gtk_tree_model_row_changed (key_entry->model, path, iter);
- return TRUE;
- }
- return FALSE;
-}
-
-static void
-keybinding_key_changed (GConfClient *client,
- guint cnxn_id,
- GConfEntry *entry,
- gpointer user_data)
-{
- KeyEntry *key_entry;
- const gchar *key_value;
-
- key_entry = (KeyEntry *) user_data;
- key_value = entry->value ? gconf_value_get_string (entry->value) : NULL;
-
- binding_from_string (key_value, &key_entry->keyval, &key_entry->keycode, &key_entry->mask);
- key_entry->editable = gconf_entry_get_is_writable (entry);
-
- /* update the model */
- gtk_tree_model_foreach (key_entry->model, keybinding_key_changed_foreach, key_entry);
-}
-
-static void
-keybinding_description_changed (GConfClient *client,
- guint cnxn_id,
- GConfEntry *entry,
- gpointer user_data)
-{
- KeyEntry *key_entry;
- const gchar *key_value;
-
- key_entry = (KeyEntry *) user_data;
- key_value = entry->value ? gconf_value_get_string (entry->value) : NULL;
-
- g_free (key_entry->description);
- key_entry->description = key_value ? g_strdup (key_value) : NULL;
- key_entry->desc_editable = gconf_entry_get_is_writable (entry);
-
- /* update the model */
- gtk_tree_model_foreach (key_entry->model, keybinding_key_changed_foreach, key_entry);
-}
-
-static void
-keybinding_command_changed (GConfClient *client,
- guint cnxn_id,
- GConfEntry *entry,
- gpointer user_data)
-{
- KeyEntry *key_entry;
- const gchar *key_value;
-
- key_entry = (KeyEntry *) user_data;
- key_value = entry->value ? gconf_value_get_string (entry->value) : NULL;
-
- g_free (key_entry->command);
- key_entry->command = key_value ? g_strdup (key_value) : NULL;
- key_entry->cmd_editable = gconf_entry_get_is_writable (entry);
-
- /* update the model */
- gtk_tree_model_foreach (key_entry->model, keybinding_key_changed_foreach, key_entry);
-}
-
-static int
-keyentry_sort_func (GtkTreeModel *model,
- GtkTreeIter *a,
- GtkTreeIter *b,
- gpointer user_data)
-{
- KeyEntry *key_entry_a;
- KeyEntry *key_entry_b;
- int retval;
-
- key_entry_a = NULL;
- gtk_tree_model_get (model, a,
- KEYENTRY_COLUMN, &key_entry_a,
- -1);
-
- key_entry_b = NULL;
- gtk_tree_model_get (model, b,
- KEYENTRY_COLUMN, &key_entry_b,
- -1);
-
- if (key_entry_a && key_entry_b)
- {
- if ((key_entry_a->keyval || key_entry_a->keycode) &&
- (key_entry_b->keyval || key_entry_b->keycode))
- {
- gchar *name_a, *name_b;
-
- name_a = binding_name (key_entry_a->keyval,
- key_entry_a->keycode,
- key_entry_a->mask,
- TRUE);
-
- name_b = binding_name (key_entry_b->keyval,
- key_entry_b->keycode,
- key_entry_b->mask,
- TRUE);
-
- retval = g_utf8_collate (name_a, name_b);
-
- g_free (name_a);
- g_free (name_b);
- }
- else if (key_entry_a->keyval || key_entry_a->keycode)
- retval = -1;
- else if (key_entry_b->keyval || key_entry_b->keycode)
- retval = 1;
- else
- retval = 0;
- }
- else if (key_entry_a)
- retval = -1;
- else if (key_entry_b)
- retval = 1;
- else
- retval = 0;
-
- return retval;
-}
-
-static void
-clear_old_model (GtkBuilder *builder)
-{
- GtkWidget *tree_view;
- GtkWidget *actions_swindow;
- GtkTreeModel *model;
-
- tree_view = WID (builder, "shortcut_treeview");
- model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
-
- if (model == NULL)
- {
- /* create a new model */
- model = (GtkTreeModel *) gtk_tree_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER);
-
- gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (model),
- KEYENTRY_COLUMN,
- keyentry_sort_func,
- NULL, NULL);
-
- gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), model);
-
- g_object_unref (model);
- }
- else
- {
- /* clear the existing model */
- GConfClient *client;
- gboolean valid;
- GtkTreeIter iter;
- KeyEntry *key_entry;
-
- client = gconf_client_get_default ();
- /* we need the schema name below;
- * cached values do not have that set, though */
- gconf_client_clear_cache (client);
-
- for (valid = gtk_tree_model_get_iter_first (model, &iter);
- valid;
- valid = gtk_tree_model_iter_next (model, &iter))
- {
- gtk_tree_model_get (model, &iter,
- KEYENTRY_COLUMN, &key_entry,
- -1);
-
- if (key_entry != NULL)
- {
- gconf_client_remove_dir (client, key_entry->gconf_key, NULL);
- gconf_client_notify_remove (client, key_entry->gconf_cnxn);
- if (key_entry->gconf_cnxn_desc != 0)
- gconf_client_notify_remove (client, key_entry->gconf_cnxn_desc);
- if (key_entry->gconf_cnxn_cmd != 0)
- gconf_client_notify_remove (client, key_entry->gconf_cnxn_cmd);
- g_free (key_entry->gconf_key);
- g_free (key_entry->description);
- g_free (key_entry->desc_gconf_key);
- g_free (key_entry->command);
- g_free (key_entry->cmd_gconf_key);
- g_free (key_entry);
- }
- }
-
- gtk_tree_store_clear (GTK_TREE_STORE (model));
- g_object_unref (client);
- }
-
- actions_swindow = WID (builder, "actions_swindow");
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (actions_swindow),
- GTK_POLICY_NEVER, GTK_POLICY_NEVER);
- gtk_widget_set_size_request (actions_swindow, -1, -1);
-}
-
typedef struct {
const char *key;
gboolean found;
@@ -311,911 +81,3 @@ ensure_scrollbar (GtkBuilder *builder, int i)
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
}
}
-
-static void
-find_section (GtkTreeModel *model,
- GtkTreeIter *iter,
- const char *title)
-{
- gboolean success;
-
- success = gtk_tree_model_get_iter_first (model, iter);
- while (success)
- {
- char *description = NULL;
-
- gtk_tree_model_get (model, iter,
- DESCRIPTION_COLUMN, &description,
- -1);
-
- if (g_strcmp0 (description, title) == 0)
- return;
- success = gtk_tree_model_iter_next (model, iter);
- }
-
- gtk_tree_store_append (GTK_TREE_STORE (model), iter, NULL);
- gtk_tree_store_set (GTK_TREE_STORE (model), iter,
- DESCRIPTION_COLUMN, title,
- -1);
-}
-
-static void
-append_keys_to_tree (GtkBuilder *builder,
- const gchar *title,
- const KeyListEntry *keys_list)
-{
- GtkTreeIter parent_iter, iter;
- GtkTreeModel *model;
- gint i, j;
-
- /* Try to find a section parent iter, if it already exists */
- find_section (model, &iter, title);
- parent_iter = iter;
-
- i = 0;
- gtk_tree_model_foreach (model, count_rows_foreach, &i);
-
- /* If the header we just added is the MAX_ELEMENTS_BEFORE_SCROLLING th,
- * then we need to scroll now */
- ensure_scrollbar (builder, i - 1);
-
-===============================================================
-
- /* Don't show an empty section */
- if (gtk_tree_model_iter_n_children (model, &parent_iter) == 0)
- gtk_tree_store_remove (GTK_TREE_STORE (model), &parent_iter);
-
- if (i == 0)
- gtk_widget_hide (WID (builder, "shortcuts_vbox"));
- else
- gtk_widget_show (WID (builder, "shortcuts_vbox"));
-}
-
-static void
-key_entry_controlling_key_changed (GConfClient *client,
- guint cnxn_id,
- GConfEntry *entry,
- gpointer user_data)
-{
- reload_key_entries (user_data);
-}
-
-static gboolean
-cb_check_for_uniqueness (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- KeyEntry *new_key)
-{
- KeyEntry *element;
-
- gtk_tree_model_get (new_key->model, iter,
- KEYENTRY_COLUMN, &element,
- -1);
-
- /* no conflict for : blanks, different modifiers, or ourselves */
- if (element == NULL || new_key->mask != element->mask ||
- !strcmp (new_key->gconf_key, element->gconf_key))
- return FALSE;
-
- if (new_key->keyval != 0) {
- if (new_key->keyval != element->keyval)
- return FALSE;
- } else if (element->keyval != 0 || new_key->keycode != element->keycode)
- return FALSE;
-
- new_key->editable = FALSE;
- new_key->gconf_key = element->gconf_key;
- new_key->description = element->description;
- new_key->desc_gconf_key = element->desc_gconf_key;
- new_key->desc_editable = element->desc_editable;
- return TRUE;
-}
-
-static const guint forbidden_keyvals[] = {
- /* Navigation keys */
- GDK_KEY_Home,
- GDK_KEY_Left,
- GDK_KEY_Up,
- GDK_KEY_Right,
- GDK_KEY_Down,
- GDK_KEY_Page_Up,
- GDK_KEY_Page_Down,
- GDK_KEY_End,
- GDK_KEY_Tab,
-
- /* Return */
- GDK_KEY_KP_Enter,
- GDK_KEY_Return,
-
- GDK_KEY_space,
- GDK_KEY_Mode_switch
-};
-
-static gboolean
-keyval_is_forbidden (guint keyval)
-{
- guint i;
-
- for (i = 0; i < G_N_ELEMENTS(forbidden_keyvals); i++) {
- if (keyval == forbidden_keyvals[i])
- return TRUE;
- }
-
- return FALSE;
-}
-
-static void
-show_error (GtkWindow *parent,
- GError *err)
-{
- GtkWidget *dialog;
-
- dialog = gtk_message_dialog_new (parent,
- GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
- GTK_MESSAGE_WARNING,
- GTK_BUTTONS_OK,
- _("Error saving the new shortcut"));
-
- gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
- "%s", err->message);
- gtk_dialog_run (GTK_DIALOG (dialog));
- gtk_widget_destroy (dialog);
-}
-
-static void
-accel_edited_callback (GtkCellRendererText *cell,
- const char *path_string,
- guint keyval,
- EggVirtualModifierType mask,
- guint keycode,
- gpointer data)
-{
- GConfClient *client;
- GtkTreeView *view = (GtkTreeView *)data;
- GtkTreeModel *model;
- GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
- GtkTreeIter iter;
- KeyEntry *key_entry, tmp_key;
- GError *err = NULL;
- char *str;
-
- block_accels = FALSE;
-
- model = gtk_tree_view_get_model (view);
- gtk_tree_model_get_iter (model, &iter, path);
- gtk_tree_path_free (path);
- gtk_tree_model_get (model, &iter,
- KEYENTRY_COLUMN, &key_entry,
- -1);
-
- /* sanity check */
- if (key_entry == NULL)
- return;
-
- /* CapsLock isn't supported as a keybinding modifier, so keep it from confusing us */
- mask &= ~EGG_VIRTUAL_LOCK_MASK;
-
- tmp_key.model = model;
- tmp_key.keyval = keyval;
- tmp_key.keycode = keycode;
- tmp_key.mask = mask;
- tmp_key.gconf_key = key_entry->gconf_key;
- tmp_key.description = NULL;
- tmp_key.editable = TRUE; /* kludge to stuff in a return flag */
-
- if (keyval != 0 || keycode != 0) /* any number of keys can be disabled */
- gtk_tree_model_foreach (model,
- (GtkTreeModelForeachFunc) cb_check_for_uniqueness,
- &tmp_key);
-
- /* Check for unmodified keys */
- if (tmp_key.mask == 0 && tmp_key.keycode != 0)
- {
- if ((tmp_key.keyval >= GDK_KEY_a && tmp_key.keyval <= GDK_KEY_z)
- || (tmp_key.keyval >= GDK_KEY_A && tmp_key.keyval <= GDK_KEY_Z)
- || (tmp_key.keyval >= GDK_KEY_0 && tmp_key.keyval <= GDK_KEY_9)
- || (tmp_key.keyval >= GDK_KEY_kana_fullstop && tmp_key.keyval <= GDK_KEY_semivoicedsound)
- || (tmp_key.keyval >= GDK_KEY_Arabic_comma && tmp_key.keyval <= GDK_KEY_Arabic_sukun)
- || (tmp_key.keyval >= GDK_KEY_Serbian_dje && tmp_key.keyval <= GDK_KEY_Cyrillic_HARDSIGN)
- || (tmp_key.keyval >= GDK_KEY_Greek_ALPHAaccent && tmp_key.keyval <= GDK_KEY_Greek_omega)
- || (tmp_key.keyval >= GDK_KEY_hebrew_doublelowline && tmp_key.keyval <= GDK_KEY_hebrew_taf)
- || (tmp_key.keyval >= GDK_KEY_Thai_kokai && tmp_key.keyval <= GDK_KEY_Thai_lekkao)
- || (tmp_key.keyval >= GDK_KEY_Hangul && tmp_key.keyval <= GDK_KEY_Hangul_Special)
- || (tmp_key.keyval >= GDK_KEY_Hangul_Kiyeog && tmp_key.keyval <= GDK_KEY_Hangul_J_YeorinHieuh)
- || keyval_is_forbidden (tmp_key.keyval)) {
- GtkWidget *dialog;
- char *name;
-
- name = binding_name (keyval, keycode, mask, TRUE);
-
- dialog =
- gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
- GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
- GTK_MESSAGE_WARNING,
- GTK_BUTTONS_CANCEL,
- _("The shortcut \"%s\" cannot be used because it will become impossible to type using this key.\n"
- "Please try with a key such as Control, Alt or Shift at the same time."),
- name);
-
- g_free (name);
- gtk_dialog_run (GTK_DIALOG (dialog));
- gtk_widget_destroy (dialog);
-
- /* set it back to its previous value. */
- egg_cell_renderer_keys_set_accelerator
- (EGG_CELL_RENDERER_KEYS (cell),
- key_entry->keyval, key_entry->keycode, key_entry->mask);
- return;
- }
- }
-
- /* flag to see if the new accelerator was in use by something */
- if (!tmp_key.editable)
- {
- GtkWidget *dialog;
- char *name;
- int response;
-
- name = binding_name (keyval, keycode, mask, TRUE);
-
- dialog =
- gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
- GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
- GTK_MESSAGE_WARNING,
- GTK_BUTTONS_CANCEL,
- _("The shortcut \"%s\" is already used for\n\"%s\""),
- name, tmp_key.description ?
- tmp_key.description : tmp_key.gconf_key);
- g_free (name);
-
- gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
- _("If you reassign the shortcut to \"%s\", the \"%s\" shortcut "
- "will be disabled."),
- key_entry->description ?
- key_entry->description : key_entry->gconf_key,
- tmp_key.description ?
- tmp_key.description : tmp_key.gconf_key);
-
- gtk_dialog_add_button (GTK_DIALOG (dialog),
- _("_Reassign"),
- GTK_RESPONSE_ACCEPT);
-
- gtk_dialog_set_default_response (GTK_DIALOG (dialog),
- GTK_RESPONSE_ACCEPT);
-
- response = gtk_dialog_run (GTK_DIALOG (dialog));
- gtk_widget_destroy (dialog);
-
- if (response == GTK_RESPONSE_ACCEPT)
- {
- GConfClient *client;
-
- client = gconf_client_get_default ();
-
- gconf_client_set_string (client,
- tmp_key.gconf_key,
- "", &err);
-
- if (err != NULL)
- {
- show_error (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
- err);
- g_error_free (err);
- g_object_unref (client);
- return;
- }
-
- str = binding_name (keyval, keycode, mask, FALSE);
- gconf_client_set_string (client,
- key_entry->gconf_key,
- str, &err);
-
- if (err != NULL)
- {
- show_error (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
- err);
- g_error_free (err);
-
- /* reset the previous shortcut */
- gconf_client_set_string (client,
- tmp_key.gconf_key,
- str, NULL);
- }
-
- g_free (str);
- g_object_unref (client);
- }
- else
- {
- /* set it back to its previous value. */
- egg_cell_renderer_keys_set_accelerator (EGG_CELL_RENDERER_KEYS (cell),
- key_entry->keyval,
- key_entry->keycode,
- key_entry->mask);
- }
-
- return;
- }
-
- str = binding_name (keyval, keycode, mask, FALSE);
-
- client = gconf_client_get_default ();
- gconf_client_set_string (client,
- key_entry->gconf_key,
- str,
- &err);
- g_free (str);
- g_object_unref (client);
-
- if (err != NULL)
- {
- show_error (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))), err);
- g_error_free (err);
- key_entry->editable = FALSE;
- }
-}
-
-static void
-accel_cleared_callback (GtkCellRendererText *cell,
- const char *path_string,
- gpointer data)
-{
- GConfClient *client;
- GtkTreeView *view = (GtkTreeView *) data;
- GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
- KeyEntry *key_entry;
- GtkTreeIter iter;
- GError *err = NULL;
- GtkTreeModel *model;
-
- block_accels = FALSE;
-
- model = gtk_tree_view_get_model (view);
- gtk_tree_model_get_iter (model, &iter, path);
- gtk_tree_path_free (path);
- gtk_tree_model_get (model, &iter,
- KEYENTRY_COLUMN, &key_entry,
- -1);
-
- /* sanity check */
- if (key_entry == NULL)
- return;
-
- /* Unset the key */
- client = gconf_client_get_default();
- gconf_client_set_string (client,
- key_entry->gconf_key,
- "",
- &err);
- g_object_unref (client);
-
- if (err != NULL)
- {
- GtkWidget *dialog;
-
- dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
- GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
- GTK_MESSAGE_WARNING,
- GTK_BUTTONS_OK,
- _("Error unsetting accelerator in configuration database: %s"),
- err->message);
- gtk_dialog_run (GTK_DIALOG (dialog));
-
- gtk_widget_destroy (dialog);
- g_error_free (err);
- key_entry->editable = FALSE;
- }
-}
-
-static void
-description_edited_callback (GtkCellRendererText *renderer,
- gchar *path_string,
- gchar *new_text,
- gpointer user_data)
-{
- GConfClient *client;
- GtkTreeView *view = GTK_TREE_VIEW (user_data);
- GtkTreeModel *model;
- GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
- GtkTreeIter iter;
- KeyEntry *key_entry;
-
- model = gtk_tree_view_get_model (view);
- gtk_tree_model_get_iter (model, &iter, path);
- gtk_tree_path_free (path);
-
- gtk_tree_model_get (model, &iter,
- KEYENTRY_COLUMN, &key_entry,
- -1);
-
- /* sanity check */
- if (key_entry == NULL || key_entry->desc_gconf_key == NULL)
- return;
-
- client = gconf_client_get_default ();
- if (!gconf_client_set_string (client, key_entry->desc_gconf_key, new_text, NULL))
- key_entry->desc_editable = FALSE;
-
- g_object_unref (client);
-}
-
-
-typedef struct
-{
- GtkTreeView *tree_view;
- GtkTreePath *path;
- GtkTreeViewColumn *column;
-} IdleData;
-
-static gboolean
-real_start_editing_cb (IdleData *idle_data)
-{
- gtk_widget_grab_focus (GTK_WIDGET (idle_data->tree_view));
- gtk_tree_view_set_cursor (idle_data->tree_view,
- idle_data->path,
- idle_data->column,
- TRUE);
- gtk_tree_path_free (idle_data->path);
- g_free (idle_data);
- return FALSE;
-}
-
-static gboolean
-edit_custom_shortcut (KeyEntry *key)
-{
- gint result;
- const gchar *text;
- gboolean ret;
-
- gtk_entry_set_text (GTK_ENTRY (custom_shortcut_name_entry), key->description ? key->description : "");
- gtk_widget_set_sensitive (custom_shortcut_name_entry, key->desc_editable);
- gtk_widget_grab_focus (custom_shortcut_name_entry);
- gtk_entry_set_text (GTK_ENTRY (custom_shortcut_command_entry), key->command ? key->command : "");
- gtk_widget_set_sensitive (custom_shortcut_command_entry, key->cmd_editable);
-
- gtk_window_present (GTK_WINDOW (custom_shortcut_dialog));
- result = gtk_dialog_run (GTK_DIALOG (custom_shortcut_dialog));
- switch (result)
- {
- case GTK_RESPONSE_OK:
- text = gtk_entry_get_text (GTK_ENTRY (custom_shortcut_name_entry));
- g_free (key->description);
- key->description = g_strdup (text);
- text = gtk_entry_get_text (GTK_ENTRY (custom_shortcut_command_entry));
- g_free (key->command);
- key->command = g_strdup (text);
- ret = TRUE;
- break;
- default:
- ret = FALSE;
- break;
- }
-
- gtk_widget_hide (custom_shortcut_dialog);
-
- return ret;
-}
-
-static gboolean
-remove_custom_shortcut (GtkTreeModel *model, GtkTreeIter *iter)
-{
- GtkTreeIter parent;
- GConfClient *client;
- gchar *base;
- KeyEntry *key;
-
- gtk_tree_model_get (model, iter,
- KEYENTRY_COLUMN, &key,
- -1);
-
- /* not a custom shortcut */
- if (key->command == NULL)
- return FALSE;
-
- client = gconf_client_get_default ();
-
- gconf_client_notify_remove (client, key->gconf_cnxn);
- if (key->gconf_cnxn_desc != 0)
- gconf_client_notify_remove (client, key->gconf_cnxn_desc);
- if (key->gconf_cnxn_cmd != 0)
- gconf_client_notify_remove (client, key->gconf_cnxn_cmd);
-
- base = g_path_get_dirname (key->gconf_key);
- gconf_client_recursive_unset (client, base, 0, NULL);
- g_free (base);
- /* suggest sync now so the unset directory actually gets dropped;
- * if we don't do this we may end up with 'zombie' shortcuts when
- * restarting the app */
- gconf_client_suggest_sync (client, NULL);
- g_object_unref (client);
-
- g_free (key->gconf_key);
- g_free (key->description);
- g_free (key->desc_gconf_key);
- g_free (key->command);
- g_free (key->cmd_gconf_key);
- g_free (key);
-
- gtk_tree_model_iter_parent (model, &parent, iter);
- gtk_tree_store_remove (GTK_TREE_STORE (model), iter);
- if (!gtk_tree_model_iter_has_child (model, &parent))
- gtk_tree_store_remove (GTK_TREE_STORE (model), &parent);
-
- return TRUE;
-}
-
-static void
-update_custom_shortcut (GtkTreeModel *model, GtkTreeIter *iter)
-{
- KeyEntry *key;
-
- gtk_tree_model_get (model, iter,
- KEYENTRY_COLUMN, &key,
- -1);
-
- edit_custom_shortcut (key);
- if (key->command == NULL || key->command[0] == '\0')
- {
- remove_custom_shortcut (model, iter);
- }
- else
- {
- GConfClient *client;
-
- gtk_tree_store_set (GTK_TREE_STORE (model), iter,
- KEYENTRY_COLUMN, key, -1);
- client = gconf_client_get_default ();
- if (key->description != NULL)
- gconf_client_set_string (client, key->desc_gconf_key, key->description, NULL);
- else
- gconf_client_unset (client, key->desc_gconf_key, NULL);
- gconf_client_set_string (client, key->cmd_gconf_key, key->command, NULL);
- g_object_unref (client);
- }
-}
-
-static gchar *
-find_free_gconf_key (GError **error)
-{
- GConfClient *client;
-
- gchar *dir;
- int i;
-
- client = gconf_client_get_default ();
-
- for (i = 0; i < MAX_CUSTOM_SHORTCUTS; i++)
- {
- dir = g_strdup_printf ("%s/custom%d", GCONF_BINDING_DIR, i);
- if (!gconf_client_dir_exists (client, dir, NULL))
- break;
- g_free (dir);
- }
-
- if (i == MAX_CUSTOM_SHORTCUTS)
- {
- dir = NULL;
- g_set_error_literal (error,
- g_quark_from_string ("Keyboard Shortcuts"),
- 0,
- _("Too many custom shortcuts"));
- }
-
- g_object_unref (client);
-
- return dir;
-}
-
-static void
-add_custom_shortcut (GtkTreeView *tree_view,
- GtkTreeModel *model)
-{
- KeyEntry *key_entry;
- GtkTreeIter iter;
- GtkTreeIter parent_iter;
- GtkTreePath *path;
- gchar *dir;
- GConfClient *client;
- GError *error;
-
- error = NULL;
- dir = find_free_gconf_key (&error);
- if (dir == NULL)
- {
- show_error (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (tree_view))), error);
-
- g_error_free (error);
- return;
- }
-
- key_entry = g_new0 (KeyEntry, 1);
- key_entry->gconf_key = g_strconcat (dir, "/binding", NULL);
- key_entry->editable = TRUE;
- key_entry->model = model;
- key_entry->desc_gconf_key = g_strconcat (dir, "/name", NULL);
- key_entry->description = g_strdup ("");
- key_entry->desc_editable = TRUE;
- key_entry->cmd_gconf_key = g_strconcat (dir, "/action", NULL);
- key_entry->command = g_strdup ("");
- key_entry->cmd_editable = TRUE;
- g_free (dir);
-
- if (edit_custom_shortcut (key_entry) &&
- key_entry->command && key_entry->command[0])
- {
- find_section (model, &iter, _("Custom Shortcuts"));
- parent_iter = iter;
- gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent_iter);
- gtk_tree_store_set (GTK_TREE_STORE (model), &iter, KEYENTRY_COLUMN, key_entry, -1);
-
- /* store in gconf */
- client = gconf_client_get_default ();
- gconf_client_set_string (client, key_entry->gconf_key, "", NULL);
- gconf_client_set_string (client, key_entry->desc_gconf_key, key_entry->description, NULL);
- gconf_client_set_string (client, key_entry->cmd_gconf_key, key_entry->command, NULL);
-
- /* add gconf watches */
- key_entry->gconf_cnxn_desc = gconf_client_notify_add (client,
- key_entry->desc_gconf_key,
- (GConfClientNotifyFunc) &keybinding_description_changed,
- key_entry, NULL, NULL);
- key_entry->gconf_cnxn_cmd = gconf_client_notify_add (client,
- key_entry->cmd_gconf_key,
- (GConfClientNotifyFunc) &keybinding_command_changed,
- key_entry, NULL, NULL);
- key_entry->gconf_cnxn = gconf_client_notify_add (client,
- key_entry->gconf_key,
- (GConfClientNotifyFunc) &keybinding_key_changed,
- key_entry, NULL, NULL);
-
-
- g_object_unref (client);
-
- /* make the new shortcut visible */
- path = gtk_tree_model_get_path (model, &iter);
- gtk_tree_view_expand_to_path (tree_view, path);
- gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0, 0);
- gtk_tree_path_free (path);
- }
- else
- {
- g_free (key_entry->gconf_key);
- g_free (key_entry->description);
- g_free (key_entry->desc_gconf_key);
- g_free (key_entry->command);
- g_free (key_entry->cmd_gconf_key);
- g_free (key_entry);
- }
-}
-
-static void
-start_editing_kb_cb (GtkTreeView *treeview,
- GtkTreePath *path,
- GtkTreeViewColumn *column,
- gpointer user_data)
-{
- GtkTreeModel *model;
- GtkTreeIter iter;
- KeyEntry *key;
-
- model = gtk_tree_view_get_model (treeview);
- gtk_tree_model_get_iter (model, &iter, path);
- gtk_tree_model_get (model, &iter,
- KEYENTRY_COLUMN, &key,
- -1);
-
- if (key == NULL)
- {
- /* This is a section heading - expand or collapse */
- if (gtk_tree_view_row_expanded (treeview, path))
- gtk_tree_view_collapse_row (treeview, path);
- else
- gtk_tree_view_expand_row (treeview, path, FALSE);
- return;
- }
-
- /* if only the accel can be edited on the selected row
- * always select the accel column */
- if (key->desc_editable &&
- column == gtk_tree_view_get_column (treeview, 0))
- {
- gtk_widget_grab_focus (GTK_WIDGET (treeview));
- gtk_tree_view_set_cursor (treeview, path,
- gtk_tree_view_get_column (treeview, 0),
- FALSE);
- update_custom_shortcut (model, &iter);
- }
- else
- {
- gtk_widget_grab_focus (GTK_WIDGET (treeview));
- gtk_tree_view_set_cursor (treeview,
- path,
- gtk_tree_view_get_column (treeview, 1),
- TRUE);
- }
-}
-
-static gboolean
-start_editing_cb (GtkTreeView *tree_view,
- GdkEventButton *event,
- gpointer user_data)
-{
- GtkTreePath *path;
- GtkTreeViewColumn *column;
-
- if (event->window != gtk_tree_view_get_bin_window (tree_view))
- return FALSE;
-
- if (gtk_tree_view_get_path_at_pos (tree_view,
- (gint) event->x,
- (gint) event->y,
- &path, &column,
- NULL, NULL))
- {
- IdleData *idle_data;
- GtkTreeModel *model;
- GtkTreeIter iter;
- KeyEntry *key;
-
- if (gtk_tree_path_get_depth (path) == 1)
- {
- gtk_tree_path_free (path);
- return FALSE;
- }
-
- model = gtk_tree_view_get_model (tree_view);
- gtk_tree_model_get_iter (model, &iter, path);
- gtk_tree_model_get (model, &iter,
- KEYENTRY_COLUMN, &key,
- -1);
-
- /* if only the accel can be edited on the selected row
- * always select the accel column */
- if (key->desc_editable &&
- column == gtk_tree_view_get_column (tree_view, 0))
- {
- gtk_widget_grab_focus (GTK_WIDGET (tree_view));
- gtk_tree_view_set_cursor (tree_view, path,
- gtk_tree_view_get_column (tree_view, 0),
- FALSE);
- update_custom_shortcut (model, &iter);
- }
- else
- {
- idle_data = g_new (IdleData, 1);
- idle_data->tree_view = tree_view;
- idle_data->path = path;
- idle_data->column = key->desc_editable ? column :
- gtk_tree_view_get_column (tree_view, 1);
- g_idle_add ((GSourceFunc) real_start_editing_cb, idle_data);
- block_accels = TRUE;
- }
- g_signal_stop_emission_by_name (tree_view, "button_press_event");
- }
- return TRUE;
-}
-
-/* this handler is used to keep accels from activating while the user
- * is assigning a new shortcut so that he won't accidentally trigger one
- * of the widgets */
-static gboolean
-maybe_block_accels (GtkWidget *widget,
- GdkEventKey *event,
- gpointer user_data)
-{
- if (block_accels)
- {
- return gtk_window_propagate_key_event (GTK_WINDOW (widget), event);
- }
- return FALSE;
-}
-
-#if 0
-static void
-cb_dialog_response (GtkWidget *widget, gint response_id, gpointer data)
-{
- GtkBuilder *builder = data;
- GtkTreeView *treeview;
- GtkTreeModel *model;
- GtkTreeSelection *selection;
- GtkTreeIter iter;
-
- treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder,
- "shortcut_treeview"));
- model = gtk_tree_view_get_model (treeview);
-
- if (response_id == GTK_RESPONSE_HELP)
- {
- capplet_help (GTK_WINDOW (widget),
- "goscustdesk-39");
- }
- else if (response_id == RESPONSE_ADD)
- {
- add_custom_shortcut (treeview, model);
- }
- else if (response_id == RESPONSE_REMOVE)
- {
- selection = gtk_tree_view_get_selection (treeview);
- if (gtk_tree_selection_get_selected (selection, NULL, &iter))
- {
- remove_custom_shortcut (model, &iter);
- }
- }
- else
- {
- clear_old_model (builder);
- gtk_main_quit ();
- }
-}
-#endif
-
-static void
-add_button_clicked (GtkWidget *button,
- GtkBuilder *builder)
-{
- GtkTreeView *treeview;
- GtkTreeModel *model;
-
- treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder,
- "shortcut_treeview"));
- model = gtk_tree_view_get_model (treeview);
-
- add_custom_shortcut (treeview, model);
-}
-
-static void
-remove_button_clicked (GtkWidget *button,
- GtkBuilder *builder)
-{
- GtkTreeView *treeview;
- GtkTreeModel *model;
- GtkTreeSelection *selection;
- GtkTreeIter iter;
-
- treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder,
- "shortcut_treeview"));
- model = gtk_tree_view_get_model (treeview);
-
- selection = gtk_tree_view_get_selection (treeview);
- if (gtk_tree_selection_get_selected (selection, NULL, &iter))
- {
- remove_custom_shortcut (model, &iter);
- }
-}
-
-static void
-on_window_manager_change (const char *wm_name, GtkBuilder *builder)
-{
- reload_key_entries (builder);
-}
-
-void
-gnome_keybinding_properties_init (CcPanel *panel, GtkBuilder *builder)
-{
- wm_common_register_window_manager_change ((GFunc) on_window_manager_change,
- builder);
-
-}
-
-void
-gnome_keybinding_properties_dispose (CcPanel *panel)
-{
- if (maybe_block_accels_id != 0)
- {
- CcShell *shell;
- GtkWidget *toplevel;
-
- shell = cc_panel_get_shell (CC_PANEL (panel));
- toplevel = cc_shell_get_toplevel (shell);
-
- g_signal_handler_disconnect (toplevel, maybe_block_accels_id);
- maybe_block_accels_id = 0;
-
- if (keyb_sections != NULL)
- g_hash_table_destroy (keyb_sections);
- }
-}
-
-/*
- * vim: sw=2 ts=8 cindent noai bs=2
- */
diff --git a/panels/keyboard/keyboard-shortcuts.c b/panels/keyboard/keyboard-shortcuts.c
index 8f60356..86dc433 100644
--- a/panels/keyboard/keyboard-shortcuts.c
+++ b/panels/keyboard/keyboard-shortcuts.c
@@ -25,6 +25,7 @@
#include "keyboard-shortcuts.h"
#include "wm-common.h"
+#define MAX_CUSTOM_SHORTCUTS 1000
#define GCONF_BINDING_DIR "/desktop/gnome/keybindings"
#define WID(builder, name) (GTK_WIDGET (gtk_builder_get_object (builder, name)))
@@ -82,6 +83,7 @@ enum
};
static guint maybe_block_accels_id = 0;
+static gboolean block_accels = FALSE;
static GtkWidget *custom_shortcut_dialog = NULL;
static GtkWidget *custom_shortcut_name_entry = NULL;
static GtkWidget *custom_shortcut_command_entry = NULL;
@@ -96,14 +98,30 @@ free_key_array (GPtrArray *keys)
for (i = 0; i < keys->len; i++)
{
- KeyEntry *entry;
-
- entry = g_ptr_array_index (keys, i);
- g_free (entry->gconf_key);
- g_free (entry->description);
- g_free (entry->desc_gconf_key);
- g_free (entry->command);
- g_free (entry->cmd_gconf_key);
+ KeyEntry *key_entry;
+ GConfClient *client;
+
+ key_entry = g_ptr_array_index (keys, i);
+
+ /* Remove GConf watches */
+ client = gconf_client_get_default ();
+ gconf_client_remove_dir (client, key_entry->gconf_key, NULL);
+ gconf_client_notify_remove (client, key_entry->gconf_cnxn);
+ if (key_entry->gconf_cnxn_desc != 0)
+ gconf_client_notify_remove (client, key_entry->gconf_cnxn_desc);
+ if (key_entry->gconf_cnxn_cmd != 0)
+ gconf_client_notify_remove (client, key_entry->gconf_cnxn_cmd);
+
+ g_object_unref (client);
+
+ /* Free memory */
+ g_free (key_entry->gconf_key);
+ g_free (key_entry->description);
+ g_free (key_entry->desc_gconf_key);
+ g_free (key_entry->command);
+ g_free (key_entry->cmd_gconf_key);
+
+ g_free (key_entry);
}
g_ptr_array_free (keys, TRUE);
@@ -171,6 +189,87 @@ binding_from_string (const char *str,
return TRUE;
}
+static gboolean
+keybinding_key_changed_foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ KeyEntry *key_entry;
+ KeyEntry *tmp_key_entry;
+
+ key_entry = (KeyEntry *)user_data;
+ gtk_tree_model_get (key_entry->model, iter,
+ KEYENTRY_COLUMN, &tmp_key_entry,
+ -1);
+
+ if (key_entry == tmp_key_entry)
+ {
+ gtk_tree_model_row_changed (key_entry->model, path, iter);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void
+keybinding_description_changed (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data)
+{
+ KeyEntry *key_entry;
+ const gchar *key_value;
+
+ key_entry = (KeyEntry *) user_data;
+ key_value = entry->value ? gconf_value_get_string (entry->value) : NULL;
+
+ g_free (key_entry->description);
+ key_entry->description = key_value ? g_strdup (key_value) : NULL;
+ key_entry->desc_editable = gconf_entry_get_is_writable (entry);
+
+ /* update the model */
+ gtk_tree_model_foreach (key_entry->model, keybinding_key_changed_foreach, key_entry);
+}
+
+static void
+keybinding_key_changed (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data)
+{
+ KeyEntry *key_entry;
+ const gchar *key_value;
+
+ key_entry = (KeyEntry *) user_data;
+ key_value = entry->value ? gconf_value_get_string (entry->value) : NULL;
+
+ binding_from_string (key_value, &key_entry->keyval, &key_entry->keycode, &key_entry->mask);
+ key_entry->editable = gconf_entry_get_is_writable (entry);
+
+ /* update the model */
+ gtk_tree_model_foreach (key_entry->model, keybinding_key_changed_foreach, key_entry);
+}
+
+static void
+keybinding_command_changed (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data)
+{
+ KeyEntry *key_entry;
+ const gchar *key_value;
+
+ key_entry = (KeyEntry *) user_data;
+ key_value = entry->value ? gconf_value_get_string (entry->value) : NULL;
+
+ g_free (key_entry->command);
+ key_entry->command = key_value ? g_strdup (key_value) : NULL;
+ key_entry->cmd_editable = gconf_entry_get_is_writable (entry);
+
+ /* update the model */
+ gtk_tree_model_foreach (key_entry->model, keybinding_key_changed_foreach, key_entry);
+}
+
static void
append_section (GtkBuilder *builder, const gchar *title, const KeyListEntry *keys_list)
{
@@ -258,26 +357,26 @@ append_section (GtkBuilder *builder, const gchar *title, const KeyListEntry *key
{
key_entry->desc_gconf_key = g_strdup (keys_list[i].description_name);
key_entry->desc_editable = gconf_client_key_is_writable (client, key_entry->desc_gconf_key, NULL);
- /* key_entry->gconf_cnxn_desc = gconf_client_notify_add (client, */
- /* key_entry->desc_gconf_key, */
- /* (GConfClientNotifyFunc) &keybinding_description_changed, */
- /* key_entry, NULL, NULL); */
+ key_entry->gconf_cnxn_desc = gconf_client_notify_add (client,
+ key_entry->desc_gconf_key,
+ (GConfClientNotifyFunc) &keybinding_description_changed,
+ key_entry, NULL, NULL);
}
if (keys_list[i].cmd_name != NULL)
{
key_entry->cmd_gconf_key = g_strdup (keys_list[i].cmd_name);
key_entry->cmd_editable = gconf_client_key_is_writable (client, key_entry->cmd_gconf_key, NULL);
- /* key_entry->gconf_cnxn_cmd = gconf_client_notify_add (client, */
- /* key_entry->cmd_gconf_key, */
- /* (GConfClientNotifyFunc) &keybinding_command_changed, */
- /* key_entry, NULL, NULL); */
+ key_entry->gconf_cnxn_cmd = gconf_client_notify_add (client,
+ key_entry->cmd_gconf_key,
+ (GConfClientNotifyFunc) &keybinding_command_changed,
+ key_entry, NULL, NULL);
}
gconf_client_add_dir (client, key_string, GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
- /* key_entry->gconf_cnxn = gconf_client_notify_add (client, */
- /* key_string, */
- /* (GConfClientNotifyFunc) &keybinding_key_changed, */
- /* key_entry, NULL, NULL); */
+ key_entry->gconf_cnxn = gconf_client_notify_add (client,
+ key_string,
+ (GConfClientNotifyFunc) &keybinding_key_changed,
+ key_entry, NULL, NULL);
key_value = gconf_client_get_string (client, key_string, NULL);
binding_from_string (key_value, &key_entry->keyval, &key_entry->keycode, &key_entry->mask);
@@ -285,8 +384,6 @@ append_section (GtkBuilder *builder, const gchar *title, const KeyListEntry *key
gconf_entry_free (entry);
- g_print ("Adding %s to section %s\n", key_entry->description, title);
-
g_ptr_array_add (keys_array, key_entry);
}
@@ -707,9 +804,6 @@ section_selection_changed (GtkTreeSelection *selection, gpointer data)
GtkTreeIter new_row;
KeyEntry *entry = g_ptr_array_index (keys, i);
- g_print ("Adding gconf: %s, keyval = %d\n",
- entry->gconf_key, entry->keyval);
-
gtk_list_store_append (GTK_LIST_STORE (shortcut_model), &new_row);
gtk_list_store_set (GTK_LIST_STORE (shortcut_model), &new_row,
DESCRIPTION_COLUMN, entry->description,
@@ -739,6 +833,859 @@ shortcut_selection_changed (GtkTreeSelection *selection, gpointer data)
gtk_widget_set_sensitive (button, can_remove);
}
+typedef struct
+{
+ GtkTreeView *tree_view;
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+} IdleData;
+
+static gboolean
+edit_custom_shortcut (KeyEntry *key)
+{
+ gint result;
+ const gchar *text;
+ gboolean ret;
+
+ gtk_entry_set_text (GTK_ENTRY (custom_shortcut_name_entry), key->description ? key->description : "");
+ gtk_widget_set_sensitive (custom_shortcut_name_entry, key->desc_editable);
+ gtk_widget_grab_focus (custom_shortcut_name_entry);
+ gtk_entry_set_text (GTK_ENTRY (custom_shortcut_command_entry), key->command ? key->command : "");
+ gtk_widget_set_sensitive (custom_shortcut_command_entry, key->cmd_editable);
+
+ gtk_window_present (GTK_WINDOW (custom_shortcut_dialog));
+ result = gtk_dialog_run (GTK_DIALOG (custom_shortcut_dialog));
+ switch (result)
+ {
+ case GTK_RESPONSE_OK:
+ text = gtk_entry_get_text (GTK_ENTRY (custom_shortcut_name_entry));
+ g_free (key->description);
+ key->description = g_strdup (text);
+ text = gtk_entry_get_text (GTK_ENTRY (custom_shortcut_command_entry));
+ g_free (key->command);
+ key->command = g_strdup (text);
+ ret = TRUE;
+ break;
+ default:
+ ret = FALSE;
+ break;
+ }
+
+ gtk_widget_hide (custom_shortcut_dialog);
+
+ return ret;
+}
+
+static gboolean
+remove_custom_shortcut (GtkTreeModel *model, GtkTreeIter *iter)
+{
+ GtkTreeIter parent;
+ GConfClient *client;
+ gchar *base;
+ KeyEntry *key;
+
+ gtk_tree_model_get (model, iter,
+ KEYENTRY_COLUMN, &key,
+ -1);
+
+ /* not a custom shortcut */
+ if (key->command == NULL)
+ return FALSE;
+
+ client = gconf_client_get_default ();
+
+ gconf_client_notify_remove (client, key->gconf_cnxn);
+ if (key->gconf_cnxn_desc != 0)
+ gconf_client_notify_remove (client, key->gconf_cnxn_desc);
+ if (key->gconf_cnxn_cmd != 0)
+ gconf_client_notify_remove (client, key->gconf_cnxn_cmd);
+
+ base = g_path_get_dirname (key->gconf_key);
+ gconf_client_recursive_unset (client, base, 0, NULL);
+ g_free (base);
+ /* suggest sync now so the unset directory actually gets dropped;
+ * if we don't do this we may end up with 'zombie' shortcuts when
+ * restarting the app */
+ gconf_client_suggest_sync (client, NULL);
+ g_object_unref (client);
+
+ g_free (key->gconf_key);
+ g_free (key->description);
+ g_free (key->desc_gconf_key);
+ g_free (key->command);
+ g_free (key->cmd_gconf_key);
+ g_free (key);
+
+ gtk_tree_model_iter_parent (model, &parent, iter);
+ gtk_tree_store_remove (GTK_TREE_STORE (model), iter);
+ if (!gtk_tree_model_iter_has_child (model, &parent))
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &parent);
+
+ return TRUE;
+}
+
+static void
+update_custom_shortcut (GtkTreeModel *model, GtkTreeIter *iter)
+{
+ KeyEntry *key;
+
+ gtk_tree_model_get (model, iter,
+ KEYENTRY_COLUMN, &key,
+ -1);
+
+ edit_custom_shortcut (key);
+ if (key->command == NULL || key->command[0] == '\0')
+ {
+ remove_custom_shortcut (model, iter);
+ }
+ else
+ {
+ GConfClient *client;
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), iter,
+ KEYENTRY_COLUMN, key, -1);
+ client = gconf_client_get_default ();
+ if (key->description != NULL)
+ gconf_client_set_string (client, key->desc_gconf_key, key->description, NULL);
+ else
+ gconf_client_unset (client, key->desc_gconf_key, NULL);
+ gconf_client_set_string (client, key->cmd_gconf_key, key->command, NULL);
+ g_object_unref (client);
+ }
+}
+
+static gboolean
+real_start_editing_cb (IdleData *idle_data)
+{
+ gtk_widget_grab_focus (GTK_WIDGET (idle_data->tree_view));
+ gtk_tree_view_set_cursor (idle_data->tree_view,
+ idle_data->path,
+ idle_data->column,
+ TRUE);
+ gtk_tree_path_free (idle_data->path);
+ g_free (idle_data);
+ return FALSE;
+}
+
+static gboolean
+start_editing_cb (GtkTreeView *tree_view,
+ GdkEventButton *event,
+ gpointer user_data)
+{
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+
+ if (event->window != gtk_tree_view_get_bin_window (tree_view))
+ return FALSE;
+
+ if (gtk_tree_view_get_path_at_pos (tree_view,
+ (gint) event->x,
+ (gint) event->y,
+ &path, &column,
+ NULL, NULL))
+ {
+ IdleData *idle_data;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ KeyEntry *key;
+
+ if (gtk_tree_path_get_depth (path) == 1)
+ {
+ gtk_tree_path_free (path);
+ return FALSE;
+ }
+
+ model = gtk_tree_view_get_model (tree_view);
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter,
+ KEYENTRY_COLUMN, &key,
+ -1);
+
+ /* if only the accel can be edited on the selected row
+ * always select the accel column */
+ if (key->desc_editable &&
+ column == gtk_tree_view_get_column (tree_view, 0))
+ {
+ gtk_widget_grab_focus (GTK_WIDGET (tree_view));
+ gtk_tree_view_set_cursor (tree_view, path,
+ gtk_tree_view_get_column (tree_view, 0),
+ FALSE);
+ update_custom_shortcut (model, &iter);
+ }
+ else
+ {
+ idle_data = g_new (IdleData, 1);
+ idle_data->tree_view = tree_view;
+ idle_data->path = path;
+ idle_data->column = key->desc_editable ? column :
+ gtk_tree_view_get_column (tree_view, 1);
+ g_idle_add ((GSourceFunc) real_start_editing_cb, idle_data);
+ block_accels = TRUE;
+ }
+ g_signal_stop_emission_by_name (tree_view, "button_press_event");
+ }
+ return TRUE;
+}
+
+static void
+start_editing_kb_cb (GtkTreeView *treeview,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ gpointer user_data)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ KeyEntry *key;
+
+ model = gtk_tree_view_get_model (treeview);
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter,
+ KEYENTRY_COLUMN, &key,
+ -1);
+
+ if (key == NULL)
+ {
+ /* This is a section heading - expand or collapse */
+ if (gtk_tree_view_row_expanded (treeview, path))
+ gtk_tree_view_collapse_row (treeview, path);
+ else
+ gtk_tree_view_expand_row (treeview, path, FALSE);
+ return;
+ }
+
+ /* if only the accel can be edited on the selected row
+ * always select the accel column */
+ if (key->desc_editable &&
+ column == gtk_tree_view_get_column (treeview, 0))
+ {
+ gtk_widget_grab_focus (GTK_WIDGET (treeview));
+ gtk_tree_view_set_cursor (treeview, path,
+ gtk_tree_view_get_column (treeview, 0),
+ FALSE);
+ update_custom_shortcut (model, &iter);
+ }
+ else
+ {
+ gtk_widget_grab_focus (GTK_WIDGET (treeview));
+ gtk_tree_view_set_cursor (treeview,
+ path,
+ gtk_tree_view_get_column (treeview, 1),
+ TRUE);
+ }
+}
+
+static void
+description_edited_callback (GtkCellRendererText *renderer,
+ gchar *path_string,
+ gchar *new_text,
+ gpointer user_data)
+{
+ GConfClient *client;
+ GtkTreeView *view = GTK_TREE_VIEW (user_data);
+ GtkTreeModel *model;
+ GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
+ GtkTreeIter iter;
+ KeyEntry *key_entry;
+
+ model = gtk_tree_view_get_model (view);
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_path_free (path);
+
+ gtk_tree_model_get (model, &iter,
+ KEYENTRY_COLUMN, &key_entry,
+ -1);
+
+ /* sanity check */
+ if (key_entry == NULL || key_entry->desc_gconf_key == NULL)
+ return;
+
+ client = gconf_client_get_default ();
+ if (!gconf_client_set_string (client, key_entry->desc_gconf_key, new_text, NULL))
+ key_entry->desc_editable = FALSE;
+
+ g_object_unref (client);
+}
+
+static const guint forbidden_keyvals[] = {
+ /* Navigation keys */
+ GDK_KEY_Home,
+ GDK_KEY_Left,
+ GDK_KEY_Up,
+ GDK_KEY_Right,
+ GDK_KEY_Down,
+ GDK_KEY_Page_Up,
+ GDK_KEY_Page_Down,
+ GDK_KEY_End,
+ GDK_KEY_Tab,
+
+ /* Return */
+ GDK_KEY_KP_Enter,
+ GDK_KEY_Return,
+
+ GDK_KEY_space,
+ GDK_KEY_Mode_switch
+};
+
+static char*
+binding_name (guint keyval,
+ guint keycode,
+ EggVirtualModifierType mask,
+ gboolean translate)
+{
+ if (keyval != 0 || keycode != 0)
+ return translate ?
+ egg_virtual_accelerator_label (keyval, keycode, mask) :
+ egg_virtual_accelerator_name (keyval, keycode, mask);
+ else
+ return g_strdup (translate ? _("Disabled") : "");
+}
+
+static gboolean
+keyval_is_forbidden (guint keyval)
+{
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS(forbidden_keyvals); i++) {
+ if (keyval == forbidden_keyvals[i])
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+show_error (GtkWindow *parent,
+ GError *err)
+{
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_OK,
+ _("Error saving the new shortcut"));
+
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ "%s", err->message);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
+
+static gboolean
+cb_check_for_uniqueness (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ KeyEntry *new_key)
+{
+ KeyEntry *element;
+
+ gtk_tree_model_get (new_key->model, iter,
+ KEYENTRY_COLUMN, &element,
+ -1);
+
+ /* no conflict for : blanks, different modifiers, or ourselves */
+ if (element == NULL || new_key->mask != element->mask ||
+ !strcmp (new_key->gconf_key, element->gconf_key))
+ return FALSE;
+
+ if (new_key->keyval != 0) {
+ if (new_key->keyval != element->keyval)
+ return FALSE;
+ } else if (element->keyval != 0 || new_key->keycode != element->keycode)
+ return FALSE;
+
+ new_key->editable = FALSE;
+ new_key->gconf_key = element->gconf_key;
+ new_key->description = element->description;
+ new_key->desc_gconf_key = element->desc_gconf_key;
+ new_key->desc_editable = element->desc_editable;
+ return TRUE;
+}
+
+static void
+accel_edited_callback (GtkCellRendererText *cell,
+ const char *path_string,
+ guint keyval,
+ EggVirtualModifierType mask,
+ guint keycode,
+ gpointer data)
+{
+ GConfClient *client;
+ GtkTreeView *view = (GtkTreeView *)data;
+ GtkTreeModel *model;
+ GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
+ GtkTreeIter iter;
+ KeyEntry *key_entry, tmp_key;
+ GError *err = NULL;
+ char *str;
+
+ block_accels = FALSE;
+
+ model = gtk_tree_view_get_model (view);
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_path_free (path);
+ gtk_tree_model_get (model, &iter,
+ KEYENTRY_COLUMN, &key_entry,
+ -1);
+
+ /* sanity check */
+ if (key_entry == NULL)
+ return;
+
+ /* CapsLock isn't supported as a keybinding modifier, so keep it from confusing us */
+ mask &= ~EGG_VIRTUAL_LOCK_MASK;
+
+ tmp_key.model = model;
+ tmp_key.keyval = keyval;
+ tmp_key.keycode = keycode;
+ tmp_key.mask = mask;
+ tmp_key.gconf_key = key_entry->gconf_key;
+ tmp_key.description = NULL;
+ tmp_key.editable = TRUE; /* kludge to stuff in a return flag */
+
+ if (keyval != 0 || keycode != 0) /* any number of keys can be disabled */
+ gtk_tree_model_foreach (model,
+ (GtkTreeModelForeachFunc) cb_check_for_uniqueness,
+ &tmp_key);
+
+ /* Check for unmodified keys */
+ if (tmp_key.mask == 0 && tmp_key.keycode != 0)
+ {
+ if ((tmp_key.keyval >= GDK_KEY_a && tmp_key.keyval <= GDK_KEY_z)
+ || (tmp_key.keyval >= GDK_KEY_A && tmp_key.keyval <= GDK_KEY_Z)
+ || (tmp_key.keyval >= GDK_KEY_0 && tmp_key.keyval <= GDK_KEY_9)
+ || (tmp_key.keyval >= GDK_KEY_kana_fullstop && tmp_key.keyval <= GDK_KEY_semivoicedsound)
+ || (tmp_key.keyval >= GDK_KEY_Arabic_comma && tmp_key.keyval <= GDK_KEY_Arabic_sukun)
+ || (tmp_key.keyval >= GDK_KEY_Serbian_dje && tmp_key.keyval <= GDK_KEY_Cyrillic_HARDSIGN)
+ || (tmp_key.keyval >= GDK_KEY_Greek_ALPHAaccent && tmp_key.keyval <= GDK_KEY_Greek_omega)
+ || (tmp_key.keyval >= GDK_KEY_hebrew_doublelowline && tmp_key.keyval <= GDK_KEY_hebrew_taf)
+ || (tmp_key.keyval >= GDK_KEY_Thai_kokai && tmp_key.keyval <= GDK_KEY_Thai_lekkao)
+ || (tmp_key.keyval >= GDK_KEY_Hangul && tmp_key.keyval <= GDK_KEY_Hangul_Special)
+ || (tmp_key.keyval >= GDK_KEY_Hangul_Kiyeog && tmp_key.keyval <= GDK_KEY_Hangul_J_YeorinHieuh)
+ || keyval_is_forbidden (tmp_key.keyval)) {
+ GtkWidget *dialog;
+ char *name;
+
+ name = binding_name (keyval, keycode, mask, TRUE);
+
+ dialog =
+ gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
+ GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_CANCEL,
+ _("The shortcut \"%s\" cannot be used because it will become impossible to type using this key.\n"
+ "Please try with a key such as Control, Alt or Shift at the same time."),
+ name);
+
+ g_free (name);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ /* set it back to its previous value. */
+ egg_cell_renderer_keys_set_accelerator
+ (EGG_CELL_RENDERER_KEYS (cell),
+ key_entry->keyval, key_entry->keycode, key_entry->mask);
+ return;
+ }
+ }
+
+ /* flag to see if the new accelerator was in use by something */
+ if (!tmp_key.editable)
+ {
+ GtkWidget *dialog;
+ char *name;
+ int response;
+
+ name = binding_name (keyval, keycode, mask, TRUE);
+
+ dialog =
+ gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
+ GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_CANCEL,
+ _("The shortcut \"%s\" is already used for\n\"%s\""),
+ name, tmp_key.description ?
+ tmp_key.description : tmp_key.gconf_key);
+ g_free (name);
+
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ _("If you reassign the shortcut to \"%s\", the \"%s\" shortcut "
+ "will be disabled."),
+ key_entry->description ?
+ key_entry->description : key_entry->gconf_key,
+ tmp_key.description ?
+ tmp_key.description : tmp_key.gconf_key);
+
+ gtk_dialog_add_button (GTK_DIALOG (dialog),
+ _("_Reassign"),
+ GTK_RESPONSE_ACCEPT);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog),
+ GTK_RESPONSE_ACCEPT);
+
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ if (response == GTK_RESPONSE_ACCEPT)
+ {
+ GConfClient *client;
+
+ client = gconf_client_get_default ();
+
+ gconf_client_set_string (client,
+ tmp_key.gconf_key,
+ "", &err);
+
+ if (err != NULL)
+ {
+ show_error (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
+ err);
+ g_error_free (err);
+ g_object_unref (client);
+ return;
+ }
+
+ str = binding_name (keyval, keycode, mask, FALSE);
+ gconf_client_set_string (client,
+ key_entry->gconf_key,
+ str, &err);
+
+ if (err != NULL)
+ {
+ show_error (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
+ err);
+ g_error_free (err);
+
+ /* reset the previous shortcut */
+ gconf_client_set_string (client,
+ tmp_key.gconf_key,
+ str, NULL);
+ }
+
+ g_free (str);
+ g_object_unref (client);
+ }
+ else
+ {
+ /* set it back to its previous value. */
+ egg_cell_renderer_keys_set_accelerator (EGG_CELL_RENDERER_KEYS (cell),
+ key_entry->keyval,
+ key_entry->keycode,
+ key_entry->mask);
+ }
+
+ return;
+ }
+
+ str = binding_name (keyval, keycode, mask, FALSE);
+
+ client = gconf_client_get_default ();
+ gconf_client_set_string (client,
+ key_entry->gconf_key,
+ str,
+ &err);
+ g_free (str);
+ g_object_unref (client);
+
+ if (err != NULL)
+ {
+ show_error (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))), err);
+ g_error_free (err);
+ key_entry->editable = FALSE;
+ }
+}
+
+static void
+accel_cleared_callback (GtkCellRendererText *cell,
+ const char *path_string,
+ gpointer data)
+{
+ GConfClient *client;
+ GtkTreeView *view = (GtkTreeView *) data;
+ GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
+ KeyEntry *key_entry;
+ GtkTreeIter iter;
+ GError *err = NULL;
+ GtkTreeModel *model;
+
+ block_accels = FALSE;
+
+ model = gtk_tree_view_get_model (view);
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_path_free (path);
+ gtk_tree_model_get (model, &iter,
+ KEYENTRY_COLUMN, &key_entry,
+ -1);
+
+ /* sanity check */
+ if (key_entry == NULL)
+ return;
+
+ /* Unset the key */
+ client = gconf_client_get_default();
+ gconf_client_set_string (client,
+ key_entry->gconf_key,
+ "",
+ &err);
+ g_object_unref (client);
+
+ if (err != NULL)
+ {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
+ GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_OK,
+ _("Error unsetting accelerator in configuration database: %s"),
+ err->message);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+
+ gtk_widget_destroy (dialog);
+ g_error_free (err);
+ key_entry->editable = FALSE;
+ }
+}
+
+static void
+key_entry_controlling_key_changed (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data)
+{
+ reload_sections (user_data);
+}
+
+/* this handler is used to keep accels from activating while the user
+ * is assigning a new shortcut so that he won't accidentally trigger one
+ * of the widgets */
+static gboolean
+maybe_block_accels (GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer user_data)
+{
+ if (block_accels)
+ {
+ return gtk_window_propagate_key_event (GTK_WINDOW (widget), event);
+ }
+ return FALSE;
+}
+
+static gchar *
+find_free_gconf_key (GError **error)
+{
+ GConfClient *client;
+
+ gchar *dir;
+ int i;
+
+ client = gconf_client_get_default ();
+
+ for (i = 0; i < MAX_CUSTOM_SHORTCUTS; i++)
+ {
+ dir = g_strdup_printf ("%s/custom%d", GCONF_BINDING_DIR, i);
+ if (!gconf_client_dir_exists (client, dir, NULL))
+ break;
+ g_free (dir);
+ }
+
+ if (i == MAX_CUSTOM_SHORTCUTS)
+ {
+ dir = NULL;
+ g_set_error_literal (error,
+ g_quark_from_string ("Keyboard Shortcuts"),
+ 0,
+ _("Too many custom shortcuts"));
+ }
+
+ g_object_unref (client);
+
+ return dir;
+}
+
+static void
+add_custom_shortcut (GtkTreeView *tree_view,
+ GtkTreeModel *model)
+{
+ KeyEntry *key_entry;
+ GtkTreePath *path;
+ gchar *dir;
+ GConfClient *client;
+ GError *error;
+
+ error = NULL;
+ dir = find_free_gconf_key (&error);
+ if (dir == NULL)
+ {
+ show_error (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (tree_view))), error);
+
+ g_error_free (error);
+ return;
+ }
+
+ key_entry = g_new0 (KeyEntry, 1);
+ key_entry->gconf_key = g_strconcat (dir, "/binding", NULL);
+ key_entry->editable = TRUE;
+ key_entry->model = model;
+ key_entry->desc_gconf_key = g_strconcat (dir, "/name", NULL);
+ key_entry->description = g_strdup ("");
+ key_entry->desc_editable = TRUE;
+ key_entry->cmd_gconf_key = g_strconcat (dir, "/action", NULL);
+ key_entry->command = g_strdup ("");
+ key_entry->cmd_editable = TRUE;
+ g_free (dir);
+
+ if (edit_custom_shortcut (key_entry) &&
+ key_entry->command && key_entry->command[0])
+ {
+ GPtrArray *keys_array;
+ GtkTreeIter iter;
+
+ keys_array = g_hash_table_lookup (kb_sections, _("Custom Shortcuts"));
+ if (keys_array == NULL)
+ {
+ keys_array = g_ptr_array_new ();
+ g_hash_table_insert (kb_sections, g_strdup (_("Custom Shortcuts")), keys_array);
+ }
+
+ g_ptr_array_add (keys_array, key_entry);
+
+ gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter, KEYENTRY_COLUMN, key_entry, -1);
+
+ /* store in gconf */
+ client = gconf_client_get_default ();
+ gconf_client_set_string (client, key_entry->gconf_key, "", NULL);
+ gconf_client_set_string (client, key_entry->desc_gconf_key, key_entry->description, NULL);
+ gconf_client_set_string (client, key_entry->cmd_gconf_key, key_entry->command, NULL);
+
+ /* add gconf watches */
+ key_entry->gconf_cnxn_desc = gconf_client_notify_add (client,
+ key_entry->desc_gconf_key,
+ (GConfClientNotifyFunc) &keybinding_description_changed,
+ key_entry, NULL, NULL);
+ key_entry->gconf_cnxn_cmd = gconf_client_notify_add (client,
+ key_entry->cmd_gconf_key,
+ (GConfClientNotifyFunc) &keybinding_command_changed,
+ key_entry, NULL, NULL);
+ key_entry->gconf_cnxn = gconf_client_notify_add (client,
+ key_entry->gconf_key,
+ (GConfClientNotifyFunc) &keybinding_key_changed,
+ key_entry, NULL, NULL);
+
+
+ g_object_unref (client);
+
+ /* make the new shortcut visible */
+ path = gtk_tree_model_get_path (model, &iter);
+ gtk_tree_view_expand_to_path (tree_view, path);
+ gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0, 0);
+ gtk_tree_path_free (path);
+ }
+ else
+ {
+ g_free (key_entry->gconf_key);
+ g_free (key_entry->description);
+ g_free (key_entry->desc_gconf_key);
+ g_free (key_entry->command);
+ g_free (key_entry->cmd_gconf_key);
+ g_free (key_entry);
+ }
+}
+
+static void
+add_button_clicked (GtkWidget *button,
+ GtkBuilder *builder)
+{
+ GtkTreeView *treeview;
+ GtkTreeModel *model;
+
+ treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder,
+ "shortcut_treeview"));
+ model = gtk_tree_view_get_model (treeview);
+
+ add_custom_shortcut (treeview, model);
+}
+
+static void
+remove_button_clicked (GtkWidget *button,
+ GtkBuilder *builder)
+{
+ GtkTreeView *treeview;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+
+ treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder,
+ "shortcut_treeview"));
+ model = gtk_tree_view_get_model (treeview);
+
+ selection = gtk_tree_view_get_selection (treeview);
+ if (gtk_tree_selection_get_selected (selection, NULL, &iter))
+ {
+ remove_custom_shortcut (model, &iter);
+ }
+}
+
+static int
+keyentry_sort_func (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gpointer user_data)
+{
+ KeyEntry *key_entry_a;
+ KeyEntry *key_entry_b;
+ int retval;
+
+ key_entry_a = NULL;
+ gtk_tree_model_get (model, a,
+ KEYENTRY_COLUMN, &key_entry_a,
+ -1);
+
+ key_entry_b = NULL;
+ gtk_tree_model_get (model, b,
+ KEYENTRY_COLUMN, &key_entry_b,
+ -1);
+
+ if (key_entry_a && key_entry_b)
+ {
+ if ((key_entry_a->keyval || key_entry_a->keycode) &&
+ (key_entry_b->keyval || key_entry_b->keycode))
+ {
+ gchar *name_a, *name_b;
+
+ name_a = binding_name (key_entry_a->keyval,
+ key_entry_a->keycode,
+ key_entry_a->mask,
+ TRUE);
+
+ name_b = binding_name (key_entry_b->keyval,
+ key_entry_b->keycode,
+ key_entry_b->mask,
+ TRUE);
+
+ retval = g_utf8_collate (name_a, name_b);
+
+ g_free (name_a);
+ g_free (name_b);
+ }
+ else if (key_entry_a->keyval || key_entry_a->keycode)
+ retval = -1;
+ else if (key_entry_b->keyval || key_entry_b->keycode)
+ retval = 1;
+ else
+ retval = 0;
+ }
+ else if (key_entry_a)
+ retval = -1;
+ else if (key_entry_b)
+ retval = 1;
+ else
+ retval = 0;
+
+ return retval;
+}
+
static void
setup_dialog (CcPanel *panel, GtkBuilder *builder)
{
@@ -764,6 +1711,7 @@ setup_dialog (CcPanel *panel, GtkBuilder *builder)
model = gtk_list_store_new (1, G_TYPE_STRING);
gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (model));
+ g_object_unref (model);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
g_signal_connect (selection, "changed",
@@ -775,16 +1723,16 @@ setup_dialog (CcPanel *panel, GtkBuilder *builder)
client = gconf_client_get_default ();
- /* g_signal_connect (treeview, "button_press_event", */
- /* G_CALLBACK (start_editing_cb), builder); */
- /* g_signal_connect (treeview, "row-activated", */
- /* G_CALLBACK (start_editing_kb_cb), NULL); */
+ g_signal_connect (treeview, "button_press_event",
+ G_CALLBACK (start_editing_cb), builder);
+ g_signal_connect (treeview, "row-activated",
+ G_CALLBACK (start_editing_kb_cb), NULL);
renderer = gtk_cell_renderer_text_new ();
- /* g_signal_connect (renderer, "edited", */
- /* G_CALLBACK (description_edited_callback), */
- /* treeview); */
+ g_signal_connect (renderer, "edited",
+ G_CALLBACK (description_edited_callback),
+ treeview);
column = gtk_tree_view_column_new_with_attributes (_("Action"),
renderer,
@@ -800,13 +1748,13 @@ setup_dialog (CcPanel *panel, GtkBuilder *builder)
"accel_mode", EGG_CELL_RENDERER_KEYS_MODE_X,
NULL);
- /* g_signal_connect (renderer, "accel_edited", */
- /* G_CALLBACK (accel_edited_callback), */
- /* treeview); */
+ g_signal_connect (renderer, "accel_edited",
+ G_CALLBACK (accel_edited_callback),
+ treeview);
- /* g_signal_connect (renderer, "accel_cleared", */
- /* G_CALLBACK (accel_cleared_callback), */
- /* treeview); */
+ g_signal_connect (renderer, "accel_cleared",
+ G_CALLBACK (accel_cleared_callback),
+ treeview);
column = gtk_tree_view_column_new_with_attributes (_("Shortcut"), renderer, NULL);
gtk_tree_view_column_set_cell_data_func (column, renderer, accel_set_func, NULL, NULL);
@@ -817,20 +1765,25 @@ setup_dialog (CcPanel *panel, GtkBuilder *builder)
gconf_client_add_dir (client, GCONF_BINDING_DIR, GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
gconf_client_add_dir (client, "/apps/metacity/general", GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
- /* gconf_client_notify_add (client, */
- /* "/apps/metacity/general/num_workspaces", */
- /* (GConfClientNotifyFunc) key_entry_controlling_key_changed, */
- /* builder, NULL, NULL); */
+ gconf_client_notify_add (client,
+ "/apps/metacity/general/num_workspaces",
+ (GConfClientNotifyFunc) key_entry_controlling_key_changed,
+ builder, NULL, NULL);
model = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER);
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (model),
+ KEYENTRY_COLUMN,
+ keyentry_sort_func,
+ NULL, NULL);
gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (model));
+ g_object_unref (model);
/* set up the dialog */
shell = cc_panel_get_shell (CC_PANEL (panel));
widget = cc_shell_get_toplevel (shell);
- /* maybe_block_accels_id = g_signal_connect (widget, "key_press_event", */
- /* G_CALLBACK (maybe_block_accels), NULL); */
+ maybe_block_accels_id = g_signal_connect (widget, "key_press_event",
+ G_CALLBACK (maybe_block_accels), NULL);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
g_signal_connect (selection, "changed",
@@ -858,10 +1811,10 @@ setup_dialog (CcPanel *panel, GtkBuilder *builder)
"custom-shortcut-name-entry");
custom_shortcut_command_entry = WID (builder,
"custom-shortcut-command-entry");
- /* g_signal_connect (WID (builder, "add-button"), */
- /* "clicked", G_CALLBACK (add_button_clicked), builder); */
- /* g_signal_connect (WID (builder, "remove-button"), */
- /* "clicked", G_CALLBACK (remove_button_clicked), builder); */
+ g_signal_connect (WID (builder, "add-button"),
+ "clicked", G_CALLBACK (add_button_clicked), builder);
+ g_signal_connect (WID (builder, "remove-button"),
+ "clicked", G_CALLBACK (remove_button_clicked), builder);
gtk_dialog_set_default_response (GTK_DIALOG (custom_shortcut_dialog),
GTK_RESPONSE_OK);
@@ -870,11 +1823,20 @@ setup_dialog (CcPanel *panel, GtkBuilder *builder)
GTK_WINDOW (widget));
}
+static void
+on_window_manager_change (const char *wm_name, GtkBuilder *builder)
+{
+ reload_sections (builder);
+}
+
void
keyboard_shortcuts_init (CcPanel *panel, GtkBuilder *builder)
{
kb_sections = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, (GDestroyNotify) free_key_array);
+
+ wm_common_register_window_manager_change ((GFunc) on_window_manager_change,
+ builder);
setup_dialog (panel, builder);
reload_sections (builder);
}
@@ -882,4 +1844,18 @@ keyboard_shortcuts_init (CcPanel *panel, GtkBuilder *builder)
void
keyboard_shortcuts_dispose (CcPanel *panel)
{
+ if (maybe_block_accels_id != 0)
+ {
+ CcShell *shell;
+ GtkWidget *toplevel;
+
+ shell = cc_panel_get_shell (CC_PANEL (panel));
+ toplevel = cc_shell_get_toplevel (shell);
+
+ g_signal_handler_disconnect (toplevel, maybe_block_accels_id);
+ maybe_block_accels_id = 0;
+
+ if (kb_sections != NULL)
+ g_hash_table_destroy (kb_sections);
+ }
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]