From a1ae3a6731728b72d90ec6978aab3775f096ea1f Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Mon, 29 Jun 2020 10:23:51 -0700 Subject: [PATCH 1/2] keyboard: Initial implementation of switch-to-application-toggle This works, but doesn't check for collisions. --- panels/keyboard/cc-keyboard-panel.c | 74 ++++++++++++++++++++++++++++ panels/keyboard/cc-keyboard-panel.ui | 17 +++++++ 2 files changed, 91 insertions(+) diff --git a/panels/keyboard/cc-keyboard-panel.c b/panels/keyboard/cc-keyboard-panel.c index e3561ec60f..4cce0ba45d 100644 --- a/panels/keyboard/cc-keyboard-panel.c +++ b/panels/keyboard/cc-keyboard-panel.c @@ -45,6 +45,8 @@ struct _CcKeyboardPanel GtkRadioButton *same_source; GtkLabel *value_input_switch; GSettings *keybindings_settings; + GtkWidget *value_switch_to_application; + GSettings *shell_keybinding_settings; /* "Type Special Characters" section */ CcXkbModifierDialog *alt_chars_dialog; @@ -149,6 +151,64 @@ keyboard_shortcuts_activated (GtkWidget *button, } } +static void +switch_to_application_set (GtkSwitch *widget, + gboolean state, + CcKeyboardPanel *self) +{ + const gchar *key[] = { + "switch-to-application-1", + "switch-to-application-2", + "switch-to-application-3", + "switch-to-application-4", + "switch-to-application-5", + "switch-to-application-6", + "switch-to-application-7", + "switch-to-application-8", + "switch-to-application-9" + }; + const gchar *binding_str[] = { + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9" + }; + const gchar *binding_strv[2] = {NULL, NULL}; + int i; + + for (i = 0; i < 9; i++) { + if (state) { + binding_strv[0] = binding_str[i]; + } + + g_settings_set_strv (self->shell_keybinding_settings, key[i], binding_strv); + } +} + +static gboolean +transform_binding_to_switch_to_application (GValue *value, + GVariant *variant, + gpointer user_data) +{ + // Assumes switch-to-application-1 is always bound to [1] or [], + // and the other bindings match. It is not clear what the best behavior + // is if the user has manually mapped these keys otherwise with dconf. + + const gchar **items = g_variant_get_strv (variant, NULL); + + if (items && items[0] && (strcmp(items[0], "1") == 0)) + g_value_set_boolean (value, TRUE); + else + g_value_set_boolean (value, FALSE); + + return TRUE; +} + static void cc_keyboard_panel_set_property (GObject *object, guint property_id, @@ -178,6 +238,7 @@ cc_keyboard_panel_finalize (GObject *object) g_clear_object (&self->input_source_settings); g_clear_object (&self->keybindings_settings); + g_clear_object (&self->shell_keybinding_settings); G_OBJECT_CLASS (cc_keyboard_panel_parent_class)->finalize (object); } @@ -210,9 +271,11 @@ cc_keyboard_panel_class_init (CcKeyboardPanelClass *klass) gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, value_alternate_chars); gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, value_compose); gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, value_input_switch); + gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, value_switch_to_application); gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, common_shortcuts_row); gtk_widget_class_bind_template_callback (widget_class, special_chars_activated); + gtk_widget_class_bind_template_callback (widget_class, switch_to_application_set); gtk_widget_class_bind_template_callback (widget_class, keyboard_shortcuts_activated); } @@ -291,6 +354,17 @@ cc_keyboard_panel_init (CcKeyboardPanel *self) (gpointer)&COMPOSE_MODIFIER, NULL); + self->shell_keybinding_settings = g_settings_new ("org.gnome.shell.keybindings"); + g_settings_bind_with_mapping (self->shell_keybinding_settings, + "switch-to-application-1", + self->value_switch_to_application, + "state", + G_SETTINGS_BIND_GET, + transform_binding_to_switch_to_application, + NULL, + self->value_switch_to_application, + NULL); + self->alt_chars_dialog = cc_xkb_modifier_dialog_new (self->input_source_settings, &LV3_MODIFIER); self->compose_dialog = cc_xkb_modifier_dialog_new (self->input_source_settings, &COMPOSE_MODIFIER); } diff --git a/panels/keyboard/cc-keyboard-panel.ui b/panels/keyboard/cc-keyboard-panel.ui index 532b53a011..28a40d8c91 100644 --- a/panels/keyboard/cc-keyboard-panel.ui +++ b/panels/keyboard/cc-keyboard-panel.ui @@ -246,6 +246,23 @@ none 250 + + + True + True + true + Switch to Application + Switch to applications with super + number keys + + + True + True + center + + + + + True -- GitLab From 89e9c91c4d3a2e3a4dca62326c14b8a0d9f857cf Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Mon, 24 Aug 2020 12:50:11 -0700 Subject: [PATCH 2/2] WIP keyboard conflict dialog --- panels/keyboard/cc-keyboard-conflict-dialog.c | 54 ++++++++++++++++ panels/keyboard/cc-keyboard-conflict-dialog.h | 15 +++++ .../keyboard/cc-keyboard-conflict-dialog.ui | 61 +++++++++++++++++++ panels/keyboard/cc-keyboard-panel.c | 55 ++++++++++++++++- panels/keyboard/keyboard.gresource.xml | 1 + panels/keyboard/meson.build | 1 + 6 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 panels/keyboard/cc-keyboard-conflict-dialog.c create mode 100644 panels/keyboard/cc-keyboard-conflict-dialog.h create mode 100644 panels/keyboard/cc-keyboard-conflict-dialog.ui diff --git a/panels/keyboard/cc-keyboard-conflict-dialog.c b/panels/keyboard/cc-keyboard-conflict-dialog.c new file mode 100644 index 0000000000..920a97c629 --- /dev/null +++ b/panels/keyboard/cc-keyboard-conflict-dialog.c @@ -0,0 +1,54 @@ +#include "cc-keyboard-conflict-dialog.h" +#include "keyboard-shortcuts.h" + +struct _CcKeyboardConflictDialog +{ + GtkDialog parent_instance; + + GtkListBox *listbox; +}; + +G_DEFINE_TYPE (CcKeyboardConflictDialog, cc_keyboard_conflict_dialog, GTK_TYPE_DIALOG) + +static void +cc_keyboard_conflict_dialog_class_init (CcKeyboardConflictDialogClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/keyboard/cc-keyboard-conflict-dialog.ui"); + + gtk_widget_class_bind_template_child (widget_class, CcKeyboardConflictDialog, listbox); + + //gtk_widget_class_bind_template_callback (widget_class, on_active_lv3_changed_cb); +} + +static void +cc_keyboard_conflict_dialog_init (CcKeyboardConflictDialog *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); +} + +// Detecting conflict w/o CcKeyboardItem for it? + +CcKeyboardConflictDialog* +cc_keyboard_conflict_dialog_new (void) +{ + return g_object_new(CC_TYPE_KEYBOARD_CONFLICT_DIALOG, + "use-header-bar", 1, + "visible", 1, + NULL); +} + +void +cc_keyboard_conflict_dialog_add (CcKeyboardConflictDialog *self, + CcKeyboardItem *collision, + CcKeyCombo combo) +{ + g_autofree gchar *accelerator = convert_keysym_state_to_string (&combo); + const gchar *description = cc_keyboard_item_get_description (collision); + g_autofree gchar *text = g_strdup_printf ("%s conflicts with %s", accelerator, description); + GtkWidget *label = gtk_label_new (text); + gtk_widget_set_visible (label, TRUE); + gtk_container_add (GTK_CONTAINER (self->listbox), label); +} \ No newline at end of file diff --git a/panels/keyboard/cc-keyboard-conflict-dialog.h b/panels/keyboard/cc-keyboard-conflict-dialog.h new file mode 100644 index 0000000000..535ea90f2b --- /dev/null +++ b/panels/keyboard/cc-keyboard-conflict-dialog.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#include "cc-keyboard-item.h" + +G_BEGIN_DECLS + +#define CC_TYPE_KEYBOARD_CONFLICT_DIALOG (cc_keyboard_conflict_dialog_get_type()) +G_DECLARE_FINAL_TYPE (CcKeyboardConflictDialog, cc_keyboard_conflict_dialog, CC, KEYBOARD_CONFLICT_DIALOG, GtkDialog) + +CcKeyboardConflictDialog* cc_keyboard_conflict_dialog_new (void); +void cc_keyboard_conflict_dialog_add (CcKeyboardConflictDialog*, CcKeyboardItem*, CcKeyCombo); + +G_END_DECLS diff --git a/panels/keyboard/cc-keyboard-conflict-dialog.ui b/panels/keyboard/cc-keyboard-conflict-dialog.ui new file mode 100644 index 0000000000..e733c1b567 --- /dev/null +++ b/panels/keyboard/cc-keyboard-conflict-dialog.ui @@ -0,0 +1,61 @@ + + + + diff --git a/panels/keyboard/cc-keyboard-panel.c b/panels/keyboard/cc-keyboard-panel.c index 4cce0ba45d..663f04be2d 100644 --- a/panels/keyboard/cc-keyboard-panel.c +++ b/panels/keyboard/cc-keyboard-panel.c @@ -26,6 +26,8 @@ #include +#include "cc-keyboard-conflict-dialog.h" +#include "cc-keyboard-manager.h" #include "cc-keyboard-panel.h" #include "cc-keyboard-resources.h" #include "cc-keyboard-shortcut-dialog.h" @@ -47,6 +49,7 @@ struct _CcKeyboardPanel GSettings *keybindings_settings; GtkWidget *value_switch_to_application; GSettings *shell_keybinding_settings; + CcKeyboardManager *manager; /* "Type Special Characters" section */ CcXkbModifierDialog *alt_chars_dialog; @@ -151,7 +154,7 @@ keyboard_shortcuts_activated (GtkWidget *button, } } -static void +static gboolean switch_to_application_set (GtkSwitch *widget, gboolean state, CcKeyboardPanel *self) @@ -180,6 +183,51 @@ switch_to_application_set (GtkSwitch *widget, }; const gchar *binding_strv[2] = {NULL, NULL}; int i; + guint *keycodes; + CcKeyCombo combos[9] = { 0 }; + CcKeyboardConflictDialog *dialog; + gboolean has_conflict = FALSE; + gint resp; + CcKeyboardItem *collisions[9]; + + if (gtk_switch_get_state (widget) == state) + return TRUE; + + if (self->manager == NULL) + return TRUE; + + // Prompt about any conflicting bindings when activating + if (state) { + dialog = cc_keyboard_conflict_dialog_new(); + + for (i = 0; i < 9; i++) { + gtk_accelerator_parse_with_keycode (binding_str[i], &combos[i].keyval, &keycodes, &combos[i].mask); + combos[i].keycode = (keycodes ? keycodes[0] : 0); + g_free(keycodes); + collisions[i] = cc_keyboard_manager_get_collision (self->manager, NULL, &combos[i]); + if (collisions[i] != NULL) { + cc_keyboard_conflict_dialog_add (dialog, collisions[i], combos[i]); + has_conflict = TRUE; + } + } + + if (has_conflict) + resp = gtk_dialog_run (GTK_DIALOG (dialog)); + else + resp = GTK_RESPONSE_OK; + + gtk_widget_destroy (GTK_WIDGET (dialog)); + + if (resp != GTK_RESPONSE_OK) { + gtk_switch_set_active (widget, !state); + return TRUE; + } + + for (i = 0; i < 9; i++) { + if (collisions[i] != NULL) + cc_keyboard_item_remove_key_combo (collisions[i], &combos[i]); + } + } for (i = 0; i < 9; i++) { if (state) { @@ -188,6 +236,8 @@ switch_to_application_set (GtkSwitch *widget, g_settings_set_strv (self->shell_keybinding_settings, key[i], binding_strv); } + + return TRUE; } static gboolean @@ -239,6 +289,7 @@ cc_keyboard_panel_finalize (GObject *object) g_clear_object (&self->input_source_settings); g_clear_object (&self->keybindings_settings); g_clear_object (&self->shell_keybinding_settings); + g_clear_object (&self->manager); G_OBJECT_CLASS (cc_keyboard_panel_parent_class)->finalize (object); } @@ -307,6 +358,8 @@ cc_keyboard_panel_init (CcKeyboardPanel *self) gtk_widget_init_template (GTK_WIDGET (self)); + self->manager = cc_keyboard_manager_new (); + provider = gtk_css_provider_new (); gtk_css_provider_load_from_data (provider, custom_css, -1, NULL); diff --git a/panels/keyboard/keyboard.gresource.xml b/panels/keyboard/keyboard.gresource.xml index a310f0500d..fdeda3f619 100644 --- a/panels/keyboard/keyboard.gresource.xml +++ b/panels/keyboard/keyboard.gresource.xml @@ -6,6 +6,7 @@ cc-keyboard-shortcut-row.ui cc-keyboard-shortcut-dialog.ui cc-keyboard-panel.ui + cc-keyboard-conflict-dialog.ui cc-keyboard-shortcut-editor.ui cc-input-chooser.ui cc-input-row.ui diff --git a/panels/keyboard/meson.build b/panels/keyboard/meson.build index a2ae0263d3..e43424ba75 100644 --- a/panels/keyboard/meson.build +++ b/panels/keyboard/meson.build @@ -57,6 +57,7 @@ endforeach sources = files( 'cc-xkb-modifier-dialog.c', + 'cc-keyboard-conflict-dialog.c', 'cc-keyboard-shortcut-row.c', 'cc-keyboard-shortcut-dialog.c', 'cc-keyboard-panel.c', -- GitLab