From 76073fe5fad8799e5850805f2f090af2cb62c741 Mon Sep 17 00:00:00 2001 From: Berke Güzel Date: Tue, 13 Oct 2026 23:41:31 +0300 Subject: Simplify the public event and CPU API Applications now need far less ceremony: hello.c is a 20-line loop that handles REFRESH, CLOSE and QUIT and draws into the surface's own pixels. - Fold GEOMETRY, STATE and FOCUS into one WINDOW event carrying size, scale and state; unchanged values send nothing. - Guarantee REFRESH once a window has a size and after every resize, never at size zero. - Merge DROP_HOVER into DROP with over/leave/data actions and give drag and drop actions enums. - Keep event strings valid until the next wait and drop yasl_event_release; empty or failed waits report NONE. - Replace copy-in presentation with a lent pixel buffer: yasl_cpu_pixels and yasl_cpu_present. - Remove yasl_poll_event, yasl_cpu_read_pixels, unused event fields and comments that restated names. - Wayland: resize floating windows in request_size instead of reporting it unsupported, and stop marking new GPU surfaces as Vulkan so yasl_vulkan_create_surface no longer fails with NATIVE_WINDOW_IN_USE. Also includes the in-progress public API refactor that was uncommitted in the tree (removal of the app/loop layer, new surface, GL and Vulkan entry points). Co-Authored-By: Claude Opus 5.5 --- include/yasl/yasl.h | 1203 ++++++--------------------------------------------- 1 file changed, 133 insertions(+), 1070 deletions(-) (limited to 'include/yasl/yasl.h') diff --git a/include/yasl/yasl.h b/include/yasl/yasl.h index 889f70a..350339b 100644 --- a/include/yasl/yasl.h +++ b/include/yasl/yasl.h @@ -1,1089 +1,152 @@ -/** - * @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. - * New window requests, clipboard operations, frame presentation, and posting - * document errno on failure. Event strings belong to the display queue. - * - * 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 display-wide dispatch/poll/flush cycle - * and backend limits. Legacy surface polling is an input-only filtered adapter. - */ +/** @file Windows, input and events. The first surface starts the backend; use the + * creating thread (main on Cocoa) for every call except yasl_wake. Coordinates are + * logical units unless named pixel. */ #ifndef YASL_H #define YASL_H - #include #include #include -#include -#include -#include - -#include "yasl/timing.h" #include "yasl/keycodes.h" - +#if defined(__GNUC__) +#define YASL_API __attribute__((visibility("default"))) +#else +#define YASL_API +#endif #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) - #elif defined(YASL_SHARED) - #define YASL_API __declspec(dllimport) - #else - #define YASL_API - #endif -#elif defined(__GNUC__) && __GNUC__ >= 4 - #define YASL_API __attribute__((visibility("default"))) -#else - #define YASL_API -#endif - -struct yasl_display; -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; - double px = (scale_120 == YASL_SCALE_UNIT) ? logical : (logical * ((double)scale_120 / YASL_SCALE_UNIT)); - if (px >= INT_MAX) return INT_MAX; - if (px <= INT_MIN) return INT_MIN; - 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; - if (scale_120 == YASL_SCALE_UNIT) return device; - int64_t px = (int64_t)device * YASL_SCALE_UNIT; - int64_t half = (int64_t)(scale_120 / 2); - int64_t bias = (px < 0) ? -half : half; - px = (px + bias) / scale_120; - if (px > INT_MAX) return INT_MAX; - if (px < INT_MIN) return INT_MIN; - return (int)px; -} - -/* Capabilities */ -/** Optional backend/server features, returned as a bitmask by yasl_display_caps(). */ -enum yasl_display_cap : uint32_t { - 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, /**< Tablet protocol support, independent of attached hardware. */ -}; - -/** Independent selections. An unsupported selection never aliases the clipboard. */ -enum yasl_selection : uint8_t { - 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, /**< 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. */ - YASL_STATE_TILED = 1 << 5, /**< At least one edge is tiled; currently reported by Wayland. */ -}; - -/** System cursor shapes. HIDDEN preserves pointer input; NONE is its compatibility alias. */ -enum yasl_cursor { - 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, /**< 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 - * 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 { - /** -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 { - /** 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; - /** Row stride in bytes, populated for the active draw callback. */ - int stride_bytes; -}; - -/** 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; - /** Zero-based index of this surface draw. */ - uint64_t frame_index; - /** Estimated animation time; not confirmed presentation. */ - uint64_t target_time_ns; - /** Device scale numerator, with 120 representing 1x. */ - uint32_t scale_120; -}; - -/** Coalesced redraw policy, valid with either loop style. */ -typedef enum yasl_pacing_mode { - YASL_PACING_ON_DEMAND = 0, /**< Draw only when invalidated or exposed. */ - YASL_PACING_CONTINUOUS, /**< Draw continuously using native pacing or a timer. */ -} yasl_pacing_mode; - -/* Drag and Drop */ -/** Target notifications for YASL surface drags, separate from external file drops. */ -enum yasl_drag_event { - 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, /**< 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, /**< 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, /**< 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, /**< 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 source class; capability support does not imply an attached device. */ -enum yasl_pointer_device { - 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. */ -}; - -/** 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. */ -}; - -/** Bit for a yasl_pointer_button in yasl_pointer_event.buttons. */ +typedef struct yasl_surface yasl_surface; +typedef struct yasl_event yasl_event; +enum yasl_backend { YASL_BACKEND_AUTO, YASL_BACKEND_WAYLAND, YASL_BACKEND_X11, YASL_BACKEND_COCOA }; +enum yasl_surface_flags { YASL_SURFACE_CPU=1u, YASL_SURFACE_HIDDEN=2u, YASL_SURFACE_UNDECORATED=4u, YASL_SURFACE_FIXED_SIZE=8u }; +enum yasl_error { YASL_ERROR_NONE, YASL_ERROR_INVALID, YASL_ERROR_UNSUPPORTED, YASL_ERROR_NO_MEMORY, + YASL_ERROR_NOT_INITIALIZED, YASL_ERROR_BUSY, YASL_ERROR_WRONG_THREAD, YASL_ERROR_CONTEXT_EXPIRED, YASL_ERROR_IO }; +enum yasl_selection { YASL_CLIPBOARD, YASL_PRIMARY }; +enum yasl_key_action { YASL_KEY_PRESS, YASL_KEY_RELEASE, YASL_KEY_REPEAT }; +enum yasl_mod { YASL_MOD_SHIFT=1u, YASL_MOD_ALT=2u, YASL_MOD_CTRL=4u, YASL_MOD_SUPER=8u, YASL_MOD_CAPS=16u }; +enum yasl_pointer_action { YASL_POINTER_MOVE, YASL_POINTER_DOWN, YASL_POINTER_UP, YASL_POINTER_LEAVE }; +enum yasl_pointer_mode { YASL_POINTER_NORMAL, YASL_POINTER_RELATIVE }; +enum yasl_button { YASL_BUTTON_PRIMARY, YASL_BUTTON_MIDDLE, YASL_BUTTON_SECONDARY, YASL_BUTTON_BACK, YASL_BUTTON_FORWARD }; #define YASL_BUTTON_BIT(button) (1u << (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. */ - uint16_t pressure; - /** Degrees in -90..90; positive right. */ - int8_t tilt_x; - /** Degrees in -90..90; positive down. */ - 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: part of the display FIFO, as well as runner delivery. - * Legacy window callbacks also receive matching native notifications. */ - 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 application message. */ - YASL_EVENT_WINDOW_STATE, /**< .state — reported state changed. */ - YASL_EVENT_DRAG, /**< .drag — surface-drag target notification. */ - YASL_EVENT_DROP_HOVER, /**< .drop — external drag hover/leave. */ - YASL_EVENT_COMPOSITION, /**< .composition — preedit snapshot, including ending. */ - YASL_EVENT_DISPLAY_QUIT, /**< No payload; system requested application quit. */ - YASL_EVENT_DISPLAY_REOPEN, /**< No payload; system requested activation. */ - YASL_EVENT_DISPLAY_LOST, /**< No payload; display connection failed. */ -}; - -/** 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. Insert committed - * YASL_EVENT_TEXT into documents instead. */ -struct yasl_key_event { - /** 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; - /** Native code: Wayland evdev, X11 server keycode, Cocoa virtual keycode. */ - uint32_t native_code; -}; - -/** 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; - /** 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; - /** YASL_BUTTON_BIT() mask of buttons held after this event, on every - * POINTER_* type. Tracked from this queue's DOWN and UP events for all - * devices; INPUT_RESET clears it. On Wayland LEAVE clears it too, since the - * compositor sends leave during a press only when it takes the pointer. - * X11 and Cocoa keep sending motion and the release after LEAVE. */ - uint32_t buttons; - /** Mouse, touch, pen, or eraser. */ - enum yasl_pointer_device device; - /** yasl_mod bitmask at this event. */ - uint32_t mods; - /** Current tablet axes, including on pressure-only motion; missing axes are zero. */ - struct yasl_pointer_pen pen; -}; - -/** 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; -}; - -/** Clipboard transfer outcome. */ -enum yasl_transfer_status { - YASL_TRANSFER_OK = 0, /**< Text received successfully, including empty text. */ - YASL_TRANSFER_UNAVAILABLE, /**< No text selection is available. */ - YASL_TRANSFER_FAILED, /**< Transfer or decoding failed. */ -}; - -/** Clipboard completion; data/len alias the legacy text payload. */ -struct yasl_paste_event { - const char *data; /**< Borrowed NUL-terminated UTF-8; empty on failure. */ - size_t len; /**< Byte length excluding NUL. */ - uint64_t request_id; /**< Zero for a legacy paste request. */ - enum yasl_transfer_status status; /**< Completion outcome. */ -}; - -/** Borrowed UTF-8 preedit snapshot, valid until the next successful display poll. */ -struct yasl_composition_event { - const char *data; /**< Borrowed NUL-terminated UTF-8 snapshot. */ - size_t len; /**< Byte length excluding NUL. */ - int begin; /**< UTF-8 byte offset, or -1 if unavailable. */ - int end; /**< UTF-8 byte offset, or -1 if unavailable. */ - bool active; /**< Whether composition text is present. */ -}; - -/** Reported window-state change. */ -struct yasl_state_event { uint32_t flags; /**< Current YASL_STATE_* flags. */ }; -/** Surface-drag target notification; position is in device pixels. */ -struct yasl_drag_target_event { - enum yasl_drag_event action; /**< Hover, leave, or drop. */ - struct yasl_vector2i pos; /**< Surface-relative device pixels. */ -}; -/** External drag hover notification; position is in device pixels. */ -struct yasl_drop_hover_event { - enum yasl_drop_event action; /**< Hover or leave. */ - struct yasl_vector2i pos; /**< Surface-relative device pixels. */ -}; - -/** Keyboard focus transition. */ -struct yasl_focus_event { - /** true on focus gain, false on loss. */ - bool focused; -}; - -/** 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; -}; - -/** 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; -}; - -/** One tagged event; read only the union member selected by type. */ +enum yasl_pen_tool { YASL_PEN_UNKNOWN, YASL_PEN_PEN, YASL_PEN_ERASER, YASL_PEN_BRUSH, YASL_PEN_AIRBRUSH, YASL_PEN_PENCIL }; +enum yasl_pen_action { YASL_PEN_ENTER, YASL_PEN_LEAVE, YASL_PEN_MOVE, YASL_PEN_DOWN, YASL_PEN_UP, YASL_PEN_BUTTON, YASL_PEN_CANCEL }; +enum yasl_pen_axis { YASL_PEN_PRESSURE=1u, YASL_PEN_TILT=2u, YASL_PEN_ROTATION=4u, YASL_PEN_DISTANCE=8u, YASL_PEN_TANGENTIAL=16u, YASL_PEN_WHEEL=32u }; +enum yasl_scroll_valid { YASL_SCROLL_LINES=1u, YASL_SCROLL_PIXELS=2u }; +enum yasl_scroll_source { YASL_SCROLL_UNKNOWN, YASL_SCROLL_WHEEL, YASL_SCROLL_FINGER, YASL_SCROLL_CONTINUOUS }; +enum yasl_scroll_phase { YASL_SCROLL_PHASE_UNKNOWN, YASL_SCROLL_BEGIN, YASL_SCROLL_UPDATE, YASL_SCROLL_END }; +enum yasl_transfer_status { YASL_TRANSFER_OK, YASL_TRANSFER_UNAVAILABLE, YASL_TRANSFER_FAILED }; +enum yasl_text_purpose { YASL_TEXT_NORMAL, YASL_TEXT_PASSWORD, YASL_TEXT_NUMBER, YASL_TEXT_TERMINAL }; +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 }; +enum yasl_surface_state { YASL_STATE_FULLSCREEN=1u, YASL_STATE_MAXIMIZED=2u, YASL_STATE_ACTIVATED=4u, + YASL_STATE_SUSPENDED=8u, YASL_STATE_CSD=16u, YASL_STATE_TILED=32u }; +enum yasl_feature { YASL_CAP_POPUPS=1u, YASL_CAP_DRAG=2u, YASL_CAP_DRAG_CARRY=4u, YASL_CAP_PLACE_WINDOW=8u, + YASL_CAP_PRIMARY_SELECTION=16u, YASL_CAP_CSD=32u, YASL_CAP_NATIVE_GRAPHICS=64u, YASL_CAP_FRAME_PACING=128u, + YASL_CAP_TABLET=256u, YASL_CAP_OPENGL=512u, YASL_CAP_VULKAN=1024u, YASL_CAP_TEXT_INPUT=2048u }; +enum yasl_popup_edge { YASL_POPUP_CENTER, YASL_POPUP_TOP, YASL_POPUP_BOTTOM, YASL_POPUP_LEFT, + YASL_POPUP_RIGHT, YASL_POPUP_TOP_LEFT, YASL_POPUP_BOTTOM_LEFT, YASL_POPUP_TOP_RIGHT, YASL_POPUP_BOTTOM_RIGHT }; +enum yasl_popup_constraint { YASL_POPUP_SLIDE_X=1u, YASL_POPUP_SLIDE_Y=2u, YASL_POPUP_FLIP_X=4u, + YASL_POPUP_FLIP_Y=8u, YASL_POPUP_RESIZE_X=16u, YASL_POPUP_RESIZE_Y=32u }; +enum yasl_resize_edge { 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 }; +enum yasl_event_type { YASL_EVENT_NONE, YASL_EVENT_CLOSE, YASL_EVENT_QUIT, YASL_EVENT_REOPEN, YASL_EVENT_WINDOW, + YASL_EVENT_REFRESH, YASL_EVENT_KEY, YASL_EVENT_TEXT, YASL_EVENT_POINTER, YASL_EVENT_SCROLL, YASL_EVENT_PEN, + YASL_EVENT_INPUT_RESET, YASL_EVENT_COMPOSITION, YASL_EVENT_TEXT_EDIT, YASL_EVENT_CLIPBOARD, YASL_EVENT_DROP, + YASL_EVENT_DRAG, YASL_EVENT_DISPLAY_LOST }; +enum yasl_drop_action { YASL_DROP_OVER, YASL_DROP_LEAVE, YASL_DROP_DATA }; +enum yasl_drag_action { YASL_DRAG_OVER, YASL_DRAG_LEAVE, YASL_DRAG_DROP }; +/** Read the union member named by type. Strings stay valid until the next wait. + * CLOSE: the user closed this window. QUIT: the system asked the app to quit. + * WINDOW: size, scale or state changed. REFRESH: draw now; sent once the window + * has a size, after every resize and when the system needs the contents again. + * INPUT_RESET: forget held keys, buttons and strokes. DROP: external data over + * the window, delivered as DATA. DRAG: another YASL surface dragged over. */ struct yasl_event { - /** Selects the valid union member. */ 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(). */ + yasl_surface *surface; uint64_t time_ns; - /** Increasing display-wide enqueue order; zero for standalone private queues. */ - uint64_t sequence; - /** Stable recipient identity; zero for display-wide events. */ - uint64_t surface_id; - union { - struct yasl_key_event key; /**< KEY */ - struct yasl_pointer_event pointer; /**< POINTER_* */ - struct yasl_text_event text; /**< TEXT, legacy PASTE, DROP */ - struct yasl_paste_event paste; /**< PASTE */ - struct yasl_composition_event composition; /**< COMPOSITION */ - struct yasl_state_event state; /**< WINDOW_STATE */ - struct yasl_drag_target_event drag; /**< DRAG */ - struct yasl_drop_hover_event drop; /**< DROP_HOVER */ - struct yasl_focus_event focus; /**< FOCUS */ - struct yasl_resize_event resize; /**< WINDOW_RESIZE */ - struct yasl_user_event user; /**< USER */ - }; -}; - -/* Ownership and threading - * All calls and callbacks run on the display's opening thread (main thread on - * Cocoa). Displays borrow supplied loops; destroy surfaces before displays, - * popups before parents, and displays before their supplied loop. - * Specs, strings, callback tables and drag listeners are copied during calls. - * Userdata is borrowed until callbacks are removed or the object/drag ends. - * Surface destruction is allowed from its callbacks; display/loop destruction - * during dispatch or callbacks is not supported. - */ - -/* 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 window/popup notifications, copied from yasl_window_spec.cbs or 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_window_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; matches yasl_surface_state(s). */ - 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, /**< 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/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); -/** Double-click interval used when the system reports none. */ -#define YASL_DOUBLE_CLICK_MS_DEFAULT 400 -/** - * Read the system's double-click interval. - * @param d Display, or NULL. - * @return Maximum milliseconds between the clicks of a double click, or - * YASL_DOUBLE_CLICK_MS_DEFAULT when d is NULL or the system reports none. - * X11 reads the XSETTINGS Net/DoubleClickTime value. Wayland, and X11 without - * XSETTINGS, read the KDE or GNOME setting through the XDG Settings portal, - * which needs D-Bus and can wait briefly. Cocoa reads the system interval. - * The user can change it at any time; read it again when a window gains focus - * rather than on every click. - */ -YASL_API int yasl_display_double_click_ms(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_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. - */ -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_window_spec { - /** Copied UTF-8 title; NULL uses backend defaults. */ - const char *title; - /** Requested logical-pixel width and height; both must be positive. */ union { - struct yasl_vector2i size_logical; /**< Requested logical-pixel extent. */ - struct yasl_vector2i size; /**< Migration alias for size_logical. */ + struct { int width,height,pixel_width,pixel_height; double scale; unsigned state; } window; + struct { enum yasl_key key; enum yasl_key_action action; unsigned mods; + uint32_t codepoint, shifted, native_code; } key; + struct { const char *data; size_t length; } text; + struct { double x,y,dx,dy; enum yasl_pointer_action action; unsigned button,buttons,mods; } pointer; + struct { double x,y,lines_x,lines_y,pixels_x,pixels_y; unsigned valid,source,phase,mods; bool momentum; } scroll; + struct { uint64_t device_id,tool_id; double x,y,pressure,tilt_x,tilt_y,rotation,distance,tangential,wheel_degrees; + unsigned axes_valid,axes_changed,buttons,changed_button,tool,action; bool in_contact; } pen; + struct { const char *data; size_t length; int begin,end; bool active; uint64_t revision,generation; } composition; + struct { const char *data; size_t length,begin,end; uint64_t revision,generation; } text_edit; + struct { const char *data; size_t length; uint64_t request_id; enum yasl_transfer_status status; } clipboard; + /** DATA carries a text/uri-list for yasl_drop_next_path; x/y are set for OVER. */ + struct { enum yasl_drop_action action; double x,y; const char *data; size_t length; } drop; + struct { enum yasl_drag_action action; double x,y; } drag; }; - /** Request initial fullscreen; actual state is reported asynchronously. */ - bool fullscreen; - /** Permit unpaced presentation where supported; a hint, not a guarantee. */ - bool tearing; - /** Copied optional window callbacks; NULL disables them. */ - const struct yasl_window_cbs *cbs; - /** Borrowed window callback userdata; ignored by the runner. */ - void *ud; - /** Borrowed application data, independent of callbacks and available in either loop style. */ - void *userdata; }; - -/** 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. The callback table in spec->cbs is copied; - * spec->ud stays borrowed until callbacks are replaced or the surface is destroyed. - * This window's callbacks cannot run before creation returns. Use - * yasl_surface_geometry() for initial geometry; an initial configure callback - * is not guaranteed. Schedule an initial redraw after setting up application state. - * On a display owned by yasl_run(), the runner installs its own callbacks instead; - * use yasl_app_desc.event and yasl_app_desc.frame for application notifications. - */ -YASL_API struct yasl_surface *yasl_surface_create_toplevel(struct yasl_display *d, - const struct yasl_window_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. - * @param cbs Table copied by value; NULL removes all callbacks. NULL members are ignored. - * @param ud Borrowed userdata passed to the installed callbacks. - * @return true if replaced; false with EINVAL for NULL, EBUSY on a runner-owned surface. - * This call only replaces callbacks; it does not invoke them. - * Use yasl_surface_geometry() to read current geometry; do not rely on receiving - * an initial configure callback when registering. - */ -YASL_API bool yasl_surface_set_callbacks(struct yasl_surface *s, - const struct yasl_window_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); -/** - * Migration adapter: consume one input event for a surface from the display FIFO. - * Popup input can belong to the root queue; inspect ev->surface. Returns false - * for empty/invalid arguments, leaving ev unchanged. Strings remain borrowed - * until the next successful display or surface poll, or display close. Pending - * recipient events are canceled on destruction. Prefer yasl_display_poll_event() - * to receive window, composition, and display events as well as input. This - * input-only adapter discards pending non-input events across the display - * (legacy callbacks already delivered lifecycle changes). Do not mix - * the two polling styles in one application. Use the display thread. - */ -YASL_API bool yasl_surface_poll_event(struct yasl_surface *s, struct yasl_event *ev); -/** - * Decode the next local file path from a YASL_EVENT_DROP payload. - * @param cursor Required in/out position in the NUL-terminated list. Start it - * at event.text.data; a NULL *cursor returns zero. - * @param out Output for the NUL-terminated path, or NULL when cap is zero. - * @param cap Size of out in bytes. - * @return Path length in bytes, excluding the NUL, or zero when no paths remain. - * When the result is less than cap, out holds the path and *cursor moves past - * it. Otherwise out and *cursor are unchanged; call again with a buffer of at - * least the result plus one. - * Accepts file:///path, file:/path, and file://host/path when host is - * localhost or this machine's name. Percent escapes decode to raw bytes, and - * a '?' or '#' ends the path. Skips blank lines, comments, other schemes, - * other hosts, and lines with a malformed escape or an escaped NUL. May be - * called from any thread. - */ -YASL_API size_t yasl_drop_next_path(const char **cursor, char *out, size_t cap); -/** - * Copy the last frame presented from the surface's CPU target. - * @param s Surface. - * @param out Output for size->x * size->y premultiplied ARGB8888 pixels with - * tightly packed rows, or NULL when cap is zero. - * @param cap Capacity of out in pixels. - * @param size Required output: the frame extent in device pixels, or zero when - * no frame is available. - * @return true if copied. false leaves out unchanged; when *size is nonzero, - * out was too small, so allocate size->x * size->y pixels and call again. - * A frame is available from a successful yasl_surface_present() until the - * next draw callback starts, and again once that draw presents. After a draw - * that does not present or a resize that replaces the target, no frame may be - * available; native rendering never has one. Call outside draw callbacks. This copies YASL's frame, not - * the composited screen: decorations, other windows, and color conversion are - * not included. - */ -YASL_API bool yasl_surface_read_pixels(struct yasl_surface *s, uint32_t *out, size_t cap, - struct yasl_vector2i *size); -/** - * 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; false leaves the current mode. - * 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(). RELATIVE is supported on - * Wayland compositors with the relative-pointer and pointer-constraints - * protocols; X11 and Cocoa return false. - */ -YASL_API bool yasl_surface_set_pointer_mode(struct yasl_surface *s, enum yasl_pointer_mode mode); - -/** - * Consume one event from the display-wide FIFO without waiting. - * Returns false for an empty queue or invalid arguments, leaving ev unchanged. - * Strings remain valid until the next successful poll or display close. - * Surface destruction cancels undelivered events, not the last polled payload. - * Use the display thread. Do not mix display and surface polling in one app. - */ -YASL_API bool yasl_display_poll_event(struct yasl_display *d, struct yasl_event *ev); - -/** Stable nonzero identity within a display; zero for NULL. Use on the display thread. */ -YASL_API uint64_t yasl_surface_id(const struct yasl_surface *s); -/** Store borrowed application data independently of callback userdata. */ -YASL_API void yasl_surface_set_userdata(struct yasl_surface *s, void *userdata); -/** Read borrowed application data, or NULL for NULL; use on the display thread. */ -YASL_API void *yasl_surface_userdata(const struct yasl_surface *s); - -/** Thread-safe message descriptor. Zero target_id means display-wide. */ -struct yasl_message { - uint64_t target_id; /**< Surface identity, or zero for the display. */ - uint32_t code; /**< Application-defined message code. */ - void *payload; /**< Borrowed until release; passed through unchanged. */ - size_t size; /**< Application-defined payload length. */ - /** Optional cleanup on display thread after delivery/cancellation, exactly once. - * May post messages, but must not dispatch, poll, or destroy YASL objects. */ - void (*release)(void *payload); -}; -/** - * Copy and enqueue a message from any thread; the display must stay alive. - * Stop producer threads before closing the display. On success release runs - * once after consumption or cancellation. On failure ownership stays with the - * caller; errno is EINVAL, ENOENT (retired identity), ENOMEM, or EOVERFLOW. - */ -YASL_API bool yasl_display_post(struct yasl_display *d, const struct yasl_message *message); - -/** - * Present the active frame once. NULL/0 means full damage; non-NULL/0 means none. - * Validate all rectangles; excess rectangles fall back to full damage. - * Returns false with EINVAL for invalid/stale targets, EALREADY for a consumed - * frame, or errno from the backend (EIO if unspecified). - * Frame and pixels expire at callback return; use the display thread. - */ -YASL_API bool yasl_frame_present(struct yasl_frame *frame, - const struct yasl_rect2i *rects, size_t count); -/** Coalesce a redraw request; use on the display thread. NULL is ignored. */ -YASL_API void yasl_surface_request_frame(struct yasl_surface *s); -/** Set drawing policy for either loop style. Returns false with errno on failure. */ -YASL_API bool yasl_surface_set_pacing(struct yasl_surface *s, yasl_pacing_mode mode); - -/** Request a positive logical-pixel size. Success means issued, not configured. */ -YASL_API bool yasl_surface_set_size(struct yasl_surface *s, struct yasl_vector2i size_logical); -/** Request fullscreen state; returns acceptance, not confirmation. */ -YASL_API bool yasl_surface_set_fullscreen(struct yasl_surface *s, bool enabled); -/** Request maximized state; returns acceptance, not confirmation. */ -YASL_API bool yasl_surface_set_maximized(struct yasl_surface *s, bool enabled); -/** Request minimization. Window requests set errno on failure; display thread only. */ -YASL_API bool yasl_surface_minimize(struct yasl_surface *s); - -/** Offer copied UTF-8 text. Returns false with errno if invalid/unsupported/failed. */ -YASL_API bool yasl_clipboard_set(struct yasl_display *d, enum yasl_selection selection, - const char *text); -/** - * Request text; returns a nonzero ID or zero with errno. One PASTE completion - * follows each accepted request unless its surface/display is destroyed. - * Inspect paste.status even when data is empty. Use the display thread. - */ -YASL_API uint64_t yasl_clipboard_request(struct yasl_surface *s, enum yasl_selection selection); - -/* 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. - * Flags may coexist. Windowed and floating have no separate flags. Suspension - * does not imply minimization, and no minimized flag is reported. - */ -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_EVENT_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); - +/** Last error on this thread; success does not clear it. */ +YASL_API enum yasl_error yasl_get_error(const char **description); +YASL_API int yasl_get_native_error(void); +/** Only before the first surface is created. */ +YASL_API bool yasl_set_app_id(const char *app_id); +YASL_API bool yasl_set_backend(enum yasl_backend backend); +/** Flags zero creates a surface for your own Vulkan or Metal renderer. */ +YASL_API yasl_surface *yasl_surface_create(const char *title, int width, int height, unsigned flags); +/** Also destroys its popups. */ +YASL_API void yasl_surface_destroy(yasl_surface *surface); +/** Destroys all surfaces. Release your GPU objects first. */ +YASL_API void yasl_shutdown(void); +/** 1 event, 0 none (timeout or wake), -1 failure. timeout_ms zero polls, negative + * waits forever. Without an event, out->type is NONE. */ +YASL_API int yasl_wait_event(yasl_event *out, int timeout_ms); +/** Makes a waiting yasl_wait_event return. Thread-safe. */ +YASL_API void yasl_wake(void); +YASL_API uint64_t yasl_time_ns(void); +YASL_API enum yasl_backend yasl_surface_backend(const yasl_surface *surface); +YASL_API unsigned yasl_surface_features(const yasl_surface *surface); +YASL_API void yasl_surface_get_size(const yasl_surface *surface, int *width, int *height); +YASL_API void yasl_surface_get_framebuffer_size(const yasl_surface *surface, int *width, int *height); +YASL_API double yasl_surface_get_scale(const yasl_surface *surface); +YASL_API unsigned yasl_surface_state(const yasl_surface *surface); +YASL_API void *yasl_surface_userdata(const yasl_surface *surface); +YASL_API void yasl_surface_set_userdata(yasl_surface *surface, void *userdata); +YASL_API bool yasl_surface_set_title(yasl_surface *surface, const char *title); +/** Requests; the result arrives as a WINDOW event. */ +YASL_API bool yasl_surface_request_size(yasl_surface *surface, int width, int height); +YASL_API bool yasl_surface_request_fullscreen(yasl_surface *surface, bool enabled); +YASL_API bool yasl_surface_request_maximized(yasl_surface *surface, bool enabled); +YASL_API bool yasl_surface_request_minimize(yasl_surface *surface); +YASL_API bool yasl_surface_set_cursor(yasl_surface *surface, enum yasl_cursor cursor); +YASL_API bool yasl_surface_set_pointer_mode(yasl_surface *surface, enum yasl_pointer_mode mode); +/** Draws during native modal loops such as a live resize. The callback may render + * but must not wait, create or destroy surfaces, or shut down. */ +YASL_API void yasl_surface_set_refresh_callback(yasl_surface *surface, void (*refresh)(yasl_surface *,void *), void *userdata); +YASL_API int yasl_double_click_ms(void); +YASL_API bool yasl_clipboard_set(enum yasl_selection selection, const char *text); +/** Returns a request ID; the text arrives as a CLIPBOARD event. Zero on failure. */ +YASL_API uint64_t yasl_clipboard_request(yasl_surface *target, enum yasl_selection selection); +/** IME support for a text field. */ +YASL_API bool yasl_surface_set_text_input(yasl_surface *surface, bool active, enum yasl_text_purpose purpose); +/** UTF-8; selection offsets are bytes. */ +YASL_API bool yasl_surface_set_surrounding_text(yasl_surface *surface, const char *text, size_t length, + size_t selection_begin, size_t selection_end, uint64_t revision); +YASL_API bool yasl_surface_set_ime_caret(yasl_surface *surface, double x, double y, double width, double height); +/** Anchor picks a point on the x/y/anchor rectangle of the parent; gravity is the + * direction the popup grows. Functions taking a trigger need a recent press event. */ +YASL_API yasl_surface *yasl_popup_create(yasl_surface *parent, int width, int height, + double x, double y, double anchor_width, double anchor_height, enum yasl_popup_edge anchor, + enum yasl_popup_edge gravity, unsigned constraints, const yasl_event *trigger); +YASL_API bool yasl_popup_reposition(yasl_surface *popup, int width, int height, + double x, double y, double anchor_width, double anchor_height, enum yasl_popup_edge anchor, + enum yasl_popup_edge gravity, unsigned constraints); +YASL_API bool yasl_surface_start_interactive_move(yasl_surface *surface, const yasl_event *trigger); +YASL_API bool yasl_surface_start_interactive_resize(yasl_surface *surface, enum yasl_resize_edge edge, const yasl_event *trigger); +YASL_API bool yasl_surface_show_window_menu(yasl_surface *surface, double x, double y, const yasl_event *trigger); +YASL_API bool yasl_drag_start(yasl_surface *origin, const yasl_event *trigger, + const uint32_t *pixels, int width, int height, int hotspot_x, int hotspot_y); +YASL_API void yasl_drag_cancel(void); +YASL_API bool yasl_surface_drag_carry(yasl_surface *surface, double x, double y); +YASL_API bool yasl_surface_place_under_pointer(yasl_surface *surface, double x, double y); +YASL_API size_t yasl_drop_next_path(const char **cursor, char *out, size_t capacity); #ifdef __cplusplus } #endif - -#endif /* YASL_H */ +#endif -- cgit v1.2.3