[mutter] backends: Add API to switch to predetermined monitor configurations
- From: Rui Matos <rtcm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter] backends: Add API to switch to predetermined monitor configurations
- Date: Wed, 19 Jul 2017 09:20:45 +0000 (UTC)
commit 3f9c5823cbb976e4cc1c56f39cea7f81469c8349
Author: Rui Matos <tiagomatos gmail com>
Date: Wed Jun 7 18:38:10 2017 +0200
backends: Add API to switch to predetermined monitor configurations
This will allows us to support the XF86Display key present on some
laptops, directly in mutter. This is also known, in evdev, as
KEY_SWITCHVIDEOMODE.
The common usage for this key is to alternate between a few well known
multi-monitor configurations though these aren't officially
standardized. As an example, Lenovo documents it as:
"Switches the display output location between the computer display
and an external monitor."
On this patch, we're just introducing the configurations that have been
implemented in g-s-d until now, which go a bit beyond the above
description.
https://bugzilla.gnome.org/show_bug.cgi?id=781906
src/backends/meta-monitor-config-manager.c | 199 ++++++++++++++++++++++++++
src/backends/meta-monitor-config-manager.h | 3 +
src/backends/meta-monitor-config.c | 201 ++++++++++++++++++++++++++-
src/backends/meta-monitor-config.h | 3 +
src/backends/meta-monitor-manager-private.h | 2 +
src/backends/meta-monitor-manager.c | 53 +++++++
src/meta/meta-monitor-manager.h | 16 ++
7 files changed, 474 insertions(+), 3 deletions(-)
---
diff --git a/src/backends/meta-monitor-config-manager.c b/src/backends/meta-monitor-config-manager.c
index 91ee2ba..6180b4e 100644
--- a/src/backends/meta-monitor-config-manager.c
+++ b/src/backends/meta-monitor-config-manager.c
@@ -751,6 +751,205 @@ meta_monitor_config_manager_create_for_rotate_monitor (MetaMonitorConfigManager
return create_for_builtin_display_rotation (config_manager, TRUE, META_MONITOR_TRANSFORM_NORMAL);
}
+static MetaMonitorsConfig *
+create_for_switch_config_all_mirror (MetaMonitorConfigManager *config_manager)
+{
+ MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
+ MetaLogicalMonitorConfig *logical_monitor_config = NULL;
+ GList *monitor_configs = NULL;
+ gint common_mode_w = 0, common_mode_h = 0;
+ float best_scale = 1.0;
+ MetaMonitor *monitor;
+ GList *modes;
+ GList *monitors;
+ GList *l;
+
+ monitors = meta_monitor_manager_get_monitors (monitor_manager);
+ monitor = monitors->data;
+ modes = meta_monitor_get_modes (monitor);
+ for (l = modes; l; l = l->next)
+ {
+ MetaMonitorMode *mode = l->data;
+ gboolean common_mode_size = TRUE;
+ gint mode_w, mode_h;
+ GList *ll;
+
+ meta_monitor_mode_get_resolution (mode, &mode_w, &mode_h);
+
+ for (ll = monitors->next; ll; ll = ll->next)
+ {
+ MetaMonitor *monitor_b = ll->data;
+ gboolean have_same_mode_size = FALSE;
+ GList *mm;
+
+ for (mm = meta_monitor_get_modes (monitor_b); mm; mm = mm->next)
+ {
+ MetaMonitorMode *mode_b = mm->data;
+ gint mode_b_w, mode_b_h;
+
+ meta_monitor_mode_get_resolution (mode_b, &mode_b_w, &mode_b_h);
+
+ if (mode_w == mode_b_w &&
+ mode_h == mode_b_h)
+ {
+ have_same_mode_size = TRUE;
+ break;
+ }
+ }
+
+ if (!have_same_mode_size)
+ {
+ common_mode_size = FALSE;
+ break;
+ }
+ }
+
+ if (common_mode_size &&
+ common_mode_w * common_mode_h < mode_w * mode_h)
+ {
+ common_mode_w = mode_w;
+ common_mode_h = mode_h;
+ }
+ }
+
+ if (common_mode_w == 0 || common_mode_h == 0)
+ return NULL;
+
+ for (l = monitors; l; l = l->next)
+ {
+ MetaMonitor *monitor = l->data;
+ MetaMonitorMode *mode = NULL;
+ GList *ll;
+ float scale;
+
+ for (ll = meta_monitor_get_modes (monitor); ll; ll = ll->next)
+ {
+ gint mode_w, mode_h;
+
+ mode = ll->data;
+ meta_monitor_mode_get_resolution (mode, &mode_w, &mode_h);
+
+ if (mode_w == common_mode_w && mode_h == common_mode_h)
+ break;
+ }
+
+ if (!mode)
+ continue;
+
+ scale = meta_monitor_manager_calculate_monitor_mode_scale (monitor_manager, monitor, mode);
+ best_scale = MAX (best_scale, scale);
+ monitor_configs = g_list_prepend (monitor_configs, create_monitor_config (monitor, mode));
+ }
+
+ logical_monitor_config = g_new0 (MetaLogicalMonitorConfig, 1);
+ *logical_monitor_config = (MetaLogicalMonitorConfig) {
+ .layout = (MetaRectangle) {
+ .x = 0,
+ .y = 0,
+ .width = common_mode_w,
+ .height = common_mode_h
+ },
+ .scale = best_scale,
+ .monitor_configs = monitor_configs
+ };
+
+ return meta_monitors_config_new (g_list_append (NULL, logical_monitor_config),
+ meta_monitor_manager_get_default_layout_mode (monitor_manager));
+}
+
+static MetaMonitorsConfig *
+create_for_switch_config_external (MetaMonitorConfigManager *config_manager)
+{
+ MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
+ GList *logical_monitor_configs = NULL;
+ int x = 0;
+ MetaLogicalMonitorLayoutMode layout_mode;
+ GList *monitors;
+ GList *l;
+
+ layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager);
+
+ monitors = meta_monitor_manager_get_monitors (monitor_manager);
+ for (l = monitors; l; l = l->next)
+ {
+ MetaMonitor *monitor = l->data;
+ MetaLogicalMonitorConfig *logical_monitor_config;
+
+ if (meta_monitor_is_laptop_panel (monitor))
+ continue;
+
+ logical_monitor_config =
+ create_preferred_logical_monitor_config (monitor_manager,
+ monitor,
+ x, 0,
+ NULL,
+ layout_mode);
+ logical_monitor_configs = g_list_append (logical_monitor_configs,
+ logical_monitor_config);
+
+ if (x == 0)
+ logical_monitor_config->is_primary = TRUE;
+
+ x += logical_monitor_config->layout.width;
+ }
+
+ return meta_monitors_config_new (logical_monitor_configs, layout_mode);
+}
+
+static MetaMonitorsConfig *
+create_for_switch_config_builtin (MetaMonitorConfigManager *config_manager)
+{
+ MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
+ MetaLogicalMonitorLayoutMode layout_mode;
+ GList *logical_monitor_configs;
+ MetaLogicalMonitorConfig *primary_logical_monitor_config;
+ MetaMonitor *monitor;
+
+ monitor = meta_monitor_manager_get_laptop_panel (monitor_manager);
+ if (!monitor)
+ return NULL;
+
+ layout_mode = meta_monitor_manager_get_default_layout_mode (monitor_manager);
+
+ primary_logical_monitor_config =
+ create_preferred_logical_monitor_config (monitor_manager,
+ monitor,
+ 0, 0,
+ NULL,
+ layout_mode);
+ primary_logical_monitor_config->is_primary = TRUE;
+ logical_monitor_configs = g_list_append (NULL,
+ primary_logical_monitor_config);
+
+ return meta_monitors_config_new (logical_monitor_configs, layout_mode);
+}
+
+MetaMonitorsConfig *
+meta_monitor_config_manager_create_for_switch_config (MetaMonitorConfigManager *config_manager,
+ MetaMonitorSwitchConfigType config_type)
+{
+ MetaMonitorManager *monitor_manager = config_manager->monitor_manager;
+
+ if (!meta_monitor_manager_can_switch_config (monitor_manager))
+ return NULL;
+
+ switch (config_type)
+ {
+ case META_MONITOR_SWITCH_CONFIG_ALL_MIRROR:
+ return create_for_switch_config_all_mirror (config_manager);
+ case META_MONITOR_SWITCH_CONFIG_ALL_LINEAR:
+ return meta_monitor_config_manager_create_linear (config_manager);
+ case META_MONITOR_SWITCH_CONFIG_EXTERNAL:
+ return create_for_switch_config_external (config_manager);
+ case META_MONITOR_SWITCH_CONFIG_BUILTIN:
+ return create_for_switch_config_builtin (config_manager);
+ case META_MONITOR_SWITCH_CONFIG_UNKNOWN:
+ g_warn_if_reached ();
+ break;
+ }
+ return NULL;
+}
+
void
meta_monitor_config_manager_set_current (MetaMonitorConfigManager *config_manager,
MetaMonitorsConfig *config)
diff --git a/src/backends/meta-monitor-config-manager.h b/src/backends/meta-monitor-config-manager.h
index c79084d..8f6f3dc 100644
--- a/src/backends/meta-monitor-config-manager.h
+++ b/src/backends/meta-monitor-config-manager.h
@@ -88,6 +88,9 @@ MetaMonitorsConfig * meta_monitor_config_manager_create_for_orientation (MetaMon
MetaMonitorsConfig * meta_monitor_config_manager_create_for_rotate_monitor (MetaMonitorConfigManager
*config_manager);
+MetaMonitorsConfig * meta_monitor_config_manager_create_for_switch_config (MetaMonitorConfigManager
*config_manager,
+ MetaMonitorSwitchConfigType
config_type);
+
void meta_monitor_config_manager_set_current (MetaMonitorConfigManager *config_manager,
MetaMonitorsConfig *config);
diff --git a/src/backends/meta-monitor-config.c b/src/backends/meta-monitor-config.c
index b527857..3ef3c62 100644
--- a/src/backends/meta-monitor-config.c
+++ b/src/backends/meta-monitor-config.c
@@ -1270,9 +1270,9 @@ make_linear_config (MetaMonitorConfig *self,
unsigned n_outputs,
int max_width,
int max_height,
- MetaConfiguration *config)
+ MetaConfiguration *config,
+ unsigned long output_configured_bitmap)
{
- unsigned long output_configured_bitmap = 0;
unsigned i;
int x;
int primary;
@@ -1409,7 +1409,7 @@ make_default_config (MetaMonitorConfig *self,
extend_stored_config (self, outputs, n_outputs, max_width, max_height, ret))
goto check_limits;
- make_linear_config (self, outputs, n_outputs, max_width, max_height, ret);
+ make_linear_config (self, outputs, n_outputs, max_width, max_height, ret, 0);
check_limits:
/* Disable outputs that would go beyond framebuffer limits */
@@ -1675,6 +1675,201 @@ meta_monitor_config_rotate_monitor (MetaMonitorConfig *self)
do_builtin_display_rotation (self, TRUE, META_MONITOR_TRANSFORM_NORMAL);
}
+static MetaConfiguration *
+make_all_mirror_config (MetaMonitorConfig *self,
+ MetaOutput *outputs,
+ guint n_outputs)
+{
+ MetaConfiguration *config;
+ gint common_width = 0;
+ gint common_height = 0;
+ guint i, j, k;
+
+ if (n_outputs < 2)
+ return NULL;
+
+ for (i = 0; i < outputs[0].n_modes; i++)
+ {
+ gboolean common_mode_size = TRUE;
+
+ for (j = 1; j < n_outputs; j++)
+ {
+ gboolean have_same_mode_size = FALSE;
+
+ for (k = 0; k < outputs[j].n_modes; k++)
+ {
+ if (outputs[j].modes[k]->width == outputs[0].modes[i]->width &&
+ outputs[j].modes[k]->height == outputs[0].modes[i]->height)
+ {
+ have_same_mode_size = TRUE;
+ break;
+ }
+ }
+
+ if (!have_same_mode_size)
+ {
+ common_mode_size = FALSE;
+ break;
+ }
+ }
+
+ if (common_mode_size &&
+ common_width * common_height < outputs[0].modes[i]->width * outputs[0].modes[i]->height)
+ {
+ common_width = outputs[0].modes[i]->width;
+ common_height = outputs[0].modes[i]->height;
+ }
+ }
+
+ if (common_width == 0 || common_height == 0)
+ return NULL;
+
+ config = config_new ();
+ make_config_key (config, outputs, n_outputs, -1);
+ config->outputs = g_new0 (MetaOutputConfig, n_outputs);
+
+ for (i = 0; i < n_outputs; i++)
+ {
+ init_config_from_preferred_mode (&config->outputs[i], &outputs[i]);
+ config->outputs[i].rect.width = common_width;
+ config->outputs[i].rect.height = common_height;
+ config->outputs[i].is_primary = TRUE;
+ }
+
+ return config;
+}
+
+static MetaConfiguration *
+make_all_linear_config (MetaMonitorConfig *self,
+ MetaOutput *outputs,
+ guint n_outputs,
+ gint max_width,
+ gint max_height)
+{
+ MetaConfiguration *config;
+
+ config = config_new ();
+ make_config_key (config, outputs, n_outputs, -1);
+ config->outputs = g_new0 (MetaOutputConfig, n_outputs);
+
+ make_linear_config (self, outputs, n_outputs, max_width, max_height, config, 0);
+
+ return config;
+}
+
+static MetaConfiguration *
+make_external_config (MetaMonitorConfig *self,
+ MetaOutput *outputs,
+ guint n_outputs,
+ gint max_width,
+ gint max_height)
+{
+ MetaConfiguration *config;
+ gulong bitmap;
+ guint i;
+
+ config = config_new ();
+ make_config_key (config, outputs, n_outputs, -1);
+ config->outputs = g_new0 (MetaOutputConfig, n_outputs);
+
+ bitmap = 0;
+ for (i = 0; i < n_outputs; i++)
+ if (meta_output_is_laptop (&outputs[i]))
+ {
+ bitmap = 1 << i;
+ break;
+ }
+
+ make_linear_config (self, outputs, n_outputs, max_width, max_height, config, bitmap);
+
+ return config;
+}
+
+static MetaConfiguration *
+make_builtin_config (MetaMonitorConfig *self,
+ MetaOutput *outputs,
+ guint n_outputs)
+{
+ MetaConfiguration *config;
+ gboolean have_builtin = FALSE;
+ guint i;
+
+ config = config_new ();
+ make_config_key (config, outputs, n_outputs, -1);
+ config->outputs = g_new0 (MetaOutputConfig, n_outputs);
+
+ for (i = 0; i < n_outputs; i++)
+ {
+ if (meta_output_is_laptop (&outputs[i]))
+ {
+ init_config_from_preferred_mode (&config->outputs[i], &outputs[i]);
+ config->outputs[i].is_primary = TRUE;
+ have_builtin = TRUE;
+ }
+ else
+ {
+ config->outputs[i].enabled = FALSE;
+ }
+ }
+
+ if (have_builtin)
+ return config;
+
+ config_unref (config);
+ return NULL;
+}
+
+gboolean
+meta_monitor_config_switch_config (MetaMonitorConfig *self,
+ MetaMonitorSwitchConfigType config_type)
+{
+ MetaBackend *backend = meta_get_backend ();
+ MetaMonitorManager *monitor_manager = meta_backend_get_monitor_manager (backend);
+ MetaConfiguration *new_config = NULL;
+ MetaOutput *outputs;
+ gint max_width, max_height;
+ guint n_outputs;
+ gboolean success;
+
+ if (!meta_monitor_manager_can_switch_config (monitor_manager))
+ return FALSE;
+
+ outputs = meta_monitor_manager_get_outputs (monitor_manager, &n_outputs);
+
+ if (!meta_monitor_manager_get_max_screen_size (monitor_manager, &max_width, &max_height))
+ {
+ max_width = 65535;
+ max_height = 65535;
+ }
+
+ switch (config_type)
+ {
+ case META_MONITOR_SWITCH_CONFIG_ALL_MIRROR:
+ new_config = make_all_mirror_config (self, outputs, n_outputs);
+ break;
+ case META_MONITOR_SWITCH_CONFIG_ALL_LINEAR:
+ new_config = make_all_linear_config (self, outputs, n_outputs, max_width, max_height);
+ break;
+ case META_MONITOR_SWITCH_CONFIG_EXTERNAL:
+ new_config = make_external_config (self, outputs, n_outputs, max_width, max_height);
+ break;
+ case META_MONITOR_SWITCH_CONFIG_BUILTIN:
+ new_config = make_builtin_config (self, outputs, n_outputs);
+ break;
+ case META_MONITOR_SWITCH_CONFIG_UNKNOWN:
+ g_warn_if_reached ();
+ break;
+ }
+
+ if (!new_config)
+ return FALSE;
+
+ success = apply_configuration (self, new_config, monitor_manager);
+ config_unref (new_config);
+
+ return success;
+}
+
typedef struct {
MetaMonitorConfig *config;
GString *buffer;
diff --git a/src/backends/meta-monitor-config.h b/src/backends/meta-monitor-config.h
index 4199570..86450dc 100644
--- a/src/backends/meta-monitor-config.h
+++ b/src/backends/meta-monitor-config.h
@@ -54,4 +54,7 @@ void meta_monitor_config_orientation_changed (MetaMonitorConfig
void meta_monitor_config_rotate_monitor (MetaMonitorConfig *self);
+gboolean meta_monitor_config_switch_config (MetaMonitorConfig *self,
+ MetaMonitorSwitchConfigType config_type);
+
#endif /* META_MONITOR_CONFIG_H */
diff --git a/src/backends/meta-monitor-manager-private.h b/src/backends/meta-monitor-manager-private.h
index 9fed7cf..3ba74f3 100644
--- a/src/backends/meta-monitor-manager-private.h
+++ b/src/backends/meta-monitor-manager-private.h
@@ -354,6 +354,8 @@ struct _MetaMonitorManager
UpClient *up_client;
gulong experimental_features_changed_handler_id;
+
+ MetaMonitorSwitchConfigType current_switch_config;
};
struct _MetaMonitorManagerClass
diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c
index 8112f29..12eb16d 100644
--- a/src/backends/meta-monitor-manager.c
+++ b/src/backends/meta-monitor-manager.c
@@ -730,6 +730,7 @@ meta_monitor_manager_constructed (GObject *object)
G_CALLBACK (orientation_changed),
manager, 0);
+ manager->current_switch_config = META_MONITOR_SWITCH_CONFIG_UNKNOWN;
manager->in_init = TRUE;
/*
@@ -2883,6 +2884,8 @@ meta_monitor_manager_notify_monitors_changed (MetaMonitorManager *manager)
{
MetaBackend *backend = meta_get_backend ();
+ manager->current_switch_config = META_MONITOR_SWITCH_CONFIG_UNKNOWN;
+
meta_backend_monitors_changed (backend);
g_signal_emit_by_name (manager, "monitors-changed");
}
@@ -3258,3 +3261,53 @@ meta_monitor_manager_rotate_monitor (MetaMonitorManager *manager)
g_object_unref (config);
}
}
+
+void
+meta_monitor_manager_switch_config (MetaMonitorManager *manager,
+ MetaMonitorSwitchConfigType config_type)
+{
+ g_return_if_fail (config_type != META_MONITOR_SWITCH_CONFIG_UNKNOWN);
+
+ if (!meta_is_monitor_config_manager_enabled ())
+ {
+ if (meta_monitor_config_switch_config (manager->legacy_config, config_type))
+ manager->current_switch_config = config_type;
+ }
+ else
+ {
+ GError *error = NULL;
+ MetaMonitorsConfig *config =
+ meta_monitor_config_manager_create_for_switch_config (manager->config_manager,
+ config_type);
+ if (!config)
+ return;
+
+ if (!meta_monitor_manager_apply_monitors_config (manager,
+ config,
+ META_MONITORS_CONFIG_METHOD_TEMPORARY,
+ &error))
+ {
+ g_warning ("Failed to use switch monitor configuration: %s",
+ error->message);
+ g_error_free (error);
+ }
+ else
+ {
+ manager->current_switch_config = config_type;
+ }
+ g_object_unref (config);
+ }
+}
+
+gboolean
+meta_monitor_manager_can_switch_config (MetaMonitorManager *manager)
+{
+ return (!meta_monitor_manager_is_lid_closed (manager) &&
+ g_list_length (manager->monitors) > 1);
+}
+
+MetaMonitorSwitchConfigType
+meta_monitor_manager_get_switch_config (MetaMonitorManager *manager)
+{
+ return manager->current_switch_config;
+}
diff --git a/src/meta/meta-monitor-manager.h b/src/meta/meta-monitor-manager.h
index da1e329..22f7349 100644
--- a/src/meta/meta-monitor-manager.h
+++ b/src/meta/meta-monitor-manager.h
@@ -24,6 +24,15 @@
#include <glib-object.h>
+typedef enum
+{
+ META_MONITOR_SWITCH_CONFIG_ALL_MIRROR,
+ META_MONITOR_SWITCH_CONFIG_ALL_LINEAR,
+ META_MONITOR_SWITCH_CONFIG_EXTERNAL,
+ META_MONITOR_SWITCH_CONFIG_BUILTIN,
+ META_MONITOR_SWITCH_CONFIG_UNKNOWN,
+} MetaMonitorSwitchConfigType;
+
typedef struct _MetaMonitorManagerClass MetaMonitorManagerClass;
typedef struct _MetaMonitorManager MetaMonitorManager;
@@ -39,4 +48,11 @@ gint meta_monitor_manager_get_monitor_for_connector (MetaMonitorManager *manager
gboolean meta_monitor_manager_get_is_builtin_display_on (MetaMonitorManager *manager);
+void meta_monitor_manager_switch_config (MetaMonitorManager *manager,
+ MetaMonitorSwitchConfigType config_type);
+
+gboolean meta_monitor_manager_can_switch_config (MetaMonitorManager *manager);
+
+MetaMonitorSwitchConfigType meta_monitor_manager_get_switch_config (MetaMonitorManager *manager);
+
#endif /* META_MONITOR_MANAGER_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]