summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Nocera <hadess@hadess.net>2018-03-29 13:33:15 +0200
committerGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>2018-06-21 17:49:37 +0000
commitffe057adc8b0d84b8a53ad1c4701dce157efb3f4 (patch)
treeaa54cd1837820479985d40b6373b716e8849fa32
parent7512860abc0830a21fa1d9abbb16710a0f305e18 (diff)
downloadgnome-control-center-wip/alt-chars-key.tar.gz
keyboard: Add "Alternate Characters Key" configurationwip/alt-chars-key
This adds an entry to select the "Level 3" selection key, which is usually Right Alt (or Alt-Gr on a majority of keyboards). Mockups at: https://raw.githubusercontent.com/gnome-design-team/gnome-mockups/master/system-settings/keyboard/keyboard-wires.png However, we replaced the "Left Ctrl" key option with a "Menu key" option, as "Left Ctrl" isn't a possible XKB option for the level3 key.
-rw-r--r--panels/keyboard/alt-chars-key.ui177
-rw-r--r--panels/keyboard/cc-keyboard-panel.c139
-rw-r--r--panels/keyboard/gnome-keyboard-panel.ui96
-rw-r--r--panels/keyboard/keyboard.gresource.xml1
4 files changed, 412 insertions, 1 deletions
diff --git a/panels/keyboard/alt-chars-key.ui b/panels/keyboard/alt-chars-key.ui
new file mode 100644
index 000000000..c6f7eeb30
--- /dev/null
+++ b/panels/keyboard/alt-chars-key.ui
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.0 -->
+<interface>
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="alt_chars_key_dialog">
+ <property name="can_focus">False</property>
+ <property name="resizable">False</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">12</property>
+ <property name="margin_right">12</property>
+ <property name="margin_top">12</property>
+ <property name="margin_bottom">12</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_top">12</property>
+ <property name="margin_bottom">12</property>
+ <property name="label" translatable="yes">The alternate characters key can be used to enter additional characters. These are sometimes printed as a third-option on your keyboard.</property>
+ <property name="wrap">True</property>
+ <property name="width_chars">50</property>
+ <property name="max_width_chars">50</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+ <property name="column_homogeneous">True</property>
+ <child>
+ <object class="GtkRadioButton" id="radiobutton_leftalt">
+ <property name="label" translatable="yes">Left Alt</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="radiobutton_rightalt">
+ <property name="label" translatable="yes">Right Alt</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">radiobutton_leftalt</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="radiobutton_leftsuper">
+ <property name="label" translatable="yes">Left Super</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">radiobutton_leftalt</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="radiobutton_rightsuper">
+ <property name="label" translatable="yes">Right Super</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">radiobutton_leftalt</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="radiobutton_menukey">
+ <property name="label" translatable="yes">Menu key</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">radiobutton_leftalt</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="radiobutton_rightctrl">
+ <property name="label" translatable="yes">Right Ctrl</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">radiobutton_leftalt</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="titlebar">
+ <placeholder/>
+ </child>
+ <child internal-child="headerbar">
+ <object class="GtkHeaderBar">
+ <property name="can_focus">False</property>
+ <property name="show_close_button">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/panels/keyboard/cc-keyboard-panel.c b/panels/keyboard/cc-keyboard-panel.c
index f5dd6e822..0f9a72021 100644
--- a/panels/keyboard/cc-keyboard-panel.c
+++ b/panels/keyboard/cc-keyboard-panel.c
@@ -57,6 +57,10 @@ struct _CcKeyboardPanel
GtkListBoxRow *add_shortcut_row;
GtkSizeGroup *accelerator_sizegroup;
+ /* Alternate characters key */
+ GSettings *input_source_settings;
+ GtkWidget *value_alternate_chars;
+
/* Custom shortcut dialog */
GtkWidget *shortcut_editor;
@@ -77,6 +81,21 @@ static const gchar* custom_css =
" padding: 0;"
"}";
+
+#define DEFAULT_LV3_OPTION 5
+static struct {
+ const char *xkb_option;
+ const char *label;
+ const char *widget_name;
+} lv3_xkb_options[] = {
+ { "lv3:switch", NC_("keyboard key", "Right Ctrl"), "radiobutton_rightctrl" },
+ { "lv3:menu_switch", NC_("keyboard key", "Menu Key"), "radiobutton_menukey" },
+ { "lv3:lwin_switch", NC_("keyboard key", "Left Super"), "radiobutton_leftsuper" },
+ { "lv3:rwin_switch", NC_("keyboard key", "Right Super"), "radiobutton_rightsuper" },
+ { "lv3:lalt_switch", NC_("keyboard key", "Left Alt"), "radiobutton_leftalt" },
+ { "lv3:ralt_switch", NC_("keyboard key", "Right Alt"), "radiobutton_rightalt" },
+};
+
/* RowData functions */
static RowData *
row_data_new (CcKeyboardItem *item,
@@ -261,7 +280,7 @@ add_item (CcKeyboardPanel *self,
"binding",
label,
"label",
- G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE,
+ G_SETTINGS_BIND_GET | G_BINDING_SYNC_CREATE,
transform_binding_to_accel,
NULL, NULL, NULL);
@@ -595,6 +614,113 @@ shortcut_row_activated (GtkWidget *button,
}
static void
+active_lv3_changed (GtkToggleButton *button,
+ CcKeyboardPanel *self)
+{
+ char **options;
+ GPtrArray *array;
+ guint i;
+ gboolean found;
+
+ if (!gtk_toggle_button_get_active (button))
+ return;
+
+ /* Either replace the existing "lv3:" option in the string
+ * array, or add the option at the end */
+ array = g_ptr_array_new_with_free_func (g_free);
+ options = g_settings_get_strv (self->input_source_settings, "xkb-options");
+ found = FALSE;
+ for (i = 0; options != NULL && options[i] != NULL; i++) {
+ if (g_str_has_prefix (options[i], "lv3:")) {
+ found = TRUE;
+ g_ptr_array_add (array, g_strdup ((char *) g_object_get_data (G_OBJECT (button), "option")));
+ } else {
+ g_ptr_array_add (array, g_strdup (options[i]));
+ }
+ }
+ g_strfreev (options);
+
+ if (!found)
+ g_ptr_array_add (array, g_strdup ((char *) g_object_get_data (G_OBJECT (button), "option")));
+
+ g_ptr_array_add (array, NULL);
+
+ g_settings_set_strv (self->input_source_settings, "xkb-options",
+ (const char **) array->pdata);
+ g_ptr_array_free (array, TRUE);
+}
+
+static void
+alternate_chars_activated (GtkWidget *button,
+ GtkListBoxRow *row,
+ CcKeyboardPanel *self)
+{
+ GtkBuilder *builder;
+ GtkWidget *dialog;
+ guint i;
+ const char *current_lv3_widget;
+
+ current_lv3_widget = g_object_get_data (G_OBJECT (self->value_alternate_chars), "lv3_widget_name");
+ builder = gtk_builder_new_from_resource ("/org/gnome/control-center/keyboard/alt-chars-key.ui");
+ for (i = 0; i < G_N_ELEMENTS(lv3_xkb_options); i++) {
+ GObject *label;
+
+ label = gtk_builder_get_object (builder, lv3_xkb_options[i].widget_name);
+ g_object_set_data (label, "option", (gpointer) lv3_xkb_options[i].xkb_option);
+ if (g_str_equal (current_lv3_widget, lv3_xkb_options[i].widget_name))
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (label), TRUE);
+
+ g_signal_connect (label, "toggled", G_CALLBACK (active_lv3_changed), self);
+ }
+ dialog = GTK_WIDGET (gtk_builder_get_object (builder, "alt_chars_key_dialog"));
+ gtk_window_set_title (GTK_WINDOW (dialog), _("Alternate Characters Key"));
+ gtk_window_set_transient_for (GTK_WINDOW (dialog),
+ GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (self)))));
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ g_object_unref (builder);
+}
+
+static gboolean
+transform_binding_to_alt_chars (GValue *value,
+ GVariant *variant,
+ gpointer user_data)
+{
+ GObject *value_alternate_chars = user_data;
+ const char **items;
+ guint i;
+
+ items = g_variant_get_strv (variant, NULL);
+ if (!items)
+ goto bail;
+
+ for (i = 0; items[i] != NULL; i++) {
+ guint j;
+ if (!g_str_has_prefix (items[i], "lv3:"))
+ continue;
+
+ for (j = 0; j < G_N_ELEMENTS (lv3_xkb_options); j++) {
+ if (g_str_equal (items[i], lv3_xkb_options[j].xkb_option)) {
+ g_value_set_string (value,
+ g_dpgettext2 (NULL, "keyboard key", lv3_xkb_options[j].label));
+ g_object_set_data (value_alternate_chars,
+ "lv3_widget_name",
+ (gpointer) lv3_xkb_options[j].widget_name);
+ return TRUE;
+ }
+ }
+ }
+
+bail:
+ g_value_set_string (value,
+ g_dpgettext2 (NULL, "keyboard key", lv3_xkb_options[DEFAULT_LV3_OPTION].label));
+ g_object_set_data (value_alternate_chars,
+ "lv3_widget_name",
+ (gpointer) lv3_xkb_options[DEFAULT_LV3_OPTION].widget_name);
+ return TRUE;
+}
+
+static void
cc_keyboard_panel_set_property (GObject *object,
guint property_id,
const GValue *value,
@@ -624,6 +750,7 @@ cc_keyboard_panel_finalize (GObject *object)
g_clear_pointer (&self->pictures_regex, g_regex_unref);
g_clear_object (&self->accelerator_sizegroup);
+ g_clear_object (&self->input_source_settings);
cc_keyboard_option_clear_all ();
@@ -680,9 +807,11 @@ cc_keyboard_panel_class_init (CcKeyboardPanelClass *klass)
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, value_alternate_chars);
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);
}
static void
@@ -704,6 +833,14 @@ cc_keyboard_panel_init (CcKeyboardPanel *self)
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, "xkb-options",
+ self->value_alternate_chars, "label",
+ G_SETTINGS_BIND_GET,
+ transform_binding_to_alt_chars,
+ NULL, self->value_alternate_chars, NULL);
+
/* Shortcut manager */
self->manager = cc_keyboard_manager_new ();
diff --git a/panels/keyboard/gnome-keyboard-panel.ui b/panels/keyboard/gnome-keyboard-panel.ui
index d5924f5d4..f17706edb 100644
--- a/panels/keyboard/gnome-keyboard-panel.ui
+++ b/panels/keyboard/gnome-keyboard-panel.ui
@@ -53,6 +53,102 @@
<property name="margin_right">18</property>
<property name="spacing">12</property>
<property name="halign">center</property>
+ <child>
+ <object class="GtkFrame">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkListBox" id="alternate_chars_listbox">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="selection-mode">none</property>
+ <property name="width-request">250</property>
+ <signal name="row-activated" handler="alternate_chars_activated" object="CcKeyboardPanel" swapped="no" />
+ <child>
+ <object class="GtkListBoxRow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="expand">True</property>
+ <property name="border_width">6</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="heading_alternate_chars">
+ <property name="hexpand">True</property>
+ <property name="expand">True</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_start">12</property>
+ <property name="margin_end">12</property>
+ <property name="margin_top">6</property>
+ <property name="margin_bottom">0</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Alternate Characters Key</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">value_alternate_chars</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="subtitle_alternate_chars">
+ <property name="hexpand">True</property>
+ <property name="expand">True</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_start">12</property>
+ <property name="margin_end">12</property>
+ <property name="margin_top">0</property>
+ <property name="margin_bottom">6</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Hold down and type to enter different characters</property>
+ <property name="use_underline">False</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="value_alternate_chars">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="margin_start">12</property>
+ <property name="margin_end">12</property>
+ <property name="margin_top">12</property>
+ <property name="margin_bottom">12</property>
+ <property name="label" translatable="no">Right Alt</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
diff --git a/panels/keyboard/keyboard.gresource.xml b/panels/keyboard/keyboard.gresource.xml
index effbe913a..d443c8240 100644
--- a/panels/keyboard/keyboard.gresource.xml
+++ b/panels/keyboard/keyboard.gresource.xml
@@ -4,5 +4,6 @@
<file preprocess="xml-stripblanks">enter-keyboard-shortcut.svg</file>
<file preprocess="xml-stripblanks">gnome-keyboard-panel.ui</file>
<file preprocess="xml-stripblanks">shortcut-editor.ui</file>
+ <file preprocess="xml-stripblanks">alt-chars-key.ui</file>
</gresource>
</gresources>