[gnome-flashback] display-config: implement dbus method handling



commit 6326bb3c476d85ca4b56f89a922e6c433b47fecd
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Thu Mar 26 23:30:21 2015 +0200

    display-config: implement dbus method handling
    
    This implements all dbus methods that are needed to comunicate with
    gnome-control-center. Code are based on mutter 3.16.0 release.
    
    Right now FlashbackMonitorManager and FlashbackMonitorConfig does
    nothing...

 configure.ac                                       |    4 +-
 data/org.gnome.gnome-flashback.gschema.xml.in.in   |    2 +-
 gnome-flashback/libdisplay-config/Makefile.am      |   22 +-
 .../libdisplay-config/flashback-display-config.c   |  882 ++++++++++++++++++--
 .../libdisplay-config/flashback-display-config.h   |   22 +-
 .../libdisplay-config/flashback-monitor-config.c   |   86 ++
 .../libdisplay-config/flashback-monitor-config.h   |   47 +
 .../libdisplay-config/flashback-monitor-manager.c  |  113 +++
 .../libdisplay-config/flashback-monitor-manager.h  |  282 +++++++
 9 files changed, 1362 insertions(+), 98 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 78f5d32..481417f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -30,7 +30,7 @@ GLIB_GSETTINGS
 GTK_REQUIRED=3.15.2
 LIBGNOME_DESKTOP_REQUIRED=3.12.0
 CANBERRA_REQUIRED=0.13
-GLIB_REQUIRED=2.39.91
+GLIB_REQUIRED=2.44.0
 GSETTINGS_DESKTOP_SCHEMAS_REQUIRED=3.12.0
 
 PKG_CHECK_MODULES(GNOME_FLASHBACK, gtk+-3.0 >= $GTK_REQUIRED dbus-glib-1)
@@ -49,7 +49,7 @@ PKG_CHECK_MODULES(DESKTOP_BACKGROUND, gtk+-3.0 >= $GTK_REQUIRED gnome-desktop-3.
 AC_SUBST(DESKTOP_BACKGROUND_CFLAGS)
 AC_SUBST(DESKTOP_BACKGROUND_LIBS)
 
-PKG_CHECK_MODULES(DISPLAY_CONFIG, gtk+-3.0 >= $GTK_REQUIRED)
+PKG_CHECK_MODULES(DISPLAY_CONFIG, gtk+-3.0 >= $GTK_REQUIRED glib-2.0 >= $GLIB_REQUIRED gnome-desktop-3.0 >= 
$LIBGNOME_DESKTOP_REQUIRED)
 AC_SUBST(DISPLAY_CONFIG_CFLAGS)
 AC_SUBST(DISPLAY_CONFIG_LIBS)
 
diff --git a/data/org.gnome.gnome-flashback.gschema.xml.in.in 
b/data/org.gnome.gnome-flashback.gschema.xml.in.in
index a546760..d8b9318 100644
--- a/data/org.gnome.gnome-flashback.gschema.xml.in.in
+++ b/data/org.gnome.gnome-flashback.gschema.xml.in.in
@@ -11,7 +11,7 @@
                        <_description>If set to true, then GNOME Flashback application will be used to draw 
desktop background.</_description>
                </key>
                <key name="display-config" type="b">
-                       <default>false</default>
+                       <default>true</default>
                        <_summary>Display config</_summary>
                        <_description>If set to true, then GNOME Flashback application will be used to 
provide display configuration.</_description>
                </key>
diff --git a/gnome-flashback/libdisplay-config/Makefile.am b/gnome-flashback/libdisplay-config/Makefile.am
index 5c6b2ee..52b3f1a 100644
--- a/gnome-flashback/libdisplay-config/Makefile.am
+++ b/gnome-flashback/libdisplay-config/Makefile.am
@@ -7,25 +7,29 @@ AM_CPPFLAGS = \
        -DGNOMELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\"
 
 libdisplay_config_la_SOURCES = \
-       dbus-display-config.c \
-       dbus-display-config.h \
+       meta-dbus-display-config.c \
+       meta-dbus-display-config.h \
        flashback-display-config.c \
-       flashback-display-config.h
+       flashback-display-config.h \
+       flashback-monitor-config.c \
+       flashback-monitor-config.h \
+       flashback-monitor-manager.c \
+       flashback-monitor-manager.h
 
 libdisplay_config_la_LIBADD = \
        $(DISPLAY_CONFIG_LIBS)
 
-dbus-display-config.h:
-dbus-display-config.c: org.gnome.Mutter.DisplayConfig.xml
+meta-dbus-display-config.h:
+meta-dbus-display-config.c: org.gnome.Mutter.DisplayConfig.xml
        $(AM_V_GEN) gdbus-codegen \
                --interface-prefix org.gnome.Mutter \
-               --c-namespace DBus \
-               --generate-c-code dbus-display-config \
+               --c-namespace MetaDBus \
+               --generate-c-code meta-dbus-display-config \
                $(srcdir)/org.gnome.Mutter.DisplayConfig.xml
 
 BUILT_SOURCES = \
-       dbus-display-config.h \
-       dbus-display-config.c
+       meta-dbus-display-config.h \
+       meta-dbus-display-config.c
 
 EXTRA_DIST = \
        org.gnome.Mutter.DisplayConfig.xml
diff --git a/gnome-flashback/libdisplay-config/flashback-display-config.c 
b/gnome-flashback/libdisplay-config/flashback-display-config.c
index 3268eb7..2db195e 100644
--- a/gnome-flashback/libdisplay-config/flashback-display-config.c
+++ b/gnome-flashback/libdisplay-config/flashback-display-config.c
@@ -1,4 +1,11 @@
 /*
+ * 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) 2013 Red Hat Inc.
  * Copyright (C) 2014 Alberts Muktupāvels
  *
  * This program is free software: you can redistribute it and/or modify
@@ -13,30 +20,361 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Adapted from mutter 3.16.0:
+ * - /src/backends/meta-monitor-manager.c
  */
 
+#include <config.h>
+#include <glib/gi18n.h>
 #include <gtk/gtk.h>
-#include "config.h"
-#include "dbus-display-config.h"
+#include <math.h>
+#include "meta-dbus-display-config.h"
 #include "flashback-display-config.h"
+#include "flashback-monitor-config.h"
+#include "flashback-monitor-manager.h"
 
-struct _FlashbackDisplayConfigPrivate {
-       gint                    bus_name;
-       GDBusInterfaceSkeleton *iface;
+struct _FlashbackDisplayConfig
+{
+  GObject                  parent;
+  gint                     bus_name;
+  GDBusInterfaceSkeleton  *iface;
+  FlashbackMonitorManager *manager;
 };
 
-G_DEFINE_TYPE (FlashbackDisplayConfig, flashback_display_config, G_TYPE_OBJECT);
+G_DEFINE_TYPE (FlashbackDisplayConfig, flashback_display_config, G_TYPE_OBJECT)
 
-static void
-handle_get_resources (DBusDisplayConfig     *object,
+static const double known_diagonals[] = { 12.1, 13.3, 15.6 };
+
+static gboolean
+save_config_timeout (gpointer user_data)
+{
+  FlashbackMonitorManager *manager;
+
+  manager = FLASHBACK_MONITOR_MANAGER (user_data);
+
+  flashback_monitor_config_restore_previous (manager->config, manager);
+
+  manager->persistent_timeout_id = 0;
+  return G_SOURCE_REMOVE;
+}
+
+static gboolean
+output_can_config (MetaOutput      *output,
+                   MetaCRTC        *crtc,
+                   MetaMonitorMode *mode)
+{
+  unsigned int i;
+  gboolean ok = FALSE;
+
+  for (i = 0; i < output->n_possible_crtcs && !ok; i++)
+    ok = output->possible_crtcs[i] == crtc;
+
+  if (!ok)
+    return FALSE;
+
+  if (mode == NULL)
+    return TRUE;
+
+  ok = FALSE;
+  for (i = 0; i < output->n_modes && !ok; i++)
+    ok = output->modes[i] == mode;
+
+  return ok;
+}
+
+static gboolean
+output_can_clone (MetaOutput *output,
+                  MetaOutput *clone)
+{
+  unsigned int i;
+  gboolean ok = FALSE;
+
+  for (i = 0; i < output->n_possible_clones && !ok; i++)
+    ok = output->possible_clones[i] == clone;
+
+  return ok;
+}
+
+static char *
+diagonal_to_str (double d)
+{
+  unsigned int i;
+
+  for (i = 0; i < G_N_ELEMENTS (known_diagonals); i++)
+    {
+      double delta;
+
+      delta = fabs(known_diagonals[i] - d);
+      if (delta < 0.1)
+        return g_strdup_printf ("%0.1lf\"", known_diagonals[i]);
+    }
+
+  return g_strdup_printf ("%d\"", (int) (d + 0.5));
+}
+
+static char *
+make_display_name (FlashbackMonitorManager *manager,
+                   MetaOutput              *output)
+{
+  char *inches = NULL;
+  char *vendor_name = NULL;
+  char *ret;
+
+  switch (output->connector_type)
+    {
+    case META_CONNECTOR_TYPE_LVDS:
+    case META_CONNECTOR_TYPE_eDP:
+      ret = g_strdup (_("Built-in display"));
+      goto out;
+    default:
+      break;
+    }
+
+  if (output->width_mm > 0 && output->height_mm > 0)
+    {
+      double d = sqrt (output->width_mm * output->width_mm +
+                       output->height_mm * output->height_mm);
+      inches = diagonal_to_str (d / 25.4);
+    }
+
+  if (g_strcmp0 (output->vendor, "unknown") != 0)
+    {
+      if (!manager->pnp_ids)
+        manager->pnp_ids = gnome_pnp_ids_new ();
+
+      vendor_name = gnome_pnp_ids_get_pnp_id (manager->pnp_ids,
+                                              output->vendor);
+
+      if (!vendor_name)
+        vendor_name = g_strdup (output->vendor);
+    }
+  else
+    {
+      if (inches != NULL)
+        vendor_name = g_strdup (_("Unknown"));
+      else
+        vendor_name = g_strdup (_("Unknown Display"));
+    }
+
+  if (inches != NULL)
+    {
+      /* TRANSLATORS: this is a monitor vendor name, followed by a
+       * size in inches, like 'Dell 15"'
+       */
+      ret = g_strdup_printf (_("%s %s"), vendor_name, inches);
+    }
+  else
+    {
+      ret = g_strdup (vendor_name);
+    }
+
+ out:
+  g_free (inches);
+  g_free (vendor_name);
+
+  return ret;
+}
+
+static const char *
+get_connector_type_name (MetaConnectorType connector_type)
+{
+  switch (connector_type)
+    {
+      case META_CONNECTOR_TYPE_Unknown:
+        return "Unknown";
+      case META_CONNECTOR_TYPE_VGA:
+        return "VGA";
+      case META_CONNECTOR_TYPE_DVII:
+        return "DVII";
+      case META_CONNECTOR_TYPE_DVID:
+        return "DVID";
+      case META_CONNECTOR_TYPE_DVIA:
+        return "DVIA";
+      case META_CONNECTOR_TYPE_Composite:
+        return "Composite";
+      case META_CONNECTOR_TYPE_SVIDEO:
+        return "SVIDEO";
+      case META_CONNECTOR_TYPE_LVDS:
+        return "LVDS";
+      case META_CONNECTOR_TYPE_Component:
+        return "Component";
+      case META_CONNECTOR_TYPE_9PinDIN:
+        return "9PinDIN";
+      case META_CONNECTOR_TYPE_DisplayPort:
+        return "DisplayPort";
+      case META_CONNECTOR_TYPE_HDMIA:
+        return "HDMIA";
+      case META_CONNECTOR_TYPE_HDMIB:
+        return "HDMIB";
+      case META_CONNECTOR_TYPE_TV:
+        return "TV";
+      case META_CONNECTOR_TYPE_eDP:
+        return "eDP";
+      case META_CONNECTOR_TYPE_VIRTUAL:
+        return "VIRTUAL";
+      case META_CONNECTOR_TYPE_DSI:
+        return "DSI";
+      default:
+        g_assert_not_reached ();
+    }
+}
+
+static gboolean
+handle_get_resources (MetaDBusDisplayConfig *skeleton,
                       GDBusMethodInvocation *invocation,
                       gpointer               user_data)
 {
-       g_warning ("GetResources is not implemented!");
+  FlashbackDisplayConfig *config;
+  FlashbackMonitorManager *manager;
+  GVariantBuilder crtc_builder;
+  GVariantBuilder output_builder;
+  GVariantBuilder mode_builder;
+  unsigned int i;
+  unsigned int j;
+
+  config = FLASHBACK_DISPLAY_CONFIG (user_data);
+  manager = config->manager;
+
+  g_variant_builder_init (&crtc_builder, G_VARIANT_TYPE ("a(uxiiiiiuaua{sv})"));
+  g_variant_builder_init (&output_builder, G_VARIANT_TYPE ("a(uxiausauaua{sv})"));
+  g_variant_builder_init (&mode_builder, G_VARIANT_TYPE ("a(uxuud)"));
+
+  for (i = 0; i < manager->n_crtcs; i++)
+    {
+      MetaCRTC *crtc;
+      GVariantBuilder transforms;
+
+      crtc = &manager->crtcs[i];
+
+      g_variant_builder_init (&transforms, G_VARIANT_TYPE ("au"));
+      for (j = 0; j <= META_MONITOR_TRANSFORM_FLIPPED_270; j++)
+        if (crtc->all_transforms & (1 << j))
+          g_variant_builder_add (&transforms, "u", j);
+
+      g_variant_builder_add (&crtc_builder, "(uxiiiiiuaua{sv})",
+                             i, /* ID */
+                             (gint64) crtc->crtc_id,
+                             (int) crtc->rect.x,
+                             (int) crtc->rect.y,
+                             (int) crtc->rect.width,
+                             (int) crtc->rect.height,
+                             (int) (crtc->current_mode ? crtc->current_mode - manager->modes : -1),
+                             (guint32) crtc->transform,
+                             &transforms,
+                             NULL /* properties */);
+    }
+
+  for (i = 0; i < manager->n_outputs; i++)
+    {
+      MetaOutput *output;
+      GVariantBuilder crtcs;
+      GVariantBuilder modes;
+      GVariantBuilder clones;
+      GVariantBuilder properties;
+      GBytes *edid;
+      char *edid_file;
+
+      output = &manager->outputs[i];
+
+      g_variant_builder_init (&crtcs, G_VARIANT_TYPE ("au"));
+      for (j = 0; j < output->n_possible_crtcs; j++)
+        g_variant_builder_add (&crtcs, "u",
+                               (unsigned)(output->possible_crtcs[j] - manager->crtcs));
+
+      g_variant_builder_init (&modes, G_VARIANT_TYPE ("au"));
+      for (j = 0; j < output->n_modes; j++)
+        g_variant_builder_add (&modes, "u",
+                               (unsigned)(output->modes[j] - manager->modes));
+
+      g_variant_builder_init (&clones, G_VARIANT_TYPE ("au"));
+      for (j = 0; j < output->n_possible_clones; j++)
+        g_variant_builder_add (&clones, "u",
+                               (unsigned)(output->possible_clones[j] - manager->outputs));
+
+      g_variant_builder_init (&properties, G_VARIANT_TYPE ("a{sv}"));
+      g_variant_builder_add (&properties, "{sv}", "vendor",
+                             g_variant_new_string (output->vendor));
+      g_variant_builder_add (&properties, "{sv}", "product",
+                             g_variant_new_string (output->product));
+      g_variant_builder_add (&properties, "{sv}", "serial",
+                             g_variant_new_string (output->serial));
+      g_variant_builder_add (&properties, "{sv}", "width-mm",
+                             g_variant_new_int32 (output->width_mm));
+      g_variant_builder_add (&properties, "{sv}", "height-mm",
+                             g_variant_new_int32 (output->height_mm));
+      g_variant_builder_add (&properties, "{sv}", "display-name",
+                             g_variant_new_take_string (make_display_name (manager, output)));
+      g_variant_builder_add (&properties, "{sv}", "backlight",
+                             g_variant_new_int32 (output->backlight));
+      g_variant_builder_add (&properties, "{sv}", "min-backlight-step",
+                             g_variant_new_int32 ((output->backlight_max - output->backlight_min) ?
+                                                  100 / (output->backlight_max - output->backlight_min) : 
-1));
+      g_variant_builder_add (&properties, "{sv}", "primary",
+                             g_variant_new_boolean (output->is_primary));
+      g_variant_builder_add (&properties, "{sv}", "presentation",
+                             g_variant_new_boolean (output->is_presentation));
+      g_variant_builder_add (&properties, "{sv}", "connector-type",
+                             g_variant_new_string (get_connector_type_name (output->connector_type)));
+
+      edid_file = flashback_monitor_manager_get_edid_file (manager, output);
+      if (edid_file)
+        {
+          g_variant_builder_add (&properties, "{sv}", "edid-file",
+                                 g_variant_new_take_string (edid_file));
+        }
+      else
+        {
+          edid = flashback_monitor_manager_read_edid (manager, output);
+
+          if (edid)
+            {
+              g_variant_builder_add (&properties, "{sv}", "edid",
+                                     g_variant_new_from_bytes (G_VARIANT_TYPE ("ay"),
+                                                               edid, TRUE));
+              g_bytes_unref (edid);
+            }
+        }
+
+      g_variant_builder_add (&output_builder, "(uxiausauaua{sv})",
+                             i, /* ID */
+                             (gint64) output->winsys_id,
+                             (int) (output->crtc ? output->crtc - manager->crtcs : -1),
+                             &crtcs,
+                             output->name,
+                             &modes,
+                             &clones,
+                             &properties);
+    }
+
+  for (i = 0; i < manager->n_modes; i++)
+    {
+      MetaMonitorMode *mode;
+
+      mode = &manager->modes[i];
+
+      g_variant_builder_add (&mode_builder, "(uxuud)",
+                             i, /* ID */
+                             (gint64) mode->mode_id,
+                             (guint32) mode->width,
+                             (guint32) mode->height,
+                             (double) mode->refresh_rate);
+    }
+
+  meta_dbus_display_config_complete_get_resources (skeleton,
+                                                   invocation,
+                                                   manager->serial,
+                                                   g_variant_builder_end (&crtc_builder),
+                                                   g_variant_builder_end (&output_builder),
+                                                   g_variant_builder_end (&mode_builder),
+                                                   manager->max_screen_width,
+                                                   manager->max_screen_height);
+
+  return TRUE;
 }
 
-static void
-handle_apply_configuration (DBusDisplayConfig     *object,
+static gboolean
+handle_apply_configuration (MetaDBusDisplayConfig *skeleton,
                             GDBusMethodInvocation *invocation,
                             guint                  serial,
                             gboolean               persistent,
@@ -44,32 +382,376 @@ handle_apply_configuration (DBusDisplayConfig     *object,
                             GVariant              *outputs,
                             gpointer               user_data)
 {
-       g_warning ("ApplyConfiguration is not implemented!");
+  FlashbackDisplayConfig *config;
+  FlashbackMonitorManager *manager;
+  GVariantIter crtc_iter;
+  GVariantIter output_iter;
+  GVariantIter *nested_outputs;
+  GVariant *properties;
+  guint crtc_id;
+  int new_mode;
+  int x;
+  int y;
+  int new_screen_width;
+  int new_screen_height;
+  guint transform;
+  guint output_index;
+  GPtrArray *crtc_infos;
+  GPtrArray *output_infos;
+
+  config = FLASHBACK_DISPLAY_CONFIG (user_data);
+  manager = config->manager;
+
+  if (serial != manager->serial)
+    {
+      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                             G_DBUS_ERROR_ACCESS_DENIED,
+                                             "The requested configuration is based on stale information");
+      return TRUE;
+    }
+
+  crtc_infos = g_ptr_array_new_full (g_variant_n_children (crtcs),
+                                     (GDestroyNotify) meta_crtc_info_free);
+  output_infos = g_ptr_array_new_full (g_variant_n_children (outputs),
+                                       (GDestroyNotify) meta_output_info_free);
+
+  /* Validate all arguments */
+  new_screen_width = 0; new_screen_height = 0;
+  g_variant_iter_init (&crtc_iter, crtcs);
+  while (g_variant_iter_loop (&crtc_iter, "(uiiiuaua{sv})",
+                              &crtc_id, &new_mode, &x, &y, &transform,
+                              &nested_outputs, NULL))
+    {
+      MetaCRTCInfo *crtc_info;
+      MetaOutput *first_output;
+      MetaCRTC *crtc;
+      MetaMonitorMode *mode;
+
+      crtc_info = g_slice_new (MetaCRTCInfo);
+      crtc_info->outputs = g_ptr_array_new ();
+
+      if (crtc_id >= manager->n_crtcs)
+        {
+          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                                 G_DBUS_ERROR_INVALID_ARGS,
+                                                 "Invalid CRTC id");
+          return TRUE;
+        }
+
+      crtc = &manager->crtcs[crtc_id];
+      crtc_info->crtc = crtc;
+
+      if (new_mode != -1 && (new_mode < 0 || (unsigned) new_mode >= manager->n_modes))
+        {
+          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                                 G_DBUS_ERROR_INVALID_ARGS,
+                                                 "Invalid mode id");
+          return TRUE;
+        }
+
+      mode = new_mode != -1 ? &manager->modes[new_mode] : NULL;
+      crtc_info->mode = mode;
+
+      if (mode)
+        {
+          int width;
+          int height;
+
+          if (transform % 2)
+            {
+              width = mode->height;
+              height = mode->width;
+            }
+          else
+            {
+              width = mode->width;
+              height = mode->height;
+            }
+
+          if (x < 0 ||
+              x + width > manager->max_screen_width ||
+              y < 0 ||
+              y + height > manager->max_screen_height)
+            {
+              g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                                     G_DBUS_ERROR_INVALID_ARGS,
+                                                     "Invalid CRTC geometry");
+              return TRUE;
+            }
+
+          new_screen_width = MAX (new_screen_width, x + width);
+          new_screen_height = MAX (new_screen_height, y + height);
+          crtc_info->x = x;
+          crtc_info->y = y;
+        }
+      else
+        {
+          crtc_info->x = 0;
+          crtc_info->y = 0;
+        }
+
+      if (transform < META_MONITOR_TRANSFORM_NORMAL ||
+          transform > META_MONITOR_TRANSFORM_FLIPPED_270 ||
+          ((crtc->all_transforms & (1 << transform)) == 0))
+        {
+          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                                 G_DBUS_ERROR_INVALID_ARGS,
+                                                 "Invalid transform");
+          return TRUE;
+        }
+
+      crtc_info->transform = transform;
+
+      first_output = NULL;
+      while (g_variant_iter_loop (nested_outputs, "u", &output_index))
+        {
+          MetaOutput *output;
+
+          if (output_index >= manager->n_outputs)
+            {
+              g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                                     G_DBUS_ERROR_INVALID_ARGS,
+                                                     "Invalid output id");
+              return TRUE;
+            }
+
+          output = &manager->outputs[output_index];
+
+          if (!output_can_config (output, crtc, mode))
+            {
+              g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                                     G_DBUS_ERROR_INVALID_ARGS,
+                                                     "Output cannot be assigned to this CRTC or mode");
+              return TRUE;
+            }
+
+          g_ptr_array_add (crtc_info->outputs, output);
+
+          if (first_output)
+            {
+              if (!output_can_clone (output, first_output))
+                {
+                  g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                                         G_DBUS_ERROR_INVALID_ARGS,
+                                                         "Outputs cannot be cloned");
+                  return TRUE;
+                }
+            }
+          else
+            first_output = output;
+        }
+
+      if (!first_output && mode)
+        {
+          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                                 G_DBUS_ERROR_INVALID_ARGS,
+                                                 "Mode specified without outputs?");
+          return TRUE;
+        }
+
+      g_ptr_array_add (crtc_infos, crtc_info);
+    }
+
+  if (new_screen_width == 0 || new_screen_height == 0)
+    {
+      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                             G_DBUS_ERROR_INVALID_ARGS,
+                                             "Refusing to disable all outputs");
+      return TRUE;
+    }
+
+  g_variant_iter_init (&output_iter, outputs);
+  while (g_variant_iter_loop (&output_iter, "(u a{sv})", &output_index, &properties))
+    {
+      MetaOutputInfo *output_info;
+      gboolean primary;
+      gboolean presentation;
+
+      if (output_index >= manager->n_outputs)
+        {
+          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                                 G_DBUS_ERROR_INVALID_ARGS,
+                                                 "Invalid output id");
+          return TRUE;
+        }
+
+      output_info = g_slice_new0 (MetaOutputInfo);
+      output_info->output = &manager->outputs[output_index];
+
+      if (g_variant_lookup (properties, "primary", "b", &primary))
+        output_info->is_primary = primary;
+
+      if (g_variant_lookup (properties, "presentation", "b", &presentation))
+        output_info->is_presentation = presentation;
+
+      g_ptr_array_add (output_infos, output_info);
+    }
+
+  /* If we were in progress of making a persistent change and we see a
+     new request, it's likely that the old one failed in some way, so
+     don't save it, but also don't queue for restoring it.
+  */
+  if (manager->persistent_timeout_id && persistent)
+    {
+      g_source_remove (manager->persistent_timeout_id);
+      manager->persistent_timeout_id = 0;
+    }
+
+  flashback_monitor_manager_apply_configuration (manager,
+                                                 (MetaCRTCInfo **) crtc_infos->pdata,
+                                                 crtc_infos->len,
+                                                 (MetaOutputInfo **) output_infos->pdata,
+                                                 output_infos->len);
+
+  g_ptr_array_unref (crtc_infos);
+  g_ptr_array_unref (output_infos);
+
+  /* Update MetaMonitorConfig data structures immediately so that we
+     don't revert the change at the next XRandR event, then ask the plugin
+     manager (through MetaScreen) to confirm the display change with the
+     appropriate UI. Then wait 20 seconds and if not confirmed, revert the
+     configuration.
+  */
+  flashback_monitor_config_update_current (manager->config, manager);
+
+  if (persistent)
+    {
+      manager->persistent_timeout_id = g_timeout_add_seconds (20, save_config_timeout, manager);
+      g_source_set_name_by_id (manager->persistent_timeout_id, "[gnome-flashback] save_config_timeout");
+    }
+
+  meta_dbus_display_config_complete_apply_configuration (skeleton,
+                                                         invocation);
+
+  return TRUE;
 }
 
-static void
-handle_change_backlight (DBusDisplayConfig     *object,
+static gboolean
+handle_change_backlight (MetaDBusDisplayConfig *skeleton,
                          GDBusMethodInvocation *invocation,
                          guint                  serial,
                          guint                  output_index,
                          gint                   value,
                          gpointer               user_data)
 {
-       g_warning ("ChangeBacklight is not implemented!");
+  FlashbackDisplayConfig *config;
+  FlashbackMonitorManager *manager;
+  MetaOutput *output;
+
+  config = FLASHBACK_DISPLAY_CONFIG (user_data);
+  manager = config->manager;
+
+  if (serial != manager->serial)
+    {
+      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                             G_DBUS_ERROR_ACCESS_DENIED,
+                                             "The requested configuration is based on stale information");
+      return TRUE;
+    }
+
+  if (output_index >= manager->n_outputs)
+    {
+      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                             G_DBUS_ERROR_INVALID_ARGS,
+                                             "Invalid output id");
+      return TRUE;
+    }
+
+  output = &manager->outputs[output_index];
+
+  if (value < 0 || value > 100)
+    {
+      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                             G_DBUS_ERROR_INVALID_ARGS,
+                                             "Invalid backlight value");
+      return TRUE;
+    }
+
+  if (output->backlight == -1 ||
+      (output->backlight_min == 0 && output->backlight_max == 0))
+    {
+      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                             G_DBUS_ERROR_INVALID_ARGS,
+                                             "Output does not support changing backlight");
+      return TRUE;
+    }
+
+  flashback_monitor_manager_change_backlight (manager, output, value);
+
+  meta_dbus_display_config_complete_change_backlight (skeleton,
+                                                      invocation,
+                                                      output->backlight);
+
+  return TRUE;
 }
 
-static void
-handle_get_crtc_gamma (DBusDisplayConfig     *object,
+static gboolean
+handle_get_crtc_gamma (MetaDBusDisplayConfig *skeleton,
                        GDBusMethodInvocation *invocation,
                        guint                  serial,
                        guint                  crtc_id,
                        gpointer               user_data)
 {
-       g_warning ("GetCrtcGamma is not implemented!");
+  FlashbackDisplayConfig *config;
+  FlashbackMonitorManager *manager;
+  MetaCRTC *crtc;
+  gsize size;
+  unsigned short *red;
+  unsigned short *green;
+  unsigned short *blue;
+  GBytes *red_bytes;
+  GBytes *green_bytes;
+  GBytes *blue_bytes;
+  GVariant *red_v;
+  GVariant *green_v;
+  GVariant *blue_v;
+
+  config = FLASHBACK_DISPLAY_CONFIG (user_data);
+  manager = config->manager;
+
+  if (serial != manager->serial)
+    {
+      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                             G_DBUS_ERROR_ACCESS_DENIED,
+                                             "The requested configuration is based on stale information");
+      return TRUE;
+    }
+
+  if (crtc_id >= manager->n_crtcs)
+    {
+      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                             G_DBUS_ERROR_INVALID_ARGS,
+                                             "Invalid crtc id");
+      return TRUE;
+    }
+
+  crtc = &manager->crtcs[crtc_id];
+
+  flashback_monitor_manager_get_crtc_gamma (manager, crtc, &size, &red, &green, &blue);
+
+  red_bytes = g_bytes_new_take (red, size * sizeof (unsigned short));
+  green_bytes = g_bytes_new_take (green, size * sizeof (unsigned short));
+  blue_bytes = g_bytes_new_take (blue, size * sizeof (unsigned short));
+
+  red_v = g_variant_new_from_bytes (G_VARIANT_TYPE ("aq"), red_bytes, TRUE);
+  green_v = g_variant_new_from_bytes (G_VARIANT_TYPE ("aq"), green_bytes, TRUE);
+  blue_v = g_variant_new_from_bytes (G_VARIANT_TYPE ("aq"), blue_bytes, TRUE);
+
+  g_bytes_unref (red_bytes);
+  g_bytes_unref (green_bytes);
+  g_bytes_unref (blue_bytes);
+
+  meta_dbus_display_config_complete_get_crtc_gamma (skeleton,
+                                                    invocation,
+                                                    red_v,
+                                                    green_v,
+                                                    blue_v);
+
+  return TRUE;
 }
 
-static void
-handle_set_crtc_gamma (DBusDisplayConfig     *object,
+static gboolean
+handle_set_crtc_gamma (MetaDBusDisplayConfig *skeleton,
                        GDBusMethodInvocation *invocation,
                        guint                  serial,
                        guint                  crtc_id,
@@ -78,7 +760,58 @@ handle_set_crtc_gamma (DBusDisplayConfig     *object,
                        GVariant              *blue_v,
                        gpointer               user_data)
 {
-       g_warning ("SetCrtcGamma is not implemented!");
+  FlashbackDisplayConfig *config;
+  FlashbackMonitorManager *manager;
+  MetaCRTC *crtc;
+  gsize size;
+  gsize dummy;
+  unsigned short *red;
+  unsigned short *green;
+  unsigned short *blue;
+  GBytes *red_bytes;
+  GBytes *green_bytes;
+  GBytes *blue_bytes;
+
+  config = FLASHBACK_DISPLAY_CONFIG (user_data);
+  manager = config->manager;
+
+  if (serial != manager->serial)
+    {
+      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                             G_DBUS_ERROR_ACCESS_DENIED,
+                                             "The requested configuration is based on stale information");
+      return TRUE;
+    }
+
+  if (crtc_id >= manager->n_crtcs)
+    {
+      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                             G_DBUS_ERROR_INVALID_ARGS,
+                                             "Invalid crtc id");
+      return TRUE;
+    }
+
+  crtc = &manager->crtcs[crtc_id];
+
+  red_bytes = g_variant_get_data_as_bytes (red_v);
+  green_bytes = g_variant_get_data_as_bytes (green_v);
+  blue_bytes = g_variant_get_data_as_bytes (blue_v);
+
+  size = g_bytes_get_size (red_bytes) / sizeof (unsigned short);
+  red = (unsigned short*) g_bytes_get_data (red_bytes, &dummy);
+  green = (unsigned short*) g_bytes_get_data (green_bytes, &dummy);
+  blue = (unsigned short*) g_bytes_get_data (blue_bytes, &dummy);
+
+  flashback_monitor_manager_set_crtc_gamma (manager, crtc, size, red, green, blue);
+
+  g_bytes_unref (red_bytes);
+  g_bytes_unref (green_bytes);
+  g_bytes_unref (blue_bytes);
+
+  meta_dbus_display_config_complete_set_crtc_gamma (skeleton,
+                                                    invocation);
+
+  return TRUE;
 }
 
 static void
@@ -86,25 +819,35 @@ on_bus_acquired (GDBusConnection *connection,
                  const gchar     *name,
                  gpointer         user_data)
 {
-       FlashbackDisplayConfig *config = FLASHBACK_DISPLAY_CONFIG (user_data);
-       GError *error = NULL;
+  FlashbackDisplayConfig *config;
+  MetaDBusDisplayConfig *skeleton;
+  GError *error;
+
+  config = FLASHBACK_DISPLAY_CONFIG (user_data);
+  skeleton = meta_dbus_display_config_skeleton_new ();
 
-       config->priv->iface = G_DBUS_INTERFACE_SKELETON (dbus_display_config_skeleton_new ());
+  g_signal_connect (skeleton, "handle-get-resources",
+                    G_CALLBACK (handle_get_resources), config);
+  g_signal_connect (skeleton, "handle-apply-configuration",
+                    G_CALLBACK (handle_apply_configuration), config);
+  g_signal_connect (skeleton, "handle-change-backlight",
+                    G_CALLBACK (handle_change_backlight), config);
+  g_signal_connect (skeleton, "handle-get-crtc-gamma",
+                    G_CALLBACK (handle_get_crtc_gamma), config);
+  g_signal_connect (skeleton, "handle-set-crtc-gamma",
+                    G_CALLBACK (handle_set_crtc_gamma), config);
 
-       g_signal_connect (config->priv->iface, "handle-get-resources", G_CALLBACK (handle_get_resources), 
config);
-       g_signal_connect (config->priv->iface, "handle-apply-configuration", G_CALLBACK 
(handle_apply_configuration), config);
-       g_signal_connect (config->priv->iface, "handle-change-backlight", G_CALLBACK 
(handle_change_backlight), config);
-       g_signal_connect (config->priv->iface, "handle-get-crtc-gamma", G_CALLBACK (handle_get_crtc_gamma), 
config);
-       g_signal_connect (config->priv->iface, "handle-set-crtc-gamma", G_CALLBACK (handle_set_crtc_gamma), 
config);
+  config->iface = G_DBUS_INTERFACE_SKELETON (skeleton);
+  error = NULL;
 
-       if (!g_dbus_interface_skeleton_export (config->priv->iface,
-                                              connection,
-                                              "/org/gnome/Mutter/DisplayConfig",
-                                              &error)) {
-               g_warning ("Failed to export interface: %s", error->message);
-               g_error_free (error);
-               return;
-       }
+  if (!g_dbus_interface_skeleton_export (config->iface, connection,
+                                         "/org/gnome/Mutter/DisplayConfig",
+                                         &error))
+    {
+      g_warning ("Failed to export interface: %s", error->message);
+      g_error_free (error);
+      return;
+    }
 }
 
 static void
@@ -124,54 +867,55 @@ on_name_lost (GDBusConnection *connection,
 static void
 flashback_display_config_finalize (GObject *object)
 {
-       FlashbackDisplayConfig *config = FLASHBACK_DISPLAY_CONFIG (object);
+  FlashbackDisplayConfig *config;
 
-       if (config->priv->iface) {
-               g_dbus_interface_skeleton_unexport (config->priv->iface);
+  config = FLASHBACK_DISPLAY_CONFIG (object);
 
-               g_object_unref (config->priv->iface);
-               config->priv->iface = NULL;
-       }
+  if (config->iface)
+    {
+      g_dbus_interface_skeleton_unexport (config->iface);
+      g_clear_object (&config->iface);
+    }
 
-       if (config->priv->bus_name) {
-               g_bus_unown_name (config->priv->bus_name);
-               config->priv->bus_name = 0;
-       }
+  if (config->bus_name)
+    {
+      g_bus_unown_name (config->bus_name);
+      config->bus_name = 0;
+    }
 
-       G_OBJECT_CLASS (flashback_display_config_parent_class)->finalize (object);
+  g_clear_object (&config->manager);
+
+  G_OBJECT_CLASS (flashback_display_config_parent_class)->finalize (object);
 }
 
 static void
-flashback_display_config_init (FlashbackDisplayConfig *config)
+flashback_display_config_class_init (FlashbackDisplayConfigClass *config_class)
 {
-       config->priv = G_TYPE_INSTANCE_GET_PRIVATE (config,
-                                                   FLASHBACK_TYPE_DISPLAY_CONFIG,
-                                                   FlashbackDisplayConfigPrivate);
+  GObjectClass *object_class;
 
-       config->priv->bus_name = g_bus_own_name (G_BUS_TYPE_SESSION,
-                                                "org.gnome.Mutter.DisplayConfig",
-                                                G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
-                                                G_BUS_NAME_OWNER_FLAGS_REPLACE,
-                                                on_bus_acquired,
-                                                on_name_acquired,
-                                                on_name_lost,
-                                                config,
-                                                NULL);
+  object_class = G_OBJECT_CLASS (config_class);
+
+  object_class->finalize = flashback_display_config_finalize;
 }
 
 static void
-flashback_display_config_class_init (FlashbackDisplayConfigClass *class)
+flashback_display_config_init (FlashbackDisplayConfig *config)
 {
-       GObjectClass *object_class = G_OBJECT_CLASS (class);
-
-       object_class->finalize = flashback_display_config_finalize;
-
-       g_type_class_add_private (class, sizeof (FlashbackDisplayConfigPrivate));
+  config->manager = flashback_monitor_manager_new ();
+  config->bus_name = g_bus_own_name (G_BUS_TYPE_SESSION,
+                                     "org.gnome.Mutter.DisplayConfig",
+                                     G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
+                                     G_BUS_NAME_OWNER_FLAGS_REPLACE,
+                                     on_bus_acquired,
+                                     on_name_acquired,
+                                     on_name_lost,
+                                     config,
+                                     NULL);
 }
 
 FlashbackDisplayConfig *
 flashback_display_config_new (void)
 {
-       return g_object_new (FLASHBACK_TYPE_DISPLAY_CONFIG,
-                            NULL);
+  return g_object_new (FLASHBACK_TYPE_DISPLAY_CONFIG,
+                       NULL);
 }
diff --git a/gnome-flashback/libdisplay-config/flashback-display-config.h 
b/gnome-flashback/libdisplay-config/flashback-display-config.h
index 2fa261d..28f25a1 100644
--- a/gnome-flashback/libdisplay-config/flashback-display-config.h
+++ b/gnome-flashback/libdisplay-config/flashback-display-config.h
@@ -22,24 +22,12 @@
 
 G_BEGIN_DECLS
 
-#define FLASHBACK_TYPE_DISPLAY_CONFIG (flashback_display_config_get_type ())
-#define FLASHBACK_DISPLAY_CONFIG(o)   (G_TYPE_CHECK_INSTANCE_CAST ((o), FLASHBACK_TYPE_DISPLAY_CONFIG, 
FlashbackDisplayConfig))
+#define FLASHBACK_TYPE_DISPLAY_CONFIG flashback_display_config_get_type ()
+G_DECLARE_FINAL_TYPE (FlashbackDisplayConfig, flashback_display_config,
+                      FLASHBACK, DISPLAY_CONFIG,
+                      GObject)
 
-typedef struct _FlashbackDisplayConfig        FlashbackDisplayConfig;
-typedef struct _FlashbackDisplayConfigClass   FlashbackDisplayConfigClass;
-typedef struct _FlashbackDisplayConfigPrivate FlashbackDisplayConfigPrivate;
-
-struct _FlashbackDisplayConfig {
-       GObject                        parent;
-       FlashbackDisplayConfigPrivate *priv;
-};
-
-struct _FlashbackDisplayConfigClass {
-    GObjectClass parent_class;
-};
-
-GType                   flashback_display_config_get_type (void);
-FlashbackDisplayConfig *flashback_display_config_new      (void);
+FlashbackDisplayConfig *flashback_display_config_new (void);
 
 G_END_DECLS
 
diff --git a/gnome-flashback/libdisplay-config/flashback-monitor-config.c 
b/gnome-flashback/libdisplay-config/flashback-monitor-config.c
new file mode 100644
index 0000000..dde6f0d
--- /dev/null
+++ b/gnome-flashback/libdisplay-config/flashback-monitor-config.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2001 Havoc Pennington
+ * Copyright (C) 2003 Rob Adams
+ * Copyright (C) 2004-2006 Elijah Newren
+ * Copyright (C) 2013 Red Hat Inc.
+ * Copyright (C) 2015 Alberts Muktupāvels
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Adapted from mutter 3.16.0:
+ * - /src/backends/meta-monitor-config.c
+ */
+
+#include <config.h>
+#include "flashback-monitor-config.h"
+
+struct _FlashbackMonitorConfig
+{
+  GObject parent;
+};
+
+G_DEFINE_TYPE (FlashbackMonitorConfig, flashback_monitor_config, G_TYPE_OBJECT)
+
+static void
+flashback_monitor_config_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (flashback_monitor_config_parent_class)->finalize (object);
+}
+
+static void
+flashback_monitor_config_class_init (FlashbackMonitorConfigClass *config_class)
+{
+  GObjectClass *object_class;
+
+  object_class = G_OBJECT_CLASS (config_class);
+
+  object_class->finalize = flashback_monitor_config_finalize;
+}
+
+static void
+flashback_monitor_config_init (FlashbackMonitorConfig *config)
+{
+}
+
+FlashbackMonitorConfig *
+flashback_monitor_config_new (void)
+{
+  return g_object_new (FLASHBACK_TYPE_MONITOR_CONFIG,
+                       NULL);
+}
+
+void
+flashback_monitor_config_update_current (FlashbackMonitorConfig  *config,
+                                         FlashbackMonitorManager *manager)
+{
+}
+
+void
+flashback_monitor_config_restore_previous (FlashbackMonitorConfig  *config,
+                                           FlashbackMonitorManager *manager)
+{
+}
+
+void
+meta_crtc_info_free (MetaCRTCInfo *info)
+{
+  g_ptr_array_free (info->outputs, TRUE);
+  g_slice_free (MetaCRTCInfo, info);
+}
+
+void
+meta_output_info_free (MetaOutputInfo *info)
+{
+  g_slice_free (MetaOutputInfo, info);
+}
diff --git a/gnome-flashback/libdisplay-config/flashback-monitor-config.h 
b/gnome-flashback/libdisplay-config/flashback-monitor-config.h
new file mode 100644
index 0000000..cf4d109
--- /dev/null
+++ b/gnome-flashback/libdisplay-config/flashback-monitor-config.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2001 Havoc Pennington
+ * Copyright (C) 2003 Rob Adams
+ * Copyright (C) 2004-2006 Elijah Newren
+ * Copyright (C) 2013 Red Hat Inc.
+ * Copyright (C) 2015 Alberts Muktupāvels
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Adapted from mutter 3.16.0:
+ * - /src/backends/meta-monitor-config.h
+ */
+
+#ifndef FLASHBACK_MONITOR_CONFIG_H
+#define FLASHBACK_MONITOR_CONFIG_H
+
+#include "flashback-monitor-manager.h"
+
+G_BEGIN_DECLS
+
+#define FLASHBACK_TYPE_MONITOR_CONFIG flashback_monitor_config_get_type ()
+G_DECLARE_FINAL_TYPE (FlashbackMonitorConfig, flashback_monitor_config,
+                      FLASHBACK, MONITOR_CONFIG,
+                      GObject)
+
+FlashbackMonitorConfig *flashback_monitor_config_new              (void);
+
+void                    flashback_monitor_config_update_current   (FlashbackMonitorConfig  *config,
+                                                                   FlashbackMonitorManager *manager);
+
+void                    flashback_monitor_config_restore_previous (FlashbackMonitorConfig  *config,
+                                                                   FlashbackMonitorManager *manager);
+
+G_END_DECLS
+
+#endif
diff --git a/gnome-flashback/libdisplay-config/flashback-monitor-manager.c 
b/gnome-flashback/libdisplay-config/flashback-monitor-manager.c
new file mode 100644
index 0000000..6e35307
--- /dev/null
+++ b/gnome-flashback/libdisplay-config/flashback-monitor-manager.c
@@ -0,0 +1,113 @@
+/*
+ * 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) 2013 Red Hat Inc.
+ * Copyright (C) 2015 Alberts Muktupāvels
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Adapted from mutter 3.16.0:
+ * - /src/backends/meta-monitor-manager.c
+ */
+
+#include <config.h>
+#include "flashback-monitor-manager.h"
+
+G_DEFINE_TYPE (FlashbackMonitorManager, flashback_monitor_manager, G_TYPE_OBJECT)
+
+static void
+flashback_monitor_manager_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (flashback_monitor_manager_parent_class)->finalize (object);
+}
+
+static void
+flashback_monitor_manager_class_init (FlashbackMonitorManagerClass *manager_class)
+{
+  GObjectClass *object_class;
+
+  object_class = G_OBJECT_CLASS (manager_class);
+
+  object_class->finalize = flashback_monitor_manager_finalize;
+}
+
+static void
+flashback_monitor_manager_init (FlashbackMonitorManager *manager)
+{
+}
+
+FlashbackMonitorManager *
+flashback_monitor_manager_new (void)
+{
+  return g_object_new (FLASHBACK_TYPE_MONITOR_MANAGER,
+                       NULL);
+}
+
+void
+flashback_monitor_manager_apply_configuration (FlashbackMonitorManager  *manager,
+                                               MetaCRTCInfo            **crtcs,
+                                               unsigned int              n_crtcs,
+                                               MetaOutputInfo          **outputs,
+                                               unsigned int              n_outputs)
+{
+}
+
+void
+flashback_monitor_manager_change_backlight (FlashbackMonitorManager *manager,
+                                                                         MetaOutput              *output,
+                                                                         gint                     value)
+{
+}
+
+void
+flashback_monitor_manager_get_crtc_gamma (FlashbackMonitorManager  *manager,
+                                          MetaCRTC                 *crtc,
+                                          gsize                    *size,
+                                          unsigned short          **red,
+                                          unsigned short          **green,
+                                          unsigned short          **blue)
+{
+  *size = 0;
+  *red = NULL;
+  *green = NULL;
+  *blue = NULL;
+}
+
+void
+flashback_monitor_manager_set_crtc_gamma (FlashbackMonitorManager *manager,
+                                          MetaCRTC                *crtc,
+                                          gsize                    size,
+                                          unsigned short          *red,
+                                          unsigned short          *green,
+                                          unsigned short          *blue)
+{
+}
+
+char *
+flashback_monitor_manager_get_edid_file (FlashbackMonitorManager *manager,
+                                         MetaOutput              *output)
+{
+  return NULL;
+}
+
+GBytes *
+flashback_monitor_manager_read_edid (FlashbackMonitorManager *manager,
+                                     MetaOutput              *output)
+{
+  return NULL;
+}
diff --git a/gnome-flashback/libdisplay-config/flashback-monitor-manager.h 
b/gnome-flashback/libdisplay-config/flashback-monitor-manager.h
new file mode 100644
index 0000000..30f12c0
--- /dev/null
+++ b/gnome-flashback/libdisplay-config/flashback-monitor-manager.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2001 Havoc Pennington
+ * Copyright (C) 2003 Rob Adams
+ * Copyright (C) 2004-2006 Elijah Newren
+ * Copyright (C) 2013 Red Hat Inc.
+ * Copyright (C) 2015 Alberts Muktupāvels
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Adapted from mutter 3.16.0:
+ * - /src/backends/meta-monitor-manager-private.h
+ */
+
+#ifndef FLASHBACK_MONITOR_MANAGER_H
+#define FLASHBACK_MONITOR_MANAGER_H
+
+#include <glib-object.h>
+#include <gdk/gdk.h>
+#include <libgnome-desktop/gnome-pnp-ids.h>
+
+G_BEGIN_DECLS
+
+typedef struct _FlashbackMonitorConfig FlashbackMonitorConfig;
+
+typedef struct _MetaCRTC        MetaCRTC;
+typedef struct _MetaOutput      MetaOutput;
+typedef struct _MetaMonitorMode MetaMonitorMode;
+typedef struct _MetaMonitorInfo MetaMonitorInfo;
+typedef struct _MetaCRTCInfo    MetaCRTCInfo;
+typedef struct _MetaOutputInfo  MetaOutputInfo;
+
+typedef enum {
+  META_MONITOR_TRANSFORM_NORMAL,
+  META_MONITOR_TRANSFORM_90,
+  META_MONITOR_TRANSFORM_180,
+  META_MONITOR_TRANSFORM_270,
+  META_MONITOR_TRANSFORM_FLIPPED,
+  META_MONITOR_TRANSFORM_FLIPPED_90,
+  META_MONITOR_TRANSFORM_FLIPPED_180,
+  META_MONITOR_TRANSFORM_FLIPPED_270,
+} MetaMonitorTransform;
+
+/* This matches the values in drm_mode.h */
+typedef enum {
+  META_CONNECTOR_TYPE_Unknown     = 0,
+  META_CONNECTOR_TYPE_VGA         = 1,
+  META_CONNECTOR_TYPE_DVII        = 2,
+  META_CONNECTOR_TYPE_DVID        = 3,
+  META_CONNECTOR_TYPE_DVIA        = 4,
+  META_CONNECTOR_TYPE_Composite   = 5,
+  META_CONNECTOR_TYPE_SVIDEO      = 6,
+  META_CONNECTOR_TYPE_LVDS        = 7,
+  META_CONNECTOR_TYPE_Component   = 8,
+  META_CONNECTOR_TYPE_9PinDIN     = 9,
+  META_CONNECTOR_TYPE_DisplayPort = 10,
+  META_CONNECTOR_TYPE_HDMIA       = 11,
+  META_CONNECTOR_TYPE_HDMIB       = 12,
+  META_CONNECTOR_TYPE_TV          = 13,
+  META_CONNECTOR_TYPE_eDP         = 14,
+  META_CONNECTOR_TYPE_VIRTUAL     = 15,
+  META_CONNECTOR_TYPE_DSI         = 16,
+} MetaConnectorType;
+
+struct _MetaOutput
+{
+  /* The CRTC driving this output, NULL if the output is not enabled */
+  MetaCRTC           *crtc;
+  /* The low-level ID of this output, used to apply back configuration */
+  glong               winsys_id;
+  char               *name;
+  char               *vendor;
+  char               *product;
+  char               *serial;
+  int                 width_mm;
+  int                 height_mm;
+  int                 scale;
+
+  MetaConnectorType   connector_type;
+
+  MetaMonitorMode    *preferred_mode;
+  MetaMonitorMode   **modes;
+  unsigned int        n_modes;
+
+  MetaCRTC          **possible_crtcs;
+  unsigned int        n_possible_crtcs;
+
+  MetaOutput        **possible_clones;
+  unsigned int        n_possible_clones;
+
+  int                 backlight;
+  int                 backlight_min;
+  int                 backlight_max;
+
+  /* Used when changing configuration */
+  gboolean            is_dirty;
+
+  /* The low-level bits used to build the high-level info
+     in MetaMonitorInfo
+  */
+  gboolean            is_primary;
+  gboolean            is_presentation;
+
+  gpointer            driver_private;
+  GDestroyNotify      driver_notify;
+
+  /* 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
+{
+  glong                 crtc_id;
+  GdkRectangle          rect;
+  MetaMonitorMode      *current_mode;
+  MetaMonitorTransform  transform;
+  unsigned int          all_transforms;
+
+  /* Only used to build the logical configuration
+     from the HW one
+  */
+  MetaMonitorInfo      *logical_monitor;
+
+  /* Used when changing configuration */
+  gboolean              is_dirty;
+};
+
+struct _MetaMonitorMode
+{
+  /* The low-level ID of this mode, used to apply back configuration */
+  glong          mode_id;
+  char          *name;
+
+  int            width;
+  int            height;
+  float          refresh_rate;
+
+  gpointer       driver_private;
+  GDestroyNotify driver_notify;
+};
+
+/**
+ * MetaMonitorInfo:
+ *
+ * A structure with high-level information about monitors.
+ * This corresponds to a subset of the compositor coordinate space.
+ * Clones are only reported once, irrespective of the way
+ * they're implemented (two CRTCs configured for the same
+ * coordinates or one CRTCs driving two outputs). Inactive CRTCs
+ * are ignored, and so are disabled outputs.
+ */
+struct _MetaMonitorInfo
+{
+  int          number;
+  int          xinerama_index;
+  GdkRectangle rect;
+  gboolean     is_primary;
+  gboolean     is_presentation; /* XXX: not yet used */
+  gboolean     in_fullscreen;
+
+  /* The primary or first output for this monitor, 0 if we can't figure out.
+     It can be matched to a winsys_id of a MetaOutput.
+
+     This is used as an opaque token on reconfiguration when switching from
+     clone to extened, to decide on what output the windows should go next
+     (it's an attempt to keep windows on the same monitor, and preferably on
+     the primary one).
+  */
+  glong        winsys_id;
+};
+
+/*
+ * MetaCRTCInfo:
+ * This represents the writable part of a CRTC, as deserialized from DBus
+ * or built by MetaMonitorConfig
+ *
+ * Note: differently from the other structures in this file, MetaCRTCInfo
+ * is handled by pointer. This is to accomodate the usage in MetaMonitorConfig
+ */
+struct _MetaCRTCInfo
+{
+  MetaCRTC             *crtc;
+  MetaMonitorMode      *mode;
+  int                   x;
+  int                   y;
+  MetaMonitorTransform  transform;
+  GPtrArray            *outputs;
+};
+
+/*
+ * MetaOutputInfo:
+ * this is the same as MetaCRTCInfo, but for outputs
+ */
+struct _MetaOutputInfo
+{
+  MetaOutput *output;
+  gboolean    is_primary;
+  gboolean    is_presentation;
+};
+
+#define FLASHBACK_TYPE_MONITOR_MANAGER flashback_monitor_manager_get_type ()
+G_DECLARE_FINAL_TYPE (FlashbackMonitorManager, flashback_monitor_manager,
+                      FLASHBACK, MONITOR_MANAGER,
+                      GObject)
+
+struct _FlashbackMonitorManager
+{
+  GObject                 parnet;
+
+  unsigned int            serial;
+
+  int                     max_screen_width;
+  int                     max_screen_height;
+
+  /* Outputs refer to physical screens,
+     CRTCs refer to stuff that can drive outputs
+     (like encoders, but less tied to the HW),
+     while monitor_infos refer to logical ones.
+  */
+  MetaOutput             *outputs;
+  unsigned int            n_outputs;
+
+  MetaMonitorMode        *modes;
+  unsigned int            n_modes;
+
+  MetaCRTC               *crtcs;
+  unsigned int            n_crtcs;
+
+  GnomePnpIds            *pnp_ids;
+
+  int                     persistent_timeout_id;
+  FlashbackMonitorConfig *config;
+};
+
+FlashbackMonitorManager *flashback_monitor_manager_new                 (void);
+
+void                     flashback_monitor_manager_apply_configuration (FlashbackMonitorManager  *manager,
+                                                                        MetaCRTCInfo            **crtcs,
+                                                                        unsigned int              n_crtcs,
+                                                                        MetaOutputInfo          **outputs,
+                                                                        unsigned int              n_outputs);
+
+void                     flashback_monitor_manager_change_backlight    (FlashbackMonitorManager  *manager,
+                                                                        MetaOutput               *output,
+                                                                        gint                      value);
+
+void                     flashback_monitor_manager_get_crtc_gamma      (FlashbackMonitorManager  *manager,
+                                                                        MetaCRTC                 *crtc,
+                                                                        gsize                    *size,
+                                                                        unsigned short          **red,
+                                                                        unsigned short          **green,
+                                                                        unsigned short          **blue);
+void                     flashback_monitor_manager_set_crtc_gamma      (FlashbackMonitorManager  *manager,
+                                                                        MetaCRTC                 *crtc,
+                                                                        gsize                     size,
+                                                                        unsigned short           *red,
+                                                                        unsigned short           *green,
+                                                                        unsigned short           *blue);
+
+char                    *flashback_monitor_manager_get_edid_file       (FlashbackMonitorManager  *manager,
+                                                                        MetaOutput               *output);
+GBytes                  *flashback_monitor_manager_read_edid           (FlashbackMonitorManager  *manager,
+                                                                        MetaOutput               *output);
+
+void                     meta_crtc_info_free                           (MetaCRTCInfo             *info);
+void                     meta_output_info_free                         (MetaOutputInfo           *info);
+
+G_END_DECLS
+
+#endif


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