[mutter/wip/wayland-display] MetaWayland: don't destroy the output list, emit the right events instead



commit 609e1978a4abab8ea1d166a37e915f31dd058bf8
Author: Giovanni Campagna <gcampagn redhat com>
Date:   Fri Jul 26 16:19:44 2013 +0200

    MetaWayland: don't destroy the output list, emit the right events instead
    
    Destroying the output list causes toolkits to believe that all
    monitors were unplugged, which then causes assertions in code
    that have outside knowledge of this not having happened (like
    in code using GnomeRR DBus API).

 src/wayland/meta-wayland-private.h |    2 +-
 src/wayland/meta-wayland.c         |  117 +++++++++++++++++++++++++++++++-----
 2 files changed, 102 insertions(+), 17 deletions(-)
---
diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h
index 2ee1fe7..15bcd0b 100644
--- a/src/wayland/meta-wayland-private.h
+++ b/src/wayland/meta-wayland-private.h
@@ -129,7 +129,7 @@ typedef struct
 
 struct _MetaWaylandCompositor
 {
-  GList *outputs;
+  GHashTable *outputs;
 
   struct wl_display *wayland_display;
   struct wl_event_loop *wayland_loop;
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index b13bdee..591ae6d 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -602,16 +602,28 @@ 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
 bind_output (struct wl_client *client,
              void *data,
              guint32 version,
              guint32 id)
 {
-  MetaOutput *output = data;
+  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);
 
   meta_verbose ("Binding output %p/%s (%u, %u, %u, %u) x %f\n",
                output, output->name,
@@ -632,9 +644,13 @@ bind_output (struct wl_client *client,
                          output->product,
                          output->crtc->transform);
 
+  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,
-                         WL_OUTPUT_MODE_PREFERRED | WL_OUTPUT_MODE_CURRENT,
+                         mode_flags,
                          (int)output->crtc->rect.width,
                          (int)output->crtc->rect.height,
                          (int)output->crtc->current_mode->refresh_rate);
@@ -645,35 +661,104 @@ bind_output (struct wl_client *client,
 }
 
 static void
-meta_wayland_compositor_create_outputs (MetaWaylandCompositor *compositor,
+wayland_output_destroy_notify (gpointer data)
+{
+  MetaWaylandOutput *wayland_output = data;
+
+  wl_global_destroy (wayland_output->global);
+  g_slice_free (MetaWaylandOutput, wayland_output);
+}
+
+static void
+wayland_output_update_for_output (MetaWaylandOutput *wayland_output,
+                                 MetaOutput        *output)
+{
+  GList *iter;
+  guint mode_flags;
+
+  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)
+    {
+      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,
+                             (int)output->crtc->rect.width,
+                             (int)output->crtc->rect.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 GHashTable *
+meta_wayland_compositor_update_outputs (MetaWaylandCompositor *compositor,
                                        MetaMonitorManager    *monitors)
 {
   MetaOutput *outputs;
   unsigned int i, n_outputs;
+  GHashTable *new_table;
 
   outputs = meta_monitor_manager_get_outputs (monitors, &n_outputs);
+  new_table = g_hash_table_new_full (NULL, NULL, NULL, wayland_output_destroy_notify);
 
   for (i = 0; i < n_outputs; i++)
     {
       MetaOutput *output = &outputs[i];
-      struct wl_global *global;
+      MetaWaylandOutput *wayland_output;
 
       /* wayland does not expose disabled outputs */
       if (output->crtc == NULL)
-       continue;
+       {
+         g_hash_table_remove (compositor->outputs, GSIZE_TO_POINTER (output->output_id));
+         continue;
+       }
+
+      wayland_output = g_hash_table_lookup (compositor->outputs, GSIZE_TO_POINTER (output->output_id));
 
-      if (compositor->outputs != NULL)
+      if (wayland_output)
+       {
+         g_hash_table_steal (compositor->outputs, GSIZE_TO_POINTER (output->output_id));
+       }
+      else
        {
-         /* FIXME! Intel xwayland crashes with multimonitor */
-         break;
+         wayland_output = g_slice_new0 (MetaWaylandOutput);
+         wayland_output->global = wl_global_create (compositor->wayland_display,
+                                                    &wl_output_interface, 2,
+                                                    wayland_output, bind_output);
        }
 
-      global = wl_global_create (compositor->wayland_display,
-                                &wl_output_interface, 2,
-                                output, bind_output);
-      compositor->outputs = g_list_prepend (compositor->outputs, global);
+      wayland_output_update_for_output (wayland_output, output);
+      g_hash_table_insert (new_table, GSIZE_TO_POINTER (output->output_id), wayland_output);
     }
 
+  g_hash_table_destroy (compositor->outputs);
+  return new_table;
 }
 
 const static struct wl_compositor_interface meta_wayland_compositor_interface = {
@@ -1942,9 +2027,7 @@ static void
 on_monitors_changed (MetaMonitorManager    *monitors,
                     MetaWaylandCompositor *compositor)
 {
-  g_list_free_full (compositor->outputs, (GDestroyNotify) wl_global_destroy);
-  compositor->outputs = NULL;
-  meta_wayland_compositor_create_outputs (compositor, monitors);
+  compositor->outputs = meta_wayland_compositor_update_outputs (compositor, monitors);
 }
 
 void
@@ -2037,7 +2120,9 @@ meta_wayland_init (void)
   monitors = meta_monitor_manager_get ();
   g_signal_connect (monitors, "monitors-changed",
                    G_CALLBACK (on_monitors_changed), compositor);
-  meta_wayland_compositor_create_outputs (compositor, monitors);
+
+  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 ();
 


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