From 641ea31345eed2a0806ce984e4a6b79d0b7ee0f5 Mon Sep 17 00:00:00 2001 From: Roelof Wobben Date: Sun, 13 Apr 2014 21:46:48 +0200 Subject: [PATCH] new package: cinnamon-control-center --- .../cinnamon/cinnamon-control-center.nix | 40 + pkgs/desktops/cinnamon/region.patch | 5314 +++++++++++++++++ pkgs/top-level/all-packages.nix | 6 +- 3 files changed, 5358 insertions(+), 2 deletions(-) create mode 100644 pkgs/desktops/cinnamon/cinnamon-control-center.nix create mode 100644 pkgs/desktops/cinnamon/region.patch diff --git a/pkgs/desktops/cinnamon/cinnamon-control-center.nix b/pkgs/desktops/cinnamon/cinnamon-control-center.nix new file mode 100644 index 000000000000..ab2f389b4f5f --- /dev/null +++ b/pkgs/desktops/cinnamon/cinnamon-control-center.nix @@ -0,0 +1,40 @@ + +{ stdenv, fetchurl, pkgconfig, autoreconfHook, glib, gettext, gnome_common, cinnamon-desktop, intltool, libxslt, gtk3, libnotify, +gnome-menus, libxml2, systemd, upower, cinnamon-settings-daemon, colord, polkit, ibus, libcanberra_gtk3, pulseaudio, isocodes, krb5, +libxkbfile}: + +let + version = "2.0.9"; +in +stdenv.mkDerivation { + name = "cinnamon-control-center-${version}"; + + src = fetchurl { + url = "http://github.com/linuxmint/cinnamon-control-center/archive/${version}.tar.gz"; + sha256 = "0kivqdgsf8w257j2ja6fap0dpvljcnb9gphr3knp7y6ma2d1gfv3"; + }; + + configureFlags = "--enable-systemd --disable-update-mimedb" ; + + patches = [ ./region.patch]; + + buildInputs = [ + pkgconfig autoreconfHook + glib gettext gnome_common + intltool libxslt gtk3 cinnamon-desktop + libnotify gnome-menus libxml2 systemd + upower cinnamon-settings-daemon colord + polkit ibus libcanberra_gtk3 pulseaudio + isocodes krb5 libxkbfile ]; + + preBuild = "patchShebangs ./scripts"; + + meta = { + homepage = "http://cinnamon.linuxmint.com"; + description = "The cinnamon session files" ; + + platforms = stdenv.lib.platforms.linux; + maintainers = [ stdenv.lib.maintainers.roelof ]; + }; +} + diff --git a/pkgs/desktops/cinnamon/region.patch b/pkgs/desktops/cinnamon/region.patch new file mode 100644 index 000000000000..7b8133e820ed --- /dev/null +++ b/pkgs/desktops/cinnamon/region.patch @@ -0,0 +1,5314 @@ + +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); + } diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 514a3f09bfba..cf1c0875e2b0 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -9887,8 +9887,10 @@ let cinnamon = recurseIntoAttrs rec { callPackage = newScope pkgs.cinnamon; - inherit (gnome3) gnome_common libgnomekbd; - + inherit (gnome3) gnome_common libgnomekbd gnome-menus; + + cinnamon-control-center = callPackage ../desktops/cinnamon/cinnamon-control-center.nix{ }; + cinnamon-settings-daemon = callPackage ../desktops/cinnamon/cinnamon-settings-daemon.nix{ }; cinnamon-session = callPackage ../desktops/cinnamon/cinnamon-session.nix{ } ;