From a4c94065fc10260be15ae4252db5a16d76153265 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABl=20Bonithon?= <gael@xfce.org>
Date: Sat, 3 Feb 2024 15:53:17 +0100
Subject: [PATCH] wayland: Use WleGtkSocket and WleGtkPlug from libwlembed

---
 configure.ac                        |   4 +
 savers/Makefile.am                  |   6 ++
 savers/floaters.c                   |   9 ++
 savers/popsquares.c                 |   9 ++
 savers/slideshow.c                  |   9 ++
 src/Makefile.am                     |  38 +++++++
 src/gs-job.c                        |  50 +++++++---
 src/gs-lock-plug.c                  |   9 ++
 src/gs-manager.c                    |  54 ++++++++--
 src/gs-manager.h                    |   7 ++
 src/gs-window-x11.c                 | 150 +++++++++++++++++-----------
 src/xfce-desktop-utils.c            | 101 ++++++++++++-------
 src/xfce-desktop-utils.h            |  26 +++--
 src/xfce4-screensaver-dialog.c      |   8 ++
 src/xfce4-screensaver-preferences.c |  54 ++++++++--
 15 files changed, 399 insertions(+), 135 deletions(-)

diff --git a/configure.ac b/configure.ac
index 03a388df..fc1bf886 100644
--- a/configure.ac
+++ b/configure.ac
@@ -60,6 +60,8 @@ m4_define([libxscrnsaver_min_version], [1.2.3])
 m4_define([libxklavier_min_version], [5.2])
 m4_define([libwnck_min_version], [3.20])
 
+m4_define([libwlembed_min_version], [0.0.0])
+
 XDT_CHECK_PACKAGE([GLIB], [glib-2.0], [glib_min_version])
 XDT_CHECK_PACKAGE([GIO], [gio-2.0], [glib_min_version])
 XDT_CHECK_PACKAGE([GTK], [gtk+-3.0], [gtk_min_version])
@@ -85,6 +87,8 @@ XDT_CHECK_OPTIONAL_FEATURE([WAYLAND],
                            [wayland],
                            [
                              XDT_FEATURE_DEPENDENCY([GDK_WAYLAND], [gdk-wayland-3.0], [gtk_min_version])
+                             XDT_FEATURE_DEPENDENCY([LIBWLEMBED], [libwlembed-0], [libwlembed_min_version])
+                             XDT_FEATURE_DEPENDENCY([LIBWLEMBED_GTK3], [libwlembed-gtk3-0], [libwlembed_min_version])
                            ],
                            [the Wayland windowing system])
 if test x"$ENABLE_X11" != x"yes" -a x"$ENABLE_WAYLAND" != x"yes"; then
diff --git a/savers/Makefile.am b/savers/Makefile.am
index 58f3c510..f534ac6e 100644
--- a/savers/Makefile.am
+++ b/savers/Makefile.am
@@ -78,6 +78,7 @@ floaters_CFLAGS = \
 	$(GLIB_CFLAGS) \
 	$(GTK_CFLAGS) \
 	$(LIBXFCE4UTIL_CFLAGS) \
+	$(LIBWLEMBED_GTK3_CFLAGS) \
 	$(NULL)
 
 floaters_LDADD = \
@@ -85,6 +86,7 @@ floaters_LDADD = \
 	$(GLIB_LIBS) \
 	$(GTK_LIBS) \
 	$(LIBXFCE4UTIL_LIBS) \
+	$(LIBWLEMBED_GTK3_LIBS) \
 	$(NULL)
 
 popsquares_SOURCES = \
@@ -97,6 +99,7 @@ popsquares_CFLAGS = \
 	$(GLIB_CFLAGS) \
 	$(GTK_CFLAGS) \
 	$(LIBXFCE4UTIL_CFLAGS) \
+	$(LIBWLEMBED_GTK3_CFLAGS) \
 	$(NULL)
 
 popsquares_LDADD = \
@@ -104,6 +107,7 @@ popsquares_LDADD = \
 	$(GLIB_LIBS) \
 	$(GTK_LIBS) \
 	$(LIBXFCE4UTIL_LIBS) \
+	$(LIBWLEMBED_GTK3_LIBS) \
 	$(NULL)
 
 slideshow_SOURCES = \
@@ -118,6 +122,7 @@ slideshow_CFLAGS = \
 	$(GLIB_CFLAGS) \
 	$(GTK_CFLAGS) \
 	$(LIBXFCE4UTIL_CFLAGS) \
+	$(LIBWLEMBED_GTK3_CFLAGS) \
 	$(NULL)
 
 slideshow_LDADD = \
@@ -125,6 +130,7 @@ slideshow_LDADD = \
 	$(GLIB_LIBS) \
 	$(GTK_LIBS) \
 	$(LIBXFCE4UTIL_LIBS) \
+	$(LIBWLEMBED_GTK3_LIBS) \
 	$(NULL)
 
 EXTRA_DIST = \
diff --git a/savers/floaters.c b/savers/floaters.c
index 6bc1c433..4a97d09e 100644
--- a/savers/floaters.c
+++ b/savers/floaters.c
@@ -38,6 +38,10 @@
 #include <gdk/gdkx.h>
 #include <gtk/gtkx.h>
 #endif
+#ifdef ENABLE_WAYLAND
+#include <gdk/gdkwayland.h>
+#include <libwlembed-gtk3/libwlembed-gtk3.h>
+#endif
 
 #include <libxfce4util/libxfce4util.h>
 
@@ -1152,6 +1156,11 @@ main (int   argc,
     if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())) {
         window = gtk_plug_new (strtoul (g_getenv ("XSCREENSAVER_WINDOW"), NULL, 0));
     }
+#endif
+#ifdef ENABLE_WAYLAND
+    if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) {
+        window = wle_gtk_plug_new (g_getenv ("XSCREENSAVER_WINDOW"));
+    }
 #endif
     gtk_widget_set_app_paintable (window, TRUE);
 
diff --git a/savers/popsquares.c b/savers/popsquares.c
index 1a4fc40c..dcba4bcd 100644
--- a/savers/popsquares.c
+++ b/savers/popsquares.c
@@ -29,6 +29,10 @@
 #include <gdk/gdkx.h>
 #include <gtk/gtkx.h>
 #endif
+#ifdef ENABLE_WAYLAND
+#include <gdk/gdkwayland.h>
+#include <libwlembed-gtk3/libwlembed-gtk3.h>
+#endif
 
 #include <libxfce4util/libxfce4util.h>
 
@@ -57,6 +61,11 @@ main (int    argc,
     if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())) {
         window = gtk_plug_new (strtoul (g_getenv ("XSCREENSAVER_WINDOW"), NULL, 0));
     }
+#endif
+#ifdef ENABLE_WAYLAND
+    if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) {
+        window = wle_gtk_plug_new (g_getenv ("XSCREENSAVER_WINDOW"));
+    }
 #endif
     gtk_widget_set_app_paintable (window, TRUE);
     g_signal_connect (G_OBJECT (window), "destroy",
diff --git a/savers/slideshow.c b/savers/slideshow.c
index c62c52b5..c08c3737 100644
--- a/savers/slideshow.c
+++ b/savers/slideshow.c
@@ -32,6 +32,10 @@
 #include <gdk/gdkx.h>
 #include <gtk/gtkx.h>
 #endif
+#ifdef ENABLE_WAYLAND
+#include <gdk/gdkwayland.h>
+#include <libwlembed-gtk3/libwlembed-gtk3.h>
+#endif
 
 #include <libxfce4util/libxfce4util.h>
 
@@ -97,6 +101,11 @@ main (int argc, char **argv) {
     if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())) {
         window = gtk_plug_new (strtoul (g_getenv ("XSCREENSAVER_WINDOW"), NULL, 0));
     }
+#endif
+#ifdef ENABLE_WAYLAND
+    if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) {
+        window = wle_gtk_plug_new (g_getenv ("XSCREENSAVER_WINDOW"));
+    }
 #endif
     gtk_widget_set_app_paintable (window, TRUE);
     g_signal_connect (G_OBJECT (window), "destroy",
diff --git a/src/Makefile.am b/src/Makefile.am
index 5770f04d..3a3e8ab6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -104,6 +104,12 @@ test_window_SOURCES = \
 	subprocs.h       \
 	xfce-desktop-utils.c \
 	xfce-desktop-utils.h \
+	gs-manager.c \
+	gs-manager.h \
+	gs-theme-manager.c \
+	gs-theme-manager.h \
+	gs-job.c \
+	gs-job.h \
 	$(NULL)
 
 test_window_CFLAGS = \
@@ -112,6 +118,7 @@ test_window_CFLAGS = \
 	$(DBUS_GLIB_CFLAGS) \
 	$(LIBXFCE4UI_CFLAGS) \
 	$(XFCONF_CFLAGS) \
+	$(GARCON_GTK3_CFLAGS) \
 	$(NULL)
 
 test_window_LDADD = \
@@ -120,6 +127,7 @@ test_window_LDADD = \
 	$(DBUS_GLIB_LIBS) \
 	$(LIBXFCE4UI_LIBS) \
 	$(XFCONF_LIBS) \
+	$(GARCON_GTK3_LIBS) \
 	$(NULL)
 
 if ENABLE_X11
@@ -141,6 +149,18 @@ test_window_LDADD += \
 	$(NULL)
 endif
 
+if ENABLE_WAYLAND
+test_window_CFLAGS += \
+	$(LIBWLEMBED_CFLAGS) \
+	$(LIBWLEMBED_GTK3_CFLAGS) \
+	$(NULL)
+
+test_window_LDADD += \
+	$(LIBWLEMBED_LIBS) \
+	$(LIBWLEMBED_GTK3_LIBS) \
+	$(NULL)
+endif
+
 xfce4_screensaver_dialog_built_sources = \
 	xfce4-screensaver-dialog-css.h  \
 	xfce4-screensaver-dialog-ui.h
@@ -179,6 +199,7 @@ xfce4_screensaver_dialog_CFLAGS = \
 	$(LIBXFCE4UI_CFLAGS) \
 	$(XFCONF_CFLAGS) \
 	$(AUTH_CFLAGS) \
+	$(LIBWLEMBED_GTK3_CFLAGS) \
 	$(NULL)
 
 xfce4_screensaver_dialog_LDADD = \
@@ -188,6 +209,7 @@ xfce4_screensaver_dialog_LDADD = \
 	$(LIBXFCE4UI_LIBS) \
 	$(XFCONF_LIBS) \
 	$(AUTH_LIBS) \
+	$(LIBWLEMBED_GTK3_LIBS) \
 	$(NULL)
 
 if ENABLE_X11
@@ -296,6 +318,18 @@ xfce4_screensaver_LDADD += \
 	$(NULL)
 endif
 
+if ENABLE_WAYLAND
+xfce4_screensaver_CFLAGS += \
+	$(LIBWLEMBED_CFLAGS) \
+	$(LIBWLEMBED_GTK3_CFLAGS) \
+	$(NULL)
+
+xfce4_screensaver_LDADD += \
+	$(LIBWLEMBED_LIBS) \
+	$(LIBWLEMBED_GTK3_LIBS) \
+	$(NULL)
+endif
+
 xfce4_screensaver_LDFLAGS = -export-dynamic
 
 xfce4_screensaver_preferences_built_sources = \
@@ -325,6 +359,8 @@ xfce4_screensaver_preferences_CFLAGS = \
 	$(XFCONF_CFLAGS) \
 	$(GARCON_GTK3_CFLAGS) \
 	$(LIBXKLAVIER_CFLAGS) \
+	$(LIBWLEMBED_CFLAGS) \
+	$(LIBWLEMBED_GTK3_CFLAGS) \
 	$(NULL)
 
 xfce4_screensaver_preferences_LDADD = \
@@ -334,6 +370,8 @@ xfce4_screensaver_preferences_LDADD = \
 	$(XFCONF_LIBS) \
 	$(GARCON_GTK3_LIBS) \
 	$(LIBXKLAVIER_LIBS) \
+	$(LIBWLEMBED_LIBS) \
+	$(LIBWLEMBED_GTK3_LIBS) \
 	$(NULL)
 
 if MAINTAINER_MODE
diff --git a/src/gs-job.c b/src/gs-job.c
index af6cfdf8..7031a9e6 100644
--- a/src/gs-job.c
+++ b/src/gs-job.c
@@ -37,6 +37,11 @@
 #include <gdk/gdkx.h>
 #include <gtk/gtkx.h>
 #endif
+#ifdef ENABLE_WAYLAND
+#include <gdk/gdkwayland.h>
+#include <libwlembed/libwlembed.h>
+#include <libwlembed-gtk3/libwlembed-gtk3.h>
+#endif
 
 #if defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS)
 #include <sys/resource.h>
@@ -47,6 +52,7 @@
 #include "gs-prefs.h"
 #include "gs-theme-manager.h"
 #include "subprocs.h"
+#include "xfce-desktop-utils.h"
 
 static void gs_job_finalize   (GObject    *object);
 
@@ -83,6 +89,11 @@ widget_get_id_string (GtkWidget *widget) {
         id = g_strdup_printf ("0x%lX", gtk_socket_get_id (GTK_SOCKET (widget)));
     }
 #endif
+#ifdef ENABLE_WAYLAND
+    if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) {
+        id = g_strdup (wle_gtk_socket_get_embedding_token (WLE_GTK_SOCKET (widget)));
+    }
+#endif
 
     return id;
 }
@@ -281,13 +292,25 @@ get_env_vars (GtkWidget *widget) {
         "LANG",
         "LANGUAGE",
         "DBUS_SESSION_BUS_ADDRESS",
-        "G_DEBUG"
+        "G_DEBUG",
+        "LD_LIBRARY_PATH",
+        "XDG_RUNTIME_DIR",
     };
 
     env = g_ptr_array_new ();
 
     display_name = gdk_display_get_name (gtk_widget_get_display (widget));
-    g_ptr_array_add (env, g_strdup_printf ("DISPLAY=%s", display_name));
+#ifdef ENABLE_X11
+    if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())) {
+        g_ptr_array_add (env, g_strdup_printf ("DISPLAY=%s", display_name));
+    }
+#endif
+#ifdef ENABLE_WAYLAND
+    if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) {
+        g_ptr_array_add (env, g_strdup_printf ("WAYLAND_DISPLAY=%s", display_name));
+        g_ptr_array_add (env, g_strdup_printf ("DISPLAY=%s", g_getenv ("DISPLAY")));
+    }
+#endif
 
     g_ptr_array_add (env, g_strdup_printf ("HOME=%s",
                                            g_get_home_dir ()));
@@ -342,17 +365,18 @@ spawn_on_widget (GtkWidget  *widget,
     env = get_env_vars (widget);
 
     error = NULL;
-    result = g_spawn_async_with_pipes (NULL,
-                                       argv,
-                                       (char **)env->pdata,
-                                       G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
-                                       NULL,
-                                       NULL,
-                                       &child_pid,
-                                       NULL,
-                                       NULL,
-                                       watch_func != NULL ? &standard_error : NULL,
-                                       &error);
+    result = spawn_async_with_pipes (widget,
+                                     NULL,
+                                     argv,
+                                     (char **)env->pdata,
+                                     G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
+                                     NULL,
+                                     NULL,
+                                     &child_pid,
+                                     NULL,
+                                     NULL,
+                                     watch_func != NULL ? &standard_error : NULL,
+                                     &error);
 
     for (guint i = 0; i < env->len; i++) {
         g_free (g_ptr_array_index (env, i));
diff --git a/src/gs-lock-plug.c b/src/gs-lock-plug.c
index 8b535d68..f2c68789 100644
--- a/src/gs-lock-plug.c
+++ b/src/gs-lock-plug.c
@@ -43,6 +43,10 @@
 #include "xfcekbd-indicator.h"
 #endif
 #endif
+#ifdef ENABLE_WAYLAND
+#include <gdk/gdkwayland.h>
+#include <libwlembed-gtk3/libwlembed-gtk3.h>
+#endif
 
 #include <libxfce4util/libxfce4util.h>
 #include <xfconf/xfconf.h>
@@ -1607,6 +1611,11 @@ gs_lock_plug_init (GSLockPlug *plug) {
     if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())) {
         plug->priv->plug_widget = gtk_plug_new (0);
     }
+#endif
+#ifdef ENABLE_WAYLAND
+    if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) {
+        plug->priv->plug_widget = wle_gtk_plug_new (g_getenv ("WLE_EMBEDDING_TOKEN"));
+    }
 #endif
     g_object_set_data (G_OBJECT (plug->priv->plug_widget), "gs-lock-plug", plug);
 
diff --git a/src/gs-manager.c b/src/gs-manager.c
index a8c53768..dae02976 100644
--- a/src/gs-manager.c
+++ b/src/gs-manager.c
@@ -29,6 +29,10 @@
 #include <gdk/gdkx.h>
 #include "gs-grab.h"
 #endif
+#ifdef ENABLE_WAYLAND
+#include <gdk/gdkwayland.h>
+#include <libwlembed-gtk3/libwlembed-gtk3.h>
+#endif
 
 #include "gs-debug.h"
 #include "gs-job.h"
@@ -61,6 +65,9 @@ struct GSManagerPrivate {
 #ifdef ENABLE_X11
     GSGrab         *grab;
 #endif
+#ifdef ENABLE_WAYLAND
+    WleEmbeddedCompositor *compositor;
+#endif
 };
 
 enum {
@@ -445,6 +452,17 @@ gs_manager_init (GSManager *manager) {
                                                  NULL, (GDestroyNotify) remove_job);
     manager->priv->windows = g_hash_table_new_full (g_direct_hash, g_direct_equal,
                                                     NULL, (GDestroyNotify) gs_window_destroy);
+
+#ifdef ENABLE_WAYLAND
+    if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) {
+        GError *error = NULL;
+        manager->priv->compositor = wle_gtk_create_embedded_compositor ("xfce4-screensaver", &error);
+        if (manager->priv->compositor == NULL) {
+            g_critical ("Failed to create embedded compositor: %s", error->message);
+            g_error_free (error);
+        }
+    }
+#endif
 }
 
 static void
@@ -958,6 +976,12 @@ gs_manager_finalize (GObject *object) {
 
     g_object_unref (manager->priv->prefs);
 
+#ifdef ENABLE_WAYLAND
+    if (manager->priv->compositor != NULL) {
+        g_object_unref (manager->priv->compositor);
+    }
+#endif
+
     G_OBJECT_CLASS (gs_manager_parent_class)->finalize (object);
 }
 
@@ -983,14 +1007,13 @@ gs_manager_create_windows (GSManager *manager) {
 
 GSManager *
 gs_manager_new (void) {
-    GObject   *manager;
-    GSManager *mgr;
-
-    manager = g_object_new (GS_TYPE_MANAGER, NULL);
-
-    mgr = GS_MANAGER (manager);
-
-    return mgr;
+    static GSManager *manager = NULL;
+    if (manager == NULL) {
+        manager = g_object_new (GS_TYPE_MANAGER, NULL);
+    } else {
+        g_object_ref (manager);
+    }
+    return manager;
 }
 
 static void
@@ -1022,6 +1045,14 @@ gs_manager_activate (GSManager *manager) {
     }
 #endif
 
+#ifdef ENABLE_WAYLAND
+    if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) {
+        if (manager->priv->compositor == NULL) {
+            return FALSE;
+        }
+    }
+#endif
+
     gs_manager_create_windows (GS_MANAGER (manager));
 
     manager->priv->active = TRUE;
@@ -1101,3 +1132,10 @@ gs_manager_request_unlock (GSManager *manager) {
 
     return TRUE;
 }
+
+#ifdef ENABLE_WAYLAND
+WleEmbeddedCompositor *
+gs_manager_get_compositor (GSManager *manager) {
+    return manager->priv->compositor;
+}
+#endif
diff --git a/src/gs-manager.h b/src/gs-manager.h
index fa615b48..edb5ebb6 100644
--- a/src/gs-manager.h
+++ b/src/gs-manager.h
@@ -24,6 +24,9 @@
 #define SRC_GS_MANAGER_H_
 
 #include "gs-prefs.h"
+#ifdef ENABLE_WAYLAND
+#include <libwlembed/libwlembed.h>
+#endif
 
 G_BEGIN_DECLS
 
@@ -72,6 +75,10 @@ void        gs_manager_show_message            (GSManager   *manager,
                                                 const char  *icon);
 gboolean    gs_manager_request_unlock          (GSManager   *manager);
 
+#ifdef ENABLE_WAYLAND
+WleEmbeddedCompositor *gs_manager_get_compositor (GSManager *manager);
+#endif
+
 G_END_DECLS
 
 #endif /* SRC_GS_MANAGER_H_ */
diff --git a/src/gs-window-x11.c b/src/gs-window-x11.c
index 6546c33b..91dac297 100644
--- a/src/gs-window-x11.c
+++ b/src/gs-window-x11.c
@@ -35,6 +35,10 @@
 #include <gtk/gtkx.h>
 #include <X11/extensions/shape.h>
 #endif
+#ifdef ENABLE_WAYLAND
+#include <gdk/gdkwayland.h>
+#include <libwlembed-gtk3/libwlembed-gtk3.h>
+#endif
 
 #include "gs-debug.h"
 #include "gs-marshal.h"
@@ -42,6 +46,7 @@
 #include "gs-window.h"
 #include "subprocs.h"
 #include "xfce-desktop-utils.h"
+#include "gs-manager.h"
 
 static void     gs_window_finalize       (GObject       *object);
 
@@ -60,6 +65,7 @@ enum {
 #define INFO_BAR_SECONDS 30
 
 struct GSWindowPrivate {
+    GSManager       *manager;
     GdkMonitor      *monitor;
 
     GdkRectangle     geometry;
@@ -796,7 +802,7 @@ error_watch (GIOChannel   *source,
 }
 
 static gboolean
-spawn_on_window (GSWindow *window,
+spawn_on_window (GtkWidget *socket,
                  char     *command,
                  int      *pid,
                  GIOFunc   watch_func,
@@ -822,18 +828,19 @@ spawn_on_window (GSWindow *window,
     }
 
     error = NULL;
-    envp = spawn_make_environment_for_display (gtk_widget_get_display (GTK_WIDGET (window)), NULL);
-    result = g_spawn_async_with_pipes (NULL,
-                                       argv,
-                                       envp,
-                                       G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
-                                       NULL,
-                                       NULL,
-                                       &child_pid,
-                                       NULL,
-                                       &standard_output,
-                                       redirect_stderr ? &standard_error : NULL,
-                                       &error);
+    envp = spawn_make_environment_for_display (socket);
+    result = spawn_async_with_pipes (socket,
+                                     NULL,
+                                     argv,
+                                     envp,
+                                     G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
+                                     NULL,
+                                     NULL,
+                                     &child_pid,
+                                     NULL,
+                                     &standard_output,
+                                     redirect_stderr ? &standard_error : NULL,
+                                     &error);
 
     if (!result) {
         gs_debug ("Could not start command '%s': %s", command, error->message);
@@ -884,15 +891,13 @@ spawn_on_window (GSWindow *window,
 }
 
 static void
-lock_plug_added (GtkWidget *widget,
-                 GSWindow  *window) {
-    gtk_widget_show (widget);
+lock_plug_added (GSWindow *window) {
+    gtk_widget_show (window->priv->lock_socket);
 }
 
 static gboolean
-lock_plug_removed (GtkWidget *widget,
-                   GSWindow  *window) {
-    gtk_widget_hide (widget);
+lock_plug_removed (GSWindow *window) {
+    gtk_widget_hide (window->priv->lock_socket);
     gtk_container_remove (GTK_CONTAINER (window->priv->overlay), GTK_WIDGET (window->priv->lock_box));
     window->priv->lock_box = NULL;
 
@@ -903,15 +908,13 @@ lock_plug_removed (GtkWidget *widget,
 }
 
 static void
-keyboard_plug_added (GtkWidget *widget,
-                     GSWindow  *window) {
-    gtk_widget_show (widget);
+keyboard_plug_added (GSWindow *window) {
+    gtk_widget_show (window->priv->keyboard_socket);
 }
 
 static gboolean
-keyboard_plug_removed (GtkWidget *widget,
-                       GSWindow  *window) {
-    gtk_widget_hide (widget);
+keyboard_plug_removed (GSWindow *window) {
+    gtk_widget_hide (window->priv->keyboard_socket);
     gtk_container_remove (GTK_CONTAINER (window->priv->overlay), GTK_WIDGET (window->priv->keyboard_socket));
 
     return TRUE;
@@ -992,6 +995,11 @@ socket_new (GSWindow *window) {
     if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())) {
         return gtk_socket_new ();
     }
+#endif
+#ifdef ENABLE_WAYLAND
+    if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) {
+        return wle_gtk_socket_new (gs_manager_get_compositor (window->priv->manager));
+    }
 #endif
     return NULL;
 }
@@ -1032,10 +1040,10 @@ create_keyboard_socket (GSWindow *window,
 
     g_signal_connect (window->priv->keyboard_socket, "destroy",
                       G_CALLBACK (keyboard_socket_destroyed), window);
-    g_signal_connect (window->priv->keyboard_socket, "plug_added",
-                      G_CALLBACK (keyboard_plug_added), window);
-    g_signal_connect (window->priv->keyboard_socket, "plug_removed",
-                      G_CALLBACK (keyboard_plug_removed), window);
+    g_signal_connect_swapped (window->priv->keyboard_socket, "plug_added",
+                              G_CALLBACK (keyboard_plug_added), window);
+    g_signal_connect_swapped (window->priv->keyboard_socket, "plug_removed",
+                              G_CALLBACK (keyboard_plug_removed), window);
 
     gtk_overlay_add_overlay (GTK_OVERLAY (window->priv->overlay), window->priv->keyboard_socket);
 #ifdef ENABLE_X11
@@ -1099,6 +1107,12 @@ keyboard_process_finish (GSWindow *window) {
         g_spawn_close_pid (window->priv->keyboard_pid);
         window->priv->keyboard_pid = 0;
     }
+
+#ifdef ENABLE_WAYLAND
+    if (window->priv->keyboard_socket != NULL) {
+        keyboard_plug_removed (window);
+    }
+#endif
 }
 
 static gboolean
@@ -1120,12 +1134,16 @@ keyboard_process_watch (GIOChannel   *source,
         switch (status) {
             case G_IO_STATUS_NORMAL:
             {
-                gulong id;
-                char c;
-                gs_debug ("Keyboard command output: %s", line);
-                if (1 == sscanf (line, " %lu %c", &id, &c)) {
-                    create_keyboard_socket (window, id);
+#ifdef ENABLE_X11
+                if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())) {
+                    gulong id;
+                    char c;
+                    gs_debug ("Keyboard command output: %s", line);
+                    if (1 == sscanf (line, " %lu %c", &id, &c)) {
+                        create_keyboard_socket (window, id);
+                    }
                 }
+#endif
             }
             break;
             case G_IO_STATUS_EOF:
@@ -1134,7 +1152,7 @@ keyboard_process_watch (GIOChannel   *source,
             case G_IO_STATUS_ERROR:
                 gs_debug ("Error reading from child: %s\n", error->message);
                 g_error_free (error);
-                return FALSE;
+                finished = TRUE;
             case G_IO_STATUS_AGAIN:
             default:
                 break;
@@ -1162,13 +1180,19 @@ embed_keyboard (GSWindow *window) {
             || window->priv->prefs->keyboard_command == NULL)
         return;
 
+#ifdef ENABLE_WAYLAND
+    if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) {
+        create_keyboard_socket (window, 0);
+    }
+#endif
+
     gs_debug ("Adding embedded keyboard widget");
 
     /* FIXME: verify command is safe */
 
     gs_debug ("Running command: %s", window->priv->prefs->keyboard_command);
 
-    res = spawn_on_window (window,
+    res = spawn_on_window (window->priv->keyboard_socket,
                            window->priv->prefs->keyboard_command,
                            &window->priv->keyboard_pid,
                            (GIOFunc)keyboard_process_watch,
@@ -1202,10 +1226,10 @@ create_lock_socket (GSWindow *window,
                       G_CALLBACK (lock_socket_show), window);
     g_signal_connect (window->priv->lock_socket, "destroy",
                       G_CALLBACK (lock_socket_destroyed), window);
-    g_signal_connect (window->priv->lock_socket, "plug_added",
-                      G_CALLBACK (lock_plug_added), window);
-    g_signal_connect (window->priv->lock_socket, "plug_removed",
-                      G_CALLBACK (lock_plug_removed), window);
+    g_signal_connect_swapped (window->priv->lock_socket, "plug-added",
+                              G_CALLBACK (lock_plug_added), window);
+    g_signal_connect_swapped (window->priv->lock_socket, "plug-removed",
+                              G_CALLBACK (lock_plug_removed), window);
 
 #ifdef ENABLE_X11
     if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())) {
@@ -1260,10 +1284,14 @@ popdown_dialog (GSWindow *window) {
     gs_window_dialog_finish (window);
 
     gtk_widget_show (window->priv->drawing_area);
-    // TODO: Avoids a critical warning due to GTK bug
-    // remove this if https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/6841 get merged
-    gtk_widget_set_can_focus (window->priv->drawing_area, TRUE);
-    gtk_widget_grab_focus (window->priv->drawing_area);
+#ifdef ENABLE_X11
+    if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())) {
+        // TODO: Avoids a critical warning due to GTK bug
+        // remove this if https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/6841 get merged
+        gtk_widget_set_can_focus (window->priv->drawing_area, TRUE);
+        gtk_widget_grab_focus (window->priv->drawing_area);
+    }
+#endif
 
     gs_window_clear (window);
     set_invisible_cursor (gtk_widget_get_window (GTK_WIDGET (window)), TRUE);
@@ -1274,14 +1302,8 @@ popdown_dialog (GSWindow *window) {
     window->priv->last_x = -1;
     window->priv->last_y = -1;
 
-    if (window->priv->lock_box != NULL) {
-        gtk_container_remove (GTK_CONTAINER (window->priv->overlay), GTK_WIDGET (window->priv->lock_box));
-        window->priv->lock_box = NULL;
-    }
-
-    if (window->priv->overlay != NULL) {
-        gtk_container_remove (GTK_CONTAINER (window->priv->vbox), GTK_WIDGET (window->priv->overlay));
-        window->priv->overlay = NULL;
+    if (window->priv->lock_socket != NULL) {
+        lock_plug_removed (window);
     }
 
     remove_popup_dialog_idle (window);
@@ -1309,11 +1331,15 @@ dialog_process_watch (GIOChannel   *source,
                 gs_debug ("Command output: %s", line);
 
                 if (strstr (line, "WINDOW ID=") != NULL) {
-                    gulong id;
-                    char c;
-                    if (1 == sscanf (line, " WINDOW ID= %lu %c", &id, &c)) {
-                        create_lock_socket (window, id);
+#ifdef ENABLE_X11
+                    if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())) {
+                        gulong id;
+                        char c;
+                        if (1 == sscanf (line, " WINDOW ID= %lu %c", &id, &c)) {
+                            create_lock_socket (window, id);
+                        }
                     }
+#endif
                 } else if (strstr (line, "NOTICE=") != NULL) {
                     if (strstr (line, "NOTICE=AUTH FAILED") != NULL) {
                         gs_debug ("Authorization failed");
@@ -1338,7 +1364,7 @@ dialog_process_watch (GIOChannel   *source,
             case G_IO_STATUS_ERROR:
                 gs_debug ("Error reading from child: %s\n", error->message);
                 g_error_free (error);
-                return FALSE;
+                finished = TRUE;
             case G_IO_STATUS_AGAIN:
             default:
                 break;
@@ -1456,8 +1482,14 @@ popup_dialog (GSWindow *window) {
     gtk_widget_queue_draw (GTK_WIDGET (window));
     set_invisible_cursor (gtk_widget_get_window (GTK_WIDGET (window)), FALSE);
 
+#ifdef ENABLE_WAYLAND
+    if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) {
+        create_lock_socket (window, 0);
+    }
+#endif
+
     gs_debug ("Executing %s", command->str);
-    result = spawn_on_window (window,
+    result = spawn_on_window (window->priv->lock_socket,
                               command->str,
                               &window->priv->lock_pid,
                               (GIOFunc)dialog_process_watch,
@@ -1979,6 +2011,7 @@ gs_window_init (GSWindow *window) {
     window->priv->last_x = -1;
     window->priv->last_y = -1;
 
+    window->priv->manager = gs_manager_new ();
     window->priv->prefs = gs_prefs_new();
 
     gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
@@ -2070,6 +2103,7 @@ gs_window_finalize (GObject *object) {
 
     gs_window_dialog_finish (window);
     g_object_unref (window->priv->prefs);
+    g_object_unref (window->priv->manager);
 
     G_OBJECT_CLASS (gs_window_parent_class)->finalize (object);
 }
diff --git a/src/xfce-desktop-utils.c b/src/xfce-desktop-utils.c
index 16c305d6..ba2651c0 100644
--- a/src/xfce-desktop-utils.c
+++ b/src/xfce-desktop-utils.c
@@ -25,16 +25,18 @@
 
 #include <config.h>
 
-#include <string.h>
 #include <gio/gio.h>
-#include <glib.h>
-#include <gdk/gdk.h>
-#include <gtk/gtk.h>
+#ifdef ENABLE_X11
+#include <gdk/gdkx.h>
+#endif
+#ifdef ENABLE_WAYLAND
+#include <gdk/gdkwayland.h>
+#include <libwlembed-gtk3/libwlembed-gtk3.h>
+#endif
 
 #include <libxfce4util/libxfce4util.h>
 
-#include <xfce-desktop-utils.h>
-
+#include "xfce-desktop-utils.h"
 #include "gs-debug.h"
 
 /**
@@ -79,40 +81,65 @@ xfce_gdk_spawn_command_line_on_screen (GdkScreen    *screen,
 }
 
 gchar **
-spawn_make_environment_for_display (GdkDisplay  *display,
-                                    gchar      **envp) {
-    gchar       **retval = NULL;
-    const gchar  *display_name;
-    gint          display_index = -1;
-    gint          i, env_len;
-    gboolean      own_envp = FALSE;
-
-    g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
-
-    if (envp == NULL) {
-        envp = g_get_environ ();
-        own_envp = TRUE;
+spawn_make_environment_for_display (GtkWidget *socket) {
+    gchar **retval = NULL;
+    const gchar *display_name = gdk_display_get_name (gdk_display_get_default ());
+    gchar **envp = g_get_environ ();
+    gint env_len = g_strv_length (envp);
+
+#ifdef ENABLE_X11
+    if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())) {
+        retval = g_new0 (char *, env_len + 1);
+        for (gint i = 0; i < env_len; i++) {
+            if (strcmp (envp[i], "DISPLAY") == 0) {
+                retval[i] = g_strconcat ("DISPLAY=", display_name, NULL);
+            } else {
+                retval[i] = g_strdup (envp[i]);
+            }
+        }
     }
-
-    for (env_len = 0; envp[env_len]; env_len++)
-        if (strncmp (envp[env_len], "DISPLAY", strlen ("DISPLAY")) == 0)
-            display_index = env_len;
-
-    retval = g_new (char *, env_len + 1);
-    retval[env_len] = NULL;
-
-    display_name = gdk_display_get_name (display);
-
-    for (i = 0; i < env_len; i++)
-        if (i == display_index)
-            retval[i] = g_strconcat ("DISPLAY=", display_name, NULL);
-        else
+#endif
+#ifdef ENABLE_WAYLAND
+    if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) {
+        retval = g_new0 (char *, env_len + 3);
+        for (gint i = 0; i < env_len; i++) {
             retval[i] = g_strdup (envp[i]);
+        }
+        retval[env_len] = g_strdup_printf ("WAYLAND_DISPLAY=%s", display_name);
+        retval[env_len + 1] = g_strdup_printf ("WLE_EMBEDDING_TOKEN=%s", wle_gtk_socket_get_embedding_token (WLE_GTK_SOCKET (socket)));
+    }
+#endif
 
-    if (own_envp)
-        g_strfreev (envp);
-
-    g_assert (i == env_len);
+    g_strfreev (envp);
 
     return retval;
 }
+
+gboolean
+spawn_async_with_pipes (GtkWidget *socket,
+                        const gchar *working_directory,
+                        gchar **argv,
+                        gchar **envp,
+                        GSpawnFlags flags,
+                        GSpawnChildSetupFunc child_setup,
+                        gpointer user_data,
+                        GPid *child_pid,
+                        gint *standard_input,
+                        gint *standard_output,
+                        gint *standard_error,
+                        GError **error) {
+#ifdef ENABLE_X11
+    if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())) {
+        return g_spawn_async_with_pipes (working_directory, argv, envp, flags, child_setup, user_data,
+                                         child_pid, standard_input, standard_output, standard_error, error);
+    }
+#endif
+#ifdef ENABLE_WAYLAND
+    if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) {
+        return wle_embedded_compositor_spawn_with_pipes (wle_gtk_socket_get_embedded_compositor (WLE_GTK_SOCKET (socket)),
+                                                         working_directory, argv, envp, flags, child_setup, user_data,
+                                                         child_pid, standard_input, standard_output, standard_error, error);
+    }
+#endif
+    return FALSE;
+}
diff --git a/src/xfce-desktop-utils.h b/src/xfce-desktop-utils.h
index 29c5582b..9e36a12d 100644
--- a/src/xfce-desktop-utils.h
+++ b/src/xfce-desktop-utils.h
@@ -26,19 +26,29 @@
 #ifndef SRC_XFCE_DESKTOP_UTILS_H_
 #define SRC_XFCE_DESKTOP_UTILS_H_
 
-#include <glib.h>
-#include <gdk/gdk.h>
 #include <gtk/gtk.h>
 
 G_BEGIN_DECLS
 
 /* replace gdk_spawn_command_line_on_screen, not available in GTK3 */
-gboolean xfce_gdk_spawn_command_line_on_screen (GdkScreen    *screen,
-                                                const gchar  *command,
-                                                GError      **error);
-
-gchar  **spawn_make_environment_for_display    (GdkDisplay   *display,
-                                                gchar       **envp);
+gboolean      xfce_gdk_spawn_command_line_on_screen       (GdkScreen               *screen,
+                                                           const gchar             *command,
+                                                           GError                 **error);
+
+gchar       **spawn_make_environment_for_display          (GtkWidget               *socket);
+
+gboolean      spawn_async_with_pipes                      (GtkWidget               *socket,
+                                                           const gchar             *working_directory,
+                                                           gchar                  **argv,
+                                                           gchar                  **envp,
+                                                           GSpawnFlags              flags,
+                                                           GSpawnChildSetupFunc     child_setup,
+                                                           gpointer                 user_data,
+                                                           GPid                    *child_pid,
+                                                           gint                    *standard_input,
+                                                           gint                    *standard_output,
+                                                           gint                    *standard_error,
+                                                           GError                 **error);
 
 G_END_DECLS
 
diff --git a/src/xfce4-screensaver-dialog.c b/src/xfce4-screensaver-dialog.c
index 506170cc..ad0976b1 100644
--- a/src/xfce4-screensaver-dialog.c
+++ b/src/xfce4-screensaver-dialog.c
@@ -37,6 +37,9 @@
 #include <gdk/gdkx.h>
 #include <gtk/gtkx.h>
 #endif
+#ifdef ENABLE_WAYLAND
+#include <gdk/gdkwayland.h>
+#endif
 
 #include <libxfce4util/libxfce4util.h>
 #include <xfconf/xfconf.h>
@@ -95,6 +98,11 @@ static char* get_id_string(GtkWidget* widget) {
         id = g_strdup_printf ("%lu", gtk_plug_get_id (GTK_PLUG (widget)));
     }
 #endif
+#ifdef ENABLE_WAYLAND
+    if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) {
+        id = g_strdup ("");
+    }
+#endif
 
     return id;
 }
diff --git a/src/xfce4-screensaver-preferences.c b/src/xfce4-screensaver-preferences.c
index d4f1ee87..8db70a2e 100644
--- a/src/xfce4-screensaver-preferences.c
+++ b/src/xfce4-screensaver-preferences.c
@@ -37,6 +37,11 @@
 #include <gdk/gdkx.h>
 #include <gtk/gtkx.h>
 #endif
+#ifdef ENABLE_WAYLAND
+#include <gdk/gdkwayland.h>
+#include <libwlembed/libwlembed.h>
+#include <libwlembed-gtk3/libwlembed-gtk3.h>
+#endif
 
 #include <libxfce4ui/libxfce4ui.h>
 #include <xfconf/xfconf.h>
@@ -68,6 +73,9 @@ static GSThemeManager *theme_manager = NULL;
 static GSJob          *job = NULL;
 static XfconfChannel  *screensaver_channel = NULL;
 static XfceScreensaver *xfce_screensaver = NULL;
+#ifdef ENABLE_WAYLAND
+static WleEmbeddedCompositor *compositor = NULL;
+#endif
 
 static gboolean        idle_delay_writable;
 static gboolean        lock_delay_writable;
@@ -611,17 +619,26 @@ preview_on_draw (GtkWidget *widget,
 }
 
 static void
-preview_set_theme (GtkWidget  *widget,
-                   const char *theme,
+preview_set_theme (const char *theme,
                    const char *name) {
-    GtkWidget *label;
+    GtkWidget *label, *preview;
     char      *markup;
 
+    preview = gtk_bin_get_child (GTK_BIN (gtk_builder_get_object (builder, "saver_themes_preview_area")));
+    if (!gtk_widget_is_visible (preview)) {
+        preview = gtk_bin_get_child (GTK_BIN (gtk_builder_get_object (builder, "fullscreen_preview_area")));
+    }
+
     if (job != NULL) {
         gs_job_stop (job);
+#ifdef ENABLE_WAYLAND
+        if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) {
+            wle_gtk_socket_destroy_embedded_view (WLE_GTK_SOCKET (preview));
+        }
+#endif
     }
 
-    gtk_widget_queue_draw (widget);
+    gtk_widget_queue_draw (preview);
 
     label = GTK_WIDGET (gtk_builder_get_object (builder, "fullscreen_preview_theme_label"));
     markup = g_markup_printf_escaped ("<i>%s</i>", name);
@@ -789,8 +806,7 @@ tree_selection_next (GtkTreeSelection *selection) {
 }
 
 static void
-tree_selection_changed_cb (GtkTreeSelection *selection,
-                           GtkWidget        *preview) {
+tree_selection_changed_cb (GtkTreeSelection *selection) {
     GtkWidget    *configure_button;
     GtkTreeIter   iter;
     GtkTreeModel *model;
@@ -816,7 +832,7 @@ tree_selection_changed_cb (GtkTreeSelection *selection,
         return;
     }
 
-    preview_set_theme (preview, theme, name);
+    preview_set_theme (theme, name);
     config_set_theme (theme);
 
     g_free (theme);
@@ -1022,12 +1038,11 @@ setup_treeview (GtkWidget *tree,
     gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
     g_signal_connect (G_OBJECT (select), "changed",
                       G_CALLBACK (tree_selection_changed_cb),
-                      preview);
+                      NULL);
 }
 
 static void
 reload_theme (GtkWidget *treeview) {
-    GtkWidget        *preview;
     GtkTreeIter       iter;
     GtkTreeModel     *model;
     GtkTreeSelection *selection;
@@ -1056,8 +1071,7 @@ reload_theme (GtkWidget *treeview) {
         return;
     }
 
-    preview  = gtk_bin_get_child (GTK_BIN (gtk_builder_get_object (builder, "saver_themes_preview_area")));
-    preview_set_theme (preview, theme, name);
+    preview_set_theme (theme, name);
 
     g_free (theme);
     g_free (name);
@@ -1812,6 +1826,19 @@ configure_capplet (void) {
         gtk_container_add (GTK_CONTAINER (preview), gtk_socket_new ());
         gtk_container_add (GTK_CONTAINER (fullscreen_preview_area), gtk_socket_new ());
     }
+#endif
+#ifdef ENABLE_WAYLAND
+    if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) {
+        GError *_error = NULL;
+        compositor = wle_gtk_create_embedded_compositor ("xfce4-screensaver-preferences", &_error);
+        if (compositor == NULL) {
+            g_critical ("Failed to create embedded compositor: %s", _error->message);
+            g_error_free (_error);
+        } else {
+            gtk_container_add (GTK_CONTAINER (preview), wle_gtk_socket_new (compositor));
+            gtk_container_add (GTK_CONTAINER (fullscreen_preview_area), wle_gtk_socket_new (compositor));
+        }
+    }
 #endif
     preview = gtk_bin_get_child (GTK_BIN (preview));
     gtk_widget_set_app_paintable (preview, TRUE);
@@ -2026,6 +2053,11 @@ finalize_capplet (void) {
 
     if (active_theme)
         g_free (active_theme);
+
+#ifdef ENABLE_WAYLAND
+    if (compositor)
+        g_object_unref (compositor);
+#endif
 }
 
 int
-- 
GitLab