summaryrefslogtreecommitdiff
path: root/tests/common/test_surface_integration.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/common/test_surface_integration.c')
-rw-r--r--tests/common/test_surface_integration.c316
1 files changed, 156 insertions, 160 deletions
diff --git a/tests/common/test_surface_integration.c b/tests/common/test_surface_integration.c
index 1f18f23..072a307 100644
--- a/tests/common/test_surface_integration.c
+++ b/tests/common/test_surface_integration.c
@@ -1,17 +1,5 @@
#define _POSIX_C_SOURCE 200809L
#include <yasl/yasl.h>
-#include <yasl/cpu.h>
-#include <yasl/gl.h>
-#include <yasl/metal.h>
-#if YASL_HAS_WAYLAND
-#include <yasl/native/wayland.h>
-#endif
-#if YASL_HAS_X11
-#include <yasl/native/x11.h>
-#endif
-#if YASL_HAS_COCOA
-#include <yasl/native/cocoa.h>
-#endif
#include "common/backend.h"
#include <assert.h>
#include <pthread.h>
@@ -40,18 +28,20 @@ static void *wake_thread(void *unused)
static void *wrong_thread(void *data)
{
assert(yasl_surface_set_title(data, "wrong") == -EPERM);
- struct yasl_cpu_buffer buffer;
- assert(yasl_cpu_acquire(data, &buffer) == -EPERM && !buffer.pixels);
-#if YASL_HAS_WAYLAND
- struct yasl_wayland_handles native;
- assert(yasl_wayland_get_native(data, &native) == -EPERM && !native.display && !native.surface);
-#endif
+ int w = 1, h = 1;
+ assert(!yasl_cpu_pixels(data, &w, &h) && errno == EPERM && !w && !h);
+ struct yasl_native native;
+ assert(yasl_surface_get_native(data, &native) == -EPERM && !native.wl_display && !native.x11_display);
return NULL;
}
+static void push(yasl_surface *s, struct yasl_private_event event)
+{
+ event.surface = s;
+ assert(yasl_private_events_push(s->display, s, &event));
+}
static int refreshes;
-static void refresh(yasl_surface *s, void *ud)
+static void refresh(yasl_surface *s)
{
- (void)ud;
refreshes++;
yasl_event e;
assert(yasl_wait_event(&e, 0) == -EBUSY);
@@ -59,7 +49,10 @@ static void refresh(yasl_surface *s, void *ud)
assert(yasl_surface_destroy(s) == -EBUSY);
struct yasl_surface_options options = {.width = 32, .height = 32};
assert(!yasl_surface_create(&options) && errno == EBUSY);
- assert(!yasl_gl_surface_create(&options, NULL) && errno == EBUSY);
+ options.type = YASL_SURFACE_GL;
+ assert(!yasl_surface_create(&options) && errno == EBUSY);
+ int w, h;
+ assert(yasl_cpu_pixels(s, &w, &h) && yasl_cpu_present(s) == 0);
}
int main(int argc, char **argv)
{
@@ -67,53 +60,32 @@ int main(int argc, char **argv)
enum yasl_backend backend = !strcmp(argv[1], "wayland") ? YASL_BACKEND_WAYLAND
: !strcmp(argv[1], "x11") ? YASL_BACKEND_X11
: YASL_BACKEND_COCOA;
- assert(yasl_init(
- &(struct yasl_options){.backend = backend, .app_id = "org.yasl.surface-test"}) == 0);
- yasl_surface *s = yasl_surface_create(&(struct yasl_surface_options){
- .title = "CPU contract", .width = 96, .height = 80, .type = YASL_SURFACE_CPU, .flags = 0});
+ assert(yasl_init(backend, "org.yasl.surface-test") == 0);
+ assert(yasl_init(backend, NULL) == -EALREADY);
+ assert(yasl_get_backend() == backend);
+ unsigned features = yasl_get_features();
+ yasl_surface *s = yasl_surface_create(
+ &(struct yasl_surface_options){.title = "CPU contract", .width = 96, .height = 80});
if (!s) {
- const char *why;
- why = strerror(errno);
- fprintf(stderr, "surface: %s native=%d\n", why, errno);
+ fprintf(stderr, "surface: %s\n", strerror(errno));
return 1;
}
- assert(yasl_surface_get_backend(s) == backend);
assert(yasl_surface_set_userdata(s, &backend) == 0);
assert(yasl_surface_get_userdata(s) == &backend);
-#if YASL_HAS_WAYLAND
- struct yasl_wayland_handles wl;
- int wl_result = yasl_wayland_get_native(s, &wl);
- assert(wl_result == (backend == YASL_BACKEND_WAYLAND ? 0 : -ENOTSUP));
- assert(backend == YASL_BACKEND_WAYLAND ? wl.display && wl.surface : !wl.display && !wl.surface);
- assert(yasl_wayland_get_native(s, NULL) == -EINVAL);
-#endif
-#if YASL_HAS_X11
- struct yasl_x11_handles x;
- int x_result = yasl_x11_get_native(s, &x);
- assert(x_result == (backend == YASL_BACKEND_X11 ? 0 : -ENOTSUP));
- assert(backend == YASL_BACKEND_X11 ? x.display && x.window : !x.display && !x.window);
-#endif
-#if YASL_HAS_COCOA
- struct yasl_cocoa_handles cocoa;
- assert(yasl_cocoa_get_native(s, &cocoa) == 0 && cocoa.application && cocoa.window &&
- cocoa.view);
-#endif
- CAMetalLayer *layer = NULL;
- assert(yasl_metal_get_layer(s, &layer) == -EBUSY && !layer);
- assert(yasl_surface_set_ime_caret(s, 1e300, 0, 1, 1) == -EOVERFLOW);
+ struct yasl_native native;
+ assert(yasl_surface_get_native(s, &native) == 0);
+ assert(backend != YASL_BACKEND_WAYLAND || (native.wl_display && native.wl_surface));
+ assert(backend != YASL_BACKEND_X11 || (native.x11_display && native.x11_window));
+ assert(backend != YASL_BACKEND_COCOA || (native.ns_window && native.ns_view));
+ assert(yasl_surface_get_native(s, NULL) == -EINVAL);
+ assert(!yasl_metal_get_layer(s) && errno == EBUSY);
if (backend == YASL_BACKEND_COCOA) {
- assert(!(yasl_surface_get_features(s) & YASL_CAP_OPENGL));
- assert(!yasl_gl_surface_create(&(struct yasl_surface_options){.title = "unsupported GL",
- .width = 64,
- .height = 64,
- .type = YASL_SURFACE_NATIVE,
- .flags = 0},
- NULL));
- assert(errno == ENOTSUP);
- assert((yasl_gl_make_current(NULL) < 0));
- assert(errno == ENOTSUP);
- assert(!yasl_gl_get_proc_address("glClear"));
+ assert(!(features & YASL_FEATURE_OPENGL));
+ assert(!yasl_surface_create(&(struct yasl_surface_options){
+ .title = "unsupported GL", .width = 64, .height = 64, .type = YASL_SURFACE_GL}));
assert(errno == ENOTSUP);
+ assert(yasl_gl_make_current(NULL) == 0);
+ assert(!yasl_gl_get_proc_address("glClear") && errno == ENOTSUP);
}
/* The first events report the window size, then ask for a frame. */
yasl_event e;
@@ -132,131 +104,155 @@ int main(int argc, char **argv)
}
}
assert(e.type == YASL_EVENT_REFRESH);
+ struct yasl_surface_info info = yasl_surface_get_info(s);
+ assert(info.pixel_width == fw && info.pixel_height == fh && info.scale > 0);
+
+ /* CPU pixels persist between frames and are the window's own buffer. */
int w, h;
- yasl_surface_get_framebuffer_size(s, &w, &h);
- assert(w == fw && h == fh);
- assert((yasl_init(&(struct yasl_options){.backend = backend}) < 0));
- assert(errno == EALREADY);
- struct yasl_cpu_buffer buffer, other;
- assert(yasl_cpu_acquire(s, &buffer) == 0);
- uint32_t *pixels = buffer.pixels;
- assert(buffer.width == w && buffer.height == h && buffer.stride_bytes == (size_t)w * 4);
+ uint32_t *pixels = yasl_cpu_pixels(s, &w, &h);
+ assert(pixels && w == fw && h == fh);
assert(pixels[0] == 0 && pixels[(size_t)w * h - 1] == 0);
- assert(yasl_cpu_acquire(s, &other) == -EBUSY && !other.pixels);
for (size_t i = 0; i < (size_t)w * h; i++)
pixels[i] = 0xff102030u;
pixels[(size_t)3 * w + 2] = 0xffaabbccu;
- other = buffer;
- other.stride_bytes++;
- assert(yasl_cpu_present(s, &other) == -EINVAL);
- assert(yasl_cpu_present(s, &buffer) == 0);
- assert(yasl_cpu_present(s, &buffer) == -ESTALE);
- assert(yasl_cpu_acquire(s, &buffer) == 0);
- assert(buffer.pixels[0] == 0xff102030u && buffer.pixels[(size_t)3 * w + 2] == 0xffaabbccu);
- buffer.pixels[0] = 0xffffffffu;
- assert(s->committed_pixels[0] == 0xff102030u);
- assert(yasl_cpu_discard(s, &buffer) == 0);
- assert(yasl_cpu_discard(s, &buffer) == -ESTALE);
- assert(yasl_cpu_acquire(s, &buffer) == 0 && buffer.pixels[0] == 0xff102030u);
+ assert(yasl_cpu_present(s) == 0);
+ drain();
+ pixels = yasl_cpu_pixels(s, &w, &h);
+ assert(pixels[0] == 0xff102030u && pixels[(size_t)3 * w + 2] == 0xffaabbccu);
+
+ /* Waiting ends only on an event, the timeout or yasl_wake, never early. */
+ drain();
+ uint64_t start = yasl_time_ns();
+ int n = yasl_wait_event(&e, 200);
+ assert(n == 1 || yasl_time_ns() - start >= 190000000ull);
drain();
- assert(yasl_cpu_present(s, &buffer) == -ESTALE);
- yasl_surface *second = yasl_surface_create(&(struct yasl_surface_options){
- .width = 32, .height = 32, .type = YASL_SURFACE_CPU, .userdata = &backend});
- assert(second && yasl_surface_get_userdata(second) == &backend);
- assert(yasl_cpu_acquire(s, &buffer) == 0);
- assert(yasl_cpu_acquire(second, &other) == 0);
- assert(yasl_cpu_present(second, &buffer) == -ESTALE);
- assert(yasl_cpu_discard(second, &other) == 0);
- assert(yasl_surface_destroy(second) == 0);
- assert(yasl_cpu_discard(s, &buffer) == 0);
pthread_t thread;
- assert(!pthread_create(&thread, NULL, wrong_thread, s));
- pthread_join(thread, NULL);
assert(!pthread_create(&thread, NULL, wake_thread, NULL));
- int n = yasl_wait_event(&e, 500);
- assert(n >= 0);
+ start = yasl_time_ns();
+ n = yasl_wait_event(&e, 5000);
pthread_join(thread, NULL);
- bool ime = (yasl_surface_set_text_input(s, true, YASL_TEXT_NORMAL) == 0);
- if (!ime)
- assert(errno == ENOTSUP);
- bool snapshot = (yasl_surface_set_surrounding_text(s, "a\xc3\xa9z", 4, 1, 3, 7) == 0);
- if (ime)
- assert(snapshot);
- else
- assert(!snapshot && errno == ENOTSUP);
- assert((yasl_surface_set_surrounding_text(s, "a\xc3\xa9z", 4, 2, 3, 8) < 0));
- assert((yasl_surface_set_surrounding_text(s, "\xc0\xaf", 2, 0, 2, 8) < 0));
+ assert(n == 1 || (n == 0 && yasl_time_ns() - start < 4000000000ull));
+ assert(!pthread_create(&thread, NULL, wrong_thread, s));
+ pthread_join(thread, NULL);
+
+ yasl_surface *second = yasl_surface_create(
+ &(struct yasl_surface_options){.width = 32, .height = 32, .userdata = &backend});
+ assert(second && yasl_surface_get_userdata(second) == &backend);
+ assert(yasl_surface_destroy(second) == 0);
+
+ /* Text input */
+ int ime = yasl_surface_set_text_input(s, &(struct yasl_text_input){
+ .text = "a\xc3\xa9z", .length = 4, .selection_begin = 1, .selection_end = 3,
+ .revision = 7, .caret_x = 1, .caret_y = 2, .caret_width = 1, .caret_height = 10});
+ assert(ime == 0 || ime == -ENOTSUP);
+ assert(yasl_surface_set_text_input(s, &(struct yasl_text_input){
+ .text = "a\xc3\xa9z", .length = 4, .selection_begin = 2, .selection_end = 3}) == -EILSEQ);
+ assert(yasl_surface_set_text_input(s, &(struct yasl_text_input){
+ .text = "\xc0\xaf", .length = 2}) == -EILSEQ);
+ assert(yasl_surface_set_text_input(s, &(struct yasl_text_input){
+ .text = "ab", .length = 2, .selection_end = 3}) == -EINVAL);
+ assert(yasl_surface_set_text_input(s, &(struct yasl_text_input){.caret_x = 1e300}) == -EOVERFLOW);
+ assert(yasl_surface_set_text_input(s, NULL) == 0 || ime == -ENOTSUP);
+
+ /* Arguments are checked before the backend sees them. */
+ assert(yasl_surface_begin_move_resize(s, YASL_EDGE_TOP | YASL_EDGE_BOTTOM) == -EINVAL);
+ assert(yasl_surface_begin_move_resize(s, 16) == -EINVAL);
+ assert(yasl_surface_request(s, (enum yasl_request)9) == -EINVAL);
+ assert(yasl_surface_request_size(s, 0, 10) == -EINVAL);
+ assert(yasl_surface_set_cursor(s, (enum yasl_cursor)99) == -EINVAL);
+ int locked = yasl_surface_set_cursor(s, YASL_CURSOR_LOCKED);
+ assert(locked == ((features & YASL_FEATURE_LOCKED_CURSOR) ? 0 : -ENOTSUP));
+ assert(yasl_surface_set_cursor(s, YASL_CURSOR_ARROW) == 0);
+ assert(yasl_drag_start(s, &(struct yasl_drag_image){.pixel_width = 4, .pixel_height = 4}) == -EINVAL);
+ uint32_t icon[4] = {0};
+ assert(yasl_drag_start(s, &(struct yasl_drag_image){
+ .pixels = icon, .pixel_width = 2, .pixel_height = 2, .hotspot_x = 2}) == -EINVAL);
+ assert(!yasl_popup_create(s, &(struct yasl_popup_options){.width = 10, .height = 10,
+ .anchor = YASL_EDGE_LEFT | YASL_EDGE_RIGHT}) &&
+ errno == EINVAL);
+ assert(yasl_clipboard_set((enum yasl_selection)5, "x") == -EINVAL);
+ assert(yasl_clipboard_set(YASL_CLIPBOARD, NULL) == -EINVAL);
+ assert(yasl_clipboard_set(YASL_CLIPBOARD, "\xff") == -EILSEQ);
+ assert(yasl_clipboard_set(YASL_PRIMARY, "x") ==
+ ((features & YASL_FEATURE_PRIMARY_SELECTION) ? 0 : -ENOTSUP));
drain();
- struct yasl_private_event pen = {.type = YASL_PRIVATE_EVENT_PEN,
- .surface = s,
- .pen = {.device_id = 10,
- .tool_id = 20,
- .x = 12.5,
- .y = 9.25,
- .pressure = 0.3,
- .axes_valid = YASL_PRIVATE_PEN_PRESSURE,
- .action = YASL_PRIVATE_PEN_DOWN,
- .in_contact = true}};
- assert(yasl_private_events_push(s->display, s, &pen));
- assert(yasl_wait_event(&e, 0) == 1 && e.type == YASL_EVENT_PEN && e.pen.device_id == 10 &&
- e.pen.pressure == 0.3 && e.pen.in_contact);
- struct yasl_private_event text = {
- .type = YASL_PRIVATE_EVENT_TEXT, .surface = s, .text = {.data = "owned", .len = 5}};
- assert(yasl_private_events_push(s->display, s, &text));
+
+ /* Event conversion: positions are logical, text is owned until the next wait. */
+ uint32_t real_scale = s->scale_120;
+ s->scale_120 = 240;
+ push(s, (struct yasl_private_event){
+ .type = YASL_PRIVATE_EVENT_PEN,
+ .pen = {.device_id = 10, .x = 25, .y = 18.5, .pressure = 0.3,
+ .axes_valid = YASL_PRIVATE_PEN_PRESSURE, .action = YASL_PRIVATE_PEN_DOWN,
+ .in_contact = true}});
+ assert(yasl_wait_event(&e, 0) == 1 && e.type == YASL_EVENT_PEN && e.action == YASL_PEN_DOWN);
+ assert(e.x == 12.5 && e.y == 9.25 && e.pen.device_id == 10 && e.pen.pressure == 0.3 &&
+ (e.pen.axes & YASL_PEN_PRESSURE) && e.pen.in_contact);
+ push(s, (struct yasl_private_event){
+ .type = YASL_PRIVATE_EVENT_POINTER_DOWN,
+ .pointer = {.pos = {20, 10}, .button = YASL_PRIVATE_BUTTON_SECONDARY,
+ .buttons = 4, .mods = YASL_PRIVATE_MOD_CTRL}});
+ assert(yasl_wait_event(&e, 0) == 1 && e.type == YASL_EVENT_POINTER &&
+ e.action == YASL_POINTER_DOWN && e.x == 10 && e.y == 5 && e.mods == YASL_MOD_CTRL &&
+ e.pointer.button == YASL_BUTTON_SECONDARY && e.pointer.buttons == 4);
+ s->scale_120 = real_scale;
+ push(s, (struct yasl_private_event){.type = YASL_PRIVATE_EVENT_TEXT, .text = {"owned", 5}});
assert(yasl_wait_event(&e, 0) == 1 && e.type == YASL_EVENT_TEXT);
- assert(e.text.length == 5 && !strcmp(e.text.data, "owned"));
- /* Unchanged focus folds into no event; a change reports the activated state. */
- unsigned active = yasl_surface_get_state(s) & YASL_STATE_ACTIVATED;
- struct yasl_private_event focus = {
- .type = YASL_PRIVATE_EVENT_FOCUS, .surface = s, .focus = {.focused = !active}};
- assert(yasl_private_events_push(s->display, s, &focus));
- assert(yasl_wait_event(&e, 0) == 1 && e.type == YASL_EVENT_WINDOW);
- assert((e.window.state & YASL_STATE_ACTIVATED) == (active ? 0u : YASL_STATE_ACTIVATED) &&
- e.window.pixel_width == w);
- assert(yasl_private_events_push(s->display, s, &focus));
+ assert(e.length == 5 && !strcmp(e.text, "owned"));
+ push(s, (struct yasl_private_event){
+ .type = YASL_PRIVATE_EVENT_PASTE,
+ .paste = {.data = "", .request_id = 1, .status = YASL_PRIVATE_TRANSFER_UNAVAILABLE}});
+ assert(yasl_wait_event(&e, 0) == 1 && e.type == YASL_EVENT_CLIPBOARD &&
+ e.action == YASL_TRANSFER_UNAVAILABLE && e.length == 0);
+ /* Losing focus releases held input; activation itself comes from the window state. */
+ push(s, (struct yasl_private_event){.type = YASL_PRIVATE_EVENT_FOCUS, .focus = {.focused = false}});
+ assert(yasl_wait_event(&e, 0) == 1 && e.type == YASL_EVENT_INPUT_RESET);
+ push(s, (struct yasl_private_event){.type = YASL_PRIVATE_EVENT_FOCUS, .focus = {.focused = true}});
assert(yasl_wait_event(&e, 0) == 0 && e.type == YASL_EVENT_NONE);
- struct yasl_private_event hover = {.type = YASL_PRIVATE_EVENT_DROP_HOVER,
- .surface = s,
- .drop = {YASL_PRIVATE_DROP_LEAVE, {0, 0}}};
- assert(yasl_private_events_push(s->display, s, &hover));
- assert(yasl_wait_event(&e, 0) == 1 && e.type == YASL_EVENT_DROP &&
- e.drop.action == YASL_DROP_LEAVE);
+ push(s, (struct yasl_private_event){.type = YASL_PRIVATE_EVENT_DROP_HOVER,
+ .drop = {YASL_PRIVATE_DROP_LEAVE, {0, 0}}});
+ assert(yasl_wait_event(&e, 0) == 1 && e.type == YASL_EVENT_DROP && e.action == YASL_DROP_LEAVE);
+
+ /* A resize keeps the overlap of the pixels and zeroes the rest. */
assert(yasl_surface_request_size(s, 112, 96) == 0);
uint64_t resize_deadline = yasl_time_ns() + 3000000000ull;
- int logical_w = 0, logical_h = 0;
do {
assert(yasl_wait_event(&e, 20) >= 0);
- yasl_surface_get_size(s, &logical_w, &logical_h);
- } while ((logical_w != 112 || logical_h != 96) && yasl_time_ns() < resize_deadline);
- assert(logical_w == 112 && logical_h == 96);
- assert(yasl_cpu_acquire(s, &buffer) == 0);
- assert(buffer.pixels[0] == 0xff102030u);
- assert(buffer.pixels[(size_t)3 * buffer.width + 2] == 0xffaabbccu);
- assert(buffer.pixels[(size_t)buffer.width * buffer.height - 1] == 0);
- assert(yasl_cpu_present(s, &buffer) == 0);
- yasl_surface_set_refresh_callback(s, refresh, NULL);
- assert(yasl_cpu_acquire(s, &buffer) == 0);
- assert(yasl_cpu_present(s, &buffer) == 0);
+ info = yasl_surface_get_info(s);
+ } while ((info.width != 112 || info.height != 96) && yasl_time_ns() < resize_deadline);
+ assert(info.width == 112 && info.height == 96);
+ pixels = yasl_cpu_pixels(s, &w, &h);
+ assert(pixels && w == info.pixel_width && h == info.pixel_height);
+ assert(pixels[0] == 0xff102030u && pixels[(size_t)3 * w + 2] == 0xffaabbccu);
+ assert(pixels[(size_t)w * h - 1] == 0);
+ assert(yasl_cpu_present(s) == 0);
+
+ /* The refresh callback is reserved for modal loops; ordinary waits deliver REFRESH. */
+ s->refresh = refresh;
+ for (int i = 0; i < 5; i++) {
+ assert(yasl_cpu_pixels(s, &w, &h) && yasl_cpu_present(s) == 0);
+ assert(yasl_wait_event(&e, 20) >= 0);
+ }
+ assert(refreshes == 0);
#if YASL_HAS_COCOA
+ s->display->modal = true;
yasl_test_frame_tick(s);
-#endif
uint64_t deadline = yasl_private_loop_now_ns() + 3000000000ull;
while (!refreshes && yasl_private_loop_now_ns() < deadline)
assert(yasl_wait_event(&e, 20) >= 0);
assert(refreshes > 0);
- yasl_surface_set_refresh_callback(s, NULL, NULL);
+ s->display->modal = false;
+#endif
+ s->refresh = NULL;
yasl_surface_destroy(s);
- assert((yasl_init(&(struct yasl_options){.backend = backend}) < 0));
+ assert(yasl_init(backend, NULL) == -EALREADY);
s = yasl_surface_create(&(struct yasl_surface_options){.title = "shared backend remains",
- .width = 64,
- .height = 64,
- .type = YASL_SURFACE_CPU,
- .flags = 0});
+ .width = 64, .height = 64});
assert(s);
yasl_shutdown();
- assert((yasl_init(&(struct yasl_options){.backend = backend}) == 0));
- s = yasl_surface_create(&(struct yasl_surface_options){
- .title = "reinitialized", .width = 64, .height = 64, .type = YASL_SURFACE_CPU, .flags = 0});
+ assert(yasl_init(backend, NULL) == 0);
+ s = yasl_surface_create(
+ &(struct yasl_surface_options){.title = "reinitialized", .width = 64, .height = 64});
assert(s);
yasl_shutdown();
puts("public surface lifecycle, pixels, ownership, input, wake and refresh passed");