diff -uNr -x .pc gnome-settings-daemon-2.30.2.orig/configure.ac gnome-settings-daemon-2.30.2/configure.ac
--- gnome-settings-daemon-2.30.2.orig/configure.ac	2010-08-19 11:17:16.679361002 +0100
+++ gnome-settings-daemon-2.30.2/configure.ac	2010-08-19 11:17:58.279361002 +0100
@@ -52,6 +52,7 @@
 GIO_REQUIRED_VERSION=2.17.3
 GNOME_DESKTOP_REQUIRED_VERSION=2.29.92
 LIBNOTIFY_REQUIRED_VERSION=0.4.3
+APPINDICATOR_REQUIRED_VERSION=0.2.4
 
 EXTRA_COMPILE_WARNINGS(yes)
 
@@ -108,6 +109,32 @@
 AC_SUBST(LIBNOTIFY_CFLAGS)
 AC_SUBST(LIBNOTIFY_LIBS)
 
+dnl ---------------------------------
+dnl - Application indicator
+dnl ---------------------------------
+
+AC_ARG_ENABLE([appindicator],
+	AS_HELP_STRING([--enable-appindicator[=@<:@no/auto/yes@:>@]],[Build support for application indicators]),
+	[enable_appindicator="yes"],
+	[enable_appindicator="auto"])
+
+
+if test x$enable_appindicator = xauto ; then
+	PKG_CHECK_EXISTS(appindicator-0.1 >= $APPINDICATOR_REQUIRED_VERSION,
+		[enable_appindicator="yes"],
+		[enable_appindicator="no"])
+fi
+
+if test x$enable_appindicator = xyes ; then
+	PKG_CHECK_MODULES(APPINDICATOR,
+		[appindicator-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 - Check for D-Bus
 dnl ---------------------------------------------------------------------------
@@ -392,6 +419,7 @@
         dbus-1 system.d dir:      ${DBUS_SYS_DIR}
 
         Libnotify support:        ${have_libnotify}
+	App indicatpr support:    ${enable_appindicator}
         PulseAudio support:       ${have_pulse}
         Profiling support:        ${enable_profiling}
 "
diff -uNr -x .pc gnome-settings-daemon-2.30.2.orig/plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c gnome-settings-daemon-2.30.2/plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c
--- gnome-settings-daemon-2.30.2.orig/plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c	2010-08-19 11:17:16.679361002 +0100
+++ gnome-settings-daemon-2.30.2/plugins/a11y-keyboard/gsd-a11y-keyboard-manager.c	2010-08-19 11:17:58.289361002 +0100
@@ -45,6 +45,10 @@
 #include <libnotify/notify.h>
 #endif /* HAVE_LIBNOTIFY */
 
+#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"
@@ -62,7 +66,11 @@
         GtkWidget *stickykeys_alert;
         GtkWidget *slowkeys_alert;
         GtkWidget *preferences_dialog;
+#ifdef HAVE_APPINDICATOR
+	AppIndicator *app_indicator;
+#else
         GtkStatusIcon *status_icon;
+#endif
         XkbDescRec *original_xkb_desc;
 
         guint      gconf_notify;
@@ -435,11 +443,24 @@
         show = gconf_client_get_bool (client, CONFIG_ROOT "/enable", NULL);
         g_object_unref (client);
 
+#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
 }
 
 #ifdef HAVE_LIBNOTIFY
@@ -521,9 +542,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);
@@ -538,7 +561,9 @@
                                                                message,
                                                                "preferences-desktop-accessibility",
                                                                NULL);
+#ifndef HAVE_APPINDICATOR
         notify_notification_attach_to_status_icon (manager->priv->notification, manager->priv->status_icon);
+#endif
         notify_notification_set_timeout (manager->priv->notification, NOTIFICATION_TIMEOUT * 1000);
 
         notify_notification_add_action (manager->priv->notification,
@@ -660,9 +685,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);
@@ -677,7 +704,9 @@
                                                                message,
                                                                "preferences-desktop-accessibility",
                                                                NULL);
+#ifndef HAVE_APPINDICATOR
         notify_notification_attach_to_status_icon (manager->priv->notification, manager->priv->status_icon);
+#endif
         notify_notification_set_timeout (manager->priv->notification, NOTIFICATION_TIMEOUT * 1000);
 
         notify_notification_add_action (manager->priv->notification,
@@ -1072,8 +1101,14 @@
 
         g_debug ("Stopping a11y_keyboard manager");
 
+#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);
+#endif
 
         if (p->gconf_notify != 0) {
                 GConfClient *client = gconf_client_get_default ();
@@ -1190,8 +1225,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 ();
@@ -1215,6 +1255,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 ("gsd-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");
@@ -1223,6 +1283,7 @@
                                   G_CALLBACK (on_status_icon_activate),
                                   manager);
         }
+#endif
 
         gnome_settings_profile_end (NULL);
 }
diff -uNr -x .pc gnome-settings-daemon-2.30.2.orig/plugins/a11y-keyboard/Makefile.am gnome-settings-daemon-2.30.2/plugins/a11y-keyboard/Makefile.am
--- gnome-settings-daemon-2.30.2.orig/plugins/a11y-keyboard/Makefile.am	2010-08-19 11:17:16.689361002 +0100
+++ gnome-settings-daemon-2.30.2/plugins/a11y-keyboard/Makefile.am	2010-08-19 11:17:58.289361002 +0100
@@ -53,6 +53,7 @@
 liba11y_keyboard_la_CFLAGS = \
 	$(SETTINGS_PLUGIN_CFLAGS)	\
 	$(LIBNOTIFY_CFLAGS)		\
+	$(APPINDICATOR_CFLAGS)		\
 	$(AM_CFLAGS)
 
 liba11y_keyboard_la_LDFLAGS = 		\
@@ -63,6 +64,7 @@
 	$(SETTINGS_PLUGIN_LIBS)		\
 	$(XF86MISC_LIBS)		\
 	$(LIBNOTIFY_LIBS)		\
+	$(APPINDICATOR_LIBS)		\
 	$(NULL)
 
 plugin_in_files = 		\
diff -uNr -x .pc gnome-settings-daemon-2.30.2.orig/plugins/keyboard/gkbd-configuration.c gnome-settings-daemon-2.30.2/plugins/keyboard/gkbd-configuration.c
--- gnome-settings-daemon-2.30.2.orig/plugins/keyboard/gkbd-configuration.c	1970-01-01 01:00:00.000000000 +0100
+++ gnome-settings-daemon-2.30.2/plugins/keyboard/gkbd-configuration.c	2010-08-19 11:17:58.289361002 +0100
@@ -0,0 +1,359 @@
+/*
+ * 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 (GConfClient * client,
+				guint cnxn_id, GConfEntry * entry,
+				GkbdConfiguration * configuration)
+{
+	GkbdConfigurationPrivate *priv = configuration->priv;
+
+	xkl_debug (100,
+		   "General configuration changed in GConf - reiniting...\n");
+	gkbd_desktop_config_load_from_gconf (&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 (GConfClient * client,
+				    guint cnxn_id, GConfEntry * entry,
+				    GkbdConfiguration * configuration)
+{
+	GkbdConfigurationPrivate *priv = configuration->priv;
+	xkl_debug (100,
+		   "Applet configuration changed in GConf - reiniting...\n");
+	gkbd_indicator_config_load_from_gconf (&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) {
+			GSList *lst = priv->kbd_cfg.layouts_variants;
+			for (i = 0; lst; lst = lst->next, i++) {
+				priv->full_group_names[i] =
+				    g_strdup ((char *) lst->data);
+			}
+		} 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;
+	GConfClient *gconf_client;
+	XklConfigRec *xklrec = xkl_config_rec_new ();
+
+	priv = GKBD_CONFIGURATION_GET_PRIVATE (configuration);
+	configuration->priv = priv;
+
+	priv->engine = xkl_engine_get_instance (GDK_DISPLAY ());
+	if (priv->engine == NULL) {
+		xkl_debug (0, "Libxklavier initialization error");
+		return;
+	}
+
+	gconf_client = gconf_client_get_default ();
+
+	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, gconf_client,
+				  priv->engine);
+	gkbd_keyboard_config_init (&priv->kbd_cfg, gconf_client,
+				   priv->engine);
+	gkbd_indicator_config_init (&priv->ind_cfg, gconf_client,
+				    priv->engine);
+
+	g_object_unref (gconf_client);
+
+	gkbd_desktop_config_load_from_gconf (&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_from_gconf (&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,
+					  (GConfClientNotifyFunc) gkbd_configuration_cfg_changed,
+					  configuration);
+	gkbd_indicator_config_start_listen (&priv->ind_cfg,
+					    (GConfClientNotifyFunc) 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;
+}
diff -uNr -x .pc gnome-settings-daemon-2.30.2.orig/plugins/keyboard/gkbd-configuration.h gnome-settings-daemon-2.30.2/plugins/keyboard/gkbd-configuration.h
--- gnome-settings-daemon-2.30.2.orig/plugins/keyboard/gkbd-configuration.h	1970-01-01 01:00:00.000000000 +0100
+++ gnome-settings-daemon-2.30.2/plugins/keyboard/gkbd-configuration.h	2010-08-19 11:17:58.289361002 +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
diff -uNr -x .pc gnome-settings-daemon-2.30.2.orig/plugins/keyboard/gsd-keyboard-xkb.c gnome-settings-daemon-2.30.2/plugins/keyboard/gsd-keyboard-xkb.c
--- gnome-settings-daemon-2.30.2.orig/plugins/keyboard/gsd-keyboard-xkb.c	2010-08-19 11:17:16.719361002 +0100
+++ gnome-settings-daemon-2.30.2/plugins/keyboard/gsd-keyboard-xkb.c	2010-09-01 16:25:07.679145002 +0100
@@ -31,12 +31,20 @@
 #include <gtk/gtk.h>
 #include <gconf/gconf-client.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-xmodmap.h"
 #include "gsd-keyboard-xkb.h"
 #include "delayed-dialog.h"
@@ -71,7 +79,14 @@
 
 static const char *gdm_keyboard_layout = NULL;
 
+#ifdef HAVE_APPINDICATOR
+static AppIndicator *app_indicator = NULL;
+static GkbdConfiguration *gkbd_configuration = NULL;
+static GkbdIndicatorConfig current_ind_config;
+GSList *groups_items_group = NULL;
+#else
 static GtkStatusIcon *icon = NULL;
+#endif
 
 static GHashTable *preview_dialogs = NULL;
 
@@ -239,7 +254,11 @@
 
 	XklEngine *engine = xkl_engine_get_instance (GDK_DISPLAY ());
 	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));
@@ -361,35 +380,171 @@
 popup_menu_set_group (GtkMenuItem * item, gpointer param)
 {
 	gint group_number = GPOINTER_TO_INT (param);
+#ifdef HAVE_APPINDICATOR
+	XklEngine *engine = gkbd_configuration_get_xkl_engine (gkbd_configuration);
+	if ((item) != NULL && (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item))))		
+                return;
+#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. As state_callback calls us
+                // without an item, we check that and only set the state if an item was sent
+                // in the callback, and therefore was a menu item click which did it. 
+                if (item != NULL) {
+		        xkl_engine_save_state (engine,
+				               xkl_engine_get_current_window
+				               (engine), st);
+                }
+#else
 		xkl_engine_save_state (engine,
 				       xkl_engine_get_current_window
-				       (engine), &st);
+				       (engine), st);
+#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);
+	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(app_indicator, image_file);
+	        app_indicator_set_label(app_indicator, NULL, NULL);
+                g_free(image_file);
+        } else {
+                gchar * guide = "XXX";
+	        gchar ** shortnames;
+	        gchar ** longnames;
+	        gchar * layout_name;
+	        gchar * lname = NULL;
+	        GHashTable *ln2cnt_map = g_hash_table_new (g_str_hash, g_str_equal);
+
+	        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 *) g_slist_nth_data (current_kbd_config.layouts_variants, g);
+				        gchar *variant_name;
+				        if (!gkbd_keyboard_config_split_items (longname, &lname, &variant_name))
+					        /* just in case */
+					        lname = longname;
+
+				        /* make it freeable */
+				        lname = g_strdup (lname);
+
+				        if (shortnames != NULL) {
+					        gchar *shortname = shortnames[g];
+					        if (shortname != NULL && *shortname != '\0') {
+						        /* drop the long name */
+						        g_free (lname);
+						        lname = g_strdup (shortname);
+					        }
+				        }
+			        } else {
+				        lname = g_strdup (longnames[g]);
+			        }
+		        }
+		        if (lname == NULL)
+			        lname = g_strdup ("");
+
+		        /* 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, 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);
+			        }
+		        }
+		        g_free(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);
+        }
+
+	g_object_unref (G_OBJECT (xklrec));
+	g_object_unref (G_OBJECT (registry));
+#endif
 }
 
+#ifdef HAVE_APPINDICATOR
 static void
-status_icon_popup_menu_cb (GtkStatusIcon * icon, guint button, guint time)
+state_callback (XklEngine * engine,
+		XklEngineStateChange changeType,
+		gint group, gboolean restore)
+{
+	if (changeType == GROUP_CHANGED)
+		popup_menu_set_group(NULL, GINT_TO_POINTER(group));
+}
+#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;
+	XklEngine *engine = gkbd_configuration_get_xkl_engine (gkbd_configuration);
+	int group = xkl_engine_get_current_window_group (engine);
+#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 (_("_Groups"));
@@ -409,8 +564,22 @@
 	gtk_widget_show (item);
 	g_signal_connect (item, "activate", popup_menu_show_layout, 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),
+				  GINT_TO_POINTER (i));
+#else
 		gchar *image_file = gkbd_status_get_image_filename (i);
 
 		if (image_file == NULL) {
@@ -438,17 +607,66 @@
 		g_signal_connect (item, "activate",
 				  G_CALLBACK (popup_menu_set_group),
 				  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 (_("Keyboard _Preferences"));
+	gtk_widget_show (item);
+	g_signal_connect (item, "activate", popup_menu_launch_capplet,
+			  NULL);
+	gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), item);
+
+	item = gtk_menu_item_new_with_mnemonic (_("Show Current _Layout"));
+	gtk_widget_show (item);
+	g_signal_connect (item, "activate", popup_menu_show_layout, 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
 
 static void
 show_hide_icon ()
 {
 	if (g_slist_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 ("gst-keyboard-xkb",
+							   "keyboard",
+							   APP_INDICATOR_CATEGORY_HARDWARE);
+			XklEngine *engine = gkbd_configuration_get_xkl_engine (gkbd_configuration);
+	                int group = xkl_engine_get_current_window_group (engine);
+	        	popup_menu_set_group(NULL, GINT_TO_POINTER(group));
+			app_indicator_set_status (app_indicator,
+						  APP_INDICATOR_STATUS_ACTIVE);
+			app_indicator_set_menu (app_indicator,
+						popup_menu);
+		} else {
+                        XklEngine *engine = gkbd_configuration_get_xkl_engine (gkbd_configuration);
+			XklState *st = xkl_engine_get_current_state(engine);
+	        	popup_menu_set_group(NULL, GINT_TO_POINTER(st->group));
+                }
+#else
 		if (icon == NULL) {
 			GConfClient *conf_client =
 			    gconf_client_get_default ();
@@ -468,12 +686,20 @@
 					  NULL);
 
 		}
+#endif
 	} else {
+#ifdef HAVE_APPINDICATOR
+		if (app_indicator != NULL) {
+			g_object_unref (app_indicator);
+			app_indicator = NULL;
+		}
+#else
 		if (icon != NULL) {
 			xkl_debug (150, "Destroying icon\n");
 			g_object_unref (icon);
 			icon = NULL;
 		}
+#endif
 	}
 }
 
@@ -677,6 +903,14 @@
 	gkbd_keyboard_config_load_from_x_current (&current_sys_kbd_config,
 						  NULL);
 
+	gkbd_indicator_config_init (&current_ind_config, conf_client,
+				    xkl_engine);
+	gkbd_indicator_config_load_from_gconf (&current_ind_config);
+
+	gkbd_indicator_config_load_image_filenames (&current_ind_config,
+						    &current_kbd_config);
+	gkbd_indicator_config_activate (&current_ind_config);
+
 	if (!try_activating_xkb_config_if_new (&current_sys_kbd_config)) {
 		if (filter_xkb_config ()) {
 			if (!try_activating_xkb_config_if_new
@@ -814,6 +1048,22 @@
 	gsd_load_modmap_files ();
 }
 
+#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)
@@ -858,6 +1108,13 @@
 	logfile = fopen ("/tmp/gsdkx.log", "a");
 	xkl_set_log_appender (gsd_keyboard_log_appender);
 #endif
+#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 (GDK_DISPLAY ());
@@ -891,6 +1148,9 @@
 					      (GConfClientNotifyFunc)
 					      apply_xkb_settings);
 
+#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);
 
@@ -962,5 +1222,13 @@
 	g_object_unref (xkl_engine);
 
 	xkl_engine = NULL;
+
+#ifdef HAVE_APPINDICATOR
+	if (gkbd_configuration) {
+		g_object_unref (gkbd_configuration);
+		gkbd_configuration = NULL;
+	}
+#endif
+
 	inited_ok = FALSE;
 }
diff -uNr -x .pc gnome-settings-daemon-2.30.2.orig/plugins/keyboard/Makefile.am gnome-settings-daemon-2.30.2/plugins/keyboard/Makefile.am
--- gnome-settings-daemon-2.30.2.orig/plugins/keyboard/Makefile.am	2010-08-19 11:17:16.709361002 +0100
+++ gnome-settings-daemon-2.30.2/plugins/keyboard/Makefile.am	2010-08-19 11:17:58.289361002 +0100
@@ -18,6 +18,8 @@
 	gsd-xmodmap.c		\
 	delayed-dialog.h	\
 	delayed-dialog.c	\
+	gkbd-configuration.c	\
+	gkbd-configuration.h	\
 	$(NULL)
 
 libkeyboard_la_CPPFLAGS = \
@@ -29,6 +31,7 @@
 libkeyboard_la_CFLAGS = \
 	$(SETTINGS_PLUGIN_CFLAGS)	\
 	$(LIBGNOMEKBDUI_CFLAGS)		\
+	$(APPINDICATOR_CFLAGS)		\
 	$(AM_CFLAGS)
 
 libkeyboard_la_LDFLAGS = 	\
@@ -39,6 +42,7 @@
 	$(SETTINGS_PLUGIN_LIBS)	\
 	$(XF86MISC_LIBS)	\
 	$(LIBGNOMEKBDUI_LIBS)	\
+	$(APPINDICATOR_LIBS)	\
 	$(NULL)
 
 plugin_in_files = 		\
diff -uNr -x .pc gnome-settings-daemon-2.30.2.orig/plugins/xrandr/gsd-xrandr-manager.c gnome-settings-daemon-2.30.2/plugins/xrandr/gsd-xrandr-manager.c
--- gnome-settings-daemon-2.30.2.orig/plugins/xrandr/gsd-xrandr-manager.c	2010-08-19 11:17:16.729361002 +0100
+++ gnome-settings-daemon-2.30.2/plugins/xrandr/gsd-xrandr-manager.c	2010-08-19 11:17:58.289361002 +0100
@@ -49,6 +49,10 @@
 #include <libnotify/notify.h>
 #endif
 
+#ifdef HAVE_APPINDICATOR
+#include <libappindicator/app-indicator.h>
+#endif
+
 #include "gnome-settings-profile.h"
 #include "gsd-xrandr-manager.h"
 
@@ -93,7 +97,11 @@
         GnomeRRScreen *rw_screen;
         gboolean running;
 
+#ifdef HAVE_APPINDICATOR
+        AppIndicator *app_indicator;
+#else
         GtkStatusIcon *status_icon;
+#endif
         GtkWidget *popup_menu;
         GnomeRRConfig *configuration;
         GnomeRRLabeler *labeler;
@@ -908,17 +916,21 @@
 error_message (GsdXrandrManager *mgr, const char *primary_text, GError *error_to_display, const char *secondary_text)
 {
 #ifdef HAVE_LIBNOTIFY
+#ifndef HAVE_APPINDICATOR
         GsdXrandrManagerPrivate *priv = mgr->priv;
+#endif
         NotifyNotification *notification;
 
         g_assert (error_to_display == NULL || secondary_text == NULL);
 
+#ifndef HAVE_APPINDICATOR
         if (priv->status_icon)
                 notification = notify_notification_new_with_status_icon (primary_text,
                                                                          error_to_display ? error_to_display->message : secondary_text,
                                                                          GSD_XRANDR_ICON_NAME,
                                                                          priv->status_icon);
         else
+#endif
                 notification = notify_notification_new (primary_text,
                                                         error_to_display ? error_to_display->message : secondary_text,
                                                         GSD_XRANDR_ICON_NAME,
@@ -1168,6 +1180,11 @@
                 gtk_menu_shell_cancel (GTK_MENU_SHELL (priv->popup_menu)); /* status_icon_popup_menu_selection_done_cb() will free everything */
                 status_icon_popup_menu (manager, 0, timestamp);
         }
+#if 0
+        else {
+                status_icon_popup_menu (manager, 0, GDK_CURRENT_TIME);
+        }
+#endif
 }
 
 static void
@@ -1482,6 +1499,8 @@
         priv->configuration = NULL;
 }
 
+#ifndef HAVE_APPINDICATOR
+
 #define OUTPUT_TITLE_ITEM_BORDER 2
 #define OUTPUT_TITLE_ITEM_PADDING 4
 
@@ -1557,6 +1576,8 @@
         return FALSE;
 }
 
+#endif
+
 static void
 title_item_size_allocate_cb (GtkWidget *widget, GtkAllocation *allocation, gpointer data)
 {
@@ -1614,6 +1635,7 @@
         gtk_label_set_markup (GTK_LABEL (label), str);
         g_free (str);
 
+#ifndef HAVE_APPINDICATOR
 	/* Make the label explicitly black.  We don't want it to follow the
 	 * theme's colors, since the label is always shown against a light
 	 * pastel background.  See bgo#556050
@@ -1625,6 +1647,7 @@
         gtk_misc_set_padding (GTK_MISC (label),
                               OUTPUT_TITLE_ITEM_BORDER + OUTPUT_TITLE_ITEM_PADDING,
                               OUTPUT_TITLE_ITEM_BORDER + OUTPUT_TITLE_ITEM_PADDING);
+#endif
 
         gtk_container_add (GTK_CONTAINER (item), label);
 
@@ -1632,10 +1655,12 @@
          * to its expose-event signal.  See the comment in *** to see why need to connect
          * to the label both 'before' and 'after'.
          */
+#ifndef HAVE_APPINDICATOR
         g_signal_connect (label, "expose-event",
                           G_CALLBACK (output_title_label_expose_event_cb), manager);
         g_signal_connect_after (label, "expose-event",
                                 G_CALLBACK (output_title_label_after_expose_event_cb), manager);
+#endif
 
         g_object_set_data (G_OBJECT (label), "output", output);
 
@@ -1874,6 +1899,13 @@
         struct GsdXrandrManagerPrivate *priv = manager->priv;
         GtkWidget *item;
 
+#ifdef HAVE_APPINDICATOR
+	if (!priv->configuration)
+		priv->configuration = gnome_rr_config_new_current (priv->rw_screen);
+
+	if (priv->popup_menu)
+		gtk_widget_destroy (priv->popup_menu);
+#else
         g_assert (priv->configuration == NULL);
         priv->configuration = gnome_rr_config_new_current (priv->rw_screen);
 
@@ -1881,6 +1913,7 @@
         priv->labeler = gnome_rr_labeler_new (priv->configuration);
 
         g_assert (priv->popup_menu == NULL);
+#endif
         priv->popup_menu = gtk_menu_new ();
 
         add_menu_items_for_outputs (manager);
@@ -1895,14 +1928,20 @@
         gtk_widget_show (item);
         gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item);
 
+#ifdef HAVE_APPINDICATOR
+        app_indicator_set_menu (priv->app_indicator,
+                                GTK_MENU (priv->popup_menu));
+#else
         g_signal_connect (priv->popup_menu, "selection-done",
                           G_CALLBACK (status_icon_popup_menu_selection_done_cb), manager);
 
         gtk_menu_popup (GTK_MENU (priv->popup_menu), NULL, NULL,
                         gtk_status_icon_position_menu,
                         priv->status_icon, button, timestamp);
+#endif
 }
 
+#ifndef HAVE_APPINDICATOR
 static void
 status_icon_activate_cb (GtkStatusIcon *status_icon, gpointer data)
 {
@@ -1919,12 +1958,23 @@
 
         status_icon_popup_menu (manager, button, timestamp);
 }
+#endif
 
 static void
 status_icon_start (GsdXrandrManager *manager)
 {
         struct GsdXrandrManagerPrivate *priv = manager->priv;
 
+#ifdef HAVE_APPINDICATOR
+        if (!priv->app_indicator) {
+                priv->app_indicator = app_indicator_new ("gsd-xrandr",
+                                                         GSD_XRANDR_ICON_NAME,
+                                                         APP_INDICATOR_CATEGORY_HARDWARE);
+                app_indicator_set_status (priv->app_indicator,
+                                          APP_INDICATOR_STATUS_ACTIVE);
+		status_icon_popup_menu (manager, 0, 0);
+        }
+#else
         /* Ideally, we should detect if we are on a tablet and only display
          * the icon in that case.
          */
@@ -1937,6 +1987,7 @@
                 g_signal_connect (priv->status_icon, "popup-menu",
                                   G_CALLBACK (status_icon_popup_menu_cb), manager);
         }
+#endif
 }
 
 static void
@@ -1944,6 +1995,14 @@
 {
         struct GsdXrandrManagerPrivate *priv = manager->priv;
 
+#ifdef HAVE_APPINDICATOR
+        if (priv->app_indicator) {
+                app_indicator_set_status (priv->app_indicator,
+                                          APP_INDICATOR_STATUS_PASSIVE);
+                g_object_unref (priv->app_indicator);
+                priv->app_indicator  = NULL;
+        }
+#else
         if (priv->status_icon) {
                 g_signal_handlers_disconnect_by_func (
                         priv->status_icon, G_CALLBACK (status_icon_activate_cb), manager);
@@ -1956,6 +2015,7 @@
                 g_object_unref (priv->status_icon);
                 priv->status_icon = NULL;
         }
+#endif
 }
 
 static void
diff -uNr -x .pc gnome-settings-daemon-2.30.2.orig/plugins/xrandr/Makefile.am gnome-settings-daemon-2.30.2/plugins/xrandr/Makefile.am
--- gnome-settings-daemon-2.30.2.orig/plugins/xrandr/Makefile.am	2010-08-19 11:17:16.739361002 +0100
+++ gnome-settings-daemon-2.30.2/plugins/xrandr/Makefile.am	2010-08-19 11:17:58.289361002 +0100
@@ -54,6 +54,7 @@
 libxrandr_la_CFLAGS =			\
 	$(SETTINGS_PLUGIN_CFLAGS)	\
 	$(LIBNOTIFY_CFLAGS)		\
+	$(APPINDICATOR_CFLAGS)		\
 	$(AM_CFLAGS)
 
 libxrandr_la_LDFLAGS = 			\
@@ -61,7 +62,8 @@
 
 libxrandr_la_LIBADD  =			\
 	$(SETTINGS_PLUGIN_LIBS)		\
-	$(LIBNOTIFY_LIBS)
+	$(LIBNOTIFY_LIBS)		\
+	$(APPINDICATOR_LIBS)
 
 plugin_in_files =			\
 	xrandr.gnome-settings-plugin.in
