diff options
| author | Berke Güzel <wenekar1@gmail.com> | 2026-10-14 13:56:48 +0300 |
|---|---|---|
| committer | Berke Güzel <wenekar1@gmail.com> | 2026-10-14 13:56:48 +0300 |
| commit | 87279f6903343e621c0446b20d1e7d6a495f1125 (patch) | |
| tree | 999b5fb5fb76702efb02f856f082147304f0859b /include | |
| parent | 1ab3e5a123109704789c2768e11a4f9af515821d (diff) | |
Simplify the public API into one dense header
yasl.h now holds everything except Vulkan: 45 functions instead of 62,
and three installed headers instead of ten.
- One constructor: yasl_surface_create takes CPU, GL or NATIVE, with
zero-initialized GL options meaning 3.2 core, RGBA8, D24S8.
- Events carry action, mods, x, y and text at the top level; pen
positions are now logical like pointer positions.
- yasl_cpu_pixels/yasl_cpu_present draw into one persistent canvas,
cutting three full-frame copies per frame.
- yasl_surface_get_info, yasl_surface_request, YASL_CURSOR_LOCKED,
yasl_surface_set_text_input, yasl_surface_begin_move_resize and
yasl_surface_get_native replace groups of narrower calls.
- Interactive calls drop the decorative trigger event argument.
- yasl_wait_event returns 0 only on timeout or yasl_wake, the refresh
callback runs only in native modal loops, focus loss sends
INPUT_RESET, and a lost event no longer fails every later wait.
- Unsupported operations and bad arguments report ENOTSUP and EINVAL
instead of EIO; the keycodes header no longer needs C23.
- The shared library gets a versioned SONAME and version macros.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'include')
| -rw-r--r-- | include/yasl/keycodes.h | 4 | ||||
| -rw-r--r-- | include/yasl/vulkan.h | 21 | ||||
| -rw-r--r-- | include/yasl/yasl.h | 596 |
3 files changed, 282 insertions, 339 deletions
diff --git a/include/yasl/keycodes.h b/include/yasl/keycodes.h index afa3eed..e14933b 100644 --- a/include/yasl/keycodes.h +++ b/include/yasl/keycodes.h @@ -3,9 +3,7 @@ #ifndef YASL_KEYCODES_H #define YASL_KEYCODES_H -#include <stdint.h> - -enum yasl_key : uint32_t { +enum yasl_key { YASL_KEY_UNKNOWN = 0x000, /**< No portable identity; native_code may still identify the key. */ YASL_KEY_SPACE = 0x020, YASL_KEY_APOSTROPHE = 0x027, diff --git a/include/yasl/vulkan.h b/include/yasl/vulkan.h index 1a1c5be..079c866 100644 --- a/include/yasl/vulkan.h +++ b/include/yasl/vulkan.h @@ -1,4 +1,4 @@ -/** @file Vulkan WSI; YASL tracks the WSI handle, the application owns rendering. */ +/** @file Vulkan window surfaces; the application owns devices and swapchains. */ #ifndef YASL_VULKAN_H #define YASL_VULKAN_H #include "yasl/yasl.h" @@ -6,26 +6,21 @@ #ifdef __cplusplus extern "C" { #endif -YASL_API int yasl_vulkan_init(PFN_vkGetInstanceProcAddr loader); +/** Instance extensions and flags YASL needs, borrowed until shutdown. Merge + * them into your VkInstanceCreateInfo. */ struct yasl_vulkan_requirements { const char *const *extensions; uint32_t extension_count; VkInstanceCreateFlags flags; }; -/** Initialize the loader first. Borrowed extensions live through shutdown; - * merge them with application extensions before creating the instance. - * Clears out on failure. */ -YASL_API int yasl_vulkan_get_requirements(const yasl_surface *surface, - struct yasl_vulkan_requirements *out); -/** WSI creation retains VkResult semantics. Uses the injected loader. - * One live VkSurfaceKHR per window; destroy it with yasl_vulkan_destroy_surface - * before destroying the YASL surface. The application owns swapchains/devices. */ +/** Records the loader and reports the requirements, initializing YASL if needed. + * Call before creating the instance. EBUSY while a Vulkan surface exists. */ +YASL_API int yasl_vulkan_init(PFN_vkGetInstanceProcAddr loader, struct yasl_vulkan_requirements *out); +/** One surface per NATIVE window; returns the VkResult, with errno set on failure. */ YASL_API VkResult yasl_vulkan_create_surface(yasl_surface *surface, VkInstance instance, const VkAllocationCallbacks *allocator, VkSurfaceKHR *out); -/** Destroy the WSI surface (including while disconnected), releasing the window - * for another renderer. Destroy dependent swapchains first. Uses the instance - * and allocation callbacks recorded at creation. No live WSI surface is a no-op. */ +/** Destroy swapchains first. Also works after DISPLAY_LOST; no surface is a no-op. */ YASL_API int yasl_vulkan_destroy_surface(yasl_surface *surface); #ifdef __cplusplus } diff --git a/include/yasl/yasl.h b/include/yasl/yasl.h index 284039a..6d2b4f0 100644 --- a/include/yasl/yasl.h +++ b/include/yasl/yasl.h @@ -1,8 +1,12 @@ -/** @file Windows, input and events. - * Commands return 0 on success or a negative errno value on failure. Constructors - * return NULL and set errno on failure; data queries document their sentinel. - * Use the initializing thread (main on Cocoa), except where stated otherwise. - * Coordinates are logical units unless named pixel. */ +/** @file YASL: desktop windows, input and events for application-owned rendering. + * + * Calls return 0 or a negative errno; constructors return NULL and set errno; + * queries name their fallback. Errors: EINVAL bad argument, ENOTSUP not + * supported here, EPERM wrong thread, ENODEV not initialized, ENOTCONN display + * lost, EBUSY not allowed now, ESTALE needs a pointer press in progress. + * Call from the thread that initialized YASL (the main thread on macOS) unless + * a function says it is thread-safe. Positions and sizes are logical units; + * multiply by the scale for pixels. Names with "pixel" are in pixels. */ #ifndef YASL_H #define YASL_H #include <errno.h> @@ -15,364 +19,310 @@ #else #define YASL_API #endif +#define YASL_VERSION_MAJOR 0 +#define YASL_VERSION_MINOR 2 +#define YASL_VERSION_PATCH 0 #ifdef __cplusplus extern "C" { #endif typedef struct yasl_surface yasl_surface; typedef struct yasl_event yasl_event; + +/* Lifecycle */ enum yasl_backend { YASL_BACKEND_AUTO, YASL_BACKEND_WAYLAND, YASL_BACKEND_X11, YASL_BACKEND_COCOA }; -enum yasl_surface_type { YASL_SURFACE_NATIVE, YASL_SURFACE_CPU }; -enum yasl_surface_flags { - YASL_SURFACE_HIDDEN = 2u, - YASL_SURFACE_UNDECORATED = 4u, - YASL_SURFACE_FIXED_SIZE = 8u -}; -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)) -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_feature { + YASL_FEATURE_POPUPS = 1, YASL_FEATURE_DRAG = 2, YASL_FEATURE_DRAG_CARRY = 4, + YASL_FEATURE_PLACE_WINDOW = 8, YASL_FEATURE_PRIMARY_SELECTION = 16, YASL_FEATURE_TABLET = 32, + YASL_FEATURE_TEXT_INPUT = 64, YASL_FEATURE_LOCKED_CURSOR = 128, YASL_FEATURE_OPENGL = 256, + YASL_FEATURE_VULKAN = 512 +}; +/** Optional: the first surface initializes with AUTO and no app ID. app_id is a + * reverse-DNS name for window grouping and notifications. EALREADY once + * initialized; a failed initialization may be retried. */ +YASL_API int yasl_init(enum yasl_backend backend, const char *app_id); +/** Destroys every surface. EBUSY while a Vulkan surface exists. */ +YASL_API int yasl_shutdown(void); +/** AUTO and 0 before initialization. */ +YASL_API enum yasl_backend yasl_get_backend(void); +YASL_API unsigned yasl_get_features(void); + +/* Surfaces */ +enum yasl_surface_type { + YASL_SURFACE_CPU, /**< Draw into yasl_cpu_pixels. */ + YASL_SURFACE_GL, /**< OpenGL through EGL; Linux only. */ + YASL_SURFACE_NATIVE /**< Draw with Vulkan, Metal or the native handles. */ +}; +/** Zero selects OpenGL 3.2 core (ES 3.0 with es), RGBA8, 24-bit depth, 8-bit stencil. */ +struct yasl_gl_options { + int major, minor, samples; + bool es, compatibility, debug, srgb, no_depth_stencil; + yasl_surface *share; /**< A GL surface whose objects the new context shares. */ }; -enum yasl_scroll_phase { - YASL_SCROLL_PHASE_UNKNOWN, - YASL_SCROLL_BEGIN, - YASL_SCROLL_UPDATE, - YASL_SCROLL_END +struct yasl_surface_options { + const char *title; + int width, height; /**< Required. */ + enum yasl_surface_type type; + bool undecorated, fixed_size; + void *userdata; + /** Called when the window needs drawing while the system blocks the event + * loop, as during a macOS live resize; draw and present before returning. + * REFRESH events cover every other case. Must not wait, create or destroy. */ + void (*refresh)(yasl_surface *surface); + struct yasl_gl_options gl; }; -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 +/** Strings are copied. */ +YASL_API yasl_surface *yasl_surface_create(const struct yasl_surface_options *options); +/** Also destroys its popups. NULL is a no-op. EBUSY while one has a Vulkan surface. */ +YASL_API int yasl_surface_destroy(yasl_surface *surface); + +enum yasl_state { + YASL_STATE_FULLSCREEN = 1, + YASL_STATE_MAXIMIZED = 2, + YASL_STATE_ACTIVATED = 4, + YASL_STATE_SUSPENDED = 8, /**< Hidden from view; skip drawing. */ + YASL_STATE_CSD = 16, /**< No system title bar: draw your own. */ + YASL_STATE_TILED = 32 +}; +struct yasl_surface_info { + int width, height, pixel_width, pixel_height; + double scale; + unsigned state; /**< YASL_STATE_* */ }; +/** Zero sizes and scale 1 for NULL. */ +YASL_API struct yasl_surface_info yasl_surface_get_info(const yasl_surface *surface); +YASL_API void *yasl_surface_get_userdata(const yasl_surface *surface); +YASL_API int yasl_surface_set_userdata(yasl_surface *surface, void *userdata); +YASL_API int yasl_surface_set_title(yasl_surface *surface, const char *title); + +/** Window requests; the outcome arrives as a WINDOW event. RESTORE leaves + * fullscreen and maximized. */ +enum yasl_request { YASL_REQUEST_RESTORE, YASL_REQUEST_FULLSCREEN, YASL_REQUEST_MAXIMIZE, YASL_REQUEST_MINIMIZE }; +YASL_API int yasl_surface_request(yasl_surface *surface, enum yasl_request request); +YASL_API int yasl_surface_request_size(yasl_surface *surface, int width, int height); + 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 + 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, + /** Hidden and held in place while focused; POINTER events then report + * motion only in dx/dy (FEATURE_LOCKED_CURSOR). */ + YASL_CURSOR_LOCKED }; -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 +YASL_API int yasl_surface_set_cursor(yasl_surface *surface, enum yasl_cursor cursor); + +enum yasl_text_purpose { YASL_TEXT_NORMAL, YASL_TEXT_PASSWORD, YASL_TEXT_NUMBER, YASL_TEXT_TERMINAL }; +/** The focused text field, for input methods. text is UTF-8 around the caret, + * selection offsets are bytes into it, and revision comes back in COMPOSITION + * and TEXT_EDIT events. The caret rectangle places the candidate window. */ +struct yasl_text_input { + enum yasl_text_purpose purpose; + const char *text; + size_t length, selection_begin, selection_end; + uint64_t revision; + double caret_x, caret_y, caret_width, caret_height; +}; +/** Copied. NULL turns input methods off. */ +YASL_API int yasl_surface_set_text_input(yasl_surface *surface, const struct yasl_text_input *input); + +enum yasl_edge { YASL_EDGE_TOP = 1, YASL_EDGE_BOTTOM = 2, YASL_EDGE_LEFT = 4, YASL_EDGE_RIGHT = 8 }; +/** While a pointer or pen button is held: let the user move the window (edges 0) + * or resize it from one edge or a corner (two adjacent edges). */ +YASL_API int yasl_surface_begin_move_resize(yasl_surface *surface, unsigned edges); +YASL_API int yasl_surface_show_window_menu(yasl_surface *surface, double x, double y); +YASL_API int yasl_surface_bell(yasl_surface *surface); + +/* Popups */ +enum yasl_popup_adjust { + YASL_ADJUST_SLIDE_X = 1, YASL_ADJUST_SLIDE_Y = 2, YASL_ADJUST_FLIP_X = 4, YASL_ADJUST_FLIP_Y = 8, + YASL_ADJUST_RESIZE_X = 16, YASL_ADJUST_RESIZE_Y = 32 +}; +/** Placed against an anchor rectangle in the parent: anchor picks a point on it + * and gravity the direction the popup grows, both as YASL_EDGE_* bits (0 is the + * center). adjust keeps it on screen; 0 flips, then slides. */ +struct yasl_popup_options { + int width, height; + double x, y, anchor_width, anchor_height; + unsigned anchor, gravity, adjust; + void *userdata; }; -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 +/** A CPU surface. Create it while handling the input that opens it; it takes + * the input grab and gets CLOSE when dismissed. */ +YASL_API yasl_surface *yasl_popup_create(yasl_surface *parent, const struct yasl_popup_options *options); +YASL_API int yasl_popup_reposition(yasl_surface *popup, const struct yasl_popup_options *options); + +/* Clipboard, drag and drop */ +enum yasl_selection { YASL_CLIPBOARD, YASL_PRIMARY }; +/** Offers copied UTF-8 text; call while handling input on one of your windows. */ +YASL_API int yasl_clipboard_set(enum yasl_selection selection, const char *text); +/** The text arrives as a CLIPBOARD event on target, in request order. */ +YASL_API int yasl_clipboard_request(yasl_surface *target, enum yasl_selection selection); +/** Premultiplied 0xAARRGGBB pixels, rows tightly packed; copied. */ +struct yasl_drag_image { + const uint32_t *pixels; + int pixel_width, pixel_height, hotspot_x, hotspot_y; }; +/** While a pointer button is held on origin: drag it over YASL surfaces, which + * get DRAG events. image may be NULL. */ +YASL_API int yasl_drag_start(yasl_surface *origin, const struct yasl_drag_image *image); +YASL_API int yasl_drag_cancel(void); +/** During a drag: carry this toplevel with (x, y) under the pointer (FEATURE_DRAG_CARRY). */ +YASL_API int yasl_drag_carry(yasl_surface *surface, double x, double y); +/** Move the toplevel so (x, y) is under the pointer (FEATURE_PLACE_WINDOW). */ +YASL_API int yasl_surface_place_under_pointer(yasl_surface *surface, double x, double y); +/** Next local path in a DROP event's text/uri-list. Returns its length, or 0 at + * the end. If capacity exceeds the length, writes it with a NUL and advances + * cursor; otherwise changes nothing, so retry larger. Thread-safe. */ +YASL_API size_t yasl_drop_next_path(const char **cursor, char *out, size_t capacity); + +/* Events */ 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_CLOSE, /**< The user asked to close the window; destroy it to comply. */ + YASL_EVENT_QUIT, /**< The system asked the app to quit; exit to comply. */ + YASL_EVENT_REOPEN, /**< macOS: the app was activated with no window open. */ + YASL_EVENT_WINDOW, /**< window: size, scale or state changed. */ + YASL_EVENT_REFRESH, /**< Draw now: once sized, after every resize, and on expose. */ + YASL_EVENT_KEY, /**< key; action is a yasl_key_action. */ + YASL_EVENT_TEXT, /**< text: typed text to insert. */ + YASL_EVENT_COMPOSITION, /**< text: input method preedit to show at the caret, + * ime.begin..end its cursor; empty ends it. */ + YASL_EVENT_TEXT_EDIT, /**< text: replaces bytes ime.begin..end of the + * yasl_text_input text with revision ime.revision. */ + YASL_EVENT_POINTER, /**< pointer, x, y; action is a yasl_pointer_action. */ + YASL_EVENT_SCROLL, /**< scroll, x, y. */ + YASL_EVENT_PEN, /**< pen, x, y; action is a yasl_pen_action. */ + YASL_EVENT_INPUT_RESET, /**< Forget held keys, buttons and strokes. */ + YASL_EVENT_CLIPBOARD, /**< text; action is a yasl_transfer. */ + YASL_EVENT_DROP, /**< External data: x, y; action is a yasl_drop_action; + * text on RELEASE is a text/uri-list. */ + YASL_EVENT_DRAG, /**< A yasl_drag_start drag: x, y; action is a yasl_drop_action. */ + /** The display server went away. Before the next wait, destroy Vulkan + * surfaces and detach GL contexts on every thread; popups close. Wayland + * reconnects and sends DISPLAY_RESTORED: recreate them (GL contexts are new). + * Elsewhere loss is final and waits fail with ENOTCONN. */ YASL_EVENT_DISPLAY_LOST, YASL_EVENT_DISPLAY_RESTORED }; -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 }; -struct yasl_window_payload { - int width, height, pixel_width, pixel_height; - double scale; - unsigned state; +enum yasl_key_action { YASL_KEY_PRESS, YASL_KEY_RELEASE, YASL_KEY_REPEAT }; +enum yasl_mod { YASL_MOD_SHIFT = 1, YASL_MOD_ALT = 2, YASL_MOD_CTRL = 4, YASL_MOD_SUPER = 8, YASL_MOD_CAPS = 16 }; +enum yasl_pointer_action { YASL_POINTER_MOVE, YASL_POINTER_DOWN, YASL_POINTER_UP, YASL_POINTER_LEAVE }; +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)) +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_tool { YASL_PEN_UNKNOWN, YASL_PEN_PEN, YASL_PEN_ERASER, YASL_PEN_BRUSH, YASL_PEN_AIRBRUSH, YASL_PEN_PENCIL }; +enum yasl_pen_axis { + YASL_PEN_PRESSURE = 1, YASL_PEN_TILT = 2, YASL_PEN_ROTATION = 4, YASL_PEN_DISTANCE = 8, + YASL_PEN_TANGENTIAL = 16, YASL_PEN_WHEEL = 32 }; -struct yasl_key_payload { +enum yasl_scroll_source { YASL_SCROLL_UNKNOWN, YASL_SCROLL_WHEEL, YASL_SCROLL_FINGER, YASL_SCROLL_CONTINUOUS }; +enum yasl_scroll_phase { YASL_SCROLL_PHASE_NONE, YASL_SCROLL_BEGIN, YASL_SCROLL_UPDATE, YASL_SCROLL_END }; +enum yasl_transfer { YASL_TRANSFER_OK, YASL_TRANSFER_UNAVAILABLE, YASL_TRANSFER_FAILED }; +enum yasl_drop_action { YASL_DROP_OVER, YASL_DROP_LEAVE, YASL_DROP_RELEASE }; + +/** Physical key, layout labels (codepoint unshifted, shifted; 0 if none) and the + * native code (evdev, X11 keycode or macOS virtual key). Type with TEXT, not this. */ +struct yasl_key_event { enum yasl_key key; - enum yasl_key_action action; - unsigned mods; uint32_t codepoint, shifted, native_code; }; -struct yasl_text_payload { - const char *data; - size_t length; +/** button changed on DOWN/UP; buttons are held YASL_BUTTON_BIT()s. */ +struct yasl_pointer_event { + double dx, dy; + unsigned button, buttons; }; -struct yasl_pointer_payload { - double x, y, dx, dy; - enum yasl_pointer_action action; - unsigned button, buttons, mods; -}; -struct yasl_scroll_payload { - double x, y, lines_x, lines_y, pixels_x, pixels_y; - unsigned valid, source, phase, mods; +/** Positive right/down; a delta is 0 when the device does not report that unit. */ +struct yasl_scroll_event { + double lines_x, lines_y, pixels_x, pixels_y; + enum yasl_scroll_source source; + enum yasl_scroll_phase phase; bool momentum; }; -struct yasl_pen_payload { +/** pressure and distance 0..1, tangential -1..1, tilt and rotation in degrees. + * axes holds the valid YASL_PEN_* axes; button changed on BUTTON. */ +struct yasl_pen_event { 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; + double pressure, tilt_x, tilt_y, rotation, distance, tangential, wheel_degrees; + enum yasl_pen_tool tool; + unsigned axes, buttons, button; bool in_contact; }; -struct yasl_composition_payload { - const char *data; - size_t length; - int begin, end; - bool active; - uint64_t revision, generation; -}; -struct yasl_text_edit_payload { - const char *data; - size_t length, begin, end; - uint64_t revision, generation; -}; -struct yasl_clipboard_payload { - const char *data; - size_t length; - uint64_t request_id; - enum yasl_transfer_status status; -}; -struct yasl_drop_payload { - enum yasl_drop_action action; - double x, y; - const char *data; - size_t length; -}; -struct yasl_drag_payload { - enum yasl_drag_action action; - double x, y; +struct yasl_ime_event { + size_t begin, end; + uint64_t revision; }; - -/** 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. - * DISPLAY_LOST: the display server went away. Destroy Vulkan surfaces and GL - * objects now; windows stay valid. Wayland reconnects, then sends DISPLAY_RESTORED: - * recreate them (GL contexts are new and must be bound again). Elsewhere loss is - * final and later waits fail. */ struct yasl_event { enum yasl_event_type type; yasl_surface *surface; uint64_t time_ns; + unsigned action, mods; /**< mods: YASL_MOD_* for KEY, POINTER and SCROLL. */ + double x, y; + const char *text; /**< NUL-terminated UTF-8 until the next wait, or NULL. */ + size_t length; union { - struct yasl_window_payload window; - struct yasl_key_payload key; - struct yasl_text_payload text; - struct yasl_pointer_payload pointer; - struct yasl_scroll_payload scroll; - struct yasl_pen_payload pen; - struct yasl_composition_payload composition; - struct yasl_text_edit_payload text_edit; - struct yasl_clipboard_payload clipboard; - /** DATA carries a text/uri-list for yasl_drop_next_path; x/y are set for OVER. */ - struct yasl_drop_payload drop; - struct yasl_drag_payload drag; + struct yasl_surface_info window; + struct yasl_key_event key; + struct yasl_pointer_event pointer; + struct yasl_scroll_event scroll; + struct yasl_pen_event pen; + struct yasl_ime_event ime; }; }; -/** NULL options select the automatic backend and no application ID. */ -struct yasl_options { - enum yasl_backend backend; - const char *app_id; -}; -/** Zero initialization selects a native GPU window. A positive logical size is - * required; title may be NULL. Strings are copied before creation returns. */ -struct yasl_surface_options { - const char *title; - int width, height; - enum yasl_surface_type type; - unsigned flags; - void *userdata; -}; -/** Optional explicit initialization. Creation initializes with defaults when - * needed. Reinitialization returns -EALREADY; failed initialization is retryable. */ -YASL_API int yasl_init(const struct yasl_options *options); -YASL_API yasl_surface *yasl_surface_create(const struct yasl_surface_options *options); -/** Also destroys its popups. NULL is a no-op. Returns -EBUSY while a window - * in the subtree owns a Vulkan surface; destroy that WSI surface first. */ -YASL_API int yasl_surface_destroy(yasl_surface *surface); -/** Destroys all surfaces. Returns -EBUSY without destroying any windows if - * a Vulkan surface remains live. Release your GPU objects first. */ -YASL_API int yasl_shutdown(void); -/** 1 event, 0 none (timeout or wake), negative errno on failure. timeout_ms zero polls, negative - * waits forever. Without an event, out->type is NONE. */ +/** 1 with an event, 0 once timeout_ms passes or after yasl_wake. 0 polls and -1 + * waits forever. On failure 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. */ +/** Makes a waiting, or the next, yasl_wait_event return 0 once no event is + * pending. Thread-safe. */ YASL_API void yasl_wake(void); -/** Monotonic nanoseconds; thread-safe and independent of initialization. */ +/** Monotonic nanoseconds, the clock of event times. Thread-safe. */ YASL_API uint64_t yasl_time_ns(void); -/** Queries accept NULL: return AUTO, zero, NULL or scale 1; size outputs are - * optional and become zero. Non-NULL surfaces must belong to the owner thread. */ -YASL_API enum yasl_backend yasl_surface_get_backend(const yasl_surface *surface); -YASL_API unsigned yasl_surface_get_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_get_state(const yasl_surface *surface); -YASL_API void *yasl_surface_get_userdata(const yasl_surface *surface); -YASL_API int yasl_surface_set_userdata(yasl_surface *surface, void *userdata); -YASL_API int yasl_surface_set_title(yasl_surface *surface, const char *title); -/** Requests; the result arrives as a WINDOW event. */ -YASL_API int yasl_surface_request_size(yasl_surface *surface, int width, int height); -YASL_API int yasl_surface_request_fullscreen(yasl_surface *surface, bool enabled); -YASL_API int yasl_surface_request_maximized(yasl_surface *surface, bool enabled); -YASL_API int yasl_surface_request_minimize(yasl_surface *surface); -YASL_API int yasl_surface_set_cursor(yasl_surface *surface, enum yasl_cursor cursor); -YASL_API int 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 int yasl_surface_set_refresh_callback(yasl_surface *surface, - void (*refresh)(yasl_surface *, void *), - void *userdata); + +/* Rendering */ +/** CPU surfaces: the window's pixel_width * pixel_height premultiplied + * 0xAARRGGBB pixels, rows tightly packed. They persist, and a resize keeps the + * overlap and zeroes the rest. Valid until the next wait. Present to show them; + * the system may also show them when it redraws the window. */ +YASL_API uint32_t *yasl_cpu_pixels(yasl_surface *surface, int *pixel_width, int *pixel_height); +YASL_API int yasl_cpu_present(yasl_surface *surface); + +typedef void (*yasl_gl_proc)(void); +/** These four may run on a rendering thread; synchronize them with destruction. + * NULL detaches the calling thread's context, also after DISPLAY_LOST. */ +YASL_API int yasl_gl_make_current(yasl_surface *surface); +YASL_API yasl_gl_proc yasl_gl_get_proc_address(const char *name); +YASL_API int yasl_gl_set_swap_interval(yasl_surface *surface, int interval); +YASL_API int yasl_gl_present(yasl_surface *surface); + +struct wl_display; +struct wl_surface; +struct _XDisplay; +/** Borrowed handles of the active backend; the rest are zero. They expire with + * the surface or on DISPLAY_LOST. Never destroy, dispatch or close them. */ +struct yasl_native { + struct wl_display *wl_display; + struct wl_surface *wl_surface; + struct _XDisplay *x11_display; + unsigned long x11_window; + void *ns_window, *ns_view; /**< NSWindow *, NSView * */ +}; +YASL_API int yasl_surface_get_native(const yasl_surface *surface, struct yasl_native *out); +/** NATIVE surfaces on macOS: the view's CAMetalLayer, reserving the surface for + * Metal. YASL sizes it; choose the device and format, and present yourself. */ +YASL_API void *yasl_metal_get_layer(yasl_surface *surface); + +/* Desktop */ +enum yasl_appearance { YASL_APPEARANCE_DARK = 1, YASL_APPEARANCE_LIGHT = 2, YASL_APPEARANCE_HIGH_CONTRAST = 4 }; +/** Opens uri with its default application. Thread-safe. */ +YASL_API int yasl_open_uri(const char *uri); +YASL_API int yasl_notify(const char *title, const char *body); +/** These two may block briefly on the session bus. 0 is no preference. */ +YASL_API unsigned yasl_get_appearance(void); +/** Milliseconds; 400 when unknown. */ YASL_API int yasl_get_double_click_ms(void); -YASL_API int 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 int yasl_surface_set_text_input(yasl_surface *surface, bool active, - enum yasl_text_purpose purpose); -/** UTF-8; selection offsets are bytes. */ -YASL_API int 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 int yasl_surface_set_ime_caret(yasl_surface *surface, double x, double y, double width, - double height); -/** Anchor selects a point on the parent rectangle; gravity is the direction - * the popup grows. Zero edges mean center. All dimensions are logical units. */ -struct yasl_popup_options { - int width, height; - double x, y, anchor_width, anchor_height; - enum yasl_popup_edge anchor, gravity; - unsigned constraints; -}; -/** Trigger must be a recent pointer/pen press on parent. */ -YASL_API yasl_surface *yasl_popup_create(yasl_surface *parent, - const struct yasl_popup_options *options, - const yasl_event *trigger); -YASL_API int yasl_popup_reposition(yasl_surface *popup, const struct yasl_popup_options *options); -YASL_API int yasl_surface_start_interactive_move(yasl_surface *surface, const yasl_event *trigger); -YASL_API int yasl_surface_start_interactive_resize(yasl_surface *surface, - enum yasl_resize_edge edge, - const yasl_event *trigger); -YASL_API int yasl_surface_show_window_menu(yasl_surface *surface, double x, double y, - const yasl_event *trigger); -/** Optional premultiplied ARGB image in device pixels. Copied by drag_start. */ -struct yasl_drag_image { - const uint32_t *pixels; - int width, height; - int hotspot_x, hotspot_y; -}; -YASL_API int yasl_drag_start(yasl_surface *origin, const yasl_event *trigger, - const struct yasl_drag_image *image); -YASL_API int yasl_drag_cancel(void); -YASL_API int yasl_surface_drag_carry(yasl_surface *surface, double x, double y); -YASL_API int yasl_surface_place_under_pointer(yasl_surface *surface, double x, double y); -/** Parse local file URIs. Returns byte length excluding NUL, zero at end. - * If capacity <= length, leaves cursor/output unchanged for retry. NULL/zero - * queries size. The caller owns the cursor string; this helper is thread-safe. */ -YASL_API size_t yasl_drop_next_path(const char **cursor, char *out, size_t capacity); +/** LOCALE is a POSIX name such as en_US; RESOURCE_DIR is macOS only. */ +enum yasl_system_string { YASL_EXECUTABLE_PATH, YASL_RESOURCE_DIR, YASL_LOCALE }; +/** Returns the length, or 0 with errno. Writes it with a NUL only if capacity + * exceeds the length. Thread-safe. */ +YASL_API size_t yasl_get_system_string(enum yasl_system_string which, char *out, size_t capacity); #ifdef __cplusplus } #endif |
