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