summaryrefslogtreecommitdiff
path: root/src/platform/wayland/surface.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/platform/wayland/surface.c')
-rw-r--r--src/platform/wayland/surface.c147
1 files changed, 57 insertions, 90 deletions
diff --git a/src/platform/wayland/surface.c b/src/platform/wayland/surface.c
index cc0c715..bc37c10 100644
--- a/src/platform/wayland/surface.c
+++ b/src/platform/wayland/surface.c
@@ -49,7 +49,7 @@ static void display_lose(struct wayland_display *c)
report_display_error(c);
display_cancel_read(c);
if (c->loop && c->watch > 0)
- yasl_private_loop_del_fd(c->loop, c->watch);
+ yasl_loop_del_fd(c->loop, c->watch);
c->watch = 0;
c->depth++;
conn_drag_end(c);
@@ -62,7 +62,7 @@ static void display_lose(struct wayland_display *c)
yasl_private_display_notify_event(&c->base, YASL_PRIVATE_EVENT_DISPLAY_LOST);
c->reconnect_delay_ns = YASL_PRIVATE_MS_TO_NS(100);
if (c->loop && !c->reconnect_timer)
- c->reconnect_timer = yasl_private_loop_add_timer(c->loop, c->reconnect_delay_ns, reconnect_tick, c);
+ c->reconnect_timer = yasl_loop_add_timer(c->loop, c->reconnect_delay_ns, reconnect_tick, c);
}
void surface_fail(struct wayland_surface *w)
@@ -73,43 +73,18 @@ void surface_fail(struct wayland_surface *w)
yasl_private_surface_notify_close(&w->base);
}
-static int display_ready(int fd, short revents, void *ud)
+/* The display fd is read in wayland_display_check, before any callback. */
+static void display_ready(void *ud, int fd, short revents)
{
- (void)fd;
- struct wayland_display *c = ud;
- if (c->lost)
- return 0;
- c->depth++;
- if (c->reading) {
- c->reading = false;
- if (!(revents & POLLIN))
- wl_display_cancel_read(c->wl);
- 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_private_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);
- display_leave(c);
- return 0;
+ (void)ud; (void)fd; (void)revents;
}
-static bool display_arm(struct wayland_display *c)
+static void display_arm(struct wayland_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 false;
+ return;
}
}
c->reading = true;
@@ -118,74 +93,65 @@ static bool display_arm(struct wayland_display *c)
if (errno != EAGAIN) {
display_cancel_read(c);
display_lose(c);
- return false;
+ return;
}
events |= POLLOUT;
}
- if (c->loop && c->watch > 0)
- yasl_private_loop_set_fd_events(c->loop, c->watch, events);
- return had_pending;
+ yasl_loop_set_fd_events(c->loop, c->watch, events);
}
-static inline bool display_has_immediate_work(const struct wayland_display *c)
+/* A draw that cannot proceed now, for want of a buffer or a configure, is not
+ * work: the release or configure that unblocks it schedules it again. */
+static bool display_has_immediate_work(const struct wayland_display *c)
{
- if (unlikely(!c || c->lost)) return false;
- for (struct wayland_surface *w = c->surfaces; w; w = w->conn_next) {
- bool ready_draw = w->want_draw & (w->frame_cb == NULL) & w->configured;
- bool has_input = (w->input.count > 0 || w->input.reset_pending);
- if (unlikely((ready_draw | has_input) & !w->closed))
+ for (const struct wayland_surface *w = c->surfaces; w; w = w->conn_next)
+ if (surface_draw_ready(w))
return true;
- }
return false;
}
-int wayland_display_dispatch_timeout(struct wayland_display *c, int timeout_ms)
+/* Before the wait: dispatch what libwayland already holds, draw due surfaces,
+ * and arm the read. While lost, only the reconnect timer runs. */
+bool wayland_display_prepare(struct wayland_display *c)
{
- if (!c)
- return -1;
-
+ if (c->lost)
+ return false;
c->depth++;
- if (c->lost) {
- /* Reconnect attempts run as a loop timer. */
- int n = c->loop ? yasl_private_loop_step(c->loop, timeout_ms) : 0;
- display_leave(c);
- return n;
- }
-
/* Losing the connection is reported as DISPLAY_LOST, not as a failed wait. */
- if (wl_display_dispatch_pending(c->wl) < 0) {
+ if (wl_display_dispatch_pending(c->wl) < 0)
display_lose(c);
- display_leave(c);
- return 0;
- }
-
- display_arm(c);
- if (c->lost) {
- display_leave(c);
- return 0;
- }
-
- if (timeout_ms != 0 && display_has_immediate_work(c)) {
- timeout_ms = 0;
- }
-
- int n = 0;
- if (c->loop) {
- n = yasl_private_loop_step(c->loop, timeout_ms);
- }
+ if (!c->lost)
+ wayland_display_flush(c);
+ if (!c->lost)
+ display_arm(c);
+ bool ready = !c->lost && display_has_immediate_work(c);
+ display_leave(c);
+ return ready;
+}
- if (c->reading) {
- display_cancel_read(c);
+/* After the wait, before any callback: finish the read prepare armed, so
+ * callbacks may do roundtrips, and dispatch what it brought. */
+void wayland_display_check(struct wayland_display *c)
+{
+ if (!c->reading)
+ return;
+ c->depth++;
+ short revents = yasl_private_loop_revents(c->loop, c->watch);
+ c->reading = false;
+ if (!(revents & POLLIN))
+ wl_display_cancel_read(c->wl);
+ else if (wl_display_read_events(c->wl) < 0)
+ revents |= POLLERR;
+ if (revents & POLLOUT) {
+ if (wl_display_flush(c->wl) >= 0)
+ yasl_loop_set_fd_events(c->loop, c->watch, POLLIN);
+ else if (errno != EAGAIN)
+ display_lose(c);
}
-
- if (c->wl && wl_display_dispatch_pending(c->wl) < 0) {
+ if (!c->lost && (wl_display_dispatch_pending(c->wl) < 0 ||
+ (revents & (POLLERR | POLLHUP | POLLNVAL))))
display_lose(c);
- display_leave(c);
- return 0;
- }
-
display_leave(c);
- return n;
}
void wayland_display_flush(struct wayland_display *c)
@@ -212,7 +178,7 @@ static void connection_release(struct wayland_display *c)
for (struct wayland_surface *w = c->surfaces; w; w = w->conn_next)
surface_release_native(w);
conn_drag_end(c);
- if (c->loop && c->watch > 0) yasl_private_loop_del_fd(c->loop, c->watch);
+ if (c->loop && c->watch > 0) yasl_loop_del_fd(c->loop, c->watch);
c->watch = 0;
if (c->wl) display_cancel_read(c);
while (c->seats)
@@ -271,7 +237,7 @@ static bool connection_open(struct wayland_display *c)
return false;
surface_init_cursor(c);
if (c->loop) {
- c->watch = yasl_private_loop_add_fd(c->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; return false; }
}
return display_input_init(c) == 0;
@@ -329,10 +295,10 @@ static uint64_t reconnect_tick(void *ud, yasl_private_timer_id id, uint64_t inte
static void display_free(struct wayland_display *c)
{
connection_release(c);
- if (c->loop && c->reconnect_timer) yasl_private_loop_del_timer(c->loop, c->reconnect_timer);
+ if (c->loop && c->reconnect_timer) yasl_loop_del_timer(c->loop, c->reconnect_timer);
if (c->xkb_ctx) xkb_context_unref(c->xkb_ctx);
if (c->owns_loop && c->loop) {
- yasl_private_loop_destroy(c->loop);
+ yasl_loop_destroy(c->loop);
c->loop = NULL;
c->base.loop = NULL;
}
@@ -340,14 +306,15 @@ static void display_free(struct wayland_display *c)
free(c);
}
-struct wayland_display *wayland_display_open(struct yasl_private_loop *loop, const struct yasl_private_display_spec *spec)
+struct wayland_display *wayland_display_open(struct yasl_loop *loop, const struct yasl_private_display_spec *spec)
{
struct wayland_display *c = calloc(1, sizeof(*c));
if (!c) return NULL;
c->owner = pthread_self();
c->base.ops = &yasl_private_wayland_backend;
+ c->base.reconnects = true;
if (!loop) {
- c->loop = yasl_private_loop_create();
+ c->loop = yasl_loop_create();
c->owns_loop = true;
} else {
c->loop = loop;
@@ -605,8 +572,8 @@ void wayland_surface_schedule_redraw(struct wayland_surface *w)
return;
}
w->want_draw = true;
- if (w->conn && w->conn->loop)
- yasl_private_loop_kick(w->conn->loop);
+ if (w->conn)
+ yasl_private_loop_wake(w->conn->loop);
}
struct yasl_private_geometry wayland_surface_geometry(const struct wayland_surface *w)