diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c index 67bc42e43..865e04192 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 #include #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) { @@ -239,6 +274,19 @@ meta_surface_actor_wayland_get_preferred_height (ClutterActor *self, *natural_height_p *= scale; } +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) { @@ -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 7071cdb0a..443bacc3c 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 6c5930302..bdd1c6839 100644 --- a/src/wayland/meta-wayland-outputs.c +++ b/src/wayland/meta-wayland-outputs.c @@ -31,6 +31,14 @@ #include +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 94a739d89..2c0f28dc6 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 565d0611c..2817ba6a7 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 66206b989..e29cf930b 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 637af775a..6b134e61d 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