diff -ur display-settings.orig/main.c display-settings.v4/main.c --- display-settings.orig/main.c 2016-04-21 21:20:19.396687823 +0200 +++ display-settings.v4/main.c 2016-04-22 21:30:36.119918123 +0200 @@ -166,6 +166,8 @@ static void display_setting_primary_toggled (GtkToggleButton *button, GtkBuilder *builder); +static XfceOutputInfo *convert_xfce_output_info (gint output_id); + static void display_settings_changed (void) { @@ -872,27 +874,28 @@ { XfceOutputInfo *output; guint n, pos = 0; - RRMode mode; + XfceRRCloneMode *mirror_mode = NULL; if (!xfce_randr) return; if (gtk_toggle_button_get_active (togglebutton)) { - /* Activate mirror-mode with a single mode for all of them */ - mode = xfce_randr_clonable_mode (xfce_randr); - /* Apply mirror settings to each output */ - for (n = 0; n < xfce_randr->noutput; n++) - { - if (xfce_randr->mode[n] == None) - continue; + /* Query for available mirror mode */ + mirror_mode = xfce_randr_mirrorable_mode (xfce_randr); - if (mode != None) - xfce_randr->mode[n] = mode; - xfce_randr->rotation[n] = RR_Rotate_0; - xfce_randr->mirrored[n] = TRUE; - xfce_randr->position[n].x = 0; - xfce_randr->position[n].y = 0; + if (mirror_mode != NULL) + { + /* Apply mirror settings to each output */ + for (n = 0; n < xfce_randr->noutput; n++) + { + xfce_randr->mode[n] = mirror_mode->modes[n]; + xfce_randr->rotation[n] = RR_Rotate_0; + xfce_randr->mirrored[n] = TRUE; + xfce_randr->position[n].x = 0; + xfce_randr->position[n].y = 0; + } + xfce_randr_rrclonemode_free(mirror_mode); } } else @@ -919,10 +922,14 @@ output->mirrored = xfce_randr->mirrored[n]; output->width = xfce_randr_mode_width (xfce_randr_find_mode_by_id (xfce_randr, n, xfce_randr->mode[n]), 0); output->height = xfce_randr_mode_height (xfce_randr_find_mode_by_id (xfce_randr, n, xfce_randr->mode[n]), 0); + convert_xfce_output_info(n); } /* Apply the changes */ display_settings_changed (); + for (n = 0; n < xfce_randr->noutput; n++) + xfce_randr_save_output (xfce_randr, "Default", display_channel, n); + xfce_randr_apply (xfce_randr, "Default", display_channel); foo_scroll_area_invalidate (FOO_SCROLL_AREA (randr_gui_area)); } @@ -930,9 +937,10 @@ display_setting_mirror_displays_populate (GtkBuilder *builder) { GObject *check; - RRMode mode = None; guint n; gint cloned = TRUE; + gboolean can_mirror = FALSE; + XfceRRCloneMode *mirror_mode = NULL; if (!xfce_randr) return; @@ -947,16 +955,13 @@ return; } - /* Can outputs be cloned? */ - if (display_settings_get_n_active_outputs () > 1) - mode = xfce_randr_clonable_mode (xfce_randr); + /* Can outputs be mirrored? */ + mirror_mode = xfce_randr_mirrorable_mode (xfce_randr); - gtk_widget_set_sensitive (GTK_WIDGET (check), mode != None); - if (mode == None) - { - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), FALSE); - return; - } + if (mirror_mode != NULL) + can_mirror = TRUE; + + gtk_widget_set_sensitive (GTK_WIDGET (check), can_mirror); /* Block the "changed" signal to avoid triggering the confirmation dialog */ g_signal_handlers_block_by_func (check, display_setting_mirror_displays_toggled, @@ -965,16 +970,29 @@ /* Check if mirror settings are on */ for (n = 0; n < xfce_randr->noutput; n++) { - if (xfce_randr->mode[n] == None) - continue; + if (mirror_mode != NULL) + { + if (xfce_randr->mode[n] == None) + continue; - cloned &= (xfce_randr->mode[n] == mode && - xfce_randr->mirrored[n]); + cloned &= (xfce_randr->mode[n] == mirror_mode->modes[n] && + xfce_randr->mirrored[n]); - if (!cloned) - break; + if (!cloned) + break; + } + else + { + cloned &= xfce_randr->mirrored[n]; + + if (!cloned) + break; + } } + if (mirror_mode != NULL) + xfce_randr_rrclonemode_free(mirror_mode); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), cloned); /* Unblock the signal */ @@ -1436,7 +1454,7 @@ { GObject *buttons; guint n; - RRMode mode; + XfceRRCloneMode *mirror_mode = NULL; if (!gtk_toggle_button_get_active(button)) return; @@ -1450,21 +1468,22 @@ buttons = gtk_builder_get_object (builder, "buttons"); gtk_widget_set_sensitive (GTK_WIDGET(buttons), FALSE); - /* Activate mirror-mode with a single mode for all of them */ - mode = xfce_randr_clonable_mode (xfce_randr); - /* Configure each available display for mirroring */ - for (n = 0; n < xfce_randr->noutput; ++n) - { - if (xfce_randr->mode[n] == None) - continue; + /* Query for available mirror mode */ + mirror_mode = xfce_randr_mirrorable_mode (xfce_randr); - if (mode != None) - xfce_randr->mode[n] = mode; - xfce_randr->mirrored[n] = TRUE; - xfce_randr->rotation[n] = RR_Rotate_0; - xfce_randr->position[n].x = 0; - xfce_randr->position[n].y = 0; - xfce_randr_save_output (xfce_randr, "Default", display_channel, n); + if (mirror_mode != NULL) + { + /* Configure each available display for mirroring */ + for (n = 0; n < xfce_randr->noutput; ++n) + { + xfce_randr->mode[n] = mirror_mode->modes[n]; + xfce_randr->mirrored[n] = TRUE; + xfce_randr->rotation[n] = RR_Rotate_0; + xfce_randr->position[n].x = 0; + xfce_randr->position[n].y = 0; + xfce_randr_save_output (xfce_randr, "Default", display_channel, n); + } + xfce_randr_rrclonemode_free(mirror_mode); } /* Apply all changes */ @@ -1558,7 +1577,7 @@ get_mirrored_configuration (void) { gboolean cloned = FALSE; - RRMode mode = None; + XfceRRCloneMode *mirror_mode = NULL; guint n; if (!xfce_randr) @@ -1567,13 +1586,15 @@ if (xfce_randr->noutput <= 1) return FALSE; - /* Can outputs be cloned? */ + /* Can outputs be mirrored? */ if (display_settings_get_n_active_outputs () > 1) - mode = xfce_randr_clonable_mode (xfce_randr); + mirror_mode = xfce_randr_mirrorable_mode (xfce_randr); - if (mode == None) + if (mirror_mode == NULL) return FALSE; + xfce_randr_rrclonemode_free(mirror_mode); + /* Check if mirror settings are on */ for (n = 0; n < xfce_randr->noutput; n++) { @@ -2884,7 +2905,7 @@ GObject *extend_right, *advanced, *fake_button, *label; GError *error = NULL; gboolean found = FALSE; - RRMode mode; + XfceRRCloneMode *mirror_mode = NULL; builder = gtk_builder_new (); @@ -2926,13 +2947,16 @@ gtk_label_set_text (GTK_LABEL (label), xfce_randr->friendly_name[1]); gtk_widget_set_tooltip_text(GTK_WIDGET(label), xfce_randr->friendly_name[1]); - /* Can outputs be cloned? */ - if (display_settings_get_n_active_outputs () > 1) - mode = xfce_randr_clonable_mode (xfce_randr); - else - mode = None; + /* Can outputs be mirrored? */ + mirror_mode = xfce_randr_mirrorable_mode (xfce_randr); - gtk_widget_set_sensitive (GTK_WIDGET (mirror_displays), mode != None); + if (mirror_mode != NULL) + { + gtk_widget_set_sensitive (GTK_WIDGET (mirror_displays), TRUE); + xfce_randr_rrclonemode_free(mirror_mode); + } + else + gtk_widget_set_sensitive (GTK_WIDGET (mirror_displays), FALSE); if (xfce_randr->mode[0] != None) { diff -ur display-settings.orig/xfce-randr.c display-settings.v4/xfce-randr.c --- display-settings.orig/xfce-randr.c 2016-04-21 21:20:19.392687823 +0200 +++ display-settings.v4/xfce-randr.c 2016-04-22 21:30:36.117918123 +0200 @@ -647,7 +647,7 @@ } - +/* Find first mode which is common to all connected displays */ RRMode xfce_randr_clonable_mode (XfceRandr *randr) { @@ -686,7 +686,106 @@ return None; } +XfceRRCloneMode * +xfce_randr_rrclonemode_new (const guint count) +{ + XfceRRCloneMode *mirror_mode; + + mirror_mode = g_new0 (XfceRRCloneMode, 1); + mirror_mode->modes = g_new0 (RRMode, count); + + return mirror_mode; +} + +void +xfce_randr_rrclonemode_free (XfceRRCloneMode *mode) +{ + if (mode != NULL) + { + if (mode->modes != NULL) + g_free(mode->modes); + g_free(mode); + } +} + +/* Find the best mode for mirroring */ +XfceRRCloneMode * +xfce_randr_mirrorable_mode (XfceRandr *randr) +{ + gint n; + guint m; + const XfceRRMode *mode0, *mode1; + const XfceRRMode *modes0, *modes1; + gint nmode0, nmode1; + GArray *resolutions; + XfceRRCloneModeTemp current_mode; + XfceRRMode lastmode; + XfceRRCloneModeTemp temp; + XfceRRCloneMode *mirror_mode = NULL; + RRMode clone_mode; + + g_return_val_if_fail (randr->noutput != 1, NULL); + + /* Can we clone all displays with same mode? */ + clone_mode = xfce_randr_clonable_mode (randr); + if (clone_mode != None) + { + /* Copy found mode to item for each display */ + mirror_mode = xfce_randr_rrclonemode_new (randr->noutput); + for (n = 0; n < randr->noutput; ++n) + mirror_mode->modes[n] = clone_mode; + return mirror_mode; + } + /* Function is prepared for two displays only */ + g_return_val_if_fail (randr->noutput == 2, NULL); + + /* It is expected that modes are ordered by resolution and rate */ + modes0 = xfce_randr_get_modes (randr, 0, &nmode0); + modes1 = xfce_randr_get_modes (randr, 1, &nmode1); + + lastmode.width = 0; + lastmode.height = 0; + resolutions = g_array_sized_new (FALSE, TRUE, sizeof(XfceRRCloneModeTemp), randr->priv->resources->nmode); + /* Try to find a "similar" mode */ + for (n = 0; n < nmode0; ++n) + { + mode0 = &modes0[n]; + for (m = 0; m < nmode1; ++m) + { + mode1 = &modes1[m]; + /* "similar" means same resolution */ + if (mode0->width == mode1->width + && mode0->height == mode1->height) + { + /* Check whether last item had same resolution */ + if (lastmode.width != mode0->width && + lastmode.height != mode0->height + ) + { // No, insert new resolution + current_mode.first_mode = mode0->id; + current_mode.second_mode = mode1->id; + lastmode.width = mode0->width; + lastmode.height = mode0->height; + g_array_append_val(resolutions, current_mode); + } + } + } + } + + if (resolutions->len != 0) + { + /* Last mode in array is the best one, copy it to return value */ + mirror_mode = xfce_randr_rrclonemode_new (2); + temp = g_array_index(resolutions, XfceRRCloneModeTemp, resolutions->len-1); + mirror_mode->modes[0] = temp.first_mode; + mirror_mode->modes[1] = temp.second_mode; + } + + g_array_free (resolutions, FALSE); + + return mirror_mode; +} const XfceRRMode * xfce_randr_get_modes (XfceRandr *randr, diff -ur display-settings.orig/xfce-randr.h display-settings.v4/xfce-randr.h --- display-settings.orig/xfce-randr.h 2016-04-21 21:20:19.390687823 +0200 +++ display-settings.v4/xfce-randr.h 2016-04-22 21:30:36.117918123 +0200 @@ -40,6 +40,8 @@ typedef struct _XfceOutputInfo XfceOutputInfo; typedef enum _XfceOutputStatus XfceOutputStatus; typedef struct _XfceOutputPosition XfceOutputPosition; +typedef struct _XfceRRCloneModeTemp XfceRRCloneModeTemp; +typedef struct _XfceRRCloneMode XfceRRCloneMode; enum _XfceOutputStatus { @@ -108,6 +110,18 @@ gpointer user_data; }; +struct _XfceRRCloneModeTemp +{ + RRMode first_mode; + RRMode second_mode; +}; + +struct _XfceRRCloneMode +{ + RRMode *modes; +}; + + XfceRandr *xfce_randr_new (GdkDisplay *display, GError **error); @@ -137,6 +151,12 @@ RRMode xfce_randr_clonable_mode (XfceRandr *randr); +XfceRRCloneMode *xfce_randr_rrclonemode_new (const guint count); + +void xfce_randr_rrclonemode_free (XfceRRCloneMode *mode); + +XfceRRCloneMode *xfce_randr_mirrorable_mode (XfceRandr *randr); + const XfceRRMode *xfce_randr_get_modes (XfceRandr *randr, guint output, gint *nmode);