swc

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/swc
Log | Files | Refs | README | LICENSE

commit e65ccedbcfb4a9cfde8a22b246c79910db898d93
parent bf9647b14f14f31dc96d8bc397f175d37aaabd44
Author: Michael Forney <mforney@mforney.org>
Date:   Wed, 23 Apr 2014 22:17:38 -0700

Update to new implementation of XWayland

Fixes #6

Diffstat:
M.gitignore | 2--
Mlibswc/internal.h | 4++++
Mlibswc/swc.c | 8+++++++-
Mlibswc/xserver.c | 182++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mlibswc/xserver.h | 5+++++
Mlibswc/xwm.c | 245++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Mlibswc/xwm.h | 5-----
Mprotocol/local.mk | 3+--
Dprotocol/xserver.xml | 18------------------
9 files changed, 266 insertions(+), 206 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -6,8 +6,6 @@ protocol/swc-protocol.c protocol/swc-server-protocol.h protocol/wayland-drm-protocol.c protocol/wayland-drm-server-protocol.h -protocol/xserver-protocol.c -protocol/xserver-server-protocol.h /.deps/ /swc.pc diff --git a/libswc/internal.h b/libswc/internal.h @@ -41,6 +41,10 @@ struct swc struct swc_compositor * const compositor; struct swc_shm * const shm; struct swc_drm * const drm; + +#ifdef ENABLE_XWAYLAND + const struct swc_xserver * const xserver; +#endif }; extern struct swc swc; diff --git a/libswc/swc.c b/libswc/swc.c @@ -47,6 +47,9 @@ extern const struct swc_bindings swc_bindings; extern struct swc_compositor swc_compositor; extern struct swc_drm swc_drm; extern struct swc_shm swc_shm; +#ifdef ENABLE_XWAYLAND +extern struct swc_xserver swc_xserver; +#endif struct swc swc = { .launch = &swc_launch, @@ -54,7 +57,10 @@ struct swc swc = { .bindings = &swc_bindings, .compositor = &swc_compositor, .drm = &swc_drm, - .shm = &swc_shm + .shm = &swc_shm, +#ifdef ENABLE_XWAYLAND + .xserver = &swc_xserver, +#endif }; static void setup_compositor() diff --git a/libswc/xserver.c b/libswc/xserver.c @@ -39,7 +39,6 @@ #include <sys/socket.h> #include <sys/un.h> #include <wayland-server.h> -#include "protocol/xserver-server-protocol.h" #define LOCK_FMT "/tmp/.X%d-lock" #define SOCKET_DIR "/tmp/.X11-unix" @@ -47,30 +46,14 @@ static struct { - struct wl_global * global; - struct wl_client * client; struct wl_resource * resource; + struct wl_event_source * usr1_source; int display; char display_name[16]; - int abstract_fd, unix_fd; + int abstract_fd, unix_fd, wm_fd; } xserver; -static char * xserver_command[] = { - "X", "-wayland", "-rootless", "-nolisten", "all", xserver.display_name, NULL -}; - -static void set_window_id(struct wl_client * client, - struct wl_resource * resource, - struct wl_resource * surface_resource, uint32_t id) -{ - struct swc_surface * surface = wl_resource_get_user_data(surface_resource); - - xwm_manage_window(id, surface); -} - -const static struct xserver_interface xserver_implementation = { - .set_window_id = &set_window_id -}; +struct swc_xserver swc_xserver; static int open_socket(struct sockaddr_un * addr, size_t path_size) { @@ -175,41 +158,22 @@ static void close_display() unsetenv("DISPLAY"); } -static void bind_xserver(struct wl_client * client, void * data, - uint32_t version, uint32_t id) +static int handle_usr1(int signal_number, void * data) { - int sv[2]; - - if (client != xserver.client) - return; - - if (version >= 1) - version = 1; - - DEBUG("Binding X server\n"); - - xserver.resource = wl_resource_create(client, &xserver_interface, - version, id); - wl_resource_set_implementation(xserver.resource, &xserver_implementation, - NULL, NULL); - - /* Start the X window manager */ - socketpair(AF_UNIX, SOCK_STREAM, 0, sv); - xserver_send_client(xserver.resource, sv[1]); - close(sv[1]); + if (!xwm_initialize(xserver.wm_fd)) + { + ERROR("Failed to initialize X window manager\n"); + /* XXX: How do we handle this case? */ + } - /* Need to flush the xserver client so the X window manager can connect to - * it's socket. */ - wl_client_flush(xserver.client); - xwm_initialize(sv[0]); + wl_event_source_remove(xserver.usr1_source); - xserver_send_listen_socket(xserver.resource, xserver.abstract_fd); - xserver_send_listen_socket(xserver.resource, xserver.unix_fd); + return 0; } -static bool start_xserver() +bool xserver_initialize() { - int sv[2]; + int wl[2], wm[2]; /* Open an X display */ if (!open_display()) @@ -218,76 +182,116 @@ static bool start_xserver() goto error0; } - /* Start the X server */ - if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) == -1) + xserver.usr1_source = wl_event_loop_add_signal(swc.event_loop, SIGUSR1, + &handle_usr1, NULL); + + if (!xserver.usr1_source) { - ERROR("Failed to create socketpair: %s\n", strerror(errno)); + ERROR("Failed to create SIGUSR1 event source\n"); goto error1; } - if (!(xserver.client = wl_client_create(swc.display, sv[0]))) + /* Open a socket for the Wayland connection from Xwayland. */ + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, wl) != 0) + { + ERROR("Failed to create socketpair: %s\n", strerror(errno)); goto error2; + } - switch (fork()) + /* Open a socket for the X connection to Xwayland. */ + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, wm) != 0) { - case 0: - { - int socket_fd; - char socket_string[32]; + ERROR("Failed to create socketpair: %s\n", strerror(errno)); + goto error3; + } - if (!(socket_fd = dup(sv[1]))) - exit(EXIT_FAILURE); + if (!(swc_xserver.client = wl_client_create(swc.display, wl[0]))) + goto error4; - snprintf(socket_string, sizeof socket_string, "%d", socket_fd); - setenv("WAYLAND_SOCKET", socket_string, true); + xserver.wm_fd = wm[0]; - execvp(xserver_command[0], xserver_command); + /* Start the X server */ + switch (fork()) + { + case 0: + { + int fds[] = { wl[1], wm[1], xserver.abstract_fd, xserver.unix_fd }; + char strings[ARRAY_LENGTH(fds)][16]; + unsigned index; + struct sigaction action = { .sa_handler = SIG_IGN }; + + /* Unset the FD_CLOEXEC flag on the FDs that will get passed to + * Xwayland. */ + for (index = 0; index < ARRAY_LENGTH(fds); ++index) + { + if (fcntl(fds[index], F_SETFD, 0) != 0) + { + ERROR("fcntl() failed: %s\n", strerror(errno)); + goto fail; + } + + if (snprintf(strings[index], sizeof strings[index], + "%d", fds[index]) >= sizeof strings[index]) + { + ERROR("FD is too large\n"); + goto fail; + } + } + + /* Ignore the USR1 signal so that Xwayland will send a USR1 signal + * to the parent process (us) after it finishes initializing. See + * Xserver(1) for more details. */ + if (sigaction(SIGUSR1, &action, NULL) != 0) + { + ERROR("Failed to set SIGUSR1 handler to SIG_IGN: %s\n", + strerror(errno)); + goto fail; + } + + setenv("WAYLAND_SOCKET", strings[0], true); + execlp("Xwayland", "Xwayland", + xserver.display_name, + "-rootless", + "-terminate", + "-listen", strings[2], + "-listen", strings[3], + "-wm", strings[1], + NULL); + + fail: exit(EXIT_FAILURE); - - break; } case -1: ERROR("fork() failed when trying to start X server: %s\n", strerror(errno)); - goto error2; + goto error5; } - close(sv[1]); + close(wl[1]); + close(wm[1]); return true; + error5: + wl_client_destroy(swc_xserver.client); + error4: + close(wm[1]); + close(wm[0]); + error3: + close(wl[1]); + close(wl[0]); error2: - close(sv[1]); - close(sv[0]); + wl_event_source_remove(xserver.usr1_source); error1: close_display(); error0: return false; } -bool xserver_initialize() -{ - xserver.global = wl_global_create(swc.display, &xserver_interface, 1, - NULL, &bind_xserver); - - if (!xserver.global) - goto error0; - - if (!start_xserver()) - goto error1; - - return true; - - error1: - wl_global_destroy(xserver.global); - error0: - return false; -} - void xserver_finalize() { xwm_finalize(); close_display(); - wl_global_destroy(xserver.global); + wl_client_destroy(swc_xserver.client); } diff --git a/libswc/xserver.h b/libswc/xserver.h @@ -26,6 +26,11 @@ #include <stdbool.h> +struct swc_xserver +{ + struct wl_client * client; +}; + bool xserver_initialize(); void xserver_finalize(); diff --git a/libswc/xwm.c b/libswc/xwm.c @@ -29,14 +29,17 @@ #include "util.h" #include "view.h" #include "window.h" +#include "xserver.h" #include <stdio.h> #include <xcb/composite.h> #include <xcb/xcb_ewmh.h> +#include <xcb/xcb_icccm.h> struct xwl_window { xcb_window_t id; + uint32_t surface_id; bool override_redirect; struct wl_list link; @@ -50,6 +53,7 @@ struct xwl_window enum atom { ATOM_WM_S0, + ATOM_WL_SURFACE_ID, }; static struct @@ -65,10 +69,11 @@ static struct const char * name; xcb_intern_atom_cookie_t cookie; xcb_atom_t value; - } atoms[1]; + } atoms[2]; } xwm = { .atoms = { [ATOM_WM_S0] = "WM_S0", + [ATOM_WL_SURFACE_ID] = "WL_SURFACE_ID", } }; @@ -100,6 +105,135 @@ static struct xwl_window * find_window(struct wl_list * list, xcb_window_t id) return NULL; } +static struct xwl_window * find_window_by_surface_id(struct wl_list * list, + uint32_t id) +{ + struct xwl_window * window; + + wl_list_for_each(window, list, link) + { + if (window->surface_id == id) + return window; + } + + return NULL; +} + +static void configure(struct window * window, + const struct swc_rectangle * geometry) +{ + uint32_t mask, values[4]; + struct xwl_window * xwl_window + = CONTAINER_OF(window, typeof(*xwl_window), window); + + mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y + | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; + values[0] = geometry->x; + values[1] = geometry->y; + values[2] = geometry->width; + values[3] = geometry->height; + + xcb_configure_window(xwm.connection, xwl_window->id, mask, values); + xcb_flush(xwm.connection); +} + +static void focus(struct window * window) +{ + xcb_window_t id = window ? CONTAINER_OF(window, struct xwl_window, + window)->id + : XCB_NONE; + + xcb_set_input_focus(xwm.connection, XCB_INPUT_FOCUS_NONE, + id, XCB_CURRENT_TIME); + xcb_flush(xwm.connection); +} + +static const struct window_impl xwl_window_handler = { + .configure = &configure, + .focus = &focus +}; + +static void handle_surface_destroy(struct wl_listener * listener, void * data) +{ + struct xwl_window * xwl_window + = CONTAINER_OF(listener, typeof(*xwl_window), surface_destroy_listener); + + window_finalize(&xwl_window->window); + wl_list_remove(&xwl_window->link); + wl_list_insert(&xwm.unpaired_windows, &xwl_window->link); + xwl_window->surface_id = 0; +} + +static bool manage_window(struct xwl_window * xwl_window) +{ + struct wl_resource * resource; + struct swc_surface * surface; + xcb_get_geometry_cookie_t geometry_cookie; + xcb_get_geometry_reply_t * geometry_reply; + + resource = wl_client_get_object(swc.xserver->client, + xwl_window->surface_id); + + if (!resource) + return false; + + surface = wl_resource_get_user_data(resource); + geometry_cookie = xcb_get_geometry(xwm.connection, xwl_window->id); + + window_initialize(&xwl_window->window, &xwl_window_handler, surface); + xwl_window->surface_destroy_listener.notify = &handle_surface_destroy; + wl_resource_add_destroy_listener(surface->resource, + &xwl_window->surface_destroy_listener); + + if ((geometry_reply = xcb_get_geometry_reply(xwm.connection, + geometry_cookie, NULL))) + { + view_move(surface->view, geometry_reply->x, geometry_reply->y); + free(geometry_reply); + } + + if (xwl_window->override_redirect) + compositor_view_show(xwl_window->window.view); + else + { + uint32_t mask, values[1]; + + mask = XCB_CW_EVENT_MASK; + values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE; + xcb_change_window_attributes(xwm.connection, xwl_window->id, + mask, values); + mask = XCB_CONFIG_WINDOW_BORDER_WIDTH; + values[0] = 0; + xcb_configure_window(xwm.connection, xwl_window->id, mask, values); + update_name(xwl_window); + + window_set_state(&xwl_window->window, SWC_WINDOW_STATE_NORMAL); + } + + wl_list_remove(&xwl_window->link); + wl_list_insert(&xwm.windows, &xwl_window->link); + + return true; +} + +static void handle_new_surface(struct wl_listener * listener, void * data) +{ + struct swc_surface * surface = data; + struct xwl_window * window; + + window = find_window_by_surface_id(&xwm.unpaired_windows, + wl_resource_get_id(surface->resource)); + + if (!window) + return; + + manage_window(window); +} + +static struct wl_listener new_surface_listener = { + .notify = &handle_new_surface +}; + /* X event handlers */ static void create_notify(xcb_create_notify_event_t * event) { @@ -109,6 +243,7 @@ static void create_notify(xcb_create_notify_event_t * event) return; xwl_window->id = event->window; + xwl_window->surface_id = 0; xwl_window->override_redirect = event->override_redirect; wl_list_insert(&xwm.unpaired_windows, &xwl_window->link); } @@ -152,6 +287,20 @@ static void property_notify(xcb_property_notify_event_t * event) } } +static void client_message(xcb_client_message_event_t * event) +{ + if (event->type == xwm.atoms[ATOM_WL_SURFACE_ID].value) + { + struct xwl_window * xwl_window; + + if (!(xwl_window = find_window(&xwm.unpaired_windows, event->window))) + return; + + xwl_window->surface_id = event->data.data32[0]; + manage_window(xwl_window); + } +} + static int connection_data(int fd, uint32_t mask, void * data) { xcb_generic_event_t * event; @@ -175,6 +324,10 @@ static int connection_data(int fd, uint32_t mask, void * data) break; case XCB_PROPERTY_NOTIFY: property_notify((xcb_property_notify_event_t *) event); + break; + case XCB_CLIENT_MESSAGE: + client_message((xcb_client_message_event_t *) event); + break; } free(event); @@ -301,6 +454,8 @@ bool xwm_initialize(int fd) xwm.atoms[ATOM_WM_S0].value, XCB_CURRENT_TIME); xcb_flush(xwm.connection); + wl_signal_add(&swc.compositor->signal.new_surface, &new_surface_listener); + return true; error3: @@ -320,91 +475,3 @@ void xwm_finalize() xcb_disconnect(xwm.connection); } -static void configure(struct window * window, - const struct swc_rectangle * geometry) -{ - uint32_t mask, values[4]; - struct xwl_window * xwl_window - = CONTAINER_OF(window, typeof(*xwl_window), window); - - mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y - | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; - values[0] = geometry->x; - values[1] = geometry->y; - values[2] = geometry->width; - values[3] = geometry->height; - - xcb_configure_window(xwm.connection, xwl_window->id, mask, values); - xcb_flush(xwm.connection); -} - -static void focus(struct window * window) -{ - xcb_window_t id = window ? CONTAINER_OF(window, struct xwl_window, - window)->id - : XCB_NONE; - - xcb_set_input_focus(xwm.connection, XCB_INPUT_FOCUS_NONE, - id, XCB_CURRENT_TIME); - xcb_flush(xwm.connection); -} - -static const struct window_impl xwl_window_handler = { - .configure = &configure, - .focus = &focus -}; - -static void handle_surface_destroy(struct wl_listener * listener, void * data) -{ - struct xwl_window * xwl_window - = CONTAINER_OF(listener, typeof(*xwl_window), surface_destroy_listener); - - window_finalize(&xwl_window->window); - wl_list_remove(&xwl_window->link); - wl_list_insert(&xwm.unpaired_windows, &xwl_window->link); -} - -void xwm_manage_window(xcb_window_t id, struct swc_surface * surface) -{ - struct xwl_window * xwl_window; - xcb_get_geometry_cookie_t geometry_cookie; - xcb_get_geometry_reply_t * geometry_reply; - - if (!(xwl_window = find_window(&xwm.unpaired_windows, id))) - return; - - geometry_cookie = xcb_get_geometry(xwm.connection, id); - - window_initialize(&xwl_window->window, &xwl_window_handler, surface); - xwl_window->surface_destroy_listener.notify = &handle_surface_destroy; - wl_resource_add_destroy_listener(surface->resource, - &xwl_window->surface_destroy_listener); - - if ((geometry_reply = xcb_get_geometry_reply(xwm.connection, - geometry_cookie, NULL))) - { - view_move(surface->view, geometry_reply->x, geometry_reply->y); - free(geometry_reply); - } - - if (xwl_window->override_redirect) - compositor_view_show(xwl_window->window.view); - else - { - uint32_t mask, values[1]; - - mask = XCB_CW_EVENT_MASK; - values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE; - xcb_change_window_attributes(xwm.connection, id, mask, values); - mask = XCB_CONFIG_WINDOW_BORDER_WIDTH; - values[0] = 0; - xcb_configure_window(xwm.connection, id, mask, values); - update_name(xwl_window); - - window_set_state(&xwl_window->window, SWC_WINDOW_STATE_NORMAL); - } - - wl_list_remove(&xwl_window->link); - wl_list_insert(&xwm.windows, &xwl_window->link); -} - diff --git a/libswc/xwm.h b/libswc/xwm.h @@ -25,14 +25,9 @@ #define SWC_XWM_H #include <stdbool.h> -#include <xcb/xcb.h> - -struct swc_surface; bool xwm_initialize(int fd); void xwm_finalize(); -void xwm_manage_window(xcb_window_t window, struct swc_surface * surface); - #endif diff --git a/protocol/local.mk b/protocol/local.mk @@ -4,8 +4,7 @@ dir := protocol PROTOCOL_EXTENSIONS = \ $(dir)/swc.xml \ - $(dir)/wayland-drm.xml \ - $(dir)/xserver.xml + $(dir)/wayland-drm.xml $(dir)_TARGETS := $(PROTOCOL_EXTENSIONS:%.xml=%-protocol.c) \ $(PROTOCOL_EXTENSIONS:%.xml=%-server-protocol.h) diff --git a/protocol/xserver.xml b/protocol/xserver.xml @@ -1,18 +0,0 @@ -<protocol name="xserver"> - - <interface name="xserver" version="1"> - <request name="set_window_id"> - <arg name="surface" type="object" interface="wl_surface"/> - <arg name="id" type="uint"/> - </request> - - <event name="client"> - <arg name="fd" type="fd"/> - </event> - - <event name="listen_socket"> - <arg name="fd" type="fd"/> - </event> - </interface> - -</protocol>