[gnome-control-center/wip/alt-chars-key: 388/388] keyboard: Add "Alternate Characters Key" configuration



commit dc3bce5226cecb2bc393457b4cf0260143d82a98
Author: Bastien Nocera <hadess hadess net>
Date:   Thu Mar 29 13:33:15 2018 +0200

    keyboard: Add "Alternate Characters Key" configuration
    
    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.

 panels/keyboard/alt-chars-key.ui       | 177 +++++++++++++++++++++++++++++++++
 panels/keyboard/cc-keyboard-panel.c    | 139 +++++++++++++++++++++++++-
 panels/keyboard/cc-keyboard-panel.ui   |  96 ++++++++++++++++++
 panels/keyboard/keyboard.gresource.xml |   1 +
 4 files changed, 412 insertions(+), 1 deletion(-)
---
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 bb2ed69e0..8029f3b76 100644
--- a/panels/keyboard/cc-keyboard-panel.c
+++ b/panels/keyboard/cc-keyboard-panel.c
@@ -58,6 +58,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;
 
@@ -78,6 +82,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,
@@ -265,7 +284,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);
 
@@ -599,6 +618,113 @@ shortcut_row_activated (GtkWidget       *button,
   gtk_widget_show (self->shortcut_editor);
 }
 
+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,
@@ -629,6 +755,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 ();
 
@@ -689,9 +816,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
@@ -713,6 +842,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/cc-keyboard-panel.ui b/panels/keyboard/cc-keyboard-panel.ui
index aad179e5c..0f48e80ae 100644
--- a/panels/keyboard/cc-keyboard-panel.ui
+++ b/panels/keyboard/cc-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="GtkFrame">
                     <property name="visible">True</property>
diff --git a/panels/keyboard/keyboard.gresource.xml b/panels/keyboard/keyboard.gresource.xml
index 862f9f754..8cc4e2b85 100644
--- a/panels/keyboard/keyboard.gresource.xml
+++ b/panels/keyboard/keyboard.gresource.xml
@@ -4,5 +4,6 @@
     <file preprocess="xml-stripblanks">cc-keyboard-panel.ui</file>
     <file preprocess="xml-stripblanks">enter-keyboard-shortcut.svg</file>
     <file preprocess="xml-stripblanks">shortcut-editor.ui</file>
+    <file preprocess="xml-stripblanks">alt-chars-key.ui</file>
   </gresource>
 </gresources>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]