diff options
Diffstat (limited to 'src/wayland/surface.c')
| -rw-r--r-- | src/wayland/surface.c | 117 |
1 files changed, 98 insertions, 19 deletions
diff --git a/src/wayland/surface.c b/src/wayland/surface.c index ced7d89..8de4992 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,91 @@ static int display_ready(int fd, short revents, void *ud) return 0; } -void wayland_display_dispatch(struct wayland_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 wayland_display *c) +static bool 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; + 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 inline 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); + if (unlikely((ready_draw | has_input) & !w->closed)) + return true; + } + return false; +} + +int wayland_display_dispatch_timeout(struct wayland_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 wayland_display_dispatch(struct wayland_display *c) +{ + if (unlikely(!c || c->lost)) + return; + int timeout = (display_has_immediate_work(c) || yasl_loop_is_running(c->loop)) ? 0 : -1; + wayland_display_dispatch_timeout(c, timeout); } void wayland_display_flush(struct wayland_display *c) @@ -130,8 +194,10 @@ void wayland_display_flush(struct wayland_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 +229,10 @@ static void display_free(struct wayland_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); } @@ -172,7 +242,13 @@ struct wayland_display *wayland_display_open(struct yasl_loop *loop, const struc struct wayland_display *c = calloc(1, sizeof(*c)); if (!c) return NULL; c->base.ops = &yasl_wayland_backend; - 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; @@ -190,7 +266,7 @@ struct wayland_display *wayland_display_open(struct yasl_loop *loop, const struc 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) @@ -374,7 +450,10 @@ struct wayland_display *wayland_surface_display(const struct wayland_surface *w) void wayland_surface_schedule_redraw(struct wayland_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 wayland_surface_size(const struct wayland_surface *w) |
