From f6f5f624d4e1bf13a8368110f695a393bc47c739 Mon Sep 17 00:00:00 2001 From: Jonathon Jongsma Date: Mon, 10 Nov 2014 15:36:47 -0600 Subject: [PATCH] monitor-manager: Add support for suggested position for outputs In recent versions of the QXL driver, it may set "suggested X|Y" connector properties. These properties are used to indicate the position at which multiple displays should be aligned. If all outputs have a suggested position, the displays are arranged according to these positions, otherwise we fall back to the default configuration. At the moment, we trust that the driver has chosen sane values for the suggested position. --- src/backends/meta-monitor-config.c | 53 +++++++++++++++++++ src/backends/meta-monitor-manager.h | 2 + .../native/meta-monitor-manager-kms.c | 2 + .../x11/meta-monitor-manager-xrandr.c | 52 ++++++++++++++++++ 4 files changed, 109 insertions(+) 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);