[gnome-initial-setup/wip/pwithnall/misc-fixes: 19/70] display: Add a "Display" page to the FBE




commit a3debe5bb7886a06128644a3b90f7057d462511b
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Thu Aug 7 22:15:41 2014 +0100

    display: Add a "Display" page to the FBE
    
    This page allows the user to configure overscan compensation during
    initial setup.
    
    Originally, this page used gnome-rr from libgnome-desktop, but the
    Mutter D-Bus API used by that C API changed in favour of a new API,
    org.gnome.Mutter.DisplayConfig.
    
    Using the new D-Bus API from Mutter directly is a bit cumbersome since the
    output values of GetCurrentstate are full of information that needs to be
    parsed (all of it) just to be able to answer the question of whether the
    primary & active monitor supports underscanning, and what its value is.
    
    Since we're no longer using gnome-rr (and even if we were, we'd have to
    port it to the new D-Bus APIs from mutter), we'd need to implement a fair
    amount of code to do this simple task, and to respond to changes (e.g screen
    changed). Instead of doing that, we just "borrow" here some helper files from
    gnome-control-center's display panel, which do exactly what we need, and we
    integrate them from gis-display-page.c.
    
    Note that this commit does not rename those files / classes to make them look
    more gnome-initial-setup-like but, instead, import them directly as they are.
    The reason for that is that not a single change has been done to those files
    at all, and thus keeping them 100% unchanged will make rebases easier in the
    future, as it will make it easier to check whether some changes have happened
    to the upstream files, and how to backport them here.
    
    Using the new CcDisplay* helper files from gnome-control-center, reimplement
    the display page so that underscanning can be enabled/disabled from the FBE,
    using the new methods from org.gnome.mutter.DisplayConfig instead of the
    GnomeRR* APIs, which does not work anymore since it's still relying on
    GetResources instead of GetCurrentState) and ApplyConfiguration (which does
    no longer exist) instead of ApplyMonitorsConfig.
    
    [The change from gnome-rr to cc-* was implemented by Mario Sanchez Prada
    <mario endlessm com>. See eos3.5 and earlier branches for full
    authorship details.]
    
    [Note from 3.36 rebase: updated cc-display-config-dbus.c and
    cc-display-config.[ch] with the version from gnome master + 4697f93c9
    (the downstream commit we have) -- Matthew Leeds]
    
    NOTE: In future rebases, check the files from gnome-control-center to
    see if they have diverged. Beware that they do have a significant
    downstream change in endlessm/gnome-control-center for the display mode
    name information.
    
    (Rebase 3.38: Update files from g-c-c to incorporate 00081c434c78.)
    
    Reference to related tickets:
        https://phabricator.endlessm.com/T3020
        https://phabricator.endlessm.com/T3370
        https://phabricator.endlessm.com/T3371
        https://phabricator.endlessm.com/T3562
        https://phabricator.endlessm.com/T3285
        https://phabricator.endlessm.com/T3639
        https://phabricator.endlessm.com/T11995
        https://phabricator.endlessm.com/T17471
        https://phabricator.endlessm.com/T17471
        https://phabricator.endlessm.com/T21591

 gnome-initial-setup/gnome-initial-setup.c          |    2 +
 gnome-initial-setup/pages/display/.gitignore       |    1 +
 .../pages/display/cc-display-config-dbus.c         | 1742 ++++++++++++++++++++
 .../pages/display/cc-display-config-dbus.h         |   40 +
 .../pages/display/cc-display-config-manager-dbus.c |  188 +++
 .../pages/display/cc-display-config-manager-dbus.h |   34 +
 .../pages/display/cc-display-config-manager.c      |   61 +
 .../pages/display/cc-display-config-manager.h      |   43 +
 .../pages/display/cc-display-config.c              |  632 +++++++
 .../pages/display/cc-display-config.h              |  252 +++
 .../pages/display/display-overscan.png             |  Bin 0 -> 31721 bytes
 .../pages/display/display.gresource.xml            |    8 +
 .../pages/display/gis-display-page.c               |  285 ++++
 .../pages/display/gis-display-page.h               |   57 +
 .../pages/display/gis-display-page.ui              |  146 ++
 gnome-initial-setup/pages/display/meson.build      |   13 +
 gnome-initial-setup/pages/meson.build              |    1 +
 po/POTFILES.in                                     |    2 +
 18 files changed, 3507 insertions(+)
---
diff --git a/gnome-initial-setup/gnome-initial-setup.c b/gnome-initial-setup/gnome-initial-setup.c
index e238f0a4..5414f5ee 100644
--- a/gnome-initial-setup/gnome-initial-setup.c
+++ b/gnome-initial-setup/gnome-initial-setup.c
@@ -36,6 +36,7 @@
 #include "pages/welcome/gis-welcome-page.h"
 #include "pages/language/gis-language-page.h"
 #include "pages/keyboard/gis-keyboard-page.h"
+#include "pages/display/gis-display-page.h"
 #include "pages/endless-eula/gis-endless-eula-page.h"
 #include "pages/network/gis-network-page.h"
 #include "pages/timezone/gis-timezone-page.h"
@@ -70,6 +71,7 @@ static PageData page_table[] = {
   PAGE (welcome, FALSE),
   PAGE (language, FALSE),
   PAGE (keyboard, FALSE),
+  PAGE (display, TRUE),
   PAGE (endless_eula, TRUE),
   PAGE (network,  FALSE),
   PAGE (privacy,  FALSE),
diff --git a/gnome-initial-setup/pages/display/.gitignore b/gnome-initial-setup/pages/display/.gitignore
new file mode 100644
index 00000000..c8443cc9
--- /dev/null
+++ b/gnome-initial-setup/pages/display/.gitignore
@@ -0,0 +1 @@
+display-resources.[ch]
diff --git a/gnome-initial-setup/pages/display/cc-display-config-dbus.c 
b/gnome-initial-setup/pages/display/cc-display-config-dbus.c
new file mode 100644
index 00000000..13b062c4
--- /dev/null
+++ b/gnome-initial-setup/pages/display/cc-display-config-dbus.c
@@ -0,0 +1,1742 @@
+/*
+ * Copyright (C) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <math.h>
+#include <gio/gio.h>
+
+#include "cc-display-config-dbus.h"
+
+#define MODE_BASE_FORMAT "ssiiddad"
+#define MODE_FORMAT "(" MODE_BASE_FORMAT "a{sv})"
+#define MODES_FORMAT "a" MODE_FORMAT
+#define MONITOR_SPEC_FORMAT "(ssss)"
+#define MONITOR_FORMAT "(" MONITOR_SPEC_FORMAT MODES_FORMAT "a{sv})"
+#define MONITORS_FORMAT "a" MONITOR_FORMAT
+
+#define LOGICAL_MONITOR_MONITORS_FORMAT "a" MONITOR_SPEC_FORMAT
+#define LOGICAL_MONITOR_FORMAT "(iidub" LOGICAL_MONITOR_MONITORS_FORMAT "a{sv})"
+#define LOGICAL_MONITORS_FORMAT "a" LOGICAL_MONITOR_FORMAT
+
+#define CURRENT_STATE_FORMAT "(u" MONITORS_FORMAT LOGICAL_MONITORS_FORMAT "a{sv})"
+
+typedef enum _CcDisplayModeFlags
+{
+  MODE_PREFERRED = 1 << 0,
+  MODE_CURRENT = 1 << 1,
+  MODE_INTERLACED = 1 << 2,
+} CcDisplayModeFlags;
+
+struct _CcDisplayModeDBus
+{
+  CcDisplayMode parent_instance;
+
+  char *id;
+  char *name;
+  int width;
+  int height;
+  double refresh_rate;
+  double preferred_scale;
+  GArray *supported_scales;
+  guint32 flags;
+};
+
+G_DEFINE_TYPE (CcDisplayModeDBus,
+               cc_display_mode_dbus,
+               CC_TYPE_DISPLAY_MODE)
+
+static gboolean
+cc_display_mode_dbus_equal (const CcDisplayModeDBus *m1,
+                            const CcDisplayModeDBus *m2)
+{
+  if (!m1 && !m2)
+    return TRUE;
+  else if (!m1 || !m2)
+    return FALSE;
+
+  return m1->width == m2->width &&
+    m1->height == m2->height &&
+    m1->refresh_rate == m2->refresh_rate &&
+    (m1->flags & MODE_INTERLACED) == (m2->flags & MODE_INTERLACED);
+}
+
+static const char *
+cc_display_mode_dbus_get_name (CcDisplayMode *pself)
+{
+  CcDisplayModeDBus *self = CC_DISPLAY_MODE_DBUS (pself);
+
+  return self->name;
+}
+
+static void
+cc_display_mode_dbus_get_resolution (CcDisplayMode *pself,
+                                     int *w, int *h)
+{
+  CcDisplayModeDBus *self = CC_DISPLAY_MODE_DBUS (pself);
+
+  if (w)
+    *w = self->width;
+  if (h)
+    *h = self->height;
+}
+
+static const double *
+cc_display_mode_dbus_get_supported_scales (CcDisplayMode *pself)
+{
+  CcDisplayModeDBus *self = CC_DISPLAY_MODE_DBUS (pself);
+
+  return (const double *) self->supported_scales->data;
+}
+
+static double
+cc_display_mode_dbus_get_preferred_scale (CcDisplayMode *pself)
+{
+  CcDisplayModeDBus *self = CC_DISPLAY_MODE_DBUS (pself);
+
+  return self->preferred_scale;
+}
+
+static gboolean
+cc_display_mode_dbus_is_supported_scale (CcDisplayMode *pself,
+                                         double scale)
+{
+  CcDisplayModeDBus *self = CC_DISPLAY_MODE_DBUS (pself);
+
+  guint i;
+  for (i = 0; i < self->supported_scales->len; i++)
+    if (g_array_index (self->supported_scales, double, i) == scale)
+      return TRUE;
+  return FALSE;
+}
+
+
+static gboolean
+cc_display_mode_dbus_is_interlaced (CcDisplayMode *pself)
+{
+  CcDisplayModeDBus *self = CC_DISPLAY_MODE_DBUS (pself);
+
+  return !!(self->flags & MODE_INTERLACED);
+}
+
+static int
+cc_display_mode_dbus_get_freq (CcDisplayMode *pself)
+{
+  CcDisplayModeDBus *self = CC_DISPLAY_MODE_DBUS (pself);
+
+  return self->refresh_rate;
+}
+
+static double
+cc_display_mode_dbus_get_freq_f (CcDisplayMode *pself)
+{
+  CcDisplayModeDBus *self = CC_DISPLAY_MODE_DBUS (pself);
+
+  return self->refresh_rate;
+}
+
+static void
+cc_display_mode_dbus_init (CcDisplayModeDBus *self)
+{
+  self->supported_scales = g_array_new (TRUE, TRUE, sizeof (double));
+}
+
+static void
+cc_display_mode_dbus_finalize (GObject *object)
+{
+  CcDisplayModeDBus *self = CC_DISPLAY_MODE_DBUS (object);
+
+  g_free (self->id);
+  g_free (self->name);
+  g_array_free (self->supported_scales, TRUE);
+
+  G_OBJECT_CLASS (cc_display_mode_dbus_parent_class)->finalize (object);
+}
+
+static void
+cc_display_mode_dbus_class_init (CcDisplayModeDBusClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  CcDisplayModeClass *parent_class = CC_DISPLAY_MODE_CLASS (klass);
+
+  gobject_class->finalize = cc_display_mode_dbus_finalize;
+
+  parent_class->get_name = cc_display_mode_dbus_get_name;
+  parent_class->get_resolution = cc_display_mode_dbus_get_resolution;
+  parent_class->get_supported_scales = cc_display_mode_dbus_get_supported_scales;
+  parent_class->get_preferred_scale = cc_display_mode_dbus_get_preferred_scale;
+  parent_class->is_interlaced = cc_display_mode_dbus_is_interlaced;
+  parent_class->get_freq = cc_display_mode_dbus_get_freq;
+  parent_class->get_freq_f = cc_display_mode_dbus_get_freq_f;
+}
+
+static CcDisplayModeDBus *
+cc_display_mode_dbus_new (GVariant *variant)
+{
+  double d;
+  g_autoptr(GVariantIter) scales_iter = NULL;
+  g_autoptr(GVariant) properties_variant = NULL;
+  gboolean is_current;
+  gboolean is_preferred;
+  gboolean is_interlaced;
+  CcDisplayModeDBus *self = g_object_new (CC_TYPE_DISPLAY_MODE_DBUS, NULL);
+
+  g_variant_get (variant, "(" MODE_BASE_FORMAT "@a{sv})",
+                 &self->id,
+                 &self->name,
+                 &self->width,
+                 &self->height,
+                 &self->refresh_rate,
+                 &self->preferred_scale,
+                 &scales_iter,
+                 &properties_variant);
+
+  while (g_variant_iter_next (scales_iter, "d", &d))
+    g_array_append_val (self->supported_scales, d);
+
+  if (!g_variant_lookup (properties_variant, "is-current", "b", &is_current))
+    is_current = FALSE;
+  if (!g_variant_lookup (properties_variant, "is-preferred", "b", &is_preferred))
+    is_preferred = FALSE;
+  if (!g_variant_lookup (properties_variant, "is-interlaced", "b", &is_interlaced))
+    is_interlaced = FALSE;
+
+  if (is_current)
+    self->flags |= MODE_CURRENT;
+  if (is_preferred)
+    self->flags |= MODE_PREFERRED;
+  if (is_interlaced)
+    self->flags |= MODE_INTERLACED;
+
+  return self;
+}
+
+
+#define CC_TYPE_DISPLAY_LOGICAL_MONITOR (cc_display_logical_monitor_get_type ())
+G_DECLARE_FINAL_TYPE (CcDisplayLogicalMonitor, cc_display_logical_monitor,
+                      CC, DISPLAY_LOGICAL_MONITOR, GObject)
+
+struct _CcDisplayLogicalMonitor
+{
+  GObject parent_instance;
+
+  int x;
+  int y;
+  double scale;
+  CcDisplayRotation rotation;
+  gboolean primary;
+
+  GHashTable *monitors;
+};
+
+G_DEFINE_TYPE (CcDisplayLogicalMonitor,
+               cc_display_logical_monitor,
+               G_TYPE_OBJECT)
+
+static gboolean
+cc_display_logical_monitor_equal (const CcDisplayLogicalMonitor *m1,
+                                  const CcDisplayLogicalMonitor *m2)
+{
+  if (!m1 && !m2)
+    return TRUE;
+  else if (!m1 || !m2)
+    return FALSE;
+
+  return m1->x == m2->x &&
+    m1->y == m2->y &&
+    m1->scale == m2->scale &&
+    m1->rotation == m2->rotation &&
+    m1->primary == m2->primary;
+}
+
+static void
+cc_display_logical_monitor_init (CcDisplayLogicalMonitor *self)
+{
+  self->scale = 1.0;
+  self->monitors = g_hash_table_new (NULL, NULL);
+}
+
+static void
+cc_display_logical_monitor_finalize (GObject *object)
+{
+  CcDisplayLogicalMonitor *self = CC_DISPLAY_LOGICAL_MONITOR (object);
+
+  g_warn_if_fail (g_hash_table_size (self->monitors) == 0);
+  g_clear_pointer (&self->monitors, g_hash_table_destroy);
+
+  G_OBJECT_CLASS (cc_display_logical_monitor_parent_class)->finalize (object);
+}
+
+static void
+cc_display_logical_monitor_class_init (CcDisplayLogicalMonitorClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = cc_display_logical_monitor_finalize;
+}
+
+
+typedef enum _CcDisplayMonitorUnderscanning
+{
+  UNDERSCANNING_UNSUPPORTED = 0,
+  UNDERSCANNING_DISABLED,
+  UNDERSCANNING_ENABLED
+} CcDisplayMonitorUnderscanning;
+
+struct _CcDisplayMonitorDBus
+{
+  CcDisplayMonitor parent_instance;
+  CcDisplayConfigDBus *config;
+
+  gchar *connector_name;
+  gchar *vendor_name;
+  gchar *product_name;
+  gchar *product_serial;
+  gchar *display_name;
+
+  int width_mm;
+  int height_mm;
+  gboolean builtin;
+  CcDisplayMonitorUnderscanning underscanning;
+  int max_width;
+  int max_height;
+
+  GList *modes;
+  CcDisplayMode *current_mode;
+  CcDisplayMode *preferred_mode;
+
+  CcDisplayLogicalMonitor *logical_monitor;
+};
+
+G_DEFINE_TYPE (CcDisplayMonitorDBus,
+               cc_display_monitor_dbus,
+               CC_TYPE_DISPLAY_MONITOR)
+
+static void
+register_logical_monitor (CcDisplayConfigDBus *self,
+                          CcDisplayLogicalMonitor *logical_monitor);
+static void
+cc_display_config_dbus_set_primary (CcDisplayConfigDBus *self,
+                                    CcDisplayMonitorDBus *new_primary);
+static void
+cc_display_config_dbus_unset_primary (CcDisplayConfigDBus *self,
+                                      CcDisplayMonitorDBus *old_primary);
+static void
+cc_display_config_dbus_ensure_non_offset_coords (CcDisplayConfigDBus *self);
+static void
+cc_display_config_dbus_append_right (CcDisplayConfigDBus *self,
+                                     CcDisplayLogicalMonitor *monitor);
+static void
+cc_display_config_dbus_make_linear (CcDisplayConfigDBus *self);
+
+
+static const char *
+cc_display_monitor_dbus_get_display_name (CcDisplayMonitor *pself)
+{
+  CcDisplayMonitorDBus *self = CC_DISPLAY_MONITOR_DBUS (pself);
+
+  if (self->display_name)
+    return self->display_name;
+
+  return self->connector_name;
+}
+
+static const char *
+cc_display_monitor_dbus_get_connector_name (CcDisplayMonitor *pself)
+{
+  CcDisplayMonitorDBus *self = CC_DISPLAY_MONITOR_DBUS (pself);
+
+  return self->connector_name;
+}
+
+static gboolean
+cc_display_monitor_dbus_is_builtin (CcDisplayMonitor *pself)
+{
+  CcDisplayMonitorDBus *self = CC_DISPLAY_MONITOR_DBUS (pself);
+
+  return self->builtin;
+}
+
+static gboolean
+cc_display_monitor_dbus_is_primary (CcDisplayMonitor *pself)
+{
+  CcDisplayMonitorDBus *self = CC_DISPLAY_MONITOR_DBUS (pself);
+
+  if (self->logical_monitor)
+    return self->logical_monitor->primary;
+
+  return FALSE;
+}
+
+static void
+cc_display_monitor_dbus_set_primary (CcDisplayMonitor *pself,
+                                     gboolean primary)
+{
+  CcDisplayMonitorDBus *self = CC_DISPLAY_MONITOR_DBUS (pself);
+
+  if (primary)
+    cc_display_config_dbus_set_primary (self->config, self);
+  else
+    cc_display_config_dbus_unset_primary (self->config, self);
+}
+
+static gboolean
+cc_display_monitor_dbus_is_active (CcDisplayMonitor *pself)
+{
+  CcDisplayMonitorDBus *self = CC_DISPLAY_MONITOR_DBUS (pself);
+
+  return self->logical_monitor != NULL;
+}
+
+static void
+cc_display_monitor_dbus_set_logical_monitor (CcDisplayMonitorDBus *self,
+                                             CcDisplayLogicalMonitor *logical_monitor)
+{
+  gboolean was_primary = FALSE;
+
+  if (self->logical_monitor)
+    {
+      was_primary = self->logical_monitor->primary;
+      if (was_primary)
+        cc_display_config_dbus_unset_primary (self->config, self);
+      g_hash_table_remove (self->logical_monitor->monitors, self);
+      g_object_unref (self->logical_monitor);
+    }
+
+  self->logical_monitor = logical_monitor;
+
+  if (self->logical_monitor)
+    {
+      g_hash_table_add (self->logical_monitor->monitors, self);
+      g_object_ref (self->logical_monitor);
+      /* unset primary with NULL will select this monitor if it is the only one.*/
+      if (was_primary)
+        cc_display_config_dbus_set_primary (self->config, self);
+      else
+        cc_display_config_dbus_unset_primary (self->config, NULL);
+    }
+}
+
+static void
+cc_display_monitor_dbus_set_active (CcDisplayMonitor *pself,
+                                    gboolean active)
+{
+  CcDisplayMonitorDBus *self = CC_DISPLAY_MONITOR_DBUS (pself);
+
+  if (!self->current_mode && active)
+    {
+      if (self->preferred_mode)
+        self->current_mode = self->preferred_mode;
+      else if (self->modes)
+        self->current_mode = (CcDisplayMode *) self->modes->data;
+      else
+        g_warning ("Couldn't find a mode to activate monitor at %s", self->connector_name);
+    }
+
+  if (!self->logical_monitor && active)
+    {
+      CcDisplayLogicalMonitor *logical_monitor;
+      logical_monitor = g_object_new (CC_TYPE_DISPLAY_LOGICAL_MONITOR, NULL);
+      cc_display_monitor_dbus_set_logical_monitor (self, logical_monitor);
+      cc_display_config_dbus_append_right (self->config, logical_monitor);
+      register_logical_monitor (self->config, logical_monitor);
+    }
+  else if (self->logical_monitor && !active)
+    {
+      cc_display_monitor_dbus_set_logical_monitor (self, NULL);
+    }
+
+  g_signal_emit_by_name (self, "active");
+}
+
+static CcDisplayRotation
+cc_display_monitor_dbus_get_rotation (CcDisplayMonitor *pself)
+{
+  CcDisplayMonitorDBus *self = CC_DISPLAY_MONITOR_DBUS (pself);
+
+  if (self->logical_monitor)
+    return self->logical_monitor->rotation;
+
+  return CC_DISPLAY_ROTATION_NONE;
+}
+
+static void
+cc_display_monitor_dbus_set_rotation (CcDisplayMonitor *pself,
+                                      CcDisplayRotation rotation)
+{
+  CcDisplayMonitorDBus *self = CC_DISPLAY_MONITOR_DBUS (pself);
+
+  if (!self->logical_monitor)
+    return;
+
+  if (self->logical_monitor->rotation != rotation)
+    {
+      self->logical_monitor->rotation = rotation;
+
+      g_signal_emit_by_name (self, "rotation");
+    }
+}
+
+static gboolean
+cc_display_monitor_dbus_supports_rotation (CcDisplayMonitor *pself,
+                                           CcDisplayRotation rotation)
+{
+  return TRUE;
+}
+
+static void
+cc_display_monitor_dbus_get_physical_size (CcDisplayMonitor *pself,
+                                           int *w, int *h)
+{
+  CcDisplayMonitorDBus *self = CC_DISPLAY_MONITOR_DBUS (pself);
+
+  if (w)
+    *w = self->width_mm;
+  if (h)
+    *h = self->height_mm;
+}
+
+static void
+cc_display_monitor_dbus_get_geometry (CcDisplayMonitor *pself,
+                                      int *x, int *y, int *w, int *h)
+{
+  CcDisplayMonitorDBus *self = CC_DISPLAY_MONITOR_DBUS (pself);
+  CcDisplayMode *mode = NULL;
+
+  if (self->logical_monitor)
+    {
+      if (x)
+        *x = self->logical_monitor->x;
+      if (y)
+        *y = self->logical_monitor->y;
+    }
+  else
+    {
+      if (x)
+        *x = -1;
+      if (y)
+        *y = -1;
+    }
+
+  if (self->current_mode)
+    mode = self->current_mode;
+  else if (self->preferred_mode)
+    mode = self->preferred_mode;
+  else if (self->modes)
+    mode = CC_DISPLAY_MODE (self->modes->data);
+
+  if (mode)
+    cc_display_mode_get_resolution (mode, w, h);
+  else
+    {
+      g_warning ("Monitor at %s has no modes?", self->connector_name);
+      if (w)
+        *w = -1;
+      if (h)
+        *h = -1;
+    }
+}
+
+static CcDisplayMode *
+cc_display_monitor_dbus_get_mode (CcDisplayMonitor *pself)
+{
+  CcDisplayMonitorDBus *self = CC_DISPLAY_MONITOR_DBUS (pself);
+
+  return self->current_mode;
+}
+
+static CcDisplayMode *
+cc_display_monitor_dbus_get_preferred_mode (CcDisplayMonitor *pself)
+{
+  CcDisplayMonitorDBus *self = CC_DISPLAY_MONITOR_DBUS (pself);
+
+  return self->preferred_mode;
+}
+
+static guint32
+cc_display_monitor_dbus_get_id (CcDisplayMonitor *pself)
+{
+  return 0;
+}
+
+static GList *
+cc_display_monitor_dbus_get_modes (CcDisplayMonitor *pself)
+{
+  CcDisplayMonitorDBus *self = CC_DISPLAY_MONITOR_DBUS (pself);
+
+  return self->modes;
+}
+
+static gboolean
+cc_display_monitor_dbus_supports_underscanning (CcDisplayMonitor *pself)
+{
+  CcDisplayMonitorDBus *self = CC_DISPLAY_MONITOR_DBUS (pself);
+
+  return self->underscanning != UNDERSCANNING_UNSUPPORTED;
+}
+
+static gboolean
+cc_display_monitor_dbus_get_underscanning (CcDisplayMonitor *pself)
+{
+  CcDisplayMonitorDBus *self = CC_DISPLAY_MONITOR_DBUS (pself);
+
+  return self->underscanning == UNDERSCANNING_ENABLED;
+}
+
+static void
+cc_display_monitor_dbus_set_underscanning (CcDisplayMonitor *pself,
+                                           gboolean underscanning)
+{
+  CcDisplayMonitorDBus *self = CC_DISPLAY_MONITOR_DBUS (pself);
+
+  if (self->underscanning == UNDERSCANNING_UNSUPPORTED)
+    return;
+
+  if (underscanning)
+    self->underscanning = UNDERSCANNING_ENABLED;
+  else
+    self->underscanning = UNDERSCANNING_DISABLED;
+}
+
+static CcDisplayMode *
+cc_display_monitor_dbus_get_closest_mode (CcDisplayMonitorDBus *self,
+                                          CcDisplayModeDBus *mode)
+{
+  CcDisplayModeDBus *best = NULL;
+  GList *l;
+
+  for (l = self->modes; l != NULL; l = l->next)
+    {
+      CcDisplayModeDBus *similar = l->data;
+
+      if (similar->width != mode->width ||
+          similar->height != mode->height)
+        continue;
+
+      if (similar->refresh_rate == mode->refresh_rate &&
+          (similar->flags & MODE_INTERLACED) == (mode->flags & MODE_INTERLACED))
+        {
+          best = similar;
+          break;
+        }
+
+      /* There might be a better heuristic. */
+      if (!best || best->refresh_rate < similar->refresh_rate)
+        {
+          best = similar;
+          continue;
+        }
+    }
+
+  return CC_DISPLAY_MODE (best);
+}
+
+static void
+cc_display_monitor_dbus_set_mode (CcDisplayMonitor *pself,
+                                  CcDisplayMode *new_mode)
+{
+  CcDisplayMonitorDBus *self = CC_DISPLAY_MONITOR_DBUS (pself);
+  CcDisplayMode *mode;
+
+  g_return_if_fail (new_mode != NULL);
+
+  mode = cc_display_monitor_dbus_get_closest_mode (self, CC_DISPLAY_MODE_DBUS (new_mode));
+
+  self->current_mode = mode;
+
+  if (!cc_display_mode_dbus_is_supported_scale (mode, cc_display_monitor_get_scale (pself)))
+    cc_display_monitor_set_scale (pself, cc_display_mode_get_preferred_scale (mode));
+
+  g_signal_emit_by_name (self, "mode");
+}
+
+static void
+cc_display_monitor_dbus_set_position (CcDisplayMonitor *pself,
+                                      int x, int y)
+{
+  CcDisplayMonitorDBus *self = CC_DISPLAY_MONITOR_DBUS (pself);
+
+  if (self->logical_monitor)
+    {
+      gboolean notify = FALSE;
+
+      if (self->logical_monitor->x != x || self->logical_monitor->y != y)
+        notify = TRUE;
+
+      self->logical_monitor->x = x;
+      self->logical_monitor->y = y;
+
+      if (notify)
+        g_signal_emit_by_name (self, "position-changed");
+    }
+
+}
+
+static double
+cc_display_monitor_dbus_get_scale (CcDisplayMonitor *pself)
+{
+  CcDisplayMonitorDBus *self = CC_DISPLAY_MONITOR_DBUS (pself);
+
+  if (self->logical_monitor)
+    return self->logical_monitor->scale;
+
+  return 1.0;
+}
+
+static void
+cc_display_monitor_dbus_set_scale (CcDisplayMonitor *pself,
+                                   double scale)
+{
+  CcDisplayMonitorDBus *self = CC_DISPLAY_MONITOR_DBUS (pself);
+
+  if (!self->current_mode)
+    return;
+
+  if (!cc_display_mode_dbus_is_supported_scale (self->current_mode, scale))
+    return;
+
+  if (!self->logical_monitor)
+    return;
+
+  if (self->logical_monitor->scale != scale)
+    {
+      self->logical_monitor->scale = scale;
+
+      g_signal_emit_by_name (self, "scale");
+    }
+}
+
+static void
+cc_display_monitor_dbus_init (CcDisplayMonitorDBus *self)
+{
+  self->underscanning = UNDERSCANNING_UNSUPPORTED;
+  self->max_width = G_MAXINT;
+  self->max_height = G_MAXINT;
+}
+
+static void
+cc_display_monitor_dbus_finalize (GObject *object)
+{
+  CcDisplayMonitorDBus *self = CC_DISPLAY_MONITOR_DBUS (object);
+
+  g_free (self->connector_name);
+  g_free (self->vendor_name);
+  g_free (self->product_name);
+  g_free (self->product_serial);
+  g_free (self->display_name);
+
+  g_list_foreach (self->modes, (GFunc) g_object_unref, NULL);
+  g_clear_pointer (&self->modes, g_list_free);
+
+  if (self->logical_monitor)
+    {
+      g_hash_table_remove (self->logical_monitor->monitors, self);
+      g_object_unref (self->logical_monitor);
+    }
+
+  G_OBJECT_CLASS (cc_display_monitor_dbus_parent_class)->finalize (object);
+}
+
+static void
+cc_display_monitor_dbus_class_init (CcDisplayMonitorDBusClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  CcDisplayMonitorClass *parent_class = CC_DISPLAY_MONITOR_CLASS (klass);
+
+  gobject_class->finalize = cc_display_monitor_dbus_finalize;
+
+  parent_class->get_display_name = cc_display_monitor_dbus_get_display_name;
+  parent_class->get_connector_name = cc_display_monitor_dbus_get_connector_name;
+  parent_class->is_builtin = cc_display_monitor_dbus_is_builtin;
+  parent_class->is_primary = cc_display_monitor_dbus_is_primary;
+  parent_class->set_primary = cc_display_monitor_dbus_set_primary;
+  parent_class->is_active = cc_display_monitor_dbus_is_active;
+  parent_class->set_active = cc_display_monitor_dbus_set_active;
+  parent_class->get_rotation = cc_display_monitor_dbus_get_rotation;
+  parent_class->set_rotation = cc_display_monitor_dbus_set_rotation;
+  parent_class->supports_rotation = cc_display_monitor_dbus_supports_rotation;
+  parent_class->get_physical_size = cc_display_monitor_dbus_get_physical_size;
+  parent_class->get_geometry = cc_display_monitor_dbus_get_geometry;
+  parent_class->get_mode = cc_display_monitor_dbus_get_mode;
+  parent_class->get_preferred_mode = cc_display_monitor_dbus_get_preferred_mode;
+  parent_class->get_id = cc_display_monitor_dbus_get_id;
+  parent_class->get_modes = cc_display_monitor_dbus_get_modes;
+  parent_class->supports_underscanning = cc_display_monitor_dbus_supports_underscanning;
+  parent_class->get_underscanning = cc_display_monitor_dbus_get_underscanning;
+  parent_class->set_underscanning = cc_display_monitor_dbus_set_underscanning;
+  parent_class->set_mode = cc_display_monitor_dbus_set_mode;
+  parent_class->set_position = cc_display_monitor_dbus_set_position;
+  parent_class->get_scale = cc_display_monitor_dbus_get_scale;
+  parent_class->set_scale = cc_display_monitor_dbus_set_scale;
+}
+
+static void
+construct_modes (CcDisplayMonitorDBus *self,
+                 GVariantIter *modes)
+{
+  CcDisplayModeDBus *mode;
+
+  while (TRUE)
+    {
+      g_autoptr(GVariant) variant = NULL;
+
+      if (!g_variant_iter_next (modes, "@"MODE_FORMAT, &variant))
+        break;
+
+      mode = cc_display_mode_dbus_new (variant);
+      self->modes = g_list_prepend (self->modes, mode);
+
+      if (mode->flags & MODE_PREFERRED)
+        self->preferred_mode = CC_DISPLAY_MODE (mode);
+      if (mode->flags & MODE_CURRENT)
+        self->current_mode = CC_DISPLAY_MODE (mode);
+    }
+}
+
+static CcDisplayMonitorDBus *
+cc_display_monitor_dbus_new (GVariant *variant,
+                             CcDisplayConfigDBus *config)
+{
+  CcDisplayMonitorDBus *self = g_object_new (CC_TYPE_DISPLAY_MONITOR_DBUS, NULL);
+  gchar *s1, *s2, *s3, *s4;
+  g_autoptr(GVariantIter) modes = NULL;
+  g_autoptr(GVariantIter) props = NULL;
+
+  self->config = config;
+
+  g_variant_get (variant, MONITOR_FORMAT,
+                 &s1, &s2, &s3, &s4, &modes, &props);
+  self->connector_name = s1;
+  self->vendor_name = s2;
+  self->product_name = s3;
+  self->product_serial = s4;
+
+  construct_modes (self, modes);
+
+  while (TRUE)
+    {
+      const char *s;
+      g_autoptr(GVariant) v = NULL;
+
+      if (!g_variant_iter_next (props, "{&sv}", &s, &v))
+        break;
+
+      if (g_str_equal (s, "width-mm"))
+        {
+          g_variant_get (v, "i", &self->width_mm);
+        }
+      else if (g_str_equal (s, "height-mm"))
+        {
+          g_variant_get (v, "i", &self->height_mm);
+        }
+      else if (g_str_equal (s, "is-underscanning"))
+        {
+          gboolean underscanning = FALSE;
+          g_variant_get (v, "b", &underscanning);
+          if (underscanning)
+            self->underscanning = UNDERSCANNING_ENABLED;
+          else
+            self->underscanning = UNDERSCANNING_DISABLED;
+        }
+      else if (g_str_equal (s, "max-screen-size"))
+        {
+          g_variant_get (v, "ii", &self->max_width, &self->max_height);
+        }
+      else if (g_str_equal (s, "is-builtin"))
+        {
+          g_variant_get (v, "b", &self->builtin);
+        }
+      else if (g_str_equal (s, "display-name"))
+        {
+          g_variant_get (v, "s", &self->display_name);
+        }
+    }
+
+  return self;
+}
+
+
+typedef enum _CcDisplayLayoutMode
+{
+  CC_DISPLAY_LAYOUT_MODE_LOGICAL = 1,
+  CC_DISPLAY_LAYOUT_MODE_PHYSICAL = 2
+} CcDisplayLayoutMode;
+
+typedef enum _CcDisplayConfigMethod
+{
+  CC_DISPLAY_CONFIG_METHOD_VERIFY = 0,
+  CC_DISPLAY_CONFIG_METHOD_TEMPORARY = 1,
+  CC_DISPLAY_CONFIG_METHOD_PERSISTENT = 2
+} CcDisplayConfigMethod;
+
+struct _CcDisplayConfigDBus
+{
+  CcDisplayConfig parent_instance;
+
+  GVariant *state;
+  GDBusConnection *connection;
+
+  int min_width;
+  int min_height;
+
+  guint32 serial;
+  gboolean supports_mirroring;
+  gboolean supports_changing_layout_mode;
+  gboolean global_scale_required;
+  CcDisplayLayoutMode layout_mode;
+
+  GList *monitors;
+  CcDisplayMonitorDBus *primary;
+
+  GHashTable *logical_monitors;
+
+  GList *clone_modes;
+};
+
+G_DEFINE_TYPE (CcDisplayConfigDBus,
+               cc_display_config_dbus,
+               CC_TYPE_DISPLAY_CONFIG)
+
+enum
+{
+  PROP_0,
+  PROP_STATE,
+  PROP_CONNECTION,
+};
+
+static GList *
+cc_display_config_dbus_get_monitors (CcDisplayConfig *pself)
+{
+  CcDisplayConfigDBus *self = CC_DISPLAY_CONFIG_DBUS (pself);
+
+  return self->monitors;
+}
+
+static GVariant *
+build_monitors_variant (GHashTable *monitors)
+{
+  GVariantBuilder builder;
+  GHashTableIter iter;
+  CcDisplayMonitorDBus *monitor;
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
+  g_hash_table_iter_init (&iter, monitors);
+
+  while (g_hash_table_iter_next (&iter, (void **) &monitor, NULL))
+    {
+      GVariantBuilder props_builder;
+      CcDisplayModeDBus *mode_dbus;
+
+      if (!monitor->current_mode)
+        continue;
+
+      g_variant_builder_init (&props_builder, G_VARIANT_TYPE ("a{sv}"));
+      g_variant_builder_add (&props_builder, "{sv}",
+                             "underscanning",
+                             g_variant_new_boolean (monitor->underscanning == UNDERSCANNING_ENABLED));
+
+      mode_dbus = CC_DISPLAY_MODE_DBUS (monitor->current_mode);
+      g_variant_builder_add (&builder, "(ss@*)",
+                             monitor->connector_name,
+                             mode_dbus->id,
+                             g_variant_builder_end (&props_builder));
+    }
+
+  return g_variant_builder_end (&builder);
+}
+
+static GVariant *
+build_logical_monitors_parameter (CcDisplayConfigDBus *self)
+{
+  GVariantBuilder builder;
+  GHashTableIter iter;
+  CcDisplayLogicalMonitor *logical_monitor;
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(iiduba(ssa{sv}))"));
+  g_hash_table_iter_init (&iter, self->logical_monitors);
+
+  while (g_hash_table_iter_next (&iter, (void **) &logical_monitor, NULL))
+    g_variant_builder_add (&builder, "(iidub@*)",
+                           logical_monitor->x,
+                           logical_monitor->y,
+                           logical_monitor->scale,
+                           logical_monitor->rotation,
+                           logical_monitor->primary,
+                           build_monitors_variant (logical_monitor->monitors));
+
+  return g_variant_builder_end (&builder);
+}
+
+static GVariant *
+build_apply_parameters (CcDisplayConfigDBus *self,
+                        CcDisplayConfigMethod method)
+{
+  GVariantBuilder props_builder;
+  g_variant_builder_init (&props_builder, G_VARIANT_TYPE ("a{sv}"));
+
+  if (self->supports_changing_layout_mode)
+    g_variant_builder_add (&props_builder, "{sv}",
+                           "layout-mode", g_variant_new_uint32 (self->layout_mode));
+
+  return g_variant_new ("(uu@*@*)",
+                        self->serial,
+                        method,
+                        build_logical_monitors_parameter (self),
+                        g_variant_builder_end (&props_builder));
+}
+
+static gboolean
+config_apply (CcDisplayConfigDBus *self,
+              CcDisplayConfigMethod method,
+              GError **error)
+{
+  g_autoptr(GVariant) retval = NULL;
+
+  cc_display_config_dbus_ensure_non_offset_coords (self);
+
+  retval = g_dbus_connection_call_sync (self->connection,
+                                        "org.gnome.Mutter.DisplayConfig",
+                                        "/org/gnome/Mutter/DisplayConfig",
+                                        "org.gnome.Mutter.DisplayConfig",
+                                        "ApplyMonitorsConfig",
+                                        build_apply_parameters (self, method),
+                                        NULL,
+                                        G_DBUS_CALL_FLAGS_NO_AUTO_START,
+                                        -1,
+                                        NULL,
+                                        error);
+  return retval != NULL;
+}
+
+static gboolean
+cc_display_config_dbus_is_applicable (CcDisplayConfig *pself)
+{
+  CcDisplayConfigDBus *self = CC_DISPLAY_CONFIG_DBUS (pself);
+  g_autoptr(GError) error = NULL;
+
+  if (!config_apply (self, CC_DISPLAY_CONFIG_METHOD_VERIFY, &error))
+    {
+      g_warning ("Config not applicable: %s", error->message);
+      return FALSE;
+    }
+  else
+    {
+      return TRUE;
+    }
+}
+
+static CcDisplayMonitorDBus *
+monitor_from_spec (CcDisplayConfigDBus *self,
+                   const gchar *connector,
+                   const gchar *vendor,
+                   const gchar *product,
+                   const gchar *serial)
+{
+  GList *l;
+  for (l = self->monitors; l != NULL; l = l->next)
+    {
+      CcDisplayMonitorDBus *m = l->data;
+      if (g_str_equal (m->connector_name, connector) &&
+          g_str_equal (m->vendor_name, vendor) &&
+          g_str_equal (m->product_name, product) &&
+          g_str_equal (m->product_serial, serial))
+        return m;
+    }
+  return NULL;
+}
+
+static gboolean
+cc_display_config_dbus_equal (CcDisplayConfig *pself,
+                              CcDisplayConfig *pother)
+{
+  CcDisplayConfigDBus *self = CC_DISPLAY_CONFIG_DBUS (pself);
+  CcDisplayConfigDBus *other = CC_DISPLAY_CONFIG_DBUS (pother);
+  GList *l;
+
+  g_return_val_if_fail (pself, FALSE);
+  g_return_val_if_fail (pother, FALSE);
+
+  cc_display_config_dbus_ensure_non_offset_coords (self);
+  cc_display_config_dbus_ensure_non_offset_coords (other);
+
+  for (l = self->monitors; l != NULL; l = l->next)
+    {
+      CcDisplayMonitorDBus *m1 = l->data;
+      CcDisplayMonitorDBus *m2 = monitor_from_spec (other,
+                                                    m1->connector_name,
+                                                    m1->vendor_name,
+                                                    m1->product_name,
+                                                    m1->product_serial);
+      if (!m2)
+        return FALSE;
+
+      if (m1->underscanning != m2->underscanning)
+        return FALSE;
+
+      if (!cc_display_logical_monitor_equal (m1->logical_monitor, m2->logical_monitor))
+        return FALSE;
+
+      /* Modes should not be compared if both monitors have no logical monitor. */
+      if (m1->logical_monitor == NULL && m2->logical_monitor == NULL)
+        continue;
+
+      if (!cc_display_mode_dbus_equal (CC_DISPLAY_MODE_DBUS (m1->current_mode),
+                                       CC_DISPLAY_MODE_DBUS (m2->current_mode)))
+        return FALSE;
+    }
+
+  return TRUE;
+}
+
+static void
+cc_display_config_dbus_set_primary (CcDisplayConfigDBus *self,
+                                    CcDisplayMonitorDBus *new_primary)
+{
+  if (self->primary == new_primary)
+    return;
+
+  if (!new_primary->logical_monitor)
+    return;
+
+  if (self->primary && self->primary->logical_monitor)
+    {
+      self->primary->logical_monitor->primary = FALSE;
+      g_signal_emit_by_name (self->primary, "primary");
+    }
+
+  self->primary = new_primary;
+  self->primary->logical_monitor->primary = TRUE;
+
+  g_signal_emit_by_name (self->primary, "primary");
+  g_signal_emit_by_name (self, "primary");
+}
+
+static void
+cc_display_config_dbus_unset_primary (CcDisplayConfigDBus *self,
+                                      CcDisplayMonitorDBus *old_primary)
+{
+  GList *l;
+
+  if (self->primary != old_primary)
+    return;
+
+  for (l = self->monitors; l != NULL; l = l->next)
+    {
+      CcDisplayMonitorDBus *monitor = l->data;
+      if (monitor->logical_monitor &&
+          monitor != old_primary)
+        {
+          cc_display_config_dbus_set_primary (self, monitor);
+          break;
+        }
+    }
+
+  if (self->primary == old_primary)
+    self->primary = NULL;
+}
+
+static gboolean
+cc_display_config_dbus_is_cloning (CcDisplayConfig *pself)
+{
+  CcDisplayConfigDBus *self = CC_DISPLAY_CONFIG_DBUS (pself);
+  guint n_active_monitors = 0;
+  GList *l;
+
+  for (l = self->monitors; l != NULL; l = l->next)
+    if (cc_display_monitor_is_active (CC_DISPLAY_MONITOR (l->data)))
+      n_active_monitors += 1;
+
+  return n_active_monitors > 1 && g_hash_table_size (self->logical_monitors) == 1;
+}
+
+static void
+cc_display_config_dbus_set_cloning (CcDisplayConfig *pself,
+                                    gboolean clone)
+{
+  CcDisplayConfigDBus *self = CC_DISPLAY_CONFIG_DBUS (pself);
+  gboolean is_cloning = cc_display_config_is_cloning (pself);
+  CcDisplayLogicalMonitor *logical_monitor;
+  GList *l;
+
+  if (clone && !is_cloning)
+    {
+      logical_monitor = g_object_new (CC_TYPE_DISPLAY_LOGICAL_MONITOR, NULL);
+      for (l = self->monitors; l != NULL; l = l->next)
+        cc_display_monitor_dbus_set_logical_monitor (CC_DISPLAY_MONITOR_DBUS (l->data),
+                                                     logical_monitor);
+      register_logical_monitor (self, logical_monitor);
+    }
+  else if (!clone && is_cloning)
+    {
+      for (l = self->monitors; l != NULL; l = l->next)
+        {
+          logical_monitor = g_object_new (CC_TYPE_DISPLAY_LOGICAL_MONITOR, NULL);
+          cc_display_monitor_dbus_set_logical_monitor (CC_DISPLAY_MONITOR_DBUS (l->data),
+                                                       logical_monitor);
+          register_logical_monitor (self, logical_monitor);
+        }
+      cc_display_config_dbus_make_linear (self);
+    }
+}
+
+static GList *
+cc_display_config_dbus_get_cloning_modes (CcDisplayConfig *pself)
+{
+  CcDisplayConfigDBus *self = CC_DISPLAY_CONFIG_DBUS (pself);
+
+  return self->clone_modes;
+}
+
+static gboolean
+cc_display_config_dbus_apply (CcDisplayConfig *pself,
+                              GError **error)
+{
+  CcDisplayConfigDBus *self = CC_DISPLAY_CONFIG_DBUS (pself);
+
+  return config_apply (self, CC_DISPLAY_CONFIG_METHOD_PERSISTENT, error);
+}
+
+static gboolean
+cc_display_config_dbus_is_layout_logical (CcDisplayConfig *pself)
+{
+  CcDisplayConfigDBus *self = CC_DISPLAY_CONFIG_DBUS (pself);
+
+  return self->layout_mode == CC_DISPLAY_LAYOUT_MODE_LOGICAL;
+}
+
+static gboolean
+is_scaled_mode_allowed (CcDisplayConfigDBus *self,
+                        CcDisplayMode       *pmode,
+                        double               scale)
+{
+  gint width, height;
+  CcDisplayModeDBus *mode = CC_DISPLAY_MODE_DBUS (pmode);
+
+  if (!cc_display_mode_dbus_is_supported_scale (pmode, scale))
+    return FALSE;
+
+  /* Do the math as if the monitor is always in landscape mode. */
+  width = round (mode->width / scale);
+  height = round (mode->height / scale);
+
+  return (MAX (width, height) >= self->min_width &&
+          MIN (width, height) >= self->min_height);
+}
+
+static gboolean
+is_scale_allowed_by_active_monitors (CcDisplayConfigDBus *self,
+                                     CcDisplayMode       *mode,
+                                     double               scale)
+{
+  GList *l;
+
+  for (l = self->monitors; l != NULL; l = l->next)
+    {
+      CcDisplayMonitorDBus *m = CC_DISPLAY_MONITOR_DBUS (l->data);
+
+      if (!cc_display_monitor_is_active (CC_DISPLAY_MONITOR (m)))
+        continue;
+
+      if (!is_scaled_mode_allowed (self, mode, scale))
+        return FALSE;
+    }
+
+  return TRUE;
+}
+
+static void
+cc_display_config_dbus_set_minimum_size (CcDisplayConfig *pself,
+                                         int              width,
+                                         int              height)
+{
+  CcDisplayConfigDBus *self = CC_DISPLAY_CONFIG_DBUS (pself);
+
+  g_assert (width >= 0 && height >= 0);
+
+  self->min_width = width;
+  self->min_height = height;
+}
+
+static gboolean
+cc_display_config_dbus_is_scaled_mode_valid (CcDisplayConfig *pself,
+                                             CcDisplayMode   *mode,
+                                             double           scale)
+{
+  CcDisplayConfigDBus *self = CC_DISPLAY_CONFIG_DBUS (pself);
+
+  if (self->global_scale_required || cc_display_config_is_cloning (pself))
+    return is_scale_allowed_by_active_monitors (self, mode, scale);
+
+  return is_scaled_mode_allowed (self, mode, scale);
+}
+
+static void
+cc_display_config_dbus_init (CcDisplayConfigDBus *self)
+{
+  self->serial = 0;
+  self->supports_mirroring = TRUE;
+  self->supports_changing_layout_mode = FALSE;
+  self->global_scale_required = FALSE;
+  self->layout_mode = CC_DISPLAY_LAYOUT_MODE_LOGICAL;
+  self->logical_monitors = g_hash_table_new (NULL, NULL);
+}
+
+static void
+gather_clone_modes (CcDisplayConfigDBus *self)
+{
+  guint n_monitors = g_list_length (self->monitors);
+  CcDisplayMonitorDBus *monitor;
+  GList *l;
+
+  if (n_monitors < 2)
+    return;
+
+  monitor = self->monitors->data;
+  for (l = monitor->modes; l != NULL; l = l->next)
+    {
+      CcDisplayModeDBus *mode = l->data;
+      gboolean valid = TRUE;
+      GList *ll;
+      for (ll = self->monitors->next; ll != NULL; ll = ll->next)
+        {
+          CcDisplayMonitorDBus *other_monitor = ll->data;
+          if (!cc_display_monitor_dbus_get_closest_mode (other_monitor, mode))
+            {
+              valid = FALSE;
+              break;
+            }
+        }
+      if (valid)
+        self->clone_modes = g_list_prepend (self->clone_modes, mode);
+    }
+}
+
+static void
+remove_logical_monitor (gpointer data,
+                        GObject *object)
+{
+  CcDisplayConfigDBus *self = CC_DISPLAY_CONFIG_DBUS (data);
+
+  g_hash_table_remove (self->logical_monitors, object);
+}
+
+static void
+register_logical_monitor (CcDisplayConfigDBus *self,
+                          CcDisplayLogicalMonitor *logical_monitor)
+{
+  g_hash_table_add (self->logical_monitors, logical_monitor);
+  g_object_weak_ref (G_OBJECT (logical_monitor), remove_logical_monitor, self);
+  g_object_unref (logical_monitor);
+}
+
+static void
+apply_global_scale_requirement (CcDisplayConfigDBus *self,
+                                CcDisplayMonitor    *monitor)
+{
+  GList *l;
+  double scale = cc_display_monitor_get_scale (monitor);
+
+  for (l = self->monitors; l != NULL; l = l->next)
+    {
+      CcDisplayMonitor *m = l->data;
+      if (m != monitor)
+        cc_display_monitor_set_scale (m, scale);
+    }
+}
+
+static void
+construct_monitors (CcDisplayConfigDBus *self,
+                    GVariantIter *monitors,
+                    GVariantIter *logical_monitors)
+{
+  while (TRUE)
+    {
+      CcDisplayMonitorDBus *monitor;
+      g_autoptr(GVariant) variant = NULL;
+
+      if (!g_variant_iter_next (monitors, "@"MONITOR_FORMAT, &variant))
+        break;
+
+      monitor = cc_display_monitor_dbus_new (variant, self);
+      self->monitors = g_list_prepend (self->monitors, monitor);
+
+      if (self->global_scale_required)
+        g_signal_connect_object (monitor, "scale",
+                                 G_CALLBACK (apply_global_scale_requirement),
+                                 self, G_CONNECT_SWAPPED);
+    }
+
+  while (TRUE)
+    {
+      g_autoptr(GVariant) variant = NULL;
+      CcDisplayLogicalMonitor *logical_monitor;
+      g_autoptr(GVariantIter) monitor_specs = NULL;
+      const gchar *s1, *s2, *s3, *s4;
+      gboolean primary;
+
+      if (!g_variant_iter_next (logical_monitors, "@"LOGICAL_MONITOR_FORMAT, &variant))
+        break;
+
+      logical_monitor = g_object_new (CC_TYPE_DISPLAY_LOGICAL_MONITOR, NULL);
+      g_variant_get (variant, LOGICAL_MONITOR_FORMAT,
+                     &logical_monitor->x,
+                     &logical_monitor->y,
+                     &logical_monitor->scale,
+                     &logical_monitor->rotation,
+                     &primary,
+                     &monitor_specs,
+                     NULL);
+
+      while (g_variant_iter_next (monitor_specs, "(&s&s&s&s)", &s1, &s2, &s3, &s4))
+        {
+          CcDisplayMonitorDBus *m = monitor_from_spec (self, s1, s2, s3, s4);
+          if (!m)
+            {
+              g_warning ("Couldn't find monitor given spec: %s, %s, %s, %s",
+                         s1, s2, s3, s4);
+              continue;
+            }
+
+          cc_display_monitor_dbus_set_logical_monitor (m, logical_monitor);
+        }
+
+      if (g_hash_table_size (logical_monitor->monitors) > 0)
+        {
+          if (primary)
+            {
+              CcDisplayMonitorDBus *m = NULL;
+              GHashTableIter iter;
+              g_hash_table_iter_init (&iter, logical_monitor->monitors);
+              g_hash_table_iter_next (&iter, (void **) &m, NULL);
+
+              cc_display_config_dbus_set_primary (self, m);
+            }
+        }
+      else
+        {
+          g_warning ("Got an empty logical monitor, ignoring");
+        }
+
+      register_logical_monitor (self, logical_monitor);
+    }
+
+  gather_clone_modes (self);
+}
+
+static void
+cc_display_config_dbus_constructed (GObject *object)
+{
+  CcDisplayConfigDBus *self = CC_DISPLAY_CONFIG_DBUS (object);
+  g_autoptr(GVariantIter) monitors = NULL;
+  g_autoptr(GVariantIter) logical_monitors = NULL;
+  g_autoptr(GVariantIter) props = NULL;
+
+  g_variant_get (self->state,
+                 CURRENT_STATE_FORMAT,
+                 &self->serial,
+                 &monitors,
+                 &logical_monitors,
+                 &props);
+
+  while (TRUE)
+    {
+      const char *s;
+      g_autoptr(GVariant) v = NULL;
+
+      if (!g_variant_iter_next (props, "{&sv}", &s, &v))
+       break;
+
+      if (g_str_equal (s, "supports-mirroring"))
+        {
+          g_variant_get (v, "b", &self->supports_mirroring);
+        }
+      else if (g_str_equal (s, "supports-changing-layout-mode"))
+        {
+          g_variant_get (v, "b", &self->supports_changing_layout_mode);
+        }
+      else if (g_str_equal (s, "global-scale-required"))
+        {
+          g_variant_get (v, "b", &self->global_scale_required);
+        }
+      else if (g_str_equal (s, "layout-mode"))
+        {
+          guint32 u = 0;
+          g_variant_get (v, "u", &u);
+          if (u >= CC_DISPLAY_LAYOUT_MODE_LOGICAL &&
+              u <= CC_DISPLAY_LAYOUT_MODE_PHYSICAL)
+            self->layout_mode = u;
+        }
+    }
+
+  construct_monitors (self, monitors, logical_monitors);
+
+  G_OBJECT_CLASS (cc_display_config_dbus_parent_class)->constructed (object);
+}
+
+static void
+cc_display_config_dbus_set_property (GObject      *object,
+                                     guint         prop_id,
+                                     const GValue *value,
+                                     GParamSpec   *pspec)
+{
+  CcDisplayConfigDBus *self = CC_DISPLAY_CONFIG_DBUS (object);
+
+  switch (prop_id)
+    {
+    case PROP_STATE:
+      self->state = g_value_dup_variant (value);
+      break;
+    case PROP_CONNECTION:
+      self->connection = g_value_dup_object (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+cc_display_config_dbus_get_property (GObject    *object,
+                                     guint       prop_id,
+                                     GValue     *value,
+                                     GParamSpec *pspec)
+{
+  CcDisplayConfigDBus *self = CC_DISPLAY_CONFIG_DBUS (object);
+
+  switch (prop_id)
+    {
+    case PROP_STATE:
+      g_value_set_variant (value, self->state);
+      break;
+    case PROP_CONNECTION:
+      g_value_set_object (value, self->connection);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+cc_display_config_dbus_finalize (GObject *object)
+{
+  CcDisplayConfigDBus *self = CC_DISPLAY_CONFIG_DBUS (object);
+
+  g_clear_pointer (&self->state, g_variant_unref);
+  g_clear_object (&self->connection);
+
+  g_list_foreach (self->monitors, (GFunc) g_object_unref, NULL);
+  g_clear_pointer (&self->monitors, g_list_free);
+  g_clear_pointer (&self->logical_monitors, g_hash_table_destroy);
+  g_clear_pointer (&self->clone_modes, g_list_free);
+
+  G_OBJECT_CLASS (cc_display_config_dbus_parent_class)->finalize (object);
+}
+
+static void
+cc_display_config_dbus_class_init (CcDisplayConfigDBusClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  CcDisplayConfigClass *parent_class = CC_DISPLAY_CONFIG_CLASS (klass);
+  GParamSpec *pspec;
+
+  gobject_class->constructed = cc_display_config_dbus_constructed;
+  gobject_class->set_property = cc_display_config_dbus_set_property;
+  gobject_class->get_property = cc_display_config_dbus_get_property;
+  gobject_class->finalize = cc_display_config_dbus_finalize;
+
+  parent_class->get_monitors = cc_display_config_dbus_get_monitors;
+  parent_class->is_applicable = cc_display_config_dbus_is_applicable;
+  parent_class->equal = cc_display_config_dbus_equal;
+  parent_class->apply = cc_display_config_dbus_apply;
+  parent_class->is_cloning = cc_display_config_dbus_is_cloning;
+  parent_class->set_cloning = cc_display_config_dbus_set_cloning;
+  parent_class->get_cloning_modes = cc_display_config_dbus_get_cloning_modes;
+  parent_class->is_layout_logical = cc_display_config_dbus_is_layout_logical;
+  parent_class->is_scaled_mode_valid = cc_display_config_dbus_is_scaled_mode_valid;
+  parent_class->set_minimum_size = cc_display_config_dbus_set_minimum_size;
+
+  pspec = g_param_spec_variant ("state",
+                                "GVariant",
+                                "GVariant",
+                                G_VARIANT_TYPE (CURRENT_STATE_FORMAT),
+                                NULL,
+                                G_PARAM_READWRITE |
+                                G_PARAM_STATIC_STRINGS |
+                                G_PARAM_CONSTRUCT_ONLY);
+  g_object_class_install_property (gobject_class, PROP_STATE, pspec);
+
+  pspec = g_param_spec_object ("connection",
+                               "GDBusConnection",
+                               "GDBusConnection",
+                                G_TYPE_DBUS_CONNECTION,
+                                G_PARAM_READWRITE |
+                                G_PARAM_STATIC_STRINGS |
+                                G_PARAM_CONSTRUCT_ONLY);
+  g_object_class_install_property (gobject_class, PROP_CONNECTION, pspec);
+}
+
+static gint
+sort_x_axis (gconstpointer a, gconstpointer b)
+{
+  const CcDisplayLogicalMonitor *ma = a;
+  const CcDisplayLogicalMonitor *mb = b;
+  return ma->x - mb->x;
+}
+
+static gint
+sort_y_axis (gconstpointer a, gconstpointer b)
+{
+  const CcDisplayLogicalMonitor *ma = a;
+  const CcDisplayLogicalMonitor *mb = b;
+  return ma->y - mb->y;
+}
+
+static void
+add_x_delta (gpointer d1, gpointer d2)
+{
+  CcDisplayLogicalMonitor *m = d1;
+  int delta = GPOINTER_TO_INT (d2);
+  m->x += delta;
+}
+
+static gboolean
+logical_monitor_is_rotated (CcDisplayLogicalMonitor *lm)
+{
+  switch (lm->rotation)
+    {
+    case CC_DISPLAY_ROTATION_90:
+    case CC_DISPLAY_ROTATION_270:
+    case CC_DISPLAY_ROTATION_90_FLIPPED:
+    case CC_DISPLAY_ROTATION_270_FLIPPED:
+      return TRUE;
+    default:
+      return FALSE;
+    }
+}
+
+static int
+logical_monitor_width (CcDisplayLogicalMonitor *lm)
+{
+  CcDisplayMonitorDBus *monitor;
+  CcDisplayModeDBus *mode;
+  GHashTableIter iter;
+  int width;
+
+  g_hash_table_iter_init (&iter, lm->monitors);
+  g_hash_table_iter_next (&iter, (void **) &monitor, NULL);
+  mode = CC_DISPLAY_MODE_DBUS (monitor->current_mode);
+  if (logical_monitor_is_rotated (lm))
+    width = mode ? mode->height : 0;
+  else
+    width = mode ? mode->width : 0;
+
+  if (monitor->config->layout_mode == CC_DISPLAY_LAYOUT_MODE_LOGICAL)
+    return round (width / lm->scale);
+  else
+    return width;
+}
+
+static void
+add_y_delta (gpointer d1, gpointer d2)
+{
+  CcDisplayLogicalMonitor *m = d1;
+  int delta = GPOINTER_TO_INT (d2);
+  m->y += delta;
+}
+
+static void
+cc_display_config_dbus_ensure_non_offset_coords (CcDisplayConfigDBus *self)
+{
+  GList *x_axis, *y_axis;
+  CcDisplayLogicalMonitor *m;
+
+  if (g_hash_table_size (self->logical_monitors) == 0)
+    return;
+
+  x_axis = g_hash_table_get_keys (self->logical_monitors);
+  x_axis = g_list_sort (x_axis, sort_x_axis);
+  y_axis = g_hash_table_get_keys (self->logical_monitors);
+  y_axis = g_list_sort (y_axis, sort_y_axis);
+
+  m = x_axis->data;
+  if (m->x != 0)
+    g_list_foreach (x_axis, add_x_delta, GINT_TO_POINTER (- m->x));
+
+  m = y_axis->data;
+  if (m->y != 0)
+    g_list_foreach (y_axis, add_y_delta, GINT_TO_POINTER (- m->y));
+
+  g_list_free (x_axis);
+  g_list_free (y_axis);
+}
+
+static void
+cc_display_config_dbus_append_right (CcDisplayConfigDBus *self,
+                                     CcDisplayLogicalMonitor *monitor)
+{
+  GList *x_axis;
+  CcDisplayLogicalMonitor *last;
+
+  if (g_hash_table_size (self->logical_monitors) == 0)
+    {
+      monitor->x = 0;
+      monitor->y = 0;
+      return;
+    }
+
+  x_axis = g_hash_table_get_keys (self->logical_monitors);
+  x_axis = g_list_sort (x_axis, sort_x_axis);
+  last = g_list_last (x_axis)->data;
+  monitor->x = last->x + logical_monitor_width (last);
+  monitor->y = last->y;
+
+  g_list_free (x_axis);
+}
+
+static void
+cc_display_config_dbus_make_linear (CcDisplayConfigDBus *self)
+{
+  CcDisplayLogicalMonitor *primary;
+  GList *logical_monitors, *l;
+  int x;
+
+  if (self->primary && self->primary->logical_monitor)
+    {
+      primary = self->primary->logical_monitor;
+      primary->x = primary->y = 0;
+      x = logical_monitor_width (primary);
+    }
+  else
+    {
+      primary = NULL;
+      x = 0;
+    }
+
+  logical_monitors = g_hash_table_get_keys (self->logical_monitors);
+  for (l = logical_monitors; l != NULL; l = l->next)
+    {
+      CcDisplayLogicalMonitor *m = l->data;
+
+      if (m == primary)
+        continue;
+
+      m->x = x;
+      m->y = 0;
+      x += logical_monitor_width (m);
+    }
+
+  g_list_free (logical_monitors);
+}
diff --git a/gnome-initial-setup/pages/display/cc-display-config-dbus.h 
b/gnome-initial-setup/pages/display/cc-display-config-dbus.h
new file mode 100644
index 00000000..8609087c
--- /dev/null
+++ b/gnome-initial-setup/pages/display/cc-display-config-dbus.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#pragma once
+
+#include <glib-object.h>
+
+#include "cc-display-config.h"
+
+G_BEGIN_DECLS
+
+#define CC_TYPE_DISPLAY_MODE_DBUS (cc_display_mode_dbus_get_type ())
+G_DECLARE_FINAL_TYPE (CcDisplayModeDBus, cc_display_mode_dbus,
+                      CC, DISPLAY_MODE_DBUS, CcDisplayMode)
+
+#define CC_TYPE_DISPLAY_MONITOR_DBUS (cc_display_monitor_dbus_get_type ())
+G_DECLARE_FINAL_TYPE (CcDisplayMonitorDBus, cc_display_monitor_dbus,
+                      CC, DISPLAY_MONITOR_DBUS, CcDisplayMonitor)
+
+#define CC_TYPE_DISPLAY_CONFIG_DBUS (cc_display_config_dbus_get_type ())
+G_DECLARE_FINAL_TYPE (CcDisplayConfigDBus, cc_display_config_dbus,
+                      CC, DISPLAY_CONFIG_DBUS, CcDisplayConfig)
+
+G_END_DECLS
diff --git a/gnome-initial-setup/pages/display/cc-display-config-manager-dbus.c 
b/gnome-initial-setup/pages/display/cc-display-config-manager-dbus.c
new file mode 100644
index 00000000..653bea0b
--- /dev/null
+++ b/gnome-initial-setup/pages/display/cc-display-config-manager-dbus.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include "cc-display-config-dbus.h"
+#include "cc-display-config-manager-dbus.h"
+
+#include <gio/gio.h>
+
+struct _CcDisplayConfigManagerDBus
+{
+  CcDisplayConfigManager parent_instance;
+
+  GCancellable *cancellable;
+  GDBusConnection *connection;
+  guint monitors_changed_id;
+
+  GVariant *current_state;
+};
+
+G_DEFINE_TYPE (CcDisplayConfigManagerDBus,
+               cc_display_config_manager_dbus,
+               CC_TYPE_DISPLAY_CONFIG_MANAGER)
+
+static CcDisplayConfig *
+cc_display_config_manager_dbus_get_current (CcDisplayConfigManager *pself)
+{
+  CcDisplayConfigManagerDBus *self = CC_DISPLAY_CONFIG_MANAGER_DBUS (pself);
+
+  if (!self->current_state)
+    return NULL;
+
+  return g_object_new (CC_TYPE_DISPLAY_CONFIG_DBUS,
+                       "state", self->current_state,
+                       "connection", self->connection, NULL);
+}
+
+static void
+got_current_state (GObject      *object,
+                   GAsyncResult *result,
+                   gpointer      data)
+{
+  CcDisplayConfigManagerDBus *self;
+  GVariant *variant;
+  g_autoptr(GError) error = NULL;
+
+  variant = g_dbus_connection_call_finish (G_DBUS_CONNECTION (object),
+                                           result, &error);
+  if (!variant)
+    {
+      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        {
+          self = CC_DISPLAY_CONFIG_MANAGER_DBUS (data);
+          g_clear_pointer (&self->current_state, g_variant_unref);
+          _cc_display_config_manager_emit_changed (CC_DISPLAY_CONFIG_MANAGER (data));
+          g_warning ("Error calling GetCurrentState: %s", error->message);
+        }
+      return;
+    }
+
+  self = CC_DISPLAY_CONFIG_MANAGER_DBUS (data);
+  g_clear_pointer (&self->current_state, g_variant_unref);
+  self->current_state = variant;
+
+  _cc_display_config_manager_emit_changed (CC_DISPLAY_CONFIG_MANAGER (self));
+}
+
+static void
+get_current_state (CcDisplayConfigManagerDBus *self)
+{
+  g_dbus_connection_call (self->connection,
+                          "org.gnome.Mutter.DisplayConfig",
+                          "/org/gnome/Mutter/DisplayConfig",
+                          "org.gnome.Mutter.DisplayConfig",
+                          "GetCurrentState",
+                          NULL,
+                          NULL,
+                          G_DBUS_CALL_FLAGS_NO_AUTO_START,
+                          -1,
+                          self->cancellable,
+                          got_current_state,
+                          self);
+}
+
+static void
+monitors_changed (GDBusConnection *connection,
+                  const gchar     *sender_name,
+                  const gchar     *object_path,
+                  const gchar     *interface_name,
+                  const gchar     *signal_name,
+                  GVariant        *parameters,
+                  gpointer         data)
+{
+  CcDisplayConfigManagerDBus *self = CC_DISPLAY_CONFIG_MANAGER_DBUS (data);
+  get_current_state (self);
+}
+
+static void
+bus_gotten (GObject      *object,
+            GAsyncResult *result,
+            gpointer      data)
+{
+  CcDisplayConfigManagerDBus *self;
+  GDBusConnection *connection;
+  g_autoptr(GError) error = NULL;
+
+  connection = g_bus_get_finish (result, &error);
+  if (!connection)
+    {
+      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        {
+          _cc_display_config_manager_emit_changed (CC_DISPLAY_CONFIG_MANAGER (data));
+          g_warning ("Error obtaining DBus connection: %s", error->message);
+        }
+      return;
+    }
+
+  self = CC_DISPLAY_CONFIG_MANAGER_DBUS (data);
+  self->connection = connection;
+  self->monitors_changed_id =
+    g_dbus_connection_signal_subscribe (self->connection,
+                                        "org.gnome.Mutter.DisplayConfig",
+                                        "org.gnome.Mutter.DisplayConfig",
+                                        "MonitorsChanged",
+                                        "/org/gnome/Mutter/DisplayConfig",
+                                        NULL,
+                                        G_DBUS_SIGNAL_FLAGS_NONE,
+                                        monitors_changed,
+                                        self,
+                                        NULL);
+  get_current_state (self);
+}
+
+static void
+cc_display_config_manager_dbus_init (CcDisplayConfigManagerDBus *self)
+{
+  self->cancellable = g_cancellable_new ();
+  g_bus_get (G_BUS_TYPE_SESSION, self->cancellable, bus_gotten, self);
+}
+
+static void
+cc_display_config_manager_dbus_finalize (GObject *object)
+{
+  CcDisplayConfigManagerDBus *self = CC_DISPLAY_CONFIG_MANAGER_DBUS (object);
+
+  g_cancellable_cancel (self->cancellable);
+  g_clear_object (&self->cancellable);
+
+  if (self->monitors_changed_id && self->connection)
+    g_dbus_connection_signal_unsubscribe (self->connection,
+                                          self->monitors_changed_id);
+  g_clear_object (&self->connection);
+  g_clear_pointer (&self->current_state, g_variant_unref);
+
+  G_OBJECT_CLASS (cc_display_config_manager_dbus_parent_class)->finalize (object);
+}
+
+static void
+cc_display_config_manager_dbus_class_init (CcDisplayConfigManagerDBusClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  CcDisplayConfigManagerClass *parent_class = CC_DISPLAY_CONFIG_MANAGER_CLASS (klass);
+
+  gobject_class->finalize = cc_display_config_manager_dbus_finalize;
+
+  parent_class->get_current = cc_display_config_manager_dbus_get_current;
+}
+
+CcDisplayConfigManager *
+cc_display_config_manager_dbus_new (void)
+{
+  return g_object_new (CC_TYPE_DISPLAY_CONFIG_MANAGER_DBUS, NULL);
+}
diff --git a/gnome-initial-setup/pages/display/cc-display-config-manager-dbus.h 
b/gnome-initial-setup/pages/display/cc-display-config-manager-dbus.h
new file mode 100644
index 00000000..a0995981
--- /dev/null
+++ b/gnome-initial-setup/pages/display/cc-display-config-manager-dbus.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#pragma once
+
+#include <glib-object.h>
+
+#include "cc-display-config-manager.h"
+
+G_BEGIN_DECLS
+
+#define CC_TYPE_DISPLAY_CONFIG_MANAGER_DBUS (cc_display_config_manager_dbus_get_type ())
+G_DECLARE_FINAL_TYPE (CcDisplayConfigManagerDBus, cc_display_config_manager_dbus,
+                      CC, DISPLAY_CONFIG_MANAGER_DBUS, CcDisplayConfigManager)
+
+CcDisplayConfigManager * cc_display_config_manager_dbus_new (void);
+
+G_END_DECLS
diff --git a/gnome-initial-setup/pages/display/cc-display-config-manager.c 
b/gnome-initial-setup/pages/display/cc-display-config-manager.c
new file mode 100644
index 00000000..0da298a2
--- /dev/null
+++ b/gnome-initial-setup/pages/display/cc-display-config-manager.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include "cc-display-config-manager.h"
+
+G_DEFINE_TYPE (CcDisplayConfigManager,
+               cc_display_config_manager,
+               G_TYPE_OBJECT)
+
+enum
+{
+  CONFIG_MANAGER_CHANGED,
+  N_CONFIG_MANAGER_SIGNALS,
+};
+
+static guint config_manager_signals[N_CONFIG_MANAGER_SIGNALS] = { 0 };
+
+static void
+cc_display_config_manager_init (CcDisplayConfigManager *self)
+{
+}
+
+static void
+cc_display_config_manager_class_init (CcDisplayConfigManagerClass *klass)
+{
+  config_manager_signals[CONFIG_MANAGER_CHANGED] =
+    g_signal_new ("changed",
+                  CC_TYPE_DISPLAY_CONFIG_MANAGER,
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+}
+
+void
+_cc_display_config_manager_emit_changed (CcDisplayConfigManager *self)
+{
+  g_signal_emit (self, config_manager_signals[CONFIG_MANAGER_CHANGED], 0);
+}
+
+CcDisplayConfig *
+cc_display_config_manager_get_current (CcDisplayConfigManager *self)
+{
+  return CC_DISPLAY_CONFIG_MANAGER_GET_CLASS (self)->get_current (self);
+}
diff --git a/gnome-initial-setup/pages/display/cc-display-config-manager.h 
b/gnome-initial-setup/pages/display/cc-display-config-manager.h
new file mode 100644
index 00000000..1e1b3637
--- /dev/null
+++ b/gnome-initial-setup/pages/display/cc-display-config-manager.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#pragma once
+
+#include <glib-object.h>
+
+#include "cc-display-config.h"
+
+G_BEGIN_DECLS
+
+#define CC_TYPE_DISPLAY_CONFIG_MANAGER (cc_display_config_manager_get_type ())
+G_DECLARE_DERIVABLE_TYPE (CcDisplayConfigManager, cc_display_config_manager,
+                          CC, DISPLAY_CONFIG_MANAGER, GObject)
+
+struct _CcDisplayConfigManagerClass
+{
+  GObjectClass parent_class;
+
+  CcDisplayConfig * (*get_current) (CcDisplayConfigManager *self);
+};
+
+CcDisplayConfig * cc_display_config_manager_get_current (CcDisplayConfigManager *self);
+
+void _cc_display_config_manager_emit_changed (CcDisplayConfigManager *self);
+
+G_END_DECLS
diff --git a/gnome-initial-setup/pages/display/cc-display-config.c 
b/gnome-initial-setup/pages/display/cc-display-config.c
new file mode 100644
index 00000000..a91930ad
--- /dev/null
+++ b/gnome-initial-setup/pages/display/cc-display-config.c
@@ -0,0 +1,632 @@
+/*
+ * Copyright (C) 2016  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <gio/gio.h>
+#include <math.h>
+#include "cc-display-config.h"
+
+static const double known_diagonals[] = {
+  12.1,
+  13.3,
+  15.6
+};
+
+static char *
+diagonal_to_str (double d)
+{
+  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_size_string (int width_mm,
+                          int height_mm)
+{
+  char *inches = NULL;
+
+  if (width_mm > 0 && height_mm > 0)
+    {
+      double d = sqrt (width_mm * width_mm + height_mm * height_mm);
+
+      inches = diagonal_to_str (d / 25.4);
+    }
+
+  return inches;
+}
+
+static char *
+make_output_ui_name (CcDisplayMonitor *output)
+{
+  int width_mm, height_mm;
+  g_autofree char *size = NULL;
+
+  cc_display_monitor_get_physical_size (output, &width_mm, &height_mm);
+  size = make_display_size_string (width_mm, height_mm);
+  if (size)
+    return g_strdup_printf ("%s (%s)", cc_display_monitor_get_display_name (output), size);
+  else
+    return g_strdup_printf ("%s", cc_display_monitor_get_display_name (output));
+}
+
+
+
+G_DEFINE_TYPE (CcDisplayMode,
+               cc_display_mode,
+               G_TYPE_OBJECT)
+
+static void
+cc_display_mode_init (CcDisplayMode *self)
+{
+}
+
+static void
+cc_display_mode_class_init (CcDisplayModeClass *klass)
+{
+}
+
+const char *
+cc_display_mode_get_name (CcDisplayMode *self)
+{
+  return CC_DISPLAY_MODE_GET_CLASS (self)->get_name (self);
+}
+
+void
+cc_display_mode_get_resolution (CcDisplayMode *self, int *w, int *h)
+{
+  return CC_DISPLAY_MODE_GET_CLASS (self)->get_resolution (self, w, h);
+}
+
+const double *
+cc_display_mode_get_supported_scales (CcDisplayMode *self)
+{
+  return CC_DISPLAY_MODE_GET_CLASS (self)->get_supported_scales (self);
+}
+
+double
+cc_display_mode_get_preferred_scale (CcDisplayMode *self)
+{
+  return CC_DISPLAY_MODE_GET_CLASS (self)->get_preferred_scale (self);
+}
+
+gboolean
+cc_display_mode_is_interlaced (CcDisplayMode *self)
+{
+  return CC_DISPLAY_MODE_GET_CLASS (self)->is_interlaced (self);
+}
+
+int
+cc_display_mode_get_freq (CcDisplayMode *self)
+{
+  return CC_DISPLAY_MODE_GET_CLASS (self)->get_freq (self);
+}
+
+double
+cc_display_mode_get_freq_f (CcDisplayMode *self)
+{
+  return CC_DISPLAY_MODE_GET_CLASS (self)->get_freq_f (self);
+}
+
+
+struct _CcDisplayMonitorPrivate {
+  int ui_number;
+  gchar *ui_name;
+  gchar *ui_number_name;
+  gboolean is_usable;
+};
+typedef struct _CcDisplayMonitorPrivate CcDisplayMonitorPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (CcDisplayMonitor,
+                            cc_display_monitor,
+                            G_TYPE_OBJECT)
+
+static void
+cc_display_monitor_init (CcDisplayMonitor *self)
+{
+  CcDisplayMonitorPrivate *priv = cc_display_monitor_get_instance_private (self);
+
+  priv->ui_number = 0;
+  priv->ui_name = NULL;
+  priv->ui_number_name = NULL;
+  priv->is_usable = TRUE;
+}
+
+static void
+cc_display_monitor_finalize (GObject *object)
+{
+  CcDisplayMonitor *self = CC_DISPLAY_MONITOR (object);
+  CcDisplayMonitorPrivate *priv = cc_display_monitor_get_instance_private (self);
+
+  g_clear_pointer (&priv->ui_name, g_free);
+  g_clear_pointer (&priv->ui_number_name, g_free);
+
+  G_OBJECT_CLASS (cc_display_monitor_parent_class)->finalize (object);
+}
+
+static void
+cc_display_monitor_class_init (CcDisplayMonitorClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = cc_display_monitor_finalize;
+
+  g_signal_new ("rotation",
+                CC_TYPE_DISPLAY_MONITOR,
+                G_SIGNAL_RUN_LAST,
+                0, NULL, NULL, NULL,
+                G_TYPE_NONE, 0);
+  g_signal_new ("mode",
+                CC_TYPE_DISPLAY_MONITOR,
+                G_SIGNAL_RUN_LAST,
+                0, NULL, NULL, NULL,
+                G_TYPE_NONE, 0);
+  g_signal_new ("primary",
+                CC_TYPE_DISPLAY_MONITOR,
+                G_SIGNAL_RUN_LAST,
+                0, NULL, NULL, NULL,
+                G_TYPE_NONE, 0);
+  g_signal_new ("active",
+                CC_TYPE_DISPLAY_MONITOR,
+                G_SIGNAL_RUN_LAST,
+                0, NULL, NULL, NULL,
+                G_TYPE_NONE, 0);
+  g_signal_new ("scale",
+                CC_TYPE_DISPLAY_MONITOR,
+                G_SIGNAL_RUN_LAST,
+                0, NULL, NULL, NULL,
+                G_TYPE_NONE, 0);
+  g_signal_new ("position-changed",
+                CC_TYPE_DISPLAY_MONITOR,
+                G_SIGNAL_RUN_LAST,
+                0, NULL, NULL, NULL,
+                G_TYPE_NONE, 0);
+  g_signal_new ("is-usable",
+                CC_TYPE_DISPLAY_MONITOR,
+                G_SIGNAL_RUN_LAST,
+                0, NULL, NULL, NULL,
+                G_TYPE_NONE, 0);
+}
+
+const char *
+cc_display_monitor_get_display_name (CcDisplayMonitor *self)
+{
+  return CC_DISPLAY_MONITOR_GET_CLASS (self)->get_display_name (self);
+}
+
+const char *
+cc_display_monitor_get_connector_name (CcDisplayMonitor *self)
+{
+  return CC_DISPLAY_MONITOR_GET_CLASS (self)->get_connector_name (self);
+}
+
+gboolean
+cc_display_monitor_is_builtin (CcDisplayMonitor *self)
+{
+  return CC_DISPLAY_MONITOR_GET_CLASS (self)->is_builtin (self);
+}
+
+gboolean
+cc_display_monitor_is_primary (CcDisplayMonitor *self)
+{
+  return CC_DISPLAY_MONITOR_GET_CLASS (self)->is_primary (self);
+}
+
+void
+cc_display_monitor_set_primary (CcDisplayMonitor *self, gboolean primary)
+{
+  return CC_DISPLAY_MONITOR_GET_CLASS (self)->set_primary (self, primary);
+}
+
+gboolean
+cc_display_monitor_is_active (CcDisplayMonitor *self)
+{
+  return CC_DISPLAY_MONITOR_GET_CLASS (self)->is_active (self);
+}
+
+void
+cc_display_monitor_set_active (CcDisplayMonitor *self, gboolean active)
+{
+  return CC_DISPLAY_MONITOR_GET_CLASS (self)->set_active (self, active);
+}
+
+CcDisplayRotation
+cc_display_monitor_get_rotation (CcDisplayMonitor *self)
+{
+  return CC_DISPLAY_MONITOR_GET_CLASS (self)->get_rotation (self);
+}
+
+void
+cc_display_monitor_set_rotation (CcDisplayMonitor *self,
+                                 CcDisplayRotation rotation)
+{
+  return CC_DISPLAY_MONITOR_GET_CLASS (self)->set_rotation (self, rotation);
+}
+
+gboolean
+cc_display_monitor_supports_rotation (CcDisplayMonitor *self, CcDisplayRotation r)
+{
+  return CC_DISPLAY_MONITOR_GET_CLASS (self)->supports_rotation (self, r);
+}
+
+void
+cc_display_monitor_get_physical_size (CcDisplayMonitor *self, int *w, int *h)
+{
+  return CC_DISPLAY_MONITOR_GET_CLASS (self)->get_physical_size (self, w, h);
+}
+
+void
+cc_display_monitor_get_geometry (CcDisplayMonitor *self, int *x, int *y, int *w, int *h)
+{
+  return CC_DISPLAY_MONITOR_GET_CLASS (self)->get_geometry (self, x, y, w, h);
+}
+
+CcDisplayMode *
+cc_display_monitor_get_mode (CcDisplayMonitor *self)
+{
+  return CC_DISPLAY_MONITOR_GET_CLASS (self)->get_mode (self);
+}
+
+CcDisplayMode *
+cc_display_monitor_get_preferred_mode (CcDisplayMonitor *self)
+{
+  return CC_DISPLAY_MONITOR_GET_CLASS (self)->get_preferred_mode (self);
+}
+
+guint32
+cc_display_monitor_get_id (CcDisplayMonitor *self)
+{
+  return CC_DISPLAY_MONITOR_GET_CLASS (self)->get_id (self);
+}
+
+GList *
+cc_display_monitor_get_modes (CcDisplayMonitor *self)
+{
+  return CC_DISPLAY_MONITOR_GET_CLASS (self)->get_modes (self);
+}
+
+gboolean
+cc_display_monitor_supports_underscanning (CcDisplayMonitor *self)
+{
+  return CC_DISPLAY_MONITOR_GET_CLASS (self)->supports_underscanning (self);
+}
+
+gboolean
+cc_display_monitor_get_underscanning (CcDisplayMonitor *self)
+{
+  return CC_DISPLAY_MONITOR_GET_CLASS (self)->get_underscanning (self);
+}
+
+void
+cc_display_monitor_set_underscanning (CcDisplayMonitor *self,
+                                      gboolean underscanning)
+{
+  return CC_DISPLAY_MONITOR_GET_CLASS (self)->set_underscanning (self, underscanning);
+}
+
+void
+cc_display_monitor_set_mode (CcDisplayMonitor *self, CcDisplayMode *m)
+{
+  return CC_DISPLAY_MONITOR_GET_CLASS (self)->set_mode (self, m);
+}
+
+void
+cc_display_monitor_set_position (CcDisplayMonitor *self, int x, int y)
+{
+  return CC_DISPLAY_MONITOR_GET_CLASS (self)->set_position (self, x, y);
+}
+
+double
+cc_display_monitor_get_scale (CcDisplayMonitor *self)
+{
+  return CC_DISPLAY_MONITOR_GET_CLASS (self)->get_scale (self);
+}
+
+void
+cc_display_monitor_set_scale (CcDisplayMonitor *self, double s)
+{
+  return CC_DISPLAY_MONITOR_GET_CLASS (self)->set_scale (self, s);
+}
+
+gboolean
+cc_display_monitor_is_useful (CcDisplayMonitor *self)
+{
+  CcDisplayMonitorPrivate *priv = cc_display_monitor_get_instance_private (self);
+
+  return priv->is_usable &&
+         cc_display_monitor_is_active (self);
+}
+
+gboolean
+cc_display_monitor_is_usable (CcDisplayMonitor *self)
+{
+  CcDisplayMonitorPrivate *priv = cc_display_monitor_get_instance_private (self);
+
+  return priv->is_usable;
+}
+
+void
+cc_display_monitor_set_usable (CcDisplayMonitor *self, gboolean is_usable)
+{
+  CcDisplayMonitorPrivate *priv = cc_display_monitor_get_instance_private (self);
+
+  priv->is_usable = is_usable;
+
+  g_signal_emit_by_name (self, "is-usable");
+}
+
+gint
+cc_display_monitor_get_ui_number (CcDisplayMonitor *self)
+{
+  CcDisplayMonitorPrivate *priv = cc_display_monitor_get_instance_private (self);
+
+  return priv->ui_number;
+}
+
+const char *
+cc_display_monitor_get_ui_name (CcDisplayMonitor *self)
+{
+  CcDisplayMonitorPrivate *priv = cc_display_monitor_get_instance_private (self);
+
+  return priv->ui_name;
+}
+
+const char *
+cc_display_monitor_get_ui_number_name (CcDisplayMonitor *self)
+{
+  CcDisplayMonitorPrivate *priv = cc_display_monitor_get_instance_private (self);
+
+  return priv->ui_number_name;
+}
+
+char *
+cc_display_monitor_dup_ui_number_name (CcDisplayMonitor *self)
+{
+  CcDisplayMonitorPrivate *priv = cc_display_monitor_get_instance_private (self);
+
+  return g_strdup (priv->ui_number_name);
+}
+
+static void
+cc_display_monitor_set_ui_info (CcDisplayMonitor *self, gint ui_number, gchar *ui_name)
+{
+
+  CcDisplayMonitorPrivate *priv = cc_display_monitor_get_instance_private (self);
+
+  priv->ui_number = ui_number;
+  g_free (priv->ui_name);
+  priv->ui_name = ui_name;
+  priv->ui_number_name = g_strdup_printf ("%d\u2003%s", ui_number, ui_name);
+}
+
+struct _CcDisplayConfigPrivate {
+  GList *ui_sorted_monitors;
+};
+typedef struct _CcDisplayConfigPrivate CcDisplayConfigPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (CcDisplayConfig,
+                            cc_display_config,
+                            G_TYPE_OBJECT)
+
+static void
+cc_display_config_init (CcDisplayConfig *self)
+{
+  CcDisplayConfigPrivate *priv = cc_display_config_get_instance_private (self);
+
+  priv->ui_sorted_monitors = NULL;
+}
+
+static void
+cc_display_config_constructed (GObject *object)
+{
+  CcDisplayConfig *self = CC_DISPLAY_CONFIG (object);
+  CcDisplayConfigPrivate *priv = cc_display_config_get_instance_private (self);
+  GList *monitors = cc_display_config_get_monitors (self);
+  GList *item;
+  gint ui_number = 1;
+
+  for (item = monitors; item != NULL; item = item->next)
+    {
+      CcDisplayMonitor *monitor = item->data;
+
+      if (cc_display_monitor_is_builtin (monitor))
+        priv->ui_sorted_monitors = g_list_prepend (priv->ui_sorted_monitors, monitor);
+      else
+        priv->ui_sorted_monitors = g_list_append (priv->ui_sorted_monitors, monitor);
+    }
+
+  for (item = priv->ui_sorted_monitors; item != NULL; item = item->next)
+    {
+      CcDisplayMonitor *monitor = item->data;
+      char *ui_name;
+      ui_name = make_output_ui_name (monitor);
+
+      cc_display_monitor_set_ui_info (monitor, ui_number, ui_name);
+
+      ui_number += 1;
+    }
+}
+
+static void
+cc_display_config_finalize (GObject *object)
+{
+  CcDisplayConfig *self = CC_DISPLAY_CONFIG (object);
+  CcDisplayConfigPrivate *priv = cc_display_config_get_instance_private (self);
+
+  g_list_free (priv->ui_sorted_monitors);
+
+  G_OBJECT_CLASS (cc_display_config_parent_class)->finalize (object);
+}
+
+static void
+cc_display_config_class_init (CcDisplayConfigClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  g_signal_new ("primary",
+                CC_TYPE_DISPLAY_CONFIG,
+                G_SIGNAL_RUN_LAST,
+                0, NULL, NULL, NULL,
+                G_TYPE_NONE, 0);
+
+  gobject_class->constructed = cc_display_config_constructed;
+  gobject_class->finalize = cc_display_config_finalize;
+}
+
+GList *
+cc_display_config_get_monitors (CcDisplayConfig *self)
+{
+  g_return_val_if_fail (CC_IS_DISPLAY_CONFIG (self), NULL);
+  return CC_DISPLAY_CONFIG_GET_CLASS (self)->get_monitors (self);
+}
+
+GList *
+cc_display_config_get_ui_sorted_monitors (CcDisplayConfig *self)
+{
+  CcDisplayConfigPrivate *priv = cc_display_config_get_instance_private (self);
+
+  g_return_val_if_fail (CC_IS_DISPLAY_CONFIG (self), NULL);
+  return priv->ui_sorted_monitors;
+}
+
+int
+cc_display_config_count_useful_monitors (CcDisplayConfig *self)
+{
+  CcDisplayConfigPrivate *priv = cc_display_config_get_instance_private (self);
+  GList *outputs, *l;
+  guint count = 0;
+
+  g_return_val_if_fail (CC_IS_DISPLAY_CONFIG (self), 0);
+
+  outputs = priv->ui_sorted_monitors;
+  for (l = outputs; l != NULL; l = l->next)
+    {
+      CcDisplayMonitor *output = l->data;
+      if (!cc_display_monitor_is_useful (output))
+        continue;
+      else
+        count++;
+    }
+  return count;
+
+}
+
+gboolean
+cc_display_config_is_applicable (CcDisplayConfig *self)
+{
+  g_return_val_if_fail (CC_IS_DISPLAY_CONFIG (self), FALSE);
+  return CC_DISPLAY_CONFIG_GET_CLASS (self)->is_applicable (self);
+}
+
+void
+cc_display_config_set_mode_on_all_outputs (CcDisplayConfig *config,
+                                           CcDisplayMode   *mode)
+{
+  GList *outputs, *l;
+
+  g_return_if_fail (CC_IS_DISPLAY_CONFIG (config));
+
+  outputs = cc_display_config_get_monitors (config);
+  for (l = outputs; l; l = l->next)
+    {
+      CcDisplayMonitor *output = l->data;
+      cc_display_monitor_set_mode (output, mode);
+      cc_display_monitor_set_position (output, 0, 0);
+    }
+}
+
+gboolean
+cc_display_config_equal (CcDisplayConfig *self,
+                         CcDisplayConfig *other)
+{
+  g_return_val_if_fail (CC_IS_DISPLAY_CONFIG (self), FALSE);
+  g_return_val_if_fail (CC_IS_DISPLAY_CONFIG (other), FALSE);
+
+  return CC_DISPLAY_CONFIG_GET_CLASS (self)->equal (self, other);
+}
+
+gboolean
+cc_display_config_apply (CcDisplayConfig *self,
+                         GError **error)
+{
+  if (!CC_IS_DISPLAY_CONFIG (self))
+    {
+      g_warning ("Cannot apply invalid configuration");
+      g_set_error (error,
+                   G_IO_ERROR,
+                   G_IO_ERROR_FAILED,
+                   "Cannot apply invalid configuration");
+      return FALSE;
+    }
+
+  return CC_DISPLAY_CONFIG_GET_CLASS (self)->apply (self, error);
+}
+
+gboolean
+cc_display_config_is_cloning (CcDisplayConfig *self)
+{
+  g_return_val_if_fail (CC_IS_DISPLAY_CONFIG (self), FALSE);
+  return CC_DISPLAY_CONFIG_GET_CLASS (self)->is_cloning (self);
+}
+
+void
+cc_display_config_set_cloning (CcDisplayConfig *self,
+                               gboolean clone)
+{
+  g_return_if_fail (CC_IS_DISPLAY_CONFIG (self));
+  return CC_DISPLAY_CONFIG_GET_CLASS (self)->set_cloning (self, clone);
+}
+
+GList *
+cc_display_config_get_cloning_modes (CcDisplayConfig *self)
+{
+  g_return_val_if_fail (CC_IS_DISPLAY_CONFIG (self), NULL);
+  return CC_DISPLAY_CONFIG_GET_CLASS (self)->get_cloning_modes (self);
+}
+
+gboolean
+cc_display_config_is_layout_logical (CcDisplayConfig *self)
+{
+  g_return_val_if_fail (CC_IS_DISPLAY_CONFIG (self), FALSE);
+  return CC_DISPLAY_CONFIG_GET_CLASS (self)->is_layout_logical (self);
+}
+
+void
+cc_display_config_set_minimum_size (CcDisplayConfig *self,
+                                    int              width,
+                                    int              height)
+{
+  CC_DISPLAY_CONFIG_GET_CLASS (self)->set_minimum_size (self, width, height);
+}
+
+gboolean
+cc_display_config_is_scaled_mode_valid (CcDisplayConfig *self,
+                                        CcDisplayMode   *mode,
+                                        double           scale)
+{
+  return CC_DISPLAY_CONFIG_GET_CLASS (self)->is_scaled_mode_valid (self, mode, scale);
+}
diff --git a/gnome-initial-setup/pages/display/cc-display-config.h 
b/gnome-initial-setup/pages/display/cc-display-config.h
new file mode 100644
index 00000000..e8a519ac
--- /dev/null
+++ b/gnome-initial-setup/pages/display/cc-display-config.h
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2016  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#pragma once
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/*
+ * GNOME Control Center display configuration system:
+ *
+ * The display configuration system consists of multiple concepts:
+ *
+ * CcDisplayConfig:
+ *
+ *   Configuration instance, read from mutter using the
+ *   org.gnome.Mutter.DisplayConfig D-Bus API. Contains information about the
+ *   current configuration. Can be copied, to create a representation of a
+ *   configuration at a given time, and applied, applying any changes that has
+ *   been made to the objects associated with the configuration.
+ *
+ *   CcDisplayConfig provides a list of all known "monitors" known to the
+ *   compositor. It does not know about ports without any monitors connected,
+ *   nor low level details about monitors, such as tiling etc.
+ *
+ * CcDisplayMonitor:
+ *
+ *   A high level representation of a connected monitor. A monitor have details
+ *   associated with it, some which can be altered. Each CcDisplayMonitor
+ *   instance is associated with a single CcDisplayConfig instance. All
+ *   alteration to a monitor is cached and not applied until
+ *   cc_display_config_apply() is called on the corresponding CcDisplayConfig
+ *   object.
+ *
+ * CcDisplayMode:
+ *
+ *   A monitor mode, including resolution, refresh rate, and scale. Each monitor
+ *   will have a list of possible modes.
+ *
+ */
+
+typedef enum _CcDisplayRotation
+{
+  CC_DISPLAY_ROTATION_NONE,
+  CC_DISPLAY_ROTATION_90,
+  CC_DISPLAY_ROTATION_180,
+  CC_DISPLAY_ROTATION_270,
+  CC_DISPLAY_ROTATION_FLIPPED,
+  CC_DISPLAY_ROTATION_90_FLIPPED,
+  CC_DISPLAY_ROTATION_180_FLIPPED,
+  CC_DISPLAY_ROTATION_270_FLIPPED,
+} CcDisplayRotation;
+
+
+#define CC_TYPE_DISPLAY_MODE (cc_display_mode_get_type ())
+G_DECLARE_DERIVABLE_TYPE (CcDisplayMode, cc_display_mode,
+                          CC, DISPLAY_MODE, GObject)
+
+struct _CcDisplayModeClass
+{
+  GObjectClass parent_class;
+
+  const char*   (*get_name)             (CcDisplayMode *self);
+  void          (*get_resolution)       (CcDisplayMode *self, int *w, int *h);
+  const double* (*get_supported_scales) (CcDisplayMode *self);
+  double        (*get_preferred_scale)  (CcDisplayMode *self);
+  gboolean      (*is_interlaced)        (CcDisplayMode *self);
+  int           (*get_freq)             (CcDisplayMode *self);
+  double        (*get_freq_f)           (CcDisplayMode *self);
+};
+
+
+#define CC_TYPE_DISPLAY_MONITOR (cc_display_monitor_get_type ())
+G_DECLARE_DERIVABLE_TYPE (CcDisplayMonitor, cc_display_monitor,
+                          CC, DISPLAY_MONITOR, GObject)
+
+struct _CcDisplayMonitorClass
+{
+  GObjectClass parent_class;
+
+  guint32           (*get_id)                 (CcDisplayMonitor  *self);
+  const char*       (*get_display_name)       (CcDisplayMonitor  *self);
+  const char*       (*get_connector_name)     (CcDisplayMonitor  *self);
+  gboolean          (*is_builtin)             (CcDisplayMonitor  *self);
+  gboolean          (*is_primary)             (CcDisplayMonitor  *self);
+  void              (*set_primary)            (CcDisplayMonitor  *self,
+                                               gboolean          primary);
+  gboolean          (*is_active)              (CcDisplayMonitor *self);
+  void              (*set_active)             (CcDisplayMonitor *self,
+                                               gboolean          a);
+  CcDisplayRotation (*get_rotation)           (CcDisplayMonitor *self);
+  void              (*set_rotation)           (CcDisplayMonitor  *self,
+                                               CcDisplayRotation  r);
+  gboolean          (*supports_rotation)      (CcDisplayMonitor  *self,
+                                               CcDisplayRotation  r);
+  void              (*get_physical_size)      (CcDisplayMonitor  *self,
+                                               int               *w,
+                                               int               *h);
+  void              (*get_geometry)           (CcDisplayMonitor  *self,
+                                               int               *x,
+                                               int               *y,
+                                               int               *w,
+                                               int               *h);
+  gboolean          (*supports_underscanning) (CcDisplayMonitor  *self);
+  gboolean          (*get_underscanning)      (CcDisplayMonitor  *self);
+  void              (*set_underscanning)      (CcDisplayMonitor  *self,
+                                               gboolean           u);
+  CcDisplayMode*    (*get_mode)               (CcDisplayMonitor  *self);
+  CcDisplayMode*    (*get_preferred_mode)     (CcDisplayMonitor  *self);
+  GList*            (*get_modes)              (CcDisplayMonitor  *self);
+  void              (*set_mode)               (CcDisplayMonitor  *self,
+                                               CcDisplayMode     *m);
+  void              (*set_position)           (CcDisplayMonitor  *self,
+                                               int                x,
+                                               int                y);
+  double            (*get_scale)              (CcDisplayMonitor  *self);
+  void              (*set_scale)              (CcDisplayMonitor  *self,
+                                               double             s);
+};
+
+
+#define CC_TYPE_DISPLAY_CONFIG (cc_display_config_get_type ())
+G_DECLARE_DERIVABLE_TYPE (CcDisplayConfig, cc_display_config,
+                          CC, DISPLAY_CONFIG, GObject)
+
+struct _CcDisplayConfigClass
+{
+  GObjectClass parent_class;
+
+  GList*   (*get_monitors)      (CcDisplayConfig  *self);
+  gboolean (*is_applicable)     (CcDisplayConfig  *self);
+  gboolean (*equal)             (CcDisplayConfig  *self,
+                                 CcDisplayConfig  *other);
+  gboolean (*apply)             (CcDisplayConfig  *self,
+                                GError           **error);
+  gboolean (*is_cloning)        (CcDisplayConfig  *self);
+  void     (*set_cloning)       (CcDisplayConfig  *self,
+                                 gboolean          clone);
+  GList*   (*get_cloning_modes) (CcDisplayConfig  *self);
+  gboolean (*is_layout_logical) (CcDisplayConfig  *self);
+  void     (*set_minimum_size)  (CcDisplayConfig  *self,
+                                 int               width,
+                                 int               height);
+  gboolean (*is_scaled_mode_valid) (CcDisplayConfig  *self,
+                                    CcDisplayMode    *mode,
+                                    double            scale);
+};
+
+
+GList*            cc_display_config_get_monitors            (CcDisplayConfig    *config);
+GList*            cc_display_config_get_ui_sorted_monitors  (CcDisplayConfig    *config);
+int               cc_display_config_count_useful_monitors   (CcDisplayConfig    *config);
+gboolean          cc_display_config_is_applicable           (CcDisplayConfig    *config);
+gboolean          cc_display_config_equal                   (CcDisplayConfig    *config,
+                                                             CcDisplayConfig    *other);
+gboolean          cc_display_config_apply                   (CcDisplayConfig    *config,
+                                                             GError            **error);
+gboolean          cc_display_config_is_cloning              (CcDisplayConfig    *config);
+void              cc_display_config_set_cloning             (CcDisplayConfig    *config,
+                                                             gboolean            clone);
+GList*            cc_display_config_get_cloning_modes       (CcDisplayConfig    *config);
+
+void              cc_display_config_set_mode_on_all_outputs (CcDisplayConfig *config,
+                                                             CcDisplayMode   *mode);
+
+gboolean          cc_display_config_is_layout_logical       (CcDisplayConfig    *self);
+void              cc_display_config_set_minimum_size        (CcDisplayConfig    *self,
+                                                             int                 width,
+                                                             int                 height);
+gboolean          cc_display_config_is_scaled_mode_valid    (CcDisplayConfig    *self,
+                                                             CcDisplayMode      *mode,
+                                                             double              scale);
+
+const char*       cc_display_monitor_get_display_name       (CcDisplayMonitor   *monitor);
+gboolean          cc_display_monitor_is_active              (CcDisplayMonitor   *monitor);
+void              cc_display_monitor_set_active             (CcDisplayMonitor   *monitor,
+                                                             gboolean            active);
+const char*       cc_display_monitor_get_connector_name     (CcDisplayMonitor   *monitor);
+CcDisplayRotation cc_display_monitor_get_rotation           (CcDisplayMonitor   *monitor);
+void              cc_display_monitor_set_rotation           (CcDisplayMonitor   *monitor,
+                                                             CcDisplayRotation  r);
+gboolean          cc_display_monitor_supports_rotation      (CcDisplayMonitor  *monitor,
+                                                             CcDisplayRotation  rotation);
+void              cc_display_monitor_get_physical_size      (CcDisplayMonitor  *monitor,
+                                                             int               *w,
+                                                             int               *h);
+gboolean          cc_display_monitor_is_builtin             (CcDisplayMonitor  *monitor);
+gboolean          cc_display_monitor_is_primary             (CcDisplayMonitor  *monitor);
+void              cc_display_monitor_set_primary            (CcDisplayMonitor  *monitor,
+                                                             gboolean           primary);
+guint32           cc_display_monitor_get_id                 (CcDisplayMonitor  *monitor);
+
+gboolean          cc_display_monitor_supports_underscanning (CcDisplayMonitor  *monitor);
+gboolean          cc_display_monitor_get_underscanning      (CcDisplayMonitor  *monitor);
+void              cc_display_monitor_set_underscanning      (CcDisplayMonitor  *monitor,
+                                                             gboolean           underscanning);
+
+CcDisplayMode*    cc_display_monitor_get_mode               (CcDisplayMonitor  *monitor);
+void              cc_display_monitor_get_geometry           (CcDisplayMonitor  *monitor,
+                                                             int               *x,
+                                                             int               *y,
+                                                             int               *width,
+                                                             int               *height);
+GList*            cc_display_monitor_get_modes              (CcDisplayMonitor  *monitor);
+CcDisplayMode*    cc_display_monitor_get_preferred_mode     (CcDisplayMonitor  *monitor);
+double            cc_display_monitor_get_scale              (CcDisplayMonitor  *monitor);
+void              cc_display_monitor_set_scale              (CcDisplayMonitor  *monitor,
+                                                             double s);
+
+void              cc_display_monitor_set_mode               (CcDisplayMonitor  *monitor,
+                                                             CcDisplayMode     *mode);
+void              cc_display_monitor_set_position           (CcDisplayMonitor  *monitor,
+                                                             int                x,
+                                                             int                y);
+
+gboolean          cc_display_monitor_is_useful              (CcDisplayMonitor  *monitor);
+gboolean          cc_display_monitor_is_usable              (CcDisplayMonitor  *monitor);
+void              cc_display_monitor_set_usable             (CcDisplayMonitor  *monitor,
+                                                             gboolean           is_usable);
+int               cc_display_monitor_get_ui_number          (CcDisplayMonitor  *monitor);
+const char*       cc_display_monitor_get_ui_name            (CcDisplayMonitor  *monitor);
+const char*       cc_display_monitor_get_ui_number_name     (CcDisplayMonitor  *monitor);
+char*             cc_display_monitor_dup_ui_number_name     (CcDisplayMonitor  *monitor);
+
+const char*       cc_display_mode_get_name                  (CcDisplayMode     *mode);
+void              cc_display_mode_get_resolution            (CcDisplayMode     *mode,
+                                                             int               *width,
+                                                             int               *height);
+const double*     cc_display_mode_get_supported_scales      (CcDisplayMode     *self);
+double            cc_display_mode_get_preferred_scale       (CcDisplayMode     *self);
+gboolean          cc_display_mode_is_interlaced             (CcDisplayMode     *mode);
+int               cc_display_mode_get_freq                  (CcDisplayMode     *mode);
+double            cc_display_mode_get_freq_f                (CcDisplayMode     *mode);
+
+G_END_DECLS
diff --git a/gnome-initial-setup/pages/display/display-overscan.png 
b/gnome-initial-setup/pages/display/display-overscan.png
new file mode 100644
index 00000000..fafb4008
Binary files /dev/null and b/gnome-initial-setup/pages/display/display-overscan.png differ
diff --git a/gnome-initial-setup/pages/display/display.gresource.xml 
b/gnome-initial-setup/pages/display/display.gresource.xml
new file mode 100644
index 00000000..e8e46b5f
--- /dev/null
+++ b/gnome-initial-setup/pages/display/display.gresource.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+  <gresource prefix="/org/gnome/initial-setup">
+    <file preprocess="xml-stripblanks" alias="gis-display-page.ui">gis-display-page.ui</file>
+    <file>display-overscan.png</file>
+  </gresource>
+</gresources>
+
diff --git a/gnome-initial-setup/pages/display/gis-display-page.c 
b/gnome-initial-setup/pages/display/gis-display-page.c
new file mode 100644
index 00000000..abc2a283
--- /dev/null
+++ b/gnome-initial-setup/pages/display/gis-display-page.c
@@ -0,0 +1,285 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2014 Endless Mobile, 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.
+ *
+ * Written by:
+ *     Emmanuele Bassi <emmanuele endlessm com>
+ */
+
+/* Display page {{{1 */
+
+#define PAGE_ID "display"
+
+#include "config.h"
+#include "gis-display-page.h"
+
+#include "display-resources.h"
+
+#include "cc-display-config-manager-dbus.h"
+#include "cc-display-config.h"
+
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+typedef struct {
+  GtkWidget *overscan_on;
+  GtkWidget *overscan_off;
+  GtkWidget *overscan_default_selection;
+
+  CcDisplayConfigManager *manager;
+  CcDisplayConfig *current_config;
+  CcDisplayMonitor *current_output;
+
+  gulong screen_changed_id;
+} GisDisplayPagePrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (GisDisplayPage, gis_display_page, GIS_TYPE_PAGE);
+
+static void
+set_toggle_options_from_config (GisDisplayPage *page)
+{
+  GisDisplayPagePrivate *priv = gis_display_page_get_instance_private (page);
+  GtkWidget *default_toggle, *toggle;
+
+  /* Do not set the toggle if we're on the default selection */
+  default_toggle = priv->overscan_default_selection;
+  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (default_toggle)))
+    return;
+
+  if (cc_display_monitor_get_underscanning (priv->current_output))
+    toggle = priv->overscan_on;
+  else
+    toggle = priv->overscan_off;
+
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), TRUE);
+}
+
+static gboolean
+should_display_overscan (GisDisplayPage *page)
+{
+  GisDisplayPagePrivate *priv = gis_display_page_get_instance_private (page);
+
+  if (!priv->current_output)
+    return FALSE;
+
+  return cc_display_monitor_supports_underscanning (priv->current_output);
+}
+
+static gboolean
+read_screen_config (GisDisplayPage *page)
+{
+  GisDisplayPagePrivate *priv = gis_display_page_get_instance_private (page);
+  CcDisplayConfig *current;
+  GList *outputs, *l;
+
+  g_clear_object (&priv->current_config);
+  priv->current_output = NULL;
+
+  current = cc_display_config_manager_get_current (priv->manager);
+  if (!current)
+    {
+      g_critical ("Could not get primary output information.");
+      return FALSE;
+    }
+
+  priv->current_config = current;
+
+  outputs = cc_display_config_get_monitors (priv->current_config);
+  for (l = outputs; l != NULL; l = l->next)
+    {
+      CcDisplayMonitor *output = l->data;
+
+      if (!cc_display_monitor_is_active (output))
+        continue;
+
+      priv->current_output = output;
+      break;
+    }
+
+  return TRUE;
+}
+
+static void
+toggle_overscan (GisDisplayPage *page,
+                 gboolean value)
+{
+  GisDisplayPagePrivate *priv = gis_display_page_get_instance_private (page);
+  GError *error = NULL;
+
+  if (value == cc_display_monitor_get_underscanning (priv->current_output))
+    return;
+
+  cc_display_monitor_set_underscanning (priv->current_output, value);
+
+  if (!cc_display_config_apply (priv->current_config, &error))
+    {
+      g_warning ("Error applying configuration: %s", error->message);
+      g_clear_error (&error);
+      return;
+    }
+}
+
+static void
+update_overscan (GisDisplayPage *page)
+{
+  GisDisplayPagePrivate *priv = gis_display_page_get_instance_private (page);
+  GtkWidget *widget;
+  gboolean value;
+
+  widget = priv->overscan_on;
+  value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+  toggle_overscan (page, value);
+}
+
+static void
+overscan_radio_toggled (GtkWidget *radio,
+                        GisDisplayPage *page)
+{
+  GisDisplayPagePrivate *priv = gis_display_page_get_instance_private (page);
+  GtkWidget *widget;
+
+  widget = priv->overscan_default_selection;
+  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
+    {
+      gis_page_set_complete (GIS_PAGE (page), FALSE);
+      return;
+    }
+
+  /* user has made a choice, page is complete */
+  gis_page_set_complete (GIS_PAGE (page), TRUE);
+}
+
+static void
+gis_display_page_dispose (GObject *gobject)
+{
+  GisDisplayPage *page = GIS_DISPLAY_PAGE (gobject);
+  GisDisplayPagePrivate *priv = gis_display_page_get_instance_private (page);
+
+  if (priv->screen_changed_id != 0)
+    {
+      g_signal_handler_disconnect (priv->manager, priv->screen_changed_id);
+      priv->screen_changed_id = 0;
+    }
+
+  g_clear_object (&priv->manager);
+  g_clear_object (&priv->current_config);
+
+  G_OBJECT_CLASS (gis_display_page_parent_class)->dispose (gobject);
+}
+
+static void
+on_screen_changed (GisDisplayPage *page)
+{
+  GisDisplayPagePrivate *priv = gis_display_page_get_instance_private (page);
+  gboolean visible = FALSE;
+
+  if (!priv->manager)
+    return;
+
+  if (!read_screen_config (page))
+    {
+      g_warning ("Could not read screen configuration. Hiding overscan page.");
+      goto out;
+    }
+
+  if (should_display_overscan (page))
+    {
+      g_debug ("Overscanning supported on primary display. Showing overscan page.");
+      visible = TRUE;
+
+      set_toggle_options_from_config (page);
+    }
+
+ out:
+  gtk_widget_set_visible (GTK_WIDGET (page), visible);
+}
+
+static void
+gis_display_page_constructed (GObject *object)
+{
+  GisDisplayPage *page = GIS_DISPLAY_PAGE (object);
+  GisDisplayPagePrivate *priv = gis_display_page_get_instance_private (page);
+  GtkWidget *widget;
+
+  G_OBJECT_CLASS (gis_display_page_parent_class)->constructed (object);
+
+  priv->manager = cc_display_config_manager_dbus_new ();
+  priv->screen_changed_id = g_signal_connect_object (priv->manager, "changed",
+                                                     G_CALLBACK (on_screen_changed),
+                                                     page,
+                                                     G_CONNECT_SWAPPED);
+  widget = priv->overscan_on;
+  g_signal_connect (widget, "toggled",
+                    G_CALLBACK (overscan_radio_toggled), page);
+
+  widget = priv->overscan_off;
+  g_signal_connect (widget, "toggled",
+                    G_CALLBACK (overscan_radio_toggled), page);
+
+  gtk_widget_show (GTK_WIDGET (page));
+}
+
+static gboolean
+gis_display_page_apply (GisPage *gis_page,
+                        GCancellable *cancellable)
+{
+  update_overscan (GIS_DISPLAY_PAGE (gis_page));
+
+  return FALSE;
+}
+
+static void
+gis_display_page_locale_changed (GisPage *page)
+{
+  gis_page_set_title (page, _("Display"));
+}
+
+static void
+gis_display_page_class_init (GisDisplayPageClass *klass)
+{
+  GisPageClass *page_class = GIS_PAGE_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (klass), 
"/org/gnome/initial-setup/gis-display-page.ui");
+
+  gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisDisplayPage, overscan_on);
+  gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisDisplayPage, overscan_off);
+  gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisDisplayPage, 
overscan_default_selection);
+
+  page_class->page_id = PAGE_ID;
+  page_class->apply = gis_display_page_apply;
+  page_class->locale_changed = gis_display_page_locale_changed;
+  object_class->constructed = gis_display_page_constructed;
+  object_class->dispose = gis_display_page_dispose;
+}
+
+static void
+gis_display_page_init (GisDisplayPage *page)
+{
+  g_resources_register (display_get_resource ());
+
+  gtk_widget_init_template (GTK_WIDGET (page));
+}
+
+GisPage *
+gis_prepare_display_page (GisDriver *driver)
+{
+  return g_object_new (GIS_TYPE_DISPLAY_PAGE,
+                       "driver", driver,
+                       NULL);
+}
diff --git a/gnome-initial-setup/pages/display/gis-display-page.h 
b/gnome-initial-setup/pages/display/gis-display-page.h
new file mode 100644
index 00000000..badb36b9
--- /dev/null
+++ b/gnome-initial-setup/pages/display/gis-display-page.h
@@ -0,0 +1,57 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2014 Endless Mobile, 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.
+ *
+ * Written by:
+ *     Emmanuele Bassi <emmanuele endlessm com>
+ */
+
+#ifndef __GIS_DISPLAY_PAGE_H__
+#define __GIS_DISPLAY_PAGE_H__
+
+#include "gnome-initial-setup.h"
+
+G_BEGIN_DECLS
+
+#define GIS_TYPE_DISPLAY_PAGE                   (gis_display_page_get_type ())
+#define GIS_DISPLAY_PAGE(obj)                   (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIS_TYPE_DISPLAY_PAGE, 
GisDisplayPage))
+#define GIS_DISPLAY_PAGE_CLASS(klass)           (G_TYPE_CHECK_CLASS_CAST ((klass),  GIS_TYPE_DISPLAY_PAGE, 
GisDisplayPageClass))
+#define GIS_IS_DISPLAY_PAGE(obj)                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIS_TYPE_DISPLAY_PAGE))
+#define GIS_IS_DISPLAY_PAGE_CLASS(klass)        (G_TYPE_CHECK_CLASS_TYPE ((klass),  GIS_TYPE_DISPLAY_PAGE))
+#define GIS_DISPLAY_PAGE_GET_CLASS(obj)         (G_TYPE_INSTANCE_GET_CLASS ((obj),  GIS_TYPE_DISPLAY_PAGE, 
GisDisplayPageClass))
+
+typedef struct _GisDisplayPage        GisDisplayPage;
+typedef struct _GisDisplayPageClass   GisDisplayPageClass;
+
+struct _GisDisplayPage
+{
+  GisPage parent;
+};
+
+struct _GisDisplayPageClass
+{
+  GisPageClass parent_class;
+};
+
+GType gis_display_page_get_type (void);
+
+GisPage *gis_prepare_display_page (GisDriver *driver);
+
+G_END_DECLS
+
+#endif /* __GIS_DISPLAY_PAGE_H__ */
diff --git a/gnome-initial-setup/pages/display/gis-display-page.ui 
b/gnome-initial-setup/pages/display/gis-display-page.ui
new file mode 100644
index 00000000..80fc9614
--- /dev/null
+++ b/gnome-initial-setup/pages/display/gis-display-page.ui
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <template class="GisDisplayPage" parent="GisPage">
+    <child>
+      <object class="GtkBox" id="box2">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="halign">center</property>
+        <property name="valign">fill</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkImage" id="image1">
+            <property name="visible" bind-source="GisDisplayPage" bind-property="small-screen" 
bind-flags="invert-boolean|sync-create"/>
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="pixel_size">96</property>
+            <property name="icon_name">preferences-desktop-display-symbolic</property>
+            <property name="icon_size">1</property>
+            <property name="margin_top">24</property>
+            <style>
+              <class name="dim-label" />
+            </style>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="title">
+            <property name="visible" bind-source="GisDisplayPage" bind-property="small-screen" 
bind-flags="invert-boolean|sync-create"/>
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="halign">center</property>
+            <property name="valign">start</property>
+            <property name="margin_top">18</property>
+            <property name="label" translatable="yes">Adjust for TV screen</property>
+            <attributes>
+              <attribute name="weight" value="bold"/>
+              <attribute name="scale" value="1.8"/>
+            </attributes>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label2">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="halign">start</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes">Do you see this at the bottom right corner of your 
screen?</property>
+            <property name="wrap">True</property>
+            <property name="max_width_chars">50</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkImage" id="image2">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="margin_top">16</property>
+            <property name="margin_bottom">16</property>
+            <property name="stock">gtk-missing-image</property>
+            <property name="resource">/org/gnome/initial-setup/display-overscan.png</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">3</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox" id="box1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="halign">center</property>
+            <property name="orientation">vertical</property>
+            <property name="spacing">3</property>
+            <child>
+              <object class="GtkRadioButton" id="overscan_default_selection">
+                <property name="label" translatable="no">radiobutton</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="xalign">0</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkRadioButton" id="overscan_off">
+                <property name="label" translatable="yes">I see it</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="xalign">0</property>
+                <property name="draw_indicator">True</property>
+                <property name="group">overscan_default_selection</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkRadioButton" id="overscan_on">
+                <property name="label" translatable="yes">I do not see it. Shrink screen to fit 
TV.</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="xalign">0</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+                <property name="group">overscan_default_selection</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">4</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/gnome-initial-setup/pages/display/meson.build b/gnome-initial-setup/pages/display/meson.build
new file mode 100644
index 00000000..7536ec85
--- /dev/null
+++ b/gnome-initial-setup/pages/display/meson.build
@@ -0,0 +1,13 @@
+sources += gnome.compile_resources(
+    'display-resources',
+    files('display.gresource.xml'),
+    c_name: 'display'
+)
+
+sources += files(
+    'cc-display-config.c',
+    'cc-display-config-dbus.c',
+    'cc-display-config-manager.c',
+    'cc-display-config-manager-dbus.c',
+    'gis-display-page.c',
+)
diff --git a/gnome-initial-setup/pages/meson.build b/gnome-initial-setup/pages/meson.build
index be3f4b46..6c14d5f6 100644
--- a/gnome-initial-setup/pages/meson.build
+++ b/gnome-initial-setup/pages/meson.build
@@ -1,5 +1,6 @@
 pages = [
    'account',
+   'display',
    'language',
    'keyboard',
    'endless-eula',
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 07f4617e..3e036645 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -13,6 +13,8 @@ gnome-initial-setup/pages/account/gis-account-page.ui
 gnome-initial-setup/pages/account/um-photo-dialog.c
 gnome-initial-setup/pages/account/um-realm-manager.c
 gnome-initial-setup/pages/account/um-utils.c
+gnome-initial-setup/pages/display/gis-display-page.c
+gnome-initial-setup/pages/display/gis-display-page.ui
 gnome-initial-setup/pages/endless-eula/gis-endless-eula-page.c
 gnome-initial-setup/pages/endless-eula/gis-endless-eula-page.ui
 gnome-initial-setup/pages/endless-eula/gis-endless-eula-viewer.c


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