diff options
Diffstat (limited to 'tests')
41 files changed, 2461 insertions, 1944 deletions
diff --git a/tests/benchmark.c b/tests/benchmark.c index 1cea614..8fa8066 100644 --- a/tests/benchmark.c +++ b/tests/benchmark.c @@ -7,12 +7,12 @@ #include <time.h> #include <limits.h> -#include "yasl/yasl.h" -#include "yasl/loop.h" -#include "yasl/timing.h" +#include "common/types.h" +#include "common/private_loop.h" +#include "common/private_timing.h" #include "common/input.h" #if YASL_HAS_WAYLAND -#include "yasl/native/wayland.h" +#include "common/private_native_wayland.h" #endif static inline uint64_t get_time_ns(void) { @@ -48,28 +48,28 @@ static void print_bench_skipped(const char *name, const char *reason) { static void bench_surface_lookup(void) { const int num_surfaces = 16; const int lookups = 10000000; - struct yasl_display_spec spec = { + struct yasl_private_display_spec spec = { .app_id = "org.yasl.benchmark", - .backend = YASL_BACKEND_WAYLAND, + .backend = YASL_PRIVATE_BACKEND_WAYLAND, }; - struct yasl_display *d = yasl_display_open(NULL, &spec); + struct yasl_private_display *d = yasl_private_display_open(NULL, &spec); struct yasl_surface *surfaces[num_surfaces]; memset(surfaces, 0, sizeof(surfaces)); if (d) { for (int i = 0; i < num_surfaces; i++) { - struct yasl_window_spec sspec = { + struct yasl_private_window_spec sspec = { .title = "Benchmark", .size = { .x = 320, .y = 240 }, }; - surfaces[i] = yasl_surface_create_toplevel(d, &sspec); + surfaces[i] = yasl_private_surface_create_toplevel(d, &sspec); } } uint64_t t0 = get_time_ns(); uintptr_t sum = 0; for (int i = 0; i < lookups; i++) { - struct wl_surface *found = yasl_wayland_surface_get_wl_surface(surfaces[i % num_surfaces]); + struct wl_surface *found = yasl_private_wayland_surface_get_wl_surface(surfaces[i % num_surfaces]); sum += (uintptr_t)found; } uint64_t t1 = get_time_ns(); @@ -82,35 +82,35 @@ static void bench_surface_lookup(void) { if (d) { for (int i = 0; i < num_surfaces; i++) { - if (surfaces[i]) yasl_surface_destroy(surfaces[i]); + if (surfaces[i]) yasl_private_surface_destroy(surfaces[i]); } - yasl_display_close(d); + yasl_private_display_close(d); } } /* Benchmark 2: Public Surface Geometry & Refresh Timing */ static void bench_output_follow(void) { const int iters = 10000000; - struct yasl_display_spec spec = { + struct yasl_private_display_spec spec = { .app_id = "org.yasl.benchmark", - .backend = YASL_BACKEND_WAYLAND, + .backend = YASL_PRIVATE_BACKEND_WAYLAND, }; - struct yasl_display *d = yasl_display_open(NULL, &spec); + struct yasl_private_display *d = yasl_private_display_open(NULL, &spec); struct yasl_surface *s = NULL; if (d) { - struct yasl_window_spec sspec = { + struct yasl_private_window_spec sspec = { .title = "Benchmark", .size = { .x = 320, .y = 240 }, }; - s = yasl_surface_create_toplevel(d, &sspec); + s = yasl_private_surface_create_toplevel(d, &sspec); } uint64_t t0 = get_time_ns(); uint64_t sum = 0; for (int i = 0; i < iters; i++) { - struct yasl_geometry geom = yasl_surface_geometry(s); - struct yasl_timing timing = yasl_surface_timing(s); - int dev = yasl_scale_to_device(320.0, geom.scale_120); + struct yasl_private_geometry geom = yasl_private_surface_geometry(s); + struct yasl_private_timing timing = yasl_private_surface_timing(s); + int dev = yasl_private_scale_to_device(320.0, geom.scale_120); sum += (uint64_t)dev + timing.refresh_ns; } uint64_t t1 = get_time_ns(); @@ -121,8 +121,8 @@ static void bench_output_follow(void) { iters, (unsigned long long)sum); print_bench_row("[2] surface_geometry_timing", per_cycle, ms, details); - if (s) yasl_surface_destroy(s); - if (d) yasl_display_close(d); + if (s) yasl_private_surface_destroy(s); + if (d) yasl_private_display_close(d); } #endif @@ -135,8 +135,8 @@ static void bench_input_queue_resize(void) { for (int b = 0; b < batches; b++) { struct input_queue q = {0}; for (int i = 0; i < size; i++) { - struct yasl_event ev = { - .type = YASL_EVENT_POINTER_MOTION, + struct yasl_private_event ev = { + .type = YASL_PRIVATE_EVENT_POINTER_MOTION, .pointer = { .pos = { .x = i, .y = b } }, }; input_queue_push(&q, &ev); @@ -160,13 +160,13 @@ static void bench_input_queue_push_pop(void) { uint64_t t0 = get_time_ns(); for (int r = 0; r < rounds; r++) { for (int i = 0; i < events_per_round; i++) { - struct yasl_event ev = { - .type = YASL_EVENT_POINTER_DOWN, - .pointer = { .pos = { .x = i, .y = r }, .button = YASL_BUTTON_MIDDLE }, + struct yasl_private_event ev = { + .type = YASL_PRIVATE_EVENT_POINTER_DOWN, + .pointer = { .pos = { .x = i, .y = r }, .button = YASL_PRIVATE_BUTTON_MIDDLE }, }; input_queue_push(&q, &ev); } - struct yasl_event out; + struct yasl_private_event out; while (input_queue_pop(&q, &out)) { /* consume */ } @@ -181,22 +181,22 @@ static void bench_input_queue_push_pop(void) { } /* Benchmark 5: Event Loop Timers Add & Delete */ -static uint64_t timer_dummy_cb(void *ud, yasl_timer_id id, uint64_t interval_ns) { +static uint64_t timer_dummy_cb(void *ud, yasl_private_timer_id id, uint64_t interval_ns) { (void)ud; (void)id; (void)interval_ns; return 0; } static void bench_timers(void) { const int iters = 2000000; - struct yasl_loop *loop = yasl_loop_create(); + struct yasl_private_loop *loop = yasl_private_loop_create(); uint64_t t0 = get_time_ns(); for (int i = 0; i < iters; i++) { - yasl_timer_id id = yasl_loop_add_timer(loop, 1000000, timer_dummy_cb, NULL); - yasl_loop_del_timer(loop, id); + yasl_private_timer_id id = yasl_private_loop_add_timer(loop, 1000000, timer_dummy_cb, NULL); + yasl_private_loop_del_timer(loop, id); } uint64_t t1 = get_time_ns(); - yasl_loop_destroy(loop); + yasl_private_loop_destroy(loop); double ms = (double)(t1 - t0) / 1e6; double per_cycle = (double)(t1 - t0) / iters; char details[128]; @@ -207,30 +207,30 @@ static void bench_timers(void) { /* Benchmark 6: Window Cold Create & Teardown */ static void bench_window_cold_create(void) { const int iters = 200; - struct yasl_display_spec dspec = { .app_id = "org.yasl.bench.cold" }; - struct yasl_window_spec sspec = { + struct yasl_private_display_spec dspec = { .app_id = "org.yasl.bench.cold" }; + struct yasl_private_window_spec sspec = { .title = "Benchmark Cold", .size = { .x = 320, .y = 240 }, }; - struct yasl_display *probe = yasl_display_open(NULL, &dspec); + struct yasl_private_display *probe = yasl_private_display_open(NULL, &dspec); if (!probe) { print_bench_skipped("[6] window_cold_create", "no display server"); return; } - yasl_display_close(probe); + yasl_private_display_close(probe); uint64_t t0 = get_time_ns(); int count = 0; for (int i = 0; i < iters; i++) { - struct yasl_display *d = yasl_display_open(NULL, &dspec); + struct yasl_private_display *d = yasl_private_display_open(NULL, &dspec); if (d) { - struct yasl_surface *s = yasl_surface_create_toplevel(d, &sspec); + struct yasl_surface *s = yasl_private_surface_create_toplevel(d, &sspec); if (s) { - yasl_surface_destroy(s); + yasl_private_surface_destroy(s); count++; } - yasl_display_close(d); + yasl_private_display_close(d); } } uint64_t t1 = get_time_ns(); @@ -244,14 +244,14 @@ static void bench_window_cold_create(void) { /* Benchmark 7: Window Warm Create */ static void bench_window_warm_create(void) { const int iters = 2000; - struct yasl_display_spec dspec = { .app_id = "org.yasl.bench.warm" }; - struct yasl_display *d = yasl_display_open(NULL, &dspec); + struct yasl_private_display_spec dspec = { .app_id = "org.yasl.bench.warm" }; + struct yasl_private_display *d = yasl_private_display_open(NULL, &dspec); if (!d) { print_bench_skipped("[7] window_warm_create", "no display server"); return; } - struct yasl_window_spec sspec = { + struct yasl_private_window_spec sspec = { .title = "Benchmark Warm", .size = { .x = 320, .y = 240 }, }; @@ -259,14 +259,14 @@ static void bench_window_warm_create(void) { uint64_t t0 = get_time_ns(); int count = 0; for (int i = 0; i < iters; i++) { - struct yasl_surface *s = yasl_surface_create_toplevel(d, &sspec); + struct yasl_surface *s = yasl_private_surface_create_toplevel(d, &sspec); if (s) { - yasl_surface_destroy(s); + yasl_private_surface_destroy(s); count++; } } uint64_t t1 = get_time_ns(); - yasl_display_close(d); + yasl_private_display_close(d); double ms = (double)(t1 - t0) / 1e6; double per_cycle = count ? (double)(t1 - t0) / count : 0.0; char details[128]; @@ -277,14 +277,14 @@ static void bench_window_warm_create(void) { /* Benchmark 8: Window Shutdown (Single) */ static void bench_window_shutdown_single(void) { const int iters = 2000; - struct yasl_display_spec dspec = { .app_id = "org.yasl.bench.shutdown_single" }; - struct yasl_display *d = yasl_display_open(NULL, &dspec); + struct yasl_private_display_spec dspec = { .app_id = "org.yasl.bench.shutdown_single" }; + struct yasl_private_display *d = yasl_private_display_open(NULL, &dspec); if (!d) { print_bench_skipped("[8] window_shutdown_single", "no display server"); return; } - struct yasl_window_spec sspec = { + struct yasl_private_window_spec sspec = { .title = "Benchmark Shutdown Single", .size = { .x = 320, .y = 240 }, }; @@ -292,16 +292,16 @@ static void bench_window_shutdown_single(void) { uint64_t destroy_time_ns = 0; int count = 0; for (int i = 0; i < iters; i++) { - struct yasl_surface *s = yasl_surface_create_toplevel(d, &sspec); + struct yasl_surface *s = yasl_private_surface_create_toplevel(d, &sspec); if (s) { uint64_t t0 = get_time_ns(); - yasl_surface_destroy(s); + yasl_private_surface_destroy(s); uint64_t t1 = get_time_ns(); destroy_time_ns += (t1 - t0); count++; } } - yasl_display_close(d); + yasl_private_display_close(d); double ms = (double)destroy_time_ns / 1e6; double per_cycle = count ? (double)destroy_time_ns / count : 0.0; char details[128]; @@ -313,14 +313,14 @@ static void bench_window_shutdown_single(void) { static void bench_window_shutdown_all(void) { const int batches = 50; const int batch_size = 64; - struct yasl_display_spec dspec = { .app_id = "org.yasl.bench.shutdown_all" }; - struct yasl_display *d = yasl_display_open(NULL, &dspec); + struct yasl_private_display_spec dspec = { .app_id = "org.yasl.bench.shutdown_all" }; + struct yasl_private_display *d = yasl_private_display_open(NULL, &dspec); if (!d) { print_bench_skipped("[9] window_shutdown_all", "no display server"); return; } - struct yasl_window_spec sspec = { + struct yasl_private_window_spec sspec = { .title = "Benchmark Bulk Window", .size = { .x = 320, .y = 240 }, }; @@ -331,12 +331,12 @@ static void bench_window_shutdown_all(void) { for (int b = 0; b < batches; b++) { for (int i = 0; i < batch_size; i++) { - surfaces[i] = yasl_surface_create_toplevel(d, &sspec); + surfaces[i] = yasl_private_surface_create_toplevel(d, &sspec); } uint64_t t0 = get_time_ns(); for (int i = 0; i < batch_size; i++) { if (surfaces[i]) { - yasl_surface_destroy(surfaces[i]); + yasl_private_surface_destroy(surfaces[i]); surfaces[i] = NULL; total_destroyed++; } @@ -344,7 +344,7 @@ static void bench_window_shutdown_all(void) { uint64_t t1 = get_time_ns(); destroy_time_ns += (t1 - t0); } - yasl_display_close(d); + yasl_private_display_close(d); double ms = (double)destroy_time_ns / 1e6; double per_cycle = total_destroyed ? (double)destroy_time_ns / total_destroyed : 0.0; double per_batch_ns = batches ? (double)destroy_time_ns / batches : 0.0; @@ -359,20 +359,20 @@ static void bench_window_shutdown_all(void) { /* Benchmark 10: Window Titlebar Update */ static void bench_window_title_update(void) { const int iters = 200000; - struct yasl_display_spec dspec = { .app_id = "org.yasl.bench.title" }; - struct yasl_display *d = yasl_display_open(NULL, &dspec); + struct yasl_private_display_spec dspec = { .app_id = "org.yasl.bench.title" }; + struct yasl_private_display *d = yasl_private_display_open(NULL, &dspec); if (!d) { print_bench_skipped("[10] window_titlebar_update", "no display server"); return; } - struct yasl_window_spec sspec = { + struct yasl_private_window_spec sspec = { .title = "Initial Title", .size = { .x = 320, .y = 240 }, }; - struct yasl_surface *s = yasl_surface_create_toplevel(d, &sspec); + struct yasl_surface *s = yasl_private_surface_create_toplevel(d, &sspec); if (!s) { - yasl_display_close(d); + yasl_private_display_close(d); print_bench_skipped("[10] window_titlebar_update", "failed to create surface"); return; } @@ -386,11 +386,11 @@ static void bench_window_title_update(void) { uint64_t t0 = get_time_ns(); for (int i = 0; i < iters; i++) { - yasl_surface_set_title(s, titles[i & 3]); + yasl_private_surface_set_title(s, titles[i & 3]); } uint64_t t1 = get_time_ns(); - yasl_surface_destroy(s); - yasl_display_close(d); + yasl_private_surface_destroy(s); + yasl_private_display_close(d); double ms = (double)(t1 - t0) / 1e6; double per_cycle = (double)(t1 - t0) / iters; char details[128]; @@ -401,14 +401,14 @@ static void bench_window_title_update(void) { /* Benchmark 11: Window Resize / Dimension Reallocation */ static void bench_window_resize(void) { const int iters = 2000; - struct yasl_display_spec dspec = { .app_id = "org.yasl.bench.resize" }; - struct yasl_display *d = yasl_display_open(NULL, &dspec); + struct yasl_private_display_spec dspec = { .app_id = "org.yasl.bench.resize" }; + struct yasl_private_display *d = yasl_private_display_open(NULL, &dspec); if (!d) { print_bench_skipped("[11] window_resize_cycle", "no display server"); return; } - static const struct yasl_vector2i sizes[] = { + static const struct yasl_private_vector2i sizes[] = { { 320, 240 }, { 640, 480 }, { 800, 600 }, @@ -421,20 +421,20 @@ static void bench_window_resize(void) { uint64_t t0 = get_time_ns(); int count = 0; for (int i = 0; i < iters; i++) { - struct yasl_window_spec sspec = { + struct yasl_private_window_spec sspec = { .title = "Resize Bench", .size = sizes[i % num_sizes], }; - struct yasl_surface *s = yasl_surface_create_toplevel(d, &sspec); + struct yasl_surface *s = yasl_private_surface_create_toplevel(d, &sspec); if (s) { - struct yasl_geometry geom = yasl_surface_geometry(s); + struct yasl_private_geometry geom = yasl_private_surface_geometry(s); (void)geom; - yasl_surface_destroy(s); + yasl_private_surface_destroy(s); count++; } } uint64_t t1 = get_time_ns(); - yasl_display_close(d); + yasl_private_display_close(d); double ms = (double)(t1 - t0) / 1e6; double per_cycle = count ? (double)(t1 - t0) / count : 0.0; char details[128]; diff --git a/tests/cocoa/test_cursor.m b/tests/cocoa/test_cursor.m index 4054d59..4c961df 100644 --- a/tests/cocoa/test_cursor.m +++ b/tests/cocoa/test_cursor.m @@ -1,5 +1,5 @@ #import <AppKit/AppKit.h> -#include <yasl/native.h> +#include <common/private_native.h> #include <assert.h> static void assert_transparent(NSCursor *cursor) @@ -15,18 +15,18 @@ static void assert_transparent(NSCursor *cursor) int main(void) { @autoreleasepool { - struct yasl_display *display = yasl_display_open(NULL, NULL); + struct yasl_private_display *display = yasl_private_display_open(NULL, NULL); assert(display); - struct yasl_window_spec spec = {.title = "Cursor test", .size = {320, 240}}; - struct yasl_surface *surface = yasl_surface_create_toplevel(display, &spec); + struct yasl_private_window_spec spec = {.title = "Cursor test", .size = {320, 240}}; + struct yasl_surface *surface = yasl_private_surface_create_toplevel(display, &spec); assert(surface); - NSWindow *window = (NSWindow *)yasl_surface_get_native_handle(surface); + NSWindow *window = (NSWindow *)yasl_private_surface_get_native_handle(surface); NSView *view = window.contentView; NSEvent *cursor = [NSEvent enterExitEventWithType:NSEventTypeCursorUpdate location:NSMakePoint(100, 120) modifierFlags:0 timestamp:0 windowNumber:window.windowNumber context:nil eventNumber:0 trackingNumber:0 userData:NULL]; assert(cursor); - yasl_surface_set_cursor(surface, YASL_CURSOR_HIDDEN); + yasl_private_surface_set_cursor(surface, YASL_PRIVATE_CURSOR_HIDDEN); [view cursorUpdate:cursor]; NSCursor *hidden = [NSCursor currentCursor]; assert_transparent(hidden); @@ -37,21 +37,21 @@ int main(void) [view mouseMoved:motion]; [view cursorUpdate:cursor]; assert([NSCursor currentCursor] == hidden); - struct yasl_event event; + struct yasl_private_event event; bool moved = false; - while (yasl_surface_poll_event(surface, &event)) - if (event.type == YASL_EVENT_POINTER_MOTION) + while (yasl_private_surface_poll_event(surface, &event)) + if (event.type == YASL_PRIVATE_EVENT_POINTER_MOTION) moved = true; assert(moved); [[NSCursor arrowCursor] set]; /* Simulate leaving and re-entering. */ [view cursorUpdate:cursor]; assert([NSCursor currentCursor] == hidden); - yasl_surface_set_cursor(surface, YASL_CURSOR_ARROW); + yasl_private_surface_set_cursor(surface, YASL_PRIVATE_CURSOR_ARROW); [view cursorUpdate:cursor]; assert([NSCursor currentCursor] == [NSCursor arrowCursor]); - yasl_surface_destroy(surface); - yasl_display_close(display); + yasl_private_surface_destroy(surface); + yasl_private_display_close(display); } return 0; } diff --git a/tests/cocoa/test_keyboard.m b/tests/cocoa/test_keyboard.m index f93a745..a41011c 100644 --- a/tests/cocoa/test_keyboard.m +++ b/tests/cocoa/test_keyboard.m @@ -1,5 +1,6 @@ #import <AppKit/AppKit.h> -#include <yasl/native.h> +#include <common/private_native.h> +#include <common/backend.h> #include <assert.h> #include <math.h> #include <string.h> @@ -31,32 +32,40 @@ } @end -static struct yasl_event next(struct yasl_surface *surface, enum yasl_event_type type) +static struct yasl_private_event next(struct yasl_surface *surface, enum yasl_private_event_type type) { - struct yasl_event event; - assert(yasl_surface_poll_event(surface, &event)); + struct yasl_private_event event; + assert(yasl_private_surface_poll_event(surface, &event)); assert(event.type == type && event.surface == surface); return event; } static void empty(struct yasl_surface *surface) { - struct yasl_event event; - assert(!yasl_surface_poll_event(surface, &event)); + struct yasl_private_event event; + assert(!yasl_private_surface_poll_event(surface, &event)); } int main(void) { @autoreleasepool { - struct yasl_display *display = yasl_display_open(NULL, NULL); + struct yasl_private_display *display = yasl_private_display_open(NULL, NULL); assert(display); - struct yasl_window_spec spec = {.title = "Keyboard test", .size = {320, 240}}; - struct yasl_surface *surface = yasl_surface_create_toplevel(display, &spec); + struct yasl_private_window_spec spec = {.title = "Keyboard test", .size = {320, 240}}; + struct yasl_surface *surface = yasl_private_surface_create_toplevel(display, &spec); assert(surface); - NSWindow *window = (NSWindow *)yasl_surface_get_native_handle(surface); + surface->text_input_active = true; + surface->text_surrounding = strdup("A😀B"); + surface->text_length = strlen(surface->text_surrounding); + surface->text_begin = 1; + surface->text_end = 5; + surface->text_revision = 7; + surface->text_generation = 3; + assert(display->ops->surface_update_text_input(surface)); + NSWindow *window = (NSWindow *)yasl_private_surface_get_native_handle(surface); NSView<NSTextInputClient> *view = (id)window.contentView; - struct yasl_event event; - while (yasl_surface_poll_event(surface, &event)) {} + struct yasl_private_event event; + while (yasl_private_surface_poll_event(surface, &event)) {} InputSample *sample = [InputSample new]; NSEvent *native = (NSEvent *)sample; @@ -65,7 +74,7 @@ int main(void) sample.label = @"q"; sample.shiftedLabel = @"Q"; [view keyUp:native]; - event = next(surface, YASL_EVENT_KEY); + event = next(surface, YASL_PRIVATE_EVENT_KEY); assert(event.key.key == YASL_KEY_A && event.key.native_code == 0); assert(event.key.action == YASL_KEY_RELEASE); assert(event.key.codepoint == 'q' && event.key.shifted == 'Q'); @@ -73,29 +82,31 @@ int main(void) sample.label = @"😀"; /* One scalar, two UTF-16 units. */ sample.shiftedLabel = @"ab"; [view keyUp:native]; - event = next(surface, YASL_EVENT_KEY); + event = next(surface, YASL_PRIVATE_EVENT_KEY); assert(event.key.codepoint == 0x1f600 && event.key.shifted == 0); sample.type = NSEventTypeFlagsChanged; sample.keyCode = 56; /* Left Shift. */ sample.modifierFlags = NSEventModifierFlagShift | 0x0002; [view flagsChanged:native]; - event = next(surface, YASL_EVENT_KEY); + event = next(surface, YASL_PRIVATE_EVENT_KEY); assert(event.key.key == YASL_KEY_LEFT_SHIFT && event.key.action == YASL_KEY_PRESS); - assert(event.key.mods == YASL_MOD_SHIFT && !event.key.codepoint && !event.key.shifted); + assert(event.key.mods == YASL_PRIVATE_MOD_SHIFT && !event.key.codepoint && !event.key.shifted); sample.modifierFlags = 0; [view flagsChanged:native]; - assert(next(surface, YASL_EVENT_KEY).key.action == YASL_KEY_RELEASE); + assert(next(surface, YASL_PRIVATE_EVENT_KEY).key.action == YASL_KEY_RELEASE); /* Native text services own preedit and commits. Marked text is not an * insertion, and commits retain all UTF-8 bytes, including non-BMP. */ [view setMarkedText:@"é" selectedRange:NSMakeRange(1, 0) - replacementRange:NSMakeRange(NSNotFound, 0)]; - assert(strcmp(yasl_surface_ime_preedit(surface), "é") == 0); + replacementRange:NSMakeRange(1, 2)]; + assert(strcmp(yasl_private_surface_ime_preedit(surface), "é") == 0); empty(surface); [view insertText:@"😀é" replacementRange:NSMakeRange(NSNotFound, 0)]; - event = next(surface, YASL_EVENT_TEXT); - assert(event.text.len == strlen("😀é") && strcmp(event.text.data, "😀é") == 0); - assert(!yasl_surface_ime_preedit(surface)); + event = next(surface, YASL_PRIVATE_EVENT_TEXT_EDIT); + assert(event.text_edit.len == strlen("😀é") && strcmp(event.text_edit.data, "😀é") == 0); + assert(event.text_edit.begin == 1 && event.text_edit.end == 5); + assert(event.text_edit.revision == 7 && event.text_edit.generation == 3); + assert(!yasl_private_surface_ime_preedit(surface)); empty(surface); /* Exercise the keyDown -> interpretKeyEvents -> insertText route with @@ -104,9 +115,16 @@ int main(void) modifierFlags:0 timestamp:0 windowNumber:window.windowNumber context:nil characters:@"a" charactersIgnoringModifiers:@"a" isARepeat:NO keyCode:0]; [view keyDown:press]; - assert(next(surface, YASL_EVENT_KEY).key.key == YASL_KEY_A); - event = next(surface, YASL_EVENT_TEXT); - assert(event.text.len == 1 && event.text.data[0] == 'a'); + assert(next(surface, YASL_PRIVATE_EVENT_KEY).key.key == YASL_KEY_A); + event = next(surface, YASL_PRIVATE_EVENT_TEXT_EDIT); + assert(event.text_edit.len == 1 && event.text_edit.data[0] == 'a'); + assert(event.text_edit.begin == 1 && event.text_edit.end == 5); + empty(surface); + + surface->text_end = 1; + [view doCommandBySelector:@selector(deleteBackward)]; + event = next(surface, YASL_PRIVATE_EVENT_TEXT_EDIT); + assert(event.text_edit.len == 0 && event.text_edit.begin == 0 && event.text_edit.end == 1); empty(surface); sample.type = NSEventTypeScrollWheel; @@ -114,20 +132,20 @@ int main(void) sample.scrollingDeltaX = -2.5; sample.scrollingDeltaY = 1.25; [view scrollWheel:native]; - event = next(surface, YASL_EVENT_POINTER_SCROLL); + event = next(surface, YASL_PRIVATE_EVENT_POINTER_SCROLL); assert(event.pointer.scroll.x == 0.25 && event.pointer.scroll.y == -0.125); sample.hasPreciseScrollingDeltas = NO; sample.scrollingDeltaX = 1; sample.scrollingDeltaY = -1; [view scrollWheel:native]; - event = next(surface, YASL_EVENT_POINTER_SCROLL); + event = next(surface, YASL_PRIVATE_EVENT_POINTER_SCROLL); assert(event.pointer.scroll.x == -1 && event.pointer.scroll.y == 1); sample.scrollingDeltaX = NAN; [view scrollWheel:native]; empty(surface); [sample release]; - yasl_surface_destroy(surface); - yasl_display_close(display); + yasl_private_surface_destroy(surface); + yasl_private_display_close(display); } return 0; } diff --git a/tests/cocoa/test_native.c b/tests/cocoa/test_native.c index 674513d..9b8f8fa 100644 --- a/tests/cocoa/test_native.c +++ b/tests/cocoa/test_native.c @@ -1,77 +1,77 @@ #define _POSIX_C_SOURCE 200809L -#include "yasl/native.h" -#include "yasl/loop.h" -#include "yasl/yasl.h" +#include "common/private_native.h" +#include "common/private_loop.h" +#include "common/types.h" #include <assert.h> #include <time.h> struct state { - struct yasl_display *display; + struct yasl_private_display *display; struct yasl_surface *surface; unsigned draws; }; -static void draw(struct yasl_surface *surface, struct yasl_frame *frame, void *ud) +static void draw(struct yasl_surface *surface, struct yasl_private_frame *frame, void *ud) { struct state *state = ud; assert(surface == state->surface && frame->surface == surface); - assert(yasl_surface_display(surface) == state->display); + assert(yasl_private_surface_display(surface) == state->display); assert(frame->target.pixels); - struct yasl_native_frame native; - assert(yasl_surface_get_native_frame(surface, &frame->target, &native)); + struct yasl_private_native_frame native; + assert(yasl_private_surface_get_native_frame(surface, &frame->target, &native)); assert(native.drawable); - struct yasl_vector2i size = yasl_surface_geometry(surface).size; + struct yasl_private_vector2i size = yasl_private_surface_geometry(surface).size; assert(size.x == frame->target.size.x && size.y == frame->target.size.y); 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(surface, &frame->target, &damage)); + struct yasl_private_damage_list damage = {.n = YASL_PRIVATE_DAMAGE_MAX + 1}; + assert(!yasl_private_surface_present(surface, &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(surface, &invalid, &damage)); + assert(!yasl_private_surface_present(surface, &invalid, &damage)); invalid = frame->target; invalid.generation--; - assert(!yasl_surface_present(surface, &invalid, &damage)); - assert(!yasl_surface_present(surface, &frame->target, NULL)); - assert(yasl_surface_present(surface, &frame->target, &damage)); - assert(!yasl_surface_get_native_frame(surface, &frame->target, &native)); - assert(!yasl_surface_present(surface, &frame->target, &damage)); + assert(!yasl_private_surface_present(surface, &invalid, &damage)); + assert(!yasl_private_surface_present(surface, &frame->target, NULL)); + assert(yasl_private_surface_present(surface, &frame->target, &damage)); + assert(!yasl_private_surface_get_native_frame(surface, &frame->target, &native)); + assert(!yasl_private_surface_present(surface, &frame->target, &damage)); state->draws++; - yasl_surface_destroy(surface); + yasl_private_surface_destroy(surface); state->surface = NULL; } -static void test_window(enum yasl_backend request, bool null_spec) +static void test_window(enum yasl_private_backend request, bool null_spec) { - struct yasl_display_spec spec = {.backend = request}; - struct state state = {.display = yasl_display_open(NULL, null_spec ? NULL : &spec)}; + struct yasl_private_display_spec spec = {.backend = request}; + struct state state = {.display = yasl_private_display_open(NULL, null_spec ? NULL : &spec)}; assert(state.display); - assert(yasl_display_backend(state.display) == YASL_BACKEND_COCOA); - struct yasl_window_cbs callbacks = {.draw = draw}; - struct yasl_window_spec surface = { + assert(yasl_private_display_backend(state.display) == YASL_PRIVATE_BACKEND_COCOA); + struct yasl_private_window_cbs callbacks = {.draw = draw}; + struct yasl_private_window_spec surface = { .title = "Native backend test", .size = {160, 100}, .cbs = &callbacks, .ud = &state, }; - state.surface = yasl_surface_create_toplevel(state.display, &surface); + state.surface = yasl_private_surface_create_toplevel(state.display, &surface); assert(state.surface); assert(!state.draws); callbacks.draw = NULL; - yasl_surface_schedule_redraw(state.surface); - uint64_t deadline = yasl_loop_now_ns() + 3000000000ull; - while (!state.draws && yasl_loop_now_ns() < deadline) { - yasl_display_dispatch(state.display, 0); - yasl_display_flush(state.display); + yasl_private_surface_schedule_redraw(state.surface); + uint64_t deadline = yasl_private_loop_now_ns() + 3000000000ull; + while (!state.draws && yasl_private_loop_now_ns() < deadline) { + yasl_private_display_dispatch(state.display, 0); + yasl_private_display_flush(state.display); nanosleep(&(struct timespec){.tv_nsec = 1000000}, NULL); } assert(state.draws == 1 && !state.surface); - yasl_display_close(state.display); + yasl_private_display_close(state.display); } int main(void) { - test_window(YASL_BACKEND_AUTO, true); - test_window(YASL_BACKEND_AUTO, false); - test_window(YASL_BACKEND_COCOA, false); + test_window(YASL_PRIVATE_BACKEND_AUTO, true); + test_window(YASL_PRIVATE_BACKEND_AUTO, false); + test_window(YASL_PRIVATE_BACKEND_COCOA, false); return 0; } diff --git a/tests/cocoa/test_ownership.m b/tests/cocoa/test_ownership.m index 6d69907..4efd164 100644 --- a/tests/cocoa/test_ownership.m +++ b/tests/cocoa/test_ownership.m @@ -1,7 +1,9 @@ -#include "yasl/native.h" -#include "yasl/native/cocoa.h" +#include "common/private_native.h" +#include "common/private_native_cocoa.h" +#include "common/backend.h" #import <AppKit/AppKit.h> -#include "yasl/yasl.h" +#import <Metal/Metal.h> +#include "common/types.h" #include <assert.h> #include <errno.h> #include <stdio.h> @@ -9,60 +11,98 @@ int main(void) { - struct yasl_display *d = yasl_display_open(NULL, NULL); + struct yasl_private_display *d = yasl_private_display_open(NULL, NULL); assert(d); - struct yasl_window_spec spec = {.title = "Ownership test", .size = {160, 100}}; - struct yasl_surface *s = yasl_surface_create_toplevel(d, &spec); + assert(yasl_private_display_caps(d) & YASL_PRIVATE_CAP_TEXT_INPUT); + struct yasl_private_window_spec spec = {.title = "Ownership test", .size = {160, 100}}; + struct yasl_surface *s = yasl_private_surface_create_toplevel(d, &spec); assert(s); - assert(yasl_display_get_native_handle(d) == (void *)NSApp); - assert(yasl_cocoa_display_get_application(d) == NSApp); - NSWindow *window = (NSWindow *)yasl_surface_get_native_handle(s); - assert(yasl_cocoa_surface_get_window(s) == window); - assert(yasl_cocoa_surface_get_view(s) == window.contentView); + assert(yasl_private_display_get_native_handle(d) == (void *)NSApp); + assert(yasl_private_cocoa_display_get_application(d) == NSApp); + NSWindow *window = (NSWindow *)yasl_private_surface_get_native_handle(s); + assert(yasl_private_cocoa_surface_get_window(s) == window); + assert(yasl_private_cocoa_surface_get_view(s) == window.contentView); assert([window isKindOfClass:[NSWindow class]] && window.contentView); - struct yasl_event event; - while (yasl_display_poll_event(d, &event)) {} + struct yasl_private_event event; + while (yasl_private_display_poll_event(d, &event)) {} - assert(yasl_surface_set_size(s, (struct yasl_vector2i){180, 110})); - assert(yasl_surface_set_fullscreen(s, false)); - assert(yasl_surface_set_maximized(s, false)); - assert(!yasl_surface_set_size(s, (struct yasl_vector2i){0, 100})); + struct yasl_private_window_spec gpu_spec = { + .flags = YASL_PRIVATE_SURFACE_HIDDEN | YASL_PRIVATE_SURFACE_UNDECORATED | + YASL_PRIVATE_SURFACE_FIXED_SIZE, + .external_gpu = true, + .title = "External GPU test", + .size = {160, 100}, + }; + struct yasl_surface *gpu = yasl_private_surface_create_toplevel(d, &gpu_spec); + assert(gpu && gpu->presenter == YASL_PRIVATE_PRESENTER_NONE); + CAMetalLayer *metal = (CAMetalLayer *)d->ops->surface_get_metal_layer(gpu); + assert(metal && [metal isKindOfClass:[CAMetalLayer class]] && !metal.device); + NSWindow *hidden = (NSWindow *)yasl_private_surface_get_native_handle(gpu); + assert(!hidden.isVisible && hidden.styleMask == NSWindowStyleMaskBorderless); + yasl_private_surface_destroy(gpu); + + struct yasl_surface *gl = d->ops->surface_create_gl(d, &gpu_spec, NULL, NULL); + if (gl) { + assert(gl->presenter == YASL_PRIVATE_PRESENTER_GL); + assert(d->ops->gl_make_current(d, gl)); + assert(d->ops->gl_get_proc_address(d, "glClear") != NULL); + assert(d->ops->gl_swap_interval(d, gl, 1)); + assert(d->ops->gl_swap_buffers(d, gl)); + assert(d->ops->gl_make_current(d, NULL)); + d->ops->surface_destroy(gl); + } + + assert(yasl_private_surface_set_size(s, (struct yasl_private_vector2i){180, 110})); + assert(yasl_private_surface_set_fullscreen(s, false)); + assert(yasl_private_surface_set_maximized(s, false)); + assert(!yasl_private_surface_set_size(s, (struct yasl_private_vector2i){0, 100})); assert(errno == EINVAL); - struct yasl_popup_spec popup_spec = { + struct yasl_private_popup_spec popup_spec = { + .positioner_explicit = true, + .anchor_edges = 4, .gravity = 3, .constraints = 63, .size = {80, 40}, .anchor = {10, 10, 2, 2}, }; - struct yasl_surface *popup = yasl_surface_create_popup(s, &popup_spec); + struct yasl_surface *popup = yasl_private_surface_create_popup(s, &popup_spec); assert(popup); - assert(!yasl_surface_set_size(popup, (struct yasl_vector2i){80, 40})); + popup_spec.anchor_edges = 8; + popup_spec.gravity = 5; + assert(yasl_private_surface_popup_reposition(popup, &popup_spec)); + assert(!yasl_private_surface_set_size(popup, (struct yasl_private_vector2i){80, 40})); assert(errno == EINVAL); - assert(!yasl_surface_set_fullscreen(popup, true) && errno == EINVAL); - assert(!yasl_surface_set_maximized(popup, true) && errno == EINVAL); - assert(!yasl_surface_minimize(popup) && errno == EINVAL); - yasl_surface_destroy(popup); - while (yasl_display_poll_event(d, &event)) {} + assert(!yasl_private_surface_set_fullscreen(popup, true) && errno == EINVAL); + assert(!yasl_private_surface_set_maximized(popup, true) && errno == EINVAL); + assert(!yasl_private_surface_minimize(popup) && errno == EINVAL); + yasl_private_surface_destroy(popup); + while (yasl_private_display_poll_event(d, &event)) {} - id<NSTextInputClient> text_input = (id<NSTextInputClient>)yasl_cocoa_surface_get_view(s); + s->text_input_active = true; + s->text_surrounding = strdup("é漢"); + s->text_length = strlen(s->text_surrounding); + s->text_begin = 0; + s->text_end = s->text_length; + assert(d->ops->surface_update_text_input(s)); + id<NSTextInputClient> text_input = (id<NSTextInputClient>)yasl_private_cocoa_surface_get_view(s); [text_input setMarkedText:@"é漢" selectedRange:NSMakeRange(1, 1) replacementRange:NSMakeRange(NSNotFound, 0)]; - assert(strcmp(yasl_surface_ime_preedit(s), "é漢") == 0); + assert(strcmp(yasl_private_surface_ime_preedit(s), "é漢") == 0); [text_input unmarkText]; - assert(yasl_surface_ime_preedit(s) == NULL); - assert(yasl_display_poll_event(d, &event)); - assert(event.type == YASL_EVENT_COMPOSITION && event.composition.active); + assert(yasl_private_surface_ime_preedit(s) == NULL); + assert(yasl_private_display_poll_event(d, &event)); + assert(event.type == YASL_PRIVATE_EVENT_COMPOSITION && event.composition.active); assert(strcmp(event.composition.data, "é漢") == 0); assert(event.composition.begin == 2 && event.composition.end == 5); - assert(yasl_display_poll_event(d, &event)); - assert(event.type == YASL_EVENT_COMPOSITION && !event.composition.active); + assert(yasl_private_display_poll_event(d, &event)); + assert(event.type == YASL_PRIVATE_EVENT_COMPOSITION && !event.composition.active); assert(event.composition.begin == -1 && event.composition.end == -1); - while (yasl_display_poll_event(d, &event)) {} + while (yasl_private_display_poll_event(d, &event)) {} uint64_t request_ids[600]; @autoreleasepool { for (int i = 0; i < 600; i++) { char text[32]; snprintf(text, sizeof(text), "paste-%d", i); - assert(yasl_clipboard_set(d, YASL_CLIPBOARD, text)); - request_ids[i] = yasl_clipboard_request(s, YASL_CLIPBOARD); + assert(yasl_private_clipboard_set(d, YASL_PRIVATE_CLIPBOARD, text)); + request_ids[i] = yasl_private_clipboard_request(s, YASL_PRIVATE_CLIPBOARD); assert(request_ids[i] != 0); memset(text, 'x', sizeof(text)); } @@ -71,32 +111,32 @@ int main(void) for (int i = 0; i < 600; i++) { char text[32]; snprintf(text, sizeof(text), "paste-%d", i); - assert(yasl_display_poll_event(d, &event)); - assert(event.type == YASL_EVENT_PASTE && event.paste.request_id == request_ids[i]); - assert(event.paste.status == YASL_TRANSFER_OK && strcmp(event.paste.data, text) == 0); + assert(yasl_private_display_poll_event(d, &event)); + assert(event.type == YASL_PRIVATE_EVENT_PASTE && event.paste.request_id == request_ids[i]); + assert(event.paste.status == YASL_PRIVATE_TRANSFER_OK && strcmp(event.paste.data, text) == 0); } const char *last = event.paste.data; - assert(!yasl_display_poll_event(d, &event)); - @autoreleasepool { yasl_display_copy(d, YASL_CLIPBOARD, "new selection"); } + assert(!yasl_private_display_poll_event(d, &event)); + @autoreleasepool { yasl_private_display_copy(d, YASL_PRIVATE_CLIPBOARD, "new selection"); } assert(strcmp(last, "paste-599") == 0); - assert(!yasl_clipboard_set(d, YASL_CLIPBOARD, "\xc3")); + assert(!yasl_private_clipboard_set(d, YASL_PRIVATE_CLIPBOARD, "\xc3")); assert(errno == EILSEQ); - assert(yasl_clipboard_set(d, YASL_CLIPBOARD, "")); - uint64_t empty_id = yasl_clipboard_request(s, YASL_CLIPBOARD); - assert(empty_id && yasl_display_poll_event(d, &event)); - assert(event.type == YASL_EVENT_PASTE && event.paste.request_id == empty_id); - assert(event.paste.status == YASL_TRANSFER_OK && !event.paste.len && !event.paste.data[0]); + assert(yasl_private_clipboard_set(d, YASL_PRIVATE_CLIPBOARD, "")); + uint64_t empty_id = yasl_private_clipboard_request(s, YASL_PRIVATE_CLIPBOARD); + assert(empty_id && yasl_private_display_poll_event(d, &event)); + assert(event.type == YASL_PRIVATE_EVENT_PASTE && event.paste.request_id == empty_id); + assert(event.paste.status == YASL_PRIVATE_TRANSFER_OK && !event.paste.len && !event.paste.data[0]); [NSPasteboard.generalPasteboard clearContents]; - uint64_t unavailable_id = yasl_clipboard_request(s, YASL_CLIPBOARD); - assert(unavailable_id && yasl_display_poll_event(d, &event)); - assert(event.type == YASL_EVENT_PASTE && event.paste.request_id == unavailable_id); - assert(event.paste.status == YASL_TRANSFER_UNAVAILABLE && !event.paste.len); - yasl_display_copy(d, YASL_CLIPBOARD, "legacy paste"); - yasl_display_paste(d, YASL_CLIPBOARD, s); - assert(yasl_display_poll_event(d, &event)); - assert(event.type == YASL_EVENT_PASTE && event.paste.request_id == 0); - assert(event.paste.status == YASL_TRANSFER_OK && strcmp(event.text.data, "legacy paste") == 0); - yasl_surface_destroy(s); - yasl_display_close(d); + uint64_t unavailable_id = yasl_private_clipboard_request(s, YASL_PRIVATE_CLIPBOARD); + assert(unavailable_id && yasl_private_display_poll_event(d, &event)); + assert(event.type == YASL_PRIVATE_EVENT_PASTE && event.paste.request_id == unavailable_id); + assert(event.paste.status == YASL_PRIVATE_TRANSFER_UNAVAILABLE && !event.paste.len); + yasl_private_display_copy(d, YASL_PRIVATE_CLIPBOARD, "legacy paste"); + yasl_private_display_paste(d, YASL_PRIVATE_CLIPBOARD, s); + assert(yasl_private_display_poll_event(d, &event)); + assert(event.type == YASL_PRIVATE_EVENT_PASTE && event.paste.request_id == 0); + assert(event.paste.status == YASL_PRIVATE_TRANSFER_OK && strcmp(event.text.data, "legacy paste") == 0); + yasl_private_surface_destroy(s); + yasl_private_display_close(d); return 0; } diff --git a/tests/cocoa/test_tablet.m b/tests/cocoa/test_tablet.m index 715a66e..8eb63d5 100644 --- a/tests/cocoa/test_tablet.m +++ b/tests/cocoa/test_tablet.m @@ -1,5 +1,5 @@ #import <AppKit/AppKit.h> -#include <yasl/native.h> +#include <common/private_native.h> #include <assert.h> /* A strict event double catches querying tablet-only properties on ordinary @@ -15,6 +15,10 @@ @property NSPointingDeviceType tool; @property float samplePressure; @property NSPoint sampleTilt; +@property double sampleRotation; +@property double sampleTangential; +@property NSInteger sampleDeviceID; +@property NSInteger sampleToolID; @end @implementation TabletSample @@ -33,70 +37,106 @@ assert(self.type == NSEventTypeTabletProximity || self.subtype == NSEventSubtypeTabletProximity); return self.tool; } +- (double)rotation { return self.sampleRotation; } +- (double)tangentialPressure { return self.sampleTangential; } +- (NSInteger)pointingDeviceID { return self.sampleDeviceID; } +- (NSInteger)pointingDeviceSerialNumber { return self.sampleToolID; } @end -static struct yasl_event next(struct yasl_surface *surface) +static struct yasl_private_event next(struct yasl_surface *surface, enum yasl_private_event_type type) { - struct yasl_event event; - while (yasl_surface_poll_event(surface, &event)) - return event; - assert(!"Expected a pointer event"); - return (struct yasl_event){0}; + struct yasl_private_event event; + assert(yasl_private_surface_poll_event(surface, &event)); + assert(event.type == type); + return event; } int main(void) { @autoreleasepool { - struct yasl_display *display = yasl_display_open(NULL, NULL); - assert(display && (yasl_display_caps(display) & YASL_CAP_TABLET)); - struct yasl_window_spec spec = {.title = "Tablet test", .size = {320, 240}}; - struct yasl_surface *surface = yasl_surface_create_toplevel(display, &spec); + struct yasl_private_display *display = yasl_private_display_open(NULL, NULL); + assert(display && (yasl_private_display_caps(display) & YASL_PRIVATE_CAP_TABLET)); + struct yasl_private_window_spec spec = {.title = "Tablet test", .size = {320, 240}}; + struct yasl_surface *surface = yasl_private_surface_create_toplevel(display, &spec); assert(surface); - NSWindow *window = (NSWindow *)yasl_surface_get_native_handle(surface); + NSWindow *window = (NSWindow *)yasl_private_surface_get_native_handle(surface); NSView *view = window.contentView; - struct yasl_event event; - while (yasl_surface_poll_event(surface, &event)) {} + struct yasl_private_event event; + while (yasl_private_surface_poll_event(surface, &event)) {} TabletSample *sample = [TabletSample new]; NSEvent *native = (NSEvent *)sample; sample.type = NSEventTypeTabletProximity; sample.enteringProximity = YES; sample.tool = NSPointingDeviceTypePen; + sample.sampleDeviceID = 17; + sample.sampleToolID = 29; [view tabletProximity:native]; sample.type = NSEventTypeMouseMoved; sample.subtype = NSEventSubtypeTabletPoint; sample.locationInWindow = NSMakePoint(100, 120); sample.sampleTilt = NSMakePoint(-0.5, 0.5); + sample.sampleRotation = 37.5; + sample.sampleTangential = -0.25; [view mouseMoved:native]; - struct yasl_event ev = next(surface); - assert(ev.pointer.device == YASL_PTR_DEV_PEN && ev.type == YASL_EVENT_POINTER_MOTION && !ev.pointer.pen.pressure); + struct yasl_private_event pen = next(surface, YASL_PRIVATE_EVENT_PEN); + assert(pen.pen.action == YASL_PRIVATE_PEN_ENTER && pen.pen.device_id == 17 && pen.pen.tool_id == 29); + struct yasl_private_event ev = next(surface, YASL_PRIVATE_EVENT_POINTER_MOTION); + assert(ev.pointer.device == YASL_PRIVATE_PTR_DEV_PEN && ev.type == YASL_PRIVATE_EVENT_POINTER_MOTION && !ev.pointer.pen.pressure); assert(ev.pointer.pen.tilt_x == -45 && ev.pointer.pen.tilt_y == -45); + pen = next(surface, YASL_PRIVATE_EVENT_PEN); + assert(pen.pen.action == YASL_PRIVATE_PEN_MOVE && pen.pen.device_id == 17 && pen.pen.tool_id == 29); + assert((pen.pen.axes_valid & (YASL_PRIVATE_PEN_PRESSURE | YASL_PRIVATE_PEN_TILT)) == + (YASL_PRIVATE_PEN_PRESSURE | YASL_PRIVATE_PEN_TILT)); + assert(pen.pen.rotation == 37.5 && pen.pen.tangential == -0.25); + assert((pen.pen.axes_valid & (YASL_PRIVATE_PEN_ROTATION | YASL_PRIVATE_PEN_TANGENTIAL)) == + (YASL_PRIVATE_PEN_ROTATION | YASL_PRIVATE_PEN_TANGENTIAL)); sample.type = NSEventTypeLeftMouseDown; sample.samplePressure = 0.5; + sample.buttonMask = NSEventButtonMaskPenTip; [view mouseDown:native]; - ev = next(surface); - assert(ev.pointer.device == YASL_PTR_DEV_PEN && ev.type == YASL_EVENT_POINTER_DOWN && ev.pointer.button == YASL_BUTTON_PRIMARY); + ev = next(surface, YASL_PRIVATE_EVENT_POINTER_DOWN); + assert(ev.pointer.device == YASL_PRIVATE_PTR_DEV_PEN && ev.type == YASL_PRIVATE_EVENT_POINTER_DOWN && ev.pointer.button == YASL_PRIVATE_BUTTON_PRIMARY); assert(ev.pointer.pen.pressure == 32767); - struct yasl_vector2i position = ev.pointer.pos; + pen = next(surface, YASL_PRIVATE_EVENT_PEN); + assert(pen.pen.action == YASL_PRIVATE_PEN_DOWN && pen.pen.in_contact && pen.pen.pressure == 0.5); + assert(pen.pen.buttons == YASL_PRIVATE_BUTTON_BIT(YASL_PRIVATE_BUTTON_PRIMARY)); + assert(pen.pen.changed_button == YASL_PRIVATE_BUTTON_BIT(YASL_PRIVATE_BUTTON_PRIMARY)); + struct yasl_private_vector2i position = ev.pointer.pos; /* Native tablet events cover stationary pressure changes. */ sample.type = NSEventTypeTabletPoint; sample.subtype = NSEventSubtypeMouseEvent; sample.buttonMask = NSEventButtonMaskPenTip; sample.samplePressure = 1.5; [view tabletPoint:native]; - ev = next(surface); - assert(ev.type == YASL_EVENT_POINTER_MOTION && ev.pointer.pen.pressure == 65535); + ev = next(surface, YASL_PRIVATE_EVENT_POINTER_MOTION); + assert(ev.type == YASL_PRIVATE_EVENT_POINTER_MOTION && ev.pointer.pen.pressure == 65535); assert(ev.pointer.pos.x == position.x && ev.pointer.pos.y == position.y); + pen = next(surface, YASL_PRIVATE_EVENT_PEN); + assert(pen.pen.action == YASL_PRIVATE_PEN_MOVE && pen.pen.pressure == 1.0); + sample.buttonMask |= NSEventButtonMaskPenLowerSide; + [view tabletPoint:native]; + next(surface, YASL_PRIVATE_EVENT_POINTER_MOTION); + pen = next(surface, YASL_PRIVATE_EVENT_PEN); + assert(pen.pen.action == YASL_PRIVATE_PEN_BUTTON); + assert(pen.pen.buttons == (YASL_PRIVATE_BUTTON_BIT(YASL_PRIVATE_BUTTON_PRIMARY) | + YASL_PRIVATE_BUTTON_BIT(YASL_PRIVATE_BUTTON_SECONDARY))); + assert(pen.pen.changed_button == YASL_PRIVATE_BUTTON_BIT(YASL_PRIVATE_BUTTON_SECONDARY)); + sample.buttonMask = NSEventButtonMaskPenTip; sample.samplePressure = 0; /* Zero does not release a held tip button. */ [view tabletPoint:native]; - assert(next(surface).type == YASL_EVENT_POINTER_MOTION); + assert(next(surface, YASL_PRIVATE_EVENT_POINTER_MOTION).type == YASL_PRIVATE_EVENT_POINTER_MOTION); + next(surface, YASL_PRIVATE_EVENT_PEN); sample.buttonMask = 0; [view tabletPoint:native]; - ev = next(surface); - assert(ev.type == YASL_EVENT_POINTER_UP && !ev.pointer.pen.pressure && ev.pointer.device == YASL_PTR_DEV_PEN); + ev = next(surface, YASL_PRIVATE_EVENT_POINTER_UP); + assert(ev.type == YASL_PRIVATE_EVENT_POINTER_UP && !ev.pointer.pen.pressure && ev.pointer.device == YASL_PRIVATE_PTR_DEV_PEN); + pen = next(surface, YASL_PRIVATE_EVENT_PEN); + assert(pen.pen.action == YASL_PRIVATE_PEN_UP && !pen.pen.in_contact && pen.pen.pressure == 0.0); sample.type = NSEventTypeTabletProximity; sample.enteringProximity = NO; [view tabletProximity:native]; - assert(next(surface).type == YASL_EVENT_POINTER_LEAVE); + assert(next(surface, YASL_PRIVATE_EVENT_POINTER_LEAVE).type == YASL_PRIVATE_EVENT_POINTER_LEAVE); + assert(next(surface, YASL_PRIVATE_EVENT_PEN).pen.action == YASL_PRIVATE_PEN_LEAVE); sample.enteringProximity = YES; sample.tool = NSPointingDeviceTypeEraser; [view tabletProximity:native]; @@ -104,20 +144,25 @@ int main(void) sample.samplePressure = 0.75; sample.buttonMask = NSEventButtonMaskPenTip; [view tabletPoint:native]; - ev = next(surface); - assert(ev.pointer.device == YASL_PTR_DEV_ERASER && ev.type == YASL_EVENT_POINTER_DOWN && ev.pointer.pen.pressure > 0); + pen = next(surface, YASL_PRIVATE_EVENT_PEN); + assert(pen.pen.action == YASL_PRIVATE_PEN_ENTER && pen.pen.tool == 2); + ev = next(surface, YASL_PRIVATE_EVENT_POINTER_DOWN); + assert(ev.pointer.device == YASL_PRIVATE_PTR_DEV_ERASER && ev.type == YASL_PRIVATE_EVENT_POINTER_DOWN && ev.pointer.pen.pressure > 0); + pen = next(surface, YASL_PRIVATE_EVENT_PEN); + assert(pen.pen.action == YASL_PRIVATE_PEN_DOWN && pen.pen.tool == 2 && pen.pen.in_contact); sample.type = NSEventTypeTabletProximity; sample.enteringProximity = NO; [view tabletProximity:native]; - ev = next(surface); - assert(ev.pointer.device == YASL_PTR_DEV_ERASER && ev.type == YASL_EVENT_POINTER_LEAVE && !ev.pointer.pen.pressure); + ev = next(surface, YASL_PRIVATE_EVENT_POINTER_LEAVE); + assert(ev.pointer.device == YASL_PRIVATE_PTR_DEV_ERASER && ev.type == YASL_PRIVATE_EVENT_POINTER_LEAVE && !ev.pointer.pen.pressure); + assert(next(surface, YASL_PRIVATE_EVENT_PEN).pen.action == YASL_PRIVATE_PEN_LEAVE); sample.type = NSEventTypeMouseMoved; [view mouseMoved:native]; - ev = next(surface); - assert(ev.pointer.device == YASL_PTR_DEV_MOUSE && !ev.pointer.pen.pressure); + ev = next(surface, YASL_PRIVATE_EVENT_POINTER_MOTION); + assert(ev.pointer.device == YASL_PRIVATE_PTR_DEV_MOUSE && !ev.pointer.pen.pressure); [sample release]; - yasl_surface_destroy(surface); - yasl_display_close(display); + yasl_private_surface_destroy(surface); + yasl_private_display_close(display); } return 0; } 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); +} diff --git a/tests/helpers/run_surfaces.py b/tests/helpers/run_surfaces.py new file mode 100644 index 0000000..f120e35 --- /dev/null +++ b/tests/helpers/run_surfaces.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +"""Run the public surface/GPU contract tests on private Weston and Xwayland.""" +import os +from pathlib import Path +import subprocess +import sys +import tempfile +import time + +def wait_for(process, ready): + deadline = time.monotonic() + 12 + while time.monotonic() < deadline: + if process.poll() is not None: + raise RuntimeError('Display server stopped before readiness') + if ready(): + return + time.sleep(0.02) + raise TimeoutError('Display server readiness') + +def main(): + weston, xwayland, contract, hello, tablet, gl, vulkan, notepad = sys.argv[1:] + servers = [] + with tempfile.TemporaryDirectory(prefix='yasl-surfaces-') as directory: + root = Path(directory) + env = os.environ.copy() + env.pop('WAYLAND_SOCKET', None) + env.update(XDG_RUNTIME_DIR=directory, WAYLAND_DISPLAY='yasl-test', + XDG_SESSION_TYPE='wayland', LIBGL_ALWAYS_SOFTWARE='1') + lavapipe = next(Path('/usr/share/vulkan/icd.d').glob('*lvp*.json'), None) + if lavapipe: + env['VK_DRIVER_FILES'] = str(lavapipe) + with (root/'weston.log').open('w+') as wl_log, (root/'xwayland.log').open('w+') as x_log: + try: + wl = subprocess.Popen([weston, '--backend=headless', '--renderer=gl', + '--socket=yasl-test', '--idle-time=0', '--no-config', + '--width=1024', '--height=768'], env=env, stdout=wl_log, stderr=wl_log) + servers.append(wl) + wait_for(wl, lambda: (root/'yasl-test').is_socket()) + display_file = root/'display' + with display_file.open('w') as fd: + x = subprocess.Popen([xwayland, '-displayfd', str(fd.fileno()), + '-shm', '-noreset', '-nolisten', 'tcp'], env=env, + pass_fds=(fd.fileno(),), stdout=x_log, stderr=x_log) + servers.append(x) + wait_for(x, lambda: bool(display_file.read_text().strip())) + env['DISPLAY'] = ':' + display_file.read_text().strip() + for backend in ('wayland', 'x11'): + case = env.copy() + if backend == 'x11': + case.pop('WAYLAND_DISPLAY', None) + case['XDG_SESSION_TYPE'] = 'x11' + for binary, args in ((contract,[backend]), (gl,[backend]), + (vulkan,[backend]), (tablet,['--backend',backend,'--smoke-test']), + (notepad,['--smoke-test'])): + if binary == '-': + continue + print('Testing', Path(binary).name, backend, flush=True) + subprocess.run([binary, *args], env=case, check=True, timeout=15) + # hello runs until closed: it must survive its first frames. + if hello == '-': + continue + print('Testing', Path(hello).name, backend, flush=True) + process = subprocess.Popen([hello], env=case) + try: + process.wait(timeout=1) + raise RuntimeError(f'{Path(hello).name} exited with {process.returncode}') + except subprocess.TimeoutExpired: + process.terminate() + process.wait() + except BaseException: + for log in (wl_log,x_log): + log.flush();log.seek(0);print(log.read(), file=sys.stderr) + raise + finally: + for server in reversed(servers): + server.terminate() + try: + server.wait(timeout=5) + except subprocess.TimeoutExpired: + server.kill();server.wait() +if __name__ == '__main__': + main() diff --git a/tests/meson.build b/tests/meson.build index cac62db..4cbf082 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -1,291 +1,105 @@ -test_exe = executable( - 'yasl-test', - 'test_lifecycle.c', - include_directories: inc, - link_with: yasl_lib.get_static_lib(), - dependencies: deps, -) - -add_test_setup('asan') -add_test_setup('tsan') -add_test_setup('msan') - -test('basic', test_exe) - -shared_dep = declare_dependency( - link_with: yasl_lib.get_shared_lib(), - include_directories: include_directories('../include'), -) - -shared_api_test = executable( - 'yasl-shared-api-test', - 'test_lifecycle.c', - dependencies: shared_dep, -) -test('shared-api', shared_api_test) - +python = find_program('python3', native: true) +shared_dep = declare_dependency(link_with: yasl_lib.get_shared_lib(), + include_directories: include_directories('../include')) +foreach kind : ['static', 'shared'] + dep = kind == 'static' ? yasl_dep : shared_dep + public_test = executable('yasl-' + kind + '-api-test', 'test_lifecycle.c', dependencies: dep) + test(kind + '-api', public_test) +endforeach if add_languages('cpp', native: false, required: false) - cpp = meson.get_compiler('cpp') - cpp_api_test = executable( - 'yasl-cpp-api-test', - 'test_api.cpp', - dependencies: shared_dep, - cpp_args: cpp.get_supported_arguments('-pedantic-errors') + [ - '-DYASL_HAS_WAYLAND=' + (has_wayland ? '1' : '0'), - '-DYASL_HAS_X11=' + (has_x11 ? '1' : '0'), - '-DYASL_HAS_COCOA=' + (has_cocoa ? '1' : '0'), - ], - override_options: ['cpp_std=c++11'], - ) - test('cpp-api', cpp_api_test) + cpp_api = executable('yasl-cpp-api-test', 'test_api.cpp', dependencies: shared_dep, + cpp_args: ['-pedantic-errors'], override_options: ['cpp_std=c++11']) + test('cpp-api', cpp_api) endif - -python = find_program('python3', native: true) -if system == 'linux' or system == 'darwin' - nm = find_program('nm', native: false) - export_args = ['--platform=' + system] - if get_option('b_sanitize').contains('address') - # Clang's ASan instrumentation exports these linker-generated markers. - export_args += ['--allow-export=__start_asan_globals', - '--allow-export=__stop_asan_globals'] - endif - exported_headers = files( - '../include/yasl/yasl.h', - '../include/yasl/app.h', - '../include/yasl/desktop.h', - '../include/yasl/timing.h', - '../include/yasl/loop.h', - '../include/yasl/native.h', - ) - if has_wayland - exported_headers += files('../include/yasl/native/wayland.h') - endif - if has_x11 - exported_headers += files('../include/yasl/native/x11.h') - endif - if has_cocoa - exported_headers += files('../include/yasl/native/cocoa.h') +headers = files('../include/yasl/yasl.h', '../include/yasl/cpu.h', '../include/yasl/gl.h', + '../include/yasl/metal.h', '../include/yasl/desktop.h') +if has_vulkan + headers += files('../include/yasl/vulkan.h') +endif +foreach backend : ['wayland', 'x11', 'cocoa'] + enabled = {'wayland': has_wayland, 'x11': has_x11, 'cocoa': has_cocoa}[backend] + if enabled + headers += files('../include/yasl/native/' + backend + '.h') endif - test('public-exports', python, - args: [files('helpers/check_exports.py')] + export_args + - [nm, yasl_lib.get_shared_lib(), exported_headers], - ) +endforeach +nm = find_program('nm') +export_args = ['--platform=' + system] +if get_option('b_sanitize').contains('address') + export_args += ['--allow-export=__start_asan_globals', '--allow-export=__stop_asan_globals'] endif - -contracts_test = executable( - 'yasl-contracts-test', - 'common/test_contracts.c', - include_directories: inc, - dependencies: yasl_dep, -) -test('contracts', contracts_test) - -# Exercise the SDK-independent mappings even when their backend is disabled. -# Enabled backends already provide their mapping through yasl_dep. -keyboard_test_sources = files('common/test_keyboard.c') +test('public-exports', python, args: [files('helpers/check_exports.py')] + export_args + + [nm, yasl_lib.get_shared_lib(), headers]) + +foreach unit : ['contracts', 'utf8', 'timers', 'loop', 'selection', 'events', 'gl_options'] + exe = executable('yasl-' + unit + '-test', 'common/test_' + unit + '.c', + include_directories: inc, dependencies: yasl_dep) + test(unit, exe) +endforeach +keyboard_sources = files('common/test_keyboard.c') if not has_wayland - keyboard_test_sources += files('../src/platform/wayland/keymap.c') + keyboard_sources += files('../src/platform/wayland/keymap.c') endif if not has_x11 - keyboard_test_sources += files('../src/platform/x11/keymap.c') + keyboard_sources += files('../src/platform/x11/keymap.c') endif if not has_cocoa - keyboard_test_sources += files('../src/platform/cocoa/keymap.c') + keyboard_sources += files('../src/platform/cocoa/keymap.c') endif -keyboard_test = executable('yasl-keyboard-test', keyboard_test_sources, - include_directories: inc, dependencies: yasl_dep, -) -test('keyboard', keyboard_test) - -utf8_test = executable('yasl-utf8-test', 'common/test_utf8.c', - include_directories: inc, dependencies: yasl_dep, -) -test('utf8', utf8_test) - -timer_test = executable( - 'yasl-timer-test', - 'common/test_timers.c', - include_directories: inc, - dependencies: yasl_dep, -) -test('timers', timer_test) - -loop_test = executable( - 'yasl-loop-test', - 'common/test_loop.c', - include_directories: inc, - dependencies: [yasl_dep, dependency('threads')], -) -test('loop', loop_test) - +keyboard = executable('yasl-keyboard-test', keyboard_sources, include_directories: inc, dependencies: yasl_dep) +test('keyboard', keyboard) +alloc = executable('yasl-input-alloc-test', ['common/test_input_alloc.c', '../src/common/input.c'], + include_directories: inc, c_args: ['-Dmalloc=yasl_private_test_malloc']) +test('input-allocation-failure', alloc) if system == 'linux' - desktop_test = executable( - 'yasl-desktop-test', - 'common/test_desktop.c', - include_directories: inc, - dependencies: [yasl_dep, dependency('threads')], - ) - # A private session bus keeps the notification and portal checks away - # from the user's desktop. - dbus_run_session = find_program('dbus-run-session', required: false) - if has_dbus and dbus_run_session.found() - test('desktop', dbus_run_session, args: ['--', desktop_test]) + desktop = executable('yasl-desktop-test', 'common/test_desktop.c', include_directories: inc, dependencies: yasl_dep) + dbus_run = find_program('dbus-run-session', required: false) + if has_dbus and dbus_run.found() + test('desktop', dbus_run, args: ['--', desktop]) else - test('desktop', desktop_test) + test('desktop', desktop) endif endif - -app_test = executable( - 'yasl-app-test', - 'common/test_app.c', - include_directories: inc, - dependencies: yasl_dep, -) -test('app-runner', app_test) - -input_alloc_test = executable( - 'yasl-input-alloc-test', - ['common/test_input_alloc.c', '../src/common/input.c'], - include_directories: inc, - c_args: ['-Dmalloc=yasl_test_malloc'], -) -test('input-allocation-failure', input_alloc_test) - -selection_test = executable( - 'yasl-selection-test', - 'common/test_selection.c', - dependencies: yasl_dep, -) -test('selection', selection_test) - -tablet_example_test = executable('yasl-tablet-example-test', 'common/test_tablet_example.c', - dependencies: yasl_dep, -) -test('tablet-example', tablet_example_test) - +if has_wayland + foreach unit : ['state', 'clipboard', 'keyboard', 'input', 'tablet', 'cursor', 'relative_pointer', 'app_input', 'popup_positioner'] + exe = executable('yasl-' + unit + '-wayland-test', 'wayland/test_' + unit + '.c', + include_directories: inc, dependencies: yasl_dep) + test(unit + '-wayland', exe) + endforeach +endif if has_x11 - state_x11_test = executable('yasl-state-x11-test', 'x11/test_state.c', - include_directories: inc, dependencies: yasl_dep, - ) - test('state-x11', state_x11_test) - tablet_x11_test = executable('yasl-tablet-x11-test', 'x11/test_tablet.c', - include_directories: inc, dependencies: yasl_dep, - ) - test('tablet-x11', tablet_x11_test) + foreach unit : ['state', 'tablet'] + exe = executable('yasl-' + unit + '-x11-test', 'x11/test_' + unit + '.c', + include_directories: inc, dependencies: yasl_dep) + test(unit + '-x11', exe) + endforeach if get_option('x11_tablet_tests') xorg = find_program('/usr/lib/Xorg', '/usr/lib/xorg/Xorg', 'Xorg') - native_tablet_test = executable('yasl-tablet-x11-native-test', 'x11/test_tablet_native.c', - dependencies: yasl_dep, - ) - test('tablet-x11-native', python, - args: [files('helpers/run_x11_tablet.py'), xorg, native_tablet_test], timeout: 30, - ) + native_tablet = executable('yasl-tablet-x11-native-test', 'x11/test_tablet_native.c', + include_directories: inc, dependencies: yasl_dep) + test('tablet-x11-native', python, args: [files('helpers/run_x11_tablet.py'), xorg, native_tablet], timeout: 30) endif -elif get_option('x11_tablet_tests') - error('Native X11 tablet tests require the X11 backend.') endif - -if has_wayland - state_wayland_test = executable('yasl-state-wayland-test', 'wayland/test_state.c', - include_directories: inc, dependencies: yasl_dep, - ) - test('state-wayland', state_wayland_test) - clipboard_wayland_test = executable('yasl-clipboard-wayland-test', 'wayland/test_clipboard.c', - include_directories: inc, dependencies: yasl_dep, - ) - test('clipboard-wayland', clipboard_wayland_test) - keyboard_wayland_test = executable('yasl-keyboard-wayland-test', 'wayland/test_keyboard.c', - include_directories: inc, dependencies: yasl_dep, - ) - test('keyboard-wayland', keyboard_wayland_test) - ime_test = executable('yasl-ime-test', 'wayland/test_input.c', - include_directories: inc, - dependencies: yasl_dep, - ) - test('ime-ownership', ime_test) - app_input_test = executable('yasl-app-input-test', 'wayland/test_app_input.c', - include_directories: inc, dependencies: yasl_dep, - ) - test('app-input-destroy', app_input_test) - tablet_wayland_test = executable('yasl-tablet-wayland-test', 'wayland/test_tablet.c', - include_directories: inc, dependencies: yasl_dep, - ) - test('tablet-wayland', tablet_wayland_test) - cursor_wayland_test = executable('yasl-cursor-wayland-test', 'wayland/test_cursor.c', - include_directories: inc, dependencies: yasl_dep, - ) - test('cursor-wayland', cursor_wayland_test) - relative_pointer_test = executable('yasl-relative-pointer-wayland-test', - 'wayland/test_relative_pointer.c', - include_directories: inc, dependencies: yasl_dep, - ) - test('relative-pointer-wayland', relative_pointer_test) -endif - -benchmark_exe = executable( - 'yasl-benchmark', - 'benchmark.c', - include_directories: inc, - dependencies: yasl_dep, -) -benchmark('performance', benchmark_exe) - if get_option('integration_tests') - hello_example_test = executable('yasl-hello-example-test', 'common/test_hello_example.c', - dependencies: shared_dep, - ) - if has_cocoa - test('hello-cocoa-window', hello_example_test, timeout: 20) - test('interactive-cocoa-window', interactive_example, - args: ['--smoke-test'], timeout: 20, - ) - native_test = executable('yasl-native-test', 'cocoa/test_native.c', - dependencies: shared_dep, - ) - test('native', native_test, timeout: 20) - ownership_test = executable('yasl-ownership-test', 'cocoa/test_ownership.m', - dependencies: [shared_dep, deps], - ) - test('native-ownership', ownership_test, timeout: 20) - keyboard_cocoa_test = executable('yasl-keyboard-cocoa-test', 'cocoa/test_keyboard.m', - dependencies: [shared_dep, deps], - ) - test('keyboard-cocoa', keyboard_cocoa_test, timeout: 20) - tablet_cocoa_test = executable('yasl-tablet-cocoa-test', 'cocoa/test_tablet.m', - dependencies: [shared_dep, deps], - ) - test('tablet-cocoa', tablet_cocoa_test, timeout: 20) - cursor_cocoa_test = executable('yasl-cursor-cocoa-test', 'cocoa/test_cursor.m', - dependencies: [shared_dep, deps], - ) - test('cursor-cocoa', cursor_cocoa_test, timeout: 20) - test('tablet-cocoa-window', tablet_example, - args: ['--backend', 'cocoa', '--smoke-test'], timeout: 20, - ) - else - if not has_wayland or not has_x11 - error('Linux integration tests require Wayland and X11.') - endif - backend_test = executable( - 'yasl-backend-test', - 'common/test_backends.c', - dependencies: [shared_dep, deps], - ) - input_x11_test = executable('yasl-input-x11-test', 'x11/test_input.c', - include_directories: inc, dependencies: yasl_dep, - ) + integration = executable('yasl-surface-integration', 'common/test_surface_integration.c', + include_directories: inc, dependencies: yasl_dep) + gl_integration = executable('yasl-gl-integration', 'common/test_gl.c', + dependencies: yasl_dep) + vulkan_integration = '-' + if has_vulkan + vulkan_integration = executable('yasl-vulkan-integration', 'common/test_vulkan.c', dependencies: yasl_dep) + endif + if system == 'linux' weston = find_program('weston') xwayland = find_program('Xwayland') - test('backends', python, - args: [files('helpers/run_backends.py'), weston, xwayland, - backend_test, timer_test, tablet_example, hello_example_test, input_x11_test, - interactive_example, app_test, app_input_test], - timeout: 60, - ) + test('surface-backends', python, args: [files('helpers/run_surfaces.py'), weston, xwayland, + integration, hello_example, tablet_example, gl_integration, vulkan_integration, notepad_example], timeout: 120) + elif has_cocoa + test('surface-cocoa', integration, args: ['cocoa'], timeout: 30) + foreach unit : ['native', 'ownership', 'keyboard', 'tablet', 'cursor'] + extension = unit == 'native' ? '.c' : '.m' + exe = executable('yasl-' + unit + '-cocoa-test', 'cocoa/test_' + unit + extension, + include_directories: inc, dependencies: yasl_dep) + test(unit + '-cocoa', exe, timeout: 30) + endforeach endif endif - -events_test = executable('yasl-events-test', 'common/test_events.c', - include_directories: inc, dependencies: [yasl_dep, dependency('threads')], -) -test('event-contracts', events_test) diff --git a/tests/test_api.cpp b/tests/test_api.cpp index c5859cd..c0693eb 100644 --- a/tests/test_api.cpp +++ b/tests/test_api.cpp @@ -1,89 +1,26 @@ -#include "yasl/native.h" -#include "yasl/app.h" +#include <yasl/yasl.h> +#include <yasl/cpu.h> +#include <yasl/gl.h> +#include <yasl/metal.h> +#include <yasl/desktop.h> +#if YASL_HAS_VULKAN +#include <yasl/vulkan.h> +#endif #if YASL_HAS_WAYLAND -#include "yasl/native/wayland.h" +#include <yasl/native/wayland.h> #endif #if YASL_HAS_X11 -#include "yasl/native/x11.h" +#include <yasl/native/x11.h> #endif #if YASL_HAS_COCOA -#include "yasl/native/cocoa.h" +#include <yasl/native/cocoa.h> #endif -#include "yasl/desktop.h" -#include "yasl/loop.h" -#include <yasl/timing.h> -#include <yasl/yasl.h> #include <cassert> - int main() { - yasl_window_cbs callbacks{}; - yasl_window_spec window{}; - window.size = {640, 480}; - window.cbs = &callbacks; - window.ud = &window; - assert(!yasl_surface_create_toplevel(nullptr, &window)); - assert(!yasl_surface_create_native(nullptr, &window, &window)); - - yasl_timing timing = yasl_surface_timing(nullptr); - assert(timing.source == YASL_TIMING_UNKNOWN); - assert(yasl_scale_to_device(10.0, 240) == 20); - yasl_geometry geometry = yasl_surface_geometry(nullptr); - assert(geometry.scale_120 == YASL_SCALE_UNIT); - assert(!yasl_display_get_native_handle(nullptr)); - assert(!yasl_surface_get_native_handle(nullptr)); - yasl_native_frame native{}; - assert(!yasl_surface_get_native_frame(nullptr, nullptr, &native)); - - yasl_loop *loop = yasl_loop_create(); - assert(loop); - assert(yasl_loop_step(loop, 0) >= 0); - yasl_loop_destroy(loop); - - yasl_message message{}; - assert(!yasl_display_post(nullptr, &message)); - assert(!yasl_frame_present(nullptr, nullptr, 0)); - assert(!yasl_display_poll_event(nullptr, nullptr)); - assert(!yasl_surface_set_size(nullptr, {640, 480})); - assert(!yasl_surface_set_fullscreen(nullptr, true)); - assert(!yasl_surface_set_maximized(nullptr, true)); - assert(!yasl_surface_minimize(nullptr)); - assert(!yasl_surface_set_pacing(nullptr, YASL_PACING_CONTINUOUS)); - assert(!yasl_surface_set_callbacks(nullptr, nullptr, nullptr)); - assert(!yasl_clipboard_set(nullptr, YASL_CLIPBOARD, "")); - assert(!yasl_clipboard_request(nullptr, YASL_CLIPBOARD)); - assert(!yasl_app_window(nullptr)); - yasl_app_exit(nullptr, YASL_APP_ERROR); - - yasl_event event{}; - event.key.key = YASL_KEY_A; - assert(event.key.key == YASL_KEY_A); - event.pointer.scroll = {0.25, -0.5}; - assert(event.pointer.scroll.x == 0.25 && event.pointer.scroll.y == -0.5); - assert(!yasl_surface_poll_event(nullptr, &event)); - assert(!yasl_display_drag_start(nullptr, nullptr, nullptr, nullptr, nullptr)); - assert(!yasl_surface_drag_carry(nullptr, {0, 0})); - -#if YASL_HAS_WAYLAND - assert(!yasl_wayland_display_get_wl_display(nullptr)); - assert(!yasl_wayland_surface_get_wl_surface(nullptr)); -#endif - -#if YASL_HAS_X11 - assert(!yasl_x11_display_get_display(nullptr)); - assert(!yasl_x11_surface_get_window(nullptr)); -#endif - -#if YASL_HAS_COCOA - assert(!yasl_cocoa_display_get_application(nullptr)); - assert(!yasl_cocoa_surface_get_window(nullptr)); - assert(!yasl_cocoa_surface_get_view(nullptr)); -#endif - - assert(!yasl_display_open_uri(nullptr, "https://example.com")); - assert(yasl_display_appearance(nullptr) == 0); - assert(!yasl_surface_bell(nullptr)); - assert(yasl_executable_path(nullptr, 0) > 0); - - return 0; + yasl_event e{}; + e.pen.x=1.5;e.pen.pressure=0.25; + assert(e.pen.pressure==0.25); + assert(!yasl_surface_create("invalid",-1,10,0)); + yasl_shutdown();return 0; } diff --git a/tests/test_lifecycle.c b/tests/test_lifecycle.c index 00d1264..a334fed 100644 --- a/tests/test_lifecycle.c +++ b/tests/test_lifecycle.c @@ -1,75 +1,24 @@ -#include "yasl/loop.h" -#include "yasl/yasl.h" +#include <yasl/yasl.h> +#include <yasl/cpu.h> +#include <yasl/gl.h> +#include <yasl/desktop.h> #include <assert.h> -#include <poll.h> -#include <stdio.h> -#include <unistd.h> - -static void test_scaling(void) -{ - assert(yasl_scale_to_device(10.0, 120) == 10); - assert(yasl_scale_to_device(10.0, 240) == 20); - assert(yasl_scale_to_logical(20, 240) == 10); -} - -static int dummy_cb(int fd, short revents, void *ud) -{ - (void)fd; (void)revents; (void)ud; - return 0; -} - -static void test_loop(void) -{ - struct yasl_loop *loop = yasl_loop_create(); - assert(loop != NULL); - - int p[2]; - assert(pipe(p) == 0); - int watch = yasl_loop_add_fd(loop, p[0], POLLIN, dummy_cb, NULL); - assert(watch > 0); - assert(yasl_loop_set_fd_events(loop, watch, POLLIN | POLLOUT) == 0); - - yasl_loop_kick(loop); - int n = yasl_loop_step(loop, 10); - assert(n >= 1); - - assert(yasl_loop_del_fd(loop, watch) == 0); - close(p[0]); - close(p[1]); - - yasl_loop_destroy(loop); -} - -static void test_display_lifecycle_standalone(void) -{ - struct yasl_display_spec spec = { .app_id = "org.yasl.test" }; - struct yasl_display *d = yasl_display_open(NULL, &spec); - if (!d) return; /* Headless CI without Wayland */ - - struct yasl_window_spec sspec = { - .title = "Test Window", - .size = { .x = 320, .y = 240 }, - }; - struct yasl_surface *s = yasl_surface_create_toplevel(d, &sspec); - assert(s != NULL); - assert(yasl_surface_display(s) == d); - - struct yasl_vector2i sz = yasl_surface_geometry(s).size; - assert(sz.x > 0 && sz.y > 0); - - yasl_surface_schedule_redraw(s); - yasl_display_flush(d); - yasl_display_dispatch(d, 0); - - yasl_surface_destroy(s); - yasl_display_close(d); -} - int main(void) { - test_scaling(); - test_loop(); - test_display_lifecycle_standalone(); - printf("All YASL basic tests passed.\n"); - return 0; + yasl_shutdown(); yasl_wake(); + yasl_event e={.type=YASL_EVENT_QUIT}; + assert(yasl_wait_event(&e,0)==-1 && e.type==YASL_EVENT_NONE); + assert(yasl_get_error(NULL)==YASL_ERROR_NOT_INITIALIZED); + assert(!yasl_set_backend((enum yasl_backend)999)); + assert(yasl_get_error(NULL)==YASL_ERROR_INVALID); + assert(!yasl_surface_create("bad",0,64,0)); + assert(!yasl_surface_create("bad",64,64,16)); + assert(yasl_set_app_id("org.yasl.api")); + assert(yasl_set_backend(YASL_BACKEND_AUTO)); + yasl_surface_destroy(NULL); + assert(yasl_time_ns()>0); + const char *description=NULL;yasl_get_error(&description);assert(description); + int w=9,h=9;yasl_surface_get_size(NULL,&w,&h);assert(w==0&&h==0); + assert(yasl_executable_path(NULL,0)>0); + yasl_shutdown();return 0; } diff --git a/tests/wayland/test_app_input.c b/tests/wayland/test_app_input.c index 7e0e9a0..c8e4d2b 100644 --- a/tests/wayland/test_app_input.c +++ b/tests/wayland/test_app_input.c @@ -1,132 +1,78 @@ -/* An input event callback that destroys its own surface. The app runner - * must not touch the surface's entry after the callback, and must not - * deliver the surface's remaining input. Needs a Wayland compositor. */ -#include "platform/wayland/internal.h" -#include "yasl/app.h" +/* The public event queue must retain FIFO order and discard events targeted + * at a surface when that surface is destroyed. Native input is injected + * through the backend queue, without requiring a compositor. */ +#include "yasl/yasl.h" +#include "common/backend.h" #include <assert.h> -#include <errno.h> -#include <stdlib.h> +#include <string.h> -struct test_state { - bool initialized; - int keys; - int buttons, motions, resets; - int end; +static struct input_queue *surface_queue(struct yasl_surface *s) +{ + return &s->input; +} + +static const struct yasl_private_backend_ops test_ops = { + .surface_input_queue = surface_queue, }; -static void push_key(struct yasl_surface *s) +static void setup(struct yasl_private_display *display, struct yasl_surface *surface) { - struct yasl_event ev = { - .surface = s, - .type = YASL_EVENT_KEY, - .key = { .key = YASL_KEY_A, .action = YASL_KEY_PRESS }, - }; - assert(input_queue_push(&((struct wayland_surface *)s)->input, &ev)); + *display = (struct yasl_private_display){.ops = &test_ops}; + *surface = (struct yasl_surface){.display = display, .scale_120 = 120}; + assert(yasl_private_events_open(display)); + assert(yasl_private_events_register(surface)); } -static enum yasl_app_result on_init(void *ud, struct yasl_display *d) +static void destroy_surface(struct yasl_surface *surface) { - struct test_state *state = ud; - state->initialized = true; - if (state->end == 3) { - /* With no event callback, a close request alone stops the runner. */ - struct yasl_surface *s = yasl_surface_create_toplevel(d, - &(struct yasl_window_spec){ .title = "App Close Test", .size = {64, 64} }); - assert(s); - yasl_surface_notify_close(s); - return YASL_APP_CONTINUE; - } - if (state->end) { - if (state->end == 1) - yasl_display_notify_event(d, YASL_EVENT_DISPLAY_QUIT); - else - yasl_display_notify_event(d, YASL_EVENT_DISPLAY_LOST); - return YASL_APP_CONTINUE; - } - struct yasl_surface *s = yasl_surface_create_toplevel(d, - &(struct yasl_window_spec){ .title = "App Input Test", .size = {64, 64} }); - assert(s); - struct input_queue *queue = &((struct wayland_surface *)s)->input; - input_queue_clear(queue); - struct yasl_event event = {.surface = s, .type = YASL_EVENT_POINTER_DOWN, - .pointer = {.device = YASL_PTR_DEV_ERASER, .button = YASL_BUTTON_PRIMARY, - .pos = {12, 34}, .pen = {.pressure = 50000, .tilt_x = -20, .tilt_y = 30}}}; - assert(input_queue_push(queue, &event)); - event.type = YASL_EVENT_POINTER_MOTION; - event.pointer.pos = (struct yasl_vector2i){15, 39}; - assert(input_queue_push(queue, &event)); - struct yasl_event reset = {.surface = s, .type = YASL_EVENT_INPUT_RESET}; - assert(input_queue_push(queue, &reset)); - event.pointer.device = YASL_PTR_DEV_PEN; - event.pointer.pos = (struct yasl_vector2i){100, 200}; - assert(input_queue_push(queue, &event)); - push_key(s); - push_key(s); - return YASL_APP_CONTINUE; + yasl_private_events_unregister(surface); + input_queue_clear(&surface->input); } -static enum yasl_app_result on_event(void *ud, const struct yasl_event *ev) +static void test_fifo_and_destroy(void) { - struct test_state *state = ud; - if (ev->type == YASL_EVENT_POINTER_DOWN) { - assert(ev->pointer.device == YASL_PTR_DEV_ERASER); - assert(ev->pointer.button == YASL_BUTTON_PRIMARY); - assert(ev->pointer.pos.x == 12 && ev->pointer.pos.y == 34); - assert(ev->pointer.pen.pressure == 50000); - assert(ev->pointer.pen.tilt_x == -20 && ev->pointer.pen.tilt_y == 30); - state->buttons++; - } else if (ev->type == YASL_EVENT_POINTER_MOTION) { - if (!state->motions) { - assert(ev->pointer.device == YASL_PTR_DEV_ERASER); - assert(ev->pointer.delta.x == 3 && ev->pointer.delta.y == 5); - } else { - assert(ev->pointer.device == YASL_PTR_DEV_PEN); - assert(!ev->pointer.delta.x && !ev->pointer.delta.y); - } - assert(ev->pointer.pen.pressure == 50000); - state->motions++; - } else if (ev->type == YASL_EVENT_INPUT_RESET) { - state->resets++; - } else if (ev->type == YASL_EVENT_KEY) { - state->keys++; - yasl_surface_destroy(ev->surface); - } - return YASL_APP_CONTINUE; + struct yasl_private_display display; + struct yasl_surface surface; + setup(&display, &surface); + + assert(input_queue_push(&surface.input, &(struct yasl_private_event){ + .type = YASL_PRIVATE_EVENT_KEY, + .surface = &surface, + .key = {.key = YASL_KEY_A, .action = YASL_KEY_PRESS}, + })); + assert(input_queue_push(&surface.input, &(struct yasl_private_event){ + .type = YASL_PRIVATE_EVENT_TEXT, + .surface = &surface, + .text = {.data = "hello", .len = 5}, + })); + + struct yasl_private_event event; + assert(yasl_private_display_poll_event(&display, &event)); + assert(event.type == YASL_PRIVATE_EVENT_KEY && event.key.key == YASL_KEY_A); + assert(yasl_private_display_poll_event(&display, &event)); + assert(event.type == YASL_PRIVATE_EVENT_TEXT && event.text.len == 5); + assert(!strcmp(event.text.data, "hello")); + + /* Queue multiple events, then destroy the target before consumption. */ + assert(input_queue_push(&surface.input, &(struct yasl_private_event){ + .type = YASL_PRIVATE_EVENT_KEY, .surface = &surface, + .key = {.key = YASL_KEY_B, .action = YASL_KEY_PRESS}, + })); + assert(input_queue_push(&surface.input, &(struct yasl_private_event){ + .type = YASL_PRIVATE_EVENT_TEXT, .surface = &surface, + .text = {.data = "discard", .len = 7}, + })); + destroy_surface(&surface); + assert(!yasl_private_display_poll_event(&display, &event)); + yasl_private_events_close(&display); + + /* Public event names remain the event stream consumed by applications. */ + assert(YASL_EVENT_KEY != YASL_EVENT_TEXT); } int main(void) { - if (!getenv("WAYLAND_DISPLAY")) - return 77; - struct test_state state = {0}; - int res = yasl_run(&(struct yasl_app_desc){ - .app_id = "org.yasl.test.app-input", - .backend = YASL_BACKEND_WAYLAND, - .userdata = &state, - .init = on_init, - .event = on_event, - }); - /* A display variable may exist even when the test sandbox cannot connect - * to that compositor. Keep this as an integration test in that case. */ - if (res < 0 && !state.initialized && - (errno == EACCES || errno == EPERM || errno == ENOENT || - errno == ECONNREFUSED || errno == ENODEV)) - return 77; - assert(res == 0); - assert(state.keys == 1); - assert(state.buttons == 1 && state.motions == 2 && state.resets == 1); - for (int end = 1; end <= 2; end++) { - state = (struct test_state){.end = end}; - res = yasl_run(&(struct yasl_app_desc){ - .backend = YASL_BACKEND_WAYLAND, .userdata = &state, .init = on_init, - }); - assert(end == 1 ? res == 0 : res < 0); - } - state = (struct test_state){.end = 3}; - res = yasl_run(&(struct yasl_app_desc){ - .backend = YASL_BACKEND_WAYLAND, .userdata = &state, .init = on_init, - }); - assert(res == 0); + test_fifo_and_destroy(); return 0; } diff --git a/tests/wayland/test_clipboard.c b/tests/wayland/test_clipboard.c index 1778ad2..0ee74b6 100644 --- a/tests/wayland/test_clipboard.c +++ b/tests/wayland/test_clipboard.c @@ -6,7 +6,7 @@ struct received { int count; size_t len; uint64_t request_id; - enum yasl_transfer_status status; + enum yasl_private_transfer_status status; struct clipboard *clipboard; bool forget_on_receive; char text[32]; @@ -14,12 +14,12 @@ struct received { static void receive(const char *text, size_t len, bool uri_list, struct wl_surface *surface, uint64_t request_id, - enum yasl_transfer_status status, void *ud) + enum yasl_private_transfer_status status, void *ud) { (void)surface; struct received *r = ud; assert(!uri_list && len < sizeof(r->text)); - if (status == YASL_TRANSFER_OK) { + if (status == YASL_PRIVATE_TRANSFER_OK) { assert(text); memcpy(r->text, text, len); r->text[len] = '\0'; @@ -39,7 +39,7 @@ static void receive(const char *text, size_t len, bool uri_list, int main(void) { struct received received = {0}; - struct clipboard c = {.loop = yasl_loop_create(), .receive = receive, .ud = &received}; + struct clipboard c = {.loop = yasl_private_loop_create(), .receive = receive, .ud = &received}; received.clipboard = &c; assert(c.loop); const struct { const char *bytes; size_t len; bool valid; } cases[] = { @@ -55,19 +55,19 @@ int main(void) assert(pipe(fds) == 0); struct transfer *transfer = start_transfer_text(&c, fds[0], false, false, c.text); assert(transfer); - yasl_timer_id timeout_id = transfer->timeout; - assert(timeout_id && yasl_loop_timer_armed(c.loop, timeout_id)); + yasl_private_timer_id timeout_id = transfer->timeout; + assert(timeout_id && yasl_private_loop_timer_armed(c.loop, timeout_id)); transfer->paste = true; transfer->request_id = 42; assert(write(fds[1], cases[i].bytes, cases[i].len) == (ssize_t)cases[i].len); close(fds[1]); for (int steps = 0; c.transfers && steps < 10; steps++) - assert(yasl_loop_step(c.loop, 0) >= 0); + assert(yasl_private_loop_step(c.loop, 0) >= 0); assert(!c.transfers); - assert(!yasl_loop_timer_armed(c.loop, timeout_id)); + assert(!yasl_private_loop_timer_armed(c.loop, timeout_id)); assert(received.count == 1); assert(received.request_id == 42); - assert(received.status == (cases[i].valid ? YASL_TRANSFER_OK : YASL_TRANSFER_FAILED)); + assert(received.status == (cases[i].valid ? YASL_PRIVATE_TRANSFER_OK : YASL_PRIVATE_TRANSFER_FAILED)); if (cases[i].valid) { assert(received.len == cases[i].len); assert(memcmp(received.text, cases[i].bytes, received.len) == 0); @@ -79,8 +79,8 @@ int main(void) assert(pipe(cancel_fds) == 0); struct transfer *pending = start_transfer_text(&c, cancel_fds[0], false, false, NULL); assert(pending); - yasl_timer_id cancel_timeout_id = pending->timeout; - assert(cancel_timeout_id && yasl_loop_timer_armed(c.loop, cancel_timeout_id)); + yasl_private_timer_id cancel_timeout_id = pending->timeout; + assert(cancel_timeout_id && yasl_private_loop_timer_armed(c.loop, cancel_timeout_id)); pending->paste = true; pending->request_id = 99; struct wl_surface *target = (struct wl_surface *)(uintptr_t)1; @@ -88,7 +88,7 @@ int main(void) clipboard_forget_surface(&c, target); close(cancel_fds[1]); assert(!c.transfers && received.count == 0); - assert(!yasl_loop_timer_armed(c.loop, cancel_timeout_id)); + assert(!yasl_private_loop_timer_armed(c.loop, cancel_timeout_id)); received.forget_on_receive = true; int timeout_fds[2]; @@ -99,12 +99,12 @@ int main(void) timed->request_id = 100; struct wl_surface *timeout_target = (struct wl_surface *)(uintptr_t)2; timed->drop_surface = timeout_target; - yasl_timer_id timeout_id = timed->timeout; - assert(yasl_loop_del_timer(c.loop, timeout_id)); + yasl_private_timer_id timeout_id = timed->timeout; + assert(yasl_private_loop_del_timer(c.loop, timeout_id)); (void)transfer_timeout(timed, timeout_id, CLIPBOARD_TRANSFER_TIMEOUT_NS); close(timeout_fds[1]); assert(!c.transfers && received.count == 1); - assert(received.request_id == 100 && received.status == YASL_TRANSFER_FAILED); - yasl_loop_destroy(c.loop); + assert(received.request_id == 100 && received.status == YASL_PRIVATE_TRANSFER_FAILED); + yasl_private_loop_destroy(c.loop); return 0; } diff --git a/tests/wayland/test_cursor.c b/tests/wayland/test_cursor.c index eb729a3..3425821 100644 --- a/tests/wayland/test_cursor.c +++ b/tests/wayland/test_cursor.c @@ -51,9 +51,9 @@ static uint32_t pointer_version(struct wl_pointer *pointer) int main(void) { - struct wayland_display display = {.base.ops = &yasl_wayland_backend}; + struct wayland_display display = {.base.ops = &yasl_private_wayland_backend}; struct wayland_surface surface = {.base.display = &display.base, .conn = &display, - .scale_factor = 1, .cursor = YASL_CURSOR_TEXT}; + .scale_factor = 1, .cursor = YASL_PRIVATE_CURSOR_TEXT}; surface.surface = (struct wl_surface *)&surface; wl_surface_set_user_data(surface.surface, &surface); display.surfaces = &surface; @@ -64,7 +64,7 @@ int main(void) tool.proxy = (struct zwp_tablet_tool_v2 *)&tool; /* The example selects hidden before either input device has entered. */ - yasl_surface_set_cursor(&surface.base, YASL_CURSOR_HIDDEN); + yasl_private_surface_set_cursor(&surface.base, YASL_PRIVATE_CURSOR_HIDDEN); assert(!pointer_hides && !tool_hides); pointer_enter(&seat, seat.pointer, 10, surface.surface, 0, 0); assert(pointer_hides == 1 && pointer_serial == 10); @@ -76,14 +76,16 @@ int main(void) pointer_frame(&seat, seat.pointer); tablet_tool_motion(&tool, tool.proxy, wl_fixed_from_int(56), wl_fixed_from_int(78)); tool_frame(&tool, tool.proxy, 0); - struct yasl_event event; - assert(yasl_surface_poll_event(&surface.base, &event)); - assert(event.type == YASL_EVENT_POINTER_MOTION && event.pointer.device == YASL_PTR_DEV_MOUSE); + struct yasl_private_event event; + assert(yasl_private_surface_poll_event(&surface.base, &event)); + assert(event.type == YASL_PRIVATE_EVENT_POINTER_MOTION && event.pointer.device == YASL_PRIVATE_PTR_DEV_MOUSE); assert(event.pointer.pos.x == 12 && event.pointer.pos.y == 34); - assert(yasl_surface_poll_event(&surface.base, &event)); - assert(event.type == YASL_EVENT_POINTER_MOTION && event.pointer.device == YASL_PTR_DEV_PEN); + assert(yasl_private_surface_poll_event(&surface.base, &event)); + assert(event.type == YASL_PRIVATE_EVENT_PEN && event.pen.action == YASL_PRIVATE_PEN_ENTER); + assert(yasl_private_surface_poll_event(&surface.base, &event)); + assert(event.type == YASL_PRIVATE_EVENT_POINTER_MOTION && event.pointer.device == YASL_PRIVATE_PTR_DEV_PEN); assert(event.pointer.pos.x == 56 && event.pointer.pos.y == 78); - assert(!yasl_surface_poll_event(&surface.base, &event)); + assert(!yasl_private_surface_poll_event(&surface.base, &event)); /* Each new entry needs a request with its own serial. */ pointer_leave(&seat, seat.pointer, 12, surface.surface); @@ -98,20 +100,20 @@ int main(void) /* Restore a visible shape on both currently focused devices. */ pointer_device = seat.cursor_shape_dev = (struct wp_cursor_shape_device_v1 *)&seat; tool.shape_dev = (struct wp_cursor_shape_device_v1 *)&tool; - yasl_surface_set_cursor(&surface.base, YASL_CURSOR_ARROW); + yasl_private_surface_set_cursor(&surface.base, YASL_PRIVATE_CURSOR_ARROW); assert(pointer_shapes == 1 && tool_shapes == 1); assert(pointer_shape == WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT); assert(tool_shape == WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT); - yasl_surface_set_cursor(&surface.base, YASL_CURSOR_HIDDEN); + yasl_private_surface_set_cursor(&surface.base, YASL_PRIVATE_CURSOR_HIDDEN); assert(pointer_hides == 3 && tool_hides == 3); assert(pointer_shapes == 1 && tool_shapes == 1); /* Updating an unfocused surface must not alter the active cursor. */ struct wayland_surface other = {.base.display = &display.base, .conn = &display}; - yasl_surface_set_cursor(&other.base, YASL_CURSOR_CROSSHAIR); + yasl_private_surface_set_cursor(&other.base, YASL_PRIVATE_CURSOR_CROSSHAIR); assert(pointer_shapes == 1 && tool_shapes == 1); - yasl_surface_set_cursor(&surface.base, (enum yasl_cursor)-1); - yasl_surface_set_cursor(&surface.base, (enum yasl_cursor)(YASL_CURSOR_HIDDEN + 1)); + yasl_private_surface_set_cursor(&surface.base, (enum yasl_private_cursor)-1); + yasl_private_surface_set_cursor(&surface.base, (enum yasl_private_cursor)(YASL_PRIVATE_CURSOR_HIDDEN + 1)); assert(pointer_hides == 3 && tool_hides == 3); assert(pointer_shapes == 1 && tool_shapes == 1); input_queue_clear(&surface.input); diff --git a/tests/wayland/test_input.c b/tests/wayland/test_input.c index f6112b6..2b5592a 100644 --- a/tests/wayland/test_input.c +++ b/tests/wayland/test_input.c @@ -1,17 +1,35 @@ #include "platform/wayland/internal.h" #include <assert.h> +#include <errno.h> +#include <stdlib.h> + +static void test_ime_capability(void) +{ + struct wayland_display display = {0}; + struct wayland_surface w = {.conn = &display}; + assert(!(wayland_display_caps(&display) & YASL_PRIVATE_CAP_TEXT_INPUT)); + errno = 0; + assert(!wayland_surface_update_text_input(&w) && errno == ENOTSUP); + display.text_input_mgr = (struct zwp_text_input_manager_v3 *)&display; + assert(wayland_display_caps(&display) & YASL_PRIVATE_CAP_TEXT_INPUT); + w.base.text_input_active = true; + w.base.text_purpose = 1; /* Public YASL_TEXT_PASSWORD. */ + /* A supported compositor can accept the requested state before a seat + * or keyboard focus has arrived. The enter callback applies it later. */ + assert(wayland_surface_update_text_input(&w)); +} static void test_popup_bounds(void) { struct seat seat = {.input_serial = 1}; - struct wayland_display d = {.base.ops = &yasl_wayland_backend, .seats = &seat}; + struct wayland_display d = {.base.ops = &yasl_private_wayland_backend, .seats = &seat}; struct wayland_surface w = {.base.display = &d.base, .conn = &d}; w.parent = &w; w.content.x = w.content.y = 1; /* Invalid bounds must be rejected before accessing any protocol object. */ w.xdg_surface = (struct xdg_surface *)&w; w.popup = (struct xdg_popup *)&w; - struct yasl_popup_spec specs[] = { + struct yasl_private_popup_spec specs[] = { {.size = {100, 100}, .content_offset = {INT_MAX, 0}, .content_size = {1, 0}}, {.size = {100, 100}, .content_offset = {0, INT_MAX}, .content_size = {0, 1}}, {.size = {100, 100}, .content_offset = {1, 0}, .content_size = {INT_MAX, 0}}, @@ -20,16 +38,18 @@ static void test_popup_bounds(void) {.size = {100, 100}, .anchor = {0, INT_MIN, 1, 1}}, }; for (size_t i = 0; i < sizeof(specs) / sizeof(specs[0]); i++) { - assert(!yasl_surface_create_popup(&w.base, &specs[i])); - assert(!yasl_surface_popup_reposition(&w.base, &specs[i])); + assert(!yasl_private_surface_create_popup(&w.base, &specs[i])); + assert(!yasl_private_surface_popup_reposition(&w.base, &specs[i])); } } int main(void) { + test_ime_capability(); test_popup_bounds(); struct wayland_surface w = {0}; struct seat seat = {.ime_focus = &w}; + w.base.text_input_active = true; wayland_surface_set_callbacks(&w, NULL, NULL); for (int i = 0; i < 600; i++) { char text[32]; @@ -41,11 +61,38 @@ int main(void) for (int i = 0; i < 600; i++) { char text[32]; snprintf(text, sizeof(text), "commit-%d", i); - struct yasl_event event; + struct yasl_private_event event; assert(wayland_surface_poll_event(&w, &event)); - assert(event.type == YASL_EVENT_TEXT && event.surface == &w.base); + assert(event.type == YASL_PRIVATE_EVENT_TEXT && event.surface == &w.base); assert(strcmp(event.text.data, text) == 0); } + w.base.text_input_active = true; + w.base.text_surrounding = strdup("ab\xf0\x9f\x98\x80" "cd"); + w.base.text_length = 8; + w.base.text_begin = 2; + w.base.text_end = 6; + w.base.text_revision = 41; + w.base.text_generation = 9; + text_input_listener.delete_surrounding_text(&seat, NULL, 2, 2); + text_input_listener.commit_string(&seat, NULL, "X"); + text_input_listener.done(&seat, NULL, 601); + struct yasl_private_event edit; + assert(wayland_surface_poll_event(&w, &edit)); + assert(edit.type == YASL_PRIVATE_EVENT_TEXT_EDIT && edit.surface == &w.base); + assert(strcmp(edit.text_edit.data, "X") == 0 && edit.text_edit.len == 1); + assert(edit.text_edit.begin == 2 && edit.text_edit.end == 8); + assert(edit.text_edit.revision == 41 && edit.text_edit.generation == 9); + struct yasl_private_event committed; + assert(!wayland_surface_poll_event(&w, &committed)); + + /* Deletion without a commit replaces the range with the empty string. */ + text_input_listener.delete_surrounding_text(&seat, NULL, 2, 2); + text_input_listener.done(&seat, NULL, 602); + assert(wayland_surface_poll_event(&w, &edit)); + assert(edit.type == YASL_PRIVATE_EVENT_TEXT_EDIT && edit.text_edit.len == 0); + assert(edit.text_edit.data[0] == '\0' && edit.text_edit.begin == 2 && edit.text_edit.end == 8); + assert(!wayland_surface_poll_event(&w, &committed)); input_queue_clear(&w.input); + free(w.base.text_surrounding); return 0; } diff --git a/tests/wayland/test_keyboard.c b/tests/wayland/test_keyboard.c index bce0a0c..ae4647f 100644 --- a/tests/wayland/test_keyboard.c +++ b/tests/wayland/test_keyboard.c @@ -1,18 +1,18 @@ #include "../../src/platform/wayland/keyboard.c" #include <assert.h> -static struct yasl_event next(struct wayland_surface *w, enum yasl_event_type type) +static struct yasl_private_event next(struct wayland_surface *w, enum yasl_private_event_type type) { - struct yasl_event ev; - assert(yasl_surface_poll_event(&w->base, &ev)); + struct yasl_private_event ev; + assert(yasl_private_surface_poll_event(&w->base, &ev)); assert(ev.type == type && ev.surface == &w->base); return ev; } static void empty(struct wayland_surface *w) { - struct yasl_event ev; - assert(!yasl_surface_poll_event(&w->base, &ev)); + struct yasl_private_event ev; + assert(!yasl_private_surface_poll_event(&w->base, &ev)); } static void layout(struct seat *s, const char *name, const char *variant) @@ -43,7 +43,7 @@ static void key(struct seat *s, uint32_t code, bool down) int main(void) { - struct wayland_display d = {.base.ops = &yasl_wayland_backend}; + struct wayland_display d = {.base.ops = &yasl_private_wayland_backend}; d.xkb_ctx = xkb_context_new(0); assert(d.xkb_ctx); struct wayland_surface w = {.base.display = &d.base, .conn = &d}; @@ -59,65 +59,66 @@ int main(void) xkb_compose_table_unref(table); layout(&s, "us", NULL); key(&s, KEY_A, true); - struct yasl_event ev = next(&w, YASL_EVENT_KEY); + struct yasl_private_event ev = next(&w, YASL_PRIVATE_EVENT_KEY); assert(ev.key.key == YASL_KEY_A && ev.key.native_code == KEY_A); assert(ev.key.codepoint == 'a' && ev.key.shifted == 'A' && !ev.key.mods); - assert(strcmp(next(&w, YASL_EVENT_TEXT).text.data, "a") == 0); + assert(strcmp(next(&w, YASL_PRIVATE_EVENT_TEXT).text.data, "a") == 0); modifiers(&s, XKB_MOD_NAME_SHIFT); key(&s, KEY_A, false); /* Modifier changes cannot change physical identity. */ - ev = next(&w, YASL_EVENT_KEY); + ev = next(&w, YASL_PRIVATE_EVENT_KEY); assert(ev.key.key == YASL_KEY_A && ev.key.action == YASL_KEY_RELEASE); - assert(ev.key.mods == YASL_MOD_SHIFT); + assert(ev.key.mods == YASL_PRIVATE_MOD_SHIFT); empty(&w); key(&s, KEY_A, true); - next(&w, YASL_EVENT_KEY); - assert(strcmp(next(&w, YASL_EVENT_TEXT).text.data, "A") == 0); + next(&w, YASL_PRIVATE_EVENT_KEY); + assert(strcmp(next(&w, YASL_PRIVATE_EVENT_TEXT).text.data, "A") == 0); modifiers(&s, XKB_MOD_NAME_CAPS); key(&s, KEY_A, true); - assert(next(&w, YASL_EVENT_KEY).key.mods == YASL_MOD_CAPS); - assert(strcmp(next(&w, YASL_EVENT_TEXT).text.data, "A") == 0); + assert(next(&w, YASL_PRIVATE_EVENT_KEY).key.mods == YASL_PRIVATE_MOD_CAPS); + assert(strcmp(next(&w, YASL_PRIVATE_EVENT_TEXT).text.data, "A") == 0); const char *shortcuts[] = {XKB_MOD_NAME_CTRL, XKB_MOD_NAME_ALT, XKB_MOD_NAME_LOGO}; for (size_t i = 0; i < sizeof(shortcuts)/sizeof(shortcuts[0]); i++) { modifiers(&s, shortcuts[i]); key(&s, KEY_A, true); - next(&w, YASL_EVENT_KEY); + next(&w, YASL_PRIVATE_EVENT_KEY); empty(&w); /* Shortcut characters never leak into committed text. */ } layout(&s, "fr", NULL); key(&s, KEY_A, true); - ev = next(&w, YASL_EVENT_KEY); + ev = next(&w, YASL_PRIVATE_EVENT_KEY); assert(ev.key.key == YASL_KEY_A && ev.key.codepoint == 'q'); - assert(strcmp(next(&w, YASL_EVENT_TEXT).text.data, "q") == 0); + assert(strcmp(next(&w, YASL_PRIVATE_EVENT_TEXT).text.data, "q") == 0); layout(&s, "de", NULL); modifiers(&s, "Mod5"); /* AltGr is text input, not an Alt shortcut. */ key(&s, KEY_E, true); - assert(next(&w, YASL_EVENT_KEY).key.key == YASL_KEY_E); - assert(strcmp(next(&w, YASL_EVENT_TEXT).text.data, "€") == 0); + assert(next(&w, YASL_PRIVATE_EVENT_KEY).key.key == YASL_KEY_E); + assert(strcmp(next(&w, YASL_PRIVATE_EVENT_TEXT).text.data, "€") == 0); layout(&s, "us", "intl"); key(&s, KEY_APOSTROPHE, true); - next(&w, YASL_EVENT_KEY); + next(&w, YASL_PRIVATE_EVENT_KEY); empty(&w); key(&s, KEY_E, true); - next(&w, YASL_EVENT_KEY); - assert(strcmp(next(&w, YASL_EVENT_TEXT).text.data, "é") == 0); + next(&w, YASL_PRIVATE_EVENT_KEY); + assert(strcmp(next(&w, YASL_PRIVATE_EVENT_TEXT).text.data, "é") == 0); assert(keyboard_dispatch_key(&s, &w, KEY_E, YASL_KEY_REPEAT)); - assert(next(&w, YASL_EVENT_KEY).key.action == YASL_KEY_REPEAT); - assert(strcmp(next(&w, YASL_EVENT_TEXT).text.data, "e") == 0); + assert(next(&w, YASL_PRIVATE_EVENT_KEY).key.action == YASL_KEY_REPEAT); + assert(strcmp(next(&w, YASL_PRIVATE_EVENT_TEXT).text.data, "e") == 0); key(&s, KEY_APOSTROPHE, true); - next(&w, YASL_EVENT_KEY); + next(&w, YASL_PRIVATE_EVENT_KEY); keyboard_reset_keys(&s, &w); key(&s, KEY_E, true); - next(&w, YASL_EVENT_KEY); - assert(strcmp(next(&w, YASL_EVENT_TEXT).text.data, "e") == 0); + next(&w, YASL_PRIVATE_EVENT_KEY); + assert(strcmp(next(&w, YASL_PRIVATE_EVENT_TEXT).text.data, "e") == 0); key(&s, KEY_APOSTROPHE, true); - next(&w, YASL_EVENT_KEY); + next(&w, YASL_PRIVATE_EVENT_KEY); s.ime_focus = &w; + w.base.text_input_active = true; text_input_listener.commit_string(&s, NULL, "å—"); text_input_listener.done(&s, NULL, 0); - assert(strcmp(next(&w, YASL_EVENT_TEXT).text.data, "å—") == 0); + assert(strcmp(next(&w, YASL_PRIVATE_EVENT_TEXT).text.data, "å—") == 0); key(&s, KEY_E, true); - next(&w, YASL_EVENT_KEY); - assert(strcmp(next(&w, YASL_EVENT_TEXT).text.data, "e") == 0); + next(&w, YASL_PRIVATE_EVENT_KEY); + assert(strcmp(next(&w, YASL_PRIVATE_EVENT_TEXT).text.data, "e") == 0); empty(&w); xkb_compose_state_unref(s.compose); xkb_state_unref(s.xkb_state); diff --git a/tests/wayland/test_popup_positioner.c b/tests/wayland/test_popup_positioner.c new file mode 100644 index 0000000..86778f6 --- /dev/null +++ b/tests/wayland/test_popup_positioner.c @@ -0,0 +1,93 @@ +/* Capture xdg_positioner requests to verify explicit placement and the legacy + * beside mapping without requiring a compositor. */ +#include "platform/wayland/internal.h" +#include <assert.h> + +struct recorded_positioner { + int width, height; + int rect_x, rect_y, rect_width, rect_height; + uint32_t anchor, gravity, constraints; + bool reactive; +}; + +static struct recorded_positioner record; +static uint64_t fake_positioner_storage[8]; +#define FAKE_POSITIONER ((struct xdg_positioner *)fake_positioner_storage) +static struct xdg_positioner *fake_create(struct xdg_wm_base *base) +{ (void)base; record = (struct recorded_positioner){0}; return FAKE_POSITIONER; } +static void fake_size(struct xdg_positioner *pos, int32_t width, int32_t height) +{ assert(pos == FAKE_POSITIONER); record.width = width; record.height = height; } +static void fake_rect(struct xdg_positioner *pos, int32_t x, int32_t y, int32_t width, int32_t height) +{ assert(pos == FAKE_POSITIONER); record.rect_x=x; record.rect_y=y; record.rect_width=width; record.rect_height=height; } +static void fake_anchor(struct xdg_positioner *pos, uint32_t value) +{ assert(pos == FAKE_POSITIONER); record.anchor = value; } +static void fake_gravity(struct xdg_positioner *pos, uint32_t value) +{ assert(pos == FAKE_POSITIONER); record.gravity = value; } +static void fake_constraints(struct xdg_positioner *pos, uint32_t value) +{ assert(pos == FAKE_POSITIONER); record.constraints = value; } +static uint32_t fake_version(struct xdg_positioner *pos) +{ assert(pos == FAKE_POSITIONER); return XDG_POSITIONER_SET_REACTIVE_SINCE_VERSION; } +static void fake_reactive(struct xdg_positioner *pos) +{ assert(pos == FAKE_POSITIONER); record.reactive = true; } + +#define xdg_wm_base_create_positioner fake_create +#define xdg_positioner_set_size fake_size +#define xdg_positioner_set_anchor_rect fake_rect +#define xdg_positioner_set_anchor fake_anchor +#define xdg_positioner_set_gravity fake_gravity +#define xdg_positioner_set_constraint_adjustment fake_constraints +#define xdg_positioner_get_version fake_version +#define xdg_positioner_set_reactive fake_reactive +#include "../../src/platform/wayland/popup.c" + +int main(void) +{ + struct wayland_display display = {.wm_base = (struct xdg_wm_base *)&record}; + struct wayland_surface parent = { + .scale_120 = 120, + .content = {.x = 3, .y = 4}, + }; + struct wayland_surface popup = { + .conn = &display, + .parent = &parent, + .scale_120 = 120, + .content = {.width = 48, .height = 36}, + }; + struct yasl_private_popup_spec spec = { + .size = {64, 48}, + .anchor = {13, 24, 8, 6}, + .beside = true, + }; + + struct xdg_positioner *positioner = popup_positioner(&popup, &spec); + assert(positioner == FAKE_POSITIONER); + assert(record.width == 48 && record.height == 36); + assert(record.rect_x == 10 && record.rect_y == 20 && + record.rect_width == 8 && record.rect_height == 6); + assert(record.anchor == XDG_POSITIONER_ANCHOR_TOP_RIGHT); + assert(record.gravity == XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT); + assert(record.constraints == (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X | + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y | + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X | + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y)); + assert(record.reactive); + + spec.positioner_explicit = true; + spec.anchor_edges = XDG_POSITIONER_ANCHOR_NONE; + spec.gravity = XDG_POSITIONER_GRAVITY_RIGHT; + spec.constraints = XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X | + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y; + assert(popup_spec_valid(&parent, &spec)); + positioner = popup_positioner(&popup, &spec); + assert(positioner == FAKE_POSITIONER); + assert(record.anchor == XDG_POSITIONER_ANCHOR_NONE); + assert(record.gravity == XDG_POSITIONER_GRAVITY_RIGHT); + assert(record.constraints == spec.constraints); + + spec.anchor_edges = XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT + 1; + assert(!popup_spec_valid(&parent, &spec)); + spec.anchor_edges = XDG_POSITIONER_ANCHOR_NONE; + spec.constraints = 1u << 9; + assert(!popup_spec_valid(&parent, &spec)); + return 0; +} diff --git a/tests/wayland/test_relative_pointer.c b/tests/wayland/test_relative_pointer.c index bcc41e3..d44238d 100644 --- a/tests/wayland/test_relative_pointer.c +++ b/tests/wayland/test_relative_pointer.c @@ -65,10 +65,10 @@ static void shape_device_destroy(struct wp_cursor_shape_device_v1 *device) { ass #define wl_pointer_release pointer_release #include "../../src/platform/wayland/pointer.c" -static struct yasl_event next_event(struct wayland_surface *w) +static struct yasl_private_event next_event(struct wayland_surface *w) { - struct yasl_event event; - assert(yasl_surface_poll_event(&w->base, &event)); + struct yasl_private_event event; + assert(yasl_private_surface_poll_event(&w->base, &event)); return event; } @@ -85,9 +85,9 @@ static void relative_move(struct seat *s, double dx, double dy) int main(void) { - struct wayland_display display = {.base.ops = &yasl_wayland_backend}; + struct wayland_display display = {.base.ops = &yasl_private_wayland_backend}; struct wayland_surface surface = {.base.display = &display.base, .conn = &display, - .scale_factor = 2, .cursor = YASL_CURSOR_TEXT}; + .scale_factor = 2, .cursor = YASL_PRIVATE_CURSOR_TEXT}; surface.surface = (struct wl_surface *)&surface; wl_surface_set_user_data(surface.surface, &surface); display.surfaces = &surface; @@ -95,10 +95,10 @@ int main(void) seat.pointer = (struct wl_pointer *)&seat; seat.cursor_shape_dev = (struct wp_cursor_shape_device_v1 *)&seat; display.seats = &seat; - struct yasl_event event; + struct yasl_private_event event; /* Without both protocols the surface stays in absolute mode. */ - assert(!yasl_surface_set_pointer_mode(&surface.base, YASL_POINTER_RELATIVE)); + assert(!yasl_private_surface_set_pointer_mode(&surface.base, YASL_PRIVATE_POINTER_RELATIVE)); assert(!surface.relative && !locks); display.relative_pointer_mgr = (struct zwp_relative_pointer_manager_v1 *)&display; display.pointer_constraints = (struct zwp_pointer_constraints_v1 *)&display; @@ -107,10 +107,10 @@ int main(void) pointer_frame(&seat, seat.pointer); assert(pointer_shapes == 1); event = next_event(&surface); - assert(event.type == YASL_EVENT_POINTER_MOTION && event.pointer.pos.x == 10); + assert(event.type == YASL_PRIVATE_EVENT_POINTER_MOTION && event.pointer.pos.x == 10); /* Relative mode locks persistently on the pointer's seat and hides the cursor. */ - assert(yasl_surface_set_pointer_mode(&surface.base, YASL_POINTER_RELATIVE)); + assert(yasl_private_surface_set_pointer_mode(&surface.base, YASL_PRIVATE_POINTER_RELATIVE)); assert(locks == 1 && locked_surface == surface.surface && locked_wl_pointer == seat.pointer); assert(lock_lifetime == ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); assert(pointer_hides == 1 && surface.lock_seat == &seat); @@ -121,14 +121,14 @@ int main(void) event = next_event(&surface); assert(event.pointer.pos.x == 14 && event.pointer.pos.y == 10); assert(event.pointer.delta.x == 4 && event.pointer.delta.y == 0); - assert(!yasl_surface_poll_event(&surface.base, &event)); + assert(!yasl_private_surface_poll_event(&surface.base, &event)); /* Locked: relative samples in device pixels, position frozen at the lock. */ pointer_locked(&surface, surface.pointer_lock); relative_move(&seat, 3.5, -2); relative_move(&seat, 1000, 0); event = next_event(&surface); - assert(event.type == YASL_EVENT_POINTER_MOTION); + assert(event.type == YASL_PRIVATE_EVENT_POINTER_MOTION); assert(event.pointer.pos.x == 14 && event.pointer.pos.y == 10); assert(event.pointer.delta.x == 7 && event.pointer.delta.y == -4); event = next_event(&surface); @@ -137,7 +137,7 @@ int main(void) /* Deactivation (e.g. focus loss) returns to absolute motion without unlocking. */ pointer_unlocked(&surface, surface.pointer_lock); relative_move(&seat, 5, 5); - assert(!yasl_surface_poll_event(&surface.base, &event)); + assert(!yasl_private_surface_poll_event(&surface.base, &event)); move_to(&seat, 8, 5); event = next_event(&surface); assert(event.pointer.delta.x == 2 && event.pointer.delta.y == 0); @@ -145,12 +145,12 @@ int main(void) pointer_locked(&surface, surface.pointer_lock); /* Returning to normal destroys the lock and restores the chosen cursor. */ - assert(yasl_surface_set_pointer_mode(&surface.base, YASL_POINTER_NORMAL)); + assert(yasl_private_surface_set_pointer_mode(&surface.base, YASL_PRIVATE_POINTER_NORMAL)); assert(unlocks == 1 && !surface.pointer_lock && !surface.input.relative); assert(pointer_shapes == 2); - assert(yasl_surface_set_pointer_mode(&surface.base, YASL_POINTER_NORMAL)); + assert(yasl_private_surface_set_pointer_mode(&surface.base, YASL_PRIVATE_POINTER_NORMAL)); assert(unlocks == 1); - assert(yasl_surface_set_pointer_mode(&surface.base, YASL_POINTER_RELATIVE)); + assert(yasl_private_surface_set_pointer_mode(&surface.base, YASL_PRIVATE_POINTER_RELATIVE)); assert(locks == 2 && pointer_hides == 2); pointer_locked(&surface, surface.pointer_lock); diff --git a/tests/wayland/test_state.c b/tests/wayland/test_state.c index 2da26e5..1ce9189 100644 --- a/tests/wayland/test_state.c +++ b/tests/wayland/test_state.c @@ -1,6 +1,20 @@ -#include "../../src/platform/wayland/shell.c" +#include "platform/wayland/internal.h" #include <assert.h> +static uint32_t acknowledged_serial; +static unsigned acknowledge_count; +static void test_ack_configure(struct xdg_surface *surface, uint32_t serial); +#define xdg_surface_ack_configure test_ack_configure +#include "../../src/platform/wayland/shell.c" +#undef xdg_surface_ack_configure + +static void test_ack_configure(struct xdg_surface *surface, uint32_t serial) +{ + (void)surface; + acknowledged_serial = serial; + acknowledge_count++; +} + struct notifications { int count; uint32_t state; @@ -9,7 +23,7 @@ struct notifications { static void state_changed(struct yasl_surface *surface, uint32_t state, void *ud) { struct notifications *notifications = ud; - assert(yasl_surface_state(surface) == state); + assert(yasl_private_surface_state(surface) == state); notifications->count++; notifications->state = state; } @@ -24,33 +38,33 @@ static void configure(struct wayland_surface *surface, uint32_t *states, size_t int main(void) { struct notifications notifications = {0}; - struct wayland_surface surface = {.base.state = YASL_STATE_CSD}; - wayland_surface_set_callbacks(&surface, &(struct yasl_window_cbs){ + struct wayland_surface surface = {.base.state = YASL_PRIVATE_STATE_CSD}; + wayland_surface_set_callbacks(&surface, &(struct yasl_private_window_cbs){ .state = state_changed}, ¬ifications); - assert(yasl_surface_state(&surface.base) == YASL_STATE_CSD); + assert(yasl_private_surface_state(&surface.base) == YASL_PRIVATE_STATE_CSD); uint32_t fullscreen[] = {XDG_TOPLEVEL_STATE_FULLSCREEN, XDG_TOPLEVEL_STATE_ACTIVATED, XDG_TOPLEVEL_STATE_FULLSCREEN, 31, UINT32_MAX}; configure(&surface, fullscreen, sizeof(fullscreen) / sizeof(*fullscreen)); assert(notifications.count == 1); - assert(notifications.state == (YASL_STATE_CSD | YASL_STATE_FULLSCREEN | YASL_STATE_ACTIVATED)); + assert(notifications.state == (YASL_PRIVATE_STATE_CSD | YASL_PRIVATE_STATE_FULLSCREEN | YASL_PRIVATE_STATE_ACTIVATED)); configure(&surface, fullscreen, sizeof(fullscreen) / sizeof(*fullscreen)); assert(notifications.count == 1); /* Decoration changes preserve the other flags and do not notify twice. */ toplevel_decoration_configure(&surface, NULL, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); assert(notifications.count == 2); - assert(notifications.state == (YASL_STATE_FULLSCREEN | YASL_STATE_ACTIVATED)); + assert(notifications.state == (YASL_PRIVATE_STATE_FULLSCREEN | YASL_PRIVATE_STATE_ACTIVATED)); toplevel_decoration_configure(&surface, NULL, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); assert(notifications.count == 2); uint32_t maximized[] = {XDG_TOPLEVEL_STATE_MAXIMIZED, XDG_TOPLEVEL_STATE_SUSPENDED}; configure(&surface, maximized, sizeof(maximized) / sizeof(*maximized)); assert(notifications.count == 3); - assert(notifications.state == (YASL_STATE_MAXIMIZED | YASL_STATE_SUSPENDED)); + assert(notifications.state == (YASL_PRIVATE_STATE_MAXIMIZED | YASL_PRIVATE_STATE_SUSPENDED)); toplevel_decoration_configure(&surface, NULL, ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE); assert(notifications.count == 4); - assert(notifications.state == (YASL_STATE_CSD | YASL_STATE_MAXIMIZED | YASL_STATE_SUSPENDED)); + assert(notifications.state == (YASL_PRIVATE_STATE_CSD | YASL_PRIVATE_STATE_MAXIMIZED | YASL_PRIVATE_STATE_SUSPENDED)); /* Each tiled edge maps to the same portable flag; changing edges alone * leaves the reported state unchanged. */ @@ -59,17 +73,38 @@ int main(void) for (size_t i = 0; i < sizeof(edges) / sizeof(*edges); i++) { configure(&surface, &edges[i], 1); assert(notifications.count == 5); - assert(notifications.state == (YASL_STATE_CSD | YASL_STATE_TILED)); + assert(notifications.state == (YASL_PRIVATE_STATE_CSD | YASL_PRIVATE_STATE_TILED)); } configure(&surface, edges, 0); assert(notifications.count == 6); - assert(notifications.state == YASL_STATE_CSD); + assert(notifications.state == YASL_PRIVATE_STATE_CSD); /* State still advances when applications have not installed callbacks. */ wayland_surface_set_callbacks(&surface, NULL, NULL); configure(&surface, fullscreen, sizeof(fullscreen) / sizeof(*fullscreen)); - assert(yasl_surface_state(&surface.base) == - (YASL_STATE_CSD | YASL_STATE_FULLSCREEN | YASL_STATE_ACTIVATED)); + assert(yasl_private_surface_state(&surface.base) == + (YASL_PRIVATE_STATE_CSD | YASL_PRIVATE_STATE_FULLSCREEN | YASL_PRIVATE_STATE_ACTIVATED)); assert(notifications.count == 6); + + /* External presentation has no SHM commit callback to acknowledge xdg + * configures. Apply geometry and acknowledge before renderer submission. */ + struct wayland_surface gpu = { + .base.presenter = YASL_PRIVATE_PRESENTER_VULKAN, + .width = 0, .height = 0, + .logical_width = 64, .logical_height = 64, + .req_width = 64, .req_height = 64, + .scale_120 = YASL_PRIVATE_SCALE_UNIT, + .pending_scale_120 = 180, + }; + acknowledge_count = 0; + xdg_surface_configure(&gpu, (struct xdg_surface *)&gpu, 1234); + assert(acknowledge_count == 1 && acknowledged_serial == 1234); + assert(!gpu.has_pending_serial && !gpu.size_pending); + assert(gpu.configured && gpu.width == 96 && gpu.height == 96); + + /* CPU presentation keeps its existing deferred ack with the SHM commit. */ + struct wayland_surface cpu = {.base.presenter = YASL_PRIVATE_PRESENTER_CPU}; + xdg_surface_configure(&cpu, (struct xdg_surface *)&cpu, 5678); + assert(acknowledge_count == 1 && cpu.has_pending_serial && cpu.want_draw); return 0; } diff --git a/tests/wayland/test_tablet.c b/tests/wayland/test_tablet.c index c76ddf8..f47fbfa 100644 --- a/tests/wayland/test_tablet.c +++ b/tests/wayland/test_tablet.c @@ -1,63 +1,101 @@ #include "../../src/platform/wayland/pointer.c" #include <assert.h> -static struct yasl_event next(struct wayland_surface *surface) +static struct yasl_private_event next_raw(struct wayland_surface *surface) { - struct yasl_event event; - assert(yasl_surface_poll_event(&surface->base, &event)); + struct yasl_private_event event; + assert(yasl_private_surface_poll_event(&surface->base, &event)); assert(event.surface == &surface->base); return event; } +static struct yasl_private_event next_pointer(struct wayland_surface *surface) +{ + struct yasl_private_event event; + do { event = next_raw(surface); } while (event.type == YASL_PRIVATE_EVENT_PEN); + return event; +} + int main(void) { - struct wayland_display display = {.base.ops = &yasl_wayland_backend}; + struct wayland_display display = {.base.ops = &yasl_private_wayland_backend}; struct wayland_surface surface = {.base.display = &display.base, .conn = &display, .scale_factor = 1.5}; struct seat seat = {.conn = &display, .tablet_focus = &surface}; - struct tablet_tool tool = {.seat = &seat}; + struct tablet_tool tool = {.seat = &seat, .device_id = 77, .tool_id = 88, .kind = 1}; seat.tool = &tool; tablet_tool_motion(&tool, NULL, wl_fixed_from_int(100), wl_fixed_from_int(120)); tool_pressure(&tool, NULL, 32768); tool_tilt(&tool, NULL, wl_fixed_from_int(-35), wl_fixed_from_int(42)); + tool_distance(&tool, NULL, 16384); + tool_rotation(&tool, NULL, wl_fixed_from_int(17)); + tool_slider(&tool, NULL, -32768); + pen_action_push(&tool, YASL_PRIVATE_PEN_ENTER, 0); tablet_tool_down(&tool, NULL, 1); tool_frame(&tool, NULL, 0); - struct yasl_event ev = next(&surface); - assert(ev.type == YASL_EVENT_POINTER_MOTION && ev.pointer.device == YASL_PTR_DEV_PEN); + struct yasl_private_event pen = next_raw(&surface); + assert(pen.type == YASL_PRIVATE_EVENT_PEN); + assert(pen.pen.action == YASL_PRIVATE_PEN_ENTER && !pen.pen.in_contact); + assert(pen.pen.device_id == 77 && pen.pen.tool_id == 88); + pen = next_raw(&surface); + assert(pen.type == YASL_PRIVATE_EVENT_PEN); + assert(pen.pen.action == YASL_PRIVATE_PEN_DOWN && pen.pen.in_contact); + assert(pen.pen.buttons & YASL_PRIVATE_BUTTON_BIT(YASL_PRIVATE_BUTTON_PRIMARY)); + assert(pen.pen.x == 150 && pen.pen.y == 180); + assert(fabs(pen.pen.pressure - (32768.0 / 65535.0)) < 0.00001); + assert(pen.pen.axes_valid == (YASL_PRIVATE_PEN_PRESSURE | YASL_PRIVATE_PEN_TILT | + YASL_PRIVATE_PEN_DISTANCE | YASL_PRIVATE_PEN_ROTATION | YASL_PRIVATE_PEN_TANGENTIAL)); + assert(pen.pen.axes_changed == pen.pen.axes_valid); + assert(fabs(pen.pen.distance - 16384.0 / 65535.0) < 0.00001); + assert(pen.pen.rotation == 17 && pen.pen.tangential == -32768.0 / 65535.0); + struct yasl_private_event ev = next_pointer(&surface); + assert(ev.type == YASL_PRIVATE_EVENT_POINTER_MOTION && ev.pointer.device == YASL_PRIVATE_PTR_DEV_PEN); assert(ev.pointer.pos.x == 150 && ev.pointer.pos.y == 180 && ev.pointer.pen.pressure == 32768); assert(ev.pointer.pen.tilt_x == -35 && ev.pointer.pen.tilt_y == 42); - ev = next(&surface); - assert(ev.type == YASL_EVENT_POINTER_DOWN && ev.pointer.button == YASL_BUTTON_PRIMARY && ev.pointer.pen.pressure == 32768); + ev = next_pointer(&surface); + assert(ev.type == YASL_PRIVATE_EVENT_POINTER_DOWN && ev.pointer.button == YASL_PRIVATE_BUTTON_PRIMARY && ev.pointer.pen.pressure == 32768); /* Stationary pressure and tilt changes are still motion samples. */ tool_pressure(&tool, NULL, 100000); tool_tilt(&tool, NULL, wl_fixed_from_int(-120), wl_fixed_from_int(120)); tool_frame(&tool, NULL, 0); - ev = next(&surface); - assert(ev.type == YASL_EVENT_POINTER_MOTION && ev.pointer.pen.pressure == 65535); + pen = next_raw(&surface); + assert(pen.type == YASL_PRIVATE_EVENT_PEN && pen.pen.action == YASL_PRIVATE_PEN_MOVE); + assert(pen.pen.axes_changed == (YASL_PRIVATE_PEN_PRESSURE | YASL_PRIVATE_PEN_TILT)); + ev = next_pointer(&surface); + assert(ev.type == YASL_PRIVATE_EVENT_POINTER_MOTION && ev.pointer.pen.pressure == 65535); assert(ev.pointer.pos.x == 150 && ev.pointer.pos.y == 180); assert(ev.pointer.pen.tilt_x == -90 && ev.pointer.pen.tilt_y == 90); tablet_tool_up(&tool, NULL); tool_frame(&tool, NULL, 0); - ev = next(&surface); - assert(ev.type == YASL_EVENT_POINTER_UP && ev.pointer.button == YASL_BUTTON_PRIMARY && !ev.pointer.pen.pressure); + pen = next_raw(&surface); + assert(pen.type == YASL_PRIVATE_EVENT_PEN && pen.pen.action == YASL_PRIVATE_PEN_UP); + assert(!pen.pen.in_contact && pen.pen.pressure == 0); + ev = next_pointer(&surface); + assert(ev.type == YASL_PRIVATE_EVENT_POINTER_UP && ev.pointer.button == YASL_PRIVATE_BUTTON_PRIMARY && !ev.pointer.pen.pressure); tool_type(&tool, NULL, ZWP_TABLET_TOOL_V2_TYPE_ERASER); tool_pressure(&tool, NULL, 22000); tool_frame(&tool, NULL, 0); - assert(next(&surface).pointer.device == YASL_PTR_DEV_ERASER); + pen = next_raw(&surface); + assert(pen.type == YASL_PRIVATE_EVENT_PEN && pen.pen.tool == 2); + assert(next_pointer(&surface).pointer.device == YASL_PRIVATE_PTR_DEV_ERASER); tool_wheel(&tool, NULL, 0, 1); tool_frame(&tool, NULL, 0); - ev = next(&surface); - assert(ev.type == YASL_EVENT_POINTER_SCROLL && ev.pointer.device == YASL_PTR_DEV_ERASER); + pen = next_raw(&surface); + assert(pen.type == YASL_PRIVATE_EVENT_PEN && pen.pen.axes_changed == YASL_PRIVATE_PEN_WHEEL); + ev = next_pointer(&surface); + assert(ev.type == YASL_PRIVATE_EVENT_POINTER_SCROLL && ev.pointer.device == YASL_PRIVATE_PTR_DEV_ERASER); assert(ev.pointer.scroll.x == 0 && ev.pointer.scroll.y == 1); tablet_tool_proximity_out(&tool, NULL); - ev = next(&surface); - assert(ev.type == YASL_EVENT_POINTER_LEAVE && ev.pointer.device == YASL_PTR_DEV_ERASER && !ev.pointer.pen.pressure); + pen = next_raw(&surface); + assert(pen.type == YASL_PRIVATE_EVENT_PEN && pen.pen.action == YASL_PRIVATE_PEN_LEAVE); + ev = next_pointer(&surface); + assert(ev.type == YASL_PRIVATE_EVENT_POINTER_LEAVE && ev.pointer.device == YASL_PRIVATE_PTR_DEV_ERASER && !ev.pointer.pen.pressure); assert(!seat.tool && !seat.tablet_focus && !seat.tool_buttons); - assert(!(yasl_display_caps(&display.base) & YASL_CAP_TABLET)); + assert(!(yasl_private_display_caps(&display.base) & YASL_PRIVATE_CAP_TABLET)); display.tablet_mgr = (void *)&display; /* Capability depends on protocol availability. */ - assert(yasl_display_caps(&display.base) & YASL_CAP_TABLET); + assert(yasl_private_display_caps(&display.base) & YASL_PRIVATE_CAP_TABLET); seat.pointer_focus = &surface; /* A compositor may describe the same detent in three ways. value120 wins, @@ -67,13 +105,32 @@ int main(void) pointer_axis_value120(&seat, NULL, WL_POINTER_AXIS_VERTICAL_SCROLL, 30); pointer_axis_value120(&seat, NULL, WL_POINTER_AXIS_HORIZONTAL_SCROLL, -60); pointer_frame(&seat, NULL); - ev = next(&surface); - assert(ev.type == YASL_EVENT_POINTER_SCROLL && ev.pointer.device == YASL_PTR_DEV_MOUSE); + ev = next_pointer(&surface); + assert(ev.type == YASL_PRIVATE_EVENT_POINTER_SCROLL && ev.pointer.device == YASL_PRIVATE_PTR_DEV_MOUSE); assert(ev.pointer.scroll.x == -0.5 && ev.pointer.scroll.y == 0.25); - struct yasl_event unused; - assert(!yasl_surface_poll_event(&surface.base, &unused)); + assert(ev.pointer.scroll_valid == 1); + assert(ev.pointer.scroll_source == 1 && ev.pointer.scroll_phase == 0); + struct yasl_private_event unused; + assert(!yasl_private_surface_poll_event(&surface.base, &unused)); + pointer_frame(&seat, NULL); + assert(!yasl_private_surface_poll_event(&surface.base, &unused)); + + /* Finger scrolling carries pixel offsets and coherent gesture phases. */ + pointer_axis_source(&seat, NULL, WL_POINTER_AXIS_SOURCE_FINGER); + pointer_axis(&seat, NULL, 0, WL_POINTER_AXIS_VERTICAL_SCROLL, wl_fixed_from_double(1.25)); + pointer_axis(&seat, NULL, 0, WL_POINTER_AXIS_HORIZONTAL_SCROLL, wl_fixed_from_double(-2.5)); + pointer_frame(&seat, NULL); + ev = next_pointer(&surface); + assert(ev.pointer.scroll_phase == 1 && ev.pointer.scroll_source == 2); + assert(ev.pointer.pixel_scroll.x == -3.75 && ev.pointer.pixel_scroll.y == 1.875); + pointer_axis(&seat, NULL, 0, WL_POINTER_AXIS_VERTICAL_SCROLL, wl_fixed_from_double(1.25)); + pointer_frame(&seat, NULL); + ev = next_pointer(&surface); + assert(ev.pointer.scroll_phase == 2 && ev.pointer.scroll.y == 0.125); + pointer_axis_stop(&seat, NULL, 0, WL_POINTER_AXIS_VERTICAL_SCROLL); pointer_frame(&seat, NULL); - assert(!yasl_surface_poll_event(&surface.base, &unused)); + ev = next_pointer(&surface); + assert(ev.pointer.scroll_phase == 3 && ev.pointer.scroll.x == 0 && ev.pointer.scroll.y == 0); /* Stops preserve offsets from the same frame. Repeated tiny movements * must be visible immediately rather than held until a whole detent. */ @@ -83,17 +140,19 @@ int main(void) pointer_axis(&seat, NULL, 0, WL_POINTER_AXIS_HORIZONTAL_SCROLL, wl_fixed_from_double(-2.5)); pointer_axis_stop(&seat, NULL, 0, WL_POINTER_AXIS_VERTICAL_SCROLL); pointer_frame(&seat, NULL); - ev = next(&surface); + ev = next_pointer(&surface); assert(ev.pointer.scroll.x == -0.25 && ev.pointer.scroll.y == 0.125); + assert(ev.pointer.scroll_source == 2 && ev.pointer.scroll_phase == 3); + assert(ev.pointer.pixel_scroll.x == -3.75 && ev.pointer.pixel_scroll.y == 1.875); } pointer_axis_discrete(&seat, NULL, WL_POINTER_AXIS_HORIZONTAL_SCROLL, 2); pointer_frame(&seat, NULL); - ev = next(&surface); + ev = next_pointer(&surface); assert(ev.pointer.scroll.x == 2 && ev.pointer.scroll.y == 0); pointer_axis_value120(&seat, NULL, WL_POINTER_AXIS_VERTICAL_SCROLL, 60); seat_pointer_reset(&seat); pointer_frame(&seat, NULL); - assert(!yasl_surface_poll_event(&surface.base, &unused)); + assert(!yasl_private_surface_poll_event(&surface.base, &unused)); input_queue_clear(&surface.input); return 0; } diff --git a/tests/x11/inputtest-protocol.h b/tests/x11/inputtest-protocol.h index 18f62ba..2a94a55 100644 --- a/tests/x11/inputtest-protocol.h +++ b/tests/x11/inputtest-protocol.h @@ -22,8 +22,8 @@ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef YASL_TEST_INPUTTEST_PROTOCOL_H -#define YASL_TEST_INPUTTEST_PROTOCOL_H +#ifndef YASL_PRIVATE_TEST_INPUTTEST_PROTOCOL_H +#define YASL_PRIVATE_TEST_INPUTTEST_PROTOCOL_H #include <stdint.h> diff --git a/tests/x11/test_input.c b/tests/x11/test_input.c index c2eca37..ccad859 100644 --- a/tests/x11/test_input.c +++ b/tests/x11/test_input.c @@ -8,10 +8,10 @@ static void check_selection_encoding(struct x11_display *d, struct x11_surface * { Window requestor = XCreateSimpleWindow(d->native, DefaultRootWindow(d->native), 0, 0, 1, 1, 0, 0, 0); - Atom property = XInternAtom(d->native, "YASL_TEST_STRING", False); + Atom property = XInternAtom(d->native, "YASL_PRIVATE_TEST_STRING", False); XSelectionRequestEvent request = {.display = d->native, .requestor = requestor, .selection = d->clipboard, .target = XA_STRING, .property = property}; - yasl_display_copy(&d->base, YASL_CLIPBOARD, "café £"); + yasl_private_display_copy(&d->base, YASL_PRIVATE_CLIPBOARD, "café £"); selection_request(d, &request); Atom actual; int format; @@ -22,7 +22,7 @@ static void check_selection_encoding(struct x11_display *d, struct x11_surface * assert(actual == XA_STRING && format == 8 && count == 6); assert(memcmp(data, "caf\xe9 \xa3", count) == 0); XFree(data); - yasl_display_copy(&d->base, YASL_CLIPBOARD, "å—"); + yasl_private_display_copy(&d->base, YASL_PRIVATE_CLIPBOARD, "å—"); selection_request(d, &request); assert(XGetWindowProperty(d->native, requestor, property, 0, 100, True, AnyPropertyType, &actual, &format, &count, &left, &data) == Success); @@ -44,12 +44,12 @@ static void check_selection_encoding(struct x11_display *d, struct x11_surface * size_t len; int format; const char *expected; - enum yasl_transfer_status status; + enum yasl_private_transfer_status status; } cases[] = { - {XA_STRING, "caf\xe9 \xa3", 6, 8, "café £", YASL_TRANSFER_OK}, - {d->utf8, "", 0, 8, "", YASL_TRANSFER_OK}, - {d->utf8, "\xff", 1, 8, NULL, YASL_TRANSFER_FAILED}, - {d->incr, NULL, 1, 32, NULL, YASL_TRANSFER_FAILED}, + {XA_STRING, "caf\xe9 \xa3", 6, 8, "café £", YASL_PRIVATE_TRANSFER_OK}, + {d->utf8, "", 0, 8, "", YASL_PRIVATE_TRANSFER_OK}, + {d->utf8, "\xff", 1, 8, NULL, YASL_PRIVATE_TRANSFER_FAILED}, + {d->incr, NULL, 1, 32, NULL, YASL_PRIVATE_TRANSFER_FAILED}, }; for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) { struct paste_request *pending = calloc(1, sizeof(*pending)); @@ -59,7 +59,7 @@ static void check_selection_encoding(struct x11_display *d, struct x11_surface * 0, 0, 1, 1, 0, 0, 0); pending->target = s; pending->id = (uint64_t)i + 1; - pending->timeout = yasl_loop_add_timer(d->loop, PASTE_TIMEOUT_NS, + pending->timeout = yasl_private_loop_add_timer(d->loop, PASTE_TIMEOUT_NS, paste_timeout, pending); assert(pending->timeout); pending->next = d->pastes; @@ -71,21 +71,21 @@ static void check_selection_encoding(struct x11_display *d, struct x11_surface * cases[i].format, PropModeReplace, bytes, (int)cases[i].len); XSelectionEvent reply = {.requestor = pending->window, .property = property}; selection_notify(d, &reply); - struct yasl_event event; - assert(yasl_surface_poll_event(&s->base, &event)); - assert(event.type == YASL_EVENT_PASTE && event.paste.request_id == i + 1); + struct yasl_private_event event; + assert(yasl_private_surface_poll_event(&s->base, &event)); + assert(event.type == YASL_PRIVATE_EVENT_PASTE && event.paste.request_id == i + 1); assert(event.paste.status == cases[i].status); - if (cases[i].status == YASL_TRANSFER_OK) { + if (cases[i].status == YASL_PRIVATE_TRANSFER_OK) { assert(event.text.len == strlen(cases[i].expected)); assert(strcmp(event.text.data, cases[i].expected) == 0); } if (cases[i].type == d->incr) { assert(d->pastes == pending && !pending->target); - assert(yasl_loop_del_timer(d->loop, pending->timeout)); + assert(yasl_private_loop_del_timer(d->loop, pending->timeout)); pending->timeout = 0; paste_timeout(pending, 0, PASTE_TIMEOUT_NS); } - assert(!yasl_surface_poll_event(&s->base, &event)); + assert(!yasl_private_surface_poll_event(&s->base, &event)); } struct paste_request *rejected = calloc(1, sizeof(*rejected)); @@ -99,10 +99,10 @@ static void check_selection_encoding(struct x11_display *d, struct x11_surface * d->pastes = rejected; XSelectionEvent no_property = {.requestor = rejected->window, .property = None}; selection_notify(d, &no_property); - struct yasl_event event; - assert(yasl_surface_poll_event(&s->base, &event)); - assert(event.type == YASL_EVENT_PASTE && event.paste.request_id == 99); - assert(event.paste.status == YASL_TRANSFER_FAILED); + struct yasl_private_event event; + assert(yasl_private_surface_poll_event(&s->base, &event)); + assert(event.type == YASL_PRIVATE_EVENT_PASTE && event.paste.request_id == 99); + assert(event.paste.status == YASL_PRIVATE_TRANSFER_FAILED); } /* Own the XSETTINGS selection with one Net/DoubleClickTime value. */ @@ -111,7 +111,7 @@ static void check_double_click(struct x11_display *d) /* No settings owner and no portal: the default applies. */ unsetenv("DBUS_SESSION_BUS_ADDRESS"); unsetenv("XDG_RUNTIME_DIR"); - assert(yasl_display_double_click_ms(&d->base) == YASL_DOUBLE_CLICK_MS_DEFAULT); + assert(yasl_private_display_double_click_ms(&d->base) == YASL_PRIVATE_DOUBLE_CLICK_MS_DEFAULT); char name[32]; snprintf(name, sizeof(name), "_XSETTINGS_S%d", d->screen); @@ -129,64 +129,64 @@ static void check_double_click(struct x11_display *d) XChangeProperty(d->native, owner, property, property, 8, PropModeReplace, blob, sizeof(blob)); XSync(d->native, False); - assert(yasl_display_double_click_ms(&d->base) == 250); + assert(yasl_private_display_double_click_ms(&d->base) == 250); XDestroyWindow(d->native, owner); XSync(d->native, False); - assert(yasl_display_double_click_ms(&d->base) == YASL_DOUBLE_CLICK_MS_DEFAULT); + assert(yasl_private_display_double_click_ms(&d->base) == YASL_PRIVATE_DOUBLE_CLICK_MS_DEFAULT); } -static struct yasl_event wait_paste(struct yasl_display *display, uint64_t id) +static struct yasl_private_event wait_paste(struct yasl_private_display *display, uint64_t id) { - struct yasl_event event; - for (int i = 0; i < 256 && yasl_display_poll_event(display, &event); i++) - if (event.type == YASL_EVENT_PASTE && event.paste.request_id == id) + struct yasl_private_event event; + for (int i = 0; i < 256 && yasl_private_display_poll_event(display, &event); i++) + if (event.type == YASL_PRIVATE_EVENT_PASTE && event.paste.request_id == id) return event; assert(!"expected paste completion was not queued"); - return (struct yasl_event){0}; + return (struct yasl_private_event){0}; } static void check_request_completion(struct x11_display *d, struct x11_surface *s) { assert(surface_input_queue(&s->base) == &s->input); - assert(copy_text(&d->base, YASL_CLIPBOARD, "")); + assert(copy_text(&d->base, YASL_PRIVATE_CLIPBOARD, "")); XSync(d->native, False); assert(XGetSelectionOwner(d->native, d->clipboard) == d->selection_window); - assert(request_paste(&d->base, YASL_CLIPBOARD, &s->base, 101)); - struct yasl_event event = wait_paste(&d->base, 101); - assert(event.paste.status == YASL_TRANSFER_OK && event.paste.len == 0); + assert(request_paste(&d->base, YASL_PRIVATE_CLIPBOARD, &s->base, 101)); + struct yasl_private_event event = wait_paste(&d->base, 101); + assert(event.paste.status == YASL_PRIVATE_TRANSFER_OK && event.paste.len == 0); assert(event.paste.data && !event.paste.data[0]); XSetSelectionOwner(d->native, d->clipboard, None, CurrentTime); XSync(d->native, False); - assert(request_paste(&d->base, YASL_CLIPBOARD, &s->base, 102)); + assert(request_paste(&d->base, YASL_PRIVATE_CLIPBOARD, &s->base, 102)); XSync(d->native, False); dispatch(&d->base); event = wait_paste(&d->base, 102); - assert(event.paste.status == YASL_TRANSFER_UNAVAILABLE); + assert(event.paste.status == YASL_PRIVATE_TRANSFER_UNAVAILABLE); Window silent_owner = XCreateSimpleWindow(d->native, DefaultRootWindow(d->native), 0, 0, 1, 1, 0, 0, 0); XSetSelectionOwner(d->native, d->clipboard, silent_owner, CurrentTime); XSync(d->native, False); - assert(request_paste(&d->base, YASL_CLIPBOARD, &s->base, 103)); + assert(request_paste(&d->base, YASL_PRIVATE_CLIPBOARD, &s->base, 103)); struct paste_request *timed = d->pastes; assert(timed && timed->id == 103 && timed->timeout); - assert(yasl_loop_del_timer(d->loop, timed->timeout)); + assert(yasl_private_loop_del_timer(d->loop, timed->timeout)); timed->timeout = 0; paste_timeout(timed, 0, PASTE_TIMEOUT_NS); event = wait_paste(&d->base, 103); - assert(event.paste.status == YASL_TRANSFER_FAILED); + assert(event.paste.status == YASL_PRIVATE_TRANSFER_FAILED); - struct yasl_window_spec spec = {.title = "Cancelled paste", .size = {80, 60}}; - struct yasl_surface *cancel_target = yasl_surface_create_toplevel(&d->base, &spec); + struct yasl_private_window_spec spec = {.title = "Cancelled paste", .size = {80, 60}}; + struct yasl_surface *cancel_target = yasl_private_surface_create_toplevel(&d->base, &spec); assert(cancel_target); - assert(request_paste(&d->base, YASL_CLIPBOARD, cancel_target, 104)); + assert(request_paste(&d->base, YASL_PRIVATE_CLIPBOARD, cancel_target, 104)); assert(d->pastes && d->pastes->target == (struct x11_surface *)cancel_target); - yasl_timer_id timeout = d->pastes->timeout; - yasl_surface_destroy(cancel_target); + yasl_private_timer_id timeout = d->pastes->timeout; + yasl_private_surface_destroy(cancel_target); assert(d->pastes && !d->pastes->target && d->pastes->id == 0); - assert(yasl_loop_del_timer(d->loop, timeout)); + assert(yasl_private_loop_del_timer(d->loop, timeout)); d->pastes->timeout = 0; XSelectionEvent late_reply = { .requestor = d->pastes->window, @@ -200,23 +200,23 @@ static void check_request_completion(struct x11_display *d, struct x11_surface * XSync(d->native, False); } -static struct yasl_event next_composition(struct yasl_display *display) +static struct yasl_private_event next_composition(struct yasl_private_display *display) { - struct yasl_event event; - for (int i = 0; i < 256 && yasl_display_poll_event(display, &event); i++) - if (event.type == YASL_EVENT_COMPOSITION) + struct yasl_private_event event; + for (int i = 0; i < 256 && yasl_private_display_poll_event(display, &event); i++) + if (event.type == YASL_PRIVATE_EVENT_COMPOSITION) return event; assert(!"expected composition snapshot was not queued"); - return (struct yasl_event){0}; + return (struct yasl_private_event){0}; } -static void drain_display_events(struct yasl_display *display) +static void drain_display_events(struct yasl_private_display *display) { - struct yasl_event event; - while (yasl_display_poll_event(display, &event)) {} + struct yasl_private_event event; + while (yasl_private_display_poll_event(display, &event)) {} } -static void check_xim_callbacks(struct yasl_display *display, struct x11_surface *s) +static void check_xim_callbacks(struct yasl_private_display *display, struct x11_surface *s) { const char *old_locale = setlocale(LC_CTYPE, NULL); char *saved_locale = old_locale ? strdup(old_locale) : NULL; @@ -235,7 +235,7 @@ static void check_xim_callbacks(struct yasl_display *display, struct x11_surface }; xim_preedit_draw(NULL, (XPointer)s, (XPointer)&draw); assert(s->ime_preedit && strcmp(s->ime_preedit, "A😀B") == 0); - struct yasl_event event = next_composition(display); + struct yasl_private_event event = next_composition(display); assert(event.composition.active && event.composition.len == 6); assert(event.composition.begin == 5 && event.composition.end == 5); @@ -271,8 +271,8 @@ static void check_xim_callbacks(struct yasl_display *display, struct x11_surface draw.chg_length = 0; xim_preedit_draw(NULL, (XPointer)s, (XPointer)&draw); assert(strcmp(s->ime_preedit, "AéZB") == 0); - struct yasl_event unused; - assert(!yasl_display_poll_event(display, &unused)); + struct yasl_private_event unused; + assert(!yasl_private_display_poll_event(display, &unused)); wchar_t empty[] = {0}; XIMText deletion = {.length = 0, .encoding_is_wchar = True, @@ -305,12 +305,12 @@ static void check_xim_callbacks(struct yasl_display *display, struct x11_surface int main(void) { - struct yasl_display_spec ds = {.backend = YASL_BACKEND_X11}; - struct yasl_display *base = yasl_display_open(NULL, &ds); + struct yasl_private_display_spec ds = {.backend = YASL_PRIVATE_BACKEND_X11}; + struct yasl_private_display *base = yasl_private_display_open(NULL, &ds); assert(base); struct x11_display *d = (struct x11_display *)base; - struct yasl_window_spec spec = {.title = "Keyboard fallback", .size = {100, 100}}; - struct yasl_surface *surface = yasl_surface_create_toplevel(base, &spec); + struct yasl_private_window_spec spec = {.title = "Keyboard fallback", .size = {100, 100}}; + struct yasl_surface *surface = yasl_private_surface_create_toplevel(base, &spec); assert(surface); struct x11_surface *s = (struct x11_surface *)surface; XIC saved_ic = s->ic; @@ -335,22 +335,22 @@ int main(void) input_queue_clear(&s->input); /* Native creation and keymap updates may already have queued focus or * reset input on the shared display stream. Isolate this synthetic key. */ - struct yasl_event event; - while (yasl_surface_poll_event(surface, &event)) {} + struct yasl_private_event event; + while (yasl_private_surface_poll_event(surface, &event)) {} XKeyEvent native = {.type = KeyPress, .display = d->native, .window = s->window, .keycode = code}; key_event(s, &native, false); - assert(yasl_surface_poll_event(surface, &event)); - assert(event.type == YASL_EVENT_KEY && event.key.key == YASL_KEY_A); + assert(yasl_private_surface_poll_event(surface, &event)); + assert(event.type == YASL_PRIVATE_EVENT_KEY && event.key.key == YASL_KEY_A); assert(event.key.codepoint == cases[i].label); - assert(yasl_surface_poll_event(surface, &event)); - assert(event.type == YASL_EVENT_TEXT && event.text.len == strlen(cases[i].text)); + assert(yasl_private_surface_poll_event(surface, &event)); + assert(event.type == YASL_PRIVATE_EVENT_TEXT && event.text.len == strlen(cases[i].text)); assert(strcmp(event.text.data, cases[i].text) == 0); - assert(!yasl_surface_poll_event(surface, &event)); + assert(!yasl_private_surface_poll_event(surface, &event)); native.type = KeyRelease; key_event(s, &native, false); - assert(yasl_surface_poll_event(surface, &event) && event.type == YASL_EVENT_KEY); - assert(!yasl_surface_poll_event(surface, &event)); + assert(yasl_private_surface_poll_event(surface, &event) && event.type == YASL_PRIVATE_EVENT_KEY); + assert(!yasl_private_surface_poll_event(surface, &event)); } XChangeKeyboardMapping(d->native, code, width, saved, 1); XSync(d->native, False); @@ -363,14 +363,14 @@ int main(void) check_xim_callbacks(base, s); /* Test CSD interactive actions, window menu, and IME caret */ - assert(yasl_display_caps(base) & YASL_CAP_CSD); - yasl_surface_set_ime_caret(surface, (struct yasl_rect2i){10, 20, 2, 16}); - assert(yasl_surface_ime_preedit(surface) == NULL); + assert(yasl_private_display_caps(base) & YASL_PRIVATE_CAP_CSD); + yasl_private_surface_set_ime_caret(surface, (struct yasl_private_rect2i){10, 20, 2, 16}); + assert(yasl_private_surface_ime_preedit(surface) == NULL); int begin = -1, end = -1; - assert(!yasl_surface_ime_preedit_cursor(surface, &begin, &end)); - assert(yasl_surface_show_window_menu(surface, (struct yasl_vector2i){50, 50})); + assert(!yasl_private_surface_ime_preedit_cursor(surface, &begin, &end)); + assert(yasl_private_surface_show_window_menu(surface, (struct yasl_private_vector2i){50, 50})); - yasl_surface_destroy(surface); - yasl_display_close(base); + yasl_private_surface_destroy(surface); + yasl_private_display_close(base); return 0; } diff --git a/tests/x11/test_state.c b/tests/x11/test_state.c index abc0851..4696e60 100644 --- a/tests/x11/test_state.c +++ b/tests/x11/test_state.c @@ -31,7 +31,7 @@ int state_property(Display *display, Window window, Atom property, static void state_changed(struct yasl_surface *surface, uint32_t state, void *ud) { (void)ud; - assert(yasl_surface_state(surface) == state); + assert(yasl_private_surface_state(surface) == state); reported_state = state; notifications++; } @@ -93,39 +93,39 @@ static void test_xsettings(void) int main(void) { test_xsettings(); - struct x11_display display = {.base.ops = &yasl_x11_backend, + struct x11_display display = {.base.ops = &yasl_private_x11_backend, .net_state = 10, .fullscreen = 20, .maximized_h = 21, .maximized_v = 22}; display.native = (Display *)&display; struct x11_surface surface = {.base = {.display = &display.base, - .state = YASL_STATE_ACTIVATED}, .window = 42}; - set_callbacks(&surface.base, &(struct yasl_window_cbs){.state = state_changed}, NULL); + .state = YASL_PRIVATE_STATE_ACTIVATED}, .window = 42}; + set_callbacks(&surface.base, &(struct yasl_private_window_cbs){.state = state_changed}, NULL); properties[0] = display.fullscreen; property_count = 1; update_state(&surface); assert(notifications == 1); - assert(reported_state == (YASL_STATE_FULLSCREEN | YASL_STATE_ACTIVATED)); + assert(reported_state == (YASL_PRIVATE_STATE_FULLSCREEN | YASL_PRIVATE_STATE_ACTIVATED)); update_state(&surface); assert(notifications == 1); /* Both maximized axes are required; activation survives property changes. */ properties[0] = display.maximized_h; update_state(&surface); - assert(notifications == 2 && reported_state == YASL_STATE_ACTIVATED); + assert(notifications == 2 && reported_state == YASL_PRIVATE_STATE_ACTIVATED); properties[1] = display.maximized_v; property_count = 2; update_state(&surface); assert(notifications == 3); - assert(reported_state == (YASL_STATE_MAXIMIZED | YASL_STATE_ACTIVATED)); + assert(reported_state == (YASL_PRIVATE_STATE_MAXIMIZED | YASL_PRIVATE_STATE_ACTIVATED)); properties[2] = display.fullscreen; property_count = 3; update_state(&surface); assert(notifications == 4); - assert(reported_state == (YASL_STATE_FULLSCREEN | YASL_STATE_MAXIMIZED | YASL_STATE_ACTIVATED)); + assert(reported_state == (YASL_PRIVATE_STATE_FULLSCREEN | YASL_PRIVATE_STATE_MAXIMIZED | YASL_PRIVATE_STATE_ACTIVATED)); property_count = 0; update_state(&surface); - assert(notifications == 5 && reported_state == YASL_STATE_ACTIVATED); + assert(notifications == 5 && reported_state == YASL_PRIVATE_STATE_ACTIVATED); update_state(&surface); assert(notifications == 5); return 0; diff --git a/tests/x11/test_tablet.c b/tests/x11/test_tablet.c index 243ae00..be5da4c 100644 --- a/tests/x11/test_tablet.c +++ b/tests/x11/test_tablet.c @@ -1,10 +1,18 @@ /* Exercise native XI2 samples through the backend and public input queue. */ #include "../../src/platform/x11/window.c" -static struct yasl_event next(struct x11_surface *surface) +static struct yasl_private_event next(struct x11_surface *surface) { - struct yasl_event event; - assert(yasl_surface_poll_event(&surface->base, &event)); + struct yasl_private_event event; + /* This backend unit harness owns a standalone input queue, without a + * registered display event FIFO. Read rich private events directly. */ + static unsigned count; + count++; + if (!input_queue_pop(&surface->input, &event)) { + fprintf(stderr, "missing private event at expectation %u (queued=%zu reset=%d)\n", + count, surface->input.count, surface->input.reset_pending); + abort(); + } assert(event.surface == &surface->base); return event; } @@ -13,51 +21,51 @@ struct drag_test_recorder { int over_count; int leave_count; int drop_count; - struct yasl_vector2i last_pos; + struct yasl_private_vector2i last_pos; }; -static void on_test_drag(struct yasl_surface *s, enum yasl_drag_event ev, - struct yasl_vector2i pos, void *ud) +static void on_test_drag(struct yasl_surface *s, enum yasl_private_drag_event ev, + struct yasl_private_vector2i pos, void *ud) { (void)s; struct drag_test_recorder *rec = ud; rec->last_pos = pos; - if (ev == YASL_DRAG_OVER) rec->over_count++; - else if (ev == YASL_DRAG_LEAVE) rec->leave_count++; - else if (ev == YASL_DRAG_DROP) rec->drop_count++; + if (ev == YASL_PRIVATE_DRAG_OVER) rec->over_count++; + else if (ev == YASL_PRIVATE_DRAG_LEAVE) rec->leave_count++; + else if (ev == YASL_PRIVATE_DRAG_DROP) rec->drop_count++; } struct drop_test_recorder { int over_count; int leave_count; - struct yasl_vector2i last_pos; + struct yasl_private_vector2i last_pos; }; -static void on_test_drop(struct yasl_surface *s, enum yasl_drop_event ev, - struct yasl_vector2i pos, void *ud) +static void on_test_drop(struct yasl_surface *s, enum yasl_private_drop_event ev, + struct yasl_private_vector2i pos, void *ud) { (void)s; struct drop_test_recorder *rec = ud; rec->last_pos = pos; - if (ev == YASL_DROP_OVER) rec->over_count++; - else if (ev == YASL_DROP_LEAVE) rec->leave_count++; + if (ev == YASL_PRIVATE_DROP_OVER) rec->over_count++; + else if (ev == YASL_PRIVATE_DROP_LEAVE) rec->leave_count++; } -static void on_test_drag_end(void *ud, enum yasl_drag_end how) +static void on_test_drag_end(void *ud, enum yasl_private_drag_end how) { - enum yasl_drag_end *res = ud; + enum yasl_private_drag_end *res = ud; *res = how; } static void test_x11_gaps(struct x11_display *d, struct x11_surface *s) { /* 1. Caps */ - assert(caps(&d->base) & YASL_CAP_POPUPS); - assert(caps(&d->base) & YASL_CAP_DRAG); - assert(caps(&d->base) & YASL_CAP_DRAG_CARRY); + assert(caps(&d->base) & YASL_PRIVATE_CAP_POPUPS); + assert(caps(&d->base) & YASL_PRIVATE_CAP_DRAG); + assert(caps(&d->base) & YASL_PRIVATE_CAP_DRAG_CARRY); /* 2. Popups: spec validation, calculation, creation, reposition, destruction */ - struct yasl_popup_spec invalid_specs[] = { + struct yasl_private_popup_spec invalid_specs[] = { {.size = {0, 100}}, {.size = {100, 0}}, {.size = {35000, 100}}, @@ -70,7 +78,7 @@ static void test_x11_gaps(struct x11_display *d, struct x11_surface *s) assert(!surface_create_popup(&s->base, &invalid_specs[i])); } - struct yasl_popup_spec valid_spec = { + struct yasl_private_popup_spec valid_spec = { .size = {100, 120}, .anchor = {30, 40, 50, 60}, .beside = false, @@ -78,12 +86,40 @@ static void test_x11_gaps(struct x11_display *d, struct x11_surface *s) }; assert(popup_spec_valid(s, &valid_spec)); int x = 0, y = 0; - popup_calculate_position(d, s, &valid_spec, &x, &y); + struct yasl_private_vector2i actual_size; + popup_calculate_position(d, s, &valid_spec, &x, &y, &actual_size); assert(x == 30 - 5); assert(y == 40 + 60 - 10); + /* Explicit XDG-style anchor/gravity stays exact unless a constraint allows a fit. */ + struct yasl_private_popup_spec positioned = { + .positioner_explicit = true, + .anchor_edges = 2, /* bottom */ + .gravity = 2, /* below */ + .size = {100, 120}, .anchor = {100, 100, 40, 20}, + .content_offset = {5, 10}, + }; + popup_calculate_position(d, s, &positioned, &x, &y, &actual_size); + assert(x == 68 && y == 110 && actual_size.x == 100 && actual_size.y == 120); + positioned.anchor_edges = 4; /* right edge */ + positioned.gravity = 4; /* to the right */ + positioned.anchor = (struct yasl_private_rect2i){1900, 100, 20, 20}; + positioned.constraints = 4; /* flip X */ + popup_calculate_position(d, s, &positioned, &x, &y, &actual_size); + assert(x == 1800 && actual_size.x == 100); + positioned.gravity = 0; + positioned.constraints = 1; /* slide X */ + popup_calculate_position(d, s, &positioned, &x, &y, &actual_size); + assert(x + actual_size.x == 1920); + positioned.content_offset = (struct yasl_private_vector2i){0, 0}; + positioned.gravity = 4; + positioned.constraints = 16; /* resize X */ + positioned.anchor = (struct yasl_private_rect2i){1880, 100, 20, 20}; + popup_calculate_position(d, s, &positioned, &x, &y, &actual_size); + assert(x == 1920 - actual_size.x && actual_size.x == 20); + valid_spec.beside = true; - popup_calculate_position(d, s, &valid_spec, &x, &y); + popup_calculate_position(d, s, &valid_spec, &x, &y, &actual_size); assert(x == 30 + 50 - 5); assert(y == 40 - 10); @@ -94,7 +130,7 @@ static void test_x11_gaps(struct x11_display *d, struct x11_surface *s) assert(popup->parent == s); assert(popup->size.x == 100 && popup->size.y == 120); - struct yasl_popup_spec repo_spec = { + struct yasl_private_popup_spec repo_spec = { .size = {150, 180}, .anchor = {10, 20, 30, 40}, .beside = false, @@ -113,24 +149,24 @@ static void test_x11_gaps(struct x11_display *d, struct x11_surface *s) struct drag_test_recorder rec1 = {0}; struct drag_test_recorder rec2 = {0}; - struct yasl_window_cbs cbs1 = {.drag = on_test_drag}; - struct yasl_window_cbs cbs2 = {.drag = on_test_drag}; + struct yasl_private_window_cbs cbs1 = {.drag = on_test_drag}; + struct yasl_private_window_cbs cbs2 = {.drag = on_test_drag}; set_callbacks(&s->base, &cbs1, &rec1); set_callbacks(&s2.base, &cbs2, &rec2); - enum yasl_drag_end end_reason = (enum yasl_drag_end)-1; - struct yasl_drag_listener l = {.end = on_test_drag_end}; + enum yasl_private_drag_end end_reason = (enum yasl_private_drag_end)-1; + struct yasl_private_drag_listener l = {.end = on_test_drag_end}; assert(drag_start(&d->base, &s->base, NULL, &l, &end_reason)); assert(d->drag.active); - /* Motion on s (window 42) -> YASL_DRAG_OVER on s */ + /* Motion on s (window 42) -> YASL_PRIVATE_DRAG_OVER on s */ XIDeviceEvent mev = {.evtype = XI_Motion, .sourceid = 8, .event = 42, .event_x = 12.0, .event_y = 34.0}; XGenericEventCookie cookie = {.evtype = XI_Motion, .data = &mev}; xi_event(d, &cookie); assert(rec1.over_count == 1); assert(rec1.last_pos.x == 12 && rec1.last_pos.y == 34); - /* Motion on s2 (window 43) -> YASL_DRAG_LEAVE on s, YASL_DRAG_OVER on s2 */ + /* Motion on s2 (window 43) -> YASL_PRIVATE_DRAG_LEAVE on s, YASL_PRIVATE_DRAG_OVER on s2 */ mev.event = 43; mev.event_x = 56.0; mev.event_y = 78.0; @@ -139,12 +175,12 @@ static void test_x11_gaps(struct x11_display *d, struct x11_surface *s) assert(rec2.over_count == 1); assert(rec2.last_pos.x == 56 && rec2.last_pos.y == 78); - /* ButtonRelease -> YASL_DRAG_DROP on s2 and drag end */ + /* ButtonRelease -> YASL_PRIVATE_DRAG_DROP on s2 and drag end */ XIDeviceEvent rel = {.evtype = XI_ButtonRelease, .sourceid = 8, .event = 43, .detail = 1}; cookie = (XGenericEventCookie){.evtype = XI_ButtonRelease, .data = &rel}; xi_event(d, &cookie); assert(rec2.drop_count == 1); - assert(end_reason == YASL_DRAG_DROPPED); + assert(end_reason == YASL_PRIVATE_DRAG_DROPPED); assert(!d->drag.active); /* Drag cancel */ @@ -155,7 +191,7 @@ static void test_x11_gaps(struct x11_display *d, struct x11_surface *s) assert(rec1.over_count == 2); drag_cancel(&d->base); assert(rec1.leave_count == 2); - assert(end_reason == YASL_DRAG_CANCELLED); + assert(end_reason == YASL_PRIVATE_DRAG_CANCELLED); assert(!d->drag.active); /* Hierarchy change cancels drag and pushes reset */ @@ -164,18 +200,18 @@ static void test_x11_gaps(struct x11_display *d, struct x11_surface *s) XIHierarchyEvent hiev = {.evtype = XI_HierarchyChanged, .flags = XISlaveRemoved}; cookie = (XGenericEventCookie){.evtype = XI_HierarchyChanged, .data = &hiev}; xi_event(d, &cookie); - assert(end_reason == YASL_DRAG_CANCELLED); + assert(end_reason == YASL_PRIVATE_DRAG_CANCELLED); assert(!d->drag.active); - struct yasl_event reset_ev; - assert(yasl_surface_poll_event(&s->base, &reset_ev)); - assert(reset_ev.type == YASL_EVENT_INPUT_RESET); + struct yasl_private_event reset_ev; + assert(yasl_private_surface_poll_event(&s->base, &reset_ev)); + assert(reset_ev.type == YASL_PRIVATE_EVENT_INPUT_RESET); /* 4. Drag image parameter */ uint32_t pixels[16] = {0xFF00FF00}; - struct yasl_drag_image img = {.pixels = pixels, .size = {4, 4}, .hotspot = {2, 2}}; + struct yasl_private_drag_image img = {.pixels = pixels, .size = {4, 4}, .hotspot = {2, 2}}; assert(drag_start(&d->base, &s->base, &img, &l, &end_reason)); assert(d->drag.active); - assert(drag_carry(&s->base, (struct yasl_vector2i){10, 10})); + assert(drag_carry(&s->base, (struct yasl_private_vector2i){10, 10})); drag_cancel(&d->base); /* 5. XDND drop-target events and URI parsing */ @@ -246,11 +282,11 @@ static void test_x11_gaps(struct x11_display *d, struct x11_surface *s) assert(drec.leave_count == 2); assert(d->pending_drop.active); - /* Push YASL_EVENT_DROP */ - push(s, (struct yasl_event){.type = YASL_EVENT_DROP}, "file:///sample.png\r\n", 20); - struct yasl_event drop_ev; - assert(yasl_surface_poll_event(&s->base, &drop_ev)); - assert(drop_ev.type == YASL_EVENT_DROP); + /* Push YASL_PRIVATE_EVENT_DROP */ + push(s, (struct yasl_private_event){.type = YASL_PRIVATE_EVENT_DROP}, "file:///sample.png\r\n", 20); + struct yasl_private_event drop_ev; + assert(yasl_private_surface_poll_event(&s->base, &drop_ev)); + assert(drop_ev.type == YASL_PRIVATE_EVENT_DROP); assert(drop_ev.text.len == 20); assert(!strcmp(drop_ev.text.data, "file:///sample.png\r\n")); @@ -262,10 +298,18 @@ static void test_x11_gaps(struct x11_display *d, struct x11_surface *s) int main(void) { + /* External GPU surfaces retain geometry without allocating CPU targets. */ + struct x11_surface external = {0}; + external.base.presenter = YASL_PRIVATE_PRESENTER_NONE; + assert(resize(&external, (struct yasl_private_vector2i){640, 480})); + assert(external.size.x == 640 && external.size.y == 480 && !external.image && !external.pixels); + struct x11_display display = { - .base.ops = &yasl_x11_backend, .abs_pressure = 10, .abs_tilt_x = 11, .abs_tilt_y = 12, + .base.ops = &yasl_private_x11_backend, .abs_pressure = 10, .abs_tilt_x = 11, .abs_tilt_y = 12, }; - struct x11_surface surface = {.base.display = &display.base, .window = 42}; + struct x11_surface surface = {.base = {.display = &display.base, + .creation_flags = YASL_PRIVATE_SURFACE_CPU, + .presenter = YASL_PRIVATE_PRESENTER_CPU}, .window = 42}; display.surfaces = &surface; XIValuatorClassInfo pressure = {.type = XIValuatorClass, .number = 2, .label = 10, .min = 100, .max = 1100, .mode = XIModeAbsolute}; @@ -277,7 +321,7 @@ int main(void) XIDeviceInfo info = {.deviceid = 8, .name = "Tablet pen", .num_classes = 3, .classes = classes}; struct x11_pointer pointer = {0}; pointer_info(&display, &pointer, &info); - assert(pointer.device == YASL_PTR_DEV_PEN); + assert(pointer.device == YASL_PRIVATE_PTR_DEV_PEN); display.pointers = &pointer; /* Cache avoids requiring a real X server. */ unsigned char mask[1] = {0}; @@ -290,9 +334,15 @@ int main(void) .mods.effective = ShiftMask, .valuators = {sizeof(mask), mask, values}}; XGenericEventCookie cookie = {.evtype = XI_ButtonPress, .data = &sample}; xi_event(&display, &cookie); - struct yasl_event ev = next(&surface); - assert(ev.type == YASL_EVENT_POINTER_DOWN && ev.pointer.button == YASL_BUTTON_PRIMARY && ev.pointer.device == YASL_PTR_DEV_PEN); - assert(ev.pointer.pos.x == 201 && ev.pointer.pos.y == 175 && ev.pointer.mods == YASL_MOD_SHIFT); + struct yasl_private_event ev = next(&surface); + assert(ev.type == YASL_PRIVATE_EVENT_PEN && ev.pen.device_id == 8 && !ev.pen.tool_id); + assert(ev.pen.tool == 1 && ev.pen.action == YASL_PRIVATE_PEN_DOWN && ev.pen.in_contact); + assert((ev.pen.axes_valid & (YASL_PRIVATE_PEN_PRESSURE | YASL_PRIVATE_PEN_TILT)) == + (YASL_PRIVATE_PEN_PRESSURE | YASL_PRIVATE_PEN_TILT)); + assert(ev.pen.axes_changed == (YASL_PRIVATE_PEN_PRESSURE | YASL_PRIVATE_PEN_TILT)); + ev = next(&surface); + assert(ev.type == YASL_PRIVATE_EVENT_POINTER_DOWN && ev.pointer.button == YASL_PRIVATE_BUTTON_PRIMARY && ev.pointer.device == YASL_PRIVATE_PTR_DEV_PEN); + assert(ev.pointer.pos.x == 201 && ev.pointer.pos.y == 175 && ev.pointer.mods == YASL_PRIVATE_MOD_SHIFT); assert(ev.pointer.pen.pressure == 32768 && ev.pointer.pen.tilt_x == -35 && ev.pointer.pen.tilt_y == 42); /* XI2 sends only changed axes, with values packed in mask order. */ @@ -302,36 +352,48 @@ int main(void) sample.evtype = cookie.evtype = XI_Motion; xi_event(&display, &cookie); ev = next(&surface); - assert(ev.type == YASL_EVENT_POINTER_MOTION && ev.pointer.pen.pressure == 65535); + assert(ev.type == YASL_PRIVATE_EVENT_PEN && ev.pen.action == YASL_PRIVATE_PEN_MOVE && + ev.pen.axes_valid == (YASL_PRIVATE_PEN_PRESSURE | YASL_PRIVATE_PEN_TILT) && + ev.pen.axes_changed == YASL_PRIVATE_PEN_PRESSURE && ev.pen.pressure == 1.0); + ev = next(&surface); + assert(ev.type == YASL_PRIVATE_EVENT_POINTER_MOTION && ev.pointer.pen.pressure == 65535); assert(ev.pointer.pen.tilt_x == -35 && ev.pointer.pen.tilt_y == 42); values[0] = 5000; xi_event(&display, &cookie); + assert(next(&surface).type == YASL_PRIVATE_EVENT_PEN); assert(next(&surface).pointer.pen.pressure == 65535); values[0] = -50; xi_event(&display, &cookie); + assert(next(&surface).type == YASL_PRIVATE_EVENT_PEN); assert(next(&surface).pointer.pen.pressure == 0); info.name = "Tablet ERASER"; pointer_info(&display, &pointer, &info); - assert(pointer.device == YASL_PTR_DEV_ERASER); + assert(pointer.device == YASL_PRIVATE_PTR_DEV_ERASER); values[0] = 900; sample.evtype = cookie.evtype = XI_ButtonPress; xi_event(&display, &cookie); ev = next(&surface); - assert(ev.pointer.device == YASL_PTR_DEV_ERASER && ev.pointer.pen.pressure > 0); + assert(ev.type == YASL_PRIVATE_EVENT_PEN && ev.pen.tool == 2 && ev.pen.action == YASL_PRIVATE_PEN_DOWN); + ev = next(&surface); + assert(ev.pointer.device == YASL_PRIVATE_PTR_DEV_ERASER && ev.pointer.pen.pressure > 0); /* Release must clear pressure even when the driver omits that valuator. */ sample.valuators.mask_len = 0; sample.evtype = cookie.evtype = XI_ButtonRelease; xi_event(&display, &cookie); ev = next(&surface); - assert(ev.type == YASL_EVENT_POINTER_UP && ev.pointer.button == YASL_BUTTON_PRIMARY && ev.pointer.pen.pressure == 0); - assert(ev.pointer.device == YASL_PTR_DEV_ERASER); + assert(ev.type == YASL_PRIVATE_EVENT_PEN && ev.pen.action == YASL_PRIVATE_PEN_UP && !ev.pen.in_contact); + ev = next(&surface); + assert(ev.type == YASL_PRIVATE_EVENT_POINTER_UP && ev.pointer.button == YASL_PRIVATE_BUTTON_PRIMARY && ev.pointer.pen.pressure == 0); + assert(ev.pointer.device == YASL_PRIVATE_PTR_DEV_ERASER); XIEnterEvent crossing = {.sourceid = 8, .event = 42, .event_x = 200, .event_y = 175}; cookie = (XGenericEventCookie){.evtype = XI_Leave, .data = &crossing}; xi_event(&display, &cookie); ev = next(&surface); - assert(ev.type == YASL_EVENT_POINTER_LEAVE && ev.pointer.device == YASL_PTR_DEV_ERASER && !ev.pointer.pen.pressure); + assert(ev.type == YASL_PRIVATE_EVENT_PEN && ev.pen.action == YASL_PRIVATE_PEN_LEAVE); + ev = next(&surface); + assert(ev.type == YASL_PRIVATE_EVENT_POINTER_LEAVE && ev.pointer.device == YASL_PRIVATE_PTR_DEV_ERASER && !ev.pointer.pen.pressure); /* No tablet axes must produce an ordinary, pressure-free mouse. */ info.num_classes = 0; @@ -340,24 +402,48 @@ int main(void) sample.detail = 3; xi_pointer_event(&surface, &sample); ev = next(&surface); - assert(ev.pointer.device == YASL_PTR_DEV_MOUSE && ev.pointer.button == YASL_BUTTON_SECONDARY && ev.pointer.pen.pressure == 0); + assert(ev.pointer.device == YASL_PRIVATE_PTR_DEV_MOUSE && ev.pointer.button == YASL_PRIVATE_BUTTON_SECONDARY && ev.pointer.pen.pressure == 0); for (int button = 4; button <= 7; button++) { sample.detail = button; sample.evtype = XI_ButtonPress; xi_pointer_event(&surface, &sample); ev = next(&surface); - assert(ev.type == YASL_EVENT_POINTER_SCROLL); + assert(ev.type == YASL_PRIVATE_EVENT_POINTER_SCROLL); assert(ev.pointer.scroll.x == (button == 6 ? -1 : button == 7 ? 1 : 0)); assert(ev.pointer.scroll.y == (button == 4 ? -1 : button == 5 ? 1 : 0)); + assert(ev.pointer.scroll_valid == 1u && ev.pointer.scroll_source == 1u && ev.pointer.scroll_phase == 2u); sample.evtype = XI_ButtonRelease; xi_pointer_event(&surface, &sample); - struct yasl_event unused; - assert(!yasl_surface_poll_event(&surface.base, &unused)); + struct yasl_private_event unused; + assert(!input_queue_pop(&surface.input, &unused)); } + /* XI2 smooth-scroll valuators preserve fractional line data and source. */ + XIValuatorClassInfo scroll_valuator = {.type = XIValuatorClass, .number = 9, + .value = 0, .mode = XIModeRelative}; + XIScrollClassInfo scroll_class = {.type = XIScrollClass, .number = 9, + .scroll_type = XIScrollTypeVertical, .increment = 2.0}; + XIAnyClassInfo *scroll_classes[] = {(void *)&scroll_valuator, (void *)&scroll_class}; + info.name = "Test touchpad"; + info.num_classes = 2; + info.classes = scroll_classes; + struct x11_pointer touchpad = {0}; + pointer_info(&display, &touchpad, &info); + display.pointers = &touchpad; + unsigned char scroll_mask[2] = {0}; + XISetMask(scroll_mask, 9); + double scroll_value[] = {-1.0}; + sample.evtype = XI_Motion; + sample.valuators = (XIValuatorState){sizeof(scroll_mask), scroll_mask, scroll_value}; + xi_pointer_event(&surface, &sample); + assert(next(&surface).type == YASL_PRIVATE_EVENT_POINTER_MOTION); + ev = next(&surface); + assert(ev.type == YASL_PRIVATE_EVENT_POINTER_SCROLL && ev.pointer.scroll_valid == 1u && + ev.pointer.scroll_source == 2u && ev.pointer.scroll.y == -0.5); + input_queue_clear(&surface.input); assert(pointer_button(2) == 1 && pointer_button(8) == 3); - pointer.pressure = (struct tablet_axis){2, 1, 1, 50}; + pointer.pressure = (struct tablet_axis){2, 1, 1, 50, true}; assert(pressure_value(&pointer.pressure) == 0); - pointer.tilt_x = (struct tablet_axis){4, -90, 90, -200}; + pointer.tilt_x = (struct tablet_axis){4, -90, 90, -200, true}; assert(tilt_value(&pointer.tilt_x) == -90); pointer.tilt_x.value = 200; assert(tilt_value(&pointer.tilt_x) == 90); diff --git a/tests/x11/test_tablet_native.c b/tests/x11/test_tablet_native.c index 706a5cc..828082c 100644 --- a/tests/x11/test_tablet_native.c +++ b/tests/x11/test_tablet_native.c @@ -2,7 +2,7 @@ #define main tablet_example_main #include "../../examples/tablet.c" #undef main -#include <yasl/native.h> +#include <common/private_native.h> #include <X11/Xatom.h> #include <X11/Xlib.h> #include <X11/Xutil.h> @@ -55,24 +55,24 @@ static int connect_tool(const char *path) return fd; } -static void native_draw(struct yasl_surface *surface, struct yasl_frame *frame, void *ud) +static void native_draw(struct yasl_surface *surface, struct yasl_private_frame *frame, void *ud) { (void)surface; draw(ud, surface, frame); } -static void native_configure(struct yasl_surface *surface, struct yasl_geometry geometry, void *ud) +static void native_configure(struct yasl_surface *surface, struct yasl_private_geometry geometry, void *ud) { - input(ud, &(struct yasl_event){.surface = surface, .type = YASL_EVENT_WINDOW_RESIZE, + input(ud, &(struct yasl_private_event){.surface = surface, .type = YASL_PRIVATE_EVENT_WINDOW_RESIZE, .resize = {.geometry = geometry}}); } -static void native_input(struct app *app, const struct yasl_event *event) +static void native_input(struct app *app, const struct yasl_private_event *event) { input(app, event); } -static void pump(int fd, struct yasl_display *display, struct yasl_surface *surface, struct app *app) +static void pump(int fd, struct yasl_private_display *display, struct yasl_surface *surface, struct app *app) { xf86ITEventWaitForSync sync = {{sizeof(sync), XF86IT_EVENT_WAIT_FOR_SYNC}}; send_all(fd, &sync, sizeof(sync)); @@ -81,14 +81,14 @@ static void pump(int fd, struct yasl_display *display, struct yasl_surface *surf assert(response.type == XF86IT_RESPONSE_SYNC_FINISHED && response.length == sizeof(response)); /* The driver acknowledgment guarantees input processing has finished. * Round-trip on YASL's X connection before draining its event queue. */ - XSync(yasl_display_get_native_handle(display), False); - assert(yasl_display_dispatch(display, 0) == 0); - struct yasl_event event; - while (yasl_surface_poll_event(surface, &event)) { + XSync(yasl_private_display_get_native_handle(display), False); + assert(yasl_private_display_dispatch(display, 0) == 0); + struct yasl_private_event event; + while (yasl_private_surface_poll_event(surface, &event)) { native_input(app, &event); - yasl_surface_schedule_redraw(surface); + yasl_private_surface_schedule_redraw(surface); } - yasl_display_flush(display); + yasl_private_display_flush(display); assert(!app->failed); } @@ -116,23 +116,23 @@ static void set_eraser_property(Display *display) int main(int argc, char **argv) { assert(argc == 3); /* pen socket, eraser socket */ - struct app app = {.tablet_supported = true, .backend = YASL_BACKEND_X11}; - struct yasl_display_spec ds = {.backend = YASL_BACKEND_X11}; - struct yasl_display *display = yasl_display_open(NULL, &ds); - assert(display && (yasl_display_caps(display) & YASL_CAP_TABLET)); - struct yasl_window_spec ss = {.title = "YASL native pressure test", .size = {500, 400}}; - struct yasl_surface *surface = yasl_surface_create_toplevel(display, &ss); + struct app app = {.tablet_supported = true, .backend = YASL_PRIVATE_BACKEND_X11}; + struct yasl_private_display_spec ds = {.backend = YASL_PRIVATE_BACKEND_X11}; + struct yasl_private_display *display = yasl_private_display_open(NULL, &ds); + assert(display && (yasl_private_display_caps(display) & YASL_PRIVATE_CAP_TABLET)); + struct yasl_private_window_spec ss = {.title = "YASL native pressure test", .size = {500, 400}}; + struct yasl_surface *surface = yasl_private_surface_create_toplevel(display, &ss); assert(surface); - struct yasl_window_cbs cbs = {.draw = native_draw, .configure = native_configure}; - yasl_surface_set_callbacks(surface, &cbs, &app); - yasl_surface_schedule_redraw(surface); - Display *x = yasl_display_get_native_handle(display); - Window window = (Window)(uintptr_t)yasl_surface_get_native_handle(surface); + struct yasl_private_window_cbs cbs = {.draw = native_draw, .configure = native_configure}; + yasl_private_surface_set_callbacks(surface, &cbs, &app); + yasl_private_surface_schedule_redraw(surface); + Display *x = yasl_private_display_get_native_handle(display); + Window window = (Window)(uintptr_t)yasl_private_surface_get_native_handle(surface); XMoveWindow(x, window, 0, 0); XSetInputFocus(x, window, RevertToParent, CurrentTime); XSync(x, False); - assert(yasl_display_dispatch(display, 0) == 0); - yasl_display_flush(display); + assert(yasl_private_display_dispatch(display, 0) == 0); + yasl_private_display_flush(display); set_eraser_property(x); int pen_fd = connect_tool(argv[1]), eraser_fd = connect_tool(argv[2]); xf86ITEventMotion motion = {.header = {sizeof(motion), XF86IT_EVENT_MOTION}, .is_absolute = 1}; @@ -144,7 +144,7 @@ int main(int argc, char **argv) send_all(pen_fd, &proximity, sizeof(proximity)); send_all(pen_fd, &motion, sizeof(motion)); pump(pen_fd, display, surface, &app); - assert(app.visible && !app.down && app.pointer.device == YASL_PTR_DEV_PEN); + assert(app.visible && !app.down && app.pointer.device == YASL_PRIVATE_PTR_DEV_PEN); assert(app.pointer.pos.x == 150 && app.pointer.pos.y == 200); assert(app.canvas[(size_t)200 * app.geometry.size.x + 150] == PAPER); xf86ITEventButton button = {.header = {sizeof(button), XF86IT_EVENT_BUTTON}, @@ -177,7 +177,7 @@ int main(int argc, char **argv) button.valuators.valuators[4] = 1000; send_all(eraser_fd, &button, sizeof(button)); pump(eraser_fd, display, surface, &app); - assert(app.down && app.pointer.device == YASL_PTR_DEV_ERASER && app.pointer.pen.pressure == 65535); + assert(app.down && app.pointer.device == YASL_PRIVATE_PTR_DEV_ERASER && app.pointer.pen.pressure == 65535); assert(app.canvas[(size_t)200 * app.geometry.size.x + 150] == PAPER && app.canvas[(size_t)200 * app.geometry.size.x + 170] == PAPER); button.is_press = 0; @@ -187,8 +187,8 @@ int main(int argc, char **argv) close(pen_fd); close(eraser_fd); free(app.canvas); - yasl_surface_destroy(surface); - yasl_display_close(display); + yasl_private_surface_destroy(surface); + yasl_private_display_close(display); puts("Native Xorg pen pressure, stationary pressure, release, and eraser drawing passed."); return 0; } |
