893 lines
38 KiB
Diff
893 lines
38 KiB
Diff
|
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
|
||
|
|