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
|
#include "yasl/app.h"
#include "common/app_internal.h"
#include "common/backend.h"
#include <errno.h>
struct app_runner {
struct yasl_display *display;
const struct yasl_app_desc *desc;
uint64_t initial_window;
bool running, failed, had_surfaces;
int error;
};
void yasl_app_exit(struct yasl_display *d, enum yasl_app_result result)
{
if (!d || !d->app_runner || result == YASL_APP_CONTINUE) return;
struct app_runner *runner = d->app_runner;
runner->running = false;
if (result == YASL_APP_ERROR) { runner->failed = true; runner->error = EIO; }
}
struct yasl_surface *yasl_app_window(struct yasl_display *d)
{
if (!d || !d->app_runner) return NULL;
struct app_runner *runner = d->app_runner;
return runner->initial_window ? yasl_events_find(d, runner->initial_window) : NULL;
}
static void dispatch_events(struct app_runner *runner)
{
struct yasl_event event;
while (runner->running && yasl_display_poll_event(runner->display, &event)) {
if (runner->desc->event)
yasl_app_exit(runner->display, runner->desc->event(runner->desc->userdata, &event));
else if (event.type == YASL_EVENT_WINDOW_CLOSE)
yasl_app_exit(runner->display, YASL_APP_QUIT);
if (event.type == YASL_EVENT_DISPLAY_QUIT)
yasl_app_exit(runner->display, YASL_APP_QUIT);
if (event.type == YASL_EVENT_DISPLAY_LOST)
yasl_app_exit(runner->display, YASL_APP_ERROR);
}
}
static void draw(struct yasl_surface *s, struct yasl_frame *frame, void *ud)
{
struct app_runner *runner = ud;
uint64_t id = s->id;
dispatch_events(runner);
/* Draining events can destroy the surface whose native draw is active. */
struct yasl_surface *live = yasl_events_find(runner->display, id);
if (live && runner->running && runner->desc->frame)
runner->desc->frame(runner->desc->userdata, live, frame);
}
void app_runner_register_surface(void *data, struct yasl_surface *s)
{
struct app_runner *runner = data;
struct yasl_window_cbs callbacks = {.draw = draw};
yasl_surface_set_callbacks(s, &callbacks, runner);
s->app_surface = runner;
runner->had_surfaces = true;
}
void app_runner_unregister_surface(void *data, struct yasl_surface *s)
{
(void)data;
s->app_surface = NULL;
}
bool yasl_frame_present_cpu(struct yasl_frame *frame, const struct yasl_rect2i *rects, int count)
{
/* Preserve the migration adapter's old NULL/nonpositive full-damage rule. */
return yasl_frame_present(frame, count <= 0 ? NULL : rects, count <= 0 ? 0 : (size_t)count);
}
bool yasl_post_event(struct yasl_display *d, struct yasl_surface *s,
uint32_t code, void *payload, size_t size)
{
if (!d || !d->app_runner) { errno = EINVAL; return false; }
/* Legacy callers must keep s alive through this call. New code passes an ID. */
return yasl_display_post(d, &(struct yasl_message){
.target_id = s ? yasl_surface_id(s) : 0, .code = code, .payload = payload, .size = size,
});
}
int yasl_app_watch_fd(struct yasl_display *d, int fd, short events,
int (*cb)(int, short, void *), void *ud)
{
if (!d || !d->loop) { errno = EINVAL; return -1; }
return yasl_loop_add_fd(d->loop, fd, events, cb, ud);
}
void yasl_app_unwatch_fd(struct yasl_display *d, int id)
{
if (d && d->loop) yasl_loop_del_fd(d->loop, id);
}
yasl_timer_id yasl_app_add_timer(struct yasl_display *d, uint64_t interval, yasl_timer_cb cb, void *ud)
{
if (!d || !d->loop) return 0;
return yasl_loop_add_timer(d->loop, interval, cb, ud);
}
void yasl_app_del_timer(struct yasl_display *d, yasl_timer_id id)
{
if (d && d->loop) yasl_loop_del_timer(d->loop, id);
}
int yasl_run(const struct yasl_app_desc *desc)
{
if (!desc) { errno = EINVAL; return -1; }
struct yasl_display *d = yasl_display_open(NULL, &(struct yasl_display_spec){
.app_id = desc->app_id, .backend = desc->backend,
});
if (!d) return -1;
struct app_runner runner = {.display = d, .desc = desc, .running = true};
d->app_runner = &runner;
if (desc->window) {
struct yasl_surface *s = yasl_surface_create_toplevel(d, desc->window);
if (!s) {
int error = errno;
d->app_runner = NULL;
yasl_display_close(d);
errno = error;
return -1;
}
runner.initial_window = s->id;
yasl_surface_request_frame(s);
}
if (desc->init) yasl_app_exit(d, desc->init(desc->userdata, d));
while (runner.running) {
dispatch_events(&runner);
if (!runner.running || (runner.had_surfaces && !d->surfaces)) break;
if (yasl_display_dispatch(d, -1) < 0) {
int dispatch_error = errno;
dispatch_events(&runner);
runner.failed = true;
runner.error = dispatch_error;
break;
}
dispatch_events(&runner);
if (runner.running) yasl_display_flush(d);
}
int queue_error = yasl_events_error(d);
if (queue_error) { runner.failed = true; runner.error = queue_error; }
int error = runner.error;
if (desc->quit) desc->quit(desc->userdata, d);
/* Backend registries create children after parents: reverse creation order
* ensures child popups are destroyed before their parent. */
while (d->surfaces) yasl_surface_destroy(d->surfaces);
d->app_runner = NULL;
yasl_display_close(d);
if (runner.failed) errno = error;
return runner.failed ? -1 : 0;
}
|