summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Ådahl <jadahl@gmail.com>2019-08-26 16:29:33 +0300
committerJonas Ådahl <jadahl@gmail.com>2019-08-27 15:31:25 +0000
commit96e831dd8a79be80a43c44de9dae1ee9b703bbb0 (patch)
tree38882e206acbb2df0d8ecb6637c26e4b6d1a429f
parent65fde269c60678fd2d00c02e94b511ec3de4a93f (diff)
downloadmutter-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.c113
-rw-r--r--src/meta/meta-window-actor.h4
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,