[mutter] wayland/surface: Send enter event when a client binds to wl_output late



commit 696b5345704cb4ee6394637ed76d2373fa9f8530
Author: Jonas Dreßler <verdre v0yd nl>
Date:   Mon Mar 9 12:33:17 2020 +0100

    wayland/surface: Send enter event when a client binds to wl_output late
    
    When hotplugging a new monitor, we recreate all the MetaWaylandOutputs
    and need to emit leave events to the surfaces for the old wl_outputs and
    enter events for the newly created ones.
    
    There's a race condition though: We might update the monitors a surface
    is on (and thus emit enter/leave events for the wl_outputs) before the
    Wayland client is registered with the new wl_output (ie. the
    bind_output() callback of MetaWaylandOutput was called), which means we
    don't send an enter event to the client in surface_entered_output().
    Since MetaWaylandSurface now has the MetaWaylandOutput in its outputs
    hashtable, it thinks the client has been notified and won't send any
    more enter events.
    
    To fix that, make MetaWaylandOutput emit a new signal "output-bound"
    when a client bound to the output and make all surfaces which are on
    that output listen to the signal. In the signal handler compare the
    newly added client to the client the surface belongs to, and if it's the
    same one, send an enter event to that client.
    
    https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1230

 src/wayland/meta-wayland-outputs.c | 10 ++++++++++
 src/wayland/meta-wayland-surface.c | 33 ++++++++++++++++++++++++++++++---
 2 files changed, 40 insertions(+), 3 deletions(-)
---
diff --git a/src/wayland/meta-wayland-outputs.c b/src/wayland/meta-wayland-outputs.c
index aed66f30c..75c29ab00 100644
--- a/src/wayland/meta-wayland-outputs.c
+++ b/src/wayland/meta-wayland-outputs.c
@@ -41,6 +41,7 @@
 enum
 {
   OUTPUT_DESTROYED,
+  OUTPUT_BOUND,
 
   LAST_SIGNAL
 };
@@ -339,6 +340,7 @@ bind_output (struct wl_client *client,
 
   send_output_events (resource, wayland_output, logical_monitor, TRUE, NULL);
 
+  g_signal_emit (wayland_output, signals[OUTPUT_BOUND], 0, resource);
 }
 
 static void
@@ -558,6 +560,14 @@ meta_wayland_output_class_init (MetaWaylandOutputClass *klass)
                                             0,
                                             NULL, NULL, NULL,
                                             G_TYPE_NONE, 0);
+
+  signals[OUTPUT_BOUND] = g_signal_new ("output-bound",
+                                        G_TYPE_FROM_CLASS (object_class),
+                                        G_SIGNAL_RUN_LAST,
+                                        0,
+                                        NULL, NULL, NULL,
+                                        G_TYPE_NONE, 1,
+                                        G_TYPE_POINTER);
 }
 
 static void
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
index fa84944bd..5ea64b12e 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -1162,6 +1162,16 @@ static const struct wl_surface_interface meta_wayland_wl_surface_interface = {
   wl_surface_damage_buffer,
 };
 
+static void
+handle_output_bound (MetaWaylandOutput  *wayland_output,
+                     struct wl_resource *output_resource,
+                     MetaWaylandSurface *surface)
+{
+  if (wl_resource_get_client (output_resource) ==
+      wl_resource_get_client (surface->resource))
+    wl_surface_send_enter (surface->resource, output_resource);
+}
+
 static void
 surface_entered_output (MetaWaylandSurface *surface,
                         MetaWaylandOutput *wayland_output)
@@ -1179,6 +1189,10 @@ surface_entered_output (MetaWaylandSurface *surface,
 
       wl_surface_send_enter (surface->resource, resource);
     }
+
+  g_signal_connect (wayland_output, "output-bound",
+                    G_CALLBACK (handle_output_bound),
+                    surface);
 }
 
 static void
@@ -1188,6 +1202,10 @@ surface_left_output (MetaWaylandSurface *surface,
   GList *iter;
   struct wl_resource *resource;
 
+  g_signal_handlers_disconnect_by_func (wayland_output,
+                                        G_CALLBACK (handle_output_bound),
+                                        surface);
+
   for (iter = wayland_output->resources; iter != NULL; iter = iter->next)
     {
       resource = iter->data;
@@ -1265,9 +1283,18 @@ update_surface_output_state (gpointer key, gpointer value, gpointer user_data)
 }
 
 static void
-surface_output_disconnect_signal (gpointer key, gpointer value, gpointer user_data)
+surface_output_disconnect_signals (gpointer key,
+                                   gpointer value,
+                                   gpointer user_data)
 {
-  g_signal_handler_disconnect (key, (gulong) GPOINTER_TO_SIZE (value));
+  MetaWaylandOutput *wayland_output = key;
+  MetaWaylandSurface *surface = user_data;
+
+  g_signal_handler_disconnect (wayland_output,
+                               (gulong) GPOINTER_TO_SIZE (value));
+  g_signal_handlers_disconnect_by_func (wayland_output,
+                                        G_CALLBACK (handle_output_bound),
+                                        surface);
 }
 
 void
@@ -1338,7 +1365,7 @@ wl_surface_destructor (struct wl_resource *resource)
   meta_wayland_compositor_destroy_frame_callbacks (compositor, surface);
 
   g_hash_table_foreach (surface->outputs_to_destroy_notify_id,
-                        surface_output_disconnect_signal,
+                        surface_output_disconnect_signals,
                         surface);
   g_hash_table_unref (surface->outputs_to_destroy_notify_id);
 


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