diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c index 016d720c..b9157238 100644 --- a/clients/desktop-shell.c +++ b/clients/desktop-shell.c @@ -323,6 +323,9 @@ int main(int argc, char *argv[]) return -1; } + /* The fd is our private, do not confuse our children with it. */ + unsetenv("WAYLAND_SOCKET"); + wl_display_add_global_listener(display_get_display(desktop.display), global_handler, &desktop); diff --git a/compositor/shell.c b/compositor/shell.c index 50c80e9d..1407272b 100644 --- a/compositor/shell.c +++ b/compositor/shell.c @@ -25,6 +25,9 @@ #include #include #include +#include +#include +#include #include "wayland-server.h" #include "compositor.h" @@ -37,6 +40,11 @@ struct wl_shell { struct wl_listener panel_listener; struct wlsc_surface *background; struct wl_listener background_listener; + + struct { + struct wlsc_process process; + struct wl_client *client; + } child; }; struct wlsc_move_grab { @@ -925,6 +933,61 @@ attach(struct wlsc_shell *base, struct wlsc_surface *es) } } +static void +desktop_shell_sigchld(struct wlsc_process *process, int status) +{ + struct wl_shell *shell = + container_of(process, struct wl_shell, child.process); + + shell->child.process.pid = 0; + shell->child.client = NULL; /* already destroyed by wayland */ +} + +static int +launch_desktop_shell_process(struct wl_shell *shell) +{ + const char *shell_exe = "./clients/desktop-shell"; + struct wlsc_compositor *compositor = shell->compositor; + char s[32]; + int sv[2], flags; + + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) { + fprintf(stderr, "socketpair failed\n"); + return -1; + } + + shell->child.process.pid = fork(); + shell->child.process.cleanup = desktop_shell_sigchld; + + switch (shell->child.process.pid) { + case 0: + /* SOCK_CLOEXEC closes both ends, so we need to unset + * the flag on the client fd. */ + flags = fcntl(sv[1], F_GETFD); + if (flags != -1) + fcntl(sv[1], F_SETFD, flags & ~FD_CLOEXEC); + + snprintf(s, sizeof s, "%d", sv[1]); + setenv("WAYLAND_SOCKET", s, 1); + if (execl(shell_exe, shell_exe, NULL) < 0) + fprintf(stderr, "%s: running '%s' failed: %m\n", + __func__, shell_exe); + exit(-1); + + default: + close(sv[1]); + shell->child.client = + wl_client_create(compositor->wl_display, sv[0]); + wlsc_watch_process(&shell->child.process); + break; + + case -1: + fprintf(stderr, "%s: fork failed: %m\n", __func__); + return -1; + } + return 0; +} + static void bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id) { @@ -972,6 +1035,9 @@ shell_init(struct wlsc_compositor *ec) shell, bind_desktop_shell) == NULL) return -1; + if (launch_desktop_shell_process(shell) != 0) + return -1; + wlsc_compositor_add_binding(ec, 0, BTN_LEFT, MODIFIER_SUPER, move_binding, shell); wlsc_compositor_add_binding(ec, 0, BTN_MIDDLE, MODIFIER_SUPER,