summaryrefslogtreecommitdiff
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
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>
-rw-r--r--docs/guide.md41
-rw-r--r--docs/migrating.md38
-rw-r--r--examples/game.c31
-rw-r--r--examples/hello.c6
-rw-r--r--examples/notepad.c94
-rw-r--r--examples/simple_window.c31
-rw-r--r--examples/tablet.c38
-rw-r--r--include/yasl/app.h125
-rw-r--r--include/yasl/keycodes.h2
-rw-r--r--include/yasl/yasl.h193
-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
-rw-r--r--src/platform/cocoa/api.h2
-rw-r--r--src/platform/cocoa/window.m113
-rw-r--r--src/platform/wayland/api.h2
-rw-r--r--src/platform/wayland/backend.c6
-rw-r--r--src/platform/wayland/ime.c6
-rw-r--r--src/platform/wayland/keyboard.c16
-rw-r--r--src/platform/wayland/pointer.c154
-rw-r--r--src/platform/x11/window.c132
-rw-r--r--tests/helpers/check_exports.py2
24 files changed, 577 insertions, 774 deletions
diff --git a/docs/guide.md b/docs/guide.md
index 1bd1aef..f195e5e 100644
--- a/docs/guide.md
+++ b/docs/guide.md
@@ -45,7 +45,9 @@ in `event`, and render into `frame->cpu.pixels` in `frame`. Present with
`yasl_frame_present_cpu(frame, NULL, 0)` and return `YASL_APP_QUIT` from an event
handler to exit. The runner handles dispatch, input polling, resize redraws,
and remaining surface/display cleanup. Display quit stops the runner; connection
-loss and dispatch failures return an error after cleanup.
+loss and dispatch failures return an error after cleanup. The runner delivers
+input exactly as `yasl_surface_poll_event()` returns it, plus
+`YASL_EVENT_WINDOW_RESIZE`, `YASL_EVENT_WINDOW_CLOSE`, and `YASL_EVENT_USER`.
Unified pointer button and motion events retain `device` and `pen` axes,
including erasers and pressure-only motion. Cancel held input or active strokes
@@ -159,19 +161,21 @@ clock; it does not establish actual scanout time.
## Input, text, and payload lifetime
-Dispatch receives native input. `yasl_surface_input_poll()` only drains it and
+Dispatch receives native input. `yasl_surface_poll_event()` only drains it and
never waits. Poll every live surface queue until empty. Wayland routes popup
pointer and keyboard events through the root parent's queue; inspect
`event.surface` to identify the recipient. Do not assume it equals the object
whose queue you polled.
-Read the union member selected by `event.kind`. The `reserved` field is internal
-and must not be interpreted. Text, paste, and file-drop payloads are UTF-8 byte
-strings, NUL-terminated; `len` excludes the NUL. They remain valid until the
+Read the union member selected by `event.type`; `time_ns` is a monotonic
+timestamp on the `yasl_loop_now_ns()` clock. Polling returns only input types,
+`YASL_EVENT_KEY` through `YASL_EVENT_INPUT_RESET`. Text, paste, and file-drop
+payloads share `event.text`: UTF-8 byte strings, NUL-terminated; `len` excludes
+the NUL. They remain valid until the
next **successful** poll on the queue or queue destruction. Dispatch, flush,
and unsuccessful polls do not invalidate them. Copy data to keep it longer.
-Use `YASL_INPUT_TEXT` for document text insertion, including committed IME text.
+Use `YASL_EVENT_TEXT` for document text insertion, including committed IME text.
It contains UTF-8 and can contain several characters. Key actions are for
commands and held-key state; releases and repeats have separate tags. A text
commit need not correspond to one key event, and a key need not produce text.
@@ -192,11 +196,11 @@ are useful for displaying shortcuts or
choosing layout-sensitive commands; they are never document text. For example:
```c
-if (event.kind == YASL_INPUT_KEY && event.key.action == YASL_KEY_PRESS &&
+if (event.type == YASL_EVENT_KEY && event.key.action == YASL_KEY_PRESS &&
event.key.key == YASL_KEY_ESCAPE) {
running = false;
}
-/* Insert event.text.text[0..event.text.len) only for YASL_INPUT_TEXT. */
+/* Insert event.text.data[0..event.text.len) only for YASL_EVENT_TEXT. */
```
Wayland uses the supplied XKB layout and locale compose rules for ordinary text
@@ -209,14 +213,21 @@ not change the process locale. IME availability and system configuration still
determine which compositions work. Physical key events
remain available for commands; input methods may consume keys while composing.
-Pointer events use `YASL_INPUT_MOUSE`, with `device` distinguishing mouse, touch,
-pen, and eraser. Press/release button 0 is primary/tip, 1 middle, and 2 secondary.
-Track those transitions; motion/leave button values are informational. Pen
+Pointer events use the `YASL_EVENT_POINTER_*` types and share `event.pointer`,
+with `device` distinguishing mouse, touch, pen, and eraser. `POINTER_DOWN` and
+`POINTER_UP` carry a `YASL_BUTTON_*` value: `PRIMARY` is the left button, pen tip,
+or touch contact. Track those transitions; other types leave `button`
+meaningless. `POINTER_MOTION` reports `delta`, the device-pixel movement since
+the previous sample, which restarts from zero after enter, leave, or reset.
+`yasl_surface_set_pointer_mode()` with `YASL_POINTER_RELATIVE` hides and locks the
+cursor while the surface is focused; motion then carries unbounded `delta` and
+`pos` stays at the lock position. No backend implements it yet, so it
+currently returns false and leaves the surface in `YASL_POINTER_NORMAL`. Pen
pressure is normalized to 0..65535, signed tilt is in degrees, and missing axes
are zero. Pressure-only changes can produce motion. Zero pressure alone does
not mean release. This interface does not expose simultaneous touch contacts.
-For `YASL_PTR_SCROLL`, read `mouse.scroll.x` and `.y`: fractional line offsets,
+For `YASL_EVENT_POINTER_SCROLL`, read `pointer.scroll.x` and `.y`: fractional line offsets,
positive right and down, after system scroll preferences. Both axes may be
nonzero in one event. Preserve fractions and choose your application's own
pixels per line; one wheel detent normally gives one line. `button` is unused
@@ -225,7 +236,7 @@ discrete/raw descriptions. Smooth Wayland offsets and precise Cocoa offsets
use ten native units per line. X11 currently reports whole wheel steps, so it
does not provide the same smooth-scroll precision as the other backends.
-Cancel held keys, buttons, active strokes, and composition on `YASL_INPUT_RESET`,
+Cancel held keys, buttons, active strokes, and composition on `YASL_EVENT_INPUT_RESET`,
focus loss, or pointer leave as appropriate to your application. RESET has no
union payload. It is emitted after input-queue allocation failure and certain
device interruptions; ignoring it can leave application input stuck.
@@ -234,7 +245,7 @@ device interruptions; ignoring it can leave application input stuck.
`yasl_display_copy()` copies a NUL-terminated UTF-8 string during the call.
`yasl_display_paste()` requests delivery to the original target as
-`YASL_INPUT_PASTE`; destroying the target cancels delivery. There is no transfer
+`YASL_EVENT_PASTE`; destroying the target cancels delivery. There is no transfer
ID or error callback, so unavailable or failed transfers may produce no event.
Wayland selection offers can require a recent input serial. X11 currently does
not implement incremental (`INCR`) selection transfers and may reject large
@@ -245,7 +256,7 @@ and never aliases the clipboard. Cocoa uses a YASL named pasteboard to emulate p
this is not a desktop-wide macOS select-to-copy convention.
External file drag hover uses the surface `drop` callback; actual file URLs
-arrive as `YASL_INPUT_DROP_FILES`. `files` is a `text/uri-list` string separated by
+arrive as `YASL_EVENT_DROP`. `text.data` is a `text/uri-list` string separated by
CRLF, not a list of native paths. Parse URL encoding, skip blank/comment lines,
and decide which schemes/hosts your application accepts before opening files.
diff --git a/docs/migrating.md b/docs/migrating.md
index 395072e..e1f5442 100644
--- a/docs/migrating.md
+++ b/docs/migrating.md
@@ -12,10 +12,34 @@ Replace manual dispatch/poll/flush loops with the runner and request redraws wit
`yasl_surface_request_frame()`. Present the frame context with
`yasl_frame_present_cpu()`; the runner destroys remaining surfaces on exit.
-Unified pointer button and motion events retain `device` and tablet axes.
-Handle `YASL_EVENT_INPUT_RESET` by clearing held input and active strokes, just
-as for the core API's `YASL_INPUT_RESET`. Window state remains a `YASL_STATE_*`
-bitmask; `YASL_STATE_TILED` is reported for tiled Wayland toplevels.
+Window state remains a `YASL_STATE_*` bitmask; `YASL_STATE_TILED` is reported
+for tiled Wayland toplevels.
+
+## Events
+
+The core API and the runner now share one `struct yasl_event`, declared in
+`<yasl/yasl.h>`. `yasl_surface_poll_event()` returns the same events that
+`yasl_app_desc.event` receives, so input handling code works under both.
+
+| Previous use | Replacement |
+| --- | --- |
+| `yasl_surface_input_poll()`, `struct yasl_input_event` | `yasl_surface_poll_event()`, `struct yasl_event` |
+| `event.kind`, `YASL_INPUT_*` | `event.type`, `YASL_EVENT_*` |
+| `YASL_INPUT_MOUSE` with `mouse.kind` | `YASL_EVENT_POINTER_DOWN`, `_UP`, `_MOTION`, `_SCROLL`, `_LEAVE` with `event.pointer` |
+| Runner `YASL_EVENT_MOUSE_BUTTON` with `pressed` | `YASL_EVENT_POINTER_DOWN` / `_UP` |
+| Integer `button` 0/1/2 | `YASL_BUTTON_PRIMARY`, `_MIDDLE`, `_SECONDARY`, `_BACK`, `_FORWARD` |
+| `paste.text`, `drop_files.files`, `text.text` | `text.data` for `PASTE`, `DROP`, and `TEXT` |
+| `YASL_INPUT_DROP_FILES` / `YASL_EVENT_DROP_FILES` | `YASL_EVENT_DROP` |
+| `YASL_EVENT_WINDOW_FOCUS` | `YASL_EVENT_FOCUS` |
+| `YASL_EVENT_WINDOW_SCALE_CHANGED` | `YASL_EVENT_WINDOW_RESIZE` with `resize.scale_changed` |
+| `YASL_EVENT_WINDOW_CLOSE_REQUEST` | `YASL_EVENT_WINDOW_CLOSE` |
+| `user.type` | `user.code` |
+| `key.repeat` | `key.action == YASL_KEY_REPEAT` |
+| `yasl_surface_set_mouse_mode()` | `yasl_surface_set_pointer_mode()` |
+
+Every event carries a monotonic `time_ns`. Pointer motion carries `delta` on
+both paths. Handle `YASL_EVENT_INPUT_RESET` by clearing held input and active
+strokes.
## Window creation
@@ -40,7 +64,7 @@ provide application notifications through `yasl_app_desc.event` and `.frame`.
| Linux keysym or Cocoa virtual keycode in `key.key` | Portable physical `YASL_KEY_*` identity |
| `key.base` | `key.native_code`, with explicit backend-specific encoding |
| `key.keypad` | Distinct `YASL_KEY_KP_*` identities |
-| Advisory `key.text` character | `YASL_INPUT_TEXT` UTF-8 payload for insertion |
+| Advisory `key.text` character | `YASL_EVENT_TEXT` UTF-8 payload for insertion |
| Layout label from a keysym | Optional `key.codepoint` and `key.shifted` Unicode scalars |
Replace magic numbers and X11 symbols with named keys. For example, a quit
@@ -49,7 +73,7 @@ US A position on every layout; use layout labels when a command should follow
the printed letter instead. Do not cast key identities to characters. Keypad
Enter and ordinary Enter now have distinct identities without a separate flag.
-Text comes only from `YASL_INPUT_TEXT`. Handle its byte length, copy it when
+Text comes only from `YASL_EVENT_TEXT`. Handle its byte length, copy it when
retaining it after the next successful poll, and allow multiple characters per
commit. Cocoa sends key events through its text input manager; Wayland emits
ordinary XKB text and locale compose results in addition to IME commits.
@@ -57,7 +81,7 @@ ordinary XKB text and locale compose results in addition to IME commits.
## Scroll events
Replace `scroll_lines`, `scroll_delta`, and scroll button numbers with
-`mouse.scroll.x` and `.y` when `mouse.kind == YASL_PTR_SCROLL`. These double
+`pointer.scroll.x` and `.y` for `YASL_EVENT_POINTER_SCROLL`. These double
values are fractional line offsets, positive right/down on every backend.
Do not infer scroll direction from `button`. One event may include both axes.
Remove backend-specific sign inversions and whole-line casts; multiply the
diff --git a/examples/game.c b/examples/game.c
index 7ec28e1..065ff99 100644
--- a/examples/game.c
+++ b/examples/game.c
@@ -6,7 +6,7 @@
* - Continuous display-synchronized ticks (YASL_PACING_CONTINUOUS)
* - 3D software rendering (rotating shaded cube + starfield)
* - WASD continuous player movement & key state tracking
- * - Relative mouse mode (YASL_MOUSE_RELATIVE) for smooth first-person camera orbit
+ * - Relative pointer mode (YASL_POINTER_RELATIVE) for smooth first-person camera orbit
* - Spacebar toggles pointer lock (Relative vs Normal cursor)
* - Real-time FPS counter and frame latency display
* - Dynamic window resizing with automatic aspect ratio adjustment
@@ -140,7 +140,7 @@ static bool project_point(struct vec3 p, int w, int h, int *out_x, int *out_y)
return true;
}
-static int on_init(void *ud, struct yasl_display *d)
+static enum yasl_app_result on_init(void *ud, struct yasl_display *d)
{
struct game_state *game = ud;
game->display = d;
@@ -169,14 +169,13 @@ static int on_init(void *ud, struct yasl_display *d)
return YASL_APP_CONTINUE;
}
-static int on_event(void *ud, const struct yasl_event *ev)
+static enum yasl_app_result on_event(void *ud, const struct yasl_event *ev)
{
struct game_state *game = ud;
switch (ev->type) {
case YASL_EVENT_KEY: {
- bool down = (ev->key.action == YASL_KEY_PRESS || ev->key.action == YASL_KEY_REPEAT);
- if (ev->key.action == YASL_KEY_RELEASE) down = false;
+ bool down = ev->key.action != YASL_KEY_RELEASE;
switch (ev->key.key) {
case YASL_KEY_W: game->key_w = down; break;
@@ -187,17 +186,17 @@ static int on_event(void *ud, const struct yasl_event *ev)
case YASL_KEY_E: game->key_e = down; break;
case YASL_KEY_SPACE:
if (ev->key.action == YASL_KEY_PRESS) {
- /* Toggle relative mouse mode */
+ /* Toggle relative pointer mode */
game->relative_mouse = !game->relative_mouse;
- yasl_surface_set_mouse_mode(game->surface,
- game->relative_mouse ? YASL_MOUSE_RELATIVE : YASL_MOUSE_NORMAL);
+ yasl_surface_set_pointer_mode(game->surface,
+ game->relative_mouse ? YASL_POINTER_RELATIVE : YASL_POINTER_NORMAL);
}
break;
case YASL_KEY_ESCAPE:
if (ev->key.action == YASL_KEY_PRESS) {
if (game->relative_mouse) {
game->relative_mouse = false;
- yasl_surface_set_mouse_mode(game->surface, YASL_MOUSE_NORMAL);
+ yasl_surface_set_pointer_mode(game->surface, YASL_POINTER_NORMAL);
} else {
return YASL_APP_QUIT;
}
@@ -209,25 +208,25 @@ static int on_event(void *ud, const struct yasl_event *ev)
break;
}
- case YASL_EVENT_MOUSE_MOTION:
+ case YASL_EVENT_POINTER_MOTION:
if (game->relative_mouse) {
/* Smooth first-person camera orbit */
- game->cam_yaw += (float)ev->mouse_motion.delta.x * 0.005f;
- game->cam_pitch += (float)ev->mouse_motion.delta.y * 0.005f;
+ game->cam_yaw += (float)ev->pointer.delta.x * 0.005f;
+ game->cam_pitch += (float)ev->pointer.delta.y * 0.005f;
if (game->cam_pitch > 1.4f) game->cam_pitch = 1.4f;
if (game->cam_pitch < -1.4f) game->cam_pitch = -1.4f;
}
break;
- case YASL_EVENT_MOUSE_BUTTON:
- if (ev->mouse_button.pressed && !game->relative_mouse) {
+ case YASL_EVENT_POINTER_DOWN:
+ if (!game->relative_mouse) {
/* Click window to capture cursor */
game->relative_mouse = true;
- yasl_surface_set_mouse_mode(game->surface, YASL_MOUSE_RELATIVE);
+ yasl_surface_set_pointer_mode(game->surface, YASL_POINTER_RELATIVE);
}
break;
- case YASL_EVENT_WINDOW_CLOSE_REQUEST:
+ case YASL_EVENT_WINDOW_CLOSE:
return YASL_APP_QUIT;
default:
diff --git a/examples/hello.c b/examples/hello.c
index 4153394..ded4235 100644
--- a/examples/hello.c
+++ b/examples/hello.c
@@ -7,7 +7,7 @@ struct app {
bool failed;
};
-static int init(void *ud, struct yasl_display *display)
+static enum yasl_app_result init(void *ud, struct yasl_display *display)
{
struct yasl_window_spec spec = {.title = "Hello YASL", .size = {640, 480}};
struct yasl_surface *surface = yasl_surface_create_toplevel(display, &spec);
@@ -20,10 +20,10 @@ static int init(void *ud, struct yasl_display *display)
return YASL_APP_CONTINUE;
}
-static int event(void *ud, const struct yasl_event *event)
+static enum yasl_app_result event(void *ud, const struct yasl_event *event)
{
(void)ud;
- return event->type == YASL_EVENT_WINDOW_CLOSE_REQUEST ? YASL_APP_QUIT : YASL_APP_CONTINUE;
+ return event->type == YASL_EVENT_WINDOW_CLOSE ? YASL_APP_QUIT : YASL_APP_CONTINUE;
}
static void draw(void *ud, struct yasl_surface *surface, struct yasl_frame_context *frame)
diff --git a/examples/notepad.c b/examples/notepad.c
index 6fb90e9..ea74a27 100644
--- a/examples/notepad.c
+++ b/examples/notepad.c
@@ -990,7 +990,7 @@ static void prompt_execute(struct editor *ed)
}
/* YASL App callbacks */
-static int on_init(void *ud, struct yasl_display *d)
+static enum yasl_app_result on_init(void *ud, struct yasl_display *d)
{
struct editor *ed = ud;
ed->display = d;
@@ -1021,7 +1021,7 @@ static int on_init(void *ud, struct yasl_display *d)
return YASL_APP_CONTINUE;
}
-static int on_event(void *ud, const struct yasl_event *ev)
+static enum yasl_app_result on_event(void *ud, const struct yasl_event *ev)
{
struct editor *ed = ud;
@@ -1029,28 +1029,28 @@ static int on_event(void *ud, const struct yasl_event *ev)
case YASL_EVENT_TEXT:
if (ed->prompt != PROMPT_NONE) {
for (size_t i = 0; i < ev->text.len && ed->prompt_len < (int)sizeof(ed->prompt_buf) - 1; i++) {
- if (ev->text.text[i] >= 32 && ev->text.text[i] <= 126) {
- ed->prompt_buf[ed->prompt_len++] = ev->text.text[i];
+ if (ev->text.data[i] >= 32 && ev->text.data[i] <= 126) {
+ ed->prompt_buf[ed->prompt_len++] = ev->text.data[i];
ed->prompt_buf[ed->prompt_len] = '\0';
}
}
} else {
- insert_text(ed, ev->text.text, ev->text.len);
+ insert_text(ed, ev->text.data, ev->text.len);
}
yasl_surface_request_frame(ed->surface);
break;
case YASL_EVENT_PASTE:
- if (ev->paste.text && ev->paste.len > 0) {
- insert_text(ed, ev->paste.text, ev->paste.len);
+ if (ev->text.data && ev->text.len > 0) {
+ insert_text(ed, ev->text.data, ev->text.len);
yasl_surface_request_frame(ed->surface);
}
break;
- case YASL_EVENT_DROP_FILES:
- if (ev->drop_files.files && ev->drop_files.len > 0) {
+ case YASL_EVENT_DROP:
+ if (ev->text.data && ev->text.len > 0) {
char path[512];
- decode_uri_path(ev->drop_files.files, path, sizeof(path));
+ decode_uri_path(ev->text.data, path, sizeof(path));
if (path[0]) {
editor_open_file(ed, path);
yasl_surface_request_frame(ed->surface);
@@ -1287,34 +1287,34 @@ static int on_event(void *ud, const struct yasl_event *ev)
}
break;
- case YASL_EVENT_MOUSE_BUTTON: {
- struct yasl_geometry geom = yasl_surface_geometry(ed->surface);
- int scale = (geom.scale_120 >= 240 ? 2 : 1) + ed->zoom_offset;
- if (scale < 1) scale = 1;
- int char_w = 8 * scale;
- int line_h = 16 * scale;
- int gutter_w = 48 * scale;
- int header_h = 24 * scale;
-
- int row = (ev->mouse_button.pos.y - header_h) / line_h + ed->scroll_y;
- int col = (ev->mouse_button.pos.x - gutter_w) / char_w + (ed->word_wrap ? 0 : ed->scroll_x);
- if (row < 0) row = 0;
- if (row >= ed->line_count) row = ed->line_count - 1;
- int len = (int)strlen(ed->lines[row]);
- if (col < 0) col = 0;
- if (col > len) col = len;
-
- if (ev->mouse_button.pressed && ev->mouse_button.button == 0) {
+ case YASL_EVENT_POINTER_DOWN: {
+ if (ev->pointer.button == YASL_BUTTON_PRIMARY) {
+ struct yasl_geometry geom = yasl_surface_geometry(ed->surface);
+ int scale = (geom.scale_120 >= 240 ? 2 : 1) + ed->zoom_offset;
+ if (scale < 1) scale = 1;
+ int char_w = 8 * scale;
+ int line_h = 16 * scale;
+ int gutter_w = 48 * scale;
+ int header_h = 24 * scale;
+
+ int row = (ev->pointer.pos.y - header_h) / line_h + ed->scroll_y;
+ int col = (ev->pointer.pos.x - gutter_w) / char_w + (ed->word_wrap ? 0 : ed->scroll_x);
+ if (row < 0) row = 0;
+ if (row >= ed->line_count) row = ed->line_count - 1;
+ int len = (int)strlen(ed->lines[row]);
+ if (col < 0) col = 0;
+ if (col > len) col = len;
+
uint64_t now = yasl_loop_now_ns();
if (now - ed->last_click_time < 350000000ull &&
- abs(ev->mouse_button.pos.x - ed->last_click_pos.x) < 8 &&
- abs(ev->mouse_button.pos.y - ed->last_click_pos.y) < 8) {
+ abs(ev->pointer.pos.x - ed->last_click_pos.x) < 8 &&
+ abs(ev->pointer.pos.y - ed->last_click_pos.y) < 8) {
ed->click_count++;
} else {
ed->click_count = 1;
}
ed->last_click_time = now;
- ed->last_click_pos = ev->mouse_button.pos;
+ ed->last_click_pos = ev->pointer.pos;
if (ed->click_count == 2) {
/* Double click: select word */
@@ -1340,13 +1340,17 @@ static int on_event(void *ud, const struct yasl_event *ev)
}
ed->caret_visible = true;
yasl_surface_request_frame(ed->surface);
- } else if (!ev->mouse_button.pressed && ev->mouse_button.button == 0) {
- ed->mouse_dragging = false;
}
break;
}
- case YASL_EVENT_MOUSE_MOTION:
+ case YASL_EVENT_POINTER_UP:
+ if (ev->pointer.button == YASL_BUTTON_PRIMARY) {
+ ed->mouse_dragging = false;
+ }
+ break;
+
+ case YASL_EVENT_POINTER_MOTION:
if (ed->mouse_dragging) {
struct yasl_geometry geom = yasl_surface_geometry(ed->surface);
int scale = (geom.scale_120 >= 240 ? 2 : 1) + ed->zoom_offset;
@@ -1356,8 +1360,8 @@ static int on_event(void *ud, const struct yasl_event *ev)
int gutter_w = 48 * scale;
int header_h = 24 * scale;
- int row = (ev->mouse_motion.pos.y - header_h) / line_h + ed->scroll_y;
- int col = (ev->mouse_motion.pos.x - gutter_w) / char_w + (ed->word_wrap ? 0 : ed->scroll_x);
+ int row = (ev->pointer.pos.y - header_h) / line_h + ed->scroll_y;
+ int col = (ev->pointer.pos.x - gutter_w) / char_w + (ed->word_wrap ? 0 : ed->scroll_x);
if (row < 0) row = 0;
if (row >= ed->line_count) row = ed->line_count - 1;
int len = (int)strlen(ed->lines[row]);
@@ -1371,18 +1375,18 @@ static int on_event(void *ud, const struct yasl_event *ev)
}
break;
- case YASL_EVENT_MOUSE_SCROLL:
- if (ev->mouse_scroll.mods & (YASL_MOD_CTRL | YASL_MOD_SUPER)) {
+ case YASL_EVENT_POINTER_SCROLL:
+ if (ev->pointer.mods & (YASL_MOD_CTRL | YASL_MOD_SUPER)) {
/* Ctrl + Wheel = Zoom */
- if (ev->mouse_scroll.scroll.y > 0 && ed->zoom_offset < 2) ed->zoom_offset++;
- else if (ev->mouse_scroll.scroll.y < 0 && ed->zoom_offset > -1) ed->zoom_offset--;
- } else if (ev->mouse_scroll.mods & YASL_MOD_SHIFT) {
+ if (ev->pointer.scroll.y > 0 && ed->zoom_offset < 2) ed->zoom_offset++;
+ else if (ev->pointer.scroll.y < 0 && ed->zoom_offset > -1) ed->zoom_offset--;
+ } else if (ev->pointer.mods & YASL_MOD_SHIFT) {
/* Shift + Wheel = Horizontal scroll */
- ed->scroll_x -= (int)(ev->mouse_scroll.scroll.y * 3.0);
+ ed->scroll_x -= (int)(ev->pointer.scroll.y * 3.0);
if (ed->scroll_x < 0) ed->scroll_x = 0;
} else {
/* Normal vertical scroll */
- ed->scroll_y -= (int)(ev->mouse_scroll.scroll.y * 3.0);
+ ed->scroll_y -= (int)(ev->pointer.scroll.y * 3.0);
if (ed->scroll_y < 0) ed->scroll_y = 0;
if (ed->scroll_y >= ed->line_count) ed->scroll_y = ed->line_count - 1;
}
@@ -1390,7 +1394,7 @@ static int on_event(void *ud, const struct yasl_event *ev)
break;
case YASL_EVENT_USER:
- if (ev->user.type == MSG_STATS_READY && ev->user.payload) {
+ if (ev->user.code == MSG_STATS_READY && ev->user.payload) {
struct doc_stats *s = (struct doc_stats *)ev->user.payload;
ed->stats = *s;
free(s);
@@ -1398,7 +1402,7 @@ static int on_event(void *ud, const struct yasl_event *ev)
}
break;
- case YASL_EVENT_WINDOW_CLOSE_REQUEST:
+ case YASL_EVENT_WINDOW_CLOSE:
return YASL_APP_QUIT;
default:
diff --git a/examples/simple_window.c b/examples/simple_window.c
index e9e6545..fca2f75 100644
--- a/examples/simple_window.c
+++ b/examples/simple_window.c
@@ -87,7 +87,7 @@ static void on_draw(void *ud, struct yasl_surface *s, struct yasl_frame_context
if (failed || smoke_test) yasl_surface_destroy(s);
}
-static int on_init(void *ud, struct yasl_display *display)
+static enum yasl_app_result on_init(void *ud, struct yasl_display *display)
{
(void)ud;
struct yasl_window_spec window_spec = {
@@ -123,19 +123,19 @@ static void pointer_sample(struct yasl_vector2i pos, enum yasl_pointer_device de
pen_tilt_y = pen.tilt_y;
}
-static int on_event(void *ud, const struct yasl_event *ev)
+static enum yasl_app_result on_event(void *ud, const struct yasl_event *ev)
{
(void)ud;
switch (ev->type) {
- case YASL_EVENT_WINDOW_CLOSE_REQUEST:
+ case YASL_EVENT_WINDOW_CLOSE:
return YASL_APP_QUIT;
case YASL_EVENT_WINDOW_RESIZE: {
uint32_t flags = yasl_surface_state(ev->surface);
const char *mode = flags & YASL_STATE_FULLSCREEN ? "fullscreen" :
flags & YASL_STATE_MAXIMIZED ? "maximized" :
flags & YASL_STATE_TILED ? "tiled" : "windowed";
- printf("[YASL] Resized to %dx%d (scale: %.2fx, %s)\n", ev->resize.size.x,
- ev->resize.size.y, (double)ev->resize.scale_120 / YASL_SCALE_UNIT, mode);
+ printf("[YASL] Resized to %dx%d (scale: %.2fx, %s)\n", ev->resize.geometry.size.x,
+ ev->resize.geometry.size.y, (double)ev->resize.geometry.scale_120 / YASL_SCALE_UNIT, mode);
break;
}
case YASL_EVENT_KEY:
@@ -144,22 +144,23 @@ static int on_event(void *ud, const struct yasl_event *ev)
if (ev->key.key == YASL_KEY_SPACE || ev->key.key == YASL_KEY_ENTER)
color_theme++;
break;
- case YASL_EVENT_MOUSE_BUTTON:
- pointer_sample(ev->mouse_button.pos, ev->mouse_button.device, ev->mouse_button.pen);
- if (ev->mouse_button.button == 0) {
- mouse_down = ev->mouse_button.pressed;
- if (!mouse_down) pen_pressure = 0;
+ case YASL_EVENT_POINTER_DOWN:
+ case YASL_EVENT_POINTER_UP:
+ case YASL_EVENT_POINTER_MOTION:
+ pointer_sample(ev->pointer.pos, ev->pointer.device, ev->pointer.pen);
+ if (ev->type == YASL_EVENT_POINTER_DOWN && ev->pointer.button == YASL_BUTTON_PRIMARY) {
+ mouse_down = true;
+ } else if (ev->type == YASL_EVENT_POINTER_UP && ev->pointer.button == YASL_BUTTON_PRIMARY) {
+ mouse_down = false;
+ pen_pressure = 0;
}
break;
- case YASL_EVENT_MOUSE_MOTION:
- pointer_sample(ev->mouse_motion.pos, ev->mouse_motion.device, ev->mouse_motion.pen);
- break;
- case YASL_EVENT_WINDOW_FOCUS:
+ case YASL_EVENT_FOCUS:
if (ev->focus.focused) return YASL_APP_CONTINUE;
/* Fall through to cancel held input on focus loss. */
[[fallthrough]];
case YASL_EVENT_INPUT_RESET:
- case YASL_EVENT_MOUSE_LEAVE:
+ case YASL_EVENT_POINTER_LEAVE:
mouse_x = mouse_y = -1;
mouse_down = false;
pen_pressure = 0;
diff --git a/examples/tablet.c b/examples/tablet.c
index f392cdc..01dcdfc 100644
--- a/examples/tablet.c
+++ b/examples/tablet.c
@@ -140,44 +140,40 @@ static void stroke(struct app *app)
app->previous = true;
}
-static int input(void *ud, const struct yasl_event *event)
+static enum yasl_app_result input(void *ud, const struct yasl_event *event)
{
struct app *app = ud;
- if (event->type == YASL_EVENT_WINDOW_CLOSE_REQUEST)
+ if (event->type == YASL_EVENT_WINDOW_CLOSE)
return YASL_APP_QUIT;
if (event->type == YASL_EVENT_WINDOW_RESIZE) {
- if (!resize_canvas(app, (struct yasl_geometry){event->resize.size, event->resize.scale_120})) {
+ if (!resize_canvas(app, event->resize.geometry)) {
app->failed = true;
return YASL_APP_QUIT;
}
- } else if (event->type == YASL_EVENT_INPUT_RESET || event->type == YASL_EVENT_MOUSE_LEAVE ||
- (event->type == YASL_EVENT_WINDOW_FOCUS && !event->focus.focused)) {
+ } else if (event->type == YASL_EVENT_INPUT_RESET || event->type == YASL_EVENT_POINTER_LEAVE ||
+ (event->type == YASL_EVENT_FOCUS && !event->focus.focused)) {
cancel_stroke(app);
} else if (event->type == YASL_EVENT_KEY && event->key.action == YASL_KEY_PRESS) {
if (event->key.key == YASL_KEY_ESCAPE) return YASL_APP_QUIT;
if (event->key.key == YASL_KEY_C || event->key.key == YASL_KEY_SPACE)
clear_canvas(app);
- } else if (event->type == YASL_EVENT_MOUSE_BUTTON) {
- if (app->pointer.device != event->mouse_button.device) cancel_stroke(app);
- app->pointer.pos = event->mouse_button.pos;
- app->pointer.device = event->mouse_button.device;
- app->pointer.pen = event->mouse_button.pen;
+ } else if (event->type == YASL_EVENT_POINTER_DOWN || event->type == YASL_EVENT_POINTER_UP ||
+ event->type == YASL_EVENT_POINTER_MOTION) {
+ if (app->pointer.device != event->pointer.device) cancel_stroke(app);
+ app->pointer.pos = event->pointer.pos;
+ app->pointer.device = event->pointer.device;
+ app->pointer.pen = event->pointer.pen;
app->visible = true;
- if (event->mouse_button.pressed && event->mouse_button.button == 0) {
+ if (event->type == YASL_EVENT_POINTER_DOWN && event->pointer.button == YASL_BUTTON_PRIMARY) {
app->down = true;
app->previous = false;
stroke(app);
- } else if (!event->mouse_button.pressed && event->mouse_button.button == 0) {
+ } else if (event->type == YASL_EVENT_POINTER_UP && event->pointer.button == YASL_BUTTON_PRIMARY) {
app->down = app->previous = false;
app->pointer.pen.pressure = 0;
+ } else if (event->type == YASL_EVENT_POINTER_MOTION) {
+ if (app->down) stroke(app);
}
- } else if (event->type == YASL_EVENT_MOUSE_MOTION) {
- if (app->pointer.device != event->mouse_motion.device) cancel_stroke(app);
- app->pointer.pos = event->mouse_motion.pos;
- app->pointer.device = event->mouse_motion.device;
- app->pointer.pen = event->mouse_motion.pen;
- app->visible = true;
- if (app->down) stroke(app);
} else {
return YASL_APP_CONTINUE;
}
@@ -293,7 +289,7 @@ static void draw(void *ud, struct yasl_surface *surface, struct yasl_frame_conte
}
}
-static int init(void *ud, struct yasl_display *display)
+static enum yasl_app_result init(void *ud, struct yasl_display *display)
{
struct app *app = ud;
app->backend = yasl_display_backend(display);
@@ -307,7 +303,7 @@ static int init(void *ud, struct yasl_display *display)
app->failed = true;
return YASL_APP_QUIT;
}
- yasl_surface_set_mouse_mode(app->surface, YASL_MOUSE_HIDDEN);
+ yasl_surface_set_cursor(app->surface, YASL_CURSOR_HIDDEN);
yasl_surface_request_frame(app->surface);
printf("YASL tablet on %s: pressure changes brush width; eraser removes ink.\n"
"Mouse: fixed-width drawing. C/Space: clear. Escape: quit.\n",
diff --git a/include/yasl/app.h b/include/yasl/app.h
index 112140d..f067d5b 100644
--- a/include/yasl/app.h
+++ b/include/yasl/app.h
@@ -41,114 +41,6 @@ typedef enum yasl_pacing_mode {
YASL_PACING_CONTINUOUS,
} yasl_pacing_mode;
-/** Mouse capture and virtualization modes. */
-typedef enum yasl_mouse_mode {
- YASL_MOUSE_NORMAL = 0, /**< Standard visible pointer. */
- YASL_MOUSE_HIDDEN, /**< Hidden cursor, normal bounded window coordinates. */
- YASL_MOUSE_RELATIVE, /**< Relative pointer lock: cursor hidden, unbounded deltas. */
-} yasl_mouse_mode;
-
-/** Unified event types delivered to the application event callback. */
-typedef enum yasl_event_type {
- YASL_EVENT_NONE = 0,
-
- /* Input events */
- YASL_EVENT_KEY,
- YASL_EVENT_TEXT,
- YASL_EVENT_MOUSE_BUTTON,
- YASL_EVENT_MOUSE_MOTION,
- YASL_EVENT_MOUSE_SCROLL,
- YASL_EVENT_MOUSE_LEAVE,
-
- /* Window lifecycle events */
- YASL_EVENT_WINDOW_RESIZE,
- YASL_EVENT_WINDOW_SCALE_CHANGED,
- YASL_EVENT_WINDOW_CLOSE_REQUEST,
- YASL_EVENT_WINDOW_FOCUS,
-
- /* System & external events */
- YASL_EVENT_PASTE,
- YASL_EVENT_DROP_FILES,
- YASL_EVENT_USER,
- YASL_EVENT_INPUT_RESET, /**< Input interrupted; clear held keys/buttons and composition. */
-} yasl_event_type;
-
-/** Unified event payload delivered to yasl_app_desc.event(). */
-struct yasl_event {
- struct yasl_surface *surface; /**< Associated surface, or NULL for display-wide events. */
- yasl_event_type type;
-
- union {
- struct {
- enum yasl_key key;
- enum yasl_key_action action;
- uint32_t mods;
- uint32_t codepoint;
- uint32_t shifted;
- uint32_t native_code;
- bool repeat; /**< true if this press is generated by OS autorepeat. */
- } key;
-
- struct {
- const char *text; /**< UTF-8 text string; borrowed for callback duration. */
- size_t len; /**< Length in bytes excluding terminating NUL. */
- } text;
-
- struct {
- struct yasl_vector2i pos; /**< Device-pixel position relative to surface. */
- enum yasl_pointer_device device; /**< Mouse, touch, pen, or eraser. */
- int16_t button; /**< 0 primary, 1 middle, 2 secondary. */
- bool pressed; /**< true for press, false for release. */
- uint32_t mods;
- struct yasl_pointer_pen pen;
- } mouse_button;
-
- struct {
- struct yasl_vector2i pos; /**< Device-pixel position relative to surface. */
- struct yasl_vector2i delta; /**< Relative motion delta (dx, dy). */
- enum yasl_pointer_device device; /**< Mouse, touch, pen, or eraser. */
- uint32_t mods;
- struct yasl_pointer_pen pen;
- } mouse_motion;
-
- struct {
- struct yasl_vector2i pos;
- struct yasl_vector2d scroll; /**< Fractional line units; positive right/down. */
- uint32_t mods;
- } mouse_scroll;
-
- struct {
- struct yasl_vector2i size; /**< Configured content extent in device pixels. */
- uint32_t scale_120;
- } resize;
-
- struct {
- uint32_t scale_120;
- struct yasl_vector2i size;
- } scale;
-
- struct {
- bool focused;
- } focus;
-
- struct {
- const char *text; /**< UTF-8 text from clipboard. */
- size_t len;
- } paste;
-
- struct {
- const char *files; /**< NUL-terminated text/uri-list. */
- size_t len;
- } drop_files;
-
- struct {
- uint32_t type; /**< Application-defined message type. */
- void *payload; /**< User-defined payload pointer. */
- size_t size; /**< Optional payload size. */
- } user;
- };
-};
-
/** Frame context provided to yasl_app_desc.frame() during presentation. */
struct yasl_frame_context {
struct yasl_surface *surface;
@@ -199,24 +91,17 @@ YASL_API void yasl_surface_set_pacing(struct yasl_surface *s, yasl_pacing_mode m
YASL_API void yasl_surface_request_frame(struct yasl_surface *s);
/**
- * Configure mouse pointer capture / virtualization mode.
- * @param s Surface.
- * @param mode Normal, hidden, or relative pointer lock.
- */
-YASL_API void yasl_surface_set_mouse_mode(struct yasl_surface *s, yasl_mouse_mode mode);
-
-/**
* Safely post a custom user event to the main event loop from ANY thread.
* Wakes the display loop and delivers YASL_EVENT_USER to the event callback.
* @param d Display.
* @param s Optional target surface, or NULL.
- * @param user_type Application-defined message type.
+ * @param code Application-defined message code (yasl_user_event.code).
* @param payload Arbitrary pointer passed through to the event.
* @param size Optional payload size.
* @return true if queued successfully, false if queue is full or memory failed.
*/
YASL_API 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);
/**
* Watch an open file descriptor or socket for poll-style readiness in the main loop.
@@ -269,15 +154,15 @@ struct yasl_app_desc {
* Use this to create windows and initialize application resources.
* Return YASL_APP_CONTINUE or YASL_APP_QUIT.
*/
- int (*init)(void *ud, struct yasl_display *d);
+ enum yasl_app_result (*init)(void *ud, struct yasl_display *d);
/**
- * Unified event handler called for input, resize, close, scale, and custom events.
+ * Unified event handler for input, window and user events, in arrival order.
* Event payloads and borrowed strings are valid for the duration of the callback.
* INPUT_RESET has no payload and requires clearing held application input.
* Return YASL_APP_CONTINUE or YASL_APP_QUIT.
*/
- int (*event)(void *ud, const struct yasl_event *ev);
+ enum yasl_app_result (*event)(void *ud, const struct yasl_event *ev);
/**
* Invoked when a surface needs to present a frame.
diff --git a/include/yasl/keycodes.h b/include/yasl/keycodes.h
index 7586945..d34aeae 100644
--- a/include/yasl/keycodes.h
+++ b/include/yasl/keycodes.h
@@ -2,7 +2,7 @@
* @file
* Portable physical keyboard identities, included by yasl/yasl.h.
* Letter/punctuation names describe positions on a US keyboard, regardless of
- * active layout or modifiers. Use YASL_INPUT_TEXT for text and codepoint/shifted
+ * active layout or modifiers. Use YASL_EVENT_TEXT for text and codepoint/shifted
* in yasl_key_event for layout labels. These values are neither Unicode nor
* native scancodes; do not derive a character from a key enumerator.
*/
diff --git a/include/yasl/yasl.h b/include/yasl/yasl.h
index 3b3b712..22ed308 100644
--- a/include/yasl/yasl.h
+++ b/include/yasl/yasl.h
@@ -282,15 +282,6 @@ enum yasl_mod : uint32_t {
YASL_MOD_CAPS = 1 << 4, /**< Caps Lock modifier. */
};
-/** Pointer transition or motion type; fields are meaningful according to this tag. */
-enum yasl_pointer_kind {
- YASL_PTR_PRESS, /**< Button/tip pressed. */
- YASL_PTR_RELEASE, /**< Button/tip released. */
- YASL_PTR_MOTION, /**< Position or tablet axes changed. */
- YASL_PTR_LEAVE, /**< Pointer/tool left the surface. */
- YASL_PTR_SCROLL, /**< Scroll sample. */
-};
-
/** Pointer source class; capability support does not imply an attached device. */
enum yasl_pointer_device {
YASL_PTR_DEV_MOUSE, /**< Mouse or trackpad pointer. */
@@ -299,6 +290,24 @@ enum yasl_pointer_device {
YASL_PTR_DEV_ERASER, /**< Tablet eraser tool. */
};
+/** Pointer button; meaningful only for POINTER_DOWN and POINTER_UP. */
+enum yasl_pointer_button {
+ YASL_BUTTON_PRIMARY = 0, /**< Left button, pen tip, or touch contact. */
+ YASL_BUTTON_MIDDLE = 1, /**< Middle button / wheel click. */
+ YASL_BUTTON_SECONDARY = 2, /**< Right button or pen barrel button. */
+ YASL_BUTTON_BACK = 3, /**< Side "back" button. */
+ YASL_BUTTON_FORWARD = 4, /**< Side "forward" button. */
+};
+
+/** Pointer capture mode for a surface. */
+enum yasl_pointer_mode {
+ YASL_POINTER_NORMAL = 0, /**< Absolute positions; cursor per yasl_surface_set_cursor(). */
+ /** Cursor hidden and locked in place while the surface has focus. POINTER_MOTION
+ * reports unbounded relative motion in delta; pos stays at the lock position.
+ * The lock is released on focus loss and re-acquired on focus gain. */
+ YASL_POINTER_RELATIVE,
+};
+
/** Normalized tablet axes; zero for unavailable axes and non-tablet devices. */
struct yasl_pointer_pen {
/** 0..65535 normalized to device range. Zero alone does not end contact. */
@@ -309,13 +318,36 @@ struct yasl_pointer_pen {
int8_t tilt_y;
};
+/** Event tag. Each tag lists the union member it selects. */
+enum yasl_event_type {
+ YASL_EVENT_NONE = 0,
+
+ /* Input: produced by backends, returned by yasl_surface_poll_event(). */
+ YASL_EVENT_KEY, /**< .key */
+ YASL_EVENT_TEXT, /**< .text — committed UTF-8; insert this, not key codepoints. */
+ YASL_EVENT_POINTER_DOWN, /**< .pointer — button/tip pressed; button valid. */
+ YASL_EVENT_POINTER_UP, /**< .pointer — button/tip released; button valid. */
+ YASL_EVENT_POINTER_MOTION, /**< .pointer — position, relative motion, or pen axes changed. */
+ YASL_EVENT_POINTER_SCROLL, /**< .pointer — scroll valid. */
+ YASL_EVENT_POINTER_LEAVE, /**< .pointer — last known pos/device; cancel hover state. */
+ YASL_EVENT_FOCUS, /**< .focus — keyboard focus changed; cancel held state on loss. */
+ YASL_EVENT_PASTE, /**< .text — UTF-8 from yasl_display_paste(). */
+ YASL_EVENT_DROP, /**< .text — dropped text/uri-list: CRLF-separated file URLs, not paths. */
+ YASL_EVENT_INPUT_RESET, /**< No payload. Input stream interrupted; clear held keys, buttons, strokes, IME. */
+
+ /* Window and application: delivered only through yasl_app_desc.event().
+ * Low-level users receive the same information via yasl_window_cbs. */
+ YASL_EVENT_WINDOW_RESIZE, /**< .resize — size and/or scale changed; reallocate and redraw. */
+ YASL_EVENT_WINDOW_CLOSE, /**< No payload. User asked to close the window. */
+ YASL_EVENT_USER, /**< .user — posted with yasl_post_event(). */
+};
+
/** Physical keyboard transition with optional layout labels.
* key is independent of modifiers/layout and stable between press and release.
* codepoint and shifted are optional single Unicode scalars for the current
* layout at levels zero/one, not text input. Zero means unavailable, a control
- * key, or a layout mapping that produces multiple characters. Native scancodes
- * are backend-specific. Insert committed YASL_INPUT_TEXT into documents.
- */
+ * key, or a layout mapping that produces multiple characters. Insert committed
+ * YASL_EVENT_TEXT into documents instead. */
struct yasl_key_event {
/** Portable physical key; YASL_KEY_UNKNOWN when unmapped. */
enum yasl_key key;
@@ -331,89 +363,75 @@ struct yasl_key_event {
uint32_t native_code;
};
-/** Pointer sample. Pen and eraser events share this structure with mouse input.
-Track contact with primary press/release, not pressure alone. Leave, focus loss,
-and YASL_INPUT_RESET must cancel held application input state. This is not a
-multi-contact touch API. Scroll offsets use fractional line units: positive x
-means right and positive y means down, after system scroll preferences. */
-struct yasl_mouse_event {
- /** Surface-relative device-pixel position. */
+/** Pointer sample shared by all POINTER_* events. Pen and eraser share it with
+ * mouse input. Track contact with DOWN/UP of the primary button, not pressure.
+ * This is not a multi-contact touch API. */
+struct yasl_pointer_event {
+ /** Surface-relative device-pixel position. Frozen while YASL_POINTER_RELATIVE is locked. */
struct yasl_vector2i pos;
- /** Press/release: 0 primary/tip, 1 middle, 2 secondary. Unused for scroll. */
- int16_t button;
- /** Sample type. */
- enum yasl_pointer_kind kind;
+ /** MOTION: device-pixel movement since the previous sample on this surface.
+ * Unbounded under YASL_POINTER_RELATIVE; zero after enter, leave, or reset. */
+ struct yasl_vector2d delta;
+ /** SCROLL: fractional line offsets after system preferences; positive right/down. */
+ struct yasl_vector2d scroll;
+ /** DOWN/UP: which button changed. */
+ enum yasl_pointer_button button;
/** Mouse, touch, pen, or eraser. */
enum yasl_pointer_device device;
/** yasl_mod bitmask at this event. */
uint32_t mods;
- /** Fractional line offsets, valid for SCROLL only; positive right/down. */
- struct yasl_vector2d scroll;
-
/** Current tablet axes, including on pressure-only motion; missing axes are zero. */
struct yasl_pointer_pen pen;
};
-/** Input union tag. RESET has no payload and requires clearing held state. */
-enum yasl_input_kind {
- YASL_INPUT_KEY, /**< key member. */
- YASL_INPUT_MOUSE, /**< mouse member. */
- YASL_INPUT_FOCUS, /**< focus member. */
- YASL_INPUT_PASTE, /**< paste member. */
- YASL_INPUT_DROP_FILES, /**< drop_files member. */
- YASL_INPUT_TEXT, /**< text member, containing committed UTF-8. */
- /* The input stream was interrupted (e.g. allocation failure or device
- * removal). Clear held keys/buttons and composition state. */
- YASL_INPUT_RESET, /**< No payload. Clear held keys/buttons and composition after an interruption. */
+/** Borrowed NUL-terminated UTF-8, shared by TEXT, PASTE and DROP. */
+struct yasl_text_event {
+ /** Borrowed NUL-terminated bytes; see yasl_surface_poll_event() for lifetime. */
+ const char *data;
+ /** Length in bytes excluding the terminating NUL. */
+ size_t len;
};
-/** Keyboard focus transition; cancel held state when focus is lost. */
+/** Keyboard focus transition. */
struct yasl_focus_event {
/** true on focus gain, false on loss. */
bool focused;
};
-/** Committed UTF-8 text; insert this instead of deriving characters from key events. */
-struct yasl_text_event {
- /** Borrowed NUL-terminated UTF-8. */
- const char *text;
- /** Length in bytes excluding the terminating NUL. */
- size_t len;
+/** New configured geometry for a surface. */
+struct yasl_resize_event {
+ /** Content size in device pixels and display scale. */
+ struct yasl_geometry geometry;
+ /** true when scale_120 differs from the previous resize of this surface. */
+ bool scale_changed;
};
-/** UTF-8 text received from an explicit selection request. */
-struct yasl_paste_event {
- /** Borrowed NUL-terminated UTF-8. */
- const char *text;
- /** Length in bytes excluding the terminating NUL. */
- size_t len;
+/** Application message posted with yasl_post_event(). */
+struct yasl_user_event {
+ /** Application-defined message code. */
+ uint32_t code;
+ /** Pointer passed through unchanged; ownership stays with the application. */
+ void *payload;
+ /** Optional payload size, passed through unchanged. */
+ size_t size;
};
-/** File URLs in text/uri-list form, separated by CRLF; not filesystem paths. */
-struct yasl_drop_files_event {
- /** Borrowed NUL-terminated text/uri-list; parse URLs and percent escapes. */
- const char *files;
- /** Length in bytes excluding the terminating NUL. */
- size_t len;
-};
-
-/** One tagged input event; read only the union member selected by kind.
-Payload strings follow yasl_surface_input_poll() lifetime rules. RESET carries
-no union payload; clear keys, buttons, strokes, and composition state. */
-struct yasl_input_event {
- /** Recipient; can differ from the polled surface for routed popup input. */
- struct yasl_surface *surface;
+/** One tagged event; read only the union member selected by type. */
+struct yasl_event {
/** Selects the valid union member. */
- enum yasl_input_kind kind;
- /** Reserved for YASL; applications must not interpret it. */
- uint32_t reserved;
+ enum yasl_event_type type;
+ /** Recipient surface, or NULL for display-wide events. Can differ from the
+ * polled surface for routed popup input. */
+ struct yasl_surface *surface;
+ /** Monotonic timestamp in nanoseconds, same clock as yasl_loop_now_ns(). */
+ uint64_t time_ns;
union {
- struct yasl_key_event key; /**< Keyboard payload. */
- struct yasl_mouse_event mouse; /**< Pointer payload. */
- struct yasl_focus_event focus; /**< Focus payload. */
- struct yasl_text_event text; /**< Committed text payload. */
- struct yasl_paste_event paste; /**< Selection text payload. */
- struct yasl_drop_files_event drop_files; /**< File URL list payload. */
+ struct yasl_key_event key; /**< KEY */
+ struct yasl_pointer_event pointer; /**< POINTER_* */
+ struct yasl_text_event text; /**< TEXT, PASTE, DROP */
+ struct yasl_focus_event focus; /**< FOCUS */
+ struct yasl_resize_event resize; /**< WINDOW_RESIZE */
+ struct yasl_user_event user; /**< USER */
};
};
@@ -556,7 +574,7 @@ YASL_API void yasl_display_copy(struct yasl_display *d, enum yasl_selection sel,
* @param d Display that owns target.
* @param sel YASL_CLIPBOARD or YASL_PRIMARY.
* @param target Destination surface; NULL or a surface on another display does nothing.
- * Results arrive as YASL_INPUT_PASTE, possibly during a later dispatch. No result
+ * Results arrive as YASL_EVENT_PASTE, possibly during a later dispatch. No result
* is promised for unavailable data or a failed transfer. Destroying target cancels
* delivery. Unsupported selections do nothing.
*/
@@ -722,18 +740,29 @@ YASL_API bool yasl_surface_present(struct yasl_surface *s, const struct yasl_fra
* the next SUCCESSFUL poll on this surface or surface destruction. Dispatch,
* flush and unsuccessful polls do not invalidate them. Copy to keep longer. */
/**
- * Remove one event from a surface's input queue without waiting.
+ * Remove one input event from a surface's queue without waiting.
* @param s Surface whose queue to drain.
* @param ev Required output event; unchanged when no event is available.
* @return true for an event, false for an empty queue or NULL arguments.
- * Dispatch receives native input; polling only drains the queue. Read the union
- * member selected by kind. Payload strings are borrowed, NUL-terminated, and
- * valid until the next successful poll on this queue or its destruction; dispatch,
- * flush, and unsuccessful polls do not invalidate them. On Wayland, popup pointer
- * and keyboard input can be routed through the root parent's queue; inspect
+ * Dispatch receives native input; polling only drains the queue. Only input
+ * types (KEY through INPUT_RESET) are returned. Read the union member selected
+ * by type. Payload strings are borrowed, NUL-terminated, and valid until the
+ * next successful poll on this queue or its destruction; dispatch, flush, and
+ * unsuccessful polls do not invalidate them. On Wayland, popup pointer and
+ * keyboard input can be routed through the root parent's queue; inspect
* ev->surface to identify the receiving surface.
*/
-YASL_API bool yasl_surface_input_poll(struct yasl_surface *s, struct yasl_input_event *ev);
+YASL_API bool yasl_surface_poll_event(struct yasl_surface *s, struct yasl_event *ev);
+/**
+ * Select absolute or relative (locked) pointer input for a surface.
+ * @param s Surface.
+ * @param mode YASL_POINTER_NORMAL or YASL_POINTER_RELATIVE.
+ * @return true if the mode is supported by the backend; false leaves NORMAL.
+ * RELATIVE hides the cursor and locks it while the surface is focused;
+ * POINTER_MOTION then carries unbounded delta. Returning to NORMAL restores
+ * the cursor selected with yasl_surface_set_cursor().
+ */
+YASL_API bool yasl_surface_set_pointer_mode(struct yasl_surface *s, enum yasl_pointer_mode mode);
/* Current device-pixel size and scale, matching the configure callback. */
/**
@@ -794,7 +823,7 @@ YASL_API void yasl_surface_set_background_color(struct yasl_surface *s, uint32_t
* @param s Surface, or NULL.
* @return Borrowed NUL-terminated text, or NULL if absent/unsupported.
* Copy to retain across the next dispatch or surface destruction. Composition
- * changes can schedule a redraw. Insert committed YASL_INPUT_TEXT into documents,
+ * changes can schedule a redraw. Insert committed YASL_EVENT_TEXT into documents,
* not preedit text.
*/
YASL_API const char *yasl_surface_ime_preedit(const struct yasl_surface *s);
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
diff --git a/src/platform/cocoa/api.h b/src/platform/cocoa/api.h
index 0f705dd..eaacc01 100644
--- a/src/platform/cocoa/api.h
+++ b/src/platform/cocoa/api.h
@@ -24,7 +24,7 @@ void cocoa_surface_set_callbacks(struct cocoa_surface *s, const struct yasl_wind
void cocoa_surface_set_title(struct cocoa_surface *s, const char *title);
void cocoa_surface_schedule_redraw(struct cocoa_surface *s);
bool cocoa_surface_present(struct cocoa_surface *s, const struct yasl_framebuffer *fb, const struct yasl_damage_list *damage);
-bool cocoa_surface_input_poll(struct cocoa_surface *s, struct yasl_input_event *ev);
+bool cocoa_surface_poll_event(struct cocoa_surface *s, struct yasl_event *ev);
struct yasl_geometry cocoa_surface_geometry(const struct cocoa_surface *s);
struct yasl_timing cocoa_surface_timing(const struct cocoa_surface *s);
void cocoa_surface_set_cursor(struct cocoa_surface *s, enum yasl_cursor cursor);
diff --git a/src/platform/cocoa/window.m b/src/platform/cocoa/window.m
index aa9fa48..f1f0f03 100644
--- a/src/platform/cocoa/window.m
+++ b/src/platform/cocoa/window.m
@@ -194,8 +194,8 @@ static void check_pointer_reset(struct cocoa_surface *w)
{
if (!w || w->closed) return;
if (w->buttons != 0 || w->tablet_down) {
- struct yasl_input_event ev = {
- .kind = YASL_INPUT_RESET,
+ struct yasl_event ev = {
+ .type = YASL_EVENT_INPUT_RESET,
.surface = &w->base,
};
input_queue_push(&w->input, &ev);
@@ -210,8 +210,8 @@ static void push_focus(struct cocoa_surface *w, bool focused)
return;
if (!focused)
check_pointer_reset(w);
- struct yasl_input_event ev = {
- .kind = YASL_INPUT_FOCUS,
+ struct yasl_event ev = {
+ .type = YASL_EVENT_FOCUS,
.surface = &w->base,
.focus = { .focused = focused },
};
@@ -303,8 +303,8 @@ static void on_key_event(struct cocoa_surface *w, NSEvent *ev, enum yasl_key_act
{
w->mods = cocoa_mods(ev.modifierFlags);
struct yasl_key_event k = cocoa_key_event(ev, action);
- struct yasl_input_event input_ev = {
- .kind = YASL_INPUT_KEY,
+ struct yasl_event input_ev = {
+ .type = YASL_EVENT_KEY,
.surface = &w->base,
.key = k,
};
@@ -314,10 +314,10 @@ static void on_key_event(struct cocoa_surface *w, NSEvent *ev, enum yasl_key_act
static void on_text_input(struct cocoa_surface *w, const char *text, size_t len)
{
if (len) {
- struct yasl_input_event ev = {
- .kind = YASL_INPUT_TEXT,
+ struct yasl_event ev = {
+ .type = YASL_EVENT_TEXT,
.surface = &w->base,
- .text = { .text = text, .len = len },
+ .text = { .data = text, .len = len },
};
input_queue_push(&w->input, &ev);
}
@@ -343,9 +343,11 @@ static bool modifier_down(NSEvent *ev)
static int cocoa_button(NSInteger number)
{
switch (number) {
- case 0: return 0;
- case 1: return 2;
- case 2: return 1;
+ case 0: return YASL_BUTTON_PRIMARY;
+ case 1: return YASL_BUTTON_SECONDARY;
+ case 2: return YASL_BUTTON_MIDDLE;
+ case 3: return YASL_BUTTON_BACK;
+ case 4: return YASL_BUTTON_FORWARD;
default: return -1;
}
}
@@ -432,10 +434,13 @@ static void update_drag_hover(struct cocoa_display *d, NSPoint screenPoint)
}
}
-static void push_pointer(struct cocoa_surface *w, NSEvent *ev, enum yasl_pointer_kind kind,
+static void push_pointer(struct cocoa_surface *w, NSEvent *ev, enum yasl_event_type type,
int button)
{
- if (!w || w->closed || button < 0)
+ if (!w || w->closed)
+ return;
+ if ((type == YASL_EVENT_POINTER_DOWN || type == YASL_EVENT_POINTER_UP) &&
+ (button < 0 || button > 4))
return;
bool proximity = ev.type == NSEventTypeTabletProximity ||
ev.subtype == NSEventSubtypeTabletProximity;
@@ -446,17 +451,16 @@ static void push_pointer(struct cocoa_surface *w, NSEvent *ev, enum yasl_pointer
YASL_PTR_DEV_PEN : YASL_PTR_DEV_MOUSE;
return;
}
- kind = YASL_PTR_LEAVE;
- button = 3;
+ type = YASL_EVENT_POINTER_LEAVE;
}
w->mods = cocoa_mods(ev.modifierFlags);
- if (kind != YASL_PTR_LEAVE)
+ if (type != YASL_EVENT_POINTER_LEAVE)
w->pointer = event_pos(w, ev);
enum yasl_pointer_device device = YASL_PTR_DEV_MOUSE;
struct yasl_pointer_pen pen = {0};
- if (kind == YASL_PTR_LEAVE && w->tablet_device != YASL_PTR_DEV_MOUSE) {
+ if (type == YASL_EVENT_POINTER_LEAVE && w->tablet_device != YASL_PTR_DEV_MOUSE) {
device = w->tablet_device;
w->tablet_down = false;
} else if (ev.type == NSEventTypeTabletPoint || ev.subtype == NSEventSubtypeTabletPoint) {
@@ -471,32 +475,32 @@ static void push_pointer(struct cocoa_surface *w, NSEvent *ev, enum yasl_pointer
NSPoint tilt = ev.tilt;
pen.tilt_x = (int8_t)lround(fmax(-1, fmin(1, tilt.x)) * 90.0);
pen.tilt_y = (int8_t)lround(fmax(-1, fmin(1, -tilt.y)) * 90.0);
- if (button == 0 && kind == YASL_PTR_PRESS) w->tablet_down = true;
- if (button == 0 && kind == YASL_PTR_RELEASE) {
+ if (button == 0 && type == YASL_EVENT_POINTER_DOWN) w->tablet_down = true;
+ if (button == 0 && type == YASL_EVENT_POINTER_UP) {
w->tablet_down = false;
pen.pressure = 0;
}
}
- if (kind == YASL_PTR_PRESS && button >= 0 && button < 32)
+ if (type == YASL_EVENT_POINTER_DOWN && button >= 0 && button < 32)
w->buttons |= (1u << button);
- else if (kind == YASL_PTR_RELEASE && button >= 0 && button < 32)
+ else if (type == YASL_EVENT_POINTER_UP && button >= 0 && button < 32)
w->buttons &= ~(1u << button);
- struct yasl_input_event input_ev = {
+ struct yasl_event input_ev = {
+ .type = type,
.surface = &w->base,
- .kind = YASL_INPUT_MOUSE,
- .mouse = {
+ .pointer = {
.pos = w->pointer,
- .button = (int16_t)button,
- .kind = kind,
+ .button = (type == YASL_EVENT_POINTER_DOWN || type == YASL_EVENT_POINTER_UP) ?
+ (enum yasl_pointer_button)button : YASL_BUTTON_PRIMARY,
.device = device,
.mods = w->mods,
.pen = pen,
},
};
input_queue_push(&w->input, &input_ev);
- if (kind == YASL_PTR_MOTION && darwin_ctx.drag.active) {
+ if (type == YASL_EVENT_POINTER_MOTION && darwin_ctx.drag.active) {
if (darwin_ctx.drag.carried) {
cocoa_surface_place_under_pointer(darwin_ctx.drag.carried, darwin_ctx.drag.carry_offset);
} else if (darwin_ctx.drag.image_window) {
@@ -510,7 +514,7 @@ static void push_pointer(struct cocoa_surface *w, NSEvent *ev, enum yasl_pointer
mouse.y - pt_h + darwin_ctx.drag.image_hotspot.y / scale)];
}
update_drag_hover(&darwin_ctx, [NSEvent mouseLocation]);
- } else if (kind == YASL_PTR_RELEASE && darwin_ctx.drag.active) {
+ } else if (type == YASL_EVENT_POINTER_UP && darwin_ctx.drag.active) {
update_drag_hover(&darwin_ctx, [NSEvent mouseLocation]);
drag_end(&darwin_ctx, YASL_DRAG_DROPPED);
}
@@ -639,10 +643,10 @@ static struct yasl_vector2i dragging_pos(YaslView *view, id<NSDraggingInfo> send
}
const char *utf8 = result.UTF8String;
if (utf8 && strlen(utf8)) {
- struct yasl_input_event ev = {
- .kind = YASL_INPUT_DROP_FILES,
+ struct yasl_event ev = {
+ .type = YASL_EVENT_DROP,
.surface = &w->base,
- .drop_files = { .files = utf8, .len = strlen(utf8) },
+ .text = { .data = utf8, .len = strlen(utf8) },
};
input_queue_push(&w->input, &ev);
cocoa_surface_schedule_redraw(w);
@@ -772,44 +776,44 @@ static struct yasl_vector2i dragging_pos(YaslView *view, id<NSDraggingInfo> send
- (void)mouseDown:(NSEvent *)event
{
[self.window makeFirstResponder:self];
- push_pointer(self.surface, event, YASL_PTR_PRESS, cocoa_button(event.buttonNumber));
+ push_pointer(self.surface, event, YASL_EVENT_POINTER_DOWN, cocoa_button(event.buttonNumber));
}
- (void)rightMouseDown:(NSEvent *)event { [self mouseDown:event]; }
- (void)otherMouseDown:(NSEvent *)event { [self mouseDown:event]; }
- (void)mouseUp:(NSEvent *)event
{
- push_pointer(self.surface, event, YASL_PTR_RELEASE, cocoa_button(event.buttonNumber));
+ push_pointer(self.surface, event, YASL_EVENT_POINTER_UP, cocoa_button(event.buttonNumber));
}
- (void)rightMouseUp:(NSEvent *)event { [self mouseUp:event]; }
- (void)otherMouseUp:(NSEvent *)event { [self mouseUp:event]; }
- (void)mouseMoved:(NSEvent *)event
{
- push_pointer(self.surface, event, YASL_PTR_MOTION, 3);
+ push_pointer(self.surface, event, YASL_EVENT_POINTER_MOTION, 0);
}
- (void)mouseDragged:(NSEvent *)event
{
- push_pointer(self.surface, event, YASL_PTR_MOTION, 0);
+ push_pointer(self.surface, event, YASL_EVENT_POINTER_MOTION, 0);
}
- (void)rightMouseDragged:(NSEvent *)event
{
- push_pointer(self.surface, event, YASL_PTR_MOTION, 2);
+ push_pointer(self.surface, event, YASL_EVENT_POINTER_MOTION, 0);
}
- (void)otherMouseDragged:(NSEvent *)event
{
- push_pointer(self.surface, event, YASL_PTR_MOTION, cocoa_button(event.buttonNumber));
+ push_pointer(self.surface, event, YASL_EVENT_POINTER_MOTION, 0);
}
- (void)mouseExited:(NSEvent *)event
{
- push_pointer(self.surface, event, YASL_PTR_LEAVE, 3);
+ push_pointer(self.surface, event, YASL_EVENT_POINTER_LEAVE, 0);
}
- (void)tabletProximity:(NSEvent *)event
{
- push_pointer(self.surface, event, YASL_PTR_MOTION, 3);
+ push_pointer(self.surface, event, YASL_EVENT_POINTER_MOTION, 0);
}
- (void)tabletPoint:(NSEvent *)event
@@ -817,9 +821,9 @@ static struct yasl_vector2i dragging_pos(YaslView *view, id<NSDraggingInfo> send
struct cocoa_surface *w = self.surface;
if (!w) return;
bool down = (event.buttonMask & NSEventButtonMaskPenTip) != 0;
- enum yasl_pointer_kind kind = down == w->tablet_down ? YASL_PTR_MOTION :
- down ? YASL_PTR_PRESS : YASL_PTR_RELEASE;
- push_pointer(w, event, kind, 0);
+ enum yasl_event_type type = down == w->tablet_down ? YASL_EVENT_POINTER_MOTION :
+ down ? YASL_EVENT_POINTER_DOWN : YASL_EVENT_POINTER_UP;
+ push_pointer(w, event, type, 0);
}
- (void)scrollWheel:(NSEvent *)event
@@ -834,12 +838,11 @@ static struct yasl_vector2i dragging_pos(YaslView *view, id<NSDraggingInfo> send
if (!isfinite(dx) || !isfinite(dy) || (dx == 0 && dy == 0)) return;
w->mods = cocoa_mods(event.modifierFlags);
w->pointer = event_pos(w, event);
- struct yasl_input_event input_ev = {
- .kind = YASL_INPUT_MOUSE,
+ struct yasl_event input_ev = {
+ .type = YASL_EVENT_POINTER_SCROLL,
.surface = &w->base,
- .mouse = {
+ .pointer = {
.pos = w->pointer,
- .kind = YASL_PTR_SCROLL,
.mods = w->mods,
.scroll = {dx, dy},
},
@@ -1574,10 +1577,10 @@ void cocoa_display_paste(struct cocoa_display *d, enum yasl_selection sel, struc
NSString *s = [pb stringForType:NSPasteboardTypeString];
const char *utf8 = s ? s.UTF8String : NULL;
if (utf8) {
- struct yasl_input_event ev = {
- .kind = YASL_INPUT_PASTE,
+ struct yasl_event ev = {
+ .type = YASL_EVENT_PASTE,
.surface = &target->base,
- .paste = { .text = utf8, .len = strlen(utf8) },
+ .text = { .data = utf8, .len = strlen(utf8) },
};
input_queue_push(&target->input, &ev);
}
@@ -1903,11 +1906,11 @@ void cocoa_surface_set_callbacks(struct cocoa_surface *w,
w->ud = ud;
}
-bool cocoa_surface_input_poll(struct cocoa_surface *w, struct yasl_input_event *ev)
+bool cocoa_surface_poll_event(struct cocoa_surface *w, struct yasl_event *ev)
{
if (!w || !ev || !input_queue_pop(&w->input, ev))
return false;
- if (ev->kind == YASL_INPUT_RESET) {
+ if (ev->type == YASL_EVENT_INPUT_RESET) {
w->buttons = 0;
w->tablet_down = false;
w->mods = 0;
@@ -2032,9 +2035,9 @@ static bool impl_surface_present(struct yasl_surface *s, const struct yasl_frame
return cocoa_surface_present((struct cocoa_surface *)s, fb, damage);
}
-static bool impl_surface_input_poll(struct yasl_surface *s, struct yasl_input_event *ev)
+static bool impl_surface_poll_event(struct yasl_surface *s, struct yasl_event *ev)
{
- return cocoa_surface_input_poll((struct cocoa_surface *)s, ev);
+ return cocoa_surface_poll_event((struct cocoa_surface *)s, ev);
}
static struct yasl_geometry impl_surface_geometry(const struct yasl_surface *s)
@@ -2148,7 +2151,7 @@ const struct yasl_backend_ops yasl_cocoa_backend = {
.surface_set_title = impl_surface_set_title,
.surface_schedule_redraw = impl_surface_schedule_redraw,
.surface_present = impl_surface_present,
- .surface_input_poll = impl_surface_input_poll,
+ .surface_poll_event = impl_surface_poll_event,
.surface_geometry = impl_surface_geometry,
.surface_timing = impl_surface_timing,
.surface_frame_time_ns = impl_surface_frame_time_ns,
diff --git a/src/platform/wayland/api.h b/src/platform/wayland/api.h
index bbd20df..aabc182 100644
--- a/src/platform/wayland/api.h
+++ b/src/platform/wayland/api.h
@@ -25,7 +25,7 @@ void wayland_surface_set_callbacks(struct wayland_surface *s, const struct yasl_
void wayland_surface_set_title(struct wayland_surface *s, const char *title);
void wayland_surface_schedule_redraw(struct wayland_surface *s);
bool wayland_surface_present(struct wayland_surface *s, const struct yasl_framebuffer *fb, const struct yasl_damage_list *damage);
-bool wayland_surface_input_poll(struct wayland_surface *s, struct yasl_input_event *ev);
+bool wayland_surface_poll_event(struct wayland_surface *s, struct yasl_event *ev);
struct yasl_geometry wayland_surface_geometry(const struct wayland_surface *s);
struct yasl_timing wayland_surface_timing(const struct wayland_surface *s);
void wayland_surface_set_cursor(struct wayland_surface *s, enum yasl_cursor cursor);
diff --git a/src/platform/wayland/backend.c b/src/platform/wayland/backend.c
index cc96934..1d83ec6 100644
--- a/src/platform/wayland/backend.c
+++ b/src/platform/wayland/backend.c
@@ -101,9 +101,9 @@ static bool impl_surface_present(struct yasl_surface *s, const struct yasl_frame
return wayland_surface_present((struct wayland_surface *)s, fb, damage);
}
-static bool impl_surface_input_poll(struct yasl_surface *s, struct yasl_input_event *ev)
+static bool impl_surface_poll_event(struct yasl_surface *s, struct yasl_event *ev)
{
- return wayland_surface_input_poll((struct wayland_surface *)s, ev);
+ return wayland_surface_poll_event((struct wayland_surface *)s, ev);
}
static struct yasl_geometry impl_surface_geometry(const struct yasl_surface *s)
@@ -205,7 +205,7 @@ const struct yasl_backend_ops yasl_wayland_backend = {
.surface_set_title = impl_surface_set_title,
.surface_schedule_redraw = impl_surface_schedule_redraw,
.surface_present = impl_surface_present,
- .surface_input_poll = impl_surface_input_poll,
+ .surface_poll_event = impl_surface_poll_event,
.surface_geometry = impl_surface_geometry,
.surface_timing = impl_surface_timing,
.surface_frame_time_ns = impl_surface_frame_time_ns,
diff --git a/src/platform/wayland/ime.c b/src/platform/wayland/ime.c
index 440b234..f326fa8 100644
--- a/src/platform/wayland/ime.c
+++ b/src/platform/wayland/ime.c
@@ -129,10 +129,10 @@ static void text_input_done(void *data, struct zwp_text_input_v3 *text_input,
struct wayland_surface *w = ((struct seat *)data)->ime_focus;
if (!w) return;
if (w->ime_commit) {
- struct yasl_input_event ev = {
- .kind = YASL_INPUT_TEXT,
+ struct yasl_event ev = {
+ .type = YASL_EVENT_TEXT,
.surface = &w->base,
- .text = { .text = w->ime_commit, .len = strlen(w->ime_commit) },
+ .text = { .data = w->ime_commit, .len = strlen(w->ime_commit) },
};
input_queue_push(&w->input, &ev);
free(w->ime_commit);
diff --git a/src/platform/wayland/keyboard.c b/src/platform/wayland/keyboard.c
index ebd0fc7..038ba78 100644
--- a/src/platform/wayland/keyboard.c
+++ b/src/platform/wayland/keyboard.c
@@ -133,8 +133,8 @@ bool conn_keyboard_on(const struct wayland_display *c, const struct wayland_surf
static void push_focus(struct wayland_surface *w, bool focused)
{
- struct yasl_input_event ev = {
- .kind = YASL_INPUT_FOCUS,
+ struct yasl_event ev = {
+ .type = YASL_EVENT_FOCUS,
.surface = &w->base,
.focus = { .focused = focused },
};
@@ -278,13 +278,13 @@ static void keyboard_text(struct seat *s, struct wayland_surface *w, uint32_t ke
else xkb_state_key_get_utf8(s->xkb_state, code, text, (size_t)len + 1);
/* Editing commands belong to key events, not text insertion. */
if ((unsigned char)text[0] >= 0x20 && text[0] != 0x7f) {
- struct yasl_input_event ev = {.kind = YASL_INPUT_TEXT,
- .surface = &w->base, .text = {text, (size_t)len}};
+ struct yasl_event ev = {.type = YASL_EVENT_TEXT,
+ .surface = &w->base, .text = {.data = text, .len = (size_t)len}};
input_queue_push(&w->input, &ev);
}
if (text != local) free(text);
} else {
- struct yasl_input_event ev = {.kind = YASL_INPUT_RESET, .surface = &w->base};
+ struct yasl_event ev = {.type = YASL_EVENT_INPUT_RESET, .surface = &w->base};
input_queue_push(&w->input, &ev);
}
}
@@ -297,8 +297,8 @@ static bool keyboard_dispatch_key(struct seat *s, struct wayland_surface *w, uin
if (!s->xkb_state || !w->cbs) return false;
struct yasl_key_event k = xkb_key_event(s, key, action);
- struct yasl_input_event ev = {
- .kind = YASL_INPUT_KEY,
+ struct yasl_event ev = {
+ .type = YASL_EVENT_KEY,
.surface = &w->base,
.key = k,
};
@@ -448,7 +448,7 @@ void wayland_display_paste(struct wayland_display *c, enum yasl_selection sel, s
clipboard_paste(s->clipboard, target->surface);
}
-bool wayland_surface_input_poll(struct wayland_surface *w, struct yasl_input_event *ev)
+bool wayland_surface_poll_event(struct wayland_surface *w, struct yasl_event *ev)
{
return w && ev && input_queue_pop(&w->input, ev);
}
diff --git a/src/platform/wayland/pointer.c b/src/platform/wayland/pointer.c
index 4652849..83f6e2f 100644
--- a/src/platform/wayland/pointer.c
+++ b/src/platform/wayland/pointer.c
@@ -34,77 +34,30 @@ static struct yasl_vector2i device_from_fixed(const struct wayland_surface *w,
};
}
-static inline int motion_button(uint64_t buttons)
-{
- static const uint8_t motion_btn_lut[256] = {
- [0] = 3,
- [1] = 0, [2] = 1, [3] = 0, [4] = 2, [5] = 0, [6] = 1, [7] = 0,
- [8] = 3, [9] = 0, [10] = 1, [11] = 0, [12] = 2, [13] = 0, [14] = 1, [15] = 0,
- [16] = 4, [17] = 0, [18] = 1, [19] = 0, [20] = 2, [21] = 0, [22] = 1, [23] = 0,
- [24] = 3, [25] = 0, [26] = 1, [27] = 0, [28] = 2, [29] = 0, [30] = 1, [31] = 0,
- [32] = 5, [33] = 0, [34] = 1, [35] = 0, [36] = 2, [37] = 0, [38] = 1, [39] = 0,
- [40] = 3, [41] = 0, [42] = 1, [43] = 0, [44] = 2, [45] = 0, [46] = 1, [47] = 0,
- [48] = 4, [49] = 0, [50] = 1, [51] = 0, [52] = 2, [53] = 0, [54] = 1, [55] = 0,
- [56] = 3, [57] = 0, [58] = 1, [59] = 0, [60] = 2, [61] = 0, [62] = 1, [63] = 0,
- [64] = 6, [65] = 0, [66] = 1, [67] = 0, [68] = 2, [69] = 0, [70] = 1, [71] = 0,
- [72] = 3, [73] = 0, [74] = 1, [75] = 0, [76] = 2, [77] = 0, [78] = 1, [79] = 0,
- [80] = 4, [81] = 0, [82] = 1, [83] = 0, [84] = 2, [85] = 0, [86] = 1, [87] = 0,
- [88] = 3, [89] = 0, [90] = 1, [91] = 0, [92] = 2, [93] = 0, [94] = 1, [95] = 0,
- [96] = 5, [97] = 0, [98] = 1, [99] = 0, [100] = 2, [101] = 0, [102] = 1, [103] = 0,
- [104] = 3, [105] = 0, [106] = 1, [107] = 0, [108] = 2, [109] = 0, [110] = 1, [111] = 0,
- [112] = 4, [113] = 0, [114] = 1, [115] = 0, [116] = 2, [117] = 0, [118] = 1, [119] = 0,
- [120] = 3, [121] = 0, [122] = 1, [123] = 0, [124] = 2, [125] = 0, [126] = 1, [127] = 0,
- [128] = 7, [129] = 0, [130] = 1, [131] = 0, [132] = 2, [133] = 0, [134] = 1, [135] = 0,
- [136] = 3, [137] = 0, [138] = 1, [139] = 0, [140] = 2, [141] = 0, [142] = 1, [143] = 0,
- [144] = 4, [145] = 0, [146] = 1, [147] = 0, [148] = 2, [149] = 0, [150] = 1, [151] = 0,
- [152] = 3, [153] = 0, [154] = 1, [155] = 0, [156] = 2, [157] = 0, [158] = 1, [159] = 0,
- [160] = 5, [161] = 0, [162] = 1, [163] = 0, [164] = 2, [165] = 0, [166] = 1, [167] = 0,
- [168] = 3, [169] = 0, [170] = 1, [171] = 0, [172] = 2, [173] = 0, [174] = 1, [175] = 0,
- [176] = 4, [177] = 0, [178] = 1, [179] = 0, [180] = 2, [181] = 0, [182] = 1, [183] = 0,
- [184] = 3, [185] = 0, [186] = 1, [187] = 0, [188] = 2, [189] = 0, [190] = 1, [191] = 0,
- [192] = 6, [193] = 0, [194] = 1, [195] = 0, [196] = 2, [197] = 0, [198] = 1, [199] = 0,
- [200] = 3, [201] = 0, [202] = 1, [203] = 0, [204] = 2, [205] = 0, [206] = 1, [207] = 0,
- [208] = 4, [209] = 0, [210] = 1, [211] = 0, [212] = 2, [213] = 0, [214] = 1, [215] = 0,
- [216] = 3, [217] = 0, [218] = 1, [219] = 0, [220] = 2, [221] = 0, [222] = 1, [223] = 0,
- [224] = 5, [225] = 0, [226] = 1, [227] = 0, [228] = 2, [229] = 0, [230] = 1, [231] = 0,
- [232] = 3, [233] = 0, [234] = 1, [235] = 0, [236] = 2, [237] = 0, [238] = 1, [239] = 0,
- [240] = 4, [241] = 0, [242] = 1, [243] = 0, [244] = 2, [245] = 0, [246] = 1, [247] = 0,
- [248] = 3, [249] = 0, [250] = 1, [251] = 0, [252] = 2, [253] = 0, [254] = 1, [255] = 0,
- };
- return motion_btn_lut[(uint8_t)buttons];
-}
-
void seat_note_input(struct seat *s, uint32_t serial)
{
s->input_serial = serial;
s->conn->active_seat = s;
}
-static void push_mouse(struct seat *s, struct wayland_surface *w, struct yasl_mouse_event ev)
+static void push_pointer(struct seat *s, struct wayland_surface *w,
+ enum yasl_event_type type, struct yasl_pointer_event ev)
{
- ev.mods = (unsigned)seat_modifiers(s);
- struct yasl_input_event input_ev = {
- .kind = YASL_INPUT_MOUSE,
+ ev.mods = (uint32_t)seat_modifiers(s);
+ struct yasl_event input_ev = {
+ .type = type,
.surface = &w->base,
- .mouse = ev,
+ .pointer = ev,
};
input_queue_push(&surface_root(w)->input, &input_ev);
}
-static void report_mouse(struct seat *s, struct wayland_surface *w, struct yasl_vector2i pos,
- int button, enum yasl_pointer_kind kind)
-{
- push_mouse(s, w, (struct yasl_mouse_event){
- .pos = pos, .button = button, .kind = kind,
- });
-}
-
static void report_wheel(struct seat *s, struct wayland_surface *w,
struct yasl_vector2i pos, double x, double y)
{
if ((x == 0 && y == 0) || !isfinite(x) || !isfinite(y)) return;
- push_mouse(s, w, (struct yasl_mouse_event){
- .pos = pos, .kind = YASL_PTR_SCROLL, .scroll = {x, y},
+ push_pointer(s, w, YASL_EVENT_POINTER_SCROLL, (struct yasl_pointer_event){
+ .pos = pos, .scroll = {x, y},
});
}
@@ -238,7 +191,7 @@ void wayland_surface_set_cursor(struct wayland_surface *w, enum yasl_cursor shap
static void press_queue_flush(struct seat *s, struct press_queue *q,
struct wayland_surface *only, uint64_t *buttons,
- struct yasl_mouse_event like)
+ struct yasl_pointer_event like)
{
int kept = 0;
int count = q->n;
@@ -251,11 +204,11 @@ static void press_queue_flush(struct seat *s, struct press_queue *q,
if (!p.surface) continue;
uint64_t mask = 1ull << p.button;
*buttons = (*buttons & ~mask) | ((uint64_t)(!p.release) << p.button);
- struct yasl_mouse_event ev = like;
+ struct yasl_pointer_event ev = like;
ev.pos = p.pos;
- ev.button = p.button;
- ev.kind = (enum yasl_pointer_kind)p.release;
- push_mouse(s, p.surface, ev);
+ ev.button = (enum yasl_pointer_button)p.button;
+ enum yasl_event_type type = p.release ? YASL_EVENT_POINTER_UP : YASL_EVENT_POINTER_DOWN;
+ push_pointer(s, p.surface, type, ev);
}
q->head = 0;
q->n = kept;
@@ -308,7 +261,9 @@ static void flush_pending_motion(struct seat *s, struct wayland_surface *w)
{
if (!s->motion_pending) return;
s->motion_pending = false;
- report_mouse(s, w, s->pointer_pos, motion_button(s->pointer_buttons), YASL_PTR_MOTION);
+ push_pointer(s, w, YASL_EVENT_POINTER_MOTION, (struct yasl_pointer_event){
+ .pos = s->pointer_pos,
+ });
}
static void pointer_enter(void *data, struct wl_pointer *pointer,
@@ -459,9 +414,13 @@ static void pointer_frame(void *data, struct wl_pointer *pointer)
if (left) {
s->ptr_left = NULL;
if (s->ptr_left_motion)
- report_mouse(s, left, s->ptr_left_pos, motion_button(s->pointer_buttons), YASL_PTR_MOTION);
- press_queue_flush(s, &s->ptr_presses, left, &s->pointer_buttons, (struct yasl_mouse_event){0});
- report_mouse(s, left, s->ptr_left_pos, 3, YASL_PTR_LEAVE);
+ push_pointer(s, left, YASL_EVENT_POINTER_MOTION, (struct yasl_pointer_event){
+ .pos = s->ptr_left_pos,
+ });
+ press_queue_flush(s, &s->ptr_presses, left, &s->pointer_buttons, (struct yasl_pointer_event){0});
+ push_pointer(s, left, YASL_EVENT_POINTER_LEAVE, (struct yasl_pointer_event){
+ .pos = s->ptr_left_pos,
+ });
struct yasl_vector2i pos = s->pointer_pos;
bool motion = s->motion_pending;
uint32_t serial = s->pointer_focus ? s->pointer_serial : 0;
@@ -479,7 +438,7 @@ static void pointer_frame(void *data, struct wl_pointer *pointer)
}
flush_pending_motion(s, w);
- press_queue_flush(s, &s->ptr_presses, NULL, &s->pointer_buttons, (struct yasl_mouse_event){0});
+ press_queue_flush(s, &s->ptr_presses, NULL, &s->pointer_buttons, (struct yasl_pointer_event){0});
pointer_frame_scroll(s, w);
}
@@ -523,10 +482,10 @@ static struct yasl_vector2i touch_pos(const struct touch_point *p)
static void touch_report(struct seat *s, struct touch_point *p, int button,
- enum yasl_pointer_kind kind)
+ enum yasl_event_type type)
{
- push_mouse(s, p->surface, (struct yasl_mouse_event){
- .pos = touch_pos(p), .button = button, .kind = kind,
+ push_pointer(s, p->surface, type, (struct yasl_pointer_event){
+ .pos = touch_pos(p), .button = (enum yasl_pointer_button)button,
.device = YASL_PTR_DEV_TOUCH,
});
}
@@ -584,7 +543,7 @@ static void touch_frame(void *data, struct wl_touch *touch)
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);
+ touch_report(s, p, 0, YASL_EVENT_POINTER_DOWN);
}
if (!p->up) {
active_n++;
@@ -597,7 +556,7 @@ static void touch_frame(void *data, struct wl_touch *touch)
struct touch_point *primary = s->touch_primary;
if (primary && !s->touch_scrolling && active_n >= 2) {
if (s->touch_pressed)
- touch_report(s, primary, 0, YASL_PTR_RELEASE);
+ touch_report(s, primary, 0, YASL_EVENT_POINTER_UP);
s->touch_pressed = false;
s->touch_scrolling = true;
s->touch_scroll_y = centroid_n ? centroid_sum / centroid_n : 0;
@@ -607,13 +566,14 @@ static void touch_frame(void *data, struct wl_touch *touch)
s->touch_scroll_y = y;
if (dy != 0.0) {
double lines = dy / SCROLL_PX_PER_LINE;
- push_mouse(s, primary->surface, (struct yasl_mouse_event){
- .pos = touch_pos(primary), .kind = YASL_PTR_SCROLL,
- .scroll = {0, -lines}, .device = YASL_PTR_DEV_TOUCH,
+ push_pointer(s, primary->surface, YASL_EVENT_POINTER_SCROLL, (struct yasl_pointer_event){
+ .pos = touch_pos(primary),
+ .scroll = {0, -lines},
+ .device = YASL_PTR_DEV_TOUCH,
});
}
} else if (primary && primary->moved && s->touch_pressed) {
- touch_report(s, primary, 0, YASL_PTR_MOTION);
+ touch_report(s, primary, 0, YASL_EVENT_POINTER_MOTION);
}
for (int i = 0; i < SEAT_TOUCH_POINTS; i++) {
struct touch_point *p = &s->touch_points[i];
@@ -622,7 +582,7 @@ static void touch_frame(void *data, struct wl_touch *touch)
active_n--;
if (p == s->touch_primary) {
if (s->touch_pressed)
- touch_report(s, p, 0, YASL_PTR_RELEASE);
+ touch_report(s, p, 0, YASL_EVENT_POINTER_UP);
s->touch_pressed = false;
s->touch_primary = NULL;
}
@@ -640,7 +600,7 @@ static void touch_cancel(void *data, struct wl_touch *touch)
(void)touch;
struct seat *s = data;
if (s->touch_primary && s->touch_pressed)
- touch_report(s, s->touch_primary, 0, YASL_PTR_RELEASE);
+ touch_report(s, s->touch_primary, 0, YASL_EVENT_POINTER_UP);
memset(s->touch_points, 0, sizeof(s->touch_points));
s->touch_primary = NULL;
s->touch_pressed = false;
@@ -658,9 +618,9 @@ static const struct wl_touch_listener touch_listener = {
.frame = touch_frame, .cancel = touch_cancel,
};
-static struct yasl_mouse_event tool_event(const struct seat *s)
+static struct yasl_pointer_event tool_event(const struct seat *s)
{
- return (struct yasl_mouse_event){
+ return (struct yasl_pointer_event){
.device = s->tool && s->tool->eraser ? YASL_PTR_DEV_ERASER : YASL_PTR_DEV_PEN,
.pen = s->pen,
};
@@ -697,11 +657,9 @@ static void tablet_tool_proximity_out(void *data, struct zwp_tablet_tool_v2 *too
if (w) {
press_queue_flush(s, &s->tool_presses, NULL, &s->tool_buttons, tool_event(s));
s->pen.pressure = 0;
- struct yasl_mouse_event ev = tool_event(s);
+ struct yasl_pointer_event ev = tool_event(s);
ev.pos = s->tool_pos;
- ev.button = 3;
- ev.kind = YASL_PTR_LEAVE;
- push_mouse(s, w, ev);
+ push_pointer(s, w, YASL_EVENT_POINTER_LEAVE, ev);
}
s->tool_presses.n = 0;
s->tablet_focus = NULL;
@@ -802,22 +760,19 @@ static void tool_frame(void *d, struct zwp_tablet_tool_v2 *t, uint32_t time)
s->tool_wheel = 0;
return;
}
- struct yasl_mouse_event like = tool_event(s);
+ struct yasl_pointer_event like = tool_event(s);
if (s->tool_motion) {
- struct yasl_mouse_event ev = like;
+ struct yasl_pointer_event ev = like;
ev.pos = s->tool_pos;
- ev.button = motion_button(s->tool_buttons);
- ev.kind = YASL_PTR_MOTION;
- push_mouse(s, w, ev);
+ push_pointer(s, w, YASL_EVENT_POINTER_MOTION, ev);
s->tool_motion = false;
}
press_queue_flush(s, &s->tool_presses, NULL, &s->tool_buttons, like);
if (s->tool_wheel) {
- struct yasl_mouse_event ev = like;
+ struct yasl_pointer_event ev = like;
ev.pos = s->tool_pos;
- ev.kind = YASL_PTR_SCROLL;
ev.scroll.y = s->tool_wheel;
- push_mouse(s, w, ev);
+ push_pointer(s, w, YASL_EVENT_POINTER_SCROLL, ev);
s->tool_wheel = 0;
}
}
@@ -985,17 +940,14 @@ static void clipboard_received(const char *text, size_t len, bool uri_list,
(struct wayland_surface *)wl_surface_get_user_data(on) : NULL;
if (uri_list) w = surface_root(w);
if (!w || w->closed) return;
- struct yasl_input_event ev = {
+ struct yasl_event ev = {
.surface = &w->base,
- .kind = uri_list ? YASL_INPUT_DROP_FILES : YASL_INPUT_PASTE,
+ .type = uri_list ? YASL_EVENT_DROP : YASL_EVENT_PASTE,
+ .text = {
+ .data = text,
+ .len = len,
+ },
};
- if (uri_list) {
- ev.drop_files.files = text;
- ev.drop_files.len = len;
- } else {
- ev.paste.text = text;
- ev.paste.len = len;
- }
input_queue_push(&w->input, &ev);
}
@@ -1214,8 +1166,8 @@ void seat_destroy(struct seat *s)
seat_drop_keyboard(s);
struct wayland_surface *left = s->focus_leaving;
if (left && !conn_keyboard_on(c, left, NULL)) {
- struct yasl_input_event ev = {
- .kind = YASL_INPUT_FOCUS,
+ struct yasl_event ev = {
+ .type = YASL_EVENT_FOCUS,
.surface = &left->base,
.focus = { .focused = false },
};
diff --git a/src/platform/x11/window.c b/src/platform/x11/window.c
index 3bab6e2..f60a878 100644
--- a/src/platform/x11/window.c
+++ b/src/platform/x11/window.c
@@ -159,21 +159,13 @@ static void leave(struct x11_display *d)
}
}
-static void push(struct x11_surface *s, struct yasl_input_event event,
+static void push(struct x11_surface *s, struct yasl_event event,
const char *text, size_t len)
{
if (s->destroyed) return;
if (text) {
- if (event.kind == YASL_INPUT_TEXT) {
- event.text.text = text;
- event.text.len = len;
- } else if (event.kind == YASL_INPUT_DROP_FILES) {
- event.drop_files.files = text;
- event.drop_files.len = len;
- } else {
- event.paste.text = text;
- event.paste.len = len;
- }
+ event.text.data = text;
+ event.text.len = len;
}
event.surface = &s->base;
input_queue_push(&s->input, &event);
@@ -354,42 +346,46 @@ static int8_t tilt_value(const struct tablet_axis *a)
(int8_t)lround(fmax(-90, fmin(90, a->value)));
}
-static int pointer_button(unsigned button)
+static enum yasl_pointer_button pointer_button(unsigned button)
{
- return button == 1 ? 0 : button == 2 ? 1 : button == 3 ? 2 :
- button >= 8 && button <= INT16_MAX ? (int)button - 5 : 3;
+ return button == 1 ? YASL_BUTTON_PRIMARY :
+ button == 2 ? YASL_BUTTON_MIDDLE :
+ button == 3 ? YASL_BUTTON_SECONDARY :
+ button >= 8 && button <= INT16_MAX ? (enum yasl_pointer_button)(button - 5) :
+ YASL_BUTTON_BACK;
}
static void xi_pointer_event(struct x11_surface *s, const XIDeviceEvent *ev)
{
struct x11_display *d = (struct x11_display *)s->base.display;
struct x11_pointer *p = pointer_for(d, ev->sourceid);
- struct yasl_mouse_event mouse = {
- .pos = {yasl_scale_to_device(ev->event_x, YASL_SCALE_UNIT),
- yasl_scale_to_device(ev->event_y, YASL_SCALE_UNIT)},
- .device = p ? p->device : YASL_PTR_DEV_MOUSE,
- .mods = modifiers(ev->mods.effective),
- .button = 3,
+ struct yasl_event event = {
+ .pointer = {
+ .pos = {yasl_scale_to_device(ev->event_x, YASL_SCALE_UNIT),
+ yasl_scale_to_device(ev->event_y, YASL_SCALE_UNIT)},
+ .device = p ? p->device : YASL_PTR_DEV_MOUSE,
+ .mods = modifiers(ev->mods.effective),
+ },
};
if (p && (p->device == YASL_PTR_DEV_PEN || p->device == YASL_PTR_DEV_ERASER)) {
update_axes(p, &ev->valuators);
if (ev->evtype == XI_ButtonRelease && ev->detail == 1)
p->pressure.value = p->pressure.min;
- mouse.pen = (struct yasl_pointer_pen){
+ event.pointer.pen = (struct yasl_pointer_pen){
pressure_value(&p->pressure), tilt_value(&p->tilt_x), tilt_value(&p->tilt_y)};
}
- if (ev->evtype == XI_Motion) mouse.kind = YASL_PTR_MOTION;
+ if (ev->evtype == XI_Motion) event.type = YASL_EVENT_POINTER_MOTION;
else if (ev->detail >= 4 && ev->detail <= 7) {
if (ev->evtype == XI_ButtonRelease) return;
- mouse.kind = YASL_PTR_SCROLL;
- if (ev->detail <= 5) mouse.scroll.y = ev->detail == 4 ? -1 : 1;
- else mouse.scroll.x = ev->detail == 6 ? -1 : 1;
+ event.type = YASL_EVENT_POINTER_SCROLL;
+ if (ev->detail <= 5) event.pointer.scroll.y = ev->detail == 4 ? -1 : 1;
+ else event.pointer.scroll.x = ev->detail == 6 ? -1 : 1;
} else {
- mouse.kind = ev->evtype == XI_ButtonPress ? YASL_PTR_PRESS : YASL_PTR_RELEASE;
- mouse.button = pointer_button(ev->detail);
+ event.type = ev->evtype == XI_ButtonPress ? YASL_EVENT_POINTER_DOWN : YASL_EVENT_POINTER_UP;
+ event.pointer.button = pointer_button(ev->detail);
}
- d->mods = mouse.mods;
- push(s, (struct yasl_input_event){.kind = YASL_INPUT_MOUSE, .mouse = mouse}, NULL, 0);
+ d->mods = event.pointer.mods;
+ push(s, event, NULL, 0);
}
static void xi_event(struct x11_display *d, XGenericEventCookie *cookie)
@@ -405,7 +401,7 @@ static void xi_event(struct x11_display *d, XGenericEventCookie *cookie)
if (d->drag.active)
drag_end(d, YASL_DRAG_CANCELLED);
for (struct x11_surface *s = d->surfaces; s; s = s->next)
- push(s, (struct yasl_input_event){.kind = YASL_INPUT_RESET}, NULL, 0);
+ push(s, (struct yasl_event){.type = YASL_EVENT_INPUT_RESET}, NULL, 0);
}
return;
}
@@ -413,7 +409,7 @@ static void xi_event(struct x11_display *d, XGenericEventCookie *cookie)
if (!crossing && cookie->evtype != XI_Motion && cookie->evtype != XI_ButtonPress &&
cookie->evtype != XI_ButtonRelease) return;
Window window = crossing ? ((XIEnterEvent *)cookie->data)->event :
- ((XIDeviceEvent *)cookie->data)->event;
+ ((XIDeviceEvent *)cookie->data)->event;
struct x11_surface *s = d->surfaces;
while (s && s->window != window) s = s->next;
if (cookie->evtype == XI_Motion && d->drag.active) {
@@ -450,13 +446,15 @@ static void xi_event(struct x11_display *d, XGenericEventCookie *cookie)
const XIEnterEvent *ev = cookie->data;
struct x11_pointer *p = pointer_for(d, ev->sourceid);
if (p) p->pressure.value = p->pressure.min;
- push(s, (struct yasl_input_event){.kind = YASL_INPUT_MOUSE, .mouse = {
- .pos = {yasl_scale_to_device(ev->event_x, YASL_SCALE_UNIT),
- yasl_scale_to_device(ev->event_y, YASL_SCALE_UNIT)},
- .device = p ? p->device : YASL_PTR_DEV_MOUSE,
- .button = 3, .mods = modifiers(ev->mods.effective),
- .kind = cookie->evtype == XI_Leave ? YASL_PTR_LEAVE : YASL_PTR_MOTION,
- }}, NULL, 0);
+ push(s, (struct yasl_event){
+ .type = cookie->evtype == XI_Leave ? YASL_EVENT_POINTER_LEAVE : YASL_EVENT_POINTER_MOTION,
+ .pointer = {
+ .pos = {yasl_scale_to_device(ev->event_x, YASL_SCALE_UNIT),
+ yasl_scale_to_device(ev->event_y, YASL_SCALE_UNIT)},
+ .device = p ? p->device : YASL_PTR_DEV_MOUSE,
+ .mods = modifiers(ev->mods.effective),
+ },
+ }, NULL, 0);
}
}
@@ -1002,7 +1000,7 @@ static void xdnd_selection_notify(struct x11_display *d, XSelectionEvent *event)
size_t out_len = 0;
char *parsed = parse_file_uris((const char *)data, count, &out_len);
if (parsed && out_len > 0) {
- push(s, (struct yasl_input_event){.kind = YASL_INPUT_DROP_FILES}, parsed, out_len);
+ push(s, (struct yasl_event){.type = YASL_EVENT_DROP}, parsed, out_len);
free(parsed);
success = true;
}
@@ -1090,7 +1088,7 @@ static void selection_notify(struct x11_display *d, XSelectionEvent *event)
if (buf) total = utf8_len;
}
if (complete && buf && yasl_utf8_validate(buf, total))
- push(s, (struct yasl_input_event){.kind = YASL_INPUT_PASTE}, buf, total);
+ push(s, (struct yasl_event){.type = YASL_EVENT_PASTE}, buf, total);
free(buf);
XDestroyWindow(d->native, r->window);
free(r);
@@ -1151,8 +1149,8 @@ static void key_event(struct x11_surface *s, XKeyEvent *key, bool repeat)
}
}
uint32_t cp = xkb_keysym_to_utf32((xkb_keysym_t)base);
- push(s, (struct yasl_input_event){
- .kind = YASL_INPUT_KEY,
+ push(s, (struct yasl_event){
+ .type = YASL_EVENT_KEY,
.key = {.key = key->keycode < 256 ? d->keys[key->keycode] : YASL_KEY_UNKNOWN,
.codepoint = yasl_key_label(cp), .native_code = key->keycode,
.shifted = yasl_key_label(xkb_keysym_to_utf32((xkb_keysym_t)shifted)),
@@ -1162,7 +1160,7 @@ static void key_event(struct x11_surface *s, XKeyEvent *key, bool repeat)
}, NULL, 0);
if (len > 0 && text && (unsigned char)text[0] >= 0x20 && text[0] != 0x7f &&
!(d->mods & (YASL_MOD_CTRL | YASL_MOD_SUPER | YASL_MOD_ALT)))
- push(s, (struct yasl_input_event){.kind = YASL_INPUT_TEXT}, text, (size_t)len);
+ push(s, (struct yasl_event){.type = YASL_EVENT_TEXT}, text, (size_t)len);
if (text != local) free(text);
}
@@ -1336,8 +1334,8 @@ static void dispatch(struct yasl_display *base)
if (s->ic) { if (focused) XSetICFocus(s->ic); else XUnsetICFocus(s->ic); }
if (focused) s->base.state |= YASL_STATE_ACTIVATED;
else s->base.state &= ~YASL_STATE_ACTIVATED;
- push(s, (struct yasl_input_event){
- .kind = YASL_INPUT_FOCUS, .focus.focused = focused}, NULL, 0);
+ push(s, (struct yasl_event){
+ .type = YASL_EVENT_FOCUS, .focus.focused = focused}, NULL, 0);
if (s->cbs && s->cbs->state) s->cbs->state(&s->base, s->base.state, s->ud);
break;
}
@@ -1359,11 +1357,13 @@ static void dispatch(struct yasl_display *base)
break;
}
case MotionNotify: case LeaveNotify: case EnterNotify: case ButtonPress: case ButtonRelease: {
- struct yasl_mouse_event mouse = {.device = YASL_PTR_DEV_MOUSE};
+ struct yasl_event ev = {
+ .pointer = {.device = YASL_PTR_DEV_MOUSE},
+ };
unsigned state;
if (event.type == MotionNotify) {
- mouse.pos = (struct yasl_vector2i){event.xmotion.x, event.xmotion.y};
- mouse.kind = YASL_PTR_MOTION;
+ ev.pointer.pos = (struct yasl_vector2i){event.xmotion.x, event.xmotion.y};
+ ev.type = YASL_EVENT_POINTER_MOTION;
state = event.xmotion.state;
if (d->drag.active) {
if (d->drag.carried)
@@ -1372,45 +1372,45 @@ static void dispatch(struct yasl_display *base)
XMoveWindow(d->native, d->drag.icon_window,
event.xmotion.x_root - d->drag.hotspot.x,
event.xmotion.y_root - d->drag.hotspot.y);
- struct yasl_vector2i hpos = mouse.pos;
+ struct yasl_vector2i hpos = ev.pointer.pos;
struct x11_surface *hsurf = d->native ?
surface_at_root_pos(d, event.xmotion.x_root, event.xmotion.y_root, &hpos) : s;
drag_set_hover(d, hsurf, hpos);
}
} else if (event.type == EnterNotify) {
- mouse.pos = (struct yasl_vector2i){event.xcrossing.x, event.xcrossing.y};
- mouse.kind = YASL_PTR_MOTION;
+ ev.pointer.pos = (struct yasl_vector2i){event.xcrossing.x, event.xcrossing.y};
+ ev.type = YASL_EVENT_POINTER_MOTION;
state = event.xcrossing.state;
if (d->drag.active) {
- struct yasl_vector2i hpos = mouse.pos;
+ struct yasl_vector2i hpos = ev.pointer.pos;
struct x11_surface *hsurf = d->native ?
surface_at_root_pos(d, event.xcrossing.x_root, event.xcrossing.y_root, &hpos) : s;
drag_set_hover(d, hsurf, hpos);
}
} else if (event.type == LeaveNotify) {
- mouse.pos = (struct yasl_vector2i){event.xcrossing.x, event.xcrossing.y};
- mouse.kind = YASL_PTR_LEAVE;
+ ev.pointer.pos = (struct yasl_vector2i){event.xcrossing.x, event.xcrossing.y};
+ ev.type = YASL_EVENT_POINTER_LEAVE;
state = event.xcrossing.state;
if (d->drag.active)
- drag_leave_hover(d, s, mouse.pos);
+ drag_leave_hover(d, s, ev.pointer.pos);
} else {
- mouse.pos = (struct yasl_vector2i){event.xbutton.x, event.xbutton.y};
+ ev.pointer.pos = (struct yasl_vector2i){event.xbutton.x, event.xbutton.y};
state = event.xbutton.state;
unsigned button = event.xbutton.button;
if (button >= 4 && button <= 7) {
if (event.type == ButtonRelease) break;
- mouse.kind = YASL_PTR_SCROLL;
- if (button <= 5) mouse.scroll.y = button == 4 ? -1 : 1;
- else mouse.scroll.x = button == 6 ? -1 : 1;
+ ev.type = YASL_EVENT_POINTER_SCROLL;
+ if (button <= 5) ev.pointer.scroll.y = button == 4 ? -1 : 1;
+ else ev.pointer.scroll.x = button == 6 ? -1 : 1;
} else {
- mouse.kind = event.type == ButtonPress ? YASL_PTR_PRESS : YASL_PTR_RELEASE;
- mouse.button = pointer_button(button);
+ ev.type = event.type == ButtonPress ? YASL_EVENT_POINTER_DOWN : YASL_EVENT_POINTER_UP;
+ ev.pointer.button = pointer_button(button);
if (event.type == ButtonRelease && d->drag.active)
drag_drop_hover(d);
}
}
- d->mods = mouse.mods = modifiers(state);
- push(s, (struct yasl_input_event){.kind = YASL_INPUT_MOUSE, .mouse = mouse}, NULL, 0);
+ d->mods = ev.pointer.mods = modifiers(state);
+ push(s, ev, NULL, 0);
break;
}
}
@@ -1708,7 +1708,7 @@ static void paste(struct yasl_display *base, enum yasl_selection sel, struct yas
Atom selection = sel == YASL_PRIMARY ? XA_PRIMARY : d->clipboard;
if (XGetSelectionOwner(d->native, selection) == d->selection_window) {
const char *text = d->selection[sel];
- if (text) push(s, (struct yasl_input_event){.kind = YASL_INPUT_PASTE}, text, strlen(text));
+ if (text) push(s, (struct yasl_event){.type = YASL_EVENT_PASTE}, text, strlen(text));
} else {
struct paste_request *r = calloc(1, sizeof(*r));
if (!r) return;
@@ -1723,7 +1723,7 @@ static void paste(struct yasl_display *base, enum yasl_selection sel, struct yas
}
}
-static bool input_poll(struct yasl_surface *base, struct yasl_input_event *event)
+static bool input_poll(struct yasl_surface *base, struct yasl_event *event)
{
struct x11_surface *s = (struct x11_surface *)base;
return !s->destroyed && input_queue_pop(&s->input, event);
@@ -2038,7 +2038,7 @@ const struct yasl_backend_ops yasl_x11_backend = {
.surface_set_title = set_title,
.surface_schedule_redraw = schedule_redraw,
.surface_present = present,
- .surface_input_poll = input_poll,
+ .surface_poll_event = input_poll,
.surface_geometry = geometry,
.surface_timing = timing,
.surface_frame_time_ns = frame_time,
diff --git a/tests/helpers/check_exports.py b/tests/helpers/check_exports.py
index acb727d..9c43d58 100644
--- a/tests/helpers/check_exports.py
+++ b/tests/helpers/check_exports.py
@@ -15,7 +15,7 @@ def main():
parser.add_argument('headers', nargs='+')
args = parser.parse_args()
declarations = re.compile(
- r"^[^\n;{}]*\b(yasl_\w+)\s*\([^;{}]*\);", re.MULTILINE
+ r"^\s*YASL_API\b[^;{}]*?\b(yasl_\w+)\s*\([^;{}]*\);", re.MULTILINE
)
expected = set()
for header in args.headers: