diff --git a/src/modules/xwayland/e_mod_main.c b/src/modules/xwayland/e_mod_main.c index a6e5ed746..fe8b64eec 100644 --- a/src/modules/xwayland/e_mod_main.c +++ b/src/modules/xwayland/e_mod_main.c @@ -1,11 +1,26 @@ #include "e.h" #include "e_comp_wl.h" +#include +#include /* local structures */ typedef struct _E_XWayland_Server E_XWayland_Server; struct _E_XWayland_Server { int disp; + int abs_fd, unx_fd; + char lock[256]; + + struct wl_event_loop *loop; + + Ecore_Fd_Handler *abs_hdlr, *unx_hdlr; + Ecore_Event_Handler *sig_hdlr; + + struct + { + pid_t pid; + /* cleanup_func func; */ + } process; }; /* local variables */ @@ -13,14 +28,12 @@ static E_XWayland_Server *exs; /* local functions */ static Eina_Bool -_lock_create(int disp) +_lock_create(char *lock) { - char lock[256], pid[16], *end; + char pid[16], *end; int fd, size; pid_t opid; - /* assemble lock file name */ - snprintf(lock, sizeof(lock), "/tmp/.X%d-lock", disp); fd = open(lock, (O_WRONLY | O_CLOEXEC | O_CREAT | O_EXCL), 0444); if ((fd < 0) && (errno == EEXIST)) { @@ -77,6 +90,158 @@ _lock_create(int disp) return EINA_TRUE; } +static int +_abstract_socket_bind(int disp) +{ + struct sockaddr_un addr; + socklen_t size, nsize; + int fd; + + /* try to create a local socket */ + if ((fd = socket(PF_LOCAL, (SOCK_STREAM | SOCK_CLOEXEC), 0)) < 0) + return -1; + + addr.sun_family = AF_LOCAL; + nsize = snprintf(addr.sun_path, sizeof(addr.sun_path), + "%c/tmp/.X11-unix/X%d", 0, disp); + size = offsetof(struct sockaddr_un, sun_path) + nsize; + + /* try to bind to the socket */ + if (bind(fd, (struct sockaddr *)&addr, size) < 0) + { + ERR("Failed to bind to abstract socket %s: %m", addr.sun_path + 1); + goto err; + } + + /* try to listen on the bound socket */ + if (listen(fd, 1) < 0) goto err; + + return fd; + +err: + close(fd); + return -1; +} + +static int +_unix_socket_bind(int disp) +{ + struct sockaddr_un addr; + socklen_t size, nsize; + int fd; + + /* try to create a local socket */ + if ((fd = socket(PF_LOCAL, (SOCK_STREAM | SOCK_CLOEXEC), 0)) < 0) + return -1; + + addr.sun_family = AF_LOCAL; + nsize = snprintf(addr.sun_path, sizeof(addr.sun_path), + "/tmp/.X11-unix/X%d", disp) + 1; + size = offsetof(struct sockaddr_un, sun_path) + nsize; + + unlink(addr.sun_path); + + /* try to bind to the socket */ + if (bind(fd, (struct sockaddr *)&addr, size) < 0) + { + ERR("Failed to bind to abstract socket %s: %m", addr.sun_path + 1); + goto err; + } + + /* try to listen on the bound socket */ + if (listen(fd, 1) < 0) goto err; + + return fd; + +err: + close(fd); + return -1; +} + +static Eina_Bool +_cb_xserver_event(void *data EINA_UNUSED, Ecore_Fd_Handler *hdlr EINA_UNUSED) +{ + int socks[2], wms[2], fd; + char disp[8], s[8], *xserver = NULL; + char abs_fd[8], unx_fd[8], wm_fd[8]; + + if (socketpair(AF_UNIX, (SOCK_STREAM | SOCK_CLOEXEC), 0, socks) < 0) + { + ERR("XServer Socketpair failed: %m"); + return ECORE_CALLBACK_RENEW; + } + + if (socketpair(AF_UNIX, (SOCK_STREAM | SOCK_CLOEXEC), 0, wms) < 0) + { + ERR("Window Manager Socketpair failed: %m"); + return ECORE_CALLBACK_RENEW; + } + + exs->process.pid = fork(); + switch (exs->process.pid) + { + case 0: + /* dup will unset CLOEXEC on the client as cloexec closes both ends */ + if ((fd = dup(socks[1]) < 0)) goto fail; + snprintf(s, sizeof(s), "%d", fd); + setenv("WAYLAND_SOCKET", s, 1); + + if ((fd = dup(exs->abs_fd)) < 0) goto fail; + snprintf(abs_fd, sizeof(abs_fd), "%d", fd); + + if ((fd = dup(exs->unx_fd)) < 0) goto fail; + snprintf(unx_fd, sizeof(unx_fd), "%d", fd); + + if ((fd = dup(wms[1])) < 0) goto fail; + snprintf(wm_fd, sizeof(wm_fd), "%d", fd); + + /* ignore usr1 and have X send it to the parent process */ + signal(SIGUSR1, SIG_IGN); + + /* FIXME: need to get the patch of xwayland */ + snprintf(disp, sizeof(disp), ":%d", exs->disp); + + DBG("XWAYLAND: %s", XWAYLAND_BIN); + if (execl(xserver, xserver, disp, "-rootless", "-listen", abs_fd, + "-listen", unx_fd, "-wm", wm_fd, "-terminate", NULL) < 0) + { + ERR("Failed to exec XWayland: %m"); + } + +fail: + _exit(EXIT_FAILURE); + + break; + default: + close(socks[1]); + /* TODO: client_create */ + close(wms[1]); + /* TODO */ + /* TODO: remove event sources */ + break; + case -1: + ERR("Failed to fork: %m"); + break; + } + + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +_cb_signal_event(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED) +{ + /* E_XWayland_Server *exs; */ + + /* NB: SIGUSR1 comes from XWayland Server when it has finished + * initialized. */ + + /* if (!(exs = data)) return ECORE_CALLBACK_RENEW; */ + + /* TODO: create "window manager" process */ + + return ECORE_CALLBACK_RENEW; +} + /* module functions */ EAPI E_Module_Api e_modapi = { E_MODULE_API_VERSION, "XWayland" }; @@ -84,6 +249,7 @@ EAPI void * e_modapi_init(E_Module *m) { E_Comp *comp; + char disp[8]; /* try to get the running compositor */ if (!(comp = e_comp_get(NULL))) return NULL; @@ -99,7 +265,11 @@ e_modapi_init(E_Module *m) exs->disp = 0; lock: - if (!_lock_create(exs->disp)) + /* assemble lock file name */ + snprintf(exs->lock, sizeof(exs->lock), "/tmp/.X%d-lock", exs->disp); + + /* try to create the xserver lock file */ + if (!_lock_create(exs->lock)) { if (errno == EAGAIN) goto lock; @@ -115,15 +285,45 @@ lock: } } - /* TODO: bind sockets */ + /* try to bind abstract socket */ + exs->abs_fd = _abstract_socket_bind(exs->disp); + if ((exs->abs_fd < 0) && (errno == EADDRINUSE)) + { + exs->disp++; + unlink(exs->lock); + goto lock; + } + + /* try to bind unix socket */ + if ((exs->unx_fd = _unix_socket_bind(exs->disp)) < 0) + { + unlink(exs->lock); + close(exs->abs_fd); + free(exs); + return NULL; + } + + /* assemble x11 display name and set it */ + snprintf(disp, sizeof(disp), ":%d", exs->disp); + setenv("DISPLAY", disp, 1); + + /* setup ecore_fd handlers for abstract and unix socket fds */ + exs->abs_hdlr = + ecore_main_fd_handler_add(exs->abs_fd, ECORE_FD_READ, + _cb_xserver_event, NULL, NULL, NULL); + exs->unx_hdlr = + ecore_main_fd_handler_add(exs->unx_fd, ECORE_FD_READ, + _cb_xserver_event, NULL, NULL, NULL); + + /* setup listener for SIGUSR1 */ + exs->sig_hdlr = + ecore_event_handler_add(ECORE_EVENT_SIGNAL_USER, _cb_signal_event, exs); return m; } EAPI int -e_modapi_shutdown(E_Module *m) +e_modapi_shutdown(E_Module *m EINA_UNUSED) { return 1; } - -