File gnome-settings-daemon-randr-gerror.diff of Package gnome-settings-daemon

diff --git a/ChangeLog b/ChangeLog
index dc3cf82..4423ee2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,65 @@
+2009-01-14  Federico Mena Quintero  <federico@novell.com>
+
+	* plugins/xrandr/gsd-xrandr-manager.c (gsd_xrandr_manager_start):
+	If there was no file with a stored configuration, don't pop up an
+	error message --- this is not an error when the daemon starts up.
+	Fixes https://bugzilla.novell.com/show_bug.cgi?id=465968
+
+2008-12-08  Jens Granseuer  <jensgr@gmx.net>
+
+	* plugins/xrandr/gsd-xrandr-manager.c: (error_message): make libnotify
+	optional again (bug #563226)
+	(handle_fn_f7): fix memory leak, use g_debug instead of g_print
+
+2008-12-02  Federico Mena Quintero  <federico@novell.com>
+
+	Use a DBus interface to tell the XRANDR manager to apply the
+	stored configuration, instead of an X client message, so that we
+	can pass errors back to the caller.
+
+	* plugins/xrandr/gsd-xrandr-manager.xml: Trivial DBus interface to
+	tell the XRANDR manager to apply the stored configuration.
+
+	* plugins/xrandr/gsd-xrandr-manager.c
+	(gsd_xrandr_manager_apply_configuration): Moved from
+	on_client_message().  Now we are a DBus-Glib method, so that we
+	can pass back errors to the remote caller.
+
+	* plugins/xrandr/Makefile.am: Add the machinery to generate DBus
+	glue.
+
+2008-12-02  Federico Mena Quintero  <federico@novell.com>
+
+	* plugins/xrandr/gsd-xrandr-manager.c (error_message): Renamed
+	from error_dialog(); use libnotify instead of ugly dialogs for
+	error messages.
+	(gsd_xrandr_manager_start):  Proxy the error from
+	gnome_rr_screen_new() to our caller.
+	(gsd_xrandr_manager_start): Display an error if we cannot apply
+	the initially-loaded configuration.
+	(generate_fn_f7_configs, get_allowed_rotations_for_output): Pass
+	GError arguments to the gnome_rr_*() functions.
+	(handle_fn_f7): Display an error if we cannot refresh the screen
+	configuration or apply the new one.
+	(output_rotation_item_activate_cb): Display an error if the
+	rotation cannot be applied.
+
+Tue Dec  2 15:37:21 2008  Søren Sandmann  <sandmann@redhat.com>
+
+	* plugins/xrandr/gsd-xrandr-manager.c: Add support for fn-F7 type
+	keys. 
+
+2008-10-04  Jens Granseuer  <jensgr@gmx.net>
+
+	Merged from trunk.
+
+	Patch by: Eric Piel <e.a.b.piel@tudelft.nl>
+
+	* plugins/xrandr/gsd-xrandr-manager.c:
+	(output_rotation_item_activate_cb): ignore the "activate" signal for
+	deselected items so that the rotation setting doesn't reset when the
+	systray menu is opened (bug #554951)
+
 ==================== 2.24.0 ====================
 
 2008-09-23  Rodrigo Moya <rodrigo@gnome-db.org>
diff --git a/plugins/xrandr/Makefile.am b/plugins/xrandr/Makefile.am
index 54eda77..78637e6 100644
--- a/plugins/xrandr/Makefile.am
+++ b/plugins/xrandr/Makefile.am
@@ -1,6 +1,9 @@
 icondir = $(datadir)/icons/hicolor
 context = apps
 
+BUILT_SOURCES =				\
+	gsd-xrandr-manager-glue.h
+
 ICON_FILES = 			\
 	gsd-xrandr-16.png	\
 	gsd-xrandr-22.png	\
@@ -30,35 +33,43 @@ uninstall-local:
 plugin_LTLIBRARIES = \
 	libxrandr.la
 
+gsd-xrandr-manager-glue.h: gsd-xrandr-manager.xml Makefile
+	dbus-binding-tool --prefix=gsd_xrandr_manager --mode=glib-server $< > xgen-$(@F) \
+	&& ( cmp -s xgen-$(@F) $@ || cp xgen-$(@F) $@ ) \
+	&& rm -f xgen-$(@F)
+
 libxrandr_la_SOURCES = 		\
+	$(BUILT_SOURCES)	\
 	gsd-xrandr-plugin.h	\
 	gsd-xrandr-plugin.c	\
 	gsd-xrandr-manager.h	\
 	gsd-xrandr-manager.c
 
-libxrandr_la_CPPFLAGS = \
-	-I$(top_srcdir)/gnome-settings-daemon		\
-	-DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \
+libxrandr_la_CPPFLAGS =						\
+	-I$(top_srcdir)/gnome-settings-daemon			\
+	-DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\"	\
 	$(AM_CPPFLAGS)
 
-libxrandr_la_CFLAGS = \
+libxrandr_la_CFLAGS =			\
 	$(SETTINGS_PLUGIN_CFLAGS)	\
+	$(LIBNOTIFY_CFLAGS)		\
 	$(AM_CFLAGS)
 
-libxrandr_la_LDFLAGS = 		\
+libxrandr_la_LDFLAGS = 			\
 	$(GSD_PLUGIN_LDFLAGS)
 
-libxrandr_la_LIBADD  = 		\
-	$(SETTINGS_PLUGIN_LIBS)	\
+libxrandr_la_LIBADD  =			\
+	$(SETTINGS_PLUGIN_LIBS)		\
+	$(LIBNOTIFY_LIBS)		\
 	$(RANDR_LIBS)
 
-plugin_in_files = 		\
+plugin_in_files =			\
 	xrandr.gnome-settings-plugin.in
 
 plugin_DATA = $(plugin_in_files:.gnome-settings-plugin.in=.gnome-settings-plugin)
 
-EXTRA_DIST = $(plugin_in_files) $(ICON_FILES)
-CLEANFILES = $(plugin_DATA)
+EXTRA_DIST = $(plugin_in_files) $(ICON_FILES) gsd-xrandr-manager.xml
+CLEANFILES = $(plugin_DATA) $(BUILT_SOURCES)
 DISTCLEANFILES = $(plugin_DATA)
 
 @GSD_INTLTOOL_PLUGIN_RULE@
diff --git a/plugins/xrandr/gsd-xrandr-manager.c b/plugins/xrandr/gsd-xrandr-manager.c
index 4d8ce2f..fcd70c1 100644
--- a/plugins/xrandr/gsd-xrandr-manager.c
+++ b/plugins/xrandr/gsd-xrandr-manager.c
@@ -37,6 +37,7 @@
 #include <gdk/gdkx.h>
 #include <gtk/gtk.h>
 #include <gconf/gconf-client.h>
+#include <dbus/dbus-glib.h>
 
 #define GNOME_DESKTOP_USE_UNSTABLE_API
 
@@ -48,6 +49,10 @@
 #include <X11/extensions/Xrandr.h>
 #endif
 
+#ifdef HAVE_LIBNOTIFY
+#include <libnotify/notify.h>
+#endif
+
 #include "gnome-settings-profile.h"
 #include "gsd-xrandr-manager.h"
 
@@ -68,13 +73,19 @@
 /* executable of the control center's display configuration capplet */
 #define GSD_XRANDR_DISPLAY_CAPPLET "gnome-display-properties"
 
+#define GSD_DBUS_PATH "/org/gnome/SettingsDaemon"
+#define GSD_DBUS_NAME "org.gnome.SettingsDaemon"
+#define GSD_XRANDR_DBUS_PATH GSD_DBUS_PATH "/XRANDR"
+#define GSD_XRANDR_DBUS_NAME GSD_DBUS_NAME ".XRANDR"
+
 struct GsdXrandrManagerPrivate
 {
+        DBusGConnection *dbus_connection;
+
         /* Key code of the fn-F7 video key (XF86Display) */
         guint keycode;
         GnomeRRScreen *rw_screen;
         gboolean running;
-        gboolean client_filter_set;
 
         GtkStatusIcon *status_icon;
         GtkWidget *popup_menu;
@@ -82,6 +93,10 @@ struct GsdXrandrManagerPrivate
         GnomeRRLabeler *labeler;
         GConfClient *client;
         int notify_id;
+
+        /* fn-F7 status */
+        int             current_fn_f7_config;             /* -1 if no configs */
+        GnomeRRConfig **fn_f7_configs;  /* NULL terminated, NULL if there are no configs */
 };
 
 static void     gsd_xrandr_manager_class_init  (GsdXrandrManagerClass *klass);
@@ -93,38 +108,472 @@ G_DEFINE_TYPE (GsdXrandrManager, gsd_xrandr_manager, G_TYPE_OBJECT)
 static gpointer manager_object = NULL;
 
 
-static GdkAtom
-gnome_randr_atom (void)
+/* DBus method; see gsd-xrandr-manager.xml for the interface definition */
+static gboolean
+gsd_xrandr_manager_apply_configuration (GsdXrandrManager *manager,
+                                        GError          **error)
 {
-        return gdk_atom_intern ("_GNOME_RANDR_ATOM", FALSE);
+        GnomeRRScreen *screen = manager->priv->rw_screen;
+
+        return gnome_rr_config_apply_stored (screen, error);
 }
+/* We include this after the definition of gsd_xrandr_manager_apply_configuration() so the prototype will already exist */
+#include "gsd-xrandr-manager-glue.h"
 
-static Atom
-gnome_randr_xatom (void)
+static gboolean
+is_laptop (GnomeOutputInfo *output)
 {
-        return gdk_x11_atom_to_xatom (gnome_randr_atom());
+        const char *output_name = output->name;
+
+        if (output->connected && output_name &&
+            (strstr ("lvds", output_name)	||
+             strstr ("LVDS", output_name)	||
+             strstr ("Lvds", output_name)))
+        {
+                return TRUE;
+        }
+
+        return FALSE;
 }
 
-static GdkFilterReturn
-on_client_message (GdkXEvent  *xevent,
-		   GdkEvent   *event,
-		   gpointer    data)
+static gboolean
+get_clone_size (GnomeRRScreen *screen, int *width, int *height)
 {
-        GsdXrandrManager *manager = GSD_XRANDR_MANAGER (data);
-        GnomeRRScreen *screen = manager->priv->rw_screen;
-        XEvent *ev = (XEvent *)xevent;
+        GnomeRRMode **modes = gnome_rr_screen_list_clone_modes (screen);
+        int best_w, best_h;
+        int i;
+
+        best_w = 0;
+        best_h = 0;
 
-        if (manager->priv->running &&
-            ev->type == ClientMessage &&
-            ev->xclient.message_type == gnome_randr_xatom ()) {
+        for (i = 0; modes[i] != NULL; ++i) {
+                GnomeRRMode *mode = modes[i];
+                int w, h;
 
-                gnome_rr_config_apply_stored (screen);
+                w = gnome_rr_mode_get_width (mode);
+                h = gnome_rr_mode_get_height (mode);
 
-                return GDK_FILTER_REMOVE;
+                if (w * h > best_w * best_h) {
+                        best_w = w;
+                        best_h = h;
+                }
         }
 
-        /* Pass the event on to GTK+ */
-        return GDK_FILTER_CONTINUE;
+        if (best_w > 0 && best_h > 0) {
+                if (width)
+                        *width = best_w;
+                if (height)
+                        *height = best_h;
+
+                return TRUE;
+        }
+
+        return FALSE;
+}
+
+static void
+print_output (GnomeOutputInfo *info)
+{
+        g_print ("  Output: %s attached to %s\n", info->display_name, info->name);
+        g_print ("     status: %s\n", info->on ? "on" : "off");
+        g_print ("     width: %d\n", info->width);
+        g_print ("     height: %d\n", info->height);
+        g_print ("     rate: %d\n", info->rate);
+        g_print ("     position: %d %d\n", info->x, info->y);
+}
+
+static void
+print_configuration (GnomeRRConfig *config, const char *header)
+{
+        int i;
+
+        g_print ("=== %s Configuration ===\n", header);
+        if (!config) {
+                g_print ("  none\n");
+                return;
+        }
+
+        for (i = 0; config->outputs[i] != NULL; ++i)
+                print_output (config->outputs[i]);
+}
+
+static GnomeRRConfig *
+make_clone_setup (GnomeRRScreen *screen)
+{
+        GnomeRRConfig *result;
+        int width, height;
+        int i;
+
+        if (!get_clone_size (screen, &width, &height))
+                return NULL;
+
+        result = gnome_rr_config_new_current (screen);
+
+        for (i = 0; result->outputs[i] != NULL; ++i) {
+                GnomeOutputInfo *info = result->outputs[i];
+
+                info->on = FALSE;
+                if (info->connected) {
+                        GnomeRROutput *output =
+                                gnome_rr_screen_get_output_by_name (screen, info->name);
+                        GnomeRRMode **modes = gnome_rr_output_list_modes (output);
+                        int j;
+                        int best_rate = 0;
+
+                        for (j = 0; modes[j] != NULL; ++j) {
+                                GnomeRRMode *mode = modes[j];
+                                int w, h;
+
+                                w = gnome_rr_mode_get_width (mode);
+                                h = gnome_rr_mode_get_height (mode);
+
+                                if (w == width && h == height) {
+                                        int r = gnome_rr_mode_get_freq (mode);
+                                        if (r > best_rate)
+                                                best_rate = r;
+                                }
+                        }
+
+                        if (best_rate > 0) {
+                                info->on = TRUE;
+                                info->width = width;
+                                info->height = height;
+                                info->rate = best_rate;
+                                info->rotation = GNOME_RR_ROTATION_0;
+                                info->x = 0;
+                                info->y = 0;
+                        }
+                }
+        }
+
+        print_configuration (result, "clone setup");
+
+        return result;
+}
+
+static gboolean
+turn_on (GnomeRRScreen *screen,
+         GnomeOutputInfo *info,
+         int x, int y)
+{
+        GnomeRROutput *output =
+                gnome_rr_screen_get_output_by_name (screen, info->name);
+        GnomeRRMode *mode = gnome_rr_output_get_preferred_mode (output);
+
+        if (mode) {
+                info->on = TRUE;
+                info->x = x;
+                info->y = y;
+                info->width = gnome_rr_mode_get_width (mode);
+                info->height = gnome_rr_mode_get_height (mode);
+                info->rotation = GNOME_RR_ROTATION_0;
+                info->rate = gnome_rr_mode_get_freq (mode);
+
+                return TRUE;
+        }
+
+        return FALSE;
+}
+
+static GnomeRRConfig *
+make_laptop_setup (GnomeRRScreen *screen)
+{
+        /* Turn on the laptop, disable everything else */
+        GnomeRRConfig *result = gnome_rr_config_new_current (screen);
+        int i;
+
+        for (i = 0; result->outputs[i] != NULL; ++i) {
+                GnomeOutputInfo *info = result->outputs[i];
+
+                if (is_laptop (info)) {
+                        if (!info->on) {
+                                if (!turn_on (screen, info, 0, 0)) {
+                                        gnome_rr_config_free (result);
+                                        result = NULL;
+                                        break;
+                                }
+                        }
+                }
+                else {
+                        info->on = FALSE;
+                }
+        }
+
+        print_configuration (result, "Laptop setup");
+
+        /* FIXME - Maybe we should return NULL if there is more than
+         * one connected "laptop" screen?
+         */
+        return result;
+
+}
+
+static GnomeRRConfig *
+make_xinerama_setup (GnomeRRScreen *screen)
+{
+        /* Turn on everything that has a preferred mode, and
+         * position it from left to right
+         */
+        GnomeRRConfig *result = gnome_rr_config_new_current (screen);
+        int i;
+        int x;
+
+        x = 0;
+        for (i = 0; result->outputs[i] != NULL; ++i) {
+                GnomeOutputInfo *info = result->outputs[i];
+
+                if (is_laptop (info)) {
+                        if (info->on || turn_on (screen, info, x, 0)) {
+                                x += info->width;
+                        }
+                }
+        }
+
+        for (i = 0; result->outputs[i] != NULL; ++i) {
+                GnomeOutputInfo *info = result->outputs[i];
+
+                if (info->connected && !is_laptop (info)) {
+                        if (info->on || turn_on (screen, info, x, 0)) {
+                                x += info->width;
+                        }
+                }
+        }
+
+        print_configuration (result, "xinerama setup");
+
+        return result;
+}
+
+static GnomeRRConfig *
+make_other_setup (GnomeRRScreen *screen)
+{
+        /* Turn off all laptops, and make all external monitors clone
+         * from (0, 0)
+         */
+
+        GnomeRRConfig *result = gnome_rr_config_new_current (screen);
+        int i;
+
+        for (i = 0; result->outputs[i] != NULL; ++i) {
+                GnomeOutputInfo *info = result->outputs[i];
+
+                if (is_laptop (info)) {
+                        info->on = FALSE;
+                }
+                else {
+                        if (info->connected && !info->on) {
+                                turn_on (screen, info, 0, 0);
+                        }
+               }
+        }
+
+        print_configuration (result, "other setup");
+
+        return result;
+}
+
+static GPtrArray *
+sanitize (GPtrArray *array)
+{
+        int i;
+        GPtrArray *new;
+
+        g_print ("before sanitizing\n");
+
+        for (i = 0; i < array->len; ++i) {
+                if (array->pdata[i]) {
+                        print_configuration (array->pdata[i], "before");
+                }
+        }
+
+
+        /* Remove configurations that are duplicates of
+         * configurations earlier in the cycle
+         */
+        for (i = 0; i < array->len; ++i) {
+                int j;
+
+                for (j = 0; j < i; ++j) {
+                        GnomeRRConfig *this = array->pdata[j];
+                        GnomeRRConfig *other = array->pdata[i];
+
+                        if (this && other && gnome_rr_config_equal (this, other)) {
+                                g_print ("removing duplicate configuration\n");
+                                gnome_rr_config_free (this);
+                                array->pdata[j] = NULL;
+                                break;
+                        }
+                }
+        }
+
+        for (i = 0; i < array->len; ++i) {
+                GnomeRRConfig *config = array->pdata[i];
+
+                if (config) {
+                        gboolean all_off = TRUE;
+                        int j;
+
+                        for (j = 0; config->outputs[j] != NULL; ++j) {
+                                if (config->outputs[j]->on)
+                                        all_off = FALSE;
+                        }
+
+                        if (all_off) {
+                                gnome_rr_config_free (array->pdata[i]);
+                                array->pdata[i] = NULL;
+                        }
+                }
+        }
+
+        /* Remove NULL configurations */
+        new = g_ptr_array_new ();
+
+        for (i = 0; i < array->len; ++i) {
+                if (array->pdata[i]) {
+                        g_ptr_array_add (new, array->pdata[i]);
+                        print_configuration (array->pdata[i], "Final");
+                }
+        }
+
+        g_ptr_array_add (new, NULL);
+
+        g_ptr_array_free (array, TRUE);
+
+        return new;
+}
+
+static void
+generate_fn_f7_configs (GsdXrandrManager *mgr)
+{
+        GPtrArray *array = g_ptr_array_new ();
+        GnomeRRScreen *screen = mgr->priv->rw_screen;
+
+        g_print ("Generating configurations\n");
+
+        /* Free any existing list of configurations */
+        if (mgr->priv->fn_f7_configs) {
+                int i;
+
+                for (i = 0; mgr->priv->fn_f7_configs[i] != NULL; ++i)
+                        gnome_rr_config_free (mgr->priv->fn_f7_configs[i]);
+                g_free (mgr->priv->fn_f7_configs);
+
+                mgr->priv->fn_f7_configs = NULL;
+                mgr->priv->current_fn_f7_config = -1;
+        }
+
+        g_ptr_array_add (array, gnome_rr_config_new_current (screen));
+        g_ptr_array_add (array, make_xinerama_setup (screen));
+        g_ptr_array_add (array, make_clone_setup (screen));
+        g_ptr_array_add (array, make_laptop_setup (screen));
+        g_ptr_array_add (array, make_other_setup (screen));
+        g_ptr_array_add (array, gnome_rr_config_new_stored (screen, NULL)); /* NULL-GError - if this can't read the stored config, no big deal */
+        g_ptr_array_add (array, NULL);
+
+        array = sanitize (array);
+
+        mgr->priv->fn_f7_configs = (GnomeRRConfig **)g_ptr_array_free (array, FALSE);
+        mgr->priv->current_fn_f7_config = 0;
+}
+
+static void
+error_message (GsdXrandrManager *mgr, const char *primary_text, GError *error_to_display, const char *secondary_text)
+{
+#ifdef HAVE_LIBNOTIFY
+        GsdXrandrManagerPrivate *priv = mgr->priv;
+        NotifyNotification *notification;
+
+        g_assert (error_to_display == NULL || secondary_text == NULL);
+
+        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);
+        notify_notification_show (notification, NULL); /* NULL-GError */
+#else
+        GtkWidget *dialog;
+
+	dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
+                                         "%s", primary_text);
+        gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s",
+                                                  error_to_display ? error_to_display->message : secondary_text);
+
+        gtk_dialog_run (GTK_DIALOG (dialog));
+        gtk_widget_destroy (dialog);
+#endif /* HAVE_LIBNOTIFY */
+}
+
+static void
+handle_fn_f7 (GsdXrandrManager *mgr)
+{
+        GsdXrandrManagerPrivate *priv = mgr->priv;
+        GnomeRRScreen *screen = priv->rw_screen;
+        GnomeRRConfig *current;
+        GError *error;
+
+        /* Theory of fn-F7 operation
+         *
+         * We maintain a datastructure "fn_f7_status", that contains
+         * a list of GnomeRRConfig's. Each of the GnomeRRConfigs has a
+         * mode (or "off") for each connected output.
+         *
+         * When the user hits fn-F7, we cycle to the next GnomeRRConfig
+         * in the data structure. If the data structure does not exist, it
+         * is generated. If the configs in the data structure do not match
+         * the current hardware reality, it is regenerated.
+         *
+         */
+        g_debug ("Handling fn-f7");
+
+        error = NULL;
+        if (!gnome_rr_screen_refresh (screen, &error)) {
+                char *str;
+
+                str = g_strdup_printf (_("Could not refresh the screen information: %s"), error->message);
+                g_error_free (error);
+
+                error_message (mgr, str, NULL, _("Trying to switch the monitor configuration anyway."));
+                g_free (str);
+        }
+
+        if (!priv->fn_f7_configs)
+                generate_fn_f7_configs (mgr);
+
+        current = gnome_rr_config_new_current (screen);
+
+        if (priv->fn_f7_configs &&
+            (!gnome_rr_config_match (current, priv->fn_f7_configs[0]) ||
+             !gnome_rr_config_equal (current, priv->fn_f7_configs[mgr->priv->current_fn_f7_config]))) {
+                    /* Our view of the world is incorrect, so regenerate the
+                     * configurations
+                     */
+                    generate_fn_f7_configs (mgr);
+            }
+
+        gnome_rr_config_free (current);
+
+        if (priv->fn_f7_configs) {
+                mgr->priv->current_fn_f7_config++;
+
+                if (priv->fn_f7_configs[mgr->priv->current_fn_f7_config] == NULL)
+                        mgr->priv->current_fn_f7_config = 0;
+
+                g_debug ("cycling to next configuration (%d)", mgr->priv->current_fn_f7_config);
+
+                print_configuration (priv->fn_f7_configs[mgr->priv->current_fn_f7_config], "new config");
+
+                g_debug ("applying");
+
+                error = NULL;
+                if (!gnome_rr_config_apply (priv->fn_f7_configs[mgr->priv->current_fn_f7_config], screen, &error)) {
+                        error_message (mgr, _("Could not switch the monitor configuration"), error, NULL);
+                        g_error_free (error);
+                }
+        }
+        else {
+                g_debug ("no configurations generated");
+        }
+        g_debug ("done handling fn-f7");
 }
 
 static GdkFilterReturn
@@ -142,11 +591,8 @@ event_filter (GdkXEvent           *xevent,
         if (xev->xany.type != KeyPress && xev->xany.type != KeyRelease)
                 return GDK_FILTER_CONTINUE;
 
-        if (xev->xkey.keycode == manager->priv->keycode) {
-                /* FIXME: here we should cycle between valid
-                 * configurations, and save them
-                 */
-                gnome_rr_config_apply_stored (manager->priv->rw_screen);
+        if (xev->xkey.keycode == manager->priv->keycode && xev->xany.type == KeyPress) {
+                handle_fn_f7 (manager);
 
                 return GDK_FILTER_CONTINUE;
         }
@@ -391,7 +837,7 @@ get_allowed_rotations_for_output (GsdXrandrManager *manager, GnomeOutputInfo *ou
 
                 output->rotation = rotation_to_test;
 
-                if (gnome_rr_config_applicable (priv->configuration, priv->rw_screen)) {
+                if (gnome_rr_config_applicable (priv->configuration, priv->rw_screen, NULL)) { /* NULL-GError */
                         (*out_num_rotations)++;
                         (*out_rotations) |= rotation_to_test;
                 }
@@ -424,20 +870,7 @@ add_unsupported_rotation_item (GsdXrandrManager *manager)
 }
 
 static void
-error_dialog (const char *title, const char *msg)
-{
-        GtkWidget *dialog;
-
-        dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
-                                         "%s", title);
-        gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", msg);
-
-        gtk_dialog_run (GTK_DIALOG (dialog));
-        gtk_widget_destroy (dialog);
-}
-
-static void
-output_rotation_item_activate_cb (GtkMenuItem *item, gpointer data)
+output_rotation_item_activate_cb (GtkCheckMenuItem *item, gpointer data)
 {
         GsdXrandrManager *manager = GSD_XRANDR_MANAGER (data);
         struct GsdXrandrManagerPrivate *priv = manager->priv;
@@ -445,25 +878,30 @@ output_rotation_item_activate_cb (GtkMenuItem *item, gpointer data)
         GnomeRRRotation rotation;
         GError *error;
 
+	/* Not interested in deselected items */
+	if (!gtk_check_menu_item_get_active (item))
+		return;
+
         output = g_object_get_data (G_OBJECT (item), "output");
         rotation = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "rotation"));
 
         output->rotation = rotation;
 
         error = NULL;
-        if (gnome_rr_config_save (priv->configuration, &error)) {
-                if (!gnome_rr_config_apply_stored (priv->rw_screen)) {
-                        error_dialog (_("The selected rotation could not be applied"),
-                                      _("An error occurred while configuring the screen"));
-                        /* FIXME: that message is really useless.  Make
-                         * gnome_rr_config_apply_stored() give us a meaningful
-                         * error message!
-                         */
-                }
-        } else {
-                error_dialog (_("The selected rotation could not be applied"),
-                              error->message);
-                g_error_free (error);
+        if (!gnome_rr_config_save (priv->configuration, &error)) {
+                error_message (manager, _("Could not save monitor configuration"), error, NULL);
+                if (error)
+                        g_error_free (error);
+
+                return;
+        }
+
+        if (!gnome_rr_config_apply_stored (priv->rw_screen, &error)) {
+                error_message (manager, _("The selected rotation could not be applied"), error, NULL);
+                if (error)
+                        g_error_free (error);
+
+                return;
         }
 }
 
@@ -687,15 +1125,15 @@ gboolean
 gsd_xrandr_manager_start (GsdXrandrManager *manager,
                           GError          **error)
 {
+        GError *my_error;
+
         g_debug ("Starting xrandr manager");
 
         manager->priv->rw_screen = gnome_rr_screen_new (
-                gdk_screen_get_default (), on_randr_event, manager);
+                gdk_screen_get_default (), on_randr_event, manager, error);
 
-        if (manager->priv->rw_screen == NULL) {
-                g_set_error (error, 0, 0, "Failed to initialize XRandR extension");
+        if (manager->priv->rw_screen == NULL)
                 return FALSE;
-        }
 
         manager->priv->running = TRUE;
         manager->priv->client = gconf_client_get_default ();
@@ -724,21 +1162,20 @@ gsd_xrandr_manager_start (GsdXrandrManager *manager,
                 gdk_error_trap_pop ();
         }
 
-        gnome_rr_config_apply_stored (manager->priv->rw_screen);
+        my_error = NULL;
+        if (!gnome_rr_config_apply_stored (manager->priv->rw_screen, &my_error)) {
+                if (my_error) {
+                        if (!g_error_matches (my_error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
+                                error_message (manager, _("Could not apply the stored configuration for monitors"), my_error, NULL);
+
+                        g_error_free (my_error);
+                }
+        }
 
         gdk_window_add_filter (gdk_get_default_root_window(),
                                (GdkFilterFunc)event_filter,
                                manager);
 
-        if (!manager->priv->client_filter_set) {
-                /* FIXME: need to remove this in _stop;
-                 * for now make sure to only add it once */
-                gdk_add_client_message_filter (gnome_randr_atom (),
-                                               on_client_message,
-                                               manager);
-                manager->priv->client_filter_set = TRUE;
-        }
-
         start_or_stop_icon (manager);
 
         return TRUE;
@@ -781,6 +1218,11 @@ gsd_xrandr_manager_stop (GsdXrandrManager *manager)
                 manager->priv->rw_screen = NULL;
         }
 
+        if (manager->priv->dbus_connection != NULL) {
+                dbus_g_connection_unref (manager->priv->dbus_connection);
+                manager->priv->dbus_connection = NULL;
+        }
+
         status_icon_stop (manager);
 }
 
@@ -856,6 +1298,8 @@ gsd_xrandr_manager_class_init (GsdXrandrManagerClass *klass)
         object_class->dispose = gsd_xrandr_manager_dispose;
         object_class->finalize = gsd_xrandr_manager_finalize;
 
+        dbus_g_object_type_install_info (GSD_TYPE_XRANDR_MANAGER, &dbus_glib_gsd_xrandr_manager_object_info);
+
         g_type_class_add_private (klass, sizeof (GsdXrandrManagerPrivate));
 }
 
@@ -869,6 +1313,9 @@ gsd_xrandr_manager_init (GsdXrandrManager *manager)
         manager->priv = GSD_XRANDR_MANAGER_GET_PRIVATE (manager);
 
         manager->priv->keycode = keycode;
+
+        manager->priv->current_fn_f7_config = -1;
+        manager->priv->fn_f7_configs = NULL;
 }
 
 static void
@@ -886,6 +1333,26 @@ gsd_xrandr_manager_finalize (GObject *object)
         G_OBJECT_CLASS (gsd_xrandr_manager_parent_class)->finalize (object);
 }
 
+static gboolean
+register_manager_dbus (GsdXrandrManager *manager)
+{
+        GError *error = NULL;
+
+        manager->priv->dbus_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+        if (manager->priv->dbus_connection == NULL) {
+                if (error != NULL) {
+                        g_warning ("Error getting session bus: %s", error->message);
+                        g_error_free (error);
+                }
+                return FALSE;
+        }
+
+        /* Hmm, should we do this in gsd_xrandr_manager_start()? */
+        dbus_g_connection_register_g_object (manager->priv->dbus_connection, GSD_XRANDR_DBUS_PATH, G_OBJECT (manager));
+
+        return TRUE;
+}
+
 GsdXrandrManager *
 gsd_xrandr_manager_new (void)
 {
@@ -895,6 +1362,11 @@ gsd_xrandr_manager_new (void)
                 manager_object = g_object_new (GSD_TYPE_XRANDR_MANAGER, NULL);
                 g_object_add_weak_pointer (manager_object,
                                            (gpointer *) &manager_object);
+
+                if (!register_manager_dbus (manager_object)) {
+                        g_object_unref (manager_object);
+                        return NULL;
+                }
         }
 
         return GSD_XRANDR_MANAGER (manager_object);
diff --git a/plugins/xrandr/gsd-xrandr-manager.xml b/plugins/xrandr/gsd-xrandr-manager.xml
new file mode 100644
index 0000000..2efd18b
--- /dev/null
+++ b/plugins/xrandr/gsd-xrandr-manager.xml
@@ -0,0 +1,8 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+  <interface name="org.gnome.SettingsDaemon.XRANDR">
+    <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="gsd_xrandr_manager"/>
+    <method name="ApplyConfiguration">
+    </method>
+  </interface>
+</node>
openSUSE Build Service is sponsored by