summaryrefslogtreecommitdiff
path: root/docs/guide.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/guide.md')
-rw-r--r--docs/guide.md149
1 files changed, 91 insertions, 58 deletions
diff --git a/docs/guide.md b/docs/guide.md
index 76279c4..1b64880 100644
--- a/docs/guide.md
+++ b/docs/guide.md
@@ -44,13 +44,21 @@ All examples include `<yasl/app.h>` and call `yasl_run()` with a
which the runner creates before `init` with its first frame requested;
`yasl_run()` returns an error if creation fails. Create further surfaces in the
optional `init`, handle `YASL_EVENT_*` notifications in `event`, and render into
-`frame->cpu.pixels` in `frame`. Present with `yasl_frame_present_cpu(frame, NULL,
+`frame->target.pixels` in `frame`. Present with `yasl_frame_present(frame, NULL,
0)` and return `YASL_APP_QUIT` from an event handler to exit. Without an `event`
-callback, closing any window stops the runner. The runner handles dispatch, input polling, resize redraws,
+callback, closing any window stops the runner. The runner handles dispatch, queued event delivery, resize redraws,
and remaining surface/display cleanup. Display quit stops the runner; connection
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`.
+the same display-wide FIFO consumed by `yasl_display_poll_event()`, including
+window state, drag hover, composition, clipboard completion, and display lifecycle
+events. `event.sequence` increases in enqueue order across all windows; it is
+YASL capture order, not a claim about ordering between native producers.
+Return `YASL_APP_ERROR` on application failure, or call
+`yasl_app_exit(display, YASL_APP_ERROR)` from a frame, timer, or fd callback.
+Cleanup still runs, and `yasl_run()` returns failure. During `init`,
+`yasl_app_window(display)` exposes the optional initial window. Application data
+can be supplied in `window.userdata` or attached with
+`yasl_surface_set_userdata()`; it is independent of callback userdata.
Unified pointer button and motion events retain `device` and `pen` axes,
including erasers and pressure-only motion. Cancel held input or active strokes
@@ -62,7 +70,7 @@ For applications managing their own event loop, use the core API below.
Open the display with application-wide options and notifications in
`yasl_display_spec`. Create each toplevel with `yasl_window_spec`, including its
-title, logical size, optional `yasl_window_cbs` table in `cbs`, and userdata in
+title, `size_logical`, optional `yasl_window_cbs` table in `cbs`, and userdata in
`ud`. One display can own multiple windows with separate callback tables.
The window copies its callbacks during creation. Its callbacks cannot run before
@@ -75,6 +83,9 @@ installs popup callbacks; the setter does not invoke the callbacks.
When using `yasl_run()`, its runner installs callbacks for windows on its display.
Use `yasl_app_desc.event` and `.frame` rather than `yasl_window_spec.cbs` and `.ud`.
+Replacing callbacks on a runner-owned surface fails with `EBUSY`.
+With a manual loop, install just the draw callback and drain the display FIFO
+after dispatch; lifecycle and input share the same event handler logic.
Read window state with `yasl_surface_state()`. Its `YASL_STATE_*` flags can
coexist, and the `state` callback receives the same current bitmask. Wayland
@@ -114,7 +125,7 @@ saturates out-of-range finite results, and returns zero for a zero scale.
## Drawing and pacing
-`yasl_surface_schedule_redraw()` coalesces requests. `yasl_display_flush()`
+`yasl_surface_request_frame()` coalesces requests. `yasl_display_flush()`
services them when the backend can draw. During a native resize, dispatch can
also draw synchronously. Avoid assuming callbacks occur only in flush.
@@ -132,27 +143,27 @@ static void draw(struct yasl_surface *surface, struct yasl_frame *frame, void *u
size_t count = (size_t)frame->target.size.x * frame->target.size.y;
for (size_t i = 0; i < count; i++)
frame->target.pixels[i] = 0xff306090;
- struct yasl_damage_list damage = {.n = -1};
- if (!yasl_surface_present(surface, &frame->target, &damage)) {
+ if (!yasl_frame_present(frame, NULL, 0)) {
/* Arrange application error handling after returning. */
}
}
```
-Present that exact target at most once during draw. Do not change its pointer,
-size, or generation, free it, or use it after callback return or surface
-destruction. A successful present consumes it. Invalid input returns false
-without consuming it. `damage.n = -1` means full target; `0` means no damaged
-rectangles; positive `n` uses the first `n` entries in `rects`. Extents must be
-nonnegative, and the core clips them to the target. `bounds` is a reserved hint
-and can be zero. Damage may reduce uploads, but every target must still contain
-complete valid content; backends may upload all pixels.
-
-To animate, schedule again from draw. With `YASL_CAP_FRAME_PACING`, the backend
-uses display/compositor signals to limit draws; tearing can bypass this. X11
-is unpaced: scheduling continuously will use CPU continuously. Use an application
-timer to limit redraws there. Suspended/hidden windows need not draw at each
-requested interval.
+Present the exact active frame at most once during its callback. Do not mutate
+the target identity or retain frame/pixel pointers after return. NULL rectangles
+with count zero mean full damage; a non-NULL array with zero count means no damage.
+All supplied extents must be nonnegative. Rectangles are clipped, and more than
+`YASL_DAMAGE_MAX` rectangles fall back to full damage after all are validated.
+Damage may reduce uploads, but every target must contain complete valid pixels.
+Native rendering uses the same frame, with a drawable queried in the extension.
+
+`yasl_surface_set_pacing()` works in either loop style. ON_DEMAND coalesces
+explicit requests and sleeps when idle. CONTINUOUS uses native display signals
+where available and a refresh-based timer otherwise, with about 60 Hz as a
+fallback estimate. It reports allocation/argument failures instead of silently
+ignoring surfaces outside the runner. Suspension can suppress actual drawing.
+Legacy `yasl_surface_present()` and `yasl_surface_schedule_redraw()` remain
+migration adapters; new code uses the frame presentation and request functions.
`yasl_surface_read_pixels()` copies the last presented CPU frame, for example
for a screenshot or a debugging tool. Call it outside draw callbacks. A frame
@@ -170,19 +181,20 @@ clock; it does not establish actual scanout time.
## Input, text, and payload lifetime
-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.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.
+Dispatch receives native input; `yasl_display_poll_event()` drains the display
+FIFO without waiting. Drain it once for the whole display, including multiple
+windows and popup input. `event.surface` identifies the live recipient and
+`surface_id` is its stable identity. Destruction cancels undelivered recipient
+events. `yasl_surface_poll_event()` remains an input-only migration adapter and
+discards pending non-input notifications, which legacy callbacks already
+delivered. Do not mix the two polling styles.
+
+Read the union member selected by `event.type`. `time_ns` is monotonic and
+`sequence` orders capture across the display. TEXT and DROP use `.text`, PASTE
+uses `.paste`, and COMPOSITION uses `.composition`. Each string is copied when
+queued, NUL-terminated, and borrowed until the next successful display/surface
+poll or display close. Dispatch, unsuccessful polls, and recipient destruction
+do not invalidate the last polled string. Copy it to retain it longer.
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
@@ -265,19 +277,22 @@ device interruptions; ignoring it can leave application input stuck.
## Clipboard, file drops, and IME
-`yasl_display_copy()` copies a NUL-terminated UTF-8 string during the call.
-`yasl_display_paste()` requests delivery to the original target as
-`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
-transfers. X11 converts legacy `STRING` data between Latin-1 and UTF-8; it only
-offers that legacy format when the copied text fits Latin-1. Malformed UTF-8
-clipboard transfers are discarded. Unsupported primary selection does nothing
-and never aliases the clipboard. Cocoa uses a YASL named pasteboard to emulate primary selection;
-this is not a desktop-wide macOS select-to-copy convention.
-
-External file drag hover uses the surface `drop` callback; actual file URLs
+`yasl_clipboard_set(display, selection, text)` copies a NUL-terminated UTF-8
+offer and reports failure through its return and errno. Wayland may require a
+recent input serial. `yasl_clipboard_request(surface, selection)` returns a
+nonzero request ID, or zero with errno when rejected. Each accepted request
+produces one `YASL_EVENT_PASTE` carrying `.paste.request_id`, `.status`, `.data`,
+and `.len`, unless its target/display is destroyed. OK includes empty text;
+UNAVAILABLE means no text offer, and FAILED means transfer/decoding failure.
+External Linux transfers have a 30-second timeout. X11 does not implement INCR
+and reports unsupported large transfers as FAILED. Legacy STRING uses Latin-1
+conversion. Malformed UTF-8 completes as failure.
+
+Unsupported primary selection reports ENOTSUP and never aliases the clipboard.
+Cocoa uses a YASL named pasteboard for primary selection. Legacy copy/paste calls
+remain adapters; legacy paste completions carry request ID zero.
+
+External file drag hover uses `YASL_EVENT_DROP_HOVER`; actual file URLs
arrive as `YASL_EVENT_DROP`. `text.data` is a `text/uri-list` string separated by
CRLF, not a list of native paths. `yasl_drop_next_path()` walks it and decodes
each local `file:` URL into a path. It skips comments, other schemes, remote
@@ -296,12 +311,12 @@ while ((len = yasl_drop_next_path(&cursor, path, sizeof(path))) != 0) {
Decoded paths are raw bytes and may contain any character the file system
allows, including newlines. Quote them before pasting into a shell.
-Use `yasl_surface_ime_preedit()` to draw the uncommitted composition. The borrowed
-pointer expires on the next dispatch or surface destruction; copy to keep it.
-Set the candidate-window caret with `yasl_surface_set_ime_caret()` in device
-pixels. X11 has no inline preedit. Cocoa supplies preedit text but currently no
-cursor range. On Wayland, `yasl_surface_ime_preedit_cursor()` returns UTF-8 byte
-offsets when a range is available. A false result leaves outputs unchanged.
+Handle `YASL_EVENT_COMPOSITION` for immutable UTF-8 preedit snapshots, byte
+selection offsets, and composition ending. Missing selection information uses
+-1 offsets. Insert only committed `YASL_EVENT_TEXT` into the document. Set the
+candidate-window caret with `yasl_surface_set_ime_caret()` in device pixels.
+X11 uses XIM preedit callbacks when offered; fallback input methods may provide
+no inline composition. The old preedit getters remain migration helpers.
## Popups and surface drags
@@ -315,8 +330,8 @@ serial to grab a popup, and older protocols may reject repositioning. Destroy
children before parents. The close callback requests application destruction;
it does not automatically free the popup.
-The surface `drag` callback handles a YASL surface drag; `drop` handles external
-data hover. `yasl_display_drag_start()` is intended for window/tab tear-off
+`YASL_EVENT_DRAG` handles a YASL surface drag; `YASL_EVENT_DROP_HOVER` handles
+external data hover. Legacy callbacks remain migration adapters. `yasl_display_drag_start()` is intended for window/tab tear-off
workflows, not arbitrary MIME data sources. Keep transferred application state
in your own registry. Start from a recent pointer press, and check the boolean
result even when `YASL_CAP_DRAG` is present. Supply an optional copied image and
@@ -367,7 +382,7 @@ Every backend's dispatch wakes when a loop descriptor becomes ready. Cocoa
waits for native events and mirrors the loop's descriptors in a kqueue while it
waits. If kqueue rejects a descriptor, Cocoa bounds the wait to 10 ms instead.
-Two calls work from any thread. `yasl_loop_kick()` only wakes the loop, and it
+Loop wake and post calls work from any thread. `yasl_loop_kick()` only wakes the loop, and it
is also safe in a signal handler. `yasl_loop_post()` queues a function to run
on the owning thread during a later step or dispatch. Use it to hand results
from worker threads to the loop:
@@ -387,6 +402,24 @@ and restores the previous action on unwatch. YASL leaves thread signal masks
alone: a watched signal must stay unblocked in at least one thread. Only one
loop can watch a given signal at a time.
+## Worker messages and window requests
+
+Capture `yasl_surface_id(surface)` on the display thread and pass that value to
+workers. `yasl_display_post(display, &message)` accepts an identity instead of a
+borrowed surface pointer. Zero targets the display. On success, optional
+`message.release(payload)` runs exactly once on the display thread after delivery
+or cancellation, including shutdown. It may post messages but must not poll,
+dispatch, or destroy YASL objects. Failed posting leaves ownership with the caller.
+Stop and join producers before closing the display. The same API works with a
+manual loop and with the runner; `yasl_post_event()` is a legacy adapter.
+
+Toplevel requests `yasl_surface_set_size(surface, logical_size)`,
+`yasl_surface_set_fullscreen`, `yasl_surface_set_maximized`, and
+`yasl_surface_minimize` return acceptance with errno on failure. Confirm actual
+geometry/state through queued events. Popup targets are invalid. Wayland cannot
+request an arbitrary live size and returns ENOTSUP for that operation; fullscreen,
+maximize, and minimize use xdg-shell requests. X11 and Cocoa implement all four.
+
## Desktop services
Include `<yasl/desktop.h>` for services that sit next to windowing. Display and
@@ -436,7 +469,7 @@ dispatch native connections, or change surface roles and buffer ownership.
Application-managed native drawing currently supports Cocoa/Metal. Use
`yasl_surface_create_native()` with a non-NULL Metal device, which YASL retains.
During draw, query `yasl_surface_get_native_frame()` for a borrowed drawable,
-encode and present with your renderer, then call `yasl_surface_present()` to
+encode and present with your renderer, then call `yasl_frame_present()` to
record submission. The drawable expires on successful present, callback return,
or surface destruction. Do not infer GPU completion from the boolean result.
Other backends return NULL with `errno = ENOTSUP` for native creation; having a