[mutter] MonitorConfig: add CRTC assignment



commit d0529b7482770c7d9ae3dcd581be3a3e65ac9748
Author: Giovanni Campagna <gcampagn redhat com>
Date:   Wed Jul 24 18:01:31 2013 +0200

    MonitorConfig: add CRTC assignment
    
    Ripped off libgnome-desktop, trimming the parts that checked
    that the configuration was plausible, as that should be done
    in gnome-control-center before asking mutter for a change.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=705670

 src/core/monitor-config.c  |  381 +++++++++++++++++++++++++++++++++++++++++---
 src/core/monitor-private.h |   48 +++++-
 src/core/monitor.c         |  176 ++++++++++++---------
 3 files changed, 510 insertions(+), 95 deletions(-)
---
diff --git a/src/core/monitor-config.c b/src/core/monitor-config.c
index da4f8a0..d6ab967 100644
--- a/src/core/monitor-config.c
+++ b/src/core/monitor-config.c
@@ -25,6 +25,15 @@
  * 02111-1307, USA.
  */
 
+/*
+ * Portions of this file are derived from gnome-desktop/libgnome-desktop/gnome-rr-config.c
+ *
+ * Copyright 2007, 2008, Red Hat, Inc.
+ * Copyright 2010 Giovanni Campagna
+ *
+ * Author: Soren Sandmann <sandmann redhat com>
+ */
+
 #include "config.h"
 
 #include <string.h>
@@ -90,6 +99,11 @@ struct _MetaMonitorConfigClass {
 
 G_DEFINE_TYPE (MetaMonitorConfig, meta_monitor_config, G_TYPE_OBJECT);
 
+static gboolean meta_monitor_config_assign_crtcs (MetaConfiguration  *config,
+                                                  MetaMonitorManager *manager,
+                                                  GPtrArray          *crtcs,
+                                                  GPtrArray          *outputs);
+
 static void
 free_output_key (MetaOutputKey *key)
 {
@@ -774,35 +788,37 @@ meta_monitor_config_get_stored (MetaMonitorConfig *self,
   return stored;
 }
 
-static void
-make_crtcs (MetaConfiguration   *config,
-           MetaMonitorManager  *manager,
-           GVariant           **crtcs,
-           GVariant           **outputs)
-{
-  *crtcs = NULL;
-  *outputs = NULL;
-  /* FIXME */
-}
-
-static void
+static gboolean
 apply_configuration (MetaMonitorConfig  *self,
                      MetaConfiguration  *config,
                     MetaMonitorManager *manager,
                      gboolean            stored)
 {
-  GVariant *crtcs, *outputs;
-                    
-  make_crtcs (config, manager, &crtcs, &outputs);
-  meta_monitor_manager_apply_configuration (manager, crtcs, outputs);
+  GPtrArray *crtcs, *outputs;
+
+  crtcs = g_ptr_array_new_full (config->n_outputs, (GDestroyNotify)meta_crtc_info_free);
+  outputs = g_ptr_array_new_full (config->n_outputs, (GDestroyNotify)meta_output_info_free);
+
+  if (!meta_monitor_config_assign_crtcs (config, manager, crtcs, outputs))
+    {
+      g_ptr_array_unref (crtcs);
+      g_ptr_array_unref (outputs);
+
+      return FALSE;
+    }
+
+  meta_monitor_manager_apply_configuration (manager,
+                                            (MetaCRTCInfo**)crtcs->pdata, crtcs->len,
+                                            (MetaOutputInfo**)outputs->pdata, outputs->len);
 
   if (self->current && !self->current_is_stored)
     config_free (self->current);
   self->current = config;
   self->current_is_stored = stored;
 
-  g_variant_unref (crtcs);
-  g_variant_unref (outputs);
+  g_ptr_array_unref (crtcs);
+  g_ptr_array_unref (outputs);
+  return TRUE;
 }
 
 gboolean
@@ -818,8 +834,7 @@ meta_monitor_config_apply_stored (MetaMonitorConfig  *self,
 
   if (stored)
     {
-      apply_configuration (self, stored, manager, TRUE);
-      return TRUE;
+      return apply_configuration (self, stored, manager, TRUE);
     }
   else
     return FALSE;
@@ -1039,3 +1054,329 @@ meta_monitor_config_make_persistent (MetaMonitorConfig *self)
 
   meta_monitor_config_save (self);
 }
+
+/*
+ * CRTC assignment
+ */
+typedef struct
+{
+  MetaConfiguration  *config;
+  MetaMonitorManager *manager;
+  GHashTable         *info;
+} CrtcAssignment;
+
+static gboolean
+output_can_clone (MetaOutput *output,
+                  MetaOutput *clone)
+{
+  unsigned int i;
+
+  for (i = 0; i < output->n_possible_clones; i++)
+    if (output->possible_clones[i] == clone)
+      return TRUE;
+
+  return FALSE;
+}
+
+static gboolean
+can_clone (MetaCRTCInfo *info,
+          MetaOutput   *output)
+{
+  unsigned int i;
+
+  for (i = 0; i < info->outputs->len; ++i)
+    {
+      MetaOutput *clone = info->outputs->pdata[i];
+
+       if (!output_can_clone (clone, output))
+           return FALSE;
+    }
+
+    return TRUE;
+}
+
+static gboolean
+crtc_can_drive_output (MetaCRTC   *crtc,
+                       MetaOutput *output)
+{
+  unsigned int i;
+
+  for (i = 0; i < output->n_possible_crtcs; i++)
+    if (output->possible_crtcs[i] == crtc)
+      return TRUE;
+
+  return FALSE;
+}
+
+static gboolean
+output_supports_mode (MetaOutput      *output,
+                      MetaMonitorMode *mode)
+{
+  unsigned int i;
+
+  for (i = 0; i < output->n_modes; i++)
+    if (output->modes[i] == mode)
+      return TRUE;
+
+  return FALSE;
+}
+
+static gboolean
+crtc_assignment_assign (CrtcAssignment            *assign,
+                       MetaCRTC                  *crtc,
+                       MetaMonitorMode           *mode,
+                       int                        x,
+                       int                        y,
+                       enum wl_output_transform   transform,
+                       MetaOutput                *output)
+{
+  MetaCRTCInfo *info = g_hash_table_lookup (assign->info, crtc);
+
+  if (!crtc_can_drive_output (crtc, output))
+    return FALSE;
+
+  if (!output_supports_mode (output, mode))
+    return FALSE;
+
+  if ((crtc->all_transforms & (1 << transform)) == 0)
+    return FALSE;
+
+  if (info)
+    {
+      if (!(info->mode == mode &&
+            info->x == x               &&
+            info->y == y               &&
+            info->transform == transform))
+        return FALSE;
+
+      if (!can_clone (info, output))
+        return FALSE;
+
+      g_ptr_array_add (info->outputs, output);
+      return TRUE;
+    }
+  else
+    {
+      MetaCRTCInfo *info = g_slice_new0 (MetaCRTCInfo);
+
+      info->crtc = crtc;
+      info->mode = mode;
+      info->x = x;
+      info->y = y;
+      info->transform = transform;
+      info->outputs = g_ptr_array_new ();
+
+      g_ptr_array_add (info->outputs, output);
+      g_hash_table_insert (assign->info, crtc, info);
+
+      return TRUE;
+    }
+}
+
+static void
+crtc_assignment_unassign (CrtcAssignment *assign,
+                          MetaCRTC       *crtc,
+                          MetaOutput     *output)
+{
+  MetaCRTCInfo *info = g_hash_table_lookup (assign->info, crtc);
+
+  if (info)
+    {
+      g_ptr_array_remove (info->outputs, output);
+
+      if (info->outputs->len == 0)
+        g_hash_table_remove (assign->info, crtc);
+    }
+}
+
+static MetaOutput *
+find_output_by_key (MetaOutput    *outputs,
+                    unsigned int   n_outputs,
+                    MetaOutputKey *key)
+{
+  unsigned int i;
+
+  for (i = 0; i < n_outputs; i++)
+    {
+      if (strcmp (outputs[i].name, key->connector) == 0)
+        {
+          /* This should be checked a lot earlier! */
+
+          g_warn_if_fail (strcmp (outputs[i].vendor, key->vendor) == 0 &&
+                          strcmp (outputs[i].product, key->product) == 0 &&
+                          strcmp (outputs[i].serial, key->serial) == 0);
+          return &outputs[i];
+        }
+    }
+
+  /* Just to satisfy GCC - this is a fatal error if occurs */
+  return NULL;
+}
+
+/* Check whether the given set of settings can be used
+ * at the same time -- ie. whether there is an assignment
+ * of CRTC's to outputs.
+ *
+ * Brute force - the number of objects involved is small
+ * enough that it doesn't matter.
+ */
+static gboolean
+real_assign_crtcs (CrtcAssignment     *assignment,
+                   unsigned int        output_num)
+{
+  MetaMonitorMode *modes;
+  MetaCRTC *crtcs;
+  MetaOutput *outputs;
+  unsigned int n_crtcs, n_modes, n_outputs;
+  MetaOutputKey *output_key;
+  MetaOutputConfig *output_config;
+  unsigned int i;
+  gboolean success;
+
+  if (output_num == assignment->config->n_outputs)
+    return TRUE;
+
+  output_key = &assignment->config->keys[output_num];
+  output_config = &assignment->config->outputs[output_num];
+
+  /* It is always allowed for an output to be turned off */
+  if (!output_config->enabled)
+    return real_assign_crtcs (assignment, output_num + 1);
+
+  meta_monitor_manager_get_resources (assignment->manager,
+                                      &modes, &n_modes,
+                                      &crtcs, &n_crtcs,
+                                      &outputs, &n_outputs);
+
+  success = FALSE;
+
+  for (i = 0; i < n_crtcs; i++)
+    {
+      MetaCRTC *crtc = &crtcs[i];
+      unsigned int pass;
+
+      /* Make two passes, one where frequencies must match, then
+       * one where they don't have to
+       */
+      for (pass = 0; pass < 2; pass++)
+       {
+          MetaOutput *output = find_output_by_key (outputs, n_outputs, output_key);
+          unsigned int j;
+
+          for (j = 0; j < n_modes; j++)
+           {
+              MetaMonitorMode *mode = &modes[j];
+              int width, height;
+
+              if (meta_monitor_transform_is_rotated (output_config->transform))
+                {
+                  width = mode->height;
+                  height = mode->width;
+                }
+              else
+                {
+                  width = mode->width;
+                  height = mode->height;
+                }
+
+              if (width == output_config->rect.width &&
+                  height == output_config->rect.height &&
+                  (pass == 1 || mode->refresh_rate == output_config->refresh_rate))
+               {
+                  meta_verbose ("CRTC %ld: trying mode %dx%d %fHz with output at %dx%d %fHz (transform %d) 
(pass %d)\n",
+                                crtc->crtc_id,
+                                mode->width, mode->height, mode->refresh_rate,
+                                output_config->rect.width, output_config->rect.height, 
output_config->refresh_rate,
+                                output_config->transform,
+                                pass);
+
+
+                  if (crtc_assignment_assign (assignment, crtc, &modes[j],
+                                              output_config->rect.x, output_config->rect.y,
+                                              output_config->transform,
+                                              output))
+                    {
+                      if (real_assign_crtcs (assignment, output_num + 1))
+                        {
+                          success = TRUE;
+                          goto out;
+                        }
+
+                      crtc_assignment_unassign (assignment, crtc, output);
+                    }
+                }
+            }
+       }
+    }
+
+out:
+  if (!success)
+    meta_warning ("Could not assign CRTC to outputs, ignoring configuration\n");
+
+  return success;
+}
+
+static gboolean
+meta_monitor_config_assign_crtcs (MetaConfiguration  *config,
+                                  MetaMonitorManager *manager,
+                                  GPtrArray          *crtcs,
+                                  GPtrArray          *outputs)
+{
+  CrtcAssignment assignment;
+  GHashTableIter iter;
+  MetaCRTC *crtc;
+  MetaCRTCInfo *info;
+  unsigned int i;
+  MetaOutput *all_outputs;
+  unsigned int n_outputs;
+
+  assignment.config = config;
+  assignment.manager = manager;
+  assignment.info = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)meta_crtc_info_free);
+
+  if (!real_assign_crtcs (&assignment, 0))
+    {
+      g_hash_table_destroy (assignment.info);
+      return FALSE;
+    }
+
+  g_hash_table_iter_init (&iter, assignment.info);
+  while (g_hash_table_iter_next (&iter, (void**)&crtc, (void**)&info))
+    {
+      g_hash_table_iter_steal (&iter);
+      g_ptr_array_add (crtcs, info);
+    }
+
+  all_outputs = meta_monitor_manager_get_outputs (manager,
+                                                  &n_outputs);
+  g_assert (n_outputs == config->n_outputs);
+
+  for (i = 0; i < n_outputs; i++)
+    {
+      MetaOutputInfo *output_info = g_slice_new (MetaOutputInfo);
+      MetaOutputConfig *output_config = &config->outputs[0];
+
+      output_info->output = find_output_by_key (all_outputs, n_outputs,
+                                                &config->keys[0]);
+      output_info->is_primary = output_config->is_primary;
+      output_info->is_presentation = output_config->is_presentation;
+
+      g_ptr_array_add (outputs, output_info);
+    }
+
+  g_hash_table_destroy (assignment.info);
+  return TRUE;
+}
+
+void
+meta_crtc_info_free (MetaCRTCInfo *info)
+{
+  g_ptr_array_free (info->outputs, TRUE);
+  g_slice_free (MetaCRTCInfo, info);
+}
+
+void
+meta_output_info_free (MetaOutputInfo *info)
+{
+  g_slice_free (MetaOutputInfo, info);
+}
diff --git a/src/core/monitor-private.h b/src/core/monitor-private.h
index 1576182..efbafd7 100644
--- a/src/core/monitor-private.h
+++ b/src/core/monitor-private.h
@@ -65,6 +65,8 @@ typedef struct _MetaOutput MetaOutput;
 typedef struct _MetaCRTC MetaCRTC;
 typedef struct _MetaMonitorMode MetaMonitorMode;
 typedef struct _MetaMonitorInfo MetaMonitorInfo;
+typedef struct _MetaCRTCInfo MetaCRTCInfo;
+typedef struct _MetaOutputInfo MetaOutputInfo;
 
 struct _MetaOutput
 {
@@ -161,6 +163,33 @@ struct _MetaMonitorInfo
   glong output_id;
 };
 
+/*
+ * MetaCRTCInfo:
+ * This represents the writable part of a CRTC, as deserialized from DBus
+ * or built by MetaMonitorConfig
+ *
+ * Note: differently from the other structures in this file, MetaCRTCInfo
+ * is handled by pointer. This is to accomodate the usage in MetaMonitorConfig
+ */
+struct _MetaCRTCInfo {
+  MetaCRTC                 *crtc;
+  MetaMonitorMode          *mode;
+  int                       x;
+  int                       y;
+  enum wl_output_transform  transform;
+  GPtrArray                *outputs;
+};
+
+/*
+ * MetaOutputInfo:
+ * this is the same as MetaOutputInfo, but for CRTCs
+ */
+struct _MetaOutputInfo {
+  MetaOutput  *output;
+  gboolean     is_primary;
+  gboolean     is_presentation;
+};
+
 #define META_TYPE_MONITOR_MANAGER            (meta_monitor_manager_get_type ())
 #define META_MONITOR_MANAGER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_MANAGER, 
MetaMonitorManager))
 #define META_MONITOR_MANAGER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  META_TYPE_MONITOR_MANAGER, 
MetaMonitorManagerClass))
@@ -182,6 +211,14 @@ MetaMonitorInfo    *meta_monitor_manager_get_monitor_infos (MetaMonitorManager *
 MetaOutput         *meta_monitor_manager_get_outputs       (MetaMonitorManager *manager,
                                                            unsigned int       *n_outputs);
 
+void                meta_monitor_manager_get_resources     (MetaMonitorManager  *manager,
+                                                            MetaMonitorMode    **modes,
+                                                            unsigned int        *n_modes,
+                                                            MetaCRTC           **crtcs,
+                                                            unsigned int        *n_crtcs,
+                                                            MetaOutput         **outputs,
+                                                            unsigned int        *n_outputs);
+
 int                 meta_monitor_manager_get_primary_index (MetaMonitorManager *manager);
 
 gboolean            meta_monitor_manager_handle_xevent     (MetaMonitorManager *manager,
@@ -191,9 +228,11 @@ void                meta_monitor_manager_get_screen_size   (MetaMonitorManager *
                                                             int                *width,
                                                             int                *height);
 
-void                meta_monitor_manager_apply_configuration (MetaMonitorManager *manager,
-                                                              GVariant           *crtcs,
-                                                              GVariant           *outputs);
+void                meta_monitor_manager_apply_configuration (MetaMonitorManager  *manager,
+                                                              MetaCRTCInfo       **crtcs,
+                                                              unsigned int         n_crtcs,
+                                                              MetaOutputInfo     **outputs,
+                                                              unsigned int         n_outputs);
 
 #define META_TYPE_MONITOR_CONFIG            (meta_monitor_config_get_type ())
 #define META_MONITOR_CONFIG(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_MONITOR_CONFIG, 
MetaMonitorConfig))
@@ -222,6 +261,9 @@ void               meta_monitor_config_update_current (MetaMonitorConfig  *confi
                                                        MetaMonitorManager *manager);
 void               meta_monitor_config_make_persistent (MetaMonitorConfig *config);
 
+void               meta_crtc_info_free   (MetaCRTCInfo   *info);
+void               meta_output_info_free (MetaOutputInfo *info);
+
 /* Returns true if transform causes width and height to be inverted
    This is true for the odd transforms in the enum */
 static inline gboolean
diff --git a/src/core/monitor.c b/src/core/monitor.c
index 867a1e8..3c34b91 100644
--- a/src/core/monitor.c
+++ b/src/core/monitor.c
@@ -1160,22 +1160,20 @@ wl_transform_to_xrandr (enum wl_output_transform transform)
      
 static void
 apply_config_xrandr (MetaMonitorManager *manager,
-                     GVariantIter       *crtcs,
-                     GVariantIter       *outputs)
+                     MetaCRTCInfo       **crtcs,
+                     unsigned int         n_crtcs,
+                     MetaOutputInfo     **outputs,
+                     unsigned int         n_outputs)
 {
-  GVariant *nested_outputs, *properties;
-  guint crtc_id, output_id, transform;
-  int new_mode, x, y;
   unsigned i;
 
-  while (g_variant_iter_loop (crtcs, "(uiiiu aua{sv})",
-                              &crtc_id, &new_mode, &x, &y,
-                              &transform, &nested_outputs, NULL))
+  for (i = 0; i < n_crtcs; i++)
     {
-      MetaCRTC *crtc = &manager->crtcs[crtc_id];
+      MetaCRTCInfo *crtc_info = crtcs[i];
+      MetaCRTC *crtc = crtc_info->crtc;
       crtc->is_dirty = TRUE;
 
-      if (new_mode == -1)
+      if (crtc_info->mode == NULL)
         {
           XRRSetCrtcConfig (manager->xdisplay,
                             manager->resources,
@@ -1190,54 +1188,47 @@ apply_config_xrandr (MetaMonitorManager *manager,
         {
           MetaMonitorMode *mode;
           XID *outputs;
-          int i, n_outputs;
-          guint output_id;
+          int j, n_outputs;
           Status ok;
 
-          mode = &manager->modes[new_mode];
+          mode = crtc_info->mode;
 
-          n_outputs = g_variant_n_children (nested_outputs);
+          n_outputs = crtc_info->outputs->len;
           outputs = g_new (XID, n_outputs);
 
-          for (i = 0; i < n_outputs; i++)
-            {
-              g_variant_get_child (nested_outputs, i, "u", &output_id);
-
-              outputs[i] = manager->outputs[output_id].output_id;
-            }
+          for (j = 0; j < n_outputs; j++)
+            outputs[i] = ((MetaOutput**)crtc_info->outputs->pdata)[i]->output_id;
 
           meta_error_trap_push (meta_get_display ());
           ok = XRRSetCrtcConfig (manager->xdisplay,
                                  manager->resources,
                                  (XID)crtc->crtc_id,
                                  manager->time,
-                                 x, y,
+                                 crtc_info->x, crtc_info->y,
                                  (XID)mode->mode_id,
-                                 wl_transform_to_xrandr (transform),
+                                 wl_transform_to_xrandr (crtc_info->transform),
                                  outputs, n_outputs);
           meta_error_trap_pop (meta_get_display ());
 
           if (ok != Success)
             meta_warning ("Configuring CRTC %d with mode %d (%d x %d @ %f) at position %d, %d and transfrom 
%u failed\n",
                           (unsigned)(crtc->crtc_id), (unsigned)(mode->mode_id),
-                          mode->width, mode->height, (float)mode->refresh_rate, x, y, transform);
+                          mode->width, mode->height, (float)mode->refresh_rate,
+                          crtc_info->x, crtc_info->y, crtc_info->transform);
 
           g_free (outputs);
         }
     }
 
-  while (g_variant_iter_loop (outputs, "(u a{sv})",
-                              &output_id, &properties))
+  for (i = 0; i < n_outputs; i++)
     {
-      gboolean primary;
+      MetaOutputInfo *output_info = outputs[i];
 
-      if (g_variant_lookup (properties, "primary", "b", &primary) && primary)
+      if (output_info->is_primary)
         {
-          MetaOutput *output = &manager->outputs[output_id];
-
           XRRSetOutputPrimary (manager->xdisplay,
                                DefaultRootWindow (manager->xdisplay),
-                               (XID)output->output_id);
+                               (XID)output_info->output->output_id);
         }
     }
 
@@ -1268,23 +1259,21 @@ apply_config_xrandr (MetaMonitorManager *manager,
 
 static void
 apply_config_dummy (MetaMonitorManager *manager,
-                    GVariantIter       *crtcs,
-                    GVariantIter       *outputs)
+                    MetaCRTCInfo       **crtcs,
+                    unsigned int         n_crtcs,
+                    MetaOutputInfo     **outputs,
+                    unsigned int         n_outputs)
 {
-  GVariant *nested_outputs, *properties;
-  guint crtc_id, output_id, transform;
-  int new_mode, x, y;
   unsigned i;
   int screen_width = 0, screen_height = 0;
 
-  while (g_variant_iter_loop (crtcs, "(uiiiu aua{sv})",
-                              &crtc_id, &new_mode, &x, &y,
-                              &transform, &nested_outputs, NULL))
+  for (i = 0; i < n_crtcs; i++)
     {
-      MetaCRTC *crtc = &manager->crtcs[crtc_id];
+      MetaCRTCInfo *crtc_info = crtcs[i];
+      MetaCRTC *crtc = crtc_info->crtc;
       crtc->is_dirty = TRUE;
 
-      if (new_mode == -1)
+      if (crtc_info->mode == NULL)
         {
           crtc->rect.x = 0;
           crtc->rect.y = 0;
@@ -1297,12 +1286,11 @@ apply_config_dummy (MetaMonitorManager *manager,
           MetaMonitorMode *mode;
           MetaOutput *output;
           int i, n_outputs;
-          guint output_id;
           int width, height;
 
-          mode = &manager->modes[new_mode];
+          mode = crtc_info->mode;
 
-          if (meta_monitor_transform_is_rotated (transform))
+          if (meta_monitor_transform_is_rotated (crtc_info->transform))
             {
               width = mode->height;
               height = mode->width;
@@ -1313,22 +1301,20 @@ apply_config_dummy (MetaMonitorManager *manager,
               height = mode->height;
             }
 
-          crtc->rect.x = x;
-          crtc->rect.y = y;
+          crtc->rect.x = crtc_info->x;
+          crtc->rect.y = crtc_info->y;
           crtc->rect.width = width;
           crtc->rect.height = height;
           crtc->current_mode = mode;
-          crtc->transform = transform;
+          crtc->transform = crtc_info->transform;
 
-          screen_width = MAX (screen_width, x + width);
-          screen_height = MAX (screen_height, y + height);
+          screen_width = MAX (screen_width, crtc_info->x + width);
+          screen_height = MAX (screen_height, crtc_info->y + height);
 
-          n_outputs = g_variant_n_children (nested_outputs);
+          n_outputs = crtc_info->outputs->len;
           for (i = 0; i < n_outputs; i++)
             {
-              g_variant_get_child (nested_outputs, i, "u", &output_id);
-
-              output = &manager->outputs[output_id];
+              output = ((MetaOutput**)crtc_info->outputs->pdata)[i];
 
               output->is_dirty = TRUE;
               output->crtc = crtc;
@@ -1336,17 +1322,13 @@ apply_config_dummy (MetaMonitorManager *manager,
         }
     }
 
-  while (g_variant_iter_loop (outputs, "(u a{sv})",
-                              &output_id, &properties))
+  for (i = 0; i < n_outputs; i++)
     {
-      MetaOutput *output = &manager->outputs[output_id];
-      gboolean primary, presentation;
-
-      if (g_variant_lookup (properties, "primary", "b", &primary))
-        output->is_primary = primary;
+      MetaOutputInfo *output_info = outputs[i];
+      MetaOutput *output = output_info->output;
 
-      if (g_variant_lookup (properties, "presentation", "b", &presentation))
-        output->is_presentation = presentation;
+      output->is_primary = output_info->is_primary;
+      output->is_presentation = output_info->is_presentation;
     }
 
   /* Disable CRTCs not mentioned in the list */
@@ -1392,18 +1374,15 @@ apply_config_dummy (MetaMonitorManager *manager,
 
 void
 meta_monitor_manager_apply_configuration (MetaMonitorManager *manager,
-                                          GVariant           *crtcs,
-                                          GVariant           *outputs)
+                                          MetaCRTCInfo       **crtcs,
+                                          unsigned int         n_crtcs,
+                                          MetaOutputInfo     **outputs,
+                                          unsigned int         n_outputs)
 {
-  GVariantIter crtc_iter, output_iter;
-
-  g_variant_iter_init (&crtc_iter, crtcs);
-  g_variant_iter_init (&output_iter, outputs);
-
  if (manager->backend == META_BACKEND_XRANDR)
-    apply_config_xrandr (manager, &crtc_iter, &output_iter);
+   apply_config_xrandr (manager, crtcs, n_crtcs, outputs, n_outputs);
   else
-    apply_config_dummy (manager, &crtc_iter, &output_iter);
+    apply_config_dummy (manager, crtcs, n_crtcs, outputs, n_outputs);
 }
 
 static gboolean
@@ -1426,10 +1405,12 @@ meta_monitor_manager_handle_apply_configuration  (MetaDBusDisplayConfig *skeleto
 {
   MetaMonitorManager *manager = META_MONITOR_MANAGER (skeleton);
   GVariantIter crtc_iter, output_iter, *nested_outputs;
+  GVariant *properties;
   guint crtc_id;
   int new_mode, x, y;
   guint transform;
   guint output_id;
+  GPtrArray *crtc_infos, *output_infos;
 
   if (serial != manager->serial)
     {
@@ -1439,17 +1420,26 @@ meta_monitor_manager_handle_apply_configuration  (MetaDBusDisplayConfig *skeleto
       return TRUE;
     }
 
+  crtc_infos = g_ptr_array_new_full (g_variant_n_children (crtcs),
+                                     (GDestroyNotify) meta_crtc_info_free);
+  output_infos = g_ptr_array_new_full (g_variant_n_children (outputs),
+                                       (GDestroyNotify) meta_output_info_free);
+
   /* Validate all arguments */
   g_variant_iter_init (&crtc_iter, crtcs);
   while (g_variant_iter_loop (&crtc_iter, "(uiiiuaua{sv})",
                               &crtc_id, &new_mode, &x, &y, &transform,
                               &nested_outputs, NULL))
     {
+      MetaCRTCInfo *crtc_info;
       MetaOutput *first_output;
       MetaCRTC *crtc;
       MetaMonitorMode *mode;
       guint output_id;
 
+      crtc_info = g_slice_new (MetaCRTCInfo);
+      crtc_info->outputs = g_ptr_array_new ();
+
       if (crtc_id >= manager->n_crtcs)
         {
           g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
@@ -1458,6 +1448,7 @@ meta_monitor_manager_handle_apply_configuration  (MetaDBusDisplayConfig *skeleto
           return TRUE;
         }
       crtc = &manager->crtcs[crtc_id];
+      crtc_info->crtc = crtc;
 
       if (new_mode != -1 && (new_mode < 0 || (unsigned)new_mode >= manager->n_modes))
         {
@@ -1467,6 +1458,7 @@ meta_monitor_manager_handle_apply_configuration  (MetaDBusDisplayConfig *skeleto
           return TRUE;
         }
       mode = new_mode != -1 ? &manager->modes[new_mode] : NULL;
+      crtc_info->mode = mode;
 
       if (mode)
         {
@@ -1494,6 +1486,8 @@ meta_monitor_manager_handle_apply_configuration  (MetaDBusDisplayConfig *skeleto
               return TRUE;
             }
         }
+      crtc_info->x = x;
+      crtc_info->y = y;
 
       if (transform < WL_OUTPUT_TRANSFORM_NORMAL ||
           transform > WL_OUTPUT_TRANSFORM_FLIPPED_270 ||
@@ -1504,6 +1498,7 @@ meta_monitor_manager_handle_apply_configuration  (MetaDBusDisplayConfig *skeleto
                                                  "Invalid transform");
           return TRUE;
         }
+      crtc_info->transform = transform;
 
       first_output = NULL;
       while (g_variant_iter_loop (nested_outputs, "u", &output_id))
@@ -1526,6 +1521,7 @@ meta_monitor_manager_handle_apply_configuration  (MetaDBusDisplayConfig *skeleto
                                                      "Output cannot be assigned to this CRTC or mode");
               return TRUE;
             }
+          g_ptr_array_add (crtc_info->outputs, output);
 
           if (first_output)
             {
@@ -1551,8 +1547,11 @@ meta_monitor_manager_handle_apply_configuration  (MetaDBusDisplayConfig *skeleto
     }
 
   g_variant_iter_init (&output_iter, outputs);
-  while (g_variant_iter_loop (&output_iter, "(ua{sv})", &output_id, NULL))
+  while (g_variant_iter_loop (&output_iter, "(u a{sv})", &output_id, &properties))
     {
+      MetaOutputInfo *output_info;
+      gboolean primary, presentation;
+
       if (output_id >= manager->n_outputs)
         {
           g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
@@ -1560,6 +1559,15 @@ meta_monitor_manager_handle_apply_configuration  (MetaDBusDisplayConfig *skeleto
                                                  "Invalid output id");
           return TRUE;
         }
+
+      output_info = g_slice_new0 (MetaOutputInfo);
+      output_info->output = &manager->outputs[output_id];
+
+      if (g_variant_lookup (properties, "primary", "b", &primary))
+        output_info->is_primary = primary;
+
+      if (g_variant_lookup (properties, "presentation", "b", &presentation))
+        output_info->is_presentation = presentation;
     }
 
   /* If we were in progress of making a persistent change and we see a
@@ -1572,7 +1580,14 @@ meta_monitor_manager_handle_apply_configuration  (MetaDBusDisplayConfig *skeleto
       manager->persistent_timeout_id = 0;
     }
 
-  meta_monitor_manager_apply_configuration (manager, crtcs, outputs);
+  meta_monitor_manager_apply_configuration (manager,
+                                            (MetaCRTCInfo**)crtc_infos->pdata,
+                                            crtc_infos->len,
+                                            (MetaOutputInfo**)output_infos->pdata,
+                                            output_infos->len);
+
+  g_ptr_array_unref (crtc_infos);
+  g_ptr_array_unref (output_infos);
 
   /* Update MetaMonitorConfig data structures immediately so that we
      don't revert the change at the next XRandR event, then wait 20
@@ -1671,6 +1686,23 @@ meta_monitor_manager_get_outputs (MetaMonitorManager *manager,
   return manager->outputs;
 }
 
+void
+meta_monitor_manager_get_resources (MetaMonitorManager  *manager,
+                                    MetaMonitorMode    **modes,
+                                    unsigned int        *n_modes,
+                                    MetaCRTC           **crtcs,
+                                    unsigned int        *n_crtcs,
+                                    MetaOutput         **outputs,
+                                    unsigned int        *n_outputs)
+{
+  *modes = manager->modes;
+  *n_modes = manager->n_modes;
+  *crtcs = manager->crtcs;
+  *n_crtcs = manager->n_crtcs;
+  *outputs = manager->outputs;
+  *n_outputs = manager->n_outputs;
+}
+
 int
 meta_monitor_manager_get_primary_index (MetaMonitorManager *manager)
 {


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