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
This commit is contained in:
parent
2bdd97e067
commit
3f9c5823cb
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -354,6 +354,8 @@ struct _MetaMonitorManager
|
||||
UpClient *up_client;
|
||||
|
||||
gulong experimental_features_changed_handler_id;
|
||||
|
||||
MetaMonitorSwitchConfigType current_switch_config;
|
||||
};
|
||||
|
||||
struct _MetaMonitorManagerClass
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user