From 757d8aff2757387bcd594e2ee2a27055b366eac3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Kristian=20H=C3=B8gsberg?= Date: Mon, 17 Mar 2014 22:33:29 -0700 Subject: [PATCH] xwayland: Use new Xwayland DDX --- Makefile.am | 6 -- configure.ac | 2 +- protocol/xserver.xml | 18 ----- xwayland/launcher.c | 103 ++++++++++++++----------- xwayland/window-manager.c | 187 ++++++++++++++++++++++++++-------------------- xwayland/xwayland.h | 9 ++- 6 files changed, 175 insertions(+), 150 deletions(-) delete mode 100644 protocol/xserver.xml diff --git a/Makefile.am b/Makefile.am index c2df8b6..a247c3d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -754,11 +754,6 @@ xwayland_la_SOURCES = \ xwayland/launcher.c \ xwayland/hash.c \ xwayland/hash.h -nodist_xwayland_la_SOURCES = \ - protocol/xserver-protocol.c \ - protocol/xserver-server-protocol.h - -BUILT_SOURCES += $(nodist_xwayland_la_SOURCES) endif @@ -967,7 +962,6 @@ BUILT_SOURCES += \ EXTRA_DIST += \ protocol/desktop-shell.xml \ protocol/screenshooter.xml \ - protocol/xserver.xml \ protocol/text.xml \ protocol/input-method.xml \ protocol/workspaces.xml \ diff --git a/configure.ac b/configure.ac index b10ceba..492abce 100644 --- a/configure.ac +++ b/configure.ac @@ -99,7 +99,7 @@ if test x$enable_xwayland = xyes; then AC_ARG_WITH(xserver-path, AS_HELP_STRING([--with-xserver-path=PATH], [Path to X server]), [XSERVER_PATH="$withval"], - [XSERVER_PATH="$bindir/Xorg"]) + [XSERVER_PATH="$bindir/Xwayland"]) AC_SUBST([XSERVER_PATH]) if test x$enable_xwayland_test = xyes; then PKG_CHECK_MODULES([XWAYLAND_TEST], xcb xcb-dri2 libdrm) diff --git a/protocol/xserver.xml b/protocol/xserver.xml deleted file mode 100644 index 9e25f5c..0000000 --- a/protocol/xserver.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/xwayland/launcher.c b/xwayland/launcher.c index 0d49647..f37cbe4 100644 --- a/xwayland/launcher.c +++ b/xwayland/launcher.c @@ -37,16 +37,35 @@ static int +handle_sigusr1(int signal_number, void *data) +{ + struct weston_xserver *wxs = data; + + /* We'd be safer if we actually had the struct + * signalfd_siginfo from the signalfd data and could verify + * this came from Xwayland.*/ + weston_wm_create(wxs, wxs->wm_fd); + wl_event_source_remove(wxs->sigusr1_source); + + return 1; +} + +static int weston_xserver_handle_event(int listen_fd, uint32_t mask, void *data) { struct weston_xserver *wxs = data; - char display[8], s[8]; - int sv[2], client_fd; + char display[8], s[8], abstract_fd[8], unix_fd[8], wm_fd[8]; + int sv[2], wm[2], fd; char *xserver = NULL; struct weston_config_section *section; if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) { - weston_log("socketpair failed\n"); + weston_log("wl connection socketpair failed\n"); + return 1; + } + + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, wm) < 0) { + weston_log("X wm connection socketpair failed\n"); return 1; } @@ -55,29 +74,52 @@ weston_xserver_handle_event(int listen_fd, uint32_t mask, void *data) 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); + fd = dup(sv[1]); + if (fd < 0) + goto fail; + snprintf(s, sizeof s, "%d", fd); setenv("WAYLAND_SOCKET", s, 1); snprintf(display, sizeof display, ":%d", wxs->display); - section = weston_config_get_section(wxs->compositor->config, "xwayland", NULL, NULL); - weston_config_section_get_string(section, "path", &xserver, XSERVER_PATH); + fd = dup(wxs->abstract_fd); + if (fd < 0) + goto fail; + snprintf(abstract_fd, sizeof abstract_fd, "%d", fd); + fd = dup(wxs->unix_fd); + if (fd < 0) + goto fail; + snprintf(unix_fd, sizeof unix_fd, "%d", fd); + fd = dup(wm[1]); + if (fd < 0) + goto fail; + snprintf(wm_fd, sizeof wm_fd, "%d", fd); + + section = weston_config_get_section(wxs->compositor->config, + "xwayland", NULL, NULL); + weston_config_section_get_string(section, "path", + &xserver, XSERVER_PATH); + + /* Ignore SIGUSR1 in the child, which will make the X + * server send SIGUSR1 to the parent (weston) when + * it's done with initialization. During + * initialization the X server will round trip and + * block on the wayland compositor, so avoid making + * blocking requests (like xcb_connect_to_fd) until + * it's done with that. */ + signal(SIGUSR1, SIG_IGN); if (execl(xserver, xserver, display, - "-wayland", "-rootless", - "-retro", - "-nolisten", "all", + "-listen", abstract_fd, + "-listen", unix_fd, + "-wm", wm_fd, "-terminate", NULL) < 0) weston_log("exec failed: %m\n"); - free(xserver); + fail: _exit(EXIT_FAILURE); default: @@ -86,6 +128,9 @@ weston_xserver_handle_event(int listen_fd, uint32_t mask, void *data) close(sv[1]); wxs->client = wl_client_create(wxs->wl_display, sv[0]); + close(wm[1]); + wxs->wm_fd = wm[0]; + weston_watch_process(&wxs->process); wl_event_source_remove(wxs->abstract_source); @@ -153,32 +198,6 @@ weston_xserver_cleanup(struct weston_process *process, int status) } } -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_resource_create(client, &xserver_interface, - 1, id); - wl_resource_set_implementation(wxs->resource, &xserver_implementation, - wxs, NULL); - - wxs->wm = weston_wm_create(wxs); - if (wxs->wm == NULL) { - weston_log("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) { @@ -380,8 +399,8 @@ module_init(struct weston_compositor *compositor, WL_EVENT_READABLE, weston_xserver_handle_event, wxs); - wl_global_create(display, &xserver_interface, 1, wxs, bind_xserver); - + wxs->sigusr1_source = wl_event_loop_add_signal(wxs->loop, SIGUSR1, + handle_sigusr1, wxs); wxs->destroy_listener.notify = weston_xserver_destroy; wl_signal_add(&compositor->destroy_signal, &wxs->destroy_listener); diff --git a/xwayland/window-manager.c b/xwayland/window-manager.c index 1bb9825..c8810a9 100644 --- a/xwayland/window-manager.c +++ b/xwayland/window-manager.c @@ -122,6 +122,7 @@ struct weston_wm_window { xcb_window_t frame_id; struct frame *frame; cairo_surface_t *cairo_surface; + uint32_t surface_id; struct weston_surface *surface; struct shell_surface *shsurf; struct weston_view *view; @@ -146,6 +147,7 @@ struct weston_wm_window { int delete_window; struct wm_size_hints size_hints; struct motif_wm_hints motif_hints; + struct wl_list link; }; static struct weston_wm_window * @@ -154,6 +156,10 @@ get_wm_window(struct weston_surface *surface); static void weston_wm_window_schedule_repaint(struct weston_wm_window *window); +static void +xserver_map_shell_surface(struct weston_wm_window *window, + struct weston_surface *surface); + static int __attribute__ ((format (printf, 1, 2))) wm_log(const char *fmt, ...) { @@ -661,6 +667,26 @@ weston_wm_kill_client(struct wl_listener *listener, void *data) } static void +weston_wm_create_surface(struct wl_listener *listener, void *data) +{ + struct weston_surface *surface = data; + struct weston_wm *wm = + container_of(listener, + struct weston_wm, create_surface_listener); + struct weston_wm_window *window; + + if (wl_resource_get_client(surface->resource) != wm->server->client) + return; + + wl_list_for_each(window, &wm->unpaired_window_list, link) + if (window->surface_id == + wl_resource_get_id(surface->resource)) { + xserver_map_shell_surface(window, surface); + break; + } +} + +static void weston_wm_window_activate(struct wl_listener *listener, void *data) { struct weston_surface *surface = data; @@ -1283,6 +1309,51 @@ weston_wm_window_handle_state(struct weston_wm_window *window, } static void +surface_destroy(struct wl_listener *listener, void *data) +{ + struct weston_wm_window *window = + container_of(listener, + struct weston_wm_window, surface_destroy_listener); + + wm_log("surface for xid %d destroyed\n", window->id); + + /* This should have been freed by the shell. + * Don't try to use it later. */ + window->shsurf = NULL; + window->surface = NULL; + window->view = NULL; +} + +static void +weston_wm_window_handle_surface_id(struct weston_wm_window *window, + xcb_client_message_event_t *client_message) +{ + struct weston_wm *wm = window->wm; + struct wl_resource *resource; + + if (window->surface_id != 0) { + wm_log("already have surface id for window %d\n", window->id); + return; + } + + /* Xwayland will send the wayland requests to create the + * wl_surface before sending this client message. Even so, we + * can end up handling the X event before the wayland requests + * and thus when we try to look up the surface ID, the surface + * hasn't been created yet. In that case put the window on + * the unpaired window list and continue when the surface gets + * created. */ + window->surface_id = client_message->data.data32[0]; + resource = wl_client_get_object(wm->server->client, + window->surface_id); + if (resource) + xserver_map_shell_surface(window, + wl_resource_get_user_data(resource)); + else + wl_list_insert(&wm->unpaired_window_list, &window->link); +} + +static void weston_wm_handle_client_message(struct weston_wm *wm, xcb_generic_event_t *event) { @@ -1305,6 +1376,8 @@ weston_wm_handle_client_message(struct weston_wm *wm, weston_wm_window_handle_moveresize(window, client_message); else if (client_message->type == wm->atom.net_wm_state) weston_wm_window_handle_state(window, client_message); + else if (client_message->type == wm->atom.wl_surface_id) + weston_wm_window_handle_surface_id(window, client_message); } enum cursor_type { @@ -1777,7 +1850,8 @@ weston_wm_get_resources(struct weston_wm *wm) { "XdndStatus", F(atom.xdnd_status) }, { "XdndFinished", F(atom.xdnd_finished) }, { "XdndTypeList", F(atom.xdnd_type_list) }, - { "XdndActionCopy", F(atom.xdnd_action_copy) } + { "XdndActionCopy", F(atom.xdnd_action_copy) }, + { "WL_SURFACE_ID", F(atom.wl_surface_id) } }; #undef F @@ -1899,13 +1973,12 @@ weston_wm_create_wm_window(struct weston_wm *wm) } struct weston_wm * -weston_wm_create(struct weston_xserver *wxs) +weston_wm_create(struct weston_xserver *wxs, int fd) { struct weston_wm *wm; struct wl_event_loop *loop; xcb_screen_iterator_t s; uint32_t values[1]; - int sv[2]; xcb_atom_t supported[3]; wm = zalloc(sizeof *wm); @@ -1919,22 +1992,11 @@ weston_wm_create(struct weston_xserver *wxs) return NULL; } - if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) { - weston_log("socketpair failed\n"); - hash_table_destroy(wm->window_hash); - free(wm); - return NULL; - } - - xserver_send_client(wxs->resource, sv[1]); - wl_client_flush(wl_resource_get_client(wxs->resource)); - close(sv[1]); - /* xcb_connect_to_fd takes ownership of the fd. */ - wm->conn = xcb_connect_to_fd(sv[0], NULL); + wm->conn = xcb_connect_to_fd(fd, NULL); if (xcb_connection_has_error(wm->conn)) { weston_log("xcb_connect_to_fd failed\n"); - close(sv[0]); + close(fd); hash_table_destroy(wm->window_hash); free(wm); return NULL; @@ -1945,7 +2007,7 @@ weston_wm_create(struct weston_xserver *wxs) loop = wl_display_get_event_loop(wxs->wl_display); wm->source = - wl_event_loop_add_fd(loop, sv[0], + wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE, weston_wm_handle_event, wm); wl_event_source_check(wm->source); @@ -1965,8 +2027,6 @@ weston_wm_create(struct weston_xserver *wxs) wm->theme = theme_create(); - weston_wm_create_wm_window(wm); - supported[0] = wm->atom.net_wm_moveresize; supported[1] = wm->atom.net_wm_state; supported[2] = wm->atom.net_wm_state_fullscreen; @@ -1984,6 +2044,9 @@ weston_wm_create(struct weston_xserver *wxs) xcb_flush(wm->conn); + wm->create_surface_listener.notify = weston_wm_create_surface; + wl_signal_add(&wxs->compositor->create_surface_signal, + &wm->create_surface_listener); wm->activate_listener.notify = weston_wm_window_activate; wl_signal_add(&wxs->compositor->activate_signal, &wm->activate_listener); @@ -1993,11 +2056,16 @@ weston_wm_create(struct weston_xserver *wxs) wm->kill_listener.notify = weston_wm_kill_client; wl_signal_add(&wxs->compositor->kill_signal, &wm->kill_listener); + wl_list_init(&wm->unpaired_window_list); weston_wm_create_cursors(wm); weston_wm_window_set_cursor(wm, wm->screen->root, XWM_CURSOR_LEFT_PTR); - weston_log("created wm\n"); + /* Create wm window and take WM_S0 selection last, which + * signals to Xwayland that we're done with setup. */ + weston_wm_create_wm_window(wm); + + weston_log("created wm, root %d\n", wm->screen->root); return wm; } @@ -2018,22 +2086,6 @@ weston_wm_destroy(struct weston_wm *wm) free(wm); } -static void -surface_destroy(struct wl_listener *listener, void *data) -{ - struct weston_wm_window *window = - container_of(listener, - struct weston_wm_window, surface_destroy_listener); - - wm_log("surface for xid %d destroyed\n", window->id); - - /* This should have been freed by the shell. - Don't try to use it later. */ - window->shsurf = NULL; - window->surface = NULL; - window->view = NULL; -} - static struct weston_wm_window * get_wm_window(struct weston_surface *surface) { @@ -2172,15 +2224,32 @@ legacy_fullscreen(struct weston_wm *wm, return 0; } + static void -xserver_map_shell_surface(struct weston_wm *wm, - struct weston_wm_window *window) +xserver_map_shell_surface(struct weston_wm_window *window, + struct weston_surface *surface) { + struct weston_wm *wm = window->wm; struct weston_shell_interface *shell_interface = &wm->server->compositor->shell_interface; struct weston_output *output; struct weston_wm_window *parent; + weston_wm_window_read_properties(window); + + /* A weston_wm_window may have many different surfaces assigned + * throughout its life, so we must make sure to remove the listener + * from the old surface signal list. */ + if (window->surface) + wl_list_remove(&window->surface_destroy_listener.link); + + window->surface = surface; + window->surface_destroy_listener.notify = surface_destroy; + wl_signal_add(&window->surface->destroy_signal, + &window->surface_destroy_listener); + + weston_wm_window_schedule_repaint(window); + if (!shell_interface->create_shell_surface) return; @@ -2224,45 +2293,3 @@ xserver_map_shell_surface(struct weston_wm *wm, shell_interface->set_toplevel(window->shsurf); } } - -static void -xserver_set_window_id(struct wl_client *client, struct wl_resource *resource, - struct wl_resource *surface_resource, uint32_t id) -{ - struct weston_xserver *wxs = wl_resource_get_user_data(resource); - struct weston_wm *wm = wxs->wm; - struct weston_surface *surface = - wl_resource_get_user_data(surface_resource); - struct weston_wm_window *window; - - if (client != wxs->client) - return; - - window = hash_table_lookup(wm->window_hash, id); - if (window == NULL) { - weston_log("set_window_id for unknown window %d\n", id); - return; - } - - wm_log("set_window_id %d for surface %p\n", id, surface); - - weston_wm_window_read_properties(window); - - /* A weston_wm_window may have many different surfaces assigned - * throughout its life, so we must make sure to remove the listener - * from the old surface signal list. */ - if (window->surface) - wl_list_remove(&window->surface_destroy_listener.link); - - window->surface = (struct weston_surface *) surface; - window->surface_destroy_listener.notify = surface_destroy; - wl_signal_add(&surface->destroy_signal, - &window->surface_destroy_listener); - - weston_wm_window_schedule_repaint(window); - xserver_map_shell_surface(wm, window); -} - -const struct xserver_interface xserver_implementation = { - xserver_set_window_id -}; diff --git a/xwayland/xwayland.h b/xwayland/xwayland.h index c684cc5..312c9b2 100644 --- a/xwayland/xwayland.h +++ b/xwayland/xwayland.h @@ -39,7 +39,9 @@ struct weston_xserver { struct wl_event_source *abstract_source; int unix_fd; struct wl_event_source *unix_source; + int wm_fd; int display; + struct wl_event_source *sigusr1_source; struct weston_process process; struct wl_resource *resource; struct wl_client *client; @@ -63,9 +65,11 @@ struct weston_wm { xcb_render_pictforminfo_t format_rgb, format_rgba; xcb_visualid_t visual_id; xcb_colormap_t colormap; + struct wl_listener create_surface_listener; struct wl_listener activate_listener; struct wl_listener transform_listener; struct wl_listener kill_listener; + struct wl_list unpaired_window_list; xcb_window_t selection_window; xcb_window_t selection_owner; @@ -142,6 +146,7 @@ struct weston_wm { xcb_atom_t xdnd_finished; xcb_atom_t xdnd_type_list; xcb_atom_t xdnd_action_copy; + xcb_atom_t wl_surface_id; } atom; }; @@ -158,10 +163,8 @@ int weston_wm_handle_selection_event(struct weston_wm *wm, xcb_generic_event_t *event); -extern const struct xserver_interface xserver_implementation; - struct weston_wm * -weston_wm_create(struct weston_xserver *wxs); +weston_wm_create(struct weston_xserver *wxs, int fd); void weston_wm_destroy(struct weston_wm *wm); -- 2.7.4