From 238327e0ae5e875d76aff973c754c860d4fd0ae2 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Thu, 9 Jul 2020 14:54:20 -0700 Subject: [PATCH 01/13] keyboard: Move keyboard shortcuts configuration to a dialog window --- panels/keyboard/cc-keyboard-panel.c | 564 +----------- panels/keyboard/cc-keyboard-panel.h | 2 - panels/keyboard/cc-keyboard-panel.ui | 127 +-- panels/keyboard/cc-keyboard-shortcut-dialog.c | 847 ++++++++++++++++++ panels/keyboard/cc-keyboard-shortcut-dialog.h | 35 + .../keyboard/cc-keyboard-shortcut-dialog.ui | 257 ++++++ .../gnome-keyboard-panel.desktop.in.in | 2 +- panels/keyboard/keyboard.gresource.xml | 1 + panels/keyboard/meson.build | 1 + 9 files changed, 1200 insertions(+), 636 deletions(-) create mode 100644 panels/keyboard/cc-keyboard-shortcut-dialog.c create mode 100644 panels/keyboard/cc-keyboard-shortcut-dialog.h create mode 100644 panels/keyboard/cc-keyboard-shortcut-dialog.ui diff --git a/panels/keyboard/cc-keyboard-panel.c b/panels/keyboard/cc-keyboard-panel.c index 213ac7f7ea..20fd2c9072 100644 --- a/panels/keyboard/cc-keyboard-panel.c +++ b/panels/keyboard/cc-keyboard-panel.c @@ -1,6 +1,8 @@ -/* +/* cc-keyboard-panel.c + * * Copyright (C) 2010 Intel, Inc * Copyright (C) 2016 Endless, Inc + * Copyright (C) 2020 System76, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,59 +19,30 @@ * * Author: Thomas Wood * Georges Basile Stavracas Neto + * Ian Douglas Scott * + * SPDX-License-Identifier: GPL-2.0-or-later */ #include -#include "cc-keyboard-shortcut-row.h" -#include "cc-keyboard-item.h" -#include "cc-keyboard-manager.h" #include "cc-keyboard-panel.h" #include "cc-keyboard-resources.h" -#include "cc-keyboard-shortcut-editor.h" +#include "cc-keyboard-shortcut-dialog.h" #include "cc-xkb-modifier-dialog.h" #include "keyboard-shortcuts.h" -#include "cc-util.h" - -#define SHORTCUT_DELIMITERS "+ " - -typedef struct { - CcKeyboardItem *item; - gchar *section_title; - gchar *section_id; -} RowData; - struct _CcKeyboardPanel { CcPanel parent_instance; - /* Search */ - GtkWidget *empty_search_placeholder; - GtkWidget *reset_button; - GtkWidget *search_bar; - GtkWidget *search_button; - GtkWidget *search_entry; - guint search_bar_handler_id; - - /* Shortcuts */ - GtkWidget *shortcuts_listbox; - GtkListBoxRow *add_shortcut_row; - GtkSizeGroup *accelerator_sizegroup; - /* Alternate characters key */ CcXkbModifierDialog *xkb_modifier_dialog; GSettings *input_source_settings; GtkWidget *value_alternate_chars; - /* Custom shortcut dialog */ - GtkWidget *shortcut_editor; - - GRegex *pictures_regex; - - CcKeyboardManager *manager; + GtkListBoxRow *common_shortcuts_row; }; CC_PANEL_REGISTER (CcKeyboardPanel, cc_keyboard_panel) @@ -79,11 +52,6 @@ enum { PROP_PARAMETERS }; -static const gchar* custom_css = -"button.reset-shortcut-button {" -" padding: 0;" -"}"; - static const XkbModifier LV3_MODIFIER = { "lv3:", N_("Alternate Characters Key"), @@ -100,420 +68,35 @@ static const XkbModifier LV3_MODIFIER = { "lv3:ralt_switch", }; -/* RowData functions */ -static RowData * -row_data_new (CcKeyboardItem *item, - const gchar *section_id, - const gchar *section_title) -{ - RowData *data; - - data = g_new0 (RowData, 1); - data->item = g_object_ref (item); - data->section_id = g_strdup (section_id); - data->section_title = g_strdup (section_title); - - return data; -} - -static void -row_data_free (RowData *data) -{ - g_object_unref (data->item); - g_free (data->section_id); - g_free (data->section_title); - g_free (data); -} - -static void -reset_all_shortcuts_cb (GtkWidget *widget, - gpointer user_data) -{ - CcKeyboardPanel *self; - RowData *data; - - self = user_data; - - if (widget == (GtkWidget *) self->add_shortcut_row) - return; - - data = g_object_get_data (G_OBJECT (widget), "data"); - - /* Don't reset custom shortcuts */ - if (cc_keyboard_item_get_item_type (data->item) == CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH) - return; - - /* cc_keyboard_manager_reset_shortcut() already resets conflicting shortcuts, - * so no other check is needed here. */ - cc_keyboard_manager_reset_shortcut (self->manager, data->item); -} - -static void -reset_all_clicked_cb (CcKeyboardPanel *self) -{ - GtkWidget *dialog, *toplevel, *button; - guint response; - - toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self)); - dialog = gtk_message_dialog_new (GTK_WINDOW (toplevel), - GTK_DIALOG_MODAL | GTK_DIALOG_USE_HEADER_BAR | GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_WARNING, - GTK_BUTTONS_NONE, - _("Reset All Shortcuts?")); - - gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), - _("Resetting the shortcuts may affect your custom shortcuts. " - "This cannot be undone.")); - - gtk_dialog_add_buttons (GTK_DIALOG (dialog), - _("Cancel"), GTK_RESPONSE_CANCEL, - _("Reset All"), GTK_RESPONSE_ACCEPT, - NULL); - - gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL); - - /* Make the "Reset All" button destructive */ - button = gtk_dialog_get_widget_for_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); - gtk_style_context_add_class (gtk_widget_get_style_context (button), "destructive-action"); - - /* Reset shortcuts if accepted */ - response = gtk_dialog_run (GTK_DIALOG (dialog)); - - if (response == GTK_RESPONSE_ACCEPT) - { - gtk_container_foreach (GTK_CONTAINER (self->shortcuts_listbox), - reset_all_shortcuts_cb, - self); - } - - gtk_widget_destroy (dialog); -} - -static void -add_item (CcKeyboardPanel *self, - CcKeyboardItem *item, - const gchar *section_id, - const gchar *section_title) -{ - GtkWidget *row; - - row = GTK_WIDGET(cc_keyboard_shortcut_row_new(item, - self->manager, - CC_KEYBOARD_SHORTCUT_EDITOR (self->shortcut_editor), - self->accelerator_sizegroup)); - g_object_set_data_full (G_OBJECT (row), - "data", - row_data_new (item, section_id, section_title), - (GDestroyNotify) row_data_free); - gtk_container_add (GTK_CONTAINER (self->shortcuts_listbox), row); -} - -static void -remove_item (CcKeyboardPanel *self, - CcKeyboardItem *item) -{ - GList *children, *l; - - children = gtk_container_get_children (GTK_CONTAINER (self->shortcuts_listbox)); - - for (l = children; l != NULL; l = l->next) - { - RowData *row_data; - - row_data = g_object_get_data (l->data, "data"); - - if (row_data->item == item) - { - gtk_container_remove (GTK_CONTAINER (self->shortcuts_listbox), l->data); - break; - } - } - - g_list_free (children); -} - -static gboolean -strv_contains_prefix_or_match (gchar **strv, - const gchar *prefix) -{ - guint i; - - const struct { - const gchar *key; - const gchar *untranslated; - const gchar *synonym; - } key_aliases[] = - { - { "ctrl", "Ctrl", "ctrl" }, - { "win", "Super", "super" }, - { "option", NULL, "alt" }, - { "command", NULL, "super" }, - { "apple", NULL, "super" }, - }; - - for (i = 0; strv[i]; i++) - { - if (g_str_has_prefix (strv[i], prefix)) - return TRUE; - } - - for (i = 0; i < G_N_ELEMENTS (key_aliases); i++) - { - g_autofree gchar *alias = NULL; - const gchar *synonym; - - if (!g_str_has_prefix (key_aliases[i].key, prefix)) - continue; - - if (key_aliases[i].untranslated) - { - const gchar *translated_label; - - /* Steal GTK+'s translation */ - translated_label = g_dpgettext2 ("gtk30", "keyboard label", key_aliases[i].untranslated); - alias = g_utf8_strdown (translated_label, -1); - } - - synonym = key_aliases[i].synonym; - - /* If a translation or synonym of the key is in the accelerator, and we typed - * the key, also consider that a prefix */ - if ((alias && g_strv_contains ((const gchar * const *) strv, alias)) || - (synonym && g_strv_contains ((const gchar * const *) strv, synonym))) - { - return TRUE; - } - } - - return FALSE; -} - -static gboolean -search_match_shortcut (CcKeyboardItem *item, - const gchar *search) -{ - GStrv shortcut_tokens, search_tokens; - g_autofree gchar *normalized_accel = NULL; - g_autofree gchar *accel = NULL; - gboolean match; - guint i; - GList *key_combos, *l; - CcKeyCombo *combo; - - key_combos = cc_keyboard_item_get_key_combos (item); - for (l = key_combos; l != NULL; l = l->next) - { - combo = l->data; - - if (is_empty_binding (combo)) - continue; - - match = TRUE; - accel = convert_keysym_state_to_string (combo); - normalized_accel = cc_util_normalize_casefold_and_unaccent (accel); - - shortcut_tokens = g_strsplit_set (normalized_accel, SHORTCUT_DELIMITERS, -1); - search_tokens = g_strsplit_set (search, SHORTCUT_DELIMITERS, -1); - - for (i = 0; search_tokens[i] != NULL; i++) - { - const gchar *token; - - /* Strip leading and trailing whitespaces */ - token = g_strstrip (search_tokens[i]); - - if (g_utf8_strlen (token, -1) == 0) - continue; - - match = match && strv_contains_prefix_or_match (shortcut_tokens, token); - - if (!match) - break; - } - - g_strfreev (shortcut_tokens); - g_strfreev (search_tokens); - - if (match) - return TRUE; - } - - return FALSE; -} - -static gint -sort_function (GtkListBoxRow *a, - GtkListBoxRow *b, - gpointer user_data) -{ - CcKeyboardPanel *self; - RowData *a_data, *b_data; - gint retval; - - self = user_data; - - if (a == self->add_shortcut_row) - return 1; - - if (b == self->add_shortcut_row) - return -1; - - a_data = g_object_get_data (G_OBJECT (a), "data"); - b_data = g_object_get_data (G_OBJECT (b), "data"); - - /* Put custom shortcuts below everything else */ - if (cc_keyboard_item_get_item_type (a_data->item) == CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH) - return 1; - else if (cc_keyboard_item_get_item_type (b_data->item) == CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH) - return -1; - - retval = g_strcmp0 (a_data->section_title, b_data->section_title); - - if (retval != 0) - return retval; - - return g_strcmp0 (cc_keyboard_item_get_description (a_data->item), cc_keyboard_item_get_description (b_data->item)); -} - static void -header_function (GtkListBoxRow *row, - GtkListBoxRow *before, - gpointer user_data) +alternate_chars_activated (GtkWidget *button, + GtkListBoxRow *row, + CcKeyboardPanel *self) { - CcKeyboardPanel *self; - gboolean add_header; - RowData *data; - - self = user_data; - add_header = FALSE; - - /* The + row always has a separator */ - if (row == self->add_shortcut_row) - { - GtkWidget *separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); - gtk_widget_show (separator); - - gtk_list_box_row_set_header (row, separator); - - return; - } - - data = g_object_get_data (G_OBJECT (row), "data"); - - if (before) - { - RowData *before_data = g_object_get_data (G_OBJECT (before), "data"); - - if (before_data) - add_header = g_strcmp0 (before_data->section_id, data->section_id) != 0; - } - else - { - add_header = TRUE; - } - - if (add_header) - { - GtkWidget *box, *label, *separator; - g_autofree gchar *markup = NULL; - - box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); - gtk_widget_show (box); - gtk_widget_set_margin_top (box, before ? 18 : 6); - - markup = g_strdup_printf ("%s", _(data->section_title)); - label = gtk_label_new (NULL); - gtk_label_set_markup (GTK_LABEL (label), markup); - gtk_label_set_xalign (GTK_LABEL (label), 0.0); - gtk_widget_set_margin_start (label, 6); - gtk_widget_show (label); - gtk_style_context_add_class (gtk_widget_get_style_context (label), "dim-label"); - gtk_container_add (GTK_CONTAINER (box), label); - - separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); - gtk_widget_show (separator); - gtk_container_add (GTK_CONTAINER (box), separator); - - gtk_list_box_row_set_header (row, box); - } - else - { - gtk_list_box_row_set_header (row, NULL); - } -} + GtkWindow *window; -static gboolean -filter_function (GtkListBoxRow *row, - gpointer user_data) -{ - CcKeyboardPanel *self = user_data; - CcKeyboardItem *item; - RowData *data; - gboolean retval; - g_autofree gchar *search = NULL; - g_autofree gchar *name = NULL; - g_auto(GStrv) terms = NULL; - guint i; - - if (gtk_entry_get_text_length (GTK_ENTRY (self->search_entry)) == 0) - return TRUE; - - /* When searching, the '+' row is always hidden */ - if (row == self->add_shortcut_row) - return FALSE; - - data = g_object_get_data (G_OBJECT (row), "data"); - item = data->item; - name = cc_util_normalize_casefold_and_unaccent (cc_keyboard_item_get_description (item)); - search = cc_util_normalize_casefold_and_unaccent (gtk_entry_get_text (GTK_ENTRY (self->search_entry))); - terms = g_strsplit (search, " ", -1); - - for (i = 0; terms && terms[i]; i++) - { - retval = strstr (name, terms[i]) || search_match_shortcut (item, terms[i]); - if (!retval) - break; - } + window = GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (self)))); - return retval; + gtk_window_set_transient_for (GTK_WINDOW (self->xkb_modifier_dialog), window); + gtk_widget_show (GTK_WIDGET (self->xkb_modifier_dialog)); } static void -shortcut_row_activated (GtkWidget *button, - GtkListBoxRow *row, - CcKeyboardPanel *self) +keyboard_shortcuts_activated (GtkWidget *button, + GtkListBoxRow *row, + CcKeyboardPanel *self) { - CcKeyboardShortcutEditor *editor; - - editor = CC_KEYBOARD_SHORTCUT_EDITOR (self->shortcut_editor); + GtkWindow *window; + GtkWidget *shortcut_dialog; - if (row != self->add_shortcut_row) + if (row == self->common_shortcuts_row) { - RowData *data = g_object_get_data (G_OBJECT (row), "data"); + window = GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (self)))); - cc_keyboard_shortcut_editor_set_mode (editor, CC_SHORTCUT_EDITOR_EDIT); - cc_keyboard_shortcut_editor_set_item (editor, data->item); + shortcut_dialog = cc_keyboard_shortcut_dialog_new (); + gtk_window_set_transient_for (GTK_WINDOW (shortcut_dialog), window); + gtk_widget_show (GTK_WIDGET (shortcut_dialog)); } - else - { - cc_keyboard_shortcut_editor_set_mode (editor, CC_SHORTCUT_EDITOR_CREATE); - cc_keyboard_shortcut_editor_set_item (editor, NULL); - } - - gtk_widget_show (self->shortcut_editor); -} - -static void -alternate_chars_activated (GtkWidget *button, - GtkListBoxRow *row, - CcKeyboardPanel *self) -{ - GtkWindow *window; - - window = GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (self)))); - - gtk_window_set_transient_for (GTK_WINDOW (self->xkb_modifier_dialog), window); - gtk_widget_show (GTK_WIDGET (self->xkb_modifier_dialog)); } static void @@ -542,45 +125,12 @@ static void cc_keyboard_panel_finalize (GObject *object) { CcKeyboardPanel *self = CC_KEYBOARD_PANEL (object); - GtkWidget *window; - g_clear_pointer (&self->pictures_regex, g_regex_unref); - g_clear_object (&self->accelerator_sizegroup); g_clear_object (&self->input_source_settings); - if (self->search_bar_handler_id != 0) - { - window = cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (self))); - g_signal_handler_disconnect (window, self->search_bar_handler_id); - } - G_OBJECT_CLASS (cc_keyboard_panel_parent_class)->finalize (object); } -static void -cc_keyboard_panel_constructed (GObject *object) -{ - CcKeyboardPanel *self = CC_KEYBOARD_PANEL (object); - GtkWindow *toplevel; - CcShell *shell; - - G_OBJECT_CLASS (cc_keyboard_panel_parent_class)->constructed (object); - - /* Setup the dialog's transient parent */ - shell = cc_panel_get_shell (CC_PANEL (self)); - toplevel = GTK_WINDOW (cc_shell_get_toplevel (shell)); - gtk_window_set_transient_for (GTK_WINDOW (self->shortcut_editor), toplevel); - - cc_shell_embed_widget_in_header (shell, self->reset_button, GTK_POS_LEFT); - cc_shell_embed_widget_in_header (shell, self->search_button, GTK_POS_RIGHT); - - self->search_bar_handler_id = - g_signal_connect_swapped (toplevel, - "key-press-event", - G_CALLBACK (gtk_search_bar_handle_event), - self->search_bar); -} - static void cc_keyboard_panel_class_init (CcKeyboardPanelClass *klass) { @@ -592,45 +142,25 @@ cc_keyboard_panel_class_init (CcKeyboardPanelClass *klass) object_class->set_property = cc_keyboard_panel_set_property; object_class->finalize = cc_keyboard_panel_finalize; - object_class->constructed = cc_keyboard_panel_constructed; g_object_class_override_property (object_class, PROP_PARAMETERS, "parameters"); gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/keyboard/cc-keyboard-panel.ui"); - gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, add_shortcut_row); - gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, empty_search_placeholder); - gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, reset_button); - gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, search_bar); - gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, search_button); - gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, search_entry); - gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, shortcuts_listbox); gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, value_alternate_chars); + gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, common_shortcuts_row); - gtk_widget_class_bind_template_callback (widget_class, reset_all_clicked_cb); - gtk_widget_class_bind_template_callback (widget_class, shortcut_row_activated); gtk_widget_class_bind_template_callback (widget_class, alternate_chars_activated); + gtk_widget_class_bind_template_callback (widget_class, keyboard_shortcuts_activated); } static void cc_keyboard_panel_init (CcKeyboardPanel *self) { - GtkCssProvider *provider; - g_resources_register (cc_keyboard_get_resource ()); gtk_widget_init_template (GTK_WIDGET (self)); - /* Custom CSS */ - provider = gtk_css_provider_new (); - gtk_css_provider_load_from_data (provider, custom_css, -1, NULL); - - gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), - GTK_STYLE_PROVIDER (provider), - GTK_STYLE_PROVIDER_PRIORITY_APPLICATION + 1); - - g_object_unref (provider); - /* Alternate characters key */ self->input_source_settings = g_settings_new ("org.gnome.desktop.input-sources"); g_settings_bind_with_mapping (self->input_source_settings, @@ -644,46 +174,4 @@ cc_keyboard_panel_init (CcKeyboardPanel *self) NULL); self->xkb_modifier_dialog = cc_xkb_modifier_dialog_new (self->input_source_settings, &LV3_MODIFIER); - - /* Shortcut manager */ - self->manager = cc_keyboard_manager_new (); - - /* Shortcut editor dialog */ - self->shortcut_editor = cc_keyboard_shortcut_editor_new (self->manager); - - /* Use a sizegroup to make the accelerator labels the same width */ - self->accelerator_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); - - g_signal_connect_object (self->manager, - "shortcut-added", - G_CALLBACK (add_item), - self, - G_CONNECT_SWAPPED); - - g_signal_connect_object (self->manager, - "shortcut-removed", - G_CALLBACK (remove_item), - self, - G_CONNECT_SWAPPED); - - cc_keyboard_manager_load_shortcuts (self->manager); - - /* Setup the shortcuts shortcuts_listbox */ - gtk_list_box_set_sort_func (GTK_LIST_BOX (self->shortcuts_listbox), - sort_function, - self, - NULL); - - gtk_list_box_set_header_func (GTK_LIST_BOX (self->shortcuts_listbox), - header_function, - self, - NULL); - - gtk_list_box_set_filter_func (GTK_LIST_BOX (self->shortcuts_listbox), - filter_function, - self, - NULL); - - gtk_list_box_set_placeholder (GTK_LIST_BOX (self->shortcuts_listbox), self->empty_search_placeholder); } - diff --git a/panels/keyboard/cc-keyboard-panel.h b/panels/keyboard/cc-keyboard-panel.h index db6e35278b..3d3076b2dc 100644 --- a/panels/keyboard/cc-keyboard-panel.h +++ b/panels/keyboard/cc-keyboard-panel.h @@ -29,6 +29,4 @@ G_BEGIN_DECLS #define CC_TYPE_KEYBOARD_PANEL (cc_keyboard_panel_get_type ()) G_DECLARE_FINAL_TYPE (CcKeyboardPanel, cc_keyboard_panel, CC, KEYBOARD_PANEL, CcPanel) -CcKeyboardItem* cc_keyboard_panel_create_custom_item (CcKeyboardPanel *self); - G_END_DECLS diff --git a/panels/keyboard/cc-keyboard-panel.ui b/panels/keyboard/cc-keyboard-panel.ui index 7c5073e334..7c977db69e 100644 --- a/panels/keyboard/cc-keyboard-panel.ui +++ b/panels/keyboard/cc-keyboard-panel.ui @@ -12,26 +12,11 @@ True False True - True False vertical - - - True - True - - - - True - 30 - - - - - True @@ -53,6 +38,17 @@ 18 12 center + + + True + False + 0 + Type Special Characters + + + + + True @@ -68,7 +64,6 @@ True True - true Alternate Characters Key Hold down and type to enter different characters True @@ -94,34 +89,41 @@ + + + True + False + 0 + Keyboard Shortcuts + + + + + True False - + True True none 250 - + - + True True + Customize Shortcuts + True - + True - False - True - 6 - - - True - False - list-add-symbolic - - + go-next-symbolic + @@ -137,69 +139,4 @@ - - - - True - - - - True - system-search-symbolic - - - - - True - True - Reset All… - Reset all shortcuts to their default keybindings - - - - - True - False - center - center - True - True - 18 - vertical - 6 - - - True - False - 80 - edit-find-symbolic - - - - - - True - False - No keyboard shortcut found - - - - - - - - - True - False - Try a different search - - - - diff --git a/panels/keyboard/cc-keyboard-shortcut-dialog.c b/panels/keyboard/cc-keyboard-shortcut-dialog.c new file mode 100644 index 0000000000..c41787eb3e --- /dev/null +++ b/panels/keyboard/cc-keyboard-shortcut-dialog.c @@ -0,0 +1,847 @@ +/* cc-keyboard-shortcut-dialog.c + * + * Copyright (C) 2010 Intel, Inc + * Copyright (C) 2016 Endless, Inc + * Copyright (C) 2020 System76, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * Author: Thomas Wood + * Georges Basile Stavracas Neto + * Ian Douglas Scott + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include +#define HANDY_USE_UNSTABLE_API +#include + +#include "cc-keyboard-shortcut-dialog.h" +#include "cc-keyboard-item.h" +#include "cc-keyboard-manager.h" +#include "cc-keyboard-shortcut-editor.h" +#include "cc-keyboard-shortcut-row.h" +#include "cc-list-row.h" +#include "cc-util.h" +#include "list-box-helper.h" +#include "keyboard-shortcuts.h" + +#define SHORTCUT_DELIMITERS "+ " + +typedef struct { + gchar *section_title; + gchar *section_id; + guint modified_count; + GtkLabel *modified_label; +} SectionRowData; + +typedef struct { + CcKeyboardItem *item; + gchar *section_title; + gchar *section_id; + SectionRowData *section_data; +} ShortcutRowData; + +struct _CcKeyboardShortcutDialog +{ + GtkDialog parent_instance; + + GtkSizeGroup *accelerator_sizegroup; + GtkRevealer *back_revealer; + GtkWidget *custom_shortcut_add_box; + guint custom_shortcut_count; + GtkWidget *empty_custom_shortcuts_placeholder; + GtkWidget *empty_search_placeholder; + GtkHeaderBar *headerbar; + GtkRevealer *reset_all_revealer; + GtkSearchEntry *search_entry; + GtkListBox *section_listbox; + GtkListBoxRow *section_row; + GtkScrolledWindow *section_scrolled_window; + GtkListBox *shortcut_listbox; + GtkScrolledWindow *shortcut_scrolled_window; + GtkStack *stack; + + CcKeyboardManager *manager; + GtkWidget *shortcut_editor; + GHashTable *sections; + }; + +G_DEFINE_TYPE (CcKeyboardShortcutDialog, cc_keyboard_shortcut_dialog, GTK_TYPE_DIALOG) + +static SectionRowData* +section_row_data_new (const gchar *section_id, + const gchar *section_title, + GtkLabel *modified_label) +{ + SectionRowData *data; + + data = g_new0 (SectionRowData, 1); + data->section_id = g_strdup (section_id); + data->section_title = g_strdup (section_title); + data->modified_count = 0; + data->modified_label = modified_label; + + return data; +} + +static void +section_row_data_free (SectionRowData *data) +{ + g_free (data->section_id); + g_free (data->section_title); + g_free (data); +} + +static ShortcutRowData* +shortcut_row_data_new (CcKeyboardItem *item, + const gchar *section_id, + const gchar *section_title, + SectionRowData *section_data) +{ + ShortcutRowData *data; + + data = g_new0 (ShortcutRowData, 1); + data->item = g_object_ref (item); + data->section_id = g_strdup (section_id); + data->section_title = g_strdup (section_title); + data->section_data = section_data; + + return data; +} + +static void +shortcut_row_data_free (ShortcutRowData *data) +{ + g_object_unref (data->item); + g_free (data->section_id); + g_free (data->section_title); + g_free (data); +} + +static GtkListBoxRow* +add_section (CcKeyboardShortcutDialog *self, + const gchar *section_id, + const gchar *section_title) +{ + GtkWidget *icon, *modified_label, *label, *box; + GtkListBoxRow *row; + + icon = g_object_new (GTK_TYPE_IMAGE, + "visible", 1, + "icon_name", "go-next-symbolic", + NULL); + gtk_style_context_add_class (gtk_widget_get_style_context (icon), "dim-label"); + + modified_label = g_object_new (GTK_TYPE_LABEL, + "visible", 1, + NULL); + gtk_style_context_add_class (gtk_widget_get_style_context (modified_label), "dim-label"); + + label = g_object_new (GTK_TYPE_LABEL, + "visible", 1, + "label", _(section_title), + NULL); + gtk_style_context_add_class (gtk_widget_get_style_context (label), "row-label"); + + box = g_object_new (GTK_TYPE_BOX, + "visible", 1, + "spacing", 8, + "margin_left", 12, + "margin_right", 12, + "margin_top", 8, + "margin_bottom", 8, + NULL); + gtk_container_add (GTK_CONTAINER (box), label); + gtk_box_pack_end (GTK_BOX (box), icon, FALSE, FALSE, 0); + gtk_box_pack_end (GTK_BOX (box), modified_label, FALSE, FALSE, 0); + + row = g_object_new (GTK_TYPE_LIST_BOX_ROW, + "visible", 1, + NULL); + gtk_container_add (GTK_CONTAINER (row), box); + + g_object_set_data_full (G_OBJECT (row), + "data", + section_row_data_new (section_id, section_title, GTK_LABEL (modified_label)), + (GDestroyNotify)section_row_data_free); + + g_hash_table_insert (self->sections, g_strdup (section_id), row); + gtk_container_add (GTK_CONTAINER (self->section_listbox), GTK_WIDGET (row)); + + return row; +} + +static void +set_custom_shortcut_add_box_visibility (CcKeyboardShortcutDialog *self) +{ + SectionRowData *section_data; + gboolean is_custom_shortcuts = FALSE; + + if (self->section_row != NULL) + { + section_data = g_object_get_data (G_OBJECT (self->section_row), "data"); + is_custom_shortcuts = (strcmp (section_data->section_id, "custom") == 0); + + gtk_stack_set_transition_type (self->stack, GTK_STACK_TRANSITION_TYPE_CROSSFADE); + if (is_custom_shortcuts && (self->custom_shortcut_count == 0)) + gtk_stack_set_visible_child (self->stack, GTK_WIDGET (self->empty_custom_shortcuts_placeholder)); + else + gtk_stack_set_visible_child (self->stack, GTK_WIDGET (self->shortcut_scrolled_window)); + } + + gtk_widget_set_visible (self->custom_shortcut_add_box, is_custom_shortcuts); +} + +static void +add_item (CcKeyboardShortcutDialog *self, + CcKeyboardItem *item, + const gchar *section_id, + const gchar *section_title) +{ + GtkWidget *row; + GtkListBoxRow *section_row; + SectionRowData *section_data; + + section_row = g_hash_table_lookup (self->sections, section_id); + if (section_row == NULL) + section_row = add_section (self, section_id, section_title); + + section_data = g_object_get_data (G_OBJECT (section_row), "data"); + + row = GTK_WIDGET (cc_keyboard_shortcut_row_new (item, + self->manager, + CC_KEYBOARD_SHORTCUT_EDITOR (self->shortcut_editor), + self->accelerator_sizegroup)); + + g_object_set_data_full (G_OBJECT (row), + "data", + shortcut_row_data_new (item, section_id, section_title, section_data), + (GDestroyNotify)shortcut_row_data_free); + + if (strcmp (section_id, "custom") == 0) + { + self->custom_shortcut_count++; + set_custom_shortcut_add_box_visibility (self); + } + + gtk_container_add (GTK_CONTAINER (self->shortcut_listbox), row); +} + +static void +remove_item (CcKeyboardShortcutDialog *self, + CcKeyboardItem *item) +{ + g_autoptr(GList) children; + + children = gtk_container_get_children (GTK_CONTAINER (self->shortcut_listbox)); + + for (GList *l = children; l != NULL; l = l->next) + { + ShortcutRowData *row_data; + + row_data = g_object_get_data (l->data, "data"); + + if (row_data->item == item) + { + if (strcmp (row_data->section_id, "custom") == 0) + { + self->custom_shortcut_count--; + set_custom_shortcut_add_box_visibility (self); + } + + gtk_container_remove (GTK_CONTAINER (self->shortcut_listbox), l->data); + break; + } + } +} + +static void +update_modified_counts (CcKeyboardShortcutDialog *self) +{ + g_autoptr(GList) sections = NULL, shortcuts = NULL; + SectionRowData *section_data; + ShortcutRowData *shortcut_data; + g_autofree gchar *modified_text = NULL; + + sections = gtk_container_get_children (GTK_CONTAINER (self->section_listbox)); + shortcuts = gtk_container_get_children (GTK_CONTAINER (self->shortcut_listbox)); + + for (GList *l = sections; l != NULL; l = l->next) + { + section_data = g_object_get_data (G_OBJECT (l->data), "data"); + section_data->modified_count = 0; + } + + for (GList *l = shortcuts; l != NULL; l = l->next) + { + shortcut_data = g_object_get_data (G_OBJECT (l->data), "data"); + if (!cc_keyboard_item_is_value_default (shortcut_data->item)) + shortcut_data->section_data->modified_count++; + } + + for (GList *l = sections; l != NULL; l = l->next) + { + section_data = g_object_get_data (G_OBJECT (l->data), "data"); + if (section_data->modified_count > 0) + { + modified_text = g_strdup_printf ("%d %s", section_data->modified_count, _("modified")); + gtk_label_set_text (section_data->modified_label, modified_text); + } + else + { + gtk_label_set_text (section_data->modified_label, ""); + } + } +} + +static void +show_section_list (CcKeyboardShortcutDialog *self) +{ + if (self->section_row != NULL) + gtk_stack_set_transition_type (self->stack, GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT); + else + gtk_stack_set_transition_type (self->stack, GTK_STACK_TRANSITION_TYPE_NONE); + self->section_row = NULL; + + gtk_stack_set_visible_child (self->stack, GTK_WIDGET (self->section_scrolled_window)); + gtk_header_bar_set_title (self->headerbar, _("Keyboard Shortcuts")); + gtk_entry_set_text(GTK_ENTRY (self->search_entry), ""); + gtk_revealer_set_reveal_child (self->reset_all_revealer, TRUE); + gtk_revealer_set_reveal_child (self->back_revealer, FALSE); + gtk_widget_set_visible (GTK_WIDGET (self->search_entry), TRUE); + + update_modified_counts (self); +} + +static void +show_shortcut_list (CcKeyboardShortcutDialog *self) +{ + SectionRowData *section_data; + gchar *title; + gboolean is_custom_shortcuts = FALSE; + + title = _("Keyboard Shortcuts"); + gtk_stack_set_transition_type (self->stack, GTK_STACK_TRANSITION_TYPE_NONE); + if (self->section_row != NULL) + { + section_data = g_object_get_data (G_OBJECT (self->section_row), "data"); + title = _(section_data->section_title); + is_custom_shortcuts = (strcmp (section_data->section_id, "custom") == 0); + gtk_stack_set_transition_type (self->stack, GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT); + } + + if (is_custom_shortcuts) + gtk_list_box_set_placeholder (self->shortcut_listbox, NULL); + else + gtk_list_box_set_placeholder (self->shortcut_listbox, self->empty_search_placeholder); + + gtk_list_box_invalidate_filter (self->shortcut_listbox); + + if (is_custom_shortcuts && (self->custom_shortcut_count == 0)) + gtk_stack_set_visible_child (self->stack, GTK_WIDGET (self->empty_custom_shortcuts_placeholder)); + else + gtk_stack_set_visible_child (self->stack, GTK_WIDGET (self->shortcut_scrolled_window)); + + gtk_header_bar_set_title (self->headerbar, title); + set_custom_shortcut_add_box_visibility (self); + gtk_revealer_set_reveal_child (self->reset_all_revealer, FALSE); + gtk_revealer_set_reveal_child (self->back_revealer, TRUE); + gtk_widget_set_visible (GTK_WIDGET (self->search_entry), self->section_row == NULL); + +} + +static void +section_row_activated (GtkWidget *button, + GtkListBoxRow *row, + CcKeyboardShortcutDialog *self) +{ + self->section_row = row; + show_shortcut_list (self); +} + +static void +shortcut_row_activated (GtkWidget *button, + GtkListBoxRow *row, + CcKeyboardShortcutDialog *self) +{ + CcKeyboardShortcutEditor *editor; + + editor = CC_KEYBOARD_SHORTCUT_EDITOR (self->shortcut_editor); + + ShortcutRowData *data = g_object_get_data (G_OBJECT (row), "data"); + + cc_keyboard_shortcut_editor_set_mode (editor, CC_SHORTCUT_EDITOR_EDIT); + cc_keyboard_shortcut_editor_set_item (editor, data->item); + + gtk_widget_show (self->shortcut_editor); +} + +static void +add_custom_shortcut_clicked_cb (CcKeyboardShortcutDialog *self) +{ + CcKeyboardShortcutEditor *editor; + + editor = CC_KEYBOARD_SHORTCUT_EDITOR (self->shortcut_editor); + + cc_keyboard_shortcut_editor_set_mode (editor, CC_SHORTCUT_EDITOR_CREATE); + cc_keyboard_shortcut_editor_set_item (editor, NULL); + + gtk_widget_show (self->shortcut_editor); +} + +static void +back_button_clicked_cb (CcKeyboardShortcutDialog *self) +{ + show_section_list (self); +} + +static void +reset_all_shortcuts_cb (GtkWidget *widget, + gpointer user_data) +{ + CcKeyboardShortcutDialog *self; + ShortcutRowData *data; + + self = user_data; + + data = g_object_get_data (G_OBJECT (widget), "data"); + + /* Don't reset custom shortcuts */ + if (cc_keyboard_item_get_item_type (data->item) == CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH) + return; + + /* cc_keyboard_manager_reset_shortcut() already resets conflicting shortcuts, + * so no other check is needed here. */ + cc_keyboard_manager_reset_shortcut (self->manager, data->item); +} + +static void +reset_all_clicked_cb (CcKeyboardShortcutDialog *self) +{ + GtkWidget *dialog, *toplevel, *button; + guint response; + + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self)); + dialog = gtk_message_dialog_new (GTK_WINDOW (toplevel), + GTK_DIALOG_MODAL | GTK_DIALOG_USE_HEADER_BAR | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_NONE, + _("Reset All Shortcuts?")); + + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + _("Resetting the shortcuts may affect your custom shortcuts. " + "This cannot be undone.")); + + gtk_dialog_add_buttons (GTK_DIALOG (dialog), + _("Cancel"), GTK_RESPONSE_CANCEL, + _("Reset All"), GTK_RESPONSE_ACCEPT, + NULL); + + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL); + + /* Make the "Reset All" button destructive */ + button = gtk_dialog_get_widget_for_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); + gtk_style_context_add_class (gtk_widget_get_style_context (button), "destructive-action"); + + /* Reset shortcuts if accepted */ + response = gtk_dialog_run (GTK_DIALOG (dialog)); + + if (response == GTK_RESPONSE_ACCEPT) + { + gtk_container_foreach (GTK_CONTAINER (self->shortcut_listbox), + reset_all_shortcuts_cb, + self); + } + + gtk_widget_destroy (dialog); + + update_modified_counts (self); +} + +static void +search_entry_cb (CcKeyboardShortcutDialog *self) +{ + if (gtk_entry_get_text_length (GTK_ENTRY (self->search_entry)) == 0 && self->section_row == NULL) + show_section_list (self); + else if (gtk_stack_get_visible_child (self->stack) != GTK_WIDGET (self->shortcut_scrolled_window)) + show_shortcut_list (self); + else + gtk_list_box_invalidate_filter (self->shortcut_listbox); +} + +static void +key_press_cb (CcKeyboardShortcutDialog *self, GdkEvent *event) +{ + if (gtk_widget_get_visible (GTK_WIDGET (self->search_entry))) + gtk_search_entry_handle_event (self->search_entry, event); +} + +static gboolean +strv_contains_prefix_or_match (gchar **strv, + const gchar *prefix) +{ + const struct { + const gchar *key; + const gchar *untranslated; + const gchar *synonym; + } key_aliases[] = + { + { "ctrl", "Ctrl", "ctrl" }, + { "win", "Super", "super" }, + { "option", NULL, "alt" }, + { "command", NULL, "super" }, + { "apple", NULL, "super" }, + }; + + for (guint i = 0; strv[i]; i++) + { + if (g_str_has_prefix (strv[i], prefix)) + return TRUE; + } + + for (guint i = 0; i < G_N_ELEMENTS (key_aliases); i++) + { + g_autofree gchar *alias = NULL; + const gchar *synonym; + + if (!g_str_has_prefix (key_aliases[i].key, prefix)) + continue; + + if (key_aliases[i].untranslated) + { + const gchar *translated_label; + + /* Steal GTK+'s translation */ + translated_label = g_dpgettext2 ("gtk30", "keyboard label", key_aliases[i].untranslated); + alias = g_utf8_strdown (translated_label, -1); + } + + synonym = key_aliases[i].synonym; + + /* If a translation or synonym of the key is in the accelerator, and we typed + * the key, also consider that a prefix */ + if ((alias && g_strv_contains ((const gchar * const *) strv, alias)) || + (synonym && g_strv_contains ((const gchar * const *) strv, synonym))) + { + return TRUE; + } + } + + return FALSE; +} + +static gboolean +search_match_shortcut (CcKeyboardItem *item, + const gchar *search) +{ + g_auto(GStrv) shortcut_tokens = NULL, search_tokens = NULL; + g_autofree gchar *normalized_accel = NULL; + g_autofree gchar *accel = NULL; + gboolean match; + GList *key_combos; + CcKeyCombo *combo; + + key_combos = cc_keyboard_item_get_key_combos (item); + for (GList *l = key_combos; l != NULL; l = l->next) + { + combo = l->data; + + if (is_empty_binding (combo)) + continue; + + match = TRUE; + accel = convert_keysym_state_to_string (combo); + normalized_accel = cc_util_normalize_casefold_and_unaccent (accel); + + shortcut_tokens = g_strsplit_set (normalized_accel, SHORTCUT_DELIMITERS, -1); + search_tokens = g_strsplit_set (search, SHORTCUT_DELIMITERS, -1); + + for (guint i = 0; search_tokens[i] != NULL; i++) + { + const gchar *token; + + /* Strip leading and trailing whitespaces */ + token = g_strstrip (search_tokens[i]); + + if (g_utf8_strlen (token, -1) == 0) + continue; + + match = match && strv_contains_prefix_or_match (shortcut_tokens, token); + + if (!match) + break; + } + + if (match) + return TRUE; + } + + return FALSE; +} + +static gint +section_sort_function (GtkListBoxRow *a, + GtkListBoxRow *b, + gpointer user_data) +{ + SectionRowData *a_data, *b_data; + + a_data = g_object_get_data (G_OBJECT (a), "data"); + b_data = g_object_get_data (G_OBJECT (b), "data"); + + /* Put custom shortcuts below everything else */ + if (g_strcmp0 (a_data->section_id, "custom") == 0) + return 1; + + return g_strcmp0 (a_data->section_title, b_data->section_title); +} + +static gint +shortcut_sort_function (GtkListBoxRow *a, + GtkListBoxRow *b, + gpointer user_data) +{ + ShortcutRowData *a_data, *b_data; + gint retval; + + a_data = g_object_get_data (G_OBJECT (a), "data"); + b_data = g_object_get_data (G_OBJECT (b), "data"); + + /* Put custom shortcuts below everything else */ + if (g_strcmp0 (a_data->section_id, "custom") == 0) + return 1; + + retval = g_strcmp0 (a_data->section_title, b_data->section_title); + + if (retval != 0) + return retval; + + return g_strcmp0 (cc_keyboard_item_get_description (a_data->item), cc_keyboard_item_get_description (b_data->item)); +} + +static gboolean +shortcut_filter_function (GtkListBoxRow *row, + gpointer userdata) +{ + CcKeyboardShortcutDialog *self = userdata; + SectionRowData *section_data; + ShortcutRowData *data; + CcKeyboardItem *item; + gboolean retval; + g_autofree gchar *search = NULL; + g_autofree gchar *name = NULL; + g_auto(GStrv) terms = NULL; + + if (self->section_row != NULL) + { + section_data = g_object_get_data (G_OBJECT (self->section_row), "data"); + data = g_object_get_data (G_OBJECT (row), "data"); + if (strcmp (data->section_id, section_data->section_id) != 0) + return FALSE; + } + + if (gtk_entry_get_text_length (GTK_ENTRY (self->search_entry)) == 0) + return TRUE; + + data = g_object_get_data (G_OBJECT (row), "data"); + item = data->item; + name = cc_util_normalize_casefold_and_unaccent (cc_keyboard_item_get_description (item)); + search = cc_util_normalize_casefold_and_unaccent (gtk_entry_get_text (GTK_ENTRY (self->search_entry))); + terms = g_strsplit (search, " ", -1); + + for (guint i = 0; terms && terms[i]; i++) + { + retval = strstr (name, terms[i]) || search_match_shortcut (item, terms[i]); + if (!retval) + break; + } + + return retval; +} + +static void +shortcut_header_function (GtkListBoxRow *row, + GtkListBoxRow *before, + gpointer user_data) +{ + CcKeyboardShortcutDialog *self; + gboolean add_header; + ShortcutRowData *data, *before_data; + + data = g_object_get_data (G_OBJECT (row), "data"); + + self = user_data; + add_header = FALSE; + + if (before) + { + before_data = g_object_get_data (G_OBJECT (before), "data"); + add_header = g_strcmp0 (before_data->section_id, data->section_id) != 0; + } + else + { + add_header = TRUE; + } + + if (self->section_row != NULL) + add_header = FALSE; + + if (add_header) + { + GtkWidget *box, *label, *separator; + g_autofree gchar *markup = NULL; + + box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); + gtk_widget_show (box); + if (!before) + gtk_widget_set_margin_top (box, 6); + + if (before) + { + separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); + gtk_widget_show (separator); + gtk_container_add (GTK_CONTAINER (box), separator); + } + + markup = g_strdup_printf ("%s", _(data->section_title)); + label = g_object_new (GTK_TYPE_LABEL, + "label", markup, + "use-markup", TRUE, + "xalign", 0.0, + "margin-start", 6, + NULL); + gtk_widget_show (label); + gtk_container_add (GTK_CONTAINER (box), label); + + separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); + gtk_widget_show (separator); + gtk_container_add (GTK_CONTAINER (box), separator); + + gtk_list_box_row_set_header (row, box); + } + else if (before) + { + GtkWidget *separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); + gtk_widget_show (separator); + + gtk_list_box_row_set_header (row, separator); + } + else + { + gtk_list_box_row_set_header (row, NULL); + } +} + +static void +cc_keyboard_shortcut_dialog_constructed (GObject *object) +{ + CcKeyboardShortcutDialog *self = CC_KEYBOARD_SHORTCUT_DIALOG (object); + + G_OBJECT_CLASS (cc_keyboard_shortcut_dialog_parent_class)->constructed (object); + + /* Setup the dialog's transient parent */ + gtk_window_set_transient_for (GTK_WINDOW (self->shortcut_editor), GTK_WINDOW (self)); +} + +static void +cc_keyboard_shortcut_dialog_class_init (CcKeyboardShortcutDialogClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->constructed = cc_keyboard_shortcut_dialog_constructed; + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/keyboard/cc-keyboard-shortcut-dialog.ui"); + + gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutDialog, accelerator_sizegroup); + gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutDialog, back_revealer); + gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutDialog, custom_shortcut_add_box); + gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutDialog, empty_custom_shortcuts_placeholder); + gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutDialog, empty_search_placeholder); + gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutDialog, headerbar); + gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutDialog, reset_all_revealer); + gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutDialog, search_entry); + gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutDialog, section_listbox); + gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutDialog, section_scrolled_window); + gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutDialog, shortcut_listbox); + gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutDialog, shortcut_scrolled_window); + gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutDialog, stack); + + gtk_widget_class_bind_template_callback (widget_class, add_custom_shortcut_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, back_button_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, key_press_cb); + gtk_widget_class_bind_template_callback (widget_class, reset_all_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, search_entry_cb); + gtk_widget_class_bind_template_callback (widget_class, section_row_activated); + gtk_widget_class_bind_template_callback (widget_class, shortcut_row_activated); +} + +static void +cc_keyboard_shortcut_dialog_init (CcKeyboardShortcutDialog *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); + + self->manager = cc_keyboard_manager_new (); + + self->shortcut_editor = cc_keyboard_shortcut_editor_new (self->manager); + + self->sections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + self->section_row = NULL; + + g_signal_connect_object (self->manager, + "shortcut-added", + G_CALLBACK (add_item), + self, + G_CONNECT_SWAPPED); + + g_signal_connect_object (self->manager, + "shortcut-removed", + G_CALLBACK (remove_item), + self, + G_CONNECT_SWAPPED); + + add_section(self, "custom", "Custom Shortcuts"); + cc_keyboard_manager_load_shortcuts (self->manager); + + gtk_list_box_set_header_func (self->section_listbox, cc_list_box_update_header_func, NULL, NULL); + gtk_list_box_set_sort_func (GTK_LIST_BOX (self->section_listbox), + section_sort_function, + self, + NULL); + + gtk_list_box_set_filter_func (self->shortcut_listbox, + shortcut_filter_function, + self, + NULL); + gtk_list_box_set_header_func (self->shortcut_listbox, + shortcut_header_function, + self, + NULL); + gtk_list_box_set_sort_func (GTK_LIST_BOX (self->shortcut_listbox), + shortcut_sort_function, + self, + NULL); + + show_section_list (self); +} + +GtkWidget* +cc_keyboard_shortcut_dialog_new (void) +{ + return g_object_new (CC_TYPE_KEYBOARD_SHORTCUT_DIALOG, + "use-header-bar", 1, + NULL); +} diff --git a/panels/keyboard/cc-keyboard-shortcut-dialog.h b/panels/keyboard/cc-keyboard-shortcut-dialog.h new file mode 100644 index 0000000000..4493dc2cec --- /dev/null +++ b/panels/keyboard/cc-keyboard-shortcut-dialog.h @@ -0,0 +1,35 @@ +/* cc-keyboard-shortcut-dialog.h + * + * Copyright (C) 2020 System76, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * Author: Ian Douglas Scott + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define CC_TYPE_KEYBOARD_SHORTCUT_DIALOG (cc_keyboard_shortcut_dialog_get_type ()) + +G_DECLARE_FINAL_TYPE (CcKeyboardShortcutDialog, cc_keyboard_shortcut_dialog, CC, KEYBOARD_SHORTCUT_DIALOG, GtkDialog) + +GtkWidget* cc_keyboard_shortcut_dialog_new (void); + +G_END_DECLS \ No newline at end of file diff --git a/panels/keyboard/cc-keyboard-shortcut-dialog.ui b/panels/keyboard/cc-keyboard-shortcut-dialog.ui new file mode 100644 index 0000000000..b158ef532d --- /dev/null +++ b/panels/keyboard/cc-keyboard-shortcut-dialog.ui @@ -0,0 +1,257 @@ + + + + + + True + False + center + center + True + True + 18 + vertical + 6 + + + True + False + 80 + edit-find-symbolic + + + + + + True + False + No keyboard shortcut found + + + + + + + + + True + False + Try a different search + + + + + + diff --git a/panels/keyboard/gnome-keyboard-panel.desktop.in.in b/panels/keyboard/gnome-keyboard-panel.desktop.in.in index 9200d692c8..b7b5627168 100644 --- a/panels/keyboard/gnome-keyboard-panel.desktop.in.in +++ b/panels/keyboard/gnome-keyboard-panel.desktop.in.in @@ -1,5 +1,5 @@ [Desktop Entry] -Name=Keyboard Shortcuts +Name=Keyboard Comment=View and change keyboard shortcuts and set your typing preferences Exec=gnome-control-center keyboard # Translators: Do NOT translate or transliterate this text (this is an icon file name)! diff --git a/panels/keyboard/keyboard.gresource.xml b/panels/keyboard/keyboard.gresource.xml index fc210ce754..14c05d8a1e 100644 --- a/panels/keyboard/keyboard.gresource.xml +++ b/panels/keyboard/keyboard.gresource.xml @@ -4,6 +4,7 @@ enter-keyboard-shortcut.svg cc-xkb-modifier-dialog.ui cc-keyboard-shortcut-row.ui + cc-keyboard-shortcut-dialog.ui cc-keyboard-panel.ui cc-keyboard-shortcut-editor.ui diff --git a/panels/keyboard/meson.build b/panels/keyboard/meson.build index 64c6a988c7..8055becf9f 100644 --- a/panels/keyboard/meson.build +++ b/panels/keyboard/meson.build @@ -58,6 +58,7 @@ endforeach sources = files( 'cc-xkb-modifier-dialog.c', 'cc-keyboard-shortcut-row.c', + 'cc-keyboard-shortcut-dialog.c', 'cc-keyboard-panel.c', 'cc-keyboard-item.c', 'cc-keyboard-manager.c', -- GitLab From fe173f661befd4147d385ce7fe0c64eb11cd6a6d Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 7 Aug 2020 10:51:00 -0700 Subject: [PATCH 02/13] keyboard: Do not call gtk_grab_{add,remove} in shortcut editor For some reason, the ungrab was making the window impossible to interact with. Without these calls, it seems to work as expected. --- panels/keyboard/cc-keyboard-shortcut-editor.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/panels/keyboard/cc-keyboard-shortcut-editor.c b/panels/keyboard/cc-keyboard-shortcut-editor.c index 75f505c34b..3afb288359 100644 --- a/panels/keyboard/cc-keyboard-shortcut-editor.c +++ b/panels/keyboard/cc-keyboard-shortcut-editor.c @@ -227,8 +227,6 @@ grab_seat (CcKeyboardShortcutEditor *self) self->grab_pointer = gdk_seat_get_keyboard (seat); if (!self->grab_pointer) self->grab_pointer = gdk_seat_get_pointer (seat); - - gtk_grab_add (GTK_WIDGET (self)); } static void @@ -238,8 +236,6 @@ release_grab (CcKeyboardShortcutEditor *self) { gdk_seat_ungrab (gdk_device_get_seat (self->grab_pointer)); self->grab_pointer = NULL; - - gtk_grab_remove (GTK_WIDGET (self)); } } -- GitLab From 25b12bf15717664d7e0d507e32fcfc6fe6517446 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Tue, 21 Jul 2020 09:14:36 -0700 Subject: [PATCH 03/13] keyboard: Compose key This was previously available only in Gnome Tweaks. --- panels/keyboard/cc-keyboard-panel.c | 72 +++++++++++++++++++++++----- panels/keyboard/cc-keyboard-panel.ui | 29 +++++++++-- 2 files changed, 87 insertions(+), 14 deletions(-) diff --git a/panels/keyboard/cc-keyboard-panel.c b/panels/keyboard/cc-keyboard-panel.c index 20fd2c9072..ffbb939949 100644 --- a/panels/keyboard/cc-keyboard-panel.c +++ b/panels/keyboard/cc-keyboard-panel.c @@ -32,15 +32,21 @@ #include "cc-xkb-modifier-dialog.h" #include "keyboard-shortcuts.h" +#include "list-box-helper.h" struct _CcKeyboardPanel { CcPanel parent_instance; - /* Alternate characters key */ - CcXkbModifierDialog *xkb_modifier_dialog; + /* "Type Special Characters" section */ + CcXkbModifierDialog *alt_chars_dialog; + CcXkbModifierDialog *compose_dialog; GSettings *input_source_settings; + GtkListBox *special_chars_list; + GtkListBoxRow *alt_chars_row; + GtkListBoxRow *compose_row; GtkWidget *value_alternate_chars; + GtkWidget *value_compose; GtkListBoxRow *common_shortcuts_row; }; @@ -68,17 +74,45 @@ static const XkbModifier LV3_MODIFIER = { "lv3:ralt_switch", }; +static const XkbModifier COMPOSE_MODIFIER = { + "compose:", + N_("Compose Key"), + N_("The compose key allows a wide variety of characters to be entered. To use it, press compose then a sequence of characters. " + " For example, compose key followed by C and o will enter ©, " + "a followed by ' will enter á."), + (XkbOption[]){ + { NC_("keyboard key", "Left Alt"), "compose:lalt" }, + { NC_("keyboard key", "Right Alt"), "compose:ralt" }, + { NC_("keyboard key", "Left Super"), "compose:lwin" }, + { NC_("keyboard key", "Right Super"), "compose:rwin" }, + { NC_("keyboard key", "Menu key"), "compose:menu" }, + { NC_("keyboard key", "Right Ctrl"), "compose:rctrl" }, + { NC_("keyboard key", "Caps Lock"), "compose:caps" }, + { NC_("keyboard key", "Scroll Lock"), "compose:sclk" }, + { NC_("keyboard key", "Print Screen"), "compose:prsc" }, + { NULL, NULL } + }, + NULL, +}; + static void -alternate_chars_activated (GtkWidget *button, - GtkListBoxRow *row, - CcKeyboardPanel *self) +special_chars_activated (GtkWidget *button, + GtkListBoxRow *row, + CcKeyboardPanel *self) { - GtkWindow *window; + GtkWindow *window, *dialog; window = GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (self)))); - gtk_window_set_transient_for (GTK_WINDOW (self->xkb_modifier_dialog), window); - gtk_widget_show (GTK_WIDGET (self->xkb_modifier_dialog)); + if (row == self->alt_chars_row) + dialog = GTK_WINDOW (self->alt_chars_dialog); + else if (row == self->compose_row) + dialog = GTK_WINDOW (self->compose_dialog); + else + return; + + gtk_window_set_transient_for (dialog, window); + gtk_widget_show (GTK_WIDGET (dialog)); } static void @@ -147,10 +181,14 @@ cc_keyboard_panel_class_init (CcKeyboardPanelClass *klass) gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/keyboard/cc-keyboard-panel.ui"); + gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, special_chars_list); + gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, alt_chars_row); + gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, compose_row); 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, common_shortcuts_row); - gtk_widget_class_bind_template_callback (widget_class, alternate_chars_activated); + gtk_widget_class_bind_template_callback (widget_class, special_chars_activated); gtk_widget_class_bind_template_callback (widget_class, keyboard_shortcuts_activated); } @@ -161,7 +199,9 @@ cc_keyboard_panel_init (CcKeyboardPanel *self) gtk_widget_init_template (GTK_WIDGET (self)); - /* Alternate characters key */ + gtk_list_box_set_header_func (self->special_chars_list, cc_list_box_update_header_func, NULL, NULL); + + /* "Type Special Characters" section */ self->input_source_settings = g_settings_new ("org.gnome.desktop.input-sources"); g_settings_bind_with_mapping (self->input_source_settings, "xkb-options", @@ -172,6 +212,16 @@ cc_keyboard_panel_init (CcKeyboardPanel *self) NULL, (gpointer)&LV3_MODIFIER, NULL); + g_settings_bind_with_mapping (self->input_source_settings, + "xkb-options", + self->value_compose, + "label", + G_SETTINGS_BIND_GET, + xcb_modifier_transform_binding_to_label, + NULL, + (gpointer)&COMPOSE_MODIFIER, + NULL); - self->xkb_modifier_dialog = cc_xkb_modifier_dialog_new (self->input_source_settings, &LV3_MODIFIER); + 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 7c977db69e..93360a97ba 100644 --- a/panels/keyboard/cc-keyboard-panel.ui +++ b/panels/keyboard/cc-keyboard-panel.ui @@ -54,14 +54,14 @@ True False - + True True none 250 - + - + True True Alternate Characters Key @@ -84,6 +84,29 @@ + + + + True + True + Compose Key + True + + + True + True + + + + + True + go-next-symbolic + + + + -- GitLab From 8996ffac88ae104781ccd3e5e842027ffeccc8a5 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 24 Jul 2020 09:06:36 -0700 Subject: [PATCH 04/13] Move input sources from region panel to keyboard panel --- panels/{region => keyboard}/cc-ibus-utils.c | 0 panels/{region => keyboard}/cc-ibus-utils.h | 0 .../{region => keyboard}/cc-input-chooser.c | 2 +- .../{region => keyboard}/cc-input-chooser.h | 0 .../{region => keyboard}/cc-input-chooser.ui | 0 .../{region => keyboard}/cc-input-list-box.c | 2 +- .../{region => keyboard}/cc-input-list-box.h | 0 .../{region => keyboard}/cc-input-list-box.ui | 0 panels/{region => keyboard}/cc-input-row.c | 2 +- panels/{region => keyboard}/cc-input-row.h | 0 panels/{region => keyboard}/cc-input-row.ui | 0 .../cc-input-source-ibus.c | 0 .../cc-input-source-ibus.h | 0 .../cc-input-source-xkb.c | 0 .../cc-input-source-xkb.h | 0 panels/{region => keyboard}/cc-input-source.c | 0 panels/{region => keyboard}/cc-input-source.h | 0 panels/keyboard/cc-keyboard-panel.c | 43 ++- panels/keyboard/cc-keyboard-panel.ui | 97 ++++++ panels/keyboard/keyboard.gresource.xml | 3 + panels/keyboard/meson.build | 14 +- panels/region/cc-region-panel.c | 124 +------- panels/region/cc-region-panel.ui | 283 +----------------- panels/region/meson.build | 8 - panels/region/region.gresource.xml | 3 - 25 files changed, 160 insertions(+), 421 deletions(-) rename panels/{region => keyboard}/cc-ibus-utils.c (100%) rename panels/{region => keyboard}/cc-ibus-utils.h (100%) rename panels/{region => keyboard}/cc-input-chooser.c (99%) rename panels/{region => keyboard}/cc-input-chooser.h (100%) rename panels/{region => keyboard}/cc-input-chooser.ui (100%) rename panels/{region => keyboard}/cc-input-list-box.c (99%) rename panels/{region => keyboard}/cc-input-list-box.h (100%) rename panels/{region => keyboard}/cc-input-list-box.ui (100%) rename panels/{region => keyboard}/cc-input-row.c (99%) rename panels/{region => keyboard}/cc-input-row.h (100%) rename panels/{region => keyboard}/cc-input-row.ui (100%) rename panels/{region => keyboard}/cc-input-source-ibus.c (100%) rename panels/{region => keyboard}/cc-input-source-ibus.h (100%) rename panels/{region => keyboard}/cc-input-source-xkb.c (100%) rename panels/{region => keyboard}/cc-input-source-xkb.h (100%) rename panels/{region => keyboard}/cc-input-source.c (100%) rename panels/{region => keyboard}/cc-input-source.h (100%) diff --git a/panels/region/cc-ibus-utils.c b/panels/keyboard/cc-ibus-utils.c similarity index 100% rename from panels/region/cc-ibus-utils.c rename to panels/keyboard/cc-ibus-utils.c diff --git a/panels/region/cc-ibus-utils.h b/panels/keyboard/cc-ibus-utils.h similarity index 100% rename from panels/region/cc-ibus-utils.h rename to panels/keyboard/cc-ibus-utils.h diff --git a/panels/region/cc-input-chooser.c b/panels/keyboard/cc-input-chooser.c similarity index 99% rename from panels/region/cc-input-chooser.c rename to panels/keyboard/cc-input-chooser.c index 7ad59fd0b5..f9aaff69a1 100644 --- a/panels/region/cc-input-chooser.c +++ b/panels/keyboard/cc-input-chooser.c @@ -1016,7 +1016,7 @@ cc_input_chooser_class_init (CcInputChooserClass *klass) object_class->dispose = cc_input_chooser_dispose; - gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/region/cc-input-chooser.ui"); + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/keyboard/cc-input-chooser.ui"); gtk_widget_class_bind_template_child (widget_class, CcInputChooser, add_button); gtk_widget_class_bind_template_child (widget_class, CcInputChooser, filter_entry); diff --git a/panels/region/cc-input-chooser.h b/panels/keyboard/cc-input-chooser.h similarity index 100% rename from panels/region/cc-input-chooser.h rename to panels/keyboard/cc-input-chooser.h diff --git a/panels/region/cc-input-chooser.ui b/panels/keyboard/cc-input-chooser.ui similarity index 100% rename from panels/region/cc-input-chooser.ui rename to panels/keyboard/cc-input-chooser.ui diff --git a/panels/region/cc-input-list-box.c b/panels/keyboard/cc-input-list-box.c similarity index 99% rename from panels/region/cc-input-list-box.c rename to panels/keyboard/cc-input-list-box.c index d42ad48e1e..6c2cb5614b 100644 --- a/panels/region/cc-input-list-box.c +++ b/panels/keyboard/cc-input-list-box.c @@ -723,7 +723,7 @@ cc_input_list_box_class_init (CcInputListBoxClass *klass) object_class->finalize = cc_input_list_box_finalize; - gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/region/cc-input-list-box.ui"); + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/keyboard/cc-input-list-box.ui"); gtk_widget_class_bind_template_child (widget_class, CcInputListBox, add_input_row); gtk_widget_class_bind_template_child (widget_class, CcInputListBox, input_size_group); diff --git a/panels/region/cc-input-list-box.h b/panels/keyboard/cc-input-list-box.h similarity index 100% rename from panels/region/cc-input-list-box.h rename to panels/keyboard/cc-input-list-box.h diff --git a/panels/region/cc-input-list-box.ui b/panels/keyboard/cc-input-list-box.ui similarity index 100% rename from panels/region/cc-input-list-box.ui rename to panels/keyboard/cc-input-list-box.ui diff --git a/panels/region/cc-input-row.c b/panels/keyboard/cc-input-row.c similarity index 99% rename from panels/region/cc-input-row.c rename to panels/keyboard/cc-input-row.c index bc38d9bef1..1748a6b092 100644 --- a/panels/region/cc-input-row.c +++ b/panels/keyboard/cc-input-row.c @@ -189,7 +189,7 @@ cc_input_row_class_init (CcInputRowClass *klass) object_class->dispose = cc_input_row_dispose; - gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/region/cc-input-row.ui"); + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/keyboard/cc-input-row.ui"); gtk_widget_class_bind_template_child (widget_class, CcInputRow, drag_handle); gtk_widget_class_bind_template_child (widget_class, CcInputRow, name_label); diff --git a/panels/region/cc-input-row.h b/panels/keyboard/cc-input-row.h similarity index 100% rename from panels/region/cc-input-row.h rename to panels/keyboard/cc-input-row.h diff --git a/panels/region/cc-input-row.ui b/panels/keyboard/cc-input-row.ui similarity index 100% rename from panels/region/cc-input-row.ui rename to panels/keyboard/cc-input-row.ui diff --git a/panels/region/cc-input-source-ibus.c b/panels/keyboard/cc-input-source-ibus.c similarity index 100% rename from panels/region/cc-input-source-ibus.c rename to panels/keyboard/cc-input-source-ibus.c diff --git a/panels/region/cc-input-source-ibus.h b/panels/keyboard/cc-input-source-ibus.h similarity index 100% rename from panels/region/cc-input-source-ibus.h rename to panels/keyboard/cc-input-source-ibus.h diff --git a/panels/region/cc-input-source-xkb.c b/panels/keyboard/cc-input-source-xkb.c similarity index 100% rename from panels/region/cc-input-source-xkb.c rename to panels/keyboard/cc-input-source-xkb.c diff --git a/panels/region/cc-input-source-xkb.h b/panels/keyboard/cc-input-source-xkb.h similarity index 100% rename from panels/region/cc-input-source-xkb.h rename to panels/keyboard/cc-input-source-xkb.h diff --git a/panels/region/cc-input-source.c b/panels/keyboard/cc-input-source.c similarity index 100% rename from panels/region/cc-input-source.c rename to panels/keyboard/cc-input-source.c diff --git a/panels/region/cc-input-source.h b/panels/keyboard/cc-input-source.h similarity index 100% rename from panels/region/cc-input-source.h rename to panels/keyboard/cc-input-source.h diff --git a/panels/keyboard/cc-keyboard-panel.c b/panels/keyboard/cc-keyboard-panel.c index ffbb939949..a2bb99b1cb 100644 --- a/panels/keyboard/cc-keyboard-panel.c +++ b/panels/keyboard/cc-keyboard-panel.c @@ -29,6 +29,7 @@ #include "cc-keyboard-panel.h" #include "cc-keyboard-resources.h" #include "cc-keyboard-shortcut-dialog.h" +#include "cc-input-list-box.h" #include "cc-xkb-modifier-dialog.h" #include "keyboard-shortcuts.h" @@ -38,6 +39,11 @@ struct _CcKeyboardPanel { CcPanel parent_instance; + GtkListBox *input_source_list; + + GtkRadioButton *per_window_source; + GtkRadioButton *same_source; + /* "Type Special Characters" section */ CcXkbModifierDialog *alt_chars_dialog; CcXkbModifierDialog *compose_dialog; @@ -95,6 +101,14 @@ static const XkbModifier COMPOSE_MODIFIER = { NULL, }; +static const gchar *custom_css = +".keyboard-panel-radio-button {" +" padding-left: 6px;" +" padding-right: 12px;" +" padding-top: 12px;" +" padding-bottom: 12px;" +"}"; + static void special_chars_activated (GtkWidget *button, GtkListBoxRow *row, @@ -179,8 +193,14 @@ cc_keyboard_panel_class_init (CcKeyboardPanelClass *klass) g_object_class_override_property (object_class, PROP_PARAMETERS, "parameters"); + // TODO better way? + CC_TYPE_INPUT_LIST_BOX; + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/keyboard/cc-keyboard-panel.ui"); + gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, input_source_list); + gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, per_window_source); + gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, same_source); gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, special_chars_list); gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, alt_chars_row); gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, compose_row); @@ -195,14 +215,35 @@ cc_keyboard_panel_class_init (CcKeyboardPanelClass *klass) static void cc_keyboard_panel_init (CcKeyboardPanel *self) { + GtkCssProvider *provider; + g_resources_register (cc_keyboard_get_resource ()); gtk_widget_init_template (GTK_WIDGET (self)); + provider = gtk_css_provider_new (); + gtk_css_provider_load_from_data (provider, custom_css, -1, NULL); + + gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), + GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION + 1); + g_object_unref (provider); + + gtk_list_box_set_header_func (self->input_source_list, cc_list_box_update_header_func, NULL, NULL); gtk_list_box_set_header_func (self->special_chars_list, cc_list_box_update_header_func, NULL, NULL); - /* "Type Special Characters" section */ self->input_source_settings = g_settings_new ("org.gnome.desktop.input-sources"); + + /* "Input Source Switching" section */ + g_settings_bind (self->input_source_settings, "per-window", + self->per_window_source, "active", + G_SETTINGS_BIND_DEFAULT); + g_settings_bind (self->input_source_settings, "per-window", + self->same_source, "active", + G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_INVERT_BOOLEAN); + + + /* "Type Special Characters" section */ g_settings_bind_with_mapping (self->input_source_settings, "xkb-options", self->value_alternate_chars, diff --git a/panels/keyboard/cc-keyboard-panel.ui b/panels/keyboard/cc-keyboard-panel.ui index 93360a97ba..b21c5fa8ba 100644 --- a/panels/keyboard/cc-keyboard-panel.ui +++ b/panels/keyboard/cc-keyboard-panel.ui @@ -38,6 +38,103 @@ 18 12 center + + + True + False + 0 + Input Sources + + + + + + + + True + False + + + True + + + + + + + True + False + 0 + Input Source Switching + + + + + + + + True + False + + + True + + + True + + + True + True + False + 0 + True + True + + + + True + 6 + True + Use the _same source for all windows + + + + + + + + + True + + + True + True + False + 0 + True + True + same_source + + + + True + 6 + True + Allow _different sources for each window + + + + + + + + + + True diff --git a/panels/keyboard/keyboard.gresource.xml b/panels/keyboard/keyboard.gresource.xml index 14c05d8a1e..a310f0500d 100644 --- a/panels/keyboard/keyboard.gresource.xml +++ b/panels/keyboard/keyboard.gresource.xml @@ -7,5 +7,8 @@ cc-keyboard-shortcut-dialog.ui cc-keyboard-panel.ui cc-keyboard-shortcut-editor.ui + cc-input-chooser.ui + cc-input-row.ui + cc-input-list-box.ui diff --git a/panels/keyboard/meson.build b/panels/keyboard/meson.build index 8055becf9f..a2ae0263d3 100644 --- a/panels/keyboard/meson.build +++ b/panels/keyboard/meson.build @@ -64,13 +64,21 @@ sources = files( 'cc-keyboard-manager.c', 'cc-keyboard-shortcut-editor.c', 'wm-common.c', - 'keyboard-shortcuts.c' + 'keyboard-shortcuts.c', + 'cc-ibus-utils.c', + 'cc-input-chooser.c', + 'cc-input-row.c', + 'cc-input-source.c', + 'cc-input-source-ibus.c', + 'cc-input-list-box.c', + 'cc-input-source-xkb.c', ) resource_data = files( 'enter-keyboard-shortcut.svg', 'cc-keyboard-panel.ui', 'cc-keyboard-shortcut-editor.ui', + 'cc-input-chooser.ui', ) sources += gnome.compile_resources( @@ -86,6 +94,10 @@ deps = common_deps + [ x11_dep ] +if enable_ibus + deps += ibus_dep +endif + panels_libs += static_library( cappletname, sources: sources, diff --git a/panels/region/cc-region-panel.c b/panels/region/cc-region-panel.c index 1049228a65..7526183c41 100644 --- a/panels/region/cc-region-panel.c +++ b/panels/region/cc-region-panel.c @@ -32,7 +32,6 @@ #include "cc-region-resources.h" #include "cc-language-chooser.h" #include "cc-format-chooser.h" -#include "cc-input-list-box.h" #include "cc-common-language.h" @@ -42,7 +41,6 @@ #include -#define GNOME_DESKTOP_INPUT_SOURCES_DIR "org.gnome.desktop.input-sources" #define GNOME_SYSTEM_LOCALE_DIR "org.gnome.system.locale" #define KEY_REGION "region" @@ -51,11 +49,8 @@ struct _CcRegionPanel { CcPanel parent_instance; - GtkLabel *alt_next_source; GtkLabel *formats_label; GtkListBoxRow *formats_row; - CcInputListBox *input_list; - GtkBox *input_section_box; GtkSizeGroup *input_size_group; GtkToggleButton *login_button; GtkLabel *login_label; @@ -63,15 +58,8 @@ struct _CcRegionPanel { GtkListBox *language_list; GtkListBoxRow *language_row; GtkFrame *language_section_frame; - GtkLabel *next_source; - GtkLabel *next_source_label; - GtkButton *options_button; - GtkRadioButton *per_window_source; - GtkLabel *previous_source; - GtkLabel *previous_source_label; GtkButton *restart_button; GtkRevealer *restart_revealer; - GtkRadioButton *same_source; gboolean login; gboolean login_auto_apply; @@ -575,96 +563,6 @@ setup_language_section (CcRegionPanel *self) update_region_from_setting (self); } -static void -update_shortcut_label (GtkLabel *label, - const gchar *value) -{ - g_autofree gchar *text = NULL; - guint accel_key; - g_autofree guint *keycode = NULL; - GdkModifierType mods; - - if (value == NULL || *value == '\0') { - gtk_widget_hide (GTK_WIDGET (label)); - return; - } - - gtk_accelerator_parse_with_keycode (value, &accel_key, &keycode, &mods); - if (accel_key == 0 && keycode == NULL && mods == 0) { - g_warning ("Failed to parse keyboard shortcut: '%s'", value); - gtk_widget_hide (GTK_WIDGET (label)); - return; - } - - text = gtk_accelerator_get_label_with_keycode (gtk_widget_get_display (GTK_WIDGET (label)), accel_key, *keycode, mods); - gtk_label_set_text (label, text); -} - -static void -update_shortcuts (CcRegionPanel *self) -{ - g_auto(GStrv) previous = NULL; - g_auto(GStrv) next = NULL; - g_autofree gchar *previous_shortcut = NULL; - g_autoptr(GSettings) settings = NULL; - - settings = g_settings_new ("org.gnome.desktop.wm.keybindings"); - - previous = g_settings_get_strv (settings, "switch-input-source-backward"); - next = g_settings_get_strv (settings, "switch-input-source"); - - previous_shortcut = g_strdup (previous[0]); - - update_shortcut_label (self->previous_source, previous_shortcut); - update_shortcut_label (self->next_source, next[0]); -} - -static void -update_modifiers_shortcut (CcRegionPanel *self) -{ - g_auto(GStrv) options = NULL; - gchar **p; - g_autoptr(GSettings) settings = NULL; - g_autoptr(GnomeXkbInfo) xkb_info = NULL; - const gchar *text; - - xkb_info = gnome_xkb_info_new (); - settings = g_settings_new ("org.gnome.desktop.input-sources"); - options = g_settings_get_strv (settings, "xkb-options"); - - for (p = options; p && *p; ++p) - if (g_str_has_prefix (*p, "grp:")) - break; - - if (p && *p) { - text = gnome_xkb_info_description_for_option (xkb_info, "grp", *p); - gtk_label_set_text (self->alt_next_source, text); - } else { - gtk_widget_hide (GTK_WIDGET (self->alt_next_source)); - } -} - -static void -setup_input_shortcuts (CcRegionPanel *self) -{ - GSettings *input_settings = g_settings_new (GNOME_DESKTOP_INPUT_SOURCES_DIR); - - g_object_bind_property (self->previous_source, "visible", - self->previous_source_label, "visible", - G_BINDING_DEFAULT); - g_object_bind_property (self->next_source, "visible", - self->next_source_label, "visible", - G_BINDING_DEFAULT); - - g_settings_bind (input_settings, "per-window", - self->per_window_source, "active", - G_SETTINGS_BIND_DEFAULT); - g_settings_bind (input_settings, "per-window", - self->same_source, "active", - G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_INVERT_BOOLEAN); - -} - static void on_localed_properties_changed (CcRegionPanel *self, GVariant *changed_properties, @@ -758,7 +656,6 @@ localed_proxy_ready (GObject *source, } self->localed = proxy; - cc_input_list_box_set_localed (self->input_list, self->localed); gtk_widget_set_sensitive (GTK_WIDGET (self->login_button), TRUE); @@ -780,7 +677,6 @@ login_changed (CcRegionPanel *self) g_permission_get_can_acquire (self->permission)); /* FIXME: insensitive doesn't look quite right for this */ gtk_widget_set_sensitive (GTK_WIDGET (self->language_section_frame), !self->login || can_acquire); - gtk_widget_set_sensitive (GTK_WIDGET (self->input_section_box), !self->login || can_acquire); update_language_label (self); } @@ -798,7 +694,6 @@ set_login_button_visibility (CcRegionPanel *self) g_object_get (self->user_manager, "has-multiple-users", &has_multiple_users, NULL); self->login_auto_apply = !has_multiple_users && g_permission_get_allowed (self->permission); - cc_input_list_box_set_login_auto_apply (self->input_list, self->login_auto_apply); gtk_widget_set_visible (GTK_WIDGET (self->login_button), !self->login_auto_apply); g_signal_handlers_disconnect_by_func (self->user_manager, set_login_button_visibility, self); @@ -817,7 +712,6 @@ setup_login_button (CcRegionPanel *self) error->message); return; } - cc_input_list_box_set_permission (self->input_list, self->permission); bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL); g_dbus_proxy_new (bus, @@ -879,30 +773,17 @@ cc_region_panel_class_init (CcRegionPanelClass * klass) object_class->constructed = cc_region_panel_constructed; object_class->finalize = cc_region_panel_finalize; - // TODO better way? - CC_TYPE_INPUT_LIST_BOX; - gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/region/cc-region-panel.ui"); - gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, alt_next_source); gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, formats_label); gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, formats_row); - gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, input_list); - gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, input_section_box); gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, login_label); gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, language_label); gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, language_list); gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, language_row); gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, language_section_frame); - gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, next_source); - gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, next_source_label); - gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, options_button); - gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, per_window_source); - gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, previous_source); - gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, previous_source_label); gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, restart_button); gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, restart_revealer); - gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, same_source); gtk_widget_class_bind_template_callback (widget_class, restart_now); } @@ -930,11 +811,8 @@ cc_region_panel_init (CcRegionPanel *self) setup_login_button (self); setup_language_section (self); - setup_input_shortcuts (self); - update_shortcuts (self); - update_modifiers_shortcut (self); needs_restart_file = get_needs_restart_file (); if (g_file_query_exists (needs_restart_file, NULL)) set_restart_notification_visible (self, NULL, TRUE); -} \ No newline at end of file +} diff --git a/panels/region/cc-region-panel.ui b/panels/region/cc-region-panel.ui index d7c70aa7c1..801f5357cf 100644 --- a/panels/region/cc-region-panel.ui +++ b/panels/region/cc-region-panel.ui @@ -167,90 +167,6 @@ - - - True - False - vertical - True - - - True - False - 6 - 12 - - - True - False - vertical - 6 - - - True - False - start - Input Sources - - - - - - - - - - - True - False - 0 - Choose keyboard layouts or input methods. - True - - - - - - - - True - True - True - options_popover - True - end - start - - - True - False - emblem-system-symbolic - - - - - - - - - - True - False - 0 - in - - - True - - - - - - end @@ -270,201 +186,4 @@ - - False - 12 - - - True - False - vertical - 2 - - - True - False - 6 - 6 - 6 - 6 - 6 - - - True - False - 6 - Input Source Options - 6 - - - - - - 0 - 0 - 2 - 1 - - - - - Use the _same source for all windows - True - True - False - True - 0 - True - True - - - 0 - 1 - 2 - 1 - - - - - Allow _different sources for each window - True - True - False - True - 0 - True - True - same_source - - - 0 - 2 - 2 - 1 - - - - - True - False - 12 - 6 - 0 - Keyboard Shortcuts - - - - - - 0 - 3 - 2 - 1 - - - - - True - False - 0 - start - Previous source - - - - 0 - 4 - 1 - 1 - - - - - True - False - 0 - True - Super+Shift+Space - - - 1 - 4 - 1 - 1 - - - - - True - False - 0 - start - Next source - - - - 0 - 5 - 1 - 1 - - - - - True - False - 0 - True - Super+Space - - - 1 - 5 - 1 - 1 - - - - - True - False - 0 - True - Left+Right Alt - - - 1 - 6 - 1 - 1 - - - - - True - False - 12 - True - 40 - These keyboard shortcuts can be changed in the keyboard settings - - - - 0 - 7 - 2 - 1 - - - - - - - - + \ No newline at end of file diff --git a/panels/region/meson.build b/panels/region/meson.build index ca9af8ae1a..68b7f000e6 100644 --- a/panels/region/meson.build +++ b/panels/region/meson.build @@ -21,19 +21,11 @@ sources = files( 'cc-region-panel.c', 'cc-format-chooser.c', 'cc-format-preview.c', - 'cc-ibus-utils.c', - 'cc-input-chooser.c', - 'cc-input-row.c', - 'cc-input-source.c', - 'cc-input-source-ibus.c', - 'cc-input-list-box.c', - 'cc-input-source-xkb.c', ) resource_data = files( 'cc-format-chooser.ui', 'cc-format-preview.ui', - 'cc-input-chooser.ui', 'cc-region-panel.ui', 'view-layout-symbolic.svg', ) diff --git a/panels/region/region.gresource.xml b/panels/region/region.gresource.xml index 61d82998b9..b1d72b2e29 100644 --- a/panels/region/region.gresource.xml +++ b/panels/region/region.gresource.xml @@ -2,9 +2,6 @@ cc-format-chooser.ui - cc-input-chooser.ui - cc-input-row.ui - cc-input-list-box.ui cc-region-panel.ui cc-format-preview.ui -- GitLab From a89b83c9ecfecfb9d2d48dd8ae9364de41006d0d Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 24 Jul 2020 10:03:33 -0700 Subject: [PATCH 05/13] keyboard: Use HdyClamp to expand similarly to other panels --- panels/keyboard/cc-keyboard-panel.ui | 29 +++++++++++++--------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/panels/keyboard/cc-keyboard-panel.ui b/panels/keyboard/cc-keyboard-panel.ui index b21c5fa8ba..c182d0c92e 100644 --- a/panels/keyboard/cc-keyboard-panel.ui +++ b/panels/keyboard/cc-keyboard-panel.ui @@ -13,31 +13,28 @@ False True - + True - False - vertical + True + True + True + never + True + True - + True - True - True - True - never - True - True - 350 + 32 + 32 + 12 + 12 True False vertical - 32 - 32 - 18 - 18 12 - center + True True -- GitLab From f1e8f9b364d9e1ca3528320e9a96ddbcaa50e083 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 24 Jul 2020 11:03:15 -0700 Subject: [PATCH 06/13] keyboard: Add margins between sections, like other panels --- panels/keyboard/cc-keyboard-panel.ui | 3 +++ 1 file changed, 3 insertions(+) diff --git a/panels/keyboard/cc-keyboard-panel.ui b/panels/keyboard/cc-keyboard-panel.ui index c182d0c92e..0e7873d404 100644 --- a/panels/keyboard/cc-keyboard-panel.ui +++ b/panels/keyboard/cc-keyboard-panel.ui @@ -50,6 +50,7 @@ True False + 20 True @@ -72,6 +73,7 @@ True False + 20 True @@ -147,6 +149,7 @@ True False + 20 True -- GitLab From e39a2916f32049be5651d8e5d289d469d31c096b Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 24 Jul 2020 11:31:52 -0700 Subject: [PATCH 07/13] keyboard: change margins of CcInputRow to better fit keyboard panel --- panels/keyboard/cc-input-row.ui | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/panels/keyboard/cc-input-row.ui b/panels/keyboard/cc-input-row.ui index 4021175c2d..9342ebb083 100644 --- a/panels/keyboard/cc-input-row.ui +++ b/panels/keyboard/cc-input-row.ui @@ -16,8 +16,8 @@ True 50 - 4 - 12 + 12 + 6 12 -- GitLab From 9366de52cd700aa331df82ddb308d0dc99a7794c Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 31 Jul 2020 13:32:04 -0700 Subject: [PATCH 08/13] region: "Language" and "Format" headers and descriptions --- panels/region/cc-region-panel.c | 10 ++++- panels/region/cc-region-panel.ui | 64 ++++++++++++++++++++++++++++++-- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/panels/region/cc-region-panel.c b/panels/region/cc-region-panel.c index 7526183c41..7fe03ee649 100644 --- a/panels/region/cc-region-panel.c +++ b/panels/region/cc-region-panel.c @@ -50,6 +50,7 @@ struct _CcRegionPanel { CcPanel parent_instance; GtkLabel *formats_label; + GtkListBox *formats_list; GtkListBoxRow *formats_row; GtkSizeGroup *input_size_group; GtkToggleButton *login_button; @@ -551,14 +552,18 @@ setup_language_section (CcRegionPanel *self) g_signal_connect_object (self->locale_settings, "changed::" KEY_REGION, G_CALLBACK (update_region_from_setting), self, G_CONNECT_SWAPPED); - gtk_list_box_set_selection_mode (self->language_list, - GTK_SELECTION_NONE); gtk_list_box_set_header_func (self->language_list, cc_list_box_update_header_func, NULL, NULL); g_signal_connect_object (self->language_list, "row-activated", G_CALLBACK (activate_language_row), self, G_CONNECT_SWAPPED); + gtk_list_box_set_header_func (self->formats_list, + cc_list_box_update_header_func, + NULL, NULL); + g_signal_connect_object (self->formats_list, "row-activated", + G_CALLBACK (activate_language_row), self, G_CONNECT_SWAPPED); + update_language_from_user (self); update_region_from_setting (self); } @@ -776,6 +781,7 @@ cc_region_panel_class_init (CcRegionPanelClass * klass) gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/region/cc-region-panel.ui"); gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, formats_label); + gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, formats_list); gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, formats_row); gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, login_label); gtk_widget_class_bind_template_child (widget_class, CcRegionPanel, language_label); diff --git a/panels/region/cc-region-panel.ui b/panels/region/cc-region-panel.ui index 801f5357cf..9fb6ebdb24 100644 --- a/panels/region/cc-region-panel.ui +++ b/panels/region/cc-region-panel.ui @@ -26,6 +26,28 @@ vertical 12 True + + + True + False + 0 + Language + + + + + + + + True + False + 0 + The language used for text in windows and web pages. + + + True @@ -36,6 +58,7 @@ True True + none True @@ -124,6 +147,42 @@ + + + + + + + True + False + 0 + Formats + + + + + + + + True + False + 0 + The format used for numbers, dates, and currencies. + + + + + + True + False + in + + + True + True + none True @@ -162,9 +221,6 @@ - - - @@ -186,4 +242,4 @@ - \ No newline at end of file + -- GitLab From a19c7c2e658c100e22bae4c426c0fa1c1b42067d Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Mon, 14 Sep 2020 10:10:55 -0700 Subject: [PATCH 09/13] keyboard: Change wording for switch input source --- panels/keyboard/cc-keyboard-panel.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panels/keyboard/cc-keyboard-panel.ui b/panels/keyboard/cc-keyboard-panel.ui index 0e7873d404..4246493d4e 100644 --- a/panels/keyboard/cc-keyboard-panel.ui +++ b/panels/keyboard/cc-keyboard-panel.ui @@ -123,7 +123,7 @@ True 6 True - Allow _different sources for each window + Switch input sources _individually for each window -- GitLab From a7d526f70babc939313751aff3bdfc0979199230 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Mon, 14 Sep 2020 11:09:40 -0700 Subject: [PATCH 10/13] keyboard: Display shortcut for switching input source --- panels/keyboard/cc-keyboard-panel.c | 30 +++++++++++++++++++++++++++- panels/keyboard/cc-keyboard-panel.ui | 15 ++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/panels/keyboard/cc-keyboard-panel.c b/panels/keyboard/cc-keyboard-panel.c index a2bb99b1cb..e3561ec60f 100644 --- a/panels/keyboard/cc-keyboard-panel.c +++ b/panels/keyboard/cc-keyboard-panel.c @@ -43,6 +43,8 @@ struct _CcKeyboardPanel GtkRadioButton *per_window_source; GtkRadioButton *same_source; + GtkLabel *value_input_switch; + GSettings *keybindings_settings; /* "Type Special Characters" section */ CcXkbModifierDialog *alt_chars_dialog; @@ -175,6 +177,7 @@ cc_keyboard_panel_finalize (GObject *object) CcKeyboardPanel *self = CC_KEYBOARD_PANEL (object); g_clear_object (&self->input_source_settings); + g_clear_object (&self->keybindings_settings); G_OBJECT_CLASS (cc_keyboard_panel_parent_class)->finalize (object); } @@ -206,12 +209,32 @@ cc_keyboard_panel_class_init (CcKeyboardPanelClass *klass) gtk_widget_class_bind_template_child (widget_class, CcKeyboardPanel, compose_row); 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, common_shortcuts_row); gtk_widget_class_bind_template_callback (widget_class, special_chars_activated); gtk_widget_class_bind_template_callback (widget_class, keyboard_shortcuts_activated); } +static gboolean +translate_switch_input_source (GValue *value, + GVariant *variant, + gpointer user_data) +{ + g_autofree const gchar **strv = NULL; + g_autofree gchar *label = NULL; + CcKeyCombo combo = { 0 }; + + strv = g_variant_get_strv (variant, NULL); + + gtk_accelerator_parse (strv[0] ? strv[0] : "", &combo.keyval, &combo.mask); + label = convert_keysym_state_to_string (&combo); + + g_value_set_string (value, label); + + return TRUE; +} + static void cc_keyboard_panel_init (CcKeyboardPanel *self) { @@ -241,7 +264,12 @@ cc_keyboard_panel_init (CcKeyboardPanel *self) g_settings_bind (self->input_source_settings, "per-window", self->same_source, "active", G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_INVERT_BOOLEAN); - + self->keybindings_settings = g_settings_new ("org.gnome.desktop.wm.keybindings"); + g_settings_bind_with_mapping (self->keybindings_settings, "switch-input-source", + self->value_input_switch, "label", + G_SETTINGS_BIND_GET, + translate_switch_input_source, + NULL, NULL, NULL); /* "Type Special Characters" section */ g_settings_bind_with_mapping (self->input_source_settings, diff --git a/panels/keyboard/cc-keyboard-panel.ui b/panels/keyboard/cc-keyboard-panel.ui index 4246493d4e..532b53a011 100644 --- a/panels/keyboard/cc-keyboard-panel.ui +++ b/panels/keyboard/cc-keyboard-panel.ui @@ -130,6 +130,21 @@ + + + True + True + False + Keyboard Shortcut + This can be changed in Customize Shortcuts + + + True + True + + + + -- GitLab From 959d530c443d23b068387820929e4789d71bca2e Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Thu, 12 Nov 2020 12:10:06 -0800 Subject: [PATCH 11/13] keyboard: Use HdyActionRow for shortcut/category --- panels/keyboard/cc-keyboard-shortcut-dialog.c | 44 ++++--------- panels/keyboard/cc-keyboard-shortcut-row.c | 8 +-- panels/keyboard/cc-keyboard-shortcut-row.h | 3 +- panels/keyboard/cc-keyboard-shortcut-row.ui | 61 +++++++------------ 4 files changed, 37 insertions(+), 79 deletions(-) diff --git a/panels/keyboard/cc-keyboard-shortcut-dialog.c b/panels/keyboard/cc-keyboard-shortcut-dialog.c index c41787eb3e..a6814a3b2d 100644 --- a/panels/keyboard/cc-keyboard-shortcut-dialog.c +++ b/panels/keyboard/cc-keyboard-shortcut-dialog.c @@ -25,7 +25,6 @@ */ #include -#define HANDY_USE_UNSTABLE_API #include #include "cc-keyboard-shortcut-dialog.h" @@ -136,42 +135,21 @@ add_section (CcKeyboardShortcutDialog *self, const gchar *section_id, const gchar *section_title) { - GtkWidget *icon, *modified_label, *label, *box; - GtkListBoxRow *row; + GtkWidget *icon, *modified_label, *row; - icon = g_object_new (GTK_TYPE_IMAGE, - "visible", 1, - "icon_name", "go-next-symbolic", - NULL); + icon = gtk_image_new_from_icon_name ("go-next-symbolic", GTK_ICON_SIZE_BUTTON); gtk_style_context_add_class (gtk_widget_get_style_context (icon), "dim-label"); - modified_label = g_object_new (GTK_TYPE_LABEL, - "visible", 1, - NULL); + modified_label = gtk_label_new (NULL); gtk_style_context_add_class (gtk_widget_get_style_context (modified_label), "dim-label"); - label = g_object_new (GTK_TYPE_LABEL, - "visible", 1, - "label", _(section_title), - NULL); - gtk_style_context_add_class (gtk_widget_get_style_context (label), "row-label"); - - box = g_object_new (GTK_TYPE_BOX, - "visible", 1, - "spacing", 8, - "margin_left", 12, - "margin_right", 12, - "margin_top", 8, - "margin_bottom", 8, - NULL); - gtk_container_add (GTK_CONTAINER (box), label); - gtk_box_pack_end (GTK_BOX (box), icon, FALSE, FALSE, 0); - gtk_box_pack_end (GTK_BOX (box), modified_label, FALSE, FALSE, 0); - - row = g_object_new (GTK_TYPE_LIST_BOX_ROW, - "visible", 1, - NULL); - gtk_container_add (GTK_CONTAINER (row), box); + row = hdy_action_row_new (); + gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), TRUE); + hdy_preferences_row_set_title (HDY_PREFERENCES_ROW (row), _(section_title)); + gtk_container_add (GTK_CONTAINER (row), modified_label); + gtk_container_add (GTK_CONTAINER (row), icon); + + gtk_widget_show_all (GTK_WIDGET (row)); g_object_set_data_full (G_OBJECT (row), "data", @@ -181,7 +159,7 @@ add_section (CcKeyboardShortcutDialog *self, g_hash_table_insert (self->sections, g_strdup (section_id), row); gtk_container_add (GTK_CONTAINER (self->section_listbox), GTK_WIDGET (row)); - return row; + return GTK_LIST_BOX_ROW (row); } static void diff --git a/panels/keyboard/cc-keyboard-shortcut-row.c b/panels/keyboard/cc-keyboard-shortcut-row.c index 6bb91d3caa..f8b9018904 100644 --- a/panels/keyboard/cc-keyboard-shortcut-row.c +++ b/panels/keyboard/cc-keyboard-shortcut-row.c @@ -24,10 +24,9 @@ struct _CcKeyboardShortcutRow { - GtkListBoxRow parent_instance; + HdyActionRow parent_instance; GtkLabel *accelerator_label; - GtkLabel *description_label; GtkButton *reset_button; CcKeyboardItem *item; @@ -35,7 +34,7 @@ struct _CcKeyboardShortcutRow CcKeyboardShortcutEditor *shortcut_editor; }; -G_DEFINE_TYPE (CcKeyboardShortcutRow, cc_keyboard_shortcut_row, GTK_TYPE_LIST_BOX_ROW) +G_DEFINE_TYPE (CcKeyboardShortcutRow, cc_keyboard_shortcut_row, HDY_TYPE_ACTION_ROW) static void reset_shortcut_cb (CcKeyboardShortcutRow *self) @@ -50,7 +49,6 @@ cc_keyboard_shortcut_row_class_init (CcKeyboardShortcutRowClass *klass) gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/keyboard/cc-keyboard-shortcut-row.ui"); - gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutRow, description_label); gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutRow, accelerator_label); gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutRow, reset_button); @@ -115,7 +113,7 @@ cc_keyboard_shortcut_row_new (CcKeyboardItem *item, self->manager = manager; self->shortcut_editor = shortcut_editor; - gtk_label_set_text (self->description_label, cc_keyboard_item_get_description (item)); + hdy_preferences_row_set_title (HDY_PREFERENCES_ROW (self), cc_keyboard_item_get_description (item)); g_object_bind_property_full (item, "key-combos", diff --git a/panels/keyboard/cc-keyboard-shortcut-row.h b/panels/keyboard/cc-keyboard-shortcut-row.h index d11143f737..919d2acdc4 100644 --- a/panels/keyboard/cc-keyboard-shortcut-row.h +++ b/panels/keyboard/cc-keyboard-shortcut-row.h @@ -21,6 +21,7 @@ #pragma once #include +#include #include "cc-keyboard-item.h" #include "cc-keyboard-manager.h" #include "cc-keyboard-shortcut-editor.h" @@ -29,7 +30,7 @@ G_BEGIN_DECLS #define CC_TYPE_KEYBOARD_SHORTCUT_ROW (cc_keyboard_shortcut_row_get_type()) -G_DECLARE_FINAL_TYPE (CcKeyboardShortcutRow, cc_keyboard_shortcut_row, CC, KEYBOARD_SHORTCUT_ROW, GtkListBoxRow) +G_DECLARE_FINAL_TYPE (CcKeyboardShortcutRow, cc_keyboard_shortcut_row, CC, KEYBOARD_SHORTCUT_ROW, HdyActionRow) CcKeyboardShortcutRow *cc_keyboard_shortcut_row_new (CcKeyboardItem*, CcKeyboardManager*, CcKeyboardShortcutEditor*, GtkSizeGroup*); diff --git a/panels/keyboard/cc-keyboard-shortcut-row.ui b/panels/keyboard/cc-keyboard-shortcut-row.ui index 87a52d77a0..7a79db6d76 100644 --- a/panels/keyboard/cc-keyboard-shortcut-row.ui +++ b/panels/keyboard/cc-keyboard-shortcut-row.ui @@ -1,57 +1,38 @@ -