summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-13 15:41:39 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-13 15:41:39 +0300
commit537b2d768b31deb0f95c5122e0d562e4406ae9a0 (patch)
treecc3e85cb2990672c11b4e35c6dbcfaac733d09f5 /src/common
parent98f0d51157fa2a2b8ccaae54ed4850a88d223d01 (diff)
Unify core and runner events into struct yasl_event
The core input queue and the yasl_run() runner each had their own event type, and the runner translated one into the other. Both now share struct yasl_event in <yasl/yasl.h>: yasl_surface_poll_event() returns the same events the app event callback receives, so the runner forwards them unchanged. Pointer input becomes POINTER_DOWN/UP/MOTION/SCROLL/LEAVE with a named yasl_pointer_button and a motion delta computed in the input queue. TEXT, PASTE and DROP share one text payload, scale changes fold into WINDOW_RESIZE, and every event carries a monotonic time_ns. yasl_surface_set_mouse_mode() is replaced by yasl_surface_set_pointer_mode(); no backend implements relative mode yet. The export check now only counts YASL_API declarations, so function pointer fields returning enum yasl_app_result are not mistaken for exports. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'src/common')
-rw-r--r--src/common/app.c197
-rw-r--r--src/common/backend.c21
-rw-r--r--src/common/backend.h7
-rw-r--r--src/common/input.c80
-rw-r--r--src/common/input.h14
5 files changed, 109 insertions, 210 deletions
diff --git a/src/common/app.c b/src/common/app.c
index e1148f9..9ec1f6a 100644
--- a/src/common/app.c
+++ b/src/common/app.c
@@ -9,7 +9,7 @@
struct user_event_node {
struct yasl_surface *surface;
- uint32_t type;
+ uint32_t code;
void *payload;
size_t size;
struct user_event_node *next;
@@ -21,10 +21,6 @@ struct app_surface {
struct yasl_surface *surface;
struct app_runner *runner;
yasl_pacing_mode pacing;
- yasl_mouse_mode mouse_mode;
- struct yasl_vector2i last_mouse_pos;
- bool has_last_mouse_pos;
- struct yasl_vector2i last_size;
uint32_t last_scale_120;
uint64_t frame_index;
bool presented;
@@ -45,6 +41,13 @@ struct app_runner {
struct user_event_node *user_event_tail;
};
+/* Deliver one event to the application; a QUIT result stops the runner. */
+static void emit(struct app_runner *ar, const struct yasl_event *ev)
+{
+ if (ar->desc->event && ar->desc->event(ar->desc->userdata, ev) == YASL_APP_QUIT)
+ ar->running = false;
+}
+
static void app_runner_surface_draw(struct yasl_surface *s, struct yasl_frame *frame, void *ud)
{
struct app_surface *as = ud;
@@ -88,35 +91,17 @@ static void app_runner_surface_configure(struct yasl_surface *s, struct yasl_geo
if (!ar || !ar->desc || !ar->desc->event)
return;
- bool scale_changed = (as->last_scale_120 != geom.scale_120 && as->last_scale_120 != 0);
- as->last_scale_120 = geom.scale_120;
- as->last_size = geom.size;
-
- if (scale_changed) {
- struct yasl_event ev = {
- .surface = s,
- .type = YASL_EVENT_WINDOW_SCALE_CHANGED,
- .scale = {
- .scale_120 = geom.scale_120,
- .size = geom.size,
- },
- };
- if (ar->desc->event(ar->desc->userdata, &ev) == YASL_APP_QUIT)
- ar->running = false;
- if (!as->surface)
- return;
- }
-
struct yasl_event ev = {
- .surface = s,
.type = YASL_EVENT_WINDOW_RESIZE,
+ .surface = s,
+ .time_ns = yasl_loop_now_ns(),
.resize = {
- .size = geom.size,
- .scale_120 = geom.scale_120,
+ .geometry = geom,
+ .scale_changed = as->last_scale_120 && as->last_scale_120 != geom.scale_120,
},
};
- if (ar->desc->event(ar->desc->userdata, &ev) == YASL_APP_QUIT)
- ar->running = false;
+ as->last_scale_120 = geom.scale_120;
+ emit(ar, &ev);
if (as->surface)
yasl_surface_schedule_redraw(s);
@@ -129,13 +114,11 @@ static void app_runner_surface_close(struct yasl_surface *s, void *ud)
if (!ar || !ar->desc || !ar->desc->event)
return;
- struct yasl_event ev = {
+ emit(ar, &(struct yasl_event){
+ .type = YASL_EVENT_WINDOW_CLOSE,
.surface = s,
- .type = YASL_EVENT_WINDOW_CLOSE_REQUEST,
- };
- if (ar->desc->event(ar->desc->userdata, &ev) == YASL_APP_QUIT) {
- ar->running = false;
- }
+ .time_ns = yasl_loop_now_ns(),
+ });
}
void app_runner_register_surface(void *runner, struct yasl_surface *s)
@@ -150,9 +133,7 @@ void app_runner_register_surface(void *runner, struct yasl_surface *s)
as->surface = s;
as->runner = ar;
as->pacing = YASL_PACING_ON_DEMAND;
- as->mouse_mode = YASL_MOUSE_NORMAL;
as->last_scale_120 = s->scale_120;
- as->last_size = s->size;
s->app_surface = as;
as->next = ar->surfaces;
@@ -237,21 +218,8 @@ void yasl_surface_request_frame(struct yasl_surface *s)
}
}
-void yasl_surface_set_mouse_mode(struct yasl_surface *s, yasl_mouse_mode mode)
-{
- if (!s || !s->app_surface)
- return;
- struct app_surface *as = s->app_surface;
- as->mouse_mode = mode;
- if (mode == YASL_MOUSE_NORMAL) {
- yasl_surface_set_cursor(s, YASL_CURSOR_ARROW);
- } else {
- yasl_surface_set_cursor(s, YASL_CURSOR_HIDDEN);
- }
-}
-
bool yasl_post_event(struct yasl_display *d, struct yasl_surface *s,
- uint32_t user_type, void *payload, size_t size)
+ uint32_t code, void *payload, size_t size)
{
if (!d || !d->app_runner)
return false;
@@ -261,7 +229,7 @@ bool yasl_post_event(struct yasl_display *d, struct yasl_surface *s,
if (!node)
return false;
node->surface = s;
- node->type = user_type;
+ node->code = code;
node->payload = payload;
node->size = size;
node->next = NULL;
@@ -322,19 +290,12 @@ static void app_runner_dispatch_user_events(struct app_runner *ar)
while (node && ar->running) {
struct user_event_node *next = node->next;
- if (ar->desc->event) {
- struct yasl_event ev = {
- .surface = node->surface,
- .type = YASL_EVENT_USER,
- .user = {
- .type = node->type,
- .payload = node->payload,
- .size = node->size,
- },
- };
- if (ar->desc->event(ar->desc->userdata, &ev) == YASL_APP_QUIT)
- ar->running = false;
- }
+ emit(ar, &(struct yasl_event){
+ .type = YASL_EVENT_USER,
+ .surface = node->surface,
+ .time_ns = yasl_loop_now_ns(),
+ .user = {.code = node->code, .payload = node->payload, .size = node->size},
+ });
free(node);
node = next;
}
@@ -348,107 +309,11 @@ static void app_runner_dispatch_user_events(struct app_runner *ar)
static void app_runner_dispatch_input_events(struct app_runner *ar)
{
for (struct app_surface *as = ar->surfaces; as && ar->running; as = as->next) {
- struct yasl_input_event ie;
- while (as->surface && yasl_surface_input_poll(as->surface, &ie) &&
- ar->running) {
- if (!ar->desc->event)
- continue;
-
- struct yasl_event ev = {0};
- ev.surface = ie.surface ? ie.surface : as->surface;
-
- switch (ie.kind) {
- case YASL_INPUT_KEY:
- ev.type = YASL_EVENT_KEY;
- ev.key.key = ie.key.key;
- ev.key.action = ie.key.action;
- ev.key.mods = ie.key.mods;
- ev.key.codepoint = ie.key.codepoint;
- ev.key.shifted = ie.key.shifted;
- ev.key.native_code = ie.key.native_code;
- ev.key.repeat = (ie.key.action == YASL_KEY_REPEAT);
- if (ar->desc->event(ar->desc->userdata, &ev) == YASL_APP_QUIT)
- ar->running = false;
- break;
- case YASL_INPUT_TEXT:
- ev.type = YASL_EVENT_TEXT;
- ev.text.text = ie.text.text;
- ev.text.len = ie.text.len;
- if (ar->desc->event(ar->desc->userdata, &ev) == YASL_APP_QUIT)
- ar->running = false;
- break;
- case YASL_INPUT_MOUSE:
- if (ie.mouse.kind == YASL_PTR_PRESS || ie.mouse.kind == YASL_PTR_RELEASE) {
- ev.type = YASL_EVENT_MOUSE_BUTTON;
- ev.mouse_button.pos = ie.mouse.pos;
- ev.mouse_button.device = ie.mouse.device;
- ev.mouse_button.button = ie.mouse.button;
- ev.mouse_button.pressed = (ie.mouse.kind == YASL_PTR_PRESS);
- ev.mouse_button.mods = ie.mouse.mods;
- ev.mouse_button.pen = ie.mouse.pen;
- as->last_mouse_pos = ie.mouse.pos;
- as->has_last_mouse_pos = true;
- if (ar->desc->event(ar->desc->userdata, &ev) == YASL_APP_QUIT)
- ar->running = false;
- } else if (ie.mouse.kind == YASL_PTR_MOTION) {
- ev.type = YASL_EVENT_MOUSE_MOTION;
- ev.mouse_motion.pos = ie.mouse.pos;
- ev.mouse_motion.device = ie.mouse.device;
- if (as->has_last_mouse_pos) {
- ev.mouse_motion.delta.x = ie.mouse.pos.x - as->last_mouse_pos.x;
- ev.mouse_motion.delta.y = ie.mouse.pos.y - as->last_mouse_pos.y;
- } else {
- ev.mouse_motion.delta = (struct yasl_vector2i){0, 0};
- }
- ev.mouse_motion.mods = ie.mouse.mods;
- ev.mouse_motion.pen = ie.mouse.pen;
- as->last_mouse_pos = ie.mouse.pos;
- as->has_last_mouse_pos = true;
- if (ar->desc->event(ar->desc->userdata, &ev) == YASL_APP_QUIT)
- ar->running = false;
- } else if (ie.mouse.kind == YASL_PTR_SCROLL) {
- ev.type = YASL_EVENT_MOUSE_SCROLL;
- ev.mouse_scroll.pos = ie.mouse.pos;
- ev.mouse_scroll.scroll = ie.mouse.scroll;
- ev.mouse_scroll.mods = ie.mouse.mods;
- if (ar->desc->event(ar->desc->userdata, &ev) == YASL_APP_QUIT)
- ar->running = false;
- } else if (ie.mouse.kind == YASL_PTR_LEAVE) {
- ev.type = YASL_EVENT_MOUSE_LEAVE;
- as->has_last_mouse_pos = false;
- if (ar->desc->event(ar->desc->userdata, &ev) == YASL_APP_QUIT)
- ar->running = false;
- }
- break;
- case YASL_INPUT_FOCUS:
- ev.type = YASL_EVENT_WINDOW_FOCUS;
- ev.focus.focused = ie.focus.focused;
- if (ar->desc->event(ar->desc->userdata, &ev) == YASL_APP_QUIT)
- ar->running = false;
- break;
- case YASL_INPUT_PASTE:
- ev.type = YASL_EVENT_PASTE;
- ev.paste.text = ie.paste.text;
- ev.paste.len = ie.paste.len;
- if (ar->desc->event(ar->desc->userdata, &ev) == YASL_APP_QUIT)
- ar->running = false;
- break;
- case YASL_INPUT_DROP_FILES:
- ev.type = YASL_EVENT_DROP_FILES;
- ev.drop_files.files = ie.drop_files.files;
- ev.drop_files.len = ie.drop_files.len;
- if (ar->desc->event(ar->desc->userdata, &ev) == YASL_APP_QUIT)
- ar->running = false;
- break;
- case YASL_INPUT_RESET:
- as->has_last_mouse_pos = false;
- ev.type = YASL_EVENT_INPUT_RESET;
- if (ar->desc->event(ar->desc->userdata, &ev) == YASL_APP_QUIT)
- ar->running = false;
- break;
- default:
- break;
- }
+ struct yasl_event ev;
+ while (ar->running && as->surface && yasl_surface_poll_event(as->surface, &ev)) {
+ if (!ev.surface)
+ ev.surface = as->surface;
+ emit(ar, &ev);
}
}
}
diff --git a/src/common/backend.c b/src/common/backend.c
index 3f2143d..d35d243 100644
--- a/src/common/backend.c
+++ b/src/common/backend.c
@@ -306,15 +306,30 @@ bool yasl_surface_present(struct yasl_surface *s, const struct yasl_framebuffer
return s->display->ops->surface_present(s, fb, &clipped);
}
-bool yasl_surface_input_poll(struct yasl_surface *s, struct yasl_input_event *ev)
+bool yasl_surface_poll_event(struct yasl_surface *s, struct yasl_event *ev)
{
if (!s || !ev)
return false;
- if (s->display && s->display->ops && s->display->ops->surface_input_poll)
- return s->display->ops->surface_input_poll(s, ev);
+ if (s->display && s->display->ops && s->display->ops->surface_poll_event)
+ return s->display->ops->surface_poll_event(s, ev);
return input_queue_pop(&s->input, ev);
}
+bool yasl_surface_set_pointer_mode(struct yasl_surface *s, enum yasl_pointer_mode mode)
+{
+ if (!s || (mode != YASL_POINTER_NORMAL && mode != YASL_POINTER_RELATIVE))
+ return false;
+ if (mode == s->pointer_mode)
+ return true;
+ const struct yasl_backend_ops *ops = s->display ? s->display->ops : NULL;
+ if (!ops || !ops->surface_set_pointer_mode)
+ return mode == YASL_POINTER_NORMAL;
+ if (!ops->surface_set_pointer_mode(s, mode))
+ return false;
+ s->pointer_mode = mode;
+ return true;
+}
+
struct yasl_geometry yasl_surface_geometry(const struct yasl_surface *s)
{
if (!s)
diff --git a/src/common/backend.h b/src/common/backend.h
index 17d781e..f0fae03 100644
--- a/src/common/backend.h
+++ b/src/common/backend.h
@@ -28,6 +28,7 @@ struct yasl_surface {
void *ud;
uint64_t frame_generation;
struct input_queue input;
+ enum yasl_pointer_mode pointer_mode;
struct yasl_frame_clock clock;
uint64_t frames_skipped;
yasl_timer_id *timers;
@@ -70,7 +71,11 @@ struct yasl_backend_ops {
void (*surface_set_title)(struct yasl_surface *s, const char *title);
void (*surface_schedule_redraw)(struct yasl_surface *s);
bool (*surface_present)(struct yasl_surface *s, const struct yasl_framebuffer *fb, const struct yasl_damage_list *damage);
- bool (*surface_input_poll)(struct yasl_surface *s, struct yasl_input_event *ev);
+ /* Optional; NULL means the common input queue is drained. */
+ bool (*surface_poll_event)(struct yasl_surface *s, struct yasl_event *ev);
+ /* Optional; NULL means only YASL_POINTER_NORMAL is supported. Backends that
+ * implement RELATIVE push POINTER_MOTION with delta set and pos frozen. */
+ bool (*surface_set_pointer_mode)(struct yasl_surface *s, enum yasl_pointer_mode mode);
struct yasl_geometry (*surface_geometry)(const struct yasl_surface *s);
struct yasl_timing (*surface_timing)(const struct yasl_surface *s);
uint64_t (*surface_frame_time_ns)(struct yasl_surface *s, uint64_t now);
diff --git a/src/common/input.c b/src/common/input.c
index 471cd2b..0b55f1f 100644
--- a/src/common/input.c
+++ b/src/common/input.c
@@ -1,57 +1,64 @@
#include "input.h"
+#include "yasl/loop.h"
#include <stdlib.h>
#include <string.h>
-static const char *event_text(const struct yasl_input_event *ev, size_t *len)
+static bool has_text(const struct yasl_event *ev)
{
- switch (ev->kind) {
- case YASL_INPUT_TEXT: *len = ev->text.len; return ev->text.text;
- case YASL_INPUT_PASTE: *len = ev->paste.len; return ev->paste.text;
- case YASL_INPUT_DROP_FILES: *len = ev->drop_files.len; return ev->drop_files.files;
- default: *len = 0; return NULL;
- }
-}
-
-static void set_text(struct yasl_input_event *ev, const char *text)
-{
- switch (ev->kind) {
- case YASL_INPUT_TEXT: ev->text.text = text; break;
- case YASL_INPUT_PASTE: ev->paste.text = text; break;
- case YASL_INPUT_DROP_FILES: ev->drop_files.files = text; break;
- default: break;
- }
+ 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++) {
- size_t len;
- free((void *)event_text(&q->events[(q->head + i) % q->capacity], &len));
+ 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_input_event *ev)
+bool input_queue_push(struct input_queue *q, const struct yasl_event *ev)
{
- struct yasl_input_event copy = *ev;
+ struct yasl_event copy = *ev;
char *owned = NULL;
- if (ev->kind == YASL_INPUT_TEXT || ev->kind == YASL_INPUT_PASTE ||
- ev->kind == YASL_INPUT_DROP_FILES) {
- size_t len;
- const char *text = event_text(ev, &len);
- if ((!text && len) || len == SIZE_MAX) goto failed;
+ 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, text, len);
+ if (len) memcpy(owned, ev->text.data, len);
owned[len] = '\0';
- set_text(&copy, owned);
+ 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_input_event *events = malloc(capacity * sizeof(*events));
+ 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;
@@ -76,10 +83,11 @@ failed:
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_input_event *ev)
+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) {
@@ -87,18 +95,16 @@ bool input_queue_pop(struct input_queue *q, struct yasl_input_event *ev)
q->last_text = NULL;
}
if (q->reset_pending) {
- *ev = (struct yasl_input_event){
- .surface = q->reset_surface, .kind = YASL_INPUT_RESET,
+ *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 (ev->kind == YASL_INPUT_TEXT || ev->kind == YASL_INPUT_PASTE ||
- ev->kind == YASL_INPUT_DROP_FILES) {
- size_t len;
- q->last_text = (char *)event_text(ev, &len);
- }
+ if (has_text(ev))
+ q->last_text = (char *)ev->text.data;
q->head = (q->head + 1) & (q->capacity - 1);
q->count--;
return true;
diff --git a/src/common/input.h b/src/common/input.h
index d7264f6..ffd1663 100644
--- a/src/common/input.h
+++ b/src/common/input.h
@@ -5,15 +5,23 @@
/* Each queued string and the last successfully polled string are owned here. */
struct input_queue {
- struct yasl_input_event *events;
+ struct yasl_event *events;
size_t head, count, capacity;
char *last_text;
+ /* Last pointer position, for computing absolute-mode motion deltas. */
+ struct yasl_vector2i last_pos;
+ bool has_last_pos;
+ /* Set by backends while YASL_POINTER_RELATIVE is active: keep pushed deltas. */
+ bool relative;
struct yasl_surface *reset_surface;
bool reset_pending;
};
-bool input_queue_push(struct input_queue *q, const struct yasl_input_event *ev);
-bool input_queue_pop(struct input_queue *q, struct yasl_input_event *ev);
+/* Copies text payloads and stamps time_ns when zero. Unless q->relative is set,
+ * POINTER_MOTION delta is computed from the previous position; otherwise the
+ * backend-supplied delta is kept. Leave and reset clear the position history. */
+bool input_queue_push(struct input_queue *q, const struct yasl_event *ev);
+bool input_queue_pop(struct input_queue *q, struct yasl_event *ev);
void input_queue_clear(struct input_queue *q);
#endif