[gnome-control-center/wip/input-sources: 3/13] More complete IBus support
- From: Rui Matos <rtcm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-control-center/wip/input-sources: 3/13] More complete IBus support
- Date: Wed, 18 Apr 2012 15:41:07 +0000 (UTC)
commit bf0c16787ed0fff025fabec6a01a967408f5f98f
Author: Matthias Clasen <mclasen redhat com>
Date: Sat Oct 22 19:42:04 2011 -0400
More complete IBus support
Things that work now:
- Adding and removing sources works
- Input soures can be rearranged
- Changes are written back to IBus configuration
- We show the actual shortcuts
- Keyboard layouts can be previewed
panels/region/Makefile.am | 1 +
panels/region/gnome-region-panel-input-chooser.ui | 161 ++++++
panels/region/gnome-region-panel-input.c | 622 ++++++++++++++++++++-
panels/region/gnome-region-panel-input.h | 2 +-
4 files changed, 755 insertions(+), 31 deletions(-)
---
diff --git a/panels/region/Makefile.am b/panels/region/Makefile.am
index 190e770..f5b3728 100644
--- a/panels/region/Makefile.am
+++ b/panels/region/Makefile.am
@@ -42,6 +42,7 @@ uidir = $(pkgdatadir)/ui
ui_DATA = \
gnome-region-panel.ui \
gnome-region-panel-layout-chooser.ui \
+ gnome-region-panel-input-chooser.ui \
gnome-region-panel-options-dialog.ui
desktopdir = $(datadir)/applications
diff --git a/panels/region/gnome-region-panel-input-chooser.ui b/panels/region/gnome-region-panel-input-chooser.ui
new file mode 100644
index 0000000..8fc2b74
--- /dev/null
+++ b/panels/region/gnome-region-panel-input-chooser.ui
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <object class="GtkListStore" id="input_source_model">
+ <columns>
+ <!-- column-name id -->
+ <column type="gchararray"/>
+ <!-- column-name name -->
+ <column type="gchararray"/>
+ <!-- column-name lang -->
+ <column type="gchararray"/>
+ <!-- column-name layout -->
+ <column type="gchararray"/>
+ <!-- column-name xkb -->
+ <column type="gboolean"/>
+ </columns>
+ </object>
+ <object class="GtkTreeModelFilter" id="filtered_input_source_model">
+ <property name="child_model">input_source_model</property>
+ </object>
+ <object class="GtkDialog" id="input_source_chooser">
+ <property name="visible">False</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Choose an input source</property>
+ <property name="modal">True</property>
+ <property name="window_position">center-on-parent</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="hbtnBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="cancel-button">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="ok-button">
+ <property name="label">gtk-add</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox40">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">5</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Select an input source to add</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="shadow_type">etched-in</property>
+ <property name="min_content_width">450</property>
+ <property name="min_content_height">250</property>
+ <child>
+ <object class="GtkTreeView" id="filtered_input_source_list">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="model">filtered_input_source_model</property>
+ <property name="headers_visible">False</property>
+ <property name="search_column">0</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="input_source_filter">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">â</property>
+ <property name="secondary-icon-name">edit-find-symbolic</property>
+ <property name="secondary-icon-activatable">False</property>
+ <property name="secondary-icon-sensitive">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">ok-button</action-widget>
+ <action-widget response="-6">cancel-button</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/panels/region/gnome-region-panel-input.c b/panels/region/gnome-region-panel-input.c
index b261ff7..9951312 100644
--- a/panels/region/gnome-region-panel-input.c
+++ b/panels/region/gnome-region-panel-input.c
@@ -23,57 +23,287 @@
#include <string.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+
#include <ibus.h>
+/* http://code.google.com/p/ibus/issues/detail?id=1338 */
+#define IBUS_COMPILATION
+#include <ibusutil.h>
+#undef IBUS_COMPILATION
+
+#include <gdk/gdkx.h>
+#include <libgnomekbd/gkbd-keyboard-drawing.h>
#include "gnome-region-panel-input.h"
#define WID(s) GTK_WIDGET(gtk_builder_get_object (builder, s))
+/* TODO
+ *
+ * - There is a large overlap between xkb and m17n:kbd -
+ * we need to somehow decide and filter out
+ * cases to consider:
+ * Amharic: xkb:layout:et vs m17n:am:sera - probably keep both
+ * Arabic: xkb:layout:ara vs m17n:ar:kbd - probably not
+ *
+ * - Straighten out the naming. It needs to be either
+ * "Language" or "Language (Method)" when the same
+ * language occurs more than once. Need to decide what
+ * to do about xkb and m17n
+ *
+ * - Implement system-wide settings
+ *
+ * - Debug hotkeys, they don't act right
+ *
+ * - Allow changing shortcuts ?
+ */
-/* another ibus bus: ibusutil.h is not included in ibus.h */
-#define IBUS_COMPILATION
-#include <ibusutil.h>
-#undef IBUS_COMPILATION
+
+static GtkWidget *input_chooser_new (GtkBuilder *builder);
+static gboolean input_chooser_get_selected (GtkWidget *chooser,
+ GtkTreeModel **model,
+ GtkTreeIter *iter);
+
+enum
+{
+ COL_NAME,
+ COL_DESC,
+ COL_LANG,
+ COL_LAYOUT,
+ COL_XKB
+};
+
+/* IBus interaction {{{1 */
+
+static gchar *
+engine_description (IBusEngineDesc *description, gboolean unique_lang)
+{
+ const gchar *lang;
+ gchar *longname;
+ gchar *desc;
+
+ lang = ibus_get_language_name (ibus_engine_desc_get_language (description));
+
+ if (g_getenv ("DEBUG_IBUS"))
+ return g_strdup_printf ("%s %s/%s/%s/%s", lang,
+ ibus_engine_desc_get_name (description),
+ ibus_engine_desc_get_longname (description),
+ ibus_engine_desc_get_language (description),
+ ibus_engine_desc_get_layout (description));
+
+ if (unique_lang)
+ return g_strdup (lang);
+
+ if (g_str_has_prefix (ibus_engine_desc_get_name (description), "xkb:layout:"))
+ {
+ if (strcmp (ibus_engine_desc_get_longname (description), lang) == 0)
+ return g_strdup_printf ("%s (xkb)", lang);
+ else
+ return g_strdup (ibus_engine_desc_get_longname (description));
+ }
+
+ longname = g_strdup (ibus_engine_desc_get_longname (description));
+ if (g_str_has_suffix (longname, " (m17n)"))
+ {
+ longname[strlen (longname) - strlen (" (m17n)")] = '\0';
+ }
+
+ desc = g_strdup_printf ("%s (%s)", lang, longname);
+
+ g_free (longname);
+
+ return desc;
+}
static void
-get_active_engines (GtkListStore *store)
+populate_model (GtkListStore *store,
+ gboolean only_active)
{
IBusBus *bus;
GList *list, *l;
- IBusEngineDesc *desc;
- GType type;
+ GList *active_list;
+ IBusEngineDesc *description;
+ GType type G_GNUC_UNUSED;
const gchar *name;
+ const gchar *lang;
+ gchar *desc;
+ gint count;
GtkTreeIter iter;
+ GHashTable *lang_hash;
+ GHashTable *active_hash;
bus = ibus_bus_new ();
- /* work around a bug in IBus which forgets to register
- * its types properly
+ /* IBus forgets to register its serializable types
+ * http://code.google.com/p/ibus/issues/detail?id=1339
*/
type = ibus_engine_desc_get_type ();
- list = ibus_bus_list_active_engines (bus);
+ list = ibus_bus_list_engines (bus);
+ active_list = ibus_bus_list_active_engines (bus);
+ lang_hash = g_hash_table_new (g_str_hash, g_str_equal);
+ active_hash = g_hash_table_new (g_str_hash, g_str_equal);
+
+ /* Figure out which languages occur more than once
+ * for these, showing only the language is not sufficient
+ */
for (l = list; l; l = l->next)
{
- desc = (IBusEngineDesc *)l->data;
+ description = (IBusEngineDesc *)l->data;
- name = ibus_engine_desc_get_name (desc);
+ name = ibus_engine_desc_get_name (description);
if (g_str_has_prefix (name, "xkb:layout:default:#"))
continue;
+ lang = ibus_engine_desc_get_language (description);
+ lang = ibus_get_language_name (lang);
+ if (lang == NULL)
+ continue;
+
+ count = GPOINTER_TO_INT (g_hash_table_lookup (lang_hash, lang));
+ count++;
+ g_hash_table_insert (lang_hash, (gpointer)lang, GINT_TO_POINTER (count));
+ }
+
+ if (only_active)
+ {
+ g_list_free (list);
+ list = active_list;
+ active_list = NULL;
+ }
+ else
+ {
+ /* We want to skip active engines when
+ * making a list of inactive engines
+ */
+ for (l = active_list; l; l = l->next)
+ {
+ description = (IBusEngineDesc *)l->data;
+ name = ibus_engine_desc_get_name (description);
+ g_hash_table_insert (active_hash, (gpointer)name, (gpointer)name);
+ }
+ g_list_free (active_list);
+ active_list = NULL;
+ }
+
+ for (l = list; l; l = l->next)
+ {
+ description = (IBusEngineDesc *)l->data;
+
+ name = ibus_engine_desc_get_name (description);
+ if (g_str_has_prefix (name, "xkb:layout:default:#"))
+ continue;
+
+ if (g_hash_table_lookup (active_hash, name))
+ continue;
+
+ lang = ibus_engine_desc_get_language (description);
+ lang = ibus_get_language_name (lang);
+ if (lang == NULL)
+ continue;
+
+ count = GPOINTER_TO_INT (g_hash_table_lookup (lang_hash, lang));
+ desc = engine_description (description, count <= 1);
+
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
- 0, name,
- 1, ibus_get_language_name (ibus_engine_desc_get_language (desc)),
- 2, ibus_engine_desc_get_layout (desc),
- 3, g_str_has_prefix (name, "xkb:layout:"),
+ COL_NAME, name,
+ COL_DESC, desc,
+ COL_LANG, lang,
+ COL_LAYOUT, ibus_engine_desc_get_layout (description),
+ COL_XKB, g_str_has_prefix (name, "xkb:layout:"),
-1);
+ g_free (desc);
}
+ g_hash_table_unref (lang_hash);
+ g_hash_table_unref (active_hash);
+
g_list_free (list);
+
+ g_object_unref (bus);
+}
+
+static void
+update_ibus_configuration (GtkTreeModel *model)
+{
+ GtkTreeIter iter;
+ IBusBus *bus;
+ IBusConfig *config;
+ gchar **active;
+ gsize n_active;
+ gchar *name;
+ gint i;
+
+ n_active = gtk_tree_model_iter_n_children (model, NULL);
+ active = g_new0 (gchar *, n_active + 1);
+ gtk_tree_model_get_iter_first (model, &iter);
+ i = 0;
+ do {
+ gtk_tree_model_get (model, &iter, COL_NAME, &name, -1);
+ active[i++] = name;
+ } while (gtk_tree_model_iter_next (model, &iter));
+ active[n_active] = NULL;
+
+ bus = ibus_bus_new ();
+ config = ibus_bus_get_config (bus);
+
+ if (!ibus_config_set_value (config,
+ "general", "preload_engines",
+ g_variant_new_strv ((const gchar * const *)active, -1)))
+ {
+ g_warning ("Failed to update IBus configuration");
+ }
+
+ g_strfreev (active);
+
+ g_object_unref (bus);
}
+static void
+get_shortcuts (gchar **previous, gchar **next)
+{
+ IBusBus *bus;
+ IBusConfig *config;
+ GVariant *value;
+ const gchar **strv;
+ gsize len;
+
+ bus = ibus_bus_new ();
+ config = ibus_bus_get_config (bus);
+
+ *previous = NULL;
+ *next = NULL;
+
+ value = ibus_config_get_value (config, "general/hotkey", "previous_engine");
+ if (value)
+ {
+ strv = g_variant_get_strv (value, &len);
+ if (len > 0)
+ *previous = g_strdup (strv[0]);
+ g_free (strv);
+ g_variant_unref (value);
+ }
+
+ value = ibus_config_get_value (config, "general/hotkey", "next_engine_in_menu");
+ if (value)
+ {
+ strv = g_variant_get_strv (value, &len);
+ if (len > 0)
+ *next = g_strdup (strv[0]);
+ g_free (strv);
+ g_variant_unref (value);
+ }
+
+ g_debug ("Hotkeys: previous: %s next: %s\n", *previous, *next);
+
+ g_object_unref (bus);
+}
+
+/* List handling {{{1 */
+
static gboolean
get_selected_iter (GtkBuilder *builder,
GtkTreeModel **model,
@@ -115,7 +345,6 @@ update_button_sensitivity (GtkBuilder *builder)
GtkWidget *down_button;
GtkWidget *show_button;
GtkTreeView *tv;
- GtkTreeSelection *selection;
gint n_active;
gint index;
@@ -125,7 +354,6 @@ update_button_sensitivity (GtkBuilder *builder)
down_button = WID("input_source_move_down");
tv = GTK_TREE_VIEW (WID ("active_input_sources"));
- selection = gtk_tree_view_get_selection (tv);
n_active = gtk_tree_model_iter_n_children (gtk_tree_view_get_model (tv), NULL);
index = find_selected_layout_idx (builder);
@@ -148,11 +376,77 @@ set_selected_path (GtkBuilder *builder,
}
static void
+chooser_response (GtkWidget *chooser, gint response_id, gpointer data)
+{
+ GtkBuilder *builder = data;
+
+ if (response_id == GTK_RESPONSE_OK)
+ {
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ if (input_chooser_get_selected (chooser, &model, &iter))
+ {
+ GtkTreeView *my_tv;
+ GtkListStore *my_model;
+ GtkTreeIter my_iter;
+ gchar *name;
+ gchar *desc;
+ gchar *lang;
+ gchar *layout;
+ gboolean xkb;
+
+ gtk_tree_model_get (model, &iter,
+ COL_NAME, &name,
+ COL_DESC, &desc,
+ COL_LANG, &lang,
+ COL_LAYOUT, &layout,
+ COL_XKB, &xkb,
+ -1);
+
+ my_tv = GTK_TREE_VIEW (WID ("active_input_sources"));
+ my_model = GTK_LIST_STORE (gtk_tree_view_get_model (my_tv));
+
+ gtk_list_store_append (my_model, &my_iter);
+
+ gtk_list_store_set (my_model, &my_iter,
+ COL_NAME, name,
+ COL_DESC, desc,
+ COL_LANG, lang,
+ COL_LAYOUT, layout,
+ COL_XKB, xkb,
+ -1);
+
+ g_free (name);
+ g_free (desc);
+ g_free (lang);
+ g_free (layout);
+
+ gtk_tree_selection_select_iter (gtk_tree_view_get_selection (my_tv), &my_iter);
+
+ update_button_sensitivity (builder);
+ update_ibus_configuration (GTK_TREE_MODEL (my_model));
+ }
+ else
+ {
+ g_debug ("nothing selected, nothing added");
+ }
+ }
+
+ gtk_widget_destroy (GTK_WIDGET (chooser));
+}
+
+static void
add_input (GtkButton *button, gpointer data)
{
GtkBuilder *builder = data;
+ GtkWidget *chooser;
g_debug ("add an input source");
+
+ chooser = input_chooser_new (builder);
+ g_signal_connect (chooser, "response",
+ G_CALLBACK (chooser_response), builder);
}
static void
@@ -161,15 +455,25 @@ remove_selected_input (GtkButton *button, gpointer data)
GtkBuilder *builder = data;
GtkTreeModel *model;
GtkTreeIter iter;
+ GtkTreePath *path;
g_debug ("remove selected input source");
if (get_selected_iter (builder, &model, &iter) == FALSE)
return;
+ path = gtk_tree_model_get_path (model, &iter);
gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+
+ if (!gtk_tree_model_get_iter (model, &iter, path))
+ gtk_tree_path_prev (path);
+
+ set_selected_path (builder, path);
+
+ gtk_tree_path_free (path);
+
update_button_sensitivity (builder);
- /* update_layouts_list (model, dialog); */
+ update_ibus_configuration (model);
}
static void
@@ -192,11 +496,11 @@ move_selected_input_up (GtkButton *button, gpointer data)
path = gtk_tree_model_get_path (model, &prev);
gtk_list_store_swap (GTK_LIST_STORE (model), &iter, &prev);
- update_button_sensitivity (builder);
- /* update_layouts_list (model, dialog); */
set_selected_path (builder, path);
-
gtk_tree_path_free (path);
+
+ update_button_sensitivity (builder);
+ update_ibus_configuration (model);
}
static void
@@ -217,23 +521,62 @@ move_selected_input_down (GtkButton *button, gpointer data)
return;
path = gtk_tree_model_get_path (model, &next);
-
gtk_list_store_swap (GTK_LIST_STORE (model), &iter, &next);
- update_button_sensitivity (builder);
- /* update_layouts_list (model, dialog); */
set_selected_path (builder, path);
-
gtk_tree_path_free (path);
+
+ update_button_sensitivity (builder);
+ update_ibus_configuration (model);
}
static void
show_selected_layout (GtkButton *button, gpointer data)
{
GtkBuilder *builder = data;
+ GtkWidget *parent;
+ GtkWidget *popup;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gchar *layout;
+ gchar *desc;
+ gchar *title;
+ XklEngine *engine;
+ XklConfigRegistry *registry;
g_debug ("show selected layout");
+
+ if (!get_selected_iter (builder, &model, &iter))
+ return;
+
+ gtk_tree_model_get (model, &iter,
+ COL_LAYOUT, &layout,
+ COL_DESC, &desc,
+ -1);
+
+ parent = WID ("region_notebook");
+ popup = gkbd_keyboard_drawing_dialog_new ();
+
+ engine = xkl_engine_get_instance (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (parent)));
+ registry = xkl_config_registry_get_instance (engine);
+
+ gkbd_keyboard_drawing_dialog_set_layout (popup, registry, layout);
+
+ g_object_unref (registry);
+
+ title = g_strdup_printf (_("Keyboard layout for %s"), desc);
+ gtk_window_set_title (GTK_WINDOW (popup), title);
+ g_free (title);
+
+ gtk_window_set_transient_for (GTK_WINDOW (popup),
+ GTK_WINDOW (gtk_widget_get_toplevel (parent)));
+ gtk_widget_show_all (popup);
+
+ g_free (layout);
+ g_free (desc);
}
+/* Main setup {{{1 */
+
void
setup_input_tabs (GtkBuilder *builder)
{
@@ -242,19 +585,22 @@ setup_input_tabs (GtkBuilder *builder)
GtkCellRenderer *cell;
GtkListStore *store;
GtkTreeSelection *selection;
+ gchar *previous = NULL;
+ gchar *next = NULL;
+ GtkWidget *label;
/* 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", 1);
+ gtk_tree_view_column_add_attribute (column, cell, "text", COL_DESC);
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
- /* id, name, layout, xkb? */
- store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
+ /* id, name, language, layout, xkb? */
+ store = gtk_list_store_new (5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
- get_active_engines (store);
+ populate_model (store, TRUE);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
g_signal_connect_swapped (selection, "changed",
@@ -273,4 +619,220 @@ setup_input_tabs (GtkBuilder *builder)
G_CALLBACK (move_selected_input_down), builder);
g_signal_connect (WID("input_source_show"), "clicked",
G_CALLBACK (show_selected_layout), builder);
+
+ /* show the right shortcuts */
+ get_shortcuts (&previous, &next);
+
+ /* use an em dash is no shortcut */
+ if (!previous)
+ previous = g_strdup ("\342\200\224");
+ if (!next)
+ next = g_strdup ("\342\200\224");
+
+ label = WID("prev-source-shortcut-label");
+ gtk_label_set_label (GTK_LABEL (label), previous);
+ label = WID("next-source-shortcut-label");
+ gtk_label_set_label (GTK_LABEL (label), next);
+
+ g_free (previous);
+ g_free (next);
+}
+
+/* Chooser dialog {{{1 */
+
+static void
+filter_clear (GtkEntry *entry,
+ GtkEntryIconPosition icon_pos,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ gtk_entry_set_text (entry, "");
+}
+
+static gchar **search_pattern_list;
+
+static void
+filter_changed (GtkBuilder *builder)
+{
+ GtkTreeModelFilter *filtered_model;
+ GtkWidget *filter_entry;
+ const gchar *pattern;
+ gchar *upattern;
+
+ filtered_model = GTK_TREE_MODEL_FILTER (gtk_builder_get_object (builder,
+ "filtered_input_source_model"));
+ filter_entry = WID ("input_source_filter");
+ pattern = gtk_entry_get_text (GTK_ENTRY (filter_entry));
+ upattern = g_utf8_strup (pattern, -1);
+ if (!g_strcmp0 (pattern, ""))
+ g_object_set (G_OBJECT (filter_entry),
+ "secondary-icon-name", "edit-find-symbolic",
+ "secondary-icon-activatable", FALSE,
+ "secondary-icon-sensitive", FALSE,
+ NULL);
+ else
+ g_object_set (G_OBJECT (filter_entry),
+ "secondary-icon-name", "edit-clear-symbolic",
+ "secondary-icon-activatable", TRUE,
+ "secondary-icon-sensitive", TRUE,
+ NULL);
+
+ if (search_pattern_list != NULL)
+ g_strfreev (search_pattern_list);
+
+ search_pattern_list = g_strsplit (upattern, " ", -1);
+ g_free (upattern);
+
+ gtk_tree_model_filter_refilter (filtered_model);
+}
+
+static void
+selection_changed (GtkTreeSelection *selection,
+ GtkBuilder *builder)
+{
+ GList *selected;
+
+ selected = gtk_tree_selection_get_selected_rows (selection, NULL);
+ gtk_widget_set_sensitive (WID ("ok-button"), selected != NULL);
+}
+
+static void
+row_activated (GtkTreeView *tree_view,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ GtkBuilder *builder)
+{
+ GtkWidget *add_button;
+ GtkWidget *dialog;
+
+ add_button = WID ("ok-button");
+ dialog = WID ("input_source_chooser");
+ if (gtk_widget_is_sensitive (add_button))
+ gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+}
+
+static gboolean
+filter_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ gchar *desc = NULL;
+ gchar **pattern;
+ gboolean rv = TRUE;
+
+ if (search_pattern_list == NULL || search_pattern_list[0] == NULL)
+ return TRUE;
+
+ gtk_tree_model_get (model, iter,
+ COL_DESC, &desc,
+ -1);
+
+ pattern = search_pattern_list;
+ do {
+ gboolean is_pattern_found = FALSE;
+ gchar *udesc = g_utf8_strup (desc, -1);
+ if (udesc != NULL && g_strstr_len (udesc, -1, *pattern))
+ {
+ is_pattern_found = TRUE;
+ }
+ g_free (udesc);
+
+ if (!is_pattern_found)
+ {
+ rv = FALSE;
+ break;
+ }
+
+ } while (*++pattern != NULL);
+
+ g_free (desc);
+
+ return rv;
+}
+
+static GtkWidget *
+input_chooser_new (GtkBuilder *main_builder)
+{
+ GtkBuilder *builder;
+ GtkWidget *chooser;
+ GtkWidget *filtered_list;
+ GtkWidget *filter_entry;
+ GtkTreeViewColumn *visible_column;
+ GtkTreeSelection *selection;
+ GtkListStore *model;
+ GtkTreeModelFilter *filtered_model;
+
+ builder = gtk_builder_new ();
+ gtk_builder_add_from_file (builder,
+ GNOMECC_UI_DIR "/gnome-region-panel-input-chooser.ui",
+ NULL);
+ chooser = WID ("input_source_chooser");
+ filtered_list = WID ("filtered_input_source_list");
+ filter_entry = WID ("input_source_filter");
+
+ g_object_set_data (G_OBJECT (chooser),
+ "filtered_input_source_list", filtered_list);
+ visible_column =
+ gtk_tree_view_column_new_with_attributes ("Layout",
+ gtk_cell_renderer_text_new (),
+ "text", COL_DESC,
+ NULL);
+
+ gtk_window_set_transient_for (GTK_WINDOW (chooser),
+ GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (gtk_builder_get_object (main_builder, "region_notebook")))));
+
+ gtk_tree_view_append_column (GTK_TREE_VIEW (filtered_list),
+ visible_column);
+ g_signal_connect_swapped (G_OBJECT (filter_entry), "notify::text",
+ G_CALLBACK (filter_changed), builder);
+
+ g_signal_connect (G_OBJECT (filter_entry), "icon-release",
+ G_CALLBACK (filter_clear), NULL);
+
+ selection =
+ gtk_tree_view_get_selection (GTK_TREE_VIEW (filtered_list));
+
+ g_signal_connect (G_OBJECT (selection), "changed",
+ G_CALLBACK (selection_changed), builder);
+
+ selection_changed (selection, builder);
+
+ g_signal_connect (G_OBJECT (filtered_list), "row-activated",
+ G_CALLBACK (row_activated), builder);
+
+ 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, FALSE);
+
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
+ COL_DESC, GTK_SORT_ASCENDING);
+
+ gtk_tree_model_filter_set_visible_func (filtered_model,
+ filter_func,
+ NULL, NULL);
+
+ gtk_widget_grab_focus (filter_entry);
+
+ gtk_widget_show (chooser);
+
+ return chooser;
+}
+
+static gboolean
+input_chooser_get_selected (GtkWidget *dialog,
+ GtkTreeModel **model,
+ GtkTreeIter *iter)
+{
+ GtkWidget *tv;
+ GtkTreeSelection *selection;
+
+ tv = g_object_get_data (G_OBJECT (dialog), "filtered_input_source_list");
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv));
+
+ return gtk_tree_selection_get_selected (selection, model, iter);
}
+/* Epilogue {{{1 */
+/* vim: set foldmethod=marker: */
diff --git a/panels/region/gnome-region-panel-input.h b/panels/region/gnome-region-panel-input.h
index 987bce6..a3aa05d 100644
--- a/panels/region/gnome-region-panel-input.h
+++ b/panels/region/gnome-region-panel-input.h
@@ -27,7 +27,7 @@
G_BEGIN_DECLS
-extern void setup_input_tabs (GtkBuilder * dialog);
+void setup_input_tabs (GtkBuilder *builder);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]