commit 2011cc7

Michael Forney  ·  2018-11-03 02:02:57 +0000 UTC
parent 390414c
Remove xwayland support

I'm not using any X applications under swc anymore, so this code
is likely to become broken without anyone using it.
10 files changed,  +0, -974
+0, -8
 1@@ -35,14 +35,6 @@ PACKAGES :=           \
 2     wld               \
 3     xkbcommon
 4 
 5-ifeq ($(ENABLE_XWAYLAND),1)
 6-PACKAGES +=         \
 7-    xcb             \
 8-    xcb-composite   \
 9-    xcb-ewmh        \
10-    xcb-icccm
11-endif
12-
13 ifeq ($(ENABLE_LIBUDEV),1)
14 PACKAGES += libudev
15 endif
+0, -4
 1@@ -24,10 +24,6 @@ Dependencies
 2 For input hotplugging, the following is also required:
 3 * libudev
 4 
 5-For XWayland support, the following are also required:
 6-* libxcb
 7-* xcb-util-wm
 8-
 9 Implementing a window manager using swc
10 ---------------------------------------
11 You must implement two callback functions, `new_window` and `new_screen`, which
+0, -1
1@@ -17,5 +17,4 @@ ENABLE_DEBUG    = 1
2 ENABLE_STATIC   = 1
3 ENABLE_SHARED   = 1
4 ENABLE_LIBUDEV  = 1
5-ENABLE_XWAYLAND = 1
6 
+0, -4
 1@@ -45,10 +45,6 @@ struct swc {
 2 	struct swc_compositor *const compositor;
 3 	struct swc_shm *const shm;
 4 	struct swc_drm *const drm;
 5-
 6-#ifdef ENABLE_XWAYLAND
 7-	const struct swc_xserver *const xserver;
 8-#endif
 9 };
10 
11 extern struct swc swc;
+0, -9
 1@@ -62,15 +62,6 @@ $(dir)_CFLAGS += -DENABLE_LIBUDEV
 2 $(dir)_PACKAGES += libudev
 3 endif
 4 
 5-ifeq ($(ENABLE_XWAYLAND),1)
 6-$(dir)_CFLAGS += -DENABLE_XWAYLAND
 7-$(dir)_PACKAGES += xcb xcb-composite xcb-ewmh xcb-icccm
 8-
 9-SWC_SOURCES +=                      \
10-    libswc/xserver.c                \
11-    libswc/xwm.c
12-endif
13-
14 SWC_STATIC_OBJECTS = $(SWC_SOURCES:%.c=%.o)
15 SWC_SHARED_OBJECTS = $(SWC_SOURCES:%.c=%.lo)
16 
+0, -23
 1@@ -40,9 +40,6 @@
 2 #include "util.h"
 3 #include "window.h"
 4 #include "xdg_shell.h"
 5-#ifdef ENABLE_XWAYLAND
 6-# include "xserver.h"
 7-#endif
 8 
 9 extern struct swc_launch swc_launch;
10 extern const struct swc_seat swc_seat;
11@@ -50,9 +47,6 @@ extern const struct swc_bindings swc_bindings;
12 extern struct swc_compositor swc_compositor;
13 extern struct swc_drm swc_drm;
14 extern struct swc_shm swc_shm;
15-#ifdef ENABLE_XWAYLAND
16-extern struct swc_xserver swc_xserver;
17-#endif
18 
19 extern struct pointer_handler screens_pointer_handler;
20 
21@@ -62,9 +56,6 @@ struct swc swc = {
22 	.compositor = &swc_compositor,
23 	.drm = &swc_drm,
24 	.shm = &swc_shm,
25-#ifdef ENABLE_XWAYLAND
26-	.xserver = &swc_xserver,
27-#endif
28 };
29 
30 static void
31@@ -179,21 +170,10 @@ swc_initialize(struct wl_display *display, struct wl_event_loop *event_loop, con
32 		goto error11;
33 	}
34 
35-#ifdef ENABLE_XWAYLAND
36-	if (!xserver_initialize()) {
37-		ERROR("Could not initialize xwayland\n");
38-		goto error12;
39-	}
40-#endif
41-
42 	setup_compositor();
43 
44 	return true;
45 
46-#ifdef ENABLE_XWAYLAND
47-error12:
48-	panel_manager_finalize();
49-#endif
50 error11:
51 	xdg_shell_finalize();
52 error10:
53@@ -223,9 +203,6 @@ error0:
54 EXPORT void
55 swc_finalize(void)
56 {
57-#ifdef ENABLE_XWAYLAND
58-	xserver_finalize();
59-#endif
60 	panel_manager_finalize();
61 	shell_finalize();
62 	seat_finalize();
+0, -319
  1@@ -1,319 +0,0 @@
  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 <signal.h>
 35-#include <stdlib.h>
 36-#include <stdio.h>
 37-#include <unistd.h>
 38-#include <fcntl.h>
 39-#include <errno.h>
 40-#include <sys/stat.h>
 41-#include <sys/socket.h>
 42-#include <sys/un.h>
 43-#include <wayland-server.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-	struct wl_resource *resource;
 51-	struct wl_event_source *usr1_source;
 52-	int display;
 53-	char display_name[16];
 54-	int abstract_fd, unix_fd, wm_fd;
 55-	bool xwm_initialized;
 56-} xserver;
 57-
 58-struct swc_xserver swc_xserver;
 59-
 60-static int
 61-open_socket(struct sockaddr_un *addr)
 62-{
 63-	int fd;
 64-
 65-	if ((fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0)) < 0)
 66-		goto error0;
 67-
 68-	/* Unlink the socket location in case it was being used by a process which
 69-	 * left around a stale lockfile. */
 70-	unlink(addr->sun_path);
 71-
 72-	if (bind(fd, (struct sockaddr *)addr, sizeof(*addr)) < 0)
 73-		goto error1;
 74-
 75-	if (listen(fd, 1) < 0)
 76-		goto error2;
 77-
 78-	return fd;
 79-
 80-error2:
 81-	if (addr->sun_path[0])
 82-		unlink(addr->sun_path);
 83-error1:
 84-	close(fd);
 85-error0:
 86-	return -1;
 87-}
 88-
 89-static bool
 90-open_display(void)
 91-{
 92-	char lock_name[64], pid[12];
 93-	int lock_fd;
 94-	struct sockaddr_un addr = {.sun_family = AF_LOCAL};
 95-
 96-	xserver.display = 0;
 97-
 98-	/* Create X lockfile and server sockets */
 99-	goto begin;
100-
101-retry2:
102-	close(xserver.abstract_fd);
103-retry1:
104-	unlink(lock_name);
105-retry0:
106-	if (++xserver.display > 32) {
107-		ERROR("No open display in first 32\n");
108-		return false;
109-	}
110-
111-begin:
112-	snprintf(lock_name, sizeof(lock_name), LOCK_FMT, xserver.display);
113-	lock_fd = open(lock_name, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0444);
114-
115-	if (lock_fd == -1) {
116-		char *end;
117-		pid_t owner;
118-
119-		/* Check if the owning process is still alive. */
120-		if ((lock_fd = open(lock_name, O_RDONLY)) == -1)
121-			goto retry0;
122-
123-		if (read(lock_fd, pid, sizeof(pid) - 1) != sizeof(pid) - 1)
124-			goto retry0;
125-
126-		owner = strtol(pid, &end, 10);
127-
128-		if (end != pid + 10)
129-			goto retry0;
130-
131-		if (kill(owner, 0) == 0 || errno != ESRCH)
132-			goto retry0;
133-
134-		if (unlink(lock_name) != 0)
135-			goto retry0;
136-
137-		goto begin;
138-	}
139-
140-	snprintf(pid, sizeof(pid), "%10d\n", getpid());
141-	if (write(lock_fd, pid, sizeof(pid) - 1) != sizeof(pid) - 1) {
142-		ERROR("Failed to write PID file\n");
143-		unlink(lock_name);
144-		close(lock_fd);
145-		return false;
146-	}
147-
148-	close(lock_fd);
149-
150-	/* Bind to abstract socket */
151-	addr.sun_path[0] = '\0';
152-	snprintf(addr.sun_path + 1, sizeof(addr.sun_path) - 1, SOCKET_FMT, xserver.display);
153-	if ((xserver.abstract_fd = open_socket(&addr)) < 0)
154-		goto retry1;
155-
156-	/* Bind to unix socket */
157-	mkdir(SOCKET_DIR, 0777);
158-	snprintf(addr.sun_path, sizeof(addr.sun_path), SOCKET_FMT, xserver.display);
159-	if ((xserver.unix_fd = open_socket(&addr)) < 0)
160-		goto retry2;
161-
162-	snprintf(xserver.display_name, sizeof(xserver.display_name), ":%d", xserver.display);
163-	setenv("DISPLAY", xserver.display_name, true);
164-
165-	return true;
166-}
167-
168-static void
169-close_display(void)
170-{
171-	char path[64];
172-
173-	close(xserver.abstract_fd);
174-	close(xserver.unix_fd);
175-
176-	snprintf(path, sizeof(path), SOCKET_FMT, xserver.display);
177-	unlink(path);
178-	snprintf(path, sizeof(path), LOCK_FMT, xserver.display);
179-	unlink(path);
180-
181-	unsetenv("DISPLAY");
182-}
183-
184-static int
185-handle_usr1(int signal_number, void *data)
186-{
187-	if (xwm_initialize(xserver.wm_fd)) {
188-		xserver.xwm_initialized = true;
189-	} else {
190-		ERROR("Failed to initialize X window manager\n");
191-		/* XXX: How do we handle this case? */
192-	}
193-
194-	wl_event_source_remove(xserver.usr1_source);
195-
196-	return 0;
197-}
198-
199-static void
200-handle_client_destroy(struct wl_listener *listener, void *data) {
201-	swc_xserver.client = NULL;
202-}
203-
204-static struct wl_listener client_destroy_listener = {
205-	.notify = handle_client_destroy,
206-};
207-
208-bool
209-xserver_initialize(void)
210-{
211-	int wl[2], wm[2];
212-
213-	/* Open an X display */
214-	if (!open_display()) {
215-		ERROR("Failed to get X lockfile and sockets\n");
216-		goto error0;
217-	}
218-
219-	xserver.usr1_source = wl_event_loop_add_signal(swc.event_loop, SIGUSR1, &handle_usr1, NULL);
220-
221-	if (!xserver.usr1_source) {
222-		ERROR("Failed to create SIGUSR1 event source\n");
223-		goto error1;
224-	}
225-
226-	/* Open a socket for the Wayland connection from Xwayland. */
227-	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, wl) != 0) {
228-		ERROR("Failed to create socketpair: %s\n", strerror(errno));
229-		goto error2;
230-	}
231-
232-	/* Open a socket for the X connection to Xwayland. */
233-	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, wm) != 0) {
234-		ERROR("Failed to create socketpair: %s\n", strerror(errno));
235-		goto error3;
236-	}
237-
238-	if (!(swc_xserver.client = wl_client_create(swc.display, wl[0])))
239-		goto error4;
240-
241-	wl_client_add_destroy_listener(swc_xserver.client, &client_destroy_listener);
242-	xserver.wm_fd = wm[0];
243-
244-	/* Start the X server */
245-	switch (fork()) {
246-	case 0: {
247-		int fds[] = { wl[1], wm[1], xserver.abstract_fd, xserver.unix_fd };
248-		char strings[ARRAY_LENGTH(fds)][16];
249-		unsigned index;
250-		struct sigaction action = {.sa_handler = SIG_IGN };
251-
252-		/* Unset the FD_CLOEXEC flag on the FDs that will get passed to Xwayland. */
253-		for (index = 0; index < ARRAY_LENGTH(fds); ++index) {
254-			if (fcntl(fds[index], F_SETFD, 0) != 0) {
255-				ERROR("fcntl() failed: %s\n", strerror(errno));
256-				goto fail;
257-			}
258-
259-			if (snprintf(strings[index], sizeof(strings[index]), "%d", fds[index]) >= sizeof(strings[index])) {
260-				ERROR("FD is too large\n");
261-				goto fail;
262-			}
263-		}
264-
265-		/* Ignore the USR1 signal so that Xwayland will send a USR1 signal to the
266-		 * parent process (us) after it finishes initializing. See Xserver(1) for
267-		 * more details. */
268-		if (sigaction(SIGUSR1, &action, NULL) != 0) {
269-			ERROR("Failed to set SIGUSR1 handler to SIG_IGN: %s\n", strerror(errno));
270-			goto fail;
271-		}
272-
273-		setenv("WAYLAND_SOCKET", strings[0], true);
274-		execlp("Xwayland", "Xwayland",
275-		       xserver.display_name,
276-		       "-rootless",
277-		       "-terminate",
278-		       "-listen", strings[2],
279-		       "-listen", strings[3],
280-		       "-wm", strings[1],
281-		       NULL);
282-
283-	fail:
284-		exit(EXIT_FAILURE);
285-	}
286-	case -1:
287-		ERROR("fork() failed when trying to start X server: %s\n", strerror(errno));
288-		goto error5;
289-	}
290-
291-	close(wl[1]);
292-	close(wm[1]);
293-
294-	return true;
295-
296-error5:
297-	wl_client_destroy(swc_xserver.client);
298-error4:
299-	close(wm[1]);
300-	close(wm[0]);
301-error3:
302-	close(wl[1]);
303-	close(wl[0]);
304-error2:
305-	wl_event_source_remove(xserver.usr1_source);
306-error1:
307-	close_display();
308-error0:
309-	return false;
310-}
311-
312-void
313-xserver_finalize(void)
314-{
315-	if (xserver.xwm_initialized)
316-		xwm_finalize();
317-	if (swc_xserver.client)
318-		wl_client_destroy(swc_xserver.client);
319-	close_display();
320-}
+0, -36
 1@@ -1,36 +0,0 @@
 2-/* swc: libswc/xserver.h
 3- *
 4- * Copyright (c) 2013, 2014 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-struct swc_xserver {
31-	struct wl_client *client;
32-};
33-
34-bool xserver_initialize(void);
35-void xserver_finalize(void);
36-
37-#endif
+0, -538
  1@@ -1,538 +0,0 @@
  2-/* swc: libswc/xwm.c
  3- *
  4- * Copyright (c) 2013, 2014 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.h"
 27-#include "internal.h"
 28-#include "surface.h"
 29-#include "swc.h"
 30-#include "util.h"
 31-#include "view.h"
 32-#include "window.h"
 33-#include "xserver.h"
 34-
 35-#include <stdio.h>
 36-#include <xcb/composite.h>
 37-#include <xcb/xcb_ewmh.h>
 38-#include <xcb/xcb_icccm.h>
 39-
 40-struct xwl_window {
 41-	xcb_window_t id;
 42-	uint32_t surface_id;
 43-	bool override_redirect, supports_delete;
 44-	struct wl_list link;
 45-
 46-	/* Only used for paired windows. */
 47-	struct {
 48-		struct window window;
 49-		struct wl_listener surface_destroy_listener;
 50-	};
 51-};
 52-
 53-enum atom {
 54-	ATOM_WL_SURFACE_ID,
 55-	ATOM_WM_DELETE_WINDOW,
 56-	ATOM_WM_PROTOCOLS,
 57-	ATOM_WM_S0,
 58-};
 59-
 60-static struct {
 61-	xcb_connection_t *connection;
 62-	xcb_ewmh_connection_t ewmh;
 63-	xcb_screen_t *screen;
 64-	xcb_window_t window;
 65-	struct xwl_window *focus;
 66-	struct wl_event_source *source;
 67-	struct wl_list windows, unpaired_windows;
 68-	union {
 69-		const char *name;
 70-		xcb_intern_atom_cookie_t cookie;
 71-		xcb_atom_t value;
 72-	} atoms[4];
 73-} xwm = {
 74-	.atoms = {
 75-		[ATOM_WL_SURFACE_ID] = "WL_SURFACE_ID",
 76-		[ATOM_WM_DELETE_WINDOW] = "WM_DELETE_WINDOW",
 77-		[ATOM_WM_PROTOCOLS] = "WM_PROTOCOLS",
 78-		[ATOM_WM_S0] = "WM_S0",
 79-	}
 80-};
 81-
 82-static void
 83-update_name(struct xwl_window *xwl_window)
 84-{
 85-	xcb_get_property_cookie_t wm_name_cookie;
 86-	xcb_ewmh_get_utf8_strings_reply_t wm_name_reply;
 87-
 88-	wm_name_cookie = xcb_ewmh_get_wm_name(&xwm.ewmh, xwl_window->id);
 89-
 90-	if (xcb_ewmh_get_wm_name_reply(&xwm.ewmh, wm_name_cookie, &wm_name_reply, NULL)) {
 91-		window_set_title(&xwl_window->window, wm_name_reply.strings, wm_name_reply.strings_len);
 92-		xcb_ewmh_get_utf8_strings_reply_wipe(&wm_name_reply);
 93-	} else {
 94-		window_set_title(&xwl_window->window, NULL, 0);
 95-	}
 96-}
 97-
 98-static void
 99-update_protocols(struct xwl_window *xwl_window)
100-{
101-	xcb_get_property_cookie_t cookie;
102-	xcb_icccm_get_wm_protocols_reply_t reply;
103-	unsigned index;
104-
105-	cookie = xcb_icccm_get_wm_protocols(xwm.connection, xwl_window->id, xwm.atoms[ATOM_WM_PROTOCOLS].value);
106-	xwl_window->supports_delete = true;
107-
108-	if (!xcb_icccm_get_wm_protocols_reply(xwm.connection, cookie, &reply, NULL))
109-		return;
110-
111-	for (index = 0; index < reply.atoms_len; ++index) {
112-		if (reply.atoms[index] == xwm.atoms[ATOM_WM_DELETE_WINDOW].value)
113-			xwl_window->supports_delete = true;
114-	}
115-
116-	xcb_icccm_get_wm_protocols_reply_wipe(&reply);
117-}
118-
119-static struct xwl_window *
120-find_window(struct wl_list *list, xcb_window_t id)
121-{
122-	struct xwl_window *window;
123-
124-	wl_list_for_each (window, list, link) {
125-		if (window->id == id)
126-			return window;
127-	}
128-
129-	return NULL;
130-}
131-
132-static struct xwl_window *
133-find_window_by_surface_id(struct wl_list *list, uint32_t id)
134-{
135-	struct xwl_window *window;
136-
137-	wl_list_for_each (window, list, link) {
138-		if (window->surface_id == id)
139-			return window;
140-	}
141-
142-	return NULL;
143-}
144-
145-static void
146-move(struct window *window, int32_t x, int32_t y)
147-{
148-	uint32_t mask, values[2];
149-	struct xwl_window *xwl_window = wl_container_of(window, xwl_window, window);
150-
151-	mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y;
152-	values[0] = x;
153-	values[1] = y;
154-
155-	xcb_configure_window(xwm.connection, xwl_window->id, mask, values);
156-	xcb_flush(xwm.connection);
157-}
158-
159-static void
160-configure(struct window *window, uint32_t width, uint32_t height)
161-{
162-	uint32_t mask, values[2];
163-	struct xwl_window *xwl_window = wl_container_of(window, xwl_window, window);
164-
165-	mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
166-	values[0] = width;
167-	values[1] = height;
168-
169-	window->configure.acknowledged = true;
170-	xcb_configure_window(xwm.connection, xwl_window->id, mask, values);
171-	xcb_flush(xwm.connection);
172-}
173-
174-static void
175-focus(struct window *window)
176-{
177-	struct xwl_window *xwl_window = wl_container_of(window, xwl_window, window);
178-
179-	xcb_set_input_focus(xwm.connection, XCB_INPUT_FOCUS_NONE, xwl_window->id, XCB_CURRENT_TIME);
180-	xcb_flush(xwm.connection);
181-	xwm.focus = xwl_window;
182-}
183-
184-static void
185-unfocus(struct window *window)
186-{
187-	struct xwl_window *xwl_window = wl_container_of(window, xwl_window, window);
188-
189-	/* If the window we are unfocusing is the latest xwl_window to be focused, we
190-	 * know we have transitioned to some other window type, so the X11 focus can
191-	 * be set to XCB_NONE. Otherwise, we have transitioned to another X11 window,
192-	 * and the X11 focus has already been updated. */
193-	if (xwl_window == xwm.focus) {
194-		xcb_set_input_focus(xwm.connection, XCB_INPUT_FOCUS_NONE, XCB_NONE, XCB_CURRENT_TIME);
195-		xcb_flush(xwm.connection);
196-	}
197-}
198-
199-static void
200-close(struct window *window)
201-{
202-	struct xwl_window *xwl_window = wl_container_of(window, xwl_window, window);
203-
204-	if (xwl_window->supports_delete) {
205-		xcb_client_message_event_t event = {
206-			.response_type = XCB_CLIENT_MESSAGE,
207-			.format = 32,
208-			.window = xwl_window->id,
209-			.type = xwm.atoms[ATOM_WM_PROTOCOLS].value,
210-			.data.data32 = {
211-				xwm.atoms[ATOM_WM_DELETE_WINDOW].value,
212-				XCB_CURRENT_TIME,
213-			},
214-		};
215-
216-		xcb_send_event(xwm.connection, false, xwl_window->id, XCB_EVENT_MASK_NO_EVENT, (const char *)&event);
217-	} else {
218-		xcb_kill_client(xwm.connection, xwl_window->id);
219-	}
220-
221-	xcb_flush(xwm.connection);
222-}
223-
224-static const struct window_impl xwl_window_handler = {
225-	.move = move,
226-	.configure = configure,
227-	.focus = focus,
228-	.unfocus = unfocus,
229-	.close = close,
230-};
231-
232-static void
233-handle_surface_destroy(struct wl_listener *listener, void *data)
234-{
235-	struct xwl_window *xwl_window = wl_container_of(listener, xwl_window, surface_destroy_listener);
236-
237-	if (xwm.focus == xwl_window)
238-		xwm.focus = NULL;
239-
240-	window_finalize(&xwl_window->window);
241-	wl_list_remove(&xwl_window->link);
242-	wl_list_insert(&xwm.unpaired_windows, &xwl_window->link);
243-	xwl_window->surface_id = 0;
244-}
245-
246-static bool
247-manage_window(struct xwl_window *xwl_window)
248-{
249-	struct wl_resource *resource;
250-	struct surface *surface;
251-	xcb_get_geometry_cookie_t geometry_cookie;
252-	xcb_get_geometry_reply_t *geometry_reply;
253-
254-	resource = wl_client_get_object(swc.xserver->client, xwl_window->surface_id);
255-
256-	if (!resource)
257-		return false;
258-
259-	surface = wl_resource_get_user_data(resource);
260-	geometry_cookie = xcb_get_geometry(xwm.connection, xwl_window->id);
261-
262-	window_initialize(&xwl_window->window, &xwl_window_handler, surface);
263-	xwl_window->surface_destroy_listener.notify = &handle_surface_destroy;
264-	wl_resource_add_destroy_listener(surface->resource, &xwl_window->surface_destroy_listener);
265-
266-	if ((geometry_reply = xcb_get_geometry_reply(xwm.connection, geometry_cookie, NULL))) {
267-		view_move(surface->view, geometry_reply->x, geometry_reply->y);
268-		free(geometry_reply);
269-	}
270-
271-	if (xwl_window->override_redirect) {
272-		compositor_view_show(xwl_window->window.view);
273-	} else {
274-		uint32_t mask, values[1];
275-
276-		mask = XCB_CW_EVENT_MASK;
277-		values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE;
278-		xcb_change_window_attributes(xwm.connection, xwl_window->id, mask, values);
279-		mask = XCB_CONFIG_WINDOW_BORDER_WIDTH;
280-		values[0] = 0;
281-		xcb_configure_window(xwm.connection, xwl_window->id, mask, values);
282-		update_name(xwl_window);
283-		update_protocols(xwl_window);
284-		window_manage(&xwl_window->window);
285-	}
286-
287-	wl_list_remove(&xwl_window->link);
288-	wl_list_insert(&xwm.windows, &xwl_window->link);
289-
290-	return true;
291-}
292-
293-static void
294-handle_new_surface(struct wl_listener *listener, void *data)
295-{
296-	struct surface *surface = data;
297-	struct xwl_window *window;
298-
299-	window = find_window_by_surface_id(&xwm.unpaired_windows, wl_resource_get_id(surface->resource));
300-
301-	if (!window)
302-		return;
303-
304-	manage_window(window);
305-}
306-
307-static struct wl_listener new_surface_listener = {
308-	.notify = &handle_new_surface
309-};
310-
311-/* X event handlers */
312-static void
313-create_notify(xcb_create_notify_event_t *event)
314-{
315-	struct xwl_window *xwl_window;
316-
317-	if (!(xwl_window = malloc(sizeof *xwl_window)))
318-		return;
319-
320-	xwl_window->id = event->window;
321-	xwl_window->surface_id = 0;
322-	xwl_window->override_redirect = event->override_redirect;
323-	wl_list_insert(&xwm.unpaired_windows, &xwl_window->link);
324-}
325-
326-static void
327-destroy_notify(xcb_destroy_notify_event_t *event)
328-{
329-	struct xwl_window *xwl_window;
330-
331-	if ((xwl_window = find_window(&xwm.windows, event->window))) {
332-		wl_list_remove(&xwl_window->surface_destroy_listener.link);
333-		window_finalize(&xwl_window->window);
334-	} else if (!(xwl_window = find_window(&xwm.unpaired_windows, event->window))) {
335-		return;
336-	}
337-
338-	wl_list_remove(&xwl_window->link);
339-	free(xwl_window);
340-}
341-
342-static void
343-map_request(xcb_map_request_event_t *event)
344-{
345-	xcb_map_window(xwm.connection, event->window);
346-}
347-
348-static void
349-configure_request(xcb_configure_request_event_t *event)
350-{
351-}
352-
353-static void
354-property_notify(xcb_property_notify_event_t *event)
355-{
356-	struct xwl_window *xwl_window;
357-
358-	if (!(xwl_window = find_window(&xwm.windows, event->window)))
359-		return;
360-
361-	if (event->atom == xwm.ewmh._NET_WM_NAME && event->state == XCB_PROPERTY_NEW_VALUE)
362-		update_name(xwl_window);
363-	else if (event->atom == xwm.atoms[ATOM_WM_PROTOCOLS].value)
364-		update_protocols(xwl_window);
365-}
366-
367-static void
368-client_message(xcb_client_message_event_t *event)
369-{
370-	if (event->type == xwm.atoms[ATOM_WL_SURFACE_ID].value) {
371-		struct xwl_window *xwl_window;
372-
373-		if (!(xwl_window = find_window(&xwm.unpaired_windows, event->window)))
374-			return;
375-
376-		xwl_window->surface_id = event->data.data32[0];
377-		manage_window(xwl_window);
378-	}
379-}
380-
381-static int
382-connection_data(int fd, uint32_t mask, void *data)
383-{
384-	xcb_generic_event_t *event;
385-	uint32_t count = 0;
386-
387-	while ((event = xcb_poll_for_event(xwm.connection))) {
388-		switch (event->response_type & ~0x80) {
389-		case XCB_CREATE_NOTIFY:
390-			create_notify((xcb_create_notify_event_t *)event);
391-			break;
392-		case XCB_DESTROY_NOTIFY:
393-			destroy_notify((xcb_destroy_notify_event_t *)event);
394-			break;
395-		case XCB_MAP_REQUEST:
396-			map_request((xcb_map_request_event_t *)event);
397-			break;
398-		case XCB_CONFIGURE_REQUEST:
399-			configure_request((xcb_configure_request_event_t *)event);
400-			break;
401-		case XCB_PROPERTY_NOTIFY:
402-			property_notify((xcb_property_notify_event_t *)event);
403-			break;
404-		case XCB_CLIENT_MESSAGE:
405-			client_message((xcb_client_message_event_t *)event);
406-			break;
407-		}
408-
409-		free(event);
410-		++count;
411-	}
412-
413-	xcb_flush(xwm.connection);
414-
415-	return count;
416-}
417-
418-bool
419-xwm_initialize(int fd)
420-{
421-	const xcb_setup_t *setup;
422-	xcb_screen_iterator_t screen_iterator;
423-	uint32_t mask;
424-	uint32_t values[1];
425-	xcb_void_cookie_t change_attributes_cookie, redirect_subwindows_cookie;
426-	xcb_generic_error_t *error;
427-	xcb_intern_atom_cookie_t *ewmh_cookies;
428-	xcb_intern_atom_reply_t *atom_reply;
429-	unsigned index;
430-	const char *name;
431-	const xcb_query_extension_reply_t *composite_extension;
432-
433-	xwm.connection = xcb_connect_to_fd(fd, NULL);
434-
435-	if (xcb_connection_has_error(xwm.connection)) {
436-		ERROR("xwm: Could not connect to X server\n");
437-		goto error0;
438-	}
439-
440-	xcb_prefetch_extension_data(xwm.connection, &xcb_composite_id);
441-	ewmh_cookies = xcb_ewmh_init_atoms(xwm.connection, &xwm.ewmh);
442-
443-	if (!ewmh_cookies) {
444-		ERROR("xwm: Failed to initialize EWMH atoms\n");
445-		goto error1;
446-	}
447-
448-	for (index = 0; index < ARRAY_LENGTH(xwm.atoms); ++index) {
449-		name = xwm.atoms[index].name;
450-		xwm.atoms[index].cookie = xcb_intern_atom(xwm.connection, 0, strlen(name), name);
451-	}
452-
453-	setup = xcb_get_setup(xwm.connection);
454-	screen_iterator = xcb_setup_roots_iterator(setup);
455-	xwm.screen = screen_iterator.data;
456-
457-	/* Try to select for substructure redirect. */
458-	mask = XCB_CW_EVENT_MASK;
459-	values[0] = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT;
460-	change_attributes_cookie = xcb_change_window_attributes(xwm.connection, xwm.screen->root, mask, values);
461-
462-	xwm.source = wl_event_loop_add_fd(swc.event_loop, fd, WL_EVENT_READABLE, &connection_data, NULL);
463-	wl_list_init(&xwm.windows);
464-	wl_list_init(&xwm.unpaired_windows);
465-
466-	if (!xwm.source) {
467-		ERROR("xwm: Failed to create X connection event source\n");
468-		goto error2;
469-	}
470-
471-	composite_extension = xcb_get_extension_data(xwm.connection, &xcb_composite_id);
472-
473-	if (!composite_extension->present) {
474-		ERROR("xwm: X server does not have composite extension\n");
475-		goto error3;
476-	}
477-
478-	redirect_subwindows_cookie = xcb_composite_redirect_subwindows_checked(xwm.connection, xwm.screen->root, XCB_COMPOSITE_REDIRECT_MANUAL);
479-
480-	if ((error = xcb_request_check(xwm.connection, change_attributes_cookie))) {
481-		ERROR("xwm: Another window manager is running\n");
482-		free(error);
483-		goto error3;
484-	}
485-
486-	if ((error = xcb_request_check(xwm.connection, redirect_subwindows_cookie))) {
487-		ERROR("xwm: Could not redirect subwindows of root for compositing\n");
488-		free(error);
489-		goto error3;
490-	}
491-
492-	xwm.window = xcb_generate_id(xwm.connection);
493-	xcb_create_window(xwm.connection, 0, xwm.window, xwm.screen->root,
494-	                  0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY,
495-	                  XCB_COPY_FROM_PARENT, 0, NULL);
496-
497-	xcb_ewmh_init_atoms_replies(&xwm.ewmh, ewmh_cookies, &error);
498-
499-	if (error) {
500-		ERROR("xwm: Failed to get EWMH atom replies: %u\n", error->error_code);
501-		goto error3;
502-	}
503-
504-	for (index = 0; index < ARRAY_LENGTH(xwm.atoms); ++index) {
505-		atom_reply = xcb_intern_atom_reply(xwm.connection, xwm.atoms[index].cookie, &error);
506-
507-		if (error) {
508-			ERROR("xwm: Failed to get atom reply: %u\n", error->error_code);
509-			return false;
510-		}
511-
512-		xwm.atoms[index].value = atom_reply->atom;
513-		free(atom_reply);
514-	}
515-
516-	xcb_set_selection_owner(xwm.connection, xwm.window, xwm.atoms[ATOM_WM_S0].value, XCB_CURRENT_TIME);
517-	xcb_flush(xwm.connection);
518-
519-	wl_signal_add(&swc.compositor->signal.new_surface, &new_surface_listener);
520-
521-	return true;
522-
523-error3:
524-	wl_event_source_remove(xwm.source);
525-error2:
526-	xcb_ewmh_connection_wipe(&xwm.ewmh);
527-error1:
528-	xcb_disconnect(xwm.connection);
529-error0:
530-	return false;
531-}
532-
533-void
534-xwm_finalize(void)
535-{
536-	wl_event_source_remove(xwm.source);
537-	xcb_ewmh_connection_wipe(&xwm.ewmh);
538-	xcb_disconnect(xwm.connection);
539-}
+0, -32
 1@@ -1,32 +0,0 @@
 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-
30-bool xwm_initialize(int fd);
31-void xwm_finalize(void);
32-
33-#endif