[mutter/wip/wayland-kms: 696/697] Integrate the monitor manager with wayland



commit 43e1b004866ce682a10da114c8e9431f09088c43
Author: Giovanni Campagna <gcampagn redhat com>
Date:   Mon Aug 19 11:12:42 2013 +0200

    Integrate the monitor manager with wayland
    
    Use the right backend when running as a wayland compositor,
    export the data to wayland clients, and use it to keep the stage
    appropriately sized.

 src/compositor/compositor.c        |   32 ++++--
 src/core/monitor.c                 |   11 ++-
 src/core/screen.c                  |    5 +-
 src/wayland/meta-wayland-private.h |   22 +----
 src/wayland/meta-wayland-stage.c   |    1 +
 src/wayland/meta-wayland.c         |  228 +++++++++++++++++++++++++++---------
 6 files changed, 208 insertions(+), 91 deletions(-)
---
diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
index 3240fc0..7991ce1 100644
--- a/src/compositor/compositor.c
+++ b/src/compositor/compositor.c
@@ -733,6 +733,9 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
     {
       wayland_compositor = meta_wayland_compositor_get_default ();
       info->stage = wayland_compositor->stage;
+
+      meta_screen_get_size (screen, &width, &height);
+      clutter_actor_set_size (info->stage, width, height);
     }
   else
     {
@@ -1481,18 +1484,25 @@ meta_compositor_sync_screen_size (MetaCompositor  *compositor,
                                  guint            width,
                                  guint            height)
 {
+  MetaDisplay    *display = meta_screen_get_display (screen);
+  MetaCompScreen *info    = meta_screen_get_compositor_data (screen);
+
   if (meta_is_wayland_compositor ())
     {
-      /* It's not clear at the moment how we will be dealing with screen
-       * resizing as a Wayland compositor so for now just abort if we
-       * hit this code. */
-      g_critical ("Unexpected call to meta_compositor_sync_screen_size() "
-                  "when running as a wayland compositor");
+      /* FIXME: when we support a sliced stage, this is the place to do it
+         But! This is not the place to apply KMS config, here we only
+         notify Clutter/Cogl/GL that the framebuffer sizes changed.
+
+         And because for now clutter does not do sliced, we use one
+         framebuffer the size of the whole screen, and when running on
+         bare metal MetaMonitorManager will do the necessary tricks to
+         show the right portions on the right screens.
+      */
+
+      clutter_actor_set_size (info->stage, width, height);
     }
   else
     {
-      MetaDisplay    *display = meta_screen_get_display (screen);
-      MetaCompScreen *info    = meta_screen_get_compositor_data (screen);
       Display        *xdisplay;
       Window          xwin;
 
@@ -1503,11 +1513,11 @@ meta_compositor_sync_screen_size (MetaCompositor  *compositor,
       xwin = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
 
       XResizeWindow (xdisplay, xwin, width, height);
-
-      meta_verbose ("Changed size for stage on screen %d to %dx%d\n",
-                    meta_screen_get_screen_number (screen),
-                    width, height);
     }
+
+  meta_verbose ("Changed size for stage on screen %d to %dx%d\n",
+                meta_screen_get_screen_number (screen),
+                width, height);
 }
 
 static void
diff --git a/src/core/monitor.c b/src/core/monitor.c
index d81ff15..3542b1f 100644
--- a/src/core/monitor.c
+++ b/src/core/monitor.c
@@ -475,6 +475,15 @@ make_logical_config (MetaMonitorManager *manager)
   manager->monitor_infos = (void*)g_array_free (monitor_infos, FALSE);
 }
 
+static GType
+get_default_backend (void)
+{
+  if (meta_is_wayland_compositor ())
+    return META_TYPE_MONITOR_MANAGER; /* FIXME: KMS */
+  else
+    return META_TYPE_MONITOR_MANAGER_XRANDR;
+}
+
 static MetaMonitorManager *
 meta_monitor_manager_new (void)
 {
@@ -484,7 +493,7 @@ meta_monitor_manager_new (void)
   env = g_getenv ("META_DEBUG_MULTIMONITOR");
 
   if (env == NULL)
-    type = META_TYPE_MONITOR_MANAGER_XRANDR;
+    type = get_default_backend ();
   else if (strcmp (env, "xrandr") == 0)
     type = META_TYPE_MONITOR_MANAGER_XRANDR;
   else
diff --git a/src/core/screen.c b/src/core/screen.c
index b8870da..ee91329 100644
--- a/src/core/screen.c
+++ b/src/core/screen.c
@@ -675,8 +675,9 @@ meta_screen_new (MetaDisplay *display,
   screen->xscreen = ScreenOfDisplay (xdisplay, number);
   screen->xroot = xroot;
   screen->rect.x = screen->rect.y = 0;
-  
-  meta_monitor_manager_initialize ();
+
+  if (!meta_is_wayland_compositor ())
+    meta_monitor_manager_initialize ();
 
   manager = meta_monitor_manager_get ();
   g_signal_connect (manager, "monitors-changed",
diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h
index f23d933..1dad985 100644
--- a/src/wayland/meta-wayland-private.h
+++ b/src/wayland/meta-wayland-private.h
@@ -113,26 +113,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;
@@ -154,7 +134,7 @@ struct _MetaWaylandCompositor
   struct wl_event_loop *wayland_loop;
   GMainLoop *init_loop;
   ClutterActor *stage;
-  GList *outputs;
+  GHashTable *outputs;
   GSource *wayland_event_source;
   GList *surfaces;
   struct wl_list frame_callbacks;
diff --git a/src/wayland/meta-wayland-stage.c b/src/wayland/meta-wayland-stage.c
index f7d28d4..48fe8e7 100644
--- a/src/wayland/meta-wayland-stage.c
+++ b/src/wayland/meta-wayland-stage.c
@@ -55,6 +55,7 @@ meta_wayland_stage_class_init (MetaWaylandStageClass *klass)
 static void
 meta_wayland_stage_init (MetaWaylandStage *self)
 {
+  clutter_stage_set_user_resizable (CLUTTER_STAGE (self), FALSE);
 }
 
 ClutterActor *
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index bb25697..ecbfd4d 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -53,6 +53,7 @@
 #include <meta/main.h>
 #include "frame.h"
 #include "meta-weston-launch.h"
+#include "monitor-private.h"
 
 static MetaWaylandCompositor _meta_wayland_compositor;
 
@@ -642,84 +643,186 @@ meta_wayland_compositor_create_region (struct wl_client *wayland_client,
   region->region = cairo_region_create ();
 }
 
+typedef struct {
+  MetaOutput               *output;
+  struct wl_global         *global;
+  int                       x, y;
+  enum wl_output_transform  transform;
+
+  GList                    *resources;
+} MetaWaylandOutput;
+
+static void
+output_resource_destroy (struct wl_resource *res)
+{
+  MetaWaylandOutput *wayland_output;
+
+  wayland_output = wl_resource_get_user_data (res);
+  wayland_output->resources = g_list_remove (wayland_output->resources, res);
+}
+
 static void
 bind_output (struct wl_client *client,
              void *data,
              guint32 version,
              guint32 id)
 {
-  MetaWaylandOutput *output = data;
-  struct wl_resource *resource =
-    wl_resource_create (client, &wl_output_interface, version, id);
-  GList *l;
+  MetaWaylandOutput *wayland_output = data;
+  MetaOutput *output = wayland_output->output;
+  struct wl_resource *resource;
+  guint mode_flags;
+
+  resource = wl_resource_create (client, &wl_output_interface, version, id);
+  wayland_output->resources = g_list_prepend (wayland_output->resources, resource);
+
+  wl_resource_set_user_data (resource, wayland_output);
+  wl_resource_set_destructor (resource, output_resource_destroy);
+
+  meta_verbose ("Binding output %p/%s (%u, %u, %u, %u) x %f\n",
+                output, output->name,
+                output->crtc->rect.x, output->crtc->rect.y,
+                output->crtc->rect.width, output->crtc->rect.height,
+                output->crtc->current_mode->refresh_rate);
 
   wl_resource_post_event (resource,
                           WL_OUTPUT_GEOMETRY,
-                          output->x, output->y,
+                          (int)output->crtc->rect.x,
+                          (int)output->crtc->rect.y,
                           output->width_mm,
                           output->height_mm,
-                          0, /* subpixel: unknown */
-                          "unknown", /* make */
-                          "unknown"); /* model */
+                          /* Cogl values reflect XRandR values,
+                             and so does wayland */
+                          output->subpixel_order,
+                          output->vendor,
+                          output->product,
+                          output->crtc->transform);
+
+  g_assert (output->crtc->current_mode != NULL);
+
+  mode_flags = WL_OUTPUT_MODE_CURRENT;
+  if (output->crtc->current_mode == output->preferred_mode)
+    mode_flags |= WL_OUTPUT_MODE_PREFERRED;
+
+  wl_resource_post_event (resource,
+                          WL_OUTPUT_MODE,
+                          mode_flags,
+                          (int)output->crtc->current_mode->width,
+                          (int)output->crtc->current_mode->height,
+                          (int)output->crtc->current_mode->refresh_rate);
+
+  if (version >= 2)
+    wl_resource_post_event (resource,
+                            WL_OUTPUT_DONE);
+}
+
+static void
+wayland_output_destroy_notify (gpointer data)
+{
+  MetaWaylandOutput *wayland_output = data;
+  GList *resources;
+
+  /* Make sure the destructors don't mess with the list */
+  resources = wayland_output->resources;
+  wayland_output->resources = NULL;
+
+  wl_global_destroy (wayland_output->global);
+  g_list_free (resources);
+
+  g_slice_free (MetaWaylandOutput, wayland_output);
+}
+
+static void
+wayland_output_update_for_output (MetaWaylandOutput *wayland_output,
+                                  MetaOutput        *output)
+{
+  GList *iter;
+  guint mode_flags;
 
-  for (l = output->modes; l; l = l->next)
+  g_assert (output->crtc->current_mode != NULL);
+
+  mode_flags = WL_OUTPUT_MODE_CURRENT;
+  if (output->crtc->current_mode == output->preferred_mode)
+    mode_flags |= WL_OUTPUT_MODE_PREFERRED;
+
+  for (iter = wayland_output->resources; iter; iter = iter->next)
     {
-      MetaWaylandMode *mode = l->data;
+      struct wl_resource *resource = iter->data;
+
+      if (wayland_output->x != output->crtc->rect.x ||
+          wayland_output->y != output->crtc->rect.y ||
+          wayland_output->transform != output->crtc->transform)
+        {
+            wl_resource_post_event (resource,
+                                    WL_OUTPUT_GEOMETRY,
+                                    (int)output->crtc->rect.x,
+                                    (int)output->crtc->rect.y,
+                                    output->width_mm,
+                                    output->height_mm,
+                                    output->subpixel_order,
+                                    output->vendor,
+                                    output->product,
+                                    output->crtc->transform);
+        }
+
       wl_resource_post_event (resource,
                               WL_OUTPUT_MODE,
-                              mode->flags,
-                              mode->width,
-                              mode->height,
-                              mode->refresh);
+                              mode_flags,
+                              (int)output->crtc->current_mode->width,
+                              (int)output->crtc->current_mode->height,
+                              (int)output->crtc->current_mode->refresh_rate);
     }
+
+  /* It's very important that we change the output pointer here, as
+     the old structure is about to be freed by MetaMonitorManager */
+  wayland_output->output = output;
+  wayland_output->x = output->crtc->rect.x;
+  wayland_output->y = output->crtc->rect.y;
+  wayland_output->transform = output->crtc->transform;
 }
 
-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);
+static GHashTable *
+meta_wayland_compositor_update_outputs (MetaWaylandCompositor *compositor,
+                                        MetaMonitorManager    *monitors)
+{
+  MetaOutput *outputs;
+  unsigned int i, n_outputs;
+  GHashTable *new_table;
 
-  /* 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;
+  outputs = meta_monitor_manager_get_outputs (monitors, &n_outputs);
+  new_table = g_hash_table_new_full (NULL, NULL, NULL, wayland_output_destroy_notify);
 
-  output->wayland_output.interface = &wl_output_interface;
+  for (i = 0; i < n_outputs; i++)
+    {
+      MetaOutput *output = &outputs[i];
+      MetaWaylandOutput *wayland_output;
 
-  output->x = x;
-  output->y = y;
-  output->width_mm = width_mm;
-  output->height_mm = height_mm;
+      /* wayland does not expose disabled outputs */
+      if (output->crtc == NULL)
+        {
+          g_hash_table_remove (compositor->outputs, GSIZE_TO_POINTER (output->output_id));
+          continue;
+        }
 
-  wl_global_create (compositor->wayland_display,
-                   &wl_output_interface, 2,
-                   output, bind_output);
+      wayland_output = g_hash_table_lookup (compositor->outputs, GSIZE_TO_POINTER (output->output_id));
 
-  mode = g_slice_new0 (MetaWaylandMode);
-  mode->flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
-  mode->width = width;
-  mode->height = height;
-  mode->refresh = 60;
+      if (wayland_output)
+        {
+          g_hash_table_steal (compositor->outputs, GSIZE_TO_POINTER (output->output_id));
+        }
+      else
+        {
+          wayland_output = g_slice_new0 (MetaWaylandOutput);
+          wayland_output->global = wl_global_create (compositor->wayland_display,
+                                                     &wl_output_interface, 2,
+                                                     wayland_output, bind_output);
+        }
 
-  output->modes = g_list_prepend (output->modes, mode);
+      wayland_output_update_for_output (wayland_output, output);
+      g_hash_table_insert (new_table, GSIZE_TO_POINTER (output->output_id), wayland_output);
+    }
 
-  compositor->outputs = g_list_prepend (compositor->outputs, output);
+  g_hash_table_destroy (compositor->outputs);
+  return new_table;
 }
 
 const static struct wl_compositor_interface meta_wayland_compositor_interface = {
@@ -1458,6 +1561,13 @@ on_evdev_device_open (const char  *path,
                                               path, flags, error);
 }
 
+static void
+on_monitors_changed (MetaMonitorManager    *monitors,
+                     MetaWaylandCompositor *compositor)
+{
+  compositor->outputs = meta_wayland_compositor_update_outputs (compositor, monitors);
+}
+
 void
 meta_wayland_init (void)
 {
@@ -1467,6 +1577,7 @@ meta_wayland_init (void)
   CoglContext *cogl_context;
   CoglRenderer *cogl_renderer;
   int weston_launch_fd;
+  MetaMonitorManager *monitors;
 
   memset (compositor, 0, sizeof (MetaWaylandCompositor));
 
@@ -1563,8 +1674,15 @@ meta_wayland_init (void)
       dup2 (fd, STDIN_FILENO);
     }
 
+  meta_monitor_manager_initialize ();
+  monitors = meta_monitor_manager_get ();
+  g_signal_connect (monitors, "monitors-changed",
+                    G_CALLBACK (on_monitors_changed), compositor);
+
+  compositor->outputs = g_hash_table_new_full (NULL, NULL, NULL, wayland_output_destroy_notify);
+  compositor->outputs = meta_wayland_compositor_update_outputs (compositor, monitors);
+
   compositor->stage = meta_wayland_stage_new ();
-  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",
@@ -1590,8 +1708,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)


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