summaryrefslogtreecommitdiff
path: root/src/platform/wayland/surface.c
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-14 14:16:42 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-14 14:17:37 +0300
commit7e8bf8d2a81f37303e0c9ae430f1acbff106da22 (patch)
tree274cc707238f930395f87e74322c7c139811fe46 /src/platform/wayland/surface.c
parent26f644f51709cc9f6cdd8060e7561498f2bb465d (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.c67
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;