commit e65cced
Michael Forney
·
2014-04-24 05:17:38 +0000 UTC
parent bf9647b
Update to new implementation of XWayland Fixes #6
9 files changed,
+266,
-206
+0,
-2
1@@ -6,8 +6,6 @@ protocol/swc-protocol.c
2 protocol/swc-server-protocol.h
3 protocol/wayland-drm-protocol.c
4 protocol/wayland-drm-server-protocol.h
5-protocol/xserver-protocol.c
6-protocol/xserver-server-protocol.h
7
8 /.deps/
9 /swc.pc
+4,
-0
1@@ -41,6 +41,10 @@ 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;
+7,
-1
1@@ -47,6 +47,9 @@ extern const struct swc_bindings swc_bindings;
2 extern struct swc_compositor swc_compositor;
3 extern struct swc_drm swc_drm;
4 extern struct swc_shm swc_shm;
5+#ifdef ENABLE_XWAYLAND
6+extern struct swc_xserver swc_xserver;
7+#endif
8
9 struct swc swc = {
10 .launch = &swc_launch,
11@@ -54,7 +57,10 @@ struct swc swc = {
12 .bindings = &swc_bindings,
13 .compositor = &swc_compositor,
14 .drm = &swc_drm,
15- .shm = &swc_shm
16+ .shm = &swc_shm,
17+#ifdef ENABLE_XWAYLAND
18+ .xserver = &swc_xserver,
19+#endif
20 };
21
22 static void setup_compositor()
+93,
-89
1@@ -39,7 +39,6 @@
2 #include <sys/socket.h>
3 #include <sys/un.h>
4 #include <wayland-server.h>
5-#include "protocol/xserver-server-protocol.h"
6
7 #define LOCK_FMT "/tmp/.X%d-lock"
8 #define SOCKET_DIR "/tmp/.X11-unix"
9@@ -47,30 +46,14 @@
10
11 static struct
12 {
13- struct wl_global * global;
14- struct wl_client * client;
15 struct wl_resource * resource;
16+ struct wl_event_source * usr1_source;
17 int display;
18 char display_name[16];
19- int abstract_fd, unix_fd;
20+ int abstract_fd, unix_fd, wm_fd;
21 } xserver;
22
23-static char * xserver_command[] = {
24- "X", "-wayland", "-rootless", "-nolisten", "all", xserver.display_name, NULL
25-};
26-
27-static void set_window_id(struct wl_client * client,
28- struct wl_resource * resource,
29- struct wl_resource * surface_resource, uint32_t id)
30-{
31- struct swc_surface * surface = wl_resource_get_user_data(surface_resource);
32-
33- xwm_manage_window(id, surface);
34-}
35-
36-const static struct xserver_interface xserver_implementation = {
37- .set_window_id = &set_window_id
38-};
39+struct swc_xserver swc_xserver;
40
41 static int open_socket(struct sockaddr_un * addr, size_t path_size)
42 {
43@@ -175,41 +158,22 @@ static void close_display()
44 unsetenv("DISPLAY");
45 }
46
47-static void bind_xserver(struct wl_client * client, void * data,
48- uint32_t version, uint32_t id)
49+static int handle_usr1(int signal_number, void * data)
50 {
51- int sv[2];
52-
53- if (client != xserver.client)
54- return;
55-
56- if (version >= 1)
57- version = 1;
58-
59- DEBUG("Binding X server\n");
60-
61- xserver.resource = wl_resource_create(client, &xserver_interface,
62- version, id);
63- wl_resource_set_implementation(xserver.resource, &xserver_implementation,
64- NULL, NULL);
65-
66- /* Start the X window manager */
67- socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
68- xserver_send_client(xserver.resource, sv[1]);
69- close(sv[1]);
70+ if (!xwm_initialize(xserver.wm_fd))
71+ {
72+ ERROR("Failed to initialize X window manager\n");
73+ /* XXX: How do we handle this case? */
74+ }
75
76- /* Need to flush the xserver client so the X window manager can connect to
77- * it's socket. */
78- wl_client_flush(xserver.client);
79- xwm_initialize(sv[0]);
80+ wl_event_source_remove(xserver.usr1_source);
81
82- xserver_send_listen_socket(xserver.resource, xserver.abstract_fd);
83- xserver_send_listen_socket(xserver.resource, xserver.unix_fd);
84+ return 0;
85 }
86
87-static bool start_xserver()
88+bool xserver_initialize()
89 {
90- int sv[2];
91+ int wl[2], wm[2];
92
93 /* Open an X display */
94 if (!open_display())
95@@ -218,76 +182,116 @@ static bool start_xserver()
96 goto error0;
97 }
98
99- /* Start the X server */
100- if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) == -1)
101+ xserver.usr1_source = wl_event_loop_add_signal(swc.event_loop, SIGUSR1,
102+ &handle_usr1, NULL);
103+
104+ if (!xserver.usr1_source)
105 {
106- ERROR("Failed to create socketpair: %s\n", strerror(errno));
107+ ERROR("Failed to create SIGUSR1 event source\n");
108 goto error1;
109 }
110
111- if (!(xserver.client = wl_client_create(swc.display, sv[0])))
112+ /* Open a socket for the Wayland connection from Xwayland. */
113+ if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, wl) != 0)
114+ {
115+ ERROR("Failed to create socketpair: %s\n", strerror(errno));
116 goto error2;
117+ }
118
119- switch (fork())
120+ /* Open a socket for the X connection to Xwayland. */
121+ if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, wm) != 0)
122 {
123- case 0:
124- {
125- int socket_fd;
126- char socket_string[32];
127+ ERROR("Failed to create socketpair: %s\n", strerror(errno));
128+ goto error3;
129+ }
130
131- if (!(socket_fd = dup(sv[1])))
132- exit(EXIT_FAILURE);
133+ if (!(swc_xserver.client = wl_client_create(swc.display, wl[0])))
134+ goto error4;
135
136- snprintf(socket_string, sizeof socket_string, "%d", socket_fd);
137- setenv("WAYLAND_SOCKET", socket_string, true);
138+ xserver.wm_fd = wm[0];
139
140- execvp(xserver_command[0], xserver_command);
141+ /* Start the X server */
142+ switch (fork())
143+ {
144+ case 0:
145+ {
146+ int fds[] = { wl[1], wm[1], xserver.abstract_fd, xserver.unix_fd };
147+ char strings[ARRAY_LENGTH(fds)][16];
148+ unsigned index;
149+ struct sigaction action = { .sa_handler = SIG_IGN };
150+
151+ /* Unset the FD_CLOEXEC flag on the FDs that will get passed to
152+ * Xwayland. */
153+ for (index = 0; index < ARRAY_LENGTH(fds); ++index)
154+ {
155+ if (fcntl(fds[index], F_SETFD, 0) != 0)
156+ {
157+ ERROR("fcntl() failed: %s\n", strerror(errno));
158+ goto fail;
159+ }
160+
161+ if (snprintf(strings[index], sizeof strings[index],
162+ "%d", fds[index]) >= sizeof strings[index])
163+ {
164+ ERROR("FD is too large\n");
165+ goto fail;
166+ }
167+ }
168+
169+ /* Ignore the USR1 signal so that Xwayland will send a USR1 signal
170+ * to the parent process (us) after it finishes initializing. See
171+ * Xserver(1) for more details. */
172+ if (sigaction(SIGUSR1, &action, NULL) != 0)
173+ {
174+ ERROR("Failed to set SIGUSR1 handler to SIG_IGN: %s\n",
175+ strerror(errno));
176+ goto fail;
177+ }
178+
179+ setenv("WAYLAND_SOCKET", strings[0], true);
180+ execlp("Xwayland", "Xwayland",
181+ xserver.display_name,
182+ "-rootless",
183+ "-terminate",
184+ "-listen", strings[2],
185+ "-listen", strings[3],
186+ "-wm", strings[1],
187+ NULL);
188+
189+ fail:
190 exit(EXIT_FAILURE);
191-
192- break;
193 }
194 case -1:
195 ERROR("fork() failed when trying to start X server: %s\n",
196 strerror(errno));
197- goto error2;
198+ goto error5;
199 }
200
201- close(sv[1]);
202+ close(wl[1]);
203+ close(wm[1]);
204
205 return true;
206
207+ error5:
208+ wl_client_destroy(swc_xserver.client);
209+ error4:
210+ close(wm[1]);
211+ close(wm[0]);
212+ error3:
213+ close(wl[1]);
214+ close(wl[0]);
215 error2:
216- close(sv[1]);
217- close(sv[0]);
218+ wl_event_source_remove(xserver.usr1_source);
219 error1:
220 close_display();
221 error0:
222 return false;
223 }
224
225-bool xserver_initialize()
226-{
227- xserver.global = wl_global_create(swc.display, &xserver_interface, 1,
228- NULL, &bind_xserver);
229-
230- if (!xserver.global)
231- goto error0;
232-
233- if (!start_xserver())
234- goto error1;
235-
236- return true;
237-
238- error1:
239- wl_global_destroy(xserver.global);
240- error0:
241- return false;
242-}
243-
244 void xserver_finalize()
245 {
246 xwm_finalize();
247 close_display();
248- wl_global_destroy(xserver.global);
249+ wl_client_destroy(swc_xserver.client);
250 }
251
+5,
-0
1@@ -26,6 +26,11 @@
2
3 #include <stdbool.h>
4
5+struct swc_xserver
6+{
7+ struct wl_client * client;
8+};
9+
10 bool xserver_initialize();
11 void xserver_finalize();
12
+156,
-89
1@@ -29,14 +29,17 @@
2 #include "util.h"
3 #include "view.h"
4 #include "window.h"
5+#include "xserver.h"
6
7 #include <stdio.h>
8 #include <xcb/composite.h>
9 #include <xcb/xcb_ewmh.h>
10+#include <xcb/xcb_icccm.h>
11
12 struct xwl_window
13 {
14 xcb_window_t id;
15+ uint32_t surface_id;
16 bool override_redirect;
17 struct wl_list link;
18
19@@ -50,6 +53,7 @@ struct xwl_window
20 enum atom
21 {
22 ATOM_WM_S0,
23+ ATOM_WL_SURFACE_ID,
24 };
25
26 static struct
27@@ -65,10 +69,11 @@ static struct
28 const char * name;
29 xcb_intern_atom_cookie_t cookie;
30 xcb_atom_t value;
31- } atoms[1];
32+ } atoms[2];
33 } xwm = {
34 .atoms = {
35 [ATOM_WM_S0] = "WM_S0",
36+ [ATOM_WL_SURFACE_ID] = "WL_SURFACE_ID",
37 }
38 };
39
40@@ -100,6 +105,135 @@ static struct xwl_window * find_window(struct wl_list * list, xcb_window_t id)
41 return NULL;
42 }
43
44+static struct xwl_window * find_window_by_surface_id(struct wl_list * list,
45+ uint32_t id)
46+{
47+ struct xwl_window * window;
48+
49+ wl_list_for_each(window, list, link)
50+ {
51+ if (window->surface_id == id)
52+ return window;
53+ }
54+
55+ return NULL;
56+}
57+
58+static void configure(struct window * window,
59+ const struct swc_rectangle * geometry)
60+{
61+ uint32_t mask, values[4];
62+ struct xwl_window * xwl_window
63+ = CONTAINER_OF(window, typeof(*xwl_window), window);
64+
65+ mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y
66+ | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
67+ values[0] = geometry->x;
68+ values[1] = geometry->y;
69+ values[2] = geometry->width;
70+ values[3] = geometry->height;
71+
72+ xcb_configure_window(xwm.connection, xwl_window->id, mask, values);
73+ xcb_flush(xwm.connection);
74+}
75+
76+static void focus(struct window * window)
77+{
78+ xcb_window_t id = window ? CONTAINER_OF(window, struct xwl_window,
79+ window)->id
80+ : XCB_NONE;
81+
82+ xcb_set_input_focus(xwm.connection, XCB_INPUT_FOCUS_NONE,
83+ id, XCB_CURRENT_TIME);
84+ xcb_flush(xwm.connection);
85+}
86+
87+static const struct window_impl xwl_window_handler = {
88+ .configure = &configure,
89+ .focus = &focus
90+};
91+
92+static void handle_surface_destroy(struct wl_listener * listener, void * data)
93+{
94+ struct xwl_window * xwl_window
95+ = CONTAINER_OF(listener, typeof(*xwl_window), surface_destroy_listener);
96+
97+ window_finalize(&xwl_window->window);
98+ wl_list_remove(&xwl_window->link);
99+ wl_list_insert(&xwm.unpaired_windows, &xwl_window->link);
100+ xwl_window->surface_id = 0;
101+}
102+
103+static bool manage_window(struct xwl_window * xwl_window)
104+{
105+ struct wl_resource * resource;
106+ struct swc_surface * surface;
107+ xcb_get_geometry_cookie_t geometry_cookie;
108+ xcb_get_geometry_reply_t * geometry_reply;
109+
110+ resource = wl_client_get_object(swc.xserver->client,
111+ xwl_window->surface_id);
112+
113+ if (!resource)
114+ return false;
115+
116+ surface = wl_resource_get_user_data(resource);
117+ geometry_cookie = xcb_get_geometry(xwm.connection, xwl_window->id);
118+
119+ window_initialize(&xwl_window->window, &xwl_window_handler, surface);
120+ xwl_window->surface_destroy_listener.notify = &handle_surface_destroy;
121+ wl_resource_add_destroy_listener(surface->resource,
122+ &xwl_window->surface_destroy_listener);
123+
124+ if ((geometry_reply = xcb_get_geometry_reply(xwm.connection,
125+ geometry_cookie, NULL)))
126+ {
127+ view_move(surface->view, geometry_reply->x, geometry_reply->y);
128+ free(geometry_reply);
129+ }
130+
131+ if (xwl_window->override_redirect)
132+ compositor_view_show(xwl_window->window.view);
133+ else
134+ {
135+ uint32_t mask, values[1];
136+
137+ mask = XCB_CW_EVENT_MASK;
138+ values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE;
139+ xcb_change_window_attributes(xwm.connection, xwl_window->id,
140+ mask, values);
141+ mask = XCB_CONFIG_WINDOW_BORDER_WIDTH;
142+ values[0] = 0;
143+ xcb_configure_window(xwm.connection, xwl_window->id, mask, values);
144+ update_name(xwl_window);
145+
146+ window_set_state(&xwl_window->window, SWC_WINDOW_STATE_NORMAL);
147+ }
148+
149+ wl_list_remove(&xwl_window->link);
150+ wl_list_insert(&xwm.windows, &xwl_window->link);
151+
152+ return true;
153+}
154+
155+static void handle_new_surface(struct wl_listener * listener, void * data)
156+{
157+ struct swc_surface * surface = data;
158+ struct xwl_window * window;
159+
160+ window = find_window_by_surface_id(&xwm.unpaired_windows,
161+ wl_resource_get_id(surface->resource));
162+
163+ if (!window)
164+ return;
165+
166+ manage_window(window);
167+}
168+
169+static struct wl_listener new_surface_listener = {
170+ .notify = &handle_new_surface
171+};
172+
173 /* X event handlers */
174 static void create_notify(xcb_create_notify_event_t * event)
175 {
176@@ -109,6 +243,7 @@ static void create_notify(xcb_create_notify_event_t * event)
177 return;
178
179 xwl_window->id = event->window;
180+ xwl_window->surface_id = 0;
181 xwl_window->override_redirect = event->override_redirect;
182 wl_list_insert(&xwm.unpaired_windows, &xwl_window->link);
183 }
184@@ -152,6 +287,20 @@ static void property_notify(xcb_property_notify_event_t * event)
185 }
186 }
187
188+static void client_message(xcb_client_message_event_t * event)
189+{
190+ if (event->type == xwm.atoms[ATOM_WL_SURFACE_ID].value)
191+ {
192+ struct xwl_window * xwl_window;
193+
194+ if (!(xwl_window = find_window(&xwm.unpaired_windows, event->window)))
195+ return;
196+
197+ xwl_window->surface_id = event->data.data32[0];
198+ manage_window(xwl_window);
199+ }
200+}
201+
202 static int connection_data(int fd, uint32_t mask, void * data)
203 {
204 xcb_generic_event_t * event;
205@@ -175,6 +324,10 @@ static int connection_data(int fd, uint32_t mask, void * data)
206 break;
207 case XCB_PROPERTY_NOTIFY:
208 property_notify((xcb_property_notify_event_t *) event);
209+ break;
210+ case XCB_CLIENT_MESSAGE:
211+ client_message((xcb_client_message_event_t *) event);
212+ break;
213 }
214
215 free(event);
216@@ -301,6 +454,8 @@ bool xwm_initialize(int fd)
217 xwm.atoms[ATOM_WM_S0].value, XCB_CURRENT_TIME);
218 xcb_flush(xwm.connection);
219
220+ wl_signal_add(&swc.compositor->signal.new_surface, &new_surface_listener);
221+
222 return true;
223
224 error3:
225@@ -320,91 +475,3 @@ void xwm_finalize()
226 xcb_disconnect(xwm.connection);
227 }
228
229-static void configure(struct window * window,
230- const struct swc_rectangle * geometry)
231-{
232- uint32_t mask, values[4];
233- struct xwl_window * xwl_window
234- = CONTAINER_OF(window, typeof(*xwl_window), window);
235-
236- mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y
237- | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
238- values[0] = geometry->x;
239- values[1] = geometry->y;
240- values[2] = geometry->width;
241- values[3] = geometry->height;
242-
243- xcb_configure_window(xwm.connection, xwl_window->id, mask, values);
244- xcb_flush(xwm.connection);
245-}
246-
247-static void focus(struct window * window)
248-{
249- xcb_window_t id = window ? CONTAINER_OF(window, struct xwl_window,
250- window)->id
251- : XCB_NONE;
252-
253- xcb_set_input_focus(xwm.connection, XCB_INPUT_FOCUS_NONE,
254- id, XCB_CURRENT_TIME);
255- xcb_flush(xwm.connection);
256-}
257-
258-static const struct window_impl xwl_window_handler = {
259- .configure = &configure,
260- .focus = &focus
261-};
262-
263-static void handle_surface_destroy(struct wl_listener * listener, void * data)
264-{
265- struct xwl_window * xwl_window
266- = CONTAINER_OF(listener, typeof(*xwl_window), surface_destroy_listener);
267-
268- window_finalize(&xwl_window->window);
269- wl_list_remove(&xwl_window->link);
270- wl_list_insert(&xwm.unpaired_windows, &xwl_window->link);
271-}
272-
273-void xwm_manage_window(xcb_window_t id, struct swc_surface * surface)
274-{
275- struct xwl_window * xwl_window;
276- xcb_get_geometry_cookie_t geometry_cookie;
277- xcb_get_geometry_reply_t * geometry_reply;
278-
279- if (!(xwl_window = find_window(&xwm.unpaired_windows, id)))
280- return;
281-
282- geometry_cookie = xcb_get_geometry(xwm.connection, id);
283-
284- window_initialize(&xwl_window->window, &xwl_window_handler, surface);
285- xwl_window->surface_destroy_listener.notify = &handle_surface_destroy;
286- wl_resource_add_destroy_listener(surface->resource,
287- &xwl_window->surface_destroy_listener);
288-
289- if ((geometry_reply = xcb_get_geometry_reply(xwm.connection,
290- geometry_cookie, NULL)))
291- {
292- view_move(surface->view, geometry_reply->x, geometry_reply->y);
293- free(geometry_reply);
294- }
295-
296- if (xwl_window->override_redirect)
297- compositor_view_show(xwl_window->window.view);
298- else
299- {
300- uint32_t mask, values[1];
301-
302- mask = XCB_CW_EVENT_MASK;
303- values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE;
304- xcb_change_window_attributes(xwm.connection, id, mask, values);
305- mask = XCB_CONFIG_WINDOW_BORDER_WIDTH;
306- values[0] = 0;
307- xcb_configure_window(xwm.connection, id, mask, values);
308- update_name(xwl_window);
309-
310- window_set_state(&xwl_window->window, SWC_WINDOW_STATE_NORMAL);
311- }
312-
313- wl_list_remove(&xwl_window->link);
314- wl_list_insert(&xwm.windows, &xwl_window->link);
315-}
316-
+0,
-5
1@@ -25,14 +25,9 @@
2 #define SWC_XWM_H
3
4 #include <stdbool.h>
5-#include <xcb/xcb.h>
6-
7-struct swc_surface;
8
9 bool xwm_initialize(int fd);
10 void xwm_finalize();
11
12-void xwm_manage_window(xcb_window_t window, struct swc_surface * surface);
13-
14 #endif
15
+1,
-2
1@@ -4,8 +4,7 @@ dir := protocol
2
3 PROTOCOL_EXTENSIONS = \
4 $(dir)/swc.xml \
5- $(dir)/wayland-drm.xml \
6- $(dir)/xserver.xml
7+ $(dir)/wayland-drm.xml
8
9 $(dir)_TARGETS := $(PROTOCOL_EXTENSIONS:%.xml=%-protocol.c) \
10 $(PROTOCOL_EXTENSIONS:%.xml=%-server-protocol.h)
+0,
-18
1@@ -1,18 +0,0 @@
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>