summaryrefslogtreecommitdiff
path: root/src/wayland/surface.c
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-11 23:27:41 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-11 23:27:41 +0300
commit472ed3e4e50a165638acecaf071ec3c2c13c451f (patch)
treed1894debde800d8e87d3c242ae6c3f4760c68787 /src/wayland/surface.c
parent8d9f7c7cb39359d62bf28ef1775b944a7dddd6fb (diff)
core: optimize struct layouts, eliminate branches, and fix event loop dispatch
- Fix Wayland event loop lockout by properly decoupling read arming and adding poll-backed dispatching - Support standalone display lifecycle without requiring caller to manage a loop - Eliminate alignment holes across yasl_surface, yasl_display, seat, touch_point, and conn_drag using pahole - Replace branching state/button decoders with compile-time locked LUTs and branchless bitwise operations - Accelerate UTF-8 validation with 64-bit word scanning for ASCII runs
Diffstat (limited to 'src/wayland/surface.c')
-rw-r--r--src/wayland/surface.c118
1 files changed, 99 insertions, 19 deletions
diff --git a/src/wayland/surface.c b/src/wayland/surface.c
index da334e4..5138201 100644
--- a/src/wayland/surface.c
+++ b/src/wayland/surface.c
@@ -83,6 +83,14 @@ static int display_ready(int fd, short revents, void *ud)
else if (wl_display_read_events(c->wl) < 0)
revents |= POLLERR;
}
+ if (revents & POLLOUT) {
+ if (wl_display_flush(c->wl) >= 0) {
+ if (c->loop && c->watch > 0)
+ yasl_loop_set_fd_events(c->loop, c->watch, POLLIN);
+ } else if (errno != EAGAIN) {
+ display_lose(c);
+ }
+ }
if (wl_display_dispatch_pending(c->wl) < 0 ||
(revents & (POLLERR | POLLHUP | POLLNVAL)))
display_lose(c);
@@ -90,35 +98,92 @@ static int display_ready(int fd, short revents, void *ud)
return 0;
}
-void yasl_display_dispatch(struct yasl_display *c)
-{
- if (!c || c->lost || c->reading)
- return;
- display_enter(c);
- if (wl_display_dispatch_pending(c->wl) < 0)
- display_lose(c);
- display_leave(c);
-}
-
-static void display_arm(struct yasl_display *c)
+static bool display_arm(struct yasl_display *c)
{
+ bool had_pending = false;
while (!c->reading && wl_display_prepare_read(c->wl) != 0) {
+ had_pending = true;
if (wl_display_dispatch_pending(c->wl) < 0) {
display_lose(c);
- return;
+ return false;
}
}
c->reading = true;
short events = POLLIN;
if (wl_display_flush(c->wl) < 0) {
if (errno != EAGAIN) {
+ display_cancel_read(c);
display_lose(c);
- return;
+ return false;
}
events |= POLLOUT;
}
- if (c->loop)
+ if (c->loop && c->watch > 0)
yasl_loop_set_fd_events(c->loop, c->watch, events);
+ return had_pending;
+}
+
+static bool display_has_immediate_work(const struct yasl_display *c)
+{
+ if (!c || c->lost) return false;
+ for (struct yasl_surface *w = c->surfaces; w; w = w->conn_next) {
+ if (w->closed) continue;
+ if (w->input.count > 0)
+ return true;
+ if (w->want_draw && !w->frame_cb && w->configured)
+ return true;
+ }
+ return false;
+}
+
+int yasl_display_dispatch_timeout(struct yasl_display *c, int timeout_ms)
+{
+ if (!c || c->lost)
+ return -1;
+
+ display_enter(c);
+
+ if (wl_display_dispatch_pending(c->wl) < 0) {
+ display_lose(c);
+ display_leave(c);
+ return -1;
+ }
+
+ bool had_pending = display_arm(c);
+ if (c->lost) {
+ display_leave(c);
+ return -1;
+ }
+
+ if (had_pending && timeout_ms != 0 && display_has_immediate_work(c)) {
+ timeout_ms = 0;
+ }
+
+ int n = 0;
+ if (c->loop) {
+ n = yasl_loop_step(c->loop, timeout_ms);
+ }
+
+ if (c->reading) {
+ display_cancel_read(c);
+ }
+
+ if (wl_display_dispatch_pending(c->wl) < 0) {
+ display_lose(c);
+ display_leave(c);
+ return -1;
+ }
+
+ display_leave(c);
+ return n;
+}
+
+void yasl_display_dispatch(struct yasl_display *c)
+{
+ if (!c || c->lost)
+ return;
+ int timeout = display_has_immediate_work(c) ? 0 : -1;
+ yasl_display_dispatch_timeout(c, timeout);
}
void yasl_display_flush(struct yasl_display *c)
@@ -130,8 +195,10 @@ void yasl_display_flush(struct yasl_display *c)
next = w->conn_next;
surface_draw_frame(w);
}
- if (!c->lost)
- display_arm(c);
+ if (!c->lost && c->wl) {
+ if (wl_display_flush(c->wl) < 0 && errno != EAGAIN)
+ display_lose(c);
+ }
display_leave(c);
}
@@ -163,6 +230,10 @@ static void display_free(struct yasl_display *c)
if (c->compositor) wl_compositor_destroy(c->compositor);
if (c->registry) wl_registry_destroy(c->registry);
if (c->wl) wl_display_disconnect(c->wl);
+ if (c->owns_loop && c->loop) {
+ yasl_loop_destroy(c->loop);
+ c->loop = NULL;
+ }
free(c->app_id);
free(c);
}
@@ -171,7 +242,13 @@ struct yasl_display *yasl_display_open(struct yasl_loop *loop, const struct yasl
{
struct yasl_display *c = calloc(1, sizeof(*c));
if (!c) return NULL;
- c->loop = loop;
+ if (!loop) {
+ c->loop = yasl_loop_create();
+ c->owns_loop = true;
+ } else {
+ c->loop = loop;
+ }
+ if (!c->loop) goto err;
if (spec) {
c->cbs = spec->cbs;
c->ud = spec->ud;
@@ -189,7 +266,7 @@ struct yasl_display *yasl_display_open(struct yasl_loop *loop, const struct yasl
surface_init_cursor(c);
if (c->loop) {
- c->watch = yasl_loop_add_fd(loop, wl_display_get_fd(c->wl), POLLIN, display_ready, c);
+ c->watch = yasl_loop_add_fd(c->loop, wl_display_get_fd(c->wl), POLLIN, display_ready, c);
if (c->watch <= 0) { c->watch = 0; goto err; }
}
if (display_input_init(c) < 0)
@@ -371,7 +448,10 @@ struct yasl_display *yasl_surface_display(const struct yasl_surface *w)
void yasl_surface_schedule_redraw(struct yasl_surface *w)
{
- if (w) w->want_draw = true;
+ if (!w || w->closed) return;
+ w->want_draw = true;
+ if (w->conn && w->conn->loop)
+ yasl_loop_kick(w->conn->loop);
}
struct yasl_vector2i yasl_surface_size(const struct yasl_surface *w)