summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-13 21:23:03 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-13 21:23:03 +0300
commitdd1775a9927922c14f8679ccbc4d3ca8d5917e20 (patch)
tree3acc442bb4a3470364b74aa82ff67cb84d555c45 /tests
parentecb81aeea4c0c880b3a60a0dc8418c4bf2a7cf85 (diff)
public api refactor
Diffstat (limited to 'tests')
-rw-r--r--tests/cocoa/test_ownership.m75
-rw-r--r--tests/common/test_app.c72
-rw-r--r--tests/common/test_events.c209
-rw-r--r--tests/common/test_hello_example.c2
-rw-r--r--tests/helpers/run_backends.py7
-rw-r--r--tests/meson.build7
-rw-r--r--tests/test_api.cpp16
-rw-r--r--tests/wayland/test_app_input.c17
-rw-r--r--tests/wayland/test_clipboard.c75
-rw-r--r--tests/x11/test_input.c236
-rw-r--r--tests/x11/test_tablet_native.c10
11 files changed, 666 insertions, 60 deletions
diff --git a/tests/cocoa/test_ownership.m b/tests/cocoa/test_ownership.m
index 5fd5cbf..6d69907 100644
--- a/tests/cocoa/test_ownership.m
+++ b/tests/cocoa/test_ownership.m
@@ -3,6 +3,7 @@
#import <AppKit/AppKit.h>
#include "yasl/yasl.h"
#include <assert.h>
+#include <errno.h>
#include <stdio.h>
#include <string.h>
@@ -20,13 +21,49 @@ int main(void)
assert(yasl_cocoa_surface_get_view(s) == window.contentView);
assert([window isKindOfClass:[NSWindow class]] && window.contentView);
struct yasl_event event;
- while (yasl_surface_poll_event(s, &event)) {}
+ while (yasl_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}));
+ assert(errno == EINVAL);
+ struct yasl_popup_spec popup_spec = {
+ .size = {80, 40}, .anchor = {10, 10, 2, 2},
+ };
+ struct yasl_surface *popup = yasl_surface_create_popup(s, &popup_spec);
+ assert(popup);
+ assert(!yasl_surface_set_size(popup, (struct yasl_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)) {}
+
+ id<NSTextInputClient> text_input = (id<NSTextInputClient>)yasl_cocoa_surface_get_view(s);
+ [text_input setMarkedText:@"é漢" selectedRange:NSMakeRange(1, 1)
+ replacementRange:NSMakeRange(NSNotFound, 0)];
+ assert(strcmp(yasl_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(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(event.composition.begin == -1 && event.composition.end == -1);
+ while (yasl_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);
- yasl_display_copy(d, YASL_CLIPBOARD, text);
- yasl_display_paste(d, YASL_CLIPBOARD, s);
+ assert(yasl_clipboard_set(d, YASL_CLIPBOARD, text));
+ request_ids[i] = yasl_clipboard_request(s, YASL_CLIPBOARD);
+ assert(request_ids[i] != 0);
memset(text, 'x', sizeof(text));
}
}
@@ -34,19 +71,31 @@ int main(void)
for (int i = 0; i < 600; i++) {
char text[32];
snprintf(text, sizeof(text), "paste-%d", i);
- assert(yasl_surface_poll_event(s, &event));
- assert(event.type == YASL_EVENT_PASTE && strcmp(event.text.data, text) == 0);
+ 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);
}
- const char *last = event.text.data;
- assert(!yasl_surface_poll_event(s, &event));
+ const char *last = event.paste.data;
+ assert(!yasl_display_poll_event(d, &event));
@autoreleasepool { yasl_display_copy(d, YASL_CLIPBOARD, "new selection"); }
assert(strcmp(last, "paste-599") == 0);
- @autoreleasepool {
- yasl_display_copy(d, YASL_CLIPBOARD, "");
- yasl_display_paste(d, YASL_CLIPBOARD, s);
- }
- assert(yasl_surface_poll_event(s, &event));
- assert(event.type == YASL_EVENT_PASTE && !event.text.len && !event.text.data[0]);
+ assert(!yasl_clipboard_set(d, YASL_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]);
+ [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);
return 0;
diff --git a/tests/common/test_app.c b/tests/common/test_app.c
index f61a957..214d8f2 100644
--- a/tests/common/test_app.c
+++ b/tests/common/test_app.c
@@ -2,6 +2,7 @@
#include "yasl/app.h"
#include <assert.h>
+#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
@@ -16,13 +17,16 @@ struct test_state {
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_post_event(state->display, state->surface, 42, (void *)0x1234, 0);
+ bool ok = yasl_display_post(state->display, &(struct yasl_message){
+ .target_id = state->target_id, .code = 42, .payload = (void *)0x1234});
assert(ok);
return NULL;
}
@@ -54,13 +58,13 @@ static enum yasl_app_result on_init(void *ud, struct yasl_display *d)
yasl_surface_set_pointer_mode(state->surface, YASL_POINTER_RELATIVE);
yasl_surface_set_pointer_mode(state->surface, YASL_POINTER_NORMAL);
- state->timer_id = yasl_app_add_timer(d, YASL_MS_TO_NS(20), on_timer, state);
+ state->timer_id = yasl_loop_add_timer(yasl_display_loop(d), YASL_MS_TO_NS(20), on_timer, state);
assert(state->timer_id > 0);
- pthread_t thread;
- int err = pthread_create(&thread, NULL, worker_thread, state);
+ state->target_id = yasl_surface_id(state->surface);
+ int err = pthread_create(&state->worker, NULL, worker_thread, state);
assert(err == 0);
- pthread_detach(thread);
+
yasl_surface_request_frame(state->surface);
return YASL_APP_CONTINUE;
@@ -80,7 +84,7 @@ static enum yasl_app_result on_event(void *ud, const struct yasl_event *ev)
return YASL_APP_CONTINUE;
}
-static void on_frame(void *ud, struct yasl_surface *s, struct yasl_frame_context *ctx)
+static void on_frame(void *ud, struct yasl_surface *s, struct yasl_frame *ctx)
{
struct test_state *state = ud;
assert(s == state->surface);
@@ -88,12 +92,12 @@ static void on_frame(void *ud, struct yasl_surface *s, struct yasl_frame_context
state->frame_called = true;
state->frame_count++;
- if (ctx->cpu.pixels) {
- size_t count = (size_t)ctx->size.x * ctx->size.y;
+ 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->cpu.pixels[i] = 0xff204060;
+ ctx->target.pixels[i] = 0xff204060;
}
- bool ok = yasl_frame_present_cpu(ctx, NULL, 0);
+ bool ok = yasl_frame_present(ctx, NULL, 0);
assert(ok);
}
@@ -106,14 +110,15 @@ 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_context *ctx)
+static void present_once(void *ud, struct yasl_surface *s, struct yasl_frame *ctx)
{
(*(int *)ud)++;
- if (ctx->cpu.pixels)
- assert(yasl_frame_present_cpu(ctx, NULL, 0));
+ if (ctx->target.pixels)
+ assert(yasl_frame_present(ctx, NULL, 0));
yasl_surface_destroy(s);
}
@@ -132,6 +137,43 @@ static void test_window_without_init(void)
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};
@@ -146,6 +188,9 @@ int main(void)
};
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);
@@ -153,6 +198,7 @@ int main(void)
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_events.c b/tests/common/test_events.c
new file mode 100644
index 0000000..c8660cb
--- /dev/null
+++ b/tests/common/test_events.c
@@ -0,0 +1,209 @@
+#include "common/backend.h"
+#include "yasl/app.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#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 int released;
+static pthread_t owner;
+static void release(void *payload)
+{
+ assert(pthread_equal(owner, pthread_self()));
+ assert(payload == &released);
+ released++;
+}
+
+static void setup(struct yasl_display *d, struct yasl_surface *a, struct yasl_surface *b)
+{
+ *d = (struct yasl_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));
+}
+
+static void teardown(struct yasl_display *d, struct yasl_surface *a, struct yasl_surface *b)
+{
+ yasl_events_unregister(a);
+ yasl_events_unregister(b);
+ input_queue_clear(&a->input);
+ input_queue_clear(&b->input);
+ yasl_events_close(d);
+}
+
+static void test_order_and_lifetimes(void)
+{
+ struct yasl_display d;
+ struct yasl_surface a, b;
+ setup(&d, &a, &b);
+ uint64_t aid = yasl_surface_id(&a), bid = yasl_surface_id(&b);
+ assert(aid && bid && aid != bid);
+ yasl_surface_set_userdata(&a, &b);
+ assert(yasl_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}}));
+ 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;
+ uint64_t sequence = 0;
+ for (size_t i = 0; i < sizeof(expected) / sizeof(*expected); i++) {
+ assert(yasl_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);
+ }
+ 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));
+ 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(!strcmp(borrowed, "kept"));
+ assert(!yasl_display_poll_event(&d, &ev));
+ /* Reusing object memory must never reuse the identity. */
+ assert(yasl_events_register(&a));
+ assert(a.id != aid);
+ errno = 0;
+ assert(!yasl_display_post(&d, &(struct yasl_message){.target_id = aid}));
+ assert(errno == ENOENT);
+ teardown(&d, &a, &b);
+}
+
+struct producer { struct yasl_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){
+ .target_id = producer->target, .code = i, .payload = &released, .release = release}));
+ return NULL;
+}
+
+static void test_post_cleanup(void)
+{
+ struct yasl_display d;
+ struct yasl_surface a, b;
+ setup(&d, &a, &b);
+ owner = pthread_self();
+ released = 0;
+ pthread_t worker;
+ struct producer producer = {&d, a.id};
+ assert(!pthread_create(&worker, NULL, post_worker, &producer));
+ assert(!pthread_join(worker, NULL));
+ struct yasl_event ev;
+ for (uint32_t i = 0; i < 8; i++) {
+ assert(yasl_display_poll_event(&d, &ev));
+ assert(ev.user.code == i && ev.surface == &a);
+ }
+ assert(released == 7); /* Last event remains borrowed. */
+ yasl_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(released == 33); /* Pending message and last consumed message. */
+ errno = 0;
+ assert(!yasl_display_post(&d, &(struct yasl_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)
+{
+ (void)s; (void)target;
+ damage_count = damage->n;
+ return true;
+}
+static void test_damage(void)
+{
+ struct yasl_backend_ops present_ops = {.surface_present = present};
+ struct yasl_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}}};
+ 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);
+ s.frame_presented = false;
+ assert(yasl_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);
+ s.frame_presented = false;
+ rects[YASL_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));
+ s.drawing = false;
+ assert(!yasl_frame_present(&frame, NULL, 0));
+}
+
+static void test_failures(void)
+{
+ struct yasl_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);
+ 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);
+ /* 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);
+ teardown(&d, &a, &b);
+}
+
+
+static void test_legacy_poll_does_not_spin(void)
+{
+ struct yasl_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));
+ teardown(&d, &a, &b);
+}
+
+int main(void)
+{
+ test_order_and_lifetimes();
+ test_post_cleanup();
+ test_damage();
+ test_failures();
+ test_legacy_poll_does_not_spin();
+ return 0;
+}
diff --git a/tests/common/test_hello_example.c b/tests/common/test_hello_example.c
index 101e2d4..350b3bb 100644
--- a/tests/common/test_hello_example.c
+++ b/tests/common/test_hello_example.c
@@ -3,7 +3,7 @@
#include "../../examples/hello.c"
#undef main
-static void draw_once(void *ud, struct yasl_surface *surface, struct yasl_frame_context *frame)
+static void draw_once(void *ud, struct yasl_surface *surface, struct yasl_frame *frame)
{
draw(ud, surface, frame);
if (!failed) yasl_surface_destroy(surface);
diff --git a/tests/helpers/run_backends.py b/tests/helpers/run_backends.py
index 76fe8ab..af7e02d 100644
--- a/tests/helpers/run_backends.py
+++ b/tests/helpers/run_backends.py
@@ -21,7 +21,7 @@ def wait_for(process, ready):
def main():
- weston, xwayland, test, timers, tablet, hello, input_x11, interactive = sys.argv[1:]
+ weston, xwayland, test, timers, tablet, hello, input_x11, interactive, app, app_input = sys.argv[1:]
servers = []
with tempfile.TemporaryDirectory(prefix="yasl-backends-") as directory:
root = Path(directory)
@@ -82,6 +82,11 @@ def main():
subprocess.run([timers], env=x_env, check=True, timeout=8)
print("Test: X11 UTF-8 keyboard fallback and clipboard", flush=True)
subprocess.run([input_x11], env=x_env, check=True, timeout=8)
+ print("Test: Wayland runner lifecycle and event destruction", flush=True)
+ subprocess.run([app], env=env, check=True, timeout=8)
+ subprocess.run([app_input], env=env, check=True, timeout=8)
+ print("Test: X11 runner lifecycle", flush=True)
+ subprocess.run([app], env=x_env, check=True, timeout=8)
for backend in ("wayland", "x11"):
print("Test: tablet example on", backend, flush=True)
subprocess.run([tablet, "--backend", backend, "--smoke-test"],
diff --git a/tests/meson.build b/tests/meson.build
index 84b6847..cac62db 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -279,8 +279,13 @@ if get_option('integration_tests')
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],
+ interactive_example, app_test, app_input_test],
timeout: 60,
)
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 bc54323..c5859cd 100644
--- a/tests/test_api.cpp
+++ b/tests/test_api.cpp
@@ -1,4 +1,5 @@
#include "yasl/native.h"
+#include "yasl/app.h"
#if YASL_HAS_WAYLAND
#include "yasl/native/wayland.h"
#endif
@@ -39,6 +40,21 @@ int main()
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);
diff --git a/tests/wayland/test_app_input.c b/tests/wayland/test_app_input.c
index 88f9ead..7e0e9a0 100644
--- a/tests/wayland/test_app_input.c
+++ b/tests/wayland/test_app_input.c
@@ -5,9 +5,11 @@
#include "yasl/app.h"
#include <assert.h>
+#include <errno.h>
#include <stdlib.h>
struct test_state {
+ bool initialized;
int keys;
int buttons, motions, resets;
int end;
@@ -26,21 +28,20 @@ static void push_key(struct yasl_surface *s)
static enum yasl_app_result on_init(void *ud, struct yasl_display *d)
{
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);
- struct wayland_surface *w = (struct wayland_surface *)s;
- w->cbs->close(s, w->ud);
+ yasl_surface_notify_close(s);
return YASL_APP_CONTINUE;
}
if (state->end) {
- struct wayland_display *display = (struct wayland_display *)d;
if (state->end == 1)
- display->cbs->quit(display->ud);
+ yasl_display_notify_event(d, YASL_EVENT_DISPLAY_QUIT);
else
- display->cbs->lost(display->ud);
+ yasl_display_notify_event(d, YASL_EVENT_DISPLAY_LOST);
return YASL_APP_CONTINUE;
}
struct yasl_surface *s = yasl_surface_create_toplevel(d,
@@ -106,6 +107,12 @@ int main(void)
.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);
diff --git a/tests/wayland/test_clipboard.c b/tests/wayland/test_clipboard.c
index ff84209..1778ad2 100644
--- a/tests/wayland/test_clipboard.c
+++ b/tests/wayland/test_clipboard.c
@@ -1,24 +1,46 @@
#include "../../src/platform/wayland/clipboard.c"
+#include "common/loop.h"
#include <assert.h>
-struct received { int count; size_t len; char text[32]; };
+struct received {
+ int count;
+ size_t len;
+ uint64_t request_id;
+ enum yasl_transfer_status status;
+ struct clipboard *clipboard;
+ bool forget_on_receive;
+ char text[32];
+};
static void receive(const char *text, size_t len, bool uri_list,
- struct wl_surface *surface, void *ud)
+ struct wl_surface *surface, uint64_t request_id,
+ enum yasl_transfer_status status, void *ud)
{
(void)surface;
struct received *r = ud;
assert(!uri_list && len < sizeof(r->text));
- memcpy(r->text, text, len);
- r->text[len] = '\0';
+ if (status == YASL_TRANSFER_OK) {
+ assert(text);
+ memcpy(r->text, text, len);
+ r->text[len] = '\0';
+ } else {
+ assert(!text && len == 0);
+ }
r->len = len;
+ r->request_id = request_id;
+ r->status = status;
r->count++;
+ if (r->forget_on_receive) {
+ r->forget_on_receive = false;
+ clipboard_forget_surface(r->clipboard, surface);
+ }
}
int main(void)
{
struct received received = {0};
struct clipboard c = {.loop = yasl_loop_create(), .receive = receive, .ud = &received};
+ received.clipboard = &c;
assert(c.loop);
const struct { const char *bytes; size_t len; bool valid; } cases[] = {
{"é字😀", sizeof("é字😀") - 1, true},
@@ -28,20 +50,61 @@ int main(void)
};
for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
received = (struct received){0};
+ received.clipboard = &c;
int fds[2];
assert(pipe(fds) == 0);
- assert(start_transfer_text(&c, fds[0], false, false, c.text));
+ 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));
+ 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(!c.transfers);
- assert(received.count == (int)cases[i].valid);
+ assert(!yasl_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));
if (cases[i].valid) {
assert(received.len == cases[i].len);
assert(memcmp(received.text, cases[i].bytes, received.len) == 0);
}
}
+ received = (struct received){0};
+ received.clipboard = &c;
+ int cancel_fds[2];
+ 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));
+ pending->paste = true;
+ pending->request_id = 99;
+ struct wl_surface *target = (struct wl_surface *)(uintptr_t)1;
+ pending->drop_surface = target;
+ 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));
+
+ received.forget_on_receive = true;
+ int timeout_fds[2];
+ assert(pipe(timeout_fds) == 0);
+ struct transfer *timed = start_transfer_text(&c, timeout_fds[0], false, false, NULL);
+ assert(timed && timed->timeout);
+ timed->paste = true;
+ 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));
+ (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);
return 0;
}
diff --git a/tests/x11/test_input.c b/tests/x11/test_input.c
index 95943d1..c2eca37 100644
--- a/tests/x11/test_input.c
+++ b/tests/x11/test_input.c
@@ -1,5 +1,7 @@
/* An isolated real X server supplies the keymap; disabling this surface's XIC
* deliberately exercises text insertion when no input method is available. */
+#define _POSIX_C_SOURCE 200809L
+#include <locale.h>
#include "../../src/platform/x11/window.c"
static void check_selection_encoding(struct x11_display *d, struct x11_surface *s)
@@ -35,34 +37,72 @@ static void check_selection_encoding(struct x11_display *d, struct x11_surface *
XFree(data);
XDestroyWindow(d->native, requestor);
- /* Simulate a legacy owner returning STRING to the paste conversion window,
- * then an empty UTF-8 owner and malformed UTF-8. */
- const struct { Atom type; const char *bytes; size_t len; const char *expected; } cases[] = {
- {XA_STRING, "caf\xe9 \xa3", 6, "café £"},
- {d->utf8, "", 0, ""},
- {d->utf8, "\xff", 1, NULL},
+ /* Simulate legacy STRING, empty UTF-8, malformed UTF-8, and rejected INCR. */
+ const struct {
+ Atom type;
+ const void *bytes;
+ size_t len;
+ int format;
+ const char *expected;
+ enum yasl_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},
};
for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
struct paste_request *pending = calloc(1, sizeof(*pending));
assert(pending);
+ pending->display = d;
pending->window = XCreateSimpleWindow(d->native, DefaultRootWindow(d->native),
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,
+ paste_timeout, pending);
+ assert(pending->timeout);
pending->next = d->pastes;
d->pastes = pending;
- XChangeProperty(d->native, pending->window, property, cases[i].type, 8,
- PropModeReplace, (const unsigned char *)cases[i].bytes, (int)cases[i].len);
+ unsigned long incr_bytes = 4096;
+ const void *bytes = cases[i].bytes;
+ if (cases[i].type == d->incr) bytes = &incr_bytes;
+ XChangeProperty(d->native, pending->window, property, cases[i].type,
+ cases[i].format, PropModeReplace, bytes, (int)cases[i].len);
XSelectionEvent reply = {.requestor = pending->window, .property = property};
selection_notify(d, &reply);
struct yasl_event event;
- if (cases[i].expected) {
- assert(yasl_surface_poll_event(&s->base, &event));
- assert(event.type == YASL_EVENT_PASTE);
+ assert(yasl_surface_poll_event(&s->base, &event));
+ assert(event.type == YASL_EVENT_PASTE && event.paste.request_id == i + 1);
+ assert(event.paste.status == cases[i].status);
+ if (cases[i].status == YASL_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));
+ pending->timeout = 0;
+ paste_timeout(pending, 0, PASTE_TIMEOUT_NS);
+ }
assert(!yasl_surface_poll_event(&s->base, &event));
}
+
+ struct paste_request *rejected = calloc(1, sizeof(*rejected));
+ assert(rejected);
+ rejected->window = XCreateSimpleWindow(d->native, DefaultRootWindow(d->native),
+ 0, 0, 1, 1, 0, 0, 0);
+ rejected->target = s;
+ rejected->selection = d->clipboard;
+ rejected->id = 99;
+ rejected->next = d->pastes;
+ 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);
}
/* Own the XSETTINGS selection with one Net/DoubleClickTime value. */
@@ -96,6 +136,173 @@ static void check_double_click(struct x11_display *d)
assert(yasl_display_double_click_ms(&d->base) == YASL_DOUBLE_CLICK_MS_DEFAULT);
}
+static struct yasl_event wait_paste(struct yasl_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)
+ return event;
+ assert(!"expected paste completion was not queued");
+ return (struct yasl_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, ""));
+ 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(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));
+ XSync(d->native, False);
+ dispatch(&d->base);
+ event = wait_paste(&d->base, 102);
+ assert(event.paste.status == YASL_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));
+ struct paste_request *timed = d->pastes;
+ assert(timed && timed->id == 103 && timed->timeout);
+ assert(yasl_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);
+
+ struct yasl_window_spec spec = {.title = "Cancelled paste", .size = {80, 60}};
+ struct yasl_surface *cancel_target = yasl_surface_create_toplevel(&d->base, &spec);
+ assert(cancel_target);
+ assert(request_paste(&d->base, YASL_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);
+ assert(d->pastes && !d->pastes->target && d->pastes->id == 0);
+ assert(yasl_loop_del_timer(d->loop, timeout));
+ d->pastes->timeout = 0;
+ XSelectionEvent late_reply = {
+ .requestor = d->pastes->window,
+ .selection = d->pastes->selection,
+ .property = None,
+ };
+ selection_notify(d, &late_reply);
+ assert(!d->pastes);
+ XDestroyWindow(d->native, silent_owner);
+ XSetSelectionOwner(d->native, d->clipboard, None, CurrentTime);
+ XSync(d->native, False);
+}
+
+static struct yasl_event next_composition(struct yasl_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)
+ return event;
+ assert(!"expected composition snapshot was not queued");
+ return (struct yasl_event){0};
+}
+
+static void drain_display_events(struct yasl_display *display)
+{
+ struct yasl_event event;
+ while (yasl_display_poll_event(display, &event)) {}
+}
+
+static void check_xim_callbacks(struct yasl_display *display, struct x11_surface *s)
+{
+ const char *old_locale = setlocale(LC_CTYPE, NULL);
+ char *saved_locale = old_locale ? strdup(old_locale) : NULL;
+ const char *utf8_locale = setlocale(LC_CTYPE, "C.UTF-8");
+ if (!utf8_locale) utf8_locale = setlocale(LC_CTYPE, "C.utf8");
+ assert(utf8_locale);
+
+ drain_display_events(display);
+ assert(xim_preedit_start(NULL, (XPointer)s, NULL) == -1);
+
+ wchar_t initial[] = {L'A', (wchar_t)0x1f600, L'B'};
+ XIMText wide = {.length = 3, .encoding_is_wchar = True,
+ .string.wide_char = initial};
+ XIMPreeditDrawCallbackStruct draw = {
+ .caret = 2, .chg_first = 0, .chg_length = 0, .text = &wide,
+ };
+ 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);
+ assert(event.composition.active && event.composition.len == 6);
+ assert(event.composition.begin == 5 && event.composition.end == 5);
+
+ /* XIMText.length counts characters. The data need not have a terminator. */
+ char multibyte[] = {(char)0xc3, (char)0xa9, 'Z', 'x'};
+ XIMText mb = {.length = 2, .encoding_is_wchar = False,
+ .string.multi_byte = multibyte};
+ draw = (XIMPreeditDrawCallbackStruct){
+ .caret = 3, .chg_first = 1, .chg_length = 1, .text = &mb,
+ };
+ xim_preedit_draw(NULL, (XPointer)s, (XPointer)&draw);
+ assert(s->ime_preedit && strcmp(s->ime_preedit, "AéZB") == 0);
+ event = next_composition(display);
+ assert(event.composition.active && event.composition.begin == 4);
+ assert(event.composition.end == 4);
+
+ /* A NULL text string updates feedback/caret while preserving the snapshot. */
+ XIMText feedback = {.length = 4, .encoding_is_wchar = False,
+ .string.multi_byte = NULL};
+ draw = (XIMPreeditDrawCallbackStruct){
+ .caret = 1, .chg_first = 0, .chg_length = 4, .text = &feedback,
+ };
+ xim_preedit_draw(NULL, (XPointer)s, (XPointer)&draw);
+ assert(strcmp(s->ime_preedit, "AéZB") == 0);
+ event = next_composition(display);
+ assert(event.composition.active && event.composition.begin == 1);
+
+ char malformed[] = {(char)0xff, 'x'};
+ XIMText invalid = {.length = 1, .encoding_is_wchar = False,
+ .string.multi_byte = malformed};
+ draw.text = &invalid;
+ draw.chg_first = 0;
+ 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));
+
+ wchar_t empty[] = {0};
+ XIMText deletion = {.length = 0, .encoding_is_wchar = True,
+ .string.wide_char = empty};
+ draw = (XIMPreeditDrawCallbackStruct){
+ .caret = 0, .chg_first = 0, .chg_length = 4, .text = &deletion,
+ };
+ xim_preedit_draw(NULL, (XPointer)s, (XPointer)&draw);
+ event = next_composition(display);
+ assert(!event.composition.active && event.composition.len == 0);
+ assert(!s->ime_preedit);
+
+ /* Done also publishes an explicit end snapshot. */
+ wide = (XIMText){.length = 3, .encoding_is_wchar = True,
+ .string.wide_char = initial};
+ draw = (XIMPreeditDrawCallbackStruct){
+ .caret = 1, .chg_first = 0, .chg_length = 0, .text = &wide,
+ };
+ xim_preedit_draw(NULL, (XPointer)s, (XPointer)&draw);
+ (void)next_composition(display);
+ xim_preedit_done(NULL, (XPointer)s, NULL);
+ event = next_composition(display);
+ assert(!event.composition.active && !s->ime_preedit);
+
+ if (saved_locale) {
+ setlocale(LC_CTYPE, saved_locale);
+ free(saved_locale);
+ }
+}
+
int main(void)
{
struct yasl_display_spec ds = {.backend = YASL_BACKEND_X11};
@@ -126,10 +333,13 @@ int main(void)
XSync(d->native, False);
dispatch(base);
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)) {}
XKeyEvent native = {.type = KeyPress, .display = d->native,
.window = s->window, .keycode = code};
key_event(s, &native, false);
- struct yasl_event event;
assert(yasl_surface_poll_event(surface, &event));
assert(event.type == YASL_EVENT_KEY && event.key.key == YASL_KEY_A);
assert(event.key.codepoint == cases[i].label);
@@ -149,6 +359,8 @@ int main(void)
s->ic = saved_ic;
check_selection_encoding(d, s);
check_double_click(d);
+ check_request_completion(d, s);
+ check_xim_callbacks(base, s);
/* Test CSD interactive actions, window menu, and IME caret */
assert(yasl_display_caps(base) & YASL_CAP_CSD);
diff --git a/tests/x11/test_tablet_native.c b/tests/x11/test_tablet_native.c
index b0d1366..706a5cc 100644
--- a/tests/x11/test_tablet_native.c
+++ b/tests/x11/test_tablet_native.c
@@ -57,14 +57,8 @@ static int connect_tool(const char *path)
static void native_draw(struct yasl_surface *surface, struct yasl_frame *frame, void *ud)
{
- struct yasl_frame_context context = {
- .surface = surface, .size = frame->target.size,
- .scale_120 = yasl_surface_geometry(surface).scale_120,
- .cpu = {.pixels = frame->target.pixels,
- .stride_bytes = frame->target.size.x * (int)sizeof(uint32_t)},
- .internal_handle = frame,
- };
- draw(ud, surface, &context);
+ (void)surface;
+ draw(ud, surface, frame);
}
static void native_configure(struct yasl_surface *surface, struct yasl_geometry geometry, void *ud)