diff --git a/src/xwayland/Makefile.am b/src/xwayland/Makefile.am index 6dd248b7..5ca5810b 100644 --- a/src/xwayland/Makefile.am +++ b/src/xwayland/Makefile.am @@ -16,6 +16,7 @@ xserver_launcher_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS) xserver_launcher_la_SOURCES = \ xserver-launcher.c \ selection.c \ + launcher.c \ xserver-protocol.c \ xserver-server-protocol.h \ hash.c \ diff --git a/src/xwayland/launcher.c b/src/xwayland/launcher.c new file mode 100644 index 00000000..d8880bd5 --- /dev/null +++ b/src/xwayland/launcher.c @@ -0,0 +1,378 @@ +/* + * Copyright © 2011 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xwayland.h" +#include "xserver-server-protocol.h" + + +static int +weston_xserver_handle_event(int listen_fd, uint32_t mask, void *data) +{ + struct weston_xserver *mxs = data; + char display[8], s[8]; + int sv[2], client_fd; + + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) { + fprintf(stderr, "socketpair failed\n"); + return 1; + } + + mxs->process.pid = fork(); + switch (mxs->process.pid) { + case 0: + /* SOCK_CLOEXEC closes both ends, so we need to unset + * the flag on the client fd. */ + client_fd = dup(sv[1]); + if (client_fd < 0) + return 1; + + snprintf(s, sizeof s, "%d", client_fd); + setenv("WAYLAND_SOCKET", s, 1); + + snprintf(display, sizeof display, ":%d", mxs->display); + + if (execl(XSERVER_PATH, + XSERVER_PATH, + display, + "-wayland", + "-rootless", + "-retro", + "-nolisten", "all", + "-terminate", + NULL) < 0) + fprintf(stderr, "exec failed: %m\n"); + exit(-1); + + default: + fprintf(stderr, "forked X server, pid %d\n", mxs->process.pid); + + close(sv[1]); + mxs->client = wl_client_create(mxs->wl_display, sv[0]); + + weston_watch_process(&mxs->process); + + wl_event_source_remove(mxs->abstract_source); + wl_event_source_remove(mxs->unix_source); + break; + + case -1: + fprintf(stderr, "failed to fork\n"); + break; + } + + return 1; +} + +static void +weston_xserver_shutdown(struct weston_xserver *wxs) +{ + char path[256]; + + snprintf(path, sizeof path, "/tmp/.X%d-lock", wxs->display); + unlink(path); + snprintf(path, sizeof path, "/tmp/.X11-unix/X%d", wxs->display); + unlink(path); + if (wxs->process.pid == 0) { + wl_event_source_remove(wxs->abstract_source); + wl_event_source_remove(wxs->unix_source); + } + close(wxs->abstract_fd); + close(wxs->unix_fd); + if (wxs->wm) + weston_wm_destroy(wxs->wm); + wxs->loop = NULL; +} + +static void +weston_xserver_cleanup(struct weston_process *process, int status) +{ + struct weston_xserver *mxs = + container_of(process, struct weston_xserver, process); + + mxs->process.pid = 0; + mxs->client = NULL; + mxs->resource = NULL; + + mxs->abstract_source = + wl_event_loop_add_fd(mxs->loop, mxs->abstract_fd, + WL_EVENT_READABLE, + weston_xserver_handle_event, mxs); + + mxs->unix_source = + wl_event_loop_add_fd(mxs->loop, mxs->unix_fd, + WL_EVENT_READABLE, + weston_xserver_handle_event, mxs); + + if (mxs->wm) { + fprintf(stderr, "xserver exited, code %d\n", status); + weston_wm_destroy(mxs->wm); + mxs->wm = NULL; + } else { + /* If the X server crashes before it binds to the + * xserver interface, shut down and don't try + * again. */ + fprintf(stderr, "xserver crashing too fast: %d\n", status); + weston_xserver_shutdown(mxs); + } +} + +static void +bind_xserver(struct wl_client *client, + void *data, uint32_t version, uint32_t id) +{ + struct weston_xserver *wxs = data; + + /* If it's a different client than the xserver we launched, + * don't start the wm. */ + if (client != wxs->client) + return; + + wxs->resource = + wl_client_add_object(client, &xserver_interface, + &xserver_implementation, id, wxs); + + wxs->wm = weston_wm_create(wxs); + if (wxs->wm == NULL) { + fprintf(stderr, "failed to create wm\n"); + } + + xserver_send_listen_socket(wxs->resource, wxs->abstract_fd); + xserver_send_listen_socket(wxs->resource, wxs->unix_fd); +} + +static int +bind_to_abstract_socket(int display) +{ + struct sockaddr_un addr; + socklen_t size, name_size; + int fd; + + fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (fd < 0) + return -1; + + addr.sun_family = AF_LOCAL; + name_size = snprintf(addr.sun_path, sizeof addr.sun_path, + "%c/tmp/.X11-unix/X%d", 0, display); + size = offsetof(struct sockaddr_un, sun_path) + name_size; + if (bind(fd, (struct sockaddr *) &addr, size) < 0) { + fprintf(stderr, "failed to bind to @%s: %s\n", + addr.sun_path + 1, strerror(errno)); + close(fd); + return -1; + } + + if (listen(fd, 1) < 0) { + close(fd); + return -1; + } + + return fd; +} + +static int +bind_to_unix_socket(int display) +{ + struct sockaddr_un addr; + socklen_t size, name_size; + int fd; + + fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (fd < 0) + return -1; + + addr.sun_family = AF_LOCAL; + name_size = snprintf(addr.sun_path, sizeof addr.sun_path, + "/tmp/.X11-unix/X%d", display) + 1; + size = offsetof(struct sockaddr_un, sun_path) + name_size; + unlink(addr.sun_path); + if (bind(fd, (struct sockaddr *) &addr, size) < 0) { + fprintf(stderr, "failed to bind to %s (%s)\n", + addr.sun_path, strerror(errno)); + close(fd); + return -1; + } + + if (listen(fd, 1) < 0) { + unlink(addr.sun_path); + close(fd); + return -1; + } + + return fd; +} + +static int +create_lockfile(int display, char *lockfile, size_t lsize) +{ + char pid[16], *end; + int fd, size; + pid_t other; + + snprintf(lockfile, lsize, "/tmp/.X%d-lock", display); + fd = open(lockfile, O_WRONLY | O_CLOEXEC | O_CREAT | O_EXCL, 0444); + if (fd < 0 && errno == EEXIST) { + fd = open(lockfile, O_CLOEXEC, O_RDONLY); + if (fd < 0 || read(fd, pid, 11) != 11) { + fprintf(stderr, "can't read lock file %s: %s\n", + lockfile, strerror(errno)); + errno = EEXIST; + return -1; + } + + other = strtol(pid, &end, 0); + if (end != pid + 10) { + fprintf(stderr, "can't parse lock file %s\n", + lockfile); + close(fd); + errno = EEXIST; + return -1; + } + + if (kill(other, 0) < 0 && errno == ESRCH) { + /* stale lock file; unlink and try again */ + fprintf(stderr, + "unlinking stale lock file %s\n", lockfile); + close(fd); + if (unlink(lockfile)) + /* If we fail to unlink, return EEXIST + so we try the next display number.*/ + errno = EEXIST; + else + errno = EAGAIN; + return -1; + } + + errno = EEXIST; + return -1; + } else if (fd < 0) { + fprintf(stderr, "failed to create lock file %s: %s\n", + lockfile, strerror(errno)); + return -1; + } + + /* Subtle detail: we use the pid of the wayland + * compositor, not the xserver in the lock file. */ + size = snprintf(pid, sizeof pid, "%10d\n", getpid()); + if (write(fd, pid, size) != size) { + unlink(lockfile); + close(fd); + return -1; + } + + close(fd); + + return 0; +} + +static void +weston_xserver_destroy(struct wl_listener *l, void *data) +{ + struct weston_xserver *wxs = + container_of(l, struct weston_xserver, destroy_listener); + + if (!wxs) + return; + + if (wxs->loop) + weston_xserver_shutdown(wxs); + + free(wxs); +} + +WL_EXPORT int +weston_xserver_init(struct weston_compositor *compositor) +{ + struct wl_display *display = compositor->wl_display; + struct weston_xserver *mxs; + char lockfile[256], display_name[8]; + + mxs = malloc(sizeof *mxs); + memset(mxs, 0, sizeof *mxs); + + mxs->process.cleanup = weston_xserver_cleanup; + mxs->wl_display = display; + mxs->compositor = compositor; + + mxs->display = 0; + + retry: + if (create_lockfile(mxs->display, lockfile, sizeof lockfile) < 0) { + if (errno == EAGAIN) { + goto retry; + } else if (errno == EEXIST) { + mxs->display++; + goto retry; + } else { + free(mxs); + return -1; + } + } + + mxs->abstract_fd = bind_to_abstract_socket(mxs->display); + if (mxs->abstract_fd < 0 && errno == EADDRINUSE) { + mxs->display++; + unlink(lockfile); + goto retry; + } + + mxs->unix_fd = bind_to_unix_socket(mxs->display); + if (mxs->unix_fd < 0) { + unlink(lockfile); + close(mxs->abstract_fd); + free(mxs); + return -1; + } + + snprintf(display_name, sizeof display_name, ":%d", mxs->display); + fprintf(stderr, "xserver listening on display %s\n", display_name); + setenv("DISPLAY", display_name, 1); + + mxs->loop = wl_display_get_event_loop(display); + mxs->abstract_source = + wl_event_loop_add_fd(mxs->loop, mxs->abstract_fd, + WL_EVENT_READABLE, + weston_xserver_handle_event, mxs); + mxs->unix_source = + wl_event_loop_add_fd(mxs->loop, mxs->unix_fd, + WL_EVENT_READABLE, + weston_xserver_handle_event, mxs); + + wl_display_add_global(display, &xserver_interface, mxs, bind_xserver); + + mxs->destroy_listener.notify = weston_xserver_destroy; + wl_signal_add(&compositor->destroy_signal, &mxs->destroy_listener); + + return 0; +} diff --git a/src/xwayland/xserver-launcher.c b/src/xwayland/xserver-launcher.c index 5a302bf6..b05f4ac6 100644 --- a/src/xwayland/xserver-launcher.c +++ b/src/xwayland/xserver-launcher.c @@ -452,30 +452,25 @@ static void weston_wm_window_schedule_repaint(struct weston_wm_window *window); static void -weston_xserver_surface_activate(struct wl_listener *listener, void *data) +weston_wm_window_activate(struct wl_listener *listener, void *data) { struct weston_surface *surface = data; struct weston_wm_window *window = get_wm_window(surface); - struct weston_xserver *wxs = - container_of(listener, - struct weston_xserver, activate_listener); - - if (!wxs->wm) - return; + struct weston_wm *wm = window->wm; if (window) - weston_wm_activate(wxs->wm, window, XCB_TIME_CURRENT_TIME); + weston_wm_activate(wm, window, XCB_TIME_CURRENT_TIME); else - xcb_set_input_focus (wxs->wm->conn, + xcb_set_input_focus (wm->conn, XCB_INPUT_FOCUS_POINTER_ROOT, XCB_NONE, XCB_TIME_CURRENT_TIME); - if (wxs->wm->focus_window) - weston_wm_window_schedule_repaint(wxs->wm->focus_window); - wxs->wm->focus_window = window; - if (wxs->wm->focus_window) - weston_wm_window_schedule_repaint(wxs->wm->focus_window); + if (wm->focus_window) + weston_wm_window_schedule_repaint(wm->focus_window); + wm->focus_window = window; + if (wm->focus_window) + weston_wm_window_schedule_repaint(wm->focus_window); } static int @@ -1026,7 +1021,7 @@ weston_wm_create_wm_window(struct weston_wm *wm) } -static struct weston_wm * +struct weston_wm * weston_wm_create(struct weston_xserver *wxs) { struct wl_seat *seat; @@ -1131,12 +1126,16 @@ weston_wm_create(struct weston_xserver *wxs) wm->selection_listener.notify = weston_wm_set_selection; wl_signal_add(&seat->selection_signal, &wm->selection_listener); + wm->activate_listener.notify = weston_wm_window_activate; + wl_signal_add(&wxs->compositor->activate_signal, + &wm->activate_listener); + fprintf(stderr, "created wm\n"); return wm; } -static void +void weston_wm_destroy(struct weston_wm *wm) { /* FIXME: Free windows in hash. */ @@ -1144,118 +1143,9 @@ weston_wm_destroy(struct weston_wm *wm) xcb_disconnect(wm->conn); wl_event_source_remove(wm->source); wl_list_remove(&wm->selection_listener.link); - free(wm); -} - -static int -weston_xserver_handle_event(int listen_fd, uint32_t mask, void *data) -{ - struct weston_xserver *mxs = data; - char display[8], s[8]; - int sv[2], client_fd; - - if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) { - fprintf(stderr, "socketpair failed\n"); - return 1; - } - - mxs->process.pid = fork(); - switch (mxs->process.pid) { - case 0: - /* SOCK_CLOEXEC closes both ends, so we need to unset - * the flag on the client fd. */ - client_fd = dup(sv[1]); - if (client_fd < 0) - return 1; - - snprintf(s, sizeof s, "%d", client_fd); - setenv("WAYLAND_SOCKET", s, 1); - - snprintf(display, sizeof display, ":%d", mxs->display); - - if (execl(XSERVER_PATH, - XSERVER_PATH, - display, - "-wayland", - "-rootless", - "-retro", - "-nolisten", "all", - "-terminate", - NULL) < 0) - fprintf(stderr, "exec failed: %m\n"); - exit(-1); - - default: - fprintf(stderr, "forked X server, pid %d\n", mxs->process.pid); - - close(sv[1]); - mxs->client = wl_client_create(mxs->wl_display, sv[0]); - - weston_watch_process(&mxs->process); - - wl_event_source_remove(mxs->abstract_source); - wl_event_source_remove(mxs->unix_source); - break; - - case -1: - fprintf(stderr, "failed to fork\n"); - break; - } - - return 1; -} - -static void -weston_xserver_shutdown(struct weston_xserver *wxs) -{ - char path[256]; - - snprintf(path, sizeof path, "/tmp/.X%d-lock", wxs->display); - unlink(path); - snprintf(path, sizeof path, "/tmp/.X11-unix/X%d", wxs->display); - unlink(path); - if (wxs->process.pid == 0) { - wl_event_source_remove(wxs->abstract_source); - wl_event_source_remove(wxs->unix_source); - } - close(wxs->abstract_fd); - close(wxs->unix_fd); - if (wxs->wm) - weston_wm_destroy(wxs->wm); - wxs->loop = NULL; -} - -static void -weston_xserver_cleanup(struct weston_process *process, int status) -{ - struct weston_xserver *mxs = - container_of(process, struct weston_xserver, process); - - mxs->process.pid = 0; - mxs->client = NULL; - mxs->resource = NULL; - - mxs->abstract_source = - wl_event_loop_add_fd(mxs->loop, mxs->abstract_fd, - WL_EVENT_READABLE, - weston_xserver_handle_event, mxs); - - mxs->unix_source = - wl_event_loop_add_fd(mxs->loop, mxs->unix_fd, - WL_EVENT_READABLE, - weston_xserver_handle_event, mxs); + wl_list_remove(&wm->activate_listener.link); - if (mxs->wm) { - fprintf(stderr, "xserver exited, code %d\n", status); - weston_wm_destroy(mxs->wm); - mxs->wm = NULL; - } else { - /* If the X server crashes before it binds to the - * xserver interface, shut down and don't try - * again. */ - fprintf(stderr, "xserver crashing too fast: %d\n", status); - weston_xserver_shutdown(mxs); - } + free(wm); } static void @@ -1341,240 +1231,6 @@ xserver_set_window_id(struct wl_client *client, struct wl_resource *resource, xserver_map_shell_surface(wm, window); } -static const struct xserver_interface xserver_implementation = { +const struct xserver_interface xserver_implementation = { xserver_set_window_id }; - -static void -bind_xserver(struct wl_client *client, - void *data, uint32_t version, uint32_t id) -{ - struct weston_xserver *wxs = data; - - /* If it's a different client than the xserver we launched, - * don't start the wm. */ - if (client != wxs->client) - return; - - wxs->resource = - wl_client_add_object(client, &xserver_interface, - &xserver_implementation, id, wxs); - - wxs->wm = weston_wm_create(wxs); - if (wxs->wm == NULL) { - fprintf(stderr, "failed to create wm\n"); - } - - xserver_send_listen_socket(wxs->resource, wxs->abstract_fd); - xserver_send_listen_socket(wxs->resource, wxs->unix_fd); -} - -static int -bind_to_abstract_socket(int display) -{ - struct sockaddr_un addr; - socklen_t size, name_size; - int fd; - - fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); - if (fd < 0) - return -1; - - addr.sun_family = AF_LOCAL; - name_size = snprintf(addr.sun_path, sizeof addr.sun_path, - "%c/tmp/.X11-unix/X%d", 0, display); - size = offsetof(struct sockaddr_un, sun_path) + name_size; - if (bind(fd, (struct sockaddr *) &addr, size) < 0) { - fprintf(stderr, "failed to bind to @%s: %s\n", - addr.sun_path + 1, strerror(errno)); - close(fd); - return -1; - } - - if (listen(fd, 1) < 0) { - close(fd); - return -1; - } - - return fd; -} - -static int -bind_to_unix_socket(int display) -{ - struct sockaddr_un addr; - socklen_t size, name_size; - int fd; - - fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); - if (fd < 0) - return -1; - - addr.sun_family = AF_LOCAL; - name_size = snprintf(addr.sun_path, sizeof addr.sun_path, - "/tmp/.X11-unix/X%d", display) + 1; - size = offsetof(struct sockaddr_un, sun_path) + name_size; - unlink(addr.sun_path); - if (bind(fd, (struct sockaddr *) &addr, size) < 0) { - fprintf(stderr, "failed to bind to %s (%s)\n", - addr.sun_path, strerror(errno)); - close(fd); - return -1; - } - - if (listen(fd, 1) < 0) { - unlink(addr.sun_path); - close(fd); - return -1; - } - - return fd; -} - -static int -create_lockfile(int display, char *lockfile, size_t lsize) -{ - char pid[16], *end; - int fd, size; - pid_t other; - - snprintf(lockfile, lsize, "/tmp/.X%d-lock", display); - fd = open(lockfile, O_WRONLY | O_CLOEXEC | O_CREAT | O_EXCL, 0444); - if (fd < 0 && errno == EEXIST) { - fd = open(lockfile, O_CLOEXEC, O_RDONLY); - if (fd < 0 || read(fd, pid, 11) != 11) { - fprintf(stderr, "can't read lock file %s: %s\n", - lockfile, strerror(errno)); - errno = EEXIST; - return -1; - } - - other = strtol(pid, &end, 0); - if (end != pid + 10) { - fprintf(stderr, "can't parse lock file %s\n", - lockfile); - close(fd); - errno = EEXIST; - return -1; - } - - if (kill(other, 0) < 0 && errno == ESRCH) { - /* stale lock file; unlink and try again */ - fprintf(stderr, - "unlinking stale lock file %s\n", lockfile); - close(fd); - if (unlink(lockfile)) - /* If we fail to unlink, return EEXIST - so we try the next display number.*/ - errno = EEXIST; - else - errno = EAGAIN; - return -1; - } - - errno = EEXIST; - return -1; - } else if (fd < 0) { - fprintf(stderr, "failed to create lock file %s: %s\n", - lockfile, strerror(errno)); - return -1; - } - - /* Subtle detail: we use the pid of the wayland - * compositor, not the xserver in the lock file. */ - size = snprintf(pid, sizeof pid, "%10d\n", getpid()); - if (write(fd, pid, size) != size) { - unlink(lockfile); - close(fd); - return -1; - } - - close(fd); - - return 0; -} - -static void -weston_xserver_destroy(struct wl_listener *l, void *data) -{ - struct weston_xserver *wxs = - container_of(l, struct weston_xserver, destroy_listener); - - if (!wxs) - return; - - if (wxs->loop) - weston_xserver_shutdown(wxs); - - free(wxs); -} - -WL_EXPORT int -weston_xserver_init(struct weston_compositor *compositor) -{ - struct wl_display *display = compositor->wl_display; - struct weston_xserver *mxs; - char lockfile[256], display_name[8]; - - mxs = malloc(sizeof *mxs); - memset(mxs, 0, sizeof *mxs); - - mxs->process.cleanup = weston_xserver_cleanup; - mxs->wl_display = display; - mxs->compositor = compositor; - - mxs->display = 0; - - retry: - if (create_lockfile(mxs->display, lockfile, sizeof lockfile) < 0) { - if (errno == EAGAIN) { - goto retry; - } else if (errno == EEXIST) { - mxs->display++; - goto retry; - } else { - free(mxs); - return -1; - } - } - - mxs->abstract_fd = bind_to_abstract_socket(mxs->display); - if (mxs->abstract_fd < 0 && errno == EADDRINUSE) { - mxs->display++; - unlink(lockfile); - goto retry; - } - - mxs->unix_fd = bind_to_unix_socket(mxs->display); - if (mxs->unix_fd < 0) { - unlink(lockfile); - close(mxs->abstract_fd); - free(mxs); - return -1; - } - - snprintf(display_name, sizeof display_name, ":%d", mxs->display); - fprintf(stderr, "xserver listening on display %s\n", display_name); - setenv("DISPLAY", display_name, 1); - - mxs->loop = wl_display_get_event_loop(display); - mxs->abstract_source = - wl_event_loop_add_fd(mxs->loop, mxs->abstract_fd, - WL_EVENT_READABLE, - weston_xserver_handle_event, mxs); - mxs->unix_source = - wl_event_loop_add_fd(mxs->loop, mxs->unix_fd, - WL_EVENT_READABLE, - weston_xserver_handle_event, mxs); - - wl_display_add_global(display, &xserver_interface, mxs, bind_xserver); - - mxs->destroy_listener.notify = weston_xserver_destroy; - wl_signal_add(&compositor->destroy_signal, &mxs->destroy_listener); - - - mxs->activate_listener.notify = weston_xserver_surface_activate; - wl_signal_add(&compositor->activate_signal, &mxs->activate_listener); - - return 0; -} diff --git a/src/xwayland/xwayland.h b/src/xwayland/xwayland.h index 78b2be86..72a25ccb 100644 --- a/src/xwayland/xwayland.h +++ b/src/xwayland/xwayland.h @@ -45,7 +45,6 @@ struct weston_xserver { struct wl_client *client; struct weston_compositor *compositor; struct weston_wm *wm; - struct wl_listener activate_listener; struct wl_listener destroy_listener; }; @@ -60,6 +59,7 @@ struct weston_wm { struct weston_wm_window *focus_window; struct theme *theme; xcb_render_pictforminfo_t render_format; + struct wl_listener activate_listener; xcb_window_t selection_window; int incr; @@ -132,3 +132,11 @@ weston_wm_handle_selection_event(struct weston_wm *wm, void weston_wm_set_selection(struct wl_listener *listener, void *data); + +extern const struct xserver_interface xserver_implementation; + +struct weston_wm * +weston_wm_create(struct weston_xserver *wxs); +void +weston_wm_destroy(struct weston_wm *wm); +