commit 28dcc02fff6729df6a593bf92fc9ffd66019fa59
parent 4ab4400c59c1166c996a23f019f9b535cc8954e0
Author: Michael Forney <mforney@mforney.org>
Date: Mon, 25 Nov 2013 18:54:43 -0800
Initial xwayland support
Diffstat:
9 files changed, 777 insertions(+), 2 deletions(-)
diff --git a/config.mk b/config.mk
@@ -14,4 +14,5 @@ WAYLAND_SCANNER ?= wayland-scanner
ENABLE_STATIC = 1
ENABLE_SHARED = 1
+ENABLE_XWAYLAND = 1
diff --git a/libswc/Makefile.local b/libswc/Makefile.local
@@ -61,12 +61,26 @@ SWC_SOURCES += \
libswc/shell_surface.c \
libswc/bindings.c
+ifeq ($(ENABLE_XWAYLAND),1)
+$(dir)_CFLAGS += -DENABLE_XWAYLAND
+$(dir)_PACKAGES += \
+ xcb \
+ xcb-composite \
+ xcb-ewmh
+
+SWC_SOURCES += \
+ libswc/xserver.c \
+ libswc/xwm.c \
+ protocol/xserver-protocol.c
+endif
+
SWC_STATIC_OBJECTS = $(SWC_SOURCES:%.c=%.o)
SWC_SHARED_OBJECTS = $(SWC_SOURCES:%.c=%.lo)
# Explicitly state dependencies on generated files
objects = $(foreach obj,$(1),$(dir)/$(obj).o $(dir)/$(obj.lo))
$(call objects,drm drm_buffer): protocol/wayland-drm-server-protocol.h
+$(call objects,xserver): protocol/xserver-server-protocol.h
$(dir)/libswc.a: $(SWC_STATIC_OBJECTS)
$(call quiet,AR) cru $@ $^
diff --git a/libswc/swc.c b/libswc/swc.c
@@ -30,6 +30,9 @@
#include "seat.h"
#include "shell.h"
#include "window.h"
+#ifdef ENABLE_XWAYLAND
+# include "xserver.h"
+#endif
#include <libudev.h>
@@ -94,10 +97,20 @@ bool swc_initialize(struct wl_display * display,
goto error4;
}
+#ifdef ENABLE_XWAYLAND
+ if (!swc_xserver_initialize())
+ {
+ fprintf(stderr, "Could not initialize xwayland\n");
+ goto error5;
+ }
+#endif
+
setup_compositor();
return true;
+ error5:
+ swc_shell_finalize();
error4:
swc_compositor_finish(&compositor);
error3:
@@ -113,6 +126,9 @@ bool swc_initialize(struct wl_display * display,
EXPORT
void swc_finalize()
{
+#ifdef ENABLE_XWAYLAND
+ swc_xserver_finalize();
+#endif
swc_shell_finalize();
swc_compositor_finish(&compositor);
swc_bindings_finalize();
diff --git a/libswc/xserver.c b/libswc/xserver.c
@@ -0,0 +1,293 @@
+/* swc: libswc/xserver.c
+ *
+ * Copyright (c) 2013 Michael Forney
+ *
+ * Based in part upon xwayland/launcher.c from weston, which is
+ *
+ * Copyright © 2011 Intel Corporation
+ *
+ * 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 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 "xserver.h"
+#include "internal.h"
+#include "util.h"
+#include "xwm.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#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"
+#define SOCKET_FMT SOCKET_DIR "/X%d"
+
+static struct
+{
+ struct wl_global * global;
+ struct wl_client * client;
+ struct wl_resource * resource;
+ int display;
+ char display_name[16];
+ int abstract_socket, unix_socket;
+} 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);
+
+ swc_xwm_manage_window(id, surface);
+}
+
+const static struct xserver_interface xserver_implementation = {
+ .set_window_id = &set_window_id
+};
+
+static int open_socket(struct sockaddr_un * addr, size_t path_size)
+{
+ int fd;
+ socklen_t size = OFFSET_OF(typeof(*addr), sun_path) + path_size + 1;
+
+ if ((fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0)) < 0)
+ goto error0;
+
+ if (bind(fd, (struct sockaddr *) addr, size) < 0)
+ goto error1;
+
+ if (listen(fd, 1) < 0)
+ goto error2;
+
+ return fd;
+
+ error2:
+ if (addr->sun_path[0])
+ unlink(addr->sun_path);
+ error1:
+ close(fd);
+ error0:
+ return -1;
+}
+
+static bool open_display()
+{
+ char lock_name[64], pid[12];
+ int lock_fd;
+ struct sockaddr_un addr = { .sun_family = AF_LOCAL };
+ size_t path_size;
+
+ xserver.display = 0;
+
+ /* Create X lockfile and server sockets */
+ goto begin;
+
+ retry2:
+ close(xserver.abstract_socket);
+ retry1:
+ unlink(lock_name);
+ retry0:
+ if (++xserver.display > 32)
+ {
+ ERROR("No open display in first 32\n");
+ return false;
+ }
+
+ begin:
+ snprintf(lock_name, sizeof lock_name, LOCK_FMT, xserver.display);
+ lock_fd = open(lock_name, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0444);
+
+ /* XXX: Stale lockfile handling? */
+ if (lock_fd < 0)
+ goto retry0;
+
+ snprintf(pid, sizeof pid, "%10d\n", getpid());
+ if (write(lock_fd, pid, sizeof pid) != sizeof pid)
+ {
+ ERROR("Failed to write PID file\n");
+ unlink(lock_name);
+ close(lock_fd);
+ return false;
+ }
+
+ close(lock_fd);
+
+ /* Bind to abstract socket */
+ addr.sun_path[0] = '\0';
+ path_size = snprintf(addr.sun_path + 1, sizeof addr.sun_path - 1,
+ SOCKET_FMT, xserver.display);
+ if ((xserver.abstract_socket = open_socket(&addr, path_size)) < 0)
+ goto retry1;
+
+ /* Bind to unix socket */
+ mkdir(SOCKET_DIR, 0777);
+ path_size = snprintf(addr.sun_path, sizeof addr.sun_path,
+ SOCKET_FMT, xserver.display);
+ if ((xserver.unix_socket = open_socket(&addr, path_size)) < 0)
+ goto retry2;
+
+ snprintf(xserver.display_name, sizeof xserver.display_name,
+ ":%d", xserver.display);
+ setenv("DISPLAY", xserver.display_name, true);
+
+ return true;
+}
+
+static void close_display()
+{
+ char path[64];
+
+ close(xserver.abstract_socket);
+ close(xserver.unix_socket);
+
+ snprintf(path, sizeof path, SOCKET_FMT, xserver.display);
+ unlink(path);
+ snprintf(path, sizeof path, LOCK_FMT, xserver.display);
+ unlink(path);
+
+ unsetenv("DISPLAY");
+}
+
+static void bind_xserver(struct wl_client * client, void * data,
+ uint32_t version, uint32_t id)
+{
+ 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]);
+
+ /* Need to flush the xserver client so the X window manager can connect to
+ * it's socket. */
+ wl_client_flush(xserver.client);
+ swc_xwm_initialize(sv[0]);
+
+ xserver_send_listen_socket(xserver.resource, xserver.abstract_socket);
+ xserver_send_listen_socket(xserver.resource, xserver.unix_socket);
+}
+
+static bool start_xserver()
+{
+ int sv[2];
+
+ /* Open an X display */
+ if (!open_display())
+ {
+ ERROR("Failed to get X lockfile and sockets\n");
+ goto error0;
+ }
+
+ /* Start the X server */
+ if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) == -1)
+ {
+ ERROR("Failed to create socketpair: %s\n", strerror(errno));
+ goto error1;
+ }
+
+ if (!(xserver.client = wl_client_create(swc.display, sv[0])))
+ goto error2;
+
+ switch (fork())
+ {
+ case 0:
+ {
+ int socket_fd;
+ char socket_string[32];
+
+ if (!(socket_fd = dup(sv[1])))
+ exit(EXIT_FAILURE);
+
+ snprintf(socket_string, sizeof socket_string, "%d", socket_fd);
+ setenv("WAYLAND_SOCKET", socket_string, true);
+
+ execvp(xserver_command[0], xserver_command);
+ exit(EXIT_FAILURE);
+
+ break;
+ }
+ case -1:
+ ERROR("fork() failed when trying to start X server: %s\n",
+ strerror(errno));
+ goto error2;
+ }
+
+ close(sv[1]);
+
+ return true;
+
+ error2:
+ close(sv[1]);
+ close(sv[0]);
+ error1:
+ close_display();
+ error0:
+ return false;
+}
+
+bool swc_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 swc_xserver_finalize()
+{
+ swc_xwm_finalize();
+ close_display();
+ wl_global_destroy(xserver.global);
+}
+
diff --git a/libswc/xserver.h b/libswc/xserver.h
@@ -0,0 +1,33 @@
+/* swc: libswc/xserver.h
+ *
+ * Copyright (c) 2013 Michael Forney
+ *
+ * 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 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.
+ */
+
+#ifndef SWC_XSERVER_H
+#define SWC_XSERVER_H
+
+#include <stdbool.h>
+
+bool swc_xserver_initialize();
+void swc_xserver_finalize();
+
+#endif
+
diff --git a/libswc/xwm.c b/libswc/xwm.c
@@ -0,0 +1,361 @@
+/* swc: libswc/xwm.c
+ *
+ * Copyright (c) 2013 Michael Forney
+ *
+ * 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 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 "xwm.h"
+#include "compositor_surface.h"
+#include "internal.h"
+#include "surface.h"
+#include "swc.h"
+#include "util.h"
+#include "window.h"
+
+#include <stdio.h>
+#include <xcb/composite.h>
+#include <xcb/xcb_ewmh.h>
+
+struct xwl_window
+{
+ xcb_window_t id;
+ struct swc_window_internal window;
+ struct wl_listener surface_destroy_listener;
+};
+
+struct xwl_window_entry
+{
+ xcb_window_t id;
+ bool override_redirect;
+ struct xwl_window * xwl_window;
+};
+
+static struct
+{
+ xcb_connection_t * connection;
+ xcb_ewmh_connection_t ewmh;
+ xcb_screen_t * screen;
+ struct wl_event_source * source;
+ struct wl_array windows;
+} xwm;
+
+static void update_name(struct xwl_window * xwl_window)
+{
+ xcb_get_property_cookie_t wm_name_cookie;
+ xcb_ewmh_get_utf8_strings_reply_t wm_name_reply;
+
+ wm_name_cookie = xcb_ewmh_get_wm_name(&xwm.ewmh, xwl_window->id);
+ xcb_ewmh_get_wm_name_reply(&xwm.ewmh, wm_name_cookie,
+ &wm_name_reply, NULL);
+
+ swc_window_set_title(&xwl_window->window.base,
+ wm_name_reply.strings, wm_name_reply.strings_len);
+}
+
+static struct xwl_window_entry * find_window(xcb_window_t id)
+{
+ struct xwl_window_entry * entry;
+
+ wl_array_for_each(entry, &xwm.windows)
+ {
+ if (entry->id == id)
+ return entry;
+ }
+
+ return NULL;
+}
+
+/* X event handlers */
+void create_notify(xcb_create_notify_event_t * event)
+{
+ struct xwl_window_entry * entry;
+
+ if (!(entry = wl_array_add(&xwm.windows, sizeof *entry)))
+ return;
+
+ entry->id = event->window;
+ entry->override_redirect = event->override_redirect;
+ entry->xwl_window = NULL;
+}
+
+void destroy_notify(xcb_destroy_notify_event_t * event)
+{
+ struct xwl_window_entry * entry;
+
+ if (!(entry = find_window(event->window)))
+ return;
+
+ swc_array_remove(&xwm.windows, entry, sizeof *entry);
+}
+
+void map_request(xcb_map_request_event_t * event)
+{
+ xcb_map_window(xwm.connection, event->window);
+}
+
+void configure_request(xcb_configure_request_event_t * event)
+{
+}
+
+void property_notify(xcb_property_notify_event_t * event)
+{
+ struct xwl_window_entry * entry;
+
+ if (!(entry = find_window(event->window)) || !entry->xwl_window)
+ return;
+
+ if (event->atom == xwm.ewmh._NET_WM_NAME
+ && event->state == XCB_PROPERTY_NEW_VALUE)
+ {
+ update_name(entry->xwl_window);
+ }
+}
+
+static int connection_data(int fd, uint32_t mask, void * data)
+{
+ xcb_generic_event_t * event;
+ uint32_t count = 0;
+
+ while ((event = xcb_poll_for_event(xwm.connection)))
+ {
+ switch (event->response_type & ~0x80)
+ {
+ case XCB_CREATE_NOTIFY:
+ create_notify((xcb_create_notify_event_t *) event);
+ break;
+ case XCB_DESTROY_NOTIFY:
+ destroy_notify((xcb_destroy_notify_event_t *) event);
+ break;
+ case XCB_MAP_REQUEST:
+ map_request((xcb_map_request_event_t *) event);
+ break;
+ case XCB_CONFIGURE_REQUEST:
+ configure_request((xcb_configure_request_event_t *) event);
+ break;
+ case XCB_PROPERTY_NOTIFY:
+ property_notify((xcb_property_notify_event_t *) event);
+ }
+
+ ++count;
+ }
+
+ xcb_flush(xwm.connection);
+
+ return count;
+}
+
+bool swc_xwm_initialize(int fd)
+{
+ const xcb_setup_t * setup;
+ xcb_screen_iterator_t screen_iterator;
+ uint32_t mask;
+ uint32_t values[1];
+ xcb_void_cookie_t change_attributes_cookie, redirect_subwindows_cookie;
+ xcb_generic_error_t * error;
+ xcb_intern_atom_cookie_t * ewmh_cookies;
+ const xcb_query_extension_reply_t * composite_extension;
+
+ xwm.connection = xcb_connect_to_fd(fd, NULL);
+
+ if (xcb_connection_has_error(xwm.connection))
+ {
+ ERROR("xwm: Could not connect to X server\n");
+ goto error0;
+ }
+
+ xcb_prefetch_extension_data(xwm.connection, &xcb_composite_id);
+ ewmh_cookies = xcb_ewmh_init_atoms(xwm.connection, &xwm.ewmh);
+
+ if (!ewmh_cookies)
+ {
+ ERROR("xwm: Failed to initialize EWMH atoms\n");
+ goto error1;
+ }
+
+ setup = xcb_get_setup(xwm.connection);
+ screen_iterator = xcb_setup_roots_iterator(setup);
+ xwm.screen = screen_iterator.data;
+
+ /* Try to select for substructure redirect. */
+ mask = XCB_CW_EVENT_MASK;
+ values[0] = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY
+ | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT;
+ change_attributes_cookie = xcb_change_window_attributes
+ (xwm.connection, xwm.screen->root, mask, values);
+
+ xwm.source = wl_event_loop_add_fd(swc.event_loop, fd, WL_EVENT_READABLE,
+ &connection_data, NULL);
+ wl_array_init(&xwm.windows);
+
+ if (!xwm.source)
+ {
+ ERROR("xwm: Failed to create X connection event source\n");
+ goto error2;
+ }
+
+ composite_extension = xcb_get_extension_data(xwm.connection, &xcb_composite_id);
+
+ if (!composite_extension->present)
+ {
+ ERROR("xwm: X server does not have composite extension\n");
+ goto error3;
+ }
+
+ redirect_subwindows_cookie = xcb_composite_redirect_subwindows_checked
+ (xwm.connection, xwm.screen->root, XCB_COMPOSITE_REDIRECT_MANUAL);
+
+ if ((error = xcb_request_check(xwm.connection, change_attributes_cookie)))
+ {
+ ERROR("xwm: Another window manager is running\n");
+ free(error);
+ goto error3;
+ }
+
+ if ((error = xcb_request_check(xwm.connection, redirect_subwindows_cookie)))
+ {
+ ERROR("xwm: Could not redirect subwindows of root for compositing\n");
+ free(error);
+ goto error3;
+ }
+
+ if (!xcb_ewmh_init_atoms_replies(&xwm.ewmh, ewmh_cookies, NULL))
+ {
+ ERROR("xwm: Failed to get EWMH atom replies\n");
+ goto error3;
+ }
+
+ return true;
+
+ error3:
+ wl_event_source_remove(xwm.source);
+ error2:
+ xcb_ewmh_connection_wipe(&xwm.ewmh);
+ error1:
+ xcb_disconnect(xwm.connection);
+ error0:
+ return false;
+}
+
+void swc_xwm_finalize()
+{
+ wl_array_release(&xwm.windows);
+ wl_event_source_remove(xwm.source);
+ xcb_ewmh_connection_wipe(&xwm.ewmh);
+ xcb_disconnect(xwm.connection);
+}
+
+static void configure(struct swc_window * window,
+ const struct swc_rectangle * geometry)
+{
+ uint32_t mask, values[4];
+ struct xwl_window * xwl_window
+ = CONTAINER_OF(window, typeof(*xwl_window), window.base);
+
+ 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 swc_window * window)
+{
+ struct xwl_window * xwl_window
+ = CONTAINER_OF(window, typeof(*xwl_window), window.base);
+
+ xcb_set_input_focus(xwm.connection, XCB_INPUT_FOCUS_NONE,
+ xwl_window->id, XCB_CURRENT_TIME);
+ xcb_flush(xwm.connection);
+}
+
+static const struct swc_window_impl xwl_window_handler = {
+ .configure = &configure,
+ .focus = &focus
+};
+
+static void handle_surface_destroy(struct wl_listener * listener, void * data)
+{
+ struct xwl_window_entry * entry;
+ struct xwl_window * xwl_window
+ = CONTAINER_OF(listener, typeof(*xwl_window), surface_destroy_listener);
+
+ swc_window_finalize(&xwl_window->window.base);
+ free(xwl_window);
+
+ wl_array_for_each(entry, &xwm.windows)
+ {
+ if (entry->xwl_window == xwl_window)
+ {
+ entry->xwl_window = NULL;
+ break;
+ }
+ }
+}
+
+void swc_xwm_manage_window(xcb_window_t id, struct swc_surface * surface)
+{
+ struct xwl_window_entry * entry;
+ struct xwl_window * xwl_window;
+ xcb_get_geometry_cookie_t geometry_cookie;
+ xcb_get_geometry_reply_t * geometry_reply;
+
+ if (!(entry = find_window(id)))
+ return;
+
+ if (!(xwl_window = malloc(sizeof *xwl_window)))
+ return;
+
+ geometry_cookie = xcb_get_geometry(xwm.connection, id);
+
+ xwl_window->id = id;
+ xwl_window->surface_destroy_listener.notify = &handle_surface_destroy;
+ wl_resource_add_destroy_listener(surface->resource,
+ &xwl_window->surface_destroy_listener);
+ swc_window_initialize(&xwl_window->window.base,
+ &xwl_window_handler, surface);
+
+ entry->xwl_window = xwl_window;
+
+ if ((geometry_reply = xcb_get_geometry_reply(xwm.connection,
+ geometry_cookie, NULL)))
+ {
+ swc_surface_move(surface, geometry_reply->x, geometry_reply->y);
+ }
+
+ if (entry->override_redirect)
+ swc_compositor_surface_show(surface);
+ 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);
+ update_name(xwl_window);
+
+ swc_window_set_state(&xwl_window->window.base,
+ SWC_WINDOW_STATE_TOPLEVEL);
+ }
+}
+
diff --git a/libswc/xwm.h b/libswc/xwm.h
@@ -0,0 +1,38 @@
+/* swc: libswc/xwm.h
+ *
+ * Copyright (c) 2013 Michael Forney
+ *
+ * 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 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.
+ */
+
+#ifndef SWC_XWM_H
+#define SWC_XWM_H
+
+#include <stdbool.h>
+#include <xcb/xcb.h>
+
+struct swc_surface;
+
+bool swc_xwm_initialize(int fd);
+void swc_xwm_finalize();
+
+void swc_xwm_manage_window(xcb_window_t window, struct swc_surface * surface);
+
+#endif
+
diff --git a/protocol/Makefile.local b/protocol/Makefile.local
@@ -2,8 +2,9 @@
dir := protocol
-PROTOCOL_EXTENSIONS = \
- $(dir)/wayland-drm.xml
+PROTOCOL_EXTENSIONS = \
+ $(dir)/wayland-drm.xml \
+ $(dir)/xserver.xml
$(dir)_TARGETS := $(PROTOCOL_EXTENSIONS:%.xml=%-protocol.c) \
$(PROTOCOL_EXTENSIONS:%.xml=%-server-protocol.h)
diff --git a/protocol/xserver.xml b/protocol/xserver.xml
@@ -0,0 +1,18 @@
+<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>