Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ● TL;DR
- To find the wl_surface backing an Xwayland X11 Window, you need to:
- 1. Legacy method: Listen for WL_SURFACE_ID ClientMessage on X11 windows (requires SubstructureRedirect on root
- window), extract the surface ID from data.l[0], but beware of race conditions.
- 2. Modern method: Use the xwayland-shell-v1 Wayland protocol with WL_SURFACE_SERIAL ClientMessage to establish a
- robust, race-free association.
- For xscreensaver, this requires becoming a hybrid X11/Wayland compositor to properly map screensaver windows, which
- is a significant architectural change.
- ---
- Detailed Solution
- The Problem
- Xscreensaver currently creates X11 windows that are managed by Xwayland, but these windows have no direct
- connection to Wayland surfaces. Under Wayland, the compositor needs to know which wl_surface corresponds to each
- X11 window to properly manage and display them.
- Method 1: Legacy WL_SURFACE_ID Approach
- When Xwayland creates a wl_surface for an X11 window, it sends a ClientMessage with the WL_SURFACE_ID atom:
- // In xscreensaver-gfx.c or similar
- static void setup_xwayland_surface_tracking(Display *dpy, Window root) {
- // Intern the WL_SURFACE_ID atom
- Atom wl_surface_id_atom = XInternAtom(dpy, "WL_SURFACE_ID", False);
- // Select SubstructureRedirect to receive ClientMessages
- XSetWindowAttributes attrs;
- attrs.event_mask = SubstructureRedirectMask | SubstructureNotifyMask;
- XChangeWindowAttributes(dpy, root, CWEventMask, &attrs);
- }
- // In event loop
- static void handle_wl_surface_id(XClientMessageEvent *event,
- Atom wl_surface_id_atom) {
- if (event->message_type == wl_surface_id_atom) {
- Window x11_window = event->window;
- uint32_t surface_id = event->data.l[0];
- // Store mapping - but beware of race conditions!
- // The surface might already be destroyed
- store_window_surface_mapping(x11_window, surface_id);
- }
- }
- Problems: Race conditions - the wl_surface might be destroyed before the X11 event is processed.
- Method 2: Modern xwayland-shell-v1 Protocol
- This requires xscreensaver to act as a Wayland client and use the xwayland-shell-v1 protocol:
- // New file: wayland-xwayland.c
- #include <wayland-client.h>
- #include "xwayland-shell-v1-client-protocol.h"
- struct xwayland_mapping {
- struct wl_surface *surface;
- Window x11_window;
- uint64_t serial;
- };
- static void handle_wl_surface_serial(XClientMessageEvent *event,
- Atom wl_surface_serial_atom,
- struct xwayland_shell_v1 *xwayland_shell) {
- if (event->message_type == wl_surface_serial_atom) {
- Window x11_window = event->window;
- uint32_t serial_lo = event->data.l[0];
- uint32_t serial_hi = event->data.l[1];
- // Create xwayland surface association
- struct wl_surface *surface = find_surface_for_window(x11_window);
- if (surface && xwayland_shell) {
- struct xwayland_surface_v1 *xwl_surface =
- xwayland_shell_v1_get_xwayland_surface(xwayland_shell, surface);
- xwayland_surface_v1_set_serial(xwl_surface, serial_lo, serial_hi);
- wl_surface_commit(surface);
- }
- }
- }
- Proposed Implementation for xscreensaver
- 1. Detect Xwayland vs regular X11:
- static Bool is_xwayland(Display *dpy) {
- // Check for Xwayland-specific atoms or properties
- Atom xwayland_atom = XInternAtom(dpy, "_XWAYLAND_SIGNATURE", True);
- return (xwayland_atom != None);
- }
- 2. Create hybrid X11/Wayland connection:
- // In driver/wayland-xwayland.c
- struct xwayland_context {
- struct wl_display *wl_display;
- struct xwayland_shell_v1 *xwayland_shell;
- Display *x11_display;
- // Mapping tables
- GHashTable *window_to_surface;
- GHashTable *surface_to_window;
- };
- static struct xwayland_context *
- init_xwayland_context(Display *dpy) {
- struct xwayland_context *ctx = calloc(1, sizeof(*ctx));
- // Connect to Wayland
- ctx->wl_display = wl_display_connect(NULL);
- ctx->x11_display = dpy;
- // Bind xwayland-shell protocol
- // ... registry handling code ...
- return ctx;
- }
- 3. Modify window creation in driver/windows.c:
- // Add after creating X11 window
- if (si->xwayland_context) {
- // Create corresponding Wayland surface
- struct wl_surface *surface =
- wl_compositor_create_surface(si->wayland_compositor);
- // Wait for WL_SURFACE_SERIAL ClientMessage
- // Then associate using xwayland-shell-v1
- }
- Architecture Changes Required
- 1. Dual Protocol Support: xscreensaver needs to connect to both X11 and Wayland simultaneously
- 2. Event Loop Integration: Merge X11 and Wayland event handling
- 3. Surface Management: Track X11 window to wl_surface mappings
- 4. Compositor Role: Act as a minimal Wayland compositor for screensaver surfaces
- Challenges
- 1. Complexity: This essentially makes xscreensaver a hybrid X11/Wayland compositor
- 2. Compatibility: Need to maintain pure X11 mode for non-Wayland systems
- 3. Security: Wayland's security model prevents screen locking without compositor support
- 4. Performance: Double event loop processing might impact responsiveness
- Alternative Approach
- Instead of mapping X11 windows to wl_surface, consider creating native Wayland screensavers:
- - Port screenhacks to use Wayland directly
- - Use wl_shell or xdg_shell for window management
- - Implement screen locking via compositor protocols
- This would be cleaner but requires rewriting all screensaver modules.
Advertisement
Add Comment
Please, Sign In to add comment