1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
#include "input.h"
#include "yasl/loop.h"
#include <stdlib.h>
#include <string.h>
static bool has_text(const struct yasl_event *ev)
{
return ev->type == YASL_EVENT_TEXT || ev->type == YASL_EVENT_PASTE ||
ev->type == YASL_EVENT_DROP;
}
static void discard_pending(struct input_queue *q)
{
for (size_t i = 0; i < q->count; i++) {
struct yasl_event *ev = &q->events[(q->head + i) & (q->capacity - 1)];
if (has_text(ev)) free((void *)ev->text.data);
}
q->head = q->count = 0;
}
bool input_queue_push(struct input_queue *q, const struct yasl_event *ev)
{
struct yasl_event copy = *ev;
char *owned = NULL;
if (!copy.time_ns) copy.time_ns = yasl_loop_now_ns();
if (has_text(ev)) {
size_t len = ev->text.len;
if ((!ev->text.data && len) || len == SIZE_MAX) goto failed;
owned = malloc(len + 1);
if (!owned) goto failed;
if (len) memcpy(owned, ev->text.data, len);
owned[len] = '\0';
copy.text.data = owned;
}
switch (ev->type) {
case YASL_EVENT_POINTER_MOTION:
if (!q->relative) {
copy.pointer.delta = q->has_last_pos
? (struct yasl_vector2d){ev->pointer.pos.x - q->last_pos.x,
ev->pointer.pos.y - q->last_pos.y}
: (struct yasl_vector2d){0, 0};
}
[[fallthrough]];
case YASL_EVENT_POINTER_DOWN:
case YASL_EVENT_POINTER_UP:
q->last_pos = ev->pointer.pos;
q->has_last_pos = true;
break;
case YASL_EVENT_POINTER_LEAVE:
case YASL_EVENT_INPUT_RESET:
q->has_last_pos = false;
break;
default:
break;
}
if (q->count == q->capacity) {
size_t capacity = q->capacity ? q->capacity * 2 : 32;
if (capacity < q->capacity || capacity > SIZE_MAX / sizeof(*q->events))
goto failed;
struct yasl_event *events = malloc(capacity * sizeof(*events));
if (!events) goto failed;
if (q->events && q->count > 0) {
size_t first = q->capacity - q->head;
if (first > q->count) first = q->count;
memcpy(events, q->events + q->head, first * sizeof(*events));
if (q->count > first)
memcpy(events + first, q->events, (q->count - first) * sizeof(*events));
}
free(q->events);
q->events = events;
q->capacity = capacity;
q->head = 0;
}
q->events[(q->head + q->count) & (q->capacity - 1)] = copy;
q->count++;
return true;
failed:
free(owned);
/* A missing release must never silently leave app input state stuck.
* Discard the old stream and deliver an allocation-free reset first. */
discard_pending(q);
q->reset_surface = ev->surface;
q->reset_pending = true;
q->has_last_pos = false;
return false;
}
bool input_queue_pop(struct input_queue *q, struct yasl_event *ev)
{
if (!ev || (!q->count && !q->reset_pending)) return false;
if (q->last_text) {
free(q->last_text);
q->last_text = NULL;
}
if (q->reset_pending) {
*ev = (struct yasl_event){
.type = YASL_EVENT_INPUT_RESET, .surface = q->reset_surface,
.time_ns = yasl_loop_now_ns(),
};
q->reset_pending = false;
return true;
}
*ev = q->events[q->head];
if (has_text(ev))
q->last_text = (char *)ev->text.data;
q->head = (q->head + 1) & (q->capacity - 1);
q->count--;
return true;
}
void input_queue_clear(struct input_queue *q)
{
discard_pending(q);
free(q->last_text);
free(q->events);
*q = (struct input_queue){0};
}
|