diff options
| -rw-r--r-- | docs/guide.md | 41 | ||||
| -rw-r--r-- | docs/migrating.md | 38 | ||||
| -rw-r--r-- | examples/game.c | 31 | ||||
| -rw-r--r-- | examples/hello.c | 6 | ||||
| -rw-r--r-- | examples/notepad.c | 94 | ||||
| -rw-r--r-- | examples/simple_window.c | 31 | ||||
| -rw-r--r-- | examples/tablet.c | 38 | ||||
| -rw-r--r-- | include/yasl/app.h | 125 | ||||
| -rw-r--r-- | include/yasl/keycodes.h | 2 | ||||
| -rw-r--r-- | include/yasl/yasl.h | 193 | ||||
| -rw-r--r-- | src/common/app.c | 197 | ||||
| -rw-r--r-- | src/common/backend.c | 21 | ||||
| -rw-r--r-- | src/common/backend.h | 7 | ||||
| -rw-r--r-- | src/common/input.c | 80 | ||||
| -rw-r--r-- | src/common/input.h | 14 | ||||
| -rw-r--r-- | src/platform/cocoa/api.h | 2 | ||||
| -rw-r--r-- | src/platform/cocoa/window.m | 113 | ||||
| -rw-r--r-- | src/platform/wayland/api.h | 2 | ||||
| -rw-r--r-- | src/platform/wayland/backend.c | 6 | ||||
| -rw-r--r-- | src/platform/wayland/ime.c | 6 | ||||
| -rw-r--r-- | src/platform/wayland/keyboard.c | 16 | ||||
| -rw-r--r-- | src/platform/wayland/pointer.c | 154 | ||||
| -rw-r--r-- | src/platform/x11/window.c | 132 | ||||
| -rw-r--r-- | tests/helpers/check_exports.py | 2 |
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(©, 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: |
