Index: gnome-settings-daemon-3.3.91/configure.ac
===================================================================
--- gnome-settings-daemon-3.3.91.orig/configure.ac	2012-03-05 21:04:12.701981055 +0100
+++ gnome-settings-daemon-3.3.91/configure.ac	2012-03-05 21:04:16.877981257 +0100
@@ -53,6 +53,7 @@
 PA_REQUIRED_VERSION=0.9.16
 LIBWACOM_REQUIRED_VERSION=0.3
 UPOWER_REQUIRED_VERSION=0.9.11
+APPINDICATOR_REQUIRED_VERSION=0.3.0
 
 EXTRA_COMPILE_WARNINGS(yes)
 
@@ -146,6 +147,32 @@
 
 PKG_CHECK_MODULES(AUTOMOUNT, x11 kbproto)
 
+dnl ---------------------------------
+dnl - Application indicator
+dnl ---------------------------------
+
+AC_ARG_ENABLE([appindicator],
+	AS_HELP_STRING([--enable-appindicator[=@<:@no/auto/yes@:>@]],[Build support for application indicators]),
+	[enable_appindicator=$enableval],
+	[enable_appindicator="auto"])
+
+
+if test x$enable_appindicator = xauto ; then
+	PKG_CHECK_EXISTS(appindicator3-0.1 >= $APPINDICATOR_REQUIRED_VERSION,
+		[enable_appindicator="yes"],
+		[enable_appindicator="no"])
+fi
+
+if test x$enable_appindicator = xyes ; then
+	PKG_CHECK_MODULES(APPINDICATOR,
+		[appindicator3-0.1 >= $APPINDICATOR_REQUIRED_VERSION],
+		[AC_DEFINE(HAVE_APPINDICATOR, 1, [Have AppIndicator])])
+fi
+
+AM_CONDITIONAL(HAVE_APPINDICATOR, test x$enable_appindicator = xyes)
+AC_SUBST(APPINDICATOR_CFLAGS)
+AC_SUBST(APPINDICATOR_LIBS)
+
 dnl ---------------------------------------------------------------------------
 dnl - background
 dnl ---------------------------------------------------------------------------
@@ -504,6 +531,7 @@
         LCMS DICT support:        ${have_new_lcms}
 
         Libnotify support:        ${have_libnotify}
+	App indicator support:    ${enable_appindicator}
         PackageKit support:       ${have_packagekit}
         Smartcard support:        ${have_smartcard_support}
         Cups support:             ${have_cups}
Index: gnome-settings-daemon-3.3.91/plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c
===================================================================
--- gnome-settings-daemon-3.3.91.orig/plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c	2012-02-01 20:33:14.000000000 +0100
+++ gnome-settings-daemon-3.3.91/plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c	2012-03-05 21:04:12.929981066 +0100
@@ -41,6 +41,10 @@
 #include <X11/XKBlib.h>
 #include <X11/extensions/XKBstr.h>
 
+#ifdef HAVE_APPINDICATOR
+#include <libappindicator/app-indicator.h>
+#endif
+
 #include "gnome-settings-profile.h"
 #include "gsd-a11y-keyboard-manager.h"
 #include "gsd-a11y-preferences-dialog.h"
@@ -61,7 +65,11 @@
         GtkWidget        *stickykeys_alert;
         GtkWidget        *slowkeys_alert;
         GtkWidget        *preferences_dialog;
+#ifdef HAVE_APPINDICATOR
+        AppIndicator *app_indicator;
+#else
         GtkStatusIcon    *status_icon;
+#endif
 
         GSettings        *settings;
 
@@ -427,11 +435,24 @@
         /* for now, show if accessx is enabled */
         show = g_settings_get_boolean (manager->priv->settings, "enable");
 
+#ifdef HAVE_APPINDICATOR
+        if (!show && manager->priv->app_indicator == NULL)
+                return;
+	
+        gsd_a11y_keyboard_manager_ensure_status_icon (manager);
+	if (show)
+		app_indicator_set_status (manager->priv->app_indicator,
+					  APP_INDICATOR_STATUS_ACTIVE);
+	else
+		app_indicator_set_status (manager->priv->app_indicator,
+					  APP_INDICATOR_STATUS_PASSIVE);
+#else
         if (!show && manager->priv->status_icon == NULL)
                 return;
 
         gsd_a11y_keyboard_manager_ensure_status_icon (manager);
         gtk_status_icon_set_visible (manager->priv->status_icon, show);
+#endif
 }
 
 static void
@@ -510,9 +531,11 @@
         message = _("You just held down the Shift key for 8 seconds.  This is the shortcut "
                     "for the Slow Keys feature, which affects the way your keyboard works.");
 
+#ifndef HAVE_APPINDICATOR
         if (manager->priv->status_icon == NULL || ! gtk_status_icon_is_embedded (manager->priv->status_icon)) {
                 return FALSE;
         }
+#endif
 
         if (manager->priv->slowkeys_alert != NULL) {
                 gtk_widget_destroy (manager->priv->slowkeys_alert);
@@ -646,9 +669,11 @@
                 _("You just pressed two keys at once, or pressed the Shift key 5 times in a row.  "
                   "This turns off the Sticky Keys feature, which affects the way your keyboard works.");
 
+#ifndef HAVE_APPINDICATOR
         if (manager->priv->status_icon == NULL || ! gtk_status_icon_is_embedded (manager->priv->status_icon)) {
                 return FALSE;
         }
+#endif
 
         if (manager->priv->slowkeys_alert != NULL) {
                 gtk_widget_destroy (manager->priv->slowkeys_alert);
@@ -1002,10 +1027,16 @@
                 p->device_manager = NULL;
         }
 
+#ifdef HAVE_APPINDICATOR
+	if (p->app_indicator)
+		app_indicator_set_status (p->app_indicator,
+					  APP_INDICATOR_STATUS_PASSIVE);
+#else
         if (p->status_icon) {
                 gtk_status_icon_set_visible (p->status_icon, FALSE);
                 p->status_icon = NULL;
         }
+#endif
 
         if (p->settings != NULL) {
                 g_signal_handlers_disconnect_by_func (p->settings, keyboard_callback, manager);
@@ -1070,8 +1101,13 @@
 }
 
 static void
+#ifdef HAVE_APPINDICATOR
+on_status_icon_activate (GtkMenuItem            *item,
+                         GsdA11yKeyboardManager *manager)
+#else
 on_status_icon_activate (GtkStatusIcon          *status_icon,
                          GsdA11yKeyboardManager *manager)
+#endif
 {
         if (manager->priv->preferences_dialog == NULL) {
                 manager->priv->preferences_dialog = gsd_a11y_preferences_dialog_new ();
@@ -1104,6 +1140,26 @@
 {
         gnome_settings_profile_start (NULL);
 
+#ifdef HAVE_APPINDICATOR
+	if (!manager->priv->app_indicator) {
+		GtkWidget *menu = gtk_menu_new ();
+		GtkWidget *item = gtk_menu_item_new_with_label (_("Universal Access Preferences"));
+
+		g_signal_connect (item,
+				  "activate",
+				  G_CALLBACK (on_status_icon_activate),
+				  manager);
+
+		gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+		gtk_widget_show_all (menu);
+
+		manager->priv->app_indicator = app_indicator_new ("a11y-keyboard",
+								  "preferences-desktop-accessibility",
+								  APP_INDICATOR_CATEGORY_OTHER);
+		app_indicator_set_menu (manager->priv->app_indicator,
+					GTK_MENU (menu));
+	}
+#else
         if (!manager->priv->status_icon) {
 
                 manager->priv->status_icon = gtk_status_icon_new_from_icon_name ("preferences-desktop-accessibility");
@@ -1117,6 +1173,7 @@
                                   G_CALLBACK (on_status_icon_popup_menu),
                                   manager);
         }
+#endif
 
         gnome_settings_profile_end (NULL);
 }
Index: gnome-settings-daemon-3.3.91/plugins/a11y-keyboard/Makefile.am
===================================================================
--- gnome-settings-daemon-3.3.91.orig/plugins/a11y-keyboard/Makefile.am	2011-09-07 16:40:46.000000000 +0200
+++ gnome-settings-daemon-3.3.91/plugins/a11y-keyboard/Makefile.am	2012-03-05 21:04:12.929981066 +0100
@@ -56,6 +56,7 @@
 liba11y_keyboard_la_CFLAGS = \
 	$(SETTINGS_PLUGIN_CFLAGS)	\
 	$(LIBNOTIFY_CFLAGS)		\
+	$(APPINDICATOR_CFLAGS)		\
 	$(AM_CFLAGS)
 
 liba11y_keyboard_la_LDFLAGS = 		\
@@ -66,6 +67,7 @@
 	$(SETTINGS_PLUGIN_LIBS)		\
 	$(XF86MISC_LIBS)		\
 	$(LIBNOTIFY_LIBS)		\
+	$(APPINDICATOR_LIBS)		\
 	$(NULL)
 
 plugin_in_files = 		\
Index: gnome-settings-daemon-3.3.91/plugins/keyboard/gkbd-configuration.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gnome-settings-daemon-3.3.91/plugins/keyboard/gkbd-configuration.c	2012-03-05 21:04:12.933981066 +0100
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2010 Canonical Ltd.
+ * 
+ * Authors: Jan Arne Petersen <jpetersen@openismus.com>
+ * 
+ * Based on gkbd-status.c by Sergey V. Udaltsov <svu@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <memory.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdkx.h>
+#include <glib/gi18n.h>
+
+#include <libgnomekbd/gkbd-desktop-config.h>
+#include <libgnomekbd/gkbd-indicator-config.h>
+
+#include "gkbd-configuration.h"
+
+struct _GkbdConfigurationPrivate {
+	XklEngine *engine;
+	XklConfigRegistry *registry;
+
+	GkbdDesktopConfig cfg;
+	GkbdIndicatorConfig ind_cfg;
+	GkbdKeyboardConfig kbd_cfg;
+
+	gchar **full_group_names;
+	gchar **short_group_names;
+
+	gulong state_changed_handler;
+	gulong config_changed_handler;
+};
+
+enum {
+	SIGNAL_CHANGED,
+	SIGNAL_GROUP_CHANGED,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0, };
+
+#define GKBD_CONFIGURATION_GET_PRIVATE(o) \
+	(G_TYPE_INSTANCE_GET_PRIVATE ((o), GKBD_TYPE_CONFIGURATION, GkbdConfigurationPrivate))
+
+G_DEFINE_TYPE (GkbdConfiguration, gkbd_configuration, G_TYPE_OBJECT)
+
+/* Should be called once for all widgets */
+static void
+gkbd_configuration_cfg_changed (GSettings *settings,
+				 const char *key,
+				 GkbdConfiguration * configuration)
+{
+	GkbdConfigurationPrivate *priv = configuration->priv;
+
+	xkl_debug (100,
+		   "General configuration changed in GSettings - reiniting...\n");
+	gkbd_desktop_config_load (&priv->cfg);
+	gkbd_desktop_config_activate (&priv->cfg);
+
+	g_signal_emit (configuration,
+		       signals[SIGNAL_CHANGED], 0);
+}
+
+/* Should be called once for all widgets */
+static void
+gkbd_configuration_ind_cfg_changed (GSettings *settings,
+				     const char *key,
+				     GkbdConfiguration * configuration)
+{
+	GkbdConfigurationPrivate *priv = configuration->priv;
+	xkl_debug (100,
+		   "Applet configuration changed in GSettings - reiniting...\n");
+	gkbd_indicator_config_load (&priv->ind_cfg);
+
+	gkbd_indicator_config_free_image_filenames (&priv->ind_cfg);
+	gkbd_indicator_config_load_image_filenames (&priv->ind_cfg,
+						    &priv->kbd_cfg);
+
+	gkbd_indicator_config_activate (&priv->ind_cfg);
+
+	g_signal_emit (configuration,
+		       signals[SIGNAL_CHANGED], 0);
+}
+
+static void
+gkbd_configuration_load_group_names (GkbdConfiguration * configuration,
+				     XklConfigRec * xklrec)
+{
+	GkbdConfigurationPrivate *priv = configuration->priv;
+
+	if (!gkbd_desktop_config_load_group_descriptions (&priv->cfg,
+							  priv->registry,
+							  (const char **) xklrec->layouts,
+							  (const char **) xklrec->variants,
+	     						  &priv->short_group_names,
+							  &priv->full_group_names)) {
+		/* We just populate no short names (remain NULL) - 
+		 * full names are going to be used anyway */
+		gint i, total_groups =
+		    xkl_engine_get_num_groups (priv->engine);
+		xkl_debug (150, "group descriptions loaded: %d!\n",
+			   total_groups);
+		priv->full_group_names =
+		    g_new0 (char *, total_groups + 1);
+
+		if (xkl_engine_get_features (priv->engine) &
+		    XKLF_MULTIPLE_LAYOUTS_SUPPORTED) {
+			for (i = 0; priv->kbd_cfg.layouts_variants[i]; i++) {
+				priv->full_group_names[i] =
+				    g_strdup ((char *) priv->kbd_cfg.layouts_variants[i]);
+			}
+		} else {
+			for (i = total_groups; --i >= 0;) {
+				priv->full_group_names[i] =
+				    g_strdup_printf ("Group %d", i);
+			}
+		}
+	}
+}
+
+/* Should be called once for all widgets */
+static void
+gkbd_configuration_kbd_cfg_callback (XklEngine *engine,
+				     GkbdConfiguration *configuration)
+{
+	GkbdConfigurationPrivate *priv = configuration->priv;
+	XklConfigRec *xklrec = xkl_config_rec_new ();
+	xkl_debug (100,
+		   "XKB configuration changed on X Server - reiniting...\n");
+
+	gkbd_keyboard_config_load_from_x_current (&priv->kbd_cfg,
+						  xklrec);
+
+	gkbd_indicator_config_free_image_filenames (&priv->ind_cfg);
+	gkbd_indicator_config_load_image_filenames (&priv->ind_cfg,
+						    &priv->kbd_cfg);
+
+	g_strfreev (priv->full_group_names);
+	priv->full_group_names = NULL;
+
+	g_strfreev (priv->short_group_names);
+	priv->short_group_names = NULL;
+
+	gkbd_configuration_load_group_names (configuration,
+				 	     xklrec);
+
+	g_signal_emit (configuration,
+		       signals[SIGNAL_CHANGED],
+		       0);
+
+	g_object_unref (G_OBJECT (xklrec));
+}
+
+/* Should be called once for all applets */
+static void
+gkbd_configuration_state_callback (XklEngine * engine,
+				   XklEngineStateChange changeType,
+			    	   gint group, gboolean restore,
+				   GkbdConfiguration * configuration)
+{
+	xkl_debug (150, "group is now %d, restore: %d\n", group, restore);
+
+	if (changeType == GROUP_CHANGED) {
+		g_signal_emit (configuration,
+			       signals[SIGNAL_GROUP_CHANGED], 0,
+			       group);
+	}
+}
+
+static void
+gkbd_configuration_init (GkbdConfiguration *configuration)
+{
+	GkbdConfigurationPrivate *priv;
+	XklConfigRec *xklrec = xkl_config_rec_new ();
+
+	priv = GKBD_CONFIGURATION_GET_PRIVATE (configuration);
+	configuration->priv = priv;
+
+	priv->engine = xkl_engine_get_instance (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
+	if (priv->engine == NULL) {
+		xkl_debug (0, "Libxklavier initialization error");
+		return;
+	}
+
+	priv->state_changed_handler =
+	    g_signal_connect (priv->engine, "X-state-changed",
+			      G_CALLBACK (gkbd_configuration_state_callback),
+			      configuration);
+	priv->config_changed_handler =
+	    g_signal_connect (priv->engine, "X-config-changed",
+			      G_CALLBACK (gkbd_configuration_kbd_cfg_callback),
+			      configuration);
+
+	gkbd_desktop_config_init (&priv->cfg, priv->engine);
+	gkbd_keyboard_config_init (&priv->kbd_cfg, priv->engine);
+	gkbd_indicator_config_init (&priv->ind_cfg, priv->engine);
+
+	gkbd_desktop_config_load (&priv->cfg);
+	gkbd_desktop_config_activate (&priv->cfg);
+
+	priv->registry = xkl_config_registry_get_instance (priv->engine);
+	xkl_config_registry_load (priv->registry,
+				  priv->cfg.load_extra_items);
+
+	gkbd_keyboard_config_load_from_x_current (&priv->kbd_cfg,
+						  xklrec);
+
+	gkbd_indicator_config_load (&priv->ind_cfg);
+
+	gkbd_indicator_config_load_image_filenames (&priv->ind_cfg,
+						    &priv->kbd_cfg);
+
+	gkbd_indicator_config_activate (&priv->ind_cfg);
+
+	gkbd_configuration_load_group_names (configuration,
+					     xklrec);
+	g_object_unref (G_OBJECT (xklrec));
+
+	gkbd_desktop_config_start_listen (&priv->cfg,
+					  G_CALLBACK (gkbd_configuration_cfg_changed),
+					  configuration);
+	gkbd_indicator_config_start_listen (&priv->ind_cfg,
+					    G_CALLBACK (gkbd_configuration_ind_cfg_changed),
+					    configuration);
+	xkl_engine_start_listen (priv->engine,
+				 XKLL_TRACK_KEYBOARD_STATE);
+
+	xkl_debug (100, "Initiating the widget startup process for %p\n",
+		   configuration);
+}
+
+static void
+gkbd_configuration_finalize (GObject * obj)
+{
+	GkbdConfiguration *configuration = GKBD_CONFIGURATION (obj);
+	GkbdConfigurationPrivate *priv = configuration->priv;
+
+	xkl_debug (100,
+		   "Starting the gnome-kbd-configuration widget shutdown process for %p\n",
+		   configuration);
+
+	xkl_engine_stop_listen (priv->engine,
+				XKLL_TRACK_KEYBOARD_STATE);
+
+	gkbd_desktop_config_stop_listen (&priv->cfg);
+	gkbd_indicator_config_stop_listen (&priv->ind_cfg);
+
+	gkbd_indicator_config_term (&priv->ind_cfg);
+	gkbd_keyboard_config_term (&priv->kbd_cfg);
+	gkbd_desktop_config_term (&priv->cfg);
+
+	if (g_signal_handler_is_connected (priv->engine,
+					   priv->state_changed_handler)) {
+		g_signal_handler_disconnect (priv->engine,
+					     priv->state_changed_handler);
+		priv->state_changed_handler = 0;
+	}
+	if (g_signal_handler_is_connected (priv->engine,
+					   priv->config_changed_handler)) {
+		g_signal_handler_disconnect (priv->engine,
+					     priv->config_changed_handler);
+		priv->config_changed_handler = 0;
+	}
+
+	g_object_unref (priv->registry);
+	priv->registry = NULL;
+	g_object_unref (priv->engine);
+	priv->engine = NULL;
+
+	G_OBJECT_CLASS (gkbd_configuration_parent_class)->finalize (obj);
+}
+
+static void
+gkbd_configuration_class_init (GkbdConfigurationClass * klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	/* Initing vtable */
+	object_class->finalize = gkbd_configuration_finalize;
+
+	/* Signals */
+	signals[SIGNAL_CHANGED] = g_signal_new ("changed",
+						GKBD_TYPE_CONFIGURATION,
+						G_SIGNAL_RUN_LAST,
+						0,
+						NULL, NULL,
+						g_cclosure_marshal_VOID__VOID,
+						G_TYPE_NONE,
+						0);
+	signals[SIGNAL_GROUP_CHANGED] = g_signal_new ("group-changed",
+						      GKBD_TYPE_CONFIGURATION,
+						      G_SIGNAL_RUN_LAST,
+						      0,
+						      NULL, NULL,
+						      g_cclosure_marshal_VOID__INT,
+						      G_TYPE_NONE,
+						      1,
+						      G_TYPE_INT);
+
+	g_type_class_add_private (klass, sizeof (GkbdConfigurationPrivate));
+}
+
+GkbdConfiguration *
+gkbd_configuration_get (void)
+{
+	static gpointer instance = NULL;
+
+	if (!instance) {
+		instance = g_object_new (GKBD_TYPE_CONFIGURATION, NULL);
+		g_object_add_weak_pointer (instance, &instance);
+	} else {
+		g_object_ref (instance);
+	}
+
+	return instance;
+}
+
+XklEngine *
+gkbd_configuration_get_xkl_engine (GkbdConfiguration *configuration)
+{
+	return configuration->priv->engine;
+}
+
+const char * const *
+gkbd_configuration_get_group_names (GkbdConfiguration *configuration)
+{
+	return configuration->priv->full_group_names;
+}
+
+const char * const *
+gkbd_configuration_get_short_group_names (GkbdConfiguration *configuration)
+{
+	return configuration->priv->short_group_names;
+}
Index: gnome-settings-daemon-3.3.91/plugins/keyboard/gkbd-configuration.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gnome-settings-daemon-3.3.91/plugins/keyboard/gkbd-configuration.h	2012-03-05 21:04:12.933981066 +0100
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010 Canonical Ltd.
+ * 
+ * Authors: Jan Arne Petersen <jpetersen@openismus.com>
+ * 
+ * Based on gkbd-status.h by Sergey V. Udaltsov <svu@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GKBD_CONFIGURATION_H__
+#define __GKBD_CONFIGURATION_H__
+
+#include <glib-object.h>
+
+#include <libxklavier/xklavier.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GkbdConfiguration GkbdConfiguration;
+typedef struct _GkbdConfigurationPrivate GkbdConfigurationPrivate;
+typedef struct _GkbdConfigurationClass GkbdConfigurationClass;
+
+#define GKBD_TYPE_CONFIGURATION           (gkbd_configuration_get_type ())
+#define GKBD_CONFIGURATION(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKBD_TYPE_CONFIGURATION, GkbdConfiguration))
+#define GKBD_INDCATOR_CLASS(obj)          (G_TYPE_CHECK_CLASS_CAST ((obj), GKBD_TYPE_CONFIGURATION,  GkbdConfigurationClass))
+#define GKBD_IS_CONFIGURATION(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKBD_TYPE_CONFIGURATION))
+#define GKBD_IS_CONFIGURATION_CLASS(obj)  (G_TYPE_CHECK_CLASS_TYPE ((obj), GKBD_TYPE_CONFIGURATION))
+#define GKBD_CONFIGURATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GKBD_TYPE_CONFIGURATION, GkbdConfigurationClass))
+
+struct _GkbdConfiguration {
+	GObject parent;
+
+	GkbdConfigurationPrivate *priv;
+};
+
+struct _GkbdConfigurationClass {
+	GObjectClass parent_class;
+};
+
+extern GType gkbd_configuration_get_type (void);
+
+extern GkbdConfiguration *gkbd_configuration_get (void);
+
+extern XklEngine *gkbd_configuration_get_xkl_engine (GkbdConfiguration *configuration);
+
+extern const char * const *gkbd_configuration_get_group_names (GkbdConfiguration *configuration);
+extern const char * const *gkbd_configuration_get_short_group_names (GkbdConfiguration *configuration);
+
+G_END_DECLS
+
+#endif
Index: gnome-settings-daemon-3.3.91/plugins/keyboard/gsd-keyboard-xkb.c
===================================================================
--- gnome-settings-daemon-3.3.91.orig/plugins/keyboard/gsd-keyboard-xkb.c	2012-02-01 20:33:15.000000000 +0100
+++ gnome-settings-daemon-3.3.91/plugins/keyboard/gsd-keyboard-xkb.c	2012-03-05 21:04:12.933981066 +0100
@@ -30,12 +30,20 @@
 #include <gdk/gdkx.h>
 #include <gtk/gtk.h>
 
+#ifndef HAVE_APPINDICATOR
 #include <libgnomekbd/gkbd-status.h>
+#endif
 #include <libgnomekbd/gkbd-keyboard-drawing.h>
 #include <libgnomekbd/gkbd-desktop-config.h>
+#include <libgnomekbd/gkbd-indicator-config.h>
 #include <libgnomekbd/gkbd-keyboard-config.h>
 #include <libgnomekbd/gkbd-util.h>
 
+#ifdef HAVE_APPINDICATOR
+#include <libappindicator/app-indicator.h>
+#include "gkbd-configuration.h"
+#endif
+
 #include "gsd-keyboard-xkb.h"
 #include "delayed-dialog.h"
 #include "gnome-settings-profile.h"
@@ -61,7 +69,21 @@
 static PostActivationCallback pa_callback = NULL;
 static void *pa_callback_user_data = NULL;
 
+#ifdef HAVE_APPINDICATOR
+static AppIndicator *app_indicator = NULL;
+static GkbdConfiguration *gkbd_configuration = NULL;
+static GkbdIndicatorConfig current_ind_config;
+static GSList *groups_items_group = NULL;
+static size_t lang_menu_items = 0;
+
+static void state_callback (XklEngine * engine,
+                            XklEngineStateChange changeType,
+                            gint group, gboolean restore);
+static void gsd_keyboard_configuration_changed (GkbdConfiguration *configuration);
+
+#else
 static GtkStatusIcon *icon = NULL;
+#endif
 
 static GHashTable *preview_dialogs = NULL;
 
@@ -174,10 +196,14 @@
 	    xkl_engine_get_instance (GDK_DISPLAY_XDISPLAY
 				     (gdk_display_get_default ()));
 	XklState *xkl_state = xkl_engine_get_current_state (engine);
+#ifdef HAVE_APPINDICATOR
+	gchar **group_names = gkbd_configuration_get_group_names (gkbd_configuration);
+#else
+	gchar **group_names = gkbd_status_get_group_names ();
+#endif
 	gpointer p = g_hash_table_lookup (preview_dialogs,
 					  GINT_TO_POINTER
 					  (xkl_state->group));
-	gchar **group_names = gkbd_status_get_group_names ();
 
 	if (xkl_state->group < 0
 	    || xkl_state->group >= g_strv_length (group_names)) {
@@ -205,38 +231,185 @@
 }
 
 static void
-popup_menu_set_group (GtkMenuItem * item, gpointer param)
+popup_menu_set_group (gint group_number, gboolean only_menu)
 {
-	gint group_number = GPOINTER_TO_INT (param);
+#ifdef HAVE_APPINDICATOR
+	XklEngine *engine = gkbd_configuration_get_xkl_engine (gkbd_configuration);
+#else
 	XklEngine *engine = gkbd_status_get_xkl_engine ();
-	XklState st;
+#endif
+	XklState *st = xkl_engine_get_current_state(engine);
 	Window cur;
-
-	st.group = group_number;
+	st->group = group_number;
 	xkl_engine_allow_one_switch_to_secondary_group (engine);
 	cur = xkl_engine_get_current_window (engine);
 	if (cur != (Window) NULL) {
 		xkl_debug (150, "Enforcing the state %d for window %lx\n",
-			   st.group, cur);
+			   st->group, cur);
+#ifdef HAVE_APPINDICATOR
+                // Setting the state may trigger state_callback to be called, which will then
+                // cause popup_menu_set_group to be called again.
+                g_signal_handlers_block_by_func (engine, G_CALLBACK (state_callback), NULL);
+#endif
 		xkl_engine_save_state (engine,
 				       xkl_engine_get_current_window
-				       (engine), &st);
+				       (engine), st);
+#ifdef HAVE_APPINDICATOR
+                g_signal_handlers_unblock_by_func (engine, G_CALLBACK (state_callback), NULL);
+#endif
 /*    XSetInputFocus( GDK_DISPLAY(), cur, RevertToNone, CurrentTime );*/
 	} else {
 		xkl_debug (150,
 			   "??? Enforcing the state %d for unknown window\n",
-			   st.group);
+			   st->group);
 		/* strange situation - bad things can happen */
 	}
-	xkl_engine_lock_group (engine, st.group);
+        if (!only_menu)
+        	xkl_engine_lock_group (engine, st->group);
+#ifdef HAVE_APPINDICATOR
+	XklConfigRec * xklrec = xkl_config_rec_new();
+	xkl_config_rec_get_from_server (xklrec, engine);
+	XklConfigRegistry *registry = xkl_config_registry_get_instance(engine);
+
+	gkbd_keyboard_config_load_from_x_current (&current_kbd_config, xklrec);
+	xkl_config_registry_load (registry, current_config.load_extra_items);
+
+	int g;
+
+        if (current_ind_config.show_flags) {
+	        gchar *image_file = gkbd_indicator_config_get_images_file (&current_ind_config,
+						              &current_kbd_config,
+						              st->group);
+
+        
+                app_indicator_set_icon_full(app_indicator, image_file, _("Keyboard"));
+	        app_indicator_set_label(app_indicator, NULL, NULL);
+                g_free(image_file);
+        } else {
+                gchar * guide = "XXX";
+	        gchar ** shortnames;
+	        gchar ** longnames;
+	        gchar * layout_name = NULL;
+	        gchar * lname = NULL;
+	        GHashTable *ln2cnt_map = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
+
+	        gkbd_desktop_config_load_group_descriptions(&current_config, registry, 
+		        (const gchar **) xklrec->layouts, 
+		        (const gchar **) xklrec->variants,
+		        &shortnames,
+		        &longnames); 
+
+	        for (g = 0; g < g_strv_length (shortnames);g++) {
+		        gpointer pcounter = NULL;
+		        gchar *prev_layout_name = NULL;
+		        int counter = 0;
+
+		        if (g < g_strv_length (shortnames)) {
+			        if (xkl_engine_get_features (engine) &
+			            XKLF_MULTIPLE_LAYOUTS_SUPPORTED) {
+				        gchar *longname = (gchar *) current_kbd_config.layouts_variants[g];
+				        gchar *variant_name;
+				        if (!gkbd_keyboard_config_split_items (longname, &lname, &variant_name))
+					        /* just in case */
+					        lname = longname;
+
+				        if (shortnames != NULL) {
+					        gchar *shortname = shortnames[g];
+					        if (shortname != NULL && *shortname != '\0') {
+						        lname = shortname;
+					        }
+				        }
+			        } else {
+				        lname = longnames[g];
+			        }
+		        }
+		        if (lname == NULL)
+			        lname = "";
+
+		        /* Process layouts with repeating description */
+		        if (g_hash_table_lookup_extended (ln2cnt_map, lname, (gpointer *) & prev_layout_name, &pcounter)) {
+			        /* "next" same description */
+			        counter = GPOINTER_TO_INT (pcounter);
+                                guide = "XXX1";
+		        }
+		        g_hash_table_insert (ln2cnt_map, g_strdup (lname), GINT_TO_POINTER (counter+1));
+
+		        if (st->group == g) {
+			        if (counter > 0) {
+				        gchar appendix[10] = "";
+				        gint utf8length;
+				        gunichar cidx;
+				        /* Unicode subscript 2, 3, 4 */
+				        cidx = 0x2081 + counter;
+				        utf8length = g_unichar_to_utf8 (cidx, appendix);
+				        appendix[utf8length] = '\0';
+				        layout_name = g_strconcat (lname, appendix, NULL);
+			        } else {
+				        layout_name = g_strdup(lname);
+			        }
+		        }
+	        }
+
+	        // Guide of 3 wide-ish and one thin
+	        app_indicator_set_label(app_indicator, layout_name, guide);
+	        g_hash_table_destroy(ln2cnt_map);
+	        g_free(layout_name);
+	        g_strfreev(longnames);
+	        g_strfreev(shortnames);
+        }
+
+        // Refresh popup menu
+        gsd_keyboard_configuration_changed (gkbd_configuration);
+
+	g_object_unref (G_OBJECT (xklrec));
+	g_object_unref (G_OBJECT (registry));
+#endif
 }
 
 static void
-status_icon_popup_menu_cb (GtkStatusIcon * icon, guint button, guint time)
+popup_menu_set_group_cb (GtkMenuItem * item, gpointer param)
+{
+	gint group_number = GPOINTER_TO_INT (param);
+
+#ifdef HAVE_APPINDICATOR
+	if ((item) != NULL && (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item))))
+		return;
+#endif
+
+	popup_menu_set_group(group_number, FALSE);
+}
+
+#ifdef HAVE_APPINDICATOR
+static void
+state_callback (XklEngine * engine,
+		XklEngineStateChange changeType,
+		gint group, gboolean restore)
+{
+	if ((changeType == GROUP_CHANGED) || (changeType == INDICATORS_CHANGED))
+		popup_menu_set_group (GINT_TO_POINTER(group), TRUE);
+}
+
+static int
+get_current_group(void)
+{
+	XklEngine *engine = gkbd_configuration_get_xkl_engine (gkbd_configuration);
+	return xkl_engine_get_current_window_group (engine);
+}
+#endif
+
+static GtkMenu *
+create_status_menu (void)
 {
 	GtkMenu *popup_menu = GTK_MENU (gtk_menu_new ());
-	GtkMenu *groups_menu = GTK_MENU (gtk_menu_new ());
 	int i = 0;
+#ifdef HAVE_APPINDICATOR
+	const char * const *current_name = gkbd_configuration_get_group_names (gkbd_configuration);
+	groups_items_group = NULL;
+        GtkWidget *item;
+	int group = get_current_group();
+	lang_menu_items = 0;
+#else
+	GtkMenu *groups_menu = GTK_MENU (gtk_menu_new ());
 	gchar **current_name = gkbd_status_get_group_names ();
 
 	GtkWidget *item = gtk_menu_item_new_with_mnemonic (_("_Layouts"));
@@ -256,8 +429,23 @@
 	gtk_widget_show (item);
 	g_signal_connect (item, "activate", popup_menu_launch_capplet, NULL);
 	gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), item);
+#endif
+
+	for (i = 0; current_name && *current_name; i++, current_name++) {
+#ifdef HAVE_APPINDICATOR
+		item = gtk_radio_menu_item_new_with_label (groups_items_group, *current_name);
+		groups_items_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item));
 
-	for (i = 0; *current_name; i++, current_name++) {
+		gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
+						i == group);
+
+		gtk_widget_show (item);
+		gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), item);
+		g_signal_connect (item, "activate",
+				  G_CALLBACK (popup_menu_set_group_cb),
+				  GINT_TO_POINTER (i));
+		lang_menu_items++;
+#else
 		gchar *image_file = gkbd_status_get_image_filename (i);
 
 		if (image_file == NULL) {
@@ -283,19 +471,84 @@
 		gtk_widget_show (item);
 		gtk_menu_shell_append (GTK_MENU_SHELL (groups_menu), item);
 		g_signal_connect (item, "activate",
-				  G_CALLBACK (popup_menu_set_group),
+				  G_CALLBACK (popup_menu_set_group_cb),
 				  GINT_TO_POINTER (i));
+#endif
 	}
 
+#ifdef HAVE_APPINDICATOR
+        item = gtk_separator_menu_item_new();
+        gtk_widget_show(item);
+        gtk_menu_shell_append(GTK_MENU_SHELL (popup_menu), item);
+
+	item =
+	    gtk_menu_item_new_with_mnemonic (_("Show _Layout Chart"));
+	gtk_widget_show (item);
+	g_signal_connect (item, "activate", popup_menu_show_layout,
+			  NULL);
+	gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), item);
+
+	item = gtk_menu_item_new_with_mnemonic (_("Keyboard Layout _Settings..."));
+	gtk_widget_show (item);
+	g_signal_connect (item, "activate", popup_menu_launch_capplet, NULL);
+	gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), item);
+#endif
+
+	return popup_menu;
+}
+
+#ifndef HAVE_APPINDICATOR
+static void
+status_icon_popup_menu_cb (GtkStatusIcon * icon, guint button, guint time)
+{
+	GtkMenu *popup_menu = create_status_menu ();
+
 	gtk_menu_popup (popup_menu, NULL, NULL,
 			gtk_status_icon_position_menu,
 			(gpointer) icon, button, time);
 }
+#endif
+
+#ifdef HAVE_APPINDICATOR
+static void
+scroll_event (AppIndicator *indicator, gint delta, guint direction)
+{
+	g_return_if_fail(IS_APP_INDICATOR(indicator));
+	int group = get_current_group();
+
+	if ((direction == 0 && group == 0) ||
+	    (direction == 1 && group == lang_menu_items-1))
+		return;
+
+        popup_menu_set_group((direction == 0 ? group-1 : group+1), FALSE);
+}
+#endif
 
 static void
 show_hide_icon ()
 {
 	if (g_strv_length (current_kbd_config.layouts_variants) > 1) {
+#ifdef HAVE_APPINDICATOR
+		if (app_indicator == NULL) {
+			GtkMenu *popup_menu = create_status_menu ();
+
+			app_indicator = app_indicator_new ("keyboard",
+							   "keyboard",
+							   APP_INDICATOR_CATEGORY_HARDWARE);
+	                int group = get_current_group();
+	        	popup_menu_set_group(GINT_TO_POINTER(group), TRUE);
+			app_indicator_set_status (app_indicator,
+						  APP_INDICATOR_STATUS_ACTIVE);
+			app_indicator_set_menu (app_indicator,
+						popup_menu);
+			app_indicator_set_title (app_indicator, _("Keyboard"));
+			g_signal_connect (app_indicator, "scroll-event", G_CALLBACK (scroll_event), NULL);
+		} else {
+                        XklEngine *engine = gkbd_configuration_get_xkl_engine (gkbd_configuration);
+			XklState *st = xkl_engine_get_current_state(engine);
+			popup_menu_set_group(GINT_TO_POINTER(st->group), TRUE);
+                }
+#else
 		if (icon == NULL) {
 			xkl_debug (150, "Creating keyboard status icon\n");
 			icon = gkbd_status_new ();
@@ -305,12 +558,17 @@
 					  NULL);
 
 		}
+#endif
 	} else {
+#ifdef HAVE_APPINDICATOR
+		g_clear_object (&app_indicator);
+#else
 		if (icon != NULL) {
 			xkl_debug (150, "Destroying icon\n");
 			g_object_unref (icon);
 			icon = NULL;
 		}
+#endif
 	}
 }
 
@@ -399,6 +660,15 @@
 	gkbd_keyboard_config_load_from_x_current (&current_sys_kbd_config,
 						  NULL);
 
+#ifdef HAVE_APPINDICATOR
+	gkbd_indicator_config_init (&current_ind_config, xkl_engine);
+	gkbd_indicator_config_load (&current_ind_config);
+
+	gkbd_indicator_config_load_image_filenames (&current_ind_config,
+						    &current_kbd_config);
+	gkbd_indicator_config_activate (&current_ind_config);
+#endif /* HAVE_APPINDICATOR */
+
 	if (!try_activating_xkb_config_if_new (&current_sys_kbd_config)) {
 		if (filter_xkb_config ()) {
 			if (!try_activating_xkb_config_if_new
@@ -431,6 +701,22 @@
 						  NULL);
 }
 
+#ifdef HAVE_APPINDICATOR
+/* When the configuration changed update the indicator */
+static void
+gsd_keyboard_configuration_changed (GkbdConfiguration *configuration)
+{
+	GtkMenu *popup_menu;
+
+	if (!app_indicator)
+		return;
+
+	popup_menu = create_status_menu ();
+	app_indicator_set_menu (app_indicator,
+			popup_menu);
+}
+#endif
+
 void
 gsd_keyboard_xkb_set_post_activation_callback (PostActivationCallback fun,
 					       void *user_data)
@@ -466,6 +752,13 @@
 					   DATADIR G_DIR_SEPARATOR_S
 					   "icons");
 
+#ifdef HAVE_APPINDICATOR
+	gkbd_configuration = gkbd_configuration_get ();
+	g_signal_connect (gkbd_configuration, "changed",
+			  G_CALLBACK (gsd_keyboard_configuration_changed), NULL);
+	g_signal_connect (gkbd_configuration, "group-changed",
+			  G_CALLBACK (gsd_keyboard_configuration_changed), NULL);
+#endif
 	manager = kbd_manager;
 	gnome_settings_profile_start ("xkl_engine_get_instance");
 	xkl_engine = xkl_engine_get_instance (display);
@@ -487,6 +780,9 @@
 		g_signal_connect (settings_keyboard, "changed",
 				  (GCallback) apply_xkb_settings, NULL);
 
+#ifdef HAVE_APPINDICATOR
+		g_signal_connect (xkl_engine, "X-state-changed", G_CALLBACK (state_callback), NULL);
+#endif
 		gdk_window_add_filter (NULL, (GdkFilterFunc)
 				       gsd_keyboard_xkb_evt_filter, NULL);
 
@@ -549,5 +845,10 @@
 	g_object_unref (xkl_engine);
 
 	xkl_engine = NULL;
+
+#ifdef HAVE_APPINDICATOR
+	g_clear_object (&gkbd_configuration);
+#endif
+
 	inited_ok = FALSE;
 }
Index: gnome-settings-daemon-3.3.91/plugins/keyboard/Makefile.am
===================================================================
--- gnome-settings-daemon-3.3.91.orig/plugins/keyboard/Makefile.am	2011-10-17 19:36:56.000000000 +0200
+++ gnome-settings-daemon-3.3.91/plugins/keyboard/Makefile.am	2012-03-05 21:04:12.937981066 +0100
@@ -24,6 +24,8 @@
 	gsd-keyboard-xkb.c	\
 	delayed-dialog.h	\
 	delayed-dialog.c	\
+	gkbd-configuration.c	\
+	gkbd-configuration.h	\
 	$(NULL)
 
 libkeyboard_la_CPPFLAGS = \
@@ -36,6 +38,7 @@
 libkeyboard_la_CFLAGS = \
 	$(PLUGIN_CFLAGS)		\
 	$(SETTINGS_PLUGIN_CFLAGS)	\
+	$(APPINDICATOR_CFLAGS)		\
 	$(KEYBOARD_CFLAGS)		\
 	$(AM_CFLAGS)
 
@@ -47,6 +50,7 @@
 	$(SETTINGS_PLUGIN_LIBS)	\
 	$(XF86MISC_LIBS)	\
 	$(KEYBOARD_LIBS)	\
+	$(APPINDICATOR_LIBS)	\
 	$(NULL)
 
 plugin_in_files = 		\
