diff -uNrp a/configure.ac b/configure.ac --- a/configure.ac 2013-08-25 14:40:14.000000000 +0100 +++ b/configure.ac 2013-08-25 16:50:30.000000000 +0100 @@ -82,6 +82,22 @@ else SYSTEMD= fi +# IBus support +IBUS_REQUIRED_VERSION=1.4.2 + +#AC_ARG_ENABLE(ibus, +# AS_HELP_STRING([--disable-ibus], +# [Disable IBus support]), +# enable_ibus=$enableval, +# enable_ibus=yes) +enable_ibus=yes +#if test "x$enable_ibus" = "xyes" ; then +IBUS_MODULE="ibus-1.0 >= $IBUS_REQUIRED_VERSION" +AC_DEFINE(HAVE_IBUS, 1, [Defined if IBus support is enabled]) +#else +# IBUS_MODULE= +#fi + dnl ============================================== dnl Check that we meet the dependencies dnl ============================================== @@ -119,9 +135,10 @@ PKG_CHECK_MODULES(NETWORK_PANEL, $COMMON PKG_CHECK_MODULES(POWER_PANEL, $COMMON_MODULES upower-glib >= 0.9.1 cinnamon-settings-daemon >= $CSD_REQUIRED_VERSION) PKG_CHECK_MODULES(COLOR_PANEL, $COMMON_MODULES colord >= 0.1.8) -PKG_CHECK_MODULES(REGION_PANEL, $COMMON_MODULES libgnomekbd >= 2.91.91 +PKG_CHECK_MODULES(REGION_PANEL, $COMMON_MODULES polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION - libxklavier >= 5.1 libgnomekbdui >= 2.91.91) + cinnamon-desktop >= $CINNAMON_DESKTOP_REQUIRED_VERSION + $IBUS_MODULE) PKG_CHECK_MODULES(SCREEN_PANEL, $COMMON_MODULES) PKG_CHECK_MODULES(SOUND_PANEL, $COMMON_MODULES libxml-2.0 libcanberra-gtk3 >= $CANBERRA_REQUIRED_VERSION diff -uNrp a/panels/region/cc-region-panel.c b/panels/region/cc-region-panel.c --- a/panels/region/cc-region-panel.c 2013-08-25 14:40:14.000000000 +0100 +++ b/panels/region/cc-region-panel.c 2013-09-21 13:24:15.329949897 +0100 @@ -18,17 +18,18 @@ * Author: Sergey Udaltsov * */ -#include "config.h" + #include "cc-region-panel.h" +#include #include #include -#include "cinnamon-region-panel-xkb.h" +#include "cinnamon-region-panel-input.h" #include "cinnamon-region-panel-lang.h" #include "cinnamon-region-panel-formats.h" #include "cinnamon-region-panel-system.h" -G_DEFINE_DYNAMIC_TYPE (CcRegionPanel, cc_region_panel, CC_TYPE_PANEL) +CC_PANEL_REGISTER (CcRegionPanel, cc_region_panel) #define REGION_PANEL_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_REGION_PANEL, CcRegionPanelPrivate)) @@ -48,14 +49,6 @@ enum { SYSTEM_PAGE }; - -static gboolean -languages_link_cb (GtkButton *button, gpointer user_data) -{ - g_spawn_command_line_async ("gnome-language-selector", NULL); - return TRUE; -} - static void cc_region_panel_set_page (CcRegionPanel *panel, const char *page) @@ -116,13 +109,22 @@ cc_region_panel_finalize (GObject * obje G_OBJECT_CLASS (cc_region_panel_parent_class)->finalize (object); } +static const char * +cc_region_panel_get_help_uri (CcPanel *panel) +{ + return "help:gnome-help/prefs-language"; +} + static void cc_region_panel_class_init (CcRegionPanelClass * klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + CcPanelClass * panel_class = CC_PANEL_CLASS (klass); g_type_class_add_private (klass, sizeof (CcRegionPanelPrivate)); + panel_class->get_help_uri = cc_region_panel_get_help_uri; + object_class->set_property = cc_region_panel_set_property; object_class->finalize = cc_region_panel_finalize; @@ -130,22 +132,14 @@ cc_region_panel_class_init (CcRegionPane } static void -cc_region_panel_class_finalize (CcRegionPanelClass * klass) -{ -} - -static void cc_region_panel_init (CcRegionPanel * self) { CcRegionPanelPrivate *priv; GtkWidget *prefs_widget; - const char *desktop; GError *error = NULL; priv = self->priv = REGION_PANEL_PRIVATE (self); - desktop = g_getenv ("XDG_CURRENT_DESKTOP"); - priv->builder = gtk_builder_new (); gtk_builder_set_translation_domain (priv->builder, GETTEXT_PACKAGE); gtk_builder_add_from_file (priv->builder, @@ -157,29 +151,16 @@ cc_region_panel_init (CcRegionPanel * se return; } - prefs_widget = (GtkWidget *) gtk_builder_get_object (priv->builder, - "region_notebook"); - + prefs_widget = (GtkWidget *) gtk_builder_get_object (priv->builder, + "region_notebook"); gtk_widget_set_size_request (GTK_WIDGET (prefs_widget), -1, 400); gtk_widget_reparent (prefs_widget, GTK_WIDGET (self)); - setup_xkb_tabs (priv->builder); - - setup_language (priv->builder); - setup_formats (priv->builder); - setup_system (priv->builder); - - /* set screen link */ - - GtkWidget *widget = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, - "get_languages_button")); - - gtk_button_set_label (GTK_BUTTON (widget), _("Get more languages...")); - - g_signal_connect (widget, "clicked", - G_CALLBACK (languages_link_cb), - self); + setup_input_tabs (priv->builder, self); + setup_language (priv->builder); + setup_formats (priv->builder); + setup_system (priv->builder); } void @@ -187,6 +168,7 @@ cc_region_panel_register (GIOModule * mo { bindtextdomain (GETTEXT_PACKAGE, "/usr/share/cinnamon/locale"); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + cc_region_panel_register_type (G_TYPE_MODULE (module)); g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT, CC_TYPE_REGION_PANEL, diff -uNrp a/panels/region/cinnamon-region-panel-formats.h b/panels/region/cinnamon-region-panel-formats.h --- a/panels/region/cinnamon-region-panel-formats.h 2013-08-25 14:40:14.000000000 +0100 +++ b/panels/region/cinnamon-region-panel-formats.h 2013-09-21 13:24:15.332949789 +0100 @@ -19,8 +19,8 @@ * 02110-1335, USA. */ -#ifndef __GNOME_REGION_PANEL_FORMATS_H -#define __GNOME_REGION_PANEL_FORMATS_H +#ifndef __CINNAMON_REGION_PANEL_FORMATS_H +#define __CINNAMON_REGION_PANEL_FORMATS_H #include diff -uNrp a/panels/region/cinnamon-region-panel-input.c b/panels/region/cinnamon-region-panel-input.c --- a/panels/region/cinnamon-region-panel-input.c 1970-01-01 01:00:00.000000000 +0100 +++ b/panels/region/cinnamon-region-panel-input.c 2013-09-21 13:24:15.338949572 +0100 @@ -0,0 +1,1563 @@ +/* + * Copyright (C) 2011 Red Hat, Inc. + * + * Written by: Matthias Clasen + * + * 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, 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA + * 02110-1335, USA. + */ + +#include + +#include + +#include +#include +#include + +#define GNOME_DESKTOP_USE_UNSTABLE_API +#include + +#ifdef HAVE_IBUS +#include +#endif + +#include "gdm-languages.h" +#include "cinnamon-region-panel-input.h" + +#define WID(s) GTK_WIDGET(gtk_builder_get_object (builder, s)) + +#define GNOME_DESKTOP_INPUT_SOURCES_DIR "org.cinnamon.desktop.input-sources" + +#define KEY_CURRENT_INPUT_SOURCE "current" +#define KEY_INPUT_SOURCES "sources" + +#define INPUT_SOURCE_TYPE_XKB "xkb" +#define INPUT_SOURCE_TYPE_IBUS "ibus" + +enum { + NAME_COLUMN, + TYPE_COLUMN, + ID_COLUMN, + SETUP_COLUMN, + N_COLUMNS +}; + +static GSettings *input_sources_settings = NULL; +static GnomeXkbInfo *xkb_info = NULL; +static GtkWidget *input_chooser = NULL; /* weak pointer */ + +#ifdef HAVE_IBUS +static IBusBus *ibus = NULL; +static GHashTable *ibus_engines = NULL; +static GCancellable *ibus_cancellable = NULL; +static guint shell_name_watch_id = 0; + +static const gchar *supported_ibus_engines[] = { + /* Simplified Chinese */ + "pinyin", + "bopomofo", + "wubi", + "erbi", + /* Default in Fedora, where ibus-libpinyin replaces ibus-pinyin */ + "libpinyin", + "libbopomofo", + + /* Traditional Chinese */ + /* https://bugzilla.gnome.org/show_bug.cgi?id=680840 */ + "chewing", + "cangjie5", + "cangjie3", + "quick5", + "quick3", + "stroke5", + + /* Japanese */ + "anthy", + "mozc-jp", + "skk", + + /* Korean */ + "hangul", + + /* Thai */ + "m17n:th:kesmanee", + "m17n:th:pattachote", + "m17n:th:tis820", + + /* Vietnamese */ + "m17n:vi:tcvn", + "m17n:vi:telex", + "m17n:vi:viqr", + "m17n:vi:vni", + "Unikey", + + /* Sinhala */ + "m17n:si:wijesekera", + "m17n:si:phonetic-dynamic", + "m17n:si:trans", + "sayura", + + /* Indic */ + /* https://fedoraproject.org/wiki/I18N/Indic#Keyboard_Layouts */ + + /* Assamese */ + "m17n:as:phonetic", + "m17n:as:inscript", + "m17n:as:itrans", + + /* Bengali */ + "m17n:bn:inscript", + "m17n:bn:itrans", + "m17n:bn:probhat", + + /* Gujarati */ + "m17n:gu:inscript", + "m17n:gu:itrans", + "m17n:gu:phonetic", + + /* Hindi */ + "m17n:hi:inscript", + "m17n:hi:itrans", + "m17n:hi:phonetic", + "m17n:hi:remington", + "m17n:hi:typewriter", + "m17n:hi:vedmata", + + /* Kannada */ + "m17n:kn:kgp", + "m17n:kn:inscript", + "m17n:kn:itrans", + + /* Kashmiri */ + "m17n:ks:inscript", + + /* Maithili */ + "m17n:mai:inscript", + + /* Malayalam */ + "m17n:ml:inscript", + "m17n:ml:itrans", + "m17n:ml:mozhi", + "m17n:ml:swanalekha", + + /* Marathi */ + "m17n:mr:inscript", + "m17n:mr:itrans", + "m17n:mr:phonetic", + + /* Nepali */ + "m17n:ne:rom", + "m17n:ne:trad", + + /* Oriya */ + "m17n:or:inscript", + "m17n:or:itrans", + "m17n:or:phonetic", + + /* Punjabi */ + "m17n:pa:inscript", + "m17n:pa:itrans", + "m17n:pa:phonetic", + "m17n:pa:jhelum", + + /* Sanskrit */ + "m17n:sa:harvard-kyoto", + + /* Sindhi */ + "m17n:sd:inscript", + + /* Tamil */ + "m17n:ta:tamil99", + "m17n:ta:inscript", + "m17n:ta:itrans", + "m17n:ta:phonetic", + "m17n:ta:lk-renganathan", + "m17n:ta:vutam", + "m17n:ta:typewriter", + + /* Telugu */ + "m17n:te:inscript", + "m17n:te:apple", + "m17n:te:pothana", + "m17n:te:rts", + + /* Urdu */ + "m17n:ur:phonetic", + + /* Inscript2 - https://bugzilla.gnome.org/show_bug.cgi?id=684854 */ + "m17n:as:inscript2", + "m17n:bn:inscript2", + "m17n:brx:inscript2-deva", + "m17n:doi:inscript2-deva", + "m17n:gu:inscript2", + "m17n:hi:inscript2", + "m17n:kn:inscript2", + "m17n:kok:inscript2-deva", + "m17n:mai:inscript2", + "m17n:ml:inscript2", + "m17n:mni:inscript2-beng", + "m17n:mni:inscript2-mtei", + "m17n:mr:inscript2", + "m17n:ne:inscript2-deva", + "m17n:or:inscript2", + "m17n:pa:inscript2-guru", + "m17n:sa:inscript2", + "m17n:sat:inscript2-deva", + "m17n:sat:inscript2-olck", + "m17n:sd:inscript2-deva", + "m17n:ta:inscript2", + "m17n:te:inscript2", + + /* No corresponding XKB map available for the languages */ + + /* Chinese Yi */ + "m17n:ii:phonetic", + + /* Tai-Viet */ + "m17n:tai:sonla", + + /* Kazakh in Arabic script */ + "m17n:kk:arabic", + + /* Yiddish */ + "m17n:yi:yivo", + + /* Canadian Aboriginal languages */ + "m17n:ath:phonetic", + "m17n:bla:phonetic", + "m17n:cr:western", + "m17n:iu:phonetic", + "m17n:nsk:phonetic", + "m17n:oj:phonetic", + + /* Non-trivial engines, like transliteration-based instead of + keymap-based. Confirmation needed that the engines below are + actually used by local language users. */ + + /* Tibetan */ + "m17n:bo:ewts", + "m17n:bo:tcrc", + "m17n:bo:wylie", + + /* Esperanto */ + "m17n:eo:h-f", + "m17n:eo:h", + "m17n:eo:plena", + "m17n:eo:q", + "m17n:eo:vi", + "m17n:eo:x", + + /* Amharic */ + "m17n:am:sera", + + /* Russian */ + "m17n:ru:translit", + + /* Classical Greek */ + "m17n:grc:mizuochi", + + /* Lao */ + "m17n:lo:lrt", + + /* Postfix modifier input methods */ + "m17n:da:post", + "m17n:sv:post", + NULL +}; +#endif /* HAVE_IBUS */ + +static void populate_model (GtkListStore *store, + GtkListStore *active_sources_store); +static GtkWidget *input_chooser_new (GtkWindow *main_window, + GtkListStore *active_sources); +static gboolean input_chooser_get_selected (GtkWidget *chooser, + GtkTreeModel **model, + GtkTreeIter *iter); +static GtkTreeModel *tree_view_get_actual_model (GtkTreeView *tv); + +static gboolean +strv_contains (const gchar * const *strv, + const gchar *str) +{ + const gchar * const *p = strv; + for (p = strv; *p; p++) + if (g_strcmp0 (*p, str) == 0) + return TRUE; + + return FALSE; +} + +#ifdef HAVE_IBUS +static void +clear_ibus (void) +{ + if (shell_name_watch_id > 0) + { + g_bus_unwatch_name (shell_name_watch_id); + shell_name_watch_id = 0; + } + g_cancellable_cancel (ibus_cancellable); + g_clear_object (&ibus_cancellable); + g_clear_pointer (&ibus_engines, g_hash_table_destroy); + g_clear_object (&ibus); +} + +static gchar * +engine_get_display_name (IBusEngineDesc *engine_desc) +{ + const gchar *name; + const gchar *language_code; + const gchar *language; + gchar *display_name; + + name = ibus_engine_desc_get_longname (engine_desc); + language_code = ibus_engine_desc_get_language (engine_desc); + language = ibus_get_language_name (language_code); + + display_name = g_strdup_printf ("%s (%s)", language, name); + + return display_name; +} + +static GDesktopAppInfo * +setup_app_info_for_id (const gchar *id) +{ + GDesktopAppInfo *app_info; + gchar *desktop_file_name; + gchar **strv; + + strv = g_strsplit (id, ":", 2); + desktop_file_name = g_strdup_printf ("ibus-setup-%s.desktop", strv[0]); + g_strfreev (strv); + + app_info = g_desktop_app_info_new (desktop_file_name); + g_free (desktop_file_name); + + return app_info; +} + +static void +input_chooser_repopulate (GtkListStore *active_sources_store) +{ + GtkBuilder *builder; + GtkListStore *model; + + if (!input_chooser) + return; + + builder = g_object_get_data (G_OBJECT (input_chooser), "builder"); + model = GTK_LIST_STORE (gtk_builder_get_object (builder, "input_source_model")); + + gtk_list_store_clear (model); + populate_model (model, active_sources_store); +} + +static void +update_ibus_active_sources (GtkBuilder *builder) +{ + GtkTreeView *tv; + GtkTreeModel *model; + GtkTreeIter iter; + gchar *type, *id; + gboolean ret; + + tv = GTK_TREE_VIEW (WID ("active_input_sources")); + model = tree_view_get_actual_model (tv); + + ret = gtk_tree_model_get_iter_first (model, &iter); + while (ret) + { + gtk_tree_model_get (model, &iter, + TYPE_COLUMN, &type, + ID_COLUMN, &id, + -1); + + if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) + { + IBusEngineDesc *engine_desc = NULL; + GDesktopAppInfo *app_info = NULL; + gchar *display_name = NULL; + + engine_desc = g_hash_table_lookup (ibus_engines, id); + if (engine_desc) + { + display_name = engine_get_display_name (engine_desc); + app_info = setup_app_info_for_id (id); + + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + NAME_COLUMN, display_name, + SETUP_COLUMN, app_info, + -1); + g_free (display_name); + if (app_info) + g_object_unref (app_info); + } + } + + g_free (type); + g_free (id); + + ret = gtk_tree_model_iter_next (model, &iter); + } + + input_chooser_repopulate (GTK_LIST_STORE (model)); +} + +static void +fetch_ibus_engines_result (GObject *object, + GAsyncResult *result, + GtkBuilder *builder) +{ + gboolean show_all_sources; + GList *list, *l; + GError *error; + + error = NULL; + list = ibus_bus_list_engines_async_finish (ibus, result, &error); + + g_clear_object (&ibus_cancellable); + + if (!list && error) + { + g_warning ("Couldn't finish IBus request: %s", error->message); + g_error_free (error); + return; + } + + show_all_sources = g_settings_get_boolean (input_sources_settings, "show-all-sources"); + + /* Maps engine ids to engine description objects */ + ibus_engines = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); + + for (l = list; l; l = l->next) + { + IBusEngineDesc *engine = l->data; + const gchar *engine_id = ibus_engine_desc_get_name (engine); + + if (show_all_sources || strv_contains (supported_ibus_engines, engine_id)) + g_hash_table_replace (ibus_engines, (gpointer)engine_id, engine); + else + g_object_unref (engine); + } + g_list_free (list); + + update_ibus_active_sources (builder); +} + +static void +fetch_ibus_engines (GtkBuilder *builder) +{ + ibus_cancellable = g_cancellable_new (); + + ibus_bus_list_engines_async (ibus, + -1, + ibus_cancellable, + (GAsyncReadyCallback)fetch_ibus_engines_result, + builder); + + /* We've got everything we needed, don't want to be called again. */ + g_signal_handlers_disconnect_by_func (ibus, fetch_ibus_engines, builder); +} + +static void +maybe_start_ibus (void) +{ + /* IBus doesn't export API in the session bus. The only thing + * we have there is a well known name which we can use as a + * sure-fire way to activate it. */ + g_bus_unwatch_name (g_bus_watch_name (G_BUS_TYPE_SESSION, + IBUS_SERVICE_IBUS, + G_BUS_NAME_WATCHER_FLAGS_AUTO_START, + NULL, + NULL, + NULL, + NULL)); +} + +static void +on_shell_appeared (GDBusConnection *connection, + const gchar *name, + const gchar *name_owner, + gpointer data) +{ + GtkBuilder *builder = data; + + if (!ibus) + { + ibus = ibus_bus_new (); + if (ibus_bus_is_connected (ibus)) + fetch_ibus_engines (builder); + else + g_signal_connect_swapped (ibus, "connected", + G_CALLBACK (fetch_ibus_engines), builder); + } + maybe_start_ibus (); +} +#endif /* HAVE_IBUS */ + +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); + +#ifdef HAVE_IBUS + if (ibus_engines) + { + gchar *display_name; + + sources = g_hash_table_get_keys (ibus_engines); + + source_id = NULL; + for (tmp = sources; tmp; tmp = tmp->next) + { + g_free (source_id); + source_id = g_strconcat (INPUT_SOURCE_TYPE_IBUS, tmp->data, NULL); + + if (g_hash_table_contains (active_sources_table, source_id)) + continue; + + display_name = engine_get_display_name (g_hash_table_lookup (ibus_engines, tmp->data)); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + NAME_COLUMN, display_name, + TYPE_COLUMN, INPUT_SOURCE_TYPE_IBUS, + ID_COLUMN, tmp->data, + -1); + g_free (display_name); + } + g_free (source_id); + + g_list_free (sources); + } +#endif + + 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; + gchar *display_name; + GDesktopAppInfo *app_info; + 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)) + { + display_name = NULL; + app_info = NULL; + + if (g_str_equal (type, INPUT_SOURCE_TYPE_XKB)) + { + 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; + } + display_name = g_strdup (name); + } + else if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) + { +#ifdef HAVE_IBUS + IBusEngineDesc *engine_desc = NULL; + + if (ibus_engines) + engine_desc = g_hash_table_lookup (ibus_engines, id); + + if (engine_desc) + { + display_name = engine_get_display_name (engine_desc); + app_info = setup_app_info_for_id (id); + } +#else + g_warning ("IBus input source type specified but IBus support was not compiled"); + continue; +#endif + } + else + { + g_warning ("Unknown input source type '%s'", type); + continue; + } + + gtk_list_store_append (store, &tree_iter); + gtk_list_store_set (store, &tree_iter, + NAME_COLUMN, display_name, + TYPE_COLUMN, type, + ID_COLUMN, id, + SETUP_COLUMN, app_info, + -1); + g_free (display_name); + if (app_info) + g_object_unref (app_info); + } + + g_variant_unref (sources); +} + +static void +update_configuration (GtkTreeModel *model) +{ + GtkTreeIter iter; + gchar *type; + gchar *id; + GVariantBuilder builder; + GVariant *old_sources; + const gchar *old_current_type; + const gchar *old_current_id; + guint old_current_index; + guint old_n_sources; + guint index; + + old_sources = g_settings_get_value (input_sources_settings, KEY_INPUT_SOURCES); + old_current_index = g_settings_get_uint (input_sources_settings, KEY_CURRENT_INPUT_SOURCE); + old_n_sources = g_variant_n_children (old_sources); + + if (old_n_sources > 0 && old_current_index < old_n_sources) + { + g_variant_get_child (old_sources, + old_current_index, + "(&s&s)", + &old_current_type, + &old_current_id); + } + else + { + old_current_type = ""; + old_current_id = ""; + } + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ss)")); + index = 0; + gtk_tree_model_get_iter_first (model, &iter); + do + { + gtk_tree_model_get (model, &iter, + TYPE_COLUMN, &type, + ID_COLUMN, &id, + -1); + if (index != old_current_index && + g_str_equal (type, old_current_type) && + g_str_equal (id, old_current_id)) + { + g_settings_set_uint (input_sources_settings, KEY_CURRENT_INPUT_SOURCE, index); + } + g_variant_builder_add (&builder, "(ss)", type, id); + g_free (type); + g_free (id); + index += 1; + } + while (gtk_tree_model_iter_next (model, &iter)); + + g_settings_set_value (input_sources_settings, KEY_INPUT_SOURCES, g_variant_builder_end (&builder)); + g_settings_apply (input_sources_settings); + + g_variant_unref (old_sources); +} + +static gboolean +get_selected_iter (GtkBuilder *builder, + GtkTreeModel **model, + GtkTreeIter *iter) +{ + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (WID ("active_input_sources"))); + + return gtk_tree_selection_get_selected (selection, model, iter); +} + +static gint +idx_from_model_iter (GtkTreeModel *model, + GtkTreeIter *iter) +{ + GtkTreePath *path; + gint idx; + + path = gtk_tree_model_get_path (model, iter); + if (path == NULL) + return -1; + + idx = gtk_tree_path_get_indices (path)[0]; + gtk_tree_path_free (path); + + return idx; +} + +static void +update_button_sensitivity (GtkBuilder *builder) +{ + GtkWidget *remove_button; + GtkWidget *up_button; + GtkWidget *down_button; + GtkWidget *show_button; + GtkWidget *settings_button; + GtkTreeView *tv; + GtkTreeModel *model; + GtkTreeIter iter; + gint n_active; + gint index; + gboolean settings_sensitive; + GDesktopAppInfo *app_info; + + remove_button = WID("input_source_remove"); + show_button = WID("input_source_show"); + up_button = WID("input_source_move_up"); + down_button = WID("input_source_move_down"); + settings_button = WID("input_source_settings"); + + tv = GTK_TREE_VIEW (WID ("active_input_sources")); + n_active = gtk_tree_model_iter_n_children (gtk_tree_view_get_model (tv), NULL); + + if (get_selected_iter (builder, &model, &iter)) + { + index = idx_from_model_iter (model, &iter); + gtk_tree_model_get (model, &iter, SETUP_COLUMN, &app_info, -1); + } + else + { + index = -1; + app_info = NULL; + } + + settings_sensitive = (index >= 0 && app_info != NULL); + + if (app_info) + g_object_unref (app_info); + + gtk_widget_set_sensitive (remove_button, index >= 0 && n_active > 1); + gtk_widget_set_sensitive (show_button, index >= 0); + gtk_widget_set_sensitive (up_button, index > 0); + gtk_widget_set_sensitive (down_button, index >= 0 && index < n_active - 1); + gtk_widget_set_sensitive (settings_button, settings_sensitive); +} + +static void +set_selected_path (GtkBuilder *builder, + GtkTreePath *path) +{ + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (WID ("active_input_sources"))); + + gtk_tree_selection_select_path (selection, path); +} + +static GtkTreeModel * +tree_view_get_actual_model (GtkTreeView *tv) +{ + GtkTreeModel *filtered_store; + + filtered_store = gtk_tree_view_get_model (tv); + + return gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filtered_store)); +} + +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 *tv; + GtkListStore *child_model; + GtkTreeIter child_iter, filter_iter; + gchar *name; + gchar *type; + gchar *id; + GDesktopAppInfo *app_info = NULL; + + gtk_tree_model_get (model, &iter, + NAME_COLUMN, &name, + TYPE_COLUMN, &type, + ID_COLUMN, &id, + -1); + +#ifdef HAVE_IBUS + if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) + app_info = setup_app_info_for_id (id); +#endif + + tv = GTK_TREE_VIEW (WID ("active_input_sources")); + child_model = GTK_LIST_STORE (tree_view_get_actual_model (tv)); + + gtk_list_store_append (child_model, &child_iter); + + gtk_list_store_set (child_model, &child_iter, + NAME_COLUMN, name, + TYPE_COLUMN, type, + ID_COLUMN, id, + SETUP_COLUMN, app_info, + -1); + g_free (name); + g_free (type); + g_free (id); + if (app_info) + g_object_unref (app_info); + + gtk_tree_model_filter_convert_child_iter_to_iter (GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (tv)), + &filter_iter, + &child_iter); + gtk_tree_selection_select_iter (gtk_tree_view_get_selection (tv), &filter_iter); + + update_button_sensitivity (builder); + update_configuration (GTK_TREE_MODEL (child_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; + GtkWidget *toplevel; + GtkWidget *treeview; + GtkListStore *active_sources; + + g_debug ("add an input source"); + + toplevel = gtk_widget_get_toplevel (WID ("region_notebook")); + treeview = WID ("active_input_sources"); + active_sources = GTK_LIST_STORE (tree_view_get_actual_model (GTK_TREE_VIEW (treeview))); + + chooser = input_chooser_new (GTK_WINDOW (toplevel), active_sources); + g_signal_connect (chooser, "response", + G_CALLBACK (chooser_response), builder); +} + +static void +remove_selected_input (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeModel *child_model; + GtkTreeIter iter; + GtkTreeIter child_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); + + child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_iter, + &iter); + gtk_list_store_remove (GTK_LIST_STORE (child_model), &child_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_configuration (child_model); +} + +static void +move_selected_input_up (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeModel *child_model; + GtkTreeIter iter, prev; + GtkTreeIter child_iter, child_prev; + GtkTreePath *path; + + g_debug ("move selected input source up"); + + if (!get_selected_iter (builder, &model, &iter)) + return; + + prev = iter; + if (!gtk_tree_model_iter_previous (model, &prev)) + return; + + path = gtk_tree_model_get_path (model, &prev); + + child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_iter, + &iter); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_prev, + &prev); + gtk_list_store_swap (GTK_LIST_STORE (child_model), &child_iter, &child_prev); + + set_selected_path (builder, path); + gtk_tree_path_free (path); + + update_button_sensitivity (builder); + update_configuration (child_model); +} + +static void +move_selected_input_down (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeModel *child_model; + GtkTreeIter iter, next; + GtkTreeIter child_iter, child_next; + GtkTreePath *path; + + g_debug ("move selected input source down"); + + if (!get_selected_iter (builder, &model, &iter)) + return; + + next = iter; + if (!gtk_tree_model_iter_next (model, &next)) + return; + + path = gtk_tree_model_get_path (model, &next); + + child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model)); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_iter, + &iter); + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), + &child_next, + &next); + gtk_list_store_swap (GTK_LIST_STORE (child_model), &child_iter, &child_next); + + set_selected_path (builder, path); + gtk_tree_path_free (path); + + update_button_sensitivity (builder); + update_configuration (child_model); +} + +static void +show_selected_layout (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeIter iter; + gchar *type; + gchar *id; + gchar *kbd_viewer_args; + const gchar *xkb_layout; + const gchar *xkb_variant; + + g_debug ("show selected layout"); + + if (!get_selected_iter (builder, &model, &iter)) + return; + + gtk_tree_model_get (model, &iter, + TYPE_COLUMN, &type, + ID_COLUMN, &id, + -1); + + if (g_str_equal (type, INPUT_SOURCE_TYPE_XKB)) + { + 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; + } + } + else if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) + { +#ifdef HAVE_IBUS + IBusEngineDesc *engine_desc = NULL; + + if (ibus_engines) + engine_desc = g_hash_table_lookup (ibus_engines, id); + + if (engine_desc) + { + xkb_layout = ibus_engine_desc_get_layout (engine_desc); + xkb_variant = ""; + } + else + { + g_warning ("Couldn't find IBus input source '%s'", id); + goto exit; + } +#else + g_warning ("IBus input source type specified but IBus support was not compiled"); + goto exit; +#endif + } + else + { + g_warning ("Unknown input source type '%s'", type); + 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); + exit: + g_free (type); + g_free (id); +} + +static void +show_selected_settings (GtkButton *button, gpointer data) +{ + GtkBuilder *builder = data; + GtkTreeModel *model; + GtkTreeIter iter; + GdkAppLaunchContext *ctx; + GDesktopAppInfo *app_info; + gchar *id; + GError *error = NULL; + + g_debug ("show selected layout"); + + if (!get_selected_iter (builder, &model, &iter)) + return; + + gtk_tree_model_get (model, &iter, SETUP_COLUMN, &app_info, -1); + + if (!app_info) + return; + + ctx = gdk_display_get_app_launch_context (gdk_display_get_default ()); + gdk_app_launch_context_set_timestamp (ctx, gtk_get_current_event_time ()); + + gtk_tree_model_get (model, &iter, ID_COLUMN, &id, -1); + g_app_launch_context_setenv (G_APP_LAUNCH_CONTEXT (ctx), + "IBUS_ENGINE_NAME", + id); + g_free (id); + + if (!g_app_info_launch (G_APP_INFO (app_info), NULL, G_APP_LAUNCH_CONTEXT (ctx), &error)) + { + g_warning ("Failed to launch input source setup: %s", error->message); + g_error_free (error); + } + + g_object_unref (ctx); + g_object_unref (app_info); +} + +static gboolean +go_to_shortcuts (GtkLinkButton *button, + CcRegionPanel *panel) +{ + gchar *argv[3]; + argv[0] = "cinnamon-settings"; + argv[1] = "keyboard"; + argv[3] = NULL; + g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL); + return TRUE; +} + +static void +input_sources_changed (GSettings *settings, + gchar *key, + GtkBuilder *builder) +{ + GtkWidget *treeview; + GtkTreeModel *store; + GtkTreePath *path; + GtkTreeIter iter; + GtkTreeModel *model; + + treeview = WID("active_input_sources"); + store = tree_view_get_actual_model (GTK_TREE_VIEW (treeview)); + + if (get_selected_iter (builder, &model, &iter)) + path = gtk_tree_model_get_path (model, &iter); + else + path = NULL; + + gtk_list_store_clear (GTK_LIST_STORE (store)); + populate_with_active_sources (GTK_LIST_STORE (store)); + + if (path) + { + set_selected_path (builder, path); + gtk_tree_path_free (path); + } +} + +static void +update_shortcut_label (GtkWidget *widget, + const char *value) +{ + char *text; + guint accel_key, *keycode; + GdkModifierType mods; + + if (value == NULL || *value == '\0') + { + gtk_label_set_text (GTK_LABEL (widget), "\342\200\224"); + return; + } + gtk_accelerator_parse_with_keycode (value, &accel_key, &keycode, &mods); + if (accel_key == 0 && keycode == NULL && mods == 0) + { + gtk_label_set_text (GTK_LABEL (widget), "\342\200\224"); + g_warning ("Failed to parse keyboard shortcut: '%s'", value); + return; + } + + text = gtk_accelerator_get_label_with_keycode (gtk_widget_get_display (widget), accel_key, *keycode, mods); + g_free (keycode); + gtk_label_set_text (GTK_LABEL (widget), text); + g_free (text); +} + +static void +update_shortcuts (GtkBuilder *builder) +{ + char *previous, *next; + GSettings *settings; + + settings = g_settings_new ("org.cinnamon.settings-daemon.plugins.media-keys"); + + previous = g_settings_get_string (settings, "switch-input-source-backward"); + next = g_settings_get_string (settings, "switch-input-source"); + + update_shortcut_label (WID ("prev-source-shortcut-label"), previous); + update_shortcut_label (WID ("next-source-shortcut-label"), next); + + g_free (previous); + g_free (next); +} + +static gboolean +active_sources_visible_func (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + gchar *display_name; + + gtk_tree_model_get (model, iter, NAME_COLUMN, &display_name, -1); + + if (!display_name) + return FALSE; + + g_free (display_name); + + return TRUE; +} + +void +setup_input_tabs (GtkBuilder *builder, + CcRegionPanel *panel) +{ + GtkWidget *treeview; + GtkTreeViewColumn *column; + GtkCellRenderer *cell; + GtkListStore *store; + GtkTreeModel *filtered_store; + GtkTreeSelection *selection; + + /* 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", NAME_COLUMN); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + store = gtk_list_store_new (N_COLUMNS, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_DESKTOP_APP_INFO); + + gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store)); + + input_sources_settings = g_settings_new (GNOME_DESKTOP_INPUT_SOURCES_DIR); + g_settings_delay (input_sources_settings); + g_object_weak_ref (G_OBJECT (builder), (GWeakNotify) g_object_unref, input_sources_settings); + + if (!xkb_info) + xkb_info = gnome_xkb_info_new (); + +#ifdef HAVE_IBUS + ibus_init (); + shell_name_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, + "org.Cinnamon", + G_BUS_NAME_WATCHER_FLAGS_NONE, + on_shell_appeared, + NULL, + builder, + NULL); + g_object_weak_ref (G_OBJECT (builder), (GWeakNotify) clear_ibus, NULL); +#endif + + populate_with_active_sources (store); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); + g_signal_connect_swapped (selection, "changed", + G_CALLBACK (update_button_sensitivity), builder); + + /* Some input source types might have their info loaded + * asynchronously. In that case we don't want to show them + * immediately so we use a filter model on top of the real model + * which mirrors the GSettings key. */ + filtered_store = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL); + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filtered_store), + active_sources_visible_func, + NULL, + NULL); + gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), filtered_store); + + /* set up the buttons */ + g_signal_connect (WID("input_source_add"), "clicked", + G_CALLBACK (add_input), builder); + g_signal_connect (WID("input_source_remove"), "clicked", + G_CALLBACK (remove_selected_input), builder); + g_signal_connect (WID("input_source_move_up"), "clicked", + G_CALLBACK (move_selected_input_up), builder); + g_signal_connect (WID("input_source_move_down"), "clicked", + G_CALLBACK (move_selected_input_down), builder); + g_signal_connect (WID("input_source_show"), "clicked", + G_CALLBACK (show_selected_layout), builder); + g_signal_connect (WID("input_source_settings"), "clicked", + G_CALLBACK (show_selected_settings), builder); + + /* use an em dash is no shortcut */ + update_shortcuts (builder); + + g_signal_connect (WID("jump-to-shortcuts"), "activate-link", + G_CALLBACK (go_to_shortcuts), panel); + + g_signal_connect (G_OBJECT (input_sources_settings), + "changed::" KEY_INPUT_SOURCES, + G_CALLBACK (input_sources_changed), + builder); +} + +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; + GtkTreeView *tree_view; + GtkTreeSelection *selection; + GtkTreeIter selected_iter; + GtkWidget *filter_entry; + const gchar *pattern; + gchar *upattern; + + 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); + + filtered_model = GTK_TREE_MODEL_FILTER (gtk_builder_get_object (builder, "filtered_input_source_model")); + gtk_tree_model_filter_refilter (filtered_model); + + tree_view = GTK_TREE_VIEW (WID ("filtered_input_source_list")); + selection = gtk_tree_view_get_selection (tree_view); + if (gtk_tree_selection_get_selected (selection, NULL, &selected_iter)) + { + GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (filtered_model), + &selected_iter); + gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.5, 0.5); + gtk_tree_path_free (path); + } + else + { + GtkTreeIter iter; + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (filtered_model), &iter)) + gtk_tree_selection_select_iter (selection, &iter); + } +} + +static void +selection_changed (GtkTreeSelection *selection, + GtkBuilder *builder) +{ + gtk_widget_set_sensitive (WID ("ok-button"), + gtk_tree_selection_get_selected (selection, NULL, 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 void +entry_activated (GtkBuilder *builder, + gpointer data) +{ + row_activated (NULL, NULL, NULL, builder); +} + +static gboolean +filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + gchar *name = NULL; + gchar **pattern; + gboolean rv = TRUE; + + if (search_pattern_list == NULL || search_pattern_list[0] == NULL) + return TRUE; + + gtk_tree_model_get (model, iter, + NAME_COLUMN, &name, + -1); + + pattern = search_pattern_list; + do { + gboolean is_pattern_found = FALSE; + gchar *udesc = g_utf8_strup (name, -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 (name); + + return rv; +} + +static GtkWidget * +input_chooser_new (GtkWindow *main_window, + GtkListStore *active_sources) +{ + GtkBuilder *builder; + GtkWidget *chooser; + GtkWidget *filtered_list; + GtkWidget *filter_entry; + GtkTreeViewColumn *visible_column; + GtkTreeSelection *selection; + GtkListStore *model; + GtkTreeModelFilter *filtered_model; + GtkTreeIter iter; + + builder = gtk_builder_new (); + gtk_builder_set_translation_domain (builder, GETTEXT_PACKAGE); + gtk_builder_add_from_file (builder, + CINNAMONCC_UI_DIR "/cinnamon-region-panel-input-chooser.ui", + NULL); + chooser = WID ("input_source_chooser"); + input_chooser = chooser; + g_object_add_weak_pointer (G_OBJECT (chooser), (gpointer *) &input_chooser); + g_object_set_data_full (G_OBJECT (chooser), "builder", builder, g_object_unref); + + 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 ("Input Sources", + gtk_cell_renderer_text_new (), + "text", NAME_COLUMN, + NULL); + + gtk_window_set_transient_for (GTK_WINDOW (chooser), main_window); + + gtk_tree_view_append_column (GTK_TREE_VIEW (filtered_list), + visible_column); + /* We handle searching ourselves, thank you. */ + gtk_tree_view_set_enable_search (GTK_TREE_VIEW (filtered_list), FALSE); + gtk_tree_view_set_search_column (GTK_TREE_VIEW (filtered_list), -1); + + g_signal_connect_swapped (G_OBJECT (filter_entry), "activate", + G_CALLBACK (entry_activated), builder); + 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); + + 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), + NAME_COLUMN, GTK_SORT_ASCENDING); + + gtk_tree_model_filter_set_visible_func (filtered_model, + filter_func, + NULL, NULL); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (filtered_list)); + + g_signal_connect (G_OBJECT (selection), "changed", + G_CALLBACK (selection_changed), builder); + + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (filtered_model), &iter)) + gtk_tree_selection_select_iter (selection, &iter); + + g_signal_connect (G_OBJECT (filtered_list), "row-activated", + G_CALLBACK (row_activated), builder); + + 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); +} diff -uNrp a/panels/region/cinnamon-region-panel-input-chooser.ui b/panels/region/cinnamon-region-panel-input-chooser.ui --- a/panels/region/cinnamon-region-panel-input-chooser.ui 1970-01-01 01:00:00.000000000 +0100 +++ b/panels/region/cinnamon-region-panel-input-chooser.ui 2013-09-21 13:24:15.339949536 +0100 @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + input_source_model + + + False + False + 5 + Choose an input source + True + center-on-parent + dialog + + + True + False + vertical + 2 + + + True + False + end + + + gtk-cancel + True + True + True + False + False + True + + + False + False + end + 1 + + + + + gtk-add + True + True + True + False + False + True + + + False + False + end + 2 + + + + + + + True + False + 5 + 6 + + + True + False + 6 + + + True + False + 0 + Select an input source to add + + + False + False + 0 + + + + + True + True + never + etched-in + 450 + 250 + + + True + True + filtered_input_source_model + False + 0 + + + + + True + True + 1 + + + + + True + True + 0 + + + + + True + True + + edit-find-symbolic + False + False + + + False + False + end + 1 + + + + + True + True + 1 + + + + + + ok-button + cancel-button + + + diff -uNrp a/panels/region/cinnamon-region-panel-input.h b/panels/region/cinnamon-region-panel-input.h --- a/panels/region/cinnamon-region-panel-input.h 1970-01-01 01:00:00.000000000 +0100 +++ b/panels/region/cinnamon-region-panel-input.h 2013-09-21 13:24:15.339949536 +0100 @@ -0,0 +1,36 @@ +/* cinnamon-region-panel-input.h + * Copyright (C) 2011 Red Hat, Inc. + * + * Written by Matthias Clasen + * + * 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, 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA + * 02110-1335, USA. + */ + +#ifndef __CINNAMON_KEYBOARD_PROPERTY_INPUT_H +#define __CINNAMON_KEYBOARD_PROPERTY_INPUT_H + +#include + +#include "cc-region-panel.h" + +G_BEGIN_DECLS + +void setup_input_tabs (GtkBuilder *builder, + CcRegionPanel *self); + +G_END_DECLS + +#endif /* __CINNAMON_KEYBOARD_PROPERTY_INPUT_H */ diff -uNrp a/panels/region/cinnamon-region-panel-lang.c b/panels/region/cinnamon-region-panel-lang.c --- a/panels/region/cinnamon-region-panel-lang.c 2013-08-25 14:40:14.000000000 +0100 +++ b/panels/region/cinnamon-region-panel-lang.c 2013-09-21 13:24:15.340949500 +0100 @@ -24,7 +24,7 @@ #endif #include -#include +#include #include "cinnamon-region-panel-lang.h" #include "cinnamon-region-panel-formats.h" diff -uNrp a/panels/region/cinnamon-region-panel-lang.h b/panels/region/cinnamon-region-panel-lang.h --- a/panels/region/cinnamon-region-panel-lang.h 2013-08-25 14:40:14.000000000 +0100 +++ b/panels/region/cinnamon-region-panel-lang.h 2013-09-21 13:24:15.340949500 +0100 @@ -19,8 +19,8 @@ * 02110-1335, USA. */ -#ifndef __GNOME_KEYBOARD_PROPERTY_LANG_H -#define __GNOME_KEYBOARD_PROPERTY_LANG_H +#ifndef __CINNAMON_KEYBOARD_PROPERTY_LANG_H +#define __CINNAMON_KEYBOARD_PROPERTY_LANG_H #include @@ -29,4 +29,4 @@ G_BEGIN_DECLS void setup_language (GtkBuilder *builder); G_END_DECLS -#endif /* __GNOME_KEYBOARD_PROPERTY_LANG_H */ +#endif /* __CINNAMON_KEYBOARD_PROPERTY_LANG_H */ diff -uNrp a/panels/region/cinnamon-region-panel-layout-chooser.ui b/panels/region/cinnamon-region-panel-layout-chooser.ui --- a/panels/region/cinnamon-region-panel-layout-chooser.ui 2013-08-25 14:40:14.000000000 +0100 +++ b/panels/region/cinnamon-region-panel-layout-chooser.ui 1970-01-01 01:00:00.000000000 +0100 @@ -1,180 +0,0 @@ - - - - - - - - - - - - - - - - - - - layout_list_model - - - False - False - 5 - Choose a Layout - True - center-on-parent - dialog - - - True - False - vertical - 2 - - - True - False - end - - - Preview - True - True - True - False - - - False - False - 0 - True - - - - - gtk-cancel - True - True - True - False - False - True - - - False - False - end - 1 - - - - - gtk-add - True - True - True - False - False - True - - - False - False - end - 2 - - - - - - - True - False - 5 - 6 - - - True - False - 6 - - - True - False - 0 - Select an input source to add - - - False - False - 0 - - - - - True - True - never - etched-in - 450 - 250 - - - True - True - filtered_layout_list_model - False - 0 - - - - - - - - True - True - 1 - - - - - True - True - 0 - - - - - True - True - - edit-find-symbolic - False - False - - - False - False - end - 1 - - - - - True - True - 1 - - - - - - btnPreview - btnOk - btnCancel - - - diff -uNrp a/panels/region/cinnamon-region-panel-options-dialog.ui b/panels/region/cinnamon-region-panel-options-dialog.ui --- a/panels/region/cinnamon-region-panel-options-dialog.ui 2013-08-25 14:40:14.000000000 +0100 +++ b/panels/region/cinnamon-region-panel-options-dialog.ui 1970-01-01 01:00:00.000000000 +0100 @@ -1,79 +0,0 @@ - - - - - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - Keyboard Layout Options - center-on-parent - 550 - 400 - dialog - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - vertical - 2 - - - True - True - 5 - out - - - True - False - none - - - True - False - - - - - - - False - True - 1 - - - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - end - - - - - - gtk-close - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - True - - - False - False - 1 - - - - - - - - button2 - - - diff -uNrp a/panels/region/cinnamon-region-panel-system.c b/panels/region/cinnamon-region-panel-system.c --- a/panels/region/cinnamon-region-panel-system.c 2013-08-25 14:40:14.000000000 +0100 +++ b/panels/region/cinnamon-region-panel-system.c 2013-09-21 13:24:15.342949428 +0100 @@ -27,15 +27,18 @@ #include -#include +#include + +#define GNOME_DESKTOP_USE_UNSTABLE_API +#include -#include #include "cc-common-language.h" #include "gdm-languages.h" #include "cinnamon-region-panel-system.h" -#include "cinnamon-region-panel-xkb.h" -static GSettings *locale_settings, *xkb_settings; +#define WID(s) GTK_WIDGET(gtk_builder_get_object (dialog, s)) + +static GSettings *locale_settings, *input_sources_settings; static GDBusProxy *localed_proxy; static GPermission *localed_permission; @@ -72,13 +75,14 @@ update_copy_button (GtkBuilder *dialog) button = WID ("copy_settings_button"); - /* If the version of localed doesn't include layouts... */ - if (system_input_source) { + if (user_input_source && user_input_source[0]) { layouts_differ = (g_strcmp0 (user_input_source, system_input_source) != 0); if (layouts_differ == FALSE) layouts_differ = (g_strcmp0 (user_input_variants, system_input_variants) != 0); - } else + } else { + /* Nothing to copy */ layouts_differ = FALSE; + } if (g_strcmp0 (user_lang, system_lang) == 0 && g_strcmp0 (user_region, system_region) == 0 && @@ -131,61 +135,67 @@ system_update_language (GtkBuilder *dial } static void -xkb_settings_changed (GSettings *settings, - const gchar *key, - GtkBuilder *dialog) +input_sources_changed (GSettings *settings, + const gchar *key, + GtkBuilder *dialog) { - guint i; - GString *disp, *list, *variants; - GtkWidget *label; - gchar **layouts; - - layouts = g_settings_get_strv (settings, "layouts"); - if (layouts == NULL) - return; - - label = WID ("user_input_source"); - disp = g_string_new (""); - list = g_string_new (""); - variants = g_string_new (""); - - for (i = 0; layouts[i]; i++) { - gchar *utf_visible; - char **split; - gchar *layout, *variant; - - utf_visible = xkb_layout_description_utf8 (layouts[i]); - if (disp->str[0] != '\0') - g_string_append (disp, ", "); - g_string_append (disp, utf_visible ? utf_visible : layouts[i]); - g_free (utf_visible); - - split = g_strsplit_set (layouts[i], " \t", 2); - - if (split == NULL || split[0] == NULL) - continue; - - layout = split[0]; - variant = split[1]; - - if (list->str[0] != '\0') - g_string_append (list, ","); - g_string_append (list, layout); - - if (variants->str[0] != '\0') - g_string_append (variants, ","); - g_string_append (variants, variant ? variant : ""); - - g_strfreev (split); - } - g_strfreev (layouts); + GString *disp, *list, *variants; + GtkWidget *label; + GnomeXkbInfo *xkb_info; + GVariantIter iter; + GVariant *sources; + const gchar *type; + const gchar *id; + + sources = g_settings_get_value (input_sources_settings, "sources"); + xkb_info = gnome_xkb_info_new (); + + label = WID ("user_input_source"); + disp = g_string_new (""); + list = g_string_new (""); + variants = g_string_new (""); + + g_variant_iter_init (&iter, sources); + while (g_variant_iter_next (&iter, "(&s&s)", &type, &id)) { + /* We can't copy non-XKB layouts to the system yet */ + if (g_str_equal (type, "xkb")) { + char **split; + gchar *layout, *variant; + const char *name; + + gnome_xkb_info_get_layout_info (xkb_info, id, &name, NULL, NULL, NULL); + if (disp->str[0] != '\0') + g_string_append (disp, ", "); + g_string_append (disp, name); + + split = g_strsplit (id, "+", 2); + + if (split == NULL || split[0] == NULL) + continue; + + layout = split[0]; + variant = split[1]; + + if (list->str[0] != '\0') { + g_string_append (list, ","); + g_string_append (variants, ","); + } + g_string_append (list, layout); + g_string_append (variants, variant ? variant : ""); + + g_strfreev (split); + } + } + g_variant_unref (sources); + g_object_unref (xkb_info); g_object_set_data_full (G_OBJECT (label), "input_source", g_string_free (list, FALSE), g_free); g_object_set_data_full (G_OBJECT (label), "input_variants", g_string_free (variants, FALSE), g_free); + gtk_label_set_text (GTK_LABEL (label), disp->str); g_string_free (disp, TRUE); - update_copy_button (dialog); + update_copy_button (dialog); } static void @@ -222,12 +232,13 @@ on_localed_properties_changed (GDBusProx const gchar **invalidated_properties, GtkBuilder *dialog) { - GVariant *v; + GVariant *v, *w; GtkWidget *label; - const char *layout; + GnomeXkbInfo *xkb_info; char **layouts; + char **variants; GString *disp; - guint i; + guint i, n; if (invalidated_properties != NULL) { guint i; @@ -236,6 +247,8 @@ on_localed_properties_changed (GDBusProx update_property (proxy, "Locale"); else if (g_str_equal (invalidated_properties[i], "X11Layout")) update_property (proxy, "X11Layout"); + else if (g_str_equal (invalidated_properties[i], "X11Variant")) + update_property (proxy, "X11Variant"); } } @@ -290,29 +303,56 @@ on_localed_properties_changed (GDBusProx label = WID ("system_input_source"); v = g_dbus_proxy_get_cached_property (proxy, "X11Layout"); if (v) { - layout = g_variant_get_string (v, NULL); - g_object_set_data_full (G_OBJECT (label), "input_source", g_strdup (layout), g_free); - } else { + layouts = g_strsplit (g_variant_get_string (v, NULL), ",", -1); + g_object_set_data_full (G_OBJECT (label), "input_source", + g_variant_dup_string (v, NULL), g_free); + g_variant_unref (v); + } else { g_object_set_data_full (G_OBJECT (label), "input_source", NULL, g_free); update_copy_button (dialog); return; } - disp = g_string_new (""); - layouts = g_strsplit (layout, ",", -1); - for (i = 0; layouts[i]; i++) { - gchar *utf_visible; - - utf_visible = xkb_layout_description_utf8 (layouts[i]); - if (disp->str[0] != '\0') - disp = g_string_append (disp, ", "); - disp = g_string_append (disp, utf_visible ? utf_visible : layouts[i]); - g_free (utf_visible); - } + w = g_dbus_proxy_get_cached_property (proxy, "X11Variant"); + if (w) { + variants = g_strsplit (g_variant_get_string (w, NULL), ",", -1); + g_object_set_data_full (G_OBJECT (label), "input_variants", + g_variant_dup_string (w, NULL), g_free); + g_variant_unref (w); + } else { + variants = NULL; + g_object_set_data_full (G_OBJECT (label), "input_variants", NULL, g_free); + } + + if (variants && variants[0]) + n = MIN (g_strv_length (layouts), g_strv_length (variants)); + else + n = g_strv_length (layouts); + + xkb_info = gnome_xkb_info_new (); + disp = g_string_new (""); + for (i = 0; i < n && layouts[i][0]; i++) { + const char *name; + char *id; + + if (variants && variants[i] && variants[i][0]) + id = g_strdup_printf ("%s+%s", layouts[i], variants[i]); + else + id = g_strdup (layouts[i]); + + gnome_xkb_info_get_layout_info (xkb_info, id, &name, NULL, NULL, NULL); + if (disp->str[0] != '\0') + disp = g_string_append (disp, ", "); + disp = g_string_append (disp, name ? name : id); + + g_free (id); + } gtk_label_set_text (GTK_LABEL (label), disp->str); g_string_free (disp, TRUE); - g_variant_unref (v); + g_strfreev (variants); + g_strfreev (layouts); + g_object_unref (xkb_info); update_copy_button (dialog); } @@ -386,6 +426,11 @@ copy_settings (GtkButton *button, GtkBui layout = g_object_get_data (G_OBJECT (label), "input_source"); variants = g_object_get_data (G_OBJECT (label), "input_variants"); + if (layout == NULL || layout[0] == '\0') { + g_debug ("Not calling SetX11Keyboard, as there are no XKB input sources in the user's settings"); + return; + } + g_dbus_proxy_call (localed_proxy, "SetX11Keyboard", g_variant_new ("(ssssbb)", layout, "", variants ? variants : "", "", TRUE, TRUE), @@ -468,10 +513,10 @@ setup_system (GtkBuilder *dialog) G_CALLBACK (locale_settings_changed), dialog); g_object_weak_ref (G_OBJECT (dialog), (GWeakNotify) g_object_unref, locale_settings); - xkb_settings = g_settings_new (GKBD_KEYBOARD_SCHEMA); - g_signal_connect (xkb_settings, "changed::layouts", - G_CALLBACK (xkb_settings_changed), dialog); - g_object_weak_ref (G_OBJECT (dialog), (GWeakNotify) g_object_unref, xkb_settings); + input_sources_settings = g_settings_new ("org.cinnamon.desktop.input-sources"); + g_signal_connect (input_sources_settings, "changed::sources", + G_CALLBACK (input_sources_changed), dialog); + g_object_weak_ref (G_OBJECT (dialog), (GWeakNotify) g_object_unref, input_sources_settings); /* Display user settings */ language = cc_common_language_get_current_language (); @@ -480,7 +525,7 @@ setup_system (GtkBuilder *dialog) locale_settings_changed (locale_settings, "region", dialog); - xkb_settings_changed (xkb_settings, "layouts", dialog); + input_sources_changed (input_sources_settings, "sources", dialog); bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL); g_dbus_proxy_new (bus, diff -uNrp a/panels/region/cinnamon-region-panel-system.h b/panels/region/cinnamon-region-panel-system.h --- a/panels/region/cinnamon-region-panel-system.h 2013-08-25 14:40:14.000000000 +0100 +++ b/panels/region/cinnamon-region-panel-system.h 2013-09-21 13:24:15.342949428 +0100 @@ -19,8 +19,8 @@ * 02110-1335, USA. */ -#ifndef __GNOME_REGION_PANEL_SYSTEM_H -#define __GNOME_REGION_PANEL_SYSTEM_H +#ifndef __CINNAMON_REGION_PANEL_SYSTEM_H +#define __CINNAMON_REGION_PANEL_SYSTEM_H #include diff -uNrp a/panels/region/cinnamon-region-panel.ui b/panels/region/cinnamon-region-panel.ui --- a/panels/region/cinnamon-region-panel.ui 2013-08-25 14:40:14.000000000 +0100 +++ b/panels/region/cinnamon-region-panel.ui 2013-09-21 13:24:15.347949247 +0100 @@ -162,27 +162,17 @@ + + False True - False Add Language - True - list-add-symbolic - - - False - True - - - - - True - False False - Remove Language True - list-remove-symbolic + list-add-symbolic False @@ -198,12 +188,13 @@ - True False True False + True + Add Language True @@ -212,23 +203,24 @@ - - button + + Install languages... True True True + True - True + False True - 13 + 1 False True - 2 + 1 @@ -305,19 +297,19 @@ - True - False icons False 1 + True + False + Add Region True False - Add Region True list-add-symbolic @@ -328,10 +320,11 @@ + False True + Remove Region False False - Remove Region True list-remove-symbolic @@ -373,18 +366,6 @@ 9 2 - - - - - - - - - - - - True False @@ -626,6 +607,12 @@ 1 + + + + + + 1 @@ -643,36 +630,43 @@ - + True False - 10 + 12 12 - + + True + False + 0 + Select keyboards or other input sources + + + False + False + 0 + - + True False 12 - + True False - + True True in - + True True False - - - @@ -683,7 +677,7 @@ - + True False icons @@ -693,70 +687,166 @@ - + True - False - Add Layout - True - list-add-symbolic + + + True + + + True + + + Add Input Source + + + + + + True + list-add-symbolic + 1 + + + + + + + True + + + Remove Input Source + + + + + True + list-remove-symbolic + 1 + + + + + + - - False - True - + - + True - False - Remove Layout - True - list-remove-symbolic + False - False - True + True + - + True - False - Move Up - True - go-up-symbolic + + + True + + + True + + + Move Input Source Up + + + + + + True + go-up-symbolic + 1 + + + + + + + True + + + Move Input Source Down + + + + + True + go-down-symbolic + 1 + + + + + + - - False - True - + - + True - False - Move Down - True - go-down-symbolic + False + True - False - True + True + - + True - False - Preview Layout - True - input-keyboard-symbolic + + + True + + + True + + + Input Source Settings + + + + + + True + preferences-system-symbolic + 1 + 16 + + + + + + + True + + + Show Keyboard Layout + + + + + + True + input-keyboard-symbolic + 1 + + + + + + - - False - True - + False @@ -772,168 +862,111 @@ - + True False - 12 + 0 + none - + True False - 6 + 12 - - Use the same layout for all windows - True - True - False - 0 - True - True - - - True - True - 0 - - - - - Allow different layouts for individual windows - True - True - False - 0 - True - True - chk_same_group - - - True - True - 1 - - - - + True False - 12 + 6 + 6 + 6 - + True False - - - New windows use the default layout - True - True - False - 0 - True - True - - - True - True - 0 - - - - - New windows use the previous window's layout - True - True - False - 0 - True - True - chk_new_windows_default_layout - - - True - True - 1 - - + 0 + Switch to previous source + + 0 + 0 + 1 + 1 + + + + + True + False + end + True + Ctrl+Alt+Space + + + + 1 + 0 + 1 + 1 + + + + + True + False + 0 + Switch to next source + + + 0 + 1 + 1 + 1 + + + + + True + False + end + True + Ctrl+Alt+Shift+Space + + + + 1 + 1 + 1 + 1 + + + + + True + True + Shortcut Settings + end + + + 1 + 2 + 1 + 1 + - - True - True - 2 - - - False - False - 0 - - - - - True - False - - - True - False - 1 - - - + + True False - 6 - end - - - _Options... - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - View and edit keyboard layout options - View and edit keyboard layout options - True - - - False - False - 0 - - - - - Reset to De_faults - True - True - True - True - Replace the current keyboard layout settings with the -default settings - Replace the current keyboard layout settings with the -default settings - True - - - False - False - end - 1 - True - - + Shortcuts + True + + + - - False - False - 2 - @@ -951,17 +984,17 @@ default settings - 2 + 3 - + True False - Keyboard Layouts + Input Sources - 2 + 3 False @@ -974,9 +1007,6 @@ default settings 12 12 - - - True False @@ -1051,6 +1081,7 @@ default settings 2 3 3 + GTK_FILL @@ -1060,6 +1091,7 @@ default settings 0 0 True + 18 1 @@ -1068,6 +1100,7 @@ default settings 2 3 3 + GTK_FILL @@ -1178,6 +1211,7 @@ default settings 2 3 3 + GTK_FILL @@ -1187,6 +1221,7 @@ default settings 0 0 True + 18 1 @@ -1195,6 +1230,7 @@ default settings 2 3 3 + GTK_FILL @@ -1254,6 +1290,7 @@ default settings Copy Settings... + False True True True @@ -1269,9 +1306,12 @@ default settings 3 + + + - 3 + 4 @@ -1281,7 +1321,7 @@ default settings System - 3 + 4 False @@ -1302,4 +1342,11 @@ default settings + + vertical + + + + + diff -uNrp a/panels/region/cinnamon-region-panel-xkb.c b/panels/region/cinnamon-region-panel-xkb.c --- a/panels/region/cinnamon-region-panel-xkb.c 2013-08-25 14:40:14.000000000 +0100 +++ b/panels/region/cinnamon-region-panel-xkb.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,190 +0,0 @@ -/* cinnamon-region-panel-xkb.c - * Copyright (C) 2003-2007 Sergey V. Udaltsov - * - * Written by: Sergey V. Udaltsov - * - * 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, 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA - * 02110-1335, USA. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include - -#include "cinnamon-region-panel-xkb.h" - -#include - -XklEngine *engine; -XklConfigRegistry *config_registry; - -GkbdKeyboardConfig initial_config; -GkbdDesktopConfig desktop_config; - -GSettings *xkb_keyboard_settings; -GSettings *xkb_desktop_settings; - -char * -xci_desc_to_utf8 (const XklConfigItem * ci) -{ - gchar *dd = g_strdup (ci->description); - gchar *sd = g_strstrip (dd); - gchar *rv = g_strdup (sd[0] == 0 ? ci->name : sd); - g_free (dd); - return rv; -} - -static void -cleanup_xkb_tabs (GtkBuilder * dialog, - GObject *where_the_object_wa) -{ - gkbd_desktop_config_term (&desktop_config); - gkbd_keyboard_config_term (&initial_config); - g_object_unref (G_OBJECT (config_registry)); - config_registry = NULL; - /* Don't unref it here, or we'll crash if open the panel again */ - engine = NULL; - g_object_unref (G_OBJECT (xkb_keyboard_settings)); - g_object_unref (G_OBJECT (xkb_desktop_settings)); - xkb_keyboard_settings = NULL; - xkb_desktop_settings = NULL; -} - -static void -reset_to_defaults (GtkWidget * button, GtkBuilder * dialog) -{ - GkbdKeyboardConfig empty_kbd_config; - - gkbd_keyboard_config_init (&empty_kbd_config, engine); - gkbd_keyboard_config_save (&empty_kbd_config); - gkbd_keyboard_config_term (&empty_kbd_config); - - g_settings_reset (xkb_desktop_settings, - GKBD_DESKTOP_CONFIG_KEY_DEFAULT_GROUP); - - /* all the rest is g-s-d's business */ -} - -static void -chk_new_windows_inherit_layout_toggled (GtkWidget * - chk_new_windows_inherit_layout, - GtkBuilder * dialog) -{ - xkb_save_default_group (gtk_toggle_button_get_active - (GTK_TOGGLE_BUTTON - (chk_new_windows_inherit_layout)) ? -1 : - 0); -} - -void -setup_xkb_tabs (GtkBuilder * dialog) -{ - GtkWidget *widget; - GtkStyleContext *context; - GtkWidget *chk_new_windows_inherit_layout; - - chk_new_windows_inherit_layout = WID ("chk_new_windows_inherit_layout"); - - xkb_desktop_settings = g_settings_new (GKBD_DESKTOP_SCHEMA); - xkb_keyboard_settings = g_settings_new (GKBD_KEYBOARD_SCHEMA); - - engine = - xkl_engine_get_instance (GDK_DISPLAY_XDISPLAY - (gdk_display_get_default ())); - config_registry = xkl_config_registry_get_instance (engine); - - gkbd_desktop_config_init (&desktop_config, engine); - gkbd_desktop_config_load (&desktop_config); - - xkl_config_registry_load (config_registry, - desktop_config.load_extra_items); - - gkbd_keyboard_config_init (&initial_config, engine); - gkbd_keyboard_config_load_from_x_initial (&initial_config, NULL); - - /* Set initial state */ - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (WID ("chk_separate_group_per_window")), - g_settings_get_boolean (xkb_desktop_settings, - GKBD_DESKTOP_CONFIG_KEY_GROUP_PER_WINDOW)); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (chk_new_windows_inherit_layout), - xkb_get_default_group () < 0); - - g_settings_bind (xkb_desktop_settings, - GKBD_DESKTOP_CONFIG_KEY_GROUP_PER_WINDOW, - WID ("chk_separate_group_per_window"), "active", - G_SETTINGS_BIND_DEFAULT); - g_settings_bind (xkb_desktop_settings, - GKBD_DESKTOP_CONFIG_KEY_GROUP_PER_WINDOW, - WID ("chk_new_windows_inherit_layout"), "sensitive", - G_SETTINGS_BIND_DEFAULT); - g_settings_bind (xkb_desktop_settings, - GKBD_DESKTOP_CONFIG_KEY_GROUP_PER_WINDOW, - WID ("chk_new_windows_default_layout"), "sensitive", - G_SETTINGS_BIND_DEFAULT); - - xkb_layouts_prepare_selected_tree (dialog); - xkb_layouts_fill_selected_tree (dialog); - - xkb_layouts_register_buttons_handlers (dialog); - g_signal_connect (G_OBJECT (WID ("xkb_reset_to_defaults")), - "clicked", G_CALLBACK (reset_to_defaults), - dialog); - - g_signal_connect (G_OBJECT (chk_new_windows_inherit_layout), - "toggled", - G_CALLBACK - (chk_new_windows_inherit_layout_toggled), - dialog); - - g_signal_connect_swapped (G_OBJECT (WID ("xkb_layout_options")), - "clicked", - G_CALLBACK (xkb_options_popup_dialog), - dialog); - - xkb_layouts_register_conf_listener (dialog); - xkb_options_register_conf_listener (dialog); - - g_object_weak_ref (G_OBJECT (WID ("region_notebook")), - (GWeakNotify) cleanup_xkb_tabs, dialog); - - enable_disable_restoring (dialog); - - /* Setup junction between toolbar and treeview */ - widget = WID ("xkb_layouts_swindow"); - context = gtk_widget_get_style_context (widget); - gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM); - widget = WID ("layouts-toolbar"); - context = gtk_widget_get_style_context (widget); - gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP); -} - -void -enable_disable_restoring (GtkBuilder * dialog) -{ - GkbdKeyboardConfig gswic; - gboolean enable; - - gkbd_keyboard_config_init (&gswic, engine); - gkbd_keyboard_config_load (&gswic, NULL); - - enable = !gkbd_keyboard_config_equals (&gswic, &initial_config); - - gkbd_keyboard_config_term (&gswic); - gtk_widget_set_sensitive (WID ("xkb_reset_to_defaults"), enable); -} diff -uNrp a/panels/region/cinnamon-region-panel-xkb.h b/panels/region/cinnamon-region-panel-xkb.h --- a/panels/region/cinnamon-region-panel-xkb.h 2013-08-25 14:40:14.000000000 +0100 +++ b/panels/region/cinnamon-region-panel-xkb.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,96 +0,0 @@ -/* cinnamon-region-panel-xkb.h - * Copyright (C) 2003-2007 Sergey V Udaltsov - * - * Written by Sergey V. Udaltsov - * - * 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, 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA - * 02110-1335, USA. - */ - -#ifndef __GNOME_KEYBOARD_PROPERTY_XKB_H -#define __GNOME_KEYBOARD_PROPERTY_XKB_H - -#include - -#include "libgnomekbd/gkbd-keyboard-config.h" -#include "libgnomekbd/gkbd-util.h" - -G_BEGIN_DECLS -#define CWID(s) GTK_WIDGET (gtk_builder_get_object (chooser_dialog, s)) -#define WID(s) GTK_WIDGET (gtk_builder_get_object (dialog, s)) -extern XklEngine *engine; -extern XklConfigRegistry *config_registry; -extern GSettings *xkb_keyboard_settings; -extern GSettings *xkb_desktop_settings; -extern GkbdKeyboardConfig initial_config; - -extern void setup_xkb_tabs (GtkBuilder * dialog); - -extern void xkb_layouts_fill_selected_tree (GtkBuilder * dialog); - -extern void xkb_layouts_register_buttons_handlers (GtkBuilder * dialog); - -extern void xkb_layouts_register_conf_listener (GtkBuilder * dialog); - -extern void xkb_options_register_conf_listener (GtkBuilder * dialog); - -extern void xkb_layouts_prepare_selected_tree (GtkBuilder * dialog); - -extern void xkb_options_load_options (GtkBuilder * dialog); - -extern void xkb_options_popup_dialog (GtkBuilder * dialog); - -extern char *xci_desc_to_utf8 (const XklConfigItem * ci); - -extern gchar *xkb_layout_description_utf8 (const gchar * visible); - -extern void enable_disable_restoring (GtkBuilder * dialog); - -extern void preview_toggled (GtkBuilder * dialog, GtkWidget * button); - -extern GtkWidget *xkb_layout_choose (GtkBuilder * dialog); - -extern void xkb_layout_chooser_response (GtkDialog *dialog, gint response_id); - -extern gchar **xkb_layouts_get_selected_list (void); - -extern gchar **xkb_options_get_selected_list (void); - -#define xkb_layouts_set_selected_list(list) \ - g_settings_set_strv (xkb_keyboard_settings, \ - GKBD_KEYBOARD_CONFIG_KEY_LAYOUTS, \ - (const gchar *const*)(list)) - -#define xkb_options_set_selected_list(list) \ - g_settings_set_strv (xkb_keyboard_settings, \ - GKBD_KEYBOARD_CONFIG_KEY_OPTIONS, \ - (const gchar *const*)(list)) - -extern GtkWidget *xkb_layout_preview_create_widget (GtkBuilder * - chooser_dialog); - -extern void xkb_layout_preview_update (GtkBuilder * chooser_dialog); - -extern void xkb_layout_preview_set_drawing_layout (GtkWidget * kbdraw, - const gchar * id); - -extern gchar *xkb_layout_chooser_get_selected_id (GtkDialog *dialog); - -extern void xkb_save_default_group (gint group_no); - -extern gint xkb_get_default_group (void); - -G_END_DECLS -#endif /* __GNOME_KEYBOARD_PROPERTY_XKB_H */ diff -uNrp a/panels/region/cinnamon-region-panel-xkbltadd.c b/panels/region/cinnamon-region-panel-xkbltadd.c --- a/panels/region/cinnamon-region-panel-xkbltadd.c 2013-08-25 14:40:14.000000000 +0100 +++ b/panels/region/cinnamon-region-panel-xkbltadd.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,495 +0,0 @@ -/* cinnamon-region-panel-xkbltadd.c - * Copyright (C) 2007 Sergey V. Udaltsov - * - * Written by: Sergey V. Udaltsov - * - * 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, 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA - * 02110-1335, USA. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#include -#include - -#include "cinnamon-region-panel-xkb.h" - -enum { - COMBO_BOX_MODEL_COL_SORT, - COMBO_BOX_MODEL_COL_VISIBLE, - COMBO_BOX_MODEL_COL_XKB_ID, - COMBO_BOX_MODEL_COL_COUNTRY_DESC, - COMBO_BOX_MODEL_COL_LANGUAGE_DESC -}; - -static gchar **search_pattern_list = NULL; - -static GtkWidget *preview_dialog = NULL; - -static GRegex *left_bracket_regex = NULL; - -#define RESPONSE_PREVIEW 1 - -static void -xkb_preview_destroy_callback (GtkWidget * widget) -{ - preview_dialog = NULL; -} - -static gboolean -xkb_layout_chooser_selection_dupe (GtkDialog * dialog) -{ - gchar *selected_id = - (gchar *) xkb_layout_chooser_get_selected_id (dialog); - gchar **layouts_list, **pl; - gboolean rv = FALSE; - if (selected_id == NULL) - return rv; - layouts_list = pl = xkb_layouts_get_selected_list (); - while (pl && *pl) { - if (!g_ascii_strcasecmp (*pl++, selected_id)) { - rv = TRUE; - break; - } - } - g_strfreev (layouts_list); - return rv; -} - -void -xkb_layout_chooser_response (GtkDialog * dialog, gint response) -{ - switch (response) - case GTK_RESPONSE_OK:{ - /* Handled by the main code */ - break; - case RESPONSE_PREVIEW:{ - gchar *selected_id = (gchar *) - xkb_layout_chooser_get_selected_id - (dialog); - - if (selected_id != NULL) { - if (preview_dialog == NULL) { - preview_dialog = - gkbd_keyboard_drawing_dialog_new - (); - g_signal_connect (G_OBJECT - (preview_dialog), - "destroy", - G_CALLBACK - (xkb_preview_destroy_callback), - NULL); - /* Put into the separate group to avoid conflict - with modal parent */ - gtk_window_group_add_window - (gtk_window_group_new - (), - GTK_WINDOW - (preview_dialog)); - }; - gkbd_keyboard_drawing_dialog_set_layout - (preview_dialog, - config_registry, selected_id); - - gtk_widget_show_all - (preview_dialog); - } - } - - return; - } - if (preview_dialog != NULL) { - gtk_widget_destroy (preview_dialog); - } - if (search_pattern_list != NULL) { - g_strfreev (search_pattern_list); - search_pattern_list = NULL; - } - gtk_widget_destroy (GTK_WIDGET (dialog)); -} - -static gchar * -xkl_create_description_from_list (const XklConfigItem * item, - const XklConfigItem * subitem, - const gchar * prop_name, - const gchar * - (*desc_getter) (const gchar * code)) -{ - gchar *rv = NULL, *code = NULL; - gchar **list = NULL; - const gchar *desc; - - if (subitem != NULL) - list = - (gchar - **) (g_object_get_data (G_OBJECT (subitem), - prop_name)); - if (list == NULL || *list == 0) - list = - (gchar - **) (g_object_get_data (G_OBJECT (item), prop_name)); - - /* First try the parent id as such */ - desc = desc_getter (item->name); - if (desc != NULL) { - rv = g_utf8_strup (desc, -1); - } else { - code = g_utf8_strup (item->name, -1); - desc = desc_getter (code); - if (desc != NULL) { - rv = g_utf8_strup (desc, -1); - } - g_free (code); - } - - if (list == NULL || *list == 0) - return rv; - - while (*list != 0) { - code = *list++; - desc = desc_getter (code); - if (desc != NULL) { - gchar *udesc = g_utf8_strup (desc, -1); - if (rv == NULL) { - rv = udesc; - } else { - gchar *orv = rv; - rv = g_strdup_printf ("%s %s", rv, udesc); - g_free (orv); - g_free (udesc); - } - } - } - return rv; -} - -static void -xkl_layout_add_to_list (XklConfigRegistry * config, - const XklConfigItem * item, - const XklConfigItem * subitem, - GtkBuilder * chooser_dialog) -{ - GtkListStore *list_store = - GTK_LIST_STORE (gtk_builder_get_object (chooser_dialog, - "layout_list_model")); - GtkTreeIter iter; - - gchar *utf_variant_name = - subitem ? - xkb_layout_description_utf8 (gkbd_keyboard_config_merge_items - (item->name, - subitem->name)) : - xci_desc_to_utf8 (item); - - const gchar *xkb_id = - subitem ? gkbd_keyboard_config_merge_items (item->name, - subitem->name) : - item->name; - - gchar *country_desc = - xkl_create_description_from_list (item, subitem, - XCI_PROP_COUNTRY_LIST, - xkl_get_country_name); - gchar *language_desc = - xkl_create_description_from_list (item, subitem, - XCI_PROP_LANGUAGE_LIST, - xkl_get_language_name); - - gchar *tmp = utf_variant_name; - utf_variant_name = - g_regex_replace_literal (left_bracket_regex, tmp, -1, 0, - "<", 0, NULL); - g_free (tmp); - - if (subitem - && g_object_get_data (G_OBJECT (subitem), - XCI_PROP_EXTRA_ITEM)) { - gchar *buf = - g_strdup_printf ("%s", utf_variant_name); - gtk_list_store_insert_with_values (list_store, &iter, -1, - COMBO_BOX_MODEL_COL_SORT, - utf_variant_name, - COMBO_BOX_MODEL_COL_VISIBLE, - buf, - COMBO_BOX_MODEL_COL_XKB_ID, - xkb_id, - COMBO_BOX_MODEL_COL_COUNTRY_DESC, - country_desc, - COMBO_BOX_MODEL_COL_LANGUAGE_DESC, - language_desc, -1); - g_free (buf); - } else - gtk_list_store_insert_with_values (list_store, &iter, - -1, - COMBO_BOX_MODEL_COL_SORT, - utf_variant_name, - COMBO_BOX_MODEL_COL_VISIBLE, - utf_variant_name, - COMBO_BOX_MODEL_COL_XKB_ID, - xkb_id, - COMBO_BOX_MODEL_COL_COUNTRY_DESC, - country_desc, - COMBO_BOX_MODEL_COL_LANGUAGE_DESC, - language_desc, -1); - g_free (utf_variant_name); - g_free (country_desc); - g_free (language_desc); -} - -static void -xkb_layout_filter_clear (GtkEntry * entry, - GtkEntryIconPosition icon_pos, - GdkEvent * event, gpointer user_data) -{ - gtk_entry_set_text (entry, ""); -} - -static void -xkb_layout_filter_changed (GtkBuilder * chooser_dialog) -{ - GtkTreeModelFilter *filtered_model = - GTK_TREE_MODEL_FILTER (gtk_builder_get_object (chooser_dialog, - "filtered_layout_list_model")); - GtkWidget *xkb_layout_filter = CWID ("xkb_layout_filter"); - const gchar *pattern = - gtk_entry_get_text (GTK_ENTRY (xkb_layout_filter)); - gchar *upattern = g_utf8_strup (pattern, -1); - - if (!g_strcmp0 (pattern, "")) { - g_object_set (G_OBJECT (xkb_layout_filter), - "secondary-icon-name", "edit-find-symbolic", - "secondary-icon-activatable", FALSE, - "secondary-icon-sensitive", FALSE, NULL); - } else { - g_object_set (G_OBJECT (xkb_layout_filter), - "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 -xkb_layout_chooser_selection_changed (GtkTreeSelection * selection, - GtkBuilder * chooser_dialog) -{ - GList *selected_layouts = - gtk_tree_selection_get_selected_rows (selection, NULL); - GtkWidget *add_button = CWID ("btnOk"); - GtkWidget *preview_button = CWID ("btnPreview"); - gboolean anything_selected = g_list_length (selected_layouts) == 1; - gboolean dupe = - xkb_layout_chooser_selection_dupe (GTK_DIALOG - (CWID - ("xkb_layout_chooser"))); - - gtk_widget_set_sensitive (add_button, anything_selected && !dupe); - gtk_widget_set_sensitive (preview_button, anything_selected); -} - -static void -xkb_layout_chooser_row_activated (GtkTreeView * tree_view, - GtkTreePath * path, - GtkTreeViewColumn * column, - GtkBuilder * chooser_dialog) -{ - GtkWidget *add_button = CWID ("btnOk"); - GtkWidget *dialog = CWID ("xkb_layout_chooser"); - - if (gtk_widget_is_sensitive (add_button)) - gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); -} - -static gboolean -xkb_filter_layouts (GtkTreeModel * model, - GtkTreeIter * iter, gpointer data) -{ - gchar *desc = NULL, *country_desc = NULL, *language_desc = - NULL, **pattern; - gboolean rv = TRUE; - - if (search_pattern_list == NULL || search_pattern_list[0] == NULL) - return TRUE; - - gtk_tree_model_get (model, iter, - COMBO_BOX_MODEL_COL_SORT, &desc, - COMBO_BOX_MODEL_COL_COUNTRY_DESC, - &country_desc, - COMBO_BOX_MODEL_COL_LANGUAGE_DESC, - &language_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; - } else if (country_desc != NULL - && g_strstr_len (country_desc, -1, *pattern)) { - is_pattern_found = TRUE; - } else if (language_desc != NULL - && g_strstr_len (language_desc, -1, *pattern)) { - is_pattern_found = TRUE; - } - g_free (udesc); - - if (!is_pattern_found) { - rv = FALSE; - break; - } - - } while (*++pattern != NULL); - - g_free (desc); - g_free (country_desc); - g_free (language_desc); - return rv; -} - -GtkWidget * -xkb_layout_choose (GtkBuilder * dialog) -{ - GtkBuilder *chooser_dialog = gtk_builder_new (); - GtkWidget *chooser, *xkb_filtered_layouts_list, *xkb_layout_filter; - GtkTreeViewColumn *visible_column; - GtkTreeSelection *selection; - GtkListStore *model; - GtkTreeModelFilter *filtered_model; - gtk_builder_set_translation_domain (chooser_dialog, GETTEXT_PACKAGE); - gtk_builder_add_from_file (chooser_dialog, CINNAMONCC_UI_DIR - "/cinnamon-region-panel-layout-chooser.ui", - NULL); - chooser = CWID ("xkb_layout_chooser"); - xkb_filtered_layouts_list = CWID ("xkb_filtered_layouts_list"); - xkb_layout_filter = CWID ("xkb_layout_filter"); - - g_object_set_data (G_OBJECT (chooser), "xkb_filtered_layouts_list", - xkb_filtered_layouts_list); - visible_column = - gtk_tree_view_column_new_with_attributes ("Layout", - gtk_cell_renderer_text_new - (), "markup", - COMBO_BOX_MODEL_COL_VISIBLE, - NULL); - - gtk_window_set_transient_for (GTK_WINDOW (chooser), - GTK_WINDOW - (gtk_widget_get_toplevel - (WID ("region_notebook")))); - - gtk_tree_view_append_column (GTK_TREE_VIEW - (xkb_filtered_layouts_list), - visible_column); - g_signal_connect_swapped (G_OBJECT (xkb_layout_filter), - "notify::text", - G_CALLBACK - (xkb_layout_filter_changed), - chooser_dialog); - - g_signal_connect (G_OBJECT (xkb_layout_filter), "icon-release", - G_CALLBACK (xkb_layout_filter_clear), NULL); - - selection = - gtk_tree_view_get_selection (GTK_TREE_VIEW - (xkb_filtered_layouts_list)); - - g_signal_connect (G_OBJECT (selection), - "changed", - G_CALLBACK - (xkb_layout_chooser_selection_changed), - chooser_dialog); - - xkb_layout_chooser_selection_changed (selection, chooser_dialog); - - g_signal_connect (G_OBJECT (xkb_filtered_layouts_list), - "row-activated", - G_CALLBACK (xkb_layout_chooser_row_activated), - chooser_dialog); - - filtered_model = - GTK_TREE_MODEL_FILTER (gtk_builder_get_object - (chooser_dialog, - "filtered_layout_list_model")); - model = - GTK_LIST_STORE (gtk_builder_get_object - (chooser_dialog, "layout_list_model")); - - left_bracket_regex = g_regex_new ("<", 0, 0, NULL); - - xkl_config_registry_search_by_pattern (config_registry, - NULL, - (TwoConfigItemsProcessFunc) - (xkl_layout_add_to_list), - chooser_dialog); - - g_regex_unref (left_bracket_regex); - - gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), - COMBO_BOX_MODEL_COL_SORT, - GTK_SORT_ASCENDING); - - gtk_tree_model_filter_set_visible_func (filtered_model, - xkb_filter_layouts, - NULL, NULL); - - gtk_widget_grab_focus (xkb_layout_filter); - - gtk_widget_show (chooser); - - return chooser; -} - -gchar * -xkb_layout_chooser_get_selected_id (GtkDialog * dialog) -{ - GtkTreeModel *filtered_list_model; - GtkWidget *xkb_filtered_layouts_list = - g_object_get_data (G_OBJECT (dialog), - "xkb_filtered_layouts_list"); - GtkTreeIter viter; - gchar *v_id; - GtkTreeSelection *selection = - gtk_tree_view_get_selection (GTK_TREE_VIEW - (xkb_filtered_layouts_list)); - GList *selected_layouts = - gtk_tree_selection_get_selected_rows (selection, - &filtered_list_model); - - if (g_list_length (selected_layouts) != 1) - return NULL; - - gtk_tree_model_get_iter (filtered_list_model, - &viter, - (GtkTreePath *) (selected_layouts->data)); - g_list_foreach (selected_layouts, - (GFunc) gtk_tree_path_free, NULL); - g_list_free (selected_layouts); - - gtk_tree_model_get (filtered_list_model, &viter, - COMBO_BOX_MODEL_COL_XKB_ID, &v_id, -1); - - return v_id; -} diff -uNrp a/panels/region/cinnamon-region-panel-xkblt.c b/panels/region/cinnamon-region-panel-xkblt.c --- a/panels/region/cinnamon-region-panel-xkblt.c 2013-08-25 14:40:14.000000000 +0100 +++ b/panels/region/cinnamon-region-panel-xkblt.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,470 +0,0 @@ -/* cinnamon-region-panel-xkblt.c - * Copyright (C) 2003-2007 Sergey V. Udaltsov - * - * Written by: Sergey V. Udaltsov - * - * 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, 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA - * 02110-1335, USA. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include - -#include -#include - -#include "cinnamon-region-panel-xkb.h" - -enum { - SEL_LAYOUT_TREE_COL_DESCRIPTION, - SEL_LAYOUT_TREE_COL_ID, - SEL_LAYOUT_TREE_COL_ENABLED, - SEL_LAYOUT_N_COLS -}; - -static int idx2select = -1; -static int max_selected_layouts = -1; - -static GtkCellRenderer *text_renderer; - -static gboolean disable_buttons_sensibility_update = FALSE; - -static gboolean -get_selected_iter (GtkBuilder *dialog, - GtkTreeModel **model, - GtkTreeIter *iter) -{ - GtkTreeSelection *selection; - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (WID ("xkb_layouts_selected"))); - - return gtk_tree_selection_get_selected (selection, model, iter); -} - -static void -set_selected_path (GtkBuilder *dialog, - GtkTreePath *path) -{ - GtkTreeSelection *selection; - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (WID ("xkb_layouts_selected"))); - - gtk_tree_selection_select_path (selection, path); -} - -static gint -find_selected_layout_idx (GtkBuilder *dialog) -{ - GtkTreeIter selected_iter; - GtkTreeModel *model; - GtkTreePath *path; - gint *indices; - gint rv; - - if (!get_selected_iter (dialog, &model, &selected_iter)) - return -1; - - path = gtk_tree_model_get_path (model, &selected_iter); - if (path == NULL) - return -1; - - indices = gtk_tree_path_get_indices (path); - rv = indices[0]; - gtk_tree_path_free (path); - return rv; -} - -gchar ** -xkb_layouts_get_selected_list (void) -{ - gchar **retval; - - retval = g_settings_get_strv (xkb_keyboard_settings, - GKBD_KEYBOARD_CONFIG_KEY_LAYOUTS); - if (retval == NULL || retval[0] == NULL) { - g_strfreev (retval); - retval = g_strdupv (initial_config.layouts_variants); - } - - return retval; -} - -gint -xkb_get_default_group () -{ - return g_settings_get_int (xkb_desktop_settings, - GKBD_DESKTOP_CONFIG_KEY_DEFAULT_GROUP); -} - -void -xkb_save_default_group (gint default_group) -{ - g_settings_set_int (xkb_desktop_settings, - GKBD_DESKTOP_CONFIG_KEY_DEFAULT_GROUP, - default_group); -} - -static void -xkb_layouts_enable_disable_buttons (GtkBuilder * dialog) -{ - GtkWidget *add_layout_btn = WID ("xkb_layouts_add"); - GtkWidget *show_layout_btn = WID ("xkb_layouts_show"); - GtkWidget *del_layout_btn = WID ("xkb_layouts_remove"); - GtkWidget *selected_layouts_tree = WID ("xkb_layouts_selected"); - GtkWidget *move_up_layout_btn = WID ("xkb_layouts_move_up"); - GtkWidget *move_down_layout_btn = WID ("xkb_layouts_move_down"); - - GtkTreeSelection *s_selection = - gtk_tree_view_get_selection (GTK_TREE_VIEW - (selected_layouts_tree)); - const int n_selected_selected_layouts = - gtk_tree_selection_count_selected_rows (s_selection); - GtkTreeModel *selected_layouts_model = gtk_tree_view_get_model - (GTK_TREE_VIEW (selected_layouts_tree)); - const int n_selected_layouts = - gtk_tree_model_iter_n_children (selected_layouts_model, - NULL); - gint sidx = find_selected_layout_idx (dialog); - - if (disable_buttons_sensibility_update) - return; - - gtk_widget_set_sensitive (add_layout_btn, - (n_selected_layouts < - max_selected_layouts - || max_selected_layouts == 0)); - gtk_widget_set_sensitive (del_layout_btn, (n_selected_layouts > 1) - && (n_selected_selected_layouts > 0)); - gtk_widget_set_sensitive (show_layout_btn, - (n_selected_selected_layouts > 0)); - gtk_widget_set_sensitive (move_up_layout_btn, sidx > 0); - gtk_widget_set_sensitive (move_down_layout_btn, sidx >= 0 - && sidx < (n_selected_layouts - 1)); -} - -static void -update_layouts_list (GtkTreeModel *model, - GtkBuilder *dialog) -{ - gboolean cont; - GtkTreeIter iter; - GPtrArray *array; - - array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free); - cont = gtk_tree_model_get_iter_first (model, &iter); - while (cont) { - char *id; - - gtk_tree_model_get (model, &iter, - SEL_LAYOUT_TREE_COL_ID, &id, - -1); - g_ptr_array_add (array, id); - cont = gtk_tree_model_iter_next (model, &iter); - } - g_ptr_array_add (array, NULL); - xkb_layouts_set_selected_list (array->pdata); - g_ptr_array_free (array, TRUE); - - xkb_layouts_enable_disable_buttons (dialog); -} - -static void -xkb_layouts_drag_end (GtkWidget *widget, - GdkDragContext *drag_context, - gpointer user_data) -{ - update_layouts_list (gtk_tree_view_get_model (GTK_TREE_VIEW (widget)), - GTK_BUILDER (user_data)); -} - -void -xkb_layouts_prepare_selected_tree (GtkBuilder * dialog) -{ - GtkListStore *list_store; - GtkWidget *tree_view = WID ("xkb_layouts_selected"); - GtkTreeSelection *selection; - GtkTreeViewColumn *desc_column; - - list_store = gtk_list_store_new (SEL_LAYOUT_N_COLS, - G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN); - - text_renderer = GTK_CELL_RENDERER (gtk_cell_renderer_text_new ()); - - desc_column = - gtk_tree_view_column_new_with_attributes (_("Layout"), - text_renderer, - "text", - SEL_LAYOUT_TREE_COL_DESCRIPTION, - "sensitive", - SEL_LAYOUT_TREE_COL_ENABLED, - NULL); - selection = - gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)); - - gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), - GTK_TREE_MODEL (list_store)); - - gtk_tree_view_column_set_sizing (desc_column, - GTK_TREE_VIEW_COLUMN_AUTOSIZE); - gtk_tree_view_column_set_resizable (desc_column, TRUE); - gtk_tree_view_column_set_expand (desc_column, TRUE); - - gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), - desc_column); - - g_signal_connect_swapped (G_OBJECT (selection), "changed", - G_CALLBACK - (xkb_layouts_enable_disable_buttons), - dialog); - max_selected_layouts = xkl_engine_get_max_num_groups (engine); - - /* Setting up DnD */ - gtk_tree_view_set_reorderable (GTK_TREE_VIEW (tree_view), TRUE); - g_signal_connect (G_OBJECT (tree_view), "drag-end", - G_CALLBACK (xkb_layouts_drag_end), dialog); -} - -gchar * -xkb_layout_description_utf8 (const gchar * visible) -{ - char *l, *sl, *v, *sv; - if (gkbd_keyboard_config_get_descriptions - (config_registry, visible, &sl, &l, &sv, &v)) - visible = - gkbd_keyboard_config_format_full_description (l, v); - return g_strstrip (g_strdup (visible)); -} - -void -xkb_layouts_fill_selected_tree (GtkBuilder * dialog) -{ - gchar **layouts = xkb_layouts_get_selected_list (); - guint i; - GtkListStore *list_store = - GTK_LIST_STORE (gtk_tree_view_get_model - (GTK_TREE_VIEW - (WID ("xkb_layouts_selected")))); - - /* temporarily disable the buttons' status update */ - disable_buttons_sensibility_update = TRUE; - - gtk_list_store_clear (list_store); - - for (i = 0; layouts != NULL && layouts[i] != NULL; i++) { - char *cur_layout = layouts[i]; - gchar *utf_visible = - xkb_layout_description_utf8 (cur_layout); - - gtk_list_store_insert_with_values (list_store, NULL, G_MAXINT, - SEL_LAYOUT_TREE_COL_DESCRIPTION, - utf_visible, - SEL_LAYOUT_TREE_COL_ID, - cur_layout, - SEL_LAYOUT_TREE_COL_ENABLED, - i < max_selected_layouts, -1); - g_free (utf_visible); - } - - g_strfreev (layouts); - - /* enable the buttons' status update */ - disable_buttons_sensibility_update = FALSE; - - if (idx2select != -1) { - GtkTreeSelection *selection = - gtk_tree_view_get_selection ((GTK_TREE_VIEW - (WID - ("xkb_layouts_selected")))); - GtkTreePath *path = - gtk_tree_path_new_from_indices (idx2select, -1); - gtk_tree_selection_select_path (selection, path); - gtk_tree_path_free (path); - idx2select = -1; - } else { - /* if there is nothing to select - just enable/disable the buttons, - otherwise it would be done by the selection change */ - xkb_layouts_enable_disable_buttons (dialog); - } -} - -static void -add_default_switcher_if_necessary () -{ - gchar **layouts_list = xkb_layouts_get_selected_list(); - gchar **options_list = xkb_options_get_selected_list (); - gboolean was_appended; - - options_list = - gkbd_keyboard_config_add_default_switch_option_if_necessary - (layouts_list, options_list, &was_appended); - if (was_appended) - xkb_options_set_selected_list (options_list); - g_strfreev (options_list); -} - -static void -chooser_response (GtkDialog *chooser, - int response_id, - GtkBuilder *dialog) -{ - if (response_id == GTK_RESPONSE_OK) { - char *id, *name; - GtkListStore *list_store; - - list_store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (WID ("xkb_layouts_selected")))); - id = xkb_layout_chooser_get_selected_id (chooser); - name = xkb_layout_description_utf8 (id); - gtk_list_store_insert_with_values (list_store, NULL, G_MAXINT, - SEL_LAYOUT_TREE_COL_DESCRIPTION, name, - SEL_LAYOUT_TREE_COL_ID, id, - SEL_LAYOUT_TREE_COL_ENABLED, TRUE, - -1); - g_free (name); - add_default_switcher_if_necessary (); - update_layouts_list (GTK_TREE_MODEL (list_store), dialog); - } - - xkb_layout_chooser_response (chooser, response_id); -} - -static void -add_selected_layout (GtkWidget * button, GtkBuilder * dialog) -{ - GtkWidget *chooser; - - chooser = xkb_layout_choose (dialog); - g_signal_connect (G_OBJECT (chooser), "response", - G_CALLBACK (chooser_response), dialog); -} - -static void -show_selected_layout (GtkWidget * button, GtkBuilder * dialog) -{ - gint idx = find_selected_layout_idx (dialog); - - if (idx != -1) { - GtkWidget *parent = WID ("region_notebook"); - GtkWidget *popup = gkbd_keyboard_drawing_dialog_new (); - gkbd_keyboard_drawing_dialog_set_group (popup, - config_registry, - idx); - gtk_window_set_transient_for (GTK_WINDOW (popup), - GTK_WINDOW - (gtk_widget_get_toplevel - (parent))); - gtk_widget_show_all (popup); - } -} - -static void -remove_selected_layout (GtkWidget * button, GtkBuilder * dialog) -{ - GtkTreeModel *model; - GtkTreeIter iter; - - if (get_selected_iter (dialog, &model, &iter) == FALSE) - return; - - gtk_list_store_remove (GTK_LIST_STORE (model), &iter); - update_layouts_list (model, dialog); -} - -static void -move_up_selected_layout (GtkWidget * button, GtkBuilder * dialog) -{ - GtkTreeModel *model; - GtkTreeIter iter, prev; - GtkTreePath *path; - - if (get_selected_iter (dialog, &model, &iter) == FALSE) - return; - - prev = iter; - if (!gtk_tree_model_iter_previous (model, &prev)) - return; - - path = gtk_tree_model_get_path (model, &prev); - - gtk_list_store_swap (GTK_LIST_STORE (model), &iter, &prev); - - update_layouts_list (model, dialog); - - set_selected_path (dialog, path); - - gtk_tree_path_free (path); -} - -static void -move_down_selected_layout (GtkWidget * button, GtkBuilder * dialog) -{ - GtkTreeModel *model; - GtkTreeIter iter, next; - GtkTreePath *path; - - if (get_selected_iter (dialog, &model, &iter) == FALSE) - return; - - next = iter; - if (!gtk_tree_model_iter_next (model, &next)) - return; - - path = gtk_tree_model_get_path (model, &next); - - gtk_list_store_swap (GTK_LIST_STORE (model), &iter, &next); - - update_layouts_list (model, dialog); - - set_selected_path (dialog, path); - - gtk_tree_path_free (path); -} - -void -xkb_layouts_register_buttons_handlers (GtkBuilder * dialog) -{ - g_signal_connect (G_OBJECT (WID ("xkb_layouts_add")), "clicked", - G_CALLBACK (add_selected_layout), dialog); - g_signal_connect (G_OBJECT (WID ("xkb_layouts_show")), "clicked", - G_CALLBACK (show_selected_layout), dialog); - g_signal_connect (G_OBJECT (WID ("xkb_layouts_remove")), "clicked", - G_CALLBACK (remove_selected_layout), dialog); - g_signal_connect (G_OBJECT (WID ("xkb_layouts_move_up")), - "clicked", G_CALLBACK (move_up_selected_layout), - dialog); - g_signal_connect (G_OBJECT (WID ("xkb_layouts_move_down")), - "clicked", - G_CALLBACK (move_down_selected_layout), dialog); -} - -static void -xkb_layouts_update_list (GSettings * settings, - gchar * key, GtkBuilder * dialog) -{ - if (strcmp (key, GKBD_KEYBOARD_CONFIG_KEY_LAYOUTS) == 0) { - xkb_layouts_fill_selected_tree (dialog); - enable_disable_restoring (dialog); - } -} - -void -xkb_layouts_register_conf_listener (GtkBuilder * dialog) -{ - g_signal_connect (xkb_keyboard_settings, "changed", - G_CALLBACK (xkb_layouts_update_list), dialog); -} diff -uNrp a/panels/region/cinnamon-region-panel-xkbot.c b/panels/region/cinnamon-region-panel-xkbot.c --- a/panels/region/cinnamon-region-panel-xkbot.c 2013-08-25 14:40:14.000000000 +0100 +++ b/panels/region/cinnamon-region-panel-xkbot.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,516 +0,0 @@ -/* cinnamon-region-panel-xkbot.c - * Copyright (C) 2003-2007 Sergey V. Udaltsov - * - * Written by: Sergey V. Udaltsov - * John Spray - * - * 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, 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA - * 02110-1335, USA. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include - -#include "cinnamon-region-panel-xkb.h" - -static GtkBuilder *chooser_dialog = NULL; -static const char *current1st_level_id = NULL; -static GSList *option_checks_list = NULL; -static GtkWidget *current_none_radio = NULL; -static GtkWidget *current_expander = NULL; -static gboolean current_multi_select = FALSE; -static GSList *current_radio_group = NULL; - -#define OPTION_ID_PROP "optionID" -#define SELCOUNTER_PROP "selectionCounter" -#define GCONFSTATE_PROP "gconfState" -#define EXPANDERS_PROP "expandersList" - -gchar ** -xkb_options_get_selected_list (void) -{ - gchar **retval; - - retval = - g_settings_get_strv (xkb_keyboard_settings, - GKBD_KEYBOARD_CONFIG_KEY_OPTIONS); - if (retval == NULL) { - retval = g_strdupv (initial_config.options); - } - - return retval; -} - -/* Returns the selection counter of the expander (static current_expander) */ -static int -xkb_options_expander_selcounter_get (void) -{ - return - GPOINTER_TO_INT (g_object_get_data - (G_OBJECT (current_expander), - SELCOUNTER_PROP)); -} - -/* Increments the selection counter in the expander (static current_expander) - using the value (can be 0)*/ -static void -xkb_options_expander_selcounter_add (int value) -{ - g_object_set_data (G_OBJECT (current_expander), SELCOUNTER_PROP, - GINT_TO_POINTER - (xkb_options_expander_selcounter_get () - + value)); -} - -/* Resets the seletion counter in the expander (static current_expander) */ -static void -xkb_options_expander_selcounter_reset (void) -{ - g_object_set_data (G_OBJECT (current_expander), SELCOUNTER_PROP, - GINT_TO_POINTER (0)); -} - -/* Formats the expander (static current_expander), based on the selection counter */ -static void -xkb_options_expander_highlight (void) -{ - char *utf_group_name = - g_object_get_data (G_OBJECT (current_expander), - "utfGroupName"); - int counter = xkb_options_expander_selcounter_get (); - if (utf_group_name != NULL) { - gchar *titlemarkup = - g_strconcat (counter > - 0 ? "" : "", - utf_group_name, "", NULL); - gtk_expander_set_label (GTK_EXPANDER (current_expander), - titlemarkup); - g_free (titlemarkup); - } -} - -/* Add optionname from the backend's selection list if it's not - already in there. */ -static void -xkb_options_select (gchar * optionname) -{ - gboolean already_selected = FALSE; - gchar **options_list; - guint i; - - options_list = xkb_options_get_selected_list (); - for (i = 0; options_list != NULL && options_list[i] != NULL; i++) { - gchar *option = options_list[i]; - if (!strcmp (option, optionname)) { - already_selected = TRUE; - break; - } - } - - if (!already_selected) { - options_list = - gkbd_strv_append (options_list, g_strdup (optionname)); - xkb_options_set_selected_list (options_list); - } - - g_strfreev (options_list); -} - -/* Remove all occurences of optionname from the backend's selection list */ -static void -xkb_options_deselect (gchar * optionname) -{ - gchar **options_list = xkb_options_get_selected_list (); - if (options_list != NULL) { - gchar **option = options_list; - while (*option != NULL) { - gchar *id = *option; - if (!strcmp (id, optionname)) { - gkbd_strv_behead (option); - } else - option++; - } - xkb_options_set_selected_list (options_list); - } - g_strfreev (options_list); -} - -/* Return true if optionname describes a string already in the backend's - list of selected options */ -static gboolean -xkb_options_is_selected (gchar * optionname) -{ - gboolean retval = FALSE; - gchar **options_list = xkb_options_get_selected_list (); - if (options_list != NULL) { - gchar **option = options_list; - while (*option != NULL) { - if (!strcmp (*option, optionname)) { - retval = TRUE; - break; - } - option++; - } - } - g_strfreev (options_list); - return retval; -} - -/* Make sure selected options stay visible when navigating with the keyboard */ -static gboolean -option_focused_cb (GtkWidget * widget, GdkEventFocus * event, - gpointer data) -{ - GtkScrolledWindow *win = GTK_SCROLLED_WINDOW (data); - GtkAllocation alloc; - GtkAdjustment *adj; - - gtk_widget_get_allocation (widget, &alloc); - adj = gtk_scrolled_window_get_vadjustment (win); - gtk_adjustment_clamp_page (adj, alloc.y, alloc.y + alloc.height); - - return FALSE; -} - -/* Update xkb backend to reflect the new UI state */ -static void -option_toggled_cb (GtkWidget * checkbutton, gpointer data) -{ - gpointer optionID = - g_object_get_data (G_OBJECT (checkbutton), OPTION_ID_PROP); - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbutton))) - xkb_options_select (optionID); - else - xkb_options_deselect (optionID); -} - -/* Add a check_button or radio_button to control a particular option - This function makes particular use of the current... variables at - the top of this file. */ -static void -xkb_options_add_option (XklConfigRegistry * config_registry, - XklConfigItem * config_item, GtkBuilder * dialog) -{ - GtkWidget *option_check; - gchar *utf_option_name = xci_desc_to_utf8 (config_item); - /* Copy this out because we'll load it into the widget with set_data */ - gchar *full_option_name = - g_strdup (gkbd_keyboard_config_merge_items - (current1st_level_id, config_item->name)); - gboolean initial_state; - - if (current_multi_select) - option_check = - gtk_check_button_new_with_label (utf_option_name); - else { - if (current_radio_group == NULL) { - /* The first radio in a group is to be "Default", meaning none of - the below options are to be included in the selected list. - This is a HIG-compliant alternative to allowing no - selection in the group. */ - option_check = - gtk_radio_button_new_with_label - (current_radio_group, _("Default")); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON - (option_check), - TRUE); - /* Make option name underscore - - to enforce its first position in the list */ - g_object_set_data_full (G_OBJECT (option_check), - "utfOptionName", - g_strdup (" "), g_free); - option_checks_list = - g_slist_append (option_checks_list, - option_check); - current_radio_group = - gtk_radio_button_get_group (GTK_RADIO_BUTTON - (option_check)); - current_none_radio = option_check; - - g_signal_connect (option_check, "focus-in-event", - G_CALLBACK (option_focused_cb), - WID ("options_scroll")); - } - option_check = - gtk_radio_button_new_with_label (current_radio_group, - utf_option_name); - current_radio_group = - gtk_radio_button_get_group (GTK_RADIO_BUTTON - (option_check)); - g_object_set_data (G_OBJECT (option_check), "NoneRadio", - current_none_radio); - } - - initial_state = xkb_options_is_selected (full_option_name); - - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (option_check), - initial_state); - - g_object_set_data_full (G_OBJECT (option_check), OPTION_ID_PROP, - full_option_name, g_free); - g_object_set_data_full (G_OBJECT (option_check), "utfOptionName", - utf_option_name, g_free); - - g_signal_connect (option_check, "toggled", - G_CALLBACK (option_toggled_cb), NULL); - - option_checks_list = - g_slist_append (option_checks_list, option_check); - - g_signal_connect (option_check, "focus-in-event", - G_CALLBACK (option_focused_cb), - WID ("options_scroll")); - - xkb_options_expander_selcounter_add (initial_state); - g_object_set_data (G_OBJECT (option_check), GCONFSTATE_PROP, - GINT_TO_POINTER (initial_state)); -} - -static gint -xkb_option_checks_compare (GtkWidget * chk1, GtkWidget * chk2) -{ - const gchar *t1 = - g_object_get_data (G_OBJECT (chk1), "utfOptionName"); - const gchar *t2 = - g_object_get_data (G_OBJECT (chk2), "utfOptionName"); - return g_utf8_collate (t1, t2); -} - -/* Add a group of options: create title and layout widgets and then - add widgets for all the options in the group. */ -static void -xkb_options_add_group (XklConfigRegistry * config_registry, - XklConfigItem * config_item, GtkBuilder * dialog) -{ - GtkWidget *align, *vbox, *option_check; - gboolean allow_multiple_selection = - GPOINTER_TO_INT (g_object_get_data (G_OBJECT (config_item), - XCI_PROP_ALLOW_MULTIPLE_SELECTION)); - - GSList *expanders_list = - g_object_get_data (G_OBJECT (dialog), EXPANDERS_PROP); - - gchar *utf_group_name = xci_desc_to_utf8 (config_item); - gchar *titlemarkup = - g_strconcat ("", utf_group_name, "", NULL); - - current_expander = gtk_expander_new (titlemarkup); - gtk_expander_set_use_markup (GTK_EXPANDER (current_expander), - TRUE); - g_object_set_data_full (G_OBJECT (current_expander), - "utfGroupName", utf_group_name, g_free); - g_object_set_data_full (G_OBJECT (current_expander), "groupId", - g_strdup (config_item->name), g_free); - - g_free (titlemarkup); - align = gtk_alignment_new (0, 0, 1, 1); - gtk_alignment_set_padding (GTK_ALIGNMENT (align), 6, 12, 12, 0); - vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); - gtk_box_set_homogeneous (GTK_BOX (vbox), TRUE); - gtk_container_add (GTK_CONTAINER (align), vbox); - gtk_container_add (GTK_CONTAINER (current_expander), align); - - current_multi_select = (gboolean) allow_multiple_selection; - current_radio_group = NULL; - current1st_level_id = config_item->name; - - option_checks_list = NULL; - - xkl_config_registry_foreach_option (config_registry, - config_item->name, - (ConfigItemProcessFunc) - xkb_options_add_option, - dialog); - /* sort it */ - option_checks_list = - g_slist_sort (option_checks_list, - (GCompareFunc) xkb_option_checks_compare); - while (option_checks_list) { - option_check = GTK_WIDGET (option_checks_list->data); - gtk_box_pack_start (GTK_BOX (vbox), option_check, TRUE, - TRUE, 0); - option_checks_list = option_checks_list->next; - } - /* free it */ - g_slist_free (option_checks_list); - option_checks_list = NULL; - - xkb_options_expander_highlight (); - - expanders_list = g_slist_append (expanders_list, current_expander); - g_object_set_data (G_OBJECT (dialog), EXPANDERS_PROP, - expanders_list); - - g_signal_connect (current_expander, "focus-in-event", - G_CALLBACK (option_focused_cb), - WID ("options_scroll")); -} - -static gint -xkb_options_expanders_compare (GtkWidget * expander1, - GtkWidget * expander2) -{ - const gchar *t1 = - g_object_get_data (G_OBJECT (expander1), "utfGroupName"); - const gchar *t2 = - g_object_get_data (G_OBJECT (expander2), "utfGroupName"); - return g_utf8_collate (t1, t2); -} - -/* Create widgets to represent the options made available by the backend */ -void -xkb_options_load_options (GtkBuilder * dialog) -{ - GtkWidget *opts_vbox = WID ("options_vbox"); - GtkWidget *dialog_vbox = WID ("dialog_vbox"); - GtkWidget *options_scroll = WID ("options_scroll"); - GtkWidget *expander; - GSList *expanders_list; - - current1st_level_id = NULL; - current_none_radio = NULL; - current_multi_select = FALSE; - current_radio_group = NULL; - - /* fill the list */ - xkl_config_registry_foreach_option_group (config_registry, - (ConfigItemProcessFunc) - xkb_options_add_group, - dialog); - /* sort it */ - expanders_list = - g_object_get_data (G_OBJECT (dialog), EXPANDERS_PROP); - expanders_list = - g_slist_sort (expanders_list, - (GCompareFunc) xkb_options_expanders_compare); - g_object_set_data (G_OBJECT (dialog), EXPANDERS_PROP, - expanders_list); - while (expanders_list) { - expander = GTK_WIDGET (expanders_list->data); - gtk_box_pack_start (GTK_BOX (opts_vbox), expander, FALSE, - FALSE, 0); - expanders_list = expanders_list->next; - } - - /* Somewhere in gtk3 the top vbox in dialog is made non-expandable */ - gtk_box_set_child_packing (GTK_BOX (dialog_vbox), options_scroll, - TRUE, TRUE, 0, GTK_PACK_START); - gtk_widget_show_all (dialog_vbox); -} - -static void -chooser_response_cb (GtkDialog * dialog, gint response, gpointer data) -{ - switch (response) { - case GTK_RESPONSE_DELETE_EVENT: - case GTK_RESPONSE_CLOSE: { - /* just cleanup */ - GSList *expanders_list = - g_object_get_data (G_OBJECT (dialog), - EXPANDERS_PROP); - g_object_set_data (G_OBJECT (dialog), - EXPANDERS_PROP, NULL); - g_slist_free (expanders_list); - - gtk_widget_destroy (GTK_WIDGET (dialog)); - chooser_dialog = NULL; - } - break; - } -} - -/* Create popup dialog */ -void -xkb_options_popup_dialog (GtkBuilder * dialog) -{ - GtkWidget *chooser; - - chooser_dialog = gtk_builder_new (); - gtk_builder_set_translation_domain (chooser_dialog, GETTEXT_PACKAGE); - gtk_builder_add_from_file (chooser_dialog, CINNAMONCC_UI_DIR - "/cinnamon-region-panel-options-dialog.ui", - NULL); - - chooser = CWID ("xkb_options_dialog"); - gtk_window_set_transient_for (GTK_WINDOW (chooser), - GTK_WINDOW (gtk_widget_get_toplevel (WID ("region_notebook")))); - gtk_window_set_modal (GTK_WINDOW (chooser), TRUE); - xkb_options_load_options (chooser_dialog); - - g_signal_connect (chooser, "response", - G_CALLBACK (chooser_response_cb), dialog); - gtk_widget_show (chooser); -} - -/* Update selected option counters for a group-bound expander */ -static void -xkb_options_update_option_counters (XklConfigRegistry * config_registry, - XklConfigItem * config_item) -{ - gchar *full_option_name = - g_strdup (gkbd_keyboard_config_merge_items - (current1st_level_id, config_item->name)); - gboolean current_state = - xkb_options_is_selected (full_option_name); - g_free (full_option_name); - - xkb_options_expander_selcounter_add (current_state); -} - -/* Respond to a change in the xkb gconf settings */ -static void -xkb_options_update (GSettings * settings, gchar * key, GtkBuilder * dialog) -{ - if (!strcmp (key, GKBD_KEYBOARD_CONFIG_KEY_OPTIONS)) { - /* Updating options is handled by gconf notifies for each widget - This is here to avoid calling it N_OPTIONS times for each gconf - change. */ - enable_disable_restoring (dialog); - - if (chooser_dialog != NULL) { - GSList *expanders_list = - g_object_get_data (G_OBJECT (chooser_dialog), - EXPANDERS_PROP); - while (expanders_list) { - current_expander = - GTK_WIDGET (expanders_list->data); - gchar *group_id = - g_object_get_data (G_OBJECT - (current_expander), - "groupId"); - current1st_level_id = group_id; - xkb_options_expander_selcounter_reset (); - xkl_config_registry_foreach_option - (config_registry, group_id, - (ConfigItemProcessFunc) - xkb_options_update_option_counters, - current_expander); - xkb_options_expander_highlight (); - expanders_list = expanders_list->next; - } - } - } -} - -void -xkb_options_register_conf_listener (GtkBuilder * dialog) -{ - g_signal_connect (xkb_keyboard_settings, "changed", - G_CALLBACK (xkb_options_update), dialog); -} diff -uNrp a/panels/region/cinnamon-region-panel-xkbpv.c b/panels/region/cinnamon-region-panel-xkbpv.c --- a/panels/region/cinnamon-region-panel-xkbpv.c 2013-08-25 14:40:14.000000000 +0100 +++ b/panels/region/cinnamon-region-panel-xkbpv.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,120 +0,0 @@ -/* cinnamon-region-panel-xkbpv.c - * Copyright (C) 2003-2007 Sergey V. Udaltsov - * - * Written by: Sergey V. Udaltsov - * - * 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, 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA - * 02110-1335, USA. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#include "cinnamon-region-panel-xkb.h" - -#ifdef HAVE_X11_EXTENSIONS_XKB_H -#include "X11/XKBlib.h" -/** - * BAD STYLE: Taken from xklavier_private_xkb.h - * Any ideas on architectural improvements are WELCOME - */ -extern gboolean xkl_xkb_config_native_prepare (XklEngine * engine, - const XklConfigRec * data, - XkbComponentNamesPtr - component_names); - -extern void xkl_xkb_config_native_cleanup (XklEngine * engine, - XkbComponentNamesPtr - component_names); - -/* */ -#endif - -static GkbdKeyboardDrawingGroupLevel groupsLevels[] = - { {0, 1}, {0, 3}, {0, 0}, {0, 2} }; -static GkbdKeyboardDrawingGroupLevel *pGroupsLevels[] = { - groupsLevels, groupsLevels + 1, groupsLevels + 2, groupsLevels + 3 -}; - -GtkWidget * -xkb_layout_preview_create_widget (GtkBuilder * chooserDialog) -{ - GtkWidget *kbdraw = gkbd_keyboard_drawing_new (); - - gkbd_keyboard_drawing_set_groups_levels (GKBD_KEYBOARD_DRAWING - (kbdraw), pGroupsLevels); - return kbdraw; -} - -void -xkb_layout_preview_set_drawing_layout (GtkWidget * kbdraw, - const gchar * id) -{ -#ifdef HAVE_X11_EXTENSIONS_XKB_H - if (kbdraw != NULL) { - if (id != NULL) { - XklConfigRec *data; - char **p, *layout, *variant; - XkbComponentNamesRec component_names; - - data = xkl_config_rec_new (); - if (xkl_config_rec_get_from_server (data, engine)) { - if ((p = data->layouts) != NULL) - g_strfreev (data->layouts); - - if ((p = data->variants) != NULL) - g_strfreev (data->variants); - - data->layouts = g_new0 (char *, 2); - data->variants = g_new0 (char *, 2); - if (gkbd_keyboard_config_split_items - (id, &layout, &variant) - && variant != NULL) { - data->layouts[0] = - (layout == - NULL) ? NULL : - g_strdup (layout); - data->variants[0] = - (variant == - NULL) ? NULL : - g_strdup (variant); - } else { - data->layouts[0] = - (id == - NULL) ? NULL : g_strdup (id); - data->variants[0] = NULL; - } - - if (xkl_xkb_config_native_prepare - (engine, data, &component_names)) { - gkbd_keyboard_drawing_set_keyboard - (GKBD_KEYBOARD_DRAWING - (kbdraw), &component_names); - - xkl_xkb_config_native_cleanup - (engine, &component_names); - } - } - g_object_unref (G_OBJECT (data)); - } else - gkbd_keyboard_drawing_set_keyboard - (GKBD_KEYBOARD_DRAWING (kbdraw), NULL); - - } -#endif -} diff -uNrp a/panels/region/.indent.pro b/panels/region/.indent.pro --- a/panels/region/.indent.pro 1970-01-01 01:00:00.000000000 +0100 +++ b/panels/region/.indent.pro 2013-08-25 16:50:30.000000000 +0100 @@ -0,0 +1,2 @@ +-kr -i8 -pcs -lps -psl + diff -uNrp a/panels/region/Makefile.am b/panels/region/Makefile.am --- a/panels/region/Makefile.am 2013-08-25 14:40:14.000000000 +0100 +++ b/panels/region/Makefile.am 2013-09-21 13:24:15.347949247 +0100 @@ -23,12 +23,9 @@ libregion_la_SOURCES = \ cinnamon-region-panel-lang.h \ cinnamon-region-panel-system.c \ cinnamon-region-panel-system.h \ - cinnamon-region-panel-xkb.c \ - cinnamon-region-panel-xkblt.c \ - cinnamon-region-panel-xkbltadd.c \ - cinnamon-region-panel-xkbot.c \ - cinnamon-region-panel-xkbpv.c \ - cinnamon-region-panel-xkb.h + cinnamon-region-panel-input.c \ + cinnamon-region-panel-input.h \ + $(NULL) libregion_la_LIBADD = $(PANEL_LIBS) $(REGION_PANEL_LIBS) $(builddir)/../common/liblanguage.la @@ -39,8 +36,8 @@ libregion_la_LDFLAGS = $(PANEL_LDFLAGS) uidir = $(pkgdatadir)/ui ui_DATA = \ cinnamon-region-panel.ui \ - cinnamon-region-panel-layout-chooser.ui \ - cinnamon-region-panel-options-dialog.ui + cinnamon-region-panel-input-chooser.ui \ + $(NULL) desktopdir = $(datadir)/applications Desktop_in_files = cinnamon-region-panel.desktop.in diff -uNrp a/panels/region/region-module.c b/panels/region/region-module.c --- a/panels/region/region-module.c 2013-08-25 14:40:14.000000000 +0100 +++ b/panels/region/region-module.c 2013-09-21 13:24:15.347949247 +0100 @@ -28,6 +28,7 @@ void g_io_module_load (GIOModule * module) { + /* register the panel */ cc_region_panel_register (module); }