diff options
Diffstat (limited to 'src/wayland')
| -rw-r--r-- | src/wayland/buffer.c | 34 | ||||
| -rw-r--r-- | src/wayland/clipboard.c | 25 | ||||
| -rw-r--r-- | src/wayland/internal.h | 9 | ||||
| -rw-r--r-- | src/wayland/pointer.c | 66 | ||||
| -rw-r--r-- | src/wayland/popup.c | 5 | ||||
| -rw-r--r-- | src/wayland/surface.c | 12 |
6 files changed, 88 insertions, 63 deletions
diff --git a/src/wayland/buffer.c b/src/wayland/buffer.c index a1486fa..0561da3 100644 --- a/src/wayland/buffer.c +++ b/src/wayland/buffer.c @@ -322,19 +322,16 @@ int buffer_pick_free_index(const struct buffer *bufs, int cur) return free_buf_lut[(unsigned)cur & 3][busy]; } -struct latency_feedback { - struct wayland_surface *window; - struct wp_presentation_feedback *proxy; - struct latency_feedback *next; -}; - static void feedback_destroy(struct latency_feedback *feedback) { struct latency_feedback **link = &feedback->window->latency_feedbacks; while (*link && *link != feedback) link = &(*link)->next; if (*link) *link = feedback->next; wp_presentation_feedback_destroy(feedback->proxy); - free(feedback); + if (feedback->in_pool) + *feedback = (struct latency_feedback){0}; + else + free(feedback); } void surface_feedback_destroy(struct wayland_surface *w) @@ -386,10 +383,22 @@ void surface_request_presentation_feedback(struct wayland_surface *w) return; struct wp_presentation_feedback *fb = wp_presentation_feedback(w->conn->presentation, w->surface); - struct latency_feedback *feedback = fb ? calloc(1, sizeof(*feedback)) : NULL; - if (!feedback) { - if (fb) wp_presentation_feedback_destroy(fb); + if (!fb) return; + struct latency_feedback *feedback = NULL; + for (int i = 0; i < 8; i++) { + if (!w->latency_pool[i].window) { + feedback = &w->latency_pool[i]; + feedback->in_pool = true; + break; + } + } + if (!feedback) { + feedback = calloc(1, sizeof(*feedback)); + if (!feedback) { + wp_presentation_feedback_destroy(fb); + return; + } } feedback->window = w; feedback->proxy = fb; @@ -449,7 +458,10 @@ bool wayland_surface_present(struct wayland_surface *w, const struct yasl_frameb fb->size.x != w->width || fb->size.y != w->height) return false; - w->damage = *damage; + w->damage.n = damage->n; + w->damage.bounds = damage->bounds; + if (damage->n > 0) + memcpy(w->damage.rects, damage->rects, (size_t)damage->n * sizeof(damage->rects[0])); arm_frame(w); if (w->closed) return false; diff --git a/src/wayland/clipboard.c b/src/wayland/clipboard.c index 7df1a70..e3eec0f 100644 --- a/src/wayland/clipboard.c +++ b/src/wayland/clipboard.c @@ -118,21 +118,18 @@ static int transfer_io(int fd, short events, void *ud) if (t->offset == t->len || n == 0 || (n < 0 && errno != EAGAIN && errno != EINTR)) transfer_destroy(t); } else { - char buf[8192]; - ssize_t n = read(fd, buf, sizeof(buf)); + 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_destroy(t); return 0; } + char *text = realloc(t->text, capacity); + if (!text) { transfer_destroy(t); return 0; } + t->text = text; + t->capacity = capacity; + } + ssize_t n = read(fd, t->text + t->len, t->capacity - t->len); if (n > 0) { - size_t need = t->len + (size_t)n; - if (need > CLIPBOARD_TEXT_MAX) { transfer_destroy(t); return 0; } - if (need > t->capacity) { - size_t capacity = t->capacity ? t->capacity * 2 : sizeof(buf); - if (capacity > CLIPBOARD_TEXT_MAX) capacity = CLIPBOARD_TEXT_MAX; - char *text = realloc(t->text, capacity); - if (!text) { transfer_destroy(t); return 0; } - t->text = text; - t->capacity = capacity; - } - memcpy(t->text + t->len, buf, (size_t)n); - t->len += n; + t->len += (size_t)n; } else if (n == 0) { t->owner->receive(t->text ? t->text : "", t->len, t->uri_list, t->drop_surface, t->owner->ud); diff --git a/src/wayland/internal.h b/src/wayland/internal.h index 04142f7..d519abd 100644 --- a/src/wayland/internal.h +++ b/src/wayland/internal.h @@ -76,6 +76,7 @@ struct pending_press { struct press_queue { struct pending_press ev[8]; + int head; int n; }; @@ -244,6 +245,13 @@ struct wayland_display { bool lost; }; +struct latency_feedback { + struct wayland_surface *window; + struct wp_presentation_feedback *proxy; + struct latency_feedback *next; + bool in_pool; +}; + struct wayland_surface { struct yasl_surface base; /* 8-byte pointers & 64-bit values */ @@ -264,6 +272,7 @@ struct wayland_surface { struct seat *ime_seat; struct wp_tearing_control_v1 *tearing_control; struct latency_feedback *latency_feedbacks; + struct latency_feedback latency_pool[8]; struct wp_fifo_v1 *fifo; struct wp_commit_timer_v1 *commit_timer; struct wl_callback *frame_cb; diff --git a/src/wayland/pointer.c b/src/wayland/pointer.c index 5924eb1..065669f 100644 --- a/src/wayland/pointer.c +++ b/src/wayland/pointer.c @@ -248,8 +248,9 @@ static void press_queue_flush(struct seat *s, struct press_queue *q, struct yasl_mouse_event like) { int kept = 0; - for (int i = 0; i < q->n; i++) { - struct pending_press p = q->ev[i]; + int count = q->n; + for (int i = 0; i < count; i++) { + struct pending_press p = q->ev[(q->head + i) & 7]; if (only && p.surface != only) { q->ev[kept++] = p; continue; @@ -263,26 +264,30 @@ static void press_queue_flush(struct seat *s, struct press_queue *q, ev.kind = (enum yasl_pointer_kind)p.release; push_mouse(s, p.surface, ev); } + q->head = 0; q->n = kept; } static void press_queue_push(struct press_queue *q, struct wayland_surface *w, struct yasl_vector2i pos, int button, bool release) { - if (q->n == (int)(sizeof(q->ev) / sizeof(q->ev[0]))) { - memmove(q->ev, q->ev + 1, sizeof(q->ev[0]) * (size_t)(q->n - 1)); + if (q->n == 8) { + q->head = (q->head + 1) & 7; q->n--; } - q->ev[q->n++] = (struct pending_press){ + q->ev[(q->head + q->n) & 7] = (struct pending_press){ .surface = w, .pos = pos, .button = button, .release = release, }; + q->n++; } static void press_queue_forget(struct press_queue *q, struct wayland_surface *w) { - for (int i = 0; i < q->n; i++) - if (q->ev[i].surface == w) - q->ev[i].surface = NULL; + for (int i = 0; i < q->n; i++) { + int idx = (q->head + i) & 7; + if (q->ev[idx].surface == w) + q->ev[idx].surface = NULL; + } } void seat_pointer_reset(struct seat *s) @@ -566,28 +571,7 @@ static struct yasl_vector2i touch_pos(const struct touch_point *p) }; } -static int touch_count(const struct seat *s) -{ - int n = 0; - for (int i = 0; i < SEAT_TOUCH_POINTS; i++) - if (s->touch_points[i].active && !s->touch_points[i].up) - n++; - return n; -} -static double touch_centroid_y(const struct seat *s, const struct wayland_surface *on) -{ - double sum = 0; - int n = 0; - for (int i = 0; i < SEAT_TOUCH_POINTS; i++) { - const struct touch_point *p = &s->touch_points[i]; - if (p->active && !p->up && p->surface == on) { - sum += p->y; - n++; - } - } - return n ? sum / n : 0; -} static void touch_report(struct seat *s, struct touch_point *p, int button, enum yasl_pointer_kind kind) @@ -641,24 +625,35 @@ static void touch_frame(void *data, struct wl_touch *touch) { (void)touch; struct seat *s = data; + int active_n = 0; + double centroid_sum = 0; + int centroid_n = 0; for (int i = 0; i < SEAT_TOUCH_POINTS; i++) { struct touch_point *p = &s->touch_points[i]; - if (p->active && p->down && !s->touch_primary && !s->touch_scrolling) { + if (!p->active) continue; + if (p->down && !s->touch_primary && !s->touch_scrolling) { s->touch_primary = p; s->touch_pressed = true; touch_report(s, p, 0, YASL_PTR_PRESS); } + if (!p->up) { + active_n++; + if (s->touch_primary && p->surface == s->touch_primary->surface) { + centroid_sum += p->y; + centroid_n++; + } + } } struct touch_point *primary = s->touch_primary; - if (primary && !s->touch_scrolling && touch_count(s) >= 2) { + if (primary && !s->touch_scrolling && active_n >= 2) { if (s->touch_pressed) touch_report(s, primary, 0, YASL_PTR_RELEASE); s->touch_pressed = false; s->touch_scrolling = true; - s->touch_scroll_y = touch_centroid_y(s, primary->surface); + s->touch_scroll_y = centroid_n ? centroid_sum / centroid_n : 0; s->touch_scroll_rest = 0; - } else if (s->touch_scrolling && primary && touch_count(s) >= 2) { - double y = touch_centroid_y(s, primary->surface); + } else if (s->touch_scrolling && primary && active_n >= 2) { + double y = centroid_n ? centroid_sum / centroid_n : 0; double dy = y - s->touch_scroll_y; s->touch_scroll_y = y; if (dy != 0.0) { @@ -679,6 +674,7 @@ static void touch_frame(void *data, struct wl_touch *touch) struct touch_point *p = &s->touch_points[i]; if (!p->active) continue; if (p->up) { + active_n--; if (p == s->touch_primary) { if (s->touch_pressed) touch_report(s, p, 0, YASL_PTR_RELEASE); @@ -690,7 +686,7 @@ static void touch_frame(void *data, struct wl_touch *touch) p->down = p->moved = false; } } - if (!touch_count(s)) + if (active_n <= 0) s->touch_scrolling = false; } diff --git a/src/wayland/popup.c b/src/wayland/popup.c index 63bcba6..4364934 100644 --- a/src/wayland/popup.c +++ b/src/wayland/popup.c @@ -145,7 +145,10 @@ struct wayland_surface *wayland_surface_create_popup(struct wayland_surface *par w->clock.refresh_ns = parent->clock.refresh_ns; w->surface = wl_compositor_create_surface(c->compositor); - if (!w->surface || surface_init_scaling(w) < 0) + if (!w->surface) + goto err; + wl_surface_set_user_data(w->surface, w); + if (surface_init_scaling(w) < 0) goto err; w->xdg_surface = xdg_wm_base_get_xdg_surface(c->wm_base, w->surface); if (!w->xdg_surface) diff --git a/src/wayland/surface.c b/src/wayland/surface.c index ce1764b..242531c 100644 --- a/src/wayland/surface.c +++ b/src/wayland/surface.c @@ -321,7 +321,11 @@ static void conn_unlink(struct wayland_surface *w) struct wayland_surface *conn_surface_for(struct wayland_display *c, struct wl_surface *s) { - for (struct wayland_surface *w = c->surfaces; w && s; w = w->conn_next) + if (unlikely(!c || !s)) return NULL; + struct wayland_surface *fast = (struct wayland_surface *)wl_surface_get_user_data(s); + if (likely(fast && fast->conn == c && fast->surface == s)) + return fast; + for (struct wayland_surface *w = c->surfaces; w; w = w->conn_next) if (w->surface == s) return w; return NULL; @@ -361,6 +365,7 @@ struct wayland_surface *wayland_surface_create_toplevel(struct wayland_display * w->surface = wl_compositor_create_surface(c->compositor); if (!w->surface) goto err; + wl_surface_set_user_data(w->surface, w); if (surface_init_scaling(w) < 0) goto err; if (surface_init_shell(w, spec->title) < 0) goto err; w->opaque = spec->fullscreen; @@ -420,7 +425,10 @@ void wayland_surface_destroy(struct wayland_surface *w) if (w->toplevel) xdg_toplevel_destroy(w->toplevel); if (w->popup) xdg_popup_destroy(w->popup); if (w->xdg_surface) xdg_surface_destroy(w->xdg_surface); - if (w->surface) wl_surface_destroy(w->surface); + if (w->surface) { + wl_surface_set_user_data(w->surface, NULL); + wl_surface_destroy(w->surface); + } struct wayland_display *c = w->conn; conn_unlink(w); static const struct yasl_surface_cbs no_callbacks = {0}; |
