diff --git a/src/shell-screenshot.c b/src/shell-screenshot.c index 36ca2fb24..3a1c92cce 100644 --- a/src/shell-screenshot.c +++ b/src/shell-screenshot.c @@ -12,6 +12,12 @@ #include "shell-screenshot.h" #include "shell-util.h" +typedef enum _ShellScreenshotFlag +{ + SHELL_SCREENSHOT_FLAG_NONE, + SHELL_SCREENSHOT_FLAG_INCLUDE_CURSOR, +} ShellScreenshotFlag; + typedef struct _ShellScreenshotPrivate ShellScreenshotPrivate; struct _ShellScreenshot @@ -32,7 +38,6 @@ struct _ShellScreenshotPrivate cairo_surface_t *image; cairo_rectangle_int_t screenshot_area; - gboolean include_cursor; gboolean include_frame; }; @@ -45,10 +50,6 @@ typedef enum G_DEFINE_TYPE_WITH_PRIVATE (ShellScreenshot, shell_screenshot, G_TYPE_OBJECT); -static void -grab_screenshot (ClutterActor *stage, - GTask *result); - static void shell_screenshot_class_init (ShellScreenshotClass *screenshot_class) { @@ -77,8 +78,6 @@ on_screenshot_written (GObject *source, g_clear_pointer (&priv->image, cairo_surface_destroy); g_clear_object (&priv->stream); g_clear_pointer (&priv->datetime, g_date_time_unref); - - meta_enable_unredirect_for_display (shell_global_get_display (priv->global)); } static void @@ -121,63 +120,49 @@ write_screenshot_thread (GTask *result, } static void -do_grab_screenshot (ShellScreenshot *screenshot, - ClutterStage *stage, - int x, - int y, - int width, - int height) +do_grab_screenshot (ShellScreenshot *screenshot, + int x, + int y, + int width, + int height, + ShellScreenshotFlag flags) { ShellScreenshotPrivate *priv = screenshot->priv; + ClutterStage *stage = shell_global_get_stage (priv->global); cairo_rectangle_int_t screenshot_rect = { x, y, width, height }; - ClutterCapture *captures; - int n_captures; - int i; + int image_width; + int image_height; + float scale; + cairo_surface_t *image; + ClutterPaintFlag paint_flags = CLUTTER_PAINT_FLAG_NONE; + g_autoptr (GError) error = NULL; - if (!clutter_stage_capture (stage, FALSE, - &screenshot_rect, - &captures, - &n_captures)) - return; + clutter_stage_get_capture_final_size (stage, &screenshot_rect, + &image_width, + &image_height, + &scale); + image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + image_width, image_height); - if (n_captures == 1) - priv->image = cairo_surface_reference (captures[0].image); + if (flags & SHELL_SCREENSHOT_FLAG_INCLUDE_CURSOR) + paint_flags |= CLUTTER_PAINT_FLAG_FORCE_CURSORS; else + paint_flags |= CLUTTER_PAINT_FLAG_NO_CURSORS; + if (!clutter_stage_paint_to_buffer (stage, &screenshot_rect, scale, + cairo_image_surface_get_data (image), + cairo_image_surface_get_stride (image), + CLUTTER_CAIRO_FORMAT_ARGB32, + paint_flags, + &error)) { - float target_scale; - - clutter_stage_get_capture_final_size (stage, &screenshot_rect, - &width, &height, &target_scale); - priv->image = shell_util_composite_capture_images (captures, - n_captures, - x, y, - width, height, - target_scale); + cairo_surface_destroy (image); + g_warning ("Failed to take screenshot: %s", error->message); + return; } + priv->image = image; + priv->datetime = g_date_time_new_now_local (); - - for (i = 0; i < n_captures; i++) - cairo_surface_destroy (captures[i].image); - - g_free (captures); -} - -static gboolean -should_draw_cursor_image (ShellScreenshotMode mode) -{ - if (mode == SHELL_SCREENSHOT_WINDOW || !meta_is_wayland_compositor ()) - { - StSettings *settings = st_settings_get (); - gboolean magnifier_active = FALSE; - - g_object_get (settings, "magnifier-active", &magnifier_active, NULL); - - if (!magnifier_active) - return TRUE; - } - - return FALSE; } static void @@ -256,116 +241,37 @@ draw_cursor_image (cairo_surface_t *surface, } static void -on_paint (ClutterActor *actor, - ClutterPaintContext *paint_context, - GTask *result) -{ - grab_screenshot (actor, result); -} - -static void -on_actors_painted (ClutterActor *actor, - GTask *result) -{ - grab_screenshot (actor, result); -} - -static void -grab_screenshot (ClutterActor *stage, - GTask *result) +grab_screenshot (ShellScreenshot *screenshot, + ShellScreenshotFlag flags, + GTask *result) { + ShellScreenshotPrivate *priv = screenshot->priv; MetaDisplay *display; int width, height; - ShellScreenshot *screenshot = g_task_get_source_object (result); - ShellScreenshotPrivate *priv = screenshot->priv; GTask *task; display = shell_global_get_display (priv->global); meta_display_get_size (display, &width, &height); - do_grab_screenshot (screenshot, CLUTTER_STAGE (stage), 0, 0, width, height); - - if (meta_display_get_n_monitors (display) > 1) - { - cairo_region_t *screen_region = cairo_region_create (); - cairo_region_t *stage_region; - MetaRectangle monitor_rect; - cairo_rectangle_int_t stage_rect; - int i; - cairo_t *cr; - - for (i = meta_display_get_n_monitors (display) - 1; i >= 0; i--) - { - meta_display_get_monitor_geometry (display, i, &monitor_rect); - cairo_region_union_rectangle (screen_region, - (const cairo_rectangle_int_t *) &monitor_rect); - } - - stage_rect.x = 0; - stage_rect.y = 0; - stage_rect.width = width; - stage_rect.height = height; - - stage_region = cairo_region_create_rectangle ((const cairo_rectangle_int_t *) &stage_rect); - cairo_region_xor (stage_region, screen_region); - cairo_region_destroy (screen_region); - - cr = cairo_create (priv->image); - - for (i = 0; i < cairo_region_num_rectangles (stage_region); i++) - { - cairo_rectangle_int_t rect; - cairo_region_get_rectangle (stage_region, i, &rect); - cairo_rectangle (cr, (double) rect.x, (double) rect.y, (double) rect.width, (double) rect.height); - cairo_fill (cr); - } - - cairo_destroy (cr); - cairo_region_destroy (stage_region); - } + do_grab_screenshot (screenshot, + 0, 0, width, height, + flags); priv->screenshot_area.x = 0; priv->screenshot_area.y = 0; priv->screenshot_area.width = width; priv->screenshot_area.height = height; - if (priv->include_cursor) - draw_cursor_image (priv->image, priv->screenshot_area); - - g_signal_handlers_disconnect_by_func (stage, on_paint, result); - g_signal_handlers_disconnect_by_func (stage, on_actors_painted, result); - task = g_task_new (screenshot, NULL, on_screenshot_written, result); g_task_run_in_thread (task, write_screenshot_thread); g_object_unref (task); } static void -grab_area_screenshot (ClutterActor *stage, - GTask *result) +grab_window_screenshot (ShellScreenshot *screenshot, + ShellScreenshotFlag flags, + GTask *result) { - ShellScreenshot *screenshot = g_task_get_source_object (result); - ShellScreenshotPrivate *priv = screenshot->priv; - GTask *task; - - do_grab_screenshot (screenshot, - CLUTTER_STAGE (stage), - priv->screenshot_area.x, - priv->screenshot_area.y, - priv->screenshot_area.width, - priv->screenshot_area.height); - - g_signal_handlers_disconnect_by_func (stage, grab_area_screenshot, result); - task = g_task_new (screenshot, NULL, on_screenshot_written, result); - g_task_run_in_thread (task, write_screenshot_thread); - g_object_unref (task); -} - -static void -grab_window_screenshot (ClutterActor *stage, - GTask *result) -{ - ShellScreenshot *screenshot = g_task_get_source_object (result); ShellScreenshotPrivate *priv = screenshot->priv; GTask *task; MetaDisplay *display = shell_global_get_display (priv->global); @@ -388,7 +294,7 @@ grab_window_screenshot (ClutterActor *stage, NULL); priv->datetime = g_date_time_new_now_local (); - if (priv->include_cursor) + if (flags & SHELL_SCREENSHOT_FLAG_INCLUDE_CURSOR) { if (meta_window_get_client_type (window) == META_WINDOW_CLIENT_TYPE_WAYLAND) { @@ -401,33 +307,11 @@ grab_window_screenshot (ClutterActor *stage, draw_cursor_image (priv->image, priv->screenshot_area); } - g_signal_handlers_disconnect_by_func (stage, grab_window_screenshot, result); task = g_task_new (screenshot, NULL, on_screenshot_written, result); g_task_run_in_thread (task, write_screenshot_thread); g_object_unref (task); } -static void -grab_pixel (ClutterActor *stage, - GTask *result) -{ - ShellScreenshot *screenshot = g_task_get_source_object (result); - ShellScreenshotPrivate *priv = screenshot->priv; - - do_grab_screenshot (screenshot, - CLUTTER_STAGE (stage), - priv->screenshot_area.x, - priv->screenshot_area.y, - 1, - 1); - - meta_enable_unredirect_for_display (shell_global_get_display (priv->global)); - - g_signal_handlers_disconnect_by_func (stage, grab_pixel, result); - g_task_return_boolean (result, TRUE); - g_object_unref (result); -} - static gboolean finish_screenshot (ShellScreenshot *screenshot, GAsyncResult *result, @@ -465,10 +349,9 @@ shell_screenshot_screenshot (ShellScreenshot *screenshot, GAsyncReadyCallback callback, gpointer user_data) { - ClutterActor *stage; ShellScreenshotPrivate *priv; - gboolean use_paint_signal = FALSE; GTask *result; + ShellScreenshotFlag flags; g_return_if_fail (SHELL_IS_SCREENSHOT (screenshot)); g_return_if_fail (G_IS_OUTPUT_STREAM (stream)); @@ -492,34 +375,12 @@ shell_screenshot_screenshot (ShellScreenshot *screenshot, g_task_set_source_tag (result, shell_screenshot_screenshot); priv->stream = g_object_ref (stream); - priv->include_cursor = FALSE; - - stage = CLUTTER_ACTOR (shell_global_get_stage (priv->global)); - - meta_disable_unredirect_for_display (shell_global_get_display (priv->global)); + flags = SHELL_SCREENSHOT_FLAG_NONE; if (include_cursor) - { - if (should_draw_cursor_image (SHELL_SCREENSHOT_SCREEN)) - priv->include_cursor = TRUE; - else - use_paint_signal = TRUE; - } + flags |= SHELL_SCREENSHOT_FLAG_INCLUDE_CURSOR; - if (use_paint_signal) - { - g_signal_connect_after (stage, "paint", - G_CALLBACK (on_paint), - result); - } - else - { - g_signal_connect_after (stage, "actors-painted", - G_CALLBACK (on_actors_painted), - result); - } - - clutter_actor_queue_redraw (stage); + grab_screenshot (screenshot, flags, result); } /** @@ -575,9 +436,9 @@ shell_screenshot_screenshot_area (ShellScreenshot *screenshot, GAsyncReadyCallback callback, gpointer user_data) { - ClutterActor *stage; ShellScreenshotPrivate *priv; GTask *result; + g_autoptr (GTask) task = NULL; g_return_if_fail (SHELL_IS_SCREENSHOT (screenshot)); g_return_if_fail (G_IS_OUTPUT_STREAM (stream)); @@ -606,13 +467,15 @@ shell_screenshot_screenshot_area (ShellScreenshot *screenshot, priv->screenshot_area.width = width; priv->screenshot_area.height = height; - stage = CLUTTER_ACTOR (shell_global_get_stage (priv->global)); + do_grab_screenshot (screenshot, + priv->screenshot_area.x, + priv->screenshot_area.y, + priv->screenshot_area.width, + priv->screenshot_area.height, + SHELL_SCREENSHOT_FLAG_NONE); - meta_disable_unredirect_for_display (shell_global_get_display (shell_global_get ())); - - g_signal_connect_after (stage, "actors-painted", G_CALLBACK (grab_area_screenshot), result); - - clutter_actor_queue_redraw (stage); + task = g_task_new (screenshot, NULL, on_screenshot_written, result); + g_task_run_in_thread (task, write_screenshot_thread); } /** @@ -666,7 +529,6 @@ shell_screenshot_screenshot_window (ShellScreenshot *screenshot, { ShellScreenshotPrivate *priv; MetaDisplay *display; - ClutterActor *stage; MetaWindow *window; GTask *result; @@ -695,16 +557,8 @@ shell_screenshot_screenshot_window (ShellScreenshot *screenshot, priv->stream = g_object_ref (stream); priv->include_frame = include_frame; - priv->include_cursor = include_cursor && - should_draw_cursor_image (SHELL_SCREENSHOT_WINDOW); - stage = CLUTTER_ACTOR (shell_global_get_stage (priv->global)); - - meta_disable_unredirect_for_display (shell_global_get_display (shell_global_get ())); - - g_signal_connect_after (stage, "actors-painted", G_CALLBACK (grab_window_screenshot), result); - - clutter_actor_queue_redraw (stage); + grab_window_screenshot (screenshot, include_cursor, result); } /** @@ -753,9 +607,7 @@ shell_screenshot_pick_color (ShellScreenshot *screenshot, gpointer user_data) { ShellScreenshotPrivate *priv; - MetaDisplay *display; - ClutterActor *stage; - GTask *result; + g_autoptr (GTask) result = NULL; g_return_if_fail (SHELL_IS_SCREENSHOT (screenshot)); @@ -769,14 +621,14 @@ shell_screenshot_pick_color (ShellScreenshot *screenshot, priv->screenshot_area.width = 1; priv->screenshot_area.height = 1; - display = shell_global_get_display (priv->global); - stage = CLUTTER_ACTOR (shell_global_get_stage (priv->global)); + do_grab_screenshot (screenshot, + priv->screenshot_area.x, + priv->screenshot_area.y, + 1, + 1, + SHELL_SCREENSHOT_FLAG_NONE); - meta_disable_unredirect_for_display (display); - - g_signal_connect_after (stage, "actors-painted", G_CALLBACK (grab_pixel), result); - - clutter_actor_queue_redraw (stage); + g_task_return_boolean (result, TRUE); } #if G_BYTE_ORDER == G_LITTLE_ENDIAN