diff options
| author | Berke Gรผzel <wenekar1@gmail.com> | 2026-10-13 23:41:31 +0300 |
|---|---|---|
| committer | Berke Gรผzel <wenekar1@gmail.com> | 2026-10-13 23:41:31 +0300 |
| commit | 76073fe5fad8799e5850805f2f090af2cb62c741 (patch) | |
| tree | 9658019babe4760a3634bdab4da0731a10e42e68 /tests/common | |
| parent | dd1775a9927922c14f8679ccbc4d3ca8d5917e20 (diff) | |
Simplify the public event and CPU API
Applications now need far less ceremony: hello.c is a 20-line loop that
handles REFRESH, CLOSE and QUIT and draws into the surface's own pixels.
- Fold GEOMETRY, STATE and FOCUS into one WINDOW event carrying size,
scale and state; unchanged values send nothing.
- Guarantee REFRESH once a window has a size and after every resize,
never at size zero.
- Merge DROP_HOVER into DROP with over/leave/data actions and give drag
and drop actions enums.
- Keep event strings valid until the next wait and drop
yasl_event_release; empty or failed waits report NONE.
- Replace copy-in presentation with a lent pixel buffer:
yasl_cpu_pixels and yasl_cpu_present.
- Remove yasl_poll_event, yasl_cpu_read_pixels, unused event fields and
comments that restated names.
- Wayland: resize floating windows in request_size instead of reporting
it unsupported, and stop marking new GPU surfaces as Vulkan so
yasl_vulkan_create_surface no longer fails with NATIVE_WINDOW_IN_USE.
Also includes the in-progress public API refactor that was uncommitted
in the tree (removal of the app/loop layer, new surface, GL and Vulkan
entry points).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'tests/common')
| -rw-r--r-- | tests/common/test_app.c | 204 | ||||
| -rw-r--r-- | tests/common/test_backends.c | 302 | ||||
| -rw-r--r-- | tests/common/test_contracts.c | 300 | ||||
| -rw-r--r-- | tests/common/test_desktop.c | 72 | ||||
| -rw-r--r-- | tests/common/test_events.c | 169 | ||||
| -rw-r--r-- | tests/common/test_gl.c | 158 | ||||
| -rw-r--r-- | tests/common/test_gl_options.c | 16 | ||||
| -rw-r--r-- | tests/common/test_hello_example.c | 20 | ||||
| -rw-r--r-- | tests/common/test_input_alloc.c | 14 | ||||
| -rw-r--r-- | tests/common/test_keyboard.c | 44 | ||||
| -rw-r--r-- | tests/common/test_loop.c | 76 | ||||
| -rw-r--r-- | tests/common/test_selection.c | 20 | ||||
| -rw-r--r-- | tests/common/test_surface_integration.c | 90 | ||||
| -rw-r--r-- | tests/common/test_tablet_example.c | 65 | ||||
| -rw-r--r-- | tests/common/test_timers.c | 148 | ||||
| -rw-r--r-- | tests/common/test_utf8.c | 22 | ||||
| -rw-r--r-- | tests/common/test_vulkan.c | 389 |
17 files changed, 1236 insertions, 873 deletions
diff --git a/tests/common/test_app.c b/tests/common/test_app.c deleted file mode 100644 index 214d8f2..0000000 --- a/tests/common/test_app.c +++ /dev/null @@ -1,204 +0,0 @@ -#define _DEFAULT_SOURCE -#include "yasl/app.h" - -#include <assert.h> -#include <errno.h> -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> - -struct test_state { - struct yasl_display *display; - struct yasl_surface *surface; - bool init_called; - bool frame_called; - bool user_event_called; - bool timer_called; - bool quit_called; - int frame_count; - yasl_timer_id timer_id; - pthread_t worker; - uint64_t target_id; -}; - -static void *worker_thread(void *arg) -{ - struct test_state *state = arg; - usleep(50000); /* 50ms */ - bool ok = yasl_display_post(state->display, &(struct yasl_message){ - .target_id = state->target_id, .code = 42, .payload = (void *)0x1234}); - assert(ok); - return NULL; -} - -static uint64_t on_timer(void *ud, yasl_timer_id id, uint64_t interval_ns) -{ - (void)id; - (void)interval_ns; - struct test_state *state = ud; - state->timer_called = true; - yasl_surface_request_frame(state->surface); - return 0; /* one-shot */ -} - -static enum yasl_app_result on_init(void *ud, struct yasl_display *d) -{ - struct test_state *state = ud; - state->display = d; - state->init_called = true; - - struct yasl_window_spec spec = { - .title = "App Runner Test", - .size = {320, 240}, - }; - state->surface = yasl_surface_create_toplevel(d, &spec); - assert(state->surface != NULL); - - yasl_surface_set_pacing(state->surface, YASL_PACING_ON_DEMAND); - yasl_surface_set_pointer_mode(state->surface, YASL_POINTER_RELATIVE); - yasl_surface_set_pointer_mode(state->surface, YASL_POINTER_NORMAL); - - state->timer_id = yasl_loop_add_timer(yasl_display_loop(d), YASL_MS_TO_NS(20), on_timer, state); - assert(state->timer_id > 0); - - state->target_id = yasl_surface_id(state->surface); - int err = pthread_create(&state->worker, NULL, worker_thread, state); - assert(err == 0); - - - yasl_surface_request_frame(state->surface); - return YASL_APP_CONTINUE; -} - -static enum yasl_app_result on_event(void *ud, const struct yasl_event *ev) -{ - struct test_state *state = ud; - if (ev->type == YASL_EVENT_USER) { - assert(ev->user.code == 42); - assert(ev->user.payload == (void *)0x1234); - state->user_event_called = true; - yasl_surface_request_frame(state->surface); - } else if (ev->type == YASL_EVENT_WINDOW_CLOSE) { - return YASL_APP_QUIT; - } - return YASL_APP_CONTINUE; -} - -static void on_frame(void *ud, struct yasl_surface *s, struct yasl_frame *ctx) -{ - struct test_state *state = ud; - assert(s == state->surface); - assert(ctx->surface == s); - state->frame_called = true; - state->frame_count++; - - if (ctx->target.pixels) { - size_t count = (size_t)ctx->target.size.x * ctx->target.size.y; - for (size_t i = 0; i < count; i++) { - ctx->target.pixels[i] = 0xff204060; - } - bool ok = yasl_frame_present(ctx, NULL, 0); - assert(ok); - } - - if (state->user_event_called) { - yasl_surface_destroy(state->surface); - } -} - -static void on_quit(void *ud, struct yasl_display *d) -{ - (void)d; - struct test_state *state = ud; - assert(!pthread_join(state->worker, NULL)); - state->quit_called = true; -} - -static void present_once(void *ud, struct yasl_surface *s, struct yasl_frame *ctx) -{ - (*(int *)ud)++; - if (ctx->target.pixels) - assert(yasl_frame_present(ctx, NULL, 0)); - yasl_surface_destroy(s); -} - -/* desc.window replaces init: the runner creates the toplevel and draws it. */ -static void test_window_without_init(void) -{ - int frames = 0; - struct yasl_window_spec window = {.title = "App Runner Window", .size = {160, 120}}; - int res = yasl_run(&(struct yasl_app_desc){ - .app_id = "org.yasl.test.app.window", - .userdata = &frames, - .window = &window, - .frame = present_once, - }); - assert(res == 0); - assert(frames == 1); -} - - -static enum yasl_app_result fail_init(void *ud, struct yasl_display *d) -{ - (void)ud; (void)d; - return YASL_APP_ERROR; -} -static void count_quit(void *ud, struct yasl_display *d) -{ - (void)d; - (*(int *)ud)++; -} -static enum yasl_app_result inspect_initial_window(void *ud, struct yasl_display *d) -{ - struct yasl_surface *s = yasl_app_window(d); - assert(s && yasl_surface_userdata(s) == ud); - errno = 0; - assert(!yasl_surface_set_callbacks(s, NULL, NULL) && errno == EBUSY); - return YASL_APP_CONTINUE; -} -static void fail_frame(void *ud, struct yasl_surface *s, struct yasl_frame *frame) -{ - (void)ud; - assert(frame->surface == s && frame->target.stride_bytes == frame->target.size.x * 4); - yasl_app_exit(yasl_surface_display(s), YASL_APP_ERROR); -} -static void test_error_lifecycle(void) -{ - int quits = 0; - assert(yasl_run(&(struct yasl_app_desc){.userdata = &quits, - .init = fail_init, .quit = count_quit}) < 0); - assert(quits == 1 && errno == EIO); - struct yasl_window_spec window = {.size_logical = {160, 120}, .userdata = &quits}; - assert(yasl_run(&(struct yasl_app_desc){.userdata = &quits, .window = &window, - .init = inspect_initial_window, .frame = fail_frame, .quit = count_quit}) < 0); - assert(quits == 2 && errno == EIO); -} - -int main(void) -{ - struct test_state state = {0}; - struct yasl_app_desc desc = { - .app_id = "org.yasl.test.app", - .backend = YASL_BACKEND_AUTO, - .userdata = &state, - .init = on_init, - .event = on_event, - .frame = on_frame, - .quit = on_quit, - }; - - int res = yasl_run(&desc); - if (res < 0 && !state.init_called && - (errno == EPERM || errno == EACCES || errno == ENOENT || - errno == ECONNREFUSED || errno == ENODEV)) return 77; - assert(res == 0); - assert(state.init_called); - assert(state.frame_called); - assert(state.user_event_called); - assert(state.timer_called); - assert(state.quit_called); - test_window_without_init(); - test_error_lifecycle(); - printf("App runner tests passed!\n"); - return 0; -} diff --git a/tests/common/test_backends.c b/tests/common/test_backends.c index 30f9b67..7eba57f 100644 --- a/tests/common/test_backends.c +++ b/tests/common/test_backends.c @@ -1,13 +1,13 @@ #define _POSIX_C_SOURCE 200809L -#include "yasl/native.h" +#include "common/private_native.h" #if YASL_HAS_WAYLAND -#include "yasl/native/wayland.h" +#include "common/private_native_wayland.h" #endif #if YASL_HAS_X11 -#include "yasl/native/x11.h" +#include "common/private_native_x11.h" #endif -#include "yasl/loop.h" -#include "yasl/yasl.h" +#include "common/private_loop.h" +#include "common/types.h" #include <X11/Xatom.h> #include <X11/Xlib.h> @@ -24,14 +24,14 @@ struct window { struct yasl_surface *surface; - struct yasl_display *display; + struct yasl_private_display *display; int draws, configures, closes; bool destroy_on_draw, destroy_on_configure; }; struct pump { - struct yasl_loop *loop; - struct yasl_display *displays[2]; + struct yasl_private_loop *loop; + struct yasl_private_display *displays[2]; int ticks; }; @@ -43,76 +43,76 @@ static int tick(int fd, short events, void *ud) struct pump *p = ud; for (int i = 0; i < 2; i++) { if (p->displays[i]) { - yasl_display_dispatch(p->displays[i], 0); - yasl_display_flush(p->displays[i]); + yasl_private_display_dispatch(p->displays[i], 0); + yasl_private_display_flush(p->displays[i]); } } - if (--p->ticks == 0) yasl_loop_quit(p->loop); + if (--p->ticks == 0) yasl_private_loop_quit(p->loop); return 0; } -static void pump(struct yasl_loop *loop, struct yasl_display *a, struct yasl_display *b) +static void pump(struct yasl_private_loop *loop, struct yasl_private_display *a, struct yasl_private_display *b) { int timer = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); assert(timer >= 0); struct pump p = {.loop = loop, .displays = {a, b}, .ticks = 20}; struct itimerspec spec = {.it_value.tv_nsec = 10000000, .it_interval.tv_nsec = 10000000}; assert(timerfd_settime(timer, 0, &spec, NULL) == 0); - int watch = yasl_loop_add_fd(loop, timer, POLLIN, tick, &p); + int watch = yasl_private_loop_add_fd(loop, timer, POLLIN, tick, &p); assert(watch > 0); - assert(yasl_loop_run(loop) == 0); - assert(yasl_loop_del_fd(loop, watch) == 0); + assert(yasl_private_loop_run(loop) == 0); + assert(yasl_private_loop_del_fd(loop, watch) == 0); close(timer); } -static void draw(struct yasl_surface *s, struct yasl_frame *frame, void *ud) +static void draw(struct yasl_surface *s, struct yasl_private_frame *frame, void *ud) { struct window *w = ud; assert(s == w->surface); assert(frame->surface == s); - assert(yasl_surface_display(s) == w->display); - struct yasl_vector2i size = yasl_surface_geometry(s).size; + assert(yasl_private_surface_display(s) == w->display); + struct yasl_private_vector2i size = yasl_private_surface_geometry(s).size; assert(size.x == frame->target.size.x && size.y == frame->target.size.y); assert(frame->target.pixels); - struct yasl_native_frame native = {0}; - assert(!yasl_surface_get_native_frame(s, &frame->target, &native)); + struct yasl_private_native_frame native = {0}; + assert(!yasl_private_surface_get_native_frame(s, &frame->target, &native)); for (int i = 0; i < size.x * size.y; i++) frame->target.pixels[i] = 0xff4080c0; - struct yasl_damage_list damage = {.n = YASL_DAMAGE_MAX + 1}; - assert(!yasl_surface_present(s, &frame->target, &damage)); + struct yasl_private_damage_list damage = {.n = YASL_PRIVATE_DAMAGE_MAX + 1}; + assert(!yasl_private_surface_present(s, &frame->target, &damage)); damage.n = -2; - assert(!yasl_surface_present(s, &frame->target, &damage)); + assert(!yasl_private_surface_present(s, &frame->target, &damage)); damage.n = 1; damage.rects[0].width = -1; - assert(!yasl_surface_present(s, &frame->target, &damage)); + assert(!yasl_private_surface_present(s, &frame->target, &damage)); damage.n = -1; - struct yasl_framebuffer invalid = frame->target; + struct yasl_private_framebuffer invalid = frame->target; invalid.size.x++; - assert(!yasl_surface_present(s, &invalid, &damage)); + assert(!yasl_private_surface_present(s, &invalid, &damage)); invalid = frame->target; invalid.generation--; - assert(!yasl_surface_present(s, &invalid, &damage)); + assert(!yasl_private_surface_present(s, &invalid, &damage)); invalid = frame->target; invalid.pixels = (uint32_t *)(uintptr_t)1; - assert(!yasl_surface_present(s, &invalid, &damage)); - assert(!yasl_surface_present(s, &frame->target, NULL)); - assert(yasl_surface_present(s, &frame->target, &damage)); - assert(!yasl_surface_present(s, &frame->target, &damage)); + assert(!yasl_private_surface_present(s, &invalid, &damage)); + assert(!yasl_private_surface_present(s, &frame->target, NULL)); + assert(yasl_private_surface_present(s, &frame->target, &damage)); + assert(!yasl_private_surface_present(s, &frame->target, &damage)); w->draws++; - if (w->destroy_on_draw) { yasl_surface_destroy(s); w->surface = NULL; } + if (w->destroy_on_draw) { yasl_private_surface_destroy(s); w->surface = NULL; } } -static void configure(struct yasl_surface *s, struct yasl_geometry geometry, void *ud) +static void configure(struct yasl_surface *s, struct yasl_private_geometry geometry, void *ud) { struct window *w = ud; assert(w->surface == s); - struct yasl_vector2i size = yasl_surface_geometry(s).size; + struct yasl_private_vector2i size = yasl_private_surface_geometry(s).size; assert(geometry.size.x == size.x && geometry.size.y == size.y); - assert(geometry.scale_120 == yasl_surface_geometry(s).scale_120); + assert(geometry.scale_120 == yasl_private_surface_geometry(s).scale_120); w->configures++; - if (w->destroy_on_configure) { yasl_surface_destroy(s); w->surface = NULL; } + if (w->destroy_on_configure) { yasl_private_surface_destroy(s); w->surface = NULL; } } -static void draw_without_present(struct yasl_surface *s, struct yasl_frame *frame, void *ud) +static void draw_without_present(struct yasl_surface *s, struct yasl_private_frame *frame, void *ud) { (void)s; struct window *w = ud; @@ -126,62 +126,62 @@ static void close_window(struct yasl_surface *s, void *ud) struct window *w = ud; assert(s == w->surface); w->closes++; - yasl_surface_destroy(s); + yasl_private_surface_destroy(s); w->surface = NULL; } -static const struct yasl_window_cbs callbacks = { +static const struct yasl_private_window_cbs callbacks = { .draw = draw, .configure = configure, .close = close_window, }; static void attach(struct window *w) { - struct yasl_window_cbs temporary = callbacks; - yasl_surface_set_callbacks(w->surface, &temporary, w); + struct yasl_private_window_cbs temporary = callbacks; + yasl_private_surface_set_callbacks(w->surface, &temporary, w); temporary.draw = NULL; temporary.configure = NULL; temporary.close = NULL; } -static struct window create(struct yasl_display *d) +static struct window create(struct yasl_private_display *d) { - struct yasl_window_spec spec = {.title = "Backend test", .size = {160, 100}}; - struct yasl_surface *s = yasl_surface_create_toplevel(d, &spec); + struct yasl_private_window_spec spec = {.title = "Backend test", .size = {160, 100}}; + struct yasl_surface *s = yasl_private_surface_create_toplevel(d, &spec); assert(s); - assert(yasl_display_get_native_handle(d)); - assert(yasl_surface_get_native_handle(s)); - assert(yasl_surface_display(s) == d); - assert(yasl_surface_timing(s).source == YASL_TIMING_UNKNOWN); + assert(yasl_private_display_get_native_handle(d)); + assert(yasl_private_surface_get_native_handle(s)); + assert(yasl_private_surface_display(s) == d); + assert(yasl_private_surface_timing(s).source == YASL_PRIVATE_TIMING_UNKNOWN); return (struct window){.surface = s, .display = d}; } /* The last presented frame reads back until a later draw replaces it. */ -static void test_read_pixels(struct yasl_loop *loop, struct yasl_display *d, struct window *w) +static void test_read_pixels(struct yasl_private_loop *loop, struct yasl_private_display *d, struct window *w) { - struct yasl_vector2i size = {-1, -1}; - assert(!yasl_surface_read_pixels(w->surface, NULL, 0, NULL)); - assert(!yasl_surface_read_pixels(NULL, NULL, 0, &size) && !size.x && !size.y); - assert(!yasl_surface_read_pixels(w->surface, NULL, 0, &size)); - struct yasl_vector2i extent = yasl_surface_geometry(w->surface).size; + struct yasl_private_vector2i size = {-1, -1}; + assert(!yasl_private_surface_read_pixels(w->surface, NULL, 0, NULL)); + assert(!yasl_private_surface_read_pixels(NULL, NULL, 0, &size) && !size.x && !size.y); + assert(!yasl_private_surface_read_pixels(w->surface, NULL, 0, &size)); + struct yasl_private_vector2i extent = yasl_private_surface_geometry(w->surface).size; assert(size.x == extent.x && size.y == extent.y); size_t count = (size_t)size.x * (size_t)size.y; uint32_t *pixels = calloc(count, sizeof(*pixels)); assert(pixels); - assert(!yasl_surface_read_pixels(w->surface, pixels, count - 1, &size)); + assert(!yasl_private_surface_read_pixels(w->surface, pixels, count - 1, &size)); assert(!pixels[0]); - assert(yasl_surface_read_pixels(w->surface, pixels, count, &size)); + assert(yasl_private_surface_read_pixels(w->surface, pixels, count, &size)); for (size_t i = 0; i < count; i++) assert(pixels[i] == 0xff4080c0); /* Draws that never present must not show through. X11 reuses its one * target; Wayland keeps the presented buffer while the compositor holds it. */ - struct yasl_window_cbs skip = callbacks; + struct yasl_private_window_cbs skip = callbacks; skip.draw = draw_without_present; - yasl_surface_set_callbacks(w->surface, &skip, w); + yasl_private_surface_set_callbacks(w->surface, &skip, w); for (int i = 0; i < 4; i++) { - yasl_surface_schedule_redraw(w->surface); + yasl_private_surface_schedule_redraw(w->surface); pump(loop, d, NULL); - if (yasl_surface_read_pixels(w->surface, pixels, count, &size)) { - assert(yasl_display_backend(d) != YASL_BACKEND_X11); + if (yasl_private_surface_read_pixels(w->surface, pixels, count, &size)) { + assert(yasl_private_display_backend(d) != YASL_PRIVATE_BACKEND_X11); for (size_t j = 0; j < count; j++) assert(pixels[j] == 0xff4080c0); } else { assert(!size.x && !size.y); @@ -189,47 +189,47 @@ static void test_read_pixels(struct yasl_loop *loop, struct yasl_display *d, str } attach(w); - yasl_surface_schedule_redraw(w->surface); + yasl_private_surface_schedule_redraw(w->surface); pump(loop, d, NULL); memset(pixels, 0, count * sizeof(*pixels)); - assert(yasl_surface_read_pixels(w->surface, pixels, count, &size)); + assert(yasl_private_surface_read_pixels(w->surface, pixels, count, &size)); assert(pixels[0] == 0xff4080c0 && pixels[count - 1] == 0xff4080c0); free(pixels); } -static void test_window_spec(struct yasl_loop *loop, struct yasl_display *d) +static void test_window_spec(struct yasl_private_loop *loop, struct yasl_private_display *d) { struct window w = {.display = d, .destroy_on_draw = true}; { - struct yasl_window_cbs temporary = callbacks; - struct yasl_window_spec spec = { + struct yasl_private_window_cbs temporary = callbacks; + struct yasl_private_window_spec spec = { .title = "Callbacks at creation", .size = {160, 100}, .cbs = &temporary, .ud = &w, }; - w.surface = yasl_surface_create_toplevel(d, &spec); + w.surface = yasl_private_surface_create_toplevel(d, &spec); assert(w.surface); assert(!w.draws && !w.configures && !w.closes); /* Neither the spec nor its callback table needs to outlive creation. */ memset(&temporary, 0, sizeof(temporary)); memset(&spec, 0, sizeof(spec)); } - yasl_surface_schedule_redraw(w.surface); + yasl_private_surface_schedule_redraw(w.surface); pump(loop, d, NULL); assert(w.draws == 1 && !w.surface); } -static void x11_behavior(struct yasl_loop *loop, struct yasl_display *d, struct window *w) +static void x11_behavior(struct yasl_private_loop *loop, struct yasl_private_display *d, struct window *w) { - Display *native = yasl_display_get_native_handle(d); - Window window = (Window)(uintptr_t)yasl_surface_get_native_handle(w->surface); + Display *native = yasl_private_display_get_native_handle(d); + Window window = (Window)(uintptr_t)yasl_private_surface_get_native_handle(w->surface); assert(native && window); - assert(yasl_x11_display_get_display(d) == native); - assert(yasl_x11_surface_get_window(w->surface) == (uintptr_t)window); + assert(yasl_private_x11_display_get_display(d) == native); + assert(yasl_private_x11_surface_get_window(w->surface) == (uintptr_t)window); XSync(native, False); XImage *image = XGetImage(native, window, 0, 0, 1, 1, AllPlanes, ZPixmap); assert(image && (XGetPixel(image, 0, 0) & 0xffffff) == 0x4080c0); XDestroyImage(image); - yasl_surface_set_title(w->surface, "Updated title"); + yasl_private_surface_set_title(w->surface, "Updated title"); char *title = NULL; assert(XFetchName(native, window, &title)); assert(strcmp(title, "Updated title") == 0); @@ -238,19 +238,19 @@ static void x11_behavior(struct yasl_loop *loop, struct yasl_display *d, struct XFlush(native); pump(loop, d, NULL); assert(w->configures > 0); - struct yasl_vector2i size = yasl_surface_geometry(w->surface).size; + struct yasl_private_vector2i size = yasl_private_surface_geometry(w->surface).size; assert(size.x == 200 && size.y == 120); /* A server-generated motion verifies the XI2 subscription and cookie * dispatch path, including source-device lookup, rather than SendEvent. */ - struct yasl_event pointer_event; - while (yasl_surface_poll_event(w->surface, &pointer_event)) {} + struct yasl_private_event pointer_event; + while (yasl_private_surface_poll_event(w->surface, &pointer_event)) {} XWarpPointer(native, None, window, 0, 0, 0, 0, 80, 50); XFlush(native); pump(loop, d, NULL); bool saw_motion = false; - while (yasl_surface_poll_event(w->surface, &pointer_event)) { - if (pointer_event.type == YASL_EVENT_POINTER_MOTION) { - assert(pointer_event.pointer.device == YASL_PTR_DEV_MOUSE); + while (yasl_private_surface_poll_event(w->surface, &pointer_event)) { + if (pointer_event.type == YASL_PRIVATE_EVENT_POINTER_MOTION) { + assert(pointer_event.pointer.device == YASL_PRIVATE_PTR_DEV_MOUSE); assert(!pointer_event.pointer.pen.pressure); if (pointer_event.pointer.pos.x == 80 && pointer_event.pointer.pos.y == 50) saw_motion = true; @@ -263,25 +263,25 @@ static void x11_behavior(struct yasl_loop *loop, struct yasl_display *d, struct .keycode = XKeysymToKeycode(native, XK_a)}; XSendEvent(native, window, False, KeyPressMask, &key); XFlush(native); - yasl_display_copy(d, YASL_CLIPBOARD, "clipboard text"); - yasl_display_paste(d, YASL_CLIPBOARD, w->surface); + yasl_private_display_copy(d, YASL_PRIVATE_CLIPBOARD, "clipboard text"); + yasl_private_display_paste(d, YASL_PRIVATE_CLIPBOARD, w->surface); pump(loop, d, NULL); bool saw_key = false, saw_paste = false, saw_text = false; - struct yasl_event event; - while (yasl_surface_poll_event(w->surface, &event)) { + struct yasl_private_event event; + while (yasl_private_surface_poll_event(w->surface, &event)) { assert(event.surface == w->surface); - if (event.type == YASL_EVENT_KEY) { + if (event.type == YASL_PRIVATE_EVENT_KEY) { assert(event.key.codepoint == 'a'); assert(event.key.shifted == 'A'); assert(event.key.native_code == key.xkey.keycode); saw_key = event.key.key == YASL_KEY_A; } - if (event.type == YASL_EVENT_PASTE) { + if (event.type == YASL_PRIVATE_EVENT_PASTE) { assert(event.text.len == strlen("clipboard text")); assert(memcmp(event.text.data, "clipboard text", event.text.len) == 0); saw_paste = true; } - if (event.type == YASL_EVENT_TEXT) { + if (event.type == YASL_PRIVATE_EVENT_TEXT) { assert(event.text.len == 1 && event.text.data[0] == 'a'); saw_text = true; } @@ -297,12 +297,12 @@ static void x11_behavior(struct yasl_loop *loop, struct yasl_display *d, struct XFlush(native); pump(loop, d, NULL); int key_count = 0, text_count = 0; - while (yasl_surface_poll_event(w->surface, &event)) { - if (event.type == YASL_EVENT_KEY) { + while (yasl_private_surface_poll_event(w->surface, &event)) { + if (event.type == YASL_PRIVATE_EVENT_KEY) { assert(event.key.key == YASL_KEY_A); assert(event.key.action == (key_count ? YASL_KEY_RELEASE : YASL_KEY_PRESS)); key_count++; - } else if (event.type == YASL_EVENT_TEXT) { + } else if (event.type == YASL_PRIVATE_EVENT_TEXT) { assert(event.text.len == 1 && event.text.data[0] == 'A'); text_count++; } @@ -313,10 +313,10 @@ static void x11_behavior(struct yasl_loop *loop, struct yasl_display *d, struct XSendEvent(native, window, False, KeyPressMask, &key); XFlush(native); pump(loop, d, NULL); - assert(yasl_surface_poll_event(w->surface, &event)); - assert(event.type == YASL_EVENT_KEY && event.key.key == YASL_KEY_A); - assert(event.key.mods & YASL_MOD_CTRL); - assert(!yasl_surface_poll_event(w->surface, &event)); + assert(yasl_private_surface_poll_event(w->surface, &event)); + assert(event.type == YASL_PRIVATE_EVENT_KEY && event.key.key == YASL_KEY_A); + assert(event.key.mods & YASL_PRIVATE_MOD_CTRL); + assert(!yasl_private_surface_poll_event(w->surface, &event)); int symbols_per_key = 0; KeySym *saved_symbols = XGetKeyboardMapping(native, key.xkey.keycode, 1, &symbols_per_key); @@ -333,11 +333,11 @@ static void x11_behavior(struct yasl_loop *loop, struct yasl_display *d, struct XFlush(native); pump(loop, d, NULL); saw_key = saw_text = false; - while (yasl_surface_poll_event(w->surface, &event)) { - if (event.type == YASL_EVENT_KEY) { + while (yasl_private_surface_poll_event(w->surface, &event)) { + if (event.type == YASL_PRIVATE_EVENT_KEY) { assert(event.key.key == YASL_KEY_A && event.key.codepoint == 'q'); saw_key = true; - } else if (event.type == YASL_EVENT_TEXT) { + } else if (event.type == YASL_PRIVATE_EVENT_TEXT) { assert(event.text.len == 1 && event.text.data[0] == 'q'); saw_text = true; } @@ -359,67 +359,67 @@ static void x11_behavior(struct yasl_loop *loop, struct yasl_display *d, struct XSendEvent(native, window, False, NoEventMask, &wheel); XFlush(native); pump(loop, d, NULL); - assert(yasl_surface_poll_event(w->surface, &event)); - assert(event.type == YASL_EVENT_POINTER_SCROLL); + assert(yasl_private_surface_poll_event(w->surface, &event)); + assert(event.type == YASL_PRIVATE_EVENT_POINTER_SCROLL); assert(event.pointer.scroll.x == (button == 6 ? -1 : button == 7 ? 1 : 0)); assert(event.pointer.scroll.y == (button == 4 ? -1 : button == 5 ? 1 : 0)); - assert(!yasl_surface_poll_event(w->surface, &event)); + assert(!yasl_private_surface_poll_event(w->surface, &event)); } - assert(yasl_surface_timing(w->surface).source == YASL_TIMING_SUBMISSION); - assert(!(yasl_display_caps(d) & YASL_CAP_FRAME_PACING)); + assert(yasl_private_surface_timing(w->surface).source == YASL_PRIVATE_TIMING_SUBMISSION); + assert(!(yasl_private_display_caps(d) & YASL_PRIVATE_CAP_FRAME_PACING)); /* Reuse caller storage, replace the selection, and exceed the old queue * cap before polling: each paste must retain its own original contents. */ for (int i = 0; i < 300; i++) { char text[32]; snprintf(text, sizeof(text), "owned-%d", i); - yasl_display_copy(d, YASL_CLIPBOARD, text); - yasl_display_paste(d, YASL_CLIPBOARD, w->surface); + yasl_private_display_copy(d, YASL_PRIVATE_CLIPBOARD, text); + yasl_private_display_paste(d, YASL_PRIVATE_CLIPBOARD, w->surface); memset(text, 'x', sizeof(text)); } for (int i = 0; i < 300; i++) { char text[32]; snprintf(text, sizeof(text), "owned-%d", i); - assert(yasl_surface_poll_event(w->surface, &event)); - assert(event.type == YASL_EVENT_PASTE && strcmp(event.text.data, text) == 0); + assert(yasl_private_surface_poll_event(w->surface, &event)); + assert(event.type == YASL_PRIVATE_EVENT_PASTE && strcmp(event.text.data, text) == 0); } const char *last = event.text.data; - assert(!yasl_surface_poll_event(w->surface, &event)); - yasl_display_copy(d, YASL_CLIPBOARD, "changed"); + assert(!yasl_private_surface_poll_event(w->surface, &event)); + yasl_private_display_copy(d, YASL_PRIVATE_CLIPBOARD, "changed"); pump(loop, d, NULL); assert(strcmp(last, "owned-299") == 0); - yasl_display_copy(d, YASL_CLIPBOARD, ""); - yasl_display_paste(d, YASL_CLIPBOARD, w->surface); - assert(yasl_surface_poll_event(w->surface, &event)); - assert(event.type == YASL_EVENT_PASTE && !event.text.len && !event.text.data[0]); + yasl_private_display_copy(d, YASL_PRIVATE_CLIPBOARD, ""); + yasl_private_display_paste(d, YASL_PRIVATE_CLIPBOARD, w->surface); + assert(yasl_private_surface_poll_event(w->surface, &event)); + assert(event.type == YASL_PRIVATE_EVENT_PASTE && !event.text.len && !event.text.data[0]); /* Concurrent external conversions must not share a mutable target slot. */ - struct yasl_display_spec ds = {.backend = YASL_BACKEND_X11}; - struct yasl_display *owner = yasl_display_open(loop, &ds); + struct yasl_private_display_spec ds = {.backend = YASL_PRIVATE_BACKEND_X11}; + struct yasl_private_display *owner = yasl_private_display_open(loop, &ds); assert(owner); - yasl_display_copy(owner, YASL_CLIPBOARD, "external"); + yasl_private_display_copy(owner, YASL_PRIVATE_CLIPBOARD, "external"); struct window other = create(d), cancelled = create(d); - yasl_display_paste(d, YASL_CLIPBOARD, w->surface); - yasl_display_paste(d, YASL_CLIPBOARD, other.surface); - yasl_display_paste(d, YASL_CLIPBOARD, cancelled.surface); - yasl_surface_destroy(cancelled.surface); + yasl_private_display_paste(d, YASL_PRIVATE_CLIPBOARD, w->surface); + yasl_private_display_paste(d, YASL_PRIVATE_CLIPBOARD, other.surface); + yasl_private_display_paste(d, YASL_PRIVATE_CLIPBOARD, cancelled.surface); + yasl_private_surface_destroy(cancelled.surface); pump(loop, d, owner); int first_pastes = 0, second_pastes = 0; - while (yasl_surface_poll_event(w->surface, &event)) { - if (event.type == YASL_EVENT_PASTE) { + while (yasl_private_surface_poll_event(w->surface, &event)) { + if (event.type == YASL_PRIVATE_EVENT_PASTE) { assert(strcmp(event.text.data, "external") == 0); first_pastes++; } } - while (yasl_surface_poll_event(other.surface, &event)) { - if (event.type == YASL_EVENT_PASTE) { + while (yasl_private_surface_poll_event(other.surface, &event)) { + if (event.type == YASL_PRIVATE_EVENT_PASTE) { assert(strcmp(event.text.data, "external") == 0); second_pastes++; } } assert(first_pastes == 1 && second_pastes == 1); - yasl_surface_destroy(other.surface); - yasl_display_close(owner); + yasl_private_surface_destroy(other.surface); + yasl_private_display_close(owner); key.xclient = (XClientMessageEvent){.type = ClientMessage, .display = native, .window = window, .message_type = XInternAtom(native, "WM_PROTOCOLS", False), .format = 32, .data.l = {(long)XInternAtom(native, "WM_DELETE_WINDOW", False)}}; @@ -432,64 +432,64 @@ static void x11_behavior(struct yasl_loop *loop, struct yasl_display *d, struct int main(int argc, char **argv) { assert(argc >= 2); - struct yasl_loop *loop = yasl_loop_create(); + struct yasl_private_loop *loop = yasl_private_loop_create(); assert(loop); if (strcmp(argv[1], "failure") == 0) { - struct yasl_display_spec spec = {.backend = (enum yasl_backend)atoi(argv[2])}; - assert(!yasl_display_open(loop, &spec)); + struct yasl_private_display_spec spec = {.backend = (enum yasl_private_backend)atoi(argv[2])}; + assert(!yasl_private_display_open(loop, &spec)); } else if (strcmp(argv[1], "mixed") == 0) { - struct yasl_display_spec spec = {.backend = YASL_BACKEND_WAYLAND}; - struct yasl_display *a = yasl_display_open(loop, &spec); - spec.backend = YASL_BACKEND_X11; - struct yasl_display *b = yasl_display_open(loop, &spec); + struct yasl_private_display_spec spec = {.backend = YASL_PRIVATE_BACKEND_WAYLAND}; + struct yasl_private_display *a = yasl_private_display_open(loop, &spec); + spec.backend = YASL_PRIVATE_BACKEND_X11; + struct yasl_private_display *b = yasl_private_display_open(loop, &spec); assert(a && b); test_window_spec(loop, a); test_window_spec(loop, b); struct window wa = create(a), wb = create(b); #if YASL_HAS_WAYLAND - assert(yasl_wayland_display_get_wl_display(a) != NULL); - assert(yasl_wayland_surface_get_wl_surface(wa.surface) != NULL); - assert(!yasl_x11_display_get_display(a)); + assert(yasl_private_wayland_display_get_wl_display(a) != NULL); + assert(yasl_private_wayland_surface_get_wl_surface(wa.surface) != NULL); + assert(!yasl_private_x11_display_get_display(a)); #endif #if YASL_HAS_X11 - assert(yasl_x11_display_get_display(b) != NULL); - assert(yasl_x11_surface_get_window(wb.surface) != 0); - assert(!yasl_wayland_display_get_wl_display(b)); + assert(yasl_private_x11_display_get_display(b) != NULL); + assert(yasl_private_x11_surface_get_window(wb.surface) != 0); + assert(!yasl_private_wayland_display_get_wl_display(b)); #endif attach(&wa); attach(&wb); pump(loop, a, b); assert(wa.draws && wb.draws); - yasl_surface_destroy(wa.surface); - yasl_surface_destroy(wb.surface); - yasl_display_close(a); - yasl_display_close(b); + yasl_private_surface_destroy(wa.surface); + yasl_private_surface_destroy(wb.surface); + yasl_private_display_close(a); + yasl_private_display_close(b); } else { assert(argc == 4); - struct yasl_display_spec spec = {.backend = (enum yasl_backend)atoi(argv[2])}; - struct yasl_display *d = strcmp(argv[1], "null") == 0 ? - yasl_display_open(loop, NULL) : yasl_display_open(loop, &spec); + struct yasl_private_display_spec spec = {.backend = (enum yasl_private_backend)atoi(argv[2])}; + struct yasl_private_display *d = strcmp(argv[1], "null") == 0 ? + yasl_private_display_open(loop, NULL) : yasl_private_display_open(loop, &spec); assert(d); - assert(yasl_display_backend(d) == (enum yasl_backend)atoi(argv[3])); + assert(yasl_private_display_backend(d) == (enum yasl_private_backend)atoi(argv[3])); struct window w = create(d); pump(loop, d, NULL); assert(w.draws == 0); attach(&w); - yasl_surface_schedule_redraw(w.surface); + yasl_private_surface_schedule_redraw(w.surface); pump(loop, d, NULL); assert(w.draws > 0); test_read_pixels(loop, d, &w); - if (yasl_display_backend(d) == YASL_BACKEND_X11) + if (yasl_private_display_backend(d) == YASL_PRIVATE_BACKEND_X11) x11_behavior(loop, d, &w); - if (w.surface) yasl_surface_destroy(w.surface); + if (w.surface) yasl_private_surface_destroy(w.surface); w = create(d); w.destroy_on_draw = true; attach(&w); pump(loop, d, NULL); assert(w.draws && !w.surface); - yasl_display_close(d); + yasl_private_display_close(d); } - yasl_loop_destroy(loop); + yasl_private_loop_destroy(loop); puts("Backend test passed."); return 0; } diff --git a/tests/common/test_contracts.c b/tests/common/test_contracts.c index d1964ff..be84586 100644 --- a/tests/common/test_contracts.c +++ b/tests/common/test_contracts.c @@ -13,17 +13,17 @@ static void test_timing_clock(void) { - struct yasl_frame_clock clock = {.refresh_ns = YASL_REFRESH_DEFAULT_NS}; - yasl_clock_presented(&clock, 1000000000, true); + struct yasl_private_frame_clock clock = {.refresh_ns = YASL_PRIVATE_REFRESH_DEFAULT_NS}; + yasl_private_clock_presented(&clock, 1000000000, true); assert(clock.last_present_ns == 1000000000); - uint64_t next = yasl_clock_next_present_ns(&clock); + uint64_t next = yasl_private_clock_next_present_ns(&clock); assert(next > 1000000000); - assert(yasl_clock_extend_ms(1000, 1000000000) == 1000000000); - assert(yasl_clock_frame_timestamp_ns(&clock, next) == next); + assert(yasl_private_clock_extend_ms(1000, 1000000000) == 1000000000); + assert(yasl_private_clock_frame_timestamp_ns(&clock, next) == next); - yasl_clock_note_resize(&clock, 500000); - struct yasl_resize_stats stats; - yasl_clock_resize_stats(&clock, &stats); + yasl_private_clock_note_resize(&clock, 500000); + struct yasl_private_resize_stats stats; + yasl_private_clock_resize_stats(&clock, &stats); assert(stats.count == 1); assert(stats.max_us == 500.0); } @@ -31,27 +31,27 @@ static void test_timing_clock(void) static void test_surface_state(void) { /* Reading reported flags does not require a backend query or display. */ - struct yasl_surface surface = {.state = YASL_STATE_FULLSCREEN | YASL_STATE_ACTIVATED}; - assert(!yasl_surface_state(NULL)); - assert(yasl_surface_state(&surface) == (YASL_STATE_FULLSCREEN | YASL_STATE_ACTIVATED)); + struct yasl_surface surface = {.state = YASL_PRIVATE_STATE_FULLSCREEN | YASL_PRIVATE_STATE_ACTIVATED}; + assert(!yasl_private_surface_state(NULL)); + assert(yasl_private_surface_state(&surface) == (YASL_PRIVATE_STATE_FULLSCREEN | YASL_PRIVATE_STATE_ACTIVATED)); } static void test_queue(void) { struct input_queue q = {0}; struct yasl_surface surface = {0}; - const enum yasl_event_type kinds[] = { - YASL_EVENT_TEXT, YASL_EVENT_PASTE, YASL_EVENT_DROP, + const enum yasl_private_event_type kinds[] = { + YASL_PRIVATE_EVENT_TEXT, YASL_PRIVATE_EVENT_PASTE, YASL_PRIVATE_EVENT_DROP, }; for (size_t k = 0; k < sizeof(kinds) / sizeof(kinds[0]); k++) { char *source = malloc(4); assert(source); memcpy(source, "a\0b", 4); - struct yasl_event in = {.surface = &surface, .type = kinds[k], .text = {.data = source, .len = 3}}; + struct yasl_private_event in = {.surface = &surface, .type = kinds[k], .text = {.data = source, .len = 3}}; assert(input_queue_push(&q, &in)); memset(source, 'x', 4); free(source); - struct yasl_event out; + struct yasl_private_event out; assert(input_queue_pop(&q, &out)); const char *payload = out.text.data; assert(out.surface == &surface && out.type == kinds[k]); @@ -60,7 +60,7 @@ static void test_queue(void) assert(memcmp(payload, "a\0b", 4) == 0); /* Growth/wraparound must not invalidate a previously polled payload. */ for (unsigned i = 0; i < 4096; i++) { - in = (struct yasl_event){.type = YASL_EVENT_KEY, .key.key = i}; + in = (struct yasl_private_event){.type = YASL_PRIVATE_EVENT_KEY, .key.key = i}; assert(input_queue_push(&q, &in)); } assert(memcmp(payload, "a\0b", 4) == 0); @@ -78,12 +78,12 @@ static void test_queue(void) } assert(!input_queue_pop(&q, &out)); } - struct yasl_event empty = {.surface = &surface, .type = YASL_EVENT_PASTE}; - struct yasl_event out; + struct yasl_private_event empty = {.surface = &surface, .type = YASL_PRIVATE_EVENT_PASTE}; + struct yasl_private_event out; assert(input_queue_push(&q, &empty)); assert(input_queue_pop(&q, &out)); assert(out.text.data && !out.text.len && out.text.data[0] == '\0'); - struct yasl_event in = {.surface = &surface, .type = YASL_EVENT_TEXT, + struct yasl_private_event in = {.surface = &surface, .type = YASL_PRIVATE_EVENT_TEXT, .text = {"owned", 5}}; assert(input_queue_push(&q, &in)); assert(input_queue_pop(&q, &out)); @@ -93,13 +93,13 @@ static void test_queue(void) in.text.len = SIZE_MAX; assert(!input_queue_push(&q, &in)); assert(strcmp(last, "owned") == 0); - in = (struct yasl_event){.surface = &surface, .type = YASL_EVENT_KEY}; + in = (struct yasl_private_event){.surface = &surface, .type = YASL_PRIVATE_EVENT_KEY}; assert(input_queue_push(&q, &in)); - assert(input_queue_pop(&q, &out) && out.type == YASL_EVENT_INPUT_RESET); + assert(input_queue_pop(&q, &out) && out.type == YASL_PRIVATE_EVENT_INPUT_RESET); assert(out.surface == &surface); - assert(input_queue_pop(&q, &out) && out.type == YASL_EVENT_KEY); + assert(input_queue_pop(&q, &out) && out.type == YASL_PRIVATE_EVENT_KEY); assert(!input_queue_pop(&q, &out)); - in = (struct yasl_event){.type = YASL_EVENT_PASTE, .text = {"pending", 7}}; + in = (struct yasl_private_event){.type = YASL_PRIVATE_EVENT_PASTE, .text = {"pending", 7}}; assert(input_queue_push(&q, &in)); input_queue_clear(&q); input_queue_clear(&q); @@ -107,49 +107,49 @@ static void test_queue(void) } static int presents, copies, pastes, creates; -static struct yasl_damage_list received; -static bool present(struct yasl_surface *s, const struct yasl_framebuffer *fb, - const struct yasl_damage_list *damage) +static struct yasl_private_damage_list received; +static bool present(struct yasl_surface *s, const struct yasl_private_framebuffer *fb, + const struct yasl_private_damage_list *damage) { (void)s; (void)fb; presents++; received = *damage; return true; } -static uint32_t caps(const struct yasl_display *d) { (void)d; return 0; } -static void copy(struct yasl_display *d, enum yasl_selection sel, const char *text) +static uint32_t caps(const struct yasl_private_display *d) { (void)d; return 0; } +static void copy(struct yasl_private_display *d, enum yasl_private_selection sel, const char *text) { (void)d; (void)sel; (void)text; copies++; } -static void paste(struct yasl_display *d, enum yasl_selection sel, struct yasl_surface *s) +static void paste(struct yasl_private_display *d, enum yasl_private_selection sel, struct yasl_surface *s) { (void)d; (void)sel; (void)s; pastes++; } -static struct yasl_surface *create(struct yasl_display *d, const struct yasl_window_spec *spec, void *graphics_device) +static struct yasl_surface *create(struct yasl_private_display *d, const struct yasl_private_window_spec *spec, void *graphics_device) { (void)d; (void)spec; (void)graphics_device; creates++; return NULL; } static void *native_device; static int native_queries; static struct yasl_surface native_surface; -static uint32_t native_caps(const struct yasl_display *d) -{ (void)d; return YASL_CAP_NATIVE_GRAPHICS; } -static struct yasl_surface *native_create(struct yasl_display *d, - const struct yasl_window_spec *spec, void *device) +static uint32_t native_caps(const struct yasl_private_display *d) +{ (void)d; return YASL_PRIVATE_CAP_NATIVE_GRAPHICS; } +static struct yasl_surface *native_create(struct yasl_private_display *d, + const struct yasl_private_window_spec *spec, void *device) { (void)spec; native_device = device; native_surface = (struct yasl_surface){.display = d, .frame_generation = 1}; return &native_surface; } -static bool native_frame(struct yasl_surface *s, const struct yasl_framebuffer *fb, - struct yasl_native_frame *out) +static bool native_frame(struct yasl_surface *s, const struct yasl_private_framebuffer *fb, + struct yasl_private_native_frame *out) { (void)s; (void)fb; native_queries++; - *out = (struct yasl_native_frame){.drawable = native_device}; + *out = (struct yasl_private_native_frame){.drawable = native_device}; return true; } -static uint32_t push_buttons(struct input_queue *q, enum yasl_event_type type, - enum yasl_pointer_button button) +static uint32_t push_buttons(struct input_queue *q, enum yasl_private_event_type type, + enum yasl_private_pointer_button button) { - struct yasl_event ev = {.type = type, .pointer.button = button}; + struct yasl_private_event ev = {.type = type, .pointer.button = button}; assert(input_queue_push(q, &ev)); assert(input_queue_pop(q, &ev)); return ev.pointer.buttons; @@ -157,31 +157,31 @@ static uint32_t push_buttons(struct input_queue *q, enum yasl_event_type type, static void test_held_buttons(void) { - const uint32_t primary = YASL_BUTTON_BIT(YASL_BUTTON_PRIMARY); - const uint32_t secondary = YASL_BUTTON_BIT(YASL_BUTTON_SECONDARY); + const uint32_t primary = YASL_PRIVATE_BUTTON_BIT(YASL_PRIVATE_BUTTON_PRIMARY); + const uint32_t secondary = YASL_PRIVATE_BUTTON_BIT(YASL_PRIVATE_BUTTON_SECONDARY); struct input_queue q = {0}; - assert(push_buttons(&q, YASL_EVENT_POINTER_MOTION, 0) == 0); - assert(push_buttons(&q, YASL_EVENT_POINTER_DOWN, YASL_BUTTON_PRIMARY) == primary); - assert(push_buttons(&q, YASL_EVENT_POINTER_MOTION, 0) == primary); - assert(push_buttons(&q, YASL_EVENT_POINTER_DOWN, YASL_BUTTON_SECONDARY) == (primary | secondary)); - assert(push_buttons(&q, YASL_EVENT_POINTER_UP, YASL_BUTTON_PRIMARY) == secondary); - assert(push_buttons(&q, YASL_EVENT_POINTER_SCROLL, 0) == secondary); + assert(push_buttons(&q, YASL_PRIVATE_EVENT_POINTER_MOTION, 0) == 0); + assert(push_buttons(&q, YASL_PRIVATE_EVENT_POINTER_DOWN, YASL_PRIVATE_BUTTON_PRIMARY) == primary); + assert(push_buttons(&q, YASL_PRIVATE_EVENT_POINTER_MOTION, 0) == primary); + assert(push_buttons(&q, YASL_PRIVATE_EVENT_POINTER_DOWN, YASL_PRIVATE_BUTTON_SECONDARY) == (primary | secondary)); + assert(push_buttons(&q, YASL_PRIVATE_EVENT_POINTER_UP, YASL_PRIVATE_BUTTON_PRIMARY) == secondary); + assert(push_buttons(&q, YASL_PRIVATE_EVENT_POINTER_SCROLL, 0) == secondary); /* X11 and Cocoa keep the press across leave; the release still follows. */ - assert(push_buttons(&q, YASL_EVENT_POINTER_LEAVE, 0) == secondary); - assert(push_buttons(&q, YASL_EVENT_POINTER_UP, YASL_BUTTON_SECONDARY) == 0); + assert(push_buttons(&q, YASL_PRIVATE_EVENT_POINTER_LEAVE, 0) == secondary); + assert(push_buttons(&q, YASL_PRIVATE_EVENT_POINTER_UP, YASL_PRIVATE_BUTTON_SECONDARY) == 0); /* A release without a press leaves nothing held. */ - assert(push_buttons(&q, YASL_EVENT_POINTER_UP, YASL_BUTTON_MIDDLE) == 0); + assert(push_buttons(&q, YASL_PRIVATE_EVENT_POINTER_UP, YASL_PRIVATE_BUTTON_MIDDLE) == 0); - assert(push_buttons(&q, YASL_EVENT_POINTER_DOWN, YASL_BUTTON_PRIMARY) == primary); - struct yasl_event reset = {.type = YASL_EVENT_INPUT_RESET}; + assert(push_buttons(&q, YASL_PRIVATE_EVENT_POINTER_DOWN, YASL_PRIVATE_BUTTON_PRIMARY) == primary); + struct yasl_private_event reset = {.type = YASL_PRIVATE_EVENT_INPUT_RESET}; assert(input_queue_push(&q, &reset)); assert(input_queue_pop(&q, &reset)); - assert(push_buttons(&q, YASL_EVENT_POINTER_MOTION, 0) == 0); + assert(push_buttons(&q, YASL_PRIVATE_EVENT_POINTER_MOTION, 0) == 0); q.leave_ends_press = true; - assert(push_buttons(&q, YASL_EVENT_POINTER_DOWN, YASL_BUTTON_PRIMARY) == primary); - assert(push_buttons(&q, YASL_EVENT_POINTER_LEAVE, 0) == 0); - assert(push_buttons(&q, YASL_EVENT_POINTER_MOTION, 0) == 0); + assert(push_buttons(&q, YASL_PRIVATE_EVENT_POINTER_DOWN, YASL_PRIVATE_BUTTON_PRIMARY) == primary); + assert(push_buttons(&q, YASL_PRIVATE_EVENT_POINTER_LEAVE, 0) == 0); + assert(push_buttons(&q, YASL_PRIVATE_EVENT_POINTER_MOTION, 0) == 0); input_queue_clear(&q); } @@ -216,117 +216,117 @@ static void test_drop_paths(void) /* A short buffer reports the length and leaves both outputs alone. */ const char *before = cursor; memcpy(path, "keep", 5); - assert(yasl_drop_next_path(&cursor, path, len) == len); + assert(yasl_private_drop_next_path(&cursor, path, len) == len); assert(cursor == before && strcmp(path, "keep") == 0); - assert(yasl_drop_next_path(&cursor, NULL, 0) == len && cursor == before); - assert(yasl_drop_next_path(&cursor, path, sizeof(path)) == len); + assert(yasl_private_drop_next_path(&cursor, NULL, 0) == len && cursor == before); + assert(yasl_private_drop_next_path(&cursor, path, sizeof(path)) == len); assert(strcmp(path, want[i]) == 0); } - assert(yasl_drop_next_path(&cursor, path, sizeof(path)) == 0 && *cursor == '\0'); - assert(yasl_drop_next_path(&cursor, path, sizeof(path)) == 0); - assert(yasl_drop_next_path(NULL, path, sizeof(path)) == 0); + assert(yasl_private_drop_next_path(&cursor, path, sizeof(path)) == 0 && *cursor == '\0'); + assert(yasl_private_drop_next_path(&cursor, path, sizeof(path)) == 0); + assert(yasl_private_drop_next_path(NULL, path, sizeof(path)) == 0); const char *none = NULL; - assert(yasl_drop_next_path(&none, path, sizeof(path)) == 0); + assert(yasl_private_drop_next_path(&none, path, sizeof(path)) == 0); cursor = list; - assert(yasl_drop_next_path(&cursor, NULL, 8) == 0 && cursor == list); + assert(yasl_private_drop_next_path(&cursor, NULL, 8) == 0 && cursor == list); } static void test_native(void) { - const struct yasl_backend_ops ops = {.display_caps = native_caps, + const struct yasl_private_backend_ops ops = {.display_caps = native_caps, .surface_create_toplevel = native_create, .surface_get_native_frame = native_frame}; - struct yasl_display d = {.ops = &ops}; - struct yasl_window_spec spec = {.size = {100, 80}}; - assert(yasl_surface_create_toplevel(&d, &spec) == &native_surface); + struct yasl_private_display d = {.ops = &ops}; + struct yasl_private_window_spec spec = {.size = {100, 80}}; + assert(yasl_private_surface_create_toplevel(&d, &spec) == &native_surface); assert(!native_device); - assert(yasl_surface_create_native(&d, &spec, &d) == &native_surface); + assert(yasl_private_surface_create_native(&d, &spec, &d) == &native_surface); assert(native_device == &d); - struct yasl_framebuffer fb = {.generation = 1, .size = {100, 80}}; - struct yasl_native_frame out = {0}; - assert(!yasl_surface_get_native_frame(NULL, &fb, &out)); - assert(!yasl_surface_get_native_frame(&native_surface, NULL, &out)); - assert(!yasl_surface_get_native_frame(&native_surface, &fb, NULL)); + struct yasl_private_framebuffer fb = {.generation = 1, .size = {100, 80}}; + struct yasl_private_native_frame out = {0}; + assert(!yasl_private_surface_get_native_frame(NULL, &fb, &out)); + assert(!yasl_private_surface_get_native_frame(&native_surface, NULL, &out)); + assert(!yasl_private_surface_get_native_frame(&native_surface, &fb, NULL)); fb.generation = 0; - assert(!yasl_surface_get_native_frame(&native_surface, &fb, &out)); + assert(!yasl_private_surface_get_native_frame(&native_surface, &fb, &out)); fb.generation = 2; - assert(!yasl_surface_get_native_frame(&native_surface, &fb, &out)); + assert(!yasl_private_surface_get_native_frame(&native_surface, &fb, &out)); assert(!native_queries && !out.drawable); fb.generation = 1; - assert(yasl_surface_get_native_frame(&native_surface, &fb, &out)); + assert(yasl_private_surface_get_native_frame(&native_surface, &fb, &out)); assert(native_queries == 1 && out.drawable == &d); } static void test_validation(void) { - const struct yasl_backend_ops ops = {.surface_present = present, + const struct yasl_private_backend_ops ops = {.surface_present = present, .display_caps = caps, .display_copy = copy, .display_paste = paste, .surface_create_toplevel = create}; - struct yasl_display d = {.ops = &ops}; + struct yasl_private_display d = {.ops = &ops}; struct yasl_surface s = {.display = &d, .frame_generation = 1}; - struct yasl_framebuffer fb = {.generation = 1, .size = {100, 80}}; - struct yasl_damage_list damage = {.n = -2}; - assert(!yasl_surface_present(&s, &fb, &damage)); - damage.n = YASL_DAMAGE_MAX + 1; - assert(!yasl_surface_present(&s, &fb, &damage)); + struct yasl_private_framebuffer fb = {.generation = 1, .size = {100, 80}}; + struct yasl_private_damage_list damage = {.n = -2}; + assert(!yasl_private_surface_present(&s, &fb, &damage)); + damage.n = YASL_PRIVATE_DAMAGE_MAX + 1; + assert(!yasl_private_surface_present(&s, &fb, &damage)); damage.n = 1; - damage.rects[0] = (struct yasl_rect2i){0, 0, -1, 1}; - assert(!yasl_surface_present(&s, &fb, &damage)); - assert(!yasl_surface_present(&s, &fb, NULL)); + damage.rects[0] = (struct yasl_private_rect2i){0, 0, -1, 1}; + assert(!yasl_private_surface_present(&s, &fb, &damage)); + assert(!yasl_private_surface_present(&s, &fb, NULL)); assert(!presents); damage.n = -1; fb.generation = 0; - assert(!yasl_surface_present(&s, &fb, &damage)); + assert(!yasl_private_surface_present(&s, &fb, &damage)); fb.generation = 2; - assert(!yasl_surface_present(&s, &fb, &damage)); + assert(!yasl_private_surface_present(&s, &fb, &damage)); fb.generation = 1; damage.n = 4; - damage.rects[0] = (struct yasl_rect2i){-10, -10, 30, 30}; - damage.rects[1] = (struct yasl_rect2i){90, 70, INT_MAX, INT_MAX}; - damage.rects[2] = (struct yasl_rect2i){INT_MAX, INT_MAX, INT_MAX, INT_MAX}; - damage.rects[3] = (struct yasl_rect2i){INT_MIN, INT_MIN, INT_MAX, INT_MAX}; - assert(yasl_surface_present(&s, &fb, &damage)); + damage.rects[0] = (struct yasl_private_rect2i){-10, -10, 30, 30}; + damage.rects[1] = (struct yasl_private_rect2i){90, 70, INT_MAX, INT_MAX}; + damage.rects[2] = (struct yasl_private_rect2i){INT_MAX, INT_MAX, INT_MAX, INT_MAX}; + damage.rects[3] = (struct yasl_private_rect2i){INT_MIN, INT_MIN, INT_MAX, INT_MAX}; + assert(yasl_private_surface_present(&s, &fb, &damage)); assert(received.n == 2 && received.rects[0].x == 0 && received.rects[0].width == 20); assert(received.rects[1].width == 10 && received.rects[1].height == 10); assert(damage.n == 4 && damage.rects[0].x == -10); damage.n = -1; - assert(yasl_surface_present(&s, &fb, &damage) && received.n == -1); + assert(yasl_private_surface_present(&s, &fb, &damage) && received.n == -1); damage.n = 0; - assert(yasl_surface_present(&s, &fb, &damage) && received.n == 0); - yasl_display_copy(&d, YASL_PRIMARY, "no alias"); - yasl_display_copy(&d, (enum yasl_selection)255, "invalid"); - yasl_display_paste(&d, YASL_PRIMARY, &s); - yasl_display_paste(&d, (enum yasl_selection)255, &s); + assert(yasl_private_surface_present(&s, &fb, &damage) && received.n == 0); + yasl_private_display_copy(&d, YASL_PRIVATE_PRIMARY, "no alias"); + yasl_private_display_copy(&d, (enum yasl_private_selection)255, "invalid"); + yasl_private_display_paste(&d, YASL_PRIVATE_PRIMARY, &s); + yasl_private_display_paste(&d, (enum yasl_private_selection)255, &s); assert(!copies && !pastes); - yasl_display_copy(&d, YASL_CLIPBOARD, "yes"); - yasl_display_paste(&d, YASL_CLIPBOARD, &s); + yasl_private_display_copy(&d, YASL_PRIVATE_CLIPBOARD, "yes"); + yasl_private_display_paste(&d, YASL_PRIVATE_CLIPBOARD, &s); assert(copies == 1 && pastes == 1); - struct yasl_window_spec spec = {.size = {100, 80}}; - assert(!yasl_surface_create_native(&d, &spec, &d) && errno == ENOTSUP); - assert(!yasl_surface_create_native(&d, &spec, NULL) && errno == EINVAL); + struct yasl_private_window_spec spec = {.size = {100, 80}}; + assert(!yasl_private_surface_create_native(&d, &spec, &d) && errno == ENOTSUP); + assert(!yasl_private_surface_create_native(&d, &spec, NULL) && errno == EINVAL); spec.size.x = 0; - assert(!yasl_surface_create_toplevel(&d, &spec) && errno == EINVAL); + assert(!yasl_private_surface_create_toplevel(&d, &spec) && errno == EINVAL); assert(!creates); } static void test_scale(void) { - assert(yasl_scale_to_device(-10, 120) == -10); - assert(yasl_scale_to_device(-0.5, 120) == -1); - assert(yasl_scale_to_device(0.5, 120) == 1); - assert(yasl_scale_to_device(NAN, 120) == 0); - assert(yasl_scale_to_device(INFINITY, 120) == 0); - assert(yasl_scale_to_device(DBL_MAX, 240) == INT_MAX); - assert(yasl_scale_to_logical(-1, 240) == -1); - assert(yasl_scale_to_logical(1, 240) == 1); - assert(yasl_scale_to_logical(INT_MAX, 1) == INT_MAX); - assert(yasl_scale_to_logical(INT_MIN, 1) == INT_MIN); - assert(yasl_scale_to_logical(1, 0) == 0); + assert(yasl_private_scale_to_device(-10, 120) == -10); + assert(yasl_private_scale_to_device(-0.5, 120) == -1); + assert(yasl_private_scale_to_device(0.5, 120) == 1); + assert(yasl_private_scale_to_device(NAN, 120) == 0); + assert(yasl_private_scale_to_device(INFINITY, 120) == 0); + assert(yasl_private_scale_to_device(DBL_MAX, 240) == INT_MAX); + assert(yasl_private_scale_to_logical(-1, 240) == -1); + assert(yasl_private_scale_to_logical(1, 240) == 1); + assert(yasl_private_scale_to_logical(INT_MAX, 1) == INT_MAX); + assert(yasl_private_scale_to_logical(INT_MIN, 1) == INT_MIN); + assert(yasl_private_scale_to_logical(1, 0) == 0); } static int popup_calls; static struct yasl_surface *popup_create(struct yasl_surface *parent, - const struct yasl_popup_spec *spec) + const struct yasl_private_popup_spec *spec) { (void)parent; (void)spec; popup_calls++; @@ -334,7 +334,7 @@ static struct yasl_surface *popup_create(struct yasl_surface *parent, } static bool popup_reposition(struct yasl_surface *popup, - const struct yasl_popup_spec *spec) + const struct yasl_private_popup_spec *spec) { (void)popup; (void)spec; popup_calls++; @@ -342,19 +342,19 @@ static bool popup_reposition(struct yasl_surface *popup, return false; } -static uint32_t popup_caps(const struct yasl_display *d) -{ (void)d; return YASL_CAP_POPUPS; } +static uint32_t popup_caps(const struct yasl_private_display *d) +{ (void)d; return YASL_PRIVATE_CAP_POPUPS; } -static int dispatch_failure(struct yasl_display *d, int timeout) +static int dispatch_failure(struct yasl_private_display *d, int timeout) { (void)d; (void)timeout; return -1; } -static struct yasl_surface *create_failure(struct yasl_display *d, - const struct yasl_window_spec *spec, void *device) +static struct yasl_surface *create_failure(struct yasl_private_display *d, + const struct yasl_private_window_spec *spec, void *device) { (void)d; (void)spec; (void)device; return NULL; } static int drag_starts; -static bool drag_without_listener(struct yasl_display *d, struct yasl_surface *s, - const struct yasl_drag_image *image, const struct yasl_drag_listener *listener, +static bool drag_without_listener(struct yasl_private_display *d, struct yasl_surface *s, + const struct yasl_private_drag_image *image, const struct yasl_private_drag_listener *listener, void *ud) { (void)d; (void)s; (void)image; (void)ud; @@ -366,52 +366,52 @@ static bool drag_without_listener(struct yasl_display *d, struct yasl_surface *s static void test_errors(void) { - const struct yasl_backend_ops ops = {.display_caps = popup_caps, + const struct yasl_private_backend_ops ops = {.display_caps = popup_caps, .surface_create_toplevel = create_failure, .surface_create_popup = popup_create, .surface_popup_reposition = popup_reposition, .display_drag_start = drag_without_listener, .display_dispatch_timeout = dispatch_failure}; - struct yasl_display d = {.ops = &ops}; + struct yasl_private_display d = {.ops = &ops}; struct yasl_surface s = {.display = &d}; - struct yasl_popup_spec spec = {.size = {120, 80}, .anchor = {0, 0, 1, 1}}; - assert(!yasl_surface_create_popup(NULL, &spec) && errno == EINVAL); - assert(!yasl_surface_create_popup(&s, NULL) && errno == EINVAL); + struct yasl_private_popup_spec spec = {.size = {120, 80}, .anchor = {0, 0, 1, 1}}; + assert(!yasl_private_surface_create_popup(NULL, &spec) && errno == EINVAL); + assert(!yasl_private_surface_create_popup(&s, NULL) && errno == EINVAL); spec.anchor.width = -1; /* Must not reach Wayland's protocol marshaler. */ - assert(!yasl_surface_create_popup(&s, &spec) && errno == EINVAL); - assert(!yasl_surface_popup_reposition(&s, &spec) && errno == EINVAL); + assert(!yasl_private_surface_create_popup(&s, &spec) && errno == EINVAL); + assert(!yasl_private_surface_popup_reposition(&s, &spec) && errno == EINVAL); spec.anchor.width = 1; spec.content_offset.x = INT_MAX; spec.content_size.x = INT_MAX; - assert(!yasl_surface_create_popup(&s, &spec) && errno == EINVAL); + assert(!yasl_private_surface_create_popup(&s, &spec) && errno == EINVAL); spec.content_offset.x = spec.content_size.x = 0; spec.size.x = 32768; - assert(!yasl_surface_create_popup(&s, &spec) && errno == EINVAL); + assert(!yasl_private_surface_create_popup(&s, &spec) && errno == EINVAL); assert(!popup_calls); spec.size.x = 120; errno = ERANGE; - assert(!yasl_surface_create_popup(&s, &spec) && errno == ENODEV); - assert(!yasl_surface_popup_reposition(&s, &spec) && errno == EBUSY); + assert(!yasl_private_surface_create_popup(&s, &spec) && errno == ENODEV); + assert(!yasl_private_surface_popup_reposition(&s, &spec) && errno == EBUSY); assert(popup_calls == 2); - const struct yasl_backend_ops unsupported = {0}; + const struct yasl_private_backend_ops unsupported = {0}; d.ops = &unsupported; - assert(!yasl_surface_create_popup(&s, &spec) && errno == ENOTSUP); - assert(!yasl_surface_popup_reposition(&s, &spec) && errno == ENOTSUP); - assert(yasl_display_dispatch(&d, 0) == -1 && errno == ENOTSUP); - assert(yasl_display_dispatch(NULL, 0) == -1 && errno == EINVAL); + assert(!yasl_private_surface_create_popup(&s, &spec) && errno == ENOTSUP); + assert(!yasl_private_surface_popup_reposition(&s, &spec) && errno == ENOTSUP); + assert(yasl_private_display_dispatch(&d, 0) == -1 && errno == ENOTSUP); + assert(yasl_private_display_dispatch(NULL, 0) == -1 && errno == EINVAL); d.ops = &ops; errno = ERANGE; - assert(yasl_display_dispatch(&d, 0) == -1 && errno == EIO); - struct yasl_window_spec toplevel = {.size = {120, 80}}; + assert(yasl_private_display_dispatch(&d, 0) == -1 && errno == EIO); + struct yasl_private_window_spec toplevel = {.size = {120, 80}}; errno = ERANGE; - assert(!yasl_surface_create_toplevel(&d, &toplevel) && errno == ENODEV); - assert(yasl_display_drag_start(&d, &s, NULL, NULL, NULL)); - struct yasl_drag_image image = {.size = {1, 1}}; - assert(!yasl_display_drag_start(&d, &s, &image, NULL, NULL)); + assert(!yasl_private_surface_create_toplevel(&d, &toplevel) && errno == ENODEV); + assert(yasl_private_display_drag_start(&d, &s, NULL, NULL, NULL)); + struct yasl_private_drag_image image = {.size = {1, 1}}; + assert(!yasl_private_display_drag_start(&d, &s, &image, NULL, NULL)); uint32_t pixel = 0; image.pixels = &pixel; image.size.x = INT_MAX; - assert(!yasl_display_drag_start(&d, &s, &image, NULL, NULL)); + assert(!yasl_private_display_drag_start(&d, &s, &image, NULL, NULL)); assert(drag_starts == 1); } diff --git a/tests/common/test_desktop.c b/tests/common/test_desktop.c index 89760fe..a665da5 100644 --- a/tests/common/test_desktop.c +++ b/tests/common/test_desktop.c @@ -1,7 +1,7 @@ #define _GNU_SOURCE #include "common/backend.h" #include "platform/freedesktop/dbus.h" -#include "yasl/desktop.h" +#include "common/private_desktop.h" #include <assert.h> #include <fcntl.h> @@ -39,31 +39,31 @@ static char *read_file(const char *path) static void test_buffers(void) { char exe[PATH_MAX], real[PATH_MAX]; - size_t len = yasl_executable_path(NULL, 0); + size_t len = yasl_private_executable_path(NULL, 0); assert(len > 0); - assert(yasl_executable_path(exe, len) == len); - assert(yasl_executable_path(exe, sizeof(exe)) == len && exe[len] == '\0'); + assert(yasl_private_executable_path(exe, len) == len); + assert(yasl_private_executable_path(exe, sizeof(exe)) == len && exe[len] == '\0'); assert(realpath("/proc/self/exe", real) && strcmp(exe, real) == 0); /* A short buffer stays untouched. */ char small[4] = "abc"; - assert(yasl_executable_path(small, sizeof(small)) == len); + assert(yasl_private_executable_path(small, sizeof(small)) == len); assert(strcmp(small, "abc") == 0); - assert(yasl_executable_path(NULL, 8) == 0); + assert(yasl_private_executable_path(NULL, 8) == 0); - assert(yasl_resource_dir(exe, sizeof(exe)) == 0); + assert(yasl_private_resource_dir(exe, sizeof(exe)) == 0); char locale[64]; setenv("LC_ALL", "", 1); setenv("LC_CTYPE", "de_DE.UTF-8", 1); setenv("LANG", "fr_FR.UTF-8", 1); - assert(yasl_default_locale(locale, sizeof(locale)) == 11); + assert(yasl_private_default_locale(locale, sizeof(locale)) == 11); assert(strcmp(locale, "de_DE.UTF-8") == 0); unsetenv("LC_CTYPE"); - assert(yasl_default_locale(locale, sizeof(locale)) == 11); + assert(yasl_private_default_locale(locale, sizeof(locale)) == 11); assert(strcmp(locale, "fr_FR.UTF-8") == 0); unsetenv("LANG"); unsetenv("LC_ALL"); - assert(yasl_default_locale(locale, sizeof(locale)) == 7); + assert(yasl_private_default_locale(locale, sizeof(locale)) == 7); assert(strcmp(locale, "C.UTF-8") == 0); } @@ -86,14 +86,14 @@ static void test_open_uri(const char *dir) snprintf(path, sizeof(path), "%s:%s", dir, old_path ? old_path : "/usr/bin:/bin"); setenv("PATH", path, 1); - struct yasl_display display = {0}; - assert(!yasl_display_open_uri(NULL, "https://example.com")); - assert(!yasl_display_open_uri(&display, NULL)); - assert(!yasl_display_open_uri(&display, "")); - assert(!yasl_display_open_uri(&display, "example.com")); - assert(!yasl_display_open_uri(&display, "-x:option")); - assert(!yasl_display_open_uri(&display, "1http://example.com")); - assert(!yasl_display_open_uri(&display, "http://example.com/\n")); + struct yasl_private_display display = {0}; + assert(!yasl_private_display_open_uri(NULL, "https://example.com")); + assert(!yasl_private_display_open_uri(&display, NULL)); + assert(!yasl_private_display_open_uri(&display, "")); + assert(!yasl_private_display_open_uri(&display, "example.com")); + assert(!yasl_private_display_open_uri(&display, "-x:option")); + assert(!yasl_private_display_open_uri(&display, "1http://example.com")); + assert(!yasl_private_display_open_uri(&display, "http://example.com/\n")); assert(access(out, F_OK) != 0); /* The opener must not inherit blocked or ignored signals or descriptors. */ @@ -110,7 +110,7 @@ static void test_open_uri(const char *dir) close(null); const char *uri = "https://example.com/a b?c='d'&e=\"f\""; - assert(yasl_display_open_uri(&display, uri)); + assert(yasl_private_display_open_uri(&display, uri)); char *text = NULL; for (int i = 0; i < 500 && !(text = read_file(out)); i++) sleep_ms(10); assert(text); @@ -137,29 +137,29 @@ static void test_open_uri(const char *dir) /* Without xdg-open in PATH, nothing launches. */ setenv("PATH", dir, 1); - assert(!yasl_display_open_uri(&display, "https://example.com")); + assert(!yasl_private_display_open_uri(&display, "https://example.com")); if (old_path) setenv("PATH", old_path, 1); } static void test_appearance_fallback(void) { - assert(yasl_display_double_click_ms(NULL) == YASL_DOUBLE_CLICK_MS_DEFAULT); + assert(yasl_private_display_double_click_ms(NULL) == YASL_PRIVATE_DOUBLE_CLICK_MS_DEFAULT); assert(portal_double_click_ms() == 0); - struct yasl_display display = {0}; - assert(yasl_display_appearance(NULL) == 0); + struct yasl_private_display display = {0}; + assert(yasl_private_display_appearance(NULL) == 0); unsetenv("GTK_THEME"); - assert(yasl_display_appearance(&display) == 0); + assert(yasl_private_display_appearance(&display) == 0); setenv("GTK_THEME", "Adwaita:dark", 1); - assert(yasl_display_appearance(&display) == YASL_APPEARANCE_DARK); + assert(yasl_private_display_appearance(&display) == YASL_PRIVATE_APPEARANCE_DARK); setenv("GTK_THEME", "HighContrast", 1); - assert(yasl_display_appearance(&display) == YASL_APPEARANCE_HIGH_CONTRAST); + assert(yasl_private_display_appearance(&display) == YASL_PRIVATE_APPEARANCE_HIGH_CONTRAST); setenv("GTK_THEME", "HighContrastInverse", 1); - assert(yasl_display_appearance(&display) == - (YASL_APPEARANCE_HIGH_CONTRAST | YASL_APPEARANCE_DARK)); + assert(yasl_private_display_appearance(&display) == + (YASL_PRIVATE_APPEARANCE_HIGH_CONTRAST | YASL_PRIVATE_APPEARANCE_DARK)); unsetenv("GTK_THEME"); - assert(!yasl_display_notify(NULL, "title", "body")); - assert(!yasl_display_notify(&display, NULL, "body")); - assert(!yasl_display_notify(&display, "title", "body")); + assert(!yasl_private_display_notify(NULL, "title", "body")); + assert(!yasl_private_display_notify(&display, NULL, "body")); + assert(!yasl_private_display_notify(&display, "title", "body")); } #if YASL_HAS_DBUS @@ -310,8 +310,8 @@ static void test_bus(const char *address) pthread_t thread; assert(pthread_create(&thread, NULL, serve, &fb) == 0); - struct yasl_display display = {.app_id = "org.example.Test"}; - assert(yasl_display_notify(&display, "Build done", NULL)); + struct yasl_private_display display = {.app_id = "org.example.Test"}; + assert(yasl_private_display_notify(&display, "Build done", NULL)); for (int i = 0; i < 500; i++) { pthread_mutex_lock(&fb.lock); int n = fb.notifications; @@ -328,10 +328,10 @@ static void test_bus(const char *address) /* Portal settings win over GTK_THEME, through ReadOne or the older Read. */ setenv("GTK_THEME", "Adwaita", 1); - uint32_t want = YASL_APPEARANCE_DARK | YASL_APPEARANCE_HIGH_CONTRAST; - assert(yasl_display_appearance(&display) == want); + uint32_t want = YASL_PRIVATE_APPEARANCE_DARK | YASL_PRIVATE_APPEARANCE_HIGH_CONTRAST; + assert(yasl_private_display_appearance(&display) == want); fb.read_one = false; - assert(yasl_display_appearance(&display) == want); + assert(yasl_private_display_appearance(&display) == want); unsetenv("GTK_THEME"); /* A KDE value, sent as a string, wins over the GNOME key. */ diff --git a/tests/common/test_events.c b/tests/common/test_events.c index c8660cb..fcfc118 100644 --- a/tests/common/test_events.c +++ b/tests/common/test_events.c @@ -1,5 +1,4 @@ #include "common/backend.h" -#include "yasl/app.h" #include <assert.h> #include <errno.h> @@ -8,7 +7,7 @@ #include <string.h> static struct input_queue *queue(struct yasl_surface *s) { return &s->input; } -static const struct yasl_backend_ops ops = {.surface_input_queue = queue}; +static const struct yasl_private_backend_ops ops = {.surface_input_queue = queue}; static int released; static pthread_t owner; static void release(void *payload) @@ -18,90 +17,90 @@ static void release(void *payload) released++; } -static void setup(struct yasl_display *d, struct yasl_surface *a, struct yasl_surface *b) +static void setup(struct yasl_private_display *d, struct yasl_surface *a, struct yasl_surface *b) { - *d = (struct yasl_display){.ops = &ops}; + *d = (struct yasl_private_display){.ops = &ops}; *a = (struct yasl_surface){.display = d, .scale_120 = 120}; *b = (struct yasl_surface){.display = d, .scale_120 = 120}; - assert(yasl_events_open(d)); - assert(yasl_events_register(a)); - assert(yasl_events_register(b)); + assert(yasl_private_events_open(d)); + assert(yasl_private_events_register(a)); + assert(yasl_private_events_register(b)); } -static void teardown(struct yasl_display *d, struct yasl_surface *a, struct yasl_surface *b) +static void teardown(struct yasl_private_display *d, struct yasl_surface *a, struct yasl_surface *b) { - yasl_events_unregister(a); - yasl_events_unregister(b); + yasl_private_events_unregister(a); + yasl_private_events_unregister(b); input_queue_clear(&a->input); input_queue_clear(&b->input); - yasl_events_close(d); + yasl_private_events_close(d); } static void test_order_and_lifetimes(void) { - struct yasl_display d; + struct yasl_private_display d; struct yasl_surface a, b; setup(&d, &a, &b); - uint64_t aid = yasl_surface_id(&a), bid = yasl_surface_id(&b); + uint64_t aid = yasl_private_surface_id(&a), bid = yasl_private_surface_id(&b); assert(aid && bid && aid != bid); - yasl_surface_set_userdata(&a, &b); - assert(yasl_surface_userdata(&a) == &b); + yasl_private_surface_set_userdata(&a, &b); + assert(yasl_private_surface_userdata(&a) == &b); char text[] = "text"; - assert(input_queue_push(&a.input, &(struct yasl_event){ - .type = YASL_EVENT_TEXT, .surface = &a, .text = {text, 4}})); + assert(input_queue_push(&a.input, &(struct yasl_private_event){ + .type = YASL_PRIVATE_EVENT_TEXT, .surface = &a, .text = {text, 4}})); memset(text, 'x', 4); - yasl_surface_notify_state(&b, YASL_STATE_MAXIMIZED); - yasl_surface_notify_configure(&a, (struct yasl_geometry){{640, 480}, 180}); - yasl_surface_notify_drag(&b, YASL_DRAG_OVER, (struct yasl_vector2i){3, 4}); - yasl_surface_notify_composition(&a, "hello", 1, 3); - yasl_surface_notify_composition(&a, NULL, -1, -1); - yasl_surface_complete_paste(&b, 42, YASL_TRANSFER_UNAVAILABLE, NULL, 0); - const enum yasl_event_type expected[] = {YASL_EVENT_TEXT, YASL_EVENT_WINDOW_STATE, - YASL_EVENT_WINDOW_RESIZE, YASL_EVENT_DRAG, YASL_EVENT_COMPOSITION, - YASL_EVENT_COMPOSITION, YASL_EVENT_PASTE}; - struct yasl_event ev; + yasl_private_surface_notify_state(&b, YASL_PRIVATE_STATE_MAXIMIZED); + yasl_private_surface_notify_configure(&a, (struct yasl_private_geometry){{640, 480}, 180}); + yasl_private_surface_notify_drag(&b, YASL_PRIVATE_DRAG_OVER, (struct yasl_private_vector2i){3, 4}); + yasl_private_surface_notify_composition(&a, "hello", 1, 3); + yasl_private_surface_notify_composition(&a, NULL, -1, -1); + yasl_private_surface_complete_paste(&b, 42, YASL_PRIVATE_TRANSFER_UNAVAILABLE, NULL, 0); + const enum yasl_private_event_type expected[] = {YASL_PRIVATE_EVENT_TEXT, YASL_PRIVATE_EVENT_WINDOW_STATE, + YASL_PRIVATE_EVENT_WINDOW_RESIZE, YASL_PRIVATE_EVENT_DRAG, YASL_PRIVATE_EVENT_COMPOSITION, + YASL_PRIVATE_EVENT_COMPOSITION, YASL_PRIVATE_EVENT_PASTE}; + struct yasl_private_event ev; uint64_t sequence = 0; for (size_t i = 0; i < sizeof(expected) / sizeof(*expected); i++) { - assert(yasl_display_poll_event(&d, &ev)); + assert(yasl_private_display_poll_event(&d, &ev)); assert(ev.type == expected[i] && ev.sequence > sequence && ev.time_ns); sequence = ev.sequence; if (i == 0) assert(!strcmp(ev.text.data, "text") && ev.surface_id == aid); if (i == 2) assert(ev.resize.scale_changed && ev.resize.geometry.size.x == 640); if (i == 4) assert(ev.composition.active && ev.composition.begin == 1 && !strcmp(ev.composition.data, "hello")); if (i == 5) assert(!ev.composition.active && !ev.composition.len); - if (i == 6) assert(ev.paste.request_id == 42 && ev.paste.status == YASL_TRANSFER_UNAVAILABLE); + if (i == 6) assert(ev.paste.request_id == 42 && ev.paste.status == YASL_PRIVATE_TRANSFER_UNAVAILABLE); } - assert(!yasl_display_poll_event(&d, &ev)); - assert(input_queue_push(&a.input, &(struct yasl_event){ - .type = YASL_EVENT_TEXT, .surface = &a, .text = {"kept", 4}})); - assert(yasl_display_poll_event(&d, &ev)); + assert(!yasl_private_display_poll_event(&d, &ev)); + assert(input_queue_push(&a.input, &(struct yasl_private_event){ + .type = YASL_PRIVATE_EVENT_TEXT, .surface = &a, .text = {"kept", 4}})); + assert(yasl_private_display_poll_event(&d, &ev)); const char *borrowed = ev.text.data; - assert(input_queue_push(&a.input, &(struct yasl_event){.type = YASL_EVENT_KEY, .surface = &a})); - yasl_events_unregister(&a); + assert(input_queue_push(&a.input, &(struct yasl_private_event){.type = YASL_PRIVATE_EVENT_KEY, .surface = &a})); + yasl_private_events_unregister(&a); assert(!strcmp(borrowed, "kept")); - assert(!yasl_display_poll_event(&d, &ev)); + assert(!yasl_private_display_poll_event(&d, &ev)); /* Reusing object memory must never reuse the identity. */ - assert(yasl_events_register(&a)); + assert(yasl_private_events_register(&a)); assert(a.id != aid); errno = 0; - assert(!yasl_display_post(&d, &(struct yasl_message){.target_id = aid})); + assert(!yasl_private_display_post(&d, &(struct yasl_private_message){.target_id = aid})); assert(errno == ENOENT); teardown(&d, &a, &b); } -struct producer { struct yasl_display *display; uint64_t target; }; +struct producer { struct yasl_private_display *display; uint64_t target; }; static void *post_worker(void *ud) { struct producer *producer = ud; for (uint32_t i = 0; i < 32; i++) - assert(yasl_display_post(producer->display, &(struct yasl_message){ + assert(yasl_private_display_post(producer->display, &(struct yasl_private_message){ .target_id = producer->target, .code = i, .payload = &released, .release = release})); return NULL; } static void test_post_cleanup(void) { - struct yasl_display d; + struct yasl_private_display d; struct yasl_surface a, b; setup(&d, &a, &b); owner = pthread_self(); @@ -110,26 +109,26 @@ static void test_post_cleanup(void) struct producer producer = {&d, a.id}; assert(!pthread_create(&worker, NULL, post_worker, &producer)); assert(!pthread_join(worker, NULL)); - struct yasl_event ev; + struct yasl_private_event ev; for (uint32_t i = 0; i < 8; i++) { - assert(yasl_display_poll_event(&d, &ev)); + assert(yasl_private_display_poll_event(&d, &ev)); assert(ev.user.code == i && ev.surface == &a); } assert(released == 7); /* Last event remains borrowed. */ - yasl_events_unregister(&a); + yasl_private_events_unregister(&a); assert(released == 31); /* Undelivered target messages canceled. */ - assert(!yasl_display_poll_event(&d, &ev)); - assert(yasl_display_post(&d, &(struct yasl_message){.payload = &released, .release = release})); - yasl_events_close(&d); + assert(!yasl_private_display_poll_event(&d, &ev)); + assert(yasl_private_display_post(&d, &(struct yasl_private_message){.payload = &released, .release = release})); + yasl_private_events_close(&d); assert(released == 33); /* Pending message and last consumed message. */ errno = 0; - assert(!yasl_display_post(&d, &(struct yasl_message){.payload = &released, .release = release})); + assert(!yasl_private_display_post(&d, &(struct yasl_private_message){.payload = &released, .release = release})); assert(errno == EINVAL && released == 33); } static int damage_count; -static bool present(struct yasl_surface *s, const struct yasl_framebuffer *target, - const struct yasl_damage_list *damage) +static bool present(struct yasl_surface *s, const struct yasl_private_framebuffer *target, + const struct yasl_private_damage_list *damage) { (void)s; (void)target; damage_count = damage->n; @@ -137,64 +136,64 @@ static bool present(struct yasl_surface *s, const struct yasl_framebuffer *targe } static void test_damage(void) { - struct yasl_backend_ops present_ops = {.surface_present = present}; - struct yasl_display d = {.ops = &present_ops}; + struct yasl_private_backend_ops present_ops = {.surface_present = present}; + struct yasl_private_display d = {.ops = &present_ops}; struct yasl_surface s = {.display = &d, .frame_generation = 1, .drawing = true}; - struct yasl_frame frame = {.surface = &s, .target = {.generation = 1, .size = {8, 8}}}; + struct yasl_private_frame frame = {.surface = &s, .target = {.generation = 1, .size = {8, 8}}}; s.active_frame = &frame; - struct yasl_rect2i rects[YASL_DAMAGE_MAX + 1] = {{0}}; - assert(yasl_frame_present(&frame, NULL, 0) && damage_count == -1); - assert(!yasl_frame_present(&frame, NULL, 0) && errno == EALREADY); + struct yasl_private_rect2i rects[YASL_PRIVATE_DAMAGE_MAX + 1] = {{0}}; + assert(yasl_private_frame_present(&frame, NULL, 0) && damage_count == -1); + assert(!yasl_private_frame_present(&frame, NULL, 0) && errno == EALREADY); s.frame_presented = false; - assert(yasl_frame_present(&frame, rects, 0) && damage_count == 0); + assert(yasl_private_frame_present(&frame, rects, 0) && damage_count == 0); s.frame_presented = false; - assert(yasl_frame_present(&frame, rects, YASL_DAMAGE_MAX + 1) && damage_count == -1); + assert(yasl_private_frame_present(&frame, rects, YASL_PRIVATE_DAMAGE_MAX + 1) && damage_count == -1); s.frame_presented = false; - rects[YASL_DAMAGE_MAX].width = -1; + rects[YASL_PRIVATE_DAMAGE_MAX].width = -1; errno = 0; - assert(!yasl_frame_present(&frame, rects, YASL_DAMAGE_MAX + 1) && errno == EINVAL); - assert(!yasl_frame_present(&frame, NULL, 1)); + assert(!yasl_private_frame_present(&frame, rects, YASL_PRIVATE_DAMAGE_MAX + 1) && errno == EINVAL); + assert(!yasl_private_frame_present(&frame, NULL, 1)); s.drawing = false; - assert(!yasl_frame_present(&frame, NULL, 0)); + assert(!yasl_private_frame_present(&frame, NULL, 0)); } static void test_failures(void) { - struct yasl_display d; + struct yasl_private_display d; struct yasl_surface a, b; setup(&d, &a, &b); - assert(!yasl_surface_set_size(&a, (struct yasl_vector2i){0, 10}) && errno == EINVAL); - assert(!yasl_surface_set_size(&a, (struct yasl_vector2i){10, 10}) && errno == ENOTSUP); - assert(!yasl_surface_set_fullscreen(&a, true) && errno == ENOTSUP); - assert(!yasl_surface_set_maximized(&a, true) && errno == ENOTSUP); - assert(!yasl_surface_minimize(&a) && errno == ENOTSUP); + assert(!yasl_private_surface_set_size(&a, (struct yasl_private_vector2i){0, 10}) && errno == EINVAL); + assert(!yasl_private_surface_set_size(&a, (struct yasl_private_vector2i){10, 10}) && errno == ENOTSUP); + assert(!yasl_private_surface_set_fullscreen(&a, true) && errno == ENOTSUP); + assert(!yasl_private_surface_set_maximized(&a, true) && errno == ENOTSUP); + assert(!yasl_private_surface_minimize(&a) && errno == ENOTSUP); a.popup = true; - assert(!yasl_surface_minimize(&a) && errno == EINVAL); - assert(!yasl_clipboard_set(&d, YASL_CLIPBOARD, "text") && errno == ENOTSUP); - assert(!yasl_clipboard_request(&a, YASL_CLIPBOARD) && errno == ENOTSUP); + assert(!yasl_private_surface_minimize(&a) && errno == EINVAL); + assert(!yasl_private_clipboard_set(&d, YASL_PRIVATE_CLIPBOARD, "text") && errno == ENOTSUP); + assert(!yasl_private_clipboard_request(&a, YASL_PRIVATE_CLIPBOARD) && errno == ENOTSUP); /* Queued native event allocation/validation failure must be observable. */ - assert(!yasl_events_push(&d, &a, &(struct yasl_event){ - .type = YASL_EVENT_TEXT, .surface = &a, .text = {"x", SIZE_MAX}})); - assert(yasl_events_error(&d) == ENOMEM); + assert(!yasl_private_events_push(&d, &a, &(struct yasl_private_event){ + .type = YASL_PRIVATE_EVENT_TEXT, .surface = &a, .text = {"x", SIZE_MAX}})); + assert(yasl_private_events_error(&d) == ENOMEM); teardown(&d, &a, &b); } static void test_legacy_poll_does_not_spin(void) { - struct yasl_display d; + struct yasl_private_display d; struct yasl_surface a, b; setup(&d, &a, &b); - yasl_surface_notify_state(&a, YASL_STATE_ACTIVATED); - yasl_surface_notify_close(&b); - assert(yasl_events_pending(&d)); - struct yasl_event ev; - assert(!yasl_surface_poll_event(&a, &ev)); - assert(!yasl_events_pending(&d)); - assert(input_queue_push(&b.input, &(struct yasl_event){.type = YASL_EVENT_KEY, .surface = &b})); - assert(!yasl_surface_poll_event(&a, &ev)); - assert(yasl_surface_poll_event(&b, &ev) && ev.surface == &b); - assert(!yasl_events_pending(&d)); + yasl_private_surface_notify_state(&a, YASL_PRIVATE_STATE_ACTIVATED); + yasl_private_surface_notify_close(&b); + assert(yasl_private_events_pending(&d)); + struct yasl_private_event ev; + assert(!yasl_private_surface_poll_event(&a, &ev)); + assert(!yasl_private_events_pending(&d)); + assert(input_queue_push(&b.input, &(struct yasl_private_event){.type = YASL_PRIVATE_EVENT_KEY, .surface = &b})); + assert(!yasl_private_surface_poll_event(&a, &ev)); + assert(yasl_private_surface_poll_event(&b, &ev) && ev.surface == &b); + assert(!yasl_private_events_pending(&d)); teardown(&d, &a, &b); } diff --git a/tests/common/test_gl.c b/tests/common/test_gl.c new file mode 100644 index 0000000..cd51575 --- /dev/null +++ b/tests/common/test_gl.c @@ -0,0 +1,158 @@ +#define _POSIX_C_SOURCE 200809L +#include <yasl/gl.h> + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +typedef const unsigned char *(*get_string_fn)(unsigned); +typedef void (*clear_color_fn)(float, float, float, float); +typedef void (*clear_fn)(unsigned); +typedef void (*finish_fn)(void); +typedef void (*read_pixels_fn)(int, int, int, int, unsigned, unsigned, void *); +typedef void (*gen_textures_fn)(int, unsigned *); +typedef void (*bind_texture_fn)(unsigned, unsigned); +typedef unsigned char (*is_texture_fn)(unsigned); +typedef void (*delete_textures_fn)(int, const unsigned *); + +enum { GL_VERSION_ = 0x1f02, GL_COLOR_BUFFER_BIT_ = 0x00004000, + GL_RGBA_ = 0x1908, GL_UNSIGNED_BYTE_ = 0x1401, GL_TEXTURE_2D_ = 0x0de1 }; + +static yasl_surface *primary; +static yasl_surface *shared; +static yasl_surface *cpu; + +static void fail(const char *message, int line) +{ + const char *description = NULL; + enum yasl_error error = yasl_get_error(&description); + fprintf(stderr, "GL integration failure at line %d: %s (YASL error %d: %s, native error %d)\n", + line, message, error, description ? description : "none", yasl_get_native_error()); + (void)yasl_gl_make_current(NULL); + if (cpu) yasl_surface_destroy(cpu); + if (shared) yasl_surface_destroy(shared); + if (primary) yasl_surface_destroy(primary); + yasl_shutdown(); + exit(1); +} + +#define REQUIRE(condition, message) do { if (!(condition)) fail((message), __LINE__); } while (0) + +#define LOAD_GL(function, type, symbol) do { \ + union { yasl_gl_proc generic; type typed; } conversion; \ + conversion.generic = yasl_gl_get_proc_address(symbol); \ + REQUIRE(conversion.generic != NULL, "missing OpenGL function " symbol); \ + function = conversion.typed; \ +} while (0) + +static double seconds_now(void) +{ + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) return 0; + return (double)ts.tv_sec + (double)ts.tv_nsec / 1e9; +} + +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); + if (actual_width == width && actual_height == height) return; + yasl_event event = {0}; + int result = yasl_wait_event(&event, 50); + REQUIRE(result >= 0, "waiting for configure event"); + } + char message[128]; + snprintf(message, sizeof(message), "resize did not settle at %dx%d (got %dx%d)", + width, height, actual_width, actual_height); + fail(message, __LINE__); +} + +int main(int argc, char **argv) +{ + REQUIRE(argc == 2, "expected backend argument: wayland or x11"); + if (!strcmp(argv[1], "wayland")) REQUIRE(yasl_set_backend(YASL_BACKEND_WAYLAND), "select Wayland backend"); + else if (!strcmp(argv[1], "x11")) REQUIRE(yasl_set_backend(YASL_BACKEND_X11), "select X11 backend"); + else REQUIRE(false, "backend must be wayland or x11"); + + primary = yasl_gl_surface_create("YASL GL test", 320, 240, 0, NULL, NULL); + REQUIRE(primary != NULL, "create default OpenGL 3.2 surface"); + REQUIRE(yasl_gl_make_current(primary), "make first GL context current"); + + get_string_fn get_string = NULL; + clear_color_fn clear_color = NULL; + clear_fn clear = NULL; + finish_fn finish = NULL; + read_pixels_fn read_pixels = NULL; + gen_textures_fn gen_textures = NULL; + bind_texture_fn bind_texture = NULL; + is_texture_fn is_texture = NULL; + delete_textures_fn delete_textures = NULL; + LOAD_GL(get_string, get_string_fn, "glGetString"); + LOAD_GL(clear_color, clear_color_fn, "glClearColor"); + LOAD_GL(clear, clear_fn, "glClear"); + LOAD_GL(finish, finish_fn, "glFinish"); + LOAD_GL(read_pixels, read_pixels_fn, "glReadPixels"); + LOAD_GL(gen_textures, gen_textures_fn, "glGenTextures"); + LOAD_GL(bind_texture, bind_texture_fn, "glBindTexture"); + LOAD_GL(is_texture, is_texture_fn, "glIsTexture"); + LOAD_GL(delete_textures, delete_textures_fn, "glDeleteTextures"); + const unsigned char *version = get_string(GL_VERSION_); + REQUIRE(version && version[0], "query GL version string"); + + clear_color(0.2f, 0.4f, 0.8f, 1.0f); + clear(GL_COLOR_BUFFER_BIT_); + finish(); + unsigned char pixel[4] = {0}; + int pixel_width = 0, pixel_height = 0; + yasl_surface_get_framebuffer_size(primary, &pixel_width, &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 && + abs((int)pixel[2] - 204) <= 3 && pixel[3] >= 250, + "read rendered pixel from the native GL framebuffer"); + REQUIRE(yasl_gl_swap_interval(primary, 0), "disable swap interval"); + REQUIRE(yasl_gl_swap_buffers(primary), "swap first GL surface"); + + unsigned texture = 0; + gen_textures(1, &texture); + bind_texture(GL_TEXTURE_2D_, texture); + REQUIRE(is_texture(texture), "create a shareable GL texture"); + + shared = yasl_gl_surface_create("YASL GL shared context", 160, 120, 0, NULL, primary); + REQUIRE(shared != NULL, "create shared GL context"); + REQUIRE(yasl_gl_make_current(shared), "make shared context current"); + REQUIRE(is_texture(texture), "verify context shares GL objects"); + delete_textures(1, &texture); + REQUIRE(yasl_gl_make_current(primary), "restore primary GL context"); + + REQUIRE(yasl_surface_request_size(primary, 400, 300), "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); + REQUIRE(abs(pixel_width - (int)lround(400 * scale)) <= 1 && + abs(pixel_height - (int)lround(300 * scale)) <= 1, + "query resized framebuffer dimensions"); + clear_color(0.7f, 0.1f, 0.3f, 1.0f); + clear(GL_COLOR_BUFFER_BIT_); + REQUIRE(yasl_gl_swap_buffers(primary), "swap resized GL surface"); + + const int invalid_attributes[] = {0x7fff, 1, YASL_GL_END}; + REQUIRE(yasl_gl_surface_create("invalid attrs", 100, 100, 0, invalid_attributes, NULL) == NULL, + "reject unknown GL context attributes"); + REQUIRE(yasl_gl_surface_create("invalid CPU GL", 100, 100, YASL_SURFACE_CPU, NULL, NULL) == NULL, + "reject CPU flag on GL surface creation"); + cpu = yasl_surface_create("CPU surface", 100, 100, YASL_SURFACE_CPU); + REQUIRE(cpu != NULL, "create CPU surface for incompatibility check"); + REQUIRE(!yasl_gl_make_current(cpu), "reject CPU surface as a GL context"); + + REQUIRE(yasl_gl_make_current(NULL), "detach GL context before destruction"); + yasl_surface_destroy(cpu); cpu = NULL; + yasl_surface_destroy(shared); shared = NULL; + yasl_surface_destroy(primary); primary = NULL; + yasl_shutdown(); + return 0; +} diff --git a/tests/common/test_gl_options.c b/tests/common/test_gl_options.c new file mode 100644 index 0000000..4bcd521 --- /dev/null +++ b/tests/common/test_gl_options.c @@ -0,0 +1,16 @@ +#include "common/gl_options.h" +#include <assert.h> +#include <stddef.h> +#include <errno.h> +int main(void) +{ + struct yasl_private_gl_options o; + assert(yasl_private_gl_parse_options(NULL,&o));assert(o.major==3&&o.minor==2&&o.red_bits==8); + const int es[]={YASL_PRIVATE_GL_API,YASL_PRIVATE_GL_OPENGL_ES,YASL_PRIVATE_GL_MAJOR,3,YASL_PRIVATE_GL_MINOR,0,YASL_PRIVATE_GL_END}; + assert(yasl_private_gl_parse_options(es,&o)&&o.api==YASL_PRIVATE_GL_OPENGL_ES&&o.minor==0); + const int invalid[]={99,0,YASL_PRIVATE_GL_END}; + assert(!yasl_private_gl_parse_options(invalid,&o)&&errno==EINVAL); + const int negative[]={YASL_PRIVATE_GL_DEPTH_BITS,-1,YASL_PRIVATE_GL_END}; + assert(!yasl_private_gl_parse_options(negative,&o)); + return 0; +} diff --git a/tests/common/test_hello_example.c b/tests/common/test_hello_example.c deleted file mode 100644 index 350b3bb..0000000 --- a/tests/common/test_hello_example.c +++ /dev/null @@ -1,20 +0,0 @@ -/* Exercise hello's real frame callback; automated exit belongs in the test. */ -#define main hello_example_main -#include "../../examples/hello.c" -#undef main - -static void draw_once(void *ud, struct yasl_surface *surface, struct yasl_frame *frame) -{ - draw(ud, surface, frame); - if (!failed) yasl_surface_destroy(surface); -} - -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, - .frame = draw_once, - }; - return yasl_run(&desc) || failed ? 1 : 0; -} diff --git a/tests/common/test_input_alloc.c b/tests/common/test_input_alloc.c index 7aba4b2..12e7656 100644 --- a/tests/common/test_input_alloc.c +++ b/tests/common/test_input_alloc.c @@ -5,7 +5,7 @@ /* This executable compiles input.c with malloc redirected here. */ static int allocations = -1; -void *yasl_test_malloc(size_t bytes) +void *yasl_private_test_malloc(size_t bytes) { if (allocations == 0) return NULL; if (allocations > 0) allocations--; @@ -13,19 +13,19 @@ void *yasl_test_malloc(size_t bytes) } /* input.c timestamps events, but this executable links no event loop. */ -uint64_t yasl_loop_now_ns(void) { return 1; } +uint64_t yasl_private_loop_now_ns(void) { return 1; } int main(void) { struct yasl_surface *surface = (struct yasl_surface *)(uintptr_t)1; for (int failure = 0; failure < 2; failure++) { struct input_queue q = {0}; - struct yasl_event in = {.surface = surface, .type = YASL_EVENT_PASTE, + struct yasl_private_event in = {.surface = surface, .type = YASL_PRIVATE_EVENT_PASTE, .text = {"payload", 7}}, out; /* Fail either payload allocation or the initial event-array allocation. */ allocations = failure; assert(!input_queue_push(&q, &in)); - assert(input_queue_pop(&q, &out) && out.type == YASL_EVENT_INPUT_RESET); + assert(input_queue_pop(&q, &out) && out.type == YASL_PRIVATE_EVENT_INPUT_RESET); assert(out.surface == surface); assert(!input_queue_pop(&q, &out)); input_queue_clear(&q); @@ -40,15 +40,15 @@ int main(void) assert(strcmp(last, "payload") == 0); assert(!q.count && q.reset_pending); allocations = -1; - in = (struct yasl_event){.surface = surface, .type = YASL_EVENT_KEY, + in = (struct yasl_private_event){.surface = surface, .type = YASL_PRIVATE_EVENT_KEY, .key.action = YASL_KEY_RELEASE}; assert(input_queue_push(&q, &in)); - assert(input_queue_pop(&q, &out) && out.type == YASL_EVENT_INPUT_RESET); + assert(input_queue_pop(&q, &out) && out.type == YASL_PRIVATE_EVENT_INPUT_RESET); assert(input_queue_pop(&q, &out) && out.key.action == YASL_KEY_RELEASE); input_queue_clear(&q); /* A lost event clears held buttons along with the stream. */ - in = (struct yasl_event){.surface = surface, .type = YASL_EVENT_POINTER_DOWN}; + in = (struct yasl_private_event){.surface = surface, .type = YASL_PRIVATE_EVENT_POINTER_DOWN}; assert(input_queue_push(&q, &in) && q.buttons); for (size_t i = 1; i < q.capacity; i++) assert(input_queue_push(&q, &in)); allocations = 0; diff --git a/tests/common/test_keyboard.c b/tests/common/test_keyboard.c index f2fc8f2..7406c1d 100644 --- a/tests/common/test_keyboard.c +++ b/tests/common/test_keyboard.c @@ -9,27 +9,27 @@ int main(void) { /* Same physical positions across native encodings, including keypad and * left/right modifiers. macOS A is code zero, which is not UNKNOWN. */ - assert(yasl_key_from_evdev(30) == YASL_KEY_A); - assert(yasl_key_from_cocoa(kVK_ANSI_A) == YASL_KEY_A); - assert(yasl_key_from_xkb_name("AC01") == YASL_KEY_A); - assert(yasl_key_from_evdev(1) == YASL_KEY_ESCAPE); - assert(yasl_key_from_cocoa(kVK_Escape) == YASL_KEY_ESCAPE); - assert(yasl_key_from_xkb_name("ESC\0") == YASL_KEY_ESCAPE); - assert(yasl_key_from_evdev(96) == YASL_KEY_KP_ENTER); - assert(yasl_key_from_cocoa(kVK_ANSI_KeypadEnter) == YASL_KEY_KP_ENTER); - assert(yasl_key_from_cocoa(kVK_Return) == YASL_KEY_ENTER); - assert(yasl_key_from_evdev(100) == YASL_KEY_RIGHT_ALT); - assert(yasl_key_from_cocoa(kVK_RightOption) == YASL_KEY_RIGHT_ALT); - assert(yasl_key_from_evdev(42) == YASL_KEY_LEFT_SHIFT); - assert(yasl_key_from_cocoa(kVK_Shift) == YASL_KEY_LEFT_SHIFT); - assert(yasl_key_from_evdev(86) == YASL_KEY_ISO_BACKSLASH); - assert(yasl_key_from_cocoa(kVK_ISO_Section) == YASL_KEY_ISO_BACKSLASH); - assert(yasl_key_from_evdev(0) == YASL_KEY_UNKNOWN); - assert(yasl_key_from_evdev(UINT32_MAX) == YASL_KEY_UNKNOWN); - assert(yasl_key_from_cocoa(UINT32_MAX) == YASL_KEY_UNKNOWN); - assert(yasl_key_from_xkb_name("ZZZZ") == YASL_KEY_UNKNOWN); - assert(yasl_key_label(0x1f600) == 0x1f600); - assert(yasl_key_label(0xd800) == 0 && yasl_key_label(0x110000) == 0); - assert(yasl_key_label(0xf700) == 0 && yasl_key_label('\t') == 0); + assert(yasl_private_key_from_evdev(30) == YASL_KEY_A); + assert(yasl_private_key_from_cocoa(kVK_ANSI_A) == YASL_KEY_A); + assert(yasl_private_key_from_xkb_name("AC01") == YASL_KEY_A); + assert(yasl_private_key_from_evdev(1) == YASL_KEY_ESCAPE); + assert(yasl_private_key_from_cocoa(kVK_Escape) == YASL_KEY_ESCAPE); + assert(yasl_private_key_from_xkb_name("ESC\0") == YASL_KEY_ESCAPE); + assert(yasl_private_key_from_evdev(96) == YASL_KEY_KP_ENTER); + assert(yasl_private_key_from_cocoa(kVK_ANSI_KeypadEnter) == YASL_KEY_KP_ENTER); + assert(yasl_private_key_from_cocoa(kVK_Return) == YASL_KEY_ENTER); + assert(yasl_private_key_from_evdev(100) == YASL_KEY_RIGHT_ALT); + assert(yasl_private_key_from_cocoa(kVK_RightOption) == YASL_KEY_RIGHT_ALT); + assert(yasl_private_key_from_evdev(42) == YASL_KEY_LEFT_SHIFT); + assert(yasl_private_key_from_cocoa(kVK_Shift) == YASL_KEY_LEFT_SHIFT); + assert(yasl_private_key_from_evdev(86) == YASL_KEY_ISO_BACKSLASH); + assert(yasl_private_key_from_cocoa(kVK_ISO_Section) == YASL_KEY_ISO_BACKSLASH); + assert(yasl_private_key_from_evdev(0) == YASL_KEY_UNKNOWN); + assert(yasl_private_key_from_evdev(UINT32_MAX) == YASL_KEY_UNKNOWN); + assert(yasl_private_key_from_cocoa(UINT32_MAX) == YASL_KEY_UNKNOWN); + assert(yasl_private_key_from_xkb_name("ZZZZ") == YASL_KEY_UNKNOWN); + assert(yasl_private_key_label(0x1f600) == 0x1f600); + assert(yasl_private_key_label(0xd800) == 0 && yasl_private_key_label(0x110000) == 0); + assert(yasl_private_key_label(0xf700) == 0 && yasl_private_key_label('\t') == 0); return 0; } diff --git a/tests/common/test_loop.c b/tests/common/test_loop.c index f982e5e..5c49691 100644 --- a/tests/common/test_loop.c +++ b/tests/common/test_loop.c @@ -1,6 +1,6 @@ #define _GNU_SOURCE #define _DARWIN_C_SOURCE -#include "yasl/loop.h" +#include "common/private_loop.h" #include <assert.h> #include <errno.h> @@ -29,7 +29,7 @@ static void on_alarm(int signo) } struct post_log { - struct yasl_loop *loop; + struct yasl_private_loop *loop; char order[8]; int count; }; @@ -46,7 +46,7 @@ static void post_a(void *ud) { struct post_log *log = ud; log->order[log->count++] = 'a'; - assert(yasl_loop_post(log->loop, post_c, log)); + assert(yasl_private_loop_post(log->loop, post_c, log)); } static void post_b(void *ud) @@ -57,28 +57,28 @@ static void post_b(void *ud) static void test_post_order(void) { - struct yasl_loop *l = yasl_loop_create(); + struct yasl_private_loop *l = yasl_private_loop_create(); assert(l); - assert(!yasl_loop_post(NULL, post_b, NULL)); - assert(!yasl_loop_post(l, NULL, NULL)); + assert(!yasl_private_loop_post(NULL, post_b, NULL)); + assert(!yasl_private_loop_post(l, NULL, NULL)); struct post_log log = {.loop = l}; - assert(yasl_loop_post(l, post_a, &log)); - assert(yasl_loop_post(l, post_b, &log)); - assert(yasl_loop_step(l, 0) >= 1); + assert(yasl_private_loop_post(l, post_a, &log)); + assert(yasl_private_loop_post(l, post_b, &log)); + assert(yasl_private_loop_step(l, 0) >= 1); /* A post made while posts run waits for a later step. */ assert(log.count == 2 && memcmp(log.order, "ab", 2) == 0); - assert(yasl_loop_step(l, 0) >= 1); + assert(yasl_private_loop_step(l, 0) >= 1); assert(log.count == 3 && log.order[2] == 'c'); /* Destroy drops posts that never ran. */ - assert(yasl_loop_post(l, post_b, &log)); - yasl_loop_destroy(l); + assert(yasl_private_loop_post(l, post_b, &log)); + yasl_private_loop_destroy(l); assert(log.count == 3); } struct thread_ctx { - struct yasl_loop *loop; + struct yasl_private_loop *loop; bool kick; int signo; _Atomic bool ran; @@ -97,35 +97,35 @@ static void *wake_thread(void *ud) if (ctx->signo) kill(getpid(), ctx->signo); else if (ctx->kick) - yasl_loop_kick(ctx->loop); + yasl_private_loop_kick(ctx->loop); else - assert(yasl_loop_post(ctx->loop, mark_ran, ctx)); + assert(yasl_private_loop_post(ctx->loop, mark_ran, ctx)); return NULL; } static void test_cross_thread(void) { - struct yasl_loop *l = yasl_loop_create(); + struct yasl_private_loop *l = yasl_private_loop_create(); assert(l); struct thread_ctx post = {.loop = l}; pthread_t t; assert(pthread_create(&t, NULL, wake_thread, &post) == 0); while (!post.ran) - assert(yasl_loop_step(l, -1) >= 0); + assert(yasl_private_loop_step(l, -1) >= 0); pthread_join(t, NULL); /* A kick ends an indefinite wait without running anything. */ struct thread_ctx kick = {.loop = l, .kick = true}; assert(pthread_create(&t, NULL, wake_thread, &kick) == 0); - assert(yasl_loop_step(l, -1) >= 1); + assert(yasl_private_loop_step(l, -1) >= 1); pthread_join(t, NULL); - yasl_loop_destroy(l); + yasl_private_loop_destroy(l); } struct signal_log { - struct yasl_loop *loop; + struct yasl_private_loop *loop; int seen[NSIG]; int total; bool unwatch; @@ -138,7 +138,7 @@ static void on_signal(void *ud, int signo) log->seen[signo]++; log->total++; if (log->unwatch) - yasl_loop_unwatch_signals(log->loop); + yasl_private_loop_unwatch_signals(log->loop); } static volatile sig_atomic_t previous_handler_hits; @@ -149,10 +149,10 @@ static void previous_handler(int signo) previous_handler_hits++; } -static void step_until(struct yasl_loop *l, const int *counter, int want) +static void step_until(struct yasl_private_loop *l, const int *counter, int want) { while (*counter < want) - assert(yasl_loop_step(l, -1) >= 0); + assert(yasl_private_loop_step(l, -1) >= 0); } static void test_signals(void) @@ -161,30 +161,30 @@ static void test_signals(void) sigemptyset(&prev.sa_mask); assert(sigaction(SIGUSR2, &prev, NULL) == 0); - struct yasl_loop *l = yasl_loop_create(); - struct yasl_loop *other = yasl_loop_create(); + struct yasl_private_loop *l = yasl_private_loop_create(); + struct yasl_private_loop *other = yasl_private_loop_create(); assert(l && other); struct signal_log log = {.loop = l}; const int bad[] = {SIGKILL}; errno = 0; - assert(!yasl_loop_watch_signals(l, bad, 1, on_signal, &log) && errno == EINVAL); + assert(!yasl_private_loop_watch_signals(l, bad, 1, on_signal, &log) && errno == EINVAL); const int sigs[] = {SIGUSR1, SIGUSR2, SIGCHLD}; errno = 0; - assert(!yasl_loop_watch_signals(l, sigs, 0, on_signal, &log) && errno == EINVAL); + assert(!yasl_private_loop_watch_signals(l, sigs, 0, on_signal, &log) && errno == EINVAL); errno = 0; - assert(!yasl_loop_watch_signals(l, sigs, 3, NULL, &log) && errno == EINVAL); - assert(yasl_loop_watch_signals(l, sigs, 3, on_signal, &log)); + assert(!yasl_private_loop_watch_signals(l, sigs, 3, NULL, &log) && errno == EINVAL); + assert(yasl_private_loop_watch_signals(l, sigs, 3, on_signal, &log)); /* One signal belongs to one loop at a time. */ errno = 0; - assert(!yasl_loop_watch_signals(other, sigs, 1, on_signal, &log) && errno == EBUSY); + assert(!yasl_private_loop_watch_signals(other, sigs, 1, on_signal, &log) && errno == EBUSY); /* Deliveries before the callback runs coalesce per signal. */ raise(SIGUSR1); raise(SIGUSR1); raise(SIGUSR2); - assert(yasl_loop_step(l, 0) >= 1); + assert(yasl_private_loop_step(l, 0) >= 1); assert(log.seen[SIGUSR1] == 1 && log.seen[SIGUSR2] == 1); assert(previous_handler_hits == 0); @@ -205,11 +205,11 @@ static void test_signals(void) /* Replacing the watch restores the signals it drops. */ const int only_usr1[] = {SIGUSR1}; - assert(yasl_loop_watch_signals(l, only_usr1, 1, on_signal, &log)); + assert(yasl_private_loop_watch_signals(l, only_usr1, 1, on_signal, &log)); raise(SIGUSR2); assert(previous_handler_hits == 1); - assert(yasl_loop_watch_signals(other, (const int[]){SIGUSR2}, 1, on_signal, &log)); - yasl_loop_unwatch_signals(other); + assert(yasl_private_loop_watch_signals(other, (const int[]){SIGUSR2}, 1, on_signal, &log)); + yasl_private_loop_unwatch_signals(other); assert(previous_handler_hits == 1); raise(SIGUSR2); assert(previous_handler_hits == 2); @@ -221,15 +221,15 @@ static void test_signals(void) struct sigaction now; assert(sigaction(SIGUSR1, NULL, &now) == 0); assert(now.sa_handler == SIG_DFL); - yasl_loop_unwatch_signals(l); + yasl_private_loop_unwatch_signals(l); /* Destroy unwatches. */ log.unwatch = false; - assert(yasl_loop_watch_signals(l, only_usr1, 1, on_signal, &log)); - yasl_loop_destroy(l); + assert(yasl_private_loop_watch_signals(l, only_usr1, 1, on_signal, &log)); + yasl_private_loop_destroy(l); assert(sigaction(SIGUSR1, NULL, &now) == 0); assert(now.sa_handler == SIG_DFL); - yasl_loop_destroy(other); + yasl_private_loop_destroy(other); struct sigaction dfl = {.sa_handler = SIG_DFL}; sigemptyset(&dfl.sa_mask); diff --git a/tests/common/test_selection.c b/tests/common/test_selection.c index d1b3eb8..9772923 100644 --- a/tests/common/test_selection.c +++ b/tests/common/test_selection.c @@ -1,5 +1,5 @@ #define _POSIX_C_SOURCE 200809L -#include "yasl/yasl.h" +#include "common/types.h" #include <assert.h> #include <errno.h> @@ -7,27 +7,27 @@ int main(void) { - struct yasl_display_spec spec = {.backend = (enum yasl_backend)999}; + struct yasl_private_display_spec spec = {.backend = (enum yasl_private_backend)999}; errno = 0; - assert(!yasl_display_open(NULL, &spec)); + assert(!yasl_private_display_open(NULL, &spec)); assert(errno == EINVAL); - assert(yasl_display_backend(NULL) == YASL_BACKEND_AUTO); + assert(yasl_private_display_backend(NULL) == YASL_PRIVATE_BACKEND_AUTO); #if !YASL_HAS_COCOA - spec.backend = YASL_BACKEND_COCOA; + spec.backend = YASL_PRIVATE_BACKEND_COCOA; errno = 0; - assert(!yasl_display_open(NULL, &spec)); + assert(!yasl_private_display_open(NULL, &spec)); assert(errno == ENOSYS); #endif #if !YASL_HAS_WAYLAND - spec.backend = YASL_BACKEND_WAYLAND; + spec.backend = YASL_PRIVATE_BACKEND_WAYLAND; errno = 0; - assert(!yasl_display_open(NULL, &spec)); + assert(!yasl_private_display_open(NULL, &spec)); assert(errno == ENOSYS); #endif #if !YASL_HAS_X11 - spec.backend = YASL_BACKEND_X11; + spec.backend = YASL_PRIVATE_BACKEND_X11; errno = 0; - assert(!yasl_display_open(NULL, &spec)); + assert(!yasl_private_display_open(NULL, &spec)); assert(errno == ENOSYS); #endif return 0; diff --git a/tests/common/test_surface_integration.c b/tests/common/test_surface_integration.c new file mode 100644 index 0000000..2752208 --- /dev/null +++ b/tests/common/test_surface_integration.c @@ -0,0 +1,90 @@ +#define _POSIX_C_SOURCE 200809L +#include <yasl/yasl.h> +#include <yasl/cpu.h> +#include "common/backend.h" +#include <assert.h> +#include <pthread.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <stdio.h> +static void drain(void) +{ + yasl_event e;int n=0; + while(yasl_wait_event(&e,0)>0)assert(++n<1000); +} +static void *wake_thread(void *unused) +{ (void)unused;struct timespec delay={0,20000000};nanosleep(&delay,NULL);yasl_wake();return NULL; } +static void *wrong_thread(void *data) +{ assert(!yasl_surface_set_title(data,"wrong"));assert(yasl_get_error(NULL)==YASL_ERROR_WRONG_THREAD);return NULL; } +static int refreshes; +static void refresh(yasl_surface *s,void *ud) +{ + (void)ud;refreshes++; + yasl_event e;assert(yasl_wait_event(&e,0)==-1);assert(yasl_get_error(NULL)==YASL_ERROR_BUSY); + yasl_surface_destroy(s);assert(yasl_get_error(NULL)==YASL_ERROR_BUSY); +} +int main(int argc,char **argv) +{ + assert(argc==2); + enum yasl_backend backend=!strcmp(argv[1],"wayland")?YASL_BACKEND_WAYLAND:!strcmp(argv[1],"x11")?YASL_BACKEND_X11:YASL_BACKEND_COCOA; + assert(yasl_set_backend(backend));assert(yasl_set_app_id("org.yasl.surface-test")); + yasl_surface *s=yasl_surface_create("CPU contract",96,80,YASL_SURFACE_CPU); + if(!s){const char *why;yasl_get_error(&why);fprintf(stderr,"surface: %s native=%d\n",why,yasl_get_native_error());return 1;} + assert(yasl_surface_backend(s)==backend); + /* The first events report the window size, then ask for a frame. */ + yasl_event e;int fw=0,fh=0;bool window=false; + for(int i=0;i<1000;i++) { + assert(yasl_wait_event(&e,i?20:0)>=0); + if(e.type==YASL_EVENT_WINDOW){window=true;fw=e.window.pixel_width;fh=e.window.pixel_height;} + if(e.type==YASL_EVENT_REFRESH){assert(window&&fw>0&&fh>0&&e.surface==s);break;} + } + assert(e.type==YASL_EVENT_REFRESH); + int w,h;yasl_surface_get_framebuffer_size(s,&w,&h);assert(w==fw&&h==fh); + assert(!yasl_set_backend(backend));assert(yasl_get_error(NULL)==YASL_ERROR_BUSY); + int pw,ph;uint32_t *pixels=yasl_cpu_pixels(s,&pw,&ph);assert(pixels&&pw==w&&ph==h); + assert(pixels[0]==0&&pixels[(size_t)w*h-1]==0); + for(size_t i=0;i<(size_t)w*h;i++)pixels[i]=0xff102030u; + pixels[(size_t)3*w+2]=0xffaabbccu; + assert(yasl_cpu_present(s)); + assert(yasl_cpu_pixels(s,&pw,&ph)==pixels&&pixels[0]==0xff102030u&&pixels[(size_t)3*w+2]==0xffaabbccu); + drain(); + 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);pthread_join(thread,NULL); + bool ime=yasl_surface_set_text_input(s,true,YASL_TEXT_NORMAL); + if(!ime)assert(yasl_get_error(NULL)==YASL_ERROR_UNSUPPORTED); + bool snapshot=yasl_surface_set_surrounding_text(s,"a\xc3\xa9z",4,1,3,7); + if(ime)assert(snapshot); + else assert(!snapshot&&yasl_get_error(NULL)==YASL_ERROR_UNSUPPORTED); + assert(!yasl_surface_set_surrounding_text(s,"a\xc3\xa9z",4,2,3,8)); + assert(!yasl_surface_set_surrounding_text(s,"\xc0\xaf",2,0,2,8)); + 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));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_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(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); + yasl_surface_set_refresh_callback(s,refresh,NULL); + assert(yasl_cpu_present(s)); + drain();assert(refreshes>0); + yasl_surface_set_refresh_callback(s,NULL,NULL); + yasl_surface_destroy(s); + assert(!yasl_set_backend(backend)); + s=yasl_surface_create("shared backend remains",64,64,YASL_SURFACE_CPU);assert(s); + yasl_shutdown();assert(yasl_set_backend(backend)); + s=yasl_surface_create("reinitialized",64,64,YASL_SURFACE_CPU);assert(s);yasl_shutdown(); + puts("public surface lifecycle, pixels, ownership, input, wake and refresh passed");return 0; +} diff --git a/tests/common/test_tablet_example.c b/tests/common/test_tablet_example.c deleted file mode 100644 index e291b2a..0000000 --- a/tests/common/test_tablet_example.c +++ /dev/null @@ -1,65 +0,0 @@ -#define main tablet_example_main -#include "../../examples/tablet.c" -#undef main -#include <assert.h> - -static void pointer(struct app *app, enum yasl_event_type type, - enum yasl_pointer_device device, enum yasl_pointer_button button, int x, int y, uint16_t pressure) -{ - struct yasl_event event = { - .type = type, - .pointer = { - .pos = (struct yasl_vector2i){x, y}, - .device = device, - .button = button, - .pen = { .pressure = pressure }, - }, - }; - input(app, &event); -} - -int main(void) -{ - struct app app = {0}; - assert(resize_canvas(&app, (struct yasl_geometry){{400, 300}, 120})); - pointer(&app, YASL_EVENT_POINTER_MOTION, YASL_PTR_DEV_PEN, YASL_BUTTON_BACK, 80, 160, 65535); - /* Hover never paints. */ - assert(app.canvas[(size_t)160 * app.geometry.size.x + 80] == PAPER); - pointer(&app, YASL_EVENT_POINTER_DOWN, YASL_PTR_DEV_PEN, YASL_BUTTON_SECONDARY, 80, 160, 65535); - /* Side button isn't the tip. */ - assert(!app.down && - app.canvas[(size_t)160 * app.geometry.size.x + 80] == PAPER); - pointer(&app, YASL_EVENT_POINTER_DOWN, YASL_PTR_DEV_PEN, YASL_BUTTON_PRIMARY, 80, 160, 0); - assert(app.down && - app.canvas[(size_t)160 * app.geometry.size.x + 80] == INK && - app.canvas[(size_t)160 * app.geometry.size.x + 90] == PAPER); - pointer(&app, YASL_EVENT_POINTER_MOTION, YASL_PTR_DEV_PEN, YASL_BUTTON_PRIMARY, 80, 160, 65535); - /* Stationary pressure widens brush. */ - assert(app.canvas[(size_t)160 * app.geometry.size.x + 100] == INK); - pointer(&app, YASL_EVENT_POINTER_MOTION, YASL_PTR_DEV_PEN, YASL_BUTTON_PRIMARY, 180, 160, 20000); - /* Segments are continuous. */ - assert(app.canvas[(size_t)160 * app.geometry.size.x + 130] == INK); - pointer(&app, YASL_EVENT_POINTER_UP, YASL_PTR_DEV_PEN, YASL_BUTTON_PRIMARY, 180, 160, 0); - pointer(&app, YASL_EVENT_POINTER_MOTION, YASL_PTR_DEV_PEN, YASL_BUTTON_BACK, 250, 160, 65535); - assert(!app.down && app.canvas[(size_t)160 * app.geometry.size.x + 250] == PAPER); - pointer(&app, YASL_EVENT_POINTER_DOWN, YASL_PTR_DEV_ERASER, YASL_BUTTON_PRIMARY, 80, 160, 65535); - assert(app.canvas[(size_t)160 * app.geometry.size.x + 80] == PAPER && - app.canvas[(size_t)160 * app.geometry.size.x + 130] == INK); - struct yasl_event reset = {.type = YASL_EVENT_INPUT_RESET}; - input(&app, &reset); - pointer(&app, YASL_EVENT_POINTER_MOTION, YASL_PTR_DEV_ERASER, YASL_BUTTON_PRIMARY, 130, 160, 65535); - assert(!app.down && app.canvas[(size_t)160 * app.geometry.size.x + 130] == INK); - pointer(&app, YASL_EVENT_POINTER_DOWN, YASL_PTR_DEV_MOUSE, YASL_BUTTON_PRIMARY, 300, 200, 0); - assert(app.canvas[(size_t)200 * app.geometry.size.x + 300] == INK); - struct yasl_event blur = {.type = YASL_EVENT_FOCUS, .focus.focused = false}; - input(&app, &blur); - assert(!app.down); - assert(resize_canvas(&app, (struct yasl_geometry){{800, 600}, 240})); - /* DPI preserves logical drawing. */ - assert(app.canvas[(size_t)400 * app.geometry.size.x + 600] == INK && - !app.previous); - clear_canvas(&app); - assert(app.canvas[(size_t)400 * app.geometry.size.x + 600] == PAPER); - free(app.canvas); - return 0; -} diff --git a/tests/common/test_timers.c b/tests/common/test_timers.c index 8c92158..2c3542f 100644 --- a/tests/common/test_timers.c +++ b/tests/common/test_timers.c @@ -1,6 +1,6 @@ #define _POSIX_C_SOURCE 200809L #include "common/loop.h" -#include "yasl/yasl.h" +#include "common/types.h" #include <assert.h> #include <stdio.h> @@ -9,15 +9,15 @@ struct test_ctx { int count; uint64_t last_time; - yasl_timer_id id; - yasl_timer_id other_id; - struct yasl_loop *loop; + yasl_private_timer_id id; + yasl_private_timer_id other_id; + struct yasl_private_loop *loop; struct yasl_surface *surface; bool done; }; /* 1. Single-shot timer: returns 0, fires exactly once. */ -static uint64_t oneshot_cb(void *ud, yasl_timer_id id, uint64_t interval_ns) +static uint64_t oneshot_cb(void *ud, yasl_private_timer_id id, uint64_t interval_ns) { struct test_ctx *ctx = ud; assert(id == ctx->id); @@ -27,7 +27,7 @@ static uint64_t oneshot_cb(void *ud, yasl_timer_id id, uint64_t interval_ns) } /* 2. Repeating timer: ticks N times, then returns 0. */ -static uint64_t repeat_cb(void *ud, yasl_timer_id id, uint64_t interval_ns) +static uint64_t repeat_cb(void *ud, yasl_private_timer_id id, uint64_t interval_ns) { struct test_ctx *ctx = ud; assert(id == ctx->id); @@ -41,7 +41,7 @@ static uint64_t repeat_cb(void *ud, yasl_timer_id id, uint64_t interval_ns) } /* 3. Rescheduling timer: changes interval dynamically. */ -static uint64_t reschedule_cb(void *ud, yasl_timer_id id, uint64_t interval_ns) +static uint64_t reschedule_cb(void *ud, yasl_private_timer_id id, uint64_t interval_ns) { struct test_ctx *ctx = ud; assert(id == ctx->id); @@ -58,7 +58,7 @@ static uint64_t reschedule_cb(void *ud, yasl_timer_id id, uint64_t interval_ns) } /* 4. Timer adding another timer from inside callback. */ -static uint64_t child_timer_cb(void *ud, yasl_timer_id id, uint64_t interval_ns) +static uint64_t child_timer_cb(void *ud, yasl_private_timer_id id, uint64_t interval_ns) { (void)interval_ns; struct test_ctx *ctx = ud; @@ -67,40 +67,40 @@ static uint64_t child_timer_cb(void *ud, yasl_timer_id id, uint64_t interval_ns) return 0; } -static uint64_t parent_timer_cb(void *ud, yasl_timer_id id, uint64_t interval_ns) +static uint64_t parent_timer_cb(void *ud, yasl_private_timer_id id, uint64_t interval_ns) { (void)interval_ns; struct test_ctx *ctx = ud; assert(id == ctx->id); ctx->count += 1; - ctx->other_id = yasl_loop_add_timer(ctx->loop, 1000000ull, child_timer_cb, ctx); + ctx->other_id = yasl_private_loop_add_timer(ctx->loop, 1000000ull, child_timer_cb, ctx); assert(ctx->other_id > 0); return 0; } /* 5. Timer deleting another timer from inside callback. */ -static uint64_t victim_timer_cb(void *ud, yasl_timer_id id, uint64_t interval_ns) +static uint64_t victim_timer_cb(void *ud, yasl_private_timer_id id, uint64_t interval_ns) { (void)ud; (void)id; (void)interval_ns; assert(false && "Victim timer should have been cancelled before firing!"); return 0; } -static uint64_t killer_timer_cb(void *ud, yasl_timer_id id, uint64_t interval_ns) +static uint64_t killer_timer_cb(void *ud, yasl_private_timer_id id, uint64_t interval_ns) { (void)id; (void)interval_ns; struct test_ctx *ctx = ud; ctx->count++; - assert(yasl_loop_del_timer(ctx->loop, ctx->other_id)); + assert(yasl_private_loop_del_timer(ctx->loop, ctx->other_id)); return 0; } /* 6. Millisecond convenience conversion uses the same timer callback. */ -static uint64_t ms_timer_cb(void *ud, yasl_timer_id id, uint64_t interval_ns) +static uint64_t ms_timer_cb(void *ud, yasl_private_timer_id id, uint64_t interval_ns) { struct test_ctx *ctx = ud; assert(id == ctx->id); - assert(interval_ns == YASL_MS_TO_NS(5)); + assert(interval_ns == YASL_PRIVATE_MS_TO_NS(5)); ctx->count++; if (ctx->count >= 3) { ctx->done = true; @@ -111,94 +111,94 @@ static uint64_t ms_timer_cb(void *ud, yasl_timer_id id, uint64_t interval_ns) static void test_loop_timers(void) { - struct yasl_loop *l = yasl_loop_create(); + struct yasl_private_loop *l = yasl_private_loop_create(); assert(l); /* Invalid arguments */ - assert(yasl_loop_add_timer(NULL, 1000, oneshot_cb, NULL) == 0); - assert(yasl_loop_add_timer(l, 0, oneshot_cb, NULL) == 0); - assert(yasl_loop_add_timer(l, 1000, NULL, NULL) == 0); - assert(!yasl_loop_del_timer(NULL, 1)); - assert(!yasl_loop_del_timer(l, 0)); - assert(!yasl_loop_del_timer(l, 99999)); - assert(yasl_loop_next_timeout_ms(l) == -1); + assert(yasl_private_loop_add_timer(NULL, 1000, oneshot_cb, NULL) == 0); + assert(yasl_private_loop_add_timer(l, 0, oneshot_cb, NULL) == 0); + assert(yasl_private_loop_add_timer(l, 1000, NULL, NULL) == 0); + assert(!yasl_private_loop_del_timer(NULL, 1)); + assert(!yasl_private_loop_del_timer(l, 0)); + assert(!yasl_private_loop_del_timer(l, 99999)); + assert(yasl_private_loop_next_timeout_ms(l) == -1); /* Test 1: Single-shot */ struct test_ctx ctx1 = { .loop = l }; - ctx1.id = yasl_loop_add_timer(l, 5000000ull, oneshot_cb, &ctx1); + ctx1.id = yasl_private_loop_add_timer(l, 5000000ull, oneshot_cb, &ctx1); assert(ctx1.id > 0); - assert(yasl_loop_next_timeout_ms(l) >= 0); + assert(yasl_private_loop_next_timeout_ms(l) >= 0); while (ctx1.count == 0) { - int handled = yasl_loop_step(l, 50); + int handled = yasl_private_loop_step(l, 50); assert(handled >= 0); } assert(ctx1.count == 1); /* Should be disarmed and removed */ - assert(!yasl_loop_del_timer(l, ctx1.id)); - assert(yasl_loop_next_timeout_ms(l) == -1); + assert(!yasl_private_loop_del_timer(l, ctx1.id)); + assert(yasl_private_loop_next_timeout_ms(l) == -1); /* Test 2: Repeating */ struct test_ctx ctx2 = { .loop = l }; - ctx2.id = yasl_loop_add_timer(l, 2000000ull, repeat_cb, &ctx2); + ctx2.id = yasl_private_loop_add_timer(l, 2000000ull, repeat_cb, &ctx2); assert(ctx2.id > 0); while (!ctx2.done) { - yasl_loop_step(l, 50); + yasl_private_loop_step(l, 50); } assert(ctx2.count == 5); - assert(!yasl_loop_del_timer(l, ctx2.id)); + assert(!yasl_private_loop_del_timer(l, ctx2.id)); /* Test 3: Reschedule dynamically */ struct test_ctx ctx3 = { .loop = l }; - ctx3.id = yasl_loop_add_timer(l, 2000000ull, reschedule_cb, &ctx3); + ctx3.id = yasl_private_loop_add_timer(l, 2000000ull, reschedule_cb, &ctx3); assert(ctx3.id > 0); while (!ctx3.done) { - yasl_loop_step(l, 50); + yasl_private_loop_step(l, 50); } assert(ctx3.count == 2); /* Test 4: Timer cancellation before firing */ struct test_ctx ctx4 = { .loop = l }; - yasl_timer_id cancel_id = yasl_loop_add_timer(l, 5000000ull, oneshot_cb, &ctx4); + yasl_private_timer_id cancel_id = yasl_private_loop_add_timer(l, 5000000ull, oneshot_cb, &ctx4); assert(cancel_id > 0); - assert(yasl_loop_del_timer(l, cancel_id)); - assert(!yasl_loop_del_timer(l, cancel_id)); + assert(yasl_private_loop_del_timer(l, cancel_id)); + assert(!yasl_private_loop_del_timer(l, cancel_id)); /* Step for 10ms; timer should not fire */ - yasl_loop_step(l, 10); + yasl_private_loop_step(l, 10); assert(ctx4.count == 0); /* Test 5: Child timer added inside callback */ struct test_ctx ctx5 = { .loop = l }; - ctx5.id = yasl_loop_add_timer(l, 2000000ull, parent_timer_cb, &ctx5); + ctx5.id = yasl_private_loop_add_timer(l, 2000000ull, parent_timer_cb, &ctx5); while (ctx5.count < 11) { - yasl_loop_step(l, 50); + yasl_private_loop_step(l, 50); } assert(ctx5.count == 11); /* Test 6: Killer timer deletes victim timer before victim fires */ struct test_ctx ctx6 = { .loop = l }; - ctx6.id = yasl_loop_add_timer(l, 1000000ull, killer_timer_cb, &ctx6); - ctx6.other_id = yasl_loop_add_timer(l, 10000000ull, victim_timer_cb, &ctx6); + ctx6.id = yasl_private_loop_add_timer(l, 1000000ull, killer_timer_cb, &ctx6); + ctx6.other_id = yasl_private_loop_add_timer(l, 10000000ull, victim_timer_cb, &ctx6); while (ctx6.count == 0) { - yasl_loop_step(l, 50); + yasl_private_loop_step(l, 50); } assert(ctx6.count == 1); - yasl_loop_step(l, 20); + yasl_private_loop_step(l, 20); /* Test 7: Millisecond conversion */ struct test_ctx ctx7 = { .loop = l }; - ctx7.id = yasl_loop_add_timer(l, YASL_MS_TO_NS(5), ms_timer_cb, &ctx7); + ctx7.id = yasl_private_loop_add_timer(l, YASL_PRIVATE_MS_TO_NS(5), ms_timer_cb, &ctx7); assert(ctx7.id > 0); while (!ctx7.done) { - yasl_loop_step(l, 50); + yasl_private_loop_step(l, 50); } assert(ctx7.count == 3); - yasl_loop_destroy(l); + yasl_private_loop_destroy(l); } /* Surface timer tests */ -static uint64_t surface_timer_repeat_cb(void *ud, yasl_timer_id id, uint64_t interval_ns) +static uint64_t surface_timer_repeat_cb(void *ud, yasl_private_timer_id id, uint64_t interval_ns) { (void)interval_ns; struct test_ctx *ctx = ud; @@ -207,96 +207,96 @@ static uint64_t surface_timer_repeat_cb(void *ud, yasl_timer_id id, uint64_t int return interval_ns; } -static uint64_t surface_suicide_cb(void *ud, yasl_timer_id id, uint64_t interval_ns) +static uint64_t surface_suicide_cb(void *ud, yasl_private_timer_id id, uint64_t interval_ns) { (void)id; (void)interval_ns; struct test_ctx *ctx = ud; ctx->count++; /* Destroy surface from within the timer callback */ - yasl_surface_destroy(ctx->surface); + yasl_private_surface_destroy(ctx->surface); ctx->surface = NULL; return 1000000ull; /* Even if it returns > 0, surface is destroyed */ } static void test_surface_timers(void) { - struct yasl_loop *loop = yasl_loop_create(); + struct yasl_private_loop *loop = yasl_private_loop_create(); assert(loop); - struct yasl_display_spec spec = { .app_id = "org.yasl.timer_test" }; - struct yasl_display *d = yasl_display_open(loop, &spec); + struct yasl_private_display_spec spec = { .app_id = "org.yasl.timer_test" }; + struct yasl_private_display *d = yasl_private_display_open(loop, &spec); if (!d) { /* Headless without display server */ - yasl_loop_destroy(loop); + yasl_private_loop_destroy(loop); return; } - assert(yasl_display_loop(d) == loop); + assert(yasl_private_display_loop(d) == loop); - struct yasl_window_spec sspec = { + struct yasl_private_window_spec sspec = { .title = "Timer Surface", .size = { .x = 160, .y = 100 }, }; - struct yasl_surface *s = yasl_surface_create_toplevel(d, &sspec); + struct yasl_surface *s = yasl_private_surface_create_toplevel(d, &sspec); assert(s); - assert(yasl_display_loop(yasl_surface_display(s)) == loop); + assert(yasl_private_display_loop(yasl_private_surface_display(s)) == loop); /* Application timers use the display's loop. */ struct test_ctx dctx = {0}; - dctx.id = yasl_loop_add_timer(yasl_display_loop(d), 2000000ull, oneshot_cb, &dctx); + dctx.id = yasl_private_loop_add_timer(yasl_private_display_loop(d), 2000000ull, oneshot_cb, &dctx); assert(dctx.id > 0); while (dctx.count == 0) { - yasl_display_dispatch(d, 50); + yasl_private_display_dispatch(d, 50); } assert(dctx.count == 1); /* Surface timer basic repeat & manual delete */ struct test_ctx sctx = {0}; - sctx.id = yasl_surface_add_timer(s, 2000000ull, surface_timer_repeat_cb, &sctx); + sctx.id = yasl_private_surface_add_timer(s, 2000000ull, surface_timer_repeat_cb, &sctx); assert(sctx.id > 0); while (sctx.count < 3) { - yasl_display_dispatch(d, 50); + yasl_private_display_dispatch(d, 50); } assert(sctx.count >= 3); - assert(yasl_surface_del_timer(s, sctx.id)); + assert(yasl_private_surface_del_timer(s, sctx.id)); int count_before = sctx.count; - yasl_display_dispatch(d, 10); + yasl_private_display_dispatch(d, 10); assert(sctx.count == count_before); /* A fired one-shot surface timer is retired, as a loop timer is. Many * of them stay retired after the surface's id list compacts. */ for (int i = 0; i < 64; i++) { struct test_ctx octx = {0}; - octx.id = yasl_surface_add_timer(s, 1000000ull, oneshot_cb, &octx); + octx.id = yasl_private_surface_add_timer(s, 1000000ull, oneshot_cb, &octx); assert(octx.id > 0); while (octx.count == 0) - yasl_display_dispatch(d, 50); - assert(!yasl_surface_del_timer(s, octx.id)); + yasl_private_display_dispatch(d, 50); + assert(!yasl_private_surface_del_timer(s, octx.id)); } /* Surface timer auto-cleanup on surface destruction */ struct test_ctx sctx2 = {0}; - sctx2.id = yasl_surface_add_timer(s, 2000000ull, surface_timer_repeat_cb, &sctx2); + sctx2.id = yasl_private_surface_add_timer(s, 2000000ull, surface_timer_repeat_cb, &sctx2); assert(sctx2.id > 0); - yasl_surface_destroy(s); + yasl_private_surface_destroy(s); /* Step display/loop; timer must not fire on dead surface */ - yasl_display_dispatch(d, 10); + yasl_private_display_dispatch(d, 10); assert(sctx2.count == 0); /* Surface suicide from timer callback */ - s = yasl_surface_create_toplevel(d, &sspec); + s = yasl_private_surface_create_toplevel(d, &sspec); assert(s); struct test_ctx sctx3 = { .surface = s }; - sctx3.id = yasl_surface_add_timer(s, 2000000ull, surface_suicide_cb, &sctx3); + sctx3.id = yasl_private_surface_add_timer(s, 2000000ull, surface_suicide_cb, &sctx3); assert(sctx3.id > 0); while (sctx3.count == 0) { - yasl_display_dispatch(d, 50); + yasl_private_display_dispatch(d, 50); } assert(sctx3.count == 1); assert(sctx3.surface == NULL); - yasl_display_close(d); - yasl_loop_destroy(loop); + yasl_private_display_close(d); + yasl_private_loop_destroy(loop); } int main(void) diff --git a/tests/common/test_utf8.c b/tests/common/test_utf8.c index 72f8904..58bfe9d 100644 --- a/tests/common/test_utf8.c +++ b/tests/common/test_utf8.c @@ -9,19 +9,19 @@ int main(void) for (int i = 1; i <= 255; i++) latin1[i - 1] = (char)i; latin1[255] = '\0'; size_t len = 0, back_len = 0; - char *utf8 = yasl_utf8_from_latin1(latin1, 255, &len); - assert(utf8 && yasl_utf8_validate(utf8, len)); - char *back = yasl_utf8_to_latin1(utf8, &back_len); + char *utf8 = yasl_private_utf8_from_latin1(latin1, 255, &len); + assert(utf8 && yasl_private_utf8_validate(utf8, len)); + char *back = yasl_private_utf8_to_latin1(utf8, &back_len); assert(back && back_len == 255 && memcmp(back, latin1, 256) == 0); free(back); free(utf8); - assert(!yasl_utf8_to_latin1("๐", &len)); - assert(!yasl_utf8_to_latin1("\xc3", &len)); - assert(!yasl_utf8_validate("\xc3", 1)); - assert(!yasl_utf8_validate("\xe2\x82", 2)); - assert(!yasl_utf8_validate("\xf0\x9f\x98", 3)); - assert(!yasl_utf8_validate("\xed\xa0\x80", 3)); /* Surrogate. */ - assert(yasl_utf8_validate("๐", sizeof("๐") - 1)); - assert(yasl_utf8_validate(NULL, 0)); + assert(!yasl_private_utf8_to_latin1("๐", &len)); + assert(!yasl_private_utf8_to_latin1("\xc3", &len)); + assert(!yasl_private_utf8_validate("\xc3", 1)); + assert(!yasl_private_utf8_validate("\xe2\x82", 2)); + assert(!yasl_private_utf8_validate("\xf0\x9f\x98", 3)); + assert(!yasl_private_utf8_validate("\xed\xa0\x80", 3)); /* Surrogate. */ + assert(yasl_private_utf8_validate("๐", sizeof("๐") - 1)); + assert(yasl_private_utf8_validate(NULL, 0)); return 0; } diff --git a/tests/common/test_vulkan.c b/tests/common/test_vulkan.c new file mode 100644 index 0000000..12daa22 --- /dev/null +++ b/tests/common/test_vulkan.c @@ -0,0 +1,389 @@ +/* Public Vulkan WSI integration test. The launcher supplies a real Wayland + * or X11 session (normally Weston/Xwayland); no internal YASL headers are + * used here. */ +#include "yasl/yasl.h" +#include "yasl/vulkan.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static int fail_vk(const char *what, VkResult result) +{ + fprintf(stderr, "vulkan integration: %s failed (VkResult %d)\n", what, result); + return 1; +} + +static bool has_device_extension(VkPhysicalDevice device, const char *name) +{ + uint32_t count = 0; + if (vkEnumerateDeviceExtensionProperties(device, NULL, &count, NULL) != VK_SUCCESS) + return false; + VkExtensionProperties *extensions = count ? calloc(count, sizeof(*extensions)) : NULL; + if (count && !extensions) return false; + bool found = false; + if (vkEnumerateDeviceExtensionProperties(device, NULL, &count, extensions) == VK_SUCCESS) + for (uint32_t i = 0; i < count; i++) + if (strcmp(extensions[i].extensionName, name) == 0) found = true; + free(extensions); + return found; +} + +static int run_test(enum yasl_backend backend) +{ + int status = 1; + yasl_surface *surface = NULL; + VkInstance instance = VK_NULL_HANDLE; + VkSurfaceKHR vk_surface = VK_NULL_HANDLE; + VkDevice device = VK_NULL_HANDLE; + VkSwapchainKHR swapchain = VK_NULL_HANDLE; + VkCommandPool command_pool = VK_NULL_HANDLE; + VkSemaphore acquired = VK_NULL_HANDLE, rendered = VK_NULL_HANDLE; + VkCommandBuffer command = VK_NULL_HANDLE; + + if (!yasl_set_backend(backend)) { + fprintf(stderr, "vulkan integration: cannot select requested backend %d (YASL error %d)\n", + backend, yasl_get_error(NULL)); + goto cleanup; + } + if (!yasl_vulkan_init(vkGetInstanceProcAddr)) { + fprintf(stderr, "vulkan integration: loader initialization failed (YASL error %d)\n", + yasl_get_error(NULL)); + goto cleanup; + } + surface = yasl_surface_create("yasl Vulkan WSI integration", 256, 192, 0); + if (!surface) { + fprintf(stderr, "vulkan integration: surface creation failed (YASL error %d)\n", + yasl_get_error(NULL)); + goto cleanup; + } + if (!(yasl_surface_features(surface) & YASL_CAP_VULKAN)) { + fprintf(stderr, "vulkan integration: requested backend does not advertise Vulkan WSI\n"); + goto cleanup; + } + + uint32_t extension_count = 0; + const char *const *required = yasl_vulkan_instance_extensions(surface, &extension_count); + if (!required || !extension_count) { + fprintf(stderr, "vulkan integration: surface returned no required instance extensions\n"); + goto cleanup; + } + uint32_t available_count = 0; + VkResult vr = vkEnumerateInstanceExtensionProperties(NULL, &available_count, NULL); + if (vr != VK_SUCCESS) { status = fail_vk("vkEnumerateInstanceExtensionProperties", vr); goto cleanup; } + VkExtensionProperties *available = available_count ? calloc(available_count, sizeof(*available)) : NULL; + if (available_count && !available) { fprintf(stderr, "vulkan integration: out of memory\n"); goto cleanup; } + vr = vkEnumerateInstanceExtensionProperties(NULL, &available_count, available); + if (vr != VK_SUCCESS) { + free(available); status = fail_vk("vkEnumerateInstanceExtensionProperties", vr); goto cleanup; + } + for (uint32_t i = 0; i < extension_count; i++) { + bool found = false; + for (uint32_t j = 0; j < available_count; j++) + if (strcmp(required[i], available[j].extensionName) == 0) found = true; + if (!found) { + fprintf(stderr, "vulkan integration: required instance extension unavailable: %s\n", required[i]); + free(available); goto cleanup; + } + } + free(available); + + VkApplicationInfo app = { + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pApplicationName = "yasl Vulkan WSI integration", + .applicationVersion = VK_MAKE_VERSION(1, 0, 0), + .pEngineName = "yasl", + .engineVersion = VK_MAKE_VERSION(1, 0, 0), + .apiVersion = VK_API_VERSION_1_0, + }; + VkInstanceCreateInfo instance_info = { + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pApplicationInfo = &app, + .flags = yasl_vulkan_instance_flags(surface), + .enabledExtensionCount = extension_count, + .ppEnabledExtensionNames = required, + }; + vr = vkCreateInstance(&instance_info, NULL, &instance); + if (vr != VK_SUCCESS) { status = fail_vk("vkCreateInstance", vr); goto cleanup; } + vr = yasl_vulkan_create_surface(surface, instance, NULL, &vk_surface); + if (vr != VK_SUCCESS) { status = fail_vk("yasl_vulkan_create_surface", vr); goto cleanup; } + + uint32_t physical_count = 0; + vr = vkEnumeratePhysicalDevices(instance, &physical_count, NULL); + if (vr != VK_SUCCESS || !physical_count) { + status = vr == VK_SUCCESS ? 1 : fail_vk("vkEnumeratePhysicalDevices", vr); + if (vr == VK_SUCCESS) fprintf(stderr, "vulkan integration: no physical devices found\n"); + goto cleanup; + } + VkPhysicalDevice *physical = calloc(physical_count, sizeof(*physical)); + if (!physical) { fprintf(stderr, "vulkan integration: out of memory\n"); goto cleanup; } + vr = vkEnumeratePhysicalDevices(instance, &physical_count, physical); + if (vr != VK_SUCCESS) { free(physical); status = fail_vk("vkEnumeratePhysicalDevices", vr); goto cleanup; } + + VkPhysicalDevice selected = VK_NULL_HANDLE; + uint32_t queue_family = UINT32_MAX; + for (uint32_t p = 0; p < physical_count && !selected; p++) { + if (!has_device_extension(physical[p], VK_KHR_SWAPCHAIN_EXTENSION_NAME)) continue; + uint32_t family_count = 0; + vkGetPhysicalDeviceQueueFamilyProperties(physical[p], &family_count, NULL); + VkQueueFamilyProperties *families = family_count ? calloc(family_count, sizeof(*families)) : NULL; + if (family_count && !families) continue; + vkGetPhysicalDeviceQueueFamilyProperties(physical[p], &family_count, families); + for (uint32_t q = 0; q < family_count; q++) { + VkBool32 present = VK_FALSE; + if ((families[q].queueFlags & VK_QUEUE_GRAPHICS_BIT) && + vkGetPhysicalDeviceSurfaceSupportKHR(physical[p], q, vk_surface, &present) == VK_SUCCESS && present) { + selected = physical[p]; + queue_family = q; + break; + } + } + free(families); + } + free(physical); + if (!selected) { + fprintf(stderr, "vulkan integration: no graphics queue with VK_KHR_swapchain presentation support\n"); + goto cleanup; + } + + VkPhysicalDeviceProperties properties; + vkGetPhysicalDeviceProperties(selected, &properties); + fprintf(stderr, "vulkan integration: using %s\n", properties.deviceName); + VkSurfaceCapabilitiesKHR capabilities; + vr = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(selected, vk_surface, &capabilities); + if (vr != VK_SUCCESS) { status = fail_vk("vkGetPhysicalDeviceSurfaceCapabilitiesKHR", vr); goto cleanup; } + if (!(capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) { + fprintf(stderr, "vulkan integration: surface images cannot be transfer destinations\n"); + goto cleanup; + } + uint32_t format_count = 0; + vr = vkGetPhysicalDeviceSurfaceFormatsKHR(selected, vk_surface, &format_count, NULL); + if (vr != VK_SUCCESS || !format_count) { + status = vr == VK_SUCCESS ? 1 : fail_vk("vkGetPhysicalDeviceSurfaceFormatsKHR", vr); + if (vr == VK_SUCCESS) fprintf(stderr, "vulkan integration: surface has no formats\n"); + goto cleanup; + } + VkSurfaceFormatKHR *formats = calloc(format_count, sizeof(*formats)); + if (!formats) { fprintf(stderr, "vulkan integration: out of memory\n"); goto cleanup; } + vr = vkGetPhysicalDeviceSurfaceFormatsKHR(selected, vk_surface, &format_count, formats); + if (vr != VK_SUCCESS) { free(formats); status = fail_vk("vkGetPhysicalDeviceSurfaceFormatsKHR", vr); goto cleanup; } + VkSurfaceFormatKHR format = formats[0]; + for (uint32_t i = 0; i < format_count; i++) + if (formats[i].format == VK_FORMAT_B8G8R8A8_SRGB && + formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { format = formats[i]; break; } + if (format.format == VK_FORMAT_UNDEFINED) format.format = VK_FORMAT_B8G8R8A8_UNORM; + free(formats); + + VkExtent2D extent = capabilities.currentExtent; + if (extent.width == UINT32_MAX) { + int width = 0, height = 0; + yasl_surface_get_framebuffer_size(surface, &width, &height); + if (width <= 0 || height <= 0) { + fprintf(stderr, "vulkan integration: surface has no drawable framebuffer extent\n"); + goto cleanup; + } + extent.width = (uint32_t)width; + extent.height = (uint32_t)height; + if (extent.width < capabilities.minImageExtent.width) extent.width = capabilities.minImageExtent.width; + if (extent.width > capabilities.maxImageExtent.width) extent.width = capabilities.maxImageExtent.width; + if (extent.height < capabilities.minImageExtent.height) extent.height = capabilities.minImageExtent.height; + if (extent.height > capabilities.maxImageExtent.height) extent.height = capabilities.maxImageExtent.height; + } + uint32_t image_count = capabilities.minImageCount + 1; + if (capabilities.maxImageCount && image_count > capabilities.maxImageCount) + image_count = capabilities.maxImageCount; + VkCompositeAlphaFlagBitsKHR alpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + if (!(capabilities.supportedCompositeAlpha & alpha)) { + const VkCompositeAlphaFlagBitsKHR alphas[] = { + VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, + }; + bool found = false; + for (size_t i = 0; i < sizeof(alphas) / sizeof(alphas[0]); i++) + if (capabilities.supportedCompositeAlpha & alphas[i]) { alpha = alphas[i]; found = true; break; } + if (!found) { fprintf(stderr, "vulkan integration: no supported composite alpha mode\n"); goto cleanup; } + } + uint32_t present_mode_count = 0; + vr = vkGetPhysicalDeviceSurfacePresentModesKHR(selected, vk_surface, &present_mode_count, NULL); + if (vr != VK_SUCCESS || !present_mode_count) { + status = vr == VK_SUCCESS ? 1 : fail_vk("vkGetPhysicalDeviceSurfacePresentModesKHR", vr); + if (vr == VK_SUCCESS) fprintf(stderr, "vulkan integration: surface has no present modes\n"); + goto cleanup; + } + VkPresentModeKHR *present_modes = calloc(present_mode_count, sizeof(*present_modes)); + if (!present_modes) { fprintf(stderr, "vulkan integration: out of memory\n"); goto cleanup; } + vr = vkGetPhysicalDeviceSurfacePresentModesKHR(selected, vk_surface, &present_mode_count, present_modes); + free(present_modes); + if (vr != VK_SUCCESS) { status = fail_vk("vkGetPhysicalDeviceSurfacePresentModesKHR", vr); goto cleanup; } + + float priority = 1.0f; + VkDeviceQueueCreateInfo queue_info = { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .queueFamilyIndex = queue_family, + .queueCount = 1, + .pQueuePriorities = &priority, + }; + const char *device_extensions[] = {VK_KHR_SWAPCHAIN_EXTENSION_NAME}; + VkDeviceCreateInfo device_info = { + .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .queueCreateInfoCount = 1, + .pQueueCreateInfos = &queue_info, + .enabledExtensionCount = 1, + .ppEnabledExtensionNames = device_extensions, + }; + vr = vkCreateDevice(selected, &device_info, NULL, &device); + if (vr != VK_SUCCESS) { status = fail_vk("vkCreateDevice", vr); goto cleanup; } + VkQueue queue; + vkGetDeviceQueue(device, queue_family, 0, &queue); + + VkSwapchainCreateInfoKHR swap_info = { + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + .surface = vk_surface, + .minImageCount = image_count, + .imageFormat = format.format, + .imageColorSpace = format.colorSpace, + .imageExtent = extent, + .imageArrayLayers = 1, + .imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT, + .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, + .preTransform = capabilities.currentTransform, + .compositeAlpha = alpha, + .presentMode = VK_PRESENT_MODE_FIFO_KHR, + .clipped = VK_TRUE, + }; + vr = vkCreateSwapchainKHR(device, &swap_info, NULL, &swapchain); + if (vr != VK_SUCCESS) { status = fail_vk("vkCreateSwapchainKHR", vr); goto cleanup; } + uint32_t swap_image_count = 0; + vr = vkGetSwapchainImagesKHR(device, swapchain, &swap_image_count, NULL); + if (vr != VK_SUCCESS || !swap_image_count) { + status = vr == VK_SUCCESS ? 1 : fail_vk("vkGetSwapchainImagesKHR", vr); + if (vr == VK_SUCCESS) fprintf(stderr, "vulkan integration: swapchain returned no images\n"); + goto cleanup; + } + VkImage *images = calloc(swap_image_count, sizeof(*images)); + if (!images) { fprintf(stderr, "vulkan integration: out of memory\n"); goto cleanup; } + vr = vkGetSwapchainImagesKHR(device, swapchain, &swap_image_count, images); + if (vr != VK_SUCCESS) { free(images); status = fail_vk("vkGetSwapchainImagesKHR", vr); goto cleanup; } + + VkCommandPoolCreateInfo pool_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, + .queueFamilyIndex = queue_family, + }; + vr = vkCreateCommandPool(device, &pool_info, NULL, &command_pool); + if (vr != VK_SUCCESS) { free(images); status = fail_vk("vkCreateCommandPool", vr); goto cleanup; } + VkCommandBufferAllocateInfo command_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .commandPool = command_pool, + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = 1, + }; + vr = vkAllocateCommandBuffers(device, &command_info, &command); + if (vr != VK_SUCCESS) { free(images); status = fail_vk("vkAllocateCommandBuffers", vr); goto cleanup; } + VkSemaphoreCreateInfo semaphore_info = {.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO}; + vr = vkCreateSemaphore(device, &semaphore_info, NULL, &acquired); + if (vr != VK_SUCCESS) { free(images); status = fail_vk("vkCreateSemaphore(acquired)", vr); goto cleanup; } + vr = vkCreateSemaphore(device, &semaphore_info, NULL, &rendered); + if (vr != VK_SUCCESS) { free(images); status = fail_vk("vkCreateSemaphore(rendered)", vr); goto cleanup; } + + uint32_t image_index = 0; + vr = vkAcquireNextImageKHR(device, swapchain, UINT64_MAX, acquired, VK_NULL_HANDLE, &image_index); + if (vr != VK_SUCCESS && vr != VK_SUBOPTIMAL_KHR) { + free(images); status = fail_vk("vkAcquireNextImageKHR", vr); goto cleanup; + } + VkCommandBufferBeginInfo begin = {.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + vr = vkBeginCommandBuffer(command, &begin); + if (vr != VK_SUCCESS) { free(images); status = fail_vk("vkBeginCommandBuffer", vr); goto cleanup; } + VkImageMemoryBarrier to_clear = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .srcAccessMask = 0, + .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = images[image_index], + .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}, + }; + vkCmdPipelineBarrier(command, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &to_clear); + VkClearColorValue color = {.float32 = {0.08f, 0.18f, 0.32f, 1.0f}}; + VkImageSubresourceRange range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; + vkCmdClearColorImage(command, images[image_index], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &color, 1, &range); + VkImageMemoryBarrier to_present = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = 0, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = images[image_index], + .subresourceRange = range, + }; + vkCmdPipelineBarrier(command, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, NULL, 0, NULL, 1, &to_present); + vr = vkEndCommandBuffer(command); + free(images); + if (vr != VK_SUCCESS) { status = fail_vk("vkEndCommandBuffer", vr); goto cleanup; } + VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_TRANSFER_BIT; + VkSubmitInfo submit = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .waitSemaphoreCount = 1, + .pWaitSemaphores = &acquired, + .pWaitDstStageMask = &wait_stage, + .commandBufferCount = 1, + .pCommandBuffers = &command, + .signalSemaphoreCount = 1, + .pSignalSemaphores = &rendered, + }; + vr = vkQueueSubmit(queue, 1, &submit, VK_NULL_HANDLE); + if (vr != VK_SUCCESS) { status = fail_vk("vkQueueSubmit", vr); goto cleanup; } + VkPresentInfoKHR present = { + .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + .waitSemaphoreCount = 1, + .pWaitSemaphores = &rendered, + .swapchainCount = 1, + .pSwapchains = &swapchain, + .pImageIndices = &image_index, + }; + vr = vkQueuePresentKHR(queue, &present); + if (vr != VK_SUCCESS && vr != VK_SUBOPTIMAL_KHR) { + status = fail_vk("vkQueuePresentKHR", vr); goto cleanup; + } + vr = vkDeviceWaitIdle(device); + if (vr != VK_SUCCESS) { status = fail_vk("vkDeviceWaitIdle", vr); goto cleanup; } + fprintf(stderr, "vulkan integration: created surface, cleared and presented %ux%u swapchain image\n", + extent.width, extent.height); + status = 0; + +cleanup: + if (device) vkDeviceWaitIdle(device); + if (rendered) vkDestroySemaphore(device, rendered, NULL); + if (acquired) vkDestroySemaphore(device, acquired, NULL); + if (command_pool) vkDestroyCommandPool(device, command_pool, NULL); + if (swapchain) vkDestroySwapchainKHR(device, swapchain, NULL); + if (device) vkDestroyDevice(device, NULL); + if (vk_surface) vkDestroySurfaceKHR(instance, vk_surface, NULL); + if (instance) vkDestroyInstance(instance, NULL); + if (surface) yasl_surface_destroy(surface); + yasl_shutdown(); + return status; +} + +int main(int argc, char **argv) +{ + if (argc != 2) { + fprintf(stderr, "usage: %s wayland|x11\n", argv[0]); + return 2; + } + enum yasl_backend backend; + if (strcmp(argv[1], "wayland") == 0) backend = YASL_BACKEND_WAYLAND; + else if (strcmp(argv[1], "x11") == 0) backend = YASL_BACKEND_X11; + else { + fprintf(stderr, "vulkan integration: unsupported backend '%s'\n", argv[1]); + return 2; + } + return run_test(backend); +} |
