1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
|
/**
* @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 successfully, false if queue is full or memory failed.
*/
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;
/**
* Called once after display and event machinery initialization.
* Use this to create 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.
*/
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 */
|