diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c index 099a48e74..1cccebc1a 100644 --- a/src/backends/meta-monitor-manager.c +++ b/src/backends/meta-monitor-manager.c @@ -1492,7 +1492,7 @@ meta_monitor_manager_legacy_handle_apply_configuration (MetaDBusDisplayConfig * #define META_DISPLAY_CONFIG_MODE_FLAGS_PREFERRED (1 << 0) #define META_DISPLAY_CONFIG_MODE_FLAGS_CURRENT (1 << 1) -#define MODE_FORMAT "(iiddadu)" +#define MODE_FORMAT "(siiddadu)" #define MODES_FORMAT "a" MODE_FORMAT #define MONITOR_SPEC_FORMAT "(ssss)" #define MONITOR_FORMAT "(" MONITOR_SPEC_FORMAT MODES_FORMAT "a{sv})" @@ -1549,13 +1549,19 @@ meta_monitor_manager_handle_get_current_state (MetaDBusDisplayConfig *skeleton, { MetaMonitorMode *monitor_mode = k->data; GVariantBuilder supported_scales_builder; - MetaMonitorModeSpec *monitor_mode_spec; + const char *mode_id; + int mode_width, mode_height; + float refresh_rate; float preferred_scale; float *supported_scales; int n_supported_scales; uint32_t flags = 0; - monitor_mode_spec = meta_monitor_mode_get_spec (monitor_mode); + mode_id = meta_monitor_mode_get_id (monitor_mode); + meta_monitor_mode_get_resolution (monitor_mode, + &mode_width, &mode_height); + refresh_rate = meta_monitor_mode_get_refresh_rate (monitor_mode); + preferred_scale = meta_monitor_manager_calculate_monitor_mode_scale (manager, monitor, @@ -1580,9 +1586,10 @@ meta_monitor_manager_handle_get_current_state (MetaDBusDisplayConfig *skeleton, flags |= META_DISPLAY_CONFIG_MODE_FLAGS_PREFERRED; g_variant_builder_add (&modes_builder, MODE_FORMAT, - monitor_mode_spec->width, - monitor_mode_spec->height, - monitor_mode_spec->refresh_rate, + mode_id, + mode_width, + mode_height, + refresh_rate, (double) preferred_scale, &supported_scales_builder, flags); @@ -1797,13 +1804,16 @@ meta_monitor_manager_is_config_applicable (MetaMonitorManager *manager, return TRUE; } -static MetaMonitorSpec * -find_monitor_spec (MetaMonitorManager *manager, - char *connector) +static MetaMonitor * +find_monitor_from_connector (MetaMonitorManager *manager, + char *connector) { GList *monitors; GList *l; + if (!connector) + return NULL; + monitors = meta_monitor_manager_get_monitors (manager); for (l = monitors; l; l = l->next) { @@ -1811,14 +1821,13 @@ find_monitor_spec (MetaMonitorManager *manager, MetaMonitorSpec *monitor_spec = meta_monitor_get_spec (monitor); if (g_str_equal (connector, monitor_spec->connector)) - return meta_monitor_spec_clone (monitor_spec); + return monitor; } return NULL; } -#define MONITOR_MODE_SPEC_FORMAT "(iid)" -#define MONITOR_CONFIG_FORMAT "(s" MONITOR_MODE_SPEC_FORMAT "a{sv})" +#define MONITOR_CONFIG_FORMAT "(ssa{sv})" #define MONITOR_CONFIGS_FORMAT "a" MONITOR_CONFIG_FORMAT #define LOGICAL_MONITOR_CONFIG_FORMAT "(iidub" MONITOR_CONFIGS_FORMAT ")" @@ -1830,49 +1839,43 @@ create_monitor_config_from_variant (MetaMonitorManager *manager, { MetaMonitorConfig *monitor_config = NULL; - char *connector; + g_autofree char *connector = NULL; + g_autofree char *mode_id = NULL; + MetaMonitorMode *monitor_mode; + MetaMonitor *monitor; MetaMonitorSpec *monitor_spec; MetaMonitorModeSpec *monitor_mode_spec; - GVariant *properties_variant = NULL; + g_autoptr (GVariant) properties_variant = NULL; gboolean enable_underscanning = FALSE; - int32_t mode_width; - int32_t mode_height; - double mode_refresh_rate; - monitor_spec = g_new0 (MetaMonitorSpec, 1); - monitor_mode_spec = g_new0 (MetaMonitorModeSpec, 1); - - g_variant_get (monitor_config_variant, "(s" MONITOR_MODE_SPEC_FORMAT "@a{sv})", + g_variant_get (monitor_config_variant, "(ss@a{sv})", &connector, - &mode_width, - &mode_height, - &mode_refresh_rate, + &mode_id, &properties_variant); - *monitor_mode_spec = (MetaMonitorModeSpec) { - .width = mode_width, - .height = mode_height, - .refresh_rate = mode_refresh_rate - }; - - monitor_spec = find_monitor_spec (manager, connector); - if (!monitor_spec) + monitor = find_monitor_from_connector (manager, connector); + if (!monitor) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Invalid connector '%s' specified", connector); - g_free (monitor_mode_spec); return NULL; } - if (!meta_verify_monitor_mode_spec (monitor_mode_spec, error)) + monitor_mode = meta_monitor_get_mode_from_id (monitor, mode_id); + if (!monitor_mode) { - g_free (monitor_mode_spec); - meta_monitor_spec_free (monitor_spec); + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Invalid mode '%s' specified", mode_id); return NULL; } g_variant_lookup (properties_variant, "underscanning", "b", &enable_underscanning); + monitor_spec = meta_monitor_spec_clone (meta_monitor_get_spec (monitor)); + + monitor_mode_spec = g_new0 (MetaMonitorModeSpec, 1); + *monitor_mode_spec = *meta_monitor_mode_get_spec (monitor_mode); + monitor_config = g_new0 (MetaMonitorConfig, 1); *monitor_config = (MetaMonitorConfig) { .monitor_spec = monitor_spec, diff --git a/src/backends/meta-monitor.c b/src/backends/meta-monitor.c index d86cea174..ba12a1341 100644 --- a/src/backends/meta-monitor.c +++ b/src/backends/meta-monitor.c @@ -33,6 +33,7 @@ typedef struct _MetaMonitorMode { + char *id; MetaMonitorModeSpec spec; MetaMonitorCrtcMode *crtc_modes; } MetaMonitorMode; @@ -50,6 +51,7 @@ typedef struct _MetaMonitorPrivate GList *outputs; GList *modes; + GHashTable *mode_ids; MetaMonitorMode *preferred_mode; MetaMonitorMode *current_mode; @@ -333,6 +335,7 @@ meta_monitor_finalize (GObject *object) MetaMonitor *monitor = META_MONITOR (object); MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor); + g_hash_table_destroy (priv->mode_ids); g_list_free_full (priv->modes, (GDestroyNotify) meta_monitor_mode_free); g_clear_pointer (&priv->outputs, g_list_free); meta_monitor_spec_free (priv->spec); @@ -341,6 +344,9 @@ meta_monitor_finalize (GObject *object) static void meta_monitor_init (MetaMonitor *monitor) { + MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor); + + priv->mode_ids = g_hash_table_new (g_str_hash, g_str_equal); } static void @@ -351,6 +357,36 @@ meta_monitor_class_init (MetaMonitorClass *klass) object_class->finalize = meta_monitor_finalize; } +static char * +generate_mode_id (MetaMonitorModeSpec *monitor_mode_spec) +{ + char refresh_rate_str[G_ASCII_DTOSTR_BUF_SIZE]; + + g_ascii_dtostr (refresh_rate_str, G_ASCII_DTOSTR_BUF_SIZE, + monitor_mode_spec->refresh_rate); + + return g_strdup_printf ("%dx%d@%s", + monitor_mode_spec->width, + monitor_mode_spec->height, + refresh_rate_str); +} + +static gboolean +meta_monitor_add_mode (MetaMonitor *monitor, + MetaMonitorMode *monitor_mode) +{ + MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor); + + if (g_hash_table_lookup (priv->mode_ids, + meta_monitor_mode_get_id (monitor_mode))) + return FALSE; + + priv->modes = g_list_append (priv->modes, monitor_mode); + g_hash_table_insert (priv->mode_ids, monitor_mode->id, monitor_mode); + + return TRUE; +} + static void meta_monitor_normal_generate_modes (MetaMonitorNormal *monitor_normal) { @@ -372,6 +408,7 @@ meta_monitor_normal_generate_modes (MetaMonitorNormal *monitor_normal) .height = crtc_mode->height, .refresh_rate = crtc_mode->refresh_rate }, + mode->id = generate_mode_id (&mode->spec); mode->crtc_modes = g_new (MetaMonitorCrtcMode, 1); mode->crtc_modes[0] = (MetaMonitorCrtcMode) { .output = output, @@ -383,7 +420,8 @@ meta_monitor_normal_generate_modes (MetaMonitorNormal *monitor_normal) if (output->crtc && crtc_mode == output->crtc->current_mode) monitor_priv->current_mode = mode; - monitor_priv->modes = g_list_append (monitor_priv->modes, mode); + if (!meta_monitor_add_mode (monitor, mode)) + meta_monitor_mode_free (mode); } } @@ -671,15 +709,22 @@ create_tiled_monitor_mode (MetaMonitorTiled *monitor_tiled, MetaMonitorPrivate *monitor_priv = meta_monitor_get_instance_private (monitor); MetaMonitorModeTiled *mode; + int width, height; GList *l; unsigned int i; gboolean is_preferred = TRUE; mode = g_new0 (MetaMonitorModeTiled, 1); mode->is_tiled = TRUE; - meta_monitor_tiled_calculate_tiled_size (monitor, - &mode->parent.spec.width, - &mode->parent.spec.height); + meta_monitor_tiled_calculate_tiled_size (monitor, &width, &height); + + mode->parent.spec = (MetaMonitorModeSpec) { + .width = width, + .height = height, + .refresh_rate = refresh_rate, + }; + mode->parent.id = generate_mode_id (&mode->parent.spec); + mode->parent.crtc_modes = g_new0 (MetaMonitorCrtcMode, g_list_length (monitor_priv->outputs)); for (l = monitor_priv->outputs, i = 0; l; l = l->next, i++) @@ -701,8 +746,6 @@ create_tiled_monitor_mode (MetaMonitorTiled *monitor_tiled, .crtc_mode = tiled_crtc_mode }; - mode->parent.spec.refresh_rate = refresh_rate; - is_preferred = is_preferred && tiled_crtc_mode == output->preferred_mode; } @@ -720,6 +763,8 @@ generate_tiled_monitor_modes (MetaMonitorTiled *monitor_tiled) MetaOutput *main_output; GList *tiled_modes = NULL; unsigned int i; + MetaMonitorMode *best_mode = NULL; + GList *l; main_output = meta_monitor_get_main_output (META_MONITOR (monitor_tiled)); @@ -746,24 +791,28 @@ generate_tiled_monitor_modes (MetaMonitorTiled *monitor_tiled) monitor_priv->preferred_mode = mode; } - if (!monitor_priv->preferred_mode) + while ((l = tiled_modes)) { - MetaMonitorMode *best_mode = NULL; - GList *l; + MetaMonitorMode *mode = l->data; - for (l = tiled_modes; l; l = l->next) + tiled_modes = g_list_remove_link (tiled_modes, l); + + if (!meta_monitor_add_mode (monitor, mode)) { - MetaMonitorMode *mode = l->data; + meta_monitor_mode_free (mode); + continue; + } + if (!monitor_priv->preferred_mode) + { if (!best_mode || mode->spec.refresh_rate > best_mode->spec.refresh_rate) best_mode = mode; } - - monitor_priv->preferred_mode = best_mode; } - monitor_priv->modes = g_list_concat (monitor_priv->modes, tiled_modes); + if (best_mode) + monitor_priv->preferred_mode = best_mode; } static MetaMonitorMode * @@ -789,6 +838,7 @@ create_untiled_monitor_mode (MetaMonitorTiled *monitor_tiled, .height = crtc_mode->height, .refresh_rate = crtc_mode->refresh_rate }; + mode->parent.id = generate_mode_id (&mode->parent.spec); mode->parent.crtc_modes = g_new0 (MetaMonitorCrtcMode, g_list_length (monitor_priv->outputs)); @@ -888,7 +938,11 @@ generate_untiled_monitor_modes (MetaMonitorTiled *monitor_tiled) if (!mode) continue; - monitor_priv->modes = g_list_append (monitor_priv->modes, mode); + if (!meta_monitor_add_mode (monitor, mode)) + { + meta_monitor_mode_free (mode); + continue; + } if (is_monitor_mode_assigned (monitor, mode)) { @@ -1130,6 +1184,7 @@ meta_monitor_tiled_class_init (MetaMonitorTiledClass *klass) static void meta_monitor_mode_free (MetaMonitorMode *monitor_mode) { + g_free (monitor_mode->id); g_free (monitor_mode->crtc_modes); g_free (monitor_mode); } @@ -1153,6 +1208,15 @@ meta_monitor_get_logical_monitor (MetaMonitor *monitor) return NULL; } +MetaMonitorMode * +meta_monitor_get_mode_from_id (MetaMonitor *monitor, + const char *monitor_mode_id) +{ + MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor); + + return g_hash_table_lookup (priv->mode_ids, monitor_mode_id); +} + static gboolean meta_monitor_mode_spec_equals (MetaMonitorModeSpec *monitor_mode_spec, MetaMonitorModeSpec *other_monitor_mode_spec) @@ -1458,6 +1522,12 @@ meta_monitor_mode_get_spec (MetaMonitorMode *monitor_mode) return &monitor_mode->spec; } +const char * +meta_monitor_mode_get_id (MetaMonitorMode *monitor_mode) +{ + return monitor_mode->id; +} + void meta_monitor_mode_get_resolution (MetaMonitorMode *monitor_mode, int *width, diff --git a/src/backends/meta-monitor.h b/src/backends/meta-monitor.h index 3e40a9de7..73903617f 100644 --- a/src/backends/meta-monitor.h +++ b/src/backends/meta-monitor.h @@ -145,6 +145,9 @@ gboolean meta_monitor_get_suggested_position (MetaMonitor *monitor, MetaLogicalMonitor * meta_monitor_get_logical_monitor (MetaMonitor *monitor); +MetaMonitorMode * meta_monitor_get_mode_from_id (MetaMonitor *monitor, + const char *monitor_mode_id); + MetaMonitorMode * meta_monitor_get_mode_from_spec (MetaMonitor *monitor, MetaMonitorModeSpec *monitor_mode_spec); @@ -174,6 +177,8 @@ float * meta_monitor_calculate_supported_scales (MetaMonitor *mon MetaMonitorScalesConstraint constraints, int *n_supported_scales); +const char * meta_monitor_mode_get_id (MetaMonitorMode *monitor_mode); + MetaMonitorModeSpec * meta_monitor_mode_get_spec (MetaMonitorMode *monitor_mode); void meta_monitor_mode_get_resolution (MetaMonitorMode *monitor_mode, diff --git a/src/org.gnome.Mutter.DisplayConfig.xml b/src/org.gnome.Mutter.DisplayConfig.xml index 62b82659c..befd68580 100644 --- a/src/org.gnome.Mutter.DisplayConfig.xml +++ b/src/org.gnome.Mutter.DisplayConfig.xml @@ -315,7 +315,8 @@ * s vendor: vendor name * s product: product name * s serial: product serial - * a(iiddadu) modes: available modes + * a(siiddad) modes: available modes + * s id: mode ID * i width: width in physical pixels * i height: height in physical pixels * d refresh rate: refresh rate @@ -404,7 +405,7 @@ --> - + @@ -431,10 +432,9 @@ * d: scale * u: transform (see GetCurrentState) * b primary: true if this is the primary logical monitor - * a(siida{sv}): a list of monitors, each consisting of: + * a(ssa{sv}): a list of monitors, each consisting of: * s: connector - * (iid): monitor mode spec (resolution width, resolution height, - refresh rate) + * s: monitor mode ID * a{sv}: monitor properties, including: - "enable_underscanning" (b): enable monitor underscanning; may only be set when underscanning @@ -450,7 +450,7 @@ - +