xserver: Clean up X server socket on exit
[profile/ivi/weston.git] / compositor / xserver-launcher.c
1 /*
2  * Copyright © 2011 Intel Corporation
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and
5  * its documentation for any purpose is hereby granted without fee, provided
6  * that the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name of the copyright holders not be used in
9  * advertising or publicity pertaining to distribution of the software
10  * without specific, written prior permission.  The copyright holders make
11  * no representations about the suitability of this software for any
12  * purpose.  It is provided "as is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21  */
22
23 #define _GNU_SOURCE
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <sys/socket.h>
29 #include <sys/un.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <unistd.h>
33 #include <signal.h>
34
35 #include <xcb/xcb.h>
36
37 #include <wayland-server.h>
38
39 #include "compositor.h"
40 #include "xserver-server-protocol.h"
41
42 /*
43  * TODO:
44  *  - Clean X socket and lock file on exit
45  *  - Nuke lock file if process doesn't exist.
46  *
47  * WM TODO:
48  *  - Send take focus, hook into wlsc_surface_activate.
49  */
50
51 struct xserver {
52         struct wl_object object;
53 };
54
55 struct wlsc_xserver {
56         struct wl_display *wl_display;
57         struct wl_event_loop *loop;
58         struct wl_event_source *source;
59         struct wl_event_source *sigchld_source;
60         struct wl_client *client;
61         int fd;
62         struct sockaddr_un addr;
63         char lock_addr[113];
64         int display;
65         struct wlsc_process process;
66
67         struct xserver xserver;
68
69         struct wlsc_wm *wm;
70 };
71
72 struct wlsc_wm {
73         xcb_connection_t *conn;
74         struct wl_event_source *source;
75         xcb_screen_t *screen;
76         struct wl_hash_table *window_hash;
77         struct {
78                 xcb_atom_t               wm_protocols;
79                 xcb_atom_t               wm_take_focus;
80                 xcb_atom_t               wm_delete_window;
81                 xcb_atom_t               net_wm_name;
82                 xcb_atom_t               net_wm_icon;
83                 xcb_atom_t               net_wm_state;
84                 xcb_atom_t               net_wm_state_fullscreen;
85                 xcb_atom_t               utf8_string;
86         } atom;
87 };
88
89 struct wlsc_wm_window {
90         xcb_window_t id;
91         struct wlsc_surface *surface;
92 };
93
94 static void
95 wlsc_wm_handle_configure_request(struct wlsc_wm *wm, xcb_generic_event_t *event)
96 {
97         xcb_configure_request_event_t *configure_request = 
98                 (xcb_configure_request_event_t *) event;
99         uint32_t values[16];
100         int i = 0;
101
102         fprintf(stderr, "XCB_CONFIGURE_REQUEST\n");
103
104         if (configure_request->value_mask & XCB_CONFIG_WINDOW_X)
105                 values[i++] = configure_request->x;
106         if (configure_request->value_mask & XCB_CONFIG_WINDOW_Y)
107                 values[i++] = configure_request->y;
108         if (configure_request->value_mask & XCB_CONFIG_WINDOW_WIDTH)
109                 values[i++] = configure_request->width;
110         if (configure_request->value_mask & XCB_CONFIG_WINDOW_HEIGHT)
111                 values[i++] = configure_request->height;
112         if (configure_request->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH)
113                 values[i++] = configure_request->border_width;
114         if (configure_request->value_mask & XCB_CONFIG_WINDOW_SIBLING)
115                 values[i++] = configure_request->sibling;
116         if (configure_request->value_mask & XCB_CONFIG_WINDOW_STACK_MODE)
117                 values[i++] = configure_request->stack_mode;
118
119         xcb_configure_window(wm->conn,
120                              configure_request->window,
121                              configure_request->value_mask, values);
122 }
123
124 static void
125 wlsc_wm_get_properties(struct wlsc_wm *wm, xcb_window_t window)
126 {
127         xcb_generic_error_t *e;
128         xcb_get_property_reply_t *reply;
129         void *value;
130         int i;
131
132         struct {
133                 xcb_atom_t atom;
134                 xcb_get_property_cookie_t cookie;
135         } props[] = {
136                 { XCB_ATOM_WM_CLASS, },
137                 { XCB_ATOM_WM_TRANSIENT_FOR },
138                 { wm->atom.wm_protocols, },
139                 { wm->atom.net_wm_name, },
140         };
141
142         for (i = 0; i < ARRAY_LENGTH(props); i++)
143                 props[i].cookie =
144                         xcb_get_property (wm->conn, 
145                                           0, /* delete */
146                                           window,
147                                           props[i].atom,
148                                           XCB_ATOM_ANY,
149                                           0, 2048);
150
151         for (i = 0; i < ARRAY_LENGTH(props); i++)  {
152                 reply = xcb_get_property_reply(wm->conn, props[i].cookie, &e);
153                 value = xcb_get_property_value(reply);
154
155                 fprintf(stderr, "property %d, type %d, format %d, "
156                         "length %d (value_len %d), value \"%s\"\n",
157                         props[i].atom,
158                         reply->type, reply->format,
159                         xcb_get_property_value_length(reply), reply->value_len,
160                         reply->type ? (char *) value : "(nil)");
161
162                 free(reply);
163         }
164 }
165
166 static void
167 wlsc_wm_activate(struct wlsc_wm *wm,
168                  struct wlsc_wm_window *window, xcb_timestamp_t time)
169 {
170         xcb_set_input_focus (wm->conn,
171                              XCB_INPUT_FOCUS_POINTER_ROOT, window->id, time);
172 }
173
174 static void
175 wlsc_wm_handle_map_request(struct wlsc_wm *wm, xcb_generic_event_t *event)
176 {
177         xcb_map_request_event_t *map_request =
178                 (xcb_map_request_event_t *) event;
179         uint32_t values[1];
180
181         fprintf(stderr, "XCB_MAP_REQUEST\n");
182
183         wlsc_wm_get_properties(wm, map_request->window);
184         values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE;
185         xcb_change_window_attributes(wm->conn, map_request->window,
186                                      XCB_CW_EVENT_MASK, values);
187
188         xcb_map_window(wm->conn, map_request->window);
189 }
190
191 static void
192 wlsc_wm_handle_map_notify(struct wlsc_wm *wm, xcb_generic_event_t *event)
193 {
194         xcb_map_notify_event_t *map_notify =
195                 (xcb_map_notify_event_t *) event;
196         struct wlsc_wm_window *window;
197         xcb_client_message_event_t client_message;
198
199         fprintf(stderr, "XCB_MAP_NOTIFY\n");
200
201         wlsc_wm_get_properties(wm, map_notify->window);
202
203         window = wl_hash_table_lookup(wm->window_hash, map_notify->window);
204         wlsc_wm_activate(wm, window, XCB_TIME_CURRENT_TIME);
205
206         client_message.response_type = XCB_CLIENT_MESSAGE;
207         client_message.format = 32;
208         client_message.window = window->id;
209         client_message.type = wm->atom.wm_protocols;
210         client_message.data.data32[0] = wm->atom.wm_take_focus;
211         client_message.data.data32[1] = XCB_TIME_CURRENT_TIME;
212
213         xcb_send_event(wm->conn, 0, window->id, 
214                        XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
215                        (char *) &client_message);
216
217 }
218
219 static void
220 wlsc_wm_handle_property_notify(struct wlsc_wm *wm, xcb_generic_event_t *event)
221 {
222         xcb_property_notify_event_t *property_notify =
223                 (xcb_property_notify_event_t *) event;
224
225         fprintf(stderr, "XCB_PROPERTY_NOTIFY\n");
226
227         if (property_notify->atom == XCB_ATOM_WM_CLASS) {
228                 fprintf(stderr, "wm_class changed\n");
229         } else if (property_notify->atom == XCB_ATOM_WM_TRANSIENT_FOR) {
230                 fprintf(stderr, "wm_transient_for changed\n");
231         } else if (property_notify->atom == wm->atom.wm_protocols) {
232                 fprintf(stderr, "wm_protocols changed\n");
233         } else if (property_notify->atom == wm->atom.net_wm_name) {
234                 fprintf(stderr, "wm_class changed\n");
235         } else {
236                 fprintf(stderr, "unhandled property change: %d\n",
237                         property_notify->atom);
238         }
239 }
240
241 static void
242 wlsc_wm_handle_create_notify(struct wlsc_wm *wm, xcb_generic_event_t *event)
243 {
244         xcb_create_notify_event_t *create_notify =
245                 (xcb_create_notify_event_t *) event;
246         struct wlsc_wm_window *window;
247
248         fprintf(stderr, "XCB_CREATE_NOTIFY, win %d\n", create_notify->window);
249
250         window = malloc(sizeof *window);
251         if (window == NULL) {
252                 fprintf(stderr, "failed to allocate window\n");
253                 return;
254         }
255
256         window->id = create_notify->window;
257         wl_hash_table_insert(wm->window_hash, window->id, window);
258
259         fprintf(stderr, "created window %p\n", window);
260 }
261
262 static void
263 wlsc_wm_handle_destroy_notify(struct wlsc_wm *wm, xcb_generic_event_t *event)
264 {
265         xcb_destroy_notify_event_t *destroy_notify =
266                 (xcb_destroy_notify_event_t *) event;
267         struct wlsc_wm_window *window;
268
269         fprintf(stderr, "XCB_DESTROY_NOTIFY, win %d\n",
270                 destroy_notify->window);
271
272         window = wl_hash_table_lookup(wm->window_hash, destroy_notify->window);
273         if (window == NULL) {
274                 fprintf(stderr, "destroy notify for unknow window %d\n",
275                         destroy_notify->window);
276                 return;
277         }
278
279         fprintf(stderr, "destroy window %p\n", window);
280         wl_hash_table_remove(wm->window_hash, window->id);
281         free(window);
282 }
283
284 static int
285 wlsc_wm_handle_event(int fd, uint32_t mask, void *data)
286 {
287         struct wlsc_wm *wm = data;
288         xcb_generic_event_t *event;
289         int count = 0;
290
291         while (event = xcb_poll_for_event(wm->conn), event != NULL) {
292                 switch (event->response_type) {
293                 case XCB_CREATE_NOTIFY:
294                         wlsc_wm_handle_create_notify(wm, event);
295                         break;
296                 case XCB_MAP_REQUEST:
297                         wlsc_wm_handle_map_request(wm, event);
298                         break;
299                 case XCB_MAP_NOTIFY:
300                         wlsc_wm_handle_map_notify(wm, event);
301                         break;
302                 case XCB_UNMAP_NOTIFY:
303                         fprintf(stderr, "XCB_UNMAP_NOTIFY\n");
304                         break;
305                 case XCB_CONFIGURE_REQUEST:
306                         wlsc_wm_handle_configure_request(wm, event);
307                         break;
308                 case XCB_CONFIGURE_NOTIFY:
309                         fprintf(stderr, "XCB_CONFIGURE_NOTIFY\n");
310                         break;
311                 case XCB_DESTROY_NOTIFY:
312                         wlsc_wm_handle_destroy_notify(wm, event);
313                         break;
314                 case XCB_MAPPING_NOTIFY:
315                         fprintf(stderr, "XCB_MAPPING_NOTIFY\n");
316                         break;
317                 case XCB_PROPERTY_NOTIFY:
318                         wlsc_wm_handle_property_notify(wm, event);
319                         break;
320                 default:
321                         fprintf(stderr, "Unhandled event %d\n",
322                                 event->response_type);
323                         break;
324                 }
325                 free(event);
326                 count++;
327         }
328
329         xcb_flush(wm->conn);
330
331         return count;
332 }
333
334 static void
335 wxs_wm_get_resources(struct wlsc_wm *wm)
336 {
337
338 #define F(field) offsetof(struct wlsc_wm, field)
339
340         static const struct { const char *name; int offset; } atoms[] = {
341                 { "WM_PROTOCOLS",       F(atom.wm_protocols) },
342                 { "WM_TAKE_FOCUS",      F(atom.wm_take_focus) },
343                 { "WM_DELETE_WINDOW",   F(atom.wm_delete_window) },
344                 { "_NET_WM_NAME",       F(atom.net_wm_name) },
345                 { "_NET_WM_ICON",       F(atom.net_wm_icon) },
346                 { "_NET_WM_STATE",      F(atom.net_wm_state) },
347                 { "_NET_WM_STATE_FULLSCREEN", F(atom.net_wm_state_fullscreen) },
348                 { "UTF8_STRING",        F(atom.utf8_string) },
349         };
350
351         xcb_intern_atom_cookie_t cookies[ARRAY_LENGTH(atoms)];
352         xcb_intern_atom_reply_t *reply;
353         int i;
354
355         for (i = 0; i < ARRAY_LENGTH(atoms); i++)
356                 cookies[i] = xcb_intern_atom (wm->conn, 0,
357                                               strlen(atoms[i].name),
358                                               atoms[i].name);
359
360         for (i = 0; i < ARRAY_LENGTH(atoms); i++) {
361                 reply = xcb_intern_atom_reply (wm->conn, cookies[i], NULL);
362                 *(xcb_atom_t *) ((char *) wm + atoms[i].offset) = reply->atom;
363                 free(reply);
364         }
365 }
366
367 static struct wlsc_wm *
368 wlsc_wm_create(struct wlsc_xserver *wxs)
369 {
370         struct wlsc_wm *wm;
371         struct wl_event_loop *loop;
372         xcb_screen_iterator_t s;
373         uint32_t values[1];
374         int sv[2];
375
376         wm = malloc(sizeof *wm);
377         if (wm == NULL)
378                 return NULL;
379
380         wm->window_hash = wl_hash_table_create();
381         if (wm->window_hash == NULL) {
382                 free(wm);
383                 return NULL;
384         }
385
386         if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
387                 fprintf(stderr, "socketpair failed\n");
388                 wl_hash_table_destroy(wm->window_hash);
389                 free(wm);
390                 return NULL;
391         }
392
393         wl_client_post_event(wxs->client,
394                              &wxs->xserver.object,
395                              XSERVER_CLIENT, sv[1]);
396         wl_client_flush(wxs->client);
397         close(sv[1]);
398         
399         wm->conn = xcb_connect_to_fd(sv[0], NULL);
400         if (xcb_connection_has_error(wm->conn)) {
401                 fprintf(stderr, "xcb_connect_to_fd failed\n");
402                 close(sv[0]);
403                 wl_hash_table_destroy(wm->window_hash);
404                 free(wm);
405                 return NULL;
406         }
407
408         s = xcb_setup_roots_iterator(xcb_get_setup(wm->conn));
409         wm->screen = s.data;
410
411         loop = wl_display_get_event_loop(wxs->wl_display);
412         wm->source =
413                 wl_event_loop_add_fd(loop, sv[0],
414                                      WL_EVENT_READABLE,
415                                      wlsc_wm_handle_event, wm);
416         wl_event_source_check(wm->source);
417
418         wxs_wm_get_resources(wm);
419
420         values[0] =
421                 XCB_EVENT_MASK_STRUCTURE_NOTIFY |
422                 XCB_EVENT_MASK_RESIZE_REDIRECT |
423                 XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
424                 XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
425                 XCB_EVENT_MASK_PROPERTY_CHANGE;
426         xcb_change_window_attributes(wm->conn, wm->screen->root,
427                                      XCB_CW_EVENT_MASK, values);
428
429         xcb_flush(wm->conn);
430         fprintf(stderr, "created wm\n");
431
432         return wm;
433 }
434
435 static void
436 wlsc_xserver_bind(struct wl_client *client,
437                   struct wl_object *global,
438                   uint32_t version)
439 {
440         struct wlsc_xserver *wxs =
441                 container_of(global, struct wlsc_xserver, xserver.object);
442
443         wxs->wm = wlsc_wm_create(wxs);
444         if (wxs == NULL) {
445                 fprintf(stderr, "failed to create wm\n");
446         }
447
448         wl_client_post_event(wxs->client,
449                              &wxs->xserver.object,
450                              XSERVER_LISTEN_SOCKET, wxs->fd);
451 }
452
453 static int
454 wlsc_xserver_handle_event(int listen_fd, uint32_t mask, void *data)
455 {
456         struct wlsc_xserver *mxs = data;
457         char display[8], s[8], logfile[32];
458         int sv[2], flags;
459
460         if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
461                 fprintf(stderr, "socketpair failed\n");
462                 return 1;
463         }
464
465         mxs->process.pid = fork();
466         switch (mxs->process.pid) {
467         case 0:
468                 /* SOCK_CLOEXEC closes both ends, so we need to unset
469                  * the flag on the client fd. */
470                 flags = fcntl(sv[1], F_GETFD);
471                 if (flags != -1)
472                         fcntl(sv[1], F_SETFD, flags & ~FD_CLOEXEC);
473
474                 snprintf(s, sizeof s, "%d", sv[1]);
475                 setenv("WAYLAND_SOCKET", s, 1);
476
477                 snprintf(display, sizeof display, ":%d", mxs->display);
478                 snprintf(logfile, sizeof logfile,
479                          "/tmp/x-log-%d", mxs->display);
480
481                 if (execl("/usr/bin/Xorg",
482                           "/usr/bin/Xorg",
483                           display,
484                           "-wayland",
485                           "-rootless",
486                           "-retro",
487                           "-logfile", logfile,
488                           "-nolisten", "all",
489                           "-terminate",
490                           NULL) < 0)
491                         fprintf(stderr, "exec failed: %m\n");
492                 exit(-1);
493
494         default:
495                 fprintf(stderr, "forked X server, pid %d\n", mxs->process.pid);
496
497                 close(sv[1]);
498                 mxs->client = wl_client_create(mxs->wl_display, sv[0]);
499
500                 wlsc_watch_process(&mxs->process);
501
502                 wl_event_source_remove(mxs->source);
503                 break;
504
505         case -1:
506                 fprintf(stderr, "failed to fork\n");
507                 break;
508         }
509
510         return 1;
511 }
512
513 static void
514 wlsc_xserver_cleanup(struct wlsc_process *process, int status)
515 {
516         struct wlsc_xserver *mxs =
517                 container_of(process, struct wlsc_xserver, process);
518
519         fprintf(stderr, "xserver exited, code %d\n", status);
520         mxs->process.pid = 0;
521         mxs->source =
522                 wl_event_loop_add_fd(mxs->loop, mxs->fd, WL_EVENT_READABLE,
523                                      wlsc_xserver_handle_event, mxs);
524 }
525
526 static void
527 xserver_set_window_id(struct wl_client *client, struct xserver *xserver,
528                       struct wl_surface *surface, uint32_t id)
529 {
530         struct wlsc_xserver *wxs =
531                 container_of(xserver, struct wlsc_xserver, xserver);
532         struct wlsc_wm *wm = wxs->wm;
533         struct wlsc_wm_window *window;
534
535         window = wl_hash_table_lookup(wm->window_hash, id);
536         if (window == NULL) {
537                 fprintf(stderr, "set_window_id for unknown window %d\n", id);
538                 return;
539         }
540
541         fprintf(stderr, "set_window_id %d for surface %p\n", id, surface);
542
543         window->surface = (struct wlsc_surface *) surface;
544         /* FIXME: Do we need a surface destroy listener? */
545 }
546
547 static const struct xserver_interface xserver_implementation = {
548         xserver_set_window_id
549 };
550
551 int
552 wlsc_xserver_init(struct wlsc_compositor *compositor)
553 {
554         struct wl_display *display = compositor->wl_display;
555         struct wlsc_xserver *mxs;
556         char lockfile[256], pid[16], *end;
557         socklen_t size, name_size;
558         pid_t other;
559         int fd;
560
561         mxs = malloc(sizeof *mxs);
562         memset(mxs, 0, sizeof mxs);
563
564         mxs->process.cleanup = wlsc_xserver_cleanup;
565         mxs->wl_display = display;
566         mxs->addr.sun_family = AF_LOCAL;
567         mxs->fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
568         if (mxs->fd < 0) {
569                 free(mxs);
570                 return -1;
571         }
572
573         mxs->display = 0;
574         do {
575                 snprintf(lockfile, sizeof lockfile,
576                          "/tmp/.X%d-lock", mxs->display);
577                 fd = open(lockfile,
578                           O_WRONLY | O_CLOEXEC | O_CREAT | O_EXCL, 0444);
579                 if (fd < 0 && errno == EEXIST) {
580                         fd = open(lockfile, O_CLOEXEC, O_RDONLY);
581                         if (fd < 0 || read(fd, pid, 11) != 11) {
582                                 fprintf(stderr,
583                                         "can't read lock file %s: %s\n",
584                                         lockfile, strerror(errno));
585                                 mxs->display++;
586                                 continue;
587                         }
588
589                         other = strtol(pid, &end, 0);
590                         if (end != pid + 10) {
591                                 fprintf(stderr, "can't parse lock file %s\n",
592                                         lockfile);
593                                 mxs->display++;
594                                 continue;
595                         }
596
597                         if (kill(other, 0) < 0 && errno == ESRCH) {
598                                 /* stale lock file; unlink and try again */
599                                 fprintf(stderr,
600                                         "unlinking stale lock file %s\n",
601                                         lockfile);
602                                 unlink(lockfile);
603                                 continue;
604                         }
605
606                         mxs->display++;
607                         continue;
608                 } else if (fd < 0) {
609                         fprintf(stderr, "failed to create lock file %s: %s\n",
610                                 lockfile, strerror(errno));
611                         close(mxs->fd);
612                         free(mxs);
613                         return -1;
614                 }
615
616                 /* Subtle detail: we use the pid of the wayland
617                  * compositor, not the xserver in the lock file. */
618                 size = snprintf(pid, sizeof pid, "%10d\n", getpid());
619                 write(fd, pid, size);
620                 close(fd);
621
622                 name_size = snprintf(mxs->addr.sun_path,
623                                      sizeof mxs->addr.sun_path,
624                                      "/tmp/.X11-unix/X%d", mxs->display) + 1;
625                 size = offsetof(struct sockaddr_un, sun_path) + name_size;
626                 unlink(mxs->addr.sun_path);
627                 if (bind(mxs->fd, (struct sockaddr *) &mxs->addr, size) < 0) {
628                         fprintf(stderr, "failed to bind to %s (%s)\n",
629                                 mxs->addr.sun_path, strerror(errno));
630                         unlink(lockfile);
631                         close(mxs->fd);
632                         free(mxs);
633                         return -1;
634                 }
635                 break;
636         } while (errno != 0);
637
638         fprintf(stderr, "xserver listening on display :%d\n", mxs->display);
639
640         if (listen(mxs->fd, 1) < 0) {
641                 unlink(mxs->addr.sun_path);
642                 unlink(lockfile);
643                 close(mxs->fd);
644                 free(mxs);
645                 return -1;
646         }
647
648         mxs->loop = wl_display_get_event_loop(display);
649         mxs->source =
650                 wl_event_loop_add_fd(mxs->loop, mxs->fd, WL_EVENT_READABLE,
651                                      wlsc_xserver_handle_event, mxs);
652
653         mxs->xserver.object.interface = &xserver_interface;
654         mxs->xserver.object.implementation =
655                 (void (**)(void)) &xserver_implementation;
656         wl_display_add_object(display, &mxs->xserver.object);
657         wl_display_add_global(display,
658                               &mxs->xserver.object, wlsc_xserver_bind);
659
660         compositor->wxs = mxs;
661
662         return 0;
663 }
664
665 void
666 wlsc_xserver_destroy(struct wlsc_compositor *compositor)
667 {
668         struct wlsc_xserver *wxs = compositor->wxs;
669         char path[256];
670
671         snprintf(path, sizeof path, "/tmp/.X%d-lock", wxs->display);
672         unlink(path);
673         snprintf(path, sizeof path, "/tmp/.X11-unix/X%d", wxs->display);
674         unlink(path);
675         close(wxs->fd);
676         wl_event_source_remove(wxs->source);
677         free(wxs);
678 }