[gnome-flashback] monitor-manager-xrandr: implement few vfuncs



commit 8fc514f013b1e1e2491b044ff28eb7f2c542fff9
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Wed Sep 20 20:58:30 2017 +0300

    monitor-manager-xrandr: implement few vfuncs

 backends/gf-monitor-manager-xrandr.c |  422 +++++++++++++++++++++++++++++++++-
 configure.ac                         |    2 +
 2 files changed, 416 insertions(+), 8 deletions(-)
---
diff --git a/backends/gf-monitor-manager-xrandr.c b/backends/gf-monitor-manager-xrandr.c
index ebd4bac..3f1e63e 100644
--- a/backends/gf-monitor-manager-xrandr.c
+++ b/backends/gf-monitor-manager-xrandr.c
@@ -26,15 +26,270 @@
  */
 
 #include "config.h"
+
+#include <string.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/Xrandr.h>
+#include <X11/extensions/dpms.h>
+
+#include "gf-backend-x11-private.h"
+#include "gf-crtc-private.h"
 #include "gf-monitor-manager-xrandr-private.h"
+#include "gf-monitor-private.h"
+#include "gf-monitor-tiled-private.h"
+#include "gf-output-private.h"
 
 struct _GfMonitorManagerXrandr
 {
-  GfMonitorManager parent;
+  GfMonitorManager    parent;
+
+  Display            *xdisplay;
+  Window              xroot;
+
+  gint                rr_event_base;
+  gint                rr_error_base;
+
+  gboolean            has_randr15;
+  GHashTable         *tiled_monitor_atoms;
+
+  XRRScreenResources *resources;
+
+  gint                max_screen_width;
+  gint                max_screen_height;
 };
 
+typedef struct
+{
+  Atom xrandr_name;
+} GfMonitorData;
+
 G_DEFINE_TYPE (GfMonitorManagerXrandr, gf_monitor_manager_xrandr, GF_TYPE_MONITOR_MANAGER)
 
+static guint8 *
+get_edid_property (Display  *xdisplay,
+                   RROutput  output,
+                   Atom      atom,
+                   gsize    *len)
+{
+  guchar *prop;
+  gint actual_format;
+  gulong 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;
+    }
+
+  if (prop)
+    XFree (prop);
+
+  return result;
+}
+
+static GBytes *
+read_output_edid (GfMonitorManagerXrandr *xrandr,
+                  XID                     winsys_id)
+{
+  Atom edid_atom;
+  guint8 *result;
+  gsize len;
+
+  edid_atom = XInternAtom (xrandr->xdisplay, "EDID", FALSE);
+  result = get_edid_property (xrandr->xdisplay, winsys_id, edid_atom, &len);
+
+  if (!result)
+    {
+      edid_atom = XInternAtom (xrandr->xdisplay, "EDID_DATA", FALSE);
+      result = get_edid_property (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 GQuark
+gf_monitor_data_quark (void)
+{
+  static GQuark quark;
+
+  if (G_UNLIKELY (quark == 0))
+    quark = g_quark_from_static_string ("gf-monitor-data-quark");
+
+  return quark;
+}
+
+static GfMonitorData *
+data_from_monitor (GfMonitor *monitor)
+{
+  GfMonitorData *data;
+  GQuark quark;
+
+  quark = gf_monitor_data_quark ();
+  data = g_object_get_qdata (G_OBJECT (monitor), quark);
+
+  if (data)
+    return data;
+
+  data = g_new0 (GfMonitorData, 1);
+  g_object_set_qdata_full (G_OBJECT (monitor), quark, data, g_free);
+
+  return data;
+}
+
+static void
+increase_monitor_count (GfMonitorManagerXrandr *xrandr,
+                        Atom                    name_atom)
+{
+  GHashTable *atoms;
+  gpointer key;
+  gint count;
+
+  atoms = xrandr->tiled_monitor_atoms;
+  key = GSIZE_TO_POINTER (name_atom);
+
+  count = GPOINTER_TO_INT (g_hash_table_lookup (atoms, key));
+  count++;
+
+  g_hash_table_insert (atoms, key, GINT_TO_POINTER (count));
+}
+
+static gint
+decrease_monitor_count (GfMonitorManagerXrandr *xrandr,
+                        Atom                    name_atom)
+{
+  GHashTable *atoms;
+  gpointer key;
+  gint count;
+
+  atoms = xrandr->tiled_monitor_atoms;
+  key = GSIZE_TO_POINTER (name_atom);
+
+  count = GPOINTER_TO_SIZE (g_hash_table_lookup (atoms, key));
+  count--;
+
+  g_hash_table_insert (atoms, key, GINT_TO_POINTER (count));
+
+  return count;
+}
+
+static void
+init_monitors (GfMonitorManagerXrandr *xrandr)
+{
+  XRRMonitorInfo *m;
+  gint n, i;
+
+  if (xrandr->has_randr15 == FALSE)
+    return;
+
+  /* Delete any tiled monitors setup, as gnome-fashback will want to
+   * recreate things in its image.
+   */
+  m = XRRGetMonitors (xrandr->xdisplay, xrandr->xroot, FALSE, &n);
+
+  if (n == -1)
+    return;
+
+  for (i = 0; i < n; i++)
+    {
+      if (m[i].noutput > 1)
+        {
+          XRRDeleteMonitor (xrandr->xdisplay, xrandr->xroot, m[i].name);
+        }
+    }
+
+  XRRFreeMonitors (m);
+}
+
+static void
+gf_monitor_manager_xrandr_constructed (GObject *object)
+{
+  GfMonitorManagerXrandr *xrandr;
+  GfBackend *backend;
+  gint rr_event_base;
+  gint rr_error_base;
+
+  xrandr = GF_MONITOR_MANAGER_XRANDR (object);
+  backend = gf_monitor_manager_get_backend (GF_MONITOR_MANAGER (xrandr));
+
+  xrandr->xdisplay = gf_backend_x11_get_xdisplay (GF_BACKEND_X11 (backend));
+  xrandr->xroot = DefaultRootWindow (xrandr->xdisplay);
+
+  if (XRRQueryExtension (xrandr->xdisplay, &rr_event_base, &rr_error_base))
+    {
+      gint major_version;
+      gint minor_version;
+
+      xrandr->rr_event_base = rr_event_base;
+      xrandr->rr_error_base = rr_error_base;
+
+      /* We only use ScreenChangeNotify, but GDK uses the others,
+       * and we don't want to step on its toes.
+       */
+      XRRSelectInput (xrandr->xdisplay, xrandr->xroot,
+                      RRScreenChangeNotifyMask |
+                      RRCrtcChangeNotifyMask |
+                      RROutputPropertyNotifyMask);
+
+      XRRQueryVersion (xrandr->xdisplay, &major_version, &minor_version);
+
+      xrandr->has_randr15 = FALSE;
+      if (major_version > 1 || (major_version == 1 && minor_version >= 5))
+        {
+          xrandr->has_randr15 = TRUE;
+          xrandr->tiled_monitor_atoms = g_hash_table_new (NULL, NULL);
+        }
+
+      init_monitors (xrandr);
+    }
+
+  G_OBJECT_CLASS (gf_monitor_manager_xrandr_parent_class)->constructed (object);
+}
+
+static void
+gf_monitor_manager_xrandr_dispose (GObject *object)
+{
+  GfMonitorManagerXrandr *xrandr;
+
+  xrandr = GF_MONITOR_MANAGER_XRANDR (object);
+
+  g_clear_pointer (&xrandr->tiled_monitor_atoms, g_hash_table_destroy);
+
+  G_OBJECT_CLASS (gf_monitor_manager_xrandr_parent_class)->dispose (object);
+}
+
+static void
+gf_monitor_manager_xrandr_finalize (GObject *object)
+{
+  GfMonitorManagerXrandr *xrandr;
+
+  xrandr = GF_MONITOR_MANAGER_XRANDR (object);
+
+  g_clear_pointer (&xrandr->resources, XRRFreeScreenResources);
+
+  G_OBJECT_CLASS (gf_monitor_manager_xrandr_parent_class)->finalize (object);
+}
+
 static void
 gf_monitor_manager_xrandr_read_current (GfMonitorManager *manager)
 {
@@ -44,7 +299,11 @@ static GBytes *
 gf_monitor_manager_xrandr_read_edid (GfMonitorManager *manager,
                                      GfOutput         *output)
 {
-  return NULL;
+  GfMonitorManagerXrandr *xrandr;
+
+  xrandr = GF_MONITOR_MANAGER_XRANDR (manager);
+
+  return read_output_edid (xrandr, output->winsys_id);
 }
 
 static void
@@ -66,6 +325,36 @@ static void
 gf_monitor_manager_xrandr_set_power_save_mode (GfMonitorManager *manager,
                                                GfPowerSave       mode)
 {
+  GfMonitorManagerXrandr *xrandr;
+  CARD16 state;
+
+  xrandr = GF_MONITOR_MANAGER_XRANDR (manager);
+
+  switch (mode)
+    {
+      case GF_POWER_SAVE_ON:
+        state = DPMSModeOn;
+        break;
+
+      case GF_POWER_SAVE_STANDBY:
+        state = DPMSModeStandby;
+        break;
+
+      case GF_POWER_SAVE_SUSPEND:
+        state = DPMSModeSuspend;
+        break;
+
+      case GF_POWER_SAVE_OFF:
+        state = DPMSModeOff;
+        break;
+
+      case GF_POWER_SAVE_UNSUPPORTED:
+      default:
+        return;
+    }
+
+  DPMSForceLevel (xrandr->xdisplay, state);
+  DPMSSetTimeouts (xrandr->xdisplay, 0, 0, 0);
 }
 
 static void
@@ -83,6 +372,18 @@ gf_monitor_manager_xrandr_get_crtc_gamma (GfMonitorManager  *manager,
                                           gushort          **green,
                                           gushort          **blue)
 {
+  GfMonitorManagerXrandr *xrandr;
+  XRRCrtcGamma *gamma;
+
+  xrandr = GF_MONITOR_MANAGER_XRANDR (manager);
+  gamma = XRRGetCrtcGamma (xrandr->xdisplay, (XID) crtc->crtc_id);
+
+  *size = gamma->size;
+  *red = g_memdup (gamma->red, sizeof (gushort) * gamma->size);
+  *green = g_memdup (gamma->green, sizeof (gushort) * gamma->size);
+  *blue = g_memdup (gamma->blue, sizeof (gushort) * gamma->size);
+
+  XRRFreeGamma (gamma);
 }
 
 static void
@@ -93,18 +394,96 @@ gf_monitor_manager_xrandr_set_crtc_gamma (GfMonitorManager *manager,
                                           gushort          *green,
                                           gushort          *blue)
 {
+  GfMonitorManagerXrandr *xrandr;
+  XRRCrtcGamma *gamma;
+
+  xrandr = GF_MONITOR_MANAGER_XRANDR (manager);
+
+  gamma = XRRAllocGamma (size);
+  memcpy (gamma->red, red, sizeof (gushort) * size);
+  memcpy (gamma->green, green, sizeof (gushort) * size);
+  memcpy (gamma->blue, blue, sizeof (gushort) * size);
+
+  XRRSetCrtcGamma (xrandr->xdisplay, (XID) crtc->crtc_id, gamma);
+  XRRFreeGamma (gamma);
 }
 
 static void
 gf_monitor_manager_xrandr_tiled_monitor_added (GfMonitorManager *manager,
                                                GfMonitor        *monitor)
 {
+  GfMonitorManagerXrandr *xrandr;
+  GfMonitorTiled *monitor_tiled;
+  const gchar *product;
+  uint32_t tile_group_id;
+  gchar *name;
+  Atom name_atom;
+  GfMonitorData *data;
+  GList *outputs;
+  XRRMonitorInfo *monitor_info;
+  GList *l;
+  gint i;
+
+  xrandr = GF_MONITOR_MANAGER_XRANDR (manager);
+
+  if (xrandr->has_randr15 == FALSE)
+    return;
+
+  monitor_tiled = GF_MONITOR_TILED (monitor);
+  product = gf_monitor_get_product (monitor);
+  tile_group_id = gf_monitor_tiled_get_tile_group_id (monitor_tiled);
+
+  if (product)
+    name = g_strdup_printf ("%s-%d", product, tile_group_id);
+  else
+    name = g_strdup_printf ("Tiled-%d", tile_group_id);
+
+  name_atom = XInternAtom (xrandr->xdisplay, name, False);
+  g_free (name);
+
+  data = data_from_monitor (monitor);
+  data->xrandr_name = name_atom;
+
+  increase_monitor_count (xrandr, name_atom);
+
+  outputs = gf_monitor_get_outputs (monitor);
+  monitor_info = XRRAllocateMonitor (xrandr->xdisplay, g_list_length (outputs));
+
+  monitor_info->name = name_atom;
+  monitor_info->primary = gf_monitor_is_primary (monitor);
+  monitor_info->automatic = True;
+
+  for (l = outputs, i = 0; l; l = l->next, i++)
+    {
+      GfOutput *output = l->data;
+
+      monitor_info->outputs[i] = output->winsys_id;
+    }
+
+  XRRSetMonitor (xrandr->xdisplay, xrandr->xroot, monitor_info);
+  XRRFreeMonitors (monitor_info);
 }
 
 static void
 gf_monitor_manager_xrandr_tiled_monitor_removed (GfMonitorManager *manager,
                                                  GfMonitor        *monitor)
 {
+  GfMonitorManagerXrandr *xrandr;
+  GfMonitorData *data;
+  gint monitor_count;
+
+  xrandr = GF_MONITOR_MANAGER_XRANDR (manager);
+
+  if (xrandr->has_randr15 == FALSE)
+    return;
+
+  data = data_from_monitor (monitor);
+  monitor_count = decrease_monitor_count (xrandr, data->xrandr_name);
+
+  if (monitor_count == 0)
+    {
+      XRRDeleteMonitor (xrandr->xdisplay, xrandr->xroot, data->xrandr_name);
+    }
 }
 
 static gboolean
@@ -112,7 +491,9 @@ gf_monitor_manager_xrandr_is_transform_handled (GfMonitorManager   *manager,
                                                 GfCrtc             *crtc,
                                                 GfMonitorTransform  transform)
 {
-  return FALSE;
+  g_warn_if_fail ((crtc->all_transforms & transform) == transform);
+
+  return TRUE;
 }
 
 static gfloat
@@ -120,7 +501,7 @@ gf_monitor_manager_xrandr_calculate_monitor_mode_scale (GfMonitorManager *manage
                                                         GfMonitor        *monitor,
                                                         GfMonitorMode    *monitor_mode)
 {
-  return 1.0;
+  return gf_monitor_calculate_mode_scale (monitor, monitor_mode);
 }
 
 static gfloat *
@@ -130,14 +511,26 @@ gf_monitor_manager_xrandr_calculate_supported_scales (GfMonitorManager
                                                       GfMonitorMode              *monitor_mode,
                                                       gint                       *n_supported_scales)
 {
-  *n_supported_scales = 0;
-  return NULL;
+  GfMonitorScalesConstraint constraints;
+
+  constraints = GF_MONITOR_SCALES_CONSTRAINT_NO_FRAC;
+
+  return gf_monitor_calculate_supported_scales (monitor, monitor_mode,
+                                                constraints,
+                                                n_supported_scales);
 }
 
 static GfMonitorManagerCapability
 gf_monitor_manager_xrandr_get_capabilities (GfMonitorManager *manager)
 {
-  return GF_MONITOR_MANAGER_CAPABILITY_NONE;
+  GfMonitorManagerCapability capabilities;
+
+  capabilities = GF_MONITOR_MANAGER_CAPABILITY_NONE;
+
+  capabilities |= GF_MONITOR_MANAGER_CAPABILITY_MIRRORING;
+  capabilities |= GF_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED;
+
+  return capabilities;
 }
 
 static gboolean
@@ -145,7 +538,14 @@ gf_monitor_manager_xrandr_get_max_screen_size (GfMonitorManager *manager,
                                                gint             *max_width,
                                                gint             *max_height)
 {
-  return FALSE;
+  GfMonitorManagerXrandr *xrandr;
+
+  xrandr = GF_MONITOR_MANAGER_XRANDR (manager);
+
+  *max_width = xrandr->max_screen_width;
+  *max_height = xrandr->max_screen_height;
+
+  return TRUE;
 }
 
 static GfLogicalMonitorLayoutMode
@@ -157,10 +557,16 @@ gf_monitor_manager_xrandr_get_default_layout_mode (GfMonitorManager *manager)
 static void
 gf_monitor_manager_xrandr_class_init (GfMonitorManagerXrandrClass *xrandr_class)
 {
+  GObjectClass *object_class;
   GfMonitorManagerClass *manager_class;
 
+  object_class = G_OBJECT_CLASS (xrandr_class);
   manager_class = GF_MONITOR_MANAGER_CLASS (xrandr_class);
 
+  object_class->constructed = gf_monitor_manager_xrandr_constructed;
+  object_class->dispose = gf_monitor_manager_xrandr_dispose;
+  object_class->finalize = gf_monitor_manager_xrandr_finalize;
+
   manager_class->read_current = gf_monitor_manager_xrandr_read_current;
   manager_class->read_edid = gf_monitor_manager_xrandr_read_edid;
   manager_class->ensure_initial_config = gf_monitor_manager_xrandr_ensure_initial_config;
diff --git a/configure.ac b/configure.ac
index 586bce2..896021c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -97,6 +97,7 @@ POLKIT_AGENT_REQUIRED=0.97
 POLKIT_GOBJECT_REQUIRED=0.97
 IBUS_REQUIRED=1.5.2
 UPOWER_GLIB_REQUIRED=0.99.0
+XRANDR_REQUIRED=1.5.0
 
 PKG_CHECK_MODULES([BACKENDS], [
   gio-2.0 >= $GLIB_REQUIRED
@@ -104,6 +105,7 @@ PKG_CHECK_MODULES([BACKENDS], [
   glib-2.0 >= $GLIB_REQUIRED
   gnome-desktop-3.0 >= $LIBGNOME_DESKTOP_REQUIRED
   upower-glib >= $UPOWER_GLIB_REQUIRED
+  xrandr >= $XRANDR_REQUIRED
   x11
 ])
 


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