diff options
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/hello.c | 104 | ||||
| -rw-r--r-- | examples/simple_window.c | 200 | ||||
| -rw-r--r-- | examples/tablet.c | 156 |
3 files changed, 203 insertions, 257 deletions
diff --git a/examples/hello.c b/examples/hello.c index 0c474c2..4153394 100644 --- a/examples/hello.c +++ b/examples/hello.c @@ -1,104 +1,56 @@ /* A complete CPU-rendered window. Build instructions: docs/getting-started.md. */ -#include <yasl/yasl.h> +#include <yasl/app.h> #include <stdio.h> -#include <string.h> struct app { - bool running; bool failed; - bool smoke_test; }; -static void quit(void *ud) +static int init(void *ud, struct yasl_display *display) { - ((struct app *)ud)->running = false; -} - -static void lost(void *ud) -{ - struct app *app = ud; - app->failed = true; - app->running = false; -} - -static void close_window(struct yasl_surface *surface, void *ud) -{ - (void)surface; - quit(ud); + struct yasl_window_spec spec = {.title = "Hello YASL", .size = {640, 480}}; + struct yasl_surface *surface = yasl_surface_create_toplevel(display, &spec); + if (!surface) { + perror("yasl_surface_create_toplevel"); + ((struct app *)ud)->failed = true; + return YASL_APP_QUIT; + } + yasl_surface_request_frame(surface); + return YASL_APP_CONTINUE; } -static void configure(struct yasl_surface *surface, struct yasl_geometry geometry, void *ud) +static int event(void *ud, const struct yasl_event *event) { - (void)geometry; (void)ud; - yasl_surface_schedule_redraw(surface); + return event->type == YASL_EVENT_WINDOW_CLOSE_REQUEST ? YASL_APP_QUIT : YASL_APP_CONTINUE; } -static void draw(struct yasl_surface *surface, struct yasl_frame *frame, void *ud) +static void draw(void *ud, struct yasl_surface *surface, struct yasl_frame_context *frame) { struct app *app = ud; - size_t count = (size_t)frame->target.size.x * frame->target.size.y; + size_t count = (size_t)frame->size.x * frame->size.y; for (size_t i = 0; i < count; i++) - frame->target.pixels[i] = 0xff306090; /* Opaque premultiplied ARGB. */ + frame->cpu.pixels[i] = 0xff306090; /* Opaque premultiplied ARGB. */ - struct yasl_damage_list damage = {.n = -1}; - if (!yasl_surface_present(surface, &frame->target, &damage)) { + if (!yasl_frame_present_cpu(frame, NULL, 0)) { fprintf(stderr, "Could not present the draw target\n"); app->failed = true; - app->running = false; } - if (app->smoke_test) app->running = false; + if (app->failed) yasl_surface_destroy(surface); } -int main(int argc, char **argv) +int main(void) { - struct app app = {.running = true}; - if (argc == 2 && strcmp(argv[1], "--smoke-test") == 0) - app.smoke_test = true; - else if (argc != 1) { - fprintf(stderr, "Usage: %s [--smoke-test]\n", argv[0]); - return 1; - } - - struct yasl_display_cbs display_callbacks = {.quit = quit, .lost = lost}; - struct yasl_display_spec display_spec = { + struct app app = {0}; + struct yasl_app_desc desc = { .app_id = "org.example.hello", - .cbs = &display_callbacks, - .ud = &app, - }; - struct yasl_display *display = yasl_display_open(NULL, &display_spec); - if (!display) { - perror("yasl_display_open"); - return 1; - } - struct yasl_window_cbs callbacks = { - .draw = draw, .configure = configure, .close = close_window, - }; - struct yasl_window_spec spec = { - .title = "Hello YASL", .size = {640, 480}, - .cbs = &callbacks, .ud = &app, + .userdata = &app, + .init = init, + .event = event, + .frame = draw, }; - struct yasl_surface *surface = yasl_surface_create_toplevel(display, &spec); - if (!surface) { - perror("yasl_surface_create_toplevel"); - yasl_display_close(display); - return 1; - } - yasl_surface_schedule_redraw(surface); - - while (app.running) { - if (yasl_display_dispatch(display, -1) < 0) { - perror("yasl_display_dispatch"); - app.failed = true; - break; - } - /* Drain even unused input so queued events do not cause a busy loop. */ - struct yasl_input_event event; - while (yasl_surface_input_poll(surface, &event)) {} - if (app.running) yasl_display_flush(display); - } - yasl_surface_destroy(surface); - yasl_display_close(display); - return app.failed ? 1 : 0; + int result = yasl_run(&desc); + if (result) fprintf(stderr, "Could not run the application\n"); + return result || app.failed ? 1 : 0; } diff --git a/examples/simple_window.c b/examples/simple_window.c index 797de3b..e9e6545 100644 --- a/examples/simple_window.c +++ b/examples/simple_window.c @@ -1,9 +1,8 @@ -#include "yasl/yasl.h" +#include <yasl/app.h> #include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> +#include <string.h> -static bool running = true; +static bool failed, smoke_test; static int mouse_x = -1; static int mouse_y = -1; static bool mouse_down = false; @@ -23,12 +22,12 @@ static const char *device_name(enum yasl_pointer_device dev) } } -static void on_draw(struct yasl_surface *s, struct yasl_frame *frame, void *ud) +static void on_draw(void *ud, struct yasl_surface *s, struct yasl_frame_context *frame) { (void)ud; - int w = frame->target.size.x; - int h = frame->target.size.y; - uint32_t *pixels = frame->target.pixels; + int w = frame->size.x; + int h = frame->size.y; + uint32_t *pixels = frame->cpu.pixels; if (!pixels || w <= 0 || h <= 0) return; @@ -81,63 +80,28 @@ static void on_draw(struct yasl_surface *s, struct yasl_frame *frame, void *ud) } } - struct yasl_damage_list dmg = { .n = -1 }; - yasl_surface_present(s, &frame->target, &dmg); -} - -static void on_configure(struct yasl_surface *s, struct yasl_geometry geo, void *ud) -{ - (void)ud; - printf("[YASL] Resized to %dx%d (scale: %.2fx)\n", - geo.size.x, geo.size.y, (double)geo.scale_120 / YASL_SCALE_UNIT); - yasl_surface_schedule_redraw(s); -} - -static void on_close(struct yasl_surface *s, void *ud) -{ - (void)s; - (void)ud; - printf("[YASL] Window close requested\n"); - running = false; + if (!yasl_frame_present_cpu(frame, NULL, 0)) { + fprintf(stderr, "Failed to present frame\n"); + failed = true; + } + if (failed || smoke_test) yasl_surface_destroy(s); } -static void on_quit(void *ud) +static int on_init(void *ud, struct yasl_display *display) { (void)ud; - running = false; -} - -int main(void) -{ - struct yasl_display_cbs disp_cbs = { .quit = on_quit }; - struct yasl_display_spec disp_spec = { - .app_id = "org.yasl.example", - .cbs = &disp_cbs, - }; - struct yasl_display *d = yasl_display_open(NULL, &disp_spec); - if (!d) { - fprintf(stderr, "Failed to open display\n"); - return 1; - } - - struct yasl_window_cbs window_cbs = { - .draw = on_draw, - .configure = on_configure, - .close = on_close, - }; struct yasl_window_spec window_spec = { .title = "YASL Interactive Window (Pen & Touch Enabled)", .size = { .x = 640, .y = 480 }, - .cbs = &window_cbs, }; - struct yasl_surface *s = yasl_surface_create_toplevel(d, &window_spec); + struct yasl_surface *s = yasl_surface_create_toplevel(display, &window_spec); if (!s) { fprintf(stderr, "Failed to create surface\n"); - yasl_display_close(d); - return 1; + failed = true; + return YASL_APP_QUIT; } - yasl_surface_schedule_redraw(s); + yasl_surface_request_frame(s); printf("=== YASL Demo Running ===\n"); printf(" - Stylus/Pen: full pressure (0..65535) and tilt detection\n"); @@ -145,56 +109,88 @@ int main(void) printf(" - Space: cycle background themes\n"); printf(" - Escape: exit\n\n"); - while (running) { - yasl_display_dispatch(d, -1); - - struct yasl_input_event ev; - while (yasl_surface_input_poll(s, &ev)) { - if (ev.kind == YASL_INPUT_KEY) { - if (ev.key.action == YASL_KEY_PRESS) { - if (ev.key.key == YASL_KEY_ESCAPE) { /* Escape */ - running = false; - } else if (ev.key.key == YASL_KEY_SPACE || ev.key.key == YASL_KEY_ENTER) { /* Space or Return */ - color_theme++; - yasl_surface_schedule_redraw(s); - } - } - } else if (ev.kind == YASL_INPUT_MOUSE) { - mouse_x = ev.mouse.pos.x; - mouse_y = ev.mouse.pos.y; - pen_pressure = ev.mouse.pen.pressure; - pen_tilt_x = ev.mouse.pen.tilt_x; - pen_tilt_y = ev.mouse.pen.tilt_y; - pointer_device = ev.mouse.device; - - if (ev.mouse.kind == YASL_PTR_PRESS) { - mouse_down = true; - if (pen_pressure > 0 || pointer_device == YASL_PTR_DEV_PEN) { - printf("[Pen Down] Pressure: %5u/65535 (%.1f%%) | Tilt: (%+3d°, %+3d°) | Device: %s\n", - pen_pressure, (pen_pressure * 100.0) / 65535.0, - pen_tilt_x, pen_tilt_y, device_name(pointer_device)); - } - } else if (ev.mouse.kind == YASL_PTR_RELEASE) { - mouse_down = false; - pen_pressure = 0; - } else if (ev.mouse.kind == YASL_PTR_MOTION && pen_pressure > 0) { - printf("[Pen Move] Pressure: %5u/65535 (%.1f%%) | Tilt: (%+3d°, %+3d°) | Device: %s\n", - pen_pressure, (pen_pressure * 100.0) / 65535.0, - pen_tilt_x, pen_tilt_y, device_name(pointer_device)); - } else if (ev.mouse.kind == YASL_PTR_LEAVE) { - mouse_x = -1; - mouse_y = -1; - mouse_down = false; - pen_pressure = 0; - } - yasl_surface_schedule_redraw(s); - } - } + return YASL_APP_CONTINUE; +} - yasl_display_flush(d); +static void pointer_sample(struct yasl_vector2i pos, enum yasl_pointer_device device, + struct yasl_pointer_pen pen) +{ + mouse_x = pos.x; + mouse_y = pos.y; + pointer_device = device; + pen_pressure = pen.pressure; + pen_tilt_x = pen.tilt_x; + pen_tilt_y = pen.tilt_y; +} + +static int on_event(void *ud, const struct yasl_event *ev) +{ + (void)ud; + switch (ev->type) { + case YASL_EVENT_WINDOW_CLOSE_REQUEST: + return YASL_APP_QUIT; + case YASL_EVENT_WINDOW_RESIZE: { + uint32_t flags = yasl_surface_state(ev->surface); + const char *mode = flags & YASL_STATE_FULLSCREEN ? "fullscreen" : + flags & YASL_STATE_MAXIMIZED ? "maximized" : + flags & YASL_STATE_TILED ? "tiled" : "windowed"; + printf("[YASL] Resized to %dx%d (scale: %.2fx, %s)\n", ev->resize.size.x, + ev->resize.size.y, (double)ev->resize.scale_120 / YASL_SCALE_UNIT, mode); + break; } + case YASL_EVENT_KEY: + if (ev->key.action != YASL_KEY_PRESS) return YASL_APP_CONTINUE; + if (ev->key.key == YASL_KEY_ESCAPE) return YASL_APP_QUIT; + if (ev->key.key == YASL_KEY_SPACE || ev->key.key == YASL_KEY_ENTER) + color_theme++; + break; + case YASL_EVENT_MOUSE_BUTTON: + pointer_sample(ev->mouse_button.pos, ev->mouse_button.device, ev->mouse_button.pen); + if (ev->mouse_button.button == 0) { + mouse_down = ev->mouse_button.pressed; + if (!mouse_down) pen_pressure = 0; + } + break; + case YASL_EVENT_MOUSE_MOTION: + pointer_sample(ev->mouse_motion.pos, ev->mouse_motion.device, ev->mouse_motion.pen); + break; + case YASL_EVENT_WINDOW_FOCUS: + if (ev->focus.focused) return YASL_APP_CONTINUE; + /* Fall through to cancel held input on focus loss. */ + [[fallthrough]]; + case YASL_EVENT_INPUT_RESET: + case YASL_EVENT_MOUSE_LEAVE: + mouse_x = mouse_y = -1; + mouse_down = false; + pen_pressure = 0; + break; + default: + return YASL_APP_CONTINUE; + } + if (pen_pressure > 0) { + printf("[Pen] Pressure: %5u/65535 (%.1f%%) | Tilt: (%+3d°, %+3d°) | Device: %s\n", + pen_pressure, pen_pressure * 100.0 / 65535.0, + pen_tilt_x, pen_tilt_y, device_name(pointer_device)); + } + yasl_surface_request_frame(ev->surface); + return YASL_APP_CONTINUE; +} - yasl_surface_destroy(s); - yasl_display_close(d); - return 0; +int main(int argc, char **argv) +{ + if (argc == 2 && strcmp(argv[1], "--smoke-test") == 0) + smoke_test = true; + else if (argc != 1) { + fprintf(stderr, "Usage: %s [--smoke-test]\n", argv[0]); + return 1; + } + struct yasl_app_desc desc = { + .app_id = "org.yasl.example", + .init = on_init, + .event = on_event, + .frame = on_draw, + }; + int result = yasl_run(&desc); + if (result) perror("yasl_run"); + return result || failed ? 1 : 0; } diff --git a/examples/tablet.c b/examples/tablet.c index 8a1af7e..f392cdc 100644 --- a/examples/tablet.c +++ b/examples/tablet.c @@ -1,5 +1,5 @@ /* Pressure-sensitive drawing using only YASL's portable API. */ -#include <yasl/yasl.h> +#include <yasl/app.h> #include <math.h> #include <stdio.h> @@ -14,10 +14,15 @@ #define HEADER 104 struct app { - bool running, smoke_test, failed, tablet_supported; + bool smoke_test, failed, tablet_supported; bool down, visible, previous; + struct yasl_surface *surface; enum yasl_backend backend; - struct yasl_mouse_event pointer; + struct { + struct yasl_vector2i pos; + enum yasl_pointer_device device; + struct yasl_pointer_pen pen; + } pointer; double last_x, last_y, last_radius; uint32_t *canvas; struct yasl_geometry geometry; @@ -135,31 +140,49 @@ static void stroke(struct app *app) app->previous = true; } -static void input(struct app *app, const struct yasl_input_event *event) +static int input(void *ud, const struct yasl_event *event) { - if (event->kind == YASL_INPUT_RESET || - (event->kind == YASL_INPUT_FOCUS && !event->focus.focused)) { + struct app *app = ud; + if (event->type == YASL_EVENT_WINDOW_CLOSE_REQUEST) + return YASL_APP_QUIT; + if (event->type == YASL_EVENT_WINDOW_RESIZE) { + if (!resize_canvas(app, (struct yasl_geometry){event->resize.size, event->resize.scale_120})) { + app->failed = true; + return YASL_APP_QUIT; + } + } else if (event->type == YASL_EVENT_INPUT_RESET || event->type == YASL_EVENT_MOUSE_LEAVE || + (event->type == YASL_EVENT_WINDOW_FOCUS && !event->focus.focused)) { cancel_stroke(app); - } else if (event->kind == YASL_INPUT_KEY && event->key.action == YASL_KEY_PRESS) { - if (event->key.key == YASL_KEY_ESCAPE) app->running = false; + } else if (event->type == YASL_EVENT_KEY && event->key.action == YASL_KEY_PRESS) { + if (event->key.key == YASL_KEY_ESCAPE) return YASL_APP_QUIT; if (event->key.key == YASL_KEY_C || event->key.key == YASL_KEY_SPACE) clear_canvas(app); - } else if (event->kind == YASL_INPUT_MOUSE) { - const struct yasl_mouse_event *pointer = &event->mouse; - if (pointer->kind == YASL_PTR_SCROLL) return; - if (app->pointer.device != pointer->device) cancel_stroke(app); - app->pointer = *pointer; - app->visible = pointer->kind != YASL_PTR_LEAVE; - if (pointer->kind == YASL_PTR_LEAVE) cancel_stroke(app); - else if (pointer->kind == YASL_PTR_PRESS && pointer->button == 0) { + } else if (event->type == YASL_EVENT_MOUSE_BUTTON) { + if (app->pointer.device != event->mouse_button.device) cancel_stroke(app); + app->pointer.pos = event->mouse_button.pos; + app->pointer.device = event->mouse_button.device; + app->pointer.pen = event->mouse_button.pen; + app->visible = true; + if (event->mouse_button.pressed && event->mouse_button.button == 0) { app->down = true; app->previous = false; stroke(app); - } else if (pointer->kind == YASL_PTR_RELEASE && pointer->button == 0) { + } else if (!event->mouse_button.pressed && event->mouse_button.button == 0) { app->down = app->previous = false; app->pointer.pen.pressure = 0; - } else if (pointer->kind == YASL_PTR_MOTION && app->down) stroke(app); + } + } else if (event->type == YASL_EVENT_MOUSE_MOTION) { + if (app->pointer.device != event->mouse_motion.device) cancel_stroke(app); + app->pointer.pos = event->mouse_motion.pos; + app->pointer.device = event->mouse_motion.device; + app->pointer.pen = event->mouse_motion.pen; + app->visible = true; + if (app->down) stroke(app); + } else { + return YASL_APP_CONTINUE; } + yasl_surface_request_frame(event->surface); + return YASL_APP_CONTINUE; } /* Tiny built-in 5x7 font keeps this example independent of a text library. */ @@ -214,18 +237,19 @@ static void text(struct yasl_framebuffer *fb, double dpi, int x, int y, } } -static void draw(struct yasl_surface *surface, struct yasl_frame *frame, void *ud) +static void draw(void *ud, struct yasl_surface *surface, struct yasl_frame_context *frame) { struct app *app = ud; - struct yasl_geometry geometry = yasl_surface_geometry(surface); - geometry.size = frame->target.size; + struct yasl_geometry geometry = {frame->size, frame->scale_120}; if (!resize_canvas(app, geometry)) { fprintf(stderr, "Cannot allocate drawing canvas\n"); - app->running = false; app->failed = true; + yasl_surface_destroy(surface); + app->surface = NULL; return; } - struct yasl_framebuffer *fb = &frame->target; + struct yasl_framebuffer target = {.size = frame->size, .pixels = frame->cpu.pixels}; + struct yasl_framebuffer *fb = ⌖ memcpy(fb->pixels, app->canvas, (size_t)geometry.size.x * geometry.size.y * sizeof(uint32_t)); double dpi = (double)app->geometry.scale_120 / YASL_SCALE_UNIT; rect(fb, 0, 0, fb->size.x, (int)lround(HEADER * dpi), PANEL); @@ -260,41 +284,42 @@ static void draw(struct yasl_surface *surface, struct yasl_frame *frame, void *u for (int i = 0; i <= 64; i++) rect(fb, (int)lround(cx + tx * i / 64), (int)lround(cy + ty * i / 64), 2, 2, ACCENT); } - struct yasl_damage_list damage = {.n = -1}; - if (!yasl_surface_present(surface, fb, &damage)) { + if (!yasl_frame_present_cpu(frame, NULL, 0)) { app->failed = true; - app->running = false; } - if (app->smoke_test) app->running = false; + if (app->failed || app->smoke_test) { + yasl_surface_destroy(surface); + app->surface = NULL; + } } -static void configure(struct yasl_surface *surface, struct yasl_geometry geometry, void *ud) +static int init(void *ud, struct yasl_display *display) { struct app *app = ud; - if (!resize_canvas(app, geometry)) { + app->backend = yasl_display_backend(display); + app->tablet_supported = (yasl_display_caps(display) & YASL_CAP_TABLET) != 0; + struct yasl_window_spec spec = { + .title = "YASL Tablet - pressure and tilt", .size = {900, 640}, + }; + app->surface = yasl_surface_create_toplevel(display, &spec); + if (!app->surface || !resize_canvas(app, yasl_surface_geometry(app->surface))) { + fprintf(stderr, "Cannot create drawing surface\n"); app->failed = true; - app->running = false; + return YASL_APP_QUIT; } - yasl_surface_schedule_redraw(surface); -} - -static void close_window(struct yasl_surface *surface, void *ud) -{ - (void)surface; - ((struct app *)ud)->running = false; -} - -static void quit(void *ud) { ((struct app *)ud)->running = false; } -static void lost(void *ud) -{ - struct app *app = ud; - app->failed = true; - app->running = false; + yasl_surface_set_mouse_mode(app->surface, YASL_MOUSE_HIDDEN); + yasl_surface_request_frame(app->surface); + printf("YASL tablet on %s: pressure changes brush width; eraser removes ink.\n" + "Mouse: fixed-width drawing. C/Space: clear. Escape: quit.\n", + backend_name(app->backend)); + if (!app->tablet_supported) + printf("This display server does not expose tablet input.\n"); + return YASL_APP_CONTINUE; } int main(int argc, char **argv) { - struct app app = {.running = true}; + struct app app = {0}; enum yasl_backend backend = YASL_BACKEND_AUTO; for (int i = 1; i < argc; i++) { if (!strcmp(argv[i], "--smoke-test")) app.smoke_test = true; @@ -312,39 +337,12 @@ int main(int argc, char **argv) return help ? 0 : 1; } } - struct yasl_display_cbs display_cbs = {.quit = quit, .lost = lost}; - struct yasl_display_spec display_spec = { - .app_id = "org.yasl.tablet", .backend = backend, .cbs = &display_cbs, .ud = &app, + struct yasl_app_desc desc = { + .app_id = "org.yasl.tablet", .backend = backend, .userdata = &app, + .init = init, .event = input, .frame = draw, }; - struct yasl_display *display = yasl_display_open(NULL, &display_spec); - if (!display) { perror("Cannot open display"); return 1; } - app.backend = yasl_display_backend(display); - app.tablet_supported = (yasl_display_caps(display) & YASL_CAP_TABLET) != 0; - struct yasl_window_cbs callbacks = {.draw = draw, .configure = configure, .close = close_window}; - struct yasl_window_spec spec = { - .title = "YASL Tablet - pressure and tilt", .size = {900, 640}, - .cbs = &callbacks, .ud = &app, - }; - struct yasl_surface *surface = yasl_surface_create_toplevel(display, &spec); - if (!surface) { perror("Cannot create surface"); yasl_display_close(display); return 1; } - yasl_surface_set_cursor(surface, YASL_CURSOR_HIDDEN); - yasl_surface_schedule_redraw(surface); - printf("YASL tablet on %s: pressure changes brush width; eraser removes ink.\n" - "Mouse: fixed-width drawing. C/Space: clear. Escape: quit.\n", - backend_name(app.backend)); - if (!app.tablet_supported) - printf("This display server does not expose tablet input.\n"); - while (app.running) { - if (yasl_display_dispatch(display, -1) < 0) { app.failed = true; break; } - struct yasl_input_event event; - while (yasl_surface_input_poll(surface, &event)) { - input(&app, &event); - yasl_surface_schedule_redraw(surface); - } - yasl_display_flush(display); - } + int result = yasl_run(&desc); + if (result) perror("yasl_run"); free(app.canvas); - yasl_surface_destroy(surface); - yasl_display_close(display); - return app.failed ? 1 : 0; + return result || app.failed ? 1 : 0; } |
