From 98f0d51157fa2a2b8ccaae54ed4850a88d223d01 Mon Sep 17 00:00:00 2001 From: Berke Güzel Date: Tue, 13 Oct 2026 15:05:06 +0300 Subject: Simplify surface state, examples, and library installation --- docs/api-policy.md | 13 ++++---- docs/getting-started.md | 81 +++++++++++++++++++++---------------------------- docs/guide.md | 26 +++++++++++++++- docs/migrating.md | 15 ++++++++- docs/testing.md | 12 ++++---- 5 files changed, 87 insertions(+), 60 deletions(-) (limited to 'docs') diff --git a/docs/api-policy.md b/docs/api-policy.md index 0c8f040..dd22ca7 100644 --- a/docs/api-policy.md +++ b/docs/api-policy.md @@ -1,16 +1,17 @@ # Public API policy -YASL 0.1 is pre-release. The installed headers are the public API; implementation +YASL 0.1 is pre-release. The headers under `include/yasl/` are the public API; implementation headers under `src/` are private even when their symbols appear in a static -archive. The shared library exports only declarations from installed headers. -Native backend headers and accessors are available only for built backends. +archive. The shared library exports only declarations from public headers. +Native backend accessors are exported only for built backends. Installation +copies only the shared and static libraries; use matching source-tree headers. There is currently no stable ABI promise and no versioned shared-library SONAME. Rebuild consumers against the exact headers/library pair they ship. Source and binary compatibility can change before 1.0. Do not assume struct layout is stable across releases, mix headers and binaries from different revisions, or persist -public structs as a file/network format. The package version is available through -`pkg-config --modversion yasl`. +public structs as a file/network format. The release version is declared in +`meson.build`. See [migration notes](migrating.md) for window creation, portable keyboard, and fractional scroll API changes. @@ -28,7 +29,7 @@ Every public addition or behavior change needs: - An update to the guide and its backend limits when observable behavior changes. - A runnable example when the new workflow cannot be understood from an isolated call, and meaningful regression coverage for ownership or behavior changes. -- A check that shared exports and installed-package consumers still work. +- A check that shared exports and consumers of the installed library still work. Functions documenting errno set it on failure. Other booleans report acceptance or availability without a guaranteed errno; void setters are best effort. diff --git a/docs/getting-started.md b/docs/getting-started.md index d21c9bd..caa25eb 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -39,79 +39,68 @@ CPU pixel targets are presented through the system's Metal device; applications do not need to create or manage that device themselves. The complete beginner example is [hello.c](../examples/hello.c). It checks -construction failures, fills every pixel, presents inside `draw`, drains input, -responds to quit/close/lost, and destroys resources in order. The +construction failures, fills every pixel, and presents inside a frame callback. +`yasl_run()` handles input delivery, display notifications, and cleanup. The [interactive window](../examples/simple_window.c) adds pointer input; the [tablet example](../examples/tablet.c) demonstrates retained application content, pressure, erasers, resizing, and scale changes. ## Link an application -Install the library and public headers into your chosen prefix: +Install the shared and static libraries into your chosen prefix. Headers, +examples, documentation, and pkg-config metadata remain in the source tree: ```sh -meson setup build --prefix=/usr/local +meson setup build --prefix=/usr/local --libdir=lib meson compile -C build meson install -C build -cc -std=c23 examples/hello.c -o hello $(pkg-config --cflags --libs yasl) +cc -std=c23 -Iinclude examples/hello.c -o hello -L/usr/local/lib -Wl,-rpath,/usr/local/lib -lyasl ./hello ``` -The prefix must be writable, and your compiler, pkg-config, and runtime loader -must search it. For a custom prefix, set `PKG_CONFIG_PATH` to its pkg-config -directory and configure the loader for its library directory. Static linking -uses `pkg-config --static --libs yasl` to include backend dependencies. +The prefix must be writable. Use matching headers from `include/`, and adjust +the library search path and runtime path for your chosen prefix and `libdir`. +Static consumers must also link the enabled backends' dependencies. -A Meson consumer uses the installed dependency: +A Meson application can instead vendor the source under `subprojects/yasl`: ```meson project('my-app', 'c', default_options: ['c_std=c23']) -yasl = dependency('yasl', version: '>=0.1.0') +yasl = subproject('yasl').get_variable('yasl_dep') executable('my-app', 'main.c', dependencies: yasl) ``` -YASL also declares `meson.override_dependency('yasl', ...)`, so the same consumer -can use a vendored Meson subproject through a fallback dependency. Public headers -can be included from C++11 or newer; the library itself builds as C23. +The subproject dependency includes headers and backend link dependencies. +Public headers can be included from C++11 or newer; the library itself builds +as C23. Only the library artifacts are installed by `meson install`. ## The application cycle -1. Open a display with `yasl_display_open(NULL, &spec)`. NULL creates a loop owned - by the display. Supply your own loop only when you need shared loop ownership. -2. Create a toplevel with `yasl_window_spec`: supply a positive **logical-pixel** - size, a `yasl_window_cbs` table in `cbs`, and callback userdata in `ud`. - Zero-initialize every option and callback struct. Callback tables are copied; - userdata must remain alive. The new window's callbacks start after creation - returns. Read initial geometry with `yasl_surface_geometry()`. -3. Schedule the initial redraw. `draw` receives a borrowed target. Fill every - pixel with premultiplied `0xAARRGGBB`, then present that exact target, once. -4. Dispatch, drain input for every live surface queue, update application state, - and flush. Flush runs scheduled drawing and sends native requests. Dispatch - may also invoke callbacks, including drawing during native live resize. -5. Destroy popups before parents, surfaces before displays, and displays before - any supplied loop. NULL destroy/close calls do nothing; freed pointers are - invalid for every operation. +1. Include `` and initialize a `yasl_app_desc` with your userdata and + `init`, `event`, and `frame` callbacks. Call `yasl_run(&desc)`. +2. In `init`, create a toplevel with a positive **logical-pixel** size and call + `yasl_surface_request_frame(surface)` for the first redraw. +3. In `event`, handle the union member selected by `event->type`. Return + `YASL_APP_QUIT` for a close request; otherwise return `YASL_APP_CONTINUE`. +4. In `frame`, fill every pixel in `frame->cpu.pixels` with premultiplied + `0xAARRGGBB` and present once with `yasl_frame_present_cpu(frame, NULL, 0)`. +5. Let the runner close remaining surfaces and the display. Release your own + resources in the optional `quit` callback or after `yasl_run()` returns. ```c -while (running) { - if (yasl_display_dispatch(display, -1) < 0) { - perror("yasl_display_dispatch"); - break; - } - struct yasl_input_event event; - while (yasl_surface_input_poll(surface, &event)) { - /* Read the union member selected by event.kind. */ - } - yasl_display_flush(display); -} +struct yasl_app_desc desc = { + .app_id = "org.example.app", + .userdata = &app, + .init = init, + .event = event, + .frame = draw, +}; +return yasl_run(&desc); ``` -Zero timeout polls, positive timeout bounds the wait in milliseconds, and a -negative timeout waits for work. Undrained input makes dispatch return without -waiting. Use the return value only to detect failure, not to count input events. -If callbacks destroy surfaces, update your application registry immediately and -only poll surfaces that are still alive. Arrange display/loop cleanup after the -cycle ends; destroying them inside a callback is unsupported. +The default pacing mode sleeps until input, resize, or a requested redraw. +Use `YASL_PACING_CONTINUOUS` for an animation or game. The core API still supports +manual dispatch/poll/flush when an application owns its event loop; see the guide. See the [application guide](guide.md) for drawing, input, popups, timers, and platform limits, or the comments in the [public header](../include/yasl/yasl.h) diff --git a/docs/guide.md b/docs/guide.md index adcacc8..1bd1aef 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -39,6 +39,22 @@ it advertises CSD. Check each result and provide an application fallback. ## Window creation and callbacks +All examples include `` and call `yasl_run()` with a +`yasl_app_desc`. Create surfaces in `init`, handle `YASL_EVENT_*` notifications +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. + +Unified pointer button and motion events retain `device` and `pen` axes, +including erasers and pressure-only motion. Cancel held input or active strokes +on `YASL_EVENT_INPUT_RESET`, pointer leave, or focus loss. Reset also starts the +next motion delta from zero. [hello.c](../examples/hello.c) shows the minimal +lifecycle; [tablet.c](../examples/tablet.c) demonstrates device-aware drawing. + +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 @@ -55,6 +71,14 @@ 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`. +Read window state with `yasl_surface_state()`. Its `YASL_STATE_*` flags can +coexist, and the `state` callback receives the same current bitmask. Wayland +also reports `YASL_STATE_TILED` when any window edge is tiled; X11 and Cocoa +currently leave that flag unset. Unsupported flags are absent. On Wayland, an +ordinary floating toplevel has fullscreen, maximized, and tiled all absent. +`YASL_STATE_SUSPENDED` describes repaint suspension rather than minimization; +there is no portable minimized flag. + ## Geometry and scaling | Value | Units | @@ -301,7 +325,7 @@ signals the loop pipe but is not a portable cross-thread event-posting API. Portable CPU drawing needs no native headers. Opt into `` and ``, ``, or `` when -integrating a platform API. Typed headers and functions are installed only for +integrating a platform API. Typed native functions are exported only for built backends. Accessors return borrowed handles and zero/NULL for the wrong backend. Do not pass freed objects, destroy borrowed handles, independently dispatch native connections, or change surface roles and buffer ownership. diff --git a/docs/migrating.md b/docs/migrating.md index da4e591..395072e 100644 --- a/docs/migrating.md +++ b/docs/migrating.md @@ -1,9 +1,22 @@ # Migrating pre-release applications YASL 0.1 has no stable source or binary compatibility promise. Rebuild all -consumers against the matching installed headers and library after updating. +consumers against matching public headers and the library after updating. See the [application guide](guide.md) for the full window and input workflow. +## Application callbacks + +All examples now use `` and `yasl_run()`. Move window creation to +`yasl_app_desc.init`, 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_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 creation Rename `struct yasl_surface_spec` to `struct yasl_window_spec` and diff --git a/docs/testing.md b/docs/testing.md index d01b82c..bd3f2f0 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -24,7 +24,7 @@ meson test -C build-sanitize --print-errorlogs Default tests need no desktop connection. C++ header coverage is built when a C++ compiler is available. On Linux and macOS, the shared-export test ensures -only installed API declarations are exported. Test disabled-backend configurations separately with +only public API declarations are exported. Test disabled-backend configurations separately with `-Dwayland=disabled` or `-Dx11=disabled`; the combined integration harness needs both backends. @@ -94,13 +94,13 @@ serves as the drawing cursor. Mouse drawing uses a fixed width. Press C or Space to clear and Escape to quit. Resizing and display scale changes preserve the drawing. `--smoke-test` presents one frame and exits for automated checks. -[`examples/tablet.c`](../examples/tablet.c) includes only `` and the C -standard library. It uses CPU framebuffers and `yasl_surface_input_poll()` on -every backend. Tablet events arrive as `YASL_INPUT_MOUSE`, distinguished by -`mouse.device == YASL_PTR_DEV_PEN` or `YASL_PTR_DEV_ERASER`; `mouse.pen` contains +[`examples/tablet.c`](../examples/tablet.c) includes `` and the C +standard library. It uses `yasl_run()`, frame callbacks, and unified input events +on every backend. Tablet button and motion events retain `device`, which is +`YASL_PTR_DEV_PEN` or `YASL_PTR_DEV_ERASER`; their `pen` member contains pressure and signed tilt. Button 0 is tip contact on every backend. Track tip press/release events: zero pressure alone does not mean release. Hover and side -buttons do not paint, and focus loss, leave, or `YASL_INPUT_RESET` cancels a stroke. +buttons do not paint, and focus loss, leave, or `YASL_EVENT_INPUT_RESET` cancels a stroke. Stationary pressure changes arrive as motion events and update the brush too. The example uses portable physical keys: C and Space clear, Escape exits. -- cgit v1.2.3