clutter/stage: Use new paint API to implement capture()

This changes the semantics a bit, e.g. we will never include the pointer
cursor sprite, as there is no way to know whether the caller wants to or
not.

We also change things a bit so that when we render to an offscreen paint
context, we don't emit the "paint" signal on actors, as doing so would
end up recursing in gnome-shell's screenshot and screencast code.

Closes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2567

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1222
This commit is contained in:
Jonas Ådahl 2020-04-28 18:13:23 +02:00
parent 797c349245
commit d9d8732096
5 changed files with 15 additions and 42 deletions

View File

@ -4194,7 +4194,9 @@ clutter_actor_continue_paint (ClutterActor *self,
clutter_paint_node_unref (dummy);
/* XXX:2.0 - Call the paint() virtual directly */
if (g_signal_has_handler_pending (self, actor_signals[PAINT],
if (!(clutter_paint_context_get_paint_flags (paint_context) &
CLUTTER_PAINT_FLAG_NO_PAINT_SIGNAL) &&
g_signal_has_handler_pending (self, actor_signals[PAINT],
0, TRUE))
g_signal_emit (self, actor_signals[PAINT], 0, paint_context);
else

View File

@ -24,6 +24,7 @@ typedef enum _ClutterPaintFlag
{
CLUTTER_PAINT_FLAG_NONE = 0,
CLUTTER_PAINT_FLAG_NO_CURSORS = 1 << 0,
CLUTTER_PAINT_FLAG_NO_PAINT_SIGNAL = 1 << 0,
} ClutterPaintFlag;
ClutterPaintContext * clutter_paint_context_new_for_view (ClutterStageView *view,

View File

@ -66,7 +66,8 @@ clutter_paint_context_new_for_framebuffer (CoglFramebuffer *framebuffer)
paint_context = g_new0 (ClutterPaintContext, 1);
g_ref_count_init (&paint_context->ref_count);
paint_context->paint_flags = CLUTTER_PAINT_FLAG_NO_CURSORS;
paint_context->paint_flags = (CLUTTER_PAINT_FLAG_NO_CURSORS |
CLUTTER_PAINT_FLAG_NO_PAINT_SIGNAL);
clutter_paint_context_push_framebuffer (paint_context, framebuffer);

View File

@ -4575,50 +4575,17 @@ capture_view_into (ClutterStage *stage,
uint8_t *data,
int stride)
{
CoglFramebuffer *framebuffer;
ClutterBackend *backend;
CoglContext *context;
CoglBitmap *bitmap;
cairo_rectangle_int_t view_layout;
g_autoptr (GError) error = NULL;
float view_scale;
float texture_width;
float texture_height;
g_return_if_fail (CLUTTER_IS_STAGE (stage));
framebuffer = clutter_stage_view_get_framebuffer (view);
if (paint)
{
cairo_region_t *region;
_clutter_stage_maybe_setup_viewport (stage, view);
region = cairo_region_create_rectangle (rect);
clutter_stage_do_paint_view (stage, view, region);
cairo_region_destroy (region);
}
view_scale = clutter_stage_view_get_scale (view);
texture_width = roundf (rect->width * view_scale);
texture_height = roundf (rect->height * view_scale);
backend = clutter_get_default_backend ();
context = clutter_backend_get_cogl_context (backend);
bitmap = cogl_bitmap_new_for_data (context,
texture_width, texture_height,
if (!clutter_stage_paint_to_buffer (stage, rect, view_scale, data, stride,
CLUTTER_CAIRO_FORMAT_ARGB32,
stride,
data);
clutter_stage_view_get_layout (view, &view_layout);
cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
roundf ((rect->x - view_layout.x) * view_scale),
roundf ((rect->y - view_layout.y) * view_scale),
COGL_READ_PIXELS_COLOR_BUFFER,
bitmap);
cogl_object_unref (bitmap);
CLUTTER_PAINT_FLAG_NO_CURSORS,
&error))
g_warning ("Failed to capture stage: %s", error->message);
}
void

View File

@ -204,6 +204,8 @@ meta_stage_paint (ClutterActor *actor,
META_STAGE_WATCH_AFTER_ACTOR_PAINT);
}
if (!(clutter_paint_context_get_paint_flags (paint_context) &
CLUTTER_PAINT_FLAG_NO_PAINT_SIGNAL))
g_signal_emit (stage, signals[ACTORS_PAINTED], 0);
if (!(clutter_paint_context_get_paint_flags (paint_context) &