From 624d1371304a5ae4b3429ad5e4267aac7cd03dfd Mon Sep 17 00:00:00 2001 From: Berke Güzel Date: Mon, 12 Oct 2026 00:09:38 +0300 Subject: missing impls and hardening --- include/yasl/timing.h | 10 ++++++++ include/yasl/yasl.h | 64 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 69 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/yasl/timing.h b/include/yasl/timing.h index 7c66967..85f305d 100644 --- a/include/yasl/timing.h +++ b/include/yasl/timing.h @@ -15,11 +15,20 @@ struct yasl_resize_stats { long minflt; }; +/* Describes last_present_ns, not merely availability of an extension. */ +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 */ +}; + struct yasl_timing { double refresh_ns; uint64_t last_present_ns; uint64_t next_present_ns; uint64_t frames_skipped; + enum yasl_timing_source source; struct yasl_resize_stats resize; }; @@ -33,6 +42,7 @@ struct yasl_frame_clock { long resize_minflt; uint64_t frame_time_ns; double refresh_ns; + enum yasl_timing_source source; }; uint64_t yasl_clock_extend_ms(uint32_t ms, uint64_t now_ns); diff --git a/include/yasl/yasl.h b/include/yasl/yasl.h index 6fea487..2852112 100644 --- a/include/yasl/yasl.h +++ b/include/yasl/yasl.h @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include "yasl/timing.h" @@ -45,14 +47,25 @@ struct yasl_rect2i { #define YASL_SCALE_UNIT 120 #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. */ static inline int yasl_scale_to_device(double logical, uint32_t scale_120) { - return (int)((logical * (double)scale_120 + YASL_SCALE_UNIT / 2) / YASL_SCALE_UNIT); + if (!scale_120 || !(logical >= -DBL_MAX && logical <= DBL_MAX)) return 0; + double px = logical * ((double)scale_120 / YASL_SCALE_UNIT); + if (px >= INT_MAX) return INT_MAX; + if (px <= INT_MIN) return INT_MIN; + return (int)(px < 0 ? px - 0.5 : px + 0.5); } static inline int yasl_scale_to_logical(int device, uint32_t scale_120) { - return (int)(((int64_t)device * YASL_SCALE_UNIT + scale_120 / 2) / scale_120); + if (!scale_120) return 0; + int64_t px = (int64_t)device * YASL_SCALE_UNIT; + px = (px + (px < 0 ? -(int64_t)(scale_120 / 2) : scale_120 / 2)) / scale_120; + if (px > INT_MAX) return INT_MAX; + if (px < INT_MIN) return INT_MIN; + return (int)px; } /* Capabilities */ @@ -63,6 +76,8 @@ enum yasl_display_cap : uint32_t { 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 */ }; enum yasl_selection : uint8_t { @@ -103,7 +118,12 @@ enum yasl_resize_edge : uint32_t { YASL_EDGE_BOTTOM_RIGHT = 10, }; -/* Damage & Framebuffer */ +/* 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 + * the whole frame. Every pixel must contain valid content on each draw. + */ #define YASL_DAMAGE_MAX 64 struct yasl_damage_list { @@ -113,6 +133,7 @@ struct yasl_damage_list { }; struct yasl_framebuffer { + uint64_t generation; /* Opaque draw identity; preserve when copying target. */ uint32_t *pixels; struct yasl_vector2i size; int buffer; @@ -224,6 +245,9 @@ enum yasl_input_kind { YASL_INPUT_PASTE, YASL_INPUT_DROP_FILES, YASL_INPUT_TEXT, + /* Allocation failure broke the input stream. Clear all held keys/buttons + * and composition state before processing subsequent events. */ + YASL_INPUT_RESET, }; struct yasl_input_event { @@ -240,6 +264,17 @@ struct yasl_input_event { }; }; +/* Ownership and threading + * All calls and callbacks run on the display's opening thread (main thread on + * Cocoa). Displays borrow supplied loops; destroy surfaces before displays, + * popups before parents, and displays before their supplied loop. + * Specs, strings, callback tables and drag listeners are copied during calls. + * Userdata is borrowed until callbacks are removed or the object/drag ends. + * Native handles are borrowed and expire when their owning object is destroyed. + * Surface destruction is allowed from its callbacks; display/loop destruction + * during dispatch or callbacks is not supported. + */ + /* Callbacks */ struct yasl_display_cbs { void (*quit)(void *ud); @@ -284,9 +319,12 @@ YASL_API void yasl_display_dispatch(struct yasl_display *d); YASL_API int yasl_display_dispatch_timeout(struct yasl_display *d, int timeout_ms); YASL_API void yasl_display_flush(struct yasl_display *d); YASL_API int yasl_display_modifiers(const struct yasl_display *d); +/* Unsupported/invalid selections are no-ops, never clipboard aliases. */ YASL_API void yasl_display_copy(struct yasl_display *d, enum yasl_selection sel, const char *text); 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. */ 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); @@ -298,7 +336,9 @@ struct yasl_surface_spec { struct yasl_vector2i size; bool fullscreen; bool tearing; - /* Optional native graphics device. NULL selects CPU pixel presentation. */ + /* Optional native graphics device (retained on Cocoa). Requires + * YASL_CAP_NATIVE_GRAPHICS; other backends reject it with ENOTSUP. + * NULL selects CPU pixel presentation. */ void *graphics_device; }; @@ -323,19 +363,33 @@ YASL_API void yasl_surface_set_callbacks(struct yasl_surface *s, const struct yasl_surface_cbs *cbs, void *ud); YASL_API void yasl_surface_set_title(struct yasl_surface *s, const char *title); 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 and native drawables 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. Native renderers submit/present their + * drawable themselves, then call this function to record the submission. */ 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. */ YASL_API bool yasl_surface_input_poll(struct yasl_surface *s, struct yasl_input_event *ev); YASL_API struct yasl_vector2i yasl_surface_size(const struct yasl_surface *s); YASL_API uint32_t yasl_surface_scale_120(const struct yasl_surface *s); 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. */ YASL_API struct yasl_timing yasl_surface_timing(const struct yasl_surface *s); YASL_API uint64_t yasl_surface_frame_time_ns(struct yasl_surface *s, uint64_t now); YASL_API void yasl_surface_set_cursor(struct yasl_surface *s, enum yasl_cursor cursor); YASL_API void yasl_surface_set_background_color(struct yasl_surface *s, uint32_t bg); -/* IME Support */ +/* IME Support: preedit is borrowed until the next dispatch or destruction. */ YASL_API const char *yasl_surface_ime_preedit(const struct yasl_surface *s); YASL_API bool yasl_surface_ime_preedit_cursor(const struct yasl_surface *s, int *begin, int *end); YASL_API void yasl_surface_set_ime_caret(struct yasl_surface *s, struct yasl_rect2i caret); -- cgit v1.2.3