From 691e7951ea9ef67497484504f16f74d4fa0840a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 14 Feb 2017 19:54:04 +0800 Subject: [PATCH] DisplayConfig: Add new API for configuring monitors Add a new D-Bus API that uses the state from GetCurrentState to configure high level monitors, instead of low level CRTCs and connectors. So far persistent configuration is not implemented, as writing to the configuration store is still not supported. https://bugzilla.gnome.org/show_bug.cgi?id=777732 --- src/backends/meta-monitor-manager-dummy.c | 14 +- src/backends/meta-monitor-manager-private.h | 15 +- src/backends/meta-monitor-manager.c | 401 +++++++++++++++++- .../native/meta-monitor-manager-kms.c | 14 +- .../x11/meta-monitor-manager-xrandr.c | 20 +- src/org.gnome.Mutter.DisplayConfig.xml | 37 ++ src/tests/meta-monitor-manager-test.c | 14 +- 7 files changed, 485 insertions(+), 30 deletions(-) diff --git a/src/backends/meta-monitor-manager-dummy.c b/src/backends/meta-monitor-manager-dummy.c index b0fbddca0..f5b993f24 100644 --- a/src/backends/meta-monitor-manager-dummy.c +++ b/src/backends/meta-monitor-manager-dummy.c @@ -499,9 +499,10 @@ update_screen_size (MetaMonitorManager *manager, } static gboolean -meta_monitor_manager_dummy_apply_monitors_config (MetaMonitorManager *manager, - MetaMonitorsConfig *config, - GError **error) +meta_monitor_manager_dummy_apply_monitors_config (MetaMonitorManager *manager, + MetaMonitorsConfig *config, + MetaMonitorsConfigMethod method, + GError **error) { GPtrArray *crtc_infos; GPtrArray *output_infos; @@ -519,6 +520,13 @@ meta_monitor_manager_dummy_apply_monitors_config (MetaMonitorManager *manager, error)) return FALSE; + if (method == META_MONITORS_CONFIG_METHOD_VERIFY) + { + g_ptr_array_free (crtc_infos, TRUE); + g_ptr_array_free (output_infos, TRUE); + return TRUE; + } + apply_crtc_assignments (manager, (MetaCrtcInfo **) crtc_infos->pdata, crtc_infos->len, diff --git a/src/backends/meta-monitor-manager-private.h b/src/backends/meta-monitor-manager-private.h index d5a98c20a..ade2c6049 100644 --- a/src/backends/meta-monitor-manager-private.h +++ b/src/backends/meta-monitor-manager-private.h @@ -74,6 +74,14 @@ typedef enum _MetaMonitorManagerCapability META_MONITOR_MANAGER_CAPABILITY_MIRRORING = (1 << 0) } MetaMonitorManagerCapability; +/* Equivalent to the 'method' enum in org.gnome.Mutter.DisplayConfig */ +typedef enum _MetaMonitorsConfigMethod +{ + META_MONITORS_CONFIG_METHOD_VERIFY = 0, + META_MONITORS_CONFIG_METHOD_TEMPORARY = 1, + META_MONITORS_CONFIG_METHOD_PERSISTENT = 2 +} MetaMonitorsConfigMethod; + typedef enum { META_MONITOR_TRANSFORM_NORMAL, @@ -316,9 +324,10 @@ struct _MetaMonitorManagerClass void (*ensure_initial_config) (MetaMonitorManager *); - gboolean (*apply_monitors_config) (MetaMonitorManager *, - MetaMonitorsConfig *, - GError **); + gboolean (*apply_monitors_config) (MetaMonitorManager *, + MetaMonitorsConfig *, + MetaMonitorsConfigMethod , + GError **); void (*apply_configuration) (MetaMonitorManager *, MetaCrtcInfo **, diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c index e60f93ae1..64a45b6e3 100644 --- a/src/backends/meta-monitor-manager.c +++ b/src/backends/meta-monitor-manager.c @@ -315,14 +315,15 @@ meta_monitor_manager_ensure_initial_config (MetaMonitorManager *manager) } static gboolean -meta_monitor_manager_apply_monitors_config (MetaMonitorManager *manager, - MetaMonitorsConfig *config, - GError **error) +meta_monitor_manager_apply_monitors_config (MetaMonitorManager *manager, + MetaMonitorsConfig *config, + MetaMonitorsConfigMethod method, + GError **error) { MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_GET_CLASS (manager); - return manager_class->apply_monitors_config (manager, config, error); + return manager_class->apply_monitors_config (manager, config, method, error); } gboolean @@ -359,6 +360,10 @@ meta_monitor_manager_ensure_configured (MetaMonitorManager *manager) { MetaMonitorsConfig *config = NULL; GError *error = NULL; + gboolean use_stored_config; + MetaMonitorsConfigMethod method; + MetaMonitorsConfigMethod fallback_method = + META_MONITORS_CONFIG_METHOD_TEMPORARY; if (!manager->config_manager) { @@ -366,12 +371,20 @@ meta_monitor_manager_ensure_configured (MetaMonitorManager *manager) return NULL; } - if (should_use_stored_config (manager)) + use_stored_config = should_use_stored_config (manager); + if (use_stored_config) + method = META_MONITORS_CONFIG_METHOD_PERSISTENT; + else + method = META_MONITORS_CONFIG_METHOD_TEMPORARY; + + if (use_stored_config) { config = meta_monitor_config_manager_get_stored (manager->config_manager); if (config) { - if (!meta_monitor_manager_apply_monitors_config (manager, config, + if (!meta_monitor_manager_apply_monitors_config (manager, + config, + method, &error)) { config = NULL; @@ -390,7 +403,10 @@ meta_monitor_manager_ensure_configured (MetaMonitorManager *manager) config = meta_monitor_config_manager_create_suggested (manager->config_manager); if (config) { - if (!meta_monitor_manager_apply_monitors_config (manager, config, &error)) + if (!meta_monitor_manager_apply_monitors_config (manager, + config, + method, + &error)) { g_clear_object (&config); g_warning ("Failed to use suggested monitor configuration: %s", @@ -406,7 +422,10 @@ meta_monitor_manager_ensure_configured (MetaMonitorManager *manager) config = meta_monitor_config_manager_create_linear (manager->config_manager); if (config) { - if (!meta_monitor_manager_apply_monitors_config (manager, config, &error)) + if (!meta_monitor_manager_apply_monitors_config (manager, + config, + method, + &error)) { g_clear_object (&config); g_warning ("Failed to use linear monitor configuration: %s", @@ -422,7 +441,10 @@ meta_monitor_manager_ensure_configured (MetaMonitorManager *manager) config = meta_monitor_config_manager_create_fallback (manager->config_manager); if (config) { - if (!meta_monitor_manager_apply_monitors_config (manager, config, &error)) + if (!meta_monitor_manager_apply_monitors_config (manager, + config, + fallback_method, + &error)) { g_clear_object (&config); g_warning ("Failed to use fallback monitor configuration: %s", @@ -440,7 +462,10 @@ done: if (!config) { - meta_monitor_manager_apply_monitors_config (manager, NULL, &error); + meta_monitor_manager_apply_monitors_config (manager, + NULL, + fallback_method, + &error); return NULL; } @@ -1364,6 +1389,361 @@ meta_monitor_manager_handle_get_current_state (MetaDBusDisplayConfig *skeleton, #undef LOGICAL_MONITOR_FORMAT #undef LOGICAL_MONITORS_FORMAT +static gboolean +meta_monitor_manager_is_scale_supported (MetaMonitorManager *manager, + float scale) +{ + float *supported_scales; + int n_supported_scales; + int i; + + meta_monitor_manager_get_supported_scales (manager, + &supported_scales, + &n_supported_scales); + for (i = 0; i < n_supported_scales; i++) + { + if (supported_scales[i] == scale) + return TRUE; + } + + return FALSE; +} + +static gboolean +meta_monitor_manager_is_config_applicable (MetaMonitorManager *manager, + MetaMonitorsConfig *config, + GError **error) +{ + GList *l; + + for (l = config->logical_monitor_configs; l; l = l->next) + { + MetaLogicalMonitorConfig *logical_monitor_config = l->data; + float scale = logical_monitor_config->scale; + GList *k; + + if (!meta_monitor_manager_is_scale_supported (manager, scale)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Scale not supported by backend"); + return FALSE; + } + + for (k = logical_monitor_config->monitor_configs; k; k = k->next) + { + MetaMonitorConfig *monitor_config = k->data; + MetaMonitorSpec *monitor_spec = monitor_config->monitor_spec; + MetaMonitorModeSpec *mode_spec = monitor_config->mode_spec; + MetaMonitor *monitor; + MetaMonitorMode *monitor_mode; + + monitor = meta_monitor_manager_get_monitor_from_spec (manager, + monitor_spec); + if (!monitor) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Specified monitor not found"); + return FALSE; + } + + monitor_mode = meta_monitor_get_mode_from_spec (monitor, mode_spec); + if (!monitor_mode) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Specified monitor mode not available"); + return FALSE; + } + } + } + + return TRUE; +} + +static MetaMonitorSpec * +find_monitor_spec (MetaMonitorManager *manager, + char *connector) +{ + GList *monitors; + GList *l; + + monitors = meta_monitor_manager_get_monitors (manager); + for (l = monitors; l; l = l->next) + { + MetaMonitor *monitor = l->data; + MetaMonitorSpec *monitor_spec = meta_monitor_get_spec (monitor); + + if (g_str_equal (connector, monitor_spec->connector)) + return meta_monitor_spec_clone (monitor_spec); + } + + return NULL; +} + +#define MONITOR_MODE_SPEC_FORMAT "(iid)" +#define MONITOR_CONFIG_FORMAT "(s" MONITOR_MODE_SPEC_FORMAT "a{sv})" +#define MONITOR_CONFIGS_FORMAT "a" MONITOR_CONFIG_FORMAT + +#define LOGICAL_MONITOR_CONFIG_FORMAT "(iidb" MONITOR_CONFIGS_FORMAT ")" + +static MetaMonitorConfig * +create_monitor_config_from_variant (MetaMonitorManager *manager, + GVariant *monitor_config_variant, + GError **error) +{ + + MetaMonitorConfig *monitor_config = NULL; + char *connector; + MetaMonitorSpec *monitor_spec; + MetaMonitorModeSpec *monitor_mode_spec; + 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})", + &connector, + &mode_width, + &mode_height, + &mode_refresh_rate, + &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) + { + 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)) + { + g_free (monitor_mode_spec); + meta_monitor_spec_free (monitor_spec); + return NULL; + } + + g_variant_lookup (properties_variant, "underscanning", "b", &enable_underscanning); + + monitor_config = g_new0 (MetaMonitorConfig, 1); + *monitor_config = (MetaMonitorConfig) { + .monitor_spec = monitor_spec, + .mode_spec = monitor_mode_spec, + .enable_underscanning = enable_underscanning + }; + + return monitor_config; +} + +static gboolean +derive_logical_monitor_size (GList *monitor_configs, + int *width, + int *height, + GError **error) +{ + MetaMonitorConfig *monitor_config; + + if (!monitor_configs) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Empty logical monitor"); + return FALSE; + } + + monitor_config = monitor_configs->data; + *width = monitor_config->mode_spec->width; + *height = monitor_config->mode_spec->height; + + return TRUE; +} + +static MetaLogicalMonitorConfig * +create_logical_monitor_config_from_variant (MetaMonitorManager *manager, + GVariant *logical_monitor_config_variant, + GError **error) +{ + MetaLogicalMonitorConfig *logical_monitor_config; + int x, y, width, height; + double scale; + gboolean is_primary; + GVariantIter *monitor_configs_iter; + GList *monitor_configs = NULL; + + g_variant_get (logical_monitor_config_variant, LOGICAL_MONITOR_CONFIG_FORMAT, + &x, + &y, + &scale, + &is_primary, + &monitor_configs_iter); + + while (TRUE) + { + GVariant *monitor_config_variant = + g_variant_iter_next_value (monitor_configs_iter); + MetaMonitorConfig *monitor_config; + + if (!monitor_config_variant) + break; + + monitor_config = + create_monitor_config_from_variant (manager, + monitor_config_variant, error); + if (!monitor_config) + goto err; + + if (!meta_verify_monitor_config (monitor_config, error)) + { + meta_monitor_config_free (monitor_config); + goto err; + } + + monitor_configs = g_list_append (monitor_configs, monitor_config); + } + g_variant_iter_free (monitor_configs_iter); + + if (!derive_logical_monitor_size (monitor_configs, &width, &height, error)) + goto err; + + logical_monitor_config = g_new0 (MetaLogicalMonitorConfig, 1); + *logical_monitor_config = (MetaLogicalMonitorConfig) { + .layout = { + .x = x, + .y = y, + .width = width, + .height = height + }, + .scale = (int) scale, + .is_primary = is_primary, + .monitor_configs = monitor_configs + }; + + if (!meta_verify_logical_monitor_config (logical_monitor_config, error)) + { + meta_logical_monitor_config_free (logical_monitor_config); + return NULL; + } + + return logical_monitor_config; + +err: + g_list_free_full (monitor_configs, (GDestroyNotify) meta_monitor_config_free); + return NULL; +} + +static gboolean +meta_monitor_manager_handle_apply_monitors_config (MetaDBusDisplayConfig *skeleton, + GDBusMethodInvocation *invocation, + guint serial, + guint method, + GVariant *logical_monitor_configs_variant, + GVariant *properties_variant) +{ + MetaMonitorManager *manager = META_MONITOR_MANAGER (skeleton); + GVariantIter logical_monitor_configs_iter; + MetaMonitorsConfig *config; + GList *logical_monitor_configs = NULL; + GError *error = NULL; + + if (!manager->config_manager) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_NOT_SUPPORTED, + "Used new configuration API with old configuration system"); + return TRUE; + } + + if (serial != manager->serial) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_ACCESS_DENIED, + "The requested configuration is based on stale information"); + return TRUE; + } + + g_variant_iter_init (&logical_monitor_configs_iter, + logical_monitor_configs_variant); + while (TRUE) + { + GVariant *logical_monitor_config_variant = + g_variant_iter_next_value (&logical_monitor_configs_iter); + MetaLogicalMonitorConfig *logical_monitor_config; + + if (!logical_monitor_config_variant) + break; + + logical_monitor_config = + create_logical_monitor_config_from_variant (manager, + logical_monitor_config_variant, + &error); + if (!logical_monitor_config) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_INVALID_ARGS, + error->message); + g_error_free (error); + g_list_free_full (logical_monitor_configs, + (GDestroyNotify) meta_logical_monitor_config_free); + return TRUE; + } + + logical_monitor_configs = g_list_append (logical_monitor_configs, + logical_monitor_config); + } + + config = meta_monitors_config_new (logical_monitor_configs); + if (!meta_verify_monitors_config (config, &error)) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_INVALID_ARGS, + error->message); + g_error_free (error); + g_object_unref (config); + return TRUE; + } + + if (!meta_monitor_manager_is_config_applicable (manager, config, &error)) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_INVALID_ARGS, + error->message); + g_error_free (error); + g_object_unref (config); + return TRUE; + } + + if (!meta_monitor_manager_apply_monitors_config (manager, + config, + method, + &error)) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_INVALID_ARGS, + error->message); + g_error_free (error); + g_object_unref (config); + return TRUE; + } + + meta_dbus_display_config_complete_apply_monitors_config (skeleton, invocation); + + return TRUE; +} + +#undef MONITOR_MODE_SPEC_FORMAT +#undef MONITOR_CONFIG_FORMAT +#undef MONITOR_CONFIGS_FORMAT +#undef LOGICAL_MONITOR_CONFIG_FORMAT + static void legacy_confirm_configuration (MetaMonitorManager *manager, gboolean confirmed) @@ -1569,6 +1949,7 @@ meta_monitor_manager_display_config_init (MetaDBusDisplayConfigIface *iface) iface->handle_get_crtc_gamma = meta_monitor_manager_handle_get_crtc_gamma; iface->handle_set_crtc_gamma = meta_monitor_manager_handle_set_crtc_gamma; iface->handle_get_current_state = meta_monitor_manager_handle_get_current_state; + iface->handle_apply_monitors_config = meta_monitor_manager_handle_apply_monitors_config; } static void diff --git a/src/backends/native/meta-monitor-manager-kms.c b/src/backends/native/meta-monitor-manager-kms.c index 1866c3801..92be434e8 100644 --- a/src/backends/native/meta-monitor-manager-kms.c +++ b/src/backends/native/meta-monitor-manager-kms.c @@ -1424,9 +1424,10 @@ update_screen_size (MetaMonitorManager *manager, } static gboolean -meta_monitor_manager_kms_apply_monitors_config (MetaMonitorManager *manager, - MetaMonitorsConfig *config, - GError **error) +meta_monitor_manager_kms_apply_monitors_config (MetaMonitorManager *manager, + MetaMonitorsConfig *config, + MetaMonitorsConfigMethod method, + GError **error) { GPtrArray *crtc_infos; GPtrArray *output_infos; @@ -1444,6 +1445,13 @@ meta_monitor_manager_kms_apply_monitors_config (MetaMonitorManager *manager, error)) return FALSE; + if (method == META_MONITORS_CONFIG_METHOD_VERIFY) + { + g_ptr_array_free (crtc_infos, TRUE); + g_ptr_array_free (output_infos, TRUE); + return TRUE; + } + apply_crtc_assignments (manager, (MetaCrtcInfo **) crtc_infos->pdata, crtc_infos->len, diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c index 06d38cfa3..d0e520986 100644 --- a/src/backends/x11/meta-monitor-manager-xrandr.c +++ b/src/backends/x11/meta-monitor-manager-xrandr.c @@ -1300,9 +1300,10 @@ meta_monitor_manager_xrandr_ensure_initial_config (MetaMonitorManager *manager) } static gboolean -meta_monitor_manager_xrandr_apply_monitors_config (MetaMonitorManager *manager, - MetaMonitorsConfig *config, - GError **error) +meta_monitor_manager_xrandr_apply_monitors_config (MetaMonitorManager *manager, + MetaMonitorsConfig *config, + MetaMonitorsConfigMethod method, + GError **error) { GPtrArray *crtc_infos; GPtrArray *output_infos; @@ -1318,11 +1319,14 @@ meta_monitor_manager_xrandr_apply_monitors_config (MetaMonitorManager *manager, error)) return FALSE; - apply_crtc_assignments (manager, - (MetaCrtcInfo **) crtc_infos->pdata, - crtc_infos->len, - (MetaOutputInfo **) output_infos->pdata, - output_infos->len); + if (method != META_MONITORS_CONFIG_METHOD_VERIFY) + { + apply_crtc_assignments (manager, + (MetaCrtcInfo **) crtc_infos->pdata, + crtc_infos->len, + (MetaOutputInfo **) output_infos->pdata, + output_infos->len); + } g_ptr_array_free (crtc_infos, TRUE); g_ptr_array_free (output_infos, TRUE); diff --git a/src/org.gnome.Mutter.DisplayConfig.xml b/src/org.gnome.Mutter.DisplayConfig.xml index 60923a84c..43ffb28a7 100644 --- a/src/org.gnome.Mutter.DisplayConfig.xml +++ b/src/org.gnome.Mutter.DisplayConfig.xml @@ -359,5 +359,42 @@ + + + + + + + + diff --git a/src/tests/meta-monitor-manager-test.c b/src/tests/meta-monitor-manager-test.c index 14afcd91a..292abe7c5 100644 --- a/src/tests/meta-monitor-manager-test.c +++ b/src/tests/meta-monitor-manager-test.c @@ -256,9 +256,10 @@ update_screen_size (MetaMonitorManager *manager, } static gboolean -meta_monitor_manager_test_apply_monitors_config (MetaMonitorManager *manager, - MetaMonitorsConfig *config, - GError **error) +meta_monitor_manager_test_apply_monitors_config (MetaMonitorManager *manager, + MetaMonitorsConfig *config, + MetaMonitorsConfigMethod method, + GError **error) { GPtrArray *crtc_infos; GPtrArray *output_infos; @@ -280,6 +281,13 @@ meta_monitor_manager_test_apply_monitors_config (MetaMonitorManager *manager, error)) return FALSE; + if (method == META_MONITORS_CONFIG_METHOD_VERIFY) + { + g_ptr_array_free (crtc_infos, TRUE); + g_ptr_array_free (output_infos, TRUE); + return TRUE; + } + apply_crtc_assignments (manager, (MetaCrtcInfo **) crtc_infos->pdata, crtc_infos->len,