/** * @file * Unified application runner, event pipeline, and presentation context. * * Implements the inverted lifecycle architecture for modern cross-platform * applications (games, IDEs, and desktop tools). Instead of managing manual * dispatch/poll/flush pumps, the application provides event and frame callbacks * to yasl_run(), which drives platform runloops, display pacing, and live resizing. */ #ifndef YASL_APP_H #define YASL_APP_H #include "yasl/yasl.h" #include "yasl/loop.h" #ifdef __cplusplus extern "C" { #endif /** Application callback return status. */ typedef enum yasl_app_result { YASL_APP_CONTINUE = 0, /**< Continue running the application. */ YASL_APP_QUIT, /**< Request graceful termination of yasl_run(). */ } yasl_app_result; /** Pacing mode governing when frame() callbacks are invoked. */ typedef enum yasl_pacing_mode { /** * Reactive / on-demand presentation (ideal for IDEs, text editors, tools). * The application sleeps at 0% CPU when idle. frame() is only invoked when * explicitly requested via yasl_surface_request_frame() or upon OS window * expose/resize events. */ YASL_PACING_ON_DEMAND = 0, /** * Continuous vsync-aligned tick (ideal for game engines and animations). * frame() is driven continuously at the display's native refresh rate * (e.g. 60/120/144 Hz) via DisplayLink, Wayland frame callbacks, or loop timers. */ YASL_PACING_CONTINUOUS, } yasl_pacing_mode; /** Frame context provided to yasl_app_desc.frame() during presentation. */ struct yasl_frame_context { struct yasl_surface *surface; uint64_t frame_index; uint64_t target_time_ns; /**< Monotonic timestamp aligned to display refresh. */ struct yasl_vector2i size; /**< Surface content size in device pixels. */ uint32_t scale_120; /** CPU software rendering target, if surface was created for CPU blitting. */ struct { uint32_t *pixels; /**< Writable premultiplied 0xAARRGGBB device pixels. */ int stride_bytes; /**< Row stride in bytes. */ } cpu; /** Native GPU rendering layer/surface, if surface was created for GPU rendering. */ struct { void *native_layer; /**< CAMetalLayer* on Cocoa, wl_surface* on Wayland, Window on X11. */ } gpu; /** Internal handle used by yasl_frame_present_cpu. Applications must not touch. */ void *internal_handle; }; /** * Present CPU software target pixels. * @param ctx Active frame context passed to yasl_app_desc.frame(). * @param dirty_rects Optional array of damaged rectangles in device pixels. * Pass NULL or count <= 0 to indicate full-surface damage. * @param count Number of rectangles in dirty_rects. * @return true if accepted, false on presentation failure. */ YASL_API bool yasl_frame_present_cpu(struct yasl_frame_context *ctx, const struct yasl_rect2i *dirty_rects, int count); /** * Configure the presentation pacing mode for a surface. * @param s Surface. * @param mode YASL_PACING_ON_DEMAND for reactive UI, YASL_PACING_CONTINUOUS for games. */ YASL_API void yasl_surface_set_pacing(struct yasl_surface *s, yasl_pacing_mode mode); /** * Mark a surface as needing a redraw on the next frame pass. * Wakes the event loop if sleeping under YASL_PACING_ON_DEMAND. * @param s Surface. */ YASL_API void yasl_surface_request_frame(struct yasl_surface *s); /** * Safely post a custom user event to the main event loop from ANY thread. * Wakes the display loop and delivers YASL_EVENT_USER to the event callback. * @param d Display. * @param s Optional target surface, or NULL. * @param code Application-defined message code (yasl_user_event.code). * @param payload Arbitrary pointer passed through to the event. * @param size Optional payload size. * @return true if queued; false if memory failed or d is not run by yasl_run(). * Applications that run their own loop use yasl_loop_post() instead. */ YASL_API bool yasl_post_event(struct yasl_display *d, struct yasl_surface *s, uint32_t code, void *payload, size_t size); /** * Watch an open file descriptor or socket for poll-style readiness in the main loop. * @param d Display. * @param fd Open file descriptor (e.g. LSP stdout pipe or socket). * @param poll_events Poll bitmask (e.g. POLLIN, POLLOUT). * @param cb Readiness callback run on the main thread. * @param ud Userdata. * @return Positive watch ID, or -1 on failure. */ YASL_API int yasl_app_watch_fd(struct yasl_display *d, int fd, short poll_events, int (*cb)(int fd, short revents, void *ud), void *ud); /** * Unregister a file watch. * @param d Display. * @param watch_id Watch ID returned by yasl_app_watch_fd(). */ YASL_API void yasl_app_unwatch_fd(struct yasl_display *d, int watch_id); /** * Schedule a repeating or one-shot timer on the display's event loop. * @param d Display. * @param interval_ns Delay in monotonic nanoseconds. * @param cb Callback returning next interval in nanoseconds, or 0 to stop. * @param ud Userdata. * @return Positive timer ID, or 0 on failure. */ YASL_API yasl_timer_id yasl_app_add_timer(struct yasl_display *d, uint64_t interval_ns, yasl_timer_cb cb, void *ud); /** * Cancel an active timer. * @param d Display. * @param id Timer ID returned by yasl_app_add_timer(). */ YASL_API void yasl_app_del_timer(struct yasl_display *d, yasl_timer_id id); /** Application callbacks descriptor passed to yasl_run(). */ struct yasl_app_desc { /** Application identifier, e.g. "org.example.app". */ const char *app_id; /** Desired backend; YASL_BACKEND_AUTO chooses native with fallback. */ enum yasl_backend backend; /** User data passed to all callbacks. */ void *userdata; /** * Optional toplevel created before init(), with its first frame requested. * Borrowed for the call; spec cbs and ud are ignored as for any runner window. * yasl_run() returns an error without calling init() if creation fails. */ const struct yasl_window_spec *window; /** * Optional; called once after display and event machinery initialization. * Use this to create further windows and initialize application resources. * Return YASL_APP_CONTINUE or YASL_APP_QUIT. */ enum yasl_app_result (*init)(void *ud, struct yasl_display *d); /** * Unified event handler for input, window and user events, in arrival order. * Event payloads and borrowed strings are valid for the duration of the callback. * INPUT_RESET has no payload and requires clearing held application input. * Return YASL_APP_CONTINUE or YASL_APP_QUIT. Optional; without it, a * WINDOW_CLOSE request on any window stops yasl_run(). */ enum yasl_app_result (*event)(void *ud, const struct yasl_event *ev); /** * Invoked when a surface needs to present a frame. * Synchronized automatically with display pacing and live window resizing. */ void (*frame)(void *ud, struct yasl_surface *s, struct yasl_frame_context *ctx); /** * Called right before the display is closed and yasl_run() exits. * Destroy remaining surfaces and release application resources here. */ void (*quit)(void *ud, struct yasl_display *d); }; /** * Run the application with the inverted lifecycle runner. * Handles the display event loop, live-resizing, pacing, and cleanup. * @param desc Application callbacks and options. * @return 0 on orderly exit, or non-zero on error. * Display quit notifications stop the runner; connection loss and dispatch * failures return an error after application cleanup. */ YASL_API int yasl_run(const struct yasl_app_desc *desc); #ifdef __cplusplus } #endif #endif /* YASL_APP_H */