commit 28dcc02
Michael Forney
·
2013-11-26 02:54:43 +0000 UTC
parent 4ab4400
Initial xwayland support
9 files changed,
+777,
-2
+1,
-0
1@@ -14,4 +14,5 @@ WAYLAND_SCANNER ?= wayland-scanner
2
3 ENABLE_STATIC = 1
4 ENABLE_SHARED = 1
5+ENABLE_XWAYLAND = 1
6
+14,
-0
1@@ -61,12 +61,26 @@ SWC_SOURCES += \
2 libswc/shell_surface.c \
3 libswc/bindings.c
4
5+ifeq ($(ENABLE_XWAYLAND),1)
6+$(dir)_CFLAGS += -DENABLE_XWAYLAND
7+$(dir)_PACKAGES += \
8+ xcb \
9+ xcb-composite \
10+ xcb-ewmh
11+
12+SWC_SOURCES += \
13+ libswc/xserver.c \
14+ libswc/xwm.c \
15+ protocol/xserver-protocol.c
16+endif
17+
18 SWC_STATIC_OBJECTS = $(SWC_SOURCES:%.c=%.o)
19 SWC_SHARED_OBJECTS = $(SWC_SOURCES:%.c=%.lo)
20
21 # Explicitly state dependencies on generated files
22 objects = $(foreach obj,$(1),$(dir)/$(obj).o $(dir)/$(obj.lo))
23 $(call objects,drm drm_buffer): protocol/wayland-drm-server-protocol.h
24+$(call objects,xserver): protocol/xserver-server-protocol.h
25
26 $(dir)/libswc.a: $(SWC_STATIC_OBJECTS)
27 $(call quiet,AR) cru $@ $^
+16,
-0
1@@ -30,6 +30,9 @@
2 #include "seat.h"
3 #include "shell.h"
4 #include "window.h"
5+#ifdef ENABLE_XWAYLAND
6+# include "xserver.h"
7+#endif
8
9 #include <libudev.h>
10
11@@ -94,10 +97,20 @@ bool swc_initialize(struct wl_display * display,
12 goto error4;
13 }
14
15+#ifdef ENABLE_XWAYLAND
16+ if (!swc_xserver_initialize())
17+ {
18+ fprintf(stderr, "Could not initialize xwayland\n");
19+ goto error5;
20+ }
21+#endif
22+
23 setup_compositor();
24
25 return true;
26
27+ error5:
28+ swc_shell_finalize();
29 error4:
30 swc_compositor_finish(&compositor);
31 error3:
32@@ -113,6 +126,9 @@ bool swc_initialize(struct wl_display * display,
33 EXPORT
34 void swc_finalize()
35 {
36+#ifdef ENABLE_XWAYLAND
37+ swc_xserver_finalize();
38+#endif
39 swc_shell_finalize();
40 swc_compositor_finish(&compositor);
41 swc_bindings_finalize();
+293,
-0
1@@ -0,0 +1,293 @@
2+/* swc: libswc/xserver.c
3+ *
4+ * Copyright (c) 2013 Michael Forney
5+ *
6+ * Based in part upon xwayland/launcher.c from weston, which is
7+ *
8+ * Copyright © 2011 Intel Corporation
9+ *
10+ * Permission is hereby granted, free of charge, to any person obtaining a copy
11+ * of this software and associated documentation files (the "Software"), to deal
12+ * in the Software without restriction, including without limitation the rights
13+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14+ * copies of the Software, and to permit persons to whom the Software is
15+ * furnished to do so, subject to the following conditions:
16+ *
17+ * The above copyright notice and this permission notice shall be included in
18+ * all copies or substantial portions of the Software.
19+ *
20+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26+ * SOFTWARE.
27+ */
28+
29+#include "xserver.h"
30+#include "internal.h"
31+#include "util.h"
32+#include "xwm.h"
33+
34+#include <stdlib.h>
35+#include <stdio.h>
36+#include <unistd.h>
37+#include <fcntl.h>
38+#include <errno.h>
39+#include <sys/stat.h>
40+#include <sys/socket.h>
41+#include <sys/un.h>
42+#include <wayland-server.h>
43+#include "protocol/xserver-server-protocol.h"
44+
45+#define LOCK_FMT "/tmp/.X%d-lock"
46+#define SOCKET_DIR "/tmp/.X11-unix"
47+#define SOCKET_FMT SOCKET_DIR "/X%d"
48+
49+static struct
50+{
51+ struct wl_global * global;
52+ struct wl_client * client;
53+ struct wl_resource * resource;
54+ int display;
55+ char display_name[16];
56+ int abstract_socket, unix_socket;
57+} xserver;
58+
59+static char * xserver_command[] = {
60+ "X", "-wayland", "-rootless", "-nolisten", "all", xserver.display_name, NULL
61+};
62+
63+static void set_window_id(struct wl_client * client,
64+ struct wl_resource * resource,
65+ struct wl_resource * surface_resource, uint32_t id)
66+{
67+ struct swc_surface * surface = wl_resource_get_user_data(surface_resource);
68+
69+ swc_xwm_manage_window(id, surface);
70+}
71+
72+const static struct xserver_interface xserver_implementation = {
73+ .set_window_id = &set_window_id
74+};
75+
76+static int open_socket(struct sockaddr_un * addr, size_t path_size)
77+{
78+ int fd;
79+ socklen_t size = OFFSET_OF(typeof(*addr), sun_path) + path_size + 1;
80+
81+ if ((fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0)) < 0)
82+ goto error0;
83+
84+ if (bind(fd, (struct sockaddr *) addr, size) < 0)
85+ goto error1;
86+
87+ if (listen(fd, 1) < 0)
88+ goto error2;
89+
90+ return fd;
91+
92+ error2:
93+ if (addr->sun_path[0])
94+ unlink(addr->sun_path);
95+ error1:
96+ close(fd);
97+ error0:
98+ return -1;
99+}
100+
101+static bool open_display()
102+{
103+ char lock_name[64], pid[12];
104+ int lock_fd;
105+ struct sockaddr_un addr = { .sun_family = AF_LOCAL };
106+ size_t path_size;
107+
108+ xserver.display = 0;
109+
110+ /* Create X lockfile and server sockets */
111+ goto begin;
112+
113+ retry2:
114+ close(xserver.abstract_socket);
115+ retry1:
116+ unlink(lock_name);
117+ retry0:
118+ if (++xserver.display > 32)
119+ {
120+ ERROR("No open display in first 32\n");
121+ return false;
122+ }
123+
124+ begin:
125+ snprintf(lock_name, sizeof lock_name, LOCK_FMT, xserver.display);
126+ lock_fd = open(lock_name, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0444);
127+
128+ /* XXX: Stale lockfile handling? */
129+ if (lock_fd < 0)
130+ goto retry0;
131+
132+ snprintf(pid, sizeof pid, "%10d\n", getpid());
133+ if (write(lock_fd, pid, sizeof pid) != sizeof pid)
134+ {
135+ ERROR("Failed to write PID file\n");
136+ unlink(lock_name);
137+ close(lock_fd);
138+ return false;
139+ }
140+
141+ close(lock_fd);
142+
143+ /* Bind to abstract socket */
144+ addr.sun_path[0] = '\0';
145+ path_size = snprintf(addr.sun_path + 1, sizeof addr.sun_path - 1,
146+ SOCKET_FMT, xserver.display);
147+ if ((xserver.abstract_socket = open_socket(&addr, path_size)) < 0)
148+ goto retry1;
149+
150+ /* Bind to unix socket */
151+ mkdir(SOCKET_DIR, 0777);
152+ path_size = snprintf(addr.sun_path, sizeof addr.sun_path,
153+ SOCKET_FMT, xserver.display);
154+ if ((xserver.unix_socket = open_socket(&addr, path_size)) < 0)
155+ goto retry2;
156+
157+ snprintf(xserver.display_name, sizeof xserver.display_name,
158+ ":%d", xserver.display);
159+ setenv("DISPLAY", xserver.display_name, true);
160+
161+ return true;
162+}
163+
164+static void close_display()
165+{
166+ char path[64];
167+
168+ close(xserver.abstract_socket);
169+ close(xserver.unix_socket);
170+
171+ snprintf(path, sizeof path, SOCKET_FMT, xserver.display);
172+ unlink(path);
173+ snprintf(path, sizeof path, LOCK_FMT, xserver.display);
174+ unlink(path);
175+
176+ unsetenv("DISPLAY");
177+}
178+
179+static void bind_xserver(struct wl_client * client, void * data,
180+ uint32_t version, uint32_t id)
181+{
182+ int sv[2];
183+
184+ if (client != xserver.client)
185+ return;
186+
187+ if (version >= 1)
188+ version = 1;
189+
190+ DEBUG("Binding X server\n");
191+
192+ xserver.resource = wl_resource_create(client, &xserver_interface,
193+ version, id);
194+ wl_resource_set_implementation(xserver.resource, &xserver_implementation,
195+ NULL, NULL);
196+
197+ /* Start the X window manager */
198+ socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
199+ xserver_send_client(xserver.resource, sv[1]);
200+ close(sv[1]);
201+
202+ /* Need to flush the xserver client so the X window manager can connect to
203+ * it's socket. */
204+ wl_client_flush(xserver.client);
205+ swc_xwm_initialize(sv[0]);
206+
207+ xserver_send_listen_socket(xserver.resource, xserver.abstract_socket);
208+ xserver_send_listen_socket(xserver.resource, xserver.unix_socket);
209+}
210+
211+static bool start_xserver()
212+{
213+ int sv[2];
214+
215+ /* Open an X display */
216+ if (!open_display())
217+ {
218+ ERROR("Failed to get X lockfile and sockets\n");
219+ goto error0;
220+ }
221+
222+ /* Start the X server */
223+ if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) == -1)
224+ {
225+ ERROR("Failed to create socketpair: %s\n", strerror(errno));
226+ goto error1;
227+ }
228+
229+ if (!(xserver.client = wl_client_create(swc.display, sv[0])))
230+ goto error2;
231+
232+ switch (fork())
233+ {
234+ case 0:
235+ {
236+ int socket_fd;
237+ char socket_string[32];
238+
239+ if (!(socket_fd = dup(sv[1])))
240+ exit(EXIT_FAILURE);
241+
242+ snprintf(socket_string, sizeof socket_string, "%d", socket_fd);
243+ setenv("WAYLAND_SOCKET", socket_string, true);
244+
245+ execvp(xserver_command[0], xserver_command);
246+ exit(EXIT_FAILURE);
247+
248+ break;
249+ }
250+ case -1:
251+ ERROR("fork() failed when trying to start X server: %s\n",
252+ strerror(errno));
253+ goto error2;
254+ }
255+
256+ close(sv[1]);
257+
258+ return true;
259+
260+ error2:
261+ close(sv[1]);
262+ close(sv[0]);
263+ error1:
264+ close_display();
265+ error0:
266+ return false;
267+}
268+
269+bool swc_xserver_initialize()
270+{
271+ xserver.global = wl_global_create(swc.display, &xserver_interface, 1,
272+ NULL, &bind_xserver);
273+
274+ if (!xserver.global)
275+ goto error0;
276+
277+ if (!start_xserver())
278+ goto error1;
279+
280+ return true;
281+
282+ error1:
283+ wl_global_destroy(xserver.global);
284+ error0:
285+ return false;
286+}
287+
288+void swc_xserver_finalize()
289+{
290+ swc_xwm_finalize();
291+ close_display();
292+ wl_global_destroy(xserver.global);
293+}
294+
+33,
-0
1@@ -0,0 +1,33 @@
2+/* swc: libswc/xserver.h
3+ *
4+ * Copyright (c) 2013 Michael Forney
5+ *
6+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7+ * of this software and associated documentation files (the "Software"), to deal
8+ * in the Software without restriction, including without limitation the rights
9+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+ * copies of the Software, and to permit persons to whom the Software is
11+ * furnished to do so, subject to the following conditions:
12+ *
13+ * The above copyright notice and this permission notice shall be included in
14+ * all copies or substantial portions of the Software.
15+ *
16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+ * SOFTWARE.
23+ */
24+
25+#ifndef SWC_XSERVER_H
26+#define SWC_XSERVER_H
27+
28+#include <stdbool.h>
29+
30+bool swc_xserver_initialize();
31+void swc_xserver_finalize();
32+
33+#endif
34+
+361,
-0
1@@ -0,0 +1,361 @@
2+/* swc: libswc/xwm.c
3+ *
4+ * Copyright (c) 2013 Michael Forney
5+ *
6+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7+ * of this software and associated documentation files (the "Software"), to deal
8+ * in the Software without restriction, including without limitation the rights
9+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+ * copies of the Software, and to permit persons to whom the Software is
11+ * furnished to do so, subject to the following conditions:
12+ *
13+ * The above copyright notice and this permission notice shall be included in
14+ * all copies or substantial portions of the Software.
15+ *
16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+ * SOFTWARE.
23+ */
24+
25+#include "xwm.h"
26+#include "compositor_surface.h"
27+#include "internal.h"
28+#include "surface.h"
29+#include "swc.h"
30+#include "util.h"
31+#include "window.h"
32+
33+#include <stdio.h>
34+#include <xcb/composite.h>
35+#include <xcb/xcb_ewmh.h>
36+
37+struct xwl_window
38+{
39+ xcb_window_t id;
40+ struct swc_window_internal window;
41+ struct wl_listener surface_destroy_listener;
42+};
43+
44+struct xwl_window_entry
45+{
46+ xcb_window_t id;
47+ bool override_redirect;
48+ struct xwl_window * xwl_window;
49+};
50+
51+static struct
52+{
53+ xcb_connection_t * connection;
54+ xcb_ewmh_connection_t ewmh;
55+ xcb_screen_t * screen;
56+ struct wl_event_source * source;
57+ struct wl_array windows;
58+} xwm;
59+
60+static void update_name(struct xwl_window * xwl_window)
61+{
62+ xcb_get_property_cookie_t wm_name_cookie;
63+ xcb_ewmh_get_utf8_strings_reply_t wm_name_reply;
64+
65+ wm_name_cookie = xcb_ewmh_get_wm_name(&xwm.ewmh, xwl_window->id);
66+ xcb_ewmh_get_wm_name_reply(&xwm.ewmh, wm_name_cookie,
67+ &wm_name_reply, NULL);
68+
69+ swc_window_set_title(&xwl_window->window.base,
70+ wm_name_reply.strings, wm_name_reply.strings_len);
71+}
72+
73+static struct xwl_window_entry * find_window(xcb_window_t id)
74+{
75+ struct xwl_window_entry * entry;
76+
77+ wl_array_for_each(entry, &xwm.windows)
78+ {
79+ if (entry->id == id)
80+ return entry;
81+ }
82+
83+ return NULL;
84+}
85+
86+/* X event handlers */
87+void create_notify(xcb_create_notify_event_t * event)
88+{
89+ struct xwl_window_entry * entry;
90+
91+ if (!(entry = wl_array_add(&xwm.windows, sizeof *entry)))
92+ return;
93+
94+ entry->id = event->window;
95+ entry->override_redirect = event->override_redirect;
96+ entry->xwl_window = NULL;
97+}
98+
99+void destroy_notify(xcb_destroy_notify_event_t * event)
100+{
101+ struct xwl_window_entry * entry;
102+
103+ if (!(entry = find_window(event->window)))
104+ return;
105+
106+ swc_array_remove(&xwm.windows, entry, sizeof *entry);
107+}
108+
109+void map_request(xcb_map_request_event_t * event)
110+{
111+ xcb_map_window(xwm.connection, event->window);
112+}
113+
114+void configure_request(xcb_configure_request_event_t * event)
115+{
116+}
117+
118+void property_notify(xcb_property_notify_event_t * event)
119+{
120+ struct xwl_window_entry * entry;
121+
122+ if (!(entry = find_window(event->window)) || !entry->xwl_window)
123+ return;
124+
125+ if (event->atom == xwm.ewmh._NET_WM_NAME
126+ && event->state == XCB_PROPERTY_NEW_VALUE)
127+ {
128+ update_name(entry->xwl_window);
129+ }
130+}
131+
132+static int connection_data(int fd, uint32_t mask, void * data)
133+{
134+ xcb_generic_event_t * event;
135+ uint32_t count = 0;
136+
137+ while ((event = xcb_poll_for_event(xwm.connection)))
138+ {
139+ switch (event->response_type & ~0x80)
140+ {
141+ case XCB_CREATE_NOTIFY:
142+ create_notify((xcb_create_notify_event_t *) event);
143+ break;
144+ case XCB_DESTROY_NOTIFY:
145+ destroy_notify((xcb_destroy_notify_event_t *) event);
146+ break;
147+ case XCB_MAP_REQUEST:
148+ map_request((xcb_map_request_event_t *) event);
149+ break;
150+ case XCB_CONFIGURE_REQUEST:
151+ configure_request((xcb_configure_request_event_t *) event);
152+ break;
153+ case XCB_PROPERTY_NOTIFY:
154+ property_notify((xcb_property_notify_event_t *) event);
155+ }
156+
157+ ++count;
158+ }
159+
160+ xcb_flush(xwm.connection);
161+
162+ return count;
163+}
164+
165+bool swc_xwm_initialize(int fd)
166+{
167+ const xcb_setup_t * setup;
168+ xcb_screen_iterator_t screen_iterator;
169+ uint32_t mask;
170+ uint32_t values[1];
171+ xcb_void_cookie_t change_attributes_cookie, redirect_subwindows_cookie;
172+ xcb_generic_error_t * error;
173+ xcb_intern_atom_cookie_t * ewmh_cookies;
174+ const xcb_query_extension_reply_t * composite_extension;
175+
176+ xwm.connection = xcb_connect_to_fd(fd, NULL);
177+
178+ if (xcb_connection_has_error(xwm.connection))
179+ {
180+ ERROR("xwm: Could not connect to X server\n");
181+ goto error0;
182+ }
183+
184+ xcb_prefetch_extension_data(xwm.connection, &xcb_composite_id);
185+ ewmh_cookies = xcb_ewmh_init_atoms(xwm.connection, &xwm.ewmh);
186+
187+ if (!ewmh_cookies)
188+ {
189+ ERROR("xwm: Failed to initialize EWMH atoms\n");
190+ goto error1;
191+ }
192+
193+ setup = xcb_get_setup(xwm.connection);
194+ screen_iterator = xcb_setup_roots_iterator(setup);
195+ xwm.screen = screen_iterator.data;
196+
197+ /* Try to select for substructure redirect. */
198+ mask = XCB_CW_EVENT_MASK;
199+ values[0] = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY
200+ | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT;
201+ change_attributes_cookie = xcb_change_window_attributes
202+ (xwm.connection, xwm.screen->root, mask, values);
203+
204+ xwm.source = wl_event_loop_add_fd(swc.event_loop, fd, WL_EVENT_READABLE,
205+ &connection_data, NULL);
206+ wl_array_init(&xwm.windows);
207+
208+ if (!xwm.source)
209+ {
210+ ERROR("xwm: Failed to create X connection event source\n");
211+ goto error2;
212+ }
213+
214+ composite_extension = xcb_get_extension_data(xwm.connection, &xcb_composite_id);
215+
216+ if (!composite_extension->present)
217+ {
218+ ERROR("xwm: X server does not have composite extension\n");
219+ goto error3;
220+ }
221+
222+ redirect_subwindows_cookie = xcb_composite_redirect_subwindows_checked
223+ (xwm.connection, xwm.screen->root, XCB_COMPOSITE_REDIRECT_MANUAL);
224+
225+ if ((error = xcb_request_check(xwm.connection, change_attributes_cookie)))
226+ {
227+ ERROR("xwm: Another window manager is running\n");
228+ free(error);
229+ goto error3;
230+ }
231+
232+ if ((error = xcb_request_check(xwm.connection, redirect_subwindows_cookie)))
233+ {
234+ ERROR("xwm: Could not redirect subwindows of root for compositing\n");
235+ free(error);
236+ goto error3;
237+ }
238+
239+ if (!xcb_ewmh_init_atoms_replies(&xwm.ewmh, ewmh_cookies, NULL))
240+ {
241+ ERROR("xwm: Failed to get EWMH atom replies\n");
242+ goto error3;
243+ }
244+
245+ return true;
246+
247+ error3:
248+ wl_event_source_remove(xwm.source);
249+ error2:
250+ xcb_ewmh_connection_wipe(&xwm.ewmh);
251+ error1:
252+ xcb_disconnect(xwm.connection);
253+ error0:
254+ return false;
255+}
256+
257+void swc_xwm_finalize()
258+{
259+ wl_array_release(&xwm.windows);
260+ wl_event_source_remove(xwm.source);
261+ xcb_ewmh_connection_wipe(&xwm.ewmh);
262+ xcb_disconnect(xwm.connection);
263+}
264+
265+static void configure(struct swc_window * window,
266+ const struct swc_rectangle * geometry)
267+{
268+ uint32_t mask, values[4];
269+ struct xwl_window * xwl_window
270+ = CONTAINER_OF(window, typeof(*xwl_window), window.base);
271+
272+ mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y
273+ | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
274+ values[0] = geometry->x;
275+ values[1] = geometry->y;
276+ values[2] = geometry->width;
277+ values[3] = geometry->height;
278+
279+ xcb_configure_window(xwm.connection, xwl_window->id, mask, values);
280+ xcb_flush(xwm.connection);
281+}
282+
283+static void focus(struct swc_window * window)
284+{
285+ struct xwl_window * xwl_window
286+ = CONTAINER_OF(window, typeof(*xwl_window), window.base);
287+
288+ xcb_set_input_focus(xwm.connection, XCB_INPUT_FOCUS_NONE,
289+ xwl_window->id, XCB_CURRENT_TIME);
290+ xcb_flush(xwm.connection);
291+}
292+
293+static const struct swc_window_impl xwl_window_handler = {
294+ .configure = &configure,
295+ .focus = &focus
296+};
297+
298+static void handle_surface_destroy(struct wl_listener * listener, void * data)
299+{
300+ struct xwl_window_entry * entry;
301+ struct xwl_window * xwl_window
302+ = CONTAINER_OF(listener, typeof(*xwl_window), surface_destroy_listener);
303+
304+ swc_window_finalize(&xwl_window->window.base);
305+ free(xwl_window);
306+
307+ wl_array_for_each(entry, &xwm.windows)
308+ {
309+ if (entry->xwl_window == xwl_window)
310+ {
311+ entry->xwl_window = NULL;
312+ break;
313+ }
314+ }
315+}
316+
317+void swc_xwm_manage_window(xcb_window_t id, struct swc_surface * surface)
318+{
319+ struct xwl_window_entry * entry;
320+ struct xwl_window * xwl_window;
321+ xcb_get_geometry_cookie_t geometry_cookie;
322+ xcb_get_geometry_reply_t * geometry_reply;
323+
324+ if (!(entry = find_window(id)))
325+ return;
326+
327+ if (!(xwl_window = malloc(sizeof *xwl_window)))
328+ return;
329+
330+ geometry_cookie = xcb_get_geometry(xwm.connection, id);
331+
332+ xwl_window->id = id;
333+ xwl_window->surface_destroy_listener.notify = &handle_surface_destroy;
334+ wl_resource_add_destroy_listener(surface->resource,
335+ &xwl_window->surface_destroy_listener);
336+ swc_window_initialize(&xwl_window->window.base,
337+ &xwl_window_handler, surface);
338+
339+ entry->xwl_window = xwl_window;
340+
341+ if ((geometry_reply = xcb_get_geometry_reply(xwm.connection,
342+ geometry_cookie, NULL)))
343+ {
344+ swc_surface_move(surface, geometry_reply->x, geometry_reply->y);
345+ }
346+
347+ if (entry->override_redirect)
348+ swc_compositor_surface_show(surface);
349+ else
350+ {
351+ uint32_t mask, values[1];
352+
353+ mask = XCB_CW_EVENT_MASK;
354+ values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE;
355+ xcb_change_window_attributes(xwm.connection, id, mask, values);
356+ update_name(xwl_window);
357+
358+ swc_window_set_state(&xwl_window->window.base,
359+ SWC_WINDOW_STATE_TOPLEVEL);
360+ }
361+}
362+
+38,
-0
1@@ -0,0 +1,38 @@
2+/* swc: libswc/xwm.h
3+ *
4+ * Copyright (c) 2013 Michael Forney
5+ *
6+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7+ * of this software and associated documentation files (the "Software"), to deal
8+ * in the Software without restriction, including without limitation the rights
9+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+ * copies of the Software, and to permit persons to whom the Software is
11+ * furnished to do so, subject to the following conditions:
12+ *
13+ * The above copyright notice and this permission notice shall be included in
14+ * all copies or substantial portions of the Software.
15+ *
16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+ * SOFTWARE.
23+ */
24+
25+#ifndef SWC_XWM_H
26+#define SWC_XWM_H
27+
28+#include <stdbool.h>
29+#include <xcb/xcb.h>
30+
31+struct swc_surface;
32+
33+bool swc_xwm_initialize(int fd);
34+void swc_xwm_finalize();
35+
36+void swc_xwm_manage_window(xcb_window_t window, struct swc_surface * surface);
37+
38+#endif
39+
+3,
-2
1@@ -2,8 +2,9 @@
2
3 dir := protocol
4
5-PROTOCOL_EXTENSIONS = \
6- $(dir)/wayland-drm.xml
7+PROTOCOL_EXTENSIONS = \
8+ $(dir)/wayland-drm.xml \
9+ $(dir)/xserver.xml
10
11 $(dir)_TARGETS := $(PROTOCOL_EXTENSIONS:%.xml=%-protocol.c) \
12 $(PROTOCOL_EXTENSIONS:%.xml=%-server-protocol.h)
+18,
-0
1@@ -0,0 +1,18 @@
2+<protocol name="xserver">
3+
4+ <interface name="xserver" version="1">
5+ <request name="set_window_id">
6+ <arg name="surface" type="object" interface="wl_surface"/>
7+ <arg name="id" type="uint"/>
8+ </request>
9+
10+ <event name="client">
11+ <arg name="fd" type="fd"/>
12+ </event>
13+
14+ <event name="listen_socket">
15+ <arg name="fd" type="fd"/>
16+ </event>
17+ </interface>
18+
19+</protocol>