diff options
| author | Berke Güzel <wenekar1@gmail.com> | 2026-10-14 14:16:42 +0300 |
|---|---|---|
| committer | Berke Güzel <wenekar1@gmail.com> | 2026-10-14 14:17:37 +0300 |
| commit | 7e8bf8d2a81f37303e0c9ae430f1acbff106da22 (patch) | |
| tree | 274cc707238f930395f87e74322c7c139811fe46 /src/platform/wayland/surface.c | |
| parent | 26f644f51709cc9f6cdd8060e7561498f2bb465d (diff) | |
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 <noreply@anthropic.com>
Diffstat (limited to 'src/platform/wayland/surface.c')
| -rw-r--r-- | src/platform/wayland/surface.c | 67 |
1 files changed, 50 insertions, 17 deletions
diff --git a/src/platform/wayland/surface.c b/src/platform/wayland/surface.c index 2b72317..cc0c715 100644 --- a/src/platform/wayland/surface.c +++ b/src/platform/wayland/surface.c @@ -45,7 +45,7 @@ static void display_lose(struct wayland_display *c) return; c->lost = true; c->stale = true; - c->base.offline = true; + atomic_store(&c->base.offline, true); report_display_error(c); display_cancel_read(c); if (c->loop && c->watch > 0) @@ -195,6 +195,7 @@ void wayland_display_flush(struct wayland_display *c) c->depth++; for (struct wayland_surface *w = c->surfaces, *next; w; w = next) { next = w->conn_next; + surface_arm_deferred(w); surface_draw_frame(w); } if (!c->lost && c->wl) { @@ -290,6 +291,10 @@ static void display_rebuild(struct wayland_display *c) if (w->base.presenter == YASL_PRIVATE_PRESENTER_GL && !w->closed && !w->gl_built && !surface_build_gl(w)) surface_fail(w); #endif + /* Seats announced their pointers before these surfaces existed, so lock them now. */ + for (struct wayland_surface *w = c->surfaces; w && !c->lost; w = w->conn_next) + if (!w->closed && w->base.pointer_mode == YASL_PRIVATE_POINTER_RELATIVE) + surface_lock_preferred(w); for (struct wayland_surface *w = c->surfaces; w && !c->lost; w = w->conn_next) if (!w->closed) yasl_private_surface_notify_refresh(&w->base); } @@ -312,9 +317,11 @@ static uint64_t reconnect_tick(void *ud, yasl_private_timer_id id, uint64_t inte } c->reconnect_timer = 0; c->lost = false; - c->base.offline = false; yasl_private_display_notify_event(&c->base, YASL_PRIVATE_EVENT_DISPLAY_RESTORED); display_rebuild(c); + /* Windows exist again only after the rebuild; a loss during it stays offline. */ + if (!c->lost) + atomic_store(&c->base.offline, false); display_leave(c); return 0; } @@ -337,6 +344,7 @@ struct wayland_display *wayland_display_open(struct yasl_private_loop *loop, con { struct wayland_display *c = calloc(1, sizeof(*c)); if (!c) return NULL; + c->owner = pthread_self(); c->base.ops = &yasl_private_wayland_backend; if (!loop) { c->loop = yasl_private_loop_create(); @@ -499,6 +507,7 @@ void surface_release_native(struct wayland_surface *w) w->base.presenter = YASL_PRIVATE_PRESENTER_NONE; w->configured = w->has_pending_serial = w->has_shown = false; w->frame_active = w->want_draw = false; + atomic_store(&w->frame_deferred, false); w->outputs = 0; } @@ -520,10 +529,10 @@ struct wayland_surface *wayland_surface_create_toplevel(struct wayland_display * w->base.presenter = (spec->external_gpu && !(spec->flags & YASL_PRIVATE_SURFACE_CPU)) ? YASL_PRIVATE_PRESENTER_NONE : YASL_PRIVATE_PRESENTER_CPU; wayland_surface_set_callbacks(w, NULL, NULL); - wayland_surface_set_title(w, spec->title ? spec->title : "yasl_private_app"); + wayland_surface_set_title(w, spec->title ? spec->title : "YASL"); w->cursor = YASL_PRIVATE_CURSOR_TEXT; - w->req_width = width; - w->req_height = height; + w->floating_width = width; + w->floating_height = height; w->logical_width = width; w->logical_height = height; w->scale_120 = YASL_PRIVATE_SCALE_UNIT; @@ -613,31 +622,55 @@ void wayland_surface_set_background_color(struct wayland_surface *w, uint32_t bg (void)w; (void)bg; } +/* The serial of the press a window request cites; it must still be held. */ +static uint32_t held_press_serial(struct wayland_surface *s, struct seat **seat) +{ + *seat = s->conn->active_seat ? s->conn->active_seat : s->conn->seats; + uint32_t serial = seat_held_press_serial(*seat); + if (!serial || !(*seat)->proxy) { + errno = ESTALE; + return 0; + } + return serial; +} + bool wayland_surface_start_interactive_move(struct wayland_surface *s) { - if (!s || !s->toplevel || !s->conn) return false; - struct seat *seat = s->conn->active_seat ? s->conn->active_seat : s->conn->seats; - if (!seat || !seat->proxy || !seat->press_serial) return false; - xdg_toplevel_move(s->toplevel, seat->proxy, seat->press_serial); + if (!s || !s->toplevel || !s->conn) { + errno = EINVAL; + return false; + } + struct seat *seat; + uint32_t serial = held_press_serial(s, &seat); + if (!serial) return false; + xdg_toplevel_move(s->toplevel, seat->proxy, serial); return true; } bool wayland_surface_start_interactive_resize(struct wayland_surface *s, enum yasl_private_resize_edge edge) { - if (!s || !s->toplevel || !s->conn || edge == YASL_PRIVATE_EDGE_NONE) return false; - struct seat *seat = s->conn->active_seat ? s->conn->active_seat : s->conn->seats; - if (!seat || !seat->proxy || !seat->press_serial) return false; - xdg_toplevel_resize(s->toplevel, seat->proxy, seat->press_serial, (uint32_t)edge); + if (!s || !s->toplevel || !s->conn || edge == YASL_PRIVATE_EDGE_NONE) { + errno = EINVAL; + return false; + } + struct seat *seat; + uint32_t serial = held_press_serial(s, &seat); + if (!serial) return false; + xdg_toplevel_resize(s->toplevel, seat->proxy, serial, (uint32_t)edge); return true; } bool wayland_surface_show_window_menu(struct wayland_surface *s, struct yasl_private_vector2i pos) { - if (!s || !s->toplevel || !s->conn) return false; - struct seat *seat = s->conn->active_seat ? s->conn->active_seat : s->conn->seats; - if (!seat || !seat->proxy || !seat->press_serial) return false; + if (!s || !s->toplevel || !s->conn) { + errno = EINVAL; + return false; + } + struct seat *seat; + uint32_t serial = held_press_serial(s, &seat); + if (!serial) return false; uint32_t scale = s->scale_120 ? s->scale_120 : YASL_PRIVATE_SCALE_UNIT; - xdg_toplevel_show_window_menu(s->toplevel, seat->proxy, seat->press_serial, + xdg_toplevel_show_window_menu(s->toplevel, seat->proxy, serial, yasl_private_scale_to_logical(pos.x, scale), yasl_private_scale_to_logical(pos.y, scale)); return true; |
