From 87279f6903343e621c0446b20d1e7d6a495f1125 Mon Sep 17 00:00:00 2001 From: Berke Güzel Date: Wed, 14 Oct 2026 13:56:48 +0300 Subject: Simplify the public API into one dense header yasl.h now holds everything except Vulkan: 45 functions instead of 62, and three installed headers instead of ten. - One constructor: yasl_surface_create takes CPU, GL or NATIVE, with zero-initialized GL options meaning 3.2 core, RGBA8, D24S8. - Events carry action, mods, x, y and text at the top level; pen positions are now logical like pointer positions. - yasl_cpu_pixels/yasl_cpu_present draw into one persistent canvas, cutting three full-frame copies per frame. - yasl_surface_get_info, yasl_surface_request, YASL_CURSOR_LOCKED, yasl_surface_set_text_input, yasl_surface_begin_move_resize and yasl_surface_get_native replace groups of narrower calls. - Interactive calls drop the decorative trigger event argument. - yasl_wait_event returns 0 only on timeout or yasl_wake, the refresh callback runs only in native modal loops, focus loss sends INPUT_RESET, and a lost event no longer fails every later wait. - Unsupported operations and bad arguments report ENOTSUP and EINVAL instead of EIO; the keycodes header no longer needs C23. - The shared library gets a versioned SONAME and version macros. Co-Authored-By: Claude Opus 5.5 --- tests/common/test_gl.c | 35 ++-- tests/common/test_surface_integration.c | 316 ++++++++++++++++---------------- tests/common/test_vulkan.c | 17 +- 3 files changed, 182 insertions(+), 186 deletions(-) (limited to 'tests/common') diff --git a/tests/common/test_gl.c b/tests/common/test_gl.c index 0e4597b..2bf3d8c 100644 --- a/tests/common/test_gl.c +++ b/tests/common/test_gl.c @@ -1,6 +1,6 @@ #define _POSIX_C_SOURCE 200809L -#include +#include #include #include #include @@ -60,7 +60,9 @@ static void wait_for_size(yasl_surface *surface, int width, int height) double deadline = seconds_now() + 8.0; int actual_width = 0, actual_height = 0; while (seconds_now() < deadline) { - yasl_surface_get_size(surface, &actual_width, &actual_height); + struct yasl_surface_info info = yasl_surface_get_info(surface); + actual_width = info.width; + actual_height = info.height; if (actual_width == width && actual_height == height) return; yasl_event event = {0}; int result = yasl_wait_event(&event, 50); @@ -75,11 +77,12 @@ static void wait_for_size(yasl_surface *surface, int width, int height) int main(int argc, char **argv) { REQUIRE(argc == 2, "expected backend argument: wayland or x11"); - if (!strcmp(argv[1], "wayland")) REQUIRE((yasl_init(&(struct yasl_options){.backend=YASL_BACKEND_WAYLAND}) == 0), "select Wayland backend"); - else if (!strcmp(argv[1], "x11")) REQUIRE((yasl_init(&(struct yasl_options){.backend=YASL_BACKEND_X11}) == 0), "select X11 backend"); + if (!strcmp(argv[1], "wayland")) REQUIRE(yasl_init(YASL_BACKEND_WAYLAND, NULL) == 0, "select Wayland backend"); + else if (!strcmp(argv[1], "x11")) REQUIRE(yasl_init(YASL_BACKEND_X11, NULL) == 0, "select X11 backend"); else REQUIRE(false, "backend must be wayland or x11"); - primary = yasl_gl_surface_create(&(struct yasl_surface_options){.title="YASL GL test", .width=320, .height=240, .type=YASL_SURFACE_NATIVE, .flags=0}, NULL); + primary = yasl_surface_create(&(struct yasl_surface_options){.title="YASL GL test", .width=320, .height=240, .type=YASL_SURFACE_GL}); + REQUIRE(yasl_get_features() & YASL_FEATURE_OPENGL, "report OpenGL support"); REQUIRE(primary != NULL, "create default OpenGL 3.2 surface"); REQUIRE((yasl_gl_make_current(primary) == 0), "make first GL context current"); @@ -109,7 +112,8 @@ int main(int argc, char **argv) finish(); unsigned char pixel[4] = {0}; int pixel_width = 0, pixel_height = 0; - yasl_surface_get_framebuffer_size(primary, &pixel_width, &pixel_height); + pixel_width = yasl_surface_get_info(primary).pixel_width; + pixel_height = yasl_surface_get_info(primary).pixel_height; REQUIRE(pixel_width > 0 && pixel_height > 0, "query initial framebuffer size"); read_pixels(pixel_width / 2, pixel_height / 2, 1, 1, GL_RGBA_, GL_UNSIGNED_BYTE_, pixel); REQUIRE(abs((int)pixel[0] - 51) <= 3 && abs((int)pixel[1] - 102) <= 3 && @@ -123,9 +127,7 @@ int main(int argc, char **argv) bind_texture(GL_TEXTURE_2D_, texture); REQUIRE(is_texture(texture), "create a shareable GL texture"); - struct yasl_gl_options sharing = YASL_GL_OPTIONS_INIT; - sharing.share = primary; - shared = yasl_gl_surface_create(&(struct yasl_surface_options){.title="YASL GL shared context", .width=160, .height=120, .type=YASL_SURFACE_NATIVE, .flags=0}, &sharing); + shared = yasl_surface_create(&(struct yasl_surface_options){.title="YASL GL shared context", .width=160, .height=120, .type=YASL_SURFACE_GL, .gl = {.share = primary}}); REQUIRE(shared != NULL, "create shared GL context"); REQUIRE((yasl_gl_make_current(shared) == 0), "make shared context current"); REQUIRE(is_texture(texture), "verify context shares GL objects"); @@ -134,8 +136,9 @@ int main(int argc, char **argv) REQUIRE((yasl_surface_request_size(primary, 400, 300) == 0), "request surface resize"); wait_for_size(primary, 400, 300); - yasl_surface_get_framebuffer_size(primary, &pixel_width, &pixel_height); - double scale = yasl_surface_get_scale(primary); + pixel_width = yasl_surface_get_info(primary).pixel_width; + pixel_height = yasl_surface_get_info(primary).pixel_height; + double scale = yasl_surface_get_info(primary).scale; REQUIRE(abs(pixel_width - (int)lround(400 * scale)) <= 1 && abs(pixel_height - (int)lround(300 * scale)) <= 1, "query resized framebuffer dimensions"); @@ -143,13 +146,11 @@ int main(int argc, char **argv) clear(GL_COLOR_BUFFER_BIT_); REQUIRE((yasl_gl_present(primary) == 0), "swap resized GL surface"); - struct yasl_gl_options invalid_options = YASL_GL_OPTIONS_INIT; - invalid_options.major = -1; - REQUIRE(yasl_gl_surface_create(&(struct yasl_surface_options){.title="invalid attrs", .width=100, .height=100, .type=YASL_SURFACE_NATIVE, .flags=0}, &invalid_options) == NULL, + REQUIRE(yasl_surface_create(&(struct yasl_surface_options){.title="invalid attrs", .width=100, .height=100, .type=YASL_SURFACE_GL, .gl = {.major = -1}}) == NULL && errno == EINVAL, "reject invalid GL context options"); - REQUIRE(yasl_gl_surface_create(&(struct yasl_surface_options){.title="invalid CPU GL", .width=100, .height=100, .type=YASL_SURFACE_CPU, .flags=0}, NULL) == NULL, - "reject CPU flag on GL surface creation"); - cpu = yasl_surface_create(&(struct yasl_surface_options){.title="CPU surface", .width=100, .height=100, .type=YASL_SURFACE_CPU, .flags=0}); + cpu = yasl_surface_create(&(struct yasl_surface_options){.title="CPU surface", .width=100, .height=100}); + REQUIRE(yasl_surface_create(&(struct yasl_surface_options){.title="no CPU sharing", .width=100, .height=100, .type=YASL_SURFACE_GL, .gl = {.share = cpu}}) == NULL && errno == EINVAL, + "reject a non-GL share surface"); REQUIRE(cpu != NULL, "create CPU surface for incompatibility check"); REQUIRE((yasl_gl_make_current(cpu) < 0), "reject CPU surface as a GL context"); diff --git a/tests/common/test_surface_integration.c b/tests/common/test_surface_integration.c index 1f18f23..072a307 100644 --- a/tests/common/test_surface_integration.c +++ b/tests/common/test_surface_integration.c @@ -1,17 +1,5 @@ #define _POSIX_C_SOURCE 200809L #include -#include -#include -#include -#if YASL_HAS_WAYLAND -#include -#endif -#if YASL_HAS_X11 -#include -#endif -#if YASL_HAS_COCOA -#include -#endif #include "common/backend.h" #include #include @@ -40,18 +28,20 @@ static void *wake_thread(void *unused) static void *wrong_thread(void *data) { assert(yasl_surface_set_title(data, "wrong") == -EPERM); - struct yasl_cpu_buffer buffer; - assert(yasl_cpu_acquire(data, &buffer) == -EPERM && !buffer.pixels); -#if YASL_HAS_WAYLAND - struct yasl_wayland_handles native; - assert(yasl_wayland_get_native(data, &native) == -EPERM && !native.display && !native.surface); -#endif + int w = 1, h = 1; + assert(!yasl_cpu_pixels(data, &w, &h) && errno == EPERM && !w && !h); + struct yasl_native native; + assert(yasl_surface_get_native(data, &native) == -EPERM && !native.wl_display && !native.x11_display); return NULL; } +static void push(yasl_surface *s, struct yasl_private_event event) +{ + event.surface = s; + assert(yasl_private_events_push(s->display, s, &event)); +} static int refreshes; -static void refresh(yasl_surface *s, void *ud) +static void refresh(yasl_surface *s) { - (void)ud; refreshes++; yasl_event e; assert(yasl_wait_event(&e, 0) == -EBUSY); @@ -59,7 +49,10 @@ static void refresh(yasl_surface *s, void *ud) assert(yasl_surface_destroy(s) == -EBUSY); struct yasl_surface_options options = {.width = 32, .height = 32}; assert(!yasl_surface_create(&options) && errno == EBUSY); - assert(!yasl_gl_surface_create(&options, NULL) && errno == EBUSY); + options.type = YASL_SURFACE_GL; + assert(!yasl_surface_create(&options) && errno == EBUSY); + int w, h; + assert(yasl_cpu_pixels(s, &w, &h) && yasl_cpu_present(s) == 0); } int main(int argc, char **argv) { @@ -67,53 +60,32 @@ int main(int argc, char **argv) enum yasl_backend backend = !strcmp(argv[1], "wayland") ? YASL_BACKEND_WAYLAND : !strcmp(argv[1], "x11") ? YASL_BACKEND_X11 : YASL_BACKEND_COCOA; - assert(yasl_init( - &(struct yasl_options){.backend = backend, .app_id = "org.yasl.surface-test"}) == 0); - yasl_surface *s = yasl_surface_create(&(struct yasl_surface_options){ - .title = "CPU contract", .width = 96, .height = 80, .type = YASL_SURFACE_CPU, .flags = 0}); + assert(yasl_init(backend, "org.yasl.surface-test") == 0); + assert(yasl_init(backend, NULL) == -EALREADY); + assert(yasl_get_backend() == backend); + unsigned features = yasl_get_features(); + yasl_surface *s = yasl_surface_create( + &(struct yasl_surface_options){.title = "CPU contract", .width = 96, .height = 80}); if (!s) { - const char *why; - why = strerror(errno); - fprintf(stderr, "surface: %s native=%d\n", why, errno); + fprintf(stderr, "surface: %s\n", strerror(errno)); return 1; } - assert(yasl_surface_get_backend(s) == backend); assert(yasl_surface_set_userdata(s, &backend) == 0); assert(yasl_surface_get_userdata(s) == &backend); -#if YASL_HAS_WAYLAND - struct yasl_wayland_handles wl; - int wl_result = yasl_wayland_get_native(s, &wl); - assert(wl_result == (backend == YASL_BACKEND_WAYLAND ? 0 : -ENOTSUP)); - assert(backend == YASL_BACKEND_WAYLAND ? wl.display && wl.surface : !wl.display && !wl.surface); - assert(yasl_wayland_get_native(s, NULL) == -EINVAL); -#endif -#if YASL_HAS_X11 - struct yasl_x11_handles x; - int x_result = yasl_x11_get_native(s, &x); - assert(x_result == (backend == YASL_BACKEND_X11 ? 0 : -ENOTSUP)); - assert(backend == YASL_BACKEND_X11 ? x.display && x.window : !x.display && !x.window); -#endif -#if YASL_HAS_COCOA - struct yasl_cocoa_handles cocoa; - assert(yasl_cocoa_get_native(s, &cocoa) == 0 && cocoa.application && cocoa.window && - cocoa.view); -#endif - CAMetalLayer *layer = NULL; - assert(yasl_metal_get_layer(s, &layer) == -EBUSY && !layer); - assert(yasl_surface_set_ime_caret(s, 1e300, 0, 1, 1) == -EOVERFLOW); + struct yasl_native native; + assert(yasl_surface_get_native(s, &native) == 0); + assert(backend != YASL_BACKEND_WAYLAND || (native.wl_display && native.wl_surface)); + assert(backend != YASL_BACKEND_X11 || (native.x11_display && native.x11_window)); + assert(backend != YASL_BACKEND_COCOA || (native.ns_window && native.ns_view)); + assert(yasl_surface_get_native(s, NULL) == -EINVAL); + assert(!yasl_metal_get_layer(s) && errno == EBUSY); if (backend == YASL_BACKEND_COCOA) { - assert(!(yasl_surface_get_features(s) & YASL_CAP_OPENGL)); - assert(!yasl_gl_surface_create(&(struct yasl_surface_options){.title = "unsupported GL", - .width = 64, - .height = 64, - .type = YASL_SURFACE_NATIVE, - .flags = 0}, - NULL)); - assert(errno == ENOTSUP); - assert((yasl_gl_make_current(NULL) < 0)); - assert(errno == ENOTSUP); - assert(!yasl_gl_get_proc_address("glClear")); + assert(!(features & YASL_FEATURE_OPENGL)); + assert(!yasl_surface_create(&(struct yasl_surface_options){ + .title = "unsupported GL", .width = 64, .height = 64, .type = YASL_SURFACE_GL})); assert(errno == ENOTSUP); + assert(yasl_gl_make_current(NULL) == 0); + assert(!yasl_gl_get_proc_address("glClear") && errno == ENOTSUP); } /* The first events report the window size, then ask for a frame. */ yasl_event e; @@ -132,131 +104,155 @@ int main(int argc, char **argv) } } assert(e.type == YASL_EVENT_REFRESH); + struct yasl_surface_info info = yasl_surface_get_info(s); + assert(info.pixel_width == fw && info.pixel_height == fh && info.scale > 0); + + /* CPU pixels persist between frames and are the window's own buffer. */ int w, h; - yasl_surface_get_framebuffer_size(s, &w, &h); - assert(w == fw && h == fh); - assert((yasl_init(&(struct yasl_options){.backend = backend}) < 0)); - assert(errno == EALREADY); - struct yasl_cpu_buffer buffer, other; - assert(yasl_cpu_acquire(s, &buffer) == 0); - uint32_t *pixels = buffer.pixels; - assert(buffer.width == w && buffer.height == h && buffer.stride_bytes == (size_t)w * 4); + uint32_t *pixels = yasl_cpu_pixels(s, &w, &h); + assert(pixels && w == fw && h == fh); assert(pixels[0] == 0 && pixels[(size_t)w * h - 1] == 0); - assert(yasl_cpu_acquire(s, &other) == -EBUSY && !other.pixels); for (size_t i = 0; i < (size_t)w * h; i++) pixels[i] = 0xff102030u; pixels[(size_t)3 * w + 2] = 0xffaabbccu; - other = buffer; - other.stride_bytes++; - assert(yasl_cpu_present(s, &other) == -EINVAL); - assert(yasl_cpu_present(s, &buffer) == 0); - assert(yasl_cpu_present(s, &buffer) == -ESTALE); - assert(yasl_cpu_acquire(s, &buffer) == 0); - assert(buffer.pixels[0] == 0xff102030u && buffer.pixels[(size_t)3 * w + 2] == 0xffaabbccu); - buffer.pixels[0] = 0xffffffffu; - assert(s->committed_pixels[0] == 0xff102030u); - assert(yasl_cpu_discard(s, &buffer) == 0); - assert(yasl_cpu_discard(s, &buffer) == -ESTALE); - assert(yasl_cpu_acquire(s, &buffer) == 0 && buffer.pixels[0] == 0xff102030u); + assert(yasl_cpu_present(s) == 0); + drain(); + pixels = yasl_cpu_pixels(s, &w, &h); + assert(pixels[0] == 0xff102030u && pixels[(size_t)3 * w + 2] == 0xffaabbccu); + + /* Waiting ends only on an event, the timeout or yasl_wake, never early. */ + drain(); + uint64_t start = yasl_time_ns(); + int n = yasl_wait_event(&e, 200); + assert(n == 1 || yasl_time_ns() - start >= 190000000ull); drain(); - assert(yasl_cpu_present(s, &buffer) == -ESTALE); - yasl_surface *second = yasl_surface_create(&(struct yasl_surface_options){ - .width = 32, .height = 32, .type = YASL_SURFACE_CPU, .userdata = &backend}); - assert(second && yasl_surface_get_userdata(second) == &backend); - assert(yasl_cpu_acquire(s, &buffer) == 0); - assert(yasl_cpu_acquire(second, &other) == 0); - assert(yasl_cpu_present(second, &buffer) == -ESTALE); - assert(yasl_cpu_discard(second, &other) == 0); - assert(yasl_surface_destroy(second) == 0); - assert(yasl_cpu_discard(s, &buffer) == 0); pthread_t thread; - assert(!pthread_create(&thread, NULL, wrong_thread, s)); - pthread_join(thread, NULL); assert(!pthread_create(&thread, NULL, wake_thread, NULL)); - int n = yasl_wait_event(&e, 500); - assert(n >= 0); + start = yasl_time_ns(); + n = yasl_wait_event(&e, 5000); pthread_join(thread, NULL); - bool ime = (yasl_surface_set_text_input(s, true, YASL_TEXT_NORMAL) == 0); - if (!ime) - assert(errno == ENOTSUP); - bool snapshot = (yasl_surface_set_surrounding_text(s, "a\xc3\xa9z", 4, 1, 3, 7) == 0); - if (ime) - assert(snapshot); - else - assert(!snapshot && errno == ENOTSUP); - assert((yasl_surface_set_surrounding_text(s, "a\xc3\xa9z", 4, 2, 3, 8) < 0)); - assert((yasl_surface_set_surrounding_text(s, "\xc0\xaf", 2, 0, 2, 8) < 0)); + assert(n == 1 || (n == 0 && yasl_time_ns() - start < 4000000000ull)); + assert(!pthread_create(&thread, NULL, wrong_thread, s)); + pthread_join(thread, NULL); + + yasl_surface *second = yasl_surface_create( + &(struct yasl_surface_options){.width = 32, .height = 32, .userdata = &backend}); + assert(second && yasl_surface_get_userdata(second) == &backend); + assert(yasl_surface_destroy(second) == 0); + + /* Text input */ + int ime = yasl_surface_set_text_input(s, &(struct yasl_text_input){ + .text = "a\xc3\xa9z", .length = 4, .selection_begin = 1, .selection_end = 3, + .revision = 7, .caret_x = 1, .caret_y = 2, .caret_width = 1, .caret_height = 10}); + assert(ime == 0 || ime == -ENOTSUP); + assert(yasl_surface_set_text_input(s, &(struct yasl_text_input){ + .text = "a\xc3\xa9z", .length = 4, .selection_begin = 2, .selection_end = 3}) == -EILSEQ); + assert(yasl_surface_set_text_input(s, &(struct yasl_text_input){ + .text = "\xc0\xaf", .length = 2}) == -EILSEQ); + assert(yasl_surface_set_text_input(s, &(struct yasl_text_input){ + .text = "ab", .length = 2, .selection_end = 3}) == -EINVAL); + assert(yasl_surface_set_text_input(s, &(struct yasl_text_input){.caret_x = 1e300}) == -EOVERFLOW); + assert(yasl_surface_set_text_input(s, NULL) == 0 || ime == -ENOTSUP); + + /* Arguments are checked before the backend sees them. */ + assert(yasl_surface_begin_move_resize(s, YASL_EDGE_TOP | YASL_EDGE_BOTTOM) == -EINVAL); + assert(yasl_surface_begin_move_resize(s, 16) == -EINVAL); + assert(yasl_surface_request(s, (enum yasl_request)9) == -EINVAL); + assert(yasl_surface_request_size(s, 0, 10) == -EINVAL); + assert(yasl_surface_set_cursor(s, (enum yasl_cursor)99) == -EINVAL); + int locked = yasl_surface_set_cursor(s, YASL_CURSOR_LOCKED); + assert(locked == ((features & YASL_FEATURE_LOCKED_CURSOR) ? 0 : -ENOTSUP)); + assert(yasl_surface_set_cursor(s, YASL_CURSOR_ARROW) == 0); + assert(yasl_drag_start(s, &(struct yasl_drag_image){.pixel_width = 4, .pixel_height = 4}) == -EINVAL); + uint32_t icon[4] = {0}; + assert(yasl_drag_start(s, &(struct yasl_drag_image){ + .pixels = icon, .pixel_width = 2, .pixel_height = 2, .hotspot_x = 2}) == -EINVAL); + assert(!yasl_popup_create(s, &(struct yasl_popup_options){.width = 10, .height = 10, + .anchor = YASL_EDGE_LEFT | YASL_EDGE_RIGHT}) && + errno == EINVAL); + assert(yasl_clipboard_set((enum yasl_selection)5, "x") == -EINVAL); + assert(yasl_clipboard_set(YASL_CLIPBOARD, NULL) == -EINVAL); + assert(yasl_clipboard_set(YASL_CLIPBOARD, "\xff") == -EILSEQ); + assert(yasl_clipboard_set(YASL_PRIMARY, "x") == + ((features & YASL_FEATURE_PRIMARY_SELECTION) ? 0 : -ENOTSUP)); drain(); - struct yasl_private_event pen = {.type = YASL_PRIVATE_EVENT_PEN, - .surface = s, - .pen = {.device_id = 10, - .tool_id = 20, - .x = 12.5, - .y = 9.25, - .pressure = 0.3, - .axes_valid = YASL_PRIVATE_PEN_PRESSURE, - .action = YASL_PRIVATE_PEN_DOWN, - .in_contact = true}}; - assert(yasl_private_events_push(s->display, s, &pen)); - assert(yasl_wait_event(&e, 0) == 1 && e.type == YASL_EVENT_PEN && e.pen.device_id == 10 && - e.pen.pressure == 0.3 && e.pen.in_contact); - struct yasl_private_event text = { - .type = YASL_PRIVATE_EVENT_TEXT, .surface = s, .text = {.data = "owned", .len = 5}}; - assert(yasl_private_events_push(s->display, s, &text)); + + /* Event conversion: positions are logical, text is owned until the next wait. */ + uint32_t real_scale = s->scale_120; + s->scale_120 = 240; + push(s, (struct yasl_private_event){ + .type = YASL_PRIVATE_EVENT_PEN, + .pen = {.device_id = 10, .x = 25, .y = 18.5, .pressure = 0.3, + .axes_valid = YASL_PRIVATE_PEN_PRESSURE, .action = YASL_PRIVATE_PEN_DOWN, + .in_contact = true}}); + assert(yasl_wait_event(&e, 0) == 1 && e.type == YASL_EVENT_PEN && e.action == YASL_PEN_DOWN); + assert(e.x == 12.5 && e.y == 9.25 && e.pen.device_id == 10 && e.pen.pressure == 0.3 && + (e.pen.axes & YASL_PEN_PRESSURE) && e.pen.in_contact); + push(s, (struct yasl_private_event){ + .type = YASL_PRIVATE_EVENT_POINTER_DOWN, + .pointer = {.pos = {20, 10}, .button = YASL_PRIVATE_BUTTON_SECONDARY, + .buttons = 4, .mods = YASL_PRIVATE_MOD_CTRL}}); + assert(yasl_wait_event(&e, 0) == 1 && e.type == YASL_EVENT_POINTER && + e.action == YASL_POINTER_DOWN && e.x == 10 && e.y == 5 && e.mods == YASL_MOD_CTRL && + e.pointer.button == YASL_BUTTON_SECONDARY && e.pointer.buttons == 4); + s->scale_120 = real_scale; + push(s, (struct yasl_private_event){.type = YASL_PRIVATE_EVENT_TEXT, .text = {"owned", 5}}); assert(yasl_wait_event(&e, 0) == 1 && e.type == YASL_EVENT_TEXT); - assert(e.text.length == 5 && !strcmp(e.text.data, "owned")); - /* Unchanged focus folds into no event; a change reports the activated state. */ - unsigned active = yasl_surface_get_state(s) & YASL_STATE_ACTIVATED; - struct yasl_private_event focus = { - .type = YASL_PRIVATE_EVENT_FOCUS, .surface = s, .focus = {.focused = !active}}; - assert(yasl_private_events_push(s->display, s, &focus)); - assert(yasl_wait_event(&e, 0) == 1 && e.type == YASL_EVENT_WINDOW); - assert((e.window.state & YASL_STATE_ACTIVATED) == (active ? 0u : YASL_STATE_ACTIVATED) && - e.window.pixel_width == w); - assert(yasl_private_events_push(s->display, s, &focus)); + assert(e.length == 5 && !strcmp(e.text, "owned")); + push(s, (struct yasl_private_event){ + .type = YASL_PRIVATE_EVENT_PASTE, + .paste = {.data = "", .request_id = 1, .status = YASL_PRIVATE_TRANSFER_UNAVAILABLE}}); + assert(yasl_wait_event(&e, 0) == 1 && e.type == YASL_EVENT_CLIPBOARD && + e.action == YASL_TRANSFER_UNAVAILABLE && e.length == 0); + /* Losing focus releases held input; activation itself comes from the window state. */ + push(s, (struct yasl_private_event){.type = YASL_PRIVATE_EVENT_FOCUS, .focus = {.focused = false}}); + assert(yasl_wait_event(&e, 0) == 1 && e.type == YASL_EVENT_INPUT_RESET); + push(s, (struct yasl_private_event){.type = YASL_PRIVATE_EVENT_FOCUS, .focus = {.focused = true}}); assert(yasl_wait_event(&e, 0) == 0 && e.type == YASL_EVENT_NONE); - struct yasl_private_event hover = {.type = YASL_PRIVATE_EVENT_DROP_HOVER, - .surface = s, - .drop = {YASL_PRIVATE_DROP_LEAVE, {0, 0}}}; - assert(yasl_private_events_push(s->display, s, &hover)); - assert(yasl_wait_event(&e, 0) == 1 && e.type == YASL_EVENT_DROP && - e.drop.action == YASL_DROP_LEAVE); + push(s, (struct yasl_private_event){.type = YASL_PRIVATE_EVENT_DROP_HOVER, + .drop = {YASL_PRIVATE_DROP_LEAVE, {0, 0}}}); + assert(yasl_wait_event(&e, 0) == 1 && e.type == YASL_EVENT_DROP && e.action == YASL_DROP_LEAVE); + + /* A resize keeps the overlap of the pixels and zeroes the rest. */ assert(yasl_surface_request_size(s, 112, 96) == 0); uint64_t resize_deadline = yasl_time_ns() + 3000000000ull; - int logical_w = 0, logical_h = 0; do { assert(yasl_wait_event(&e, 20) >= 0); - yasl_surface_get_size(s, &logical_w, &logical_h); - } while ((logical_w != 112 || logical_h != 96) && yasl_time_ns() < resize_deadline); - assert(logical_w == 112 && logical_h == 96); - assert(yasl_cpu_acquire(s, &buffer) == 0); - assert(buffer.pixels[0] == 0xff102030u); - assert(buffer.pixels[(size_t)3 * buffer.width + 2] == 0xffaabbccu); - assert(buffer.pixels[(size_t)buffer.width * buffer.height - 1] == 0); - assert(yasl_cpu_present(s, &buffer) == 0); - yasl_surface_set_refresh_callback(s, refresh, NULL); - assert(yasl_cpu_acquire(s, &buffer) == 0); - assert(yasl_cpu_present(s, &buffer) == 0); + info = yasl_surface_get_info(s); + } while ((info.width != 112 || info.height != 96) && yasl_time_ns() < resize_deadline); + assert(info.width == 112 && info.height == 96); + pixels = yasl_cpu_pixels(s, &w, &h); + assert(pixels && w == info.pixel_width && h == info.pixel_height); + assert(pixels[0] == 0xff102030u && pixels[(size_t)3 * w + 2] == 0xffaabbccu); + assert(pixels[(size_t)w * h - 1] == 0); + assert(yasl_cpu_present(s) == 0); + + /* The refresh callback is reserved for modal loops; ordinary waits deliver REFRESH. */ + s->refresh = refresh; + for (int i = 0; i < 5; i++) { + assert(yasl_cpu_pixels(s, &w, &h) && yasl_cpu_present(s) == 0); + assert(yasl_wait_event(&e, 20) >= 0); + } + assert(refreshes == 0); #if YASL_HAS_COCOA + s->display->modal = true; yasl_test_frame_tick(s); -#endif uint64_t deadline = yasl_private_loop_now_ns() + 3000000000ull; while (!refreshes && yasl_private_loop_now_ns() < deadline) assert(yasl_wait_event(&e, 20) >= 0); assert(refreshes > 0); - yasl_surface_set_refresh_callback(s, NULL, NULL); + s->display->modal = false; +#endif + s->refresh = NULL; yasl_surface_destroy(s); - assert((yasl_init(&(struct yasl_options){.backend = backend}) < 0)); + assert(yasl_init(backend, NULL) == -EALREADY); s = yasl_surface_create(&(struct yasl_surface_options){.title = "shared backend remains", - .width = 64, - .height = 64, - .type = YASL_SURFACE_CPU, - .flags = 0}); + .width = 64, .height = 64}); assert(s); yasl_shutdown(); - assert((yasl_init(&(struct yasl_options){.backend = backend}) == 0)); - s = yasl_surface_create(&(struct yasl_surface_options){ - .title = "reinitialized", .width = 64, .height = 64, .type = YASL_SURFACE_CPU, .flags = 0}); + assert(yasl_init(backend, NULL) == 0); + s = yasl_surface_create( + &(struct yasl_surface_options){.title = "reinitialized", .width = 64, .height = 64}); assert(s); yasl_shutdown(); puts("public surface lifecycle, pixels, ownership, input, wake and refresh passed"); diff --git a/tests/common/test_vulkan.c b/tests/common/test_vulkan.c index b12256a..4633d55 100644 --- a/tests/common/test_vulkan.c +++ b/tests/common/test_vulkan.c @@ -41,30 +41,29 @@ static int run_test(enum yasl_backend backend) VkSemaphore acquired = VK_NULL_HANDLE, rendered = VK_NULL_HANDLE; VkCommandBuffer command = VK_NULL_HANDLE; - if ((yasl_init(&(struct yasl_options){.backend=backend}) < 0)) { + if (yasl_init(backend, NULL) < 0) { fprintf(stderr, "vulkan integration: cannot select requested backend %d (YASL error %d)\n", backend, errno); goto cleanup; } - if ((yasl_vulkan_init(vkGetInstanceProcAddr) < 0)) { + struct yasl_vulkan_requirements requirements; + if (yasl_vulkan_init(vkGetInstanceProcAddr, &requirements) < 0) { fprintf(stderr, "vulkan integration: loader initialization failed (YASL error %d)\n", errno); goto cleanup; } - surface = yasl_surface_create(&(struct yasl_surface_options){.title="yasl Vulkan WSI integration", .width=256, .height=192, .type=YASL_SURFACE_NATIVE, .flags=0}); + surface = yasl_surface_create(&(struct yasl_surface_options){.title="yasl Vulkan WSI integration", .width=256, .height=192, .type=YASL_SURFACE_NATIVE}); if (!surface) { fprintf(stderr, "vulkan integration: surface creation failed (YASL error %d)\n", errno); goto cleanup; } - if (!(yasl_surface_get_features(surface) & YASL_CAP_VULKAN)) { + if (!(yasl_get_features() & YASL_FEATURE_VULKAN)) { fprintf(stderr, "vulkan integration: requested backend does not advertise Vulkan WSI\n"); goto cleanup; } uint32_t extension_count = 0; - struct yasl_vulkan_requirements requirements; - if (yasl_vulkan_get_requirements(surface, &requirements) < 0) goto cleanup; extension_count = requirements.extension_count; const char *const *required = requirements.extensions; if (!required || !extension_count) { @@ -114,7 +113,7 @@ static int run_test(enum yasl_backend backend) VkSurfaceKHR duplicate = VK_NULL_HANDLE; if (yasl_vulkan_create_surface(surface, instance, NULL, &duplicate) != VK_ERROR_NATIVE_WINDOW_IN_USE_KHR || duplicate != VK_NULL_HANDLE || yasl_surface_destroy(surface) != -EBUSY || - yasl_shutdown() != -EBUSY || yasl_vulkan_init(vkGetInstanceProcAddr) != -EBUSY) { + yasl_shutdown() != -EBUSY || yasl_vulkan_init(vkGetInstanceProcAddr, &requirements) != -EBUSY) { fprintf(stderr, "vulkan integration: live WSI ownership was not enforced\n"); goto cleanup; } @@ -191,8 +190,8 @@ static int run_test(enum yasl_backend backend) VkExtent2D extent = capabilities.currentExtent; if (extent.width == UINT32_MAX) { - int width = 0, height = 0; - yasl_surface_get_framebuffer_size(surface, &width, &height); + int width = yasl_surface_get_info(surface).pixel_width; + int height = yasl_surface_get_info(surface).pixel_height; if (width <= 0 || height <= 0) { fprintf(stderr, "vulkan integration: surface has no drawable framebuffer extent\n"); goto cleanup; -- cgit v1.2.3