From 7e8bf8d2a81f37303e0c9ae430f1acbff106da22 Mon Sep 17 00:00:00 2001 From: Berke Güzel Date: Wed, 14 Oct 2026 14:16:42 +0300 Subject: Wayland: fix GL thread races, reconnect ordering and sizing bugs - GL swaps on a rendering thread no longer touch frame callbacks or presentation feedback. They set a per-surface flag and wake the loop; the owner thread arms both at its next flush and commits, so the frame callback fires without waiting for the application's next swap. - Clear the offline flag only after the reconnect rebuild succeeds, and not when the connection was lost again during it. - make_current fails with ENOTCONN for a window without a context. Detaching is a no-op when nothing is current or the EGL display is gone. - Window move, resize, window menu and drag start need a pointer button or tablet tip that is still held; otherwise they fail with ESTALE and use that press's serial. Popups fail with ESTALE without an input serial and with ENOTCONN while the display is lost. - An oversized device size shrinks to the buffer limits, keeping the aspect ratio, instead of closing the window. - FIXED_SIZE windows pin xdg min and max on every set_size. The 64px minimum applies only to compositor-suggested sizes, not to application sizes. - The keyboard-enter serial becomes the input serial. Clipboard copy with no keyboard focus fails with ESTALE. - Relative-pointer windows relock after a reconnect rebuild. - errno: EBUSY for an active drag, ENOTSUP for place_under_pointer and for GL without EGL, EINVAL for drag carry without a drag. - Default window title and app ID are "YASL". - Pointer motion and button events carry unrounded device-pixel positions in precise_x/precise_y with precise_position set. Co-Authored-By: Claude Haiku 5.5 --- src/platform/wayland/internal.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src/platform/wayland/internal.h') diff --git a/src/platform/wayland/internal.h b/src/platform/wayland/internal.h index ff1b18f..d5b7de1 100644 --- a/src/platform/wayland/internal.h +++ b/src/platform/wayland/internal.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -79,6 +80,7 @@ struct wl_conn_output { struct pending_press { struct wayland_surface *surface; struct yasl_private_vector2i pos; + struct yasl_private_vector2d precise; int button; bool release; }; @@ -179,6 +181,8 @@ struct seat { struct yasl_private_vector2i pointer_pos; struct yasl_private_vector2i ptr_left_pos; struct yasl_private_vector2i tool_pos; + /* Unrounded device-pixel positions behind the rounded ones above. */ + struct yasl_private_vector2d pointer_precise, ptr_left_precise, tool_precise; struct touch_point touch_points[SEAT_TOUCH_POINTS]; struct press_queue ptr_presses; struct press_queue tool_presses; @@ -212,6 +216,8 @@ struct wayland_display { struct yasl_private_display base; /* 8-byte pointers & 64-bit masks */ struct wl_display *wl; + /* The thread that opened the display: the only one that arms frame callbacks. */ + pthread_t owner; #if YASL_HAS_EGL EGLDisplay egl_display; EGLint egl_api; @@ -363,6 +369,8 @@ struct wayland_surface { bool relative; bool pointer_locked; bool ime_delete_pending; + /* Set by a swap on a rendering thread; the owner arms the frame request at its next flush. */ + atomic_bool frame_deferred; }; @@ -389,6 +397,7 @@ static inline void wl_damage_list(struct wl_surface *s, const struct yasl_privat void surface_update_opaque_region(struct wayland_surface *w); int surface_init_scaling(struct wayland_surface *w); +void surface_arm_deferred(struct wayland_surface *w); uint64_t conn_output_mask(const struct wayland_display *c, const struct wl_output *proxy); uint32_t conn_output_scale_120(const struct wayland_display *c, uint64_t outputs); @@ -425,6 +434,10 @@ void seat_bind(struct wayland_display *c, struct wl_registry *registry, bool seat_remove(struct wayland_display *c, uint32_t name); void seat_destroy(struct seat *s); void seat_note_input(struct seat *s, uint32_t serial); +/* Serial of the latest press while a pointer button or tablet tip is still down, else 0. */ +uint32_t seat_held_press_serial(const struct seat *s); +/* Locks the pointer through the seat that last delivered input, or any seat with a pointer. */ +void surface_lock_preferred(struct wayland_surface *w); void seat_ensure_text_input(struct seat *s); void seat_forget_surface(struct seat *s, struct wayland_surface *w); void seat_clipboard_ensure(struct seat *s); -- cgit v1.2.3