[mutter/wip/wayland-display: 58/93] Rework and consolidate monitor handling between MetaScreen and MetaWaylandCompositor



commit de6c16078fc06b8837e301ab6f6210d0699f9500
Author: Giovanni Campagna <gcampagn redhat com>
Date:   Thu Jul 18 13:09:16 2013 +0200

    Rework and consolidate monitor handling between MetaScreen and MetaWaylandCompositor
    
    Consolidate all places that deal with output configuration in
    MetaScreen, which gets it either from XRandR or from Cogl (which
    in turn would read it from XRandR or KMS, depending on the backend).
    We still need to read the Xinerama config, even when running xwayland,
    because we need the indices for _NET_WM_FULLSCREEN_MONITORS, but
    now we do it only when needed.
    Also, now MetaWaylandCompositor listens for MetaScreen::monitor-changed
    and exports the real configuration on the wayland socket.

 src/core/screen-private.h          |   34 +++-
 src/core/screen.c                  |  447 +++++++++++++++++++++---------------
 src/core/window-private.h          |    2 +-
 src/core/window.c                  |   27 ++-
 src/wayland/meta-wayland-private.h |   28 +--
 src/wayland/meta-wayland.c         |  120 +++++-----
 6 files changed, 376 insertions(+), 282 deletions(-)
---
diff --git a/src/core/screen-private.h b/src/core/screen-private.h
index 7e8a133..8ca1d1c 100644
--- a/src/core/screen-private.h
+++ b/src/core/screen-private.h
@@ -39,15 +39,32 @@
 #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;
-  XID output; /* The primary or first output for this crtc, None if no xrandr */
+  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;
 };
 
 typedef void (* MetaScreenWindowFunc) (MetaScreen *screen, MetaWindow *window,
@@ -100,10 +117,18 @@ struct _MetaScreen
   Window wm_sn_selection_window;
   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;
+  gboolean has_xinerama_indices;
 
   /* Cache the current monitor */
   int last_monitor_index;
@@ -259,4 +284,9 @@ void meta_screen_set_active_workspace_hint (MetaScreen *screen);
 
 Window   meta_screen_create_guard_window (Display *xdisplay, MetaScreen *screen);
 
+int meta_screen_xinerama_index_to_monitor_index (MetaScreen *screen,
+                                                 int         index);
+int meta_screen_monitor_index_to_xinerama_index (MetaScreen *screen,
+                                                 int         index);
+
 #endif
diff --git a/src/core/screen.c b/src/core/screen.c
index 073a8af..76da6cc 100644
--- a/src/core/screen.c
+++ b/src/core/screen.c
@@ -353,250 +353,317 @@ set_wm_icon_size_hint (MetaScreen *screen)
 #undef N_VALS
 }
 
-/* The list of monitors reported by the windowing system might include
- * mirrored monitors with identical bounds. Since mirrored monitors
- * shouldn't be treated as separate monitors for most purposes, we
- * filter them out here. (We ignore the possibility of partially
- * overlapping monitors because they are rare and it's hard to come
- * up with any sensible interpretation.)
+/*
+ * 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
-filter_mirrored_monitors (MetaScreen *screen)
+make_dummy_monitor_config (MetaScreen *screen)
 {
-  int i, j;
+  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)
+{
+  XineramaScreenInfo *infos;
+  int n_infos, i, j;
+
+  if (screen->has_xinerama_indices)
+    return;
 
-  /* Currently always true and simplifies things */
-  g_assert (screen->primary_monitor_index == 0);
+  screen->has_xinerama_indices = TRUE;
 
-  for (i = 1; i < screen->n_monitor_infos; i++)
+  if (!XineramaIsActive (screen->display->xdisplay))
+    return;
+
+  infos = XineramaQueryScreens (screen->display->xdisplay, &n_infos);
+  if (n_infos <= 0 || infos == NULL)
     {
-      /* In case we've filtered previous monitors */
-      screen->monitor_infos[i].number = i;
+      meta_XFree (infos);
+      return;
+    }
 
-      for (j = 0; j < i; j++)
+  for (i = 0; i < screen->n_monitor_infos; ++i)
+    {
+      for (j = 0; j < n_infos; ++j)
         {
-          if (meta_rectangle_equal (&screen->monitor_infos[i].rect,
-                                    &screen->monitor_infos[j].rect))
-            {
-              memmove (&screen->monitor_infos[i],
-                       &screen->monitor_infos[i + 1],
-                       (screen->n_monitor_infos - i - 1) * sizeof (MetaMonitorInfo));
-              screen->n_monitor_infos--;
-              i--;
-
-              continue;
-            }
+          if (screen->monitor_infos[i].rect.x == infos[j].x_org &&
+             screen->monitor_infos[i].rect.y == infos[j].y_org &&
+             screen->monitor_infos[i].rect.width == infos[j].width &&
+             screen->monitor_infos[i].rect.height == infos[j].height)
+            screen->monitor_infos[i].xinerama_index = j;
         }
     }
+
+  meta_XFree (infos);
 }
 
-#ifdef HAVE_RANDR
-static MetaMonitorInfo *
-find_monitor_with_rect (MetaScreen *screen, int x, int y, int w, int h)
+int
+meta_screen_monitor_index_to_xinerama_index (MetaScreen *screen,
+                                             int         index)
+{
+  meta_screen_ensure_xinerama_indices (screen);
+
+  return screen->monitor_infos[index].xinerama_index;
+}
+
+int
+meta_screen_xinerama_index_to_monitor_index (MetaScreen *screen,
+                                             int         index)
 {
-  MetaMonitorInfo *info;
   int i;
 
+  meta_screen_ensure_xinerama_indices (screen);
+
   for (i = 0; i < screen->n_monitor_infos; i++)
-    {
-      info = &screen->monitor_infos[i];
-      if (x == info->rect.x &&
-          y == info->rect.y &&
-          w == info->rect.width &&
-          h == info->rect.height)
-        return info;
-    }
-  return NULL;
+    if (screen->monitor_infos[i].xinerama_index == index)
+      return i;
+
+  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 XID
-find_main_output_for_crtc (MetaScreen *screen, XRRScreenResources *resources, XRRCrtcInfo *crtc)
+static void
+find_main_output_for_crtc (MetaScreen         *screen,
+                           XRRScreenResources *resources,
+                           XRRCrtcInfo        *crtc,
+                           MetaMonitorInfo    *info,
+                           GArray             *outputs)
 {
   XRROutputInfo *output;
   RROutput primary_output;
   int i;
-  XID res;
 
   primary_output = XRRGetOutputPrimary (screen->display->xdisplay, screen->xroot);
 
-  res = None;
   for (i = 0; i < crtc->noutput; i++)
     {
       output = XRRGetOutputInfo (screen->display->xdisplay, resources, crtc->outputs[i]);
-      if (output->connection != RR_Disconnected &&
-          (res == None || crtc->outputs[i] == primary_output))
-        res = 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);
     }
-
-  return res;
 }
 
-#endif
-
 static void
-reload_monitor_infos (MetaScreen *screen)
+read_monitor_infos_from_xrandr (MetaScreen *screen)
 {
-  MetaDisplay *display;
+    XRRScreenResources *resources;
+    GArray *outputs;
+    int i, j;
 
-  {
-    GList *tmp;
+    resources = XRRGetScreenResourcesCurrent (screen->display->xdisplay, screen->xroot);
+    if (!resources)
+      return make_dummy_monitor_config (screen);
 
-    tmp = screen->workspaces;
-    while (tmp != NULL)
+    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++)
       {
-        MetaWorkspace *space = tmp->data;
+        XRRCrtcInfo *crtc;
+        MetaMonitorInfo *info;
 
-        meta_workspace_invalidate_work_area (space);
-        
-        tmp = tmp->next;
+        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);
       }
-  }
 
-  display = screen->display;
+    screen->n_outputs = outputs->len;
+    screen->outputs = (void*)g_array_free (outputs, FALSE);
 
-  /* Any previous screen->monitor_infos is freed by the caller */
+    XRRFreeScreenResources (resources);
+}
 
-  screen->monitor_infos = NULL;
-  screen->n_monitor_infos = 0;
-  screen->last_monitor_index = 0;
+#endif
 
-  /* Xinerama doesn't have a concept of primary monitor, however XRandR
-   * does. However, the XRandR xinerama compat code always sorts the
-   * primary output first, so we rely on that here. We could use the
-   * native XRandR calls instead of xinerama, but that would be
-   * slightly problematic for _NET_WM_FULLSCREEN_MONITORS support, as
-   * that is defined in terms of xinerama monitor indexes.
-   * So, since we don't need anything in xrandr except the primary
-   * we can keep using xinerama and use the first monitor as the
-   * primary.
-   */
-  screen->primary_monitor_index = 0;
+typedef struct {
+  GArray *monitor_infos;
+  GArray *outputs;
+} ReadMonitorCoglClosure;
 
-  screen->display->monitor_cache_invalidated = TRUE;
+static void
+read_monitor_from_cogl_helper (CoglOutput *output,
+                               void       *user_data)
+{
+  ReadMonitorCoglClosure *closure = user_data;
+  MetaMonitorInfo info;
+  MetaOutput meta_output;
 
-  if (g_getenv ("MUTTER_DEBUG_XINERAMA"))
-    {
-      meta_topic (META_DEBUG_XINERAMA,
-                  "Pretending a single monitor has two Xinerama screens\n");
+  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 */
 
-      screen->monitor_infos = g_new0 (MetaMonitorInfo, 2);
-      screen->n_monitor_infos = 2;
+  g_array_append_val (closure->monitor_infos, info);
 
-      screen->monitor_infos[0].number = 0;
-      screen->monitor_infos[0].rect = screen->rect;
-      screen->monitor_infos[0].rect.width = screen->rect.width / 2;
-      screen->monitor_infos[0].in_fullscreen = -1;
+  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);
 
-      screen->monitor_infos[1].number = 1;
-      screen->monitor_infos[1].rect = screen->rect;
-      screen->monitor_infos[1].rect.x = screen->rect.width / 2;
-      screen->monitor_infos[1].rect.width = screen->rect.width / 2;
-      screen->monitor_infos[0].in_fullscreen = -1;
-    }
+  g_array_append_val (closure->outputs, meta_output);
+}
 
-  if (screen->n_monitor_infos == 0 &&
-      XineramaIsActive (display->xdisplay))
-    {
-      XineramaScreenInfo *infos;
-      int n_infos;
-      int i;
-      
-      n_infos = 0;
-      infos = XineramaQueryScreens (display->xdisplay, &n_infos);
+static void
+read_monitor_infos_from_cogl (MetaScreen *screen)
+{
+  ReadMonitorCoglClosure closure;
+  ClutterBackend *backend;
+  CoglContext *cogl_context;
+  CoglRenderer *cogl_renderer;
 
-      meta_topic (META_DEBUG_XINERAMA,
-                  "Found %d Xinerama screens on display %s\n",
-                  n_infos, display->name);
+  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));
 
-      if (n_infos > 0)
-        {
-          screen->monitor_infos = g_new0 (MetaMonitorInfo, n_infos);
-          screen->n_monitor_infos = n_infos;
-          
-          i = 0;
-          while (i < n_infos)
-            {
-              screen->monitor_infos[i].number = infos[i].screen_number;
-              screen->monitor_infos[i].rect.x = infos[i].x_org;
-              screen->monitor_infos[i].rect.y = infos[i].y_org;
-              screen->monitor_infos[i].rect.width = infos[i].width;
-              screen->monitor_infos[i].rect.height = infos[i].height;
-              screen->monitor_infos[i].in_fullscreen = -1;
-
-              meta_topic (META_DEBUG_XINERAMA,
-                          "Monitor %d is %d,%d %d x %d\n",
-                          screen->monitor_infos[i].number,
-                          screen->monitor_infos[i].rect.x,
-                          screen->monitor_infos[i].rect.y,
-                          screen->monitor_infos[i].rect.width,
-                          screen->monitor_infos[i].rect.height);
-              
-              ++i;
-            }
-        }
-      
-      meta_XFree (infos);
+  closure.monitor_infos = g_array_new (FALSE, TRUE, sizeof (MetaMonitorInfo));
+  closure.outputs = g_array_new (FALSE, TRUE, sizeof (MetaOutput));
 
-#ifdef HAVE_RANDR
-      {
-        XRRScreenResources *resources;
+  cogl_renderer_foreach_output (cogl_renderer,
+                                read_monitor_from_cogl_helper, &closure);
 
-        resources = XRRGetScreenResourcesCurrent (display->xdisplay, screen->xroot);
-        if (resources)
-          {
-            for (i = 0; i < resources->ncrtc; i++)
-              {
-                XRRCrtcInfo *crtc;
-                MetaMonitorInfo *info;
-
-                crtc = XRRGetCrtcInfo (display->xdisplay, resources, resources->crtcs[i]);
-                info = find_monitor_with_rect (screen, crtc->x, crtc->y, (int)crtc->width, 
(int)crtc->height);
-                if (info)
-                  info->output = find_main_output_for_crtc (screen, resources, crtc);
-
-                XRRFreeCrtcInfo (crtc);
-              }
-            XRRFreeScreenResources (resources);
-          }
-      }
-#endif
-    }
-  else if (screen->n_monitor_infos > 0)
-    {
-      meta_topic (META_DEBUG_XINERAMA,
-                  "No Xinerama extension or Xinerama inactive on display %s\n",
-                  display->name);
-    }
+  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);
 
-  /* If no Xinerama, fill in the single screen info so
-   * we can use the field unconditionally
-   */
-  if (screen->n_monitor_infos == 0)
+  screen->primary_monitor_index = 0;
+}
+
+static void
+reload_monitor_infos (MetaScreen *screen)
+{
+  GList *tmp;
+
+  tmp = screen->workspaces;
+  while (tmp != NULL)
     {
-      meta_topic (META_DEBUG_XINERAMA,
-                  "No Xinerama screens, using default screen info\n");
-          
-      screen->monitor_infos = g_new0 (MetaMonitorInfo, 1);
-      screen->n_monitor_infos = 1;
-          
-      screen->monitor_infos[0].number = 0;
-      screen->monitor_infos[0].rect = screen->rect;
-      screen->monitor_infos[0].in_fullscreen = -1;
+      MetaWorkspace *space = tmp->data;
+
+      meta_workspace_invalidate_work_area (space);
+      
+      tmp = tmp->next;
     }
 
-  filter_mirrored_monitors (screen);
+  /* Any previous screen->monitor_infos or screen->outputs is freed by the caller */
 
-  screen->monitor_infos[screen->primary_monitor_index].is_primary = TRUE;
+  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;
 
-  g_assert (screen->n_monitor_infos > 0);
-  g_assert (screen->monitor_infos != NULL);
+  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
+
+  return read_monitor_infos_from_cogl (screen);
 }
 
 /* The guard window allows us to leave minimized windows mapped so
@@ -675,7 +742,7 @@ meta_screen_new (MetaDisplay *display,
   guint32 manager_timestamp;
   gulong current_workspace;
 #ifdef HAVE_WAYLAND
-  MetaWaylandCompositor *compositor;
+  MetaWaylandCompositor *compositor = NULL;
 #endif
   
   replace_current_wm = meta_get_replace_current_wm ();
@@ -874,10 +941,6 @@ meta_screen_new (MetaDisplay *display,
   screen->compositor_data = NULL;
   screen->guard_window = None;
 
-  screen->monitor_infos = NULL;
-  screen->n_monitor_infos = 0;
-  screen->last_monitor_index = 0;  
-  
   reload_monitor_infos (screen);
   
   meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
@@ -963,7 +1026,13 @@ 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;
 }
 
@@ -3028,12 +3097,16 @@ meta_screen_resize (MetaScreen *screen,
                     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;
 
   reload_monitor_infos (screen);
@@ -3079,6 +3152,10 @@ meta_screen_resize (MetaScreen *screen,
   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/core/window-private.h b/src/core/window-private.h
index 4827e58..0e3f104 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -181,7 +181,7 @@ struct _MetaWindow
    * been overridden (via a client message), the window will cover the union of
    * these monitors.  If not, this is the single monitor which the window's
    * origin is on. */
-  long fullscreen_monitors[4];
+  gint fullscreen_monitors[4];
   
   /* Whether we're trying to constrain the window to be fully onscreen */
   guint require_fully_onscreen : 1;
diff --git a/src/core/window.c b/src/core/window.c
index efb4f74..e065989 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -2289,10 +2289,14 @@ set_net_wm_state (MetaWindow *window)
 
   if (window->fullscreen)
     {
-      data[0] = window->fullscreen_monitors[0];
-      data[1] = window->fullscreen_monitors[1];
-      data[2] = window->fullscreen_monitors[2];
-      data[3] = window->fullscreen_monitors[3];
+      data[0] = meta_screen_monitor_index_to_xinerama_index (window->screen,
+                                                             window->fullscreen_monitors[0]);
+      data[1] = meta_screen_monitor_index_to_xinerama_index (window->screen,
+                                                             window->fullscreen_monitors[1]);
+      data[2] = meta_screen_monitor_index_to_xinerama_index (window->screen,
+                                                             window->fullscreen_monitors[2]);
+      data[3] = meta_screen_monitor_index_to_xinerama_index (window->screen,
+                                                             window->fullscreen_monitors[3]);
 
       meta_verbose ("Setting _NET_WM_FULLSCREEN_MONITORS\n");
       meta_error_trap_push (window->display);
@@ -4966,7 +4970,8 @@ meta_window_update_for_monitors_changed (MetaWindow *window)
     {
       MetaMonitorInfo *info = &window->screen->monitor_infos[i];
 
-      if (info->output == old->output)
+      if (info->output_id != 0 &&
+          info->output_id == old->output_id)
         {
           new = info;
           break;
@@ -7300,10 +7305,14 @@ meta_window_client_message (MetaWindow *window,
       meta_verbose ("_NET_WM_FULLSCREEN_MONITORS request for window '%s'\n",
                     window->desc);
 
-      top = event->xclient.data.l[0];
-      bottom = event->xclient.data.l[1];
-      left = event->xclient.data.l[2];
-      right = event->xclient.data.l[3];
+      top = meta_screen_xinerama_index_to_monitor_index (window->screen,
+                                                         event->xclient.data.l[0]);
+      bottom = meta_screen_xinerama_index_to_monitor_index (window->screen,
+                                                            event->xclient.data.l[1]);
+      left = meta_screen_xinerama_index_to_monitor_index (window->screen,
+                                                          event->xclient.data.l[2]);
+      right = meta_screen_xinerama_index_to_monitor_index (window->screen,
+                                                           event->xclient.data.l[3]);
       /* source_indication = event->xclient.data.l[4]; */
 
       meta_window_update_fullscreen_monitors (window, top, bottom, left, right);
diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h
index 1d5b884..675450a 100644
--- a/src/wayland/meta-wayland-private.h
+++ b/src/wayland/meta-wayland-private.h
@@ -112,26 +112,6 @@ typedef struct
 
 typedef struct
 {
-  guint32 flags;
-  int width;
-  int height;
-  int refresh;
-} MetaWaylandMode;
-
-typedef struct
-{
-  struct wl_object wayland_output;
-  int x;
-  int y;
-  int width_mm;
-  int height_mm;
-  /* XXX: with sliced stages we'd reference a CoglFramebuffer here. */
-
-  GList *modes;
-} MetaWaylandOutput;
-
-typedef struct
-{
   GSource source;
   GPollFD pfd;
   struct wl_display *display;
@@ -149,11 +129,13 @@ typedef struct
 
 struct _MetaWaylandCompositor
 {
+  MetaScreen *screen;
+  GList *outputs;
+
   struct wl_display *wayland_display;
   struct wl_event_loop *wayland_loop;
   GMainLoop *init_loop;
   ClutterActor *stage;
-  GList *outputs;
   GSource *wayland_event_source;
   GList *surfaces;
   struct wl_list frame_callbacks;
@@ -356,12 +338,16 @@ 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,
                                                                  MetaWindow            *window);
 
 MetaTTY                *meta_wayland_compositor_get_tty         (MetaWaylandCompositor *compositor);
+gboolean                meta_wayland_compositor_is_native       (MetaWaylandCompositor *compositor);
 
 void                    meta_wayland_surface_free               (MetaWaylandSurface    *surface);
 
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index 9e0cdee..b5eca2c 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -635,78 +635,46 @@ bind_output (struct wl_client *client,
              guint32 version,
              guint32 id)
 {
-  MetaWaylandOutput *output = data;
-  struct wl_resource *resource =
-    wl_resource_create (client, &wl_output_interface, version, id);
-  GList *l;
+  MetaOutput *output = data;
+  struct wl_resource *resource;
+
+  resource = wl_resource_create (client, &wl_output_interface, version, id);
 
   wl_resource_post_event (resource,
                           WL_OUTPUT_GEOMETRY,
-                          output->x, output->y,
-                          output->width_mm,
+                          (int)output->monitor->rect.x,
+                         (int)output->monitor->rect.y,
+                         output->width_mm,
                           output->height_mm,
-                          0, /* subpixel: unknown */
+                         /* Cogl values reflect XRandR values,
+                            and so does wayland */
+                         output->subpixel_order,
                           "unknown", /* make */
-                          "unknown"); /* model */
+                          "unknown", /* model */
+                         WL_OUTPUT_TRANSFORM_NORMAL);
 
-  for (l = output->modes; l; l = l->next)
-    {
-      MetaWaylandMode *mode = l->data;
-      wl_resource_post_event (resource,
-                              WL_OUTPUT_MODE,
-                              mode->flags,
-                              mode->width,
-                              mode->height,
-                              mode->refresh);
-    }
+  wl_resource_post_event (resource,
+                         WL_OUTPUT_MODE,
+                         WL_OUTPUT_MODE_PREFERRED | WL_OUTPUT_MODE_CURRENT,
+                         (int)output->monitor->rect.width,
+                         (int)output->monitor->rect.height,
+                         (int)output->monitor->refresh_rate);
+
+  wl_resource_post_event (resource,
+                         WL_OUTPUT_DONE);
 }
 
 static void
-meta_wayland_compositor_create_output (MetaWaylandCompositor *compositor,
-                                       int x,
-                                       int y,
-                                       int width,
-                                       int height,
-                                       int width_mm,
-                                       int height_mm)
-{
-  MetaWaylandOutput *output = g_slice_new0 (MetaWaylandOutput);
-  MetaWaylandMode *mode;
-  float final_width, final_height;
-
-  /* XXX: eventually we will support sliced stages and an output should
-   * correspond to a slice/CoglFramebuffer, but for now we only support
-   * one output so we make sure it always matches the size of the stage
-   */
-  clutter_actor_set_size (compositor->stage, width, height);
-
-  /* Read back the actual size we were given.
-   * XXX: This really needs re-thinking later though so we know the
-   * correct output geometry to use. */
-  clutter_actor_get_size (compositor->stage, &final_width, &final_height);
-  width = final_width;
-  height = final_height;
-
-  output->wayland_output.interface = &wl_output_interface;
-
-  output->x = x;
-  output->y = y;
-  output->width_mm = width_mm;
-  output->height_mm = height_mm;
-
-  wl_global_create (compositor->wayland_display,
-                   &wl_output_interface, 2,
-                   output, bind_output);
-
-  mode = g_slice_new0 (MetaWaylandMode);
-  mode->flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
-  mode->width = width;
-  mode->height = height;
-  mode->refresh = 60;
-
-  output->modes = g_list_prepend (output->modes, mode);
+meta_wayland_compositor_create_outputs (MetaWaylandCompositor *compositor)
+{
+  MetaScreen *screen = compositor->screen;
+  int i;
 
-  compositor->outputs = g_list_prepend (compositor->outputs, output);
+  for (i = 0; i < screen->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));
 }
 
 const static struct wl_compositor_interface meta_wayland_compositor_interface = {
@@ -1587,8 +1555,6 @@ meta_wayland_init (void)
                               compositor, /* hook_data */
                               NULL /* data_destroy */);
 
-  meta_wayland_compositor_create_output (compositor, 0, 0, 1024, 600, 222, 125);
-
   if (wl_global_create (compositor->wayland_display,
                        &wl_shell_interface, 1,
                        compositor, bind_shell) == NULL)
@@ -1631,3 +1597,29 @@ meta_wayland_compositor_get_tty (MetaWaylandCompositor *compositor)
 {
   return compositor->tty;
 }
+
+gboolean
+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]