[gnome-flashback] backends: add GfMonitorTiled



commit d8b40c21572cc272ed6b23b40159b6cb8ede9fbf
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Mon Sep 11 20:00:53 2017 +0300

    backends: add GfMonitorTiled

 backends/Makefile.am                  |    2 +
 backends/gf-monitor-manager-private.h |   10 +-
 backends/gf-monitor-manager.c         |   24 +
 backends/gf-monitor-tiled-private.h   |   41 ++
 backends/gf-monitor-tiled.c           |  739 +++++++++++++++++++++++++++++++++
 5 files changed, 814 insertions(+), 2 deletions(-)
---
diff --git a/backends/Makefile.am b/backends/Makefile.am
index a2d6ad3..e768918 100644
--- a/backends/Makefile.am
+++ b/backends/Makefile.am
@@ -49,6 +49,8 @@ libbackends_la_SOURCES = \
        gf-monitor-private.h \
        gf-monitor-spec-private.h \
        gf-monitor-spec.c \
+       gf-monitor-tiled-private.h \
+       gf-monitor-tiled.c \
        gf-monitor.c \
        gf-orientation-manager-private.h \
        gf-orientation-manager.c \
diff --git a/backends/gf-monitor-manager-private.h b/backends/gf-monitor-manager-private.h
index edeaf7d..5b16dbd 100644
--- a/backends/gf-monitor-manager-private.h
+++ b/backends/gf-monitor-manager-private.h
@@ -155,9 +155,15 @@ typedef struct
   GfLogicalMonitorLayoutMode   (* get_default_layout_mode)      (GfMonitorManager            *manager);
 } GfMonitorManagerClass;
 
-GType      gf_monitor_manager_get_type    (void);
+GType      gf_monitor_manager_get_type              (void);
 
-GfBackend *gf_monitor_manager_get_backend (GfMonitorManager *manager);
+GfBackend *gf_monitor_manager_get_backend           (GfMonitorManager *manager);
+
+void       gf_monitor_manager_tiled_monitor_added   (GfMonitorManager *manager,
+                                                     GfMonitor        *monitor);
+
+void       gf_monitor_manager_tiled_monitor_removed (GfMonitorManager *manager,
+                                                     GfMonitor        *monitor);
 
 G_END_DECLS
 
diff --git a/backends/gf-monitor-manager.c b/backends/gf-monitor-manager.c
index 0befb10..6324434 100644
--- a/backends/gf-monitor-manager.c
+++ b/backends/gf-monitor-manager.c
@@ -161,3 +161,27 @@ gf_monitor_manager_get_backend (GfMonitorManager *manager)
 
   return priv->backend;
 }
+
+void
+gf_monitor_manager_tiled_monitor_added (GfMonitorManager *manager,
+                                        GfMonitor        *monitor)
+{
+  GfMonitorManagerClass *manager_class;
+
+  manager_class = GF_MONITOR_MANAGER_GET_CLASS (manager);
+
+  if (manager_class->tiled_monitor_added)
+    manager_class->tiled_monitor_added (manager, monitor);
+}
+
+void
+gf_monitor_manager_tiled_monitor_removed (GfMonitorManager *manager,
+                                          GfMonitor        *monitor)
+{
+  GfMonitorManagerClass *manager_class;
+
+  manager_class = GF_MONITOR_MANAGER_GET_CLASS (manager);
+
+  if (manager_class->tiled_monitor_removed)
+    manager_class->tiled_monitor_removed (manager, monitor);
+}
diff --git a/backends/gf-monitor-tiled-private.h b/backends/gf-monitor-tiled-private.h
new file mode 100644
index 0000000..b211ac6
--- /dev/null
+++ b/backends/gf-monitor-tiled-private.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016 Red Hat
+ * Copyright (C) 2017 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Adapted from mutter:
+ * - src/backends/meta-monitor.h
+ */
+
+#ifndef GF_MONITOR_TILED_PRIVATE_H
+#define GF_MONITOR_TILED_PRIVATE_H
+
+#include <stdint.h>
+#include "gf-monitor-private.h"
+
+G_BEGIN_DECLS
+
+#define GF_TYPE_MONITOR_TILED (gf_monitor_tiled_get_type ())
+G_DECLARE_FINAL_TYPE (GfMonitorTiled, gf_monitor_tiled,
+                      GF, MONITOR_TILED, GfMonitor)
+
+GfMonitorTiled *gf_monitor_tiled_new               (GfMonitorManager *monitor_manager,
+                                                    GfOutput         *output);
+
+uint32_t        gf_monitor_tiled_get_tile_group_id (GfMonitorTiled   *monitor_tiled);
+
+G_END_DECLS
+
+#endif
diff --git a/backends/gf-monitor-tiled.c b/backends/gf-monitor-tiled.c
new file mode 100644
index 0000000..ef9d1a3
--- /dev/null
+++ b/backends/gf-monitor-tiled.c
@@ -0,0 +1,739 @@
+/*
+ * Copyright (C) 2016 Red Hat
+ * Copyright (C) 2017 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Adapted from mutter:
+ * - src/backends/meta-monitor.c
+ */
+
+#include "config.h"
+#include "gf-crtc-private.h"
+#include "gf-monitor-manager-private.h"
+#include "gf-monitor-spec-private.h"
+#include "gf-monitor-tiled-private.h"
+#include "gf-output-private.h"
+
+typedef struct
+{
+  GfMonitorMode parent;
+  gboolean      is_tiled;
+} GfMonitorModeTiled;
+
+struct _GfMonitorTiled
+{
+  GfMonitor  parent;
+
+  uint32_t   tile_group_id;
+
+  /* The tile (0, 0) output. */
+  GfOutput  *origin_output;
+
+  /* The output enabled even when a non-tiled mode is used. */
+  GfOutput  *main_output;
+};
+
+G_DEFINE_TYPE (GfMonitorTiled, gf_monitor_tiled, GF_TYPE_MONITOR)
+
+static gboolean
+is_crtc_mode_tiled (GfOutput   *output,
+                    GfCrtcMode *crtc_mode)
+{
+  return (crtc_mode->width == (gint) output->tile_info.tile_w &&
+          crtc_mode->height == (gint) output->tile_info.tile_h);
+}
+
+static GfCrtcMode *
+find_tiled_crtc_mode (GfOutput   *output,
+                      GfCrtcMode *reference_crtc_mode)
+{
+  GfCrtcMode *crtc_mode;
+  guint i;
+
+  crtc_mode = output->preferred_mode;
+  if (is_crtc_mode_tiled (output, crtc_mode))
+    return crtc_mode;
+
+  for (i = 0; i < output->n_modes; i++)
+    {
+      crtc_mode = output->modes[i];
+
+      if (!is_crtc_mode_tiled (output, crtc_mode))
+        continue;
+
+      if (crtc_mode->refresh_rate != reference_crtc_mode->refresh_rate)
+        continue;
+
+      if (crtc_mode->flags != reference_crtc_mode->flags)
+        continue;
+
+      return crtc_mode;
+    }
+
+  return NULL;
+}
+
+static void
+calculate_tiled_size (GfMonitor *monitor,
+                      gint      *out_width,
+                      gint      *out_height)
+{
+  GList *outputs;
+  GList *l;
+  gint width;
+  gint height;
+
+  outputs = gf_monitor_get_outputs (monitor);
+
+  width = 0;
+  height = 0;
+
+  for (l = outputs; l; l = l->next)
+    {
+      GfOutput *output = l->data;
+
+      if (output->tile_info.loc_v_tile == 0)
+        width += output->tile_info.tile_w;
+
+      if (output->tile_info.loc_h_tile == 0)
+        height += output->tile_info.tile_h;
+    }
+
+  *out_width = width;
+  *out_height = height;
+}
+
+static GfMonitorMode *
+create_tiled_monitor_mode (GfMonitorTiled *tiled,
+                           GfCrtcMode     *reference_crtc_mode,
+                           gboolean       *out_is_preferred)
+{
+  GfMonitor *monitor;
+  GList *outputs;
+  gboolean is_preferred;
+  GfMonitorModeTiled *mode;
+  gint width, height;
+  GList *l;
+  guint i;
+
+  monitor = GF_MONITOR (tiled);
+  outputs = gf_monitor_get_outputs (monitor);
+
+  is_preferred = TRUE;
+
+  mode = g_new0 (GfMonitorModeTiled, 1);
+  mode->is_tiled = TRUE;
+
+  calculate_tiled_size (monitor, &width, &height);
+
+  mode->parent.spec.width = width;
+  mode->parent.spec.height = height;
+  mode->parent.spec.refresh_rate = reference_crtc_mode->refresh_rate;
+  mode->parent.spec.flags = reference_crtc_mode->flags & HANDLED_CRTC_MODE_FLAGS;
+
+  mode->parent.id = gf_monitor_mode_spec_generate_id (&mode->parent.spec);
+  mode->parent.crtc_modes = g_new0 (GfMonitorCrtcMode, g_list_length (outputs));
+
+  for (l = outputs, i = 0; l; l = l->next, i++)
+    {
+      GfOutput *output;
+      GfCrtcMode *tiled_crtc_mode;
+
+      output = l->data;
+      tiled_crtc_mode = find_tiled_crtc_mode (output, reference_crtc_mode);
+
+      if (!tiled_crtc_mode)
+        {
+          g_warning ("No tiled mode found on %s", output->name);
+          gf_monitor_mode_free ((GfMonitorMode *) mode);
+          return NULL;
+        }
+
+      mode->parent.crtc_modes[i].output = output;
+      mode->parent.crtc_modes[i].crtc_mode = tiled_crtc_mode;
+
+      is_preferred = is_preferred && tiled_crtc_mode == output->preferred_mode;
+    }
+
+  *out_is_preferred = is_preferred;
+
+  return (GfMonitorMode *) mode;
+}
+
+static GfMonitorMode *
+create_untiled_monitor_mode (GfMonitorTiled *tiled,
+                             GfOutput       *main_output,
+                             GfCrtcMode     *crtc_mode)
+{
+  GfMonitor *monitor;
+  GList *outputs;
+  GfMonitorModeTiled *mode;
+  GList *l;
+  guint i;
+
+  monitor = GF_MONITOR (tiled);
+  outputs = gf_monitor_get_outputs (monitor);
+
+  if (is_crtc_mode_tiled (main_output, crtc_mode))
+    return NULL;
+
+  mode = g_new0 (GfMonitorModeTiled, 1);
+  mode->is_tiled = FALSE;
+
+  mode->parent.spec.width = crtc_mode->width;
+  mode->parent.spec.height = crtc_mode->height;
+  mode->parent.spec.refresh_rate = crtc_mode->refresh_rate;
+  mode->parent.spec.flags = crtc_mode->flags & HANDLED_CRTC_MODE_FLAGS;
+
+  mode->parent.id = gf_monitor_mode_spec_generate_id (&mode->parent.spec);
+  mode->parent.crtc_modes = g_new0 (GfMonitorCrtcMode, g_list_length (outputs));
+
+  for (l = outputs, i = 0; l; l = l->next, i++)
+    {
+      GfOutput *output = l->data;
+
+      if (output == main_output)
+        {
+          mode->parent.crtc_modes[i].output = output;
+          mode->parent.crtc_modes[i].crtc_mode = crtc_mode;
+        }
+      else
+        {
+          mode->parent.crtc_modes[i].output = output;
+          mode->parent.crtc_modes[i].crtc_mode = NULL;
+        }
+    }
+
+  return &mode->parent;
+}
+
+static void
+generate_tiled_monitor_modes (GfMonitorTiled *tiled)
+{
+  GfMonitor *monitor;
+  GfOutput *main_output;
+  GList *tiled_modes;
+  GfMonitorMode *best_mode;
+  guint i;
+  GList *l;
+
+  monitor = GF_MONITOR (tiled);
+  main_output = gf_monitor_get_main_output (monitor);
+
+  tiled_modes = NULL;
+  best_mode = NULL;
+
+  for (i = 0; i < main_output->n_modes; i++)
+    {
+      GfCrtcMode *reference_crtc_mode;
+      GfMonitorMode *mode;
+      gboolean is_preferred;
+
+      reference_crtc_mode = main_output->modes[i];
+
+      if (!is_crtc_mode_tiled (main_output, reference_crtc_mode))
+        continue;
+
+      mode = create_tiled_monitor_mode (tiled, reference_crtc_mode, &is_preferred);
+
+      if (!mode)
+        continue;
+
+      tiled_modes = g_list_append (tiled_modes, mode);
+
+      if (gf_monitor_is_mode_assigned (monitor, mode))
+        gf_monitor_set_current_mode (monitor, mode);
+
+      if (is_preferred)
+        gf_monitor_set_preferred_mode (monitor, mode);
+    }
+
+  while ((l = tiled_modes))
+    {
+      GfMonitorMode *mode;
+      GfMonitorMode *preferred_mode;
+
+      mode = l->data;
+      tiled_modes = g_list_remove_link (tiled_modes, l);
+
+      if (!gf_monitor_add_mode (monitor, mode))
+        {
+          gf_monitor_mode_free (mode);
+          continue;
+        }
+
+      preferred_mode = gf_monitor_get_preferred_mode (monitor);
+      if (!preferred_mode)
+        {
+          if (!best_mode || mode->spec.refresh_rate > best_mode->spec.refresh_rate)
+            best_mode = mode;
+        }
+    }
+
+  if (best_mode)
+    gf_monitor_set_preferred_mode (monitor, best_mode);
+}
+
+static void
+generate_untiled_monitor_modes (GfMonitorTiled *tiled)
+{
+  GfMonitor *monitor;
+  GfOutput *main_output;
+  guint i;
+
+  monitor = GF_MONITOR (tiled);
+  main_output = gf_monitor_get_main_output (monitor);
+
+  for (i = 0; i < main_output->n_modes; i++)
+    {
+      GfCrtcMode *crtc_mode;
+      GfMonitorMode *mode;
+      GfMonitorMode *preferred_mode;
+
+      crtc_mode = main_output->modes[i];
+      mode = create_untiled_monitor_mode (tiled, main_output, crtc_mode);
+
+      if (!mode)
+        continue;
+
+      if (!gf_monitor_add_mode (monitor, mode))
+        {
+          gf_monitor_mode_free (mode);
+          continue;
+        }
+
+      if (gf_monitor_is_mode_assigned (monitor, mode))
+        {
+          GfMonitorMode *current_mode;
+
+          current_mode = gf_monitor_get_current_mode (monitor);
+          g_assert (!current_mode);
+
+          gf_monitor_set_current_mode (monitor, mode);
+        }
+
+      preferred_mode = gf_monitor_get_preferred_mode (monitor);
+      if (!preferred_mode && crtc_mode == main_output->preferred_mode)
+        gf_monitor_set_preferred_mode (monitor, mode);
+    }
+}
+
+static GfMonitorMode *
+find_best_mode (GfMonitor *monitor)
+{
+  GList *modes;
+  GfMonitorMode *best_mode;
+  GList *l;
+
+  modes = gf_monitor_get_modes (monitor);
+  best_mode = NULL;
+
+  for (l = modes; l; l = l->next)
+    {
+      GfMonitorMode *mode;
+      gint area, best_area;
+
+      mode = l->data;
+
+      if (!best_mode)
+        {
+          best_mode = mode;
+          continue;
+        }
+
+      area = mode->spec.width * mode->spec.height;
+      best_area = best_mode->spec.width * best_mode->spec.height;
+      if (area > best_area)
+        {
+          best_mode = mode;
+          continue;
+        }
+
+      if (mode->spec.refresh_rate > best_mode->spec.refresh_rate)
+        {
+          best_mode = mode;
+          continue;
+        }
+    }
+
+  return best_mode;
+}
+
+static void
+generate_modes (GfMonitorTiled *tiled)
+{
+  GfMonitor *monitor;
+
+  monitor = GF_MONITOR (tiled);
+
+  /*
+   * Tiled monitors may look a bit different from each other, depending on the
+   * monitor itself, the driver, etc.
+   *
+   * On some, the tiled modes will be the preferred CRTC modes, and running
+   * untiled is done by only enabling (0, 0) tile. In this case, things are
+   * pretty straight forward.
+   *
+   * Other times a monitor may have some bogus mode preferred on the main tile,
+   * and an untiled mode preferred on the non-main tile, and there seems to be
+   * no guarantee that the (0, 0) tile is the one that should drive the
+   * non-tiled mode.
+   *
+   * To handle both these cases, the following hueristics are implemented:
+   *
+   *  1) Find all the tiled CRTC modes of the (0, 0) tile, and create tiled
+   *     monitor modes for all tiles based on these.
+   *  2) If there is any tiled monitor mode combination where all CRTC modes
+   *     are the preferred ones, that one is marked as preferred.
+   *  3) If there is no preferred mode determined so far, assume the tiled
+   *     monitor mode with the highest refresh rate is preferred.
+   *  4) Find the tile with highest number of untiled CRTC modes available,
+   *     assume this is the one driving the monitor in untiled mode, and
+   *     create monitor modes for all untiled CRTC modes of that tile. If
+   *     there is still no preferred mode, set any untiled mode as preferred
+   *     if the CRTC mode is marked as such.
+   *  5) If at this point there is still no preferred mode, just pick the one
+   *     with the highest number of pixels and highest refresh rate.
+   *
+   * Note that this ignores the preference if the preference is a non-tiled
+   * mode. This seems to be the case on some systems, where the user tends to
+   * manually set up the tiled mode anyway.
+   */
+
+  generate_tiled_monitor_modes (tiled);
+
+  if (!gf_monitor_get_preferred_mode (monitor))
+    {
+      GfMonitorSpec *spec;
+
+      spec = gf_monitor_get_spec (monitor);
+
+      g_warning ("Tiled monitor on %s didn't have any tiled modes",
+                 spec->connector);
+    }
+
+  generate_untiled_monitor_modes (tiled);
+
+  if (!gf_monitor_get_preferred_mode (monitor))
+    {
+      GfMonitorSpec *spec;
+
+      spec = gf_monitor_get_spec (monitor);
+
+      g_warning ("Tiled monitor on %s didn't have a valid preferred mode",
+                 spec->connector);
+
+      gf_monitor_set_preferred_mode (monitor, find_best_mode (monitor));
+    }
+}
+
+static int
+count_untiled_crtc_modes (GfOutput *output)
+{
+  gint count;
+  guint i;
+
+  count = 0;
+  for (i = 0; i < output->n_modes; i++)
+    {
+      GfCrtcMode *crtc_mode;
+
+      crtc_mode = output->modes[i];
+      if (!is_crtc_mode_tiled (output, crtc_mode))
+        count++;
+    }
+
+  return count;
+}
+
+static GfOutput *
+find_untiled_output (GfMonitorTiled *tiled)
+{
+  GfMonitor *monitor;
+  GList *outputs;
+  GfOutput *best_output;
+  gint best_mode_count;
+  GList *l;
+
+  monitor = GF_MONITOR (tiled);
+  outputs = gf_monitor_get_outputs (monitor);
+
+  best_output = tiled->origin_output;
+  best_mode_count = count_untiled_crtc_modes (tiled->origin_output);
+
+  for (l = outputs; l; l = l->next)
+    {
+      GfOutput *output;
+      gint mode_count;
+
+      output = l->data;
+      if (output == tiled->origin_output)
+        continue;
+
+      mode_count = count_untiled_crtc_modes (output);
+      if (mode_count > best_mode_count)
+        {
+          best_mode_count = mode_count;
+          best_output = output;
+        }
+    }
+
+  return best_output;
+}
+
+static void
+add_tiled_monitor_outputs (GfMonitorManager *monitor_manager,
+                           GfMonitorTiled   *tiled)
+{
+  GfMonitor *monitor;
+  guint i;
+
+  monitor = GF_MONITOR (tiled);
+
+  for (i = 0; i < monitor_manager->n_outputs; i++)
+    {
+      GfOutput *output;
+
+      output = &monitor_manager->outputs[i];
+
+      if (output->tile_info.group_id != tiled->tile_group_id)
+        continue;
+
+      gf_monitor_append_output (monitor, output);
+    }
+}
+
+static void
+calculate_tile_coordinate (GfMonitor          *monitor,
+                           GfOutput           *output,
+                           GfMonitorTransform  crtc_transform,
+                           gint               *out_x,
+                           gint               *out_y)
+{
+  GList *outputs;
+  GList *l;
+  gint x;
+  gint y;
+
+  outputs = gf_monitor_get_outputs (monitor);
+  x = y = 0;
+
+  for (l = outputs; l; l = l->next)
+    {
+      GfOutput *other_output;
+
+      other_output = l->data;
+
+      switch (crtc_transform)
+        {
+          case GF_MONITOR_TRANSFORM_NORMAL:
+          case GF_MONITOR_TRANSFORM_FLIPPED:
+            if (other_output->tile_info.loc_v_tile == output->tile_info.loc_v_tile &&
+                other_output->tile_info.loc_h_tile < output->tile_info.loc_h_tile)
+              x += other_output->tile_info.tile_w;
+            if (other_output->tile_info.loc_h_tile == output->tile_info.loc_h_tile &&
+                other_output->tile_info.loc_v_tile < output->tile_info.loc_v_tile)
+              y += other_output->tile_info.tile_h;
+            break;
+
+          case GF_MONITOR_TRANSFORM_180:
+          case GF_MONITOR_TRANSFORM_FLIPPED_180:
+            if (other_output->tile_info.loc_v_tile == output->tile_info.loc_v_tile &&
+                other_output->tile_info.loc_h_tile > output->tile_info.loc_h_tile)
+              x += other_output->tile_info.tile_w;
+            if (other_output->tile_info.loc_h_tile == output->tile_info.loc_h_tile &&
+                other_output->tile_info.loc_v_tile > output->tile_info.loc_v_tile)
+              y += other_output->tile_info.tile_h;
+            break;
+
+          case GF_MONITOR_TRANSFORM_270:
+          case GF_MONITOR_TRANSFORM_FLIPPED_270:
+            if (other_output->tile_info.loc_v_tile == output->tile_info.loc_v_tile &&
+                other_output->tile_info.loc_h_tile < output->tile_info.loc_h_tile)
+              y += other_output->tile_info.tile_w;
+            if (other_output->tile_info.loc_h_tile == output->tile_info.loc_h_tile &&
+                other_output->tile_info.loc_v_tile < output->tile_info.loc_v_tile)
+              x += other_output->tile_info.tile_h;
+            break;
+
+          case GF_MONITOR_TRANSFORM_90:
+          case GF_MONITOR_TRANSFORM_FLIPPED_90:
+            if (other_output->tile_info.loc_v_tile == output->tile_info.loc_v_tile &&
+                other_output->tile_info.loc_h_tile > output->tile_info.loc_h_tile)
+              y += other_output->tile_info.tile_w;
+            if (other_output->tile_info.loc_h_tile == output->tile_info.loc_h_tile &&
+                other_output->tile_info.loc_v_tile > output->tile_info.loc_v_tile)
+              x += other_output->tile_info.tile_h;
+            break;
+
+          default:
+            break;
+        }
+    }
+
+  *out_x = x;
+  *out_y = y;
+}
+
+static void
+gf_monitor_tiled_finalize (GObject *object)
+{
+  GfMonitor *monitor;
+  GfMonitorManager *monitor_manager;
+
+  monitor = GF_MONITOR (object);
+
+  monitor_manager = gf_monitor_get_monitor_manager (monitor);
+  gf_monitor_manager_tiled_monitor_removed (monitor_manager, monitor);
+
+  G_OBJECT_CLASS (gf_monitor_tiled_parent_class)->finalize (object);
+}
+
+static GfOutput *
+gf_monitor_tiled_get_main_output (GfMonitor *monitor)
+{
+  GfMonitorTiled *tiled;
+
+  tiled = GF_MONITOR_TILED (monitor);
+
+  return tiled->main_output;
+}
+
+static void
+gf_monitor_tiled_derived_derive_layout (GfMonitor   *monitor,
+                                        GfRectangle *layout)
+{
+  GList *outputs;
+  GList *l;
+  gint min_x;
+  gint min_y;
+  gint max_x;
+  gint max_y;
+
+  outputs = gf_monitor_get_outputs (monitor);
+
+  min_x = INT_MAX;
+  min_y = INT_MAX;
+  max_x = 0;
+  max_y = 0;
+
+  for (l = outputs; l; l = l->next)
+    {
+      GfOutput *output = l->data;
+
+      if (!output->crtc)
+        continue;
+
+      min_x = MIN (output->crtc->rect.x, min_x);
+      min_y = MIN (output->crtc->rect.y, min_y);
+      max_x = MAX (output->crtc->rect.x + output->crtc->rect.width, max_x);
+      max_y = MAX (output->crtc->rect.y + output->crtc->rect.height, max_y);
+    }
+
+  *layout = (GfRectangle) {
+    .x = min_x,
+    .y = min_y,
+    .width = max_x - min_x,
+    .height = max_y - min_y
+  };
+}
+
+static void
+gf_monitor_tiled_calculate_crtc_pos (GfMonitor          *monitor,
+                                     GfMonitorMode      *monitor_mode,
+                                     GfOutput           *output,
+                                     GfMonitorTransform  crtc_transform,
+                                     gint               *out_x,
+                                     gint               *out_y)
+{
+  GfMonitorModeTiled *mode_tiled;
+
+  mode_tiled = (GfMonitorModeTiled *) monitor_mode;
+
+  if (mode_tiled->is_tiled)
+    {
+      calculate_tile_coordinate (monitor, output, crtc_transform, out_x, out_y);
+    }
+  else
+    {
+      *out_x = 0;
+      *out_y = 0;
+    }
+}
+
+static gboolean
+gf_monitor_tiled_get_suggested_position (GfMonitor *monitor,
+                                         gint      *x,
+                                         gint      *y)
+{
+  return FALSE;
+}
+
+static void
+gf_monitor_tiled_class_init (GfMonitorTiledClass *tiled_class)
+{
+  GObjectClass *object_class;
+  GfMonitorClass *monitor_class;
+
+  object_class = G_OBJECT_CLASS (tiled_class);
+  monitor_class = GF_MONITOR_CLASS (tiled_class);
+
+  object_class->finalize = gf_monitor_tiled_finalize;
+
+  monitor_class->get_main_output = gf_monitor_tiled_get_main_output;
+  monitor_class->derive_layout = gf_monitor_tiled_derived_derive_layout;
+  monitor_class->calculate_crtc_pos = gf_monitor_tiled_calculate_crtc_pos;
+  monitor_class->get_suggested_position = gf_monitor_tiled_get_suggested_position;
+}
+
+static void
+gf_monitor_tiled_init (GfMonitorTiled *tiled)
+{
+}
+
+GfMonitorTiled *
+gf_monitor_tiled_new (GfMonitorManager *monitor_manager,
+                      GfOutput         *output)
+{
+  GfMonitorTiled *tiled;
+  GfMonitor *monitor;
+
+  tiled = g_object_new (GF_TYPE_MONITOR_TILED,
+                        "monitor-manager", monitor_manager,
+                        NULL);
+
+  monitor = GF_MONITOR (tiled);
+
+  tiled->tile_group_id = output->tile_info.group_id;
+  gf_monitor_set_winsys_id (monitor, output->winsys_id);
+
+  tiled->origin_output = output;
+  add_tiled_monitor_outputs (monitor_manager, tiled);
+
+  tiled->main_output = find_untiled_output (tiled);
+
+  gf_monitor_generate_spec (monitor);
+
+  gf_monitor_manager_tiled_monitor_added (monitor_manager, monitor);
+  generate_modes (tiled);
+
+  return tiled;
+}
+
+uint32_t
+gf_monitor_tiled_get_tile_group_id (GfMonitorTiled *tiled)
+{
+  return tiled->tile_group_id;
+}


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