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
This commit is contained in:
Jonas Ådahl 2017-02-14 19:54:04 +08:00
parent 7eaeba520a
commit 691e7951ea
7 changed files with 485 additions and 30 deletions

View File

@ -501,6 +501,7 @@ update_screen_size (MetaMonitorManager *manager,
static gboolean
meta_monitor_manager_dummy_apply_monitors_config (MetaMonitorManager *manager,
MetaMonitorsConfig *config,
MetaMonitorsConfigMethod method,
GError **error)
{
GPtrArray *crtc_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,

View File

@ -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,
@ -318,6 +326,7 @@ struct _MetaMonitorManagerClass
gboolean (*apply_monitors_config) (MetaMonitorManager *,
MetaMonitorsConfig *,
MetaMonitorsConfigMethod ,
GError **);
void (*apply_configuration) (MetaMonitorManager *,

View File

@ -317,12 +317,13 @@ meta_monitor_manager_ensure_initial_config (MetaMonitorManager *manager)
static gboolean
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

View File

@ -1426,6 +1426,7 @@ update_screen_size (MetaMonitorManager *manager,
static gboolean
meta_monitor_manager_kms_apply_monitors_config (MetaMonitorManager *manager,
MetaMonitorsConfig *config,
MetaMonitorsConfigMethod method,
GError **error)
{
GPtrArray *crtc_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,

View File

@ -1302,6 +1302,7 @@ meta_monitor_manager_xrandr_ensure_initial_config (MetaMonitorManager *manager)
static gboolean
meta_monitor_manager_xrandr_apply_monitors_config (MetaMonitorManager *manager,
MetaMonitorsConfig *config,
MetaMonitorsConfigMethod method,
GError **error)
{
GPtrArray *crtc_infos;
@ -1318,11 +1319,14 @@ meta_monitor_manager_xrandr_apply_monitors_config (MetaMonitorManager *manager,
error))
return FALSE;
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);

View File

@ -359,5 +359,42 @@
<arg name="max_screen_size" direction="out" type="(ii)" />
<arg name="properties" direction="out" type="a{sv}" />
</method>
<!--
ApplyMonitorsConfig:
@serial: configuration serial
@method: configuration method
@logical_monitors: monitors configuration
@properties: properties
@method represents the way the configuration should be handled.
Possible methods:
0: verify
1: temporary
2: persistent
@logical_monitors consists of a list of logical monitor configurations.
Each logical monitor configuration consists of:
* i: layout x position
* i: layout y position
* d: scale
* b primary: true if this is the primary logical monitor
* a(siida{sv}): a list of monitors, each consisting of:
* s: connector
* (iid): monitor mode spec (resolution width, resolution height,
refresh rate)
* a{sv}: monitor properties, including:
- "enable_underscanning" (b): enable monitor underscanning;
may only be set when underscanning
is supported (see GetCurrentState).
-->
<method name="ApplyMonitorsConfig">
<arg name="serial" direction="in" type="u" />
<arg name="method" direction="in" type="u" />
<arg name="logical_monitors" direction="in" type="a(iidba(s(iid)a{sv}))" />
<arg name="properties" direction="in" type="a{sv}" />
</method>
</interface>
</node>

View File

@ -258,6 +258,7 @@ update_screen_size (MetaMonitorManager *manager,
static gboolean
meta_monitor_manager_test_apply_monitors_config (MetaMonitorManager *manager,
MetaMonitorsConfig *config,
MetaMonitorsConfigMethod method,
GError **error)
{
GPtrArray *crtc_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,