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>
This commit is contained in:
		
							parent
							
								
									d1fbee9cf5
								
							
						
					
					
						commit
						87e5db75fb
					
				| 
						 | 
					@ -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')
 | 
					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')
 | 
					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')
 | 
					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,
 | 
					client_header = generator(scanner,
 | 
				
			||||||
    output : '@BASENAME@-client-protocol.h',
 | 
					    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(xdg_shell_xml)
 | 
				
			||||||
srcs += client_header.process(drm_lease_xml)
 | 
					srcs += client_header.process(drm_lease_xml)
 | 
				
			||||||
srcs += client_header.process(shortcuts_inhibit_xml)
 | 
					srcs += client_header.process(shortcuts_inhibit_xml)
 | 
				
			||||||
 | 
					srcs += client_header.process(xwayland_shell_xml)
 | 
				
			||||||
srcs += code.process(relative_xml)
 | 
					srcs += code.process(relative_xml)
 | 
				
			||||||
srcs += code.process(pointer_xml)
 | 
					srcs += code.process(pointer_xml)
 | 
				
			||||||
srcs += code.process(gestures_xml)
 | 
					srcs += code.process(gestures_xml)
 | 
				
			||||||
| 
						 | 
					@ -85,6 +87,7 @@ srcs += code.process(viewporter_xml)
 | 
				
			||||||
srcs += code.process(xdg_shell_xml)
 | 
					srcs += code.process(xdg_shell_xml)
 | 
				
			||||||
srcs += code.process(drm_lease_xml)
 | 
					srcs += code.process(drm_lease_xml)
 | 
				
			||||||
srcs += code.process(shortcuts_inhibit_xml)
 | 
					srcs += code.process(shortcuts_inhibit_xml)
 | 
				
			||||||
 | 
					srcs += code.process(xwayland_shell_xml)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
xwayland_glamor = []
 | 
					xwayland_glamor = []
 | 
				
			||||||
eglstream_srcs = []
 | 
					eglstream_srcs = []
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,6 +59,7 @@
 | 
				
			||||||
#include "xdg-output-unstable-v1-client-protocol.h"
 | 
					#include "xdg-output-unstable-v1-client-protocol.h"
 | 
				
			||||||
#include "viewporter-client-protocol.h"
 | 
					#include "viewporter-client-protocol.h"
 | 
				
			||||||
#include "xdg-shell-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_screen_private_key;
 | 
				
			||||||
static DevPrivateKeyRec xwl_client_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) {
 | 
					    else if (strcmp(interface, "wp_viewporter") == 0) {
 | 
				
			||||||
        xwl_screen->viewporter = wl_registry_bind(registry, id, &wp_viewporter_interface, 1);
 | 
					        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
 | 
					#ifdef XWL_HAS_GLAMOR
 | 
				
			||||||
    else if (xwl_screen->glamor) {
 | 
					    else if (xwl_screen->glamor) {
 | 
				
			||||||
        xwl_glamor_init_wl_registry(xwl_screen, registry, id, interface,
 | 
					        xwl_glamor_init_wl_registry(xwl_screen, registry, id, interface,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -103,11 +103,13 @@ struct xwl_screen {
 | 
				
			||||||
    struct zwp_linux_dmabuf_v1 *dmabuf;
 | 
					    struct zwp_linux_dmabuf_v1 *dmabuf;
 | 
				
			||||||
    struct zxdg_output_manager_v1 *xdg_output_manager;
 | 
					    struct zxdg_output_manager_v1 *xdg_output_manager;
 | 
				
			||||||
    struct wp_viewporter *viewporter;
 | 
					    struct wp_viewporter *viewporter;
 | 
				
			||||||
 | 
					    struct xwayland_shell_v1 *xwayland_shell;
 | 
				
			||||||
    struct xorg_list drm_lease_devices;
 | 
					    struct xorg_list drm_lease_devices;
 | 
				
			||||||
    struct xorg_list queued_drm_lease_devices;
 | 
					    struct xorg_list queued_drm_lease_devices;
 | 
				
			||||||
    struct xorg_list drm_leases;
 | 
					    struct xorg_list drm_leases;
 | 
				
			||||||
    struct xwl_output *fixed_output;
 | 
					    struct xwl_output *fixed_output;
 | 
				
			||||||
    struct xorg_list pending_wl_surface_destroy;
 | 
					    struct xorg_list pending_wl_surface_destroy;
 | 
				
			||||||
 | 
					    uint64_t surface_association_serial;
 | 
				
			||||||
    uint32_t serial;
 | 
					    uint32_t serial;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define XWL_FORMAT_ARGB8888 (1 << 0)
 | 
					#define XWL_FORMAT_ARGB8888 (1 << 0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,6 +45,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "viewporter-client-protocol.h"
 | 
					#include "viewporter-client-protocol.h"
 | 
				
			||||||
#include "xdg-shell-client-protocol.h"
 | 
					#include "xdg-shell-client-protocol.h"
 | 
				
			||||||
 | 
					#include "xwayland-shell-v1-client-protocol.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DELAYED_WL_SURFACE_DESTROY 1000 /* ms */
 | 
					#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");
 | 
					        xwl_window_set_allow_commits(xwl_window, TRUE, "no property");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static uint32_t
 | 
				
			||||||
send_surface_id_event(struct xwl_window *xwl_window)
 | 
					serial_lo(uint64_t value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return value & 0xFFFFFFFFu;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint32_t
 | 
				
			||||||
 | 
					serial_hi(uint64_t value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return value >> 32u;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					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;
 | 
					    DeviceIntPtr dev;
 | 
				
			||||||
    xEvent e;
 | 
					    xEvent e;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (type_atom == None)
 | 
					 | 
				
			||||||
        type_atom = MakeAtom(atom_name, strlen(atom_name), TRUE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    e.u.u.type = ClientMessage;
 | 
					    e.u.u.type = ClientMessage;
 | 
				
			||||||
    e.u.u.detail = 32;
 | 
					    e.u.u.detail = 32;
 | 
				
			||||||
    e.u.clientMessage.window = xwl_window->window->drawable.id;
 | 
					    e.u.clientMessage.window = xwl_window->window->drawable.id;
 | 
				
			||||||
    e.u.clientMessage.u.l.type = type_atom;
 | 
					    e.u.clientMessage.u.l.type = type_atom;
 | 
				
			||||||
    e.u.clientMessage.u.l.longs0 =
 | 
					    e.u.clientMessage.u.l.longs0 = serial_lo(value);
 | 
				
			||||||
        wl_proxy_get_id((struct wl_proxy *) xwl_window->surface);
 | 
					    e.u.clientMessage.u.l.longs1 = serial_hi(value);
 | 
				
			||||||
    e.u.clientMessage.u.l.longs1 = 0;
 | 
					 | 
				
			||||||
    e.u.clientMessage.u.l.longs2 = 0;
 | 
					    e.u.clientMessage.u.l.longs2 = 0;
 | 
				
			||||||
    e.u.clientMessage.u.l.longs3 = 0;
 | 
					    e.u.clientMessage.u.l.longs3 = 0;
 | 
				
			||||||
    e.u.clientMessage.u.l.longs4 = 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);
 | 
					                          &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
 | 
					static Bool
 | 
				
			||||||
xwl_window_set_fullscreen(struct xwl_window *xwl_window)
 | 
					xwl_window_set_fullscreen(struct xwl_window *xwl_window)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -772,11 +827,14 @@ ensure_surface_for_window(WindowPtr window)
 | 
				
			||||||
        goto err;
 | 
					        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))
 | 
					    if (!xwl_screen->rootless && !xwl_create_root_surface(xwl_window))
 | 
				
			||||||
        goto err;
 | 
					        goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wl_display_flush(xwl_screen->display);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    send_surface_id_event(xwl_window);
 | 
					    send_surface_id_event(xwl_window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wl_surface_set_user_data(xwl_window->surface, 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
 | 
					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;
 | 
					    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);
 | 
					                 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
 | 
					Bool
 | 
				
			||||||
xwl_unrealize_window(WindowPtr window)
 | 
					xwl_unrealize_window(WindowPtr window)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -67,6 +67,7 @@ struct xwl_window {
 | 
				
			||||||
#ifdef XWL_HAS_LIBDECOR
 | 
					#ifdef XWL_HAS_LIBDECOR
 | 
				
			||||||
    struct libdecor_frame *libdecor_frame;
 | 
					    struct libdecor_frame *libdecor_frame;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					    struct xwayland_surface_v1 *xwayland_surface;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct xwl_window *xwl_window_get(WindowPtr window);
 | 
					struct xwl_window *xwl_window_get(WindowPtr window);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,7 +64,7 @@ libdrm_req = '>= 2.4.89'
 | 
				
			||||||
libselinux_req = '>= 2.0.86'
 | 
					libselinux_req = '>= 2.0.86'
 | 
				
			||||||
xext_req = '>= 1.0.99.4'
 | 
					xext_req = '>= 1.0.99.4'
 | 
				
			||||||
wayland_req = '>= 1.18.0'
 | 
					wayland_req = '>= 1.18.0'
 | 
				
			||||||
wayland_protocols_req = '>= 1.22'
 | 
					wayland_protocols_req = '>= 1.28'
 | 
				
			||||||
gbm_req = '>= 10.2'
 | 
					gbm_req = '>= 10.2'
 | 
				
			||||||
xf86dgaproto_req = '>= 2.0.99.1'
 | 
					xf86dgaproto_req = '>= 2.0.99.1'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue