diff options
author | Jonas Ådahl <jadahl@gmail.com> | 2019-08-26 16:29:33 +0300 |
---|---|---|
committer | Jonas Ådahl <jadahl@gmail.com> | 2019-08-27 15:31:25 +0000 |
commit | 96e831dd8a79be80a43c44de9dae1ee9b703bbb0 (patch) | |
tree | 38882e206acbb2df0d8ecb6637c26e4b6d1a429f | |
parent | 65fde269c60678fd2d00c02e94b511ec3de4a93f (diff) | |
download | mutter-96e831dd8a79be80a43c44de9dae1ee9b703bbb0.tar.gz |
window-actor: Add API to get a cairo surface of the window
This currently uses a hack where it pushes a CoglFramebuffer backed by a
texture to the framebuffer stack, then calls clutter_actor_paint() on
the window actor causing it to render into the framebuffer. This has the
effect that all subsurfaces of a window will be drawn as part of the
window.
https://gitlab.gnome.org/GNOME/mutter/merge_requests/752
-rw-r--r-- | src/compositor/meta-window-actor.c | 113 | ||||
-rw-r--r-- | src/meta/meta-window-actor.h | 4 |
2 files changed, 117 insertions, 0 deletions
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c index f0df27666..34e88a316 100644 --- a/src/compositor/meta-window-actor.c +++ b/src/compositor/meta-window-actor.c @@ -2134,3 +2134,116 @@ meta_window_actor_notify_damaged (MetaWindowActor *window_actor) { g_signal_emit (window_actor, signals[DAMAGED], 0); } + +cairo_surface_t * +meta_window_actor_get_image (MetaWindowActor *self, + MetaRectangle *clip) +{ + MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private (self); + ClutterActor *actor = CLUTTER_ACTOR (self); + MetaBackend *backend = meta_get_backend (); + ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); + CoglContext *cogl_context = + clutter_backend_get_cogl_context (clutter_backend); + float resource_scale; + float width, height; + CoglTexture2D *texture; + g_autoptr (GError) error = NULL; + CoglOffscreen *offscreen; + CoglFramebuffer *framebuffer; + CoglColor clear_color; + float x, y; + MetaRectangle scaled_clip; + cairo_surface_t *surface; + + if (!priv->surface) + return NULL; + + if (clutter_actor_get_n_children (actor) == 1) + { + MetaShapedTexture *stex; + + stex = meta_surface_actor_get_texture (priv->surface); + return meta_shaped_texture_get_image (stex, clip); + } + + clutter_actor_get_size (actor, &width, &height); + + if (width == 0 || height == 0) + return NULL; + + if (!clutter_actor_get_resource_scale (actor, &resource_scale)) + return NULL; + + width = ceilf (width * resource_scale); + height = ceilf (height * resource_scale); + + texture = cogl_texture_2d_new_with_size (cogl_context, width, height); + if (!texture) + return NULL; + + cogl_primitive_texture_set_auto_mipmap (COGL_PRIMITIVE_TEXTURE (texture), + FALSE); + + offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (texture)); + framebuffer = COGL_FRAMEBUFFER (offscreen); + + cogl_object_unref (texture); + + if (!cogl_framebuffer_allocate (framebuffer, &error)) + { + g_warning ("Failed to allocate framebuffer for screenshot: %s", + error->message); + cogl_object_unref (framebuffer); + cogl_object_unref (texture); + return NULL; + } + + cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0); + clutter_actor_get_position (actor, &x, &y); + + cogl_push_framebuffer (framebuffer); + + cogl_framebuffer_clear (framebuffer, COGL_BUFFER_BIT_COLOR, &clear_color); + cogl_framebuffer_orthographic (framebuffer, 0, 0, width, height, 0, 1.0); + cogl_framebuffer_scale (framebuffer, resource_scale, resource_scale, 1); + cogl_framebuffer_translate (framebuffer, -x, -y, 0); + + clutter_actor_paint (actor); + + cogl_pop_framebuffer (); + + if (clip) + { + meta_rectangle_scale_double (clip, resource_scale, + META_ROUNDING_STRATEGY_GROW, + &scaled_clip); + meta_rectangle_intersect (&scaled_clip, + &(MetaRectangle) { + .width = width, + .height = height, + }, + &scaled_clip); + } + else + { + scaled_clip = (MetaRectangle) { + .width = width, + .height = height, + }; + } + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + scaled_clip.width, scaled_clip.height); + cogl_framebuffer_read_pixels (framebuffer, + scaled_clip.x, scaled_clip.y, + scaled_clip.width, scaled_clip.height, + CLUTTER_CAIRO_FORMAT_ARGB32, + cairo_image_surface_get_data (surface)); + + cogl_object_unref (framebuffer); + + cairo_surface_mark_dirty (surface); + + return surface; +} diff --git a/src/meta/meta-window-actor.h b/src/meta/meta-window-actor.h index ad4b7bf1d..7d3b96e59 100644 --- a/src/meta/meta-window-actor.h +++ b/src/meta/meta-window-actor.h @@ -47,6 +47,10 @@ void meta_window_actor_sync_visibility (MetaWindowActor *self META_EXPORT gboolean meta_window_actor_is_destroyed (MetaWindowActor *self); +META_EXPORT +cairo_surface_t * meta_window_actor_get_image (MetaWindowActor *self, + cairo_rectangle_int_t *clip); + typedef enum { META_SHADOW_MODE_AUTO, |