[mutter/wip/wayland-display: 27/65] Split monitor handling into an helper object



commit 2777dfc533d232a8542e3a618c90323a306f8434
Author: Giovanni Campagna <gcampagn redhat com>
Date:   Thu Jul 18 14:45:48 2013 +0200

    Split monitor handling into an helper object
    
    Create a new singleton object, MetaMonitorManager, which deals
    with reading the XRandR configuration and in the future applying
    the new one.
    This is required because xwayland will not bind the xserver interface
    until he has seen the current wl_outputs, so we can't wait
    until MetaScreen is built to expose them.

 src/Makefile.am                    |    2 +
 src/core/display.c                 |    2 +-
 src/core/monitor-private.h         |   98 ++++++++
 src/core/monitor.c                 |  432 ++++++++++++++++++++++++++++++++++++
 src/core/screen-private.h          |   38 +---
 src/core/screen.c                  |  291 +++---------------------
 src/wayland/meta-wayland-private.h |    4 -
 src/wayland/meta-wayland.c         |   55 +++---
 8 files changed, 596 insertions(+), 326 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 60dd85f..19ded9c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -125,6 +125,8 @@ libmutter_la_SOURCES =                              \
        core/main.c                             \
        core/meta-cursor-tracker.c              \
        core/meta-cursor-tracker-private.h      \
+       core/monitor.c                          \
+       core/monitor-private.h                  \
        core/mutter-Xatomtype.h                 \
        core/place.c                            \
        core/place.h                            \
diff --git a/src/core/display.c b/src/core/display.c
index d760080..178c10d 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -517,7 +517,7 @@ meta_display_open (void)
 
   if (meta_is_syncing ())
     XSynchronize (xdisplay, True);
-  
+
   g_assert (the_display == NULL);
   the_display = g_object_new (META_TYPE_DISPLAY, NULL);
 
diff --git a/src/core/monitor-private.h b/src/core/monitor-private.h
new file mode 100644
index 0000000..0150dc2
--- /dev/null
+++ b/src/core/monitor-private.h
@@ -0,0 +1,98 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/**
+ * \file screen-private.h  Handling of monitor configuration
+ *
+ * Managing multiple monitors
+ * This file contains structures and functions that handle
+ * multiple monitors, including reading the current configuration
+ * and available hardware, and applying it.
+ *
+ * This interface is private to mutter, API users should look
+ * at MetaScreen instead.
+ */
+
+/* 
+ * Copyright (C) 2001 Havoc Pennington
+ * Copyright (C) 2003 Rob Adams
+ * Copyright (C) 2004-2006 Elijah Newren
+ * Copyright (C) 2013 Red Hat Inc.
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef META_MONITOR_PRIVATE_H
+#define META_MONITOR_PRIVATE_H
+
+#include "display-private.h"
+#include <meta/screen.h>
+#include "stack-tracker.h"
+#include "ui.h"
+
+#include <cogl/cogl.h>
+
+typedef struct _MetaOutput MetaOutput;
+typedef struct _MetaMonitorInfo MetaMonitorInfo;
+
+struct _MetaOutput
+{
+  MetaMonitorInfo *monitor;
+  char *name;
+  int width_mm;
+  int height_mm;
+  CoglSubpixelOrder subpixel_order;
+};
+
+struct _MetaMonitorInfo
+{
+  int number;
+  int xinerama_index;
+  MetaRectangle rect;
+  gboolean is_primary;
+  gboolean in_fullscreen;
+  float refresh_rate;
+
+  /* The primary or first output for this crtc, 0 if we can't figure out.
+     This is a XID when using XRandR, otherwise a KMS id (not implemented) */
+  glong output_id;
+};
+
+#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))
+#define META_IS_MONITOR_MANAGER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_MONITOR_MANAGER))
+#define META_IS_MONITOR_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  META_TYPE_MONITOR_MANAGER))
+#define META_MONITOR_MANAGER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  META_TYPE_MONITOR_MANAGER, 
MetaMonitorManagerClass))
+
+typedef struct _MetaMonitorManagerClass    MetaMonitorManagerClass;
+typedef struct _MetaMonitorManager         MetaMonitorManager;
+
+GType meta_monitor_manager_get_type (void);
+
+void                meta_monitor_manager_initialize (Display *display);
+MetaMonitorManager *meta_monitor_manager_get  (void);
+
+MetaMonitorInfo    *meta_monitor_manager_get_monitor_infos (MetaMonitorManager *manager,
+                                                           int                *n_infos);
+
+MetaOutput         *meta_monitor_manager_get_outputs       (MetaMonitorManager *manager,
+                                                           int                *n_outputs);
+
+int                 meta_monitor_manager_get_primary_index (MetaMonitorManager *manager);
+
+void                meta_monitor_manager_invalidate        (MetaMonitorManager *manager);
+
+#endif
diff --git a/src/core/monitor.c b/src/core/monitor.c
new file mode 100644
index 0000000..8fbcc92
--- /dev/null
+++ b/src/core/monitor.c
@@ -0,0 +1,432 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/* 
+ * Copyright (C) 2001, 2002 Havoc Pennington
+ * Copyright (C) 2002, 2003 Red Hat Inc.
+ * Some ICCCM manager selection code derived from fvwm2,
+ * Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
+ * Copyright (C) 2003 Rob Adams
+ * Copyright (C) 2004-2006 Elijah Newren
+ * Copyright (C) 2013 Red Hat Inc.
+ * 
+ * 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 <clutter/clutter.h>
+
+#ifdef HAVE_RANDR
+#include <X11/extensions/Xrandr.h>
+#endif
+
+#include "monitor-private.h"
+#ifdef HAVE_WAYLAND
+#include "meta-wayland-private.h"
+#endif
+
+struct _MetaMonitorManager
+{
+  GObject parent_instance;
+
+  /* Outputs refers to physical screens,
+     while monitor_infos refer to logical ones (aka CRTC)
+     They can be different if two outputs are
+     in clone mode
+  */
+  MetaOutput *outputs;
+  int primary_monitor_index;
+  int n_outputs;
+
+  MetaMonitorInfo *monitor_infos;
+  int n_monitor_infos;
+
+#ifdef HAVE_RANDR
+  Display *xdisplay;
+#endif
+};
+
+struct _MetaMonitorManagerClass
+{
+  GObjectClass parent_class;
+};
+
+enum {
+  MONITORS_CHANGED,
+  SIGNALS_LAST
+};
+
+static int signals[SIGNALS_LAST];
+
+G_DEFINE_TYPE (MetaMonitorManager, meta_monitor_manager, G_TYPE_OBJECT);
+
+static void
+make_dummy_monitor_config (MetaMonitorManager *manager)
+{
+  manager->monitor_infos = g_new0 (MetaMonitorInfo, 1);
+  manager->n_monitor_infos = 1;
+
+  manager->monitor_infos[0].number = 0;
+  manager->monitor_infos[0].xinerama_index = 0;
+  manager->monitor_infos[0].rect.x = 0;
+  manager->monitor_infos[0].rect.y = 0;
+  if (manager->xdisplay)
+    {
+      Screen *screen = ScreenOfDisplay (manager->xdisplay,
+                                        DefaultScreen (manager->xdisplay));
+
+      manager->monitor_infos[0].rect.width = WidthOfScreen (screen);
+      manager->monitor_infos[0].rect.height = HeightOfScreen (screen);
+    }
+  else
+    {
+      manager->monitor_infos[0].rect.width = 1024;
+      manager->monitor_infos[0].rect.height = 768;
+    }
+  manager->monitor_infos[0].refresh_rate = 60.0f;
+  manager->monitor_infos[0].is_primary = TRUE;
+  manager->monitor_infos[0].in_fullscreen = -1;
+  manager->monitor_infos[0].output_id = 1;
+
+  manager->outputs = g_new0 (MetaOutput, 1);
+  manager->n_outputs = 1;
+
+  manager->outputs[0].monitor = &manager->monitor_infos[0];
+  manager->outputs[0].name = g_strdup ("LVDS");
+  manager->outputs[0].width_mm = 222;
+  manager->outputs[0].height_mm = 125;
+  manager->outputs[0].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
+}
+
+#ifdef HAVE_RANDR
+
+/* In the case of multiple outputs of a single crtc (mirroring), we consider one of the
+ * outputs the "main". This is the one we consider "owning" the windows, so if
+ * the mirroring is changed to a dual monitor setup then the windows are moved to the
+ * crtc that now has that main output. If one of the outputs is the primary that is
+ * always the main, otherwise we just use the first.
+ */
+static void
+find_main_output_for_crtc (MetaMonitorManager         *manager,
+                           XRRScreenResources *resources,
+                           XRRCrtcInfo        *crtc,
+                           MetaMonitorInfo    *info,
+                           GArray             *outputs)
+{
+  XRROutputInfo *output;
+  RROutput primary_output;
+  int i;
+
+  primary_output = XRRGetOutputPrimary (manager->xdisplay,
+                                        DefaultRootWindow (manager->xdisplay));
+
+  for (i = 0; i < crtc->noutput; i++)
+    {
+      output = XRRGetOutputInfo (manager->xdisplay, resources, crtc->outputs[i]);
+
+      if (output->connection != RR_Disconnected)
+        {
+          MetaOutput meta_output;
+
+          meta_output.name = g_strdup (output->name);
+          meta_output.width_mm = output->mm_width;
+          meta_output.height_mm = output->mm_height;
+          meta_output.subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
+
+          g_array_append_val (outputs, meta_output);
+
+          if (crtc->outputs[i] == primary_output)
+            {
+              info->output_id = crtc->outputs[i];
+              info->is_primary = TRUE;
+              manager->primary_monitor_index = info->number;
+            }
+          else if (info->output_id == 0)
+            {
+              info->output_id = crtc->outputs[i];
+            }
+        }
+
+      XRRFreeOutputInfo (output);
+    }
+}
+
+static void
+read_monitor_infos_from_xrandr (MetaMonitorManager *manager)
+{
+    XRRScreenResources *resources;
+    GArray *outputs;
+    int i, j;
+
+    resources = XRRGetScreenResourcesCurrent (manager->xdisplay,
+                                              DefaultRootWindow (manager->xdisplay));
+    if (!resources)
+      return make_dummy_monitor_config (manager);
+
+    outputs = g_array_new (FALSE, TRUE, sizeof (MetaOutput));
+
+    manager->n_outputs = 0;
+    manager->n_monitor_infos = resources->ncrtc;
+
+    manager->monitor_infos = g_new0 (MetaMonitorInfo, manager->n_monitor_infos);
+
+    for (i = 0; i < resources->ncrtc; i++)
+      {
+        XRRCrtcInfo *crtc;
+        MetaMonitorInfo *info;
+
+        crtc = XRRGetCrtcInfo (manager->xdisplay, resources, resources->crtcs[i]);
+
+        info = &manager->monitor_infos[i];
+
+        info->number = i;
+        info->rect.x = crtc->x;
+        info->rect.y = crtc->y;
+        info->rect.width = crtc->width;
+        info->rect.height = crtc->height;
+        info->in_fullscreen = -1;
+
+        for (j = 0; j < resources->nmode; j++)
+          {
+            if (resources->modes[j].id == crtc->mode)
+              info->refresh_rate = (resources->modes[j].dotClock /
+                                    ((float)resources->modes[j].hTotal *
+                                     resources->modes[j].vTotal));
+          }
+
+        find_main_output_for_crtc (manager, resources, crtc, info, outputs);
+
+        XRRFreeCrtcInfo (crtc);
+      }
+
+    manager->n_outputs = outputs->len;
+    manager->outputs = (void*)g_array_free (outputs, FALSE);
+
+    XRRFreeScreenResources (resources);
+}
+
+#endif
+
+typedef struct {
+  GArray *monitor_infos;
+  GArray *outputs;
+} ReadMonitorCoglClosure;
+
+static void
+read_monitor_from_cogl_helper (CoglOutput *output,
+                               void       *user_data)
+{
+  ReadMonitorCoglClosure *closure = user_data;
+  MetaMonitorInfo info;
+  MetaOutput meta_output;
+
+  info.number = closure->monitor_infos->len;
+  info.rect.x = cogl_output_get_x (output);
+  info.rect.y = cogl_output_get_y (output);
+  info.rect.width = cogl_output_get_width (output);
+  info.rect.height = cogl_output_get_height (output);
+  info.refresh_rate = cogl_output_get_refresh_rate (output);
+  info.is_primary = (info.number == 0);
+  info.in_fullscreen = -1;
+  info.output_id = 0; /* unknown */
+
+  g_array_append_val (closure->monitor_infos, info);
+
+  meta_output.monitor = &g_array_index (closure->monitor_infos,
+                                        MetaMonitorInfo,
+                                        closure->monitor_infos->len - 1);
+  meta_output.name = NULL;
+  meta_output.width_mm = cogl_output_get_mm_width (output);
+  meta_output.height_mm = cogl_output_get_mm_height (output);
+  meta_output.subpixel_order = cogl_output_get_subpixel_order (output);
+
+  g_array_append_val (closure->outputs, meta_output);
+}
+
+static void
+read_monitor_infos_from_cogl (MetaMonitorManager *manager)
+{
+  ReadMonitorCoglClosure closure;
+  ClutterBackend *backend;
+  CoglContext *cogl_context;
+  CoglRenderer *cogl_renderer;
+
+  backend = clutter_get_default_backend ();
+  cogl_context = clutter_backend_get_cogl_context (backend);
+  cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (cogl_context));
+
+  closure.monitor_infos = g_array_new (FALSE, TRUE, sizeof (MetaMonitorInfo));
+  closure.outputs = g_array_new (FALSE, TRUE, sizeof (MetaOutput));
+
+  cogl_renderer_foreach_output (cogl_renderer,
+                                read_monitor_from_cogl_helper, &closure);
+
+  manager->n_monitor_infos = closure.monitor_infos->len;
+  manager->monitor_infos = (void*)g_array_free (closure.monitor_infos, FALSE);
+  manager->n_outputs = closure.outputs->len;
+  manager->outputs = (void*)g_array_free (closure.outputs, FALSE);
+
+  manager->primary_monitor_index = 0;
+}
+
+/*
+ * meta_has_dummy_output:
+ *
+ * Returns TRUE if the only available monitor is the dummy one
+ * backing the ClutterStage window.
+ */
+static gboolean
+has_dummy_output (void)
+{
+  MetaWaylandCompositor *compositor;
+
+  if (!meta_is_wayland_compositor ())
+    return FALSE;
+
+  /* FIXME: actually, even in EGL-KMS mode, Cogl does not
+     expose the outputs through CoglOutput - yet */
+  compositor = meta_wayland_compositor_get_default ();
+  return !meta_wayland_compositor_is_native (compositor);
+}
+
+static void
+meta_monitor_manager_init (MetaMonitorManager *manager)
+{
+}
+
+static void
+read_current_config (MetaMonitorManager *manager)
+{
+  if (has_dummy_output ())
+    return make_dummy_monitor_config (manager);
+
+#ifdef HAVE_RANDR
+  if (!meta_is_wayland_compositor ())
+    return read_monitor_infos_from_xrandr (manager);
+#endif
+
+  return read_monitor_infos_from_cogl (manager);
+}
+
+static MetaMonitorManager *
+meta_monitor_manager_new (Display *display)
+{
+  MetaMonitorManager *manager;
+
+  manager = g_object_new (META_TYPE_MONITOR_MANAGER, NULL);
+
+  manager->xdisplay = display;
+
+  read_current_config (manager);
+  return manager;
+}
+
+static void
+free_output_array (MetaOutput *old_outputs,
+                   int         n_old_outputs)
+{
+  int i;
+
+  for (i = 0; i < n_old_outputs; i++)
+    g_free (old_outputs[i].name);
+  g_free (old_outputs);
+}
+
+static void
+meta_monitor_manager_finalize (GObject *object)
+{
+  MetaMonitorManager *manager = META_MONITOR_MANAGER (object);
+
+  free_output_array (manager->outputs, manager->n_outputs);
+  g_free (manager->monitor_infos);
+
+  G_OBJECT_CLASS (meta_monitor_manager_parent_class)->finalize (object);
+}
+
+static void
+meta_monitor_manager_class_init (MetaMonitorManagerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = meta_monitor_manager_finalize;
+
+  signals[MONITORS_CHANGED] =
+    g_signal_new ("monitors-changed",
+                 G_TYPE_FROM_CLASS (object_class),
+                 G_SIGNAL_RUN_LAST,
+                 0,
+                  NULL, NULL, NULL,
+                 G_TYPE_NONE, 0);
+}
+
+static MetaMonitorManager *global_manager;
+
+void
+meta_monitor_manager_initialize (Display *display)
+{
+  global_manager = meta_monitor_manager_new (display);
+}
+
+MetaMonitorManager *
+meta_monitor_manager_get (void)
+{
+  g_assert (global_manager != NULL);
+
+  return global_manager;
+}
+
+MetaMonitorInfo *
+meta_monitor_manager_get_monitor_infos (MetaMonitorManager *manager,
+                                        int                *n_infos)
+{
+  *n_infos = manager->n_monitor_infos;
+  return manager->monitor_infos;
+}
+
+MetaOutput *
+meta_monitor_manager_get_outputs (MetaMonitorManager *manager,
+                                  int                *n_outputs)
+{
+  *n_outputs = manager->n_outputs;
+  return manager->outputs;
+}
+
+int
+meta_monitor_manager_get_primary_index (MetaMonitorManager *manager)
+{
+  return manager->primary_monitor_index;
+}
+
+void
+meta_monitor_manager_invalidate (MetaMonitorManager *manager)
+{
+  MetaOutput *old_outputs;
+  MetaMonitorInfo *old_monitor_infos;
+  int n_old_outputs;
+
+  /* Save the old monitor infos, so they stay valid during the update */
+  old_outputs = manager->outputs;
+  n_old_outputs = manager->n_outputs;
+  old_monitor_infos = manager->monitor_infos;
+
+  read_current_config (manager);
+
+  g_signal_emit (manager, signals[MONITORS_CHANGED], 0);
+
+  g_free (old_monitor_infos);
+  free_output_array (old_outputs, n_old_outputs);
+}
+
diff --git a/src/core/screen-private.h b/src/core/screen-private.h
index 4fcd92b..9856653 100644
--- a/src/core/screen-private.h
+++ b/src/core/screen-private.h
@@ -38,34 +38,7 @@
 #include <X11/Xutil.h>
 #include "stack-tracker.h"
 #include "ui.h"
-
-#include <cogl/cogl.h>
-
-typedef struct _MetaOutput MetaOutput;
-typedef struct _MetaMonitorInfo MetaMonitorInfo;
-
-struct _MetaOutput
-{
-  MetaMonitorInfo *monitor;
-  char *name;
-  int width_mm;
-  int height_mm;
-  CoglSubpixelOrder subpixel_order;
-};
-
-struct _MetaMonitorInfo
-{
-  int number;
-  int xinerama_index;
-  MetaRectangle rect;
-  gboolean is_primary;
-  gboolean in_fullscreen;
-  float refresh_rate;
-
-  /* The primary or first output for this crtc, 0 if we can't figure out.
-     This is a XID when using XRandR, otherwise a KMS id (not implemented) */
-  glong output_id;
-};
+#include "monitor-private.h"
 
 typedef void (* MetaScreenWindowFunc) (MetaScreen *screen, MetaWindow *window,
                                        gpointer user_data);
@@ -119,16 +92,9 @@ struct _MetaScreen
   Atom wm_sn_atom;
   guint32 wm_sn_timestamp;
 
-  /* Outputs refers to physical screens,
-     while monitor_infos refer to logical ones (aka CRTC)
-     They can be different if two outputs are
-     in clone mode
-  */
-  MetaOutput *outputs;
   MetaMonitorInfo *monitor_infos;
-  int primary_monitor_index;
-  int n_outputs;
   int n_monitor_infos;
+  int primary_monitor_index;
   gboolean has_xinerama_indices;
 
   /* Cache the current monitor */
diff --git a/src/core/screen.c b/src/core/screen.c
index afb04dc..ab3aca5 100644
--- a/src/core/screen.c
+++ b/src/core/screen.c
@@ -52,10 +52,6 @@
 
 #include <X11/extensions/Xinerama.h>
 
-#ifdef HAVE_RANDR
-#include <X11/extensions/Xrandr.h>
-#endif
-
 #include <X11/Xatom.h>
 #include <locale.h>
 #include <string.h>
@@ -80,6 +76,9 @@ static void meta_screen_sn_event   (SnMonitorEvent *event,
                                     void           *user_data);
 #endif
 
+static void on_monitors_changed (MetaMonitorManager *manager,
+                                 MetaScreen         *screen);
+
 enum
 {
   PROP_N_WORKSPACES = 1,
@@ -354,54 +353,6 @@ set_wm_icon_size_hint (MetaScreen *screen)
 #undef N_VALS
 }
 
-/*
- * meta_has_dummy_output:
- *
- * Returns TRUE if the only available monitor is the dummy one
- * backing the ClutterStage window.
- */
-static gboolean
-has_dummy_output (void)
-{
-  MetaWaylandCompositor *compositor;
-
-  if (!meta_is_wayland_compositor ())
-    return FALSE;
-
-  /* FIXME: actually, even in EGL-KMS mode, Cogl does not
-     expose the outputs through CoglOutput - yet */
-  compositor = meta_wayland_compositor_get_default ();
-  return !meta_wayland_compositor_is_native (compositor);
-}
-
-static void
-make_dummy_monitor_config (MetaScreen *screen)
-{
-  screen->outputs = g_new0 (MetaOutput, 1);
-  screen->n_outputs = 1;
-
-  screen->outputs[0].name = g_strdup ("LVDS");
-  screen->outputs[0].width_mm = 222;
-  screen->outputs[0].height_mm = 125;
-  screen->outputs[0].subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
-
-  screen->monitor_infos = g_new0 (MetaMonitorInfo, 1);
-  screen->n_monitor_infos = 1;
-
-  screen->monitor_infos[0].number = 0;
-  screen->monitor_infos[0].xinerama_index = 0;
-  screen->monitor_infos[0].rect.x = 0;
-  screen->monitor_infos[0].rect.y = 0;
-  screen->monitor_infos[0].rect.width = screen->rect.width;
-  screen->monitor_infos[0].rect.height = screen->rect.height;
-  screen->monitor_infos[0].refresh_rate = 60.0f;
-  screen->monitor_infos[0].is_primary = TRUE;
-  screen->monitor_infos[0].in_fullscreen = -1;
-  screen->monitor_infos[0].output_id = 1;
-
-  screen->has_xinerama_indices = TRUE;
-}
-
 static void
 meta_screen_ensure_xinerama_indices (MetaScreen *screen)
 {
@@ -462,179 +413,11 @@ meta_screen_xinerama_index_to_monitor_index (MetaScreen *screen,
   return -1;
 }
 
-#ifdef HAVE_RANDR
-
-/* In the case of multiple outputs of a single crtc (mirroring), we consider one of the
- * outputs the "main". This is the one we consider "owning" the windows, so if
- * the mirroring is changed to a dual monitor setup then the windows are moved to the
- * crtc that now has that main output. If one of the outputs is the primary that is
- * always the main, otherwise we just use the first.
- */
-static void
-find_main_output_for_crtc (MetaScreen         *screen,
-                           XRRScreenResources *resources,
-                           XRRCrtcInfo        *crtc,
-                           MetaMonitorInfo    *info,
-                           GArray             *outputs)
-{
-  XRROutputInfo *output;
-  RROutput primary_output;
-  int i;
-
-  primary_output = XRRGetOutputPrimary (screen->display->xdisplay, screen->xroot);
-
-  for (i = 0; i < crtc->noutput; i++)
-    {
-      output = XRRGetOutputInfo (screen->display->xdisplay, resources, crtc->outputs[i]);
-
-      if (output->connection != RR_Disconnected)
-        {
-          MetaOutput meta_output;
-
-          meta_output.name = g_strdup (output->name);
-          meta_output.width_mm = output->mm_width;
-          meta_output.height_mm = output->mm_height;
-          meta_output.subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
-
-          g_array_append_val (outputs, meta_output);
-
-          if (crtc->outputs[i] == primary_output)
-            {
-              info->output_id = crtc->outputs[i];
-              info->is_primary = TRUE;
-              screen->primary_monitor_index = info->number;
-            }
-          else if (info->output_id == 0)
-            {
-              info->output_id = crtc->outputs[i];
-            }
-        }
-
-      XRRFreeOutputInfo (output);
-    }
-}
-
-static void
-read_monitor_infos_from_xrandr (MetaScreen *screen)
-{
-    XRRScreenResources *resources;
-    GArray *outputs;
-    int i, j;
-
-    resources = XRRGetScreenResourcesCurrent (screen->display->xdisplay, screen->xroot);
-    if (!resources)
-      return make_dummy_monitor_config (screen);
-
-    outputs = g_array_new (FALSE, TRUE, sizeof (MetaOutput));
-
-    screen->n_outputs = 0;
-    screen->n_monitor_infos = resources->ncrtc;
-
-    screen->monitor_infos = g_new0 (MetaMonitorInfo, screen->n_monitor_infos);
-
-    for (i = 0; i < resources->ncrtc; i++)
-      {
-        XRRCrtcInfo *crtc;
-        MetaMonitorInfo *info;
-
-        crtc = XRRGetCrtcInfo (screen->display->xdisplay, resources, resources->crtcs[i]);
-
-        info = &screen->monitor_infos[i];
-
-        info->number = i;
-        info->rect.x = crtc->x;
-        info->rect.y = crtc->y;
-        info->rect.width = crtc->width;
-        info->rect.height = crtc->height;
-        info->in_fullscreen = -1;
-
-        for (j = 0; j < resources->nmode; j++)
-          {
-            if (resources->modes[j].id == crtc->mode)
-              info->refresh_rate = (resources->modes[j].dotClock /
-                                    ((float)resources->modes[j].hTotal *
-                                     resources->modes[j].vTotal));
-          }
-
-        find_main_output_for_crtc (screen, resources, crtc, info, outputs);
-
-        XRRFreeCrtcInfo (crtc);
-      }
-
-    screen->n_outputs = outputs->len;
-    screen->outputs = (void*)g_array_free (outputs, FALSE);
-
-    XRRFreeScreenResources (resources);
-}
-
-#endif
-
-typedef struct {
-  GArray *monitor_infos;
-  GArray *outputs;
-} ReadMonitorCoglClosure;
-
-static void
-read_monitor_from_cogl_helper (CoglOutput *output,
-                               void       *user_data)
-{
-  ReadMonitorCoglClosure *closure = user_data;
-  MetaMonitorInfo info;
-  MetaOutput meta_output;
-
-  info.number = closure->monitor_infos->len;
-  info.rect.x = cogl_output_get_x (output);
-  info.rect.y = cogl_output_get_y (output);
-  info.rect.width = cogl_output_get_width (output);
-  info.rect.height = cogl_output_get_height (output);
-  info.refresh_rate = cogl_output_get_refresh_rate (output);
-  info.is_primary = (info.number == 0);
-  info.in_fullscreen = -1;
-  info.output_id = 0; /* unknown */
-
-  g_array_append_val (closure->monitor_infos, info);
-
-  meta_output.monitor = &g_array_index (closure->monitor_infos,
-                                        MetaMonitorInfo,
-                                        closure->monitor_infos->len - 1);
-  meta_output.name = NULL;
-  meta_output.width_mm = cogl_output_get_mm_width (output);
-  meta_output.height_mm = cogl_output_get_mm_height (output);
-  meta_output.subpixel_order = cogl_output_get_subpixel_order (output);
-
-  g_array_append_val (closure->outputs, meta_output);
-}
-
-static void
-read_monitor_infos_from_cogl (MetaScreen *screen)
-{
-  ReadMonitorCoglClosure closure;
-  ClutterBackend *backend;
-  CoglContext *cogl_context;
-  CoglRenderer *cogl_renderer;
-
-  backend = clutter_get_default_backend ();
-  cogl_context = clutter_backend_get_cogl_context (backend);
-  cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (cogl_context));
-
-  closure.monitor_infos = g_array_new (FALSE, TRUE, sizeof (MetaMonitorInfo));
-  closure.outputs = g_array_new (FALSE, TRUE, sizeof (MetaOutput));
-
-  cogl_renderer_foreach_output (cogl_renderer,
-                                read_monitor_from_cogl_helper, &closure);
-
-  screen->n_monitor_infos = closure.monitor_infos->len;
-  screen->monitor_infos = (void*)g_array_free (closure.monitor_infos, FALSE);
-  screen->n_outputs = closure.outputs->len;
-  screen->outputs = (void*)g_array_free (closure.outputs, FALSE);
-
-  screen->primary_monitor_index = 0;
-}
-
 static void
 reload_monitor_infos (MetaScreen *screen)
 {
   GList *tmp;
+  MetaMonitorManager *manager;
 
   tmp = screen->workspaces;
   while (tmp != NULL)
@@ -648,23 +431,15 @@ reload_monitor_infos (MetaScreen *screen)
 
   /* Any previous screen->monitor_infos or screen->outputs is freed by the caller */
 
-  screen->outputs = NULL;
-  screen->n_outputs = 0;
-  screen->monitor_infos = NULL;
-  screen->n_monitor_infos = 0;
   screen->last_monitor_index = 0;
   screen->has_xinerama_indices = FALSE;
   screen->display->monitor_cache_invalidated = TRUE;
 
-  if (has_dummy_output ())
-    return make_dummy_monitor_config (screen);
-
-#ifdef HAVE_RANDR
-  if (!meta_is_wayland_compositor ())
-    return read_monitor_infos_from_xrandr (screen);
-#endif
+  manager = meta_monitor_manager_get ();
 
-  return read_monitor_infos_from_cogl (screen);
+  screen->monitor_infos = meta_monitor_manager_get_monitor_infos (manager,
+                                                                  &screen->n_monitor_infos);
+  screen->primary_monitor_index = meta_monitor_manager_get_primary_index (manager);
 }
 
 /* The guard window allows us to leave minimized windows mapped so
@@ -942,9 +717,20 @@ meta_screen_new (MetaDisplay *display,
   screen->compositor_data = NULL;
   screen->guard_window = None;
 
-  reload_monitor_infos (screen);
+  {
+    MetaMonitorManager *manager;
 
-  meta_cursor_tracker_get_for_screen (screen);
+    if (!meta_is_wayland_compositor ())
+      meta_monitor_manager_initialize (screen->display->xdisplay);
+
+    reload_monitor_infos (screen);
+
+    manager = meta_monitor_manager_get ();
+    g_signal_connect (manager, "monitors-changed",
+                      G_CALLBACK (on_monitors_changed), screen);
+  }
+
+  meta_cursor_tracker_get_for_screen (screen);  
   meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
 
   /* Handle creating a no_focus_window for this screen */  
@@ -1029,12 +815,6 @@ meta_screen_new (MetaDisplay *display,
   meta_verbose ("Added screen %d ('%s') root 0x%lx\n",
                 screen->number, screen->screen_name, screen->xroot);
 
-#ifdef HAVE_WAYLAND
-  if (meta_is_wayland_compositor ())
-    meta_wayland_compositor_init_screen (compositor,
-                                         screen);
-#endif
-
   return screen;
 }
 
@@ -3087,18 +2867,17 @@ meta_screen_resize (MetaScreen *screen,
                     int         width,
                     int         height)
 {
-  GSList *windows, *tmp;
-  MetaOutput *old_outputs;
-  MetaMonitorInfo *old_monitor_infos;
-  int n_old_outputs, i;
-
   screen->rect.width = width;
   screen->rect.height = height;
 
-  /* Save the old monitor infos, so they stay valid during the update */
-  old_outputs = screen->outputs;
-  n_old_outputs = screen->n_outputs;
-  old_monitor_infos = screen->monitor_infos;
+  meta_monitor_manager_invalidate (meta_monitor_manager_get ());
+}
+
+static void
+on_monitors_changed (MetaMonitorManager *manager,
+                     MetaScreen         *screen)
+{
+  GSList *tmp, *windows;
 
   reload_monitor_infos (screen);
   set_desktop_geometry_hint (screen);
@@ -3110,8 +2889,8 @@ meta_screen_resize (MetaScreen *screen,
 
       changes.x = 0;
       changes.y = 0;
-      changes.width = width;
-      changes.height = height;
+      changes.width = screen->rect.width;
+      changes.height = screen->rect.height;
 
       XConfigureWindow(screen->display->xdisplay,
                        screen->guard_window,
@@ -3121,7 +2900,8 @@ meta_screen_resize (MetaScreen *screen,
 
   if (screen->display->compositor)
     meta_compositor_sync_screen_size (screen->display->compositor,
-                                     screen, width, height);
+                                     screen,
+                                      screen->rect.width, screen->rect.height);
 
   /* Queue a resize on all the windows */
   meta_screen_foreach_window (screen, meta_screen_resize_func, 0);
@@ -3137,16 +2917,11 @@ meta_screen_resize (MetaScreen *screen,
         meta_window_update_for_monitors_changed (window);
     }
 
-  g_free (old_monitor_infos);
   g_slist_free (windows);
 
   meta_screen_queue_check_fullscreen (screen);
 
   g_signal_emit (screen, screen_signals[MONITORS_CHANGED], 0);
-
-  for (i = 0; i < n_old_outputs; i++)
-    g_free (old_outputs[i].name);
-  g_free (old_outputs);
 }
 
 void
diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h
index c931f47..65674ff 100644
--- a/src/wayland/meta-wayland-private.h
+++ b/src/wayland/meta-wayland-private.h
@@ -130,7 +130,6 @@ typedef struct
 
 struct _MetaWaylandCompositor
 {
-  MetaScreen *screen;
   GList *outputs;
 
   struct wl_display *wayland_display;
@@ -340,9 +339,6 @@ void                    meta_wayland_finalize                   (void);
  * API after meta_wayland_init() has been called. */
 MetaWaylandCompositor  *meta_wayland_compositor_get_default     (void);
 
-void                    meta_wayland_compositor_init_screen     (MetaWaylandCompositor *compositor,
-                                                                MetaScreen            *screen);
-
 void                    meta_wayland_compositor_repick          (MetaWaylandCompositor *compositor);
 
 void                    meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index 9f1e8b2..99fd4b3 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -661,21 +661,25 @@ bind_output (struct wl_client *client,
                          (int)output->monitor->rect.height,
                          (int)output->monitor->refresh_rate);
 
-  wl_resource_post_event (resource,
-                         WL_OUTPUT_DONE);
+  if (version >= 2)
+    wl_resource_post_event (resource,
+                           WL_OUTPUT_DONE);
 }
 
 static void
-meta_wayland_compositor_create_outputs (MetaWaylandCompositor *compositor)
+meta_wayland_compositor_create_outputs (MetaWaylandCompositor *compositor,
+                                       MetaMonitorManager    *monitors)
 {
-  MetaScreen *screen = compositor->screen;
-  int i;
+  MetaOutput *outputs;
+  int i, n_outputs;
+
+  outputs = meta_monitor_manager_get_outputs (monitors, &n_outputs);
 
-  for (i = 0; i < screen->n_outputs; i++)
+  for (i = 0; i < n_outputs; i++)
     compositor->outputs = g_list_prepend (compositor->outputs,
                                          wl_global_create (compositor->wayland_display,
                                                            &wl_output_interface, 2,
-                                                           &screen->outputs[i], bind_output));
+                                                           &outputs[i], bind_output));
 }
 
 const static struct wl_compositor_interface meta_wayland_compositor_interface = {
@@ -1414,6 +1418,14 @@ on_evdev_device_open (const char  *path,
                                               path, flags, error);
 }
 
+static void
+on_monitors_changed (MetaMonitorManager    *monitors,
+                    MetaWaylandCompositor *compositor)
+{
+  g_list_free_full (compositor->outputs, (GDestroyNotify) wl_global_destroy);
+  meta_wayland_compositor_create_outputs (compositor, monitors);
+}
+
 void
 meta_wayland_init (void)
 {
@@ -1423,6 +1435,7 @@ meta_wayland_init (void)
   CoglContext *cogl_context;
   CoglRenderer *cogl_renderer;
   int weston_launch_fd;
+  MetaMonitorManager *monitors;
 
   memset (compositor, 0, sizeof (MetaWaylandCompositor));
 
@@ -1520,12 +1533,20 @@ meta_wayland_init (void)
     }
 
   compositor->stage = meta_wayland_stage_new ();
+  /* FIXME */
+  clutter_actor_set_size (CLUTTER_ACTOR (compositor->stage), 1024, 768);
   clutter_stage_set_user_resizable (CLUTTER_STAGE (compositor->stage), FALSE);
   g_signal_connect_after (compositor->stage, "paint",
                           G_CALLBACK (paint_finished_cb), compositor);
   g_signal_connect (compositor->stage, "destroy",
                     G_CALLBACK (stage_destroy_cb), NULL);
 
+  meta_monitor_manager_initialize (NULL);
+  monitors = meta_monitor_manager_get ();
+  g_signal_connect (monitors, "monitors-changed",
+                   G_CALLBACK (on_monitors_changed), compositor);
+  meta_wayland_compositor_create_outputs (compositor, monitors);
+
   meta_wayland_data_device_manager_init (compositor->wayland_display);
 
   compositor->seat = meta_wayland_seat_new (compositor->wayland_display,
@@ -1594,23 +1615,3 @@ meta_wayland_compositor_is_native (MetaWaylandCompositor *compositor)
 {
   return compositor->drm_fd >= 0;
 }
-
-static void
-on_monitors_changed (MetaScreen            *screen,
-                    MetaWaylandCompositor *compositor)
-{
-  g_list_free_full (compositor->outputs, (GDestroyNotify) wl_global_destroy);
-  meta_wayland_compositor_create_outputs (compositor);
-}
-
-void
-meta_wayland_compositor_init_screen (MetaWaylandCompositor *compositor,
-                                    MetaScreen            *screen)
-{
-  compositor->screen = screen;
-
-  g_signal_connect (compositor->screen, "monitors-changed",
-                   G_CALLBACK (on_monitors_changed), compositor);
-
-  meta_wayland_compositor_create_outputs (compositor);
-}


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