From 94c5e361fbb229b0cd6853e2102a7d95f1f358b3 Mon Sep 17 00:00:00 2001 From: Berke Güzel Date: Mon, 12 Oct 2026 22:12:02 +0300 Subject: better public interface and doxygen --- include/yasl/yasl.h | 614 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 515 insertions(+), 99 deletions(-) (limited to 'include/yasl/yasl.h') diff --git a/include/yasl/yasl.h b/include/yasl/yasl.h index df94800..f40264e 100644 --- a/include/yasl/yasl.h +++ b/include/yasl/yasl.h @@ -1,3 +1,26 @@ +/** + * @file + * Portable desktop surfaces, CPU drawing, input, and display dispatch. + * + * All calls and callbacks use the display's opening thread (the main thread on + * Cocoa), unless explicitly documented otherwise. Userdata is borrowed; callback + * tables and creation specs are copied. Do not recursively dispatch/flush or + * destroy a display/loop while dispatch or a callback is active. Destroy child + * popups before parents, surfaces before displays, displays before borrowed loops. + * Surface destruction from its own callback is supported; stop using it immediately. + * + * Zero-initialize option and callback structs before setting fields. Pointers to + * destroyed objects are invalid, even for getters and destroy functions. NULL + * handling is documented per function; it does not make freed pointers safe. + * Only functions explicitly documenting errno guarantee a diagnostic there. + * Other boolean results report success/availability; void setters are best effort. + * + * Toplevel creation sizes use logical pixels. Geometry, framebuffers, pointer + * positions, damage, IME carets, popup specs, and drag offsets use device pixels. + * Coordinates have their origin at the upper left; x grows right and y grows down. + * Scale is an integer ratio with YASL_SCALE_UNIT (120) representing 1x. + * See the application guide for the dispatch/poll/flush cycle and backend limits. + */ #ifndef YASL_H #define YASL_H @@ -9,11 +32,13 @@ #include #include "yasl/timing.h" +#include "yasl/keycodes.h" #ifdef __cplusplus extern "C" { #endif +/** Public shared-library symbol visibility annotation. */ #if defined(_WIN32) || defined(__CYGWIN__) #if defined(YASL_BUILD_SHARED) #define YASL_API __declspec(dllexport) @@ -33,23 +58,46 @@ struct yasl_surface; struct yasl_loop; /* Geometry */ +/** A two-dimensional integer size, position, or offset; units depend on the caller. */ struct yasl_vector2i { + /** Horizontal coordinate or width. */ int x; + /** Vertical coordinate or height. */ int y; }; +/** Two-dimensional fractional offset; units depend on the containing structure. */ +struct yasl_vector2d { + /** Horizontal component. */ + double x; + /** Vertical component. */ + double y; +}; + +/** Integer rectangle; origin is upper left and extents must be nonnegative. */ struct yasl_rect2i { + /** Left coordinate. */ int x; + /** Top coordinate. */ int y; + /** Nonnegative horizontal extent. */ int width; + /** Nonnegative vertical extent. */ int height; }; +/** Scale numerator representing 1x. */ #define YASL_SCALE_UNIT 120 +/** Backend minimum logical dimension used when constraining toplevel sizes. */ #define YASL_MIN_LOGICAL_PX 64 /* Nearest integer, ties away from zero. Zero scale returns zero; finite * out-of-range results saturate. Non-finite logical coordinates return zero. */ +/** Convert a logical coordinate to device pixels, rounding ties away from zero. + * @param logical Logical coordinate; non-finite values return zero. + * @param scale_120 Scale numerator; zero returns zero. + * @return Rounded device coordinate, saturated to the range of int. + */ static inline int yasl_scale_to_device(double logical, uint32_t scale_120) { if (!scale_120 || !(logical >= -DBL_MAX && logical <= DBL_MAX)) return 0; @@ -59,6 +107,11 @@ static inline int yasl_scale_to_device(double logical, uint32_t scale_120) return (int)(px + copysign(0.5, px)); } +/** Convert a device coordinate to logical pixels, rounding ties away from zero. + * @param device Device coordinate. + * @param scale_120 Scale numerator; zero returns zero. + * @return Rounded logical coordinate, saturated to the range of int. + */ static inline int yasl_scale_to_logical(int device, uint32_t scale_120) { if (!scale_120) return 0; @@ -73,219 +126,293 @@ static inline int yasl_scale_to_logical(int device, uint32_t scale_120) } /* Capabilities */ +/** Optional backend/server features, returned as a bitmask by yasl_display_caps(). */ enum yasl_display_cap : uint32_t { - YASL_CAP_POPUPS = 1 << 0, - YASL_CAP_DRAG = 1 << 1, - YASL_CAP_DRAG_CARRY = 1 << 2, - YASL_CAP_PLACE_WINDOW = 1 << 3, - YASL_CAP_PRIMARY_SELECTION = 1 << 4, - YASL_CAP_CSD = 1 << 5, - YASL_CAP_NATIVE_GRAPHICS = 1 << 6, - YASL_CAP_FRAME_PACING = 1 << 7, /* compositor/display-driven draws */ + YASL_CAP_POPUPS = 1 << 0, /**< Popup creation and placement. */ + YASL_CAP_DRAG = 1 << 1, /**< Surface-drag source and target support. */ + YASL_CAP_DRAG_CARRY = 1 << 2, /**< Carry a toplevel during a drag. */ + YASL_CAP_PLACE_WINDOW = 1 << 3, /**< Place a window relative to the pointer. */ + YASL_CAP_PRIMARY_SELECTION = 1 << 4, /**< Separate primary selection. */ + YASL_CAP_CSD = 1 << 5, /**< Backend advertises client decoration support; check each action result. */ + YASL_CAP_NATIVE_GRAPHICS = 1 << 6, /**< Application-managed native rendering. */ + YASL_CAP_FRAME_PACING = 1 << 7, /**< Compositor/display-driven draws. */ /* Backend/protocol supports tablet axes, independent of attached hardware. */ - YASL_CAP_TABLET = 1 << 8, + YASL_CAP_TABLET = 1 << 8, /**< Tablet protocol support, independent of attached hardware. */ }; +/** Independent selections. An unsupported selection never aliases the clipboard. */ enum yasl_selection : uint8_t { - YASL_CLIPBOARD, - YASL_PRIMARY, + YASL_CLIPBOARD, /**< Explicit copy/paste selection. */ + YASL_PRIMARY, /**< Independent primary selection, if supported. */ }; +/** Reported surface state flags; absent flags may also mean unsupported state. */ enum yasl_surface_state : uint32_t { - YASL_STATE_FULLSCREEN = 1 << 0, - YASL_STATE_MAXIMIZED = 1 << 1, - YASL_STATE_ACTIVATED = 1 << 2, - YASL_STATE_SUSPENDED = 1 << 3, - YASL_STATE_CSD = 1 << 4, + YASL_STATE_FULLSCREEN = 1 << 0, /**< Fullscreen. */ + YASL_STATE_MAXIMIZED = 1 << 1, /**< Maximized. */ + YASL_STATE_ACTIVATED = 1 << 2, /**< Active window. */ + YASL_STATE_SUSPENDED = 1 << 3, /**< Compositor reports suspension. */ + YASL_STATE_CSD = 1 << 4, /**< Backend reports client-side decorations. */ }; +/** System cursor shapes. HIDDEN preserves pointer input; NONE is its compatibility alias. */ enum yasl_cursor { - YASL_CURSOR_ARROW, - YASL_CURSOR_TEXT, - YASL_CURSOR_LINK, - YASL_CURSOR_CROSSHAIR, - YASL_CURSOR_MOVE, - YASL_CURSOR_RESIZE_NWSE, - YASL_CURSOR_RESIZE_NESW, - YASL_CURSOR_RESIZE_EW, - YASL_CURSOR_RESIZE_NS, - YASL_CURSOR_HIDDEN, /* Hide the system cursor; pointer input is unchanged. */ - YASL_CURSOR_NONE = YASL_CURSOR_HIDDEN, /* Compatibility alias. */ -}; - + YASL_CURSOR_ARROW, /**< Default arrow. */ + YASL_CURSOR_TEXT, /**< Text insertion. */ + YASL_CURSOR_LINK, /**< Link/pointer hand. */ + YASL_CURSOR_CROSSHAIR, /**< Crosshair. */ + YASL_CURSOR_MOVE, /**< Move in any direction. */ + YASL_CURSOR_RESIZE_NWSE, /**< Northwest/southeast resize. */ + YASL_CURSOR_RESIZE_NESW, /**< Northeast/southwest resize. */ + YASL_CURSOR_RESIZE_EW, /**< Horizontal resize. */ + YASL_CURSOR_RESIZE_NS, /**< Vertical resize. */ + YASL_CURSOR_HIDDEN, /**< Hidden system cursor; pointer input continues. */ + YASL_CURSOR_NONE = YASL_CURSOR_HIDDEN, /**< Compatibility alias for HIDDEN. */ +}; + +/** Valid interactive resize edges; combinations are restricted to the named values. */ enum yasl_resize_edge : uint32_t { - YASL_EDGE_NONE = 0, - YASL_EDGE_TOP = 1, - YASL_EDGE_BOTTOM = 2, - YASL_EDGE_LEFT = 4, - YASL_EDGE_TOP_LEFT = 5, - YASL_EDGE_BOTTOM_LEFT = 6, - YASL_EDGE_RIGHT = 8, - YASL_EDGE_TOP_RIGHT = 9, - YASL_EDGE_BOTTOM_RIGHT = 10, + YASL_EDGE_NONE = 0, /**< No resize edge; rejected by interactive resize. */ + YASL_EDGE_TOP = 1, /**< Top edge. */ + YASL_EDGE_BOTTOM = 2, /**< Bottom edge. */ + YASL_EDGE_LEFT = 4, /**< Left edge. */ + YASL_EDGE_TOP_LEFT = 5, /**< Top-left corner. */ + YASL_EDGE_BOTTOM_LEFT = 6, /**< Bottom-left corner. */ + YASL_EDGE_RIGHT = 8, /**< Right edge. */ + YASL_EDGE_TOP_RIGHT = 9, /**< Top-right corner. */ + YASL_EDGE_BOTTOM_RIGHT = 10, /**< Bottom-right corner. */ }; /* Damage & Framebuffer * CPU pixels are tightly packed premultiplied ARGB8888 (0xAARRGGBB). * Size, pointer positions, IME caret and damage use device pixels; surface - * creation sizes use logical pixels. Damage is a hint: backends may upload + * toplevel creation sizes use logical pixels. Damage is a hint: backends may upload * the whole frame. Every pixel must contain valid content on each draw. */ +/** Maximum number of damage rectangles in one presentation. */ #define YASL_DAMAGE_MAX 64 +/** Damage hints for one presentation; every target still needs complete valid pixels. */ struct yasl_damage_list { - int n; /* -1 means full repaint */ + /** -1: full target; 0: no damaged rectangles; otherwise number of rects. */ + int n; + /** Reserved hint; callers may leave zero. Core presentation uses rects. */ struct yasl_rect2i bounds; + /** First n rectangles, in device pixels; ignored for n == -1. */ struct yasl_rect2i rects[YASL_DAMAGE_MAX]; }; +/** Borrowed draw target, valid only for the current draw callback. Never free pixels. */ struct yasl_framebuffer { - uint64_t generation; /* Opaque draw identity; preserve when copying target. */ + /** Opaque draw identity. Preserve it and all target fields when copying. */ + uint64_t generation; + /** Writable premultiplied ARGB8888, row stride size.x * sizeof(uint32_t); may be NULL for native rendering. */ uint32_t *pixels; + /** Target extent in device pixels. */ struct yasl_vector2i size; }; +/** One draw invocation. Do not retain its pointer after the callback returns. */ struct yasl_frame { + /** Surface being drawn. */ struct yasl_surface *surface; + /** Target to initialize and present before returning. */ struct yasl_framebuffer target; }; /* Drag and Drop */ +/** Target notifications for YASL surface drags, separate from external file drops. */ enum yasl_drag_event { - YASL_DRAG_OVER, - YASL_DRAG_LEAVE, - YASL_DRAG_DROP, + YASL_DRAG_OVER, /**< Surface drag entered or moved over the target. */ + YASL_DRAG_LEAVE, /**< Surface drag left the target. */ + YASL_DRAG_DROP, /**< Surface drag dropped on the target. */ }; +/** External text/file drag hover notifications; completed data arrives through input. */ enum yasl_drop_event { - YASL_DROP_OVER, - YASL_DROP_LEAVE, + YASL_DROP_OVER, /**< External data drag entered or moved over the target. */ + YASL_DROP_LEAVE, /**< External data drag left the target. */ }; +/** Source-side drag completion; DROPPED does not prove application-level acceptance. */ enum yasl_drag_end { - YASL_DRAG_DROPPED, - YASL_DRAG_CANCELLED, + YASL_DRAG_DROPPED, /**< Drag ended in a drop; not an application acceptance receipt. */ + YASL_DRAG_CANCELLED, /**< Drag canceled, including display close. */ }; +/** Copied drag icon in tightly packed premultiplied 0xAARRGGBB device pixels. */ struct yasl_drag_image { + /** Copied pixel array; required when an image is supplied. */ const uint32_t *pixels; + /** Positive width and height in device pixels. */ struct yasl_vector2i size; + /** Pointer position within the image, in device pixels. */ struct yasl_vector2i hotspot; }; +/** Copied drag completion listener; userdata remains owned by the application. */ struct yasl_drag_listener { + /** Called exactly once after a successful start, possibly synchronously on cancel/close. */ void (*end)(void *ud, enum yasl_drag_end how); }; +/** Configured device-pixel content size and the corresponding display scale. */ struct yasl_geometry { + /** Current content extent in device pixels. */ struct yasl_vector2i size; + /** Positive scale numerator; 120 means 1x and 180 means 1.5x. */ uint32_t scale_120; }; /* Input Model */ +/** Keyboard press, release, or autorepeat; releases must not insert text. */ enum yasl_key_action { - YASL_KEY_PRESS, - YASL_KEY_RELEASE, - YASL_KEY_REPEAT, + YASL_KEY_PRESS, /**< Key pressed. */ + YASL_KEY_RELEASE, /**< Key released. */ + YASL_KEY_REPEAT, /**< Key autorepeat. */ }; +/** Modifier bitmask. SUPER is Command on macOS. */ enum yasl_mod : uint32_t { - YASL_MOD_SHIFT = 1 << 0, - YASL_MOD_ALT = 1 << 1, - YASL_MOD_CTRL = 1 << 2, - YASL_MOD_SUPER = 1 << 3, - YASL_MOD_CAPS = 1 << 4, + YASL_MOD_SHIFT = 1 << 0, /**< Shift modifier. */ + YASL_MOD_ALT = 1 << 1, /**< Alt/Option modifier. */ + YASL_MOD_CTRL = 1 << 2, /**< Control modifier. */ + YASL_MOD_SUPER = 1 << 3, /**< Super/Command modifier. */ + 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, - YASL_PTR_RELEASE, - YASL_PTR_MOTION, - YASL_PTR_LEAVE, - YASL_PTR_SCROLL, + 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, - YASL_PTR_DEV_TOUCH, - YASL_PTR_DEV_PEN, - YASL_PTR_DEV_ERASER, + YASL_PTR_DEV_MOUSE, /**< Mouse or trackpad pointer. */ + YASL_PTR_DEV_TOUCH, /**< Touch translated into pointer input. */ + YASL_PTR_DEV_PEN, /**< Tablet stylus. */ + YASL_PTR_DEV_ERASER, /**< Tablet eraser tool. */ }; +/** Normalized tablet axes; zero for unavailable axes and non-tablet devices. */ struct yasl_pointer_pen { - uint16_t pressure; /* 0..65535, normalized to the device's pressure range. */ - int8_t tilt_x; /* Degrees, -90..90; positive toward the right. */ - int8_t tilt_y; /* Degrees, -90..90; positive toward the bottom. */ -}; - + /** 0..65535 normalized to device range. Zero alone does not end contact. */ + uint16_t pressure; + /** Degrees in -90..90; positive right. */ + int8_t tilt_x; + /** Degrees in -90..90; positive down. */ + int8_t tilt_y; +}; + +/** 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. + */ struct yasl_key_event { - uint32_t key; - uint32_t keypad; + /** Portable physical key; YASL_KEY_UNKNOWN when unmapped. */ + enum yasl_key key; + /** Press, release, or autorepeat. */ enum yasl_key_action action; + /** yasl_mod bitmask at this event. */ uint32_t mods; + /** Optional unshifted layout Unicode scalar; zero if unavailable. */ uint32_t codepoint; + /** Optional shifted layout Unicode scalar; zero if unavailable. */ uint32_t shifted; - uint32_t base; - uint32_t text; + /** Native code: Wayland evdev, X11 server keycode, Cocoa virtual keycode. */ + 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. */ struct yasl_vector2i pos; - int16_t button; /* Press/release: 0 = primary/tip, 1 = middle, 2 = secondary. - * Motion/leave: informational; track presses and releases. */ - int16_t scroll_lines; + /** Press/release: 0 primary/tip, 1 middle, 2 secondary. Unused for scroll. */ + int16_t button; + /** Sample type. */ enum yasl_pointer_kind kind; + /** Mouse, touch, pen, or eraser. */ enum yasl_pointer_device device; + /** yasl_mod bitmask at this event. */ uint32_t mods; - float scroll_delta; - /* Pen/eraser samples include the current axes, also on pressure-only - * motion. Missing axes and non-tablet devices report zero. A primary - * release or leave ends contact; zero pressure alone is not a release. */ + /** 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, - YASL_INPUT_MOUSE, - YASL_INPUT_FOCUS, - YASL_INPUT_PASTE, - YASL_INPUT_DROP_FILES, - YASL_INPUT_TEXT, + 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, + YASL_INPUT_RESET, /**< No payload. Clear held keys/buttons and composition after an interruption. */ }; +/** Keyboard focus transition; cancel held state when focus is lost. */ 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; }; +/** 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; }; +/** 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; + /** Selects the valid union member. */ enum yasl_input_kind kind; + /** Reserved for YASL; applications must not interpret it. */ uint32_t reserved; union { - struct yasl_key_event key; - struct yasl_mouse_event mouse; - struct yasl_focus_event focus; - struct yasl_text_event text; - struct yasl_paste_event paste; - struct yasl_drop_files_event drop_files; + 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. */ }; }; @@ -300,128 +427,417 @@ struct yasl_input_event { */ /* Callbacks */ +/** Optional display notifications. NULL callback members are ignored. */ struct yasl_display_cbs { + /** Application quit request; arrange orderly shutdown after dispatch returns. */ void (*quit)(void *ud); + /** Application reopen/activation request, currently Cocoa. */ void (*reopen)(void *ud); + /** Display connection lost; arrange cleanup after dispatch returns. */ void (*lost)(void *ud); }; +/** Optional surface notifications, copied by yasl_surface_set_callbacks(). +Callbacks may destroy their surface. They must then return without further use +of the surface or draw target. NULL members are ignored. */ struct yasl_surface_cbs { + /** Initialize the entire target and optionally present. Requested through schedule_redraw/flush. */ void (*draw)(struct yasl_surface *s, struct yasl_frame *frame, void *ud); + /** Configured size/scale changed; reallocate application content and request a redraw. */ void (*configure)(struct yasl_surface *s, struct yasl_geometry geometry, void *ud); + /** Window/popup close request; application is responsible for destruction. */ void (*close)(struct yasl_surface *s, void *ud); + /** Reported yasl_surface_state bitmask changed. */ void (*state)(struct yasl_surface *s, uint32_t state, void *ud); + /** YASL surface-drag target hover, leave, or drop; pos is in device pixels. */ void (*drag)(struct yasl_surface *s, enum yasl_drag_event ev, struct yasl_vector2i pos, void *ud); + /** External data-drag hover or leave; pos is in device pixels. */ void (*drop)(struct yasl_surface *s, enum yasl_drop_event ev, struct yasl_vector2i pos, void *ud); }; /* Display Lifecycle */ +/** Runtime backend choice. AUTO selects a native backend and allows fallback. */ enum yasl_backend { - YASL_BACKEND_AUTO = 0, - YASL_BACKEND_WAYLAND, - YASL_BACKEND_X11, - YASL_BACKEND_COCOA, + YASL_BACKEND_AUTO = 0, /**< Choose native backend with fallback. */ + YASL_BACKEND_WAYLAND, /**< Require Wayland. */ + YASL_BACKEND_X11, /**< Require X11. */ + YASL_BACKEND_COCOA, /**< Require Cocoa. */ }; +/** Display options. Zero-initialize for automatic backend selection. */ struct yasl_display_spec { + /** Copied application identifier, conventionally a reverse-domain UTF-8 string; NULL uses backend defaults. */ const char *app_id; + /** Copied optional display callbacks; NULL disables them. */ const struct yasl_display_cbs *cbs; + /** Borrowed display callback userdata. */ void *ud; - /* Zero selects the native backend. An explicit choice never falls back. */ + + /** Zero/AUTO chooses native backend; explicit choices never fall back. */ enum yasl_backend backend; }; /* Return NULL and set errno if the requested backend cannot open. */ +/** + * Open a desktop connection and its event machinery. + * @param loop Borrowed loop, or NULL to create a display-owned loop. + * @param spec Copied options, or NULL for automatic backend selection and defaults. + * @return An owned display, or NULL with errno set. EINVAL means an invalid backend; + * ENOSYS means the requested backend was not built; ENODEV is the fallback when + * opening fails without a more specific platform error. Explicit choices never + * fall back. Close with yasl_display_close() after destroying its surfaces. + */ YASL_API struct yasl_display *yasl_display_open(struct yasl_loop *loop, const struct yasl_display_spec *spec); +/** + * Read the selected backend. + * @param d Display, or NULL. + * @return The actual backend, or YASL_BACKEND_AUTO for NULL. + */ YASL_API enum yasl_backend yasl_display_backend(const struct yasl_display *d); +/** + * Close a display and release its owned loop, if any. + * @param d Display to close, or NULL for no action. + * Destroy all surfaces first. Cancels an active drag and may invoke its end + * listener. Must not be called during dispatch or from a callback. + */ YASL_API void yasl_display_close(struct yasl_display *d); +/** + * Query currently available optional features. + * @param d Display, or NULL. + * @return A bitmask of yasl_display_cap values, or zero for NULL. + * Capabilities describe backend/server support, not attached input hardware or + * permission to perform an operation at any arbitrary moment. + */ YASL_API uint32_t yasl_display_caps(const struct yasl_display *d); /* Process events, waiting at most timeout_ms: zero polls, negative waits. * Pending input or redraw work returns immediately. Returns -1 on failure. */ +/** + * Receive events and run ready loop sources. + * @param d Display to dispatch. + * @param timeout_ms Maximum wait in milliseconds: zero polls, negative waits indefinitely. + * @return A nonnegative backend-specific work count on success, or -1 with errno + * set on failure (EINVAL for NULL, EIO if no specific backend error is available). + * Do not interpret the count as the number of queued input events. Pending input + * or runnable redraw work prevents waiting. Drain input and call + * yasl_display_flush() after updating application state. Do not dispatch recursively. + */ YASL_API int yasl_display_dispatch(struct yasl_display *d, int timeout_ms); +/** + * Draw scheduled surfaces and send pending display requests. + * @param d Display, or NULL for no action. + * May synchronously invoke draw and other callbacks. A paced surface may wait + * for its next display/compositor signal. This is not a GPU completion wait. + */ YASL_API void yasl_display_flush(struct yasl_display *d); +/** + * Read the latest modifier state known to the backend. + * @param d Display, or NULL. + * @return A bitmask of yasl_mod values, or zero for NULL. + * For an individual event use its own mods field instead. + */ YASL_API int yasl_display_modifiers(const struct yasl_display *d); /* Unsupported/invalid selections are no-ops, never clipboard aliases. */ +/** + * Offer a copy of a NUL-terminated UTF-8 string as a selection. + * @param d Display, or NULL for no action. + * @param sel YASL_CLIPBOARD or YASL_PRIMARY. + * @param text Text copied during this call; NULL does nothing. + * Unsupported selections do nothing. The void return does not confirm that the + * system accepted the offer; Wayland may require a recent input serial. + */ YASL_API void yasl_display_copy(struct yasl_display *d, enum yasl_selection sel, const char *text); +/** + * Request text delivery to a particular surface. + * @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 + * is promised for unavailable data or a failed transfer. Destroying target cancels + * delivery. Unsupported selections do nothing. + */ YASL_API void yasl_display_paste(struct yasl_display *d, enum yasl_selection sel, struct yasl_surface *target); /* A successful drag invokes the copied listener's non-NULL end once, including * cancel and display close. Failed starts do not invoke it. */ +/** + * Start a surface drag from a recent pointer press. + * @param d Display that owns origin. + * @param origin Origin surface. + * @param image Optional copied premultiplied ARGB8888 drag image, or NULL. + * @param l Optional copied completion listener, or NULL. + * @param ud Borrowed listener userdata until completion. + * @return true if started; false if unsupported, invalid, or not currently permitted. + * A successful start invokes a non-NULL end callback exactly once, including + * cancellation or display close. Failed starts do not invoke it. This API carries + * surfaces, not arbitrary MIME payloads; use application state to identify the item. + */ YASL_API bool yasl_display_drag_start(struct yasl_display *d, struct yasl_surface *origin, const struct yasl_drag_image *image, const struct yasl_drag_listener *l, void *ud); +/** + * Cancel the active surface drag, if any. + * @param d Display, or NULL for no action. + * May invoke the end listener synchronously. + */ YASL_API void yasl_display_drag_cancel(struct yasl_display *d); /* Surface Lifecycle */ +/** Toplevel options. Zero-initialize, then supply a positive logical-pixel size. */ struct yasl_surface_spec { + /** Copied UTF-8 title; NULL uses backend defaults. */ const char *title; + /** Requested logical-pixel width and height; both must be positive. */ struct yasl_vector2i size; + /** Request initial fullscreen; actual state is reported asynchronously. */ bool fullscreen; + /** Permit unpaced presentation where supported; a hint, not a guarantee. */ bool tearing; }; +/** Popup options, entirely in device pixels, including size. +The content rectangle excludes transparent margins/shadows used for placement. +An axis of content_size equal to zero extends to that axis of size. The offset +and resolved content size must fit in size. Anchor extents must be nonnegative. +Dimensions must be positive, at most 32767, and fit an INT32_MAX-byte buffer; +backends may impose further limits after scaling or resolving placement. */ struct yasl_popup_spec { + /** Full popup framebuffer extent in device pixels, including transparent margins. */ struct yasl_vector2i size; + /** Rectangle in parent framebuffer coordinates, in device pixels. */ struct yasl_rect2i anchor; + /** true prefers right of anchor; false prefers below. Placement may flip/slide. */ bool beside; + /** Top-left content offset within the popup, in device pixels. */ struct yasl_vector2i content_offset; + /** Content extent; zero per axis extends to the corresponding size edge. */ struct yasl_vector2i content_size; }; +/** + * Create a resizable desktop window with CPU drawing targets. + * @param d Owning display. + * @param spec Required copied options; size is in logical pixels. + * @return An owned surface, or NULL with errno set. EINVAL means invalid options, + * including a nonpositive dimension, a dimension above 32767, or a buffer above + * INT32_MAX bytes. ENODEV is the fallback backend failure. Actual configured + * size may differ from the request. Install callbacks and schedule a redraw. + */ YASL_API struct yasl_surface *yasl_surface_create_toplevel(struct yasl_display *d, const struct yasl_surface_spec *spec); +/** + * Create an owned popup attached to a parent surface. + * @param parent Borrowed parent; destroy the popup before the parent. + * @param spec Required copied options, entirely in device pixels. + * @return A popup, or NULL with errno set: EINVAL for invalid options, ENOTSUP + * for missing popup support, or a backend error (ENODEV if none was supplied). + * Wayland requires a recent input serial for its popup grab. The backend may + * flip or slide placement to fit the screen. See yasl_popup_spec. + */ YASL_API struct yasl_surface *yasl_surface_create_popup(struct yasl_surface *parent, const struct yasl_popup_spec *spec); +/** + * Update a popup's geometry and placement. + * @param popup An existing popup. + * @param spec Required copied replacement options, in device pixels. + * @return true on success; false with errno set: EINVAL for invalid options, + * ENOTSUP for missing popup support, or a backend error (ENODEV if unspecified). + * Older Wayland popup protocol versions can reject repositioning. + */ YASL_API bool yasl_surface_popup_reposition(struct yasl_surface *popup, const struct yasl_popup_spec *spec); +/** + * Destroy a surface and cancel its surface timers and pending input. + * @param s Surface, or NULL for no action. + * Destroy child popups first. May be called from a surface callback; return from + * that callback without further use of the surface or its draw target. Every + * pointer or native handle obtained from this surface becomes invalid. + */ YASL_API void yasl_surface_destroy(struct yasl_surface *s); +/** + * Get the display that owns a surface. + * @param s Surface, or NULL. + * @return A borrowed display, or NULL. + */ YASL_API struct yasl_display *yasl_surface_display(const struct yasl_surface *s); +/** + * Replace the surface's callback table and userdata. + * @param s Surface, or NULL for no action. + * @param cbs Table copied by value; NULL removes all callbacks. NULL members are ignored. + * @param ud Borrowed userdata passed to the installed callbacks. + * Callbacks may run synchronously during this call; initialize userdata first. + * Use yasl_surface_geometry() to read current geometry; do not rely on receiving + * an initial configure callback when registering. + */ YASL_API void yasl_surface_set_callbacks(struct yasl_surface *s, const struct yasl_surface_cbs *cbs, void *ud); +/** + * Replace the window title with copied UTF-8 text. + * @param s Surface. + * @param title NUL-terminated UTF-8 title. Pass an empty string to clear it. + * Backends may truncate the title. + */ YASL_API void yasl_surface_set_title(struct yasl_surface *s, const char *title); +/** + * Request a future draw callback, coalescing repeated requests. + * @param s Surface, or NULL for no action. + * Call yasl_display_flush() to service the request. Schedule again from draw to + * animate. Without YASL_CAP_FRAME_PACING, throttle animation with a timer. + */ YASL_API void yasl_surface_schedule_redraw(struct yasl_surface *s); /* Present exactly the target supplied to the current draw callback, at most * once. Targets expire when that callback returns or the surface is destroyed. * damage is required: n must be -1 or 0..YASL_DAMAGE_MAX. Rectangles must have * nonnegative extents; they are clipped to the target. Invalid input returns * false without consuming the frame. See yasl/native.h for native rendering. */ +/** + * Submit the current draw target at most once. + * @param s Surface currently being drawn. + * @param fb Exact target from the current draw callback, including its generation. + * @param damage Required damage hint: n is -1 for all pixels or 0..YASL_DAMAGE_MAX. + * @return true if accepted; false for invalid, stale, already presented, or failed targets. + * Rectangles must have nonnegative extents and are clipped to the target. Invalid + * input does not consume the frame. All pixels must be initialized even with + * partial damage. The backend may upload all pixels. Success records submission, + * not confirmed scanout. The target expires when draw returns or s is destroyed. + */ YASL_API bool yasl_surface_present(struct yasl_surface *s, const struct yasl_framebuffer *fb, const struct yasl_damage_list *damage); /* Event payload strings are library-owned, NUL-terminated, and valid until * 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. + * @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 + * ev->surface to identify the receiving surface. + */ YASL_API bool yasl_surface_input_poll(struct yasl_surface *s, struct yasl_input_event *ev); /* Current device-pixel size and scale, matching the configure callback. */ +/** + * Read current device-pixel size and scale together. + * @param s Surface, or NULL. + * @return Geometry matching configure callbacks; NULL gives zero size and unit scale. + */ YASL_API struct yasl_geometry yasl_surface_geometry(const struct yasl_surface *s); +/** + * Read current window state. + * @param s Surface, or NULL. + * @return A bitmask of yasl_surface_state values, or zero for NULL. + * Flags are reported state, not requests; unsupported states are absent. + */ YASL_API uint32_t yasl_surface_state(const struct yasl_surface *s); /* Timing uses monotonic nanoseconds. Check source before treating timestamps * as presentation confirmation. refresh/next_present are estimates. Without * YASL_CAP_FRAME_PACING, redraws run on flush without display synchronization. * Tearing may bypass pacing even when the capability is present. */ +/** + * Read frame timing estimates and their provenance. + * @param s Surface, or NULL. + * @return Current timing, or a zero-initialized result for NULL. + * Timestamps use monotonic nanoseconds. Inspect source before treating a timestamp + * as confirmation of presentation. Refresh and next-present values are estimates. + */ YASL_API struct yasl_timing yasl_surface_timing(const struct yasl_surface *s); +/** + * Get a nondecreasing animation timestamp aligned to estimated refresh. + * @param s Surface, or NULL. + * @param now Current monotonic nanoseconds, usually from yasl_loop_now_ns(). + * @return Animation timestamp, or zero for NULL. Before timing is known, returns now. + * Use this to advance animations; it is not presentation feedback. + */ YASL_API uint64_t yasl_surface_frame_time_ns(struct yasl_surface *s, uint64_t now); /* Set the mouse and tablet cursor for this surface, including future entries. * YASL_CURSOR_HIDDEN stays hidden until another cursor is selected. */ +/** + * Select the surface's system mouse and tablet cursor. + * @param s Surface. + * @param cursor Cursor shape; YASL_CURSOR_HIDDEN hides the cursor without disabling input. + * The choice persists across motion and re-entry until another shape is selected. + */ YASL_API void yasl_surface_set_cursor(struct yasl_surface *s, enum yasl_cursor cursor); +/** + * Set a backend window background hint. + * @param s Surface. + * @param bg Packed 0xAARRGGBB color; backends may ignore alpha or the entire hint. + * Does not initialize framebuffer pixels or replace drawing. + */ YASL_API void yasl_surface_set_background_color(struct yasl_surface *s, uint32_t bg); /* IME Support: preedit is borrowed until the next dispatch or destruction. */ +/** + * Read the current uncommitted UTF-8 composition text. + * @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, + * not preedit text. + */ YASL_API const char *yasl_surface_ime_preedit(const struct yasl_surface *s); +/** + * Read the cursor/selection range in the preedit string. + * @param s Surface. + * @param begin Required output UTF-8 byte offset for the range start. + * @param end Required output UTF-8 byte offset for the range end. + * @return true if available; false without changing outputs otherwise. + * Currently available on Wayland; Cocoa preedit text has no range result. + */ YASL_API bool yasl_surface_ime_preedit_cursor(const struct yasl_surface *s, int *begin, int *end); +/** + * Place the composition candidate window near the application caret. + * @param s Surface. + * @param caret Caret rectangle relative to the surface, in device pixels. + * Update after caret motion or scale changes. Unsupported backends ignore it. + */ YASL_API void yasl_surface_set_ime_caret(struct yasl_surface *s, struct yasl_rect2i caret); /* Client-Side Decorations (CSD) Actions */ +/** + * Ask the window system to begin an interactive move. + * @param s Toplevel surface, normally during handling of a pointer press. + * @return true if the request was issued; false if unsupported or not permitted. + * A recent input serial may be required. Success does not confirm a final position. + */ YASL_API bool yasl_surface_start_interactive_move(struct yasl_surface *s); +/** + * Ask the window system to begin an interactive resize. + * @param s Toplevel surface, normally during handling of a pointer press. + * @param edge One nonzero yasl_resize_edge enumerator. + * @return true if issued; false for an invalid edge, missing support, or rejected request. + */ YASL_API bool yasl_surface_start_interactive_resize(struct yasl_surface *s, enum yasl_resize_edge edge); +/** + * Ask the window system to display its window management menu. + * @param s Toplevel surface. + * @param pos Surface-relative position in device pixels. + * @return true if issued; false if unsupported or not currently permitted. + */ YASL_API bool yasl_surface_show_window_menu(struct yasl_surface *s, struct yasl_vector2i pos); /* Drag Support */ +/** + * Attach a toplevel surface to the current surface drag. + * @param s Surface to carry; check YASL_CAP_DRAG_CARRY first. + * @param offset Device-pixel offset of the pointer within the carried surface. + * @return true if accepted; false if unsupported or no compatible drag is active. + */ YASL_API bool yasl_surface_drag_carry(struct yasl_surface *s, struct yasl_vector2i offset); +/** + * Place a toplevel surface relative to the current pointer. + * @param s Surface; check YASL_CAP_PLACE_WINDOW first. + * @param at Device-pixel position within the surface to place under the pointer. + * @return true if issued; false if unsupported or unavailable. + */ YASL_API bool yasl_surface_place_under_pointer(struct yasl_surface *s, struct yasl_vector2i at); #ifdef __cplusplus -- cgit v1.2.3