[gnome-control-center/wip/gbsneto/new-keyboard-panel: 7/9] keyboard: bring back uniqueness check
- From: Georges Basile Stavracas Neto <gbsneto src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-control-center/wip/gbsneto/new-keyboard-panel: 7/9] keyboard: bring back uniqueness check
- Date: Fri, 15 Jul 2016 15:50:52 +0000 (UTC)
commit 986e71cd99ea2a3e97059fc12e3c049d9f85f7bc
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date: Wed Jul 13 20:09:17 2016 -0300
keyboard: bring back uniqueness check
The collision detection code was removed as the
cleanup was happening, and this patch readd the
feature in a much cleaner and saner code.
panels/keyboard/cc-keyboard-manager.c | 121 +++++++++++++++++++++++++
panels/keyboard/cc-keyboard-manager.h | 9 ++
panels/keyboard/cc-keyboard-shortcut-editor.c | 93 ++++++++++++++++++-
panels/keyboard/shortcut-editor.ui | 1 +
4 files changed, 221 insertions(+), 3 deletions(-)
---
diff --git a/panels/keyboard/cc-keyboard-manager.c b/panels/keyboard/cc-keyboard-manager.c
index 5bb00cf..223c3cb 100644
--- a/panels/keyboard/cc-keyboard-manager.c
+++ b/panels/keyboard/cc-keyboard-manager.c
@@ -79,6 +79,61 @@ free_key_array (GPtrArray *keys)
}
}
+static gboolean
+compare_keys_for_uniqueness (CcKeyboardItem *current_item,
+ CcUniquenessData *data)
+{
+ CcKeyboardItem *item;
+
+ item = data->orig_item;
+
+ /* No conflict for: blanks, different modifiers or ourselves */
+ if (!current_item ||
+ item == current_item ||
+ data->new_mask != current_item->mask)
+ {
+ return FALSE;
+ }
+
+ if (item && current_item && cc_keyboard_item_equal (item, current_item))
+ return TRUE;
+
+ if (data->new_keyval != 0)
+ {
+ if (data->new_keyval != current_item->keyval)
+ return FALSE;
+ }
+ else if (current_item->keyval != 0 || data->new_keycode != current_item->keycode)
+ {
+ return FALSE;
+ }
+
+ data->conflict_item = current_item;
+
+ return TRUE;
+}
+
+static gboolean
+check_for_uniqueness (gpointer key,
+ GPtrArray *keys_array,
+ CcUniquenessData *data)
+{
+ guint i;
+
+ for (i = 0; i < keys_array->len; i++)
+ {
+ CcKeyboardItem *item;
+
+ item = keys_array->pdata[i];
+
+ if (compare_keys_for_uniqueness (item, data))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
static GHashTable*
get_hash_for_group (CcKeyboardManager *self,
BindingGroupType group)
@@ -840,3 +895,69 @@ cc_keyboard_manager_remove_custom_shortcut (CcKeyboardManager *self,
g_signal_emit (self, signals[SHORTCUT_REMOVED], 0, item);
}
+
+/**
+ * cc_keyboard_manager_get_collision:
+ * @self: a #CcKeyboardManager
+ * @item: (nullable): a keyboard shortcut
+ * @keyval: the key value
+ * @mask: a mask for the key sequence
+ * @keycode: the code of the key.
+ *
+ * Retrieves the collision item for the given shortcut.
+ *
+ * Returns: (transfer none)(nullable): the collisioned shortcut
+ */
+CcKeyboardItem*
+cc_keyboard_manager_get_collision (CcKeyboardManager *self,
+ CcKeyboardItem *item,
+ gint keyval,
+ GdkModifierType mask,
+ gint keycode)
+{
+ CcUniquenessData data;
+
+ g_return_val_if_fail (CC_IS_KEYBOARD_MANAGER (self), NULL);
+
+ data.orig_item = item;
+ data.new_keyval = keyval;
+ data.new_mask = mask;
+ data.new_keycode = keycode;
+ data.conflict_item = NULL;
+
+ /* Any number of shortcuts can be disabled */
+ if (keyval != 0 || keycode != 0)
+ {
+ BindingGroupType i;
+
+ for (i = BINDING_GROUP_SYSTEM; i <= BINDING_GROUP_USER && !data.conflict_item; i++)
+ {
+ GHashTable *table;
+
+ table = get_hash_for_group (self, i);
+
+ if (!table)
+ continue;
+
+ g_hash_table_find (table, (GHRFunc) check_for_uniqueness, &data);
+ }
+ }
+
+ return data.conflict_item;
+}
+
+/**
+ * cc_keyboard_manager_disable_shortcut:
+ * @self: a #CcKeyboardManager
+ * @item: a @CcKeyboardItem
+ *
+ * Disables the given keyboard shortcut.
+ */
+void
+cc_keyboard_manager_disable_shortcut (CcKeyboardManager *self,
+ CcKeyboardItem *item)
+{
+ g_return_if_fail (CC_IS_KEYBOARD_MANAGER (self));
+
+ g_object_set (item, "binding", NULL, NULL);
+}
diff --git a/panels/keyboard/cc-keyboard-manager.h b/panels/keyboard/cc-keyboard-manager.h
index 2bf9ba6..bd227ed 100644
--- a/panels/keyboard/cc-keyboard-manager.h
+++ b/panels/keyboard/cc-keyboard-manager.h
@@ -46,6 +46,15 @@ void cc_keyboard_manager_add_custom_shortcut (CcKeyboardMana
void cc_keyboard_manager_remove_custom_shortcut (CcKeyboardManager *self,
CcKeyboardItem *item);
+CcKeyboardItem* cc_keyboard_manager_get_collision (CcKeyboardManager *self,
+ CcKeyboardItem *item,
+ gint keyval,
+ GdkModifierType mask,
+ gint keycode);
+
+void cc_keyboard_manager_disable_shortcut (CcKeyboardManager *self,
+ CcKeyboardItem *item);
+
G_END_DECLS
#endif /* CC_KEYBOARD_MANAGER_H */
diff --git a/panels/keyboard/cc-keyboard-shortcut-editor.c b/panels/keyboard/cc-keyboard-shortcut-editor.c
index aaacdce..7d3a191 100644
--- a/panels/keyboard/cc-keyboard-shortcut-editor.c
+++ b/panels/keyboard/cc-keyboard-shortcut-editor.c
@@ -45,6 +45,7 @@ struct _CcKeyboardShortcutEditor
GtkWidget *edit_button;
GtkWidget *headerbar;
GtkWidget *name_entry;
+ GtkWidget *new_shortcut_conflict_label;
GtkWidget *remove_button;
GtkWidget *replace_button;
GtkWidget *shortcut_accel_label;
@@ -58,6 +59,8 @@ struct _CcKeyboardShortcutEditor
CcKeyboardManager *manager;
CcKeyboardItem *item;
+ CcKeyboardItem *collision_item;
+
/* Custom shortcuts */
GdkDevice *grab_pointer;
@@ -133,6 +136,7 @@ clear_custom_entries (CcKeyboardShortcutEditor *self)
gtk_entry_set_text (GTK_ENTRY (self->command_entry), "");
cc_shortcut_label_set_accelerator (CC_SHORTCUT_LABEL (self->custom_shortcut_accel_label), "");
+ gtk_label_set_label (GTK_LABEL (self->new_shortcut_conflict_label), "");
self->custom_keycode = 0;
self->custom_keyval = 0;
@@ -140,6 +144,8 @@ clear_custom_entries (CcKeyboardShortcutEditor *self)
self->custom_is_modifier = TRUE;
self->edited = FALSE;
+ self->collision_item = NULL;
+
g_signal_handlers_unblock_by_func (self->command_entry, command_entry_changed_cb, self);
g_signal_handlers_unblock_by_func (self->name_entry, name_entry_changed_cb, self);
}
@@ -205,6 +211,10 @@ update_shortcut (CcKeyboardShortcutEditor *self)
/* Setup the binding */
apply_custom_item_fields (self, self->item);
+ /* Eventually disable the conflict shortcut */
+ if (self->collision_item)
+ cc_keyboard_manager_disable_shortcut (self->manager, self->collision_item);
+
/* Cleanup whatever was set before */
clear_custom_entries (self);
@@ -212,21 +222,39 @@ update_shortcut (CcKeyboardShortcutEditor *self)
}
static void
+set_collision_headerbar (CcKeyboardShortcutEditor *self,
+ gboolean has_collision)
+{
+ gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (self->headerbar), !has_collision);
+
+ gtk_widget_set_visible (self->cancel_button, has_collision);
+ gtk_widget_set_visible (self->replace_button, has_collision);
+}
+
+static void
validate_custom_shortcut (CcKeyboardShortcutEditor *self)
{
gboolean valid;
valid = gtk_entry_get_text_length (GTK_ENTRY (self->name_entry)) > 0 &&
gtk_entry_get_text_length (GTK_ENTRY (self->command_entry)) > 0 &&
- !self->custom_is_modifier &&
- is_valid_binding (self->custom_keyval, self->custom_mask, self->custom_keycode);
+ is_valid_binding (self->custom_keyval, self->custom_mask, self->custom_keycode) &&
+ gtk_accelerator_valid (self->custom_keyval, self->custom_mask) &&
+ !self->custom_is_modifier;
gtk_widget_set_sensitive (self->add_button, valid);
if (valid)
{
+ CcKeyboardItem *collision_item;
gchar *accel;
+ collision_item = cc_keyboard_manager_get_collision (self->manager,
+ self->item,
+ self->custom_keyval,
+ self->custom_mask,
+ self->custom_keycode);
+
accel = gtk_accelerator_name (self->custom_keyval, self->custom_mask);
/* Setup the accelerator label */
@@ -242,6 +270,45 @@ validate_custom_shortcut (CcKeyboardShortcutEditor *self)
release_grab (self);
+ /*
+ * Oops! Looks like the accelerator is already being used, so we
+ * must warn the user and let it be very clear that adding this
+ * shortcut will disable the other.
+ */
+ gtk_widget_set_visible (self->new_shortcut_conflict_label, collision_item != NULL);
+
+ if (collision_item)
+ {
+ gchar *friendly_accelerator;
+ gchar *collision_text;
+
+ friendly_accelerator = convert_keysym_state_to_string (self->custom_keyval,
+ self->custom_mask,
+ self->custom_keycode);
+
+ collision_text = g_strdup_printf (_("%s is already being used for <b>%s</b>. If you "
+ "replace it, %s will be disabled"),
+ friendly_accelerator,
+ collision_item->description,
+ collision_item->description);
+
+ gtk_label_set_markup (GTK_LABEL (self->new_shortcut_conflict_label), collision_text);
+
+ g_free (friendly_accelerator);
+ g_free (collision_text);
+ }
+
+ /*
+ * When there is a collision between the current shortcut and another shortcut,
+ * and we're editing an existing shortcut (rather than creating a new one), setup
+ * the headerbar to display "Cancel" and "Replace". Otherwise, make sure to set
+ * only the close button again.
+ */
+ if (self->mode == CC_SHORTCUT_EDITOR_EDIT)
+ set_collision_headerbar (self, collision_item != NULL);
+
+ self->collision_item = collision_item;
+
g_free (accel);
}
}
@@ -259,6 +326,10 @@ add_button_clicked_cb (CcKeyboardShortcutEditor *self)
/* Apply the custom shortcut setup at the new item */
apply_custom_item_fields (self, item);
+ /* Eventually disable the conflict shortcut */
+ if (self->collision_item)
+ cc_keyboard_manager_disable_shortcut (self->manager, self->collision_item);
+
/* Cleanup everything once we're done */
clear_custom_entries (self);
@@ -309,6 +380,14 @@ remove_button_clicked_cb (CcKeyboardShortcutEditor *self)
}
static void
+replace_button_clicked_cb (CcKeyboardShortcutEditor *self)
+{
+ update_shortcut (self);
+
+ gtk_widget_hide (GTK_WIDGET (self));
+}
+
+static void
setup_keyboard_item (CcKeyboardShortcutEditor *self,
CcKeyboardItem *item)
{
@@ -524,6 +603,7 @@ cc_keyboard_shortcut_editor_class_init (CcKeyboardShortcutEditorClass *klass)
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, edit_button);
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, headerbar);
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, name_entry);
+ gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, new_shortcut_conflict_label);
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, remove_button);
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, replace_button);
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, shortcut_accel_label);
@@ -536,6 +616,7 @@ cc_keyboard_shortcut_editor_class_init (CcKeyboardShortcutEditorClass *klass)
gtk_widget_class_bind_template_callback (widget_class, edit_custom_shortcut_button_toggled_cb);
gtk_widget_class_bind_template_callback (widget_class, name_entry_changed_cb);
gtk_widget_class_bind_template_callback (widget_class, remove_button_clicked_cb);
+ gtk_widget_class_bind_template_callback (widget_class, replace_button_clicked_cb);
}
static void
@@ -616,9 +697,15 @@ cc_keyboard_shortcut_editor_set_mode (CcKeyboardShortcutEditor *self,
if (self->mode != mode)
{
+ gboolean is_create_mode;
+
self->mode = mode;
- if (mode == CC_SHORTCUT_EDITOR_CREATE)
+ is_create_mode = mode == CC_SHORTCUT_EDITOR_CREATE;
+
+ gtk_widget_set_visible (self->new_shortcut_conflict_label, is_create_mode);
+
+ if (is_create_mode)
{
/* Cleanup whatever was set before */
clear_custom_entries (self);
diff --git a/panels/keyboard/shortcut-editor.ui b/panels/keyboard/shortcut-editor.ui
index f2e963d..8551e0f 100644
--- a/panels/keyboard/shortcut-editor.ui
+++ b/panels/keyboard/shortcut-editor.ui
@@ -240,6 +240,7 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
+ <signal name="clicked" handler="replace_button_clicked_cb" object="CcKeyboardShortcutEditor"
swapped="yes" />
</object>
<packing>
<property name="pack_type">end</property>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]