summaryrefslogtreecommitdiff
path: root/include/yasl/yasl.h
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-14 13:56:48 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-14 13:56:48 +0300
commit87279f6903343e621c0446b20d1e7d6a495f1125 (patch)
tree999b5fb5fb76702efb02f856f082147304f0859b /include/yasl/yasl.h
parent1ab3e5a123109704789c2768e11a4f9af515821d (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/yasl/yasl.h')
-rw-r--r--include/yasl/yasl.h596
1 files changed, 273 insertions, 323 deletions
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