diff --git a/src/backends/meta-monitor-config.c b/src/backends/meta-monitor-config.c index 74239a3ed..81f0a5e54 100644 --- a/src/backends/meta-monitor-config.c +++ b/src/backends/meta-monitor-config.c @@ -34,6 +34,7 @@ #include "config.h" +#include "boxes-private.h" #include "meta-monitor-config.h" #include @@ -1096,6 +1097,55 @@ init_config_from_preferred_mode (MetaOutputConfig *config, config->is_presentation = FALSE; } +/* This function handles configuring the outputs when the driver provides a + * suggested layout position for each output. This is done in recent versions + * of qxl and allows displays to be aligned on the guest in the same order as + * they are aligned on the client. + */ +static gboolean +make_suggested_config (MetaMonitorConfig *self, + MetaOutput *outputs, + unsigned n_outputs, + int max_width, + int max_height, + MetaConfiguration *config) +{ + unsigned int i; + MetaOutput *primary; + GList *region = NULL; + + g_return_if_fail (config != NULL); + primary = find_primary_output (outputs, n_outputs); + + for (i = 0; i < n_outputs; i++) + { + gboolean is_primary = (&outputs[i] == primary); + + if (outputs[i].suggested_x < 0 || outputs[i].suggested_y < 0) + return FALSE; + + init_config_from_preferred_mode (&config->outputs[i], &outputs[i]); + config->outputs[i].is_primary = is_primary; + + config->outputs[i].rect.x = outputs[i].suggested_x; + config->outputs[i].rect.y = outputs[i].suggested_y; + + /* Reject the configuration if the suggested positions result in + * overlapping displays */ + if (meta_rectangle_overlaps_with_region (region, &config->outputs[i].rect)) + { + g_warning ("Overlapping outputs, rejecting suggested configuration"); + g_list_free (region); + return FALSE; + } + + region = g_list_prepend (region, &config->outputs[i].rect); + } + + g_list_free (region); + return TRUE; +} + static void make_linear_config (MetaMonitorConfig *self, MetaOutput *outputs, @@ -1228,6 +1278,9 @@ make_default_config (MetaMonitorConfig *self, return ret; } + if (make_suggested_config (self, outputs, n_outputs, max_width, max_height, ret)) + return ret; + if (use_stored_config && extend_stored_config (self, outputs, n_outputs, max_width, max_height, ret)) return ret; diff --git a/src/backends/meta-monitor-manager.h b/src/backends/meta-monitor-manager.h index 4d1b3b7e2..102759f7c 100644 --- a/src/backends/meta-monitor-manager.h +++ b/src/backends/meta-monitor-manager.h @@ -116,6 +116,8 @@ struct _MetaOutput /* get a new preferred mode on hotplug events, to handle dynamic guest resizing */ gboolean hotplug_mode_update; + gint suggested_x; + gint suggested_y; }; struct _MetaCRTC diff --git a/src/backends/native/meta-monitor-manager-kms.c b/src/backends/native/meta-monitor-manager-kms.c index 63344879b..c5285167c 100644 --- a/src/backends/native/meta-monitor-manager-kms.c +++ b/src/backends/native/meta-monitor-manager-kms.c @@ -415,6 +415,8 @@ meta_monitor_manager_kms_read_current (MetaMonitorManager *manager) meta_output->name = make_output_name (connector); meta_output->width_mm = connector->mmWidth; meta_output->height_mm = connector->mmHeight; + meta_output->suggested_x = -1; + meta_output->suggested_y = -1; switch (connector->subpixel) { diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c index 3fdfca24e..dd32bd4b6 100644 --- a/src/backends/x11/meta-monitor-manager-xrandr.c +++ b/src/backends/x11/meta-monitor-manager-xrandr.c @@ -139,6 +139,34 @@ meta_monitor_transform_from_xrandr_all (Rotation rotation) return ret; } +static gboolean +output_get_integer_property (MetaMonitorManagerXrandr *manager_xrandr, + MetaOutput *output, const char *propname, + gint *value) +{ + gboolean exists = FALSE; + Atom atom, actual_type; + int actual_format; + unsigned long nitems, bytes_after; + unsigned char *buffer; + + atom = XInternAtom (manager_xrandr->xdisplay, propname, False); + XRRGetOutputProperty (manager_xrandr->xdisplay, + (XID)output->winsys_id, + atom, + 0, G_MAXLONG, False, False, XA_INTEGER, + &actual_type, &actual_format, + &nitems, &bytes_after, &buffer); + + exists = (actual_type == XA_INTEGER && actual_format == 32 && nitems == 1); + + if (exists && value != NULL) + *value = ((int*)buffer)[0]; + + XFree (buffer); + return exists; +} + static gboolean output_get_property_exists (MetaMonitorManagerXrandr *manager_xrandr, MetaOutput *output, const char *propname) @@ -356,6 +384,28 @@ output_get_hotplug_mode_update (MetaMonitorManagerXrandr *manager_xrandr, return output_get_property_exists (manager_xrandr, output, "hotplug_mode_update"); } +static gint +output_get_suggested_x (MetaMonitorManagerXrandr *manager_xrandr, + MetaOutput *output) +{ + gint val; + if (output_get_integer_property (manager_xrandr, output, "suggested X", &val)) + return val; + + return -1; +} + +static gint +output_get_suggested_y (MetaMonitorManagerXrandr *manager_xrandr, + MetaOutput *output) +{ + gint val; + if (output_get_integer_property (manager_xrandr, output, "suggested Y", &val)) + return val; + + return -1; +} + static char * get_xmode_name (XRRModeInfo *xmode) { @@ -543,6 +593,8 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager) meta_output->height_mm = output->mm_height; meta_output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN; meta_output->hotplug_mode_update = output_get_hotplug_mode_update (manager_xrandr, meta_output); + meta_output->suggested_x = output_get_suggested_x (manager_xrandr, meta_output); + meta_output->suggested_y = output_get_suggested_y (manager_xrandr, meta_output); meta_output->n_modes = output->nmode; meta_output->modes = g_new0 (MetaMonitorMode *, meta_output->n_modes);