/** @file Windows, input and events. The first surface starts the backend; use the * creating thread (main on Cocoa) for every call except yasl_wake. Coordinates are * logical units unless named pixel. */ #ifndef YASL_H #define YASL_H #include #include #include #include "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_flags { YASL_SURFACE_CPU=1u, YASL_SURFACE_HIDDEN=2u, YASL_SURFACE_UNDECORATED=4u, YASL_SURFACE_FIXED_SIZE=8u }; enum yasl_error { YASL_ERROR_NONE, YASL_ERROR_INVALID, YASL_ERROR_UNSUPPORTED, YASL_ERROR_NO_MEMORY, YASL_ERROR_NOT_INITIALIZED, YASL_ERROR_BUSY, YASL_ERROR_WRONG_THREAD, YASL_ERROR_CONTEXT_EXPIRED, YASL_ERROR_IO, YASL_ERROR_DISCONNECTED }; 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; }; }; /** Last error on this thread; success does not clear it. */ YASL_API enum yasl_error yasl_get_error(const char **description); YASL_API int yasl_get_native_error(void); /** Only before the first surface is created. */ YASL_API bool yasl_set_app_id(const char *app_id); YASL_API bool yasl_set_backend(enum yasl_backend backend); /** Flags zero creates a surface for your own Vulkan or Metal renderer. */ YASL_API yasl_surface *yasl_surface_create(const char *title, int width, int height, unsigned flags); /** Also destroys its popups. */ YASL_API void yasl_surface_destroy(yasl_surface *surface); /** Destroys all surfaces. Release your GPU objects first. */ YASL_API void yasl_shutdown(void); /** 1 event, 0 none (timeout or wake), -1 failure. timeout_ms zero polls, negative * waits forever. Without an event, out->type is NONE. */ YASL_API int yasl_wait_event(yasl_event *out, int timeout_ms); /** Makes a waiting yasl_wait_event return. Thread-safe. */ YASL_API void yasl_wake(void); YASL_API uint64_t yasl_time_ns(void); YASL_API enum yasl_backend yasl_surface_backend(const yasl_surface *surface); YASL_API unsigned yasl_surface_features(const yasl_surface *surface); YASL_API void yasl_surface_get_size(const yasl_surface *surface, int *width, int *height); YASL_API void yasl_surface_get_framebuffer_size(const yasl_surface *surface, int *width, int *height); YASL_API double yasl_surface_get_scale(const yasl_surface *surface); YASL_API unsigned yasl_surface_state(const yasl_surface *surface); YASL_API void *yasl_surface_userdata(const yasl_surface *surface); YASL_API void yasl_surface_set_userdata(yasl_surface *surface, void *userdata); YASL_API bool yasl_surface_set_title(yasl_surface *surface, const char *title); /** Requests; the result arrives as a WINDOW event. */ YASL_API bool yasl_surface_request_size(yasl_surface *surface, int width, int height); YASL_API bool yasl_surface_request_fullscreen(yasl_surface *surface, bool enabled); YASL_API bool yasl_surface_request_maximized(yasl_surface *surface, bool enabled); YASL_API bool yasl_surface_request_minimize(yasl_surface *surface); YASL_API bool yasl_surface_set_cursor(yasl_surface *surface, enum yasl_cursor cursor); YASL_API bool yasl_surface_set_pointer_mode(yasl_surface *surface, enum yasl_pointer_mode mode); /** Draws during native modal loops such as a live resize. The callback may render * but must not wait, create or destroy surfaces, or shut down. */ YASL_API void yasl_surface_set_refresh_callback(yasl_surface *surface, void (*refresh)(yasl_surface *,void *), void *userdata); YASL_API int yasl_double_click_ms(void); YASL_API bool yasl_clipboard_set(enum yasl_selection selection, const char *text); /** Returns a request ID; the text arrives as a CLIPBOARD event. Zero on failure. */ YASL_API uint64_t yasl_clipboard_request(yasl_surface *target, enum yasl_selection selection); /** IME support for a text field. */ YASL_API bool yasl_surface_set_text_input(yasl_surface *surface, bool active, enum yasl_text_purpose purpose); /** UTF-8; selection offsets are bytes. */ YASL_API bool yasl_surface_set_surrounding_text(yasl_surface *surface, const char *text, size_t length, size_t selection_begin, size_t selection_end, uint64_t revision); YASL_API bool yasl_surface_set_ime_caret(yasl_surface *surface, double x, double y, double width, double height); /** Anchor picks a point on the x/y/anchor rectangle of the parent; gravity is the * direction the popup grows. Functions taking a trigger need a recent press event. */ YASL_API yasl_surface *yasl_popup_create(yasl_surface *parent, int width, int height, double x, double y, double anchor_width, double anchor_height, enum yasl_popup_edge anchor, enum yasl_popup_edge gravity, unsigned constraints, const yasl_event *trigger); YASL_API bool yasl_popup_reposition(yasl_surface *popup, int width, int height, double x, double y, double anchor_width, double anchor_height, enum yasl_popup_edge anchor, enum yasl_popup_edge gravity, unsigned constraints); YASL_API bool yasl_surface_start_interactive_move(yasl_surface *surface, const yasl_event *trigger); YASL_API bool yasl_surface_start_interactive_resize(yasl_surface *surface, enum yasl_resize_edge edge, const yasl_event *trigger); YASL_API bool yasl_surface_show_window_menu(yasl_surface *surface, double x, double y, const yasl_event *trigger); YASL_API bool yasl_drag_start(yasl_surface *origin, const yasl_event *trigger, const uint32_t *pixels, int width, int height, int hotspot_x, int hotspot_y); YASL_API void yasl_drag_cancel(void); YASL_API bool yasl_surface_drag_carry(yasl_surface *surface, double x, double y); YASL_API bool yasl_surface_place_under_pointer(yasl_surface *surface, double x, double y); YASL_API size_t yasl_drop_next_path(const char **cursor, char *out, size_t capacity); #ifdef __cplusplus } #endif #endif