diff options
author | Joshua Ashton <joshua@froggi.es> | 2022-09-24 16:13:04 +0000 |
---|---|---|
committer | Joshua Ashton <joshua@froggi.es> | 2022-12-21 11:13:07 +0000 |
commit | 87e5db75fb4f004d9cf25a6f335ddb8722b9c467 (patch) | |
tree | 372c89408b82f87b85dfcc4b90711911790755ac | |
parent | d1fbee9cf5dcf47a195eec6d56dd1cc720835ecf (diff) | |
download | xserver-87e5db75fb4f004d9cf25a6f335ddb8722b9c467.tar.gz |
xwayland: Implement xwayland_shell_v1
Implements the xwayland_shell protocol which makes the surface
association happen via a shared serial, rather than sharing a wl_surface
resource ID across an X atom.
This solves a race that can happen if the wl_surface
associated with a WL_SURFACE_ID for a window was destroyed before the
update of the atom was processed by the compositor and another surface
(or other object) had taken its id due to recycling.
Closes: #1157
Signed-off-by: Joshua Ashton <joshua@froggi.es>
Reviewed-by: Olivier Fourdan <ofourdan@redhat.com>
-rw-r--r-- | hw/xwayland/meson.build | 3 | ||||
-rw-r--r-- | hw/xwayland/xwayland-screen.c | 5 | ||||
-rw-r--r-- | hw/xwayland/xwayland-screen.h | 2 | ||||
-rw-r--r-- | hw/xwayland/xwayland-window.c | 98 | ||||
-rw-r--r-- | hw/xwayland/xwayland-window.h | 1 | ||||
-rw-r--r-- | meson.build | 2 |
6 files changed, 98 insertions, 13 deletions
diff --git a/hw/xwayland/meson.build b/hw/xwayland/meson.build index 692b0442a..6dddfd63e 100644 --- a/hw/xwayland/meson.build +++ b/hw/xwayland/meson.build @@ -47,6 +47,7 @@ viewporter_xml = join_paths(protodir, 'stable', 'viewporter', 'viewporter.xml') xdg_shell_xml = join_paths(protodir, 'stable', 'xdg-shell', 'xdg-shell.xml') drm_lease_xml = join_paths(protodir, 'staging', 'drm-lease', 'drm-lease-v1.xml') shortcuts_inhibit_xml = join_paths(protodir, 'unstable', 'keyboard-shortcuts-inhibit', 'keyboard-shortcuts-inhibit-unstable-v1.xml') +xwayland_shell_xml = join_paths(protodir, 'staging', 'xwayland-shell', 'xwayland-shell-v1.xml') client_header = generator(scanner, output : '@BASENAME@-client-protocol.h', @@ -74,6 +75,7 @@ srcs += client_header.process(viewporter_xml) srcs += client_header.process(xdg_shell_xml) srcs += client_header.process(drm_lease_xml) srcs += client_header.process(shortcuts_inhibit_xml) +srcs += client_header.process(xwayland_shell_xml) srcs += code.process(relative_xml) srcs += code.process(pointer_xml) srcs += code.process(gestures_xml) @@ -85,6 +87,7 @@ srcs += code.process(viewporter_xml) srcs += code.process(xdg_shell_xml) srcs += code.process(drm_lease_xml) srcs += code.process(shortcuts_inhibit_xml) +srcs += code.process(xwayland_shell_xml) xwayland_glamor = [] eglstream_srcs = [] diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c index 427489690..0e38c1cdf 100644 --- a/hw/xwayland/xwayland-screen.c +++ b/hw/xwayland/xwayland-screen.c @@ -59,6 +59,7 @@ #include "xdg-output-unstable-v1-client-protocol.h" #include "viewporter-client-protocol.h" #include "xdg-shell-client-protocol.h" +#include "xwayland-shell-v1-client-protocol.h" static DevPrivateKeyRec xwl_screen_private_key; static DevPrivateKeyRec xwl_client_private_key; @@ -451,6 +452,10 @@ registry_global(void *data, struct wl_registry *registry, uint32_t id, else if (strcmp(interface, "wp_viewporter") == 0) { xwl_screen->viewporter = wl_registry_bind(registry, id, &wp_viewporter_interface, 1); } + else if (strcmp(interface, "xwayland_shell_v1") == 0 && xwl_screen->rootless) { + xwl_screen->xwayland_shell = + wl_registry_bind(registry, id, &xwayland_shell_v1_interface, 1); + } #ifdef XWL_HAS_GLAMOR else if (xwl_screen->glamor) { xwl_glamor_init_wl_registry(xwl_screen, registry, id, interface, diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h index 3c8eb8270..8ccfc9b4d 100644 --- a/hw/xwayland/xwayland-screen.h +++ b/hw/xwayland/xwayland-screen.h @@ -103,11 +103,13 @@ struct xwl_screen { struct zwp_linux_dmabuf_v1 *dmabuf; struct zxdg_output_manager_v1 *xdg_output_manager; struct wp_viewporter *viewporter; + struct xwayland_shell_v1 *xwayland_shell; struct xorg_list drm_lease_devices; struct xorg_list queued_drm_lease_devices; struct xorg_list drm_leases; struct xwl_output *fixed_output; struct xorg_list pending_wl_surface_destroy; + uint64_t surface_association_serial; uint32_t serial; #define XWL_FORMAT_ARGB8888 (1 << 0) diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c index 2a88c89ea..5c59caaab 100644 --- a/hw/xwayland/xwayland-window.c +++ b/hw/xwayland/xwayland-window.c @@ -45,6 +45,7 @@ #include "viewporter-client-protocol.h" #include "xdg-shell-client-protocol.h" +#include "xwayland-shell-v1-client-protocol.h" #define DELAYED_WL_SURFACE_DESTROY 1000 /* ms */ @@ -438,24 +439,30 @@ xwl_window_init_allow_commits(struct xwl_window *xwl_window) xwl_window_set_allow_commits(xwl_window, TRUE, "no property"); } +static uint32_t +serial_lo(uint64_t value) +{ + return value & 0xFFFFFFFFu; +} + +static uint32_t +serial_hi(uint64_t value) +{ + return value >> 32u; +} + static void -send_surface_id_event(struct xwl_window *xwl_window) +send_window_client_message(struct xwl_window *xwl_window, Atom type_atom, uint64_t value) { - static const char atom_name[] = "WL_SURFACE_ID"; - static Atom type_atom; DeviceIntPtr dev; xEvent e; - if (type_atom == None) - type_atom = MakeAtom(atom_name, strlen(atom_name), TRUE); - e.u.u.type = ClientMessage; e.u.u.detail = 32; e.u.clientMessage.window = xwl_window->window->drawable.id; e.u.clientMessage.u.l.type = type_atom; - e.u.clientMessage.u.l.longs0 = - wl_proxy_get_id((struct wl_proxy *) xwl_window->surface); - e.u.clientMessage.u.l.longs1 = 0; + e.u.clientMessage.u.l.longs0 = serial_lo(value); + e.u.clientMessage.u.l.longs1 = serial_hi(value); e.u.clientMessage.u.l.longs2 = 0; e.u.clientMessage.u.l.longs3 = 0; e.u.clientMessage.u.l.longs4 = 0; @@ -465,6 +472,54 @@ send_surface_id_event(struct xwl_window *xwl_window) &e, 1, SubstructureRedirectMask, NullGrab); } +static void +send_surface_id_event_serial(struct xwl_window *xwl_window) +{ + static const char atom_name[] = "WL_SURFACE_SERIAL"; + static Atom type_atom; + uint64_t serial; + + if (type_atom == None) + type_atom = MakeAtom(atom_name, strlen(atom_name), TRUE); + + serial = ++xwl_window->xwl_screen->surface_association_serial; + + send_window_client_message(xwl_window, type_atom, serial); + xwayland_surface_v1_set_serial(xwl_window->xwayland_surface, + serial_lo(serial), serial_hi(serial)); + wl_surface_commit(xwl_window->surface); + + /* Flush wayland display *after* commit in the new path. */ + wl_display_flush(xwl_window->xwl_screen->display); +} + +static void +send_surface_id_event_legacy(struct xwl_window *xwl_window) +{ + static const char atom_name[] = "WL_SURFACE_ID"; + static Atom type_atom; + uint32_t surface_id; + + if (type_atom == None) + type_atom = MakeAtom(atom_name, strlen(atom_name), TRUE); + + surface_id = wl_proxy_get_id((struct wl_proxy *) xwl_window->surface); + + /* Flush wayland display *before* setting the atom in the legacy path */ + wl_display_flush(xwl_window->xwl_screen->display); + + send_window_client_message(xwl_window, type_atom, (uint64_t)surface_id); +} + +static void +send_surface_id_event(struct xwl_window *xwl_window) +{ + return xwl_window->xwayland_surface + ? send_surface_id_event_serial(xwl_window) + : send_surface_id_event_legacy(xwl_window); + +} + static Bool xwl_window_set_fullscreen(struct xwl_window *xwl_window) { @@ -772,11 +827,14 @@ ensure_surface_for_window(WindowPtr window) goto err; } + if (xwl_screen->xwayland_shell) { + xwl_window->xwayland_surface = xwayland_shell_v1_get_xwayland_surface( + xwl_screen->xwayland_shell, xwl_window->surface); + } + if (!xwl_screen->rootless && !xwl_create_root_surface(xwl_window)) goto err; - wl_display_flush(xwl_screen->display); - send_surface_id_event(xwl_window); wl_surface_set_user_data(xwl_window->surface, xwl_window); @@ -889,7 +947,7 @@ xwl_surface_destroy_callback(OsTimerPtr timer, CARD32 now, void *arg) } static void -release_wl_surface_for_window(struct xwl_window *xwl_window) +release_wl_surface_for_window_legacy_delay(struct xwl_window *xwl_window) { struct xwl_wl_surface *xwl_wl_surface; @@ -916,6 +974,22 @@ release_wl_surface_for_window(struct xwl_window *xwl_window) xwl_surface_destroy_callback, xwl_wl_surface); } +static void +release_wl_surface_for_window_shell(struct xwl_window *xwl_window) +{ + xwayland_surface_v1_destroy(xwl_window->xwayland_surface); + wl_surface_destroy(xwl_window->surface); +} + +static void +release_wl_surface_for_window(struct xwl_window *xwl_window) +{ + if (xwl_window->xwayland_surface) + release_wl_surface_for_window_shell(xwl_window); + else + release_wl_surface_for_window_legacy_delay(xwl_window); +} + Bool xwl_unrealize_window(WindowPtr window) { diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h index 49ef3c1f9..fdeb80c7a 100644 --- a/hw/xwayland/xwayland-window.h +++ b/hw/xwayland/xwayland-window.h @@ -67,6 +67,7 @@ struct xwl_window { #ifdef XWL_HAS_LIBDECOR struct libdecor_frame *libdecor_frame; #endif + struct xwayland_surface_v1 *xwayland_surface; }; struct xwl_window *xwl_window_get(WindowPtr window); diff --git a/meson.build b/meson.build index 0f0a4442a..dc77b85a3 100644 --- a/meson.build +++ b/meson.build @@ -64,7 +64,7 @@ libdrm_req = '>= 2.4.89' libselinux_req = '>= 2.0.86' xext_req = '>= 1.0.99.4' wayland_req = '>= 1.18.0' -wayland_protocols_req = '>= 1.22' +wayland_protocols_req = '>= 1.28' gbm_req = '>= 10.2' xf86dgaproto_req = '>= 2.0.99.1' |