summaryrefslogtreecommitdiff
path: root/src/wayland
diff options
context:
space:
mode:
Diffstat (limited to 'src/wayland')
-rw-r--r--src/wayland/buffer.c9
-rw-r--r--src/wayland/clipboard.c32
-rw-r--r--src/wayland/clipboard.h5
-rw-r--r--src/wayland/drag.c12
-rw-r--r--src/wayland/internal.h34
-rw-r--r--src/wayland/keyboard.c6
-rw-r--r--src/wayland/pointer.c8
-rw-r--r--src/wayland/surface.c13
8 files changed, 50 insertions, 69 deletions
diff --git a/src/wayland/buffer.c b/src/wayland/buffer.c
index 76f6c0e..3f9cf84 100644
--- a/src/wayland/buffer.c
+++ b/src/wayland/buffer.c
@@ -278,8 +278,10 @@ static void frame_done(void *data, struct wl_callback *cb, uint32_t ms)
w->frame_cb = NULL;
uint64_t now = yasl_loop_now_ns();
- if (!w->conn->pres_clock_known)
+ if (!w->conn->pres_clock_known) {
yasl_clock_presented(&w->clock, yasl_clock_extend_ms(ms, now), w->sample_refresh);
+ w->clock.source = YASL_TIMING_FRAME_CALLBACK;
+ }
if (w->want_draw)
wayland_surface_schedule_redraw(w);
@@ -358,6 +360,7 @@ static void presented(void *data, struct wp_presentation_feedback *fb,
(((uint64_t)tv_sec_hi << 32) | tv_sec_lo) * 1000000000ull + tv_nsec);
if (refresh) w->clock.refresh_ns = refresh;
w->clock.last_present_ns = ns;
+ w->clock.source = YASL_TIMING_PRESENTATION;
}
(void)fb;
feedback_destroy(feedback);
@@ -444,7 +447,7 @@ bool wayland_surface_present(struct wayland_surface *w, const struct yasl_frameb
if (!w || w->closed || !w->frame_active || w->frame_presented || !fb ||
!damage || fb->pixels != w->frame.target.pixels ||
fb->size.x != w->width || fb->size.y != w->height ||
- fb->buffer != w->cur)
+ fb->buffer != w->cur || fb->native_drawable || fb->transaction)
return false;
w->damage = *damage;
@@ -485,6 +488,7 @@ void surface_draw_frame(struct wayland_surface *w)
w->frame = (struct yasl_frame){
.surface = &w->base,
.target = {
+ .generation = yasl_frame_begin(&w->base),
.pixels = w->buffers[idx].pixels,
.size = { .x = w->width, .y = w->height },
.buffer = idx,
@@ -544,6 +548,7 @@ struct yasl_timing wayland_surface_timing(const struct wayland_surface *w)
.last_present_ns = w->clock.last_present_ns,
.next_present_ns = yasl_clock_next_present_ns(&w->clock),
.frames_skipped = w->frames_skipped,
+ .source = w->clock.source,
};
yasl_clock_resize_stats(&w->clock, &t.resize);
return t;
diff --git a/src/wayland/clipboard.c b/src/wayland/clipboard.c
index 0e6ce33..7df1a70 100644
--- a/src/wayland/clipboard.c
+++ b/src/wayland/clipboard.c
@@ -134,10 +134,8 @@ static int transfer_io(int fd, short events, void *ud)
memcpy(t->text + t->len, buf, (size_t)n);
t->len += n;
} else if (n == 0) {
- if (t->len) {
- t->owner->receive(t->text, t->len, t->uri_list,
- t->drop_surface, t->owner->ud);
- }
+ t->owner->receive(t->text ? t->text : "", t->len, t->uri_list,
+ t->drop_surface, t->owner->ud);
transfer_end(t, true);
} else if (errno != EAGAIN && errno != EINTR) transfer_destroy(t);
}
@@ -556,24 +554,22 @@ void clipboard_copy(struct clipboard *c, const char *text, uint32_t serial)
wl_data_device_set_selection(c->device, c->source, serial);
}
-void clipboard_paste(struct clipboard *c)
+void clipboard_paste(struct clipboard *c, struct wl_surface *target)
{
if (!c || !c->device || !c->selection || !c->selection->mime) return;
int fds[2];
if (pipe2(fds, O_CLOEXEC) < 0) return;
wl_data_offer_receive(c->selection->proxy, c->selection->mime, fds[1]);
close(fds[1]);
- start_transfer(c, fds[0], false, false);
+ struct transfer *t = start_transfer(c, fds[0], false, false);
+ if (t) t->drop_surface = target;
wl_display_flush(c->display);
}
void clipboard_copy_primary(struct clipboard *c, const char *text, uint32_t serial)
{
if (!c || !text || !serial) return;
- if (!c->primary_device || !c->primary_manager) {
- clipboard_copy(c, text, serial);
- return;
- }
+ if (!c->primary_device || !c->primary_manager) return;
char *copy = strdup(text);
if (!copy) return;
if (c->primary_source) zwp_primary_selection_source_v1_destroy(c->primary_source);
@@ -589,7 +585,7 @@ void clipboard_copy_primary(struct clipboard *c, const char *text, uint32_t seri
zwp_primary_selection_device_v1_set_selection(c->primary_device, c->primary_source, serial);
}
-void clipboard_paste_primary(struct clipboard *c)
+void clipboard_paste_primary(struct clipboard *c, struct wl_surface *target)
{
if (!c) return;
if (c->primary_device && c->primary_selection && c->primary_selection->mime) {
@@ -598,11 +594,21 @@ void clipboard_paste_primary(struct clipboard *c)
zwp_primary_selection_offer_v1_receive(c->primary_selection->proxy,
c->primary_selection->mime, fds[1]);
close(fds[1]);
- start_transfer(c, fds[0], false, false);
+ struct transfer *t = start_transfer(c, fds[0], false, false);
+ if (t) t->drop_surface = target;
wl_display_flush(c->display);
return;
}
- clipboard_paste(c);
+}
+
+void clipboard_forget_surface(struct clipboard *c, struct wl_surface *surface)
+{
+ if (!c || !surface) return;
+ for (struct transfer *t = c->transfers, *next; t; t = next) {
+ next = t->next;
+ if (t->drop_surface == surface) transfer_destroy(t);
+ }
+ if (c->drag_surface == surface) c->drag_surface = NULL;
}
void clipboard_destroy(struct clipboard *c)
diff --git a/src/wayland/clipboard.h b/src/wayland/clipboard.h
index 6ea75c6..9fefa8e 100644
--- a/src/wayland/clipboard.h
+++ b/src/wayland/clipboard.h
@@ -24,9 +24,10 @@ void clipboard_destroy(struct clipboard *);
bool clipboard_set_seat(struct clipboard *, struct wl_seat *);
void clipboard_set_primary_manager(struct clipboard *, struct zwp_primary_selection_device_manager_v1 *);
void clipboard_copy(struct clipboard *, const char *, uint32_t);
-void clipboard_paste(struct clipboard *);
+void clipboard_paste(struct clipboard *, struct wl_surface *target);
+void clipboard_forget_surface(struct clipboard *, struct wl_surface *);
void clipboard_copy_primary(struct clipboard *, const char *, uint32_t);
-void clipboard_paste_primary(struct clipboard *);
+void clipboard_paste_primary(struct clipboard *, struct wl_surface *target);
typedef void (*clipboard_drag_fn)(enum yasl_drag_event, struct wl_surface *on,
double x, double y, void *);
diff --git a/src/wayland/drag.c b/src/wayland/drag.c
index 7c15002..989dbb6 100644
--- a/src/wayland/drag.c
+++ b/src/wayland/drag.c
@@ -90,11 +90,11 @@ static void drag_clear(struct wayland_display *c, bool ended)
static void drag_finish(struct wayland_display *c, enum yasl_drag_end how, bool ended)
{
- const struct yasl_drag_listener *l = c->drag.listener;
+ struct yasl_drag_listener l = c->drag.listener;
void *ud = c->drag.ud;
drag_clear(c, ended);
- if (l && l->end)
- l->end(ud, how);
+ if (l.end)
+ l.end(ud, how);
}
void conn_drag_end(struct wayland_display *c)
@@ -111,7 +111,7 @@ static void source_cancelled(void *ud, struct wl_data_source *s)
{
(void)s;
struct wayland_display *c = ud;
- bool released = c->drag.dropped || !c->drag.carrying;
+ bool released = c->drag.dropped;
drag_finish(c, released ? YASL_DRAG_DROPPED : YASL_DRAG_CANCELLED, true);
}
@@ -171,7 +171,7 @@ bool wayland_display_drag_start(struct wayland_display *c, struct wayland_surfac
}
c->drag.source = s;
c->drag.seat = seat;
- c->drag.listener = l;
+ c->drag.listener = *l;
c->drag.ud = ud;
wl_data_source_add_listener(s, &source_listener, c);
wl_data_source_offer(s, clipboard_drag_mime());
@@ -190,7 +190,7 @@ bool wayland_display_drag_start(struct wayland_display *c, struct wayland_surfac
void wayland_display_drag_cancel(struct wayland_display *c)
{
if (c && c->drag.source)
- drag_clear(c, false);
+ drag_finish(c, YASL_DRAG_CANCELLED, false);
}
bool wayland_surface_drag_carry(struct wayland_surface *w, struct yasl_vector2i offset)
diff --git a/src/wayland/internal.h b/src/wayland/internal.h
index cba5096..ccfd2dc 100644
--- a/src/wayland/internal.h
+++ b/src/wayland/internal.h
@@ -100,7 +100,7 @@ struct conn_drag {
struct wl_data_source *source;
struct xdg_toplevel_drag_v1 *toplevel;
struct drag_icon icon;
- const struct yasl_drag_listener *listener;
+ struct yasl_drag_listener listener;
void *ud;
struct seat *seat;
uint32_t scale_120;
@@ -192,36 +192,7 @@ struct seat {
bool touch_scrolling;
};
-#define YASL_QUEUE_CAP 256
-#define YASL_QUEUE_MASK (YASL_QUEUE_CAP - 1)
-struct input_queue {
- struct yasl_input_event events[YASL_QUEUE_CAP];
- int head;
- int tail;
- int count;
-};
-
-static inline void input_queue_push(struct input_queue *q, const struct yasl_input_event *ev)
-{
- if (unlikely(q->count >= YASL_QUEUE_CAP)) return;
- q->events[q->tail] = *ev;
- q->tail = (q->tail + 1) & YASL_QUEUE_MASK;
- q->count++;
-}
-
-static inline bool input_queue_pop(struct input_queue *q, struct yasl_input_event *ev)
-{
- if (unlikely(q->count <= 0)) return false;
- *ev = q->events[q->head];
- q->head = (q->head + 1) & YASL_QUEUE_MASK;
- q->count--;
- return true;
-}
-
-static inline void input_queue_clear(struct input_queue *q)
-{
- q->head = q->tail = q->count = 0;
-}
+#include "common/input.h"
struct wayland_display {
struct yasl_display base;
@@ -257,7 +228,6 @@ struct wayland_display {
struct xdg_toplevel_drag_manager_v1 *toplevel_drag_mgr;
struct conn_drag drag;
struct wayland_surface *surfaces;
- struct wayland_surface *paste_target;
struct wayland_surface *dead;
/* 4-byte integers */
diff --git a/src/wayland/keyboard.c b/src/wayland/keyboard.c
index 6bdd58c..f7e2691 100644
--- a/src/wayland/keyboard.c
+++ b/src/wayland/keyboard.c
@@ -374,11 +374,11 @@ void wayland_display_paste(struct wayland_display *c, enum yasl_selection sel, s
struct seat *s = c ? conn_active_seat(c) : NULL;
if (!s || !s->clipboard)
return;
- c->paste_target = target;
+ if (!target || target->closed) return;
if (sel == YASL_PRIMARY)
- clipboard_paste_primary(s->clipboard);
+ clipboard_paste_primary(s->clipboard, target->surface);
else
- clipboard_paste(s->clipboard);
+ clipboard_paste(s->clipboard, target->surface);
}
bool wayland_surface_input_poll(struct wayland_surface *w, struct yasl_input_event *ev)
diff --git a/src/wayland/pointer.c b/src/wayland/pointer.c
index d434047..3b3ad73 100644
--- a/src/wayland/pointer.c
+++ b/src/wayland/pointer.c
@@ -1032,10 +1032,9 @@ static void clipboard_received(const char *text, size_t len, bool uri_list,
{
struct seat *s = ud;
struct wayland_display *c = s->conn;
- struct wayland_surface *w = on ? surface_root(conn_surface_for(c, on)) : NULL;
- if (!w)
- w = c->paste_target ? c->paste_target : s->keyboard_focus;
- if (!len || !w) return;
+ struct wayland_surface *w = conn_surface_for(c, on);
+ if (uri_list) w = surface_root(w);
+ if (!w || w->closed) return;
struct yasl_input_event ev = {
.surface = &w->base,
.kind = uri_list ? YASL_INPUT_DROP_FILES : YASL_INPUT_PASTE,
@@ -1216,6 +1215,7 @@ void seat_bind(struct wayland_display *c, struct wl_registry *registry,
void seat_forget_surface(struct seat *s, struct wayland_surface *w)
{
+ clipboard_forget_surface(s->clipboard, w->surface);
struct wayland_surface **refs[] = {
&s->pointer_focus, &s->keyboard_focus,
&s->tablet_focus, &s->ime_focus, &s->focus_leaving, &s->ptr_left,
diff --git a/src/wayland/surface.c b/src/wayland/surface.c
index 8de4992..ef355ab 100644
--- a/src/wayland/surface.c
+++ b/src/wayland/surface.c
@@ -128,7 +128,7 @@ 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);
+ bool has_input = (w->input.count > 0 || w->input.reset_pending);
if (unlikely((ready_draw | has_input) & !w->closed))
return true;
}
@@ -250,7 +250,8 @@ struct wayland_display *wayland_display_open(struct yasl_loop *loop, const struc
}
if (!c->loop) goto err;
if (spec) {
- c->cbs = spec->cbs;
+ c->base.callbacks = spec->cbs ? *spec->cbs : (struct yasl_display_cbs){0};
+ c->cbs = &c->base.callbacks;
c->ud = spec->ud;
if (spec->app_id) c->app_id = strdup(spec->app_id);
}
@@ -288,7 +289,7 @@ void wayland_display_close(struct wayland_display *c)
uint32_t wayland_display_caps(const struct wayland_display *c)
{
if (!c) return 0;
- uint32_t caps = YASL_CAP_POPUPS | YASL_CAP_CSD;
+ uint32_t caps = YASL_CAP_POPUPS | YASL_CAP_CSD | YASL_CAP_FRAME_PACING;
struct seat *s = conn_active_seat(c);
const struct wl_data_device *device = s ? clipboard_data_device(s->clipboard) : NULL;
if (device && wl_data_device_get_version((struct wl_data_device *)device) >= 3)
@@ -318,8 +319,6 @@ static void conn_unlink(struct wayland_surface *w)
break;
}
}
- if (c->paste_target == w)
- c->paste_target = NULL;
for (struct seat *s = c->seats; s; s = s->next)
seat_forget_surface(s, w);
w->conn = NULL;
@@ -397,8 +396,8 @@ err:
void wayland_surface_set_callbacks(struct wayland_surface *w, const struct yasl_surface_cbs *cbs, void *ud)
{
if (w && !w->closed) {
- static const struct yasl_surface_cbs no_callbacks = {0};
- w->cbs = cbs ? cbs : &no_callbacks;
+ w->base.callbacks = cbs ? *cbs : (struct yasl_surface_cbs){0};
+ w->cbs = &w->base.callbacks;
w->ud = ud;
}
}