From 1e6b3faa83323943cb45f4ef1b910f87b2c30d88 Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Tue, 18 Feb 2014 21:27:20 -0500 Subject: [PATCH] Fix the input region not working properly The input region was set on the shaped texture, but the shaped texture was never picked properly, as it was never set to be reactive. Move the pick implementation and reactivity to the MetaSurfaceActor, and update the code everywhere else to expect a MetaSurfaceActor. --- src/compositor/meta-shaped-texture.c | 105 --------------------------- src/compositor/meta-surface-actor.c | 99 ++++++++++++++++++++++++- src/compositor/meta-surface-actor.h | 4 +- src/compositor/meta-window-actor.c | 5 +- src/core/display.c | 8 +- src/meta/meta-shaped-texture.h | 3 - src/wayland/meta-wayland-seat.c | 9 +-- src/wayland/meta-wayland-surface.c | 3 +- 8 files changed, 109 insertions(+), 127 deletions(-) diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c index ae46b34d2..30697ee6a 100644 --- a/src/compositor/meta-shaped-texture.c +++ b/src/compositor/meta-shaped-texture.c @@ -42,8 +42,6 @@ static void meta_shaped_texture_dispose (GObject *object); static void meta_shaped_texture_paint (ClutterActor *actor); -static void meta_shaped_texture_pick (ClutterActor *actor, - const ClutterColor *color); static void meta_shaped_texture_get_preferred_width (ClutterActor *self, gfloat for_height, @@ -73,8 +71,6 @@ struct _MetaShapedTexturePrivate CoglTexture *texture; CoglTexture *mask_texture; - cairo_region_t *input_shape_region; - /* The region containing only fully opaque pixels */ cairo_region_t *opaque_region; @@ -98,7 +94,6 @@ meta_shaped_texture_class_init (MetaShapedTextureClass *klass) actor_class->get_preferred_width = meta_shaped_texture_get_preferred_width; actor_class->get_preferred_height = meta_shaped_texture_get_preferred_height; actor_class->paint = meta_shaped_texture_paint; - actor_class->pick = meta_shaped_texture_pick; actor_class->get_paint_volume = meta_shaped_texture_get_paint_volume; g_type_class_add_private (klass, sizeof (MetaShapedTexturePrivate)); @@ -463,71 +458,6 @@ meta_shaped_texture_paint (ClutterActor *actor) cairo_region_destroy (blended_region); } -static void -meta_shaped_texture_pick (ClutterActor *actor, - const ClutterColor *color) -{ - MetaShapedTexture *stex = (MetaShapedTexture *) actor; - MetaShapedTexturePrivate *priv = stex->priv; - - if (!clutter_actor_should_pick_paint (actor) || - (priv->clip_region && cairo_region_is_empty (priv->clip_region))) - return; - - /* If there is no region then use the regular pick */ - if (priv->input_shape_region == NULL) - CLUTTER_ACTOR_CLASS (meta_shaped_texture_parent_class)->pick (actor, color); - else - { - int n_rects; - float *rectangles; - int i; - CoglPipeline *pipeline; - CoglContext *ctx; - CoglFramebuffer *fb; - CoglColor cogl_color; - - /* Note: We don't bother trying to intersect the pick and clip regions - * since needing to copy the region, do the intersection, and probably - * increase the number of rectangles seems more likely to have a negative - * effect. - * - * NB: Most of the time when just using rectangles for picking then - * picking shouldn't involve any rendering, and minimizing the number of - * rectangles has more benefit than reducing the area of the pick - * region. - */ - - n_rects = cairo_region_num_rectangles (priv->input_shape_region); - rectangles = g_alloca (sizeof (float) * 4 * n_rects); - - for (i = 0; i < n_rects; i++) - { - cairo_rectangle_int_t rect; - int pos = i * 4; - - cairo_region_get_rectangle (priv->input_shape_region, i, &rect); - - rectangles[pos] = rect.x; - rectangles[pos + 1] = rect.y; - rectangles[pos + 2] = rect.x + rect.width; - rectangles[pos + 3] = rect.y + rect.height; - } - - ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); - fb = cogl_get_draw_framebuffer (); - - cogl_color_init_from_4ub (&cogl_color, color->red, color->green, color->blue, color->alpha); - - pipeline = cogl_pipeline_new (ctx); - cogl_pipeline_set_color (pipeline, &cogl_color); - - cogl_framebuffer_draw_rectangles (fb, pipeline, - rectangles, n_rects); - cogl_object_unref (pipeline); - } -} - static void meta_shaped_texture_get_preferred_width (ClutterActor *self, gfloat for_height, @@ -764,41 +694,6 @@ meta_shaped_texture_get_texture (MetaShapedTexture *stex) return COGL_TEXTURE (stex->priv->texture); } -/** - * meta_shaped_texture_set_input_shape_region: - * @stex: a #MetaShapedTexture - * @shape_region: the region of the texture that should respond to - * input. - * - * Determines what region of the texture should accept input. For - * X based windows this is defined by the ShapeInput region of the - * window. - */ -void -meta_shaped_texture_set_input_shape_region (MetaShapedTexture *stex, - cairo_region_t *shape_region) -{ - MetaShapedTexturePrivate *priv; - - g_return_if_fail (META_IS_SHAPED_TEXTURE (stex)); - - priv = stex->priv; - - if (priv->input_shape_region != NULL) - { - cairo_region_destroy (priv->input_shape_region); - priv->input_shape_region = NULL; - } - - if (shape_region != NULL) - { - cairo_region_reference (shape_region); - priv->input_shape_region = shape_region; - } - - clutter_actor_queue_redraw (CLUTTER_ACTOR (stex)); -} - /** * meta_shaped_texture_set_opaque_region: * @stex: a #MetaShapedTexture diff --git a/src/compositor/meta-surface-actor.c b/src/compositor/meta-surface-actor.c index 541094cff..5afa4d70f 100644 --- a/src/compositor/meta-surface-actor.c +++ b/src/compositor/meta-surface-actor.c @@ -22,8 +22,12 @@ struct _MetaSurfaceActorPrivate { + MetaWaylandSurface *surface; + MetaShapedTexture *texture; MetaWaylandBuffer *buffer; + + cairo_region_t *input_region; }; static void cullable_iface_init (MetaCullableInterface *iface); @@ -39,9 +43,77 @@ meta_surface_actor_get_unobscured_bounds (MetaSurfaceActor *self, return meta_shaped_texture_get_unobscured_bounds (priv->texture, unobscured_bounds); } +static void +meta_surface_actor_pick (ClutterActor *actor, + const ClutterColor *color) +{ + MetaSurfaceActor *self = META_SURFACE_ACTOR (actor); + MetaSurfaceActorPrivate *priv = self->priv; + + if (!clutter_actor_should_pick_paint (actor)) + return; + + /* If there is no region then use the regular pick */ + if (priv->input_region == NULL) + CLUTTER_ACTOR_CLASS (meta_surface_actor_parent_class)->pick (actor, color); + else + { + int n_rects; + float *rectangles; + int i; + CoglPipeline *pipeline; + CoglContext *ctx; + CoglFramebuffer *fb; + CoglColor cogl_color; + + n_rects = cairo_region_num_rectangles (priv->input_region); + rectangles = g_alloca (sizeof (float) * 4 * n_rects); + + for (i = 0; i < n_rects; i++) + { + cairo_rectangle_int_t rect; + int pos = i * 4; + + cairo_region_get_rectangle (priv->input_region, i, &rect); + + rectangles[pos + 0] = rect.x; + rectangles[pos + 1] = rect.y; + rectangles[pos + 2] = rect.x + rect.width; + rectangles[pos + 3] = rect.y + rect.height; + } + + ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); + fb = cogl_get_draw_framebuffer (); + + cogl_color_init_from_4ub (&cogl_color, color->red, color->green, color->blue, color->alpha); + + pipeline = cogl_pipeline_new (ctx); + cogl_pipeline_set_color (pipeline, &cogl_color); + cogl_framebuffer_draw_rectangles (fb, pipeline, rectangles, n_rects); + cogl_object_unref (pipeline); + } +} + +static void +meta_surface_actor_dispose (GObject *object) +{ + MetaSurfaceActor *self = META_SURFACE_ACTOR (object); + MetaSurfaceActorPrivate *priv = self->priv; + + g_clear_pointer (&priv->input_region, cairo_region_destroy); + + G_OBJECT_CLASS (meta_surface_actor_parent_class)->dispose (object); +} + static void meta_surface_actor_class_init (MetaSurfaceActorClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); + ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); + + object_class->dispose = meta_surface_actor_dispose; + actor_class->pick = meta_surface_actor_pick; + g_type_class_add_private (klass, sizeof (MetaSurfaceActorPrivate)); } @@ -172,7 +244,14 @@ meta_surface_actor_set_input_region (MetaSurfaceActor *self, cairo_region_t *region) { MetaSurfaceActorPrivate *priv = self->priv; - meta_shaped_texture_set_input_shape_region (priv->texture, region); + + if (priv->input_region) + cairo_region_destroy (priv->input_region); + + if (region) + priv->input_region = cairo_region_reference (region); + else + priv->input_region = NULL; } void @@ -183,8 +262,20 @@ meta_surface_actor_set_opaque_region (MetaSurfaceActor *self, meta_shaped_texture_set_opaque_region (priv->texture, region); } -MetaSurfaceActor * -meta_surface_actor_new (void) +MetaWaylandSurface * +meta_surface_actor_get_surface (MetaSurfaceActor *self) { - return g_object_new (META_TYPE_SURFACE_ACTOR, NULL); + MetaSurfaceActorPrivate *priv = self->priv; + return priv->surface; +} + +MetaSurfaceActor * +meta_surface_actor_new (MetaWaylandSurface *surface) +{ + MetaSurfaceActor *self = g_object_new (META_TYPE_SURFACE_ACTOR, NULL); + MetaSurfaceActorPrivate *priv = self->priv; + + priv->surface = surface; + + return self; } diff --git a/src/compositor/meta-surface-actor.h b/src/compositor/meta-surface-actor.h index fa7f0c307..e42deb42f 100644 --- a/src/compositor/meta-surface-actor.h +++ b/src/compositor/meta-surface-actor.h @@ -36,7 +36,7 @@ struct _MetaSurfaceActor GType meta_surface_actor_get_type (void); -MetaSurfaceActor *meta_surface_actor_new (void); +MetaSurfaceActor *meta_surface_actor_new (MetaWaylandSurface *surface); cairo_surface_t *meta_surface_actor_get_image (MetaSurfaceActor *self, cairo_rectangle_int_t *clip); @@ -63,6 +63,8 @@ void meta_surface_actor_set_input_region (MetaSurfaceActor *self, void meta_surface_actor_set_opaque_region (MetaSurfaceActor *self, cairo_region_t *region); +MetaWaylandSurface *meta_surface_actor_get_surface (MetaSurfaceActor *surface); + G_END_DECLS #endif /* META_SURFACE_ACTOR_PRIVATE_H */ diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c index f9568f393..c6071979c 100644 --- a/src/compositor/meta-window-actor.c +++ b/src/compositor/meta-window-actor.c @@ -353,7 +353,7 @@ meta_window_actor_constructed (GObject *object) if (window->surface) priv->surface = window->surface->surface_actor; else - priv->surface = meta_surface_actor_new (); + priv->surface = meta_surface_actor_new (NULL); g_object_ref_sink (priv->surface); clutter_actor_add_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->surface)); @@ -1424,7 +1424,6 @@ meta_window_actor_hide (MetaWindowActor *self, g_return_if_fail (priv->visible); priv->visible = FALSE; - clutter_actor_set_reactive (CLUTTER_ACTOR (self), FALSE); /* If a plugin is animating a workspace transition, we have to * hold off on hiding the window, and do it after the workspace @@ -1557,8 +1556,6 @@ meta_window_actor_new (MetaWindow *window) clutter_actor_hide (CLUTTER_ACTOR (self)); - clutter_actor_set_reactive (CLUTTER_ACTOR (self), TRUE); - /* Initial position in the stack is arbitrary; stacking will be synced * before we first paint. */ diff --git a/src/core/display.c b/src/core/display.c index 749938fd8..907f1a597 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -1682,8 +1682,12 @@ get_window_for_event (MetaDisplay *display, return display->grab_window; source = clutter_event_get_source (event); - if (META_IS_WINDOW_ACTOR (source)) - return meta_window_actor_get_meta_window (META_WINDOW_ACTOR (source)); + if (META_IS_SURFACE_ACTOR (source)) + { + MetaWaylandSurface *surface = meta_surface_actor_get_surface (META_SURFACE_ACTOR (source)); + g_assert (surface != NULL); + return surface->window; + } return NULL; } diff --git a/src/meta/meta-shaped-texture.h b/src/meta/meta-shaped-texture.h index b0870bf95..80b23f2ea 100644 --- a/src/meta/meta-shaped-texture.h +++ b/src/meta/meta-shaped-texture.h @@ -75,9 +75,6 @@ CoglTexture * meta_shaped_texture_get_texture (MetaShapedTexture *stex); void meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex, CoglTexture *mask_texture); -void meta_shaped_texture_set_input_shape_region (MetaShapedTexture *stex, - cairo_region_t *shape_region); - void meta_shaped_texture_set_opaque_region (MetaShapedTexture *stex, cairo_region_t *opaque_region); diff --git a/src/wayland/meta-wayland-seat.c b/src/wayland/meta-wayland-seat.c index ff6f57de6..df8e7814f 100644 --- a/src/wayland/meta-wayland-seat.c +++ b/src/wayland/meta-wayland-seat.c @@ -420,13 +420,8 @@ meta_wayland_seat_repick (MetaWaylandSeat *seat, else seat->current_stage = NULL; - if (META_IS_WINDOW_ACTOR (actor)) - { - MetaWindow *window = - meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor)); - - surface = window->surface; - } + if (META_IS_SURFACE_ACTOR (actor)) + surface = meta_surface_actor_get_surface (META_SURFACE_ACTOR (actor)); pointer->current = surface; if (surface != pointer->focus_surface) diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index 2ae212d9c..10767cfff 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -645,7 +645,8 @@ meta_wayland_surface_create (MetaWaylandCompositor *compositor, wl_resource_set_implementation (surface->resource, &meta_wayland_surface_interface, surface, wl_surface_destructor); surface->buffer_destroy_listener.notify = surface_handle_buffer_destroy; - surface->surface_actor = g_object_ref_sink (meta_surface_actor_new ()); + surface->surface_actor = g_object_ref_sink (meta_surface_actor_new (surface)); + clutter_actor_set_reactive (CLUTTER_ACTOR (surface->surface_actor), TRUE); double_buffered_state_init (&surface->pending);