[mutter] backends/x11: Move output code to its own file



commit e32d52b9b8eca6c82747afb59dea7d0464f435ee
Author: Jonas Ådahl <jadahl gmail com>
Date:   Tue Jul 4 18:42:16 2017 +0800

    backends/x11: Move output code to its own file
    
    Move code dealing with X11 MetaOutputs and related functionality to its
    own file. Eventually, a MetaOutputXrandr should be introduced, based on
    MetaOutput, and this commit is in preparation for that.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=785381

 src/Makefile.am                                |    2 +
 src/backends/x11/meta-monitor-manager-xrandr.c |  738 +---------------------
 src/backends/x11/meta-monitor-manager-xrandr.h |    4 +
 src/backends/x11/meta-output-xrandr.c          |  786 ++++++++++++++++++++++++
 src/backends/x11/meta-output-xrandr.h          |   42 ++
 5 files changed, 860 insertions(+), 712 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index afcbc3e..71a846a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -171,6 +171,8 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES =      \
        backends/x11/meta-input-settings-x11.h          \
        backends/x11/meta-monitor-manager-xrandr.c      \
        backends/x11/meta-monitor-manager-xrandr.h      \
+       backends/x11/meta-output-xrandr.c               \
+       backends/x11/meta-output-xrandr.h               \
        backends/x11/meta-renderer-x11.c                \
        backends/x11/meta-renderer-x11.h                \
        backends/x11/meta-stage-x11-nested.c            \
diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c
index 5f78c6a..f8eec04 100644
--- a/src/backends/x11/meta-monitor-manager-xrandr.c
+++ b/src/backends/x11/meta-monitor-manager-xrandr.c
@@ -32,11 +32,8 @@
 #include <math.h>
 #include <clutter/clutter.h>
 
-#include <X11/Xatom.h>
 #include <X11/Xlibint.h>
-#include <X11/extensions/Xrandr.h>
 #include <X11/extensions/dpms.h>
-#include <X11/extensions/extutil.h>
 #include <X11/Xlib-xcb.h>
 #include <xcb/randr.h>
 
@@ -47,6 +44,7 @@
 #include "backends/meta-monitor-config-manager.h"
 #include "backends/meta-logical-monitor.h"
 #include "backends/meta-output.h"
+#include "backends/x11/meta-output-xrandr.h"
 
 #define ALL_TRANSFORMS ((1 << (META_MONITOR_TRANSFORM_FLIPPED_270 + 1)) - 1)
 
@@ -91,6 +89,18 @@ typedef struct _MetaMonitorXrandrData
 GQuark quark_meta_monitor_xrandr_data;
 #endif /* HAVE_RANDR15 */
 
+Display *
+meta_monitor_manager_xrandr_get_xdisplay (MetaMonitorManagerXrandr *manager_xrandr)
+{
+  return manager_xrandr->xdisplay;
+}
+
+gboolean
+meta_monitor_manager_xrandr_has_randr15 (MetaMonitorManagerXrandr *manager_xrandr)
+{
+  return manager_xrandr->has_randr15;
+}
+
 static MetaMonitorTransform
 meta_monitor_transform_from_xrandr (Rotation rotation)
 {
@@ -162,226 +172,6 @@ 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)
-{
-  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, AnyPropertyType,
-                        &actual_type, &actual_format,
-                        &nitems, &bytes_after, &buffer);
-
-  exists = (actual_type != None);
-
-  XFree (buffer);
-  return exists;
-}
-
-static gboolean
-output_get_boolean_property (MetaMonitorManagerXrandr *manager_xrandr,
-                             MetaOutput *output, const char *propname)
-{
-  Atom atom, actual_type;
-  int actual_format;
-  unsigned long nitems, bytes_after;
-  g_autofree unsigned char *buffer = NULL;
-
-  atom = XInternAtom (manager_xrandr->xdisplay, propname, False);
-  XRRGetOutputProperty (manager_xrandr->xdisplay,
-                        (XID)output->winsys_id,
-                        atom,
-                        0, G_MAXLONG, False, False, XA_CARDINAL,
-                        &actual_type, &actual_format,
-                        &nitems, &bytes_after, &buffer);
-
-  if (actual_type != XA_CARDINAL || actual_format != 32 || nitems < 1)
-    return FALSE;
-
-  return ((int*)buffer)[0];
-}
-
-static gboolean
-output_get_presentation_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
-                                MetaOutput *output)
-{
-  return output_get_boolean_property (manager_xrandr, output, "_MUTTER_PRESENTATION_OUTPUT");
-}
-
-static gboolean
-output_get_underscanning_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
-                                 MetaOutput               *output)
-{
-  Atom atom, actual_type;
-  int actual_format;
-  unsigned long nitems, bytes_after;
-  g_autofree unsigned char *buffer = NULL;
-  g_autofree char *str = NULL;
-
-  atom = XInternAtom (manager_xrandr->xdisplay, "underscan", False);
-  XRRGetOutputProperty (manager_xrandr->xdisplay,
-                        (XID)output->winsys_id,
-                        atom,
-                        0, G_MAXLONG, False, False, XA_ATOM,
-                        &actual_type, &actual_format,
-                        &nitems, &bytes_after, &buffer);
-
-  if (actual_type != XA_ATOM || actual_format != 32 || nitems < 1)
-    return FALSE;
-
-  str = XGetAtomName (manager_xrandr->xdisplay, *(Atom *)buffer);
-  return (strcmp (str, "on") == 0);
-}
-
-static gboolean
-output_get_supports_underscanning_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
-                                          MetaOutput               *output)
-{
-  Atom atom, actual_type;
-  int actual_format, i;
-  unsigned long nitems, bytes_after;
-  g_autofree unsigned char *buffer = NULL;
-  XRRPropertyInfo *property_info;
-  Atom *values;
-  gboolean supports_underscanning = FALSE;
-
-  atom = XInternAtom (manager_xrandr->xdisplay, "underscan", False);
-  XRRGetOutputProperty (manager_xrandr->xdisplay,
-                        (XID)output->winsys_id,
-                        atom,
-                        0, G_MAXLONG, False, False, XA_ATOM,
-                        &actual_type, &actual_format,
-                        &nitems, &bytes_after, &buffer);
-
-  if (actual_type != XA_ATOM || actual_format != 32 || nitems < 1)
-    return FALSE;
-
-  property_info = XRRQueryOutputProperty (manager_xrandr->xdisplay,
-                                          (XID) output->winsys_id,
-                                          atom);
-  values = (Atom *) property_info->values;
-
-  for (i = 0; i < property_info->num_values; i++)
-    {
-      /* The output supports underscanning if "on" is a valid value
-       * for the underscan property.
-       */
-      char *name = XGetAtomName (manager_xrandr->xdisplay, values[i]);
-      if (strcmp (name, "on") == 0)
-        supports_underscanning = TRUE;
-
-      XFree (name);
-    }
-
-  XFree (property_info);
-
-  return supports_underscanning;
-}
-
-static int
-normalize_backlight (MetaOutput *output,
-                     int         hw_value)
-{
-  return round ((double)(hw_value - output->backlight_min) /
-                (output->backlight_max - output->backlight_min) * 100.0);
-}
-
-static int
-output_get_backlight_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
-                             MetaOutput               *output)
-{
-  int value = -1;
-  Atom atom, actual_type;
-  int actual_format;
-  unsigned long nitems, bytes_after;
-  g_autofree unsigned char *buffer = NULL;
-
-  atom = XInternAtom (manager_xrandr->xdisplay, "Backlight", 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);
-
-  if (actual_type != XA_INTEGER || actual_format != 32 || nitems < 1)
-    return FALSE;
-
-  value = ((int*)buffer)[0];
-  if (value > 0)
-    return normalize_backlight (output, value);
-  else
-    return -1;
-}
-
-static void
-output_get_backlight_limits_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
-                                    MetaOutput               *output)
-{
-  Atom atom;
-  xcb_connection_t *xcb_conn;
-  g_autofree xcb_randr_query_output_property_reply_t *reply = NULL;
-
-  atom = XInternAtom (manager_xrandr->xdisplay, "Backlight", False);
-
-  xcb_conn = XGetXCBConnection (manager_xrandr->xdisplay);
-  reply = xcb_randr_query_output_property_reply (xcb_conn,
-                                                 xcb_randr_query_output_property (xcb_conn,
-                                                                                  (xcb_randr_output_t) 
output->winsys_id,
-                                                                                  (xcb_atom_t) atom),
-                                                 NULL);
-
-  /* This can happen on systems without backlights. */
-  if (reply == NULL)
-    return;
-
-  if (!reply->range || reply->length != 2)
-    {
-      meta_verbose ("backlight %s was not range\n", output->name);
-      return;
-    }
-
-  int32_t *values = xcb_randr_query_output_property_valid_values (reply);
-  output->backlight_min = values[0];
-  output->backlight_max = values[1];
-}
-
 static int
 compare_outputs (const void *one,
                  const void *two)
@@ -391,342 +181,6 @@ compare_outputs (const void *one,
   return strcmp (o_one->name, o_two->name);
 }
 
-static guint8 *
-get_edid_property (Display  *dpy,
-                   RROutput  output,
-                   Atom      atom,
-                   gsize    *len)
-{
-  unsigned char *prop;
-  int actual_format;
-  unsigned long nitems, bytes_after;
-  Atom actual_type;
-  guint8 *result;
-
-  XRRGetOutputProperty (dpy, output, atom,
-                        0, 100, False, False,
-                        AnyPropertyType,
-                        &actual_type, &actual_format,
-                        &nitems, &bytes_after, &prop);
-
-  if (actual_type == XA_INTEGER && actual_format == 8)
-    {
-      result = g_memdup (prop, nitems);
-      if (len)
-        *len = nitems;
-    }
-  else
-    {
-      result = NULL;
-    }
-
-  XFree (prop);
-
-  return result;
-}
-
-static GBytes *
-read_output_edid (MetaMonitorManagerXrandr *manager_xrandr,
-                  XID                       winsys_id)
-{
-  Atom edid_atom;
-  guint8 *result;
-  gsize len;
-
-  edid_atom = XInternAtom (manager_xrandr->xdisplay, "EDID", FALSE);
-  result = get_edid_property (manager_xrandr->xdisplay, winsys_id, edid_atom, &len);
-
-  if (!result)
-    {
-      edid_atom = XInternAtom (manager_xrandr->xdisplay, "EDID_DATA", FALSE);
-      result = get_edid_property (manager_xrandr->xdisplay, winsys_id, edid_atom, &len);
-    }
-
-  if (result)
-    {
-      if (len > 0 && len % 128 == 0)
-        return g_bytes_new_take (result, len);
-      else
-        g_free (result);
-    }
-
-  return NULL;
-}
-
-static void
-output_get_tile_info (MetaMonitorManagerXrandr *manager_xrandr,
-                      MetaOutput *output)
-{
-  Atom tile_atom;
-  unsigned char *prop;
-  unsigned long nitems, bytes_after;
-  int actual_format;
-  Atom actual_type;
-
-  if (manager_xrandr->has_randr15 == FALSE)
-    return;
-
-  tile_atom = XInternAtom (manager_xrandr->xdisplay, "TILE", FALSE);
-  XRRGetOutputProperty (manager_xrandr->xdisplay,
-                        output->winsys_id,
-                        tile_atom, 0, 100, False,
-                        False, AnyPropertyType,
-                        &actual_type, &actual_format,
-                        &nitems, &bytes_after, &prop);
-
-  if (actual_type == XA_INTEGER && actual_format == 32 && nitems == 8)
-    {
-      long *values = (long *)prop;
-      output->tile_info.group_id = values[0];
-      output->tile_info.flags = values[1];
-      output->tile_info.max_h_tiles = values[2];
-      output->tile_info.max_v_tiles = values[3];
-      output->tile_info.loc_h_tile = values[4];
-      output->tile_info.loc_v_tile = values[5];
-      output->tile_info.tile_w = values[6];
-      output->tile_info.tile_h = values[7];
-    }
-  XFree (prop);
-}
-
-static gboolean
-output_get_hotplug_mode_update (MetaMonitorManagerXrandr *manager_xrandr,
-                                MetaOutput               *output)
-{
-  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 MetaConnectorType
-connector_type_from_atom (MetaMonitorManagerXrandr *manager_xrandr,
-                          Atom                      atom)
-{
-  Display *xdpy = manager_xrandr->xdisplay;
-
-  if (atom == XInternAtom (xdpy, "HDMI", True))
-    return META_CONNECTOR_TYPE_HDMIA;
-  if (atom == XInternAtom (xdpy, "VGA", True))
-    return META_CONNECTOR_TYPE_VGA;
-  /* Doesn't have a DRM equivalent, but means an internal panel.
-   * We could pick either LVDS or eDP here. */
-  if (atom == XInternAtom (xdpy, "Panel", True))
-    return META_CONNECTOR_TYPE_LVDS;
-  if (atom == XInternAtom (xdpy, "DVI", True) || atom == XInternAtom (xdpy, "DVI-I", True))
-    return META_CONNECTOR_TYPE_DVII;
-  if (atom == XInternAtom (xdpy, "DVI-A", True))
-    return META_CONNECTOR_TYPE_DVIA;
-  if (atom == XInternAtom (xdpy, "DVI-D", True))
-    return META_CONNECTOR_TYPE_DVID;
-  if (atom == XInternAtom (xdpy, "DisplayPort", True))
-    return META_CONNECTOR_TYPE_DisplayPort;
-
-  if (atom == XInternAtom (xdpy, "TV", True))
-    return META_CONNECTOR_TYPE_TV;
-  if (atom == XInternAtom (xdpy, "TV-Composite", True))
-    return META_CONNECTOR_TYPE_Composite;
-  if (atom == XInternAtom (xdpy, "TV-SVideo", True))
-    return META_CONNECTOR_TYPE_SVIDEO;
-  /* Another set of mismatches. */
-  if (atom == XInternAtom (xdpy, "TV-SCART", True))
-    return META_CONNECTOR_TYPE_TV;
-  if (atom == XInternAtom (xdpy, "TV-C4", True))
-    return META_CONNECTOR_TYPE_TV;
-
-  return META_CONNECTOR_TYPE_Unknown;
-}
-
-static MetaConnectorType
-output_get_connector_type_from_prop (MetaMonitorManagerXrandr *manager_xrandr,
-                                     MetaOutput               *output)
-{
-  Atom atom, actual_type, connector_type_atom;
-  int actual_format;
-  unsigned long nitems, bytes_after;
-  g_autofree unsigned char *buffer = NULL;
-
-  atom = XInternAtom (manager_xrandr->xdisplay, "ConnectorType", False);
-  XRRGetOutputProperty (manager_xrandr->xdisplay,
-                        (XID)output->winsys_id,
-                        atom,
-                        0, G_MAXLONG, False, False, XA_ATOM,
-                        &actual_type, &actual_format,
-                        &nitems, &bytes_after, &buffer);
-
-  if (actual_type != XA_ATOM || actual_format != 32 || nitems < 1)
-    return META_CONNECTOR_TYPE_Unknown;
-
-  connector_type_atom = ((Atom *) buffer)[0];
-  return connector_type_from_atom (manager_xrandr, connector_type_atom);
-}
-
-static MetaConnectorType
-output_get_connector_type_from_name (MetaMonitorManagerXrandr *manager_xrandr,
-                                     MetaOutput               *output)
-{
-  const char *name = output->name;
-
-  /* drmmode_display.c, which was copy/pasted across all the FOSS
-   * xf86-video-* drivers, seems to name its outputs based on the
-   * connector type, so look for that....
-   *
-   * SNA has its own naming scheme, because what else did you expect
-   * from SNA, but it's not too different, so we can thankfully use
-   * that with minor changes.
-   *
-   * http://cgit.freedesktop.org/xorg/xserver/tree/hw/xfree86/drivers/modesetting/drmmode_display.c#n953
-   * http://cgit.freedesktop.org/xorg/driver/xf86-video-intel/tree/src/sna/sna_display.c#n3486
-   */
-
-  if (g_str_has_prefix (name, "DVI"))
-    return META_CONNECTOR_TYPE_DVII;
-  if (g_str_has_prefix (name, "LVDS"))
-    return META_CONNECTOR_TYPE_LVDS;
-  if (g_str_has_prefix (name, "HDMI"))
-    return META_CONNECTOR_TYPE_HDMIA;
-  if (g_str_has_prefix (name, "VGA"))
-    return META_CONNECTOR_TYPE_VGA;
-  /* SNA uses DP, not DisplayPort. Test for both. */
-  if (g_str_has_prefix (name, "DP") || g_str_has_prefix (name, "DisplayPort"))
-    return META_CONNECTOR_TYPE_DisplayPort;
-  if (g_str_has_prefix (name, "eDP"))
-    return META_CONNECTOR_TYPE_eDP;
-  if (g_str_has_prefix (name, "Virtual"))
-    return META_CONNECTOR_TYPE_VIRTUAL;
-  if (g_str_has_prefix (name, "Composite"))
-    return META_CONNECTOR_TYPE_Composite;
-  if (g_str_has_prefix (name, "S-video"))
-    return META_CONNECTOR_TYPE_SVIDEO;
-  if (g_str_has_prefix (name, "TV"))
-    return META_CONNECTOR_TYPE_TV;
-  if (g_str_has_prefix (name, "CTV"))
-    return META_CONNECTOR_TYPE_Composite;
-  if (g_str_has_prefix (name, "DSI"))
-    return META_CONNECTOR_TYPE_DSI;
-  if (g_str_has_prefix (name, "DIN"))
-    return META_CONNECTOR_TYPE_9PinDIN;
-
-  return META_CONNECTOR_TYPE_Unknown;
-}
-
-static MetaConnectorType
-output_get_connector_type (MetaMonitorManagerXrandr *manager_xrandr,
-                           MetaOutput               *output)
-{
-  MetaConnectorType ret;
-
-  /* The "ConnectorType" property is considered mandatory since RandR 1.3,
-   * but none of the FOSS drivers support it, because we're a bunch of
-   * professional software developers.
-   *
-   * Try poking it first, without any expectations that it will work.
-   * If it's not there, we thankfully have other bonghits to try next.
-   */
-  ret = output_get_connector_type_from_prop (manager_xrandr, output);
-  if (ret != META_CONNECTOR_TYPE_Unknown)
-    return ret;
-
-  /* Fall back to heuristics based on the output name. */
-  ret = output_get_connector_type_from_name (manager_xrandr, output);
-  if (ret != META_CONNECTOR_TYPE_Unknown)
-    return ret;
-
-  return META_CONNECTOR_TYPE_Unknown;
-}
-
-static void
-output_get_modes (MetaMonitorManager *manager,
-                  MetaOutput         *output,
-                  XRROutputInfo      *xrandr_output)
-{
-  guint j;
-  guint n_actual_modes;
-
-  output->modes = g_new0 (MetaCrtcMode *, xrandr_output->nmode);
-
-  n_actual_modes = 0;
-  for (j = 0; j < (guint)xrandr_output->nmode; j++)
-    {
-      GList *l;
-
-      for (l = manager->modes; l; l = l->next)
-        {
-          MetaCrtcMode *mode = l->data;
-
-          if (xrandr_output->modes[j] == (XID) mode->mode_id)
-            {
-              output->modes[n_actual_modes] = mode;
-              n_actual_modes += 1;
-              break;
-            }
-        }
-    }
-  output->n_modes = n_actual_modes;
-  if (n_actual_modes > 0)
-    output->preferred_mode = output->modes[0];
-}
-
-static void
-output_get_crtcs (MetaMonitorManager *manager,
-                  MetaOutput         *output,
-                  XRROutputInfo      *xrandr_output)
-{
-  guint j;
-  guint n_actual_crtcs;
-  GList *l;
-
-  output->possible_crtcs = g_new0 (MetaCrtc *, xrandr_output->ncrtc);
-
-  n_actual_crtcs = 0;
-  for (j = 0; j < (unsigned) xrandr_output->ncrtc; j++)
-    {
-      for (l = manager->crtcs; l; l = l->next)
-        {
-          MetaCrtc *crtc = l->data;
-
-          if ((XID) crtc->crtc_id == xrandr_output->crtcs[j])
-            {
-              output->possible_crtcs[n_actual_crtcs] = crtc;
-              n_actual_crtcs += 1;
-              break;
-            }
-        }
-    }
-  output->n_possible_crtcs = n_actual_crtcs;
-
-  output->crtc = NULL;
-  for (l = manager->crtcs; l; l = l->next)
-    {
-      MetaCrtc *crtc = l->data;
-
-      if ((XID) crtc->crtc_id == xrandr_output->crtc)
-        {
-          output->crtc = crtc;
-          break;
-        }
-    }
-}
-
 static char *
 get_xmode_name (XRRModeInfo *xmode)
 {
@@ -864,70 +318,24 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
 
   for (i = 0; i < (unsigned)resources->noutput; i++)
     {
+      RROutput output_id;
       XRROutputInfo *xrandr_output;
-      MetaOutput *output;
 
+      output_id = resources->outputs[i];
       xrandr_output = XRRGetOutputInfo (manager_xrandr->xdisplay,
-                                        resources, resources->outputs[i]);
+                                        resources, output_id);
       if (!xrandr_output)
         continue;
 
-      output = g_object_new (META_TYPE_OUTPUT, NULL);
-      output->monitor_manager = manager;
-
       if (xrandr_output->connection != RR_Disconnected)
        {
-          GBytes *edid;
-
-         output->winsys_id = resources->outputs[i];
-         output->name = g_strdup (xrandr_output->name);
-
-          edid = read_output_edid (manager_xrandr, output->winsys_id);
-          meta_output_parse_edid (output, edid);
-          g_bytes_unref (edid);
-
-         output->width_mm = xrandr_output->mm_width;
-         output->height_mm = xrandr_output->mm_height;
-         output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
-          output->hotplug_mode_update =
-            output_get_hotplug_mode_update (manager_xrandr, output);
-         output->suggested_x = output_get_suggested_x (manager_xrandr, output);
-         output->suggested_y = output_get_suggested_y (manager_xrandr, output);
-          output->connector_type = output_get_connector_type (manager_xrandr,
-                                                              output);
-
-         output_get_tile_info (manager_xrandr, output);
-         output_get_modes (manager, output, xrandr_output);
-          output_get_crtcs (manager, output, xrandr_output);
-
-         output->n_possible_clones = xrandr_output->nclone;
-         output->possible_clones = g_new0 (MetaOutput *,
-                                            output->n_possible_clones);
-         /* We can build the list of clones now, because we don't have the list of outputs
-            yet, so temporarily set the pointers to the bare XIDs, and then we'll fix them
-            in a second pass
-         */
-         for (j = 0; j < (unsigned) xrandr_output->nclone; j++)
-           {
-             output->possible_clones[j] =
-                GINT_TO_POINTER (xrandr_output->clones[j]);
-           }
-
-         output->is_primary = ((XID) output->winsys_id == primary_output);
-         output->is_presentation = output_get_presentation_xrandr (manager_xrandr, output);
-         output->is_underscanning = output_get_underscanning_xrandr (manager_xrandr, output);
-          output->supports_underscanning =
-            output_get_supports_underscanning_xrandr (manager_xrandr, output);
-         output_get_backlight_limits_xrandr (manager_xrandr, output);
+          MetaOutput *output;
 
-         if (!(output->backlight_min == 0 && output->backlight_max == 0))
-           output->backlight = output_get_backlight_xrandr (manager_xrandr, output);
-         else
-           output->backlight = -1;
-
-          if (output->n_modes == 0 || output->n_possible_crtcs == 0)
-            g_object_unref (output);
-          else
+          output = meta_create_xrandr_output (manager,
+                                              xrandr_output,
+                                              output_id,
+                                              primary_output);
+          if (output)
             manager->outputs = g_list_prepend (manager->outputs, output);
        }
 
@@ -965,9 +373,7 @@ static GBytes *
 meta_monitor_manager_xrandr_read_edid (MetaMonitorManager *manager,
                                        MetaOutput         *output)
 {
-  MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
-
-  return read_output_edid (manager_xrandr, output->winsys_id);
+  return meta_output_xrandr_read_edid (output);
 }
 
 static void
@@ -1024,69 +430,6 @@ meta_monitor_transform_to_xrandr (MetaMonitorTransform transform)
   g_assert_not_reached ();
 }
 
-static void
-output_set_presentation_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
-                                MetaOutput               *output,
-                                gboolean                  presentation)
-{
-  Atom atom;
-  int value = presentation;
-
-  atom = XInternAtom (manager_xrandr->xdisplay, "_MUTTER_PRESENTATION_OUTPUT", False);
-
-  xcb_randr_change_output_property (XGetXCBConnection (manager_xrandr->xdisplay),
-                                    (XID)output->winsys_id,
-                                    atom, XCB_ATOM_CARDINAL, 32,
-                                    XCB_PROP_MODE_REPLACE,
-                                    1, &value);
-}
-
-static void
-output_set_underscanning_xrandr (MetaMonitorManagerXrandr *manager_xrandr,
-                                 MetaOutput               *output,
-                                 gboolean                  underscanning)
-{
-  Atom prop, valueatom;
-  const char *value;
-
-  prop = XInternAtom (manager_xrandr->xdisplay, "underscan", False);
-
-  value = underscanning ? "on" : "off";
-  valueatom = XInternAtom (manager_xrandr->xdisplay, value, False);
-
-  xcb_randr_change_output_property (XGetXCBConnection (manager_xrandr->xdisplay),
-                                    (XID)output->winsys_id,
-                                    prop, XCB_ATOM_ATOM, 32,
-                                    XCB_PROP_MODE_REPLACE,
-                                    1, &valueatom);
-
-  /* Configure the border at the same time. Currently, we use a
-   * 5% of the width/height of the mode. In the future, we should
-   * make the border configurable. */
-  if (underscanning)
-    {
-      uint32_t border_value;
-
-      prop = XInternAtom (manager_xrandr->xdisplay, "underscan hborder", False);
-      border_value = output->crtc->current_mode->width * 0.05;
-
-      xcb_randr_change_output_property (XGetXCBConnection (manager_xrandr->xdisplay),
-                                        (XID)output->winsys_id,
-                                        prop, XCB_ATOM_INTEGER, 32,
-                                        XCB_PROP_MODE_REPLACE,
-                                        1, &border_value);
-
-      prop = XInternAtom (manager_xrandr->xdisplay, "underscan vborder", False);
-      border_value = output->crtc->current_mode->height * 0.05;
-
-      xcb_randr_change_output_property (XGetXCBConnection (manager_xrandr->xdisplay),
-                                        (XID)output->winsys_id,
-                                        prop, XCB_ATOM_INTEGER, 32,
-                                        XCB_PROP_MODE_REPLACE,
-                                        1, &border_value);
-    }
-}
-
 static gboolean
 xrandr_set_crtc_config (MetaMonitorManagerXrandr *manager_xrandr,
                         gboolean                  save_timestamp,
@@ -1437,25 +780,11 @@ apply_crtc_assignments (MetaMonitorManager *manager,
       MetaOutputInfo *output_info = outputs[i];
       MetaOutput *output = output_info->output;
 
-      if (output_info->is_primary)
-        {
-          XRRSetOutputPrimary (manager_xrandr->xdisplay,
-                               DefaultRootWindow (manager_xrandr->xdisplay),
-                               (XID)output_info->output->winsys_id);
-        }
-
-      output_set_presentation_xrandr (manager_xrandr,
-                                      output_info->output,
-                                      output_info->is_presentation);
-
-      if (output_get_supports_underscanning_xrandr (manager_xrandr, output_info->output))
-        output_set_underscanning_xrandr (manager_xrandr,
-                                         output_info->output,
-                                         output_info->is_underscanning);
-
       output->is_primary = output_info->is_primary;
       output->is_presentation = output_info->is_presentation;
       output->is_underscanning = output_info->is_underscanning;
+
+      meta_output_xrandr_apply_mode (output);
     }
 
   /* Disable outputs not mentioned in the list */
@@ -1557,22 +886,7 @@ meta_monitor_manager_xrandr_change_backlight (MetaMonitorManager *manager,
                                              MetaOutput         *output,
                                              gint                value)
 {
-  MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
-  Atom atom;
-  int hw_value;
-
-  hw_value = round ((double)value / 100.0 * output->backlight_max + output->backlight_min);
-
-  atom = XInternAtom (manager_xrandr->xdisplay, "Backlight", False);
-
-  xcb_randr_change_output_property (XGetXCBConnection (manager_xrandr->xdisplay),
-                                    (XID)output->winsys_id,
-                                    atom, XCB_ATOM_INTEGER, 32,
-                                    XCB_PROP_MODE_REPLACE,
-                                    1, &hw_value);
-
-  /* We're not selecting for property notifies, so update the value immediately */
-  output->backlight = normalize_backlight (output, hw_value);
+  meta_output_xrandr_change_backlight (output, value);
 }
 
 static void
diff --git a/src/backends/x11/meta-monitor-manager-xrandr.h b/src/backends/x11/meta-monitor-manager-xrandr.h
index 3076e24..9f1d6ff 100644
--- a/src/backends/x11/meta-monitor-manager-xrandr.h
+++ b/src/backends/x11/meta-monitor-manager-xrandr.h
@@ -29,6 +29,10 @@
 G_DECLARE_FINAL_TYPE (MetaMonitorManagerXrandr, meta_monitor_manager_xrandr,
                       META, MONITOR_MANAGER_XRANDR, MetaMonitorManager)
 
+Display * meta_monitor_manager_xrandr_get_xdisplay (MetaMonitorManagerXrandr *manager_xrandr);
+
+gboolean meta_monitor_manager_xrandr_has_randr15 (MetaMonitorManagerXrandr *manager_xrandr);
+
 gboolean meta_monitor_manager_xrandr_handle_xevent (MetaMonitorManagerXrandr *manager,
                                                     XEvent                   *event);
 
diff --git a/src/backends/x11/meta-output-xrandr.c b/src/backends/x11/meta-output-xrandr.c
new file mode 100644
index 0000000..608c6b6
--- /dev/null
+++ b/src/backends/x11/meta-output-xrandr.c
@@ -0,0 +1,786 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/*
+ * Copyright (C) 2001, 2002 Havoc Pennington
+ * Copyright (C) 2001, 2002 Havoc Pennington
+ * Copyright (C) 2002, 2003 Red Hat Inc.
+ * Some ICCCM manager selection code derived from fvwm2,
+ * Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
+ * Copyright (C) 2003 Rob Adams
+ * Copyright (C) 2004-2006 Elijah Newren
+ * Copyright (C) 2002, 2003 Red Hat Inc.
+ * Some ICCCM manager selection code derived from fvwm2,
+ * Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
+ * Copyright (C) 2003 Rob Adams
+ * Copyright (C) 2004-2006 Elijah Newren
+ * Copyright (C) 2013-2017 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "backends/x11/meta-output-xrandr.h"
+
+#include <glib.h>
+#include <string.h>
+#include <X11/Xatom.h>
+#include <X11/Xlib-xcb.h>
+#include <xcb/randr.h>
+
+#include "backends/meta-crtc.h"
+#include "backends/x11/meta-monitor-manager-xrandr.h"
+#include "meta/util.h"
+
+static Display *
+xdisplay_from_output (MetaOutput *output)
+{
+  MetaMonitorManager *monitor_manager =
+    meta_output_get_monitor_manager (output);
+  MetaMonitorManagerXrandr *monitor_manager_xrandr =
+    META_MONITOR_MANAGER_XRANDR (monitor_manager);
+
+  return meta_monitor_manager_xrandr_get_xdisplay (monitor_manager_xrandr);
+}
+
+static void
+output_set_presentation_xrandr (MetaOutput *output,
+                                gboolean    presentation)
+{
+  Display *xdisplay = xdisplay_from_output (output);
+  Atom atom;
+  int value = presentation;
+
+  atom = XInternAtom (xdisplay, "_MUTTER_PRESENTATION_OUTPUT", False);
+
+  xcb_randr_change_output_property (XGetXCBConnection (xdisplay),
+                                    (XID) output->winsys_id,
+                                    atom, XCB_ATOM_CARDINAL, 32,
+                                    XCB_PROP_MODE_REPLACE,
+                                    1, &value);
+}
+
+static void
+output_set_underscanning_xrandr (MetaOutput *output,
+                                 gboolean    underscanning)
+{
+  Display *xdisplay = xdisplay_from_output (output);
+  Atom prop, valueatom;
+  const char *value;
+
+  prop = XInternAtom (xdisplay, "underscan", False);
+
+  value = underscanning ? "on" : "off";
+  valueatom = XInternAtom (xdisplay, value, False);
+
+  xcb_randr_change_output_property (XGetXCBConnection (xdisplay),
+                                    (XID) output->winsys_id,
+                                    prop, XCB_ATOM_ATOM, 32,
+                                    XCB_PROP_MODE_REPLACE,
+                                    1, &valueatom);
+
+  /* Configure the border at the same time. Currently, we use a
+   * 5% of the width/height of the mode. In the future, we should
+   * make the border configurable. */
+  if (underscanning)
+    {
+      uint32_t border_value;
+
+      prop = XInternAtom (xdisplay, "underscan hborder", False);
+      border_value = output->crtc->current_mode->width * 0.05;
+
+      xcb_randr_change_output_property (XGetXCBConnection (xdisplay),
+                                        (XID) output->winsys_id,
+                                        prop, XCB_ATOM_INTEGER, 32,
+                                        XCB_PROP_MODE_REPLACE,
+                                        1, &border_value);
+
+      prop = XInternAtom (xdisplay, "underscan vborder", False);
+      border_value = output->crtc->current_mode->height * 0.05;
+
+      xcb_randr_change_output_property (XGetXCBConnection (xdisplay),
+                                        (XID) output->winsys_id,
+                                        prop, XCB_ATOM_INTEGER, 32,
+                                        XCB_PROP_MODE_REPLACE,
+                                        1, &border_value);
+    }
+}
+
+void
+meta_output_xrandr_apply_mode (MetaOutput *output)
+{
+  Display *xdisplay = xdisplay_from_output (output);
+
+  if (output->is_primary)
+    {
+      XRRSetOutputPrimary (xdisplay, DefaultRootWindow (xdisplay),
+                           (XID) output->winsys_id);
+    }
+
+  output_set_presentation_xrandr (output, output->is_presentation);
+
+  if (output->supports_underscanning)
+    output_set_underscanning_xrandr (output, output->is_underscanning);
+}
+
+static int
+normalize_backlight (MetaOutput *output,
+                     int         hw_value)
+{
+  return round ((double)(hw_value - output->backlight_min) /
+                (output->backlight_max - output->backlight_min) * 100.0);
+}
+
+void
+meta_output_xrandr_change_backlight (MetaOutput *output,
+                                     int         value)
+{
+  Display *xdisplay = xdisplay_from_output (output);
+  Atom atom;
+  int hw_value;
+
+  hw_value = round ((double) value / 100.0 * output->backlight_max +
+                    output->backlight_min);
+
+  atom = XInternAtom (xdisplay, "Backlight", False);
+
+  xcb_randr_change_output_property (XGetXCBConnection (xdisplay),
+                                    (XID)output->winsys_id,
+                                    atom, XCB_ATOM_INTEGER, 32,
+                                    XCB_PROP_MODE_REPLACE,
+                                    1, &hw_value);
+
+  /* We're not selecting for property notifies, so update the value immediately */
+  output->backlight = normalize_backlight (output, hw_value);
+}
+
+static gboolean
+output_get_integer_property (MetaOutput *output,
+                             const char *propname,
+                             gint       *value)
+{
+  Display *xdisplay = xdisplay_from_output (output);
+  gboolean exists = FALSE;
+  Atom atom, actual_type;
+  int actual_format;
+  unsigned long nitems, bytes_after;
+  unsigned char *buffer;
+
+  atom = XInternAtom (xdisplay, propname, False);
+  XRRGetOutputProperty (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 (MetaOutput *output,
+                            const char *propname)
+{
+  Display *xdisplay = xdisplay_from_output (output);
+  gboolean exists = FALSE;
+  Atom atom, actual_type;
+  int actual_format;
+  unsigned long nitems, bytes_after;
+  unsigned char *buffer;
+
+  atom = XInternAtom (xdisplay, propname, False);
+  XRRGetOutputProperty (xdisplay,
+                        (XID)output->winsys_id,
+                        atom,
+                        0, G_MAXLONG, False, False, AnyPropertyType,
+                        &actual_type, &actual_format,
+                        &nitems, &bytes_after, &buffer);
+
+  exists = (actual_type != None);
+
+  XFree (buffer);
+  return exists;
+}
+
+static gboolean
+output_get_boolean_property (MetaOutput *output,
+                             const char *propname)
+{
+  Display *xdisplay = xdisplay_from_output (output);
+  Atom atom, actual_type;
+  int actual_format;
+  unsigned long nitems, bytes_after;
+  g_autofree unsigned char *buffer = NULL;
+
+  atom = XInternAtom (xdisplay, propname, False);
+  XRRGetOutputProperty (xdisplay,
+                        (XID)output->winsys_id,
+                        atom,
+                        0, G_MAXLONG, False, False, XA_CARDINAL,
+                        &actual_type, &actual_format,
+                        &nitems, &bytes_after, &buffer);
+
+  if (actual_type != XA_CARDINAL || actual_format != 32 || nitems < 1)
+    return FALSE;
+
+  return ((int*)buffer)[0];
+}
+
+static gboolean
+output_get_presentation_xrandr (MetaOutput *output)
+{
+  return output_get_boolean_property (output, "_MUTTER_PRESENTATION_OUTPUT");
+}
+
+static gboolean
+output_get_underscanning_xrandr (MetaOutput *output)
+{
+  Display *xdisplay = xdisplay_from_output (output);
+  Atom atom, actual_type;
+  int actual_format;
+  unsigned long nitems, bytes_after;
+  g_autofree unsigned char *buffer = NULL;
+  g_autofree char *str = NULL;
+
+  atom = XInternAtom (xdisplay, "underscan", False);
+  XRRGetOutputProperty (xdisplay,
+                        (XID)output->winsys_id,
+                        atom,
+                        0, G_MAXLONG, False, False, XA_ATOM,
+                        &actual_type, &actual_format,
+                        &nitems, &bytes_after, &buffer);
+
+  if (actual_type != XA_ATOM || actual_format != 32 || nitems < 1)
+    return FALSE;
+
+  str = XGetAtomName (xdisplay, *(Atom *)buffer);
+  return (strcmp (str, "on") == 0);
+}
+
+static gboolean
+output_get_supports_underscanning_xrandr (MetaOutput *output)
+{
+  Display *xdisplay = xdisplay_from_output (output);
+  Atom atom, actual_type;
+  int actual_format, i;
+  unsigned long nitems, bytes_after;
+  g_autofree unsigned char *buffer = NULL;
+  XRRPropertyInfo *property_info;
+  Atom *values;
+  gboolean supports_underscanning = FALSE;
+
+  atom = XInternAtom (xdisplay, "underscan", False);
+  XRRGetOutputProperty (xdisplay,
+                        (XID)output->winsys_id,
+                        atom,
+                        0, G_MAXLONG, False, False, XA_ATOM,
+                        &actual_type, &actual_format,
+                        &nitems, &bytes_after, &buffer);
+
+  if (actual_type != XA_ATOM || actual_format != 32 || nitems < 1)
+    return FALSE;
+
+  property_info = XRRQueryOutputProperty (xdisplay,
+                                          (XID) output->winsys_id,
+                                          atom);
+  values = (Atom *) property_info->values;
+
+  for (i = 0; i < property_info->num_values; i++)
+    {
+      /* The output supports underscanning if "on" is a valid value
+       * for the underscan property.
+       */
+      char *name = XGetAtomName (xdisplay, values[i]);
+      if (strcmp (name, "on") == 0)
+        supports_underscanning = TRUE;
+
+      XFree (name);
+    }
+
+  XFree (property_info);
+
+  return supports_underscanning;
+}
+
+static int
+output_get_backlight_xrandr (MetaOutput *output)
+{
+  Display *xdisplay = xdisplay_from_output (output);
+  int value = -1;
+  Atom atom, actual_type;
+  int actual_format;
+  unsigned long nitems, bytes_after;
+  g_autofree unsigned char *buffer = NULL;
+
+  atom = XInternAtom (xdisplay, "Backlight", False);
+  XRRGetOutputProperty (xdisplay,
+                        (XID)output->winsys_id,
+                        atom,
+                        0, G_MAXLONG, False, False, XA_INTEGER,
+                        &actual_type, &actual_format,
+                        &nitems, &bytes_after, &buffer);
+
+  if (actual_type != XA_INTEGER || actual_format != 32 || nitems < 1)
+    return FALSE;
+
+  value = ((int*)buffer)[0];
+  if (value > 0)
+    return normalize_backlight (output, value);
+  else
+    return -1;
+}
+
+static void
+output_get_backlight_limits_xrandr (MetaOutput *output)
+{
+  Display *xdisplay = xdisplay_from_output (output);
+  Atom atom;
+  xcb_connection_t *xcb_conn;
+  xcb_randr_query_output_property_cookie_t cookie;
+  g_autofree xcb_randr_query_output_property_reply_t *reply = NULL;
+
+  atom = XInternAtom (xdisplay, "Backlight", False);
+
+  xcb_conn = XGetXCBConnection (xdisplay);
+  cookie = xcb_randr_query_output_property (xcb_conn,
+                                            (xcb_randr_output_t) output->winsys_id,
+                                            (xcb_atom_t) atom);
+  reply = xcb_randr_query_output_property_reply (xcb_conn,
+                                                 cookie,
+                                                 NULL);
+
+  /* This can happen on systems without backlights. */
+  if (reply == NULL)
+    return;
+
+  if (!reply->range || reply->length != 2)
+    {
+      meta_verbose ("backlight %s was not range\n", output->name);
+      return;
+    }
+
+  int32_t *values = xcb_randr_query_output_property_valid_values (reply);
+  output->backlight_min = values[0];
+  output->backlight_max = values[1];
+}
+
+static guint8 *
+get_edid_property (Display  *xdisplay,
+                   RROutput  output,
+                   Atom      atom,
+                   gsize    *len)
+{
+  unsigned char *prop;
+  int actual_format;
+  unsigned long nitems, bytes_after;
+  Atom actual_type;
+  guint8 *result;
+
+  XRRGetOutputProperty (xdisplay, output, atom,
+                        0, 100, False, False,
+                        AnyPropertyType,
+                        &actual_type, &actual_format,
+                        &nitems, &bytes_after, &prop);
+
+  if (actual_type == XA_INTEGER && actual_format == 8)
+    {
+      result = g_memdup (prop, nitems);
+      if (len)
+        *len = nitems;
+    }
+  else
+    {
+      result = NULL;
+    }
+
+  XFree (prop);
+
+  return result;
+}
+
+GBytes *
+meta_output_xrandr_read_edid (MetaOutput *output)
+{
+  Display *xdisplay = xdisplay_from_output (output);
+  Atom edid_atom;
+  guint8 *result;
+  gsize len;
+
+  edid_atom = XInternAtom (xdisplay, "EDID", FALSE);
+  result = get_edid_property (xdisplay, output->winsys_id, edid_atom, &len);
+
+  if (!result)
+    {
+      edid_atom = XInternAtom (xdisplay, "EDID_DATA", FALSE);
+      result = get_edid_property (xdisplay, output->winsys_id, edid_atom, &len);
+    }
+
+  if (result)
+    {
+      if (len > 0 && len % 128 == 0)
+        return g_bytes_new_take (result, len);
+      else
+        g_free (result);
+    }
+
+  return NULL;
+}
+
+static gboolean
+output_get_hotplug_mode_update (MetaOutput *output)
+{
+  return output_get_property_exists (output, "hotplug_mode_update");
+}
+
+static gint
+output_get_suggested_x (MetaOutput *output)
+{
+  gint val;
+  if (output_get_integer_property (output, "suggested X", &val))
+    return val;
+
+  return -1;
+}
+
+static gint
+output_get_suggested_y (MetaOutput *output)
+{
+  gint val;
+  if (output_get_integer_property (output, "suggested Y", &val))
+    return val;
+
+  return -1;
+}
+
+static MetaConnectorType
+connector_type_from_atom (Display *xdisplay,
+                          Atom     atom)
+{
+  if (atom == XInternAtom (xdisplay, "HDMI", True))
+    return META_CONNECTOR_TYPE_HDMIA;
+  if (atom == XInternAtom (xdisplay, "VGA", True))
+    return META_CONNECTOR_TYPE_VGA;
+  /* Doesn't have a DRM equivalent, but means an internal panel.
+   * We could pick either LVDS or eDP here. */
+  if (atom == XInternAtom (xdisplay, "Panel", True))
+    return META_CONNECTOR_TYPE_LVDS;
+  if (atom == XInternAtom (xdisplay, "DVI", True) ||
+      atom == XInternAtom (xdisplay, "DVI-I", True))
+    return META_CONNECTOR_TYPE_DVII;
+  if (atom == XInternAtom (xdisplay, "DVI-A", True))
+    return META_CONNECTOR_TYPE_DVIA;
+  if (atom == XInternAtom (xdisplay, "DVI-D", True))
+    return META_CONNECTOR_TYPE_DVID;
+  if (atom == XInternAtom (xdisplay, "DisplayPort", True))
+    return META_CONNECTOR_TYPE_DisplayPort;
+
+  if (atom == XInternAtom (xdisplay, "TV", True))
+    return META_CONNECTOR_TYPE_TV;
+  if (atom == XInternAtom (xdisplay, "TV-Composite", True))
+    return META_CONNECTOR_TYPE_Composite;
+  if (atom == XInternAtom (xdisplay, "TV-SVideo", True))
+    return META_CONNECTOR_TYPE_SVIDEO;
+  /* Another set of mismatches. */
+  if (atom == XInternAtom (xdisplay, "TV-SCART", True))
+    return META_CONNECTOR_TYPE_TV;
+  if (atom == XInternAtom (xdisplay, "TV-C4", True))
+    return META_CONNECTOR_TYPE_TV;
+
+  return META_CONNECTOR_TYPE_Unknown;
+}
+
+static MetaConnectorType
+output_get_connector_type_from_prop (MetaOutput *output)
+{
+  Display *xdisplay = xdisplay_from_output (output);
+  Atom atom, actual_type, connector_type_atom;
+  int actual_format;
+  unsigned long nitems, bytes_after;
+  g_autofree unsigned char *buffer = NULL;
+
+  atom = XInternAtom (xdisplay, "ConnectorType", False);
+  XRRGetOutputProperty (xdisplay,
+                        (XID)output->winsys_id,
+                        atom,
+                        0, G_MAXLONG, False, False, XA_ATOM,
+                        &actual_type, &actual_format,
+                        &nitems, &bytes_after, &buffer);
+
+  if (actual_type != XA_ATOM || actual_format != 32 || nitems < 1)
+    return META_CONNECTOR_TYPE_Unknown;
+
+  connector_type_atom = ((Atom *) buffer)[0];
+  return connector_type_from_atom (xdisplay, connector_type_atom);
+}
+
+static MetaConnectorType
+output_get_connector_type_from_name (MetaOutput *output)
+{
+  const char *name = output->name;
+
+  /* drmmode_display.c, which was copy/pasted across all the FOSS
+   * xf86-video-* drivers, seems to name its outputs based on the
+   * connector type, so look for that....
+   *
+   * SNA has its own naming scheme, because what else did you expect
+   * from SNA, but it's not too different, so we can thankfully use
+   * that with minor changes.
+   *
+   * http://cgit.freedesktop.org/xorg/xserver/tree/hw/xfree86/drivers/modesetting/drmmode_display.c#n953
+   * http://cgit.freedesktop.org/xorg/driver/xf86-video-intel/tree/src/sna/sna_display.c#n3486
+   */
+
+  if (g_str_has_prefix (name, "DVI"))
+    return META_CONNECTOR_TYPE_DVII;
+  if (g_str_has_prefix (name, "LVDS"))
+    return META_CONNECTOR_TYPE_LVDS;
+  if (g_str_has_prefix (name, "HDMI"))
+    return META_CONNECTOR_TYPE_HDMIA;
+  if (g_str_has_prefix (name, "VGA"))
+    return META_CONNECTOR_TYPE_VGA;
+  /* SNA uses DP, not DisplayPort. Test for both. */
+  if (g_str_has_prefix (name, "DP") || g_str_has_prefix (name, "DisplayPort"))
+    return META_CONNECTOR_TYPE_DisplayPort;
+  if (g_str_has_prefix (name, "eDP"))
+    return META_CONNECTOR_TYPE_eDP;
+  if (g_str_has_prefix (name, "Virtual"))
+    return META_CONNECTOR_TYPE_VIRTUAL;
+  if (g_str_has_prefix (name, "Composite"))
+    return META_CONNECTOR_TYPE_Composite;
+  if (g_str_has_prefix (name, "S-video"))
+    return META_CONNECTOR_TYPE_SVIDEO;
+  if (g_str_has_prefix (name, "TV"))
+    return META_CONNECTOR_TYPE_TV;
+  if (g_str_has_prefix (name, "CTV"))
+    return META_CONNECTOR_TYPE_Composite;
+  if (g_str_has_prefix (name, "DSI"))
+    return META_CONNECTOR_TYPE_DSI;
+  if (g_str_has_prefix (name, "DIN"))
+    return META_CONNECTOR_TYPE_9PinDIN;
+
+  return META_CONNECTOR_TYPE_Unknown;
+}
+
+static MetaConnectorType
+output_get_connector_type (MetaOutput *output)
+{
+  MetaConnectorType ret;
+
+  /* The "ConnectorType" property is considered mandatory since RandR 1.3,
+   * but none of the FOSS drivers support it, because we're a bunch of
+   * professional software developers.
+   *
+   * Try poking it first, without any expectations that it will work.
+   * If it's not there, we thankfully have other bonghits to try next.
+   */
+  ret = output_get_connector_type_from_prop (output);
+  if (ret != META_CONNECTOR_TYPE_Unknown)
+    return ret;
+
+  /* Fall back to heuristics based on the output name. */
+  ret = output_get_connector_type_from_name (output);
+  if (ret != META_CONNECTOR_TYPE_Unknown)
+    return ret;
+
+  return META_CONNECTOR_TYPE_Unknown;
+}
+
+static void
+output_get_tile_info (MetaOutput *output)
+{
+  MetaMonitorManager *monitor_manager =
+    meta_output_get_monitor_manager (output);
+  MetaMonitorManagerXrandr *monitor_manager_xrandr =
+    META_MONITOR_MANAGER_XRANDR (monitor_manager);
+  Display *xdisplay = xdisplay_from_output (output);
+  Atom tile_atom;
+  unsigned char *prop;
+  unsigned long nitems, bytes_after;
+  int actual_format;
+  Atom actual_type;
+
+  if (!meta_monitor_manager_xrandr_has_randr15 (monitor_manager_xrandr))
+    return;
+
+  tile_atom = XInternAtom (xdisplay, "TILE", FALSE);
+  XRRGetOutputProperty (xdisplay,
+                        output->winsys_id,
+                        tile_atom, 0, 100, False,
+                        False, AnyPropertyType,
+                        &actual_type, &actual_format,
+                        &nitems, &bytes_after, &prop);
+
+  if (actual_type == XA_INTEGER && actual_format == 32 && nitems == 8)
+    {
+      long *values = (long *)prop;
+      output->tile_info.group_id = values[0];
+      output->tile_info.flags = values[1];
+      output->tile_info.max_h_tiles = values[2];
+      output->tile_info.max_v_tiles = values[3];
+      output->tile_info.loc_h_tile = values[4];
+      output->tile_info.loc_v_tile = values[5];
+      output->tile_info.tile_w = values[6];
+      output->tile_info.tile_h = values[7];
+    }
+  XFree (prop);
+}
+
+
+static void
+output_get_modes (MetaMonitorManager *monitor_manager,
+                  MetaOutput         *output,
+                  XRROutputInfo      *xrandr_output)
+{
+  unsigned int i;
+  unsigned int n_actual_modes;
+
+  output->modes = g_new0 (MetaCrtcMode *, xrandr_output->nmode);
+
+  n_actual_modes = 0;
+  for (i = 0; i < (unsigned int) xrandr_output->nmode; i++)
+    {
+      GList *l;
+
+      for (l = monitor_manager->modes; l; l = l->next)
+        {
+          MetaCrtcMode *mode = l->data;
+
+          if (xrandr_output->modes[i] == (XID) mode->mode_id)
+            {
+              output->modes[n_actual_modes] = mode;
+              n_actual_modes += 1;
+              break;
+            }
+        }
+    }
+  output->n_modes = n_actual_modes;
+  if (n_actual_modes > 0)
+    output->preferred_mode = output->modes[0];
+}
+
+static void
+output_get_crtcs (MetaMonitorManager *monitor_manager,
+                  MetaOutput         *output,
+                  XRROutputInfo      *xrandr_output)
+{
+  unsigned int i;
+  unsigned int n_actual_crtcs;
+  GList *l;
+
+  output->possible_crtcs = g_new0 (MetaCrtc *, xrandr_output->ncrtc);
+
+  n_actual_crtcs = 0;
+  for (i = 0; i < (unsigned int) xrandr_output->ncrtc; i++)
+    {
+      for (l = monitor_manager->crtcs; l; l = l->next)
+        {
+          MetaCrtc *crtc = l->data;
+
+          if ((XID) crtc->crtc_id == xrandr_output->crtcs[i])
+            {
+              output->possible_crtcs[n_actual_crtcs] = crtc;
+              n_actual_crtcs += 1;
+              break;
+            }
+        }
+    }
+  output->n_possible_crtcs = n_actual_crtcs;
+
+  output->crtc = NULL;
+  for (l = monitor_manager->crtcs; l; l = l->next)
+    {
+      MetaCrtc *crtc = l->data;
+
+      if ((XID) crtc->crtc_id == xrandr_output->crtc)
+        {
+          output->crtc = crtc;
+          break;
+        }
+    }
+}
+
+MetaOutput *
+meta_create_xrandr_output (MetaMonitorManager *monitor_manager,
+                           XRROutputInfo      *xrandr_output,
+                           RROutput            output_id,
+                           RROutput            primary_output)
+{
+  MetaOutput *output;
+  GBytes *edid;
+  unsigned int i;
+
+  output = g_object_new (META_TYPE_OUTPUT, NULL);
+  output->monitor_manager = monitor_manager;
+  output->winsys_id = output_id;
+  output->name = g_strdup (xrandr_output->name);
+
+  edid = meta_output_xrandr_read_edid (output);
+  meta_output_parse_edid (output, edid);
+  g_bytes_unref (edid);
+
+  output->width_mm = xrandr_output->mm_width;
+  output->height_mm = xrandr_output->mm_height;
+  output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
+  output->hotplug_mode_update = output_get_hotplug_mode_update (output);
+  output->suggested_x = output_get_suggested_x (output);
+  output->suggested_y = output_get_suggested_y (output);
+  output->connector_type = output_get_connector_type (output);
+
+  output_get_tile_info (output);
+  output_get_modes (monitor_manager, output, xrandr_output);
+  output_get_crtcs (monitor_manager, output, xrandr_output);
+
+  output->n_possible_clones = xrandr_output->nclone;
+  output->possible_clones = g_new0 (MetaOutput *,
+                                    output->n_possible_clones);
+  /*
+   * We can build the list of clones now, because we don't have the list of
+   * outputs yet, so temporarily set the pointers to the bare XIDs, and then
+   * we'll fix them in a second pass.
+   */
+  for (i = 0; i < (unsigned int) xrandr_output->nclone; i++)
+    {
+      output->possible_clones[i] = GINT_TO_POINTER (xrandr_output->clones[i]);
+    }
+
+  output->is_primary = ((XID) output->winsys_id == primary_output);
+  output->is_presentation = output_get_presentation_xrandr (output);
+  output->is_underscanning = output_get_underscanning_xrandr (output);
+  output->supports_underscanning =
+    output_get_supports_underscanning_xrandr (output);
+  output_get_backlight_limits_xrandr (output);
+
+  if (!(output->backlight_min == 0 && output->backlight_max == 0))
+    output->backlight = output_get_backlight_xrandr (output);
+  else
+    output->backlight = -1;
+
+  if (output->n_modes == 0 || output->n_possible_crtcs == 0)
+    {
+      g_object_unref (output);
+      return NULL;
+    }
+  else
+    {
+      return output;
+    }
+}
diff --git a/src/backends/x11/meta-output-xrandr.h b/src/backends/x11/meta-output-xrandr.h
new file mode 100644
index 0000000..3a263a4
--- /dev/null
+++ b/src/backends/x11/meta-output-xrandr.h
@@ -0,0 +1,42 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/*
+ * Copyright (C) 2017 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef META_OUTPUT_XRANDR
+#define META_OUTPUT_XRANDR
+
+#include <X11/extensions/Xrandr.h>
+
+#include "backends/meta-output.h"
+#include "backends/x11/meta-monitor-manager-xrandr.h"
+
+void meta_output_xrandr_apply_mode (MetaOutput *output);
+
+void meta_output_xrandr_change_backlight (MetaOutput *output,
+                                          int         value);
+
+GBytes * meta_output_xrandr_read_edid (MetaOutput *output);
+
+MetaOutput * meta_create_xrandr_output (MetaMonitorManager *monitor_manager,
+                                        XRROutputInfo      *xrandr_output,
+                                        RROutput            output_id,
+                                        RROutput            primary_output);
+
+#endif /* META_OUTPUT_XRANDR */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]