[gnome-control-center] region: Add XKB input sources



commit 0a78c3504e34927c9864d489fafd3e8025e21d5c
Author: Rui Matos <tiagomatos gmail com>
Date:   Tue May 22 19:14:19 2012 +0200

    region: Add XKB input sources
    
    We allow the user to choose from all XKB layouts installed and keep a
    user picked list in gsettings.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=662489

 configure.ac                                      |    3 +-
 panels/region/gnome-region-panel-input-chooser.ui |    5 +
 panels/region/gnome-region-panel-input.c          |  250 +++++++++++++++++++--
 3 files changed, 238 insertions(+), 20 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 0318ae2..3ec7242 100644
--- a/configure.ac
+++ b/configure.ac
@@ -115,7 +115,8 @@ PKG_CHECK_MODULES(COLOR_PANEL, $COMMON_MODULES colord >= 0.1.8)
 PKG_CHECK_MODULES(PRINTERS_PANEL, $COMMON_MODULES
                   polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION)
 PKG_CHECK_MODULES(REGION_PANEL, $COMMON_MODULES
-                  polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION)
+                  polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION
+                  gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION)
 PKG_CHECK_MODULES(SCREEN_PANEL, $COMMON_MODULES)
 PKG_CHECK_MODULES(SOUND_PANEL, $COMMON_MODULES libxml-2.0
                   libcanberra-gtk3 >= $CANBERRA_REQUIRED_VERSION
diff --git a/panels/region/gnome-region-panel-input-chooser.ui b/panels/region/gnome-region-panel-input-chooser.ui
index a7d30aa..c81c856 100644
--- a/panels/region/gnome-region-panel-input-chooser.ui
+++ b/panels/region/gnome-region-panel-input-chooser.ui
@@ -3,6 +3,11 @@
   <requires lib="gtk+" version="2.16"/>
   <object class="GtkListStore" id="input_source_model">
     <columns>
+      <!-- display name -->
+      <column type="gchararray"/>
+      <!-- input source type -->
+      <column type="gchararray"/>
+      <!-- type specific identifier -->
       <column type="gchararray"/>
     </columns>
   </object>
diff --git a/panels/region/gnome-region-panel-input.c b/panels/region/gnome-region-panel-input.c
index d8a6815..9e93293 100644
--- a/panels/region/gnome-region-panel-input.c
+++ b/panels/region/gnome-region-panel-input.c
@@ -26,16 +26,168 @@
 #include <glib.h>
 #include <glib/gi18n.h>
 
+#define GNOME_DESKTOP_USE_UNSTABLE_API
+#include <libgnome-desktop/gnome-xkb-info.h>
+
 #include "gnome-region-panel-input.h"
 
 #define WID(s) GTK_WIDGET(gtk_builder_get_object (builder, s))
 
-static GtkWidget *input_chooser_new          (GtkWindow     *main_window);
+#define GNOME_DESKTOP_INPUT_SOURCES_DIR "org.gnome.desktop.input-sources"
+
+#define KEY_INPUT_SOURCES "sources"
+
+#define INPUT_SOURCE_TYPE_XKB "xkb"
+
+enum {
+  NAME_COLUMN,
+  TYPE_COLUMN,
+  ID_COLUMN,
+  N_COLUMNS
+};
+
+static GSettings *input_sources_settings = NULL;
+static gulong input_sources_settings_changed_id = 0;
+static GnomeXkbInfo *xkb_info = NULL;
+
+static GtkWidget *input_chooser_new          (GtkWindow     *main_window,
+                                              GtkListStore  *active_sources);
 static gboolean   input_chooser_get_selected (GtkWidget     *chooser,
                                               GtkTreeModel **model,
                                               GtkTreeIter   *iter);
 
 static gboolean
+add_source_to_table (GtkTreeModel *model,
+                     GtkTreePath  *path,
+                     GtkTreeIter  *iter,
+                     gpointer      data)
+{
+  GHashTable *hash = data;
+  gchar *type;
+  gchar *id;
+
+  gtk_tree_model_get (model, iter,
+                      TYPE_COLUMN, &type,
+                      ID_COLUMN, &id,
+                      -1);
+
+  g_hash_table_add (hash, g_strconcat (type, id, NULL));
+
+  g_free (type);
+  g_free (id);
+
+  return FALSE;
+}
+
+static void
+populate_model (GtkListStore *store,
+                GtkListStore *active_sources_store)
+{
+  GHashTable *active_sources_table;
+  GtkTreeIter iter;
+  const gchar *name;
+  GList *sources, *tmp;
+  gchar *source_id = NULL;
+
+  active_sources_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+  gtk_tree_model_foreach (GTK_TREE_MODEL (active_sources_store),
+                          add_source_to_table,
+                          active_sources_table);
+
+  sources = gnome_xkb_info_get_all_layouts (xkb_info);
+
+  for (tmp = sources; tmp; tmp = tmp->next)
+    {
+      g_free (source_id);
+      source_id = g_strconcat (INPUT_SOURCE_TYPE_XKB, tmp->data, NULL);
+
+      if (g_hash_table_contains (active_sources_table, source_id))
+        continue;
+
+      gnome_xkb_info_get_layout_info (xkb_info, (const gchar *)tmp->data,
+                                      &name, NULL, NULL, NULL);
+
+      gtk_list_store_append (store, &iter);
+      gtk_list_store_set (store, &iter,
+                          NAME_COLUMN, name,
+                          TYPE_COLUMN, INPUT_SOURCE_TYPE_XKB,
+                          ID_COLUMN, tmp->data,
+                          -1);
+    }
+  g_free (source_id);
+
+  g_list_free (sources);
+  g_hash_table_destroy (active_sources_table);
+}
+
+static void
+populate_with_active_sources (GtkListStore *store)
+{
+  GVariant *sources;
+  GVariantIter iter;
+  const gchar *name;
+  const gchar *type;
+  const gchar *id;
+  GtkTreeIter tree_iter;
+
+  sources = g_settings_get_value (input_sources_settings, KEY_INPUT_SOURCES);
+
+  g_variant_iter_init (&iter, sources);
+  while (g_variant_iter_next (&iter, "(&s&s)", &type, &id))
+    {
+      if (!g_str_equal (type, INPUT_SOURCE_TYPE_XKB))
+        {
+          g_warning ("Unknown input source type '%s'", type);
+          continue;
+        }
+
+      gnome_xkb_info_get_layout_info (xkb_info, id, &name, NULL, NULL, NULL);
+
+      if (!name)
+        {
+          g_warning ("Couldn't find XKB input source '%s'", id);
+          continue;
+        }
+
+      gtk_list_store_append (store, &tree_iter);
+      gtk_list_store_set (store, &tree_iter,
+                          NAME_COLUMN, name,
+                          TYPE_COLUMN, type,
+                          ID_COLUMN, id,
+                          -1);
+    }
+
+  g_variant_unref (sources);
+}
+
+static void
+update_configuration (GtkTreeModel *model)
+{
+  GtkTreeIter iter;
+  gchar *type;
+  gchar *id;
+  GVariantBuilder builder;
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ss)"));
+
+  gtk_tree_model_get_iter_first (model, &iter);
+  do {
+    gtk_tree_model_get (model, &iter,
+                        TYPE_COLUMN, &type,
+                        ID_COLUMN, &id,
+                        -1);
+    g_variant_builder_add (&builder, "(ss)", type, id);
+    g_free (type);
+    g_free (id);
+  } while (gtk_tree_model_iter_next (model, &iter));
+
+  g_signal_handler_block (input_sources_settings, input_sources_settings_changed_id);
+  g_settings_set_value (input_sources_settings, KEY_INPUT_SOURCES, g_variant_builder_end (&builder));
+  g_signal_handler_unblock (input_sources_settings, input_sources_settings_changed_id);
+}
+
+static gboolean
 get_selected_iter (GtkBuilder    *builder,
                    GtkTreeModel **model,
                    GtkTreeIter   *iter)
@@ -122,9 +274,13 @@ chooser_response (GtkWidget *chooser, gint response_id, gpointer data)
           GtkListStore *my_model;
           GtkTreeIter my_iter;
           gchar *name;
+          gchar *type;
+          gchar *id;
 
           gtk_tree_model_get (model, &iter,
-                              0, &name,
+                              NAME_COLUMN, &name,
+                              TYPE_COLUMN, &type,
+                              ID_COLUMN, &id,
                               -1);
 
           my_tv = GTK_TREE_VIEW (WID ("active_input_sources"));
@@ -133,14 +289,18 @@ chooser_response (GtkWidget *chooser, gint response_id, gpointer data)
           gtk_list_store_append (my_model, &my_iter);
 
           gtk_list_store_set (my_model, &my_iter,
-                              0, name,
+                              NAME_COLUMN, name,
+                              TYPE_COLUMN, type,
+                              ID_COLUMN, id,
                               -1);
-
           g_free (name);
+          g_free (type);
+          g_free (id);
 
           gtk_tree_selection_select_iter (gtk_tree_view_get_selection (my_tv), &my_iter);
 
           update_button_sensitivity (builder);
+          update_configuration (GTK_TREE_MODEL (my_model));
         }
       else
         {
@@ -157,11 +317,16 @@ add_input (GtkButton *button, gpointer data)
   GtkBuilder *builder = data;
   GtkWidget *chooser;
   GtkWidget *toplevel;
+  GtkWidget *treeview;
+  GtkListStore *active_sources;
 
   g_debug ("add an input source");
 
   toplevel = gtk_widget_get_toplevel (WID ("region_notebook"));
-  chooser = input_chooser_new (GTK_WINDOW (toplevel));
+  treeview = WID ("active_input_sources");
+  active_sources = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)));
+
+  chooser = input_chooser_new (GTK_WINDOW (toplevel), active_sources);
   g_signal_connect (chooser, "response",
                     G_CALLBACK (chooser_response), builder);
 }
@@ -190,6 +355,7 @@ remove_selected_input (GtkButton *button, gpointer data)
   gtk_tree_path_free (path);
 
   update_button_sensitivity (builder);
+  update_configuration (model);
 }
 
 static void
@@ -216,6 +382,7 @@ move_selected_input_up (GtkButton *button, gpointer data)
   gtk_tree_path_free (path);
 
   update_button_sensitivity (builder);
+  update_configuration (model);
 }
 
 static void
@@ -241,6 +408,7 @@ move_selected_input_down (GtkButton *button, gpointer data)
   gtk_tree_path_free (path);
 
   update_button_sensitivity (builder);
+  update_configuration (model);
 }
 
 static void
@@ -249,8 +417,10 @@ show_selected_layout (GtkButton *button, gpointer data)
   GtkBuilder *builder = data;
   GtkTreeModel *model;
   GtkTreeIter iter;
-  gchar *layout;
+  gchar *id;
   gchar *kbd_viewer_args;
+  const gchar *xkb_layout;
+  const gchar *xkb_variant;
 
   g_debug ("show selected layout");
 
@@ -258,14 +428,29 @@ show_selected_layout (GtkButton *button, gpointer data)
     return;
 
   gtk_tree_model_get (model, &iter,
-                      0, &layout,
+                      ID_COLUMN, &id,
                       -1);
 
-  kbd_viewer_args = g_strdup_printf ("gkbd-keyboard-display -l %s", layout);
+  gnome_xkb_info_get_layout_info (xkb_info, id, NULL, NULL, &xkb_layout, &xkb_variant);
+
+  if (!xkb_layout || !xkb_layout[0])
+    {
+      g_warning ("Couldn't find XKB input source '%s'", id);
+      goto exit;
+    }
+
+  if (xkb_variant[0])
+    kbd_viewer_args = g_strdup_printf ("gkbd-keyboard-display -l \"%s\t%s\"",
+                                       xkb_layout, xkb_variant);
+  else
+    kbd_viewer_args = g_strdup_printf ("gkbd-keyboard-display -l %s",
+                                       xkb_layout);
+
   g_spawn_command_line_async (kbd_viewer_args, NULL);
 
   g_free (kbd_viewer_args);
-  g_free (layout);
+ exit:
+  g_free (id);
 }
 
 static gboolean
@@ -286,6 +471,20 @@ go_to_shortcuts (GtkLinkButton *button,
   return TRUE;
 }
 
+static void
+input_sources_changed (GSettings  *settings,
+                       gchar      *key,
+                       GtkBuilder *builder)
+{
+  GtkWidget *treeview;
+  GtkTreeModel *store;
+
+  treeview = WID("active_input_sources");
+  store = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview));
+  gtk_list_store_clear (GTK_LIST_STORE (store));
+  populate_with_active_sources (GTK_LIST_STORE (store));
+}
+
 void
 setup_input_tabs (GtkBuilder    *builder,
                   CcRegionPanel *panel)
@@ -299,15 +498,20 @@ setup_input_tabs (GtkBuilder    *builder,
   gchar *next = NULL;
   GtkWidget *label;
 
+  input_sources_settings = g_settings_new (GNOME_DESKTOP_INPUT_SOURCES_DIR);
+  xkb_info = gnome_xkb_info_new ();
+
   /* set up the list of active inputs */
   treeview = WID("active_input_sources");
   column = gtk_tree_view_column_new ();
   cell = gtk_cell_renderer_text_new ();
   gtk_tree_view_column_pack_start (column, cell, TRUE);
-  gtk_tree_view_column_add_attribute (column, cell, "text", 0);
+  gtk_tree_view_column_add_attribute (column, cell, "text", NAME_COLUMN);
   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
 
-  store = gtk_list_store_new (1, G_TYPE_STRING);
+  store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+
+  populate_with_active_sources (store);
 
   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
   g_signal_connect_swapped (selection, "changed",
@@ -343,6 +547,11 @@ setup_input_tabs (GtkBuilder    *builder,
 
   g_signal_connect (WID("jump-to-shortcuts"), "activate-link",
                     G_CALLBACK (go_to_shortcuts), panel);
+
+  input_sources_settings_changed_id = g_signal_connect (G_OBJECT (input_sources_settings),
+                                                        "changed::" KEY_INPUT_SOURCES,
+                                                        G_CALLBACK (input_sources_changed),
+                                                        builder);
 }
 
 static void
@@ -444,7 +653,7 @@ filter_func (GtkTreeModel *model,
              GtkTreeIter  *iter,
              gpointer      data)
 {
-  gchar *desc = NULL;
+  gchar *name = NULL;
   gchar **pattern;
   gboolean rv = TRUE;
 
@@ -452,13 +661,13 @@ filter_func (GtkTreeModel *model,
     return TRUE;
 
   gtk_tree_model_get (model, iter,
-                      0, &desc,
+                      NAME_COLUMN, &name,
                       -1);
 
   pattern = search_pattern_list;
   do {
     gboolean is_pattern_found = FALSE;
-    gchar *udesc = g_utf8_strup (desc, -1);
+    gchar *udesc = g_utf8_strup (name, -1);
     if (udesc != NULL && g_strstr_len (udesc, -1, *pattern))
       {
         is_pattern_found = TRUE;
@@ -473,13 +682,14 @@ filter_func (GtkTreeModel *model,
 
   } while (*++pattern != NULL);
 
-  g_free (desc);
+  g_free (name);
 
   return rv;
 }
 
 static GtkWidget *
-input_chooser_new (GtkWindow *main_window)
+input_chooser_new (GtkWindow    *main_window,
+                   GtkListStore *active_sources)
 {
   GtkBuilder *builder;
   GtkWidget *chooser;
@@ -504,9 +714,9 @@ input_chooser_new (GtkWindow *main_window)
   g_object_set_data (G_OBJECT (chooser),
                      "filtered_input_source_list", filtered_list);
   visible_column =
-    gtk_tree_view_column_new_with_attributes ("Layout",
+    gtk_tree_view_column_new_with_attributes ("Input Sources",
                                               gtk_cell_renderer_text_new (),
-                                              "text", 0,
+                                              "text", NAME_COLUMN,
                                               NULL);
 
   gtk_window_set_transient_for (GTK_WINDOW (chooser), main_window);
@@ -528,8 +738,10 @@ input_chooser_new (GtkWindow *main_window)
   filtered_model = GTK_TREE_MODEL_FILTER (gtk_builder_get_object (builder, "filtered_input_source_model"));
   model = GTK_LIST_STORE (gtk_builder_get_object (builder, "input_source_model"));
 
+  populate_model (model, active_sources);
+
   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
-                                        0, GTK_SORT_ASCENDING);
+                                        NAME_COLUMN, GTK_SORT_ASCENDING);
 
   gtk_tree_model_filter_set_visible_func (filtered_model,
                                           filter_func,



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