[mutter] wayland: Send wl_surface.enter and wl_surface.leave



commit eb023ff2c9dc7dd92e3a7c232995083e6bdcbb48
Author: Jonas Ådahl <jadahl gmail com>
Date:   Tue Feb 3 15:49:52 2015 +0800

    wayland: Send wl_surface.enter and wl_surface.leave
    
    Whenever a MetaSurfaceActor is painted, update the list of what outputs
    the surface is being drawed upon. Since we do this on paint, we
    effectively avoids this whenever the surface is not drawn, for example
    being minimized, on a non-active workspace, or simply outside of the
    damage region of a frame.
    
    DND icons and cursors are not affected by this patch, since they are not
    drawn as MetaSurfaceActors. If a MetaSurfaceActor or a parent is cloned,
    then we'll check the position of the original actor again when the clone is
    drawn, which is slightly expensive, but harmless. If the MetaShapedTexture
    instead is cloned, as GNOME Shell does in many cases, then these clones
    will not cause duplicate position checks.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=744453

 src/compositor/meta-surface-actor-wayland.c |   49 ++++++++++++
 src/compositor/meta-surface-actor-wayland.h |    5 +
 src/wayland/meta-wayland-outputs.c          |   16 ++++
 src/wayland/meta-wayland-outputs.h          |    1 -
 src/wayland/meta-wayland-surface.c          |  113 +++++++++++++++++++++++++++
 src/wayland/meta-wayland-surface.h          |    3 +
 src/wayland/meta-wayland-types.h            |    2 +
 7 files changed, 188 insertions(+), 1 deletions(-)
---
diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c
index 67bc42e..865e041 100644
--- a/src/compositor/meta-surface-actor-wayland.c
+++ b/src/compositor/meta-surface-actor-wayland.c
@@ -26,6 +26,7 @@
 
 #include "meta-surface-actor-wayland.h"
 
+#include <math.h>
 #include <cogl/cogl-wayland-server.h>
 #include "meta-shaped-texture-private.h"
 
@@ -195,6 +196,40 @@ meta_surface_actor_wayland_sync_state_recursive (MetaSurfaceActorWayland *self)
     }
 }
 
+gboolean
+meta_surface_actor_wayland_is_on_monitor (MetaSurfaceActorWayland *self,
+                                          MetaMonitorInfo         *monitor)
+{
+  float x, y, width, height;
+  cairo_rectangle_int_t actor_rect;
+  cairo_region_t *region;
+  gboolean is_on_monitor;
+
+  clutter_actor_get_transformed_position (CLUTTER_ACTOR (self), &x, &y);
+  clutter_actor_get_transformed_size (CLUTTER_ACTOR (self), &width, &height);
+
+  actor_rect.x = (int)roundf (x);
+  actor_rect.y = (int)roundf (y);
+  actor_rect.width = (int)roundf (x + width) - actor_rect.x;
+  actor_rect.height = (int)roundf (y + height) - actor_rect.y;
+
+  /* Calculate the scaled surface actor region. */
+  region = cairo_region_create_rectangle (&actor_rect);
+
+  cairo_region_intersect_rectangle (region,
+                                   &((cairo_rectangle_int_t) {
+                                     .x = monitor->rect.x,
+                                     .y = monitor->rect.y,
+                                     .width = monitor->rect.width,
+                                     .height = monitor->rect.height,
+                                   }));
+
+  is_on_monitor = !cairo_region_is_empty (region);
+  cairo_region_destroy (region);
+
+  return is_on_monitor;
+}
+
 static MetaWindow *
 meta_surface_actor_wayland_get_window (MetaSurfaceActor *actor)
 {
@@ -240,6 +275,19 @@ meta_surface_actor_wayland_get_preferred_height  (ClutterActor *self,
 }
 
 static void
+meta_surface_actor_wayland_paint (ClutterActor *actor)
+{
+  MetaSurfaceActorWayland *self = META_SURFACE_ACTOR_WAYLAND (actor);
+  MetaSurfaceActorWaylandPrivate *priv =
+    meta_surface_actor_wayland_get_instance_private (self);
+
+  if (priv->surface)
+    meta_wayland_surface_update_outputs (priv->surface);
+
+  CLUTTER_ACTOR_CLASS (meta_surface_actor_wayland_parent_class)->paint (actor);
+}
+
+static void
 meta_surface_actor_wayland_dispose (GObject *object)
 {
   MetaSurfaceActorWayland *self = META_SURFACE_ACTOR_WAYLAND (object);
@@ -258,6 +306,7 @@ meta_surface_actor_wayland_class_init (MetaSurfaceActorWaylandClass *klass)
 
   actor_class->get_preferred_width = meta_surface_actor_wayland_get_preferred_width;
   actor_class->get_preferred_height = meta_surface_actor_wayland_get_preferred_height;
+  actor_class->paint = meta_surface_actor_wayland_paint;
 
   surface_actor_class->process_damage = meta_surface_actor_wayland_process_damage;
   surface_actor_class->pre_paint = meta_surface_actor_wayland_pre_paint;
diff --git a/src/compositor/meta-surface-actor-wayland.h b/src/compositor/meta-surface-actor-wayland.h
index 7071cdb..443bacc 100644
--- a/src/compositor/meta-surface-actor-wayland.h
+++ b/src/compositor/meta-surface-actor-wayland.h
@@ -31,6 +31,8 @@
 
 #include "wayland/meta-wayland.h"
 
+#include "backends/meta-monitor-manager-private.h"
+
 G_BEGIN_DECLS
 
 #define META_TYPE_SURFACE_ACTOR_WAYLAND            (meta_surface_actor_wayland_get_type ())
@@ -68,6 +70,9 @@ void meta_surface_actor_wayland_sync_state (MetaSurfaceActorWayland *self);
 
 void meta_surface_actor_wayland_sync_state_recursive (MetaSurfaceActorWayland *self);
 
+gboolean meta_surface_actor_wayland_is_on_monitor (MetaSurfaceActorWayland *self,
+                                                   MetaMonitorInfo         *monitor);
+
 G_END_DECLS
 
 #endif /* __META_SURFACE_ACTOR_WAYLAND_H__ */
diff --git a/src/wayland/meta-wayland-outputs.c b/src/wayland/meta-wayland-outputs.c
index 6c59303..bdd1c68 100644
--- a/src/wayland/meta-wayland-outputs.c
+++ b/src/wayland/meta-wayland-outputs.c
@@ -31,6 +31,14 @@
 
 #include <string.h>
 
+enum {
+  OUTPUT_DESTROYED,
+
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
 G_DEFINE_TYPE (MetaWaylandOutput, meta_wayland_output, G_TYPE_OBJECT)
 
 static void
@@ -102,6 +110,7 @@ wayland_output_destroy_notify (gpointer data)
 {
   MetaWaylandOutput *wayland_output = data;
 
+  g_signal_emit (wayland_output, signals[OUTPUT_DESTROYED], 0);
   g_object_unref (wayland_output);
 }
 
@@ -243,6 +252,13 @@ meta_wayland_output_class_init (MetaWaylandOutputClass *klass)
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
   object_class->finalize = meta_wayland_output_finalize;
+
+  signals[OUTPUT_DESTROYED] = g_signal_new ("output-destroyed",
+                                            G_TYPE_FROM_CLASS (object_class),
+                                            G_SIGNAL_RUN_LAST,
+                                            0,
+                                            NULL, NULL, NULL,
+                                            G_TYPE_NONE, 0);
 }
 
 void
diff --git a/src/wayland/meta-wayland-outputs.h b/src/wayland/meta-wayland-outputs.h
index 94a739d..2c0f28d 100644
--- a/src/wayland/meta-wayland-outputs.h
+++ b/src/wayland/meta-wayland-outputs.h
@@ -35,7 +35,6 @@
 #define META_IS_WAYLAND_OUTPUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  META_TYPE_WAYLAND_OUTPUT))
 #define META_WAYLAND_OUTPUT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  META_TYPE_WAYLAND_OUTPUT, 
MetaWaylandOutputClass))
 
-typedef struct _MetaWaylandOutput       MetaWaylandOutput;
 typedef struct _MetaWaylandOutputClass  MetaWaylandOutputClass;
 
 struct _MetaWaylandOutput
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
index 565d061..2817ba6 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -42,6 +42,7 @@
 #include "meta-wayland-pointer.h"
 #include "meta-wayland-popup.h"
 #include "meta-wayland-data-device.h"
+#include "meta-wayland-outputs.h"
 
 #include "meta-cursor-tracker-private.h"
 #include "display-private.h"
@@ -773,6 +774,114 @@ sync_drag_dest_funcs (MetaWaylandSurface *surface)
     surface->dnd.funcs = meta_wayland_data_device_get_drag_dest_funcs ();
 }
 
+static void
+surface_entered_output (MetaWaylandSurface *surface,
+                        MetaWaylandOutput *wayland_output)
+{
+  GList *iter;
+  struct wl_resource *resource;
+
+  for (iter = wayland_output->resources; iter != NULL; iter = iter->next)
+    {
+      resource = iter->data;
+
+      if (wl_resource_get_client (resource) !=
+          wl_resource_get_client (surface->resource))
+        continue;
+
+      wl_surface_send_enter (surface->resource, resource);
+    }
+}
+
+static void
+surface_left_output (MetaWaylandSurface *surface,
+                     MetaWaylandOutput *wayland_output)
+{
+  GList *iter;
+  struct wl_resource *resource;
+
+  for (iter = wayland_output->resources; iter != NULL; iter = iter->next)
+    {
+      resource = iter->data;
+
+      if (wl_resource_get_client (resource) !=
+          wl_resource_get_client (surface->resource))
+        continue;
+
+      wl_surface_send_leave (surface->resource, resource);
+    }
+}
+
+static void
+set_surface_is_on_output (MetaWaylandSurface *surface,
+                          MetaWaylandOutput *wayland_output,
+                          gboolean is_on_output);
+
+static void
+surface_handle_output_destroy (MetaWaylandOutput *wayland_output,
+                               GParamSpec *pspec,
+                               MetaWaylandSurface *surface)
+{
+  set_surface_is_on_output (surface, wayland_output, FALSE);
+}
+
+static void
+set_surface_is_on_output (MetaWaylandSurface *surface,
+                          MetaWaylandOutput *wayland_output,
+                          gboolean is_on_output)
+{
+  gboolean was_on_output = g_hash_table_contains (surface->outputs,
+                                                  wayland_output);
+
+  if (!was_on_output && is_on_output)
+    {
+      g_signal_connect (wayland_output, "output-destroyed",
+                        G_CALLBACK (surface_handle_output_destroy),
+                        surface);
+      g_hash_table_add (surface->outputs, wayland_output);
+      surface_entered_output (surface, wayland_output);
+    }
+  else if (was_on_output && !is_on_output)
+    {
+      g_hash_table_remove (surface->outputs, wayland_output);
+      g_signal_handlers_disconnect_by_func  (
+        wayland_output, (gpointer)surface_handle_output_destroy, surface);
+      surface_left_output (surface, wayland_output);
+    }
+}
+
+static void
+update_surface_output_state (gpointer key, gpointer value, gpointer user_data)
+{
+  MetaWaylandOutput *wayland_output = value;
+  MetaWaylandSurface *surface = user_data;
+  MetaSurfaceActorWayland *actor =
+    META_SURFACE_ACTOR_WAYLAND (surface->surface_actor);
+  MetaMonitorInfo *monitor;
+  gboolean is_on_output;
+
+  monitor = wayland_output->monitor_info;
+  if (!monitor)
+    {
+      set_surface_is_on_output (surface, wayland_output, FALSE);
+      return;
+    }
+
+  is_on_output = meta_surface_actor_wayland_is_on_monitor (actor, monitor);
+  set_surface_is_on_output (surface, wayland_output, is_on_output);
+}
+
+void
+meta_wayland_surface_update_outputs (MetaWaylandSurface *surface)
+{
+  if (!surface->compositor)
+    return;
+
+  g_hash_table_foreach (surface->compositor->outputs,
+                        update_surface_output_state,
+                        surface);
+}
+
 void
 meta_wayland_surface_set_window (MetaWaylandSurface *surface,
                                  MetaWindow         *window)
@@ -809,6 +918,8 @@ wl_surface_destructor (struct wl_resource *resource)
 
   meta_wayland_compositor_destroy_frame_callbacks (compositor, surface);
 
+  g_hash_table_unref (surface->outputs);
+
   if (surface->resource)
     wl_resource_set_user_data (surface->resource, NULL);
 
@@ -847,6 +958,8 @@ meta_wayland_surface_create (MetaWaylandCompositor *compositor,
 
   sync_drag_dest_funcs (surface);
 
+  surface->outputs = g_hash_table_new (NULL, NULL);
+
   pending_state_init (&surface->pending);
   return surface;
 }
diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h
index 66206b9..e29cf93 100644
--- a/src/wayland/meta-wayland-surface.h
+++ b/src/wayland/meta-wayland-surface.h
@@ -100,6 +100,7 @@ struct _MetaWaylandSurface
   int scale;
   int32_t offset_x, offset_y;
   GList *subsurfaces;
+  GHashTable *outputs;
 
   struct {
     const MetaWaylandDragDestFuncs *funcs;
@@ -187,4 +188,6 @@ void                meta_wayland_surface_drag_dest_motion    (MetaWaylandSurface
 void                meta_wayland_surface_drag_dest_focus_out (MetaWaylandSurface   *surface);
 void                meta_wayland_surface_drag_dest_drop      (MetaWaylandSurface   *surface);
 
+void                meta_wayland_surface_update_outputs (MetaWaylandSurface *surface);
+
 #endif
diff --git a/src/wayland/meta-wayland-types.h b/src/wayland/meta-wayland-types.h
index 637af77..6b134e6 100644
--- a/src/wayland/meta-wayland-types.h
+++ b/src/wayland/meta-wayland-types.h
@@ -39,6 +39,8 @@ typedef struct _MetaWaylandRegion MetaWaylandRegion;
 
 typedef struct _MetaWaylandSurface MetaWaylandSurface;
 
+typedef struct _MetaWaylandOutput MetaWaylandOutput;
+
 typedef struct _MetaWaylandSerial MetaWaylandSerial;
 
 #endif


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