summaryrefslogtreecommitdiff
path: root/src/wayland/surface.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/wayland/surface.c')
-rw-r--r--src/wayland/surface.c117
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)