# Migrating pre-release applications YASL 0.1 has no stable source or binary compatibility promise. Rebuild all consumers against matching public headers and the library after updating. See the [application guide](guide.md) for the full window and input workflow. ## Display queue, frames, and application failures The runner now consumes the display-wide FIFO directly. Manual loops should replace per-surface polling with `yasl_display_poll_event(display, &event)`. Surface polling remains an input-only adapter that discards pending non-input notifications delivered through legacy callbacks. Do not mix polling styles. Strings from either poll now survive recipient destruction and expire at the next successful poll on that display, or display close. Queue allocation failure is reported by dispatch as an error instead of silently losing a lifecycle notification. Replace `struct yasl_frame_context` with `struct yasl_frame`, `frame->cpu.pixels` with `frame->target.pixels`, and `frame->size` with `frame->target.size`. `target.stride_bytes` replaces `cpu.stride_bytes`. Native drawing uses `yasl_surface_get_native_frame(surface, &frame->target, &native)`. `yasl_frame_present(frame, NULL, 0)` replaces the CPU presentation wrapper. A non-NULL damage array with count zero now explicitly means no damaged pixels. Lists larger than the backend limit become full damage instead of truncating. `YASL_APP_ERROR` and `yasl_app_exit(display, result)` report application failures through `yasl_run`. `yasl_app_window(display)` gives init access to desc.window. Use `yasl_surface_set_userdata` / `yasl_surface_userdata` for per-window state, or `window.userdata` during creation. `yasl_surface_set_callbacks` now returns a boolean and rejects runner-owned surfaces with EBUSY. Spell toplevel creation sizes `size_logical`; `size` remains an alias. New window request functions report acceptance with errno. Pacing now works outside the runner too, and returns a boolean instead of silently ignoring calls. Replace clipboard copy/paste with `yasl_clipboard_set` / `yasl_clipboard_request`. Check the returned request ID and `event.paste.status` on completion. Empty text is successful; missing data and transfer errors now have explicit outcomes. Preedit snapshots arrive through `YASL_EVENT_COMPOSITION`; state and hover use `YASL_EVENT_WINDOW_STATE`, `YASL_EVENT_DRAG`, and `YASL_EVENT_DROP_HOVER`. For worker messages, capture a surface ID on the display thread and use `yasl_display_post` with an optional release callback. Do not also free the payload in the event handler when release owns cleanup. Stop producer threads before display shutdown; retired IDs reject posting with ENOENT. ## Application callbacks All examples now use `` and `yasl_run()`. Describe a single window in `yasl_app_desc.window`, or create windows in `.init`; move input handling to `.event` and drawing to `.frame`. Replace manual dispatch/poll/flush loops with the runner and request redraws with `yasl_surface_request_frame()`. Present the frame context with `yasl_frame_present()`; the runner destroys remaining surfaces on exit. 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_display_poll_event()` returns the same events that `yasl_app_desc.event` receives. Legacy surface polling returns only input types. | 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 Rename `struct yasl_surface_spec` to `struct yasl_window_spec` and `struct yasl_surface_cbs` to `struct yasl_window_cbs`. Surface handles and functions retain their names. Supply the window's callback table in `spec.cbs` and its userdata in `spec.ud` when calling `yasl_surface_create_toplevel()` or `yasl_surface_create_native()`. Callback tables are copied, and userdata is borrowed. The new window's callbacks cannot run before creation returns; read initial geometry with `yasl_surface_geometry()` and request the first redraw after initializing application state. `yasl_surface_set_callbacks()` remains available to replace callbacks after creation and to configure popups. A NULL `spec.cbs` creates a window without callbacks. Displays owned by `yasl_run()` use the runner's callbacks instead; provide application notifications through `yasl_app_desc.event` and `.frame`. ## Keyboard events | Previous use | Replacement | | --- | --- | | 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_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 command checks `key.key == YASL_KEY_ESCAPE` on a press. `YASL_KEY_A` means the 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_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. ## Scroll events Replace `scroll_lines`, `scroll_delta`, and scroll button numbers with `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 offset by your application's preferred pixels per line instead. X11 still supplies whole wheel steps. Wayland high-resolution wheels and smooth offsets, and Cocoa precise scrolling, preserve fractions. Device acceleration and system preferences still affect the native offsets.