Update to 49.0

Resolves: https://issues.redhat.com/browse/RHEL-127385
This commit is contained in:
Florian Müllner 2025-11-10 22:01:12 +01:00
parent 7a50351fc2
commit fd5a0af9d7
No known key found for this signature in database
20 changed files with 7 additions and 3268 deletions

1
.gitignore vendored
View File

@ -14,3 +14,4 @@
/gnome-kiosk-47.alpha.tar.xz
/gnome-kiosk-47.rc.tar.xz
/gnome-kiosk-47.0.tar.xz
/gnome-kiosk-49.0.tar.xz

File diff suppressed because it is too large Load Diff

View File

@ -1,49 +0,0 @@
From 231001c019b379f573baa0e869811fa8c429775b Mon Sep 17 00:00:00 2001
From: Olivier Fourdan <ofourdan@redhat.com>
Date: Wed, 13 Nov 2024 11:36:25 +0100
Subject: [PATCH 1/5] compositor: Use the meta window API for set-above
Currently, GNOME Kiosk would place windows that need to be above in a
special window group on top.
Unfortunately, that means windows in that group will remain there, and
there is no way to send these back to the notmal layer using the
existing mutter API.
To avoid the problem, use the meta_window_make_above() API.
See-also: https://gitlab.gnome.org/GNOME/gnome-kiosk/-/issues/26
(cherry picked from commit 1c2994e5eada4286655d007f91c22452c27f8ead)
---
compositor/kiosk-compositor.c | 14 +++-----------
1 file changed, 3 insertions(+), 11 deletions(-)
diff --git a/compositor/kiosk-compositor.c b/compositor/kiosk-compositor.c
index 8432a24..37588da 100644
--- a/compositor/kiosk-compositor.c
+++ b/compositor/kiosk-compositor.c
@@ -377,18 +377,10 @@ kiosk_compositor_map (MetaPlugin *plugin,
meta_window_make_fullscreen (window);
easing_duration = 3000;
} else {
- ClutterActor *window_group;
-
g_debug ("KioskCompositor: Mapping window that does not need to be fullscreened");
- window_group = meta_get_top_window_group_for_display (self->display);
-
- if (kiosk_compositor_wants_window_above (self, window)) {
- g_object_ref (G_OBJECT (actor));
- clutter_actor_remove_child (clutter_actor_get_parent (CLUTTER_ACTOR (actor)), CLUTTER_ACTOR (actor));
- clutter_actor_add_child (window_group, CLUTTER_ACTOR (actor));
- clutter_actor_set_child_above_sibling (window_group, CLUTTER_ACTOR (actor), NULL);
- g_object_unref (G_OBJECT (actor));
- }
+
+ if (kiosk_compositor_wants_window_above (self, window))
+ meta_window_make_above (window);
easing_duration = 500;
}
--
2.49.0

View File

@ -1,42 +0,0 @@
From 269cf451feb18206f9a8326d8fa36bc36f9b1897 Mon Sep 17 00:00:00 2001
From: Olivier Fourdan <ofourdan@redhat.com>
Date: Wed, 19 Mar 2025 14:41:15 +0100
Subject: [PATCH] input-sources-manager: Do not crash if there is no X11Layouts
When queried for the X11Layout property, localed will try to get the
configuration from /etc/X11/xorg.conf.d/00-keyboard.conf.
If for some reason (the system was misconfigured or the installation was
altered), that directory is not accessible or not present, localed will
return a NULL string instead of the actual X11 layouts or even an empty
string if no X11 layout was ever configured.
In such a case, gnome-kiosk will segfault.
To avoid that potential problem, check for the X11 layouts to be not
NULL or return early if that's not the case.
Fixes: 38407233 - input-sources-manager: Add APIs for setting keymap
Part-of: <https://gitlab.gnome.org/GNOME/gnome-kiosk/-/merge_requests/68>
---
compositor/kiosk-input-sources-manager.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/compositor/kiosk-input-sources-manager.c b/compositor/kiosk-input-sources-manager.c
index 31dab12..6200af5 100644
--- a/compositor/kiosk-input-sources-manager.c
+++ b/compositor/kiosk-input-sources-manager.c
@@ -869,6 +869,10 @@ kiosk_input_sources_manager_set_input_sources_from_system_configuration (KioskIn
g_debug ("KioskInputSourcesManager: Setting keymap from system configuration");
layouts_string = sd_locale1_get_x11_layout (self->locale_proxy);
+ if (layouts_string == NULL) {
+ g_debug ("KioskInputSourcesManager: No layouts defined");
+ return FALSE;
+ }
g_debug ("KioskInputSourcesManager: System layout is '%s'", layouts_string);
layouts = g_strsplit (layouts_string, ",", -1);
--
2.49.0

View File

@ -1,99 +0,0 @@
From 67cb8748dbc8c237d7b7486c7cec9e7902dcb51f Mon Sep 17 00:00:00 2001
From: Olivier Fourdan <ofourdan@redhat.com>
Date: Mon, 7 Oct 2024 18:09:32 +0200
Subject: [PATCH] kiosk-app: Do not add the window in
kiosk_app_new_for_window()
When a window has no matching application (like, when there is no
corresponding desktop file), a KioskApp is created for the window and
the window would be added to the newly-created KioskApp.
However, by doing so, we add the window before the calling window
tracker had a change to setup the state notify handler.
As a result, the window tracker is never notified of the state change
and the KioskApp is never added to the list of running applications in
the KioskAppState.
Too bad, since the introspection iterates on the running applications to
report the windows.
To avoid the issue, simply do not add the window so soon in
kiosk_app_new_for_window(), it will be added in time in track_window()
and the notifications will be correctly triggered.
Fixes: commit 50ae635dc - kiosk-app: Add a new KioskApp class
---
compositor/kiosk-app.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/compositor/kiosk-app.c b/compositor/kiosk-app.c
index acc9d9e..5b19e4e 100644
--- a/compositor/kiosk-app.c
+++ b/compositor/kiosk-app.c
@@ -441,62 +441,60 @@ kiosk_app_remove_window (KioskApp *app,
if (!meta_window_is_skip_taskbar (window))
app->running_state->number_of_interesting_windows--;
kiosk_app_sync_running_state (app);
if (app->running_state->windows == NULL)
g_clear_pointer (&app->running_state, unref_running_state);
g_signal_handlers_disconnect_by_func (window,
G_CALLBACK (kiosk_app_on_user_time_changed),
app);
g_signal_handlers_disconnect_by_func (window,
G_CALLBACK (kiosk_app_on_skip_taskbar_changed),
app);
g_object_unref (window);
g_signal_emit (app, kiosk_app_signals[WINDOWS_CHANGED], 0);
}
KioskApp *
kiosk_app_new_for_window (KioskCompositor *compositor,
MetaWindow *window)
{
KioskApp *app;
app = g_object_new (KIOSK_TYPE_APP, "compositor", compositor, NULL);
app->window_id_string = g_strdup_printf ("window:%d",
meta_window_get_stable_sequence (window));
- kiosk_app_add_window (app, window);
-
return app;
}
KioskApp *
kiosk_app_new (KioskCompositor *compositor,
GDesktopAppInfo *info)
{
KioskApp *app;
app = g_object_new (KIOSK_TYPE_APP,
"compositor", compositor, "app-info", info, NULL);
return app;
}
const char *
kiosk_app_get_sandbox_id (KioskApp *app)
{
KioskAppWindowIter iter;
MetaWindow *window;
kiosk_app_window_iter_init (&iter, app);
while (kiosk_app_window_iter_next (&iter, &window)) {
const char *sandbox_id = meta_window_get_sandboxed_app_id (window);
if (sandbox_id)
return sandbox_id;
}
return NULL;
--
2.46.0

View File

@ -1,56 +0,0 @@
From 9497651214baaae6dabe7cc1971a1799633983a6 Mon Sep 17 00:00:00 2001
From: Olivier Fourdan <ofourdan@redhat.com>
Date: Fri, 22 Nov 2024 17:04:09 +0100
Subject: [PATCH] kiosk-script: Copy and run the script from XDG_RUNTIME_DIR
Some setup may enforce the noexec flag on the HOME directories.
That prevents any executable placed in the HOME directory from running,
including the GNOME Kiosk script session.
To work around such an issue, copy and execute the script from the
XDG_RUNTIME_DIR instead.
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
---
kiosk-script/gnome-kiosk-script | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/kiosk-script/gnome-kiosk-script b/kiosk-script/gnome-kiosk-script
index e45438d..c4ab176 100755
--- a/kiosk-script/gnome-kiosk-script
+++ b/kiosk-script/gnome-kiosk-script
@@ -1,8 +1,10 @@
#!/usr/bin/sh
-if [ ! -e ~/.local/bin/gnome-kiosk-script ]; then
- mkdir -p ~/.local/bin ~/.config
- cat > ~/.local/bin/gnome-kiosk-script <<- "EOF"
+EXECDIR=~/.local/bin
+
+if [ ! -e $EXECDIR/gnome-kiosk-script ]; then
+ mkdir -p $EXECDIR ~/.config
+ cat > $EXECDIR/gnome-kiosk-script <<- "EOF"
#!/bin/sh
# This script is located in ~/.local/bin.
# It's provided as an example script to show how
@@ -16,8 +18,14 @@ if [ ! -e ~/.local/bin/gnome-kiosk-script ]; then
exec "$0" "$@"
EOF
- chmod +x ~/.local/bin/gnome-kiosk-script
+ chmod +x $EXECDIR/gnome-kiosk-script
touch ~/.config/gnome-initial-setup-done
fi
-exec ~/.local/bin/gnome-kiosk-script "$@"
+# Copy and run the script from the XDG_RUNTIME_DIR directory if that exists
+if [ -d $XDG_RUNTIME_DIR ]; then
+ cp $EXECDIR/gnome-kiosk-script $XDG_RUNTIME_DIR/
+ EXECDIR=$XDG_RUNTIME_DIR
+fi
+
+exec $EXECDIR/gnome-kiosk-script "$@"
--
2.47.1

View File

@ -1,68 +0,0 @@
From fea0d74ff155f05e9f1e8e0351562af6c7c15b3c Mon Sep 17 00:00:00 2001
From: Olivier Fourdan <ofourdan@redhat.com>
Date: Tue, 4 Mar 2025 16:21:30 +0100
Subject: [PATCH 1/2] search-app: Add systemd session files
The search appliance session would fail to start as a systemd session.
Add the required systemd plumbing to fix the search appliance session.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-kiosk/-/merge_requests/66>
(cherry picked from commit a40ac8d8dc132d9c94506419158ec4034eaaf2c8)
---
meson.build | 12 ++++++++++++
.../systemd/org.gnome.Kiosk.SearchApp.service.in | 8 ++++++++
search-app/systemd/session.conf | 3 +++
3 files changed, 23 insertions(+)
create mode 100644 search-app/systemd/org.gnome.Kiosk.SearchApp.service.in
create mode 100644 search-app/systemd/session.conf
diff --git a/meson.build b/meson.build
index fb9a76d..2024b76 100644
--- a/meson.build
+++ b/meson.build
@@ -350,5 +350,17 @@ i18n.merge_file(
type: 'desktop'
)
+configure_file(
+ input: 'search-app/systemd/org.gnome.Kiosk.SearchApp.service.in',
+ output: '@BASENAME@',
+ configuration: systemd_service_config_data,
+ install_dir: systemd_user_unit_dir
+)
+
+kiosk_search_appliance_systemd_target_dir = join_paths(systemd_user_unit_dir, 'gnome-session@org.gnome.Kiosk.SearchApp.target.d')
+install_data('search-app/systemd/session.conf',
+ install_dir: kiosk_search_appliance_systemd_target_dir
+)
+
test('check-format', find_program('scripts/check-format.sh'))
diff --git a/search-app/systemd/org.gnome.Kiosk.SearchApp.service.in b/search-app/systemd/org.gnome.Kiosk.SearchApp.service.in
new file mode 100644
index 0000000..29ddcd8
--- /dev/null
+++ b/search-app/systemd/org.gnome.Kiosk.SearchApp.service.in
@@ -0,0 +1,8 @@
+[Unit]
+Description=Kiosk Search Appliance
+BindsTo=gnome-session.target
+After=gnome-session.target
+
+[Service]
+ExecStart=@bindir@/firefox --kiosk --private-window --new-instance https://www.google.com
+Restart=always
diff --git a/search-app/systemd/session.conf b/search-app/systemd/session.conf
new file mode 100644
index 0000000..1ab41da
--- /dev/null
+++ b/search-app/systemd/session.conf
@@ -0,0 +1,3 @@
+[Unit]
+Requires=org.gnome.Kiosk.target
+Requires=org.gnome.Kiosk.SearchApp.service
--
2.48.1

View File

@ -1,4 +1,4 @@
From bad81e556eca3acad1b97f6dbc00f3788e24d25f Mon Sep 17 00:00:00 2001
From c8c4aac6d68bc864fa197d0bef0a747c70dd67f3 Mon Sep 17 00:00:00 2001
From: Olivier Fourdan <ofourdan@redhat.com>
Date: Thu, 12 Dec 2024 14:05:04 +0100
Subject: [PATCH] search-app: Use firefox from flatpak
@ -37,5 +37,5 @@ index 29ddcd8..d4f5d0f 100644
+ExecStart=@bindir@/flatpak run --command=firefox --file-forwarding org.mozilla.firefox --kiosk --private-window --new-instance https://www.google.com
Restart=always
--
2.48.1
2.51.1

View File

@ -1,30 +0,0 @@
From 108aa947aaf8bf14a26756ba078bcf4141b6434b Mon Sep 17 00:00:00 2001
From: Olivier Fourdan <ofourdan@redhat.com>
Date: Wed, 30 Jul 2025 15:15:34 +0200
Subject: [PATCH 1/3] shell-service: Fix GrabAccelerators return value
The DBus definitions expects an array of uint32, not an array of
variants.
(cherry picked from commit e9477c3cbdd81a14888b0b08ef38aa70188f736e)
---
compositor/kiosk-shell-service.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/compositor/kiosk-shell-service.c b/compositor/kiosk-shell-service.c
index a6b4258..4f21ae2 100644
--- a/compositor/kiosk-shell-service.c
+++ b/compositor/kiosk-shell-service.c
@@ -332,8 +332,7 @@ kiosk_shell_service_handle_grab_accelerators (KioskShellDBusService *object,
guint action_id;
action_id = grab_accelerator_for_client (self, accelerator, mode_flags, grab_flags, client_unique_name);
-
- g_variant_builder_add (&builder, "u", g_variant_new_uint32 (action_id));
+ g_variant_builder_add (&builder, "u", action_id);
}
kiosk_shell_dbus_service_complete_grab_accelerators (KIOSK_SHELL_DBUS_SERVICE (self),
--
2.50.1

View File

@ -1,34 +0,0 @@
From 9dd06017bf85eb779579342f7f5e7955017aa893 Mon Sep 17 00:00:00 2001
From: Olivier Fourdan <ofourdan@redhat.com>
Date: Wed, 16 Jul 2025 11:51:49 +0200
Subject: [PATCH] systemd/session: Enable remote session
To be able to get something on screen when starting a session remotely,
using remote login via gdm, the session has to pull in gsd-sharing, i.e.
the session wants the SettingsDaemon Sharing target.
---
kiosk-script/systemd/session.conf | 1 +
search-app/systemd/session.conf | 1 +
2 files changed, 2 insertions(+)
diff --git a/kiosk-script/systemd/session.conf b/kiosk-script/systemd/session.conf
index a948efb..aeb722c 100644
--- a/kiosk-script/systemd/session.conf
+++ b/kiosk-script/systemd/session.conf
@@ -1,3 +1,4 @@
[Unit]
Requires=org.gnome.Kiosk.target
Requires=org.gnome.Kiosk.Script.service
+Wants=org.gnome.SettingsDaemon.Sharing.target
diff --git a/search-app/systemd/session.conf b/search-app/systemd/session.conf
index 1ab41da..d038670 100644
--- a/search-app/systemd/session.conf
+++ b/search-app/systemd/session.conf
@@ -1,3 +1,4 @@
[Unit]
Requires=org.gnome.Kiosk.target
Requires=org.gnome.Kiosk.SearchApp.service
+Wants=org.gnome.SettingsDaemon.Sharing.target
--
2.50.1

View File

@ -1,892 +0,0 @@
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

View File

@ -1,517 +0,0 @@
From f30b19d09bf521f3b731e08551428c5a7afb26c6 Mon Sep 17 00:00:00 2001
From: Olivier Fourdan <ofourdan@redhat.com>
Date: Fri, 11 Oct 2024 14:36:02 +0200
Subject: [PATCH 2/5] compositor: Add a window configuration file
This adds a configuration file to specify the windows configuration at
start-up.
The file is an "ini" style file with sections and keys/values.
There can be as many sections as desired, each section gets evaluated.
There are two categories of keys, the "match" keys and the "set" keys.
The "match" keys are used to filter the windows before applying the
values from the "set" keys.
The "match" keys can take wildcards and patterns.
Currently the following "match" keys as supported:
* match-title (string) - Matches the window title
* match-class (string) - Matches the window class
* match-sandboxed-app-id (string) - Matches the sandboxed application id
The following "set" keys are supported:
* set-fullscreen (boolean) - Whether the window should be fullscreen
* set-x (integer) - the X position
* set-y (integer) - the Y position
* set-width (integer) - the width
* set-height (integer) - the height
E.g.:
# Place all windows at (0,0) by default
[all]
set-x=0
set-y=0
# Make all Mozilla windows fullscreen
[mozilla]
match-class=org.mozilla.*
set-fullscreen=true
# All other windows will be set fullscreen automatically using the
# existing GNOME Kiosk heuristic, as before.
see-also: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4076
(cherry picked from commit 9cb4f91724e489ab8b849ffb83f5a6c01e0ac552)
(cherry picked from commit 047bd8c83f4a6e950b0ce608417cba178df19f10)
---
CONFIG.md | 62 ++++++
compositor/kiosk-window-config.c | 315 +++++++++++++++++++++++++++++++
compositor/kiosk-window-config.h | 21 +++
meson.build | 1 +
window-config.ini | 17 ++
5 files changed, 416 insertions(+)
create mode 100644 CONFIG.md
create mode 100644 compositor/kiosk-window-config.c
create mode 100644 compositor/kiosk-window-config.h
create mode 100644 window-config.ini
diff --git a/CONFIG.md b/CONFIG.md
new file mode 100644
index 0000000..b0045ee
--- /dev/null
+++ b/CONFIG.md
@@ -0,0 +1,62 @@
+# Configuration file
+
+GNOME Kiosk takes a configuration file to specify the windows configuration at start-up.
+
+The configuration file called `window-config.ini` is searched in multiple places on the
+system. The first instance of the file found is used.
+
+ * The base directory in which user-specific application configuration is stored
+ `$XDG_CONFIG_HOME/gnome-kiosk/window-config.ini` (usually `$HOME/.config/gnome-kiosk/window-config.ini`)
+ * The system-wide list of directories in which system-wide application data is stored `$XDG_DATA_DIRS`
+ This list usually includes:
+ - `/var/lib/flatpak/exports/share/gnome-kiosk/window-config.ini`
+ - `/usr/local/share/gnome-kiosk/window-config.ini`
+ - `/usr/share/gnome-kiosk/window-config.ini`
+
+# Syntax
+
+The configuration file is an "ini" style file with sections and keys/values.
+
+There can be as many sections as desired.
+
+The name of the sections does not matter, there is no special name of section,
+each section gets evaluated.
+
+There are two categories of keys, the "*match*" keys and the "*set*" keys.
+
+The "*match*" keys are used to filter the windows before applying the
+values from the "*set*" keys.
+
+The "*match*" keys can take wildcards and patterns.
+
+The following "*match*" keys as supported:
+
+ * `match-title` (string) - Matches the window title
+ * `match-class` (string) - Matches the window class
+ * `match-sandboxed-app-id` (string) - Matches the sandboxed application id
+
+The following "*set*" keys are supported:
+
+ * `set-fullscreen` (boolean) - Whether the window should be fullscreen
+ * `set-x` (integer) - the X position
+ * `set-y` (integer) - the Y position
+ * `set-width` (integer) - the width
+ * `set-height` (integer) - the height
+
+# Example
+
+```
+ # Place all windows at (0,0) by default, not fullscreen
+ [all]
+ set-x=0
+ set-y=0
+ set-fullscreen=false
+
+ # Make all Mozilla windows fullscreen
+ [mozilla]
+ match-class=org.mozilla.*
+ set-fullscreen=true
+
+ # All other windows will be set fullscreen automatically using the
+ # existing GNOME Kiosk heuristic, as before.
+```
diff --git a/compositor/kiosk-window-config.c b/compositor/kiosk-window-config.c
new file mode 100644
index 0000000..5e6c830
--- /dev/null
+++ b/compositor/kiosk-window-config.c
@@ -0,0 +1,315 @@
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "kiosk-window-config.h"
+
+#define KIOSK_WINDOW_CONFIG_DIR "gnome-kiosk"
+#define KIOSK_WINDOW_CONFIG_FILENAME "window-config.ini"
+#define KIOSK_WINDOW_CONFIG_GET_KEY_VALUE(f) ((KioskWindowConfigGetKeyValue) (f))
+
+typedef gpointer (*KioskWindowConfigGetKeyValue) (GKeyFile *key_file,
+ const char *section_name,
+ const char *key_name,
+ GError **error);
+
+struct _KioskWindowConfig
+{
+ GObject parent;
+
+ GKeyFile *config_key_file;
+};
+
+G_DEFINE_TYPE (KioskWindowConfig, kiosk_window_config, G_TYPE_OBJECT)
+
+static gboolean
+kiosk_window_config_try_load_file (KioskWindowConfig *kiosk_window_config,
+ char *filename)
+{
+ g_autoptr (GError) error = NULL;
+
+ if (!g_key_file_load_from_file (kiosk_window_config->config_key_file,
+ filename,
+ G_KEY_FILE_NONE,
+ &error)) {
+ g_debug ("KioskWindowConfig: Error loading key file %s: %s",
+ filename, error->message);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+kiosk_window_config_load (KioskWindowConfig *kiosk_window_config)
+{
+ const char * const *xdg_data_dirs;
+ g_autofree gchar *filename = NULL;
+ int i;
+
+ /* Try user config first */
+ filename = g_build_filename (g_get_user_config_dir (),
+ KIOSK_WINDOW_CONFIG_DIR,
+ KIOSK_WINDOW_CONFIG_FILENAME, NULL);
+
+ if (kiosk_window_config_try_load_file (kiosk_window_config, filename))
+ goto out;
+
+ /* Then system config */
+ xdg_data_dirs = g_get_system_data_dirs ();
+ for (i = 0; xdg_data_dirs[i]; i++) {
+ filename = g_build_filename (xdg_data_dirs[i],
+ KIOSK_WINDOW_CONFIG_DIR,
+ KIOSK_WINDOW_CONFIG_FILENAME, NULL);
+
+ if (kiosk_window_config_try_load_file (kiosk_window_config, filename))
+ goto out;
+ }
+
+ g_debug ("KioskWindowConfig: No configuration file found");
+
+ return FALSE;
+out:
+ g_debug ("KioskWindowConfig: Loading key file %s", filename);
+
+ return TRUE;
+}
+
+static void
+kiosk_window_config_init (KioskWindowConfig *self)
+{
+ self->config_key_file = g_key_file_new ();
+ kiosk_window_config_load (self);
+}
+
+static void
+kiosk_window_config_dispose (GObject *object)
+{
+ KioskWindowConfig *self = KIOSK_WINDOW_CONFIG (object);
+
+ g_clear_pointer (&self->config_key_file, g_key_file_free);
+
+ G_OBJECT_CLASS (kiosk_window_config_parent_class)->dispose (object);
+}
+
+static void
+kiosk_window_config_class_init (KioskWindowConfigClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->dispose = kiosk_window_config_dispose;
+}
+
+#define KIOSK_WINDOW_CONFIG_CHECK_FUNC_VALUE(self, section, key, func, value) \
+ G_STMT_START { \
+ g_autoptr (GError) error = NULL; \
+ if (!g_key_file_has_key (self->config_key_file, section, key, NULL)) { \
+ g_debug ("KioskWindowConfig: No key '%s' in section [%s]", \
+ key, section); \
+ return FALSE; \
+ } \
+ *value = func (self->config_key_file, section, key, &error); \
+ if (error) { \
+ g_debug ("KioskWindowConfig: Error with key '%s' in section [%s]: %s", \
+ key, section, error->message); \
+ return FALSE; \
+ } \
+ return TRUE; \
+ } G_STMT_END
+
+static gboolean
+kiosk_window_config_check_for_string_value (KioskWindowConfig *kiosk_window_config,
+ const char *section_name,
+ const char *key_name,
+ char **value)
+{
+ KIOSK_WINDOW_CONFIG_CHECK_FUNC_VALUE (kiosk_window_config,
+ section_name,
+ key_name,
+ g_key_file_get_string,
+ value);
+}
+
+static gboolean
+kiosk_window_config_check_for_integer_value (KioskWindowConfig *kiosk_window_config,
+ const char *section_name,
+ const char *key_name,
+ int *value)
+{
+ KIOSK_WINDOW_CONFIG_CHECK_FUNC_VALUE (kiosk_window_config,
+ section_name,
+ key_name,
+ g_key_file_get_integer,
+ value);
+}
+
+static gboolean
+kiosk_window_config_check_for_boolean_value (KioskWindowConfig *kiosk_window_config,
+ const char *section_name,
+ const char *key_name,
+ gboolean *value)
+{
+ KIOSK_WINDOW_CONFIG_CHECK_FUNC_VALUE (kiosk_window_config,
+ section_name,
+ key_name,
+ g_key_file_get_boolean,
+ value);
+}
+
+static void
+kiosk_window_config_apply_config (KioskWindowConfig *kiosk_window_config,
+ MetaWindowConfig *window_config,
+ const char *section_name)
+{
+ MtkRectangle rect;
+ int new_x, new_y, new_width, new_height;
+ gboolean fullscreen;
+
+ if (kiosk_window_config_check_for_boolean_value (kiosk_window_config,
+ section_name,
+ "set-fullscreen",
+ &fullscreen)) {
+ g_debug ("KioskWindowConfig: Using 'set-fullscreen=%s' from section [%s]",
+ fullscreen ? "TRUE" : "FALSE", section_name);
+ meta_window_config_set_is_fullscreen (window_config, fullscreen);
+ }
+
+ rect = meta_window_config_get_rect (window_config);
+
+ if (kiosk_window_config_check_for_integer_value (kiosk_window_config,
+ section_name,
+ "set-x",
+ &new_x)) {
+ g_debug ("KioskWindowConfig: Using 'set-x=%i' from section [%s]",
+ new_x, section_name);
+ rect.x = new_x;
+ }
+
+ if (kiosk_window_config_check_for_integer_value (kiosk_window_config,
+ section_name,
+ "set-y",
+ &new_y)) {
+ g_debug ("KioskWindowConfig: Using 'set-y=%i' from section [%s]",
+ new_y, section_name);
+ rect.y = new_y;
+ }
+
+ if (kiosk_window_config_check_for_integer_value (kiosk_window_config,
+ section_name,
+ "set-width",
+ &new_width)) {
+ g_debug ("KioskWindowConfig: Using 'set-width=%i' from section [%s]",
+ new_width, section_name);
+ rect.width = new_width;
+ }
+
+ if (kiosk_window_config_check_for_integer_value (kiosk_window_config,
+ section_name,
+ "set-height",
+ &new_height)) {
+ g_debug ("KioskWindowConfig: Using 'set-height=%i' from section [%s]",
+ new_height, section_name);
+ rect.height = new_height;
+ }
+
+ meta_window_config_set_rect (window_config, rect);
+}
+
+static gboolean
+kiosk_window_config_match_string_key (KioskWindowConfig *kiosk_window_config,
+ const char *section_name,
+ const char *key_name,
+ const char *value)
+{
+ g_autofree gchar *key_value = NULL;
+ g_autoptr (GError) error = NULL;
+ gboolean is_a_match = TRUE;
+
+ /* Keys are used to filter out, no key means we have a match */
+ if (!kiosk_window_config_check_for_string_value (kiosk_window_config,
+ section_name,
+ key_name,
+ &key_value))
+ return TRUE;
+
+ is_a_match = g_pattern_match_simple (key_value, value);
+ g_debug ("KioskWindowConfig: Value '%s' %s key '%s=%s' from section [%s]",
+ value,
+ is_a_match ? "matches" : "does not match",
+ key_name,
+ key_value,
+ section_name);
+
+ return is_a_match;
+}
+
+static gboolean
+kiosk_window_config_match_window (KioskWindowConfig *kiosk_window_config,
+ MetaWindow *window,
+ const char *section_name)
+{
+ const char *match_value;
+
+ g_debug ("KioskWindowConfig: Checking section [%s]", section_name);
+
+ match_value = meta_window_get_title (window);
+ if (match_value &&
+ !kiosk_window_config_match_string_key (kiosk_window_config,
+ section_name,
+ "match-title",
+ match_value))
+ return FALSE;
+
+ match_value = meta_window_get_wm_class (window);
+ if (match_value &&
+ !kiosk_window_config_match_string_key (kiosk_window_config,
+ section_name,
+ "match-class",
+ match_value))
+ return FALSE;
+
+ match_value = meta_window_get_sandboxed_app_id (window);
+ if (match_value &&
+ !kiosk_window_config_match_string_key (kiosk_window_config,
+ section_name,
+ "match-sandboxed-app-id",
+ match_value))
+ return FALSE;
+
+ return TRUE;
+}
+
+void
+kiosk_window_config_update_window (KioskWindowConfig *kiosk_window_config,
+ MetaWindow *window,
+ MetaWindowConfig *window_config)
+{
+ g_auto (GStrv) sections;
+ gsize length;
+ int i;
+
+ sections = g_key_file_get_groups (kiosk_window_config->config_key_file, &length);
+ for (i = 0; i < length; i++) {
+ if (!kiosk_window_config_match_window (kiosk_window_config,
+ window,
+ sections[i]))
+ continue;
+
+ kiosk_window_config_apply_config (kiosk_window_config,
+ window_config,
+ sections[i]);
+ }
+}
+
+KioskWindowConfig *
+kiosk_window_config_new (void)
+{
+ KioskWindowConfig *kiosk_window_config;
+
+ kiosk_window_config = g_object_new (KIOSK_TYPE_WINDOW_CONFIG,
+ NULL);
+
+ return kiosk_window_config;
+}
diff --git a/compositor/kiosk-window-config.h b/compositor/kiosk-window-config.h
new file mode 100644
index 0000000..1c7e8ea
--- /dev/null
+++ b/compositor/kiosk-window-config.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <glib-object.h>
+#include <glib.h>
+
+#include <meta/window.h>
+#include <meta/meta-window-config.h>
+
+G_BEGIN_DECLS
+
+#define KIOSK_TYPE_WINDOW_CONFIG (kiosk_window_config_get_type ())
+G_DECLARE_FINAL_TYPE (KioskWindowConfig, kiosk_window_config,
+ KIOSK, WINDOW_CONFIG, GObject)
+
+KioskWindowConfig *kiosk_window_config_new (void);
+
+void kiosk_window_config_update_window (KioskWindowConfig *kiosk_window_config,
+ MetaWindow *window,
+ MetaWindowConfig *window_config);
+
+G_END_DECLS
diff --git a/meson.build b/meson.build
index 23aaff7..c3eb74c 100644
--- a/meson.build
+++ b/meson.build
@@ -166,6 +166,7 @@ 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-window-config.c'
compositor_sources += 'compositor/kiosk-screenshot.c'
if mutter_have_x11
diff --git a/window-config.ini b/window-config.ini
new file mode 100644
index 0000000..c4c825e
--- /dev/null
+++ b/window-config.ini
@@ -0,0 +1,17 @@
+# This is just an example for a window configuration file.
+# Copy this file to $HOME/.config/gnome-kiosk/window-config.ini
+
+# The section names are free and all sections get evaluated.
+
+# Place all windows at (0,0) by default
+[all]
+set-x=0
+set-y=0
+
+# Make all Mozilla windows fullscreen
+[browser]
+match-class=org.mozilla*
+set-fullscreen=true
+
+# All other windows will be set fullscreen automatically using the
+# existing GNOME Kiosk heuristic, as before.
--
2.49.0

View File

@ -1,55 +0,0 @@
From a695282b8da73fe7df50293f177855a9b3c92416 Mon Sep 17 00:00:00 2001
From: Olivier Fourdan <ofourdan@redhat.com>
Date: Wed, 30 Jul 2025 15:16:54 +0200
Subject: [PATCH 2/3] compositor: Use the Shell service
The Shell service is used by gnome-settings-daemon to implement media
keys.
That in turn allows to start the screen reader, audio control, etc.
(cherry picked from commit 722055b88747d5b6cc4de0875f4b9f0169fcf9c2)
---
compositor/kiosk-compositor.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/compositor/kiosk-compositor.c b/compositor/kiosk-compositor.c
index aa5603d..73f5524 100644
--- a/compositor/kiosk-compositor.c
+++ b/compositor/kiosk-compositor.c
@@ -24,6 +24,7 @@
#include "kiosk-service.h"
#include "kiosk-app-system.h"
#include "kiosk-window-tracker.h"
+#include "kiosk-shell-service.h"
#include "kiosk-shell-introspect-service.h"
#include "kiosk-shell-screenshot-service.h"
#include "kiosk-window-config.h"
@@ -51,6 +52,7 @@ struct _KioskCompositor
KioskShellIntrospectService *introspect_service;
KioskShellScreenshotService *screenshot_service;
KioskWindowConfig *kiosk_window_config;
+ KioskShellService *shell_service;
};
enum
@@ -84,6 +86,7 @@ kiosk_compositor_dispose (GObject *object)
g_clear_object (&self->backgrounds);
g_clear_object (&self->automount_manager);
+ g_clear_object (&self->shell_service);
G_OBJECT_CLASS (kiosk_compositor_parent_class)->dispose (object);
}
@@ -293,6 +296,8 @@ kiosk_compositor_start (MetaPlugin *plugin)
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);
+ self->shell_service = kiosk_shell_service_new (self);
+ kiosk_shell_service_start (self->shell_service, &error);
if (error != NULL) {
g_debug ("KioskCompositor: Could not start D-Bus service: %s", error->message);
--
2.50.1

View File

@ -1,32 +0,0 @@
From 30d48384d2b98dc6ba9534ef41ce445f6da41d7f Mon Sep 17 00:00:00 2001
From: Olivier Fourdan <ofourdan@redhat.com>
Date: Wed, 5 Mar 2025 14:23:49 +0100
Subject: [PATCH 2/2] search-app: Update desktop file definition
Firefox itself has nothing to do with neither Gtk or GNOME, no need to
list those in the categories.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-kiosk/-/merge_requests/66>
(cherry picked from commit 5441999573a07c3513eeda5150683448bdd71c50)
---
search-app/org.gnome.Kiosk.SearchApp.desktop.in.in | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/search-app/org.gnome.Kiosk.SearchApp.desktop.in.in b/search-app/org.gnome.Kiosk.SearchApp.desktop.in.in
index 360e6df..478b328 100644
--- a/search-app/org.gnome.Kiosk.SearchApp.desktop.in.in
+++ b/search-app/org.gnome.Kiosk.SearchApp.desktop.in.in
@@ -3,7 +3,6 @@ Type=Application
Name=Search Appliance
Comment=Sample Search Appliance Application for GNOME Kiosk
Exec=@bindir@/firefox --kiosk --private-window --new-instance https://www.google.com
-Categories=GNOME;GTK;Core;
-OnlyShowIn=GNOME;
+Categories=Core;System;
NoDisplay=true
-X-GNOME-AutoRestart=true
+X-GNOME-HiddenUnderSystemd=true
--
2.48.1

View File

@ -1,124 +0,0 @@
From bf79fe519d55a5fc6d31775164e0a4c5831a9020 Mon Sep 17 00:00:00 2001
From: Olivier Fourdan <ofourdan@redhat.com>
Date: Fri, 25 Oct 2024 14:04:17 +0200
Subject: [PATCH 3/5] compositor: Apply the window configuration
Use the "MetaWindow::configure" signal in mutter-16 to apply the GNOME
Kiosk window configuration.
(cherry picked from commit 30d0c4233f84234bd6d470fc42715593360e115a)
---
compositor/kiosk-compositor.c | 47 +++++++++++++++++++++++++++++++++--
1 file changed, 45 insertions(+), 2 deletions(-)
diff --git a/compositor/kiosk-compositor.c b/compositor/kiosk-compositor.c
index 37588da..650ac50 100644
--- a/compositor/kiosk-compositor.c
+++ b/compositor/kiosk-compositor.c
@@ -12,6 +12,7 @@
#include <meta/keybindings.h>
#include <meta/meta-context.h>
#include <meta/util.h>
+#include <meta/meta-window-config.h>
#include <meta/meta-window-group.h>
#include <systemd/sd-daemon.h>
@@ -25,6 +26,7 @@
#include "kiosk-window-tracker.h"
#include "kiosk-shell-introspect-service.h"
#include "kiosk-shell-screenshot-service.h"
+#include "kiosk-window-config.h"
#include "org.gnome.DisplayManager.Manager.h"
@@ -48,6 +50,7 @@ struct _KioskCompositor
KioskWindowTracker *tracker;
KioskShellIntrospectService *introspect_service;
KioskShellScreenshotService *screenshot_service;
+ KioskWindowConfig *kiosk_window_config;
};
enum
@@ -61,6 +64,8 @@ static guint signals[NUMBER_OF_SIGNALS] = { 0, };
G_DEFINE_TYPE (KioskCompositor, kiosk_compositor, META_TYPE_PLUGIN)
static void kiosk_compositor_dispose (GObject *object);
+static gboolean kiosk_compositor_wants_window_fullscreen (KioskCompositor *self,
+ MetaWindow *window);
static void
kiosk_compositor_dispose (GObject *object)
@@ -220,6 +225,39 @@ neuter_builtin_keybindings (KioskCompositor *self)
}
}
+static void
+kiosk_compositor_on_window_configure (MetaWindow *window,
+ MetaWindowConfig *window_config,
+ gpointer user_data)
+{
+ KioskCompositor *self = KIOSK_COMPOSITOR (user_data);
+ gboolean fullscreen;
+
+ if (!meta_window_config_get_is_initial (window_config)) {
+ g_debug ("KioskCompositor: Ignoring configure for window: %s",
+ meta_window_get_description (window));
+ return;
+ }
+
+ g_debug ("KioskCompositor: configure window: %s", meta_window_get_description (window));
+
+ fullscreen = kiosk_compositor_wants_window_fullscreen (self, window);
+ meta_window_config_set_is_fullscreen (window_config, fullscreen);
+ kiosk_window_config_update_window (self->kiosk_window_config,
+ window,
+ window_config);
+}
+
+static void
+kiosk_compositor_on_window_created (MetaDisplay *display,
+ MetaWindow *window,
+ gpointer user_data)
+{
+ g_signal_connect (window, "configure",
+ G_CALLBACK (kiosk_compositor_on_window_configure),
+ user_data);
+}
+
static void
kiosk_compositor_start (MetaPlugin *plugin)
{
@@ -250,6 +288,7 @@ kiosk_compositor_start (MetaPlugin *plugin)
self->input_sources_manager = kiosk_input_sources_manager_new (self);
self->app_system = kiosk_app_system_new (self);
self->tracker = kiosk_window_tracker_new (self, self->app_system);
+ self->kiosk_window_config = kiosk_window_config_new ();
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);
@@ -265,6 +304,11 @@ kiosk_compositor_start (MetaPlugin *plugin)
self->cancellable,
KIOSK_OBJECT_CALLBACK (register_session),
NULL);
+
+ g_signal_connect_object (self->display, "window-created",
+ G_CALLBACK (kiosk_compositor_on_window_created),
+ self,
+ G_CONNECT_DEFAULT);
}
static void
@@ -372,9 +416,8 @@ kiosk_compositor_map (MetaPlugin *plugin,
window = meta_window_actor_get_meta_window (actor);
- if (kiosk_compositor_wants_window_fullscreen (self, window)) {
+ if (meta_window_is_fullscreen (window)) {
g_debug ("KioskCompositor: Mapping window that does need to be fullscreened");
- meta_window_make_fullscreen (window);
easing_duration = 3000;
} else {
g_debug ("KioskCompositor: Mapping window that does not need to be fullscreened");
--
2.49.0

View File

@ -1,35 +0,0 @@
From 3bec84a57c51906880a1cf25d3255158ed6e9825 Mon Sep 17 00:00:00 2001
From: Olivier Fourdan <ofourdan@redhat.com>
Date: Tue, 29 Jul 2025 18:08:24 +0200
Subject: [PATCH 3/3] systemd/sessions: Add Mediakeys support
That allows to start the screen reader using the default key shortcut.
Closes: https://gitlab.gnome.org/GNOME/gnome-kiosk/-/issues/46
(cherry picked from commit eacd8f733cdf8f53923268de43ff09cace758e50)
---
kiosk-script/systemd/session.conf | 1 +
search-app/systemd/session.conf | 1 +
2 files changed, 2 insertions(+)
diff --git a/kiosk-script/systemd/session.conf b/kiosk-script/systemd/session.conf
index aeb722c..5652e83 100644
--- a/kiosk-script/systemd/session.conf
+++ b/kiosk-script/systemd/session.conf
@@ -2,3 +2,4 @@
Requires=org.gnome.Kiosk.target
Requires=org.gnome.Kiosk.Script.service
Wants=org.gnome.SettingsDaemon.Sharing.target
+Wants=org.gnome.SettingsDaemon.MediaKeys.target
diff --git a/search-app/systemd/session.conf b/search-app/systemd/session.conf
index d038670..e37baf7 100644
--- a/search-app/systemd/session.conf
+++ b/search-app/systemd/session.conf
@@ -2,3 +2,4 @@
Requires=org.gnome.Kiosk.target
Requires=org.gnome.Kiosk.SearchApp.service
Wants=org.gnome.SettingsDaemon.Sharing.target
+Wants=org.gnome.SettingsDaemon.MediaKeys.target
--
2.50.1

View File

@ -1,78 +0,0 @@
From fed3a11e0f9c21f2361b3fea564c51957cd24fa5 Mon Sep 17 00:00:00 2001
From: Olivier Fourdan <ofourdan@redhat.com>
Date: Tue, 12 Nov 2024 10:38:19 +0100
Subject: [PATCH 4/5] compositor: Add an API to retrieve a boolean setting
This adds a direct search API to the window configuration to retrieve
the boolean value for a matching window.
This is preparation work for the following commit.
(cherry picked from commit 62a7053d14b8432ef8dbc3ad78cd043ea95cf043)
---
compositor/kiosk-window-config.c | 32 ++++++++++++++++++++++++++++++++
compositor/kiosk-window-config.h | 5 +++++
2 files changed, 37 insertions(+)
diff --git a/compositor/kiosk-window-config.c b/compositor/kiosk-window-config.c
index 5e6c830..a07798b 100644
--- a/compositor/kiosk-window-config.c
+++ b/compositor/kiosk-window-config.c
@@ -281,6 +281,38 @@ kiosk_window_config_match_window (KioskWindowConfig *kiosk_window_config,
return TRUE;
}
+gboolean
+kiosk_window_config_get_boolean_for_window (KioskWindowConfig *kiosk_window_config,
+ MetaWindow *window,
+ const char *key_name,
+ gboolean *value)
+{
+ g_auto (GStrv) sections;
+ gsize length;
+ gboolean key_found = FALSE;
+ int i;
+
+ sections = g_key_file_get_groups (kiosk_window_config->config_key_file, &length);
+ for (i = 0; i < length; i++) {
+ if (!kiosk_window_config_match_window (kiosk_window_config,
+ window,
+ sections[i]))
+ continue;
+
+ if (kiosk_window_config_check_for_boolean_value (kiosk_window_config,
+ sections[i],
+ key_name,
+ value)) {
+ g_debug ("KioskWindowConfig: Using '%s=%s' from section [%s]",
+ key_name, *value ? "TRUE" : "FALSE", sections[i]);
+
+ key_found = TRUE;
+ }
+ }
+
+ return key_found;
+}
+
void
kiosk_window_config_update_window (KioskWindowConfig *kiosk_window_config,
MetaWindow *window,
diff --git a/compositor/kiosk-window-config.h b/compositor/kiosk-window-config.h
index 1c7e8ea..3482c43 100644
--- a/compositor/kiosk-window-config.h
+++ b/compositor/kiosk-window-config.h
@@ -14,6 +14,11 @@ G_DECLARE_FINAL_TYPE (KioskWindowConfig, kiosk_window_config,
KioskWindowConfig *kiosk_window_config_new (void);
+gboolean kiosk_window_config_get_boolean_for_window (KioskWindowConfig *kiosk_window_config,
+ MetaWindow *window,
+ const char *key_name,
+ gboolean *value);
+
void kiosk_window_config_update_window (KioskWindowConfig *kiosk_window_config,
MetaWindow *window,
MetaWindowConfig *window_config);
--
2.49.0

View File

@ -1,81 +0,0 @@
From 8a9121bb11f0423aefe5a51252986765e10214b0 Mon Sep 17 00:00:00 2001
From: Olivier Fourdan <ofourdan@redhat.com>
Date: Fri, 8 Nov 2024 18:18:32 +0100
Subject: [PATCH 5/5] compositor: Make set-above configurable
GNOME Kiosk has heuristics to place windows on the top group.
However, in some cases, it may desirable to avoid that behavior as that
prevents the windows stacking from being changed by the user.
Add a new option "set-above" to the configuration file to control that
behaviour.
If not specified, the existing heuristics will be applied, not breaking
possible existing setups.
Closes: https://gitlab.gnome.org/GNOME/gnome-kiosk/-/issues/26
(cherry picked from commit b50c25fe739c00f4a1984919ee93cd351f58dfc1)
---
CONFIG.md | 3 +++
compositor/kiosk-compositor.c | 9 +++++++++
window-config.ini | 2 ++
3 files changed, 14 insertions(+)
diff --git a/CONFIG.md b/CONFIG.md
index b0045ee..652fb71 100644
--- a/CONFIG.md
+++ b/CONFIG.md
@@ -42,6 +42,7 @@ The following "*set*" keys are supported:
* `set-y` (integer) - the Y position
* `set-width` (integer) - the width
* `set-height` (integer) - the height
+ * `set-above` (boolean) - Whether the window should be placed on a layer above
# Example
@@ -51,6 +52,8 @@ The following "*set*" keys are supported:
set-x=0
set-y=0
set-fullscreen=false
+ # The following will place all windows on the same layer
+ set-above=false
# Make all Mozilla windows fullscreen
[mozilla]
diff --git a/compositor/kiosk-compositor.c b/compositor/kiosk-compositor.c
index 650ac50..aa5603d 100644
--- a/compositor/kiosk-compositor.c
+++ b/compositor/kiosk-compositor.c
@@ -385,6 +385,15 @@ static gboolean
kiosk_compositor_wants_window_above (KioskCompositor *self,
MetaWindow *window)
{
+ gboolean set_above;
+
+ if (kiosk_window_config_get_boolean_for_window (self->kiosk_window_config,
+ window,
+ "set-above",
+ &set_above))
+ return set_above;
+
+ /* If not specified in the config, use the heuristics */
if (meta_window_is_screen_sized (window)) {
return FALSE;
}
diff --git a/window-config.ini b/window-config.ini
index c4c825e..f4f37b3 100644
--- a/window-config.ini
+++ b/window-config.ini
@@ -7,6 +7,8 @@
[all]
set-x=0
set-y=0
+# Uncomment the following to have all windows on the same layer
+# set-above=false
# Make all Mozilla windows fullscreen
[browser]
--
2.49.0

View File

@ -5,13 +5,13 @@
%global gnome_desktop_version 44.0
%global glib2_version 2.68.0
%global gtk4_version 3.24.27
%global mutter_version 47.5-9
%global mutter_version 49~beta
%global gsettings_desktop_schemas_version 40~rc
%global ibus_version 1.5.24
%global gnome_settings_daemon_version 40~rc
Name: gnome-kiosk
Version: 47.0
Version: 49.0
Release: %{autorelease}
Summary: Window management and application launching for GNOME
@ -35,7 +35,7 @@ BuildRequires: pkgconfig(gio-2.0) >= %{glib2_version}
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(libmutter-17) >= %{mutter_version}
BuildRequires: pkgconfig(gdk-pixbuf-2.0)
Requires: gnome-settings-daemon%{?_isa} >= %{gnome_settings_daemon_version}
@ -44,32 +44,8 @@ Requires: mutter%{?_isa} >= %{mutter_version}
Recommends: xorg-x11-server-Xwayland
Recommends: dbus-daemon
Patch: 0001-kiosk-app-Do-not-add-the-window-in-kiosk_app_new_for.patch
# https://issues.redhat.com/browse/RHEL-71757
Patch: 0001-kiosk-script-Copy-and-run-the-script-from-XDG_RUNTIM.patch
# https://issues.redhat.com/browse/RHEL-62420
Patch: 0001-compositor-Add-screenshot-utilities.patch
Patch: 0002-compositor-Add-Shell-Screenshot-support.patch
# https://issues.redhat.com/browse/RHEL-82250
# https://issues.redhat.com/browse/RHEL-82404
Patch: 0001-search-app-Add-systemd-session-files.patch
Patch: 0002-search-app-Update-desktop-file-definition.patch
# https://issues.redhat.com/browse/RHEL-36521
Patch: 0001-search-app-Use-firefox-from-flatpak.patch
# https://issues.redhat.com/browse/RHEL-84829
Patch: 0001-input-sources-manager-Do-not-crash-if-there-is-no-X1.patch
# https://issues.redhat.com/browse/RHEL-84697
Patch: 0001-compositor-Use-the-meta-window-API-for-set-above.patch
Patch: 0002-compositor-Add-a-window-configuration-file.patch
Patch: 0003-compositor-Apply-the-window-configuration.patch
Patch: 0004-compositor-Add-an-API-to-retrieve-a-boolean-setting.patch
Patch: 0005-compositor-Make-set-above-configurable.patch
# https://issues.redhat.com/browse/RHEL-103639
Patch: 0001-systemd-session-Enable-remote-session.patch
# https://issues.redhat.com/browse/RHEL-106584
Patch: 0001-shell-service-Fix-GrabAccelerators-return-value.patch
Patch: 0002-compositor-Use-the-Shell-service.patch
Patch: 0003-systemd-sessions-Add-Mediakeys-support.patch
%description
GNOME Kiosk provides a desktop enviroment suitable for fixed purpose, or

View File

@ -1 +1 @@
SHA512 (gnome-kiosk-47.0.tar.xz) = 497b7e3500d4afc38f9d57a4a40c2ea2ad834365989893d71742ce02c1e67cd7976bf884d02248b269a2141ca865845beac97e130bfe1032dbebaa95cfe52e4f
SHA512 (gnome-kiosk-49.0.tar.xz) = a2d92b39516b7f70074f4ef210ddf98215820699d717973f4addeafa9e68875d0e8b49913a5f175027878aab5eca7b810abd20c8df1a7b011ac9e573560feacb