diff --git a/SOURCES/0001-compositor-Add-screenshot-utilities.patch b/SOURCES/0001-compositor-Add-screenshot-utilities.patch
new file mode 100644
index 0000000000000000000000000000000000000000..025b5c4d34b2ed3196887454c8b1fd5130dcdbfd
--- /dev/null
+++ b/SOURCES/0001-compositor-Add-screenshot-utilities.patch
@@ -0,0 +1,1046 @@
+From 52f9b3792196e405d7ce9917e735c707d369b8f9 Mon Sep 17 00:00:00 2001
+From: Olivier Fourdan <ofourdan@redhat.com>
+Date: Wed, 22 Jan 2025 11:20:38 +0100
+Subject: [PATCH 1/2] compositor: Add screenshot utilities
+
+This code is a simplified and expunged version based on GNOME Shell
+implementation of ShellScreenshot.
+
+This is preparation work for implementing support for the Shell
+screenshot DBus API org.gnome.Shell.Screenshot.
+
+Part-of: <https://gitlab.gnome.org/GNOME/gnome-kiosk/-/merge_requests/61>
+(cherry picked from commit 20edc0cc81a4ecc29d74c32446717ee969b7b33e)
+---
+ compositor/kiosk-screenshot.c | 930 ++++++++++++++++++++++++++++++++++
+ compositor/kiosk-screenshot.h |  59 +++
+ meson.build                   |   3 +
+ 3 files changed, 992 insertions(+)
+ create mode 100644 compositor/kiosk-screenshot.c
+ create mode 100644 compositor/kiosk-screenshot.h
+
+diff --git a/compositor/kiosk-screenshot.c b/compositor/kiosk-screenshot.c
+new file mode 100644
+index 0000000..04b7b99
+--- /dev/null
++++ b/compositor/kiosk-screenshot.c
+@@ -0,0 +1,930 @@
++#include "config.h"
++#include "kiosk-compositor.h"
++#include "kiosk-screenshot.h"
++#include "kiosk-gobject-utils.h"
++
++#include <stdlib.h>
++#include <string.h>
++
++#include <cogl/cogl.h>
++
++#include <meta/display.h>
++#include <meta/util.h>
++#include <meta/compositor-mutter.h>
++
++#include <meta/meta-backend.h>
++#include <meta/meta-context.h>
++#include <meta/meta-cursor-tracker.h>
++#include <meta/meta-plugin.h>
++#include <meta/meta-monitor-manager.h>
++#include <meta/meta-background-actor.h>
++#include <meta/meta-background-content.h>
++#include <meta/meta-background-group.h>
++#include <meta/meta-background-image.h>
++#include <meta/meta-background.h>
++
++/* This code is a largely based on GNOME Shell implementation of ShellScreenshot */
++
++typedef enum _KioskScreenshotFlag
++{
++        KIOSK_SCREENSHOT_FLAG_NONE,
++        KIOSK_SCREENSHOT_FLAG_INCLUDE_CURSOR,
++} KioskScreenshotFlag;
++
++typedef enum _KioskScreenshotMode
++{
++        KIOSK_SCREENSHOT_SCREEN,
++        KIOSK_SCREENSHOT_WINDOW,
++        KIOSK_SCREENSHOT_AREA,
++} KioskScreenshotMode;
++
++enum
++{
++        SCREENSHOT_TAKEN,
++
++        LAST_SIGNAL
++};
++
++static guint signals[LAST_SIGNAL] = { 0, };
++
++typedef struct _KioskScreenshot KioskScreenshot;
++
++struct _KioskScreenshot
++{
++        GObject             parent_instance;
++
++        /* weak references */
++        KioskCompositor    *compositor;
++        MetaDisplay        *display;
++        MetaContext        *context;
++        MetaBackend        *backend;
++        ClutterActor       *stage;
++
++        /* strong references */
++        GOutputStream      *stream;
++        KioskScreenshotFlag flags;
++        KioskScreenshotMode mode;
++
++        GDateTime          *datetime;
++
++        cairo_surface_t    *image;
++        MtkRectangle        screenshot_area;
++
++        gboolean            include_frame;
++
++        float               scale;
++        ClutterContent     *cursor_content;
++        graphene_point_t    cursor_point;
++        float               cursor_scale;
++};
++
++enum
++{
++        PROP_COMPOSITOR = 1,
++        NUMBER_OF_PROPERTIES
++};
++static GParamSpec *kiosk_screenshot_properties[NUMBER_OF_PROPERTIES] = { NULL, };
++
++G_DEFINE_TYPE (KioskScreenshot, kiosk_screenshot, G_TYPE_OBJECT);
++
++static void
++kiosk_screenshot_dispose (GObject *object)
++{
++        KioskScreenshot *self = KIOSK_SCREENSHOT (object);
++
++        g_clear_weak_pointer (&self->context);
++        g_clear_weak_pointer (&self->backend);
++        g_clear_weak_pointer (&self->stage);
++        g_clear_weak_pointer (&self->display);
++        g_clear_weak_pointer (&self->compositor);
++
++        G_OBJECT_CLASS (kiosk_screenshot_parent_class)->dispose (object);
++}
++
++static void
++kiosk_screenshot_constructed (GObject *object)
++{
++        KioskScreenshot *self = KIOSK_SCREENSHOT (object);
++        MetaDisplay *display = meta_plugin_get_display (META_PLUGIN (self->compositor));
++
++        G_OBJECT_CLASS (kiosk_screenshot_parent_class)->constructed (object);
++
++        g_set_weak_pointer (&self->display, display);
++        g_set_weak_pointer (&self->context, meta_display_get_context (self->display));
++        g_set_weak_pointer (&self->backend, meta_context_get_backend (self->context));
++        g_set_weak_pointer (&self->stage, CLUTTER_ACTOR (meta_get_stage_for_display (self->display)));
++}
++
++static void
++kiosk_screenshot_set_property (GObject      *object,
++                               guint         property_id,
++                               const GValue *value,
++                               GParamSpec   *param_spec)
++{
++        KioskScreenshot *self = KIOSK_SCREENSHOT (object);
++
++        switch (property_id) {
++        case PROP_COMPOSITOR:
++                g_set_weak_pointer (&self->compositor, g_value_get_object (value));
++                break;
++
++        default:
++                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
++                break;
++        }
++}
++
++static void
++kiosk_screenshot_get_property (GObject    *object,
++                               guint       property_id,
++                               GValue     *value,
++                               GParamSpec *param_spec)
++{
++        switch (property_id) {
++        default:
++                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
++                break;
++        }
++}
++
++static void
++kiosk_screenshot_class_init (KioskScreenshotClass *screenshot_class)
++{
++        GObjectClass *object_class = G_OBJECT_CLASS (screenshot_class);
++
++        object_class->constructed = kiosk_screenshot_constructed;
++        object_class->set_property = kiosk_screenshot_set_property;
++        object_class->get_property = kiosk_screenshot_get_property;
++        object_class->dispose = kiosk_screenshot_dispose;
++
++        kiosk_screenshot_properties[PROP_COMPOSITOR] = g_param_spec_object ("compositor",
++                                                                            "compositor",
++                                                                            "compositor",
++                                                                            KIOSK_TYPE_COMPOSITOR,
++                                                                            G_PARAM_CONSTRUCT_ONLY
++                                                                            | G_PARAM_WRITABLE
++                                                                            | G_PARAM_STATIC_NAME
++                                                                            | G_PARAM_STATIC_NICK
++                                                                            | G_PARAM_STATIC_BLURB);
++        g_object_class_install_properties (object_class, NUMBER_OF_PROPERTIES, kiosk_screenshot_properties);
++
++        signals[SCREENSHOT_TAKEN] =
++                g_signal_new ("screenshot-taken",
++                              G_TYPE_FROM_CLASS (object_class),
++                              G_SIGNAL_RUN_LAST,
++                              0,
++                              NULL, NULL, NULL,
++                              G_TYPE_NONE,
++                              1,
++                              MTK_TYPE_RECTANGLE);
++}
++
++static void
++kiosk_screenshot_init (KioskScreenshot *screenshot)
++{
++        g_debug ("KiosScreenshot: Initializing");
++}
++
++static void
++on_screenshot_written (GObject      *source,
++                       GAsyncResult *task,
++                       gpointer      user_data)
++{
++        KioskScreenshot *screenshot = KIOSK_SCREENSHOT (source);
++        GTask *result = user_data;
++
++        g_task_return_boolean (result, g_task_propagate_boolean (G_TASK (task), NULL));
++        g_object_unref (result);
++
++        g_clear_pointer (&screenshot->image, cairo_surface_destroy);
++        g_clear_object (&screenshot->stream);
++        g_clear_pointer (&screenshot->datetime, g_date_time_unref);
++}
++
++static cairo_format_t
++util_cairo_format_for_content (cairo_content_t  content)
++{
++        switch (content) {
++        case CAIRO_CONTENT_COLOR:
++                return CAIRO_FORMAT_RGB24;
++        case CAIRO_CONTENT_ALPHA:
++                return CAIRO_FORMAT_A8;
++        case CAIRO_CONTENT_COLOR_ALPHA:
++        default:
++                return CAIRO_FORMAT_ARGB32;
++        }
++}
++
++static cairo_surface_t *
++util_cairo_surface_coerce_to_image (cairo_surface_t *surface,
++                                    cairo_content_t  content,
++                                    int              src_x,
++                                    int              src_y,
++                                    int              width,
++                                    int              height)
++{
++        cairo_surface_t *copy;
++        cairo_t *cr;
++
++        copy = cairo_image_surface_create (util_cairo_format_for_content (content),
++                                           width,
++                                           height);
++
++        cr = cairo_create (copy);
++        cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
++        cairo_set_source_surface (cr, surface, -src_x, -src_y);
++        cairo_paint (cr);
++        cairo_destroy (cr);
++
++        return copy;
++}
++
++static void
++convert_alpha (guchar *dest_data,
++               int     dest_stride,
++               guchar *src_data,
++               int     src_stride,
++               int     src_x,
++               int     src_y,
++               int     width,
++               int     height)
++{
++        int x, y;
++
++        src_data += src_stride * src_y + src_x * 4;
++
++        for (y = 0; y < height; y++) {
++                uint32_t *src = (guint32 *) src_data;
++
++                for (x = 0; x < width; x++) {
++                        unsigned int alpha = src[x] >> 24;
++
++                        if (alpha == 0) {
++                                dest_data[x * 4 + 0] = 0;
++                                dest_data[x * 4 + 1] = 0;
++                                dest_data[x * 4 + 2] = 0;
++                        } else {
++                                dest_data[x * 4 + 0] = (((src[x] & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
++                                dest_data[x * 4 + 1] = (((src[x] & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
++                                dest_data[x * 4 + 2] = (((src[x] & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
++                        }
++                        dest_data[x * 4 + 3] = alpha;
++                }
++
++                src_data += src_stride;
++                dest_data += dest_stride;
++        }
++}
++
++static void
++convert_no_alpha (guchar *dest_data,
++                  int     dest_stride,
++                  guchar *src_data,
++                  int     src_stride,
++                  int     src_x,
++                  int     src_y,
++                  int     width,
++                  int     height)
++{
++        int x, y;
++
++        src_data += src_stride * src_y + src_x * 4;
++
++        for (y = 0; y < height; y++) {
++                uint32_t *src = (uint32_t *) src_data;
++
++                for (x = 0; x < width; x++) {
++                        dest_data[x * 3 + 0] = src[x] >> 16;
++                        dest_data[x * 3 + 1] = src[x] >> 8;
++                        dest_data[x * 3 + 2] = src[x];
++                }
++
++                src_data += src_stride;
++                dest_data += dest_stride;
++        }
++}
++
++static GdkPixbuf *
++util_pixbuf_from_surface (cairo_surface_t *surface,
++                          gint             src_x,
++                          gint             src_y,
++                          gint             width,
++                          gint             height)
++{
++        cairo_content_t content;
++        GdkPixbuf *dest;
++
++        /* General sanity checks */
++        g_return_val_if_fail (surface != NULL, NULL);
++        g_return_val_if_fail (width > 0 && height > 0, NULL);
++
++        content = cairo_surface_get_content (surface) | CAIRO_CONTENT_COLOR;
++        dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
++                               !!(content & CAIRO_CONTENT_ALPHA),
++                               8,
++                               width, height);
++
++        if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE &&
++            cairo_image_surface_get_format (surface) == util_cairo_format_for_content (content)) {
++                surface = cairo_surface_reference (surface);
++        } else {
++                surface = util_cairo_surface_coerce_to_image (surface, content,
++                                                              src_x, src_y,
++                                                              width, height);
++                src_x = 0;
++                src_y = 0;
++        }
++        cairo_surface_flush (surface);
++        if (cairo_surface_status (surface) || dest == NULL) {
++                cairo_surface_destroy (surface);
++                g_clear_object (&dest);
++                return NULL;
++        }
++
++        if (gdk_pixbuf_get_has_alpha (dest)) {
++                convert_alpha (gdk_pixbuf_get_pixels (dest),
++                               gdk_pixbuf_get_rowstride (dest),
++                               cairo_image_surface_get_data (surface),
++                               cairo_image_surface_get_stride (surface),
++                               src_x, src_y,
++                               width, height);
++        } else {
++                convert_no_alpha (gdk_pixbuf_get_pixels (dest),
++                                  gdk_pixbuf_get_rowstride (dest),
++                                  cairo_image_surface_get_data (surface),
++                                  cairo_image_surface_get_stride (surface),
++                                  src_x, src_y,
++                                  width, height);
++        }
++
++        cairo_surface_destroy (surface);
++
++        return dest;
++}
++
++static void
++write_screenshot_thread (GTask        *result,
++                         gpointer      object,
++                         gpointer      task_data,
++                         GCancellable *cancellable)
++{
++        KioskScreenshot *screenshot = KIOSK_SCREENSHOT (object);
++        g_autoptr (GOutputStream) stream = NULL;
++        g_autoptr (GdkPixbuf) pixbuf = NULL;
++        g_autofree char *creation_time = NULL;
++        GError *error = NULL;
++
++        g_assert (screenshot != NULL);
++
++        stream = g_object_ref (screenshot->stream);
++
++        pixbuf = util_pixbuf_from_surface (screenshot->image,
++                                           0, 0,
++                                           cairo_image_surface_get_width (screenshot->image),
++                                           cairo_image_surface_get_height (screenshot->image));
++        creation_time = g_date_time_format (screenshot->datetime, "%c");
++
++        if (!creation_time)
++                creation_time = g_date_time_format (screenshot->datetime, "%FT%T%z");
++
++        gdk_pixbuf_save_to_stream (pixbuf, stream, "png", NULL, &error,
++                                   "tEXt::Software", "gnome-screenshot",
++                                   "tEXt::Creation Time", creation_time,
++                                   NULL);
++
++        if (error)
++                g_task_return_error (result, error);
++        else
++                g_task_return_boolean (result, TRUE);
++}
++
++static void
++do_grab_screenshot (KioskScreenshot     *screenshot,
++                    int                  x,
++                    int                  y,
++                    int                  width,
++                    int                  height,
++                    KioskScreenshotFlag  flags)
++{
++        MtkRectangle screenshot_rect = { x, y, width, height };
++        int image_width;
++        int image_height;
++        float scale;
++        cairo_surface_t *image;
++        ClutterPaintFlag paint_flags = CLUTTER_PAINT_FLAG_NONE;
++        g_autoptr (GError) error = NULL;
++
++        clutter_stage_get_capture_final_size (CLUTTER_STAGE (screenshot->stage),
++                                              &screenshot_rect,
++                                              &image_width,
++                                              &image_height,
++                                              &scale);
++        image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
++                                            image_width, image_height);
++
++        if (flags & KIOSK_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 (CLUTTER_STAGE (screenshot->stage),
++                                            &screenshot_rect, scale,
++                                            cairo_image_surface_get_data (image),
++                                            cairo_image_surface_get_stride (image),
++                                            COGL_PIXEL_FORMAT_CAIRO_ARGB32_COMPAT,
++                                            paint_flags,
++                                            &error)) {
++                cairo_surface_destroy (image);
++                g_warning ("Failed to take screenshot: %s", error->message);
++                return;
++        }
++
++        screenshot->image = image;
++
++        screenshot->datetime = g_date_time_new_now_local ();
++}
++
++static void
++draw_cursor_image (KioskScreenshot *screenshot,
++                   cairo_surface_t *surface,
++                   MtkRectangle     area)
++{
++        CoglTexture *texture;
++        int width, height;
++        int stride;
++        guint8 *data;
++        MetaCursorTracker *tracker;
++        cairo_surface_t *cursor_surface;
++        cairo_t *cr;
++        int x, y;
++        int xhot, yhot;
++        double xscale, yscale;
++        graphene_point_t point;
++
++        tracker = meta_cursor_tracker_get_for_display (screenshot->display);
++        texture = meta_cursor_tracker_get_sprite (tracker);
++
++        if (!texture)
++                return;
++
++        meta_cursor_tracker_get_pointer (tracker, &point, NULL);
++        x = point.x;
++        y = point.y;
++
++        if (!mtk_rectangle_contains_point (&area, point.x, point.y))
++                return;
++
++        meta_cursor_tracker_get_hot (tracker, &xhot, &yhot);
++        width = cogl_texture_get_width (texture);
++        height = cogl_texture_get_height (texture);
++        stride = 4 * width;
++        data = g_new (guint8, stride * height);
++        cogl_texture_get_data (texture, COGL_PIXEL_FORMAT_CAIRO_ARGB32_COMPAT, stride, data);
++
++        /* FIXME: cairo-gl? */
++        cursor_surface = cairo_image_surface_create_for_data (data,
++                                                              CAIRO_FORMAT_ARGB32,
++                                                              width, height,
++                                                              stride);
++
++        cairo_surface_get_device_scale (surface, &xscale, &yscale);
++
++        if (xscale != 1.0 || yscale != 1.0) {
++                int monitor;
++                float monitor_scale;
++                MtkRectangle cursor_rect = {
++                        .x = x, .y = y, .width = width, .height = height
++                };
++
++                monitor = meta_display_get_monitor_index_for_rect (screenshot->display,
++                                                                   &cursor_rect);
++                monitor_scale = meta_display_get_monitor_scale (screenshot->display,
++                                                                monitor);
++
++                cairo_surface_set_device_scale (cursor_surface, monitor_scale, monitor_scale);
++        }
++
++        cr = cairo_create (surface);
++        cairo_set_source_surface (cr,
++                                  cursor_surface,
++                                  x - xhot - area.x,
++                                  y - yhot - area.y);
++        cairo_paint (cr);
++
++        cairo_destroy (cr);
++        cairo_surface_destroy (cursor_surface);
++        g_free (data);
++}
++
++static void
++grab_screenshot (KioskScreenshot     *screenshot,
++                 KioskScreenshotFlag  flags,
++                 GTask               *result)
++{
++        int width, height;
++        GTask *task;
++
++        meta_display_get_size (screenshot->display, &width, &height);
++
++        do_grab_screenshot (screenshot,
++                            0, 0, width, height,
++                            flags);
++
++        screenshot->screenshot_area.x = 0;
++        screenshot->screenshot_area.y = 0;
++        screenshot->screenshot_area.width = width;
++        screenshot->screenshot_area.height = height;
++
++        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 (KioskScreenshot     *screenshot,
++                        KioskScreenshotFlag  flags,
++                        GTask               *result)
++{
++        GTask *task;
++        MetaWindow *window = meta_display_get_focus_window (screenshot->display);
++        ClutterActor *window_actor;
++        gfloat actor_x, actor_y;
++        MtkRectangle rect;
++
++        window_actor = CLUTTER_ACTOR (meta_window_get_compositor_private (window));
++        clutter_actor_get_position (window_actor, &actor_x, &actor_y);
++
++        meta_window_get_frame_rect (window, &rect);
++
++        if (!screenshot->include_frame)
++                meta_window_frame_rect_to_client_rect (window, &rect, &rect);
++
++        screenshot->screenshot_area = rect;
++
++        screenshot->image = meta_window_actor_get_image (META_WINDOW_ACTOR (window_actor),
++                                                         NULL);
++
++        if (!screenshot->image) {
++                g_task_report_new_error (screenshot, on_screenshot_written, result, NULL,
++                                         G_IO_ERROR, G_IO_ERROR_FAILED,
++                                         "Capturing window failed");
++                return;
++        }
++
++        screenshot->datetime = g_date_time_new_now_local ();
++
++        if (flags & KIOSK_SCREENSHOT_FLAG_INCLUDE_CURSOR) {
++                if (meta_window_get_client_type (window) == META_WINDOW_CLIENT_TYPE_WAYLAND) {
++                        float resource_scale;
++                        resource_scale = clutter_actor_get_resource_scale (window_actor);
++
++                        cairo_surface_set_device_scale (screenshot->image, resource_scale, resource_scale);
++                }
++
++                draw_cursor_image (screenshot,
++                                   screenshot->image,
++                                   screenshot->screenshot_area);
++        }
++
++        g_signal_emit (screenshot, signals[SCREENSHOT_TAKEN], 0, &rect);
++
++        task = g_task_new (screenshot, NULL, on_screenshot_written, result);
++        g_task_run_in_thread (task, write_screenshot_thread);
++        g_object_unref (task);
++}
++
++static gboolean
++finish_screenshot (KioskScreenshot *screenshot,
++                   GAsyncResult    *result,
++                   MtkRectangle   **area,
++                   GError         **error)
++{
++        if (!g_task_propagate_boolean (G_TASK (result), error))
++                return FALSE;
++
++        if (area)
++                *area = &screenshot->screenshot_area;
++
++        return TRUE;
++}
++
++static void
++on_after_paint (ClutterStage     *stage,
++                ClutterStageView *view,
++                ClutterFrame     *frame,
++                GTask            *result)
++{
++        KioskScreenshot *screenshot = g_task_get_task_data (result);
++        GTask *task;
++
++        g_signal_handlers_disconnect_by_func (stage, on_after_paint, result);
++
++        if (screenshot->mode == KIOSK_SCREENSHOT_AREA) {
++                do_grab_screenshot (screenshot,
++                                    screenshot->screenshot_area.x,
++                                    screenshot->screenshot_area.y,
++                                    screenshot->screenshot_area.width,
++                                    screenshot->screenshot_area.height,
++                                    screenshot->flags);
++
++                task = g_task_new (screenshot, NULL, on_screenshot_written, result);
++                g_task_run_in_thread (task, write_screenshot_thread);
++        } else {
++                grab_screenshot (screenshot, screenshot->flags, result);
++        }
++
++        g_signal_emit (screenshot, signals[SCREENSHOT_TAKEN], 0,
++                       (MtkRectangle *) &screenshot->screenshot_area);
++
++        meta_enable_unredirect_for_display (screenshot->display);
++}
++
++/**
++ * kiosk_screenshot_screenshot:
++ * @screenshot: the #KioskScreenshot
++ * @include_cursor: Whether to include the cursor or not
++ * @stream: The stream for the screenshot
++ * @callback: (scope async): function to call returning success or failure
++ * of the async grabbing
++ * @user_data: the data to pass to callback function
++ *
++ * Takes a screenshot of the whole screen
++ * in @stream as png image.
++ *
++ */
++void
++kiosk_screenshot_screenshot (KioskScreenshot     *screenshot,
++                             gboolean             include_cursor,
++                             GOutputStream       *stream,
++                             GAsyncReadyCallback  callback,
++                             gpointer             user_data)
++{
++        GTask *result;
++        KioskScreenshotFlag flags;
++
++        g_return_if_fail (KIOSK_IS_SCREENSHOT (screenshot));
++        g_return_if_fail (G_IS_OUTPUT_STREAM (stream));
++
++        if (screenshot->stream != NULL) {
++                if (callback) {
++                        g_task_report_new_error (screenshot,
++                                                 callback,
++                                                 user_data,
++                                                 kiosk_screenshot_screenshot,
++                                                 G_IO_ERROR,
++                                                 G_IO_ERROR_PENDING,
++                                                 "Only one screenshot operation at a time "
++                                                 "is permitted");
++                }
++                return;
++        }
++
++        result = g_task_new (screenshot, NULL, callback, user_data);
++        g_task_set_source_tag (result, kiosk_screenshot_screenshot);
++        g_task_set_task_data (result, screenshot, NULL);
++
++        screenshot->stream = g_object_ref (stream);
++
++        flags = KIOSK_SCREENSHOT_FLAG_NONE;
++        if (include_cursor)
++                flags |= KIOSK_SCREENSHOT_FLAG_INCLUDE_CURSOR;
++
++        if (meta_is_wayland_compositor ()) {
++                grab_screenshot (screenshot, flags, result);
++
++                g_signal_emit (screenshot, signals[SCREENSHOT_TAKEN], 0,
++                               (MtkRectangle *) &screenshot->screenshot_area);
++        } else {
++                meta_disable_unredirect_for_display (screenshot->display);
++                clutter_actor_queue_redraw (CLUTTER_ACTOR (screenshot->stage));
++                screenshot->flags = flags;
++                screenshot->mode = KIOSK_SCREENSHOT_SCREEN;
++                g_signal_connect (screenshot->stage, "after-paint",
++                                  G_CALLBACK (on_after_paint), result);
++        }
++}
++
++/**
++ * kiosk_screenshot_screenshot_finish:
++ * @screenshot: the #KioskScreenshot
++ * @result: the #GAsyncResult that was provided to the callback
++ * @area: (out) (transfer none): the area that was grabbed in screen coordinates
++ * @error: #GError for error reporting
++ *
++ * Finish the asynchronous operation started by kiosk_screenshot_screenshot()
++ * and obtain its result.
++ *
++ * Returns: whether the operation was successful
++ *
++ */
++gboolean
++kiosk_screenshot_screenshot_finish (KioskScreenshot *screenshot,
++                                    GAsyncResult    *result,
++                                    MtkRectangle   **area,
++                                    GError         **error)
++{
++        g_return_val_if_fail (KIOSK_IS_SCREENSHOT (screenshot), FALSE);
++        g_return_val_if_fail (G_IS_TASK (result), FALSE);
++        g_return_val_if_fail (g_async_result_is_tagged (result,
++                                                        kiosk_screenshot_screenshot),
++                              FALSE);
++        return finish_screenshot (screenshot, result, area, error);
++}
++
++/**
++ * kiosk_screenshot_screenshot_area:
++ * @screenshot: the #KioskScreenshot
++ * @x: The X coordinate of the area
++ * @y: The Y coordinate of the area
++ * @width: The width of the area
++ * @height: The height of the area
++ * @stream: The stream for the screenshot
++ * @callback: (scope async): function to call returning success or failure
++ * of the async grabbing
++ * @user_data: the data to pass to callback function
++ *
++ * Takes a screenshot of the passed in area and saves it
++ * in @stream as png image.
++ *
++ */
++void
++kiosk_screenshot_screenshot_area (KioskScreenshot     *screenshot,
++                                  int                  x,
++                                  int                  y,
++                                  int                  width,
++                                  int                  height,
++                                  GOutputStream       *stream,
++                                  GAsyncReadyCallback  callback,
++                                  gpointer             user_data)
++{
++        GTask *result;
++        g_autoptr (GTask) task = NULL;
++
++        g_return_if_fail (KIOSK_IS_SCREENSHOT (screenshot));
++        g_return_if_fail (G_IS_OUTPUT_STREAM (stream));
++
++        if (screenshot->stream != NULL) {
++                if (callback) {
++                        g_task_report_new_error (screenshot,
++                                                 callback,
++                                                 NULL,
++                                                 kiosk_screenshot_screenshot_area,
++                                                 G_IO_ERROR,
++                                                 G_IO_ERROR_PENDING,
++                                                 "Only one screenshot operation at a time "
++                                                 "is permitted");
++                }
++                return;
++        }
++
++        result = g_task_new (screenshot, NULL, callback, user_data);
++        g_task_set_source_tag (result, kiosk_screenshot_screenshot_area);
++        g_task_set_task_data (result, screenshot, NULL);
++
++        screenshot->stream = g_object_ref (stream);
++        screenshot->screenshot_area.x = x;
++        screenshot->screenshot_area.y = y;
++        screenshot->screenshot_area.width = width;
++        screenshot->screenshot_area.height = height;
++
++
++        if (meta_is_wayland_compositor ()) {
++                do_grab_screenshot (screenshot,
++                                    screenshot->screenshot_area.x,
++                                    screenshot->screenshot_area.y,
++                                    screenshot->screenshot_area.width,
++                                    screenshot->screenshot_area.height,
++                                    KIOSK_SCREENSHOT_FLAG_NONE);
++
++                g_signal_emit (screenshot, signals[SCREENSHOT_TAKEN], 0,
++                               (MtkRectangle *) &screenshot->screenshot_area);
++
++                task = g_task_new (screenshot, NULL, on_screenshot_written, result);
++                g_task_run_in_thread (task, write_screenshot_thread);
++        } else {
++                meta_disable_unredirect_for_display (screenshot->display);
++                clutter_actor_queue_redraw (CLUTTER_ACTOR (screenshot->stage));
++                screenshot->flags = KIOSK_SCREENSHOT_FLAG_NONE;
++                screenshot->mode = KIOSK_SCREENSHOT_AREA;
++                g_signal_connect (screenshot->stage, "after-paint",
++                                  G_CALLBACK (on_after_paint), result);
++        }
++}
++
++/**
++ * kiosk_screenshot_screenshot_area_finish:
++ * @screenshot: the #KioskScreenshot
++ * @result: the #GAsyncResult that was provided to the callback
++ * @area: (out) (transfer none): the area that was grabbed in screen coordinates
++ * @error: #GError for error reporting
++ *
++ * Finish the asynchronous operation started by kiosk_screenshot_screenshot_area()
++ * and obtain its result.
++ *
++ * Returns: whether the operation was successful
++ *
++ */
++gboolean
++kiosk_screenshot_screenshot_area_finish (KioskScreenshot *screenshot,
++                                         GAsyncResult    *result,
++                                         MtkRectangle   **area,
++                                         GError         **error)
++{
++        g_return_val_if_fail (KIOSK_IS_SCREENSHOT (screenshot), FALSE);
++        g_return_val_if_fail (G_IS_TASK (result), FALSE);
++        g_return_val_if_fail (g_async_result_is_tagged (result,
++                                                        kiosk_screenshot_screenshot_area),
++                              FALSE);
++        return finish_screenshot (screenshot, result, area, error);
++}
++
++/**
++ * kiosk_screenshot_screenshot_window:
++ * @screenshot: the #KioskScreenshot
++ * @include_frame: Whether to include the frame or not
++ * @include_cursor: Whether to include the cursor or not
++ * @stream: The stream for the screenshot
++ * @callback: (scope async): function to call returning success or failure
++ * of the async grabbing
++ * @user_data: the data to pass to callback function
++ *
++ * Takes a screenshot of the focused window (optionally omitting the frame)
++ * in @stream as png image.
++ *
++ */
++void
++kiosk_screenshot_screenshot_window (KioskScreenshot     *screenshot,
++                                    gboolean             include_frame,
++                                    gboolean             include_cursor,
++                                    GOutputStream       *stream,
++                                    GAsyncReadyCallback  callback,
++                                    gpointer             user_data)
++{
++        MetaWindow *window;
++        GTask *result;
++
++        g_return_if_fail (KIOSK_IS_SCREENSHOT (screenshot));
++        g_return_if_fail (G_IS_OUTPUT_STREAM (stream));
++
++        window = meta_display_get_focus_window (screenshot->display);
++
++        if (screenshot->stream != NULL || !window) {
++                if (callback) {
++                        g_task_report_new_error (screenshot,
++                                                 callback,
++                                                 NULL,
++                                                 kiosk_screenshot_screenshot_window,
++                                                 G_IO_ERROR,
++                                                 G_IO_ERROR_PENDING,
++                                                 "Only one screenshot operation at a time "
++                                                 "is permitted");
++                }
++                return;
++        }
++
++        result = g_task_new (screenshot, NULL, callback, user_data);
++        g_task_set_source_tag (result, kiosk_screenshot_screenshot_window);
++
++        screenshot->stream = g_object_ref (stream);
++        screenshot->include_frame = include_frame;
++
++        grab_window_screenshot (screenshot, include_cursor, result);
++}
++
++/**
++ * kiosk_screenshot_screenshot_window_finish:
++ * @screenshot: the #KioskScreenshot
++ * @result: the #GAsyncResult that was provided to the callback
++ * @area: (out) (transfer none): the area that was grabbed in screen coordinates
++ * @error: #GError for error reporting
++ *
++ * Finish the asynchronous operation started by kiosk_screenshot_screenshot_window()
++ * and obtain its result.
++ *
++ * Returns: whether the operation was successful
++ *
++ */
++gboolean
++kiosk_screenshot_screenshot_window_finish (KioskScreenshot *screenshot,
++                                           GAsyncResult    *result,
++                                           MtkRectangle   **area,
++                                           GError         **error)
++{
++        g_return_val_if_fail (KIOSK_IS_SCREENSHOT (screenshot), FALSE);
++        g_return_val_if_fail (G_IS_TASK (result), FALSE);
++        g_return_val_if_fail (g_async_result_is_tagged (result,
++                                                        kiosk_screenshot_screenshot_window),
++                              FALSE);
++        return finish_screenshot (screenshot, result, area, error);
++}
++
++KioskScreenshot *
++kiosk_screenshot_new (KioskCompositor *compositor)
++{
++        GObject *object;
++
++        object = g_object_new (KIOSK_TYPE_SCREENSHOT,
++                               "compositor", compositor,
++                               NULL);
++
++        return KIOSK_SCREENSHOT (object);
++}
+diff --git a/compositor/kiosk-screenshot.h b/compositor/kiosk-screenshot.h
+new file mode 100644
+index 0000000..ec03fa8
+--- /dev/null
++++ b/compositor/kiosk-screenshot.h
+@@ -0,0 +1,59 @@
++#pragma once
++
++#include <glib-object.h>
++#include <gio/gio.h>
++#include <mtk/mtk.h>
++#include <clutter/clutter.h>
++#include <gdk-pixbuf/gdk-pixbuf.h>
++
++typedef struct _KioskCompositor KioskCompositor;
++
++/**
++ * KioskScreenshot:
++ *
++ * Grabs screenshots of areas and/or windows
++ *
++ * The #KioskScreenshot object is used to take screenshots of screen
++ * areas or windows and write them out as png files.
++ *
++ */
++#define KIOSK_TYPE_SCREENSHOT (kiosk_screenshot_get_type ())
++
++G_DECLARE_FINAL_TYPE (KioskScreenshot, kiosk_screenshot,
++                      KIOSK, SCREENSHOT, GObject)
++
++KioskScreenshot *kiosk_screenshot_new (KioskCompositor * compositor);
++
++void    kiosk_screenshot_screenshot_area (KioskScreenshot     *screenshot,
++                                          int                  x,
++                                          int                  y,
++                                          int                  width,
++                                          int                  height,
++                                          GOutputStream       *stream,
++                                          GAsyncReadyCallback  callback,
++                                          gpointer             user_data);
++gboolean kiosk_screenshot_screenshot_area_finish (KioskScreenshot *screenshot,
++                                                  GAsyncResult    *result,
++                                                  MtkRectangle   **area,
++                                                  GError         **error);
++
++void    kiosk_screenshot_screenshot_window (KioskScreenshot     *screenshot,
++                                            gboolean             include_frame,
++                                            gboolean             include_cursor,
++                                            GOutputStream       *stream,
++                                            GAsyncReadyCallback  callback,
++                                            gpointer             user_data);
++gboolean kiosk_screenshot_screenshot_window_finish (KioskScreenshot *screenshot,
++                                                    GAsyncResult    *result,
++                                                    MtkRectangle   **area,
++                                                    GError         **error);
++
++void    kiosk_screenshot_screenshot (KioskScreenshot     *screenshot,
++                                     gboolean             include_cursor,
++                                     GOutputStream       *stream,
++                                     GAsyncReadyCallback  callback,
++                                     gpointer             user_data);
++gboolean kiosk_screenshot_screenshot_finish (KioskScreenshot *screenshot,
++                                             GAsyncResult    *result,
++                                             MtkRectangle   **area,
++                                             GError         **error);
+diff --git a/meson.build b/meson.build
+index fb9a76d..d1efcab 100644
+--- a/meson.build
++++ b/meson.build
+@@ -123,6 +123,7 @@ compositor_dependencies += dependency('glib-2.0')
+ compositor_dependencies += dependency('gnome-desktop-4')
+ compositor_dependencies += dependency('gobject-2.0')
+ compositor_dependencies += dependency('ibus-1.0')
++compositor_dependencies += dependency('gdk-pixbuf-2.0')
+ compositor_dependencies += dependency(libmutter_cogl_name)
+ compositor_dependencies += dependency(libmutter_cogl_pango_name)
+ compositor_dependencies += dependency(libmutter_clutter_name)
+@@ -153,6 +154,8 @@ compositor_sources += 'compositor/kiosk-input-source-group.c'
+ compositor_sources += 'compositor/kiosk-service.c'
+ compositor_sources += 'compositor/kiosk-shell-service.c'
+ compositor_sources += 'compositor/kiosk-shell-introspect-service.c'
++compositor_sources += 'compositor/kiosk-screenshot.c'
++
+ if mutter_have_x11
+         compositor_sources += 'compositor/kiosk-x-keyboard-manager.c'
+ endif
+-- 
+2.48.1
+
diff --git a/SOURCES/0002-compositor-Add-Shell-Screenshot-support.patch b/SOURCES/0002-compositor-Add-Shell-Screenshot-support.patch
new file mode 100644
index 0000000000000000000000000000000000000000..f3658cece8213caeb91976591dca915b0e68db0b
--- /dev/null
+++ b/SOURCES/0002-compositor-Add-Shell-Screenshot-support.patch
@@ -0,0 +1,892 @@
+From 0ab97a3be415e7cc3937d68fd66a421f96f45417 Mon Sep 17 00:00:00 2001
+From: Olivier Fourdan <ofourdan@redhat.com>
+Date: Fri, 24 Jan 2025 09:41:04 +0100
+Subject: [PATCH 2/2] compositor: Add Shell Screenshot support
+
+Add support for the org.gnome.Shell.Screenshot DBus API which is
+required by the desktop portals.
+
+Not all of the org.gnome.Shell.Screenshot API is implemented though,
+only the non-interactive part which require no UI interaction are
+currently available. Also missing is the pick-color API.
+
+To have access to the Shell screenshot API from all other clients,
+gnome-kiosk needs to be started in unsafe mode (using the command line
+option "--unsafe-mode").
+
+Part-of: <https://gitlab.gnome.org/GNOME/gnome-kiosk/-/merge_requests/61>
+(cherry picked from commit 5338c8ab454b8cad607e2f696a9a352b375dff0d)
+---
+ compositor/kiosk-compositor.c                 |   4 +
+ compositor/kiosk-shell-screenshot-service.c   | 599 ++++++++++++++++++
+ compositor/kiosk-shell-screenshot-service.h   |  23 +
+ .../org.gnome.Shell.Screenshot.xml            | 161 +++++
+ meson.build                                   |  12 +
+ 5 files changed, 799 insertions(+)
+ create mode 100644 compositor/kiosk-shell-screenshot-service.c
+ create mode 100644 compositor/kiosk-shell-screenshot-service.h
+ create mode 100644 dbus-interfaces/org.gnome.Shell.Screenshot.xml
+
+diff --git a/compositor/kiosk-compositor.c b/compositor/kiosk-compositor.c
+index d5a2b64..8432a24 100644
+--- a/compositor/kiosk-compositor.c
++++ b/compositor/kiosk-compositor.c
+@@ -24,6 +24,7 @@
+ #include "kiosk-app-system.h"
+ #include "kiosk-window-tracker.h"
+ #include "kiosk-shell-introspect-service.h"
++#include "kiosk-shell-screenshot-service.h"
+ 
+ #include "org.gnome.DisplayManager.Manager.h"
+ 
+@@ -46,6 +47,7 @@ struct _KioskCompositor
+         KioskAppSystem              *app_system;
+         KioskWindowTracker          *tracker;
+         KioskShellIntrospectService *introspect_service;
++        KioskShellScreenshotService *screenshot_service;
+ };
+ 
+ enum
+@@ -250,6 +252,8 @@ kiosk_compositor_start (MetaPlugin *plugin)
+         self->tracker = kiosk_window_tracker_new (self, self->app_system);
+         self->introspect_service = kiosk_shell_introspect_service_new (self);
+         kiosk_shell_introspect_service_start (self->introspect_service, &error);
++        self->screenshot_service = kiosk_shell_screenshot_service_new (self);
++        kiosk_shell_screenshot_service_start (self->screenshot_service, &error);
+ 
+         if (error != NULL) {
+                 g_debug ("KioskCompositor: Could not start D-Bus service: %s", error->message);
+diff --git a/compositor/kiosk-shell-screenshot-service.c b/compositor/kiosk-shell-screenshot-service.c
+new file mode 100644
+index 0000000..a961905
+--- /dev/null
++++ b/compositor/kiosk-shell-screenshot-service.c
+@@ -0,0 +1,599 @@
++#include "config.h"
++#include "kiosk-shell-screenshot-service.h"
++
++#include <stdlib.h>
++#include <string.h>
++#include <meta/display.h>
++#include <meta/meta-context.h>
++
++#include "kiosk-compositor.h"
++#include "kiosk-screenshot.h"
++
++#define KIOSK_SHELL_SCREENSHOT_SERVICE_BUS_NAME "org.gnome.Shell.Screenshot"
++#define KIOSK_SHELL_SCREENSHOT_SERVICE_OBJECT_PATH "/org/gnome/Shell/Screenshot"
++
++struct _KioskShellScreenshotService
++{
++        KioskShellScreenshotDBusServiceSkeleton parent;
++
++        /* weak references */
++        KioskCompositor                        *compositor;
++        MetaDisplay                            *display;
++        MetaContext                            *context;
++
++        /* strong references */
++        GCancellable                           *cancellable;
++        KioskScreenshot                        *screenshot;
++
++        /* handles */
++        guint                                   bus_id;
++};
++
++struct KioskShellScreenshotCompletion
++{
++        KioskShellScreenshotDBusService *service;
++        GDBusMethodInvocation           *invocation;
++
++        gpointer                         data;
++};
++
++enum
++{
++        PROP_COMPOSITOR = 1,
++        NUMBER_OF_PROPERTIES
++};
++
++static GParamSpec *kiosk_shell_screenshot_service_properties[NUMBER_OF_PROPERTIES] = { NULL, };
++
++static void kiosk_shell_screenshot_dbus_service_interface_init (KioskShellScreenshotDBusServiceIface *interface);
++
++G_DEFINE_TYPE_WITH_CODE (KioskShellScreenshotService,
++                         kiosk_shell_screenshot_service,
++                         KIOSK_TYPE_SHELL_SCREENSHOT_DBUS_SERVICE_SKELETON,
++                         G_IMPLEMENT_INTERFACE (KIOSK_TYPE_SHELL_SCREENSHOT_DBUS_SERVICE,
++                                                kiosk_shell_screenshot_dbus_service_interface_init));
++
++static void kiosk_shell_screenshot_service_set_property (GObject      *object,
++                                                         guint         property_id,
++                                                         const GValue *value,
++                                                         GParamSpec   *param_spec);
++
++static void kiosk_shell_screenshot_service_constructed (GObject *object);
++static void kiosk_shell_screenshot_service_dispose (GObject *object);
++
++static void
++kiosk_shell_screenshot_service_class_init (KioskShellScreenshotServiceClass *shell_service_class)
++{
++        GObjectClass *object_class = G_OBJECT_CLASS (shell_service_class);
++
++        object_class->constructed = kiosk_shell_screenshot_service_constructed;
++        object_class->set_property = kiosk_shell_screenshot_service_set_property;
++        object_class->dispose = kiosk_shell_screenshot_service_dispose;
++
++        kiosk_shell_screenshot_service_properties[PROP_COMPOSITOR] =
++                g_param_spec_object ("compositor",
++                                     NULL,
++                                     NULL,
++                                     KIOSK_TYPE_COMPOSITOR,
++                                     G_PARAM_CONSTRUCT_ONLY
++                                     | G_PARAM_WRITABLE
++                                     | G_PARAM_STATIC_NAME);
++        g_object_class_install_properties (object_class,
++                                           NUMBER_OF_PROPERTIES,
++                                           kiosk_shell_screenshot_service_properties);
++}
++
++static void
++kiosk_shell_screenshot_service_set_property (GObject      *object,
++                                             guint         property_id,
++                                             const GValue *value,
++                                             GParamSpec   *param_spec)
++{
++        KioskShellScreenshotService *self = KIOSK_SHELL_SCREENSHOT_SERVICE (object);
++
++        switch (property_id) {
++        case PROP_COMPOSITOR:
++                g_set_weak_pointer (&self->compositor, g_value_get_object (value));
++                break;
++
++        default:
++                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
++                break;
++        }
++}
++
++static void
++kiosk_shell_screenshot_service_dispose (GObject *object)
++{
++        KioskShellScreenshotService *self = KIOSK_SHELL_SCREENSHOT_SERVICE (object);
++
++        kiosk_shell_screenshot_service_stop (self);
++
++        g_clear_object (&self->screenshot);
++        g_clear_weak_pointer (&self->context);
++        g_clear_weak_pointer (&self->display);
++        g_clear_weak_pointer (&self->compositor);
++
++        G_OBJECT_CLASS (kiosk_shell_screenshot_service_parent_class)->dispose (object);
++}
++
++static void
++kiosk_shell_screenshot_service_constructed (GObject *object)
++{
++        KioskShellScreenshotService *self = KIOSK_SHELL_SCREENSHOT_SERVICE (object);
++
++        self->screenshot = kiosk_screenshot_new (self->compositor);
++
++        g_set_weak_pointer (&self->display, meta_plugin_get_display (META_PLUGIN (self->compositor)));
++        g_set_weak_pointer (&self->context, meta_display_get_context (self->display));
++
++        G_OBJECT_CLASS (kiosk_shell_screenshot_service_parent_class)->constructed (object);
++}
++
++static gboolean
++kiosk_shell_screenshot_check_access (KioskShellScreenshotService *self,
++                                     const char                  *client_unique_name)
++{
++        GValue value = G_VALUE_INIT;
++        gboolean unsafe_mode;
++
++        g_object_get_property (G_OBJECT (self->context), "unsafe-mode", &value);
++        unsafe_mode = g_value_get_boolean (&value);
++        g_debug ("KioskShellScreenshotService: unsafe-mode is %s",
++                 unsafe_mode ? "TRUE" : "FALSE");
++
++        return unsafe_mode;
++}
++
++static void
++completion_dispose (struct KioskShellScreenshotCompletion *completion)
++{
++        g_object_unref (completion->service);
++        g_object_unref (completion->invocation);
++        g_free (completion->data);
++
++        g_free (completion);
++}
++
++static struct KioskShellScreenshotCompletion *
++completion_new (KioskShellScreenshotDBusService *service,
++                GDBusMethodInvocation           *invocation,
++                const char                      *filename)
++{
++        struct KioskShellScreenshotCompletion *completion;
++
++        completion = g_new0 (struct KioskShellScreenshotCompletion, 1);
++        completion->service = g_object_ref (service);
++        completion->invocation = g_object_ref (invocation);
++        completion->data = g_strdup (filename);
++
++        return completion;
++}
++
++static gboolean
++kiosk_shell_screenshot_service_handle_flash_area (KioskShellScreenshotDBusService *object,
++                                                  GDBusMethodInvocation           *invocation,
++                                                  gint                             arg_x,
++                                                  gint                             arg_y,
++                                                  gint                             arg_width,
++                                                  gint                             arg_height)
++{
++        KioskShellScreenshotService *self = KIOSK_SHELL_SCREENSHOT_SERVICE (object);
++        const char *client_unique_name = g_dbus_method_invocation_get_sender (invocation);
++
++        g_debug ("KioskShellScreenshotService: Handling FlashArea(x=%i, y=%i, w=%i, h=%i) from %s",
++                 arg_x, arg_y, arg_width, arg_height, client_unique_name);
++
++        if (!kiosk_shell_screenshot_check_access (self, client_unique_name)) {
++                g_dbus_method_invocation_return_error (invocation,
++                                                       G_DBUS_ERROR,
++                                                       G_DBUS_ERROR_ACCESS_DENIED,
++                                                       "Permission denied");
++                return G_DBUS_METHOD_INVOCATION_HANDLED;
++        }
++
++        g_dbus_method_invocation_return_error (invocation,
++                                               G_DBUS_ERROR,
++                                               G_DBUS_ERROR_NOT_SUPPORTED,
++                                               "FlashArea is not supported");
++
++        return G_DBUS_METHOD_INVOCATION_HANDLED;
++}
++
++static gboolean
++kiosk_shell_screenshot_service_handle_interactive_screenshot (KioskShellScreenshotDBusService *object,
++                                                              GDBusMethodInvocation           *invocation)
++{
++        KioskShellScreenshotService *self = KIOSK_SHELL_SCREENSHOT_SERVICE (object);
++        const char *client_unique_name = g_dbus_method_invocation_get_sender (invocation);
++
++        g_debug ("KioskShellScreenshotService: Handling InteractiveScreenshot() from %s",
++                 client_unique_name);
++
++        if (!kiosk_shell_screenshot_check_access (self, client_unique_name)) {
++                g_dbus_method_invocation_return_error (invocation,
++                                                       G_DBUS_ERROR,
++                                                       G_DBUS_ERROR_ACCESS_DENIED,
++                                                       "Permission denied");
++                return G_DBUS_METHOD_INVOCATION_HANDLED;
++        }
++
++        g_dbus_method_invocation_return_error (invocation,
++                                               G_DBUS_ERROR,
++                                               G_DBUS_ERROR_NOT_SUPPORTED,
++                                               "InteractiveScreenshot is not supported");
++
++        return G_DBUS_METHOD_INVOCATION_HANDLED;
++}
++
++static void
++screenshot_ready_callback (GObject      *source_object,
++                           GAsyncResult *result,
++                           gpointer      data)
++{
++        struct KioskShellScreenshotCompletion *completion = data;
++        KioskShellScreenshotService *self = KIOSK_SHELL_SCREENSHOT_SERVICE (completion->service);
++        g_autoptr (GError) error = NULL;
++        gboolean success = TRUE;
++
++        kiosk_screenshot_screenshot_finish (self->screenshot,
++                                            result,
++                                            NULL,
++                                            &error);
++
++        if (error) {
++                g_warning ("Screenshot failed: %s", error->message);
++                success = FALSE;
++        }
++
++        kiosk_shell_screenshot_dbus_service_complete_screenshot (completion->service,
++                                                                 completion->invocation,
++                                                                 success,
++                                                                 completion->data);
++
++        completion_dispose (completion);
++}
++
++static gboolean
++kiosk_shell_screenshot_service_handle_screenshot (KioskShellScreenshotDBusService *object,
++                                                  GDBusMethodInvocation           *invocation,
++                                                  gboolean                         arg_include_cursor,
++                                                  gboolean                         arg_flash,
++                                                  const gchar                     *arg_filename)
++{
++        KioskShellScreenshotService *self = KIOSK_SHELL_SCREENSHOT_SERVICE (object);
++        const char *client_unique_name = g_dbus_method_invocation_get_sender (invocation);
++        struct KioskShellScreenshotCompletion *completion;
++        g_autoptr (GFile) file = NULL;
++        g_autoptr (GFileOutputStream) stream = NULL;
++        g_autoptr (GError) error = NULL;
++        g_autoptr (GAsyncResult) result = NULL;
++
++        g_debug ("KioskShellScreenshotService: Handling Screenshot(cursor=%i, flash=%i, file='%s') from %s",
++                 arg_include_cursor, arg_flash, arg_filename, client_unique_name);
++
++        if (!kiosk_shell_screenshot_check_access (self, client_unique_name)) {
++                g_dbus_method_invocation_return_error (invocation,
++                                                       G_DBUS_ERROR,
++                                                       G_DBUS_ERROR_ACCESS_DENIED,
++                                                       "Permission denied");
++                return G_DBUS_METHOD_INVOCATION_HANDLED;
++        }
++
++        file = g_file_new_for_path (arg_filename);
++        stream = g_file_create (file, G_FILE_CREATE_NONE, NULL, &error);
++        if (error) {
++                g_dbus_method_invocation_return_error (invocation,
++                                                       G_DBUS_ERROR,
++                                                       G_DBUS_ERROR_FAILED,
++                                                       "Error creating file: %s",
++                                                       error->message);
++
++                return G_DBUS_METHOD_INVOCATION_HANDLED;
++        }
++
++        completion = completion_new (object, invocation, arg_filename);
++        kiosk_screenshot_screenshot (self->screenshot,
++                                     arg_include_cursor,
++                                     G_OUTPUT_STREAM (stream),
++                                     screenshot_ready_callback,
++                                     completion);
++
++        return G_DBUS_METHOD_INVOCATION_HANDLED;
++}
++
++static void
++screenshot_area_ready_callback (GObject      *source_object,
++                                GAsyncResult *result,
++                                gpointer      data)
++{
++        struct KioskShellScreenshotCompletion *completion = data;
++        KioskShellScreenshotService *self = KIOSK_SHELL_SCREENSHOT_SERVICE (completion->service);
++        g_autoptr (GError) error = NULL;
++        gboolean success = TRUE;
++
++        kiosk_screenshot_screenshot_area_finish (self->screenshot,
++                                                 result,
++                                                 NULL,
++                                                 &error);
++
++        if (error) {
++                g_warning ("Screenshot area failed: %s", error->message);
++                success = FALSE;
++        }
++
++        kiosk_shell_screenshot_dbus_service_complete_screenshot_area (completion->service,
++                                                                      completion->invocation,
++                                                                      success,
++                                                                      completion->data);
++
++        completion_dispose (completion);
++}
++
++static gboolean
++kiosk_shell_screenshot_service_handle_screenshot_area (KioskShellScreenshotDBusService *object,
++                                                       GDBusMethodInvocation           *invocation,
++                                                       gint                             arg_x,
++                                                       gint                             arg_y,
++                                                       gint                             arg_width,
++                                                       gint                             arg_height,
++                                                       gboolean                         arg_flash,
++                                                       const gchar                     *arg_filename)
++{
++        KioskShellScreenshotService *self = KIOSK_SHELL_SCREENSHOT_SERVICE (object);
++        const char *client_unique_name = g_dbus_method_invocation_get_sender (invocation);
++        struct KioskShellScreenshotCompletion *completion;
++        g_autoptr (GFile) file = NULL;
++        g_autoptr (GFileOutputStream) stream = NULL;
++        g_autoptr (GError) error = NULL;
++        g_autoptr (GAsyncResult) result = NULL;
++
++        g_debug ("KioskShellScreenshotService: Handling ScreenshotArea(x=%i, y=%i, w=%i, h=%i, flash=%i, file='%s') from %s",
++                 arg_x, arg_y, arg_width, arg_height, arg_flash, arg_filename, client_unique_name);
++
++        if (!kiosk_shell_screenshot_check_access (self, client_unique_name)) {
++                g_dbus_method_invocation_return_error (invocation,
++                                                       G_DBUS_ERROR,
++                                                       G_DBUS_ERROR_ACCESS_DENIED,
++                                                       "Permission denied");
++                return G_DBUS_METHOD_INVOCATION_HANDLED;
++        }
++
++        file = g_file_new_for_path (arg_filename);
++        stream = g_file_create (file, G_FILE_CREATE_NONE, NULL, &error);
++        if (error) {
++                g_dbus_method_invocation_return_error (invocation,
++                                                       G_DBUS_ERROR,
++                                                       G_DBUS_ERROR_FAILED,
++                                                       "Error creating file: %s",
++                                                       error->message);
++
++                return G_DBUS_METHOD_INVOCATION_HANDLED;
++        }
++
++        completion = completion_new (object, invocation, arg_filename);
++        kiosk_screenshot_screenshot_area (self->screenshot,
++                                          arg_x,
++                                          arg_y,
++                                          arg_width,
++                                          arg_height,
++                                          G_OUTPUT_STREAM (stream),
++                                          screenshot_area_ready_callback,
++                                          completion);
++
++        return G_DBUS_METHOD_INVOCATION_HANDLED;
++}
++
++static void
++screenshot_window_ready_callback (GObject      *source_object,
++                                  GAsyncResult *result,
++                                  gpointer      data)
++{
++        struct KioskShellScreenshotCompletion *completion = data;
++        KioskShellScreenshotService *self = KIOSK_SHELL_SCREENSHOT_SERVICE (completion->service);
++        g_autoptr (GError) error = NULL;
++        gboolean success = TRUE;
++
++        kiosk_screenshot_screenshot_window_finish (self->screenshot,
++                                                   result,
++                                                   NULL,
++                                                   &error);
++
++        if (error) {
++                g_warning ("Screenshot window failed: %s", error->message);
++                success = FALSE;
++        }
++
++        kiosk_shell_screenshot_dbus_service_complete_screenshot_window (completion->service,
++                                                                        completion->invocation,
++                                                                        success,
++                                                                        completion->data);
++
++        completion_dispose (completion);
++}
++
++static gboolean
++kiosk_shell_screenshot_service_handle_screenshot_window (KioskShellScreenshotDBusService *object,
++                                                         GDBusMethodInvocation           *invocation,
++                                                         gboolean                         arg_include_frame,
++                                                         gboolean                         arg_include_cursor,
++                                                         gboolean                         arg_flash,
++                                                         const gchar                     *arg_filename)
++{
++        KioskShellScreenshotService *self = KIOSK_SHELL_SCREENSHOT_SERVICE (object);
++        const char *client_unique_name = g_dbus_method_invocation_get_sender (invocation);
++        struct KioskShellScreenshotCompletion *completion;
++        g_autoptr (GFile) file = NULL;
++        g_autoptr (GFileOutputStream) stream = NULL;
++        g_autoptr (GError) error = NULL;
++        g_autoptr (GAsyncResult) result = NULL;
++
++        g_debug ("KioskShellScreenshotService: Handling ScreenshotWindow(frame=%i, cursor=%i, flash=%i, file='%s') from %s",
++                 arg_include_frame, arg_include_cursor, arg_flash, arg_filename, client_unique_name);
++
++        if (!kiosk_shell_screenshot_check_access (self, client_unique_name)) {
++                g_dbus_method_invocation_return_error (invocation,
++                                                       G_DBUS_ERROR,
++                                                       G_DBUS_ERROR_ACCESS_DENIED,
++                                                       "Permission denied");
++                return G_DBUS_METHOD_INVOCATION_HANDLED;
++        }
++
++        file = g_file_new_for_path (arg_filename);
++        stream = g_file_create (file, G_FILE_CREATE_NONE, NULL, &error);
++        if (error) {
++                g_dbus_method_invocation_return_error (invocation,
++                                                       G_DBUS_ERROR,
++                                                       G_DBUS_ERROR_FAILED,
++                                                       "Error creating file: %s",
++                                                       error->message);
++
++                return G_DBUS_METHOD_INVOCATION_HANDLED;
++        }
++
++        completion = completion_new (object, invocation, arg_filename);
++        kiosk_screenshot_screenshot_window (self->screenshot,
++                                            arg_include_frame,
++                                            arg_include_cursor,
++                                            G_OUTPUT_STREAM (stream),
++                                            screenshot_window_ready_callback,
++                                            completion);
++
++        return G_DBUS_METHOD_INVOCATION_HANDLED;
++}
++
++static gboolean
++kiosk_shell_screenshot_service_handle_select_area (KioskShellScreenshotDBusService *object,
++                                                   GDBusMethodInvocation           *invocation)
++{
++        KioskShellScreenshotService *self = KIOSK_SHELL_SCREENSHOT_SERVICE (object);
++        const char *client_unique_name = g_dbus_method_invocation_get_sender (invocation);
++
++        g_debug ("KioskShellScreenshotService: Handling SelectArea() from %s",
++                 client_unique_name);
++
++        if (!kiosk_shell_screenshot_check_access (self, client_unique_name)) {
++                g_dbus_method_invocation_return_error (invocation,
++                                                       G_DBUS_ERROR,
++                                                       G_DBUS_ERROR_ACCESS_DENIED,
++                                                       "Permission denied");
++                return G_DBUS_METHOD_INVOCATION_HANDLED;
++        }
++
++        g_dbus_method_invocation_return_error (invocation,
++                                               G_DBUS_ERROR,
++                                               G_DBUS_ERROR_NOT_SUPPORTED,
++                                               "SelectArea is not supported");
++
++        return G_DBUS_METHOD_INVOCATION_HANDLED;
++}
++
++static void
++kiosk_shell_screenshot_dbus_service_interface_init (KioskShellScreenshotDBusServiceIface *interface)
++{
++        interface->handle_flash_area =
++                kiosk_shell_screenshot_service_handle_flash_area;
++        interface->handle_interactive_screenshot =
++                kiosk_shell_screenshot_service_handle_interactive_screenshot;
++        interface->handle_screenshot =
++                kiosk_shell_screenshot_service_handle_screenshot;
++        interface->handle_screenshot_area =
++                kiosk_shell_screenshot_service_handle_screenshot_area;
++        interface->handle_screenshot_window =
++                kiosk_shell_screenshot_service_handle_screenshot_window;
++        interface->handle_select_area =
++                kiosk_shell_screenshot_service_handle_select_area;
++}
++
++static void
++kiosk_shell_screenshot_service_init (KioskShellScreenshotService *self)
++{
++        g_debug ("KioskShellScreenshotService: Initializing");
++}
++
++KioskShellScreenshotService *
++kiosk_shell_screenshot_service_new (KioskCompositor *compositor)
++{
++        GObject *object;
++
++        object = g_object_new (KIOSK_TYPE_SHELL_SCREENSHOT_SERVICE,
++                               "compositor", compositor,
++                               NULL);
++
++        return KIOSK_SHELL_SCREENSHOT_SERVICE (object);
++}
++
++static void
++on_user_bus_acquired (GDBusConnection             *connection,
++                      const char                  *unique_name,
++                      KioskShellScreenshotService *self)
++{
++        g_autoptr (GError) error = NULL;
++
++        g_debug ("KioskShellScreenshotService: Connected to user bus");
++
++        g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self),
++                                          connection,
++                                          KIOSK_SHELL_SCREENSHOT_SERVICE_OBJECT_PATH,
++                                          &error);
++
++        if (error != NULL) {
++                g_debug ("KioskShellScreenshotService: Could not export interface skeleton: %s",
++                         error->message);
++                g_clear_error (&error);
++        }
++}
++
++static void
++on_bus_name_acquired (GDBusConnection             *connection,
++                      const char                  *name,
++                      KioskShellScreenshotService *self)
++{
++        if (g_strcmp0 (name, KIOSK_SHELL_SCREENSHOT_SERVICE_BUS_NAME) != 0) {
++                return;
++        }
++
++        g_debug ("KioskShellScreenshotService: Acquired name %s", name);
++}
++
++static void
++on_bus_name_lost (GDBusConnection             *connection,
++                  const char                  *name,
++                  KioskShellScreenshotService *self)
++{
++        if (g_strcmp0 (name, KIOSK_SHELL_SCREENSHOT_SERVICE_BUS_NAME) != 0) {
++                return;
++        }
++
++        g_debug ("KioskShellScreenshotService: Lost name %s", name);
++}
++
++gboolean
++kiosk_shell_screenshot_service_start (KioskShellScreenshotService *self,
++                                      GError                     **error)
++{
++        g_return_val_if_fail (KIOSK_IS_SHELL_SCREENSHOT_SERVICE (self), FALSE);
++
++        g_debug ("KioskShellScreenshotService: Starting");
++        self->bus_id = g_bus_own_name (G_BUS_TYPE_SESSION,
++                                       KIOSK_SHELL_SCREENSHOT_SERVICE_BUS_NAME,
++                                       G_BUS_NAME_OWNER_FLAGS_REPLACE,
++                                       (GBusAcquiredCallback) on_user_bus_acquired,
++                                       (GBusNameAcquiredCallback) on_bus_name_acquired,
++                                       (GBusNameVanishedCallback) on_bus_name_lost,
++                                       self,
++                                       NULL);
++
++        return TRUE;
++}
++
++void
++kiosk_shell_screenshot_service_stop (KioskShellScreenshotService *self)
++{
++        g_return_if_fail (KIOSK_IS_SHELL_SCREENSHOT_SERVICE (self));
++
++        g_debug ("KioskShellScreenshotService: Stopping");
++
++        g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self));
++        g_clear_handle_id (&self->bus_id, g_bus_unown_name);
++}
+diff --git a/compositor/kiosk-shell-screenshot-service.h b/compositor/kiosk-shell-screenshot-service.h
+new file mode 100644
+index 0000000..520c319
+--- /dev/null
++++ b/compositor/kiosk-shell-screenshot-service.h
+@@ -0,0 +1,23 @@
++#pragma once
++
++#include <glib-object.h>
++
++#include "org.gnome.Shell.Screenshot.h"
++
++typedef struct _KioskCompositor KioskCompositor;
++
++G_BEGIN_DECLS
++
++#define KIOSK_TYPE_SHELL_SCREENSHOT_SERVICE (kiosk_shell_screenshot_service_get_type ())
++
++G_DECLARE_FINAL_TYPE (KioskShellScreenshotService,
++                      kiosk_shell_screenshot_service,
++                      KIOSK, SHELL_SCREENSHOT_SERVICE,
++                      KioskShellScreenshotDBusServiceSkeleton);
++
++KioskShellScreenshotService *kiosk_shell_screenshot_service_new (KioskCompositor *compositor);
++gboolean kiosk_shell_screenshot_service_start (KioskShellScreenshotService *service,
++                                               GError                     **error);
++void kiosk_shell_screenshot_service_stop (KioskShellScreenshotService *service);
++
++G_END_DECLS
+diff --git a/dbus-interfaces/org.gnome.Shell.Screenshot.xml b/dbus-interfaces/org.gnome.Shell.Screenshot.xml
+new file mode 100644
+index 0000000..8e16a30
+--- /dev/null
++++ b/dbus-interfaces/org.gnome.Shell.Screenshot.xml
+@@ -0,0 +1,161 @@
++<!DOCTYPE node PUBLIC
++'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
++'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
++<node>
++
++  <!--
++      org.gnome.Shell.Screenshot:
++      @short_description: Screenshot interface
++
++      The interface used to capture pictures of the screen contents.
++  -->
++  <interface name="org.gnome.Shell.Screenshot">
++
++    <!--
++        InteractiveScreenshot:
++        @success: whether the screenshot was captured
++        @uri: the file where the screenshot was saved
++
++        Shows Shell's interactive screenshot dialog, and lets the
++        user take an interactive screenshot, which is then returned
++        in @filename as png image. It returns a boolean indicating
++        whether the operation was successful or not. The URI of the
++        screenshot will be returned in @uri.
++    -->
++    <method name="InteractiveScreenshot">
++      <arg type="b" direction="out" name="success"/>
++      <arg type="s" direction="out" name="uri"/>
++    </method>
++
++    <!--
++        Screenshot:
++        @filename: The filename for the screenshot
++        @include_cursor: Whether to include the cursor image or not
++        @flash: Whether to flash the screen or not
++        @success: whether the screenshot was captured
++        @filename_used: the file where the screenshot was saved
++
++        Takes a screenshot of the whole screen and saves it
++        in @filename as png image, it returns a boolean
++        indicating whether the operation was successful or not.
++        @filename can either be an absolute path or a basename, in
++        which case the screenshot will be saved in the $XDG_PICTURES_DIR
++        or the home directory if it doesn't exist. The filename used
++        to save the screenshot will be returned in @filename_used.
++    -->
++    <method name="Screenshot">
++      <arg type="b" direction="in" name="include_cursor"/>
++      <arg type="b" direction="in" name="flash"/>
++      <arg type="s" direction="in" name="filename"/>
++      <arg type="b" direction="out" name="success"/>
++      <arg type="s" direction="out" name="filename_used"/>
++    </method>
++
++    <!--
++        ScreenshotWindow:
++        @include_frame: Whether to include the frame or not
++        @include_cursor: Whether to include the cursor image or not
++        @flash: Whether to flash the window area or not
++        @filename: The filename for the screenshot
++        @success: whether the screenshot was captured
++        @filename_used: the file where the screenshot was saved
++
++        Takes a screenshot of the focused window (optionally omitting the frame)
++        and saves it in @filename as png image, it returns a boolean
++        indicating whether the operation was successful or not.
++        @filename can either be an absolute path or a basename, in
++        which case the screenshot will be saved in the $XDG_PICTURES_DIR
++        or the home directory if it doesn't exist. The filename used
++        to save the screenshot will be returned in @filename_used.
++    -->
++    <method name="ScreenshotWindow">
++      <arg type="b" direction="in" name="include_frame"/>
++      <arg type="b" direction="in" name="include_cursor"/>
++      <arg type="b" direction="in" name="flash"/>
++      <arg type="s" direction="in" name="filename"/>
++      <arg type="b" direction="out" name="success"/>
++      <arg type="s" direction="out" name="filename_used"/>
++    </method>
++
++    <!--
++        ScreenshotArea:
++        @x: the X coordinate of the area to capture
++        @y: the Y coordinate of the area to capture
++        @width: the width of the area to capture
++        @height: the height of the area to capture
++        @flash: whether to flash the area or not
++        @filename: the filename for the screenshot
++        @success: whether the screenshot was captured
++        @filename_used: the file where the screenshot was saved
++
++        Takes a screenshot of the passed in area and saves it
++        in @filename as png image, it returns a boolean
++        indicating whether the operation was successful or not.
++        @filename can either be an absolute path or a basename, in
++        which case the screenshot will be saved in the $XDG_PICTURES_DIR
++        or the home directory if it doesn't exist. The filename used
++        to save the screenshot will be returned in @filename_used.
++    -->
++    <method name="ScreenshotArea">
++      <arg type="i" direction="in" name="x"/>
++      <arg type="i" direction="in" name="y"/>
++      <arg type="i" direction="in" name="width"/>
++      <arg type="i" direction="in" name="height"/>
++      <arg type="b" direction="in" name="flash"/>
++      <arg type="s" direction="in" name="filename"/>
++      <arg type="b" direction="out" name="success"/>
++      <arg type="s" direction="out" name="filename_used"/>
++    </method>
++
++    <!--
++        PickColor:
++
++        Picks a color and returns the result.
++
++        The @result vardict contains:
++        <variablelist>
++          <varlistentry>
++            <term>color (ddd)</term>
++            <listitem><para>The color, RGB values in the range [0,1].</para></listitem>
++          </varlistentry>
++        </variablelist>
++    -->
++    <method name="PickColor">
++      <arg type="a{sv}" direction="out" name="result"/>
++    </method>
++
++    <!--
++        FlashArea:
++        @x: the X coordinate of the area to flash
++        @y: the Y coordinate of the area to flash
++        @width: the width of the area to flash
++        @height: the height of the area to flash
++
++        Renders a flash spot effect in the specified rectangle of the screen.
++    -->
++    <method name="FlashArea">
++      <arg type="i" direction="in" name="x"/>
++      <arg type="i" direction="in" name="y"/>
++      <arg type="i" direction="in" name="width"/>
++      <arg type="i" direction="in" name="height"/>
++    </method>
++
++    <!--
++        SelectArea:
++        @x: the X coordinate of the selected area
++        @y: the Y coordinate of the selected area
++        @width: the width of the selected area
++        @height: the height of the selected area
++
++        Interactively allows the user to select a rectangular area of
++        the screen, and returns its coordinates.
++    -->
++    <method name="SelectArea">
++      <arg type="i" direction="out" name="x"/>
++      <arg type="i" direction="out" name="y"/>
++      <arg type="i" direction="out" name="width"/>
++      <arg type="i" direction="out" name="height"/>
++    </method>
++
++  </interface>
++</node>
+diff --git a/meson.build b/meson.build
+index d1efcab..d5941bf 100644
+--- a/meson.build
++++ b/meson.build
+@@ -116,6 +116,17 @@ sources = gnome.gdbus_codegen(dbus_interface, dbus_interface_file,
+ )
+ dbus_interface_sources_map += { dbus_interface: sources }
+ 
++dbus_interface = 'org.gnome.Shell.Screenshot'
++dbus_interface_file = join_paths('dbus-interfaces', dbus_interface + '.xml')
++sources = gnome.gdbus_codegen(dbus_interface, dbus_interface_file,
++        namespace: 'Kiosk',
++        interface_prefix: 'org.gnome',
++        annotations: [
++                [ dbus_interface, 'org.gtk.GDBus.C.Name', 'ShellScreenshotDBusService' ]
++        ]
++)
++dbus_interface_sources_map += { dbus_interface: sources }
++
+ compositor_dependencies = []
+ compositor_dependencies += c_compiler.find_library('m')
+ compositor_dependencies += dependency('gio-2.0')
+@@ -154,6 +165,7 @@ compositor_sources += 'compositor/kiosk-input-source-group.c'
+ compositor_sources += 'compositor/kiosk-service.c'
+ compositor_sources += 'compositor/kiosk-shell-service.c'
+ compositor_sources += 'compositor/kiosk-shell-introspect-service.c'
++compositor_sources += 'compositor/kiosk-shell-screenshot-service.c'
+ compositor_sources += 'compositor/kiosk-screenshot.c'
+ 
+ if mutter_have_x11
+-- 
+2.48.1
+
diff --git a/SPECS/gnome-kiosk.spec b/SPECS/gnome-kiosk.spec
index fdd435afcb79f92d2c51a855914a7f68462a4d63..85177fdf138b6403745ef6bd94481589e0270415 100644
--- a/SPECS/gnome-kiosk.spec
+++ b/SPECS/gnome-kiosk.spec
@@ -2,7 +2,7 @@
 ## (rpmautospec version 0.7.3)
 ## RPMAUTOSPEC: autorelease, autochangelog
 %define autorelease(e:s:pb:n) %{?-p:0.}%{lua:
-    release_number = 6;
+    release_number = 7;
     base_release_number = tonumber(rpm.expand("%{?-b*}%{!?-b:1}"));
     print(release_number + base_release_number - 1);
 }%{?-e:.%{-e*}}%{?-s:.%{-s*}}%{!?-n:%{?dist}}
@@ -46,6 +46,7 @@ BuildRequires:  pkgconfig(gnome-desktop-4) >= %{gnome_desktop_version}
 BuildRequires:  pkgconfig(gtk4) >= %{gtk4_version}
 BuildRequires:  pkgconfig(ibus-1.0) >= %{ibus_version}
 BuildRequires:  pkgconfig(libmutter-15) >= %{mutter_version}
+BuildRequires:  pkgconfig(gdk-pixbuf-2.0)
 
 Requires:       gnome-settings-daemon%{?_isa} >= %{gnome_settings_daemon_version}
 Requires:       gsettings-desktop-schemas%{?_isa} >= %{gsettings_desktop_schemas_version}
@@ -55,6 +56,9 @@ Patch0: 0001-kiosk-app-Do-not-add-the-window-in-kiosk_app_new_for.patch
 Patch1: 0001-search-app-Use-firefox-from-flatpak.patch
 # https://issues.redhat.com/browse/RHEL-71757
 Patch2: 0001-kiosk-script-Copy-and-run-the-script-from-XDG_RUNTIM.patch
+# https://issues.redhat.com/browse/RHEL-62420
+Patch3: 0001-compositor-Add-screenshot-utilities.patch
+Patch4: 0002-compositor-Add-Shell-Screenshot-support.patch
 
 %description
 GNOME Kiosk provides a desktop enviroment suitable for fixed purpose, or
@@ -123,6 +127,9 @@ desktop-file-validate %{buildroot}%{_datadir}/applications/org.gnome.Kiosk.Searc
 
 %changelog
 ## START: Generated by rpmautospec
+* Thu Feb 13 2025 Olivier Fourdan <ofourdan@redhat.com> - 47.0-7
+- Enable screenshots support
+
 * Fri Dec 20 2024 Olivier Fourdan <ofourdan@redhat.com> - 47.0-6
 - Copy and run the script from XDG_RUNTIME_DIR