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:
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>