[mutter] window-actor: Add API to get a cairo surface of the window



commit 96e831dd8a79be80a43c44de9dae1ee9b703bbb0
Author: Jonas Ådahl <jadahl gmail com>
Date:   Mon Aug 26 16:29:33 2019 +0300

    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

 src/compositor/meta-window-actor.c | 113 +++++++++++++++++++++++++++++++++++++
 src/meta/meta-window-actor.h       |   4 ++
 2 files changed, 117 insertions(+)
---
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,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]