f0e2ab9
diff -up gnome-desktop-2.24.0/libgnome-desktop/gnome-rr.c.clone-modes gnome-desktop-2.24.0/libgnome-desktop/gnome-rr.c
f0e2ab9
--- gnome-desktop-2.24.0/libgnome-desktop/gnome-rr.c.clone-modes	2008-09-24 14:09:09.000000000 -0400
f0e2ab9
+++ gnome-desktop-2.24.0/libgnome-desktop/gnome-rr.c	2008-09-24 14:09:09.000000000 -0400
f0e2ab9
@@ -50,6 +50,8 @@ struct ScreenInfo
17369df
     GnomeRRMode **	modes;
17369df
     
17369df
     GnomeRRScreen *	screen;
17369df
+
17369df
+    GnomeRRMode **	clone_modes;
17369df
 };
17369df
 
17369df
 struct GnomeRRScreen
f0e2ab9
@@ -222,11 +224,86 @@ screen_info_free (ScreenInfo *info)
17369df
 	    mode_free (*mode);
17369df
 	g_free (info->modes);
17369df
     }
17369df
+
17369df
+    if (info->clone_modes)
17369df
+    {
17369df
+	/* The modes themselves were freed above */
17369df
+	g_free (info->clone_modes);
17369df
+    }
17369df
     
17369df
     g_free (info);
17369df
 }
17369df
 
17369df
 static gboolean
17369df
+has_similar_mode (GnomeRROutput *output, GnomeRRMode *mode)
17369df
+{
17369df
+    int i;
17369df
+    GnomeRRMode **modes = gnome_rr_output_list_modes (output);
17369df
+    int width = gnome_rr_mode_get_width (mode);
17369df
+    int height = gnome_rr_mode_get_height (mode);
17369df
+
17369df
+    for (i = 0; modes[i] != NULL; ++i)
17369df
+    {
17369df
+	GnomeRRMode *m = modes[i];
17369df
+
17369df
+	if (gnome_rr_mode_get_width (m) == width	&&
17369df
+	    gnome_rr_mode_get_height (m) == height)
17369df
+	{
17369df
+	    return TRUE;
17369df
+	}
17369df
+    }
17369df
+
17369df
+    return FALSE;
17369df
+}
17369df
+
17369df
+static void
17369df
+gather_clone_modes (ScreenInfo *info)
17369df
+{
17369df
+    int i;
17369df
+    GPtrArray *result = g_ptr_array_new ();
17369df
+
17369df
+    for (i = 0; info->outputs[i] != NULL; ++i)
17369df
+    {
17369df
+	int j;
17369df
+	GnomeRROutput *output1, *output2;
17369df
+
17369df
+	output1 = info->outputs[i];
17369df
+	
17369df
+	if (!output1->connected)
17369df
+	    continue;
17369df
+	
17369df
+	for (j = 0; output1->modes[j] != NULL; ++j)
17369df
+	{
17369df
+	    GnomeRRMode *mode = output1->modes[j];
17369df
+	    gboolean valid;
17369df
+	    int k;
17369df
+
17369df
+	    valid = TRUE;
17369df
+	    for (k = 0; info->outputs[k] != NULL; ++k)
17369df
+	    {
17369df
+		output2 = info->outputs[k];
17369df
+		
17369df
+		if (!output2->connected)
17369df
+		    continue;
17369df
+		
17369df
+		if (!has_similar_mode (output2, mode))
17369df
+		{
17369df
+		    valid = FALSE;
17369df
+		    break;
17369df
+		}
17369df
+	    }
17369df
+
17369df
+	    if (valid)
17369df
+		g_ptr_array_add (result, mode);
17369df
+	}
17369df
+    }
17369df
+
17369df
+    g_ptr_array_add (result, NULL);
17369df
+    
17369df
+    info->clone_modes = (GnomeRRMode **)g_ptr_array_free (result, FALSE);
17369df
+}
17369df
+
17369df
+static gboolean
17369df
 fill_out_screen_info (Display *xdisplay,
17369df
 		      Window xroot,
17369df
 		      ScreenInfo *info)
f0e2ab9
@@ -322,6 +399,8 @@ fill_out_screen_info (Display *xdisplay,
17369df
 	    
17369df
 	    mode_initialize (mode, &(resources->modes[i]));
17369df
 	}
17369df
+
17369df
+	gather_clone_modes (info);
17369df
 	
17369df
 	return TRUE;
17369df
     }
f0e2ab9
@@ -526,6 +605,15 @@ gnome_rr_screen_list_modes (GnomeRRScree
17369df
     return screen->info->modes;
17369df
 }
17369df
 
17369df
+GnomeRRMode **
17369df
+gnome_rr_screen_list_clone_modes   (GnomeRRScreen *screen)
17369df
+{
17369df
+    g_return_val_if_fail (screen != NULL, NULL);
17369df
+    g_return_val_if_fail (screen->info != NULL, NULL);
17369df
+
17369df
+    return screen->info->clone_modes;
17369df
+}
17369df
+
17369df
 GnomeRRCrtc **
17369df
 gnome_rr_screen_list_crtcs (GnomeRRScreen *screen)
17369df
 {
f0e2ab9
diff -up gnome-desktop-2.24.0/libgnome-desktop/gnome-rr-config.c.clone-modes gnome-desktop-2.24.0/libgnome-desktop/gnome-rr-config.c
f0e2ab9
--- gnome-desktop-2.24.0/libgnome-desktop/gnome-rr-config.c.clone-modes	2008-09-24 14:09:09.000000000 -0400
f0e2ab9
+++ gnome-desktop-2.24.0/libgnome-desktop/gnome-rr-config.c	2008-09-24 14:11:34.000000000 -0400
f0e2ab9
@@ -748,6 +748,42 @@ output_match (GnomeOutputInfo *output1, 
17369df
     return TRUE;
17369df
 }
17369df
 
17369df
+static gboolean
17369df
+output_equal (GnomeOutputInfo *output1, GnomeOutputInfo *output2)
17369df
+{
17369df
+    g_assert (output1 != NULL);
17369df
+    g_assert (output2 != NULL);
17369df
+
17369df
+    if (!output_match (output1, output2))
17369df
+	return FALSE;
17369df
+
17369df
+    if (output1->on != output2->on)
17369df
+	return FALSE;
17369df
+
17369df
+    if (output1->on)
17369df
+    {
17369df
+	if (output1->width != output2->width)
17369df
+	    return FALSE;
17369df
+	
17369df
+	if (output1->height != output2->height)
17369df
+	    return FALSE;
17369df
+	
17369df
+	if (output1->rate != output2->rate)
17369df
+	    return FALSE;
17369df
+	
17369df
+	if (output1->x != output2->x)
17369df
+	    return FALSE;
17369df
+	
17369df
+	if (output1->y != output2->y)
17369df
+	    return FALSE;
17369df
+	
17369df
+	if (output1->rotation != output2->rotation)
17369df
+	    return FALSE;
17369df
+    }
17369df
+
17369df
+    return TRUE;
17369df
+}
17369df
+
17369df
 static GnomeOutputInfo *
17369df
 find_output (GnomeRRConfig *config, const char *name)
17369df
 {
f0e2ab9
@@ -764,6 +800,9 @@ find_output (GnomeRRConfig *config, cons
17369df
     return NULL;
17369df
 }
17369df
 
17369df
+/* Match means "these configurations apply to the same hardware
17369df
+ * setups"
17369df
+ */
17369df
 gboolean
17369df
 gnome_rr_config_match (GnomeRRConfig *c1, GnomeRRConfig *c2)
17369df
 {
f0e2ab9
@@ -782,6 +821,28 @@ gnome_rr_config_match (GnomeRRConfig *c1
17369df
     return TRUE;
17369df
 }
17369df
 
17369df
+/* Equal means "the configurations will result in the same
17369df
+ * modes being set on the outputs"
17369df
+ */
17369df
+gboolean
17369df
+gnome_rr_config_equal (GnomeRRConfig  *c1,
17369df
+		       GnomeRRConfig  *c2)
17369df
+{
17369df
+    int i;
17369df
+
17369df
+    for (i = 0; c1->outputs[i] != NULL; ++i)
17369df
+    {
17369df
+	GnomeOutputInfo *output1 = c1->outputs[i];
17369df
+	GnomeOutputInfo *output2;
17369df
+
17369df
+	output2 = find_output (c2, output1->name);
17369df
+	if (!output2 || !output_equal (output1, output2))
17369df
+	    return FALSE;
17369df
+    }
17369df
+    
17369df
+    return TRUE;
17369df
+}
17369df
+
17369df
 static GnomeOutputInfo **
17369df
 make_outputs (GnomeRRConfig *config)
17369df
 {
f0e2ab9
@@ -843,21 +904,6 @@ gnome_rr_config_applicable (GnomeRRConfi
17369df
     return result;
17369df
 }
17369df
 
17369df
-static GnomeRRConfig *
17369df
-gnome_rr_config_find (GnomeRRConfig **haystack,
17369df
-		    GnomeRRConfig  *needle)
17369df
-{
17369df
-    int i;
17369df
-
17369df
-    for (i = 0; haystack[i] != NULL; ++i)
17369df
-    {
17369df
-	if (gnome_rr_config_match (haystack[i], needle))
17369df
-	    return haystack[i];
17369df
-    }
17369df
-
17369df
-    return NULL;
17369df
-}
17369df
-
17369df
 /* Database management */
17369df
 
17369df
 static gchar *
f0e2ab9
@@ -1039,14 +1085,69 @@ gnome_rr_config_save (GnomeRRConfig *con
17369df
     return result;
17369df
 }
17369df
 
17369df
-static gboolean
17369df
-apply_configuration (GnomeRRConfig *conf, GnomeRRScreen *screen)
17369df
+static GnomeRRConfig *
17369df
+gnome_rr_config_copy (GnomeRRConfig *config)
f0e2ab9
+{
17369df
+    GnomeRRConfig *copy = g_new0 (GnomeRRConfig, 1);
17369df
+    int i;
17369df
+    GPtrArray *array = g_ptr_array_new ();
17369df
+
17369df
+    copy->clone = config->clone;
17369df
+    
17369df
+    for (i = 0; config->outputs[i] != NULL; ++i)
17369df
+	g_ptr_array_add (array, output_copy (config->outputs[i]));
17369df
+
17369df
+    g_ptr_array_add (array, NULL);
17369df
+    copy->outputs = (GnomeOutputInfo **)g_ptr_array_free (array, FALSE);
17369df
+
17369df
+    return copy;
17369df
+}
17369df
+
17369df
+GnomeRRConfig *
17369df
+gnome_rr_config_new_stored (GnomeRRScreen *screen)
17369df
+{
17369df
+    GnomeRRConfig *current;
17369df
+    GnomeRRConfig **configs;
17369df
+    GnomeRRConfig *result;
17369df
+
17369df
+    if (!screen)
17369df
+	return NULL;
17369df
+    
17369df
+    current = gnome_rr_config_new_current (screen);
17369df
+    
17369df
+    configs = configurations_read (NULL); /* NULL_GError */
17369df
+
17369df
+    result = NULL;
17369df
+    if (configs)
17369df
+    {
17369df
+	int i;
17369df
+	
17369df
+	for (i = 0; configs[i] != NULL; ++i)
17369df
+	{
17369df
+	    if (gnome_rr_config_match (configs[i], current))
17369df
+	    {
17369df
+		result = gnome_rr_config_copy (configs[i]);
17369df
+		break;
17369df
+	    }
17369df
+	}
faa77ef
+
faa77ef
+	configurations_free (configs);
17369df
+    }
17369df
+
17369df
+    gnome_rr_config_free (current);
17369df
+    
17369df
+    return result;
17369df
+}
17369df
+
17369df
+gboolean
17369df
+gnome_rr_config_apply (GnomeRRConfig *config,
17369df
+		       GnomeRRScreen *screen)
f0e2ab9
 {
17369df
     CrtcAssignment *assignment;
17369df
     GnomeOutputInfo **outputs;
f0e2ab9
     gboolean result = FALSE;
17369df
 
17369df
-    outputs = make_outputs (conf);
17369df
+    outputs = make_outputs (config);
17369df
 
17369df
     assignment = crtc_assignment_new (screen, outputs);
17369df
 
f0e2ab9
@@ -1068,42 +1169,51 @@ apply_configuration (GnomeRRConfig *conf
17369df
 gboolean
17369df
 gnome_rr_config_apply_stored (GnomeRRScreen *screen)
17369df
 {
17369df
-    GnomeRRConfig **configs;
17369df
-    GnomeRRConfig *current;
17369df
-    GnomeRRConfig *found;
17369df
-    gboolean result = TRUE;
17369df
+    GnomeRRConfig *stored;
17369df
 
17369df
     if (!screen)
17369df
 	return FALSE;
17369df
 
17369df
-    configs = configurations_read (NULL); /* NULL-GError */
17369df
-
17369df
     gnome_rr_screen_refresh (screen);
17369df
-    
17369df
-    current = gnome_rr_config_new_current (screen);
17369df
 
17369df
-    if (configs)
17369df
+    stored = gnome_rr_config_new_stored (screen);
17369df
+
17369df
+    if (stored)
17369df
     {
17369df
-	if ((found = gnome_rr_config_find (configs, current)))
17369df
-	{
17369df
-	    apply_configuration (found, screen);
17369df
+	gnome_rr_config_apply (stored, screen);
17369df
 
17369df
-	    result = TRUE;
17369df
-	}
17369df
-	else
17369df
+	gnome_rr_config_free (stored);
17369df
+	
17369df
+	return TRUE;
17369df
+    }
17369df
+    else
17369df
+    {
17369df
+	return FALSE;
17369df
+    }
17369df
+}
17369df
+
17369df
+static gboolean
17369df
+has_similar_mode (GnomeRROutput *output, GnomeRRMode *mode)
17369df
+{
17369df
+    int i;
17369df
+    GnomeRRMode **modes = gnome_rr_output_list_modes (output);
17369df
+    int width = gnome_rr_mode_get_width (mode);
17369df
+    int height = gnome_rr_mode_get_height (mode);
17369df
+
17369df
+    for (i = 0; modes[i] != NULL; ++i)
17369df
+    {
17369df
+	GnomeRRMode *m = modes[i];
17369df
+
17369df
+	if (gnome_rr_mode_get_width (m) == width	&&
17369df
+	    gnome_rr_mode_get_height (m) == height)
17369df
 	{
17369df
-	    result = FALSE;
17369df
+	    return TRUE;
17369df
 	}
17369df
-	
17369df
-	configurations_free (configs);
17369df
     }
17369df
-	
17369df
-    gnome_rr_config_free (current);
17369df
 
17369df
-    return result;
17369df
+    return FALSE;
17369df
 }
17369df
 
17369df
-
17369df
 /*
17369df
  * CRTC assignment
17369df
  */
f0e2ab9
diff -up gnome-desktop-2.24.0/libgnome-desktop/libgnomeui/gnome-rr-config.h.clone-modes gnome-desktop-2.24.0/libgnome-desktop/libgnomeui/gnome-rr-config.h
f0e2ab9
--- gnome-desktop-2.24.0/libgnome-desktop/libgnomeui/gnome-rr-config.h.clone-modes	2008-09-22 17:01:45.000000000 -0400
f0e2ab9
+++ gnome-desktop-2.24.0/libgnome-desktop/libgnomeui/gnome-rr-config.h	2008-09-24 14:09:09.000000000 -0400
f0e2ab9
@@ -34,6 +34,13 @@
f0e2ab9
 typedef struct GnomeOutputInfo GnomeOutputInfo;
f0e2ab9
 typedef struct GnomeRRConfig GnomeRRConfig;
f0e2ab9
 
f0e2ab9
+/* FIXME:
f0e2ab9
+ *
f0e2ab9
+ * This structure is a Frankenstein monster where all of the fields
f0e2ab9
+ * are generated by the system, but some of them can be changed by
f0e2ab9
+ * the client.
f0e2ab9
+ */
f0e2ab9
+
f0e2ab9
 struct GnomeOutputInfo
f0e2ab9
 {
f0e2ab9
     char *		name;
f0e2ab9
@@ -66,14 +73,24 @@ struct GnomeRRConfig
f0e2ab9
 };
f0e2ab9
 
f0e2ab9
 GnomeRRConfig  *gnome_rr_config_new_current  (GnomeRRScreen  *screen);
f0e2ab9
+GnomeRRConfig  *gnome_rr_config_new_stored   (GnomeRRScreen  *screen);
f0e2ab9
 void            gnome_rr_config_free         (GnomeRRConfig  *configuration);
f0e2ab9
 gboolean        gnome_rr_config_match        (GnomeRRConfig  *config1,
f0e2ab9
 					      GnomeRRConfig  *config2);
f0e2ab9
+gboolean        gnome_rr_config_equal	     (GnomeRRConfig  *config1,
f0e2ab9
+					      GnomeRRConfig  *config2);
f0e2ab9
 gboolean        gnome_rr_config_save         (GnomeRRConfig  *configuration,
f0e2ab9
 					      GError        **err);
f0e2ab9
 void            gnome_rr_config_sanitize     (GnomeRRConfig  *configuration);
f0e2ab9
+gboolean	gnome_rr_config_apply        (GnomeRRConfig  *configuration,
f0e2ab9
+					      GnomeRRScreen  *screen);
f0e2ab9
 gboolean        gnome_rr_config_apply_stored (GnomeRRScreen  *screen);
f0e2ab9
 gboolean        gnome_rr_config_applicable   (GnomeRRConfig  *configuration,
f0e2ab9
 					      GnomeRRScreen  *screen);
f0e2ab9
 
f0e2ab9
+/* A utility function that isn't really in the spirit of this file, but I don't
f0e2ab9
+ * don't know a better place for it.
f0e2ab9
+ */
f0e2ab9
+GnomeRRMode **gnome_rr_create_clone_modes (GnomeRRScreen *screen);
f0e2ab9
+
f0e2ab9
 #endif
f0e2ab9
diff -up gnome-desktop-2.24.0/libgnome-desktop/libgnomeui/gnome-rr.h.clone-modes gnome-desktop-2.24.0/libgnome-desktop/libgnomeui/gnome-rr.h
f0e2ab9
--- gnome-desktop-2.24.0/libgnome-desktop/libgnomeui/gnome-rr.h.clone-modes	2008-09-22 17:01:45.000000000 -0400
f0e2ab9
+++ gnome-desktop-2.24.0/libgnome-desktop/libgnomeui/gnome-rr.h	2008-09-24 14:09:09.000000000 -0400
f0e2ab9
@@ -56,6 +56,7 @@ void            gnome_rr_screen_destroy 
f0e2ab9
 GnomeRROutput **gnome_rr_screen_list_outputs       (GnomeRRScreen         *screen);
f0e2ab9
 GnomeRRCrtc **  gnome_rr_screen_list_crtcs         (GnomeRRScreen         *screen);
f0e2ab9
 GnomeRRMode **  gnome_rr_screen_list_modes         (GnomeRRScreen         *screen);
f0e2ab9
+GnomeRRMode **  gnome_rr_screen_list_clone_modes   (GnomeRRScreen	  *screen);
f0e2ab9
 void            gnome_rr_screen_set_size           (GnomeRRScreen         *screen,
f0e2ab9
 						    int                    width,
f0e2ab9
 						    int                    height,