summaryrefslogtreecommitdiff
path: root/src/platform/wayland
diff options
context:
space:
mode:
Diffstat (limited to 'src/platform/wayland')
-rw-r--r--src/platform/wayland/api.h5
-rw-r--r--src/platform/wayland/backend.c20
-rw-r--r--src/platform/wayland/buffer.c8
-rw-r--r--src/platform/wayland/clipboard.c25
-rw-r--r--src/platform/wayland/clipboard.h2
-rw-r--r--src/platform/wayland/internal.h4
-rw-r--r--src/platform/wayland/keyboard.c9
-rw-r--r--src/platform/wayland/pointer.c2
-rw-r--r--src/platform/wayland/surface.c147
9 files changed, 105 insertions, 117 deletions
diff --git a/src/platform/wayland/api.h b/src/platform/wayland/api.h
index 69f61b1..1fb6d5c 100644
--- a/src/platform/wayland/api.h
+++ b/src/platform/wayland/api.h
@@ -6,10 +6,11 @@
struct wayland_display;
struct wayland_surface;
-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);
void wayland_display_close(struct wayland_display *d);
uint32_t wayland_display_caps(const struct wayland_display *d);
-int wayland_display_dispatch_timeout(struct wayland_display *d, int timeout_ms);
+bool wayland_display_prepare(struct wayland_display *d);
+void wayland_display_check(struct wayland_display *d);
void wayland_display_flush(struct wayland_display *d);
int wayland_display_modifiers(const struct wayland_display *d);
bool wayland_display_copy_text(struct wayland_display *d, enum yasl_private_selection sel, const char *text);
diff --git a/src/platform/wayland/backend.c b/src/platform/wayland/backend.c
index 3ff696c..f6207ed 100644
--- a/src/platform/wayland/backend.c
+++ b/src/platform/wayland/backend.c
@@ -2,7 +2,7 @@
#include "platform/freedesktop/dbus.h"
#include <errno.h>
-static struct yasl_private_display *impl_display_open(struct yasl_private_loop *loop, const struct yasl_private_display_spec *spec)
+static struct yasl_private_display *impl_display_open(struct yasl_loop *loop, const struct yasl_private_display_spec *spec)
{
struct wayland_display *result = wayland_display_open(loop, spec);
return result ? &result->base : NULL;
@@ -18,9 +18,19 @@ static uint32_t impl_display_caps(const struct yasl_private_display *d)
return wayland_display_caps((const struct wayland_display *)d);
}
-static int impl_display_dispatch_timeout(struct yasl_private_display *d, int timeout_ms)
+static bool impl_display_prepare(struct yasl_private_display *d)
{
- return wayland_display_dispatch_timeout((struct wayland_display *)d, timeout_ms);
+ return wayland_display_prepare((struct wayland_display *)d);
+}
+
+static void impl_display_check(struct yasl_private_display *d)
+{
+ wayland_display_check((struct wayland_display *)d);
+}
+
+static bool impl_surface_frame_in_flight(const struct yasl_surface *s)
+{
+ return ((const struct wayland_surface *)s)->frame_cb != NULL;
}
static void impl_display_flush(struct yasl_private_display *d)
@@ -497,7 +507,9 @@ const struct yasl_private_backend_ops yasl_private_wayland_backend = {
.display_open = impl_display_open,
.display_close = impl_display_close,
.display_caps = impl_display_caps,
- .display_dispatch_timeout = impl_display_dispatch_timeout,
+ .display_prepare = impl_display_prepare,
+ .display_check = impl_display_check,
+ .surface_frame_in_flight = impl_surface_frame_in_flight,
.display_flush = impl_display_flush,
.display_modifiers = impl_display_modifiers,
.display_double_click_ms = impl_display_double_click_ms,
diff --git a/src/platform/wayland/buffer.c b/src/platform/wayland/buffer.c
index 7ff4bd0..4f42b60 100644
--- a/src/platform/wayland/buffer.c
+++ b/src/platform/wayland/buffer.c
@@ -335,6 +335,7 @@ static void frame_done(void *data, struct wl_callback *cb, uint32_t ms)
w->clock.source = YASL_PRIVATE_TIMING_FRAME_CALLBACK;
}
+ yasl_private_surface_notify_frame_shown(&w->base);
if (w->base.presenter != YASL_PRIVATE_PRESENTER_CPU)
yasl_private_surface_notify_refresh(&w->base);
else if (w->want_draw)
@@ -550,6 +551,13 @@ bool wayland_surface_read_pixels(struct wayland_surface *w, uint32_t *out, size_
return yasl_private_copy_frame(b->pixels, (struct yasl_private_vector2i){b->width, b->height}, out, cap, size);
}
+bool surface_draw_ready(const struct wayland_surface *w)
+{
+ return w->want_draw && w->configured && !w->closed &&
+ w->base.presenter == YASL_PRIVATE_PRESENTER_CPU &&
+ buffer_pick_free_index(w->buffers, w->cur) >= 0;
+}
+
void surface_draw_frame(struct wayland_surface *w)
{
if (w->closed || !w->configured || w->base.presenter != YASL_PRIVATE_PRESENTER_CPU)
diff --git a/src/platform/wayland/clipboard.c b/src/platform/wayland/clipboard.c
index 9a75953..9c019a1 100644
--- a/src/platform/wayland/clipboard.c
+++ b/src/platform/wayland/clipboard.c
@@ -48,7 +48,7 @@ struct clipboard {
struct offer *drag_offer;
struct primary_offer *primary_selection;
struct primary_offer *primary_pending_offers;
- struct yasl_private_loop *loop;
+ struct yasl_loop *loop;
struct transfer *transfers;
char *text;
char *primary_text;
@@ -106,9 +106,9 @@ static void transfer_end(struct transfer *t, bool complete)
struct transfer **p = &owner->transfers;
while (*p && *p != t) p = &(*p)->next;
if (*p) *p = t->next;
- yasl_private_loop_del_fd(owner->loop, t->id);
+ yasl_loop_del_fd(owner->loop, t->id);
if (t->timeout)
- yasl_private_loop_del_timer(owner->loop, t->timeout);
+ yasl_loop_del_timer(owner->loop, t->timeout);
close(t->fd);
if (t->drop) {
if (complete && wl_data_offer_get_version(t->drop->proxy) >=
@@ -133,10 +133,10 @@ static void transfer_end(struct transfer *t, bool complete)
free(t);
}
-static int transfer_io(int fd, short events, void *ud)
+static void transfer_io(void *ud, int fd, short events)
{
struct transfer *t = ud;
- if (events & (POLLERR | POLLNVAL)) { transfer_end(t, false); return 0; }
+ if (events & (POLLERR | POLLNVAL)) { transfer_end(t, false); return; }
if (t->sending) {
ssize_t n = write(fd, t->text + t->offset, t->len - t->offset);
if (n > 0) t->offset += (size_t)n;
@@ -146,9 +146,9 @@ static int transfer_io(int fd, short events, void *ud)
if (t->capacity - t->len < 4096) {
size_t capacity = t->capacity ? t->capacity * 2 : 8192;
if (capacity > CLIPBOARD_TEXT_MAX) capacity = CLIPBOARD_TEXT_MAX;
- if (capacity <= t->len) { transfer_end(t, false); return 0; }
+ if (capacity <= t->len) { transfer_end(t, false); return; }
char *text = realloc(t->text, capacity);
- if (!text) { transfer_end(t, false); return 0; }
+ if (!text) { transfer_end(t, false); return; }
t->text = text;
t->capacity = capacity;
}
@@ -160,7 +160,6 @@ static int transfer_io(int fd, short events, void *ud)
transfer_end(t, valid);
} else if (errno != EAGAIN && errno != EINTR) transfer_end(t, false);
}
- return 0;
}
static struct transfer *start_transfer_text(struct clipboard *c, int fd, bool sending,
@@ -176,12 +175,12 @@ static struct transfer *start_transfer_text(struct clipboard *c, int fd, bool se
if (!t->text) { close(fd); free(t); return NULL; }
t->len = strlen(t->text);
}
- t->id = yasl_private_loop_add_fd(c->loop, fd, sending ? POLLOUT : POLLIN, transfer_io, t);
- if (t->id < 0) { close(fd); free(t->text); free(t); return NULL; }
- t->timeout = yasl_private_loop_add_timer(c->loop, CLIPBOARD_TRANSFER_TIMEOUT_NS,
+ t->id = yasl_loop_add_fd(c->loop, fd, sending ? POLLOUT : POLLIN, transfer_io, t);
+ if (t->id <= 0) { close(fd); free(t->text); free(t); return NULL; }
+ t->timeout = yasl_loop_add_timer(c->loop, CLIPBOARD_TRANSFER_TIMEOUT_NS,
transfer_timeout, t);
if (!t->timeout) {
- yasl_private_loop_del_fd(c->loop, t->id);
+ yasl_loop_del_fd(c->loop, t->id);
close(fd);
free(t->text);
free(t);
@@ -522,7 +521,7 @@ struct wl_data_device *clipboard_data_device(const struct clipboard *c)
}
struct clipboard *clipboard_create(struct wl_display *display, struct wl_data_device_manager *manager,
- struct wl_seat *seat, struct yasl_private_loop *loop,
+ struct wl_seat *seat, struct yasl_loop *loop,
clipboard_receive_fn receive, void *ud)
{
if (!manager || !seat) return NULL;
diff --git a/src/platform/wayland/clipboard.h b/src/platform/wayland/clipboard.h
index 7ab1719..738d32e 100644
--- a/src/platform/wayland/clipboard.h
+++ b/src/platform/wayland/clipboard.h
@@ -19,7 +19,7 @@ typedef void (*clipboard_receive_fn)(const char *, size_t, bool uri_list,
enum yasl_private_transfer_status, void *);
struct clipboard *clipboard_create(struct wl_display *, struct wl_data_device_manager *,
- struct wl_seat *, struct yasl_private_loop *,
+ struct wl_seat *, struct yasl_loop *,
clipboard_receive_fn, void *);
void clipboard_destroy(struct clipboard *);
bool clipboard_set_seat(struct clipboard *, struct wl_seat *);
diff --git a/src/platform/wayland/internal.h b/src/platform/wayland/internal.h
index d5b7de1..a580e71 100644
--- a/src/platform/wayland/internal.h
+++ b/src/platform/wayland/internal.h
@@ -249,7 +249,7 @@ struct wayland_display {
struct wp_fifo_manager_v1 *fifo_mgr;
struct wp_commit_timing_manager_v1 *commit_timing_mgr;
struct xkb_context *xkb_ctx;
- struct yasl_private_loop *loop;
+ struct yasl_loop *loop;
char *app_id;
struct xdg_toplevel_drag_manager_v1 *toplevel_drag_mgr;
struct conn_drag drag;
@@ -405,6 +405,8 @@ void conn_destroy_outputs(struct wayland_display *c);
void surface_follow_outputs(struct wayland_surface *w);
uint64_t conn_pres_to_mono(const struct wayland_display *c, uint64_t ns);
uint64_t conn_mono_to_pres(const struct wayland_display *c, uint64_t ns);
+/* True when surface_draw_frame would draw now. */
+bool surface_draw_ready(const struct wayland_surface *w);
void surface_draw_frame(struct wayland_surface *w);
void wayland_surface_arm_frame(struct wayland_surface *w);
void surface_fail(struct wayland_surface *w);
diff --git a/src/platform/wayland/keyboard.c b/src/platform/wayland/keyboard.c
index cf6d56c..294f553 100644
--- a/src/platform/wayland/keyboard.c
+++ b/src/platform/wayland/keyboard.c
@@ -336,23 +336,22 @@ static void keyboard_key(void *data, struct wl_keyboard *keyboard,
}
}
-static int keyboard_repeat_ready(int fd, short revents, void *data)
+static void keyboard_repeat_ready(void *data, int fd, short revents)
{
struct seat *s = data;
uint64_t count;
- if (!(revents & POLLIN) || read(fd, &count, sizeof(count)) != sizeof(count)) return 0;
+ if (!(revents & POLLIN) || read(fd, &count, sizeof(count)) != sizeof(count)) return;
struct wayland_surface *w = s->keyboard_focus;
if (!w) {
keyboard_repeat_stop(s);
- return 0;
+ return;
}
if (count > 32) count = 32;
while (count-- && s->repeat_held && s->repeat_rate > 0) {
if (!keyboard_dispatch_key(s, w, s->repeat_key, YASL_KEY_REPEAT))
keyboard_repeat_stop(s);
}
- return 0;
}
static void keyboard_modifiers(void *data, struct wl_keyboard *keyboard,
@@ -391,7 +390,7 @@ int keyboard_repeat_init(struct seat *s)
if (s->repeat_fd >= 0) return 0;
s->repeat_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
if (s->repeat_fd < 0) return -1;
- s->repeat_watch = yasl_private_loop_add_fd(s->conn->loop, s->repeat_fd, POLLIN,
+ s->repeat_watch = yasl_loop_add_fd(s->conn->loop, s->repeat_fd, POLLIN,
keyboard_repeat_ready, s);
if (s->repeat_watch <= 0) {
s->repeat_watch = 0;
diff --git a/src/platform/wayland/pointer.c b/src/platform/wayland/pointer.c
index 571bb12..6cf2710 100644
--- a/src/platform/wayland/pointer.c
+++ b/src/platform/wayland/pointer.c
@@ -1552,7 +1552,7 @@ void seat_destroy(struct seat *s)
}
seat_drop_touch(s);
clipboard_destroy(s->clipboard);
- if (s->repeat_watch > 0) yasl_private_loop_del_fd(c->loop, s->repeat_watch);
+ if (s->repeat_watch > 0) yasl_loop_del_fd(c->loop, s->repeat_watch);
if (s->repeat_fd >= 0) close(s->repeat_fd);
if (s->cursor_viewport) wp_viewport_destroy(s->cursor_viewport);
if (s->cursor_surface) wl_surface_destroy(s->cursor_surface);
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)