summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-13 16:24:56 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-13 16:24:56 +0300
commited963bba0b234d52fda14b2a8237dbf02ef4d655 (patch)
tree0c7bd51ff01089fbc810f94a55e0adb94084478e
parent4a61a0f8a749831b74aca04302a30ebbbb6f5586 (diff)
Quit on window close when the app has no event callback
Without yasl_app_desc.event, a close request had nowhere to go and the window stayed open. The runner now stops instead, so hello drops its event callback. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
-rw-r--r--README.md2
-rw-r--r--docs/guide.md12
-rw-r--r--examples/hello.c9
-rw-r--r--include/yasl/app.h3
-rw-r--r--src/common/app.c7
-rw-r--r--tests/common/test_hello_example.c2
-rw-r--r--tests/wayland/test_app_input.c14
7 files changed, 30 insertions, 19 deletions
diff --git a/README.md b/README.md
index db52dd1..d94edb1 100644
--- a/README.md
+++ b/README.md
@@ -49,7 +49,7 @@ explicit backend with `yasl_display_spec.backend`.
Include `<yasl/app.h>` and pass application callbacks to `yasl_run()`.
The complete [hello.c](examples/hello.c) describes its window in
-`yasl_app_desc.window`, handles close requests in `event`, and fills every pixel
+`yasl_app_desc.window`, lets the runner quit when it is closed, and fills every pixel
in its frame callback:
```c
diff --git a/docs/guide.md b/docs/guide.md
index 62c2e1a..ab30c3d 100644
--- a/docs/guide.md
+++ b/docs/guide.md
@@ -41,12 +41,12 @@ it advertises CSD. Check each result and provide an application fallback.
All examples include `<yasl/app.h>` and call `yasl_run()` with a
`yasl_app_desc`. Set `window` to a `yasl_window_spec` for a single toplevel,
-which the runner creates before `init` with its first frame requested; `yasl_run()` returns an
-error if creation fails. Create further surfaces in the optional `init`, handle
-`YASL_EVENT_*` notifications in `event`, and render into `frame->cpu.pixels` in
-`frame`. Present with
-`yasl_frame_present_cpu(frame, NULL, 0)` and return `YASL_APP_QUIT` from an event
-handler to exit. The runner handles dispatch, input polling, resize redraws,
+which the runner creates before `init` with its first frame requested;
+`yasl_run()` returns an error if creation fails. Create further surfaces in the
+optional `init`, handle `YASL_EVENT_*` notifications in `event`, and render into
+`frame->cpu.pixels` in `frame`. Present with `yasl_frame_present_cpu(frame, NULL,
+0)` and return `YASL_APP_QUIT` from an event handler to exit. Without an `event`
+callback, closing any window stops the runner. The runner handles dispatch, input polling, resize redraws,
and remaining surface/display cleanup. Display quit stops the runner; connection
loss and dispatch failures return an error after cleanup. The runner delivers
input exactly as `yasl_surface_poll_event()` returns it, plus
diff --git a/examples/hello.c b/examples/hello.c
index d3d74cf..38a0cac 100644
--- a/examples/hello.c
+++ b/examples/hello.c
@@ -1,16 +1,8 @@
/* A complete CPU-rendered window. Build instructions: docs/getting-started.md. */
#include <yasl/app.h>
-
#include <stdio.h>
static bool failed;
-
-static enum yasl_app_result event(void *ud, const struct yasl_event *event)
-{
- (void)ud;
- return event->type == YASL_EVENT_WINDOW_CLOSE ? YASL_APP_QUIT : YASL_APP_CONTINUE;
-}
-
static void draw(void *ud, struct yasl_surface *surface, struct yasl_frame_context *frame)
{
(void)ud;
@@ -31,7 +23,6 @@ int main(void)
struct yasl_app_desc desc = {
.app_id = "org.example.hello",
.window = &window,
- .event = event,
.frame = draw,
};
int result = yasl_run(&desc);
diff --git a/include/yasl/app.h b/include/yasl/app.h
index 79b2519..bf6de9c 100644
--- a/include/yasl/app.h
+++ b/include/yasl/app.h
@@ -166,7 +166,8 @@ struct yasl_app_desc {
* 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.
+ * 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);
diff --git a/src/common/app.c b/src/common/app.c
index 9d52e4a..435d020 100644
--- a/src/common/app.c
+++ b/src/common/app.c
@@ -111,8 +111,13 @@ static void app_runner_surface_close(struct yasl_surface *s, void *ud)
{
struct app_surface *as = ud;
struct app_runner *ar = as ? as->runner : NULL;
- if (!ar || !ar->desc || !ar->desc->event)
+ if (!ar || !ar->desc)
+ return;
+ /* Without an event callback nothing could answer the request, so quit. */
+ if (!ar->desc->event) {
+ ar->running = false;
return;
+ }
emit(ar, &(struct yasl_event){
.type = YASL_EVENT_WINDOW_CLOSE,
diff --git a/tests/common/test_hello_example.c b/tests/common/test_hello_example.c
index c648038..101e2d4 100644
--- a/tests/common/test_hello_example.c
+++ b/tests/common/test_hello_example.c
@@ -14,7 +14,7 @@ int main(void)
struct yasl_window_spec window = {.title = "Hello YASL", .size = {640, 480}};
struct yasl_app_desc desc = {
.app_id = "org.yasl.test.hello", .window = &window,
- .event = event, .frame = draw_once,
+ .frame = draw_once,
};
return yasl_run(&desc) || failed ? 1 : 0;
}
diff --git a/tests/wayland/test_app_input.c b/tests/wayland/test_app_input.c
index 843f38d..88f9ead 100644
--- a/tests/wayland/test_app_input.c
+++ b/tests/wayland/test_app_input.c
@@ -26,6 +26,15 @@ static void push_key(struct yasl_surface *s)
static enum yasl_app_result on_init(void *ud, struct yasl_display *d)
{
struct test_state *state = ud;
+ if (state->end == 3) {
+ /* With no event callback, a close request alone stops the runner. */
+ struct yasl_surface *s = yasl_surface_create_toplevel(d,
+ &(struct yasl_window_spec){ .title = "App Close Test", .size = {64, 64} });
+ assert(s);
+ struct wayland_surface *w = (struct wayland_surface *)s;
+ w->cbs->close(s, w->ud);
+ return YASL_APP_CONTINUE;
+ }
if (state->end) {
struct wayland_display *display = (struct wayland_display *)d;
if (state->end == 1)
@@ -107,5 +116,10 @@ int main(void)
});
assert(end == 1 ? res == 0 : res < 0);
}
+ state = (struct test_state){.end = 3};
+ res = yasl_run(&(struct yasl_app_desc){
+ .backend = YASL_BACKEND_WAYLAND, .userdata = &state, .init = on_init,
+ });
+ assert(res == 0);
return 0;
}