diff -Nru gnome-control-center-41.7/debian/changelog gnome-control-center-41.7/debian/changelog --- gnome-control-center-41.7/debian/changelog 2022-12-25 22:47:24.000000000 +0800 +++ gnome-control-center-41.7/debian/changelog 2023-07-07 12:45:49.000000000 +0800 @@ -1,3 +1,12 @@ +gnome-control-center (1:41.7-0ubuntu0.22.04.7) jammy; urgency=medium + + * debian/patches: Update mirror mode handling + - Fix mirror mode crashed when monitors resolution not match (LP: #2026228) + - Use virtual clone modes when mirroring + This allows monitors to have their own refresh rates + + -- Dirk Su Fri, 07 Jul 2023 12:45:49 +0800 + gnome-control-center (1:41.7-0ubuntu0.22.04.6) jammy; urgency=medium * d/p/keyboard-For-xkb-options-have-Layout-default-toggle-and-N.patch: diff -Nru gnome-control-center-41.7/debian/patches/Check-best_mode-exist-before-adding-flag.patch gnome-control-center-41.7/debian/patches/Check-best_mode-exist-before-adding-flag.patch --- gnome-control-center-41.7/debian/patches/Check-best_mode-exist-before-adding-flag.patch 1970-01-01 08:00:00.000000000 +0800 +++ gnome-control-center-41.7/debian/patches/Check-best_mode-exist-before-adding-flag.patch 2023-07-07 12:45:16.000000000 +0800 @@ -0,0 +1,29 @@ +From b7c0c42317db9bea85cbf83667babf2d73a10b4a Mon Sep 17 00:00:00 2001 +From: Dirk Su +Date: Mon, 26 Jun 2023 16:38:48 +0800 +Subject: [PATCH] Check best_mode exist before adding flag + +When there is no compatible clone mode, the best_mode will be NULL +. It will cause gnome-control-center crash when access to the +variable. +--- + panels/display/cc-display-config-dbus.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/panels/display/cc-display-config-dbus.c b/panels/display/cc-display-config-dbus.c +index d94f5417b..7b454955e 100644 +--- a/panels/display/cc-display-config-dbus.c ++++ b/panels/display/cc-display-config-dbus.c +@@ -1438,7 +1438,8 @@ cc_display_config_dbus_generate_cloning_modes (CcDisplayConfig *pself) + best_mode = virtual_mode; + } + +- best_mode->flags |= MODE_PREFERRED; ++ if (best_mode) ++ best_mode->flags |= MODE_PREFERRED; + + return clone_modes; + } +-- +2.34.1 + diff -Nru gnome-control-center-41.7/debian/patches/display-Add-is_preferred-mode-getter.patch gnome-control-center-41.7/debian/patches/display-Add-is_preferred-mode-getter.patch --- gnome-control-center-41.7/debian/patches/display-Add-is_preferred-mode-getter.patch 1970-01-01 08:00:00.000000000 +0800 +++ gnome-control-center-41.7/debian/patches/display-Add-is_preferred-mode-getter.patch 2023-07-07 12:45:32.000000000 +0800 @@ -0,0 +1,78 @@ +From 6087c0397b9133d09830fa4aca20498df154a480 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Thu, 23 Jun 2022 13:01:53 +0200 +Subject: [PATCH 1/2] display: Add 'is_preferred()' mode getter + +--- + panels/display/cc-display-config-dbus.c | 9 +++++++++ + panels/display/cc-display-config.c | 6 ++++++ + panels/display/cc-display-config.h | 2 ++ + 3 files changed, 17 insertions(+) + +diff --git a/panels/display/cc-display-config-dbus.c b/panels/display/cc-display-config-dbus.c +index 83a49ade9..fc38fd83b 100644 +--- a/panels/display/cc-display-config-dbus.c ++++ b/panels/display/cc-display-config-dbus.c +@@ -124,6 +124,14 @@ cc_display_mode_dbus_is_interlaced (CcDisplayMode *pself) + return !!(self->flags & MODE_INTERLACED); + } + ++static gboolean ++cc_display_mode_dbus_is_preferred (CcDisplayMode *pself) ++{ ++ CcDisplayModeDBus *self = CC_DISPLAY_MODE_DBUS (pself); ++ ++ return !!(self->flags & MODE_PREFERRED); ++} ++ + static int + cc_display_mode_dbus_get_freq (CcDisplayMode *pself) + { +@@ -169,6 +177,7 @@ cc_display_mode_dbus_class_init (CcDisplayModeDBusClass *klass) + parent_class->get_supported_scales = cc_display_mode_dbus_get_supported_scales; + parent_class->get_preferred_scale = cc_display_mode_dbus_get_preferred_scale; + parent_class->is_interlaced = cc_display_mode_dbus_is_interlaced; ++ parent_class->is_preferred = cc_display_mode_dbus_is_preferred; + parent_class->get_freq = cc_display_mode_dbus_get_freq; + parent_class->get_freq_f = cc_display_mode_dbus_get_freq_f; + } +diff --git a/panels/display/cc-display-config.c b/panels/display/cc-display-config.c +index a78b33fc9..9346dc3de 100644 +--- a/panels/display/cc-display-config.c ++++ b/panels/display/cc-display-config.c +@@ -114,6 +114,12 @@ cc_display_mode_is_interlaced (CcDisplayMode *self) + return CC_DISPLAY_MODE_GET_CLASS (self)->is_interlaced (self); + } + ++gboolean ++cc_display_mode_is_preferred (CcDisplayMode *self) ++{ ++ return CC_DISPLAY_MODE_GET_CLASS (self)->is_preferred (self); ++} ++ + int + cc_display_mode_get_freq (CcDisplayMode *self) + { +diff --git a/panels/display/cc-display-config.h b/panels/display/cc-display-config.h +index d83fa8edc..dbaaa5cc5 100644 +--- a/panels/display/cc-display-config.h ++++ b/panels/display/cc-display-config.h +@@ -81,6 +81,7 @@ struct _CcDisplayModeClass + GArray* (*get_supported_scales) (CcDisplayMode *self); + double (*get_preferred_scale) (CcDisplayMode *self); + gboolean (*is_interlaced) (CcDisplayMode *self); ++ gboolean (*is_preferred) (CcDisplayMode *self); + int (*get_freq) (CcDisplayMode *self); + double (*get_freq_f) (CcDisplayMode *self); + }; +@@ -247,6 +248,7 @@ void cc_display_mode_get_resolution (CcDisplayMode * + GArray* cc_display_mode_get_supported_scales (CcDisplayMode *self); + double cc_display_mode_get_preferred_scale (CcDisplayMode *self); + gboolean cc_display_mode_is_interlaced (CcDisplayMode *mode); ++gboolean cc_display_mode_is_preferred (CcDisplayMode *mode); + int cc_display_mode_get_freq (CcDisplayMode *mode); + double cc_display_mode_get_freq_f (CcDisplayMode *mode); + +-- +2.34.1 + diff -Nru gnome-control-center-41.7/debian/patches/display-Use-virtual-clone-modes-when-mirroring.patch gnome-control-center-41.7/debian/patches/display-Use-virtual-clone-modes-when-mirroring.patch --- gnome-control-center-41.7/debian/patches/display-Use-virtual-clone-modes-when-mirroring.patch 1970-01-01 08:00:00.000000000 +0800 +++ gnome-control-center-41.7/debian/patches/display-Use-virtual-clone-modes-when-mirroring.patch 2023-07-07 12:45:25.000000000 +0800 @@ -0,0 +1,592 @@ +From 9e4f15353c9601dd7a57f49abacb115f3592c2bb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Thu, 23 Jun 2022 12:59:50 +0200 +Subject: [PATCH 2/2] display: Use virtual clone modes when mirroring + +These are not real modes, but just as place holders when generating +'mirror' configurations. The clone modes will be just to match the +flag/dimension, while the actual mode applied will be individual for +each monitor. + +This allows monitors to have their own refresh rates, which is possible +since a few mutter versions back. This also matches how mutter itself +generates mirror modes when doing so via the key binding. +--- + panels/display/cc-display-config-dbus.c | 257 ++++++++++++++++++++---- + panels/display/cc-display-config.c | 21 +- + panels/display/cc-display-config.h | 10 +- + panels/display/cc-display-panel.c | 44 ++-- + panels/display/cc-display-settings.c | 10 +- + 5 files changed, 276 insertions(+), 66 deletions(-) + +diff --git a/panels/display/cc-display-config-dbus.c b/panels/display/cc-display-config-dbus.c +index fc38fd83b..be496a898 100644 +--- a/panels/display/cc-display-config-dbus.c ++++ b/panels/display/cc-display-config-dbus.c +@@ -76,6 +76,14 @@ cc_display_mode_dbus_equal (const CcDisplayModeDBus *m1, + (m1->flags & MODE_INTERLACED) == (m2->flags & MODE_INTERLACED); + } + ++static gboolean ++cc_display_mode_dbus_is_clone_mode (CcDisplayMode *pself) ++{ ++ CcDisplayModeDBus *self = CC_DISPLAY_MODE_DBUS (pself); ++ ++ return !self->id; ++} ++ + static void + cc_display_mode_dbus_get_resolution (CcDisplayMode *pself, + int *w, int *h) +@@ -173,6 +181,7 @@ cc_display_mode_dbus_class_init (CcDisplayModeDBusClass *klass) + + gobject_class->finalize = cc_display_mode_dbus_finalize; + ++ parent_class->is_clone_mode = cc_display_mode_dbus_is_clone_mode; + parent_class->get_resolution = cc_display_mode_dbus_get_resolution; + parent_class->get_supported_scales = cc_display_mode_dbus_get_supported_scales; + parent_class->get_preferred_scale = cc_display_mode_dbus_get_preferred_scale; +@@ -182,6 +191,25 @@ cc_display_mode_dbus_class_init (CcDisplayModeDBusClass *klass) + parent_class->get_freq_f = cc_display_mode_dbus_get_freq_f; + } + ++static CcDisplayModeDBus * ++cc_display_mode_dbus_new_virtual (int width, ++ int height, ++ double preferred_scale, ++ GArray *supported_scales) ++{ ++ g_autoptr(GVariant) properties_variant = NULL; ++ CcDisplayModeDBus *self; ++ ++ self = g_object_new (CC_TYPE_DISPLAY_MODE_DBUS, NULL); ++ ++ self->width = width; ++ self->height = height; ++ self->preferred_scale = preferred_scale; ++ self->supported_scales = g_array_ref (supported_scales); ++ ++ return self; ++} ++ + static CcDisplayModeDBus * + cc_display_mode_dbus_new (CcDisplayMonitorDBus *monitor, + GVariant *variant) +@@ -664,6 +692,44 @@ cc_display_monitor_dbus_set_mode (CcDisplayMonitor *pself, + g_signal_emit_by_name (self, "mode"); + } + ++static void ++cc_display_monitor_dbus_set_compatible_clone_mode (CcDisplayMonitor *pself, ++ CcDisplayMode *clone_mode) ++{ ++ CcDisplayMonitorDBus *self = CC_DISPLAY_MONITOR_DBUS (pself); ++ GList *l; ++ CcDisplayMode *best_mode = NULL; ++ int clone_width, clone_height; ++ ++ g_return_if_fail (cc_display_mode_is_clone_mode (clone_mode)); ++ ++ cc_display_mode_get_resolution (clone_mode, &clone_width, &clone_height); ++ ++ for (l = self->modes; l; l = l->next) ++ { ++ CcDisplayMode *mode = l->data; ++ int width, height; ++ ++ cc_display_mode_get_resolution (mode, &width, &height); ++ if (width != clone_width || height != clone_height) ++ continue; ++ ++ if (!best_mode) ++ { ++ best_mode = mode; ++ continue; ++ } ++ ++ if (cc_display_mode_get_freq_f (mode) > ++ cc_display_mode_get_freq_f (best_mode)) ++ best_mode = mode; ++ } ++ ++ g_return_if_fail (best_mode); ++ ++ cc_display_monitor_set_mode (CC_DISPLAY_MONITOR (self), best_mode); ++} ++ + static void + cc_display_monitor_dbus_set_position (CcDisplayMonitor *pself, + int x, int y) +@@ -778,6 +844,7 @@ cc_display_monitor_dbus_class_init (CcDisplayMonitorDBusClass *klass) + parent_class->set_underscanning = cc_display_monitor_dbus_set_underscanning; + parent_class->get_privacy = cc_display_monitor_dbus_get_privacy; + parent_class->set_mode = cc_display_monitor_dbus_set_mode; ++ parent_class->set_compatible_clone_mode = cc_display_monitor_dbus_set_compatible_clone_mode; + parent_class->set_position = cc_display_monitor_dbus_set_position; + parent_class->get_scale = cc_display_monitor_dbus_get_scale; + parent_class->set_scale = cc_display_monitor_dbus_set_scale; +@@ -907,8 +974,6 @@ struct _CcDisplayConfigDBus + CcDisplayMonitorDBus *primary; + + GHashTable *logical_monitors; +- +- GList *clone_modes; + }; + + G_DEFINE_TYPE (CcDisplayConfigDBus, +@@ -1193,12 +1258,161 @@ cc_display_config_dbus_set_cloning (CcDisplayConfig *pself, + } + } + ++static gboolean ++mode_supports_scale (CcDisplayMode *mode, ++ double scale) ++{ ++ g_autoptr(GArray) scales = NULL; ++ int i; ++ ++ scales = cc_display_mode_get_supported_scales (mode); ++ for (i = 0; i < scales->len; i++) ++ { ++ if (G_APPROX_VALUE (scale, g_array_index (scales, double, i), ++ DBL_EPSILON)) ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++static void ++remove_unsupported_scales (CcDisplayMode *mode, ++ GArray *supported_scales) ++{ ++ g_autoptr(GArray) mode_scales = NULL; ++ int i; ++ ++ mode_scales = cc_display_mode_get_supported_scales (mode); ++ i = 0; ++ while (i < supported_scales->len) ++ { ++ double scale; ++ ++ if (i == supported_scales->len) ++ break; ++ ++ scale = g_array_index (supported_scales, double, i); ++ ++ if (mode_supports_scale (mode, scale)) ++ { ++ i++; ++ continue; ++ } ++ ++ g_array_remove_range (supported_scales, i, 1); ++ } ++} ++ ++static gboolean ++monitor_has_compatible_clone_mode (CcDisplayMonitorDBus *monitor, ++ CcDisplayModeDBus *mode, ++ GArray *supported_scales) ++{ ++ GList *l; ++ ++ for (l = monitor->modes; l; l = l->next) ++ { ++ CcDisplayModeDBus *other_mode = l->data; ++ ++ if (other_mode->width != mode->width || ++ other_mode->height != mode->height) ++ continue; ++ ++ if ((other_mode->flags & MODE_INTERLACED) != ++ (mode->flags & MODE_INTERLACED)) ++ continue; ++ ++ remove_unsupported_scales (CC_DISPLAY_MODE (other_mode), supported_scales); ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++static gboolean ++monitors_has_compatible_clone_mode (CcDisplayConfigDBus *self, ++ CcDisplayModeDBus *mode, ++ GArray *supported_scales) ++{ ++ GList *l; ++ ++ for (l = self->monitors; l; l = l->next) ++ { ++ CcDisplayMonitorDBus *monitor = l->data; ++ ++ if (!monitor_has_compatible_clone_mode (monitor, mode, supported_scales)) ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++static gboolean ++is_mode_better (CcDisplayModeDBus *mode, ++ CcDisplayModeDBus *other_mode) ++{ ++ if (mode->width * mode->height > other_mode->width * other_mode->height) ++ return TRUE; ++ else if (mode->width * mode->height < other_mode->width * other_mode->height) ++ return FALSE; ++ ++ if (!(mode->flags & MODE_INTERLACED) && ++ (other_mode->flags & MODE_INTERLACED)) ++ return TRUE; ++ ++ return FALSE; ++} ++ + static GList * +-cc_display_config_dbus_get_cloning_modes (CcDisplayConfig *pself) ++cc_display_config_dbus_generate_cloning_modes (CcDisplayConfig *pself) + { + CcDisplayConfigDBus *self = CC_DISPLAY_CONFIG_DBUS (pself); ++ CcDisplayMonitorDBus *base_monitor = NULL; ++ GList *l; ++ GList *clone_modes = NULL; ++ CcDisplayModeDBus *best_mode = NULL; + +- return self->clone_modes; ++ for (l = self->monitors; l; l = l->next) ++ { ++ CcDisplayMonitor *monitor = l->data; ++ ++ if (cc_display_monitor_is_active (monitor)) ++ { ++ base_monitor = CC_DISPLAY_MONITOR_DBUS (monitor); ++ break; ++ } ++ } ++ ++ if (!base_monitor) ++ return NULL; ++ ++ for (l = base_monitor->modes; l; l = l->next) ++ { ++ CcDisplayModeDBus *mode = l->data; ++ CcDisplayModeDBus *virtual_mode; ++ g_autoptr (GArray) supported_scales = NULL; ++ ++ supported_scales = ++ cc_display_mode_get_supported_scales (CC_DISPLAY_MODE (mode)); ++ ++ if (!monitors_has_compatible_clone_mode (self, mode, supported_scales)) ++ continue; ++ ++ virtual_mode = cc_display_mode_dbus_new_virtual (mode->width, ++ mode->height, ++ mode->preferred_scale, ++ supported_scales); ++ clone_modes = g_list_append (clone_modes, virtual_mode); ++ ++ if (!best_mode || is_mode_better (virtual_mode, best_mode)) ++ best_mode = virtual_mode; ++ } ++ ++ best_mode->flags |= MODE_PREFERRED; ++ ++ return clone_modes; + } + + static gboolean +@@ -1387,36 +1601,6 @@ cc_display_config_dbus_init (CcDisplayConfigDBus *self) + self->renderer = g_strdup ("xrandr"); + } + +-static void +-gather_clone_modes (CcDisplayConfigDBus *self) +-{ +- guint n_monitors = g_list_length (self->monitors); +- CcDisplayMonitorDBus *monitor; +- GList *l; +- +- if (n_monitors < 2) +- return; +- +- monitor = self->monitors->data; +- for (l = monitor->modes; l != NULL; l = l->next) +- { +- CcDisplayModeDBus *mode = l->data; +- gboolean valid = TRUE; +- GList *ll; +- for (ll = self->monitors->next; ll != NULL; ll = ll->next) +- { +- CcDisplayMonitorDBus *other_monitor = ll->data; +- if (!cc_display_monitor_dbus_get_closest_mode (other_monitor, mode)) +- { +- valid = FALSE; +- break; +- } +- } +- if (valid) +- self->clone_modes = g_list_prepend (self->clone_modes, mode); +- } +-} +- + static void + remove_logical_monitor (gpointer data, + GObject *object) +@@ -1525,8 +1709,6 @@ construct_monitors (CcDisplayConfigDBus *self, + + register_logical_monitor (self, logical_monitor); + } +- +- gather_clone_modes (self); + } + + static void +@@ -1704,7 +1886,6 @@ cc_display_config_dbus_finalize (GObject *object) + g_clear_pointer (&self->monitors, g_list_free); + g_clear_pointer (&self->logical_monitors, g_hash_table_destroy); +- g_clear_pointer (&self->clone_modes, g_list_free); + g_clear_pointer (&self->renderer, g_free); + + G_OBJECT_CLASS (cc_display_config_dbus_parent_class)->finalize (object); + } +@@ -1728,7 +1909,7 @@ cc_display_config_dbus_class_init (CcDisplayConfigDBusClass *klass) + parent_class->apply = cc_display_config_dbus_apply; + parent_class->is_cloning = cc_display_config_dbus_is_cloning; + parent_class->set_cloning = cc_display_config_dbus_set_cloning; +- parent_class->get_cloning_modes = cc_display_config_dbus_get_cloning_modes; ++ parent_class->generate_cloning_modes = cc_display_config_dbus_generate_cloning_modes; + parent_class->is_layout_logical = cc_display_config_dbus_is_layout_logical; + parent_class->set_layout_logical = cc_display_config_dbus_set_layout_logical; + parent_class->is_scaled_mode_valid = cc_display_config_dbus_is_scaled_mode_valid; +diff --git a/panels/display/cc-display-config.c b/panels/display/cc-display-config.c +index 9346dc3de..271342cbf 100644 +--- a/panels/display/cc-display-config.c ++++ b/panels/display/cc-display-config.c +@@ -90,6 +90,12 @@ cc_display_mode_class_init (CcDisplayModeClass *klass) + { + } + ++gboolean ++cc_display_mode_is_clone_mode (CcDisplayMode *self) ++{ ++ return CC_DISPLAY_MODE_GET_CLASS (self)->is_clone_mode (self); ++} ++ + void + cc_display_mode_get_resolution (CcDisplayMode *self, int *w, int *h) + { +@@ -334,6 +340,12 @@ cc_display_monitor_set_mode (CcDisplayMonitor *self, CcDisplayMode *m) + return CC_DISPLAY_MONITOR_GET_CLASS (self)->set_mode (self, m); + } + ++void ++cc_display_monitor_set_compatible_clone_mode (CcDisplayMonitor *self, CcDisplayMode *m) ++{ ++ return CC_DISPLAY_MONITOR_GET_CLASS (self)->set_mode (self, m); ++} ++ + void + cc_display_monitor_set_position (CcDisplayMonitor *self, int x, int y) + { +@@ -549,17 +561,18 @@ cc_display_config_is_applicable (CcDisplayConfig *self) + + void + cc_display_config_set_mode_on_all_outputs (CcDisplayConfig *config, +- CcDisplayMode *mode) ++ CcDisplayMode *clone_mode) + { + GList *outputs, *l; + + g_return_if_fail (CC_IS_DISPLAY_CONFIG (config)); ++ g_return_if_fail (cc_display_mode_is_clone_mode (clone_mode)); + + outputs = cc_display_config_get_monitors (config); + for (l = outputs; l; l = l->next) + { + CcDisplayMonitor *output = l->data; +- cc_display_monitor_set_mode (output, mode); ++ cc_display_monitor_set_compatible_clone_mode (output, clone_mode); + cc_display_monitor_set_position (output, 0, 0); + } + } +@@ -607,10 +620,10 @@ cc_display_config_set_cloning (CcDisplayConfig *self, + } + + GList * +-cc_display_config_get_cloning_modes (CcDisplayConfig *self) ++cc_display_config_generate_cloning_modes (CcDisplayConfig *self) + { + g_return_val_if_fail (CC_IS_DISPLAY_CONFIG (self), NULL); +- return CC_DISPLAY_CONFIG_GET_CLASS (self)->get_cloning_modes (self); ++ return CC_DISPLAY_CONFIG_GET_CLASS (self)->generate_cloning_modes (self); + } + + gboolean +diff --git a/panels/display/cc-display-config.h b/panels/display/cc-display-config.h +index dbaaa5cc5..852efa109 100644 +--- a/panels/display/cc-display-config.h ++++ b/panels/display/cc-display-config.h +@@ -77,6 +77,7 @@ struct _CcDisplayModeClass + { + GObjectClass parent_class; + ++ gboolean (*is_clone_mode) (CcDisplayMode *self); + void (*get_resolution) (CcDisplayMode *self, int *w, int *h); + GArray* (*get_supported_scales) (CcDisplayMode *self); + double (*get_preferred_scale) (CcDisplayMode *self); +@@ -125,6 +126,8 @@ struct _CcDisplayMonitorClass + CcDisplayMode* (*get_mode) (CcDisplayMonitor *self); + CcDisplayMode* (*get_preferred_mode) (CcDisplayMonitor *self); + GList* (*get_modes) (CcDisplayMonitor *self); ++ void (*set_compatible_clone_mode) (CcDisplayMonitor *self, ++ CcDisplayMode *m); + void (*set_mode) (CcDisplayMonitor *self, + CcDisplayMode *m); + void (*set_position) (CcDisplayMonitor *self, +@@ -153,7 +156,7 @@ struct _CcDisplayConfigClass + gboolean (*is_cloning) (CcDisplayConfig *self); + void (*set_cloning) (CcDisplayConfig *self, + gboolean clone); +- GList* (*get_cloning_modes) (CcDisplayConfig *self); ++ GList* (*generate_cloning_modes) (CcDisplayConfig *self); + gboolean (*is_layout_logical) (CcDisplayConfig *self); + void (*set_layout_logical) (CcDisplayConfig *self, + gboolean enabled); +@@ -176,7 +179,7 @@ gboolean cc_display_config_apply (CcDisplayConfig + gboolean cc_display_config_is_cloning (CcDisplayConfig *config); + void cc_display_config_set_cloning (CcDisplayConfig *config, + gboolean clone); +-GList* cc_display_config_get_cloning_modes (CcDisplayConfig *config); ++GList* cc_display_config_generate_cloning_modes (CcDisplayConfig *config); + + void cc_display_config_set_mode_on_all_outputs (CcDisplayConfig *config, + CcDisplayMode *mode); +@@ -227,6 +230,8 @@ double cc_display_monitor_get_scale (CcDisplayMonitor * + void cc_display_monitor_set_scale (CcDisplayMonitor *monitor, + double s); + ++void cc_display_monitor_set_compatible_clone_mode (CcDisplayMonitor *monitor, ++ CcDisplayMode *mode); + void cc_display_monitor_set_mode (CcDisplayMonitor *monitor, + CcDisplayMode *mode); + void cc_display_monitor_set_position (CcDisplayMonitor *monitor, +@@ -242,6 +247,7 @@ const char* cc_display_monitor_get_ui_name (CcDisplayMonitor * + const char* cc_display_monitor_get_ui_number_name (CcDisplayMonitor *monitor); + char* cc_display_monitor_dup_ui_number_name (CcDisplayMonitor *monitor); + ++gboolean cc_display_mode_is_clone_mode (CcDisplayMode *mode); + void cc_display_mode_get_resolution (CcDisplayMode *mode, + int *width, + int *height); +diff --git a/panels/display/cc-display-panel.c b/panels/display/cc-display-panel.c +index 593328acc..79d51c2c3 100644 +--- a/panels/display/cc-display-panel.c ++++ b/panels/display/cc-display-panel.c +@@ -164,6 +164,22 @@ cc_panel_get_selected_type (CcDisplayPanel *panel) + g_assert_not_reached (); + } + ++static CcDisplayMode * ++find_preferred_mode (GList *modes) ++{ ++ GList *l; ++ ++ for (l = modes; l; l = l->next) ++ { ++ CcDisplayMode *mode = l->data; ++ ++ if (cc_display_mode_is_preferred (mode)) ++ return mode; ++ } ++ ++ return NULL; ++} ++ + static void + config_ensure_of_type (CcDisplayPanel *panel, CcDisplayConfigType type) + { +@@ -238,34 +254,22 @@ config_ensure_of_type (CcDisplayPanel *panel, CcDisplayConfigType type) + { + g_debug ("Creating new clone config"); + gdouble scale; +- GList *modes = cc_display_config_get_cloning_modes (panel->current_config); +- gint bw, bh; +- CcDisplayMode *best = NULL; ++ g_autolist(CcDisplayMode) modes = NULL; ++ CcDisplayMode *clone_mode; + + /* Turn on cloning and select the best mode we can find by default */ + cc_display_config_set_cloning (panel->current_config, TRUE); + +- while (modes) +- { +- CcDisplayMode *mode = modes->data; +- gint w, h; +- +- cc_display_mode_get_resolution (mode, &w, &h); +- if (best == NULL || (bw*bh < w*h)) +- { +- best = mode; +- cc_display_mode_get_resolution (best, &bw, &bh); +- } +- +- modes = modes->next; +- } ++ modes = cc_display_config_generate_cloning_modes (panel->current_config); ++ clone_mode = find_preferred_mode (modes); ++ g_return_if_fail (clone_mode); + + /* Take the preferred scale by default, */ +- scale = cc_display_mode_get_preferred_scale (best); ++ scale = cc_display_mode_get_preferred_scale (clone_mode); + /* but prefer the old primary scale if that is valid. */ + if (current_primary && + cc_display_config_is_scaled_mode_valid (panel->current_config, +- best, ++ clone_mode, + old_primary_scale)) + scale = old_primary_scale; + +@@ -273,7 +277,7 @@ config_ensure_of_type (CcDisplayPanel *panel, CcDisplayConfigType type) + { + CcDisplayMonitor *output = l->data; + +- cc_display_monitor_set_mode (output, best); ++ cc_display_monitor_set_compatible_clone_mode (output, clone_mode); + cc_display_monitor_set_scale (output, scale); + } + } +diff --git a/panels/display/cc-display-settings.c b/panels/display/cc-display-settings.c +index 54301b30a..21a0a1ad8 100644 +--- a/panels/display/cc-display-settings.c ++++ b/panels/display/cc-display-settings.c +@@ -235,5 +235,6 @@ static gboolean + cc_display_settings_rebuild_ui (CcDisplaySettings *self) + { ++ g_autolist(CcDisplayMode) clone_modes = NULL; + GList *modes; + GList *item; + gint width, height; +@@ -365,9 +366,14 @@ cc_display_settings_rebuild_ui (CcDisplaySettings *self) + /* Resolutions are always shown. */ + gtk_widget_set_visible (self->resolution_row, TRUE); + if (cc_display_config_is_cloning (self->config)) +- modes = cc_display_config_get_cloning_modes (self->config); ++ { ++ clone_modes = cc_display_config_generate_cloning_modes (self->config); ++ modes = clone_modes; ++ } + else +- modes = cc_display_monitor_get_modes (self->selected_output); ++ { ++ modes = cc_display_monitor_get_modes (self->selected_output); ++ } + + g_list_store_remove_all (self->resolution_list); + g_list_store_append (self->resolution_list, current_mode); +-- +2.34.1 + diff -Nru gnome-control-center-41.7/debian/patches/series gnome-control-center-41.7/debian/patches/series --- gnome-control-center-41.7/debian/patches/series 2022-12-25 21:12:14.000000000 +0800 +++ gnome-control-center-41.7/debian/patches/series 2023-07-07 12:45:32.000000000 +0800 @@ -68,3 +68,6 @@ ubuntu/sharing-rdp/0016-sharing-Turn-off-RDP-gsettings-key-when-turning-off-RDP.patch ubuntu/sharing-rdp/0017-sharing-Turn-off-VNC-gsettings-key-when-turning-off-VNC.patch panels-wwan-Add-WWAN-5G-connection-support.patch +display-Add-is_preferred-mode-getter.patch +display-Use-virtual-clone-modes-when-mirroring.patch +Check-best_mode-exist-before-adding-flag.patch