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>