[mutter] Make MetaOutput a GObject



commit 9817a6aa47b4510e790baa3908565770dbf0fa5c
Author: Jonas Ådahl <jadahl gmail com>
Date:   Fri Mar 24 17:35:51 2017 +0800

    Make MetaOutput a GObject
    
    Turn MetaOutput into a GObject and move it to a separate file. This
    changes the storage format, resulting in changing the API for accessing
    MetaOutputs from using an array, to using a GList.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=785381

 src/Makefile.am                                    |    2 +
 src/backends/meta-logical-monitor.c                |    4 +-
 src/backends/meta-monitor-config-manager.c         |    1 +
 src/backends/meta-monitor-manager-dummy.c          |  172 ++++++++++----------
 src/backends/meta-monitor-manager-private.h        |   96 +-----------
 src/backends/meta-monitor-manager.c                |   79 +++------
 src/backends/meta-monitor.c                        |    9 +-
 src/backends/meta-monitor.h                        |    1 +
 src/backends/meta-output.c                         |   56 +++++++
 src/backends/meta-output.h                         |  120 ++++++++++++++
 src/backends/native/meta-cursor-renderer-native.c  |    1 +
 src/backends/native/meta-monitor-manager-kms.c     |  121 +++++++--------
 src/backends/native/meta-renderer-native.c         |    1 +
 src/backends/x11/meta-monitor-manager-xrandr.c     |   44 +++---
 src/backends/x11/meta-stage-x11-nested.c           |    1 +
 src/backends/x11/nested/meta-renderer-x11-nested.c |    1 +
 src/compositor/meta-window-actor.c                 |   15 +-
 src/tests/headless-start-test.c                    |   39 ++---
 src/tests/meta-monitor-manager-test.c              |    7 +-
 src/tests/meta-monitor-manager-test.h              |    3 +-
 src/tests/monitor-unit-tests.c                     |   96 ++++++-----
 21 files changed, 473 insertions(+), 396 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 6aef50d..97b6da1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -131,6 +131,8 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES =      \
        backends/meta-monitor-manager-dummy.h   \
        backends/meta-orientation-manager.c     \
        backends/meta-orientation-manager.h     \
+       backends/meta-output.c                  \
+       backends/meta-output.h                  \
        backends/meta-pointer-constraint.c      \
        backends/meta-pointer-constraint.h      \
        backends/meta-settings.c                \
diff --git a/src/backends/meta-logical-monitor.c b/src/backends/meta-logical-monitor.c
index 2404d23..2c11044 100644
--- a/src/backends/meta-logical-monitor.c
+++ b/src/backends/meta-logical-monitor.c
@@ -21,9 +21,11 @@
 
 #include "config.h"
 
-#include "backends/meta-backend-private.h"
 #include "backends/meta-logical-monitor.h"
 
+#include "backends/meta-backend-private.h"
+#include "backends/meta-output.h"
+
 G_DEFINE_TYPE (MetaLogicalMonitor, meta_logical_monitor, G_TYPE_OBJECT)
 
 static MetaMonitor *
diff --git a/src/backends/meta-monitor-config-manager.c b/src/backends/meta-monitor-config-manager.c
index cdc9fb7..d00aa6f 100644
--- a/src/backends/meta-monitor-config-manager.c
+++ b/src/backends/meta-monitor-config-manager.c
@@ -26,6 +26,7 @@
 #include "backends/meta-monitor-config-migration.h"
 #include "backends/meta-monitor-config-store.h"
 #include "backends/meta-monitor-manager-private.h"
+#include "backends/meta-output.h"
 #include "core/boxes-private.h"
 
 #define CONFIG_HISTORY_MAX_SIZE 3
diff --git a/src/backends/meta-monitor-manager-dummy.c b/src/backends/meta-monitor-manager-dummy.c
index dfc14da..452b501 100644
--- a/src/backends/meta-monitor-manager-dummy.c
+++ b/src/backends/meta-monitor-manager-dummy.c
@@ -33,6 +33,7 @@
 #include "backends/meta-backend-private.h"
 #include "backends/meta-monitor.h"
 #include "backends/meta-monitor-config-manager.h"
+#include "backends/meta-output.h"
 
 #define ALL_TRANSFORMS ((1 << (META_MONITOR_TRANSFORM_FLIPPED_270 + 1)) - 1)
 
@@ -69,7 +70,7 @@ meta_output_dummy_notify_destroy (MetaOutput *output);
 static void
 append_monitor (GArray *modes,
                 GArray *crtcs,
-                GArray *outputs,
+                GList **outputs,
                 float   scale)
 {
   MetaCrtcMode modes_decl[] = {
@@ -86,8 +87,9 @@ append_monitor (GArray *modes,
   };
   MetaCrtc crtc;
   MetaOutputDummy *output_dummy;
-  MetaOutput output;
+  MetaOutput *output;
   unsigned int i;
+  unsigned int number;
 
   for (i = 0; i < G_N_ELEMENTS (modes_decl); i++)
     modes_decl[i].mode_id = modes->len + i;
@@ -99,47 +101,49 @@ append_monitor (GArray *modes,
   };
   g_array_append_val (crtcs, crtc);
 
+  output = g_object_new (META_TYPE_OUTPUT, NULL);
+
   output_dummy = g_new0 (MetaOutputDummy, 1);
   *output_dummy = (MetaOutputDummy) {
     .scale = scale
   };
 
-  output = (MetaOutput) {
-    .winsys_id = outputs->len + 1,
-    .name = g_strdup_printf ("LVDS%d", outputs->len + 1),
-    .vendor = g_strdup ("MetaProducts Inc."),
-    .product = g_strdup ("MetaMonitor"),
-    .serial = g_strdup_printf ("0xC0FFEE-%d", outputs->len + 1),
-    .suggested_x = -1,
-    .suggested_y = -1,
-    .width_mm = 222,
-    .height_mm = 125,
-    .subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN,
-    .preferred_mode = &array_last (modes, MetaCrtcMode),
-    .n_possible_clones = 0,
-    .backlight = -1,
-    .connector_type = META_CONNECTOR_TYPE_LVDS,
-    .driver_private = output_dummy,
-    .driver_notify =
-      (GDestroyNotify) meta_output_dummy_notify_destroy
-  };
-
-  output.modes = g_new0 (MetaCrtcMode *, G_N_ELEMENTS (modes_decl));
+  number = g_list_length (*outputs) + 1;
+
+  output->winsys_id = number;
+  output->name = g_strdup_printf ("LVDS%d", number);
+  output->vendor = g_strdup ("MetaProducts Inc.");
+  output->product = g_strdup ("MetaMonitor");
+  output->serial = g_strdup_printf ("0xC0FFEE-%d", number);
+  output->suggested_x = -1;
+  output->suggested_y = -1;
+  output->width_mm = 222;
+  output->height_mm = 125;
+  output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
+  output->preferred_mode = &array_last (modes, MetaCrtcMode);
+  output->n_possible_clones = 0;
+  output->backlight = -1;
+  output->connector_type = META_CONNECTOR_TYPE_LVDS;
+  output->driver_private = output_dummy;
+  output->driver_notify =
+    (GDestroyNotify) meta_output_dummy_notify_destroy;
+
+  output->modes = g_new0 (MetaCrtcMode *, G_N_ELEMENTS (modes_decl));
   for (i = 0; i < G_N_ELEMENTS (modes_decl); i++)
-    output.modes[i] = &g_array_index (modes, MetaCrtcMode,
-                                      modes->len - (i + 1));
-  output.n_modes = G_N_ELEMENTS (modes_decl);
-  output.possible_crtcs = g_new0 (MetaCrtc *, 1);
-  output.possible_crtcs[0] = &array_last (crtcs, MetaCrtc);
-  output.n_possible_crtcs = 1;
-
-  g_array_append_val (outputs, output);
+    output->modes[i] = &g_array_index (modes, MetaCrtcMode,
+                                       modes->len - (i + 1));
+  output->n_modes = G_N_ELEMENTS (modes_decl);
+  output->possible_crtcs = g_new0 (MetaCrtc *, 1);
+  output->possible_crtcs[0] = &array_last (crtcs, MetaCrtc);
+  output->n_possible_crtcs = 1;
+
+  *outputs = g_list_append (*outputs, output);
 }
 
 static void
 append_tiled_monitor (GArray *modes,
                       GArray *crtcs,
-                      GArray *outputs,
+                      GList **outputs,
                       int     scale)
 {
   MetaCrtcMode modes_decl[] = {
@@ -162,7 +166,7 @@ append_tiled_monitor (GArray *modes,
       .all_transforms = ALL_TRANSFORMS,
     },
   };
-  MetaOutput output;
+  MetaOutput *output;
   unsigned int i;
   uint32_t tile_group_id;
 
@@ -174,61 +178,66 @@ append_tiled_monitor (GArray *modes,
     crtcs_decl[i].crtc_id = crtcs->len + i + 1;
   g_array_append_vals (crtcs, crtcs_decl, G_N_ELEMENTS (crtcs_decl));
 
-  tile_group_id = outputs->len + 1;
+  tile_group_id = g_list_length (*outputs) + 1;
   for (i = 0; i < G_N_ELEMENTS (crtcs_decl); i++)
     {
       MetaOutputDummy *output_dummy;
       MetaCrtcMode *preferred_mode;
       unsigned int j;
+      unsigned int number;
 
       output_dummy = g_new0 (MetaOutputDummy, 1);
       *output_dummy = (MetaOutputDummy) {
         .scale = scale
       };
 
-      preferred_mode = &array_last (modes, MetaCrtcMode),
-      output = (MetaOutput) {
-        .winsys_id = outputs->len + 1,
-        .name = g_strdup_printf ("LVDS%d", outputs->len + 1),
-        .vendor = g_strdup ("MetaProducts Inc."),
-        .product = g_strdup ("MetaMonitor"),
-        .serial = g_strdup_printf ("0xC0FFEE-%d", outputs->len + 1),
-        .suggested_x = -1,
-        .suggested_y = -1,
-        .width_mm = 222,
-        .height_mm = 125,
-        .subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN,
-        .preferred_mode = preferred_mode,
-        .n_possible_clones = 0,
-        .backlight = -1,
-        .connector_type = META_CONNECTOR_TYPE_LVDS,
-        .tile_info = (MetaTileInfo) {
-          .group_id = tile_group_id,
-          .max_h_tiles = G_N_ELEMENTS (crtcs_decl),
-          .max_v_tiles = 1,
-          .loc_h_tile = i,
-          .loc_v_tile = 0,
-          .tile_w = preferred_mode->width,
-          .tile_h = preferred_mode->height
-        },
-        .driver_private = output_dummy,
-        .driver_notify =
-          (GDestroyNotify) meta_output_dummy_notify_destroy
-      };
-
-      output.modes = g_new0 (MetaCrtcMode *, G_N_ELEMENTS (modes_decl));
+      /* Arbitrary ID unique for this output */
+      number = g_list_length (*outputs) + 1;
+
+      preferred_mode = &array_last (modes, MetaCrtcMode);
+
+      output = g_object_new (META_TYPE_OUTPUT, NULL);
+
+      output->winsys_id = number;
+      output->name = g_strdup_printf ("LVDS%d", number);
+      output->vendor = g_strdup ("MetaProducts Inc.");
+      output->product = g_strdup ("MetaMonitor");
+      output->serial = g_strdup_printf ("0xC0FFEE-%d", number);
+      output->suggested_x = -1;
+      output->suggested_y = -1;
+      output->width_mm = 222;
+      output->height_mm = 125;
+      output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
+      output->preferred_mode = preferred_mode;
+      output->n_possible_clones = 0;
+      output->backlight = -1;
+      output->connector_type = META_CONNECTOR_TYPE_LVDS;
+      output->tile_info = (MetaTileInfo) {
+        .group_id = tile_group_id,
+        .max_h_tiles = G_N_ELEMENTS (crtcs_decl),
+        .max_v_tiles = 1,
+        .loc_h_tile = i,
+        .loc_v_tile = 0,
+        .tile_w = preferred_mode->width,
+        .tile_h = preferred_mode->height
+      },
+      output->driver_private = output_dummy;
+      output->driver_notify =
+        (GDestroyNotify) meta_output_dummy_notify_destroy;
+
+      output->modes = g_new0 (MetaCrtcMode *, G_N_ELEMENTS (modes_decl));
       for (j = 0; j < G_N_ELEMENTS (modes_decl); j++)
-        output.modes[j] = &g_array_index (modes, MetaCrtcMode,
-                                          modes->len - (j + 1));
-      output.n_modes = G_N_ELEMENTS (modes_decl);
+        output->modes[j] = &g_array_index (modes, MetaCrtcMode,
+                                           modes->len - (j + 1));
+      output->n_modes = G_N_ELEMENTS (modes_decl);
 
-      output.possible_crtcs = g_new0 (MetaCrtc *, G_N_ELEMENTS (crtcs_decl));
+      output->possible_crtcs = g_new0 (MetaCrtc *, G_N_ELEMENTS (crtcs_decl));
       for (j = 0; j < G_N_ELEMENTS (crtcs_decl); j++)
-        output.possible_crtcs[j] = &g_array_index (crtcs, MetaCrtc,
-                                                   crtcs->len - (j + 1));
-      output.n_possible_crtcs = G_N_ELEMENTS (crtcs_decl);
+        output->possible_crtcs[j] = &g_array_index (crtcs, MetaCrtc,
+                                                    crtcs->len - (j + 1));
+      output->n_possible_crtcs = G_N_ELEMENTS (crtcs_decl);
 
-      g_array_append_val (outputs, output);
+      *outputs = g_list_append (*outputs, output);
     }
 }
 
@@ -248,7 +257,7 @@ meta_monitor_manager_dummy_read_current (MetaMonitorManager *manager)
   const char *tiled_monitors_str;
   gboolean tiled_monitors;
   unsigned int i;
-  GArray *outputs;
+  GList *outputs;
   GArray *crtcs;
   GArray *modes;
 
@@ -321,26 +330,24 @@ meta_monitor_manager_dummy_read_current (MetaMonitorManager *manager)
 
   modes = g_array_sized_new (FALSE, TRUE, sizeof (MetaCrtcMode), MAX_MODES);
   crtcs = g_array_sized_new (FALSE, TRUE, sizeof (MetaCrtc), MAX_CRTCS);
-  outputs = g_array_sized_new (FALSE, TRUE, sizeof (MetaOutput), MAX_OUTPUTS);
+  outputs = NULL;
 
   for (i = 0; i < num_monitors; i++)
     {
       if (tiled_monitors)
-        append_tiled_monitor (modes, crtcs, outputs, monitor_scales[i]);
+        append_tiled_monitor (modes, crtcs, &outputs, monitor_scales[i]);
       else
-        append_monitor (modes, crtcs, outputs, monitor_scales[i]);
+        append_monitor (modes, crtcs, &outputs, monitor_scales[i]);
     }
 
   manager->modes = (MetaCrtcMode *) modes->data;
   manager->n_modes = modes->len;
   manager->crtcs = (MetaCrtc *) crtcs->data;
   manager->n_crtcs = crtcs->len;
-  manager->outputs = (MetaOutput *) outputs->data;
-  manager->n_outputs = outputs->len;
+  manager->outputs = outputs;
 
   g_array_free (modes, FALSE);
   g_array_free (crtcs, FALSE);
-  g_array_free (outputs, FALSE);
 }
 
 static void
@@ -363,6 +370,7 @@ apply_crtc_assignments (MetaMonitorManager *manager,
                         MetaOutputInfo    **outputs,
                         unsigned int        n_outputs)
 {
+  GList *l;
   unsigned i;
 
   for (i = 0; i < n_crtcs; i++)
@@ -446,9 +454,9 @@ apply_crtc_assignments (MetaMonitorManager *manager,
     }
 
   /* Disable outputs not mentioned in the list */
-  for (i = 0; i < manager->n_outputs; i++)
+  for (l = manager->outputs; l; l = l->next)
     {
-      MetaOutput *output = &manager->outputs[i];
+      MetaOutput *output = l->data;
 
       if (output->is_dirty)
         {
diff --git a/src/backends/meta-monitor-manager-private.h b/src/backends/meta-monitor-manager-private.h
index 072e765..3bf8864 100644
--- a/src/backends/meta-monitor-manager-private.h
+++ b/src/backends/meta-monitor-manager-private.h
@@ -105,28 +105,6 @@ typedef enum
   META_MONITOR_TRANSFORM_FLIPPED_270,
 } MetaMonitorTransform;
 
-/* This matches the values in drm_mode.h */
-typedef enum
-{
-  META_CONNECTOR_TYPE_Unknown = 0,
-  META_CONNECTOR_TYPE_VGA = 1,
-  META_CONNECTOR_TYPE_DVII = 2,
-  META_CONNECTOR_TYPE_DVID = 3,
-  META_CONNECTOR_TYPE_DVIA = 4,
-  META_CONNECTOR_TYPE_Composite = 5,
-  META_CONNECTOR_TYPE_SVIDEO = 6,
-  META_CONNECTOR_TYPE_LVDS = 7,
-  META_CONNECTOR_TYPE_Component = 8,
-  META_CONNECTOR_TYPE_9PinDIN = 9,
-  META_CONNECTOR_TYPE_DisplayPort = 10,
-  META_CONNECTOR_TYPE_HDMIA = 11,
-  META_CONNECTOR_TYPE_HDMIB = 12,
-  META_CONNECTOR_TYPE_TV = 13,
-  META_CONNECTOR_TYPE_eDP = 14,
-  META_CONNECTOR_TYPE_VIRTUAL = 15,
-  META_CONNECTOR_TYPE_DSI = 16,
-} MetaConnectorType;
-
 /* Same as KMS mode flags and X11 randr flags */
 typedef enum
 {
@@ -149,74 +127,6 @@ typedef enum
   META_CRTC_MODE_FLAG_MASK = 0x3fff
 } MetaCrtcModeFlag;
 
-struct _MetaTileInfo
-{
-  guint32 group_id;
-  guint32 flags;
-  guint32 max_h_tiles;
-  guint32 max_v_tiles;
-  guint32 loc_h_tile;
-  guint32 loc_v_tile;
-  guint32 tile_w;
-  guint32 tile_h;
-};
-
-struct _MetaOutput
-{
-  /* The CRTC driving this output, NULL if the output is not enabled */
-  MetaCrtc *crtc;
-  /* The low-level ID of this output, used to apply back configuration */
-  glong winsys_id;
-  char *name;
-  char *vendor;
-  char *product;
-  char *serial;
-  int width_mm;
-  int height_mm;
-  CoglSubpixelOrder subpixel_order;
-
-  MetaConnectorType connector_type;
-
-  MetaCrtcMode *preferred_mode;
-  MetaCrtcMode **modes;
-  unsigned int n_modes;
-
-  MetaCrtc **possible_crtcs;
-  unsigned int n_possible_crtcs;
-
-  MetaOutput **possible_clones;
-  unsigned int n_possible_clones;
-
-  int backlight;
-  int backlight_min;
-  int backlight_max;
-
-  /* Used when changing configuration */
-  gboolean is_dirty;
-
-  /* The low-level bits used to build the high-level info
-     in MetaLogicalMonitor
-
-     XXX: flags maybe?
-     There is a lot of code that uses MonitorInfo->is_primary,
-     but nobody uses MetaOutput yet
-  */
-  gboolean is_primary;
-  gboolean is_presentation;
-  gboolean is_underscanning;
-  gboolean supports_underscanning;
-
-  gpointer driver_private;
-  GDestroyNotify driver_notify;
-
-  /* get a new preferred mode on hotplug events, to handle dynamic guest resizing */
-  gboolean hotplug_mode_update;
-  gint suggested_x;
-  gint suggested_y;
-
-  MetaTileInfo tile_info;
-};
-
 struct _MetaCrtc
 {
   glong crtc_id;
@@ -317,8 +227,7 @@ struct _MetaMonitorManager
      (like encoders, but less tied to the HW),
      while logical_monitors refer to logical ones.
   */
-  MetaOutput *outputs;
-  unsigned int n_outputs;
+  GList *outputs;
 
   MetaCrtcMode *modes;
   unsigned int n_modes;
@@ -451,8 +360,7 @@ MetaMonitor *       meta_monitor_manager_get_monitor_from_connector (MetaMonitor
 
 GList *             meta_monitor_manager_get_monitors      (MetaMonitorManager *manager);
 
-MetaOutput         *meta_monitor_manager_get_outputs       (MetaMonitorManager *manager,
-                                                           unsigned int       *n_outputs);
+GList *             meta_monitor_manager_get_outputs       (MetaMonitorManager *manager);
 
 void                meta_monitor_manager_get_resources     (MetaMonitorManager  *manager,
                                                             MetaCrtcMode       **modes,
diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c
index 2caec1b..82b50e0 100644
--- a/src/backends/meta-monitor-manager.c
+++ b/src/backends/meta-monitor-manager.c
@@ -40,6 +40,7 @@
 #include "backends/meta-monitor.h"
 #include "backends/meta-monitor-config-manager.h"
 #include "backends/meta-orientation-manager.h"
+#include "backends/meta-output.h"
 #include "backends/x11/meta-monitor-manager-xrandr.h"
 #include "meta-backend-private.h"
 
@@ -446,11 +447,11 @@ meta_monitor_manager_apply_monitors_config (MetaMonitorManager      *manager,
 gboolean
 meta_monitor_manager_has_hotplug_mode_update (MetaMonitorManager *manager)
 {
-  unsigned int i;
+  GList *l;
 
-  for (i = 0; i < manager->n_outputs; i++)
+  for (l = manager->outputs; l; l = l->next)
     {
-      MetaOutput *output = &manager->outputs[i];
+      MetaOutput *output = l->data;
 
       if (output->hotplug_mode_update)
         return TRUE;
@@ -719,35 +720,6 @@ meta_monitor_manager_constructed (GObject *object)
 }
 
 void
-meta_monitor_manager_clear_output (MetaOutput *output)
-{
-  g_free (output->name);
-  g_free (output->vendor);
-  g_free (output->product);
-  g_free (output->serial);
-  g_free (output->modes);
-  g_free (output->possible_crtcs);
-  g_free (output->possible_clones);
-
-  if (output->driver_notify)
-    output->driver_notify (output);
-
-  memset (output, 0, sizeof (*output));
-}
-
-static void
-meta_monitor_manager_free_output_array (MetaOutput *old_outputs,
-                                        int         n_old_outputs)
-{
-  int i;
-
-  for (i = 0; i < n_old_outputs; i++)
-    meta_monitor_manager_clear_output (&old_outputs[i]);
-
-  g_free (old_outputs);
-}
-
-void
 meta_monitor_manager_clear_mode (MetaCrtcMode *mode)
 {
   g_free (mode->name);
@@ -796,7 +768,7 @@ meta_monitor_manager_finalize (GObject *object)
 {
   MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
 
-  meta_monitor_manager_free_output_array (manager->outputs, manager->n_outputs);
+  g_list_free_full (manager->outputs, g_object_unref);
   meta_monitor_manager_free_mode_array (manager->modes, manager->n_modes);
   meta_monitor_manager_free_crtc_array (manager->crtcs, manager->n_crtcs);
   g_list_free_full (manager->logical_monitors, g_object_unref);
@@ -965,6 +937,7 @@ meta_monitor_manager_handle_get_resources (MetaDBusDisplayConfig *skeleton,
   MetaMonitorManager *manager = META_MONITOR_MANAGER (skeleton);
   MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_GET_CLASS (skeleton);
   GVariantBuilder crtc_builder, output_builder, mode_builder;
+  GList *l;
   unsigned int i, j;
   int max_screen_width;
   int max_screen_height;
@@ -996,9 +969,9 @@ meta_monitor_manager_handle_get_resources (MetaDBusDisplayConfig *skeleton,
                              NULL /* properties */);
     }
 
-  for (i = 0; i < manager->n_outputs; i++)
+  for (l = manager->outputs; l; l = l->next)
     {
-      MetaOutput *output = &manager->outputs[i];
+      MetaOutput *output = l->data;
       GVariantBuilder crtcs, modes, clones, properties;
       GBytes *edid;
       char *edid_file;
@@ -1015,8 +988,13 @@ meta_monitor_manager_handle_get_resources (MetaDBusDisplayConfig *skeleton,
 
       g_variant_builder_init (&clones, G_VARIANT_TYPE ("au"));
       for (j = 0; j < output->n_possible_clones; j++)
-        g_variant_builder_add (&clones, "u",
-                               (unsigned)(output->possible_clones[j] - manager->outputs));
+        {
+          unsigned int possible_clone_index;
+
+          possible_clone_index = g_list_index (manager->outputs,
+                                               output->possible_clones[j]);
+          g_variant_builder_add (&clones, "u", possible_clone_index);
+        }
 
       g_variant_builder_init (&properties, G_VARIANT_TYPE ("a{sv}"));
       g_variant_builder_add (&properties, "{sv}", "vendor",
@@ -2030,14 +2008,14 @@ meta_monitor_manager_handle_change_backlight  (MetaDBusDisplayConfig *skeleton,
       return TRUE;
     }
 
-  if (output_index >= manager->n_outputs)
+  if (output_index >= g_list_length (manager->outputs))
     {
       g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
                                              G_DBUS_ERROR_INVALID_ARGS,
                                              "Invalid output id");
       return TRUE;
     }
-  output = &manager->outputs[output_index];
+  output = g_list_nth_data (manager->outputs, output_index);
 
   if (value < 0 || value > 100)
     {
@@ -2425,11 +2403,9 @@ meta_monitor_manager_get_monitors (MetaMonitorManager *manager)
   return manager->monitors;
 }
 
-MetaOutput *
-meta_monitor_manager_get_outputs (MetaMonitorManager *manager,
-                                  unsigned int       *n_outputs)
+GList *
+meta_monitor_manager_get_outputs (MetaMonitorManager *manager)
 {
-  *n_outputs = manager->n_outputs;
   return manager->outputs;
 }
 
@@ -2471,7 +2447,7 @@ meta_monitor_manager_get_screen_size (MetaMonitorManager *manager,
 static void
 rebuild_monitors (MetaMonitorManager *manager)
 {
-  unsigned int i;
+  GList *l;
 
   if (manager->monitors)
     {
@@ -2479,9 +2455,9 @@ rebuild_monitors (MetaMonitorManager *manager)
       manager->monitors = NULL;
     }
 
-  for (i = 0; i < manager->n_outputs; i++)
+  for (l = manager->outputs; l; l = l->next)
     {
-      MetaOutput *output = &manager->outputs[i];
+      MetaOutput *output = l->data;
 
       if (output->tile_info.group_id)
         {
@@ -2541,16 +2517,15 @@ meta_monitor_manager_is_transform_handled (MetaMonitorManager  *manager,
 void
 meta_monitor_manager_read_current_state (MetaMonitorManager *manager)
 {
-  MetaOutput *old_outputs;
+  GList *old_outputs;
   MetaCrtc *old_crtcs;
   MetaCrtcMode *old_modes;
-  unsigned int n_old_outputs, n_old_crtcs, n_old_modes;
+  unsigned int n_old_crtcs, n_old_modes;
 
   /* Some implementations of read_current use the existing information
    * we have available, so don't free the old configuration until after
    * read_current finishes. */
   old_outputs = manager->outputs;
-  n_old_outputs = manager->n_outputs;
   old_crtcs = manager->crtcs;
   n_old_crtcs = manager->n_crtcs;
   old_modes = manager->modes;
@@ -2561,7 +2536,7 @@ meta_monitor_manager_read_current_state (MetaMonitorManager *manager)
 
   rebuild_monitors (manager);
 
-  meta_monitor_manager_free_output_array (old_outputs, n_old_outputs);
+  g_list_free_full (old_outputs, g_object_unref);
   meta_monitor_manager_free_mode_array (old_modes, n_old_modes);
   meta_monitor_manager_free_crtc_array (old_crtcs, n_old_crtcs);
 }
@@ -2832,9 +2807,9 @@ meta_monitor_manager_get_monitor_for_output (MetaMonitorManager *manager,
   GList *l;
 
   g_return_val_if_fail (META_IS_MONITOR_MANAGER (manager), -1);
-  g_return_val_if_fail (id < manager->n_outputs, -1);
+  g_return_val_if_fail (id < g_list_length (manager->outputs), -1);
 
-  output = &manager->outputs[id];
+  output = g_list_nth_data (manager->outputs, id);
   if (!output || !output->crtc)
     return -1;
 
diff --git a/src/backends/meta-monitor.c b/src/backends/meta-monitor.c
index 8ca6ea8..477bbed 100644
--- a/src/backends/meta-monitor.c
+++ b/src/backends/meta-monitor.c
@@ -26,6 +26,7 @@
 #include "backends/meta-backend-private.h"
 #include "backends/meta-monitor-manager-private.h"
 #include "backends/meta-settings-private.h"
+#include "backends/meta-output.h"
 
 #define SCALE_FACTORS_PER_INTEGER 4
 #define MINIMUM_SCALE_FACTOR 1.0f
@@ -560,11 +561,13 @@ add_tiled_monitor_outputs (MetaMonitorManager *monitor_manager,
 {
   MetaMonitorPrivate *monitor_priv =
     meta_monitor_get_instance_private (META_MONITOR (monitor_tiled));
-  unsigned int i;
+  GList *outputs;
+  GList *l;
 
-  for (i = 0; i < monitor_manager->n_outputs; i++)
+  outputs = monitor_manager->outputs;
+  for (l = outputs; l; l = l->next)
     {
-      MetaOutput *output = &monitor_manager->outputs[i];
+      MetaOutput *output = l->data;
 
       if (output->tile_info.group_id != monitor_tiled->tile_group_id)
         continue;
diff --git a/src/backends/meta-monitor.h b/src/backends/meta-monitor.h
index f4260d6..9a9e6d8 100644
--- a/src/backends/meta-monitor.h
+++ b/src/backends/meta-monitor.h
@@ -25,6 +25,7 @@
 #include <glib-object.h>
 
 #include "backends/meta-monitor-manager-private.h"
+#include "backends/meta-output.h"
 
 typedef struct _MetaMonitorSpec
 {
diff --git a/src/backends/meta-output.c b/src/backends/meta-output.c
new file mode 100644
index 0000000..1dd0ffa
--- /dev/null
+++ b/src/backends/meta-output.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "backends/meta-output.h"
+
+G_DEFINE_TYPE (MetaOutput, meta_output, G_TYPE_OBJECT)
+
+static void
+meta_output_finalize (GObject *object)
+{
+  MetaOutput *output = META_OUTPUT (object);
+
+  g_free (output->name);
+  g_free (output->vendor);
+  g_free (output->product);
+  g_free (output->serial);
+  g_free (output->modes);
+  g_free (output->possible_crtcs);
+  g_free (output->possible_clones);
+
+  if (output->driver_notify)
+    output->driver_notify (output);
+
+  G_OBJECT_CLASS (meta_output_parent_class)->finalize (object);
+}
+
+static void
+meta_output_init (MetaOutput *output)
+{
+}
+
+static void
+meta_output_class_init (MetaOutputClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = meta_output_finalize;
+}
diff --git a/src/backends/meta-output.h b/src/backends/meta-output.h
new file mode 100644
index 0000000..5f51d52
--- /dev/null
+++ b/src/backends/meta-output.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2017 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef META_OUTPUT_H
+#define META_OUTPUT_H
+
+#include <glib-object.h>
+
+#include "backends/meta-monitor-manager-private.h"
+
+struct _MetaTileInfo
+{
+  guint32 group_id;
+  guint32 flags;
+  guint32 max_h_tiles;
+  guint32 max_v_tiles;
+  guint32 loc_h_tile;
+  guint32 loc_v_tile;
+  guint32 tile_w;
+  guint32 tile_h;
+};
+
+/* This matches the values in drm_mode.h */
+typedef enum
+{
+  META_CONNECTOR_TYPE_Unknown = 0,
+  META_CONNECTOR_TYPE_VGA = 1,
+  META_CONNECTOR_TYPE_DVII = 2,
+  META_CONNECTOR_TYPE_DVID = 3,
+  META_CONNECTOR_TYPE_DVIA = 4,
+  META_CONNECTOR_TYPE_Composite = 5,
+  META_CONNECTOR_TYPE_SVIDEO = 6,
+  META_CONNECTOR_TYPE_LVDS = 7,
+  META_CONNECTOR_TYPE_Component = 8,
+  META_CONNECTOR_TYPE_9PinDIN = 9,
+  META_CONNECTOR_TYPE_DisplayPort = 10,
+  META_CONNECTOR_TYPE_HDMIA = 11,
+  META_CONNECTOR_TYPE_HDMIB = 12,
+  META_CONNECTOR_TYPE_TV = 13,
+  META_CONNECTOR_TYPE_eDP = 14,
+  META_CONNECTOR_TYPE_VIRTUAL = 15,
+  META_CONNECTOR_TYPE_DSI = 16,
+} MetaConnectorType;
+
+struct _MetaOutput
+{
+  GObject parent;
+
+  /* The CRTC driving this output, NULL if the output is not enabled */
+  MetaCrtc *crtc;
+
+  /* The low-level ID of this output, used to apply back configuration */
+  glong winsys_id;
+  char *name;
+  char *vendor;
+  char *product;
+  char *serial;
+  int width_mm;
+  int height_mm;
+  CoglSubpixelOrder subpixel_order;
+
+  MetaConnectorType connector_type;
+
+  MetaCrtcMode *preferred_mode;
+  MetaCrtcMode **modes;
+  unsigned int n_modes;
+
+  MetaCrtc **possible_crtcs;
+  unsigned int n_possible_crtcs;
+
+  MetaOutput **possible_clones;
+  unsigned int n_possible_clones;
+
+  int backlight;
+  int backlight_min;
+  int backlight_max;
+
+  /* Used when changing configuration */
+  gboolean is_dirty;
+
+  gboolean is_primary;
+  gboolean is_presentation;
+
+  gboolean is_underscanning;
+  gboolean supports_underscanning;
+
+  gpointer driver_private;
+  GDestroyNotify driver_notify;
+
+  /*
+   * Get a new preferred mode on hotplug events, to handle dynamic guest
+   * resizing.
+   */
+  gboolean hotplug_mode_update;
+  gint suggested_x;
+  gint suggested_y;
+
+  MetaTileInfo tile_info;
+};
+
+#define META_TYPE_OUTPUT (meta_output_get_type ())
+G_DECLARE_FINAL_TYPE (MetaOutput, meta_output, META, OUTPUT, GObject)
+
+#endif /* META_OUTPUT_H */
diff --git a/src/backends/native/meta-cursor-renderer-native.c 
b/src/backends/native/meta-cursor-renderer-native.c
index 72276eb..cb5686e 100644
--- a/src/backends/native/meta-cursor-renderer-native.c
+++ b/src/backends/native/meta-cursor-renderer-native.c
@@ -38,6 +38,7 @@
 #include "backends/meta-logical-monitor.h"
 #include "backends/meta-monitor.h"
 #include "backends/meta-monitor-manager-private.h"
+#include "backends/meta-output.h"
 #include "backends/native/meta-renderer-native.h"
 #include "core/boxes-private.h"
 #include "meta/boxes.h"
diff --git a/src/backends/native/meta-monitor-manager-kms.c b/src/backends/native/meta-monitor-manager-kms.c
index 23a79ae..48e4d14 100644
--- a/src/backends/native/meta-monitor-manager-kms.c
+++ b/src/backends/native/meta-monitor-manager-kms.c
@@ -25,6 +25,7 @@
 
 #include "meta-monitor-manager-kms.h"
 #include "meta-monitor-config-manager.h"
+#include "meta-output.h"
 #include "meta-backend-private.h"
 #include "meta-renderer-native.h"
 
@@ -134,8 +135,8 @@ free_resources (MetaMonitorManagerKms *manager_kms)
 }
 
 static int
-compare_outputs (const void *one,
-                 const void *two)
+compare_outputs (gconstpointer one,
+                 gconstpointer two)
 {
   const MetaOutput *o_one = one, *o_two = two;
 
@@ -470,15 +471,18 @@ compare_modes (const void *one,
 }
 
 static MetaOutput *
-find_output_by_id (MetaOutput *outputs,
-                   unsigned    n_outputs,
-                   glong       id)
+find_output_by_id (GList *outputs,
+                   glong  id)
 {
-  unsigned i;
+  GList *l;
 
-  for (i = 0; i < n_outputs; i++)
-    if (outputs[i].winsys_id == id)
-      return &outputs[i];
+  for (l = outputs; l; l = l->next)
+    {
+      MetaOutput *output = l->data;
+
+      if (output->winsys_id == id)
+        return output;
+    }
 
   return NULL;
 }
@@ -692,19 +696,21 @@ init_crtc (MetaCrtc           *crtc,
   crtc->driver_notify = (GDestroyNotify) meta_crtc_destroy_notify;
 }
 
-static void
-init_output (MetaOutput         *output,
-             MetaMonitorManager *manager,
-             drmModeConnector   *connector,
-             MetaOutput         *old_output)
+static MetaOutput *
+create_output (MetaMonitorManager *manager,
+               drmModeConnector   *connector,
+               MetaOutput         *old_output)
 {
   MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
+  MetaOutput *output;
   MetaOutputKms *output_kms;
   GArray *crtcs;
   GBytes *edid;
   unsigned int i;
   unsigned int crtc_mask;
 
+  output = g_object_new (META_TYPE_OUTPUT, NULL);
+
   output_kms = g_slice_new0 (MetaOutputKms);
   output->driver_private = output_kms;
   output->driver_notify = (GDestroyNotify)meta_output_destroy_notify;
@@ -865,6 +871,8 @@ init_output (MetaOutput         *output,
   output->backlight_min = 0;
   output->backlight_max = 0;
   output->backlight = -1;
+
+  return output;
 }
 
 static void
@@ -874,6 +882,7 @@ detect_and_setup_output_clones (MetaMonitorManager *manager,
   MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
   drmModeEncoder **encoders;
   unsigned int i, n_encoders;
+  GList *l;
 
   n_encoders = (unsigned int) resources->count_encoders;
   encoders = g_new (drmModeEncoder *, n_encoders);
@@ -883,15 +892,12 @@ detect_and_setup_output_clones (MetaMonitorManager *manager,
   /*
    * Setup encoder position mask and encoder clone mask.
    */
-  for (i = 0; i < manager->n_outputs; i++)
+  for (l = manager->outputs; l; l = l->next)
     {
-      MetaOutput *output;
-      MetaOutputKms *output_kms;
+      MetaOutput *output = l->data;
+      MetaOutputKms *output_kms = output->driver_private;
       unsigned int j;
 
-      output = &manager->outputs[i];
-      output_kms = output->driver_private;
-
       output_kms->enc_clone_mask = 0xff;
       output_kms->encoder_mask = 0;
 
@@ -920,27 +926,21 @@ detect_and_setup_output_clones (MetaMonitorManager *manager,
   /*
    * Setup MetaOutput <-> MetaOutput clone associations.
    */
-  for (i = 0; i < manager->n_outputs; i++)
+  for (l = manager->outputs; l; l = l->next)
     {
-      MetaOutput *output;
-      MetaOutputKms *output_kms;
-      unsigned int j;
-
-      output = &manager->outputs[i];
-      output_kms = output->driver_private;
+      MetaOutput *output = l->data;
+      MetaOutputKms *output_kms = output->driver_private;
+      GList *k;
 
       if (output_kms->enc_clone_mask == 0)
         continue;
 
-      for (j = 0; j < manager->n_outputs; j++)
+      for (k = manager->outputs; k; k = k->next)
         {
-          MetaOutput *meta_clone;
-          MetaOutputKms *clone_kms;
-
-          meta_clone = &manager->outputs[i];
-          clone_kms = meta_clone->driver_private;
+          MetaOutput *clone = k->data;
+          MetaOutputKms *clone_kms = clone->driver_private;
 
-          if (meta_clone == output)
+          if (clone == output)
             continue;
 
           if (clone_kms->encoder_mask == 0)
@@ -952,7 +952,7 @@ detect_and_setup_output_clones (MetaMonitorManager *manager,
               output->possible_clones = g_renew (MetaOutput *,
                                                  output->possible_clones,
                                                  output->n_possible_clones);
-              output->possible_clones[output->n_possible_clones - 1] = meta_clone;
+              output->possible_clones[output->n_possible_clones - 1] = clone;
             }
         }
     }
@@ -1066,42 +1066,33 @@ init_outputs (MetaMonitorManager *manager,
               drmModeRes         *resources)
 {
   MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
-  MetaOutput *old_outputs;
-  unsigned int n_old_outputs;
-  unsigned int n_actual_outputs;
+  GList *old_outputs;
   unsigned int i;
 
   old_outputs = manager->outputs;
-  n_old_outputs = manager->n_outputs;
 
-  manager->outputs = g_new0 (MetaOutput, manager_kms->n_connectors);
-  n_actual_outputs = 0;
+  manager->outputs = NULL;
 
   for (i = 0; i < manager_kms->n_connectors; i++)
     {
       drmModeConnector *connector;
-      MetaOutput *output;
 
       connector = manager_kms->connectors[i];
-      output = &manager->outputs[n_actual_outputs];
 
       if (connector && connector->connection == DRM_MODE_CONNECTED)
         {
+          MetaOutput *output;
           MetaOutput *old_output;
 
-          old_output = find_output_by_id (old_outputs, n_old_outputs,
-                                          connector->connector_id);
-          init_output (output, manager, connector, old_output);
-          n_actual_outputs++;
+          old_output = find_output_by_id (old_outputs, connector->connector_id);
+          output = create_output (manager, connector, old_output);
+          manager->outputs = g_list_prepend (manager->outputs, output);
         }
     }
 
-  manager->n_outputs = n_actual_outputs;
-  manager->outputs = g_renew (MetaOutput, manager->outputs, manager->n_outputs);
 
   /* Sort the outputs for easier handling in MetaMonitorConfig */
-  qsort (manager->outputs, manager->n_outputs, sizeof (MetaOutput),
-         compare_outputs);
+  manager->outputs = g_list_sort (manager->outputs, compare_outputs);
 
   detect_and_setup_output_clones (manager, resources);
 }
@@ -1163,7 +1154,7 @@ meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager,
 {
   MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
   uint64_t state;
-  unsigned i;
+  GList *l;
 
   switch (mode) {
   case META_POWER_SAVE_ON:
@@ -1182,13 +1173,10 @@ meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager,
     return;
   }
 
-  for (i = 0; i < manager->n_outputs; i++)
+  for (l = manager->outputs; l; l = l->next)
     {
-      MetaOutput *output;
-      MetaOutputKms *output_kms;
-
-      output = &manager->outputs[i];
-      output_kms = output->driver_private;
+      MetaOutput *output = l->data;
+      MetaOutputKms *output_kms = output->driver_private;
 
       if (output_kms->dpms_prop_id != 0)
         {
@@ -1264,6 +1252,7 @@ apply_crtc_assignments (MetaMonitorManager *manager,
 {
   MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
   unsigned i;
+  GList *l;
 
   for (i = 0; i < n_crtcs; i++)
     {
@@ -1370,9 +1359,9 @@ apply_crtc_assignments (MetaMonitorManager *manager,
     }
 
   /* Disable outputs not mentioned in the list */
-  for (i = 0; i < manager->n_outputs; i++)
+  for (l = manager->outputs; l; l = l->next)
     {
-      MetaOutput *output = &manager->outputs[i];
+      MetaOutput *output = l->data;
 
       if (output->is_dirty)
         {
@@ -1605,12 +1594,12 @@ get_crtc_connectors (MetaMonitorManager *manager,
                      uint32_t          **connectors,
                      unsigned int       *n_connectors)
 {
-  unsigned int i;
   GArray *connectors_array = g_array_new (FALSE, FALSE, sizeof (uint32_t));
+  GList *l;
 
-  for (i = 0; i < manager->n_outputs; i++)
+  for (l = manager->outputs; l; l = l->next)
     {
-      MetaOutput *output = &manager->outputs[i];
+      MetaOutput *output = l->data;
 
       if (output->crtc == crtc)
         g_array_append_val (connectors_array, output->winsys_id);
@@ -1671,16 +1660,16 @@ meta_monitor_manager_kms_is_crtc_active (MetaMonitorManagerKms *manager_kms,
                                          MetaCrtc              *crtc)
 {
   MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms);
-  unsigned int i;
+  GList *l;
   gboolean connected_crtc_found;
 
   if (manager->power_save_mode != META_POWER_SAVE_ON)
     return FALSE;
 
   connected_crtc_found = FALSE;
-  for (i = 0; i < manager->n_outputs; i++)
+  for (l = manager->outputs; l; l = l->next)
     {
-      MetaOutput *output = &manager->outputs[i];
+      MetaOutput *output = l->data;
 
       if (output->crtc == crtc)
         {
diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c
index 4d1d890..7c822fd 100644
--- a/src/backends/native/meta-renderer-native.c
+++ b/src/backends/native/meta-renderer-native.c
@@ -51,6 +51,7 @@
 #include "backends/meta-egl.h"
 #include "backends/meta-egl-ext.h"
 #include "backends/meta-logical-monitor.h"
+#include "backends/meta-output.h"
 #include "backends/meta-renderer-view.h"
 #include "backends/native/meta-monitor-manager-kms.h"
 #include "backends/native/meta-renderer-native.h"
diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c
index c369d49..98b1f4d 100644
--- a/src/backends/x11/meta-monitor-manager-xrandr.c
+++ b/src/backends/x11/meta-monitor-manager-xrandr.c
@@ -45,6 +45,7 @@
 #include <meta/errors.h>
 #include "backends/meta-monitor-config-manager.h"
 #include "backends/meta-logical-monitor.h"
+#include "backends/meta-output.h"
 
 #define ALL_TRANSFORMS ((1 << (META_MONITOR_TRANSFORM_FLIPPED_270 + 1)) - 1)
 
@@ -731,8 +732,8 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
   MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
   XRRScreenResources *resources;
   RROutput primary_output;
-  unsigned int i, j, k;
-  unsigned int n_actual_outputs;
+  unsigned int i, j;
+  GList *l;
   int min_width, min_height;
   Screen *screen;
   BOOL dpms_capable, dpms_enabled;
@@ -790,10 +791,9 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
     return;
 
   manager_xrandr->resources = resources;
-  manager->n_outputs = resources->noutput;
   manager->n_crtcs = resources->ncrtc;
   manager->n_modes = resources->nmode;
-  manager->outputs = g_new0 (MetaOutput, manager->n_outputs);
+  manager->outputs = NULL;
   manager->modes = g_new0 (MetaCrtcMode, manager->n_modes);
   manager->crtcs = g_new0 (MetaCrtc, manager->n_crtcs);
 
@@ -846,7 +846,6 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
   primary_output = XRRGetOutputPrimary (manager_xrandr->xdisplay,
                                        DefaultRootWindow (manager_xrandr->xdisplay));
 
-  n_actual_outputs = 0;
   for (i = 0; i < (unsigned)resources->noutput; i++)
     {
       XRROutputInfo *xrandr_output;
@@ -857,7 +856,7 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
       if (!xrandr_output)
         continue;
 
-      output = &manager->outputs[n_actual_outputs];
+      output = g_object_new (META_TYPE_OUTPUT, NULL);
 
       if (xrandr_output->connection != RR_Disconnected)
        {
@@ -910,35 +909,34 @@ meta_monitor_manager_xrandr_read_current (MetaMonitorManager *manager)
            output->backlight = -1;
 
           if (output->n_modes == 0 || output->n_possible_crtcs == 0)
-            meta_monitor_manager_clear_output (output);
+            g_object_unref (output);
           else
-            n_actual_outputs++;
+            manager->outputs = g_list_prepend (manager->outputs, output);
        }
 
       XRRFreeOutputInfo (xrandr_output);
     }
 
-  manager->n_outputs = n_actual_outputs;
-
   /* Sort the outputs for easier handling in MetaMonitorConfig */
-  qsort (manager->outputs, manager->n_outputs, sizeof (MetaOutput), compare_outputs);
+  manager->outputs = g_list_sort (manager->outputs, compare_outputs);
 
   /* Now fix the clones */
-  for (i = 0; i < manager->n_outputs; i++)
+  for (l = manager->outputs; l; l = l->next)
     {
-      MetaOutput *output;
-
-      output = &manager->outputs[i];
+      MetaOutput *output = l->data;
+      GList *k;
 
       for (j = 0; j < output->n_possible_clones; j++)
        {
          RROutput clone = GPOINTER_TO_INT (output->possible_clones[j]);
 
-         for (k = 0; k < manager->n_outputs; k++)
+         for (k = manager->outputs; k; k = k->next)
            {
-             if (clone == (XID)manager->outputs[k].winsys_id)
+              MetaOutput *possible_clone = k->data;
+
+             if (clone == (XID) possible_clone->winsys_id)
                {
-                 output->possible_clones[j] = &manager->outputs[k];
+                 output->possible_clones[j] = possible_clone;
                  break;
                }
            }
@@ -1219,6 +1217,7 @@ is_assignments_changed (MetaMonitorManager *manager,
                         unsigned int        n_output_infos)
 {
   unsigned int i;
+  GList *l;
 
   for (i = 0; i < manager->n_crtcs; i++)
     {
@@ -1228,9 +1227,9 @@ is_assignments_changed (MetaMonitorManager *manager,
         return TRUE;
     }
 
-  for (i = 0; i < manager->n_outputs; i++)
+  for (l = manager->outputs; l; l = l->next)
     {
-      MetaOutput *output = &manager->outputs[i];
+      MetaOutput *output = l->data;
 
       if (is_output_assignment_changed (output,
                                         crtc_infos,
@@ -1253,6 +1252,7 @@ apply_crtc_assignments (MetaMonitorManager *manager,
 {
   MetaMonitorManagerXrandr *manager_xrandr = META_MONITOR_MANAGER_XRANDR (manager);
   unsigned i;
+  GList *l;
   int width, height, width_mm, height_mm;
 
   XGrabServer (manager_xrandr->xdisplay);
@@ -1443,9 +1443,9 @@ apply_crtc_assignments (MetaMonitorManager *manager,
     }
 
   /* Disable outputs not mentioned in the list */
-  for (i = 0; i < manager->n_outputs; i++)
+  for (l = manager->outputs; l; l = l->next)
     {
-      MetaOutput *output = &manager->outputs[i];
+      MetaOutput *output = l->data;
 
       if (output->is_dirty)
         {
diff --git a/src/backends/x11/meta-stage-x11-nested.c b/src/backends/x11/meta-stage-x11-nested.c
index cf3b920..ba70b4b 100644
--- a/src/backends/x11/meta-stage-x11-nested.c
+++ b/src/backends/x11/meta-stage-x11-nested.c
@@ -29,6 +29,7 @@
 #include "backends/meta-backend-private.h"
 #include "backends/meta-logical-monitor.h"
 #include "backends/meta-monitor.h"
+#include "backends/meta-output.h"
 #include "backends/meta-renderer.h"
 #include "backends/x11/nested/meta-renderer-x11-nested.h"
 #include "clutter/clutter-mutter.h"
diff --git a/src/backends/x11/nested/meta-renderer-x11-nested.c 
b/src/backends/x11/nested/meta-renderer-x11-nested.c
index eb94b65..d5ad778 100644
--- a/src/backends/x11/nested/meta-renderer-x11-nested.c
+++ b/src/backends/x11/nested/meta-renderer-x11-nested.c
@@ -29,6 +29,7 @@
 #include "clutter/x11/clutter-x11.h"
 #include "backends/meta-backend-private.h"
 #include "backends/meta-logical-monitor.h"
+#include "backends/meta-output.h"
 #include "backends/meta-renderer.h"
 #include "backends/meta-renderer-view.h"
 #include "core/boxes-private.h"
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
index 1184cd4..aefd30c 100644
--- a/src/compositor/meta-window-actor.c
+++ b/src/compositor/meta-window-actor.c
@@ -952,18 +952,19 @@ queue_send_frame_messages_timeout (MetaWindowActor *self)
   gint64 current_time = meta_compositor_monotonic_time_to_server_time (display, g_get_monotonic_time ());
   MetaMonitorManager *monitor_manager = meta_monitor_manager_get ();
   MetaWindow *window = priv->window;
-
-  MetaOutput *outputs;
-  guint n_outputs, i;
+  GList *outputs;
+  GList *l;
   float refresh_rate = 60.0f;
   gint interval, offset;
 
-  outputs = meta_monitor_manager_get_outputs (monitor_manager, &n_outputs);
-  for (i = 0; i < n_outputs; i++)
+  outputs = meta_monitor_manager_get_outputs (monitor_manager);
+  for (l = outputs; l; l = l->next)
     {
-      if (outputs[i].winsys_id == window->monitor->winsys_id && outputs[i].crtc)
+      MetaOutput *output = l->data;
+
+      if (output->winsys_id == window->monitor->winsys_id && output->crtc)
         {
-          refresh_rate = outputs[i].crtc->current_mode->refresh_rate;
+          refresh_rate = output->crtc->current_mode->refresh_rate;
           break;
         }
     }
diff --git a/src/tests/headless-start-test.c b/src/tests/headless-start-test.c
index f2fb70c..e53d599 100644
--- a/src/tests/headless-start-test.c
+++ b/src/tests/headless-start-test.c
@@ -20,6 +20,7 @@
 #include "config.h"
 
 #include "backends/meta-monitor-manager-private.h"
+#include "backends/meta-output.h"
 #include "compositor/meta-plugin-manager.h"
 #include "core/main-private.h"
 #include "meta/main.h"
@@ -59,12 +60,8 @@ meta_test_headless_start (void)
   g_assert_cmpint ((int) monitor_manager->n_modes,
                    ==,
                    0);
-  g_assert_cmpint ((int) monitor_manager->n_outputs,
-                   ==,
-                   0);
-  g_assert_cmpint ((int) monitor_manager->n_crtcs,
-                   ==,
-                   0);
+  g_assert_null (monitor_manager->outputs);
+  g_assert_null (monitor_manager->crtcs);
   g_assert_null (monitor_manager->monitors);
   g_assert_null (monitor_manager->logical_monitors);
 
@@ -102,6 +99,7 @@ meta_test_headless_monitor_connect (void)
   MetaMonitorTestSetup *test_setup;
   MetaCrtcMode **modes;
   MetaCrtc **possible_crtcs;
+  MetaOutput *output;
   GList *logical_monitors;
   ClutterActor *stage;
 
@@ -128,22 +126,19 @@ meta_test_headless_monitor_connect (void)
   possible_crtcs = g_new0 (MetaCrtc *, 1);
   possible_crtcs[0] = &test_setup->crtcs[0];
 
-  test_setup->n_outputs = 1;
-  test_setup->outputs = g_new0 (MetaOutput, test_setup->n_outputs);
-  test_setup->outputs[0] = (MetaOutput) {
-    .winsys_id = 1,
-    .name = g_strdup ("DP-1"),
-    .vendor = g_strdup ("MetaProduct's Inc."),
-    .product = g_strdup ("MetaMonitor"),
-    .serial = g_strdup ("0x987654"),
-    .preferred_mode = modes[0],
-    .n_modes = 1,
-    .modes = modes,
-    .n_possible_crtcs = 1,
-    .possible_crtcs = possible_crtcs,
-    .backlight = -1,
-    .connector_type = META_CONNECTOR_TYPE_DisplayPort
-  };
+  output = g_object_new (META_TYPE_OUTPUT, NULL);
+  output->winsys_id = 1;
+  output->name = g_strdup ("DP-1");
+  output->vendor = g_strdup ("MetaProduct's Inc.");
+  output->product = g_strdup ("MetaMonitor");
+  output->serial = g_strdup ("0x987654");
+  output->preferred_mode = modes[0];
+  output->n_modes = 1;
+  output->modes = modes;
+  output->n_possible_crtcs = 1;
+  output->possible_crtcs = possible_crtcs;
+  output->connector_type = META_CONNECTOR_TYPE_DisplayPort;
+  test_setup->outputs = g_list_append (NULL, output);
 
   meta_monitor_manager_test_emulate_hotplug (monitor_manager_test, test_setup);
 
diff --git a/src/tests/meta-monitor-manager-test.c b/src/tests/meta-monitor-manager-test.c
index a457b90..79e5272 100644
--- a/src/tests/meta-monitor-manager-test.c
+++ b/src/tests/meta-monitor-manager-test.c
@@ -23,6 +23,7 @@
 
 #include "backends/meta-backend-private.h"
 #include "backends/meta-monitor-config-manager.h"
+#include "backends/meta-output.h"
 
 struct _MetaMonitorManagerTest
 {
@@ -99,7 +100,6 @@ meta_monitor_manager_test_read_current (MetaMonitorManager *manager)
   manager->n_crtcs = manager_test->test_setup->n_crtcs;
 
   manager->outputs = manager_test->test_setup->outputs;
-  manager->n_outputs = manager_test->test_setup->n_outputs;
 }
 
 static gboolean
@@ -134,6 +134,7 @@ apply_crtc_assignments (MetaMonitorManager *manager,
                         MetaOutputInfo    **outputs,
                         unsigned int        n_outputs)
 {
+  GList *l;
   unsigned int i;
 
   for (i = 0; i < n_crtcs; i++)
@@ -218,9 +219,9 @@ apply_crtc_assignments (MetaMonitorManager *manager,
     }
 
   /* Disable outputs not mentioned in the list */
-  for (i = 0; i < manager->n_outputs; i++)
+  for (l = manager->outputs; l; l = l->next)
     {
-      MetaOutput *output = &manager->outputs[i];
+      MetaOutput *output = l->data;
 
       if (output->is_dirty)
         {
diff --git a/src/tests/meta-monitor-manager-test.h b/src/tests/meta-monitor-manager-test.h
index 2500a9e..4f35b22 100644
--- a/src/tests/meta-monitor-manager-test.h
+++ b/src/tests/meta-monitor-manager-test.h
@@ -26,8 +26,7 @@ typedef struct _MetaMonitorTestSetup
 {
   MetaCrtcMode *modes;
   int n_modes;
-  MetaOutput *outputs;
-  int n_outputs;
+  GList *outputs;
   MetaCrtc *crtcs;
   int n_crtcs;
 } MetaMonitorTestSetup;
diff --git a/src/tests/monitor-unit-tests.c b/src/tests/monitor-unit-tests.c
index 6685650..e42534f 100644
--- a/src/tests/monitor-unit-tests.c
+++ b/src/tests/monitor-unit-tests.c
@@ -26,6 +26,7 @@
 #include "backends/meta-monitor.h"
 #include "backends/meta-monitor-config-migration.h"
 #include "backends/meta-monitor-config-store.h"
+#include "backends/meta-output.h"
 #include "tests/meta-monitor-manager-test.h"
 #include "tests/monitor-test-utils.h"
 #include "tests/test-utils.h"
@@ -366,11 +367,11 @@ static MetaOutput *
 output_from_winsys_id (MetaMonitorManager *monitor_manager,
                        long                winsys_id)
 {
-  unsigned int i;
+  GList *l;
 
-  for (i = 0; i < monitor_manager->n_outputs; i++)
+  for (l = monitor_manager->outputs; l; l = l->next)
     {
-      MetaOutput *output = &monitor_manager->outputs[i];
+      MetaOutput *output = l->data;
 
       if (output->winsys_id == winsys_id)
         return output;
@@ -616,7 +617,7 @@ check_monitor_configuration (MonitorTestCase *test_case)
   g_assert_cmpint (monitor_manager->screen_height,
                    ==,
                    test_case->expect.screen_height);
-  g_assert_cmpint ((int) monitor_manager->n_outputs,
+  g_assert_cmpint ((int) g_list_length (monitor_manager->outputs),
                    ==,
                    test_case->expect.n_outputs);
   g_assert_cmpint ((int) monitor_manager->n_crtcs,
@@ -892,10 +893,10 @@ create_monitor_test_setup (MonitorTestCase *test_case,
       };
     }
 
-  test_setup->n_outputs = test_case->setup.n_outputs;
-  test_setup->outputs = g_new0 (MetaOutput, test_setup->n_outputs);
-  for (i = 0; i < test_setup->n_outputs; i++)
+  test_setup->outputs = NULL;
+  for (i = 0; i < test_case->setup.n_outputs; i++)
     {
+      MetaOutput *output;
       MetaOutputTest *output_test;
       int crtc_index;
       MetaCrtc *crtc;
@@ -958,37 +959,39 @@ create_monitor_test_setup (MonitorTestCase *test_case,
       if (!serial)
         serial = "0x123456";
 
-      test_setup->outputs[i] = (MetaOutput) {
-        .crtc = crtc,
-        .winsys_id = i,
-        .name = (is_laptop_panel ? g_strdup_printf ("eDP-%d",
-                                                    ++n_laptop_panels)
-                                 : g_strdup_printf ("DP-%d",
-                                                    ++n_normal_panels)),
-        .vendor = g_strdup ("MetaProduct's Inc."),
-        .product = g_strdup ("MetaMonitor"),
-        .serial = g_strdup (serial),
-        .suggested_x = -1,
-        .suggested_y = -1,
-        .hotplug_mode_update = hotplug_mode_update,
-        .width_mm = test_case->setup.outputs[i].width_mm,
-        .height_mm = test_case->setup.outputs[i].height_mm,
-        .subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN,
-        .preferred_mode = preferred_mode,
-        .n_modes = n_modes,
-        .modes = modes,
-        .n_possible_crtcs = n_possible_crtcs,
-        .possible_crtcs = possible_crtcs,
-        .n_possible_clones = 0,
-        .possible_clones = NULL,
-        .backlight = -1,
-        .connector_type = (is_laptop_panel ? META_CONNECTOR_TYPE_eDP
-                                           : META_CONNECTOR_TYPE_DisplayPort),
-        .tile_info = test_case->setup.outputs[i].tile_info,
-        .is_underscanning = test_case->setup.outputs[i].is_underscanning,
-        .driver_private = output_test,
-        .driver_notify = (GDestroyNotify) meta_output_test_destroy_notify
-      };
+      output = g_object_new (META_TYPE_OUTPUT, NULL);
+
+      output->crtc = crtc;
+      output->winsys_id = i;
+      output->name = (is_laptop_panel ? g_strdup_printf ("eDP-%d",
+                                                  ++n_laptop_panels)
+                               : g_strdup_printf ("DP-%d",
+                                                  ++n_normal_panels));
+      output->vendor = g_strdup ("MetaProduct's Inc.");
+      output->product = g_strdup ("MetaMonitor");
+      output->serial = g_strdup (serial);
+      output->suggested_x = -1;
+      output->suggested_y = -1;
+      output->hotplug_mode_update = hotplug_mode_update;
+      output->width_mm = test_case->setup.outputs[i].width_mm;
+      output->height_mm = test_case->setup.outputs[i].height_mm;
+      output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
+      output->preferred_mode = preferred_mode;
+      output->n_modes = n_modes;
+      output->modes = modes;
+      output->n_possible_crtcs = n_possible_crtcs;
+      output->possible_crtcs = possible_crtcs;
+      output->n_possible_clones = 0;
+      output->possible_clones = NULL;
+      output->backlight = -1;
+      output->connector_type = (is_laptop_panel ? META_CONNECTOR_TYPE_eDP
+                                         : META_CONNECTOR_TYPE_DisplayPort);
+      output->tile_info = test_case->setup.outputs[i].tile_info;
+      output->is_underscanning = test_case->setup.outputs[i].is_underscanning;
+      output->driver_private = output_test;
+      output->driver_notify = (GDestroyNotify) meta_output_test_destroy_notify;
+
+      test_setup->outputs = g_list_append (test_setup->outputs, output);
     }
 
   return test_setup;
@@ -1910,6 +1913,15 @@ meta_test_monitor_hidpi_linear_config (void)
 }
 
 static void
+set_suggested_output_position (MetaOutput *output,
+                               int         x,
+                               int         y)
+{
+  output->suggested_x = x;
+  output->suggested_y = y;
+}
+
+static void
 meta_test_monitor_suggested_config (void)
 {
   MonitorTestCase test_case = {
@@ -2047,10 +2059,10 @@ meta_test_monitor_suggested_config (void)
   test_setup = create_monitor_test_setup (&test_case,
                                           MONITOR_TEST_FLAG_NO_STORED);
 
-  test_setup->outputs[0].suggested_x = 1024;
-  test_setup->outputs[0].suggested_y = 758;
-  test_setup->outputs[1].suggested_x = 0;
-  test_setup->outputs[1].suggested_y = 0;
+  set_suggested_output_position (g_list_nth_data (test_setup->outputs, 0),
+                                 1024, 758);
+  set_suggested_output_position (g_list_nth_data (test_setup->outputs, 1),
+                                 0, 0);
 
   emulate_hotplug (test_setup);
   check_monitor_configuration (&test_case);


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