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
This commit is contained in:
Jonas Ådahl 2015-02-03 15:49:52 +08:00
parent ba7c524a18
commit eb023ff2c9
7 changed files with 188 additions and 1 deletions

View File

@ -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)
{
@ -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;

View File

@ -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__ */

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -39,6 +39,8 @@ typedef struct _MetaWaylandRegion MetaWaylandRegion;
typedef struct _MetaWaylandSurface MetaWaylandSurface;
typedef struct _MetaWaylandOutput MetaWaylandOutput;
typedef struct _MetaWaylandSerial MetaWaylandSerial;
#endif