/** @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. */ #ifndef YASL_H #define YASL_H #include #include #include #include #include "yasl/keycodes.h" #if defined(__GNUC__) #define YASL_API __attribute__((visibility("default"))) #else #define YASL_API #endif #ifdef __cplusplus extern "C" { #endif typedef struct yasl_surface yasl_surface; typedef struct yasl_event yasl_event; enum yasl_backend { YASL_BACKEND_AUTO, YASL_BACKEND_WAYLAND, YASL_BACKEND_X11, YASL_BACKEND_COCOA }; enum yasl_surface_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_scroll_phase { YASL_SCROLL_PHASE_UNKNOWN, YASL_SCROLL_BEGIN, YASL_SCROLL_UPDATE, YASL_SCROLL_END }; enum yasl_transfer_status { YASL_TRANSFER_OK, YASL_TRANSFER_UNAVAILABLE, YASL_TRANSFER_FAILED }; enum yasl_text_purpose { YASL_TEXT_NORMAL, YASL_TEXT_PASSWORD, YASL_TEXT_NUMBER, YASL_TEXT_TERMINAL }; enum yasl_cursor { YASL_CURSOR_ARROW, YASL_CURSOR_TEXT, YASL_CURSOR_LINK, YASL_CURSOR_CROSSHAIR, YASL_CURSOR_MOVE, YASL_CURSOR_RESIZE_NWSE, YASL_CURSOR_RESIZE_NESW, YASL_CURSOR_RESIZE_EW, YASL_CURSOR_RESIZE_NS, YASL_CURSOR_HIDDEN }; enum yasl_surface_state { YASL_STATE_FULLSCREEN = 1u, YASL_STATE_MAXIMIZED = 2u, YASL_STATE_ACTIVATED = 4u, YASL_STATE_SUSPENDED = 8u, YASL_STATE_CSD = 16u, YASL_STATE_TILED = 32u }; enum yasl_feature { YASL_CAP_POPUPS = 1u, YASL_CAP_DRAG = 2u, YASL_CAP_DRAG_CARRY = 4u, YASL_CAP_PLACE_WINDOW = 8u, YASL_CAP_PRIMARY_SELECTION = 16u, YASL_CAP_CSD = 32u, YASL_CAP_NATIVE_GRAPHICS = 64u, YASL_CAP_FRAME_PACING = 128u, YASL_CAP_TABLET = 256u, YASL_CAP_OPENGL = 512u, YASL_CAP_VULKAN = 1024u, YASL_CAP_TEXT_INPUT = 2048u }; enum yasl_popup_edge { YASL_POPUP_CENTER, YASL_POPUP_TOP, YASL_POPUP_BOTTOM, YASL_POPUP_LEFT, YASL_POPUP_RIGHT, YASL_POPUP_TOP_LEFT, YASL_POPUP_BOTTOM_LEFT, YASL_POPUP_TOP_RIGHT, YASL_POPUP_BOTTOM_RIGHT }; enum yasl_popup_constraint { YASL_POPUP_SLIDE_X = 1u, YASL_POPUP_SLIDE_Y = 2u, YASL_POPUP_FLIP_X = 4u, YASL_POPUP_FLIP_Y = 8u, YASL_POPUP_RESIZE_X = 16u, YASL_POPUP_RESIZE_Y = 32u }; enum yasl_resize_edge { YASL_EDGE_TOP = 1, YASL_EDGE_BOTTOM = 2, YASL_EDGE_LEFT = 4, YASL_EDGE_TOP_LEFT = 5, YASL_EDGE_BOTTOM_LEFT = 6, YASL_EDGE_RIGHT = 8, YASL_EDGE_TOP_RIGHT = 9, YASL_EDGE_BOTTOM_RIGHT = 10 }; enum yasl_event_type { YASL_EVENT_NONE, YASL_EVENT_CLOSE, YASL_EVENT_QUIT, YASL_EVENT_REOPEN, YASL_EVENT_WINDOW, YASL_EVENT_REFRESH, YASL_EVENT_KEY, YASL_EVENT_TEXT, YASL_EVENT_POINTER, YASL_EVENT_SCROLL, YASL_EVENT_PEN, YASL_EVENT_INPUT_RESET, YASL_EVENT_COMPOSITION, YASL_EVENT_TEXT_EDIT, YASL_EVENT_CLIPBOARD, YASL_EVENT_DROP, YASL_EVENT_DRAG, YASL_EVENT_DISPLAY_LOST, 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; }; struct yasl_key_payload { 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; }; 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; bool momentum; }; struct yasl_pen_payload { uint64_t device_id, tool_id; double x, y, pressure, tilt_x, tilt_y, rotation, distance, tangential, wheel_degrees; unsigned axes_valid, axes_changed, buttons, changed_button, tool, action; bool in_contact; }; 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; }; /** 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; 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; }; }; /** 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. */ YASL_API int yasl_wait_event(yasl_event *out, int timeout_ms); /** Makes a waiting yasl_wait_event return. Thread-safe. */ YASL_API void yasl_wake(void); /** Monotonic nanoseconds; thread-safe and independent of initialization. */ 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); 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); #ifdef __cplusplus } #endif #endif