diff options
Diffstat (limited to 'include')
| -rw-r--r-- | include/yasl/keycodes.h | 149 | ||||
| -rw-r--r-- | include/yasl/loop.h | 117 | ||||
| -rw-r--r-- | include/yasl/native.h | 49 | ||||
| -rw-r--r-- | include/yasl/native/cocoa.h | 33 | ||||
| -rw-r--r-- | include/yasl/native/wayland.h | 20 | ||||
| -rw-r--r-- | include/yasl/native/x11.h | 22 | ||||
| -rw-r--r-- | include/yasl/timing.h | 26 | ||||
| -rw-r--r-- | include/yasl/yasl.h | 614 |
8 files changed, 918 insertions, 112 deletions
diff --git a/include/yasl/keycodes.h b/include/yasl/keycodes.h new file mode 100644 index 0000000..7586945 --- /dev/null +++ b/include/yasl/keycodes.h @@ -0,0 +1,149 @@ +/** + * @file + * Portable physical keyboard identities, included by yasl/yasl.h. + * Letter/punctuation names describe positions on a US keyboard, regardless of + * active layout or modifiers. Use YASL_INPUT_TEXT for text and codepoint/shifted + * in yasl_key_event for layout labels. These values are neither Unicode nor + * native scancodes; do not derive a character from a key enumerator. + */ +#ifndef YASL_KEYCODES_H +#define YASL_KEYCODES_H + +#include <stdint.h> + +/** Physical keys. Unrecognized native keys report YASL_KEY_UNKNOWN. */ +enum yasl_key : uint32_t { + YASL_KEY_UNKNOWN = 0x000, /**< No portable identity; native_code may still identify the key. */ + YASL_KEY_SPACE = 0x020, /**< Space. */ + YASL_KEY_APOSTROPHE = 0x027, /**< Apostrophe. */ + YASL_KEY_COMMA = 0x02c, /**< Comma. */ + YASL_KEY_MINUS = 0x02d, /**< Minus. */ + YASL_KEY_PERIOD = 0x02e, /**< Period. */ + YASL_KEY_SLASH = 0x02f, /**< Slash. */ + YASL_KEY_0 = 0x030, /**< Physical 0 key. */ + YASL_KEY_1 = 0x031, /**< Physical 1 key. */ + YASL_KEY_2 = 0x032, /**< Physical 2 key. */ + YASL_KEY_3 = 0x033, /**< Physical 3 key. */ + YASL_KEY_4 = 0x034, /**< Physical 4 key. */ + YASL_KEY_5 = 0x035, /**< Physical 5 key. */ + YASL_KEY_6 = 0x036, /**< Physical 6 key. */ + YASL_KEY_7 = 0x037, /**< Physical 7 key. */ + YASL_KEY_8 = 0x038, /**< Physical 8 key. */ + YASL_KEY_9 = 0x039, /**< Physical 9 key. */ + YASL_KEY_SEMICOLON = 0x03b, /**< Semicolon. */ + YASL_KEY_EQUAL = 0x03d, /**< Equal. */ + YASL_KEY_A = 0x041, /**< Physical US A position; independent of layout and modifiers. */ + YASL_KEY_B = 0x042, /**< Physical US B position; independent of layout and modifiers. */ + YASL_KEY_C = 0x043, /**< Physical US C position; independent of layout and modifiers. */ + YASL_KEY_D = 0x044, /**< Physical US D position; independent of layout and modifiers. */ + YASL_KEY_E = 0x045, /**< Physical US E position; independent of layout and modifiers. */ + YASL_KEY_F = 0x046, /**< Physical US F position; independent of layout and modifiers. */ + YASL_KEY_G = 0x047, /**< Physical US G position; independent of layout and modifiers. */ + YASL_KEY_H = 0x048, /**< Physical US H position; independent of layout and modifiers. */ + YASL_KEY_I = 0x049, /**< Physical US I position; independent of layout and modifiers. */ + YASL_KEY_J = 0x04a, /**< Physical US J position; independent of layout and modifiers. */ + YASL_KEY_K = 0x04b, /**< Physical US K position; independent of layout and modifiers. */ + YASL_KEY_L = 0x04c, /**< Physical US L position; independent of layout and modifiers. */ + YASL_KEY_M = 0x04d, /**< Physical US M position; independent of layout and modifiers. */ + YASL_KEY_N = 0x04e, /**< Physical US N position; independent of layout and modifiers. */ + YASL_KEY_O = 0x04f, /**< Physical US O position; independent of layout and modifiers. */ + YASL_KEY_P = 0x050, /**< Physical US P position; independent of layout and modifiers. */ + YASL_KEY_Q = 0x051, /**< Physical US Q position; independent of layout and modifiers. */ + YASL_KEY_R = 0x052, /**< Physical US R position; independent of layout and modifiers. */ + YASL_KEY_S = 0x053, /**< Physical US S position; independent of layout and modifiers. */ + YASL_KEY_T = 0x054, /**< Physical US T position; independent of layout and modifiers. */ + YASL_KEY_U = 0x055, /**< Physical US U position; independent of layout and modifiers. */ + YASL_KEY_V = 0x056, /**< Physical US V position; independent of layout and modifiers. */ + YASL_KEY_W = 0x057, /**< Physical US W position; independent of layout and modifiers. */ + YASL_KEY_X = 0x058, /**< Physical US X position; independent of layout and modifiers. */ + YASL_KEY_Y = 0x059, /**< Physical US Y position; independent of layout and modifiers. */ + YASL_KEY_Z = 0x05a, /**< Physical US Z position; independent of layout and modifiers. */ + YASL_KEY_LEFT_BRACKET = 0x05b, /**< Left Bracket. */ + YASL_KEY_BACKSLASH = 0x05c, /**< Backslash. */ + YASL_KEY_RIGHT_BRACKET = 0x05d, /**< Right Bracket. */ + YASL_KEY_GRAVE = 0x060, /**< Grave. */ + YASL_KEY_ESCAPE = 0x100, /**< Escape. */ + YASL_KEY_ENTER = 0x101, /**< Enter. */ + YASL_KEY_TAB = 0x102, /**< Tab. */ + YASL_KEY_BACKSPACE = 0x103, /**< Backspace. */ + YASL_KEY_INSERT = 0x104, /**< Insert. */ + YASL_KEY_DELETE = 0x105, /**< Delete. */ + YASL_KEY_RIGHT = 0x106, /**< Right. */ + YASL_KEY_LEFT = 0x107, /**< Left. */ + YASL_KEY_DOWN = 0x108, /**< Down. */ + YASL_KEY_UP = 0x109, /**< Up. */ + YASL_KEY_PAGE_UP = 0x10a, /**< Page Up. */ + YASL_KEY_PAGE_DOWN = 0x10b, /**< Page Down. */ + YASL_KEY_HOME = 0x10c, /**< Home. */ + YASL_KEY_END = 0x10d, /**< End. */ + YASL_KEY_CAPS_LOCK = 0x10e, /**< Caps Lock. */ + YASL_KEY_SCROLL_LOCK = 0x10f, /**< Scroll Lock. */ + YASL_KEY_NUM_LOCK = 0x110, /**< Num Lock. */ + YASL_KEY_PRINT_SCREEN = 0x111, /**< Print Screen. */ + YASL_KEY_PAUSE = 0x112, /**< Pause. */ + YASL_KEY_ISO_BACKSLASH = 0x113, /**< Iso Backslash. */ + YASL_KEY_YEN = 0x114, /**< Yen. */ + YASL_KEY_RO = 0x115, /**< Ro. */ + YASL_KEY_KANA = 0x116, /**< Kana. */ + YASL_KEY_EISU = 0x117, /**< Eisu. */ + YASL_KEY_CONVERT = 0x118, /**< Convert. */ + YASL_KEY_NONCONVERT = 0x119, /**< Nonconvert. */ + YASL_KEY_F1 = 0x120, /**< Function key F1. */ + YASL_KEY_F2 = 0x121, /**< Function key F2. */ + YASL_KEY_F3 = 0x122, /**< Function key F3. */ + YASL_KEY_F4 = 0x123, /**< Function key F4. */ + YASL_KEY_F5 = 0x124, /**< Function key F5. */ + YASL_KEY_F6 = 0x125, /**< Function key F6. */ + YASL_KEY_F7 = 0x126, /**< Function key F7. */ + YASL_KEY_F8 = 0x127, /**< Function key F8. */ + YASL_KEY_F9 = 0x128, /**< Function key F9. */ + YASL_KEY_F10 = 0x129, /**< Function key F10. */ + YASL_KEY_F11 = 0x12a, /**< Function key F11. */ + YASL_KEY_F12 = 0x12b, /**< Function key F12. */ + YASL_KEY_F13 = 0x12c, /**< Function key F13. */ + YASL_KEY_F14 = 0x12d, /**< Function key F14. */ + YASL_KEY_F15 = 0x12e, /**< Function key F15. */ + YASL_KEY_F16 = 0x12f, /**< Function key F16. */ + YASL_KEY_F17 = 0x130, /**< Function key F17. */ + YASL_KEY_F18 = 0x131, /**< Function key F18. */ + YASL_KEY_F19 = 0x132, /**< Function key F19. */ + YASL_KEY_F20 = 0x133, /**< Function key F20. */ + YASL_KEY_F21 = 0x134, /**< Function key F21. */ + YASL_KEY_F22 = 0x135, /**< Function key F22. */ + YASL_KEY_F23 = 0x136, /**< Function key F23. */ + YASL_KEY_F24 = 0x137, /**< Function key F24. */ + YASL_KEY_F25 = 0x138, /**< Function key F25. */ + YASL_KEY_KP_0 = 0x140, /**< Numeric keypad 0. */ + YASL_KEY_KP_1 = 0x141, /**< Numeric keypad 1. */ + YASL_KEY_KP_2 = 0x142, /**< Numeric keypad 2. */ + YASL_KEY_KP_3 = 0x143, /**< Numeric keypad 3. */ + YASL_KEY_KP_4 = 0x144, /**< Numeric keypad 4. */ + YASL_KEY_KP_5 = 0x145, /**< Numeric keypad 5. */ + YASL_KEY_KP_6 = 0x146, /**< Numeric keypad 6. */ + YASL_KEY_KP_7 = 0x147, /**< Numeric keypad 7. */ + YASL_KEY_KP_8 = 0x148, /**< Numeric keypad 8. */ + YASL_KEY_KP_9 = 0x149, /**< Numeric keypad 9. */ + YASL_KEY_KP_DECIMAL = 0x14a, /**< Numeric keypad decimal. */ + YASL_KEY_KP_DIVIDE = 0x14b, /**< Numeric keypad divide. */ + YASL_KEY_KP_MULTIPLY = 0x14c, /**< Numeric keypad multiply. */ + YASL_KEY_KP_SUBTRACT = 0x14d, /**< Numeric keypad subtract. */ + YASL_KEY_KP_ADD = 0x14e, /**< Numeric keypad add. */ + YASL_KEY_KP_ENTER = 0x14f, /**< Numeric keypad enter. */ + YASL_KEY_KP_EQUAL = 0x150, /**< Numeric keypad equal. */ + YASL_KEY_KP_COMMA = 0x151, /**< Numeric keypad comma. */ + YASL_KEY_KP_CLEAR = 0x152, /**< Numeric keypad clear. */ + YASL_KEY_LEFT_SHIFT = 0x160, /**< Left Shift. */ + YASL_KEY_LEFT_CONTROL = 0x161, /**< Left Control. */ + YASL_KEY_LEFT_ALT = 0x162, /**< Left Alt. */ + YASL_KEY_LEFT_SUPER = 0x163, /**< Left Super. */ + YASL_KEY_RIGHT_SHIFT = 0x164, /**< Right Shift. */ + YASL_KEY_RIGHT_CONTROL = 0x165, /**< Right Control. */ + YASL_KEY_RIGHT_ALT = 0x166, /**< Right Alt. */ + YASL_KEY_RIGHT_SUPER = 0x167, /**< Right Super. */ + YASL_KEY_MENU = 0x168, /**< Menu. */ + YASL_KEY_VOLUME_UP = 0x169, /**< Volume Up. */ + YASL_KEY_VOLUME_DOWN = 0x16a, /**< Volume Down. */ + YASL_KEY_MUTE = 0x16b, /**< Mute. */ +}; + +#endif /* YASL_KEYCODES_H */ diff --git a/include/yasl/loop.h b/include/yasl/loop.h index a65fa12..9faa8f7 100644 --- a/include/yasl/loop.h +++ b/include/yasl/loop.h @@ -1,3 +1,14 @@ +/** + * @file + * Optional event loop, file watches, and timers. + * + * Use the loop's owning thread for all calls and callbacks, except + * yasl_loop_now_ns(). A display borrows a supplied loop. For window applications, + * drive yasl_display_dispatch(), drain input, then yasl_display_flush(); the + * standalone loop_run() function does not replace this cycle. Timer intervals are + * nanoseconds; timeout_ms arguments are milliseconds. Do not recursively step/run + * or destroy a loop from a callback. + */ #ifndef YASL_LOOP_H #define YASL_LOOP_H @@ -10,33 +21,139 @@ extern "C" { /* Optional event loop. Use the display's loop when adding application timers. * A step waits at most timeout_ms: zero polls, a negative value waits indefinitely. * Calls and callbacks use the loop's owning thread. */ +/** + * Create an owned standalone file-descriptor and timer loop. + * @return A loop to destroy with yasl_loop_destroy(), or NULL on allocation failure. + * Use on one owning thread. Passing it to yasl_display_open() only lends it to + * the display; the caller retains ownership. + */ YASL_API struct yasl_loop *yasl_loop_create(void); +/** + * Release a loop, its watches, and its timers. + * @param l Loop, or NULL for no action. + * Close displays borrowing this loop first. Must not run during a loop callback + * or an active step/run. Watched file descriptors are not closed. + */ YASL_API void yasl_loop_destroy(struct yasl_loop *l); +/** + * Step a standalone loop until yasl_loop_quit() is called. + * @param l Loop. + * @return Zero after quit, or -1 on failure. + * For a window application, use a dispatch, input-poll, flush cycle instead; + * loop_run alone does not perform that full cycle on every backend. + */ YASL_API int yasl_loop_run(struct yasl_loop *l); +/** + * Wait for file-descriptor readiness or a timer deadline and run callbacks. + * @param l Loop. + * @param timeout_ms Maximum wait: zero polls, negative waits indefinitely. + * @return Number of callbacks handled, or -1 on failure. + * Timer deadlines shorten the wait. Callbacks can add/delete sources, including + * themselves. Do not recursively step/run this loop. + */ YASL_API int yasl_loop_step(struct yasl_loop *l, int timeout_ms); +/** + * Ask the currently running yasl_loop_run() to return after this step. + * @param l Loop, or NULL for no action. + * Call on the owning thread, usually from a callback. + */ YASL_API void yasl_loop_quit(struct yasl_loop *l); +/** + * Signal the loop's wake pipe without dispatching callbacks. + * @param l Loop, or NULL for no action. + * Multiple signals may coalesce. This does not schedule a redraw or enqueue an + * event, and it does not provide a cross-thread application messaging contract. + */ YASL_API void yasl_loop_kick(struct yasl_loop *l); +/** + * Read the monotonic clock used by YASL timers and timing results. + * @return Nanoseconds from CLOCK_MONOTONIC, unrelated to wall-clock time. + * May be called from any thread. + */ YASL_API uint64_t yasl_loop_now_ns(void); +/** + * Get the loop used for a display's file watches and application timers. + * @param d Display, or NULL. + * @return Borrowed loop, or NULL. Do not destroy a display-owned loop yourself. + */ YASL_API struct yasl_loop *yasl_display_loop(struct yasl_display *d); +/** + * Register a borrowed file descriptor for poll-style readiness. + * @param l Loop. + * @param fd Open file descriptor; it remains owned by the caller. + * @param events Bitmask from <poll.h>, for example POLLIN or POLLOUT. + * @param fn Callback receiving poll revents (including errors/hangup); return value is ignored. + * @param ud Borrowed userdata until watch removal or loop destruction. + * @return Positive watch ID, or -1 on failure. + * Delete the watch before closing fd. The callback must consume readiness or + * change/remove its watch to avoid repeated immediate wakeups. + */ YASL_API int yasl_loop_add_fd(struct yasl_loop *l, int fd, short events, int (*fn)(int fd, short revents, void *ud), void *ud); +/** + * Remove a file watch without closing its descriptor. + * @param l Loop. + * @param id Watch ID returned by yasl_loop_add_fd(). + * @return Zero if removed, or -1 for an invalid/missing watch. + */ YASL_API int yasl_loop_del_fd(struct yasl_loop *l, int id); +/** + * Replace a watch's poll event mask. + * @param l Loop. + * @param id Watch ID. + * @param events New <poll.h> mask; zero disables requested readiness (errors may still arrive). + * @return Zero if updated, or -1 for an invalid/missing watch. + */ YASL_API int yasl_loop_set_fd_events(struct yasl_loop *l, int id, short events); /* Timers use nanoseconds. Return the next interval to repeat/reschedule, or zero * to remove the timer. A zero ID indicates failure. Loop timers live until they * stop, are deleted, or the loop is destroyed. Surface timers are also canceled * when their surface is destroyed. */ +/** Timer identity scoped to its loop. Zero is invalid; do not reuse a retired ID. */ typedef uint32_t yasl_timer_id; +/** Timer callback. interval_ns is the last scheduled delay; return the next delay or zero to stop. */ typedef uint64_t (*yasl_timer_cb)(void *ud, yasl_timer_id id, uint64_t interval_ns); +/** Convert a nonnegative integer millisecond value to nanoseconds; avoid overflow. */ #define YASL_MS_TO_NS(ms) ((uint64_t)(ms) * 1000000ull) +/** + * Schedule a timer on a loop. + * @param l Loop. + * @param interval_ns Nonzero delay in monotonic nanoseconds before first firing. + * @param cb Required callback; returns a new nonzero interval to repeat, or zero to stop. + * @param ud Borrowed userdata until the timer stops, is deleted, or the loop is destroyed. + * @return Nonzero timer ID, or zero for invalid arguments or allocation failure. + * Repeating timers coalesce missed deadlines; do not use them to count elapsed + * wall time. The callback receives the last scheduled interval, not elapsed time. + */ YASL_API yasl_timer_id yasl_loop_add_timer(struct yasl_loop *l, uint64_t interval_ns, yasl_timer_cb cb, void *ud); +/** + * Cancel a loop timer, including from its own callback. + * @param l Loop. + * @param id Timer ID. + * @return true if an armed timer was removed, false if invalid or already retired. + */ YASL_API bool yasl_loop_del_timer(struct yasl_loop *l, yasl_timer_id id); +/** + * Schedule a timer canceled automatically on surface destruction. + * @param s Surface whose display loop will run the timer. + * @param interval_ns Nonzero initial delay in nanoseconds. + * @param cb Required timer callback, with the same rules as yasl_loop_add_timer(). + * @param ud Borrowed userdata until the timer ends or the surface is destroyed. + * @return Nonzero timer ID, or zero on failure. + * The surface does not own userdata. Cancel with yasl_surface_del_timer(). + */ YASL_API yasl_timer_id yasl_surface_add_timer(struct yasl_surface *s, uint64_t interval_ns, yasl_timer_cb cb, void *ud); +/** + * Cancel a timer registered through yasl_surface_add_timer(). + * @param s Owning surface. + * @param id Timer ID. + * @return true if still armed and removed; false if unknown or already retired. + */ YASL_API bool yasl_surface_del_timer(struct yasl_surface *s, yasl_timer_id id); #ifdef __cplusplus diff --git a/include/yasl/native.h b/include/yasl/native.h index f7e3020..d65f8d3 100644 --- a/include/yasl/native.h +++ b/include/yasl/native.h @@ -1,3 +1,12 @@ +/** + * @file + * Optional native handles and application-managed rendering. + * + * These extensions follow the core thread and lifetime rules. Handles are borrowed; + * never destroy them or dispatch their native connection independently. Typed + * backend accessors live in the yasl/native headers and are installed only for built + * backends. Application-managed drawing currently supports Cocoa/Metal only. + */ #ifndef YASL_NATIVE_H #define YASL_NATIVE_H @@ -15,25 +24,61 @@ extern "C" { * X11 Display * Window (cast through uintptr_t) * Cocoa NSApplication * NSWindow * (view: window.contentView) */ +/** + * Get a borrowed, backend-specific display handle. + * @param d Display, or NULL. + * @return Native handle, or NULL. Inspect yasl_display_backend() before casting. + * Prefer a typed accessor from yasl/native/wayland.h, x11.h, or cocoa.h. + * The handle expires on display close; do not close or dispatch it independently. + */ YASL_API void *yasl_display_get_native_handle(struct yasl_display *d); +/** + * Get a borrowed, backend-specific surface handle. + * @param s Surface, or NULL. + * @return Native handle, or NULL. X11 encodes a Window through uintptr_t. + * Prefer typed accessors. The handle expires on surface destruction. Do not + * change native ownership, event masks, buffer attachment, or surface roles. + */ YASL_API void *yasl_surface_get_native_handle(struct yasl_surface *s); /* Create a surface for application-managed native rendering. graphics_device * must be non-NULL; currently an id<MTLDevice> on Cocoa, retained by the surface. * Other backends return NULL with errno=ENOTSUP. CPU rendering uses the ordinary * yasl_surface_create_toplevel() and requires no native device. */ +/** + * Create a toplevel for application-managed native rendering. + * @param d Display with YASL_CAP_NATIVE_GRAPHICS. + * @param spec Copied toplevel options, with logical-pixel size. + * @param graphics_device Required native graphics device; currently id<MTLDevice> on Cocoa. + * @return Owned surface, or NULL with errno set: EINVAL for invalid arguments, + * ENOTSUP for an unsupported backend, or a backend error. + * Cocoa retains the device. Query the drawable during draw, submit/present it, + * then call yasl_surface_present() to record submission. + */ YASL_API struct yasl_surface *yasl_surface_create_native(struct yasl_display *d, const struct yasl_surface_spec *spec, void *graphics_device); +/** Borrowed native drawable for the current draw target, currently Cocoa/Metal. */ struct yasl_native_frame { - void *drawable; /* id<CAMetalDrawable> on Cocoa */ - bool transaction; /* CAMetalLayer.presentsWithTransaction */ + /** Borrowed id<CAMetalDrawable> on Cocoa. */ + void *drawable; + /** Cocoa CAMetalLayer presentsWithTransaction setting for this frame. */ + bool transaction; }; /* Query the current draw target's native drawable. Returns false for unsupported * backends, stale targets, or outside the draw callback. The result expires on * successful present, callback return, or surface destruction. Native renderers * submit/present the drawable, then call yasl_surface_present() to record it. */ +/** + * Get the current draw target's native drawable. + * @param s Surface currently being drawn. + * @param target Exact framebuffer identity supplied to this draw callback. + * @param out Required output native frame. + * @return true if available, false for NULL arguments, unsupported backends, + * stale targets, or calls outside draw. The drawable is borrowed and expires on + * successful present, callback return, or surface destruction. Currently Cocoa only. + */ YASL_API bool yasl_surface_get_native_frame(struct yasl_surface *s, const struct yasl_framebuffer *target, struct yasl_native_frame *out); diff --git a/include/yasl/native/cocoa.h b/include/yasl/native/cocoa.h index 9066a19..9b221cf 100644 --- a/include/yasl/native/cocoa.h +++ b/include/yasl/native/cocoa.h @@ -1,3 +1,7 @@ +/** + * @file + * Typed borrowed Cocoa handles; available on macOS. Use on the main thread. + */ #ifndef YASL_NATIVE_COCOA_H #define YASL_NATIVE_COCOA_H @@ -8,9 +12,9 @@ @class NSWindow; @class NSView; #else -typedef struct objc_object NSApplication; -typedef struct objc_object NSWindow; -typedef struct objc_object NSView; +typedef struct objc_object NSApplication; /**< Opaque Cocoa application in plain C/C++. */ +typedef struct objc_object NSWindow; /**< Opaque Cocoa window in plain C/C++. */ +typedef struct objc_object NSView; /**< Opaque Cocoa view in plain C/C++. */ #endif #ifdef __cplusplus @@ -18,9 +22,30 @@ extern "C" { #endif /* Return borrowed Cocoa handles (expire on display/surface destruction). - * Return NULL / nil if display/surface is not a Cocoa object or destroyed. */ + * Return NULL / nil if display/surface is not a Cocoa object or NULL. */ +/** + * Get the borrowed NSApplication for an object of the matching backend. + * @param d Live display, or NULL. + * @return The handle, or zero/NULL for NULL or a different backend. + * Expires on display destruction. Available only when this backend is built. + * Never pass a pointer to a destroyed object. + */ YASL_API NSApplication *yasl_cocoa_display_get_application(struct yasl_display *d); +/** + * Get the borrowed NSWindow for an object of the matching backend. + * @param s Live surface, or NULL. + * @return The handle, or zero/NULL for NULL or a different backend. + * Expires on surface destruction. Available only when this backend is built. + * Never pass a pointer to a destroyed object. + */ YASL_API NSWindow *yasl_cocoa_surface_get_window(struct yasl_surface *s); +/** + * Get the borrowed NSView for an object of the matching backend. + * @param s Live surface, or NULL. + * @return The handle, or zero/NULL for NULL or a different backend. + * Expires on surface destruction. Available only when this backend is built. + * Never pass a pointer to a destroyed object. + */ YASL_API NSView *yasl_cocoa_surface_get_view(struct yasl_surface *s); #ifdef __cplusplus diff --git a/include/yasl/native/wayland.h b/include/yasl/native/wayland.h index 4a759d4..b11e3b8 100644 --- a/include/yasl/native/wayland.h +++ b/include/yasl/native/wayland.h @@ -1,3 +1,7 @@ +/** + * @file + * Typed borrowed Wayland handles; available when built with Wayland support. + */ #ifndef YASL_NATIVE_WAYLAND_H #define YASL_NATIVE_WAYLAND_H @@ -11,8 +15,22 @@ struct wl_display; struct wl_surface; /* Return borrowed Wayland handles (expire on display/surface destruction). - * Return NULL if display/surface is not a Wayland object or destroyed. */ + * Return NULL if display/surface is not a Wayland object or NULL. */ +/** + * Get the borrowed Wayland connection for an object of the matching backend. + * @param d Live display, or NULL. + * @return The handle, or zero/NULL for NULL or a different backend. + * Expires on display destruction. Available only when this backend is built. + * Never pass a pointer to a destroyed object. + */ YASL_API struct wl_display *yasl_wayland_display_get_wl_display(struct yasl_display *d); +/** + * Get the borrowed Wayland surface for an object of the matching backend. + * @param s Live surface, or NULL. + * @return The handle, or zero/NULL for NULL or a different backend. + * Expires on surface destruction. Available only when this backend is built. + * Never pass a pointer to a destroyed object. + */ YASL_API struct wl_surface *yasl_wayland_surface_get_wl_surface(struct yasl_surface *s); #ifdef __cplusplus diff --git a/include/yasl/native/x11.h b/include/yasl/native/x11.h index c0105cb..b719b4b 100644 --- a/include/yasl/native/x11.h +++ b/include/yasl/native/x11.h @@ -1,3 +1,7 @@ +/** + * @file + * Typed borrowed X11 handles; available when built with X11 support. + */ #ifndef YASL_NATIVE_X11_H #define YASL_NATIVE_X11_H @@ -8,11 +12,25 @@ extern "C" { #endif -typedef struct _XDisplay Display; +typedef struct _XDisplay Display; /**< Opaque Xlib connection, compatible with Xlib.h. */ /* Return borrowed X11 handles (expire on display/surface destruction). - * Return NULL / 0 if display/surface is not an X11 object or destroyed. */ + * Return NULL / 0 if display/surface is not an X11 object or NULL. */ +/** + * Get the borrowed X11 Display for an object of the matching backend. + * @param d Live display, or NULL. + * @return The handle, or zero/NULL for NULL or a different backend. + * Expires on display destruction. Available only when this backend is built. + * Never pass a pointer to a destroyed object. + */ YASL_API Display *yasl_x11_display_get_display(struct yasl_display *d); +/** + * Get the borrowed X11 Window ID for an object of the matching backend. + * @param s Live surface, or NULL. + * @return The handle, or zero/NULL for NULL or a different backend. + * Expires on surface destruction. Available only when this backend is built. + * Never pass a pointer to a destroyed object. + */ YASL_API uintptr_t yasl_x11_surface_get_window(struct yasl_surface *s); #ifdef __cplusplus diff --git a/include/yasl/timing.h b/include/yasl/timing.h index d443bf6..7e4af9e 100644 --- a/include/yasl/timing.h +++ b/include/yasl/timing.h @@ -1,3 +1,8 @@ +/** + * @file + * Timing provenance, refresh estimates, and buffer-resize statistics. + * All timestamps are monotonic nanoseconds, not wall-clock dates. + */ #ifndef YASL_TIMING_H #define YASL_TIMING_H @@ -7,27 +12,40 @@ extern "C" { #endif +/** Cumulative backend buffer-resize measurements; unavailable counters are zero. */ struct yasl_resize_stats { + /** Number of measured buffer resizes. */ uint64_t count; + /** Mean measured resize duration in microseconds. */ double avg_us; + /** Maximum measured resize duration in microseconds. */ double max_us; + /** Backend minor page-fault counter, if collected. */ long minflt; }; /* Describes last_present_ns, not merely availability of an extension. */ +/** Provenance of last_present_ns; only PRESENTATION confirms compositor presentation. */ enum yasl_timing_source { - YASL_TIMING_UNKNOWN = 0, - YASL_TIMING_SUBMISSION, /* CPU submission time; not scanout confirmation */ - YASL_TIMING_FRAME_CALLBACK, /* compositor pacing callback, not scanout */ - YASL_TIMING_PRESENTATION, /* compositor-confirmed presentation */ + YASL_TIMING_UNKNOWN = 0, /**< No timing sample yet. */ + YASL_TIMING_SUBMISSION, /**< CPU submission time, not scanout confirmation. */ + YASL_TIMING_FRAME_CALLBACK, /**< Compositor pacing callback, not scanout confirmation. */ + YASL_TIMING_PRESENTATION, /**< Compositor-confirmed presentation. */ }; +/** Snapshot of estimates and timing provenance. Zero timestamps mean no sample yet. */ struct yasl_timing { + /** Estimated refresh interval in nanoseconds; zero if unavailable. */ double refresh_ns; + /** Last timestamp, whose meaning is specified by source. */ uint64_t last_present_ns; + /** Estimated next presentation time, or zero without a prior sample. */ uint64_t next_present_ns; + /** Backend skipped-frame counter; not comparable across backends. */ uint64_t frames_skipped; + /** Provenance of last_present_ns. */ enum yasl_timing_source source; + /** Cumulative backend resize statistics. */ struct yasl_resize_stats resize; }; 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 <math.h> #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 |
