Init Xwayland
authorMarius Vlad <marius.vlad@collabora.com>
Mon, 8 May 2023 16:20:25 +0000 (19:20 +0300)
committerMarius Vlad <marius.vlad@collabora.com>
Wed, 10 May 2023 15:25:31 +0000 (18:25 +0300)
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
Change-Id: I87d2a852165cb3f03482bea1e04931bdd6d4c115

meson.build
meson_options.txt
src/compositor.c
src/desktop.c
src/ivi-compositor.h
src/layout.c
src/xwayland.c [new file with mode: 0644]

index 388f785..d10c337 100644 (file)
@@ -237,6 +237,13 @@ if dep_libsmack.found()
   deps_libweston += dep_libsmack
 endif
 
+if get_option('xwayland')
+        config_h.set('BUILD_XWAYLAND', '1')
+
+        srcs_agl_compositor += 'src/xwayland.c'
+        config_h.set_quoted('XSERVER_PATH', get_option('xwayland-path'))
+endif
+
 dir_module_agl_compositor = join_paths(join_paths(prefix_path, get_option('libdir')), 'agl-compositor')
 
 libexec_compositor = shared_library(
index e4d8f3d..31bbb73 100644 (file)
@@ -19,3 +19,17 @@ option(
         value: false,
         description: 'Build compositor with Waltham support. Disabled by default'
 )
+
+option(
+    'xwayland',
+    type: 'boolean',
+    value: false,
+    description: 'Build compositor with XWayland support. Disabled by default'
+)
+
+option(
+        'xwayland-path',
+        type: 'string',
+        value: '/usr/bin/Xwayland',
+        description: 'Xwayland: path to installed Xwayland binary'
+)
index 250c90c..663fc4c 100644 (file)
@@ -1327,27 +1327,18 @@ load_modules(struct ivi_compositor *ivi, const char *modules,
                snprintf(buffer, sizeof buffer, "%.*s", (int) (end - p), p);
 
                if (strstr(buffer, "xwayland.so")) {
-                       weston_log("Xwayland plug-in not supported!\n");
-                       p = end;
-                       while (*p == ',')
-                               p++;
-                       continue;
-               }
-
-               if (strstr(buffer, "systemd-notify.so")) {
+                       *xwayland = true;
+               } else if (strstr(buffer, "systemd-notify.so")) {
                        weston_log("systemd-notify plug-in already loaded!\n");
-                       p = end;
-                       while (*p == ',')
-                               p++;
-                       continue;
-               }
+               } else {
+                       module_init = weston_load_module(buffer, "wet_module_init");
+                       if (!module_init)
+                               return -1;
 
-               module_init = weston_load_module(buffer, "wet_module_init");
-               if (!module_init)
-                       return -1;
+                       if (module_init(ivi->compositor, *argc, argv) < 0)
+                               return -1;
 
-               if (module_init(ivi->compositor, *argc, argv) < 0)
-                       return -1;
+               }
 
                p = end;
                while (*p == ',')
@@ -1742,6 +1733,14 @@ copy_command_line(int argc, char * const argv[])
        return str;
 }
 
+#if !defined(BUILD_XWAYLAND)
+int
+wet_load_xwayland(struct weston_compositor *comp)
+{
+       return -1;
+}
+#endif
+
 WL_EXPORT
 int wet_main(int argc, char *argv[], const struct weston_testsuite_data *test_data)
 {
@@ -1900,6 +1899,16 @@ int wet_main(int argc, char *argv[], const struct weston_testsuite_data *test_da
        if (load_modules(&ivi, option_modules, &argc, argv, &xwayland) < 0)
                goto error_compositor;
 
+       if (!xwayland) {
+               weston_config_section_get_bool(section, "xwayland", &xwayland,
+                                              false);
+       }
+
+       if (xwayland) {
+               if (wet_load_xwayland(ivi.compositor) < 0)
+                       goto error_compositor;
+       }
+
        if (ivi_policy_init(&ivi) < 0)
                goto error_compositor;
 
index 340f14f..c938f4a 100644 (file)
@@ -30,6 +30,7 @@
 #include "shared/helpers.h"
 #include <libweston/libweston.h>
 #include <libweston-desktop/libweston-desktop.h>
+#include <libweston/xwayland-api.h>
 
 #include "agl-shell-desktop-server-protocol.h"
 
@@ -516,7 +517,12 @@ static void
 desktop_set_xwayland_position(struct weston_desktop_surface *dsurface,
                              int32_t x, int32_t y, void *userdata)
 {
-       /* not supported */
+       struct ivi_surface *ivisurf =
+               weston_desktop_surface_get_user_data(dsurface);
+
+       ivisurf->xwayland.x = x;
+       ivisurf->xwayland.y = y;
+       ivisurf->xwayland.is_set = true;
 }
 
 static const struct weston_desktop_api desktop_api = {
@@ -547,9 +553,39 @@ ivi_shell_destroy(struct wl_listener *listener, void *data)
        ivi_layout_destroy_saved_outputs(ivi);
 
        weston_desktop_destroy(ivi->desktop);
+       wl_list_remove(&ivi->transform_listener.link);
        wl_list_remove(&listener->link);
 }
 
+static void
+transform_handler(struct wl_listener *listener, void *data)
+{
+       struct weston_surface *surface = data;
+       struct ivi_surface *ivisurf = get_ivi_shell_surface(surface);
+       const struct weston_xwayland_surface_api *api;
+       int x, y;
+
+       if (!ivisurf)
+               return;
+
+       api = ivisurf->ivi->xwayland_surface_api;
+       if (!api) {
+               api = weston_xwayland_surface_get_api(ivisurf->ivi->compositor);
+               ivisurf->ivi->xwayland_surface_api = api;
+       }
+
+       if (!api || !api->is_xwayland_surface(surface))
+               return;
+
+       if (!weston_view_is_mapped(ivisurf->view))
+               return;
+
+       x = ivisurf->view->geometry.x;
+       y = ivisurf->view->geometry.y;
+
+       api->send_position(surface, x, y);
+}
+
 int
 ivi_desktop_init(struct ivi_compositor *ivi)
 {
@@ -564,5 +600,10 @@ ivi_desktop_init(struct ivi_compositor *ivi)
                return -1;
        }
 
+       ivi->transform_listener.notify = transform_handler;
+       wl_signal_add(&ivi->compositor->transform_signal,
+                     &ivi->transform_listener);
+
+
        return 0;
 }
index 857b816..41978ea 100644 (file)
@@ -118,6 +118,8 @@ struct ivi_compositor {
        struct wl_list remote_pending_apps;
 
        struct wl_listener destroy_listener;
+       struct wl_listener transform_listener;
+       const struct weston_xwayland_surface_api *xwayland_surface_api;
 
        struct weston_layer hidden;
        struct weston_layer background;
@@ -316,6 +318,12 @@ struct ivi_surface {
        struct ivi_surface_waltham waltham_surface;
        struct wl_listener listener_advertise_app;
        struct wl_signal signal_advertise_app;
+
+       struct {
+               bool is_set;
+               int32_t x;
+               int32_t y;
+       } xwayland;
 };
 
 struct ivi_shell_seat {
index ea293ca..98a1df8 100644 (file)
@@ -587,7 +587,12 @@ ivi_layout_desktop_committed(struct ivi_surface *surf)
                                 */
                                weston_log("Surface no app_id, role %s activating by default\n",
                                        ivi_layout_get_surface_role_name(surf));
-                               ivi_layout_activate_by_surf(r_output, surf);
+                               if (surf->xwayland.is_set) {
+                                       ivi_layout_activate_by_surf(r_output, surf);
+                                       ivi_layout_activate_complete(r_output, surf);
+                               } else {
+                                       ivi_layout_activate_by_surf(r_output, surf);
+                               }
                        }
                }
 
diff --git a/src/xwayland.c b/src/xwayland.c
new file mode 100644 (file)
index 0000000..8ac5edc
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * Copyright © 2011 Intel Corporation
+ * Copyright © 2016 Giulio Camuffo
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+#include "ivi-compositor.h"
+
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+
+#include <libweston/libweston.h>
+#include <weston.h>
+#include <libweston/xwayland-api.h>
+#include "shared/helpers.h"
+
+struct wet_xwayland {
+       struct ivi_compositor *ivi_compositor;
+       const struct weston_xwayland_api *api;
+       struct weston_xwayland *xwayland;
+       struct wl_event_source *sigusr1_source;
+       struct wl_client *client;
+       int wm_fd;
+       struct weston_process process;
+};
+
+static int
+handle_sigusr1(int signal_number, void *data)
+{
+       struct wet_xwayland *wxw = data;
+
+       /* We'd be safer if we actually had the struct
+        * signalfd_siginfo from the signalfd data and could verify
+        * this came from Xwayland.*/
+       wxw->api->xserver_loaded(wxw->xwayland, wxw->client, wxw->wm_fd);
+       wl_event_source_remove(wxw->sigusr1_source);
+
+       return 1;
+}
+
+static pid_t
+spawn_xserver(void *user_data, const char *display, int abstract_fd, int unix_fd)
+{
+       struct wet_xwayland *wxw = user_data;
+       pid_t pid;
+       char s[12], abstract_fd_str[12], unix_fd_str[12], wm_fd_str[12];
+       int sv[2], wm[2], fd;
+       char *xserver = NULL;
+       struct weston_config *config = wxw->ivi_compositor->config;
+       struct weston_config_section *section;
+
+       if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
+               weston_log("wl connection socketpair failed\n");
+               return 1;
+       }
+
+       if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, wm) < 0) {
+               weston_log("X wm connection socketpair failed\n");
+               return 1;
+       }
+
+       pid = fork();
+       switch (pid) {
+       case 0:
+               /* SOCK_CLOEXEC closes both ends, so we need to unset
+                * the flag on the client fd. */
+               fd = dup(sv[1]);
+               if (fd < 0)
+                       goto fail;
+               snprintf(s, sizeof s, "%d", fd);
+               setenv("WAYLAND_SOCKET", s, 1);
+
+               fd = dup(abstract_fd);
+               if (fd < 0)
+                       goto fail;
+               snprintf(abstract_fd_str, sizeof abstract_fd_str, "%d", fd);
+               fd = dup(unix_fd);
+               if (fd < 0)
+                       goto fail;
+               snprintf(unix_fd_str, sizeof unix_fd_str, "%d", fd);
+               fd = dup(wm[1]);
+               if (fd < 0)
+                       goto fail;
+               snprintf(wm_fd_str, sizeof wm_fd_str, "%d", fd);
+
+               section = weston_config_get_section(config,
+                                                   "xwayland", NULL, NULL);
+               weston_config_section_get_string(section, "path",
+                                                &xserver, XSERVER_PATH);
+
+               /* Ignore SIGUSR1 in the child, which will make the X
+                * server send SIGUSR1 to the parent (weston) when
+                * it's done with initialization.  During
+                * initialization the X server will round trip and
+                * block on the wayland compositor, so avoid making
+                * blocking requests (like xcb_connect_to_fd) until
+                * it's done with that. */
+               signal(SIGUSR1, SIG_IGN);
+
+               if (execl(xserver,
+                         xserver,
+                         display,
+                         "-rootless",
+#ifdef HAVE_XWAYLAND_LISTENFD
+                         "-listenfd", abstract_fd_str,
+                         "-listenfd", unix_fd_str,
+#else
+                         "-listen", abstract_fd_str,
+                         "-listen", unix_fd_str,
+#endif
+                         "-wm", wm_fd_str,
+                         "-terminate",
+                         NULL) < 0)
+                       weston_log("exec of '%s %s -rootless "
+#ifdef HAVE_XWAYLAND_LISTENFD
+                                  "-listenfd %s -listenfd %s "
+#else
+                                  "-listen %s -listen %s "
+#endif
+                                  "-wm %s -terminate' failed: %s\n",
+                                  xserver, display,
+                                  abstract_fd_str, unix_fd_str, wm_fd_str,
+                                  strerror(errno));
+       fail:
+               _exit(EXIT_FAILURE);
+
+       default:
+               close(sv[1]);
+               wxw->client = wl_client_create(wxw->ivi_compositor->compositor->wl_display, sv[0]);
+
+               close(wm[1]);
+               wxw->wm_fd = wm[0];
+
+               wxw->process.pid = pid;
+               wl_list_insert(&wxw->ivi_compositor->child_process_list,
+                              &wxw->process.link);
+               break;
+
+       case -1:
+               weston_log("Failed to fork to spawn xserver process\n");
+               break;
+       }
+
+       return pid;
+}
+
+static void
+xserver_cleanup(struct weston_process *process, int status)
+{
+       struct wet_xwayland *wxw =
+               container_of(process, struct wet_xwayland, process);
+       struct wl_event_loop *loop =
+               wl_display_get_event_loop(wxw->ivi_compositor->compositor->wl_display);
+
+       wxw->api->xserver_exited(wxw->xwayland, status);
+       wxw->sigusr1_source = wl_event_loop_add_signal(loop, SIGUSR1,
+                                                      handle_sigusr1, wxw);
+       wxw->client = NULL;
+}
+
+int
+wet_load_xwayland(struct weston_compositor *comp)
+{
+       const struct weston_xwayland_api *api;
+       struct weston_xwayland *xwayland;
+       struct wet_xwayland *wxw;
+       struct wl_event_loop *loop;
+       struct ivi_compositor *ivi = to_ivi_compositor(comp);
+
+       if (weston_compositor_load_xwayland(comp) < 0)
+               return -1;
+
+       api = weston_xwayland_get_api(comp);
+       if (!api) {
+               weston_log("Failed to get the xwayland module API.\n");
+               return -1;
+       }
+
+       xwayland = api->get(comp);
+       if (!xwayland) {
+               weston_log("Failed to get the xwayland object.\n");
+               return -1;
+       }
+
+       wxw = zalloc(sizeof *wxw);
+       if (!wxw)
+               return -1;
+
+       wxw->ivi_compositor = ivi;
+       wxw->api = api;
+       wxw->xwayland = xwayland;
+       wxw->process.cleanup = xserver_cleanup;
+       if (api->listen(xwayland, wxw, spawn_xserver) < 0)
+               return -1;
+
+       loop = wl_display_get_event_loop(comp->wl_display);
+       wxw->sigusr1_source = wl_event_loop_add_signal(loop, SIGUSR1,
+                                                      handle_sigusr1, wxw);
+
+       return 0;
+}