summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBerke Güzel <berke.guzel@gdh.digital>2026-10-14 09:38:31 +0300
committerBerke Güzel <berke.guzel@gdh.digital>2026-10-14 09:38:31 +0300
commit5ef6ca21ab9e1cf4f69254234d190a634b777d52 (patch)
tree974d3797a6d9487e54a811e224bf78a3f52dda85
parent563b23a33726289387193b85d90fb569631ee05f (diff)
Remove deprecated Cocoa OpenGL and private compatibility APIs
-rw-r--r--README.md5
-rw-r--r--docs/getting-started.md9
-rw-r--r--docs/guide.md4
-rw-r--r--include/yasl/gl.h5
-rw-r--r--include/yasl/yasl.h38
-rw-r--r--meson.build15
-rw-r--r--src/common/backend.c32
-rw-r--r--src/common/backend.h9
-rw-r--r--src/common/events.c56
-rw-r--r--src/common/surface.c6
-rw-r--r--src/common/types.h106
-rw-r--r--src/platform/cocoa/api.h3
-rw-r--r--src/platform/cocoa/window.m239
-rw-r--r--src/platform/wayland/api.h3
-rw-r--r--src/platform/wayland/backend.c23
-rw-r--r--src/platform/wayland/clipboard.c12
-rw-r--r--src/platform/wayland/clipboard.h2
-rw-r--r--src/platform/wayland/internal.h2
-rw-r--r--src/platform/wayland/keyboard.c25
-rw-r--r--src/platform/wayland/popup.c17
-rw-r--r--src/platform/wayland/surface.c3
-rw-r--r--src/platform/x11/window.c135
-rw-r--r--tests/cocoa/display.m13
-rw-r--r--tests/cocoa/test_cursor.m2
-rw-r--r--tests/cocoa/test_keyboard.m9
-rw-r--r--tests/cocoa/test_native.c3
-rw-r--r--tests/cocoa/test_ownership.m22
-rw-r--r--tests/cocoa/test_tablet.m4
-rw-r--r--tests/common/test_backends.c495
-rw-r--r--tests/common/test_contracts.c24
-rw-r--r--tests/common/test_events.c19
-rw-r--r--tests/common/test_surface_integration.c20
-rw-r--r--tests/helpers/package_cocoa_tests.py4
-rw-r--r--tests/helpers/run_backends.py119
-rw-r--r--tests/meson.build16
-rw-r--r--tests/wayland/test_cursor.c8
-rw-r--r--tests/wayland/test_input.c10
-rw-r--r--tests/wayland/test_keyboard.c4
-rw-r--r--tests/wayland/test_popup_positioner.c11
-rw-r--r--tests/wayland/test_relative_pointer.c6
-rw-r--r--tests/wayland/test_state.c37
-rw-r--r--tests/wayland/test_tablet.c8
-rw-r--r--tests/x11/test_input.c24
-rw-r--r--tests/x11/test_state.c25
-rw-r--r--tests/x11/test_tablet.c79
-rw-r--r--tests/x11/test_tablet_native.c126
46 files changed, 403 insertions, 1434 deletions
diff --git a/README.md b/README.md
index d486b80..e528220 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,8 @@
YASL is a small C desktop surface and input library for applications that own
their event loop and renderer. It supports Wayland, X11, and Cocoa, with CPU
-images, optional OpenGL contexts, Vulkan window surfaces, and direct Metal layers.
+images, optional EGL/OpenGL contexts on Linux, Vulkan window surfaces, and direct
+Metal layers on macOS.
Pen input includes tool identity, proximity/contact, pressure, tilt, and available
rotation/distance/tangential/wheel axes. It also supplies IME composition/editing,
clipboard text, popups, file drops, and surface drags.
@@ -17,7 +18,7 @@ yasl_surface *surface = yasl_surface_create("Example", 800, 600, 0);
Flags zero creates a GPU window without choosing a graphics API. The application
attaches a Vulkan surface or Metal layer, or uses `yasl_gl_surface_create` to create
-an OpenGL window/context. `YASL_SURFACE_CPU` gives the window a pixel buffer: draw into
+an OpenGL window/context on Linux. `YASL_SURFACE_CPU` gives the window a pixel buffer: draw into
`yasl_cpu_pixels` and call `yasl_cpu_present`. Native handles are available through typed extension headers.
**Status:** pre-release 0.1; source and ABI compatibility are not promised.
diff --git a/docs/getting-started.md b/docs/getting-started.md
index b82dae5..aeed4cd 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -7,14 +7,14 @@ Build with a C23 compiler, Meson 1.6+, and Ninja. Linux backend dependencies are
wayland-client, wayland-cursor, xkbcommon, or x11, xi, xext, xkbcommon (optional
xrandr). Optional egl and wayland-egl enable GL contexts; Vulkan SDK development
files enable the Vulkan bridge. Optional dbus-1 enables Linux desktop services.
-Cocoa requires macOS 14+ and the AppKit, Metal, QuartzCore, OpenGL, and
-UserNotifications system frameworks. Optional Vulkan SDK enables MoltenVK WSI.
+Cocoa requires macOS 14+ and the AppKit, Metal, QuartzCore, and UserNotifications
+system frameworks. Use Metal or MoltenVK for GPU rendering on macOS; Cocoa does
+not provide OpenGL contexts. Optional Vulkan SDK enables MoltenVK WSI.
```sh
meson setup build
meson compile -C build
./build/yasl-hello
-./build/yasl-game
meson test -C build --print-errorlogs
```
@@ -53,7 +53,8 @@ reconnects, and sends DISPLAY_RESTORED. CPU windows need nothing; GPU renderers
their Vulkan surfaces and GL objects on loss and rebuild them on restore.
[hello.c](../examples/hello.c) draws into a CPU surface's pixel buffer on every REFRESH.
-[game.c](../examples/game.c) creates a GL context, binds it, loads procedures, draws,
+On Linux with EGL, `./build/yasl-game` runs [game.c](../examples/game.c), which
+creates a GL context, binds it, loads procedures, draws,
swaps, and rebinds the context after a compositor restart. [tablet.c](../examples/tablet.c) retains a canvas
and draws pressure-sensitive pen/eraser strokes. [notepad.c](../examples/notepad.c)
uses a worker queue, wakeups, clipboard, IME, and its own blink deadline.
diff --git a/docs/guide.md b/docs/guide.md
index d0db071..5435370 100644
--- a/docs/guide.md
+++ b/docs/guide.md
@@ -64,8 +64,8 @@ One presenter attaches to each surface. Incompatible second attachments fail.
key/value attribute list terminated by YASL_GL_END, and an optional sharing surface.
NULL attributes default to GL3.2 core, RGBA8, depth24/stencil8. The surface owns
its context. Bind, load procedures, set swap interval, and swap explicitly.
- GL API support depends on the native driver; Cocoa rejects OpenGL ES/debug contexts
- and supports its native legacy/core profiles.
+ Available on Linux with EGL; GL API support depends on the native driver. Cocoa
+ reports UNSUPPORTED for GL creation; use Metal or MoltenVK.
- CPU: create with YASL_SURFACE_CPU and call `yasl_cpu_present` with premultiplied
numeric 0xAARRGGBB, width/height, byte stride, and optional damage rows containing
x/y/width/height. Extent must match current framebuffer. NULL/zero damage means full;
diff --git a/include/yasl/gl.h b/include/yasl/gl.h
index 66a245a..39d2c63 100644
--- a/include/yasl/gl.h
+++ b/include/yasl/gl.h
@@ -1,4 +1,4 @@
-/** @file Optional OpenGL/OpenGL ES contexts. Attribute lists are per-call. */
+/** @file Optional EGL/OpenGL/OpenGL ES contexts on Linux. Attribute lists are per-call. */
#ifndef YASL_GL_H
#define YASL_GL_H
#include "yasl/yasl.h"
@@ -13,7 +13,8 @@ enum yasl_gl_api { YASL_GL_OPENGL, YASL_GL_OPENGL_ES };
typedef void (*yasl_gl_proc)(void);
/** key/value pairs terminated by END, NULL defaults to GL3.2 core RGBA8 D24 S8.
* share is a live GL surface or NULL. CPU flag is invalid. Context is owned by
- * the returned surface. Detach it from all rendering threads before destruction. */
+ * the returned surface. Detach it from all rendering threads before destruction.
+ * Cocoa returns NULL with YASL_ERROR_UNSUPPORTED; use Metal or MoltenVK. */
YASL_API yasl_surface *yasl_gl_surface_create(const char *title, int width, int height,
unsigned flags, const int *attributes, yasl_surface *share);
/** May run on a rendering thread. NULL detaches this thread's current context. */
diff --git a/include/yasl/yasl.h b/include/yasl/yasl.h
index 38c5b88..c0ebb75 100644
--- a/include/yasl/yasl.h
+++ b/include/yasl/yasl.h
@@ -55,6 +55,20 @@ enum yasl_event_type { YASL_EVENT_NONE, YASL_EVENT_CLOSE, YASL_EVENT_QUIT, YASL_
YASL_EVENT_DRAG, YASL_EVENT_DISPLAY_LOST, YASL_EVENT_DISPLAY_RESTORED };
enum yasl_drop_action { YASL_DROP_OVER, YASL_DROP_LEAVE, YASL_DROP_DATA };
enum yasl_drag_action { YASL_DRAG_OVER, YASL_DRAG_LEAVE, YASL_DRAG_DROP };
+struct yasl_window_payload { int width,height,pixel_width,pixel_height; double scale; unsigned state; };
+struct yasl_key_payload { enum yasl_key key; enum yasl_key_action action; unsigned mods;
+ uint32_t codepoint, shifted, native_code; };
+struct yasl_text_payload { const char *data; size_t length; };
+struct yasl_pointer_payload { double x,y,dx,dy; enum yasl_pointer_action action; unsigned button,buttons,mods; };
+struct yasl_scroll_payload { double x,y,lines_x,lines_y,pixels_x,pixels_y; unsigned valid,source,phase,mods; bool momentum; };
+struct yasl_pen_payload { uint64_t device_id,tool_id; double x,y,pressure,tilt_x,tilt_y,rotation,distance,tangential,wheel_degrees;
+ unsigned axes_valid,axes_changed,buttons,changed_button,tool,action; bool in_contact; };
+struct yasl_composition_payload { const char *data; size_t length; int begin,end; bool active; uint64_t revision,generation; };
+struct yasl_text_edit_payload { const char *data; size_t length,begin,end; uint64_t revision,generation; };
+struct yasl_clipboard_payload { const char *data; size_t length; uint64_t request_id; enum yasl_transfer_status status; };
+struct yasl_drop_payload { enum yasl_drop_action action; double x,y; const char *data; size_t length; };
+struct yasl_drag_payload { enum yasl_drag_action action; double x,y; };
+
/** Read the union member named by type. Strings stay valid until the next wait.
* CLOSE: the user closed this window. QUIT: the system asked the app to quit.
* WINDOW: size, scale or state changed. REFRESH: draw now; sent once the window
@@ -70,20 +84,18 @@ struct yasl_event {
yasl_surface *surface;
uint64_t time_ns;
union {
- struct { int width,height,pixel_width,pixel_height; double scale; unsigned state; } window;
- struct { enum yasl_key key; enum yasl_key_action action; unsigned mods;
- uint32_t codepoint, shifted, native_code; } key;
- struct { const char *data; size_t length; } text;
- struct { double x,y,dx,dy; enum yasl_pointer_action action; unsigned button,buttons,mods; } pointer;
- struct { double x,y,lines_x,lines_y,pixels_x,pixels_y; unsigned valid,source,phase,mods; bool momentum; } scroll;
- struct { uint64_t device_id,tool_id; double x,y,pressure,tilt_x,tilt_y,rotation,distance,tangential,wheel_degrees;
- unsigned axes_valid,axes_changed,buttons,changed_button,tool,action; bool in_contact; } pen;
- struct { const char *data; size_t length; int begin,end; bool active; uint64_t revision,generation; } composition;
- struct { const char *data; size_t length,begin,end; uint64_t revision,generation; } text_edit;
- struct { const char *data; size_t length; uint64_t request_id; enum yasl_transfer_status status; } clipboard;
+ struct yasl_window_payload window;
+ struct yasl_key_payload key;
+ struct yasl_text_payload text;
+ struct yasl_pointer_payload pointer;
+ struct yasl_scroll_payload scroll;
+ struct yasl_pen_payload pen;
+ struct yasl_composition_payload composition;
+ struct yasl_text_edit_payload text_edit;
+ struct yasl_clipboard_payload clipboard;
/** DATA carries a text/uri-list for yasl_drop_next_path; x/y are set for OVER. */
- struct { enum yasl_drop_action action; double x,y; const char *data; size_t length; } drop;
- struct { enum yasl_drag_action action; double x,y; } drag;
+ struct yasl_drop_payload drop;
+ struct yasl_drag_payload drag;
};
};
/** Last error on this thread; success does not clear it. */
diff --git a/meson.build b/meson.build
index 4d7d7ce..5f5b26c 100644
--- a/meson.build
+++ b/meson.build
@@ -76,7 +76,7 @@ elif system == 'darwin'
error('Cocoa requires macOS 14 or newer. Set MACOSX_DEPLOYMENT_TARGET=14.0 or a newer target before configuring.')
endif
deps += [
- dependency('appleframeworks', modules: ['AppKit', 'Metal', 'QuartzCore', 'UserNotifications', 'OpenGL']),
+ dependency('appleframeworks', modules: ['AppKit', 'Metal', 'QuartzCore', 'UserNotifications']),
]
else
error('YASL supports Linux and macOS.')
@@ -92,6 +92,7 @@ if not has_wayland and not has_x11 and not has_cocoa
endif
add_project_arguments(
+ '-Werror=deprecated-declarations',
'-DYASL_HAS_EGL=' + (has_egl ? '1' : '0'),
'-DYASL_HAS_VULKAN=' + (has_vulkan ? '1' : '0'),
'-DYASL_HAS_WAYLAND=' + (has_wayland ? '1' : '0'),
@@ -172,10 +173,12 @@ notepad_example = executable(
dependencies: yasl_dep,
)
-game_example = executable(
- 'yasl-game',
- 'examples/game.c',
- dependencies: yasl_dep,
-)
+if has_egl
+ game_example = executable(
+ 'yasl-game',
+ 'examples/game.c',
+ dependencies: yasl_dep,
+ )
+endif
subdir('tests')
diff --git a/src/common/backend.c b/src/common/backend.c
index 8d20f67..939ec71 100644
--- a/src/common/backend.c
+++ b/src/common/backend.c
@@ -34,7 +34,6 @@ static struct yasl_private_display *open_backend(enum yasl_private_backend backe
struct yasl_private_display *d = ops->display_open(loop, spec);
if (!d && !errno) errno = ENODEV;
if (d) {
- d->callback_ud = spec ? spec->ud : NULL;
if (!yasl_private_events_open(d)) {
int error = errno;
ops->display_close(d);
@@ -132,26 +131,6 @@ int yasl_private_display_double_click_ms(const struct yasl_private_display *d)
return ms > 0 && ms <= 10000 ? ms : YASL_PRIVATE_DOUBLE_CLICK_MS_DEFAULT;
}
-void yasl_private_display_copy(struct yasl_private_display *d, enum yasl_private_selection sel, const char *text)
-{
- if (!d || !d->ops->display_copy || !text ||
- (sel != YASL_PRIVATE_CLIPBOARD && sel != YASL_PRIVATE_PRIMARY) ||
- (sel == YASL_PRIVATE_PRIMARY && !(yasl_private_display_caps(d) & YASL_PRIVATE_CAP_PRIMARY_SELECTION)))
- return;
- d->ops->display_copy(d, sel, text);
-}
-
-void yasl_private_display_paste(struct yasl_private_display *d, enum yasl_private_selection sel, struct yasl_surface *target)
-{
- if (!d || !d->ops->display_paste ||
- (sel != YASL_PRIVATE_CLIPBOARD && sel != YASL_PRIVATE_PRIMARY) ||
- (sel == YASL_PRIVATE_PRIMARY && !(yasl_private_display_caps(d) & YASL_PRIVATE_CAP_PRIMARY_SELECTION)))
- return;
- if (!target || target->display != d)
- return;
- d->ops->display_paste(d, sel, target);
-}
-
bool yasl_private_display_drag_start(struct yasl_private_display *d, struct yasl_surface *origin, const struct yasl_private_drag_image *image, const struct yasl_private_drag_listener *l, void *ud)
{
if (!d || !d->ops->display_drag_start)
@@ -336,17 +315,6 @@ bool yasl_private_surface_present(struct yasl_surface *s, const struct yasl_priv
return s->display->ops->surface_present(s, fb, &clipped);
}
-bool yasl_private_surface_poll_event(struct yasl_surface *s, struct yasl_private_event *ev)
-{
- if (!s || !ev)
- return false;
- if (s->display && s->display->events)
- return yasl_private_events_poll_surface(s, ev);
- if (s->display && s->display->ops && s->display->ops->surface_poll_event)
- return s->display->ops->surface_poll_event(s, ev);
- return input_queue_pop(&s->input, ev);
-}
-
bool yasl_private_surface_read_pixels(struct yasl_surface *s, uint32_t *out, size_t cap,
struct yasl_private_vector2i *size)
{
diff --git a/src/common/backend.h b/src/common/backend.h
index bf6815a..6eefbb3 100644
--- a/src/common/backend.h
+++ b/src/common/backend.h
@@ -17,11 +17,9 @@ struct yasl_private_display {
const struct yasl_private_backend_ops *ops;
void *native_handle;
bool offline; /* Connection lost; native handles are unusable until it is restored. */
- struct yasl_private_display_cbs callbacks;
struct yasl_private_loop *loop;
/* Backend's copy of yasl_private_display_spec.app_id, or NULL; for desktop services. */
const char *app_id;
- void *callback_ud;
struct yasl_private_event_state *events;
struct yasl_surface *surfaces;
};
@@ -82,7 +80,6 @@ bool yasl_private_events_register(struct yasl_surface *s);
void yasl_private_events_unregister(struct yasl_surface *s);
bool yasl_private_events_push(struct yasl_private_display *d, struct yasl_surface *queue_owner,
const struct yasl_private_event *event);
-bool yasl_private_events_poll_surface(struct yasl_surface *s, struct yasl_private_event *event);
void yasl_private_surface_notify_configure(struct yasl_surface *s, struct yasl_private_geometry geometry);
void yasl_private_surface_notify_refresh(struct yasl_surface *s);
void yasl_private_surface_notify_close(struct yasl_surface *s);
@@ -136,8 +133,6 @@ struct yasl_private_backend_ops {
int (*display_modifiers)(const struct yasl_private_display *d);
/* Optional; returns zero or less when the system reports no interval. */
int (*display_double_click_ms)(const struct yasl_private_display *d);
- void (*display_copy)(struct yasl_private_display *d, enum yasl_private_selection sel, const char *text);
- void (*display_paste)(struct yasl_private_display *d, enum yasl_private_selection sel, struct yasl_surface *target);
bool (*display_copy_text)(struct yasl_private_display *d, enum yasl_private_selection sel, const char *text);
bool (*display_request_paste)(struct yasl_private_display *d, enum yasl_private_selection sel,
struct yasl_surface *target, uint64_t request_id);
@@ -150,7 +145,7 @@ struct yasl_private_backend_ops {
bool (*surface_popup_reposition)(struct yasl_surface *popup, const struct yasl_private_popup_spec *spec);
void (*surface_destroy)(struct yasl_surface *s);
struct input_queue *(*surface_input_queue)(struct yasl_surface *s);
- bool (*surface_set_size)(struct yasl_surface *s, struct yasl_private_vector2i size_logical);
+ bool (*surface_set_size)(struct yasl_surface *s, struct yasl_private_vector2i size);
bool (*surface_set_fullscreen)(struct yasl_surface *s, bool enabled);
bool (*surface_set_maximized)(struct yasl_surface *s, bool enabled);
bool (*surface_minimize)(struct yasl_surface *s);
@@ -160,8 +155,6 @@ struct yasl_private_backend_ops {
void (*surface_set_title)(struct yasl_surface *s, const char *title);
void (*surface_schedule_redraw)(struct yasl_surface *s);
bool (*surface_present)(struct yasl_surface *s, const struct yasl_private_framebuffer *fb, const struct yasl_private_damage_list *damage);
- /* Optional; NULL means the common input queue is drained. */
- bool (*surface_poll_event)(struct yasl_surface *s, struct yasl_private_event *ev);
/* Optional; NULL means only YASL_PRIVATE_POINTER_NORMAL is supported. Backends that
* implement RELATIVE push POINTER_MOTION with delta set and pos frozen. */
bool (*surface_set_pointer_mode)(struct yasl_surface *s, enum yasl_private_pointer_mode mode);
diff --git a/src/common/events.c b/src/common/events.c
index ba78d77..9245050 100644
--- a/src/common/events.c
+++ b/src/common/events.c
@@ -228,46 +228,18 @@ bool yasl_private_display_post(struct yasl_private_display *d, const struct yasl
return true;
}
-static bool poll_event(struct yasl_private_display *d, uint64_t queue_id, struct yasl_private_event *event)
+bool yasl_private_display_poll_event(struct yasl_private_display *d, struct yasl_private_event *event)
{
if (!d || !d->events || !event) return false;
struct yasl_private_event_state *state = d->events;
yasl_private_mutex_lock(&state->mutex);
- struct event_node *discarded = NULL;
- struct event_node **entry = &state->head;
- struct event_node *previous = NULL;
- if (queue_id) {
- /* The input-only migration adapter uses legacy callbacks for lifecycle.
- * Retaining those notifications would keep dispatch permanently ready.
- * Mixing this adapter with display polling is deliberately unsupported. */
- while (*entry) {
- struct event_node *candidate = *entry;
- if (candidate->event.type < YASL_PRIVATE_EVENT_KEY ||
- candidate->event.type > YASL_PRIVATE_EVENT_INPUT_RESET) {
- *entry = candidate->next;
- if (state->tail == candidate) state->tail = previous;
- candidate->next = discarded;
- discarded = candidate;
- } else {
- previous = candidate;
- entry = &candidate->next;
- }
- }
- entry = &state->head;
- previous = NULL;
- while (*entry && (*entry)->queue_id != queue_id) {
- previous = *entry;
- entry = &(*entry)->next;
- }
- }
- struct event_node *node = *entry;
+ struct event_node *node = state->head;
if (!node) {
yasl_private_mutex_unlock(&state->mutex);
- dispose_list(discarded);
return false;
}
- *entry = node->next;
- if (state->tail == node) state->tail = previous;
+ state->head = node->next;
+ if (state->tail == node) state->tail = NULL;
node->next = NULL;
if (node->event.surface_id)
node->event.surface = yasl_private_events_find(d, node->event.surface_id);
@@ -276,20 +248,9 @@ static bool poll_event(struct yasl_private_display *d, uint64_t queue_id, struct
*event = node->event;
yasl_private_mutex_unlock(&state->mutex);
dispose(last);
- dispose_list(discarded);
return true;
}
-bool yasl_private_display_poll_event(struct yasl_private_display *d, struct yasl_private_event *event)
-{
- return poll_event(d, 0, event);
-}
-
-bool yasl_private_events_poll_surface(struct yasl_surface *s, struct yasl_private_event *event)
-{
- return s && s->id ? poll_event(s->display, s->id, event) : false;
-}
-
uint64_t yasl_private_events_request_id(struct yasl_private_display *d)
{
if (!d->events || d->events->request == UINT64_MAX) { errno = EOVERFLOW; return 0; }
@@ -310,14 +271,12 @@ void yasl_private_surface_notify_configure(struct yasl_surface *s, struct yasl_p
.resize = {.geometry = geometry, .scale_changed = previous_scale != geometry.scale_120}};
yasl_private_events_push(s->display, s, &event);
if (s->display) yasl_private_surface_request_frame(s);
- if (s->callbacks.configure) s->callbacks.configure(s, geometry, s->ud);
}
void yasl_private_surface_notify_close(struct yasl_surface *s)
{
struct yasl_private_event event = {.type = YASL_PRIVATE_EVENT_WINDOW_CLOSE, .surface = s};
yasl_private_events_push(s->display, s, &event);
- if (s->callbacks.close) s->callbacks.close(s, s->ud);
}
void yasl_private_surface_notify_state(struct yasl_surface *s, uint32_t flags)
@@ -325,21 +284,18 @@ void yasl_private_surface_notify_state(struct yasl_surface *s, uint32_t flags)
s->state = flags;
struct yasl_private_event event = {.type = YASL_PRIVATE_EVENT_WINDOW_STATE, .surface = s, .state.flags = flags};
yasl_private_events_push(s->display, s, &event);
- if (s->callbacks.state) s->callbacks.state(s, flags, s->ud);
}
void yasl_private_surface_notify_drag(struct yasl_surface *s, enum yasl_private_drag_event action, struct yasl_private_vector2i pos)
{
struct yasl_private_event event = {.type = YASL_PRIVATE_EVENT_DRAG, .surface = s, .drag = {action, pos}};
yasl_private_events_push(s->display, s, &event);
- if (s->callbacks.drag) s->callbacks.drag(s, action, pos, s->ud);
}
void yasl_private_surface_notify_drop(struct yasl_surface *s, enum yasl_private_drop_event action, struct yasl_private_vector2i pos)
{
struct yasl_private_event event = {.type = YASL_PRIVATE_EVENT_DROP_HOVER, .surface = s, .drop = {action, pos}};
yasl_private_events_push(s->display, s, &event);
- if (s->callbacks.drop) s->callbacks.drop(s, action, pos, s->ud);
}
void yasl_private_surface_notify_composition(struct yasl_surface *s, const char *text, int begin, int end)
@@ -367,8 +323,4 @@ void yasl_private_display_notify_event(struct yasl_private_display *d, enum yasl
{
struct yasl_private_event event = {.type = type};
yasl_private_events_push(d, NULL, &event);
- void (*callback)(void *) = type == YASL_PRIVATE_EVENT_DISPLAY_QUIT ? d->callbacks.quit
- : type == YASL_PRIVATE_EVENT_DISPLAY_REOPEN ? d->callbacks.reopen
- : type == YASL_PRIVATE_EVENT_DISPLAY_LOST ? d->callbacks.lost : NULL;
- if (callback) callback(d->callback_ud);
}
diff --git a/src/common/surface.c b/src/common/surface.c
index 9b4a8ad..b47fea7 100644
--- a/src/common/surface.c
+++ b/src/common/surface.c
@@ -119,7 +119,7 @@ yasl_surface *yasl_surface_create(const char *title,int width,int height,unsigne
if(!creation_valid(width,height,flags)) return NULL;
bool fresh=!display;
if(!initialize()) return NULL;
- struct yasl_private_window_spec spec={.title=title,.size_logical={width,height},
+ struct yasl_private_window_spec spec={.title=title,.size={width,height},
.flags=flags,.external_gpu=!(flags&YASL_SURFACE_CPU)};
yasl_surface *s=yasl_private_surface_create_toplevel(display,&spec);
if(!s) {
@@ -446,7 +446,7 @@ static bool trigger_valid(yasl_surface *s,const yasl_event *e)
static bool popup_spec(yasl_surface *s,int w,int h,double x,double y,double aw,double ah,enum yasl_popup_edge anchor,enum yasl_popup_edge gravity,unsigned constraints,struct yasl_private_popup_spec *out)
{
if(w<=0||h<=0 || (unsigned)anchor>8 || (unsigned)gravity>8 || (constraints&~63u))return yasl_public_fail(EINVAL);
- *out=(struct yasl_private_popup_spec){.size={yasl_private_scale_to_device(w,s->scale_120),yasl_private_scale_to_device(h,s->scale_120)},.anchor_edges=anchor,.gravity=gravity,.constraints=constraints,.positioner_explicit=true};
+ *out=(struct yasl_private_popup_spec){.size={yasl_private_scale_to_device(w,s->scale_120),yasl_private_scale_to_device(h,s->scale_120)},.anchor_edges=anchor,.gravity=gravity,.constraints=constraints};
return logical_rect(s,x,y,aw,ah,&out->anchor);
}
yasl_surface *yasl_popup_create(yasl_surface *parent,int w,int h,double x,double y,double aw,double ah,enum yasl_popup_edge anchor,enum yasl_popup_edge gravity,unsigned constraints,const yasl_event *trigger)
@@ -494,7 +494,7 @@ yasl_surface *yasl_gl_surface_create(const char *title,int w,int h,unsigned flag
bool fresh=!display;if(!initialize())return NULL;
if(share && (share->display!=display || share->presenter!=YASL_PRIVATE_PRESENTER_GL)) {yasl_public_fail(EINVAL);return NULL;}
if(!display->ops->surface_create_gl) {if(fresh)yasl_shutdown();yasl_public_fail(ENOTSUP);return NULL;}
- struct yasl_private_window_spec spec={.title=title,.size_logical={w,h},.flags=flags,.external_gpu=true};
+ struct yasl_private_window_spec spec={.title=title,.size={w,h},.flags=flags,.external_gpu=true};
yasl_surface *s=display->ops->surface_create_gl(display,&spec,attrs,share);
if(!s){int error=errno;if(fresh)yasl_shutdown();yasl_public_fail(error);return NULL;}
if(!yasl_private_events_register(s)){int error=errno;display->ops->surface_destroy(s);if(fresh)yasl_shutdown();yasl_public_fail(error);return NULL;}
diff --git a/src/common/types.h b/src/common/types.h
index 40c502f..8b9bbba 100644
--- a/src/common/types.h
+++ b/src/common/types.h
@@ -22,7 +22,7 @@
* Coordinates have their origin at the upper left; x grows right and y grows down.
* Scale is an integer ratio with YASL_PRIVATE_SCALE_UNIT (120) representing 1x.
* See the application guide for the display-wide dispatch/poll/flush cycle
- * and backend limits. Legacy surface polling is an input-only filtered adapter.
+ * and backend limits.
*/
#ifndef YASL_PRIVATE_H
#define YASL_PRIVATE_H
@@ -145,7 +145,7 @@ enum yasl_private_surface_state : uint32_t {
YASL_PRIVATE_STATE_TILED = 1 << 5, /**< At least one edge is tiled; currently reported by Wayland. */
};
-/** System cursor shapes. HIDDEN preserves pointer input; NONE is its compatibility alias. */
+/** System cursor shapes. HIDDEN preserves pointer input. */
enum yasl_private_cursor {
YASL_PRIVATE_CURSOR_ARROW, /**< Default arrow. */
YASL_PRIVATE_CURSOR_TEXT, /**< Text insertion. */
@@ -157,7 +157,6 @@ enum yasl_private_cursor {
YASL_PRIVATE_CURSOR_RESIZE_EW, /**< Horizontal resize. */
YASL_PRIVATE_CURSOR_RESIZE_NS, /**< Vertical resize. */
YASL_PRIVATE_CURSOR_HIDDEN, /**< Hidden system cursor; pointer input continues. */
- YASL_PRIVATE_CURSOR_NONE = YASL_PRIVATE_CURSOR_HIDDEN, /**< Compatibility alias for HIDDEN. */
};
/** Valid interactive resize edges; combinations are restricted to the named values. */
@@ -328,7 +327,7 @@ struct yasl_private_pointer_pen {
enum yasl_private_event_type {
YASL_PRIVATE_EVENT_NONE = 0,
- /* Input: produced by backends, returned by yasl_private_surface_poll_event(). */
+ /* Input: produced by backends and consumed from the display FIFO. */
YASL_PRIVATE_EVENT_KEY, /**< .key */
YASL_PRIVATE_EVENT_TEXT, /**< .text — committed UTF-8; insert this, not key codepoints. */
YASL_PRIVATE_EVENT_POINTER_DOWN, /**< .pointer — button/tip pressed; button valid. */
@@ -337,12 +336,11 @@ enum yasl_private_event_type {
YASL_PRIVATE_EVENT_POINTER_SCROLL, /**< .pointer — scroll valid. */
YASL_PRIVATE_EVENT_POINTER_LEAVE, /**< .pointer — last known pos/device; cancel hover state. */
YASL_PRIVATE_EVENT_FOCUS, /**< .focus — keyboard focus changed; cancel held state on loss. */
- YASL_PRIVATE_EVENT_PASTE, /**< .text — UTF-8 from yasl_private_display_paste(). */
+ YASL_PRIVATE_EVENT_PASTE, /**< .paste — clipboard request completion. */
YASL_PRIVATE_EVENT_DROP, /**< .text — dropped text/uri-list: CRLF-separated file URLs, not paths. */
YASL_PRIVATE_EVENT_INPUT_RESET, /**< No payload. Input stream interrupted; clear held keys, buttons, strokes, IME. */
- /* Window and application: part of the display FIFO, as well as runner delivery.
- * Legacy window callbacks also receive matching native notifications. */
+ /* Window and application notifications in the display FIFO. */
YASL_PRIVATE_EVENT_WINDOW_RESIZE, /**< .resize — size and/or scale changed; reallocate and redraw. */
YASL_PRIVATE_EVENT_WINDOW_CLOSE, /**< No payload. User asked to close the window. */
YASL_PRIVATE_EVENT_USER, /**< .user — posted application message. */
@@ -414,7 +412,7 @@ struct yasl_private_pointer_event {
/** Borrowed NUL-terminated UTF-8, shared by TEXT, PASTE and DROP. */
struct yasl_private_text_event {
- /** Borrowed NUL-terminated bytes; see yasl_private_surface_poll_event() for lifetime. */
+ /** Borrowed NUL-terminated bytes; valid until the next successful display poll or display close. */
const char *data;
/** Length in bytes excluding the terminating NUL. */
size_t len;
@@ -427,11 +425,11 @@ enum yasl_private_transfer_status {
YASL_PRIVATE_TRANSFER_FAILED, /**< Transfer or decoding failed. */
};
-/** Clipboard completion; data/len alias the legacy text payload. */
+/** Clipboard completion; data/len share the text payload layout. */
struct yasl_private_paste_event {
const char *data; /**< Borrowed NUL-terminated UTF-8; empty on failure. */
size_t len; /**< Byte length excluding NUL. */
- uint64_t request_id; /**< Zero for a legacy paste request. */
+ uint64_t request_id; /**< Nonzero clipboard request identity. */
enum yasl_private_transfer_status status; /**< Completion outcome. */
};
@@ -511,7 +509,7 @@ struct yasl_private_event {
struct { const char *data; size_t len; uint64_t revision, generation; size_t begin, end; } text_edit;
struct yasl_private_key_event key; /**< KEY */
struct yasl_private_pointer_event pointer; /**< POINTER_* */
- struct yasl_private_text_event text; /**< TEXT, legacy PASTE, DROP */
+ struct yasl_private_text_event text; /**< TEXT, DROP */
struct yasl_private_paste_event paste; /**< PASTE */
struct yasl_private_composition_event composition; /**< COMPOSITION */
struct yasl_private_state_event state; /**< WINDOW_STATE */
@@ -534,35 +532,9 @@ struct yasl_private_event {
*/
/* Callbacks */
-/** Optional display notifications. NULL callback members are ignored. */
-struct yasl_private_display_cbs {
- /** Application quit request; arrange orderly shutdown after dispatch returns. */
- void (*quit)(void *ud);
- /** Application reopen/activation request, currently Cocoa. */
- void (*reopen)(void *ud);
- /** Display connection lost; arrange cleanup after dispatch returns. */
- void (*lost)(void *ud);
-};
-
-/** Optional window/popup notifications, copied from yasl_private_window_spec.cbs or by
-yasl_private_surface_set_callbacks().
-Callbacks may destroy their surface. They must then return without further use
-of the surface or draw target. NULL members are ignored. */
+/** Internal CPU presenter callback, copied on installation. */
struct yasl_private_window_cbs {
- /** Initialize the entire target and optionally present. Requested through schedule_redraw/flush. */
void (*draw)(struct yasl_surface *s, struct yasl_private_frame *frame, void *ud);
- /** Configured size/scale changed; reallocate application content and request a redraw. */
- void (*configure)(struct yasl_surface *s, struct yasl_private_geometry geometry, void *ud);
- /** Window/popup close request; application is responsible for destruction. */
- void (*close)(struct yasl_surface *s, void *ud);
- /** Reported yasl_private_surface_state bitmask changed; matches yasl_private_surface_state(s). */
- void (*state)(struct yasl_surface *s, uint32_t state, void *ud);
- /** YASL surface-drag target hover, leave, or drop; pos is in device pixels. */
- void (*drag)(struct yasl_surface *s, enum yasl_private_drag_event ev,
- struct yasl_private_vector2i pos, void *ud);
- /** External data-drag hover or leave; pos is in device pixels. */
- void (*drop)(struct yasl_surface *s, enum yasl_private_drop_event ev,
- struct yasl_private_vector2i pos, void *ud);
};
/* Display Lifecycle */
@@ -578,10 +550,6 @@ enum yasl_private_backend {
struct yasl_private_display_spec {
/** Copied application identifier, conventionally a reverse-domain UTF-8 string; NULL uses backend defaults. */
const char *app_id;
- /** Copied optional display callbacks; NULL disables them. */
- const struct yasl_private_display_cbs *cbs;
- /** Borrowed display callback userdata. */
- void *ud;
/** Zero/AUTO chooses native backend; explicit choices never fall back. */
enum yasl_private_backend backend;
@@ -661,26 +629,6 @@ int yasl_private_display_modifiers(const struct yasl_private_display *d);
* rather than on every click.
*/
int yasl_private_display_double_click_ms(const struct yasl_private_display *d);
-/* Unsupported/invalid selections are no-ops, never clipboard aliases. */
-/**
- * Offer a copy of a NUL-terminated UTF-8 string as a selection.
- * @param d Display, or NULL for no action.
- * @param sel YASL_PRIVATE_CLIPBOARD or YASL_PRIVATE_PRIMARY.
- * @param text Text copied during this call; NULL does nothing.
- * Unsupported selections do nothing. The void return does not confirm that the
- * system accepted the offer; Wayland may require a recent input serial.
- */
-void yasl_private_display_copy(struct yasl_private_display *d, enum yasl_private_selection sel, const char *text);
-/**
- * Request text delivery to a particular surface.
- * @param d Display that owns target.
- * @param sel YASL_PRIVATE_CLIPBOARD or YASL_PRIVATE_PRIMARY.
- * @param target Destination surface; NULL or a surface on another display does nothing.
- * Results arrive as YASL_PRIVATE_EVENT_PASTE, possibly during a later dispatch. No result
- * is promised for unavailable data or a failed transfer. Destroying target cancels
- * delivery. Unsupported selections do nothing.
- */
-void yasl_private_display_paste(struct yasl_private_display *d, enum yasl_private_selection sel, struct yasl_surface *target);
/* A successful drag invokes the copied listener's non-NULL end once, including
* cancel and display close. Failed starts do not invoke it. */
@@ -714,19 +662,16 @@ struct yasl_private_window_spec {
/** Copied UTF-8 title; NULL uses backend defaults. */
const char *title;
/** Requested logical-pixel width and height; both must be positive. */
- union {
- struct yasl_private_vector2i size_logical; /**< Requested logical-pixel extent. */
- struct yasl_private_vector2i size; /**< Migration alias for size_logical. */
- };
+ struct yasl_private_vector2i size;
/** Request initial fullscreen; actual state is reported asynchronously. */
bool fullscreen;
/** Permit unpaced presentation where supported; a hint, not a guarantee. */
bool tearing;
/** Copied optional window callbacks; NULL disables them. */
const struct yasl_private_window_cbs *cbs;
- /** Borrowed window callback userdata; ignored by the runner. */
+ /** Borrowed CPU presenter userdata. */
void *ud;
- /** Borrowed application data, independent of callbacks and available in either loop style. */
+ /** Borrowed application data, independent of the CPU presenter. */
void *userdata;
};
@@ -738,13 +683,10 @@ Dimensions must be positive, at most 32767, and fit an INT32_MAX-byte buffer;
backends may impose further limits after scaling or resolving placement. */
struct yasl_private_popup_spec {
unsigned anchor_edges, gravity, constraints;
- bool positioner_explicit;
/** Full popup framebuffer extent in device pixels, including transparent margins. */
struct yasl_private_vector2i size;
/** Rectangle in parent framebuffer coordinates, in device pixels. */
struct yasl_private_rect2i anchor;
- /** true prefers right of anchor; false prefers below. Placement may flip/slide. */
- bool beside;
/** Top-left content offset within the popup, in device pixels. */
struct yasl_private_vector2i content_offset;
/** Content extent; zero per axis extends to the corresponding size edge. */
@@ -761,10 +703,8 @@ struct yasl_private_popup_spec {
* size may differ from the request. The callback table in spec->cbs is copied;
* spec->ud stays borrowed until callbacks are replaced or the surface is destroyed.
* This window's callbacks cannot run before creation returns. Use
- * yasl_private_surface_geometry() for initial geometry; an initial configure callback
- * is not guaranteed. Schedule an initial redraw after setting up application state.
- * On a display owned by yasl_private_run(), the runner installs its own callbacks instead;
- * use yasl_private_app_desc.event and yasl_private_app_desc.frame for application notifications.
+ * yasl_private_surface_geometry() for initial geometry. Schedule an initial redraw
+ * after setting up the CPU presenter. Lifecycle notifications arrive in the display FIFO.
*/
struct yasl_surface *yasl_private_surface_create_toplevel(struct yasl_private_display *d,
const struct yasl_private_window_spec *spec);
@@ -809,7 +749,7 @@ struct yasl_private_display *yasl_private_surface_display(const struct yasl_surf
* @param s Surface.
* @param cbs Table copied by value; NULL removes all callbacks. NULL members are ignored.
* @param ud Borrowed userdata passed to the installed callbacks.
- * @return true if replaced; false with EINVAL for NULL, EBUSY on a runner-owned surface.
+ * @return true if replaced; false with EINVAL for NULL.
* This call only replaces callbacks; it does not invoke them.
* Use yasl_private_surface_geometry() to read current geometry; do not rely on receiving
* an initial configure callback when registering.
@@ -849,18 +789,6 @@ void yasl_private_surface_schedule_redraw(struct yasl_surface *s);
bool yasl_private_surface_present(struct yasl_surface *s, const struct yasl_private_framebuffer *fb,
const struct yasl_private_damage_list *damage);
/**
- * Migration adapter: consume one input event for a surface from the display FIFO.
- * Popup input can belong to the root queue; inspect ev->surface. Returns false
- * for empty/invalid arguments, leaving ev unchanged. Strings remain borrowed
- * until the next successful display or surface poll, or display close. Pending
- * recipient events are canceled on destruction. Prefer yasl_private_display_poll_event()
- * to receive window, composition, and display events as well as input. This
- * input-only adapter discards pending non-input events across the display
- * (legacy callbacks already delivered lifecycle changes). Do not mix
- * the two polling styles in one application. Use the display thread.
- */
-bool yasl_private_surface_poll_event(struct yasl_surface *s, struct yasl_private_event *ev);
-/**
* Decode the next local file path from a YASL_PRIVATE_EVENT_DROP payload.
* @param cursor Required in/out position in the NUL-terminated list. Start it
* at event.text.data; a NULL *cursor returns zero.
@@ -958,7 +886,7 @@ void yasl_private_surface_request_frame(struct yasl_surface *s);
bool yasl_private_surface_set_pacing(struct yasl_surface *s, yasl_private_pacing_mode mode);
/** Request a positive logical-pixel size. Success means issued, not configured. */
-bool yasl_private_surface_set_size(struct yasl_surface *s, struct yasl_private_vector2i size_logical);
+bool yasl_private_surface_set_size(struct yasl_surface *s, struct yasl_private_vector2i size);
/** Request fullscreen state; returns acceptance, not confirmation. */
bool yasl_private_surface_set_fullscreen(struct yasl_surface *s, bool enabled);
/** Request maximized state; returns acceptance, not confirmation. */
diff --git a/src/platform/cocoa/api.h b/src/platform/cocoa/api.h
index 4a22410..006954c 100644
--- a/src/platform/cocoa/api.h
+++ b/src/platform/cocoa/api.h
@@ -12,8 +12,6 @@ uint32_t cocoa_display_caps(const struct cocoa_display *d);
int cocoa_display_dispatch_timeout(struct cocoa_display *d, int timeout_ms);
void cocoa_display_flush(struct cocoa_display *d);
int cocoa_display_modifiers(const struct cocoa_display *d);
-void cocoa_display_copy(struct cocoa_display *d, enum yasl_private_selection sel, const char *text);
-void cocoa_display_paste(struct cocoa_display *d, enum yasl_private_selection sel, struct cocoa_surface *target);
bool cocoa_display_drag_start(struct cocoa_display *d, struct cocoa_surface *origin, const struct yasl_private_drag_image *image, const struct yasl_private_drag_listener *l, void *ud);
struct cocoa_surface *cocoa_surface_create_toplevel(struct cocoa_display *d,
const struct yasl_private_window_spec *spec, void *graphics_device);
@@ -24,7 +22,6 @@ void cocoa_surface_set_callbacks(struct cocoa_surface *s, const struct yasl_priv
void cocoa_surface_set_title(struct cocoa_surface *s, const char *title);
void cocoa_surface_schedule_redraw(struct cocoa_surface *s);
bool cocoa_surface_present(struct cocoa_surface *s, const struct yasl_private_framebuffer *fb, const struct yasl_private_damage_list *damage);
-bool cocoa_surface_poll_event(struct cocoa_surface *s, struct yasl_private_event *ev);
struct yasl_private_geometry cocoa_surface_geometry(const struct cocoa_surface *s);
struct yasl_private_timing cocoa_surface_timing(const struct cocoa_surface *s);
void cocoa_surface_set_cursor(struct cocoa_surface *s, enum yasl_private_cursor cursor);
diff --git a/src/platform/cocoa/window.m b/src/platform/cocoa/window.m
index 7be78fd..4b97ce1 100644
--- a/src/platform/cocoa/window.m
+++ b/src/platform/cocoa/window.m
@@ -1,7 +1,6 @@
#import <AppKit/AppKit.h>
#import <Metal/Metal.h>
#import <QuartzCore/QuartzCore.h>
-#import <OpenGL/OpenGL.h>
#include "platform/cocoa/api.h"
#include "common/backend.h"
@@ -20,7 +19,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <dlfcn.h>
#include <sys/event.h>
#include <unistd.h>
#include <objc/message.h>
@@ -68,7 +66,6 @@ struct cocoa_surface {
YaslWindowController *controller;
YaslView *view;
CAMetalLayer *layer;
- NSOpenGLContext *gl_context;
id<MTLCommandQueue> software_queue;
id<MTLBuffer> software_buffer;
NSUInteger software_buffer_capacity;
@@ -130,8 +127,6 @@ struct cocoa_display {
struct cocoa_surface **windows;
int count;
int capacity;
- const struct yasl_private_display_cbs *cbs;
- void *ud;
char *app_id;
struct yasl_private_loop *loop;
id key_up_monitor;
@@ -275,11 +270,7 @@ static void sync_size(struct cocoa_surface *w, bool force)
w->layer.contentsScale = scale;
w->layer.drawableSize = CGSizeMake(size.x, size.y);
}
- if (w->gl_context)
- [w->gl_context update];
- /* Common configure notification already requests a frame before invoking
- * the legacy callback. Finish local bookkeeping before that callback can
- * destroy this surface. */
+ /* Finish local bookkeeping before publishing geometry and requesting a frame. */
yasl_private_clock_note_resize(&w->clock, yasl_private_loop_now_ns() - start);
yasl_private_surface_notify_configure(&w->base, (struct yasl_private_geometry){
.size = size, .scale_120 = scale_120,
@@ -1642,10 +1633,6 @@ struct cocoa_display *cocoa_display_open(struct yasl_private_loop *loop, const s
}
darwin_ctx.base.loop = darwin_ctx.loop;
if (spec) {
- darwin_ctx.base.callbacks = spec->cbs ? *spec->cbs : (struct yasl_private_display_cbs){0};
- darwin_ctx.cbs = &darwin_ctx.base.callbacks;
- darwin_ctx.ud = spec->ud;
- darwin_ctx.base.callback_ud = spec->ud;
if (spec->app_id) darwin_ctx.app_id = strdup(spec->app_id);
darwin_ctx.base.app_id = darwin_ctx.app_id;
}
@@ -1789,7 +1776,6 @@ struct cocoa_surface *cocoa_surface_create_toplevel(struct cocoa_display *d,
static void surface_free(struct cocoa_surface *w)
{
[w->link release];
- [w->gl_context release];
[w->software_buffer release];
[w->software_queue release];
[w->view release];
@@ -1987,11 +1973,6 @@ static NSPasteboard *pasteboard_for_selection(enum yasl_private_selection sel)
static bool cocoa_display_copy_text(struct cocoa_display *d, enum yasl_private_selection sel, const char *text);
-void cocoa_display_copy(struct cocoa_display *d, enum yasl_private_selection sel, const char *text)
-{
- (void)cocoa_display_copy_text(d, sel, text);
-}
-
static bool cocoa_display_copy_text(struct cocoa_display *d, enum yasl_private_selection sel, const char *text)
{
assert([NSThread isMainThread]);
@@ -2030,11 +2011,6 @@ static bool cocoa_display_request_paste(struct cocoa_display *d, enum yasl_priva
return true;
}
-void cocoa_display_paste(struct cocoa_display *d, enum yasl_private_selection sel, struct cocoa_surface *target)
-{
- (void)cocoa_display_request_paste(d, sel, target, 0);
-}
-
int cocoa_display_modifiers(const struct cocoa_display *d)
{
(void)d;
@@ -2053,8 +2029,8 @@ static bool popup_spec_valid(const struct cocoa_surface *parent,
const struct yasl_private_popup_spec *spec)
{
if (!parent || !spec) return false;
- if (spec->positioner_explicit && (spec->anchor_edges > 8 || spec->gravity > 8 ||
- (spec->constraints & ~63u))) return false;
+ if (spec->anchor_edges > 8 || spec->gravity > 8 ||
+ (spec->constraints & ~63u)) return false;
int parent_cx = parent->is_popup ? parent->content_offset.x : 0;
int parent_cy = parent->is_popup ? parent->content_offset.y : 0;
int64_t x = (int64_t)spec->anchor.x - parent_cx;
@@ -2069,70 +2045,6 @@ static bool popup_spec_valid(const struct cocoa_surface *parent,
(int64_t)spec->content_offset.y + spec->content_size.y <= spec->size.y;
}
-static NSRect popup_calc_frame_legacy(struct cocoa_surface *parent, const struct yasl_private_popup_spec *spec)
-{
- CGFloat scale = parent->window ? parent->window.backingScaleFactor : 1.0;
- if (scale < 1.0) scale = 1.0;
-
- CGFloat pcx = (parent->is_popup ? parent->content_offset.x : 0) / scale;
- CGFloat pcy = (parent->is_popup ? parent->content_offset.y : 0) / scale;
-
- CGFloat pw = spec->size.x / scale;
- CGFloat ph = spec->size.y / scale;
- CGFloat ax = (spec->anchor.x / scale) - pcx;
- CGFloat ay = (spec->anchor.y / scale) - pcy;
- CGFloat aw = spec->anchor.width / scale;
- CGFloat ah = spec->anchor.height / scale;
- CGFloat ox = spec->content_offset.x / scale;
- CGFloat oy = spec->content_offset.y / scale;
-
- CGFloat top_left_x = spec->beside ? (ax + aw - ox) : (ax - ox);
- CGFloat top_left_y = spec->beside ? (ay - oy) : (ay + ah - oy);
-
- CGFloat view_h = parent->view.bounds.size.height;
- CGFloat view_y = view_h - top_left_y;
-
- NSPoint ptInView = NSMakePoint(top_left_x, view_y);
- NSPoint ptInWin = [parent->view convertPoint:ptInView toView:nil];
- NSPoint screen_tl = [parent->window convertPointToScreen:ptInWin];
-
- NSRect frame = NSMakeRect(screen_tl.x, screen_tl.y - ph, pw, ph);
-
- NSScreen *screen = parent->window.screen ?: [NSScreen mainScreen];
- if (screen) {
- NSRect visible = screen.visibleFrame;
- if (NSMaxX(frame) > NSMaxX(visible)) {
- if (spec->beside) {
- CGFloat flip_tl_x = ax - pw + ox;
- NSPoint flip_v = NSMakePoint(flip_tl_x, view_y);
- NSPoint flip_w = [parent->view convertPoint:flip_v toView:nil];
- NSPoint flip_s = [parent->window convertPointToScreen:flip_w];
- frame.origin.x = flip_s.x;
- }
- if (NSMaxX(frame) > NSMaxX(visible))
- frame.origin.x = NSMaxX(visible) - frame.size.width;
- }
- if (NSMinX(frame) < NSMinX(visible))
- frame.origin.x = NSMinX(visible);
-
- if (NSMinY(frame) < NSMinY(visible)) {
- if (!spec->beside) {
- CGFloat flip_top_y = ay - ph + oy;
- CGFloat flip_vy = view_h - flip_top_y;
- NSPoint flip_v = NSMakePoint(top_left_x, flip_vy);
- NSPoint flip_w = [parent->view convertPoint:flip_v toView:nil];
- NSPoint flip_s = [parent->window convertPointToScreen:flip_w];
- frame.origin.y = flip_s.y - ph;
- }
- if (NSMinY(frame) < NSMinY(visible))
- frame.origin.y = NSMinY(visible);
- }
- if (NSMaxY(frame) > NSMaxY(visible))
- frame.origin.y = NSMaxY(visible) - frame.size.height;
- }
- return frame;
-}
-
enum {
POPUP_EDGE_TOP = 1,
POPUP_EDGE_BOTTOM = 2,
@@ -2227,8 +2139,6 @@ static NSRect popup_frame_explicit(struct cocoa_surface *parent,
static NSRect popup_calc_frame(struct cocoa_surface *parent, const struct yasl_private_popup_spec *spec)
{
- if (!spec->positioner_explicit)
- return popup_calc_frame_legacy(parent, spec);
NSRect frame = popup_frame_explicit(parent, spec, spec->anchor_edges, spec->gravity);
NSScreen *screen = parent->window.screen ?: [NSScreen mainScreen];
@@ -2505,22 +2415,6 @@ void cocoa_surface_set_callbacks(struct cocoa_surface *w,
w->ud = ud;
}
-bool cocoa_surface_poll_event(struct cocoa_surface *w, struct yasl_private_event *ev)
-{
- if (!w || !ev || !input_queue_pop(&w->input, ev))
- return false;
- if (ev->type == YASL_PRIVATE_EVENT_INPUT_RESET) {
- w->buttons = 0;
- w->tablet_down = false;
- w->mods = 0;
- if (w->preedit) {
- free(w->preedit);
- w->preedit = NULL;
- }
- }
- return true;
-}
-
struct yasl_private_timing cocoa_surface_timing(const struct cocoa_surface *w)
{
struct yasl_private_timing timing = {0};
@@ -2572,16 +2466,6 @@ static int impl_display_modifiers(const struct yasl_private_display *d)
return cocoa_display_modifiers((const struct cocoa_display *)d);
}
-static void impl_display_copy(struct yasl_private_display *d, enum yasl_private_selection sel, const char *text)
-{
- cocoa_display_copy((struct cocoa_display *)d, sel, text);
-}
-
-static void impl_display_paste(struct yasl_private_display *d, enum yasl_private_selection sel, struct yasl_surface *target)
-{
- cocoa_display_paste((struct cocoa_display *)d, sel, (struct cocoa_surface *)target);
-}
-
static bool impl_display_copy_text(struct yasl_private_display *d, enum yasl_private_selection sel, const char *text)
{
return cocoa_display_copy_text((struct cocoa_display *)d, sel, text);
@@ -2725,116 +2609,6 @@ static bool impl_surface_place_under_pointer(struct yasl_surface *s, struct yasl
return cocoa_surface_place_under_pointer((struct cocoa_surface *)s, at);
}
-static struct yasl_surface *impl_surface_create_gl(struct yasl_private_display *display,
- const struct yasl_private_window_spec *spec, const int *attrs, struct yasl_surface *share)
-{
- struct yasl_private_gl_options options;
- if (!spec || !yasl_private_gl_parse_options(attrs, &options) ||
- options.api != YASL_PRIVATE_GL_OPENGL || options.debug || (share &&
- (share->display != display || share->presenter != YASL_PRIVATE_PRESENTER_GL)))
- return NULL;
- int profile = options.profile;
- if (profile == YASL_PRIVATE_GL_ANY)
- profile = options.major >= 3 ? YASL_PRIVATE_GL_CORE : YASL_PRIVATE_GL_COMPATIBILITY;
- if (options.forward_compat && profile != YASL_PRIVATE_GL_CORE)
- return NULL;
- if ((profile == YASL_PRIVATE_GL_CORE &&
- (options.major != 3 || options.minor != 2)) ||
- (profile == YASL_PRIVATE_GL_COMPATIBILITY &&
- (options.major > 2 || (options.major == 2 && options.minor > 1))))
- return NULL;
-
- struct yasl_private_window_spec gl_spec = *spec;
- gl_spec.external_gpu = true;
- struct cocoa_surface *w = cocoa_surface_create_toplevel((struct cocoa_display *)display, &gl_spec, NULL);
- if (!w) return NULL;
-
- NSOpenGLPixelFormatAttribute pixel_attrs[32];
- NSUInteger n = 0;
- pixel_attrs[n++] = NSOpenGLPFAAccelerated;
- pixel_attrs[n++] = NSOpenGLPFADoubleBuffer;
- pixel_attrs[n++] = NSOpenGLPFAColorSize;
- pixel_attrs[n++] = options.red_bits + options.green_bits + options.blue_bits + options.alpha_bits;
- pixel_attrs[n++] = NSOpenGLPFAAlphaSize;
- pixel_attrs[n++] = options.alpha_bits;
- pixel_attrs[n++] = NSOpenGLPFADepthSize;
- pixel_attrs[n++] = options.depth_bits;
- pixel_attrs[n++] = NSOpenGLPFAStencilSize;
- pixel_attrs[n++] = options.stencil_bits;
- if (options.samples > 0) {
- pixel_attrs[n++] = NSOpenGLPFASampleBuffers;
- pixel_attrs[n++] = 1;
- pixel_attrs[n++] = NSOpenGLPFASamples;
- pixel_attrs[n++] = options.samples;
- }
- if (options.srgb) pixel_attrs[n++] = NSOpenGLPFASRGB;
- if (profile == YASL_PRIVATE_GL_CORE) {
- pixel_attrs[n++] = NSOpenGLPFAOpenGLProfile;
- pixel_attrs[n++] = NSOpenGLProfileVersion3_2Core;
- } else if (profile == YASL_PRIVATE_GL_COMPATIBILITY) {
- pixel_attrs[n++] = NSOpenGLPFAOpenGLProfile;
- pixel_attrs[n++] = NSOpenGLProfileVersionLegacy;
- }
- pixel_attrs[n++] = 0;
-
- NSOpenGLPixelFormat *format = [[NSOpenGLPixelFormat alloc] initWithAttributes:pixel_attrs];
- NSOpenGLContext *shared = share ? ((struct cocoa_surface *)share)->gl_context : nil;
- if (format)
- w->gl_context = [[NSOpenGLContext alloc] initWithFormat:format shareContext:shared];
- [format release];
- if (!w->gl_context) {
- cocoa_surface_destroy(w);
- reap_dead((struct cocoa_display *)display);
- return NULL;
- }
- [w->view setLayer:[CALayer layer]];
- w->layer = nil;
- [w->gl_context setView:w->view];
- w->base.presenter = YASL_PRIVATE_PRESENTER_GL;
- return &w->base;
-}
-
-static bool impl_gl_make_current(struct yasl_private_display *display, struct yasl_surface *surface)
-{
- (void)display;
- if (!surface) {
- [NSOpenGLContext clearCurrentContext];
- return true;
- }
- struct cocoa_surface *w = (struct cocoa_surface *)surface;
- if (w->base.presenter != YASL_PRIVATE_PRESENTER_GL || !w->gl_context || w->closed)
- return false;
- [w->gl_context makeCurrentContext];
- return [NSOpenGLContext currentContext] == w->gl_context;
-}
-
-static yasl_private_gl_proc impl_gl_get_proc_address(struct yasl_private_display *display, const char *name)
-{
- (void)display;
- return name ? (yasl_private_gl_proc)dlsym(RTLD_DEFAULT, name) : NULL;
-}
-
-static bool impl_gl_swap_interval(struct yasl_private_display *display, struct yasl_surface *surface, int interval)
-{
- (void)display;
- struct cocoa_surface *w = (struct cocoa_surface *)surface;
- if (!w || w->base.presenter != YASL_PRIVATE_PRESENTER_GL || !w->gl_context || w->closed)
- return false;
- [w->gl_context setValues:&interval forParameter:NSOpenGLCPSwapInterval];
- return true;
-}
-
-static bool impl_gl_swap_buffers(struct yasl_private_display *display, struct yasl_surface *surface)
-{
- (void)display;
- struct cocoa_surface *w = (struct cocoa_surface *)surface;
- if (!w || w->base.presenter != YASL_PRIVATE_PRESENTER_GL || !w->gl_context || w->closed)
- return false;
- [w->gl_context flushBuffer];
- yasl_private_clock_presented(&w->clock, yasl_private_loop_now_ns(), false);
- return true;
-}
-
static void *impl_surface_get_metal_layer(struct yasl_surface *surface)
{
struct cocoa_surface *w = (struct cocoa_surface *)surface;
@@ -2899,11 +2673,6 @@ static bool impl_surface_get_native_frame(struct yasl_surface *s,
const struct yasl_private_backend_ops yasl_private_cocoa_backend = {
.type = YASL_PRIVATE_BACKEND_COCOA,
- .surface_create_gl = impl_surface_create_gl,
- .gl_make_current = impl_gl_make_current,
- .gl_get_proc_address = impl_gl_get_proc_address,
- .gl_swap_interval = impl_gl_swap_interval,
- .gl_swap_buffers = impl_gl_swap_buffers,
.surface_get_metal_layer = impl_surface_get_metal_layer,
.surface_update_text_input = impl_surface_update_text_input,
.display_open = impl_display_open,
@@ -2913,8 +2682,6 @@ const struct yasl_private_backend_ops yasl_private_cocoa_backend = {
.display_flush = impl_display_flush,
.display_modifiers = impl_display_modifiers,
.display_double_click_ms = impl_display_double_click_ms,
- .display_copy = impl_display_copy,
- .display_paste = impl_display_paste,
.display_copy_text = impl_display_copy_text,
.display_request_paste = impl_display_request_paste,
.display_drag_start = impl_display_drag_start,
diff --git a/src/platform/wayland/api.h b/src/platform/wayland/api.h
index 9670af1..69f61b1 100644
--- a/src/platform/wayland/api.h
+++ b/src/platform/wayland/api.h
@@ -12,8 +12,6 @@ uint32_t wayland_display_caps(const struct wayland_display *d);
int wayland_display_dispatch_timeout(struct wayland_display *d, int timeout_ms);
void wayland_display_flush(struct wayland_display *d);
int wayland_display_modifiers(const struct wayland_display *d);
-void wayland_display_copy(struct wayland_display *d, enum yasl_private_selection sel, const char *text);
-void wayland_display_paste(struct wayland_display *d, enum yasl_private_selection sel, struct wayland_surface *target);
bool wayland_display_copy_text(struct wayland_display *d, enum yasl_private_selection sel, const char *text);
bool wayland_display_request_paste(struct wayland_display *d, enum yasl_private_selection sel,
struct wayland_surface *target, uint64_t request_id);
@@ -28,7 +26,6 @@ void wayland_surface_set_callbacks(struct wayland_surface *s, const struct yasl_
void wayland_surface_set_title(struct wayland_surface *s, const char *title);
void wayland_surface_schedule_redraw(struct wayland_surface *s);
bool wayland_surface_present(struct wayland_surface *s, const struct yasl_private_framebuffer *fb, const struct yasl_private_damage_list *damage);
-bool wayland_surface_poll_event(struct wayland_surface *s, struct yasl_private_event *ev);
struct yasl_private_geometry wayland_surface_geometry(const struct wayland_surface *s);
struct yasl_private_timing wayland_surface_timing(const struct wayland_surface *s);
void wayland_surface_set_cursor(struct wayland_surface *s, enum yasl_private_cursor cursor);
diff --git a/src/platform/wayland/backend.c b/src/platform/wayland/backend.c
index b3337cc..7ac1c65 100644
--- a/src/platform/wayland/backend.c
+++ b/src/platform/wayland/backend.c
@@ -40,11 +40,6 @@ static int impl_display_double_click_ms(const struct yasl_private_display *d)
return portal_double_click_ms();
}
-static void impl_display_copy(struct yasl_private_display *d, enum yasl_private_selection sel, const char *text)
-{
- wayland_display_copy((struct wayland_display *)d, sel, text);
-}
-
static bool impl_display_copy_text(struct yasl_private_display *d, enum yasl_private_selection sel,
const char *text)
{
@@ -53,11 +48,6 @@ static bool impl_display_copy_text(struct yasl_private_display *d, enum yasl_pri
return ok;
}
-static void impl_display_paste(struct yasl_private_display *d, enum yasl_private_selection sel, struct yasl_surface *target)
-{
- wayland_display_paste((struct wayland_display *)d, sel, (struct wayland_surface *)target);
-}
-
static bool impl_display_request_paste(struct yasl_private_display *d, enum yasl_private_selection sel,
struct yasl_surface *target, uint64_t request_id)
{
@@ -348,11 +338,6 @@ static bool impl_surface_present(struct yasl_surface *s, const struct yasl_priva
return wayland_surface_present((struct wayland_surface *)s, fb, damage);
}
-static bool impl_surface_poll_event(struct yasl_surface *s, struct yasl_private_event *ev)
-{
- return wayland_surface_poll_event((struct wayland_surface *)s, ev);
-}
-
static struct yasl_private_geometry impl_surface_geometry(const struct yasl_surface *s)
{
return wayland_surface_geometry((const struct wayland_surface *)s);
@@ -449,11 +434,6 @@ static void *impl_surface_get_native_handle(struct yasl_surface *s)
const struct yasl_private_backend_ops yasl_private_wayland_backend = {
#if YASL_HAS_EGL
- .surface_create_gl = impl_surface_create_gl,
- .gl_make_current = impl_gl_make_current,
- .gl_get_proc_address = impl_gl_get_proc_address,
- .gl_swap_interval = impl_gl_swap_interval,
- .gl_swap_buffers = impl_gl_swap_buffers,
#endif
.surface_update_text_input = impl_surface_update_text_input,
.type = YASL_PRIVATE_BACKEND_WAYLAND,
@@ -464,8 +444,6 @@ const struct yasl_private_backend_ops yasl_private_wayland_backend = {
.display_flush = impl_display_flush,
.display_modifiers = impl_display_modifiers,
.display_double_click_ms = impl_display_double_click_ms,
- .display_copy = impl_display_copy,
- .display_paste = impl_display_paste,
.display_copy_text = impl_display_copy_text,
.display_request_paste = impl_display_request_paste,
.display_drag_start = impl_display_drag_start,
@@ -484,7 +462,6 @@ const struct yasl_private_backend_ops yasl_private_wayland_backend = {
.surface_set_title = impl_surface_set_title,
.surface_schedule_redraw = impl_surface_schedule_redraw,
.surface_present = impl_surface_present,
- .surface_poll_event = impl_surface_poll_event,
.surface_set_pointer_mode = impl_surface_set_pointer_mode,
.surface_geometry = impl_surface_geometry,
.surface_timing = impl_surface_timing,
diff --git a/src/platform/wayland/clipboard.c b/src/platform/wayland/clipboard.c
index cf39b6c..9a75953 100644
--- a/src/platform/wayland/clipboard.c
+++ b/src/platform/wayland/clipboard.c
@@ -600,12 +600,6 @@ bool clipboard_copy(struct clipboard *c, const char *text, uint32_t serial)
return true;
}
-void clipboard_paste(struct clipboard *c, struct wl_surface *target)
-{
- if (c && target)
- (void)clipboard_request_paste(c, YASL_PRIVATE_CLIPBOARD, target, 0);
-}
-
bool clipboard_copy_primary(struct clipboard *c, const char *text, uint32_t serial)
{
if (!c || !c->primary_device || !c->primary_manager) { errno = ENOTSUP; return false; }
@@ -627,12 +621,6 @@ bool clipboard_copy_primary(struct clipboard *c, const char *text, uint32_t seri
return true;
}
-void clipboard_paste_primary(struct clipboard *c, struct wl_surface *target)
-{
- if (c && target)
- (void)clipboard_request_paste(c, YASL_PRIVATE_PRIMARY, target, 0);
-}
-
bool clipboard_request_paste(struct clipboard *c, enum yasl_private_selection selection,
struct wl_surface *target, uint64_t request_id)
{
diff --git a/src/platform/wayland/clipboard.h b/src/platform/wayland/clipboard.h
index d03df17..7ab1719 100644
--- a/src/platform/wayland/clipboard.h
+++ b/src/platform/wayland/clipboard.h
@@ -25,12 +25,10 @@ void clipboard_destroy(struct clipboard *);
bool clipboard_set_seat(struct clipboard *, struct wl_seat *);
void clipboard_set_primary_manager(struct clipboard *, struct zwp_primary_selection_device_manager_v1 *);
bool clipboard_copy(struct clipboard *, const char *, uint32_t);
-void clipboard_paste(struct clipboard *, struct wl_surface *target);
bool clipboard_request_paste(struct clipboard *, enum yasl_private_selection,
struct wl_surface *target, uint64_t request_id);
void clipboard_forget_surface(struct clipboard *, struct wl_surface *);
bool clipboard_copy_primary(struct clipboard *, const char *, uint32_t);
-void clipboard_paste_primary(struct clipboard *, struct wl_surface *target);
typedef void (*clipboard_drag_fn)(enum yasl_private_drag_event, struct wl_surface *on,
double x, double y, void *);
diff --git a/src/platform/wayland/internal.h b/src/platform/wayland/internal.h
index 92108c1..ff1b18f 100644
--- a/src/platform/wayland/internal.h
+++ b/src/platform/wayland/internal.h
@@ -244,8 +244,6 @@ struct wayland_display {
struct wp_commit_timing_manager_v1 *commit_timing_mgr;
struct xkb_context *xkb_ctx;
struct yasl_private_loop *loop;
- const struct yasl_private_display_cbs *cbs;
- void *ud;
char *app_id;
struct xdg_toplevel_drag_manager_v1 *toplevel_drag_mgr;
struct conn_drag drag;
diff --git a/src/platform/wayland/keyboard.c b/src/platform/wayland/keyboard.c
index 6f9dec9..9637341 100644
--- a/src/platform/wayland/keyboard.c
+++ b/src/platform/wayland/keyboard.c
@@ -425,11 +425,6 @@ int wayland_display_modifiers(const struct wayland_display *c)
return c ? seat_modifiers(c->active_seat ? c->active_seat : c->seats) : 0;
}
-void wayland_display_copy(struct wayland_display *c, enum yasl_private_selection sel, const char *text)
-{
- (void)wayland_display_copy_text(c, sel, text);
-}
-
bool wayland_display_copy_text(struct wayland_display *c, enum yasl_private_selection sel,
const char *text)
{
@@ -453,21 +448,6 @@ bool wayland_display_copy_text(struct wayland_display *c, enum yasl_private_sele
return ok;
}
-void wayland_display_paste(struct wayland_display *c, enum yasl_private_selection sel, struct wayland_surface *target)
-{
- struct seat *s = c ? (c->active_seat ? c->active_seat : c->seats) : NULL;
- if (!target || target->closed || target->destroyed) return;
- if (!s || !s->clipboard) {
- yasl_private_surface_complete_paste(&target->base, 0,
- YASL_PRIVATE_TRANSFER_UNAVAILABLE, NULL, 0);
- return;
- }
- if (sel == YASL_PRIVATE_PRIMARY)
- clipboard_paste_primary(s->clipboard, target->surface);
- else
- clipboard_paste(s->clipboard, target->surface);
-}
-
bool wayland_display_request_paste(struct wayland_display *c, enum yasl_private_selection sel,
struct wayland_surface *target, uint64_t request_id)
{
@@ -485,8 +465,3 @@ bool wayland_display_request_paste(struct wayland_display *c, enum yasl_private_
if (!ok) errno = ENOMEM;
return ok;
}
-
-bool wayland_surface_poll_event(struct wayland_surface *w, struct yasl_private_event *ev)
-{
- return w && ev && input_queue_pop(&w->input, ev);
-}
diff --git a/src/platform/wayland/popup.c b/src/platform/wayland/popup.c
index c563eb4..1ae4805 100644
--- a/src/platform/wayland/popup.c
+++ b/src/platform/wayland/popup.c
@@ -27,15 +27,14 @@ static bool popup_spec_valid(const struct wayland_surface *parent,
const struct yasl_private_popup_spec *spec)
{
if (!parent || !spec) return false;
- if (spec->positioner_explicit &&
- (spec->anchor_edges > XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT ||
+ if (spec->anchor_edges > XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT ||
spec->gravity > XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT ||
(spec->constraints & ~(unsigned)(XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X |
XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y |
XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X |
XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y |
XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X |
- XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y))))
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y)))
return false;
int64_t x = (int64_t)spec->anchor.x - parent->content.x;
int64_t y = (int64_t)spec->anchor.y - parent->content.y;
@@ -121,15 +120,9 @@ static struct xdg_positioner *popup_positioner(struct wayland_surface *w,
yasl_private_scale_to_logical(at.x, scale),
yasl_private_scale_to_logical(at.y, scale),
aw > 0 ? aw : 1, ah > 0 ? ah : 1);
- uint32_t anchor = spec->positioner_explicit ? spec->anchor_edges :
- (spec->beside ? XDG_POSITIONER_ANCHOR_TOP_RIGHT : XDG_POSITIONER_ANCHOR_TOP_LEFT);
- uint32_t gravity = spec->positioner_explicit ? spec->gravity :
- XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT;
- uint32_t constraints = spec->positioner_explicit ? spec->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;
+ uint32_t anchor = spec->anchor_edges;
+ uint32_t gravity = spec->gravity;
+ uint32_t constraints = spec->constraints;
xdg_positioner_set_anchor(pos, anchor);
xdg_positioner_set_gravity(pos, gravity);
xdg_positioner_set_constraint_adjustment(pos, constraints);
diff --git a/src/platform/wayland/surface.c b/src/platform/wayland/surface.c
index e04a594..635c905 100644
--- a/src/platform/wayland/surface.c
+++ b/src/platform/wayland/surface.c
@@ -347,9 +347,6 @@ struct wayland_display *wayland_display_open(struct yasl_private_loop *loop, con
c->base.loop = c->loop;
if (!c->loop) goto err;
if (spec) {
- c->base.callbacks = spec->cbs ? *spec->cbs : (struct yasl_private_display_cbs){0};
- c->cbs = &c->base.callbacks;
- c->ud = spec->ud;
if (spec->app_id) c->app_id = strdup(spec->app_id);
c->base.app_id = c->app_id;
}
diff --git a/src/platform/x11/window.c b/src/platform/x11/window.c
index ef13afe..43e2109 100644
--- a/src/platform/x11/window.c
+++ b/src/platform/x11/window.c
@@ -1384,8 +1384,8 @@ static bool popup_spec_valid(const struct x11_surface *parent,
const struct yasl_private_popup_spec *spec)
{
if (!parent || !spec) return false;
- if (spec->positioner_explicit && (spec->anchor_edges > 8 || spec->gravity > 8 ||
- (spec->constraints & ~63u))) return false;
+ if (spec->anchor_edges > 8 || spec->gravity > 8 ||
+ (spec->constraints & ~63u)) return false;
int parent_cx = parent->is_popup ? parent->content_offset.x : 0;
int parent_cy = parent->is_popup ? parent->content_offset.y : 0;
int64_t x = (int64_t)spec->anchor.x - parent_cx;
@@ -1494,22 +1494,10 @@ static void popup_calculate_position(struct x11_display *d,
struct yasl_private_vector2i size = spec->size;
int anchor_x, anchor_y, root_x, root_y;
- if (spec->positioner_explicit) {
- popup_anchor_point(spec, &anchor_x, &anchor_y);
- anchor_x += parent_rx - parent_cx;
- anchor_y += parent_ry - parent_cy;
- popup_position_at(spec, anchor_x, anchor_y, spec->gravity, size, &root_x, &root_y);
- } else {
- anchor_x = parent_rx + (spec->anchor.x - parent_cx);
- anchor_y = parent_ry + (spec->anchor.y - parent_cy);
- if (spec->beside) {
- root_x = anchor_x + spec->anchor.width - spec->content_offset.x;
- root_y = anchor_y - spec->content_offset.y;
- } else {
- root_x = anchor_x - spec->content_offset.x;
- root_y = anchor_y + spec->anchor.height - spec->content_offset.y;
- }
- }
+ popup_anchor_point(spec, &anchor_x, &anchor_y);
+ anchor_x += parent_rx - parent_cx;
+ anchor_y += parent_ry - parent_cy;
+ popup_position_at(spec, anchor_x, anchor_y, spec->gravity, size, &root_x, &root_y);
int mon_x = 0, mon_y = 0;
int mon_w = d->native ? DisplayWidth(d->native, d->screen) : 1920;
@@ -1535,60 +1523,44 @@ static void popup_calculate_position(struct x11_display *d,
}
#endif
- if (spec->positioner_explicit) {
- if (spec->constraints & X11_CONSTRAINT_FLIP_X) {
- int flip_x, flip_y;
- /* Reflect the selected anchor edge across the anchor rectangle center. */
- int anchor_origin_x = parent_rx - parent_cx + spec->anchor.x;
- int flipped_anchor_x = 2 * anchor_origin_x + spec->anchor.width - anchor_x;
- popup_position_at(spec, flipped_anchor_x, anchor_y, popup_flip_x(spec->gravity), size, &flip_x, &flip_y);
- if (popup_overflow(flip_x, size.x, mon_x, mon_x + mon_w) <
- popup_overflow(root_x, size.x, mon_x, mon_x + mon_w)) root_x = flip_x;
- }
- if (spec->constraints & X11_CONSTRAINT_FLIP_Y) {
- int flip_x, flip_y;
- int anchor_origin_y = parent_ry - parent_cy + spec->anchor.y;
- int flipped_anchor_y = 2 * anchor_origin_y + spec->anchor.height - anchor_y;
- popup_position_at(spec, anchor_x, flipped_anchor_y, popup_flip_y(spec->gravity), size, &flip_x, &flip_y);
- if (popup_overflow(flip_y, size.y, mon_y, mon_y + mon_h) <
- popup_overflow(root_y, size.y, mon_y, mon_y + mon_h)) root_y = flip_y;
- }
- if (spec->constraints & X11_CONSTRAINT_SLIDE_X) {
- if (root_x < mon_x) root_x = mon_x;
- if (root_x + size.x > mon_x + mon_w) root_x = mon_x + mon_w - size.x;
- }
- if (spec->constraints & X11_CONSTRAINT_SLIDE_Y) {
- if (root_y < mon_y) root_y = mon_y;
- if (root_y + size.y > mon_y + mon_h) root_y = mon_y + mon_h - size.y;
- }
- if ((spec->constraints & X11_CONSTRAINT_RESIZE_X) &&
- popup_overflow(root_x, size.x, mon_x, mon_x + mon_w)) {
- if (root_x >= mon_x + mon_w) root_x = mon_x + mon_w - 1;
- if (root_x < mon_x) { size.x -= mon_x - root_x; root_x = mon_x; }
- if (root_x + size.x > mon_x + mon_w) size.x = mon_x + mon_w - root_x;
- if (size.x < 1) size.x = 1;
- }
- if ((spec->constraints & X11_CONSTRAINT_RESIZE_Y) &&
- popup_overflow(root_y, size.y, mon_y, mon_y + mon_h)) {
- if (root_y >= mon_y + mon_h) root_y = mon_y + mon_h - 1;
- if (root_y < mon_y) { size.y -= mon_y - root_y; root_y = mon_y; }
- if (root_y + size.y > mon_y + mon_h) size.y = mon_y + mon_h - root_y;
- if (size.y < 1) size.y = 1;
- }
- } else {
- if (spec->beside) {
- if (root_x + size.x > mon_x + mon_w) {
- int flipped_x = anchor_x - size.x + spec->content_offset.x;
- if (flipped_x >= mon_x) root_x = flipped_x;
- }
- } else if (root_y + size.y > mon_y + mon_h) {
- int flipped_y = anchor_y - size.y + spec->content_offset.y;
- if (flipped_y >= mon_y) root_y = flipped_y;
- }
- if (root_x + size.x > mon_x + mon_w) root_x = mon_x + mon_w - size.x;
+ if (spec->constraints & X11_CONSTRAINT_FLIP_X) {
+ int flip_x, flip_y;
+ /* Reflect the selected anchor edge across the anchor rectangle center. */
+ int anchor_origin_x = parent_rx - parent_cx + spec->anchor.x;
+ int flipped_anchor_x = 2 * anchor_origin_x + spec->anchor.width - anchor_x;
+ popup_position_at(spec, flipped_anchor_x, anchor_y, popup_flip_x(spec->gravity), size, &flip_x, &flip_y);
+ if (popup_overflow(flip_x, size.x, mon_x, mon_x + mon_w) <
+ popup_overflow(root_x, size.x, mon_x, mon_x + mon_w)) root_x = flip_x;
+ }
+ if (spec->constraints & X11_CONSTRAINT_FLIP_Y) {
+ int flip_x, flip_y;
+ int anchor_origin_y = parent_ry - parent_cy + spec->anchor.y;
+ int flipped_anchor_y = 2 * anchor_origin_y + spec->anchor.height - anchor_y;
+ popup_position_at(spec, anchor_x, flipped_anchor_y, popup_flip_y(spec->gravity), size, &flip_x, &flip_y);
+ if (popup_overflow(flip_y, size.y, mon_y, mon_y + mon_h) <
+ popup_overflow(root_y, size.y, mon_y, mon_y + mon_h)) root_y = flip_y;
+ }
+ if (spec->constraints & X11_CONSTRAINT_SLIDE_X) {
if (root_x < mon_x) root_x = mon_x;
- if (root_y + size.y > mon_y + mon_h) root_y = mon_y + mon_h - size.y;
+ if (root_x + size.x > mon_x + mon_w) root_x = mon_x + mon_w - size.x;
+ }
+ if (spec->constraints & X11_CONSTRAINT_SLIDE_Y) {
if (root_y < mon_y) root_y = mon_y;
+ if (root_y + size.y > mon_y + mon_h) root_y = mon_y + mon_h - size.y;
+ }
+ if ((spec->constraints & X11_CONSTRAINT_RESIZE_X) &&
+ popup_overflow(root_x, size.x, mon_x, mon_x + mon_w)) {
+ if (root_x >= mon_x + mon_w) root_x = mon_x + mon_w - 1;
+ if (root_x < mon_x) { size.x -= mon_x - root_x; root_x = mon_x; }
+ if (root_x + size.x > mon_x + mon_w) size.x = mon_x + mon_w - root_x;
+ if (size.x < 1) size.x = 1;
+ }
+ if ((spec->constraints & X11_CONSTRAINT_RESIZE_Y) &&
+ popup_overflow(root_y, size.y, mon_y, mon_y + mon_h)) {
+ if (root_y >= mon_y + mon_h) root_y = mon_y + mon_h - 1;
+ if (root_y < mon_y) { size.y -= mon_y - root_y; root_y = mon_y; }
+ if (root_y + size.y > mon_y + mon_h) size.y = mon_y + mon_h - root_y;
+ if (size.y < 1) size.y = 1;
}
*out_x = root_x;
@@ -2434,7 +2406,6 @@ static struct yasl_private_display *display_open(struct yasl_private_loop *loop,
struct x11_display *d = calloc(1, sizeof(*d));
if (!d) return NULL;
d->base.ops = &yasl_private_x11_backend;
- d->base.callbacks = spec && spec->cbs ? *spec->cbs : (struct yasl_private_display_cbs){0};
d->native = XOpenDisplay(NULL);
if (!d->native) { free(d); errno = ENODEV; return NULL; }
XSetErrorHandler(yasl_private_x11_error_handler);
@@ -2590,11 +2561,6 @@ static bool copy_text(struct yasl_private_display *base, enum yasl_private_selec
return true;
}
-static void copy(struct yasl_private_display *base, enum yasl_private_selection sel, const char *text)
-{
- (void)copy_text(base, sel, text);
-}
-
static bool request_paste(struct yasl_private_display *base, enum yasl_private_selection sel,
struct yasl_surface *target, uint64_t id)
{
@@ -2646,20 +2612,6 @@ static bool request_paste(struct yasl_private_display *base, enum yasl_private_s
}
}
-static void paste(struct yasl_private_display *base, enum yasl_private_selection sel,
- struct yasl_surface *target)
-{
- (void)request_paste(base, sel, target, 0);
-}
-
-static bool input_poll(struct yasl_surface *base, struct yasl_private_event *event)
-{
- struct x11_surface *s = (struct x11_surface *)base;
- if (s->destroyed) return false;
- if (base->display->events) return yasl_private_events_poll_surface(base, event);
- return input_queue_pop(&s->input, event);
-}
-
static struct input_queue *surface_input_queue(struct yasl_surface *base)
{
return &((struct x11_surface *)base)->input;
@@ -3077,8 +3029,6 @@ const struct yasl_private_backend_ops yasl_private_x11_backend = {
.display_dispatch_timeout = dispatch_timeout,
.display_flush = flush,
.display_modifiers = mods,
- .display_copy = copy,
- .display_paste = paste,
.display_copy_text = copy_text,
.display_request_paste = request_paste,
.display_drag_start = drag_start,
@@ -3097,7 +3047,6 @@ const struct yasl_private_backend_ops yasl_private_x11_backend = {
.surface_set_title = set_title,
.surface_schedule_redraw = schedule_redraw,
.surface_present = present,
- .surface_poll_event = input_poll,
.surface_geometry = geometry,
.surface_timing = timing,
.surface_frame_time_ns = frame_time,
diff --git a/tests/cocoa/display.m b/tests/cocoa/display.m
new file mode 100644
index 0000000..0b2d9d8
--- /dev/null
+++ b/tests/cocoa/display.m
@@ -0,0 +1,13 @@
+#import <AppKit/AppKit.h>
+#include "common/private_native.h"
+
+@interface NSView (YaslTestDisplayLink)
+- (void)displayLinkFired:(id)link;
+@end
+
+/* Exercise the native CPU presenter without depending on the host's cadence. */
+void yasl_test_frame_tick(struct yasl_surface *surface)
+{
+ NSWindow *window = (NSWindow *)yasl_private_surface_get_native_handle(surface);
+ [window.contentView displayLinkFired:nil];
+}
diff --git a/tests/cocoa/test_cursor.m b/tests/cocoa/test_cursor.m
index 4c961df..b50ab55 100644
--- a/tests/cocoa/test_cursor.m
+++ b/tests/cocoa/test_cursor.m
@@ -39,7 +39,7 @@ int main(void)
assert([NSCursor currentCursor] == hidden);
struct yasl_private_event event;
bool moved = false;
- while (yasl_private_surface_poll_event(surface, &event))
+ while (yasl_private_display_poll_event(yasl_private_surface_display(surface), &event))
if (event.type == YASL_PRIVATE_EVENT_POINTER_MOTION)
moved = true;
assert(moved);
diff --git a/tests/cocoa/test_keyboard.m b/tests/cocoa/test_keyboard.m
index a41011c..a457a74 100644
--- a/tests/cocoa/test_keyboard.m
+++ b/tests/cocoa/test_keyboard.m
@@ -35,7 +35,7 @@
static struct yasl_private_event next(struct yasl_surface *surface, enum yasl_private_event_type type)
{
struct yasl_private_event event;
- assert(yasl_private_surface_poll_event(surface, &event));
+ assert(yasl_private_display_poll_event(yasl_private_surface_display(surface), &event));
assert(event.type == type && event.surface == surface);
return event;
}
@@ -43,7 +43,7 @@ static struct yasl_private_event next(struct yasl_surface *surface, enum yasl_pr
static void empty(struct yasl_surface *surface)
{
struct yasl_private_event event;
- assert(!yasl_private_surface_poll_event(surface, &event));
+ assert(!yasl_private_display_poll_event(yasl_private_surface_display(surface), &event));
}
int main(void)
@@ -65,7 +65,7 @@ int main(void)
NSWindow *window = (NSWindow *)yasl_private_surface_get_native_handle(surface);
NSView<NSTextInputClient> *view = (id)window.contentView;
struct yasl_private_event event;
- while (yasl_private_surface_poll_event(surface, &event)) {}
+ while (yasl_private_display_poll_event(yasl_private_surface_display(surface), &event)) {}
InputSample *sample = [InputSample new];
NSEvent *native = (NSEvent *)sample;
@@ -100,6 +100,8 @@ int main(void)
[view setMarkedText:@"é" selectedRange:NSMakeRange(1, 0)
replacementRange:NSMakeRange(1, 2)];
assert(strcmp(yasl_private_surface_ime_preedit(surface), "é") == 0);
+ event = next(surface, YASL_PRIVATE_EVENT_COMPOSITION);
+ assert(event.composition.active && !strcmp(event.composition.data, "é"));
empty(surface);
[view insertText:@"😀é" replacementRange:NSMakeRange(NSNotFound, 0)];
event = next(surface, YASL_PRIVATE_EVENT_TEXT_EDIT);
@@ -107,6 +109,7 @@ int main(void)
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));
+ assert(!next(surface, YASL_PRIVATE_EVENT_COMPOSITION).composition.active);
empty(surface);
/* Exercise the keyDown -> interpretKeyEvents -> insertText route with
diff --git a/tests/cocoa/test_native.c b/tests/cocoa/test_native.c
index 9b8f8fa..d26a89d 100644
--- a/tests/cocoa/test_native.c
+++ b/tests/cocoa/test_native.c
@@ -49,8 +49,9 @@ static void test_window(enum yasl_private_backend request, bool null_spec)
assert(state.display);
assert(yasl_private_display_backend(state.display) == YASL_PRIVATE_BACKEND_COCOA);
struct yasl_private_window_cbs callbacks = {.draw = draw};
+ /* Check real Metal draw/ownership without waiting for a display-link tick. */
struct yasl_private_window_spec surface = {
- .title = "Native backend test", .size = {160, 100},
+ .title = "Native backend test", .size = {160, 100}, .tearing = true,
.cbs = &callbacks, .ud = &state,
};
state.surface = yasl_private_surface_create_toplevel(state.display, &surface);
diff --git a/tests/cocoa/test_ownership.m b/tests/cocoa/test_ownership.m
index 4efd164..10aae99 100644
--- a/tests/cocoa/test_ownership.m
+++ b/tests/cocoa/test_ownership.m
@@ -3,6 +3,7 @@
#include "common/backend.h"
#import <AppKit/AppKit.h>
#import <Metal/Metal.h>
+#import <QuartzCore/QuartzCore.h>
#include "common/types.h"
#include <assert.h>
#include <errno.h>
@@ -41,16 +42,8 @@ int main(void)
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(!d->ops->surface_create_gl && !d->ops->gl_make_current &&
+ !d->ops->gl_get_proc_address && !d->ops->gl_swap_interval && !d->ops->gl_swap_buffers);
assert(yasl_private_surface_set_size(s, (struct yasl_private_vector2i){180, 110}));
assert(yasl_private_surface_set_fullscreen(s, false));
@@ -58,7 +51,7 @@ int main(void)
assert(!yasl_private_surface_set_size(s, (struct yasl_private_vector2i){0, 100}));
assert(errno == EINVAL);
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},
};
@@ -117,7 +110,7 @@ int main(void)
}
const char *last = event.paste.data;
assert(!yasl_private_display_poll_event(d, &event));
- @autoreleasepool { yasl_private_display_copy(d, YASL_PRIVATE_CLIPBOARD, "new selection"); }
+ @autoreleasepool { yasl_private_clipboard_set(d, YASL_PRIVATE_CLIPBOARD, "new selection"); }
assert(strcmp(last, "paste-599") == 0);
assert(!yasl_private_clipboard_set(d, YASL_PRIVATE_CLIPBOARD, "\xc3"));
assert(errno == EILSEQ);
@@ -131,11 +124,6 @@ int main(void)
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 8eb63d5..5cd7375 100644
--- a/tests/cocoa/test_tablet.m
+++ b/tests/cocoa/test_tablet.m
@@ -46,7 +46,7 @@
static struct yasl_private_event next(struct yasl_surface *surface, enum yasl_private_event_type type)
{
struct yasl_private_event event;
- assert(yasl_private_surface_poll_event(surface, &event));
+ assert(yasl_private_display_poll_event(yasl_private_surface_display(surface), &event));
assert(event.type == type);
return event;
}
@@ -62,7 +62,7 @@ int main(void)
NSWindow *window = (NSWindow *)yasl_private_surface_get_native_handle(surface);
NSView *view = window.contentView;
struct yasl_private_event event;
- while (yasl_private_surface_poll_event(surface, &event)) {}
+ while (yasl_private_display_poll_event(yasl_private_surface_display(surface), &event)) {}
TabletSample *sample = [TabletSample new];
NSEvent *native = (NSEvent *)sample;
sample.type = NSEventTypeTabletProximity;
diff --git a/tests/common/test_backends.c b/tests/common/test_backends.c
deleted file mode 100644
index 7eba57f..0000000
--- a/tests/common/test_backends.c
+++ /dev/null
@@ -1,495 +0,0 @@
-#define _POSIX_C_SOURCE 200809L
-#include "common/private_native.h"
-#if YASL_HAS_WAYLAND
-#include "common/private_native_wayland.h"
-#endif
-#if YASL_HAS_X11
-#include "common/private_native_x11.h"
-#endif
-#include "common/private_loop.h"
-#include "common/types.h"
-
-#include <X11/Xatom.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/keysym.h>
-#include <assert.h>
-#include <poll.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/timerfd.h>
-#include <time.h>
-#include <unistd.h>
-
-struct window {
- struct yasl_surface *surface;
- struct yasl_private_display *display;
- int draws, configures, closes;
- bool destroy_on_draw, destroy_on_configure;
-};
-
-struct pump {
- struct yasl_private_loop *loop;
- struct yasl_private_display *displays[2];
- int ticks;
-};
-
-static int tick(int fd, short events, void *ud)
-{
- (void)events;
- uint64_t expirations;
- assert(read(fd, &expirations, sizeof(expirations)) == sizeof(expirations));
- struct pump *p = ud;
- for (int i = 0; i < 2; i++) {
- if (p->displays[i]) {
- yasl_private_display_dispatch(p->displays[i], 0);
- yasl_private_display_flush(p->displays[i]);
- }
- }
- if (--p->ticks == 0) yasl_private_loop_quit(p->loop);
- return 0;
-}
-
-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_private_loop_add_fd(loop, timer, POLLIN, tick, &p);
- assert(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_private_frame *frame, void *ud)
-{
- struct window *w = ud;
- assert(s == w->surface);
- assert(frame->surface == s);
- 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_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_private_damage_list damage = {.n = YASL_PRIVATE_DAMAGE_MAX + 1};
- assert(!yasl_private_surface_present(s, &frame->target, &damage));
- damage.n = -2;
- assert(!yasl_private_surface_present(s, &frame->target, &damage));
- damage.n = 1;
- damage.rects[0].width = -1;
- assert(!yasl_private_surface_present(s, &frame->target, &damage));
- damage.n = -1;
- struct yasl_private_framebuffer invalid = frame->target;
- invalid.size.x++;
- assert(!yasl_private_surface_present(s, &invalid, &damage));
- invalid = frame->target;
- invalid.generation--;
- assert(!yasl_private_surface_present(s, &invalid, &damage));
- invalid = frame->target;
- invalid.pixels = (uint32_t *)(uintptr_t)1;
- 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_private_surface_destroy(s); w->surface = NULL; }
-}
-
-static void configure(struct yasl_surface *s, struct yasl_private_geometry geometry, void *ud)
-{
- struct window *w = ud;
- assert(w->surface == s);
- 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_private_surface_geometry(s).scale_120);
- w->configures++;
- if (w->destroy_on_configure) { yasl_private_surface_destroy(s); w->surface = NULL; }
-}
-
-static void draw_without_present(struct yasl_surface *s, struct yasl_private_frame *frame, void *ud)
-{
- (void)s;
- struct window *w = ud;
- size_t count = (size_t)frame->target.size.x * (size_t)frame->target.size.y;
- for (size_t i = 0; i < count; i++) frame->target.pixels[i] = 0xff000000;
- w->draws++;
-}
-
-static void close_window(struct yasl_surface *s, void *ud)
-{
- struct window *w = ud;
- assert(s == w->surface);
- w->closes++;
- yasl_private_surface_destroy(s);
- w->surface = NULL;
-}
-
-static const struct yasl_private_window_cbs callbacks = {
- .draw = draw, .configure = configure, .close = close_window,
-};
-
-static void attach(struct window *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_private_display *d)
-{
- 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_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_private_loop *loop, struct yasl_private_display *d, struct window *w)
-{
- 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_private_surface_read_pixels(w->surface, pixels, count - 1, &size));
- assert(!pixels[0]);
- 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_private_window_cbs skip = callbacks;
- skip.draw = draw_without_present;
- yasl_private_surface_set_callbacks(w->surface, &skip, w);
- for (int i = 0; i < 4; i++) {
- yasl_private_surface_schedule_redraw(w->surface);
- pump(loop, d, NULL);
- 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);
- }
- }
-
- attach(w);
- yasl_private_surface_schedule_redraw(w->surface);
- pump(loop, d, NULL);
- memset(pixels, 0, count * sizeof(*pixels));
- 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_private_loop *loop, struct yasl_private_display *d)
-{
- struct window w = {.display = d, .destroy_on_draw = true};
- {
- 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_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_private_surface_schedule_redraw(w.surface);
- pump(loop, d, NULL);
- assert(w.draws == 1 && !w.surface);
-}
-
-static void x11_behavior(struct yasl_private_loop *loop, struct yasl_private_display *d, struct window *w)
-{
- 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_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_private_surface_set_title(w->surface, "Updated title");
- char *title = NULL;
- assert(XFetchName(native, window, &title));
- assert(strcmp(title, "Updated title") == 0);
- XFree(title);
- XResizeWindow(native, window, 200, 120);
- XFlush(native);
- pump(loop, d, NULL);
- assert(w->configures > 0);
- 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_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_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;
- }
- }
- assert(saw_motion);
- XEvent key = {0};
- key.xkey = (XKeyEvent){.type = KeyPress, .display = native, .window = window,
- .root = DefaultRootWindow(native), .same_screen = True,
- .keycode = XKeysymToKeycode(native, XK_a)};
- XSendEvent(native, window, False, KeyPressMask, &key);
- XFlush(native);
- 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_private_event event;
- while (yasl_private_surface_poll_event(w->surface, &event)) {
- assert(event.surface == w->surface);
- 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_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_PRIVATE_EVENT_TEXT) {
- assert(event.text.len == 1 && event.text.data[0] == 'a');
- saw_text = true;
- }
- }
- assert(saw_key && saw_paste && saw_text);
- /* Physical identity survives modifier and layout changes, including a
- * release whose modifiers differ from its press. */
- key.xkey.state = ShiftMask;
- XSendEvent(native, window, False, KeyPressMask, &key);
- key.xkey.type = KeyRelease;
- key.xkey.state = 0;
- XSendEvent(native, window, False, KeyReleaseMask, &key);
- XFlush(native);
- pump(loop, d, NULL);
- int key_count = 0, text_count = 0;
- 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_PRIVATE_EVENT_TEXT) {
- assert(event.text.len == 1 && event.text.data[0] == 'A');
- text_count++;
- }
- }
- assert(key_count == 2 && text_count == 1);
- key.xkey.type = KeyPress;
- key.xkey.state = ControlMask;
- XSendEvent(native, window, False, KeyPressMask, &key);
- XFlush(native);
- pump(loop, d, NULL);
- 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);
- assert(saved_symbols && symbols_per_key >= 2);
- KeySym *changed_symbols = calloc((size_t)symbols_per_key, sizeof(KeySym));
- assert(changed_symbols);
- changed_symbols[0] = XK_q;
- changed_symbols[1] = XK_Q;
- XChangeKeyboardMapping(native, key.xkey.keycode, symbols_per_key, changed_symbols, 1);
- XSync(native, False);
- pump(loop, d, NULL); /* Consume MappingNotify before translating the key. */
- key.xkey.state = 0;
- XSendEvent(native, window, False, KeyPressMask, &key);
- XFlush(native);
- pump(loop, d, NULL);
- saw_key = saw_text = false;
- 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_PRIVATE_EVENT_TEXT) {
- assert(event.text.len == 1 && event.text.data[0] == 'q');
- saw_text = true;
- }
- }
- assert(saw_key && saw_text);
- XChangeKeyboardMapping(native, key.xkey.keycode, symbols_per_key, saved_symbols, 1);
- free(changed_symbols);
- XFree(saved_symbols);
- XSync(native, False);
- pump(loop, d, NULL);
-
- for (unsigned button = 4; button <= 7; button++) {
- XEvent wheel = {.xbutton = {.type = ButtonPress, .display = native,
- .window = window, .root = DefaultRootWindow(native),
- .same_screen = True, .button = button}};
- /* Direct delivery exercises the core fallback even with XI2 enabled. */
- XSendEvent(native, window, False, NoEventMask, &wheel);
- wheel.xbutton.type = ButtonRelease;
- XSendEvent(native, window, False, NoEventMask, &wheel);
- XFlush(native);
- pump(loop, d, NULL);
- 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_private_surface_poll_event(w->surface, &event));
- }
- 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_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_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_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_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_private_display_spec ds = {.backend = YASL_PRIVATE_BACKEND_X11};
- struct yasl_private_display *owner = yasl_private_display_open(loop, &ds);
- assert(owner);
- yasl_private_display_copy(owner, YASL_PRIVATE_CLIPBOARD, "external");
- struct window other = create(d), cancelled = create(d);
- 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_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_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_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)}};
- XSendEvent(native, window, False, NoEventMask, &key);
- XFlush(native);
- pump(loop, d, NULL);
- assert(w->closes == 1 && !w->surface);
-}
-
-int main(int argc, char **argv)
-{
- assert(argc >= 2);
- struct yasl_private_loop *loop = yasl_private_loop_create();
- assert(loop);
- if (strcmp(argv[1], "failure") == 0) {
- 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_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_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_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_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_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_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_private_surface_schedule_redraw(w.surface);
- pump(loop, d, NULL);
- assert(w.draws > 0);
- test_read_pixels(loop, d, &w);
- if (yasl_private_display_backend(d) == YASL_PRIVATE_BACKEND_X11)
- x11_behavior(loop, d, &w);
- 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_private_display_close(d);
- }
- 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 be84586..f9f427f 100644
--- a/tests/common/test_contracts.c
+++ b/tests/common/test_contracts.c
@@ -117,10 +117,10 @@ static bool present(struct yasl_surface *s, const struct yasl_private_framebuffe
return true;
}
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_private_display *d, enum yasl_private_selection sel, struct yasl_surface *s)
-{ (void)d; (void)sel; (void)s; pastes++; }
+static bool copy(struct yasl_private_display *d, enum yasl_private_selection sel, const char *text)
+{ (void)d; (void)sel; (void)text; copies++; return true; }
+static bool paste(struct yasl_private_display *d, enum yasl_private_selection sel, struct yasl_surface *s, uint64_t id)
+{ (void)d; (void)sel; (void)s; assert(id); pastes++; return true; }
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; }
@@ -260,7 +260,7 @@ static void test_native(void)
static void test_validation(void)
{
const struct yasl_private_backend_ops ops = {.surface_present = present,
- .display_caps = caps, .display_copy = copy, .display_paste = paste,
+ .display_caps = caps, .display_copy_text = copy, .display_request_paste = paste,
.surface_create_toplevel = create};
struct yasl_private_display d = {.ops = &ops};
struct yasl_surface s = {.display = &d, .frame_generation = 1};
@@ -293,14 +293,16 @@ static void test_validation(void)
assert(yasl_private_surface_present(&s, &fb, &damage) && received.n == -1);
damage.n = 0;
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(yasl_private_events_open(&d));
+ yasl_private_clipboard_set(&d, YASL_PRIVATE_PRIMARY, "no alias");
+ yasl_private_clipboard_set(&d, (enum yasl_private_selection)255, "invalid");
+ yasl_private_clipboard_request(&s, YASL_PRIVATE_PRIMARY);
+ yasl_private_clipboard_request(&s, (enum yasl_private_selection)255);
assert(!copies && !pastes);
- yasl_private_display_copy(&d, YASL_PRIVATE_CLIPBOARD, "yes");
- yasl_private_display_paste(&d, YASL_PRIVATE_CLIPBOARD, &s);
+ yasl_private_clipboard_set(&d, YASL_PRIVATE_CLIPBOARD, "yes");
+ yasl_private_clipboard_request(&s, YASL_PRIVATE_CLIPBOARD);
assert(copies == 1 && pastes == 1);
+ yasl_private_events_close(&d);
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);
diff --git a/tests/common/test_events.c b/tests/common/test_events.c
index fcfc118..e9f61da 100644
--- a/tests/common/test_events.c
+++ b/tests/common/test_events.c
@@ -179,20 +179,23 @@ static void test_failures(void)
}
-static void test_legacy_poll_does_not_spin(void)
+static void test_fifo_preserves_notifications(void)
{
struct yasl_private_display d;
struct yasl_surface a, b;
setup(&d, &a, &b);
yasl_private_surface_notify_state(&a, YASL_PRIVATE_STATE_ACTIVATED);
yasl_private_surface_notify_close(&b);
- assert(yasl_private_events_pending(&d));
+ yasl_private_surface_notify_composition(&a, "preedit", 0, 7);
+ assert(input_queue_push(&b.input, &(struct yasl_private_event){
+ .type = YASL_PRIVATE_EVENT_PEN, .surface = &b}));
+ const enum yasl_private_event_type types[] = {YASL_PRIVATE_EVENT_WINDOW_STATE,
+ YASL_PRIVATE_EVENT_WINDOW_CLOSE, YASL_PRIVATE_EVENT_COMPOSITION, YASL_PRIVATE_EVENT_PEN};
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);
+ for (size_t i = 0; i < sizeof(types) / sizeof(*types); ++i) {
+ assert(yasl_private_display_poll_event(&d, &ev));
+ assert(ev.type == types[i] && ev.surface == (i % 2 ? &b : &a));
+ }
assert(!yasl_private_events_pending(&d));
teardown(&d, &a, &b);
}
@@ -203,6 +206,6 @@ int main(void)
test_post_cleanup();
test_damage();
test_failures();
- test_legacy_poll_does_not_spin();
+ test_fifo_preserves_notifications();
return 0;
}
diff --git a/tests/common/test_surface_integration.c b/tests/common/test_surface_integration.c
index 2752208..7cc938a 100644
--- a/tests/common/test_surface_integration.c
+++ b/tests/common/test_surface_integration.c
@@ -1,6 +1,7 @@
#define _POSIX_C_SOURCE 200809L
#include <yasl/yasl.h>
#include <yasl/cpu.h>
+#include <yasl/gl.h>
#include "common/backend.h"
#include <assert.h>
#include <pthread.h>
@@ -8,6 +9,9 @@
#include <string.h>
#include <time.h>
#include <stdio.h>
+#if YASL_HAS_COCOA
+void yasl_test_frame_tick(struct yasl_surface *surface);
+#endif
static void drain(void)
{
yasl_event e;int n=0;
@@ -32,6 +36,15 @@ int main(int argc,char **argv)
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);
+ if(backend==YASL_BACKEND_COCOA) {
+ assert(!(yasl_surface_features(s)&YASL_CAP_OPENGL));
+ assert(!yasl_gl_surface_create("unsupported GL",64,64,0,NULL,NULL));
+ assert(yasl_get_error(NULL)==YASL_ERROR_UNSUPPORTED);
+ assert(!yasl_gl_make_current(NULL));
+ assert(yasl_get_error(NULL)==YASL_ERROR_UNSUPPORTED);
+ assert(!yasl_gl_get_proc_address("glClear"));
+ assert(yasl_get_error(NULL)==YASL_ERROR_UNSUPPORTED);
+ }
/* 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++) {
@@ -79,7 +92,12 @@ int main(int argc,char **argv)
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);
+#if YASL_HAS_COCOA
+ 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);
yasl_surface_destroy(s);
assert(!yasl_set_backend(backend));
diff --git a/tests/helpers/package_cocoa_tests.py b/tests/helpers/package_cocoa_tests.py
index 8f801f8..1f72126 100644
--- a/tests/helpers/package_cocoa_tests.py
+++ b/tests/helpers/package_cocoa_tests.py
@@ -21,8 +21,8 @@ def main():
if host['system'] != 'darwin':
parser.error('Use a configured and compiled Cocoa build.')
tests = json.loads((info / 'intro-tests.json').read_text())
- required = {'native', 'native-ownership', 'keyboard-cocoa', 'tablet-cocoa',
- 'cursor-cocoa', 'hello-cocoa-window', 'tablet-cocoa-window'}
+ required = {'surface-cocoa', 'native-cocoa', 'ownership-cocoa', 'keyboard-cocoa',
+ 'tablet-cocoa', 'cursor-cocoa'}
missing = required - {test['name'] for test in tests}
if missing:
parser.error('Enable integration_tests; missing: ' + ', '.join(sorted(missing)))
diff --git a/tests/helpers/run_backends.py b/tests/helpers/run_backends.py
deleted file mode 100644
index af7e02d..0000000
--- a/tests/helpers/run_backends.py
+++ /dev/null
@@ -1,119 +0,0 @@
-#!/usr/bin/env python3
-"""Test public window behavior on isolated display servers."""
-
-import os
-from pathlib import Path
-import subprocess
-import sys
-import tempfile
-import time
-
-
-def wait_for(process, ready):
- deadline = time.monotonic() + 10
- while time.monotonic() < deadline:
- if process.poll() is not None:
- raise RuntimeError("The display server stopped.")
- if ready():
- return
- time.sleep(0.02)
- raise TimeoutError("The display server did not start.")
-
-
-def main():
- 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)
- env = os.environ.copy()
- env.pop("WAYLAND_SOCKET", None)
- env.update(XDG_RUNTIME_DIR=directory, WAYLAND_DISPLAY="yasl-test",
- XDG_SESSION_TYPE="wayland")
- 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=pixman",
- "--socket=yasl-test", "--idle-time=0", "--no-config",
- ], 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 display_fd:
- x = subprocess.Popen([
- xwayland, "-displayfd", str(display_fd.fileno()),
- "-shm", "-noreset", "-nolisten", "tcp",
- ], env=env, pass_fds=(display_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()
-
- def run(mode, request=None, expected=None, **changes):
- case_env = env.copy()
- for key, value in changes.items():
- if value is None:
- case_env.pop(key, None)
- else:
- case_env[key] = value
- args = [test, mode]
- if request is not None:
- args.append(str(request))
- if expected is not None:
- args.append(str(expected))
- print("Test:", mode, request, expected, changes, flush=True)
- subprocess.run(args, env=case_env, check=True, timeout=8)
-
- run("open", 1, 1)
- run("open", 2, 2)
- run("open", 0, 1)
- run("null", 0, 1)
- run("open", 0, 2, WAYLAND_DISPLAY=None, XDG_SESSION_TYPE="x11")
- run("open", 0, 2, WAYLAND_DISPLAY="missing-socket")
- run("failure", 1, WAYLAND_DISPLAY="missing-socket")
- run("failure", 2, DISPLAY=":59999")
- run("failure", 0, WAYLAND_DISPLAY="missing-socket", DISPLAY=":59999")
- run("mixed")
- print("Test: Wayland surface timers", flush=True)
- subprocess.run([timers], env=env, check=True, timeout=8)
- x_env = env.copy()
- x_env.pop("WAYLAND_DISPLAY", None)
- x_env["XDG_SESSION_TYPE"] = "x11"
- print("Test: X11 surface timers", flush=True)
- 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"],
- env=env, check=True, timeout=8)
- print("Test: hello example on", backend, flush=True)
- subprocess.run([hello],
- env=env if backend == "wayland" else x_env,
- check=True, timeout=8)
- print("Test: interactive example on", backend, flush=True)
- subprocess.run([interactive, "--smoke-test"],
- env=env if backend == "wayland" else x_env,
- check=True, timeout=8)
- 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 d61d094..8370423 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -33,7 +33,7 @@ test('public-exports', python, args: [files('helpers/check_exports.py')] + expor
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)
+ test(unit, exe, is_parallel: not has_cocoa or unit != 'timers')
endforeach
keyboard_sources = files('common/test_keyboard.c')
if not has_wayland
@@ -80,10 +80,14 @@ if has_x11
endif
endif
if get_option('integration_tests')
- integration = executable('yasl-surface-integration', 'common/test_surface_integration.c',
+ display_test_sources = has_cocoa ? files('cocoa/display.m') : []
+ integration = executable('yasl-surface-integration', ['common/test_surface_integration.c'] + display_test_sources,
include_directories: inc, dependencies: yasl_dep)
- gl_integration = executable('yasl-gl-integration', 'common/test_gl.c',
- dependencies: yasl_dep)
+ gl_integration = '-'
+ if has_egl
+ gl_integration = executable('yasl-gl-integration', 'common/test_gl.c',
+ dependencies: yasl_dep)
+ endif
vulkan_integration = '-'
if has_vulkan
vulkan_integration = executable('yasl-vulkan-integration', 'common/test_vulkan.c', dependencies: yasl_dep)
@@ -99,12 +103,12 @@ if get_option('integration_tests')
test('reconnect-wayland', python, args: [files('helpers/run_reconnect.py'), weston, reconnect], timeout: 60)
endif
elif has_cocoa
- test('surface-cocoa', integration, args: ['cocoa'], timeout: 30)
+ test('surface-cocoa', integration, args: ['cocoa'], timeout: 30, is_parallel: false)
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)
+ test(unit + '-cocoa', exe, timeout: 30, is_parallel: false)
endforeach
endif
endif
diff --git a/tests/wayland/test_cursor.c b/tests/wayland/test_cursor.c
index 3425821..87cea9a 100644
--- a/tests/wayland/test_cursor.c
+++ b/tests/wayland/test_cursor.c
@@ -77,15 +77,15 @@ int main(void)
tablet_tool_motion(&tool, tool.proxy, wl_fixed_from_int(56), wl_fixed_from_int(78));
tool_frame(&tool, tool.proxy, 0);
struct yasl_private_event event;
- assert(yasl_private_surface_poll_event(&surface.base, &event));
+ assert(input_queue_pop(&surface.input, &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_private_surface_poll_event(&surface.base, &event));
+ assert(input_queue_pop(&surface.input, &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(input_queue_pop(&surface.input, &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_private_surface_poll_event(&surface.base, &event));
+ assert(!input_queue_pop(&surface.input, &event));
/* Each new entry needs a request with its own serial. */
pointer_leave(&seat, seat.pointer, 12, surface.surface);
diff --git a/tests/wayland/test_input.c b/tests/wayland/test_input.c
index 2b5592a..820eb8b 100644
--- a/tests/wayland/test_input.c
+++ b/tests/wayland/test_input.c
@@ -62,7 +62,7 @@ int main(void)
char text[32];
snprintf(text, sizeof(text), "commit-%d", i);
struct yasl_private_event event;
- assert(wayland_surface_poll_event(&w, &event));
+ assert(input_queue_pop(&w.input, &event));
assert(event.type == YASL_PRIVATE_EVENT_TEXT && event.surface == &w.base);
assert(strcmp(event.text.data, text) == 0);
}
@@ -77,21 +77,21 @@ int main(void)
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(input_queue_pop(&w.input, &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));
+ assert(!input_queue_pop(&w.input, &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(input_queue_pop(&w.input, &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));
+ assert(!input_queue_pop(&w.input, &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 ae4647f..2f55cf6 100644
--- a/tests/wayland/test_keyboard.c
+++ b/tests/wayland/test_keyboard.c
@@ -4,7 +4,7 @@
static struct yasl_private_event next(struct wayland_surface *w, enum yasl_private_event_type type)
{
struct yasl_private_event ev;
- assert(yasl_private_surface_poll_event(&w->base, &ev));
+ assert(input_queue_pop(&w->input, &ev));
assert(ev.type == type && ev.surface == &w->base);
return ev;
}
@@ -12,7 +12,7 @@ static struct yasl_private_event next(struct wayland_surface *w, enum yasl_priva
static void empty(struct wayland_surface *w)
{
struct yasl_private_event ev;
- assert(!yasl_private_surface_poll_event(&w->base, &ev));
+ assert(!input_queue_pop(&w->input, &ev));
}
static void layout(struct seat *s, const char *name, const char *variant)
diff --git a/tests/wayland/test_popup_positioner.c b/tests/wayland/test_popup_positioner.c
index 86778f6..a851ddb 100644
--- a/tests/wayland/test_popup_positioner.c
+++ b/tests/wayland/test_popup_positioner.c
@@ -1,5 +1,4 @@
-/* Capture xdg_positioner requests to verify explicit placement and the legacy
- * beside mapping without requiring a compositor. */
+/* Capture explicit xdg_positioner placement without requiring a compositor. */
#include "platform/wayland/internal.h"
#include <assert.h>
@@ -56,7 +55,12 @@ int main(void)
struct yasl_private_popup_spec spec = {
.size = {64, 48},
.anchor = {13, 24, 8, 6},
- .beside = true,
+ .anchor_edges = XDG_POSITIONER_ANCHOR_TOP_RIGHT,
+ .gravity = XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT,
+ .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,
};
struct xdg_positioner *positioner = popup_positioner(&popup, &spec);
@@ -72,7 +76,6 @@ int main(void)
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 |
diff --git a/tests/wayland/test_relative_pointer.c b/tests/wayland/test_relative_pointer.c
index d44238d..81cec2f 100644
--- a/tests/wayland/test_relative_pointer.c
+++ b/tests/wayland/test_relative_pointer.c
@@ -68,7 +68,7 @@ static void shape_device_destroy(struct wp_cursor_shape_device_v1 *device) { ass
static struct yasl_private_event next_event(struct wayland_surface *w)
{
struct yasl_private_event event;
- assert(yasl_private_surface_poll_event(&w->base, &event));
+ assert(input_queue_pop(&w->input, &event));
return event;
}
@@ -121,7 +121,7 @@ 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_private_surface_poll_event(&surface.base, &event));
+ assert(!input_queue_pop(&surface.input, &event));
/* Locked: relative samples in device pixels, position frozen at the lock. */
pointer_locked(&surface, surface.pointer_lock);
@@ -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_private_surface_poll_event(&surface.base, &event));
+ assert(!input_queue_pop(&surface.input, &event));
move_to(&seat, 8, 5);
event = next_event(&surface);
assert(event.pointer.delta.x == 2 && event.pointer.delta.y == 0);
diff --git a/tests/wayland/test_state.c b/tests/wayland/test_state.c
index 1ce9189..c02e01b 100644
--- a/tests/wayland/test_state.c
+++ b/tests/wayland/test_state.c
@@ -20,12 +20,15 @@ struct notifications {
uint32_t state;
};
-static void state_changed(struct yasl_surface *surface, uint32_t state, void *ud)
+static void collect(struct yasl_private_display *display, struct notifications *notifications)
{
- struct notifications *notifications = ud;
- assert(yasl_private_surface_state(surface) == state);
- notifications->count++;
- notifications->state = state;
+ struct yasl_private_event event;
+ while (yasl_private_display_poll_event(display, &event)) {
+ assert(event.type == YASL_PRIVATE_EVENT_WINDOW_STATE);
+ assert(yasl_private_surface_state(event.surface) == event.state.flags);
+ notifications->count++;
+ notifications->state = event.state.flags;
+ }
}
static void configure(struct wayland_surface *surface, uint32_t *states, size_t count)
@@ -38,31 +41,39 @@ 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_PRIVATE_STATE_CSD};
- wayland_surface_set_callbacks(&surface, &(struct yasl_private_window_cbs){
- .state = state_changed}, &notifications);
+ const struct yasl_private_backend_ops ops = {0};
+ struct yasl_private_display display = {.ops = &ops};
+ struct wayland_surface surface = {.base = {.display = &display, .state = YASL_PRIVATE_STATE_CSD}};
+ assert(yasl_private_events_open(&display));
+ assert(yasl_private_events_register(&surface.base));
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));
+ collect(&display, &notifications);
assert(notifications.count == 1);
assert(notifications.state == (YASL_PRIVATE_STATE_CSD | YASL_PRIVATE_STATE_FULLSCREEN | YASL_PRIVATE_STATE_ACTIVATED));
configure(&surface, fullscreen, sizeof(fullscreen) / sizeof(*fullscreen));
+ collect(&display, &notifications);
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);
+ collect(&display, &notifications);
assert(notifications.count == 2);
assert(notifications.state == (YASL_PRIVATE_STATE_FULLSCREEN | YASL_PRIVATE_STATE_ACTIVATED));
toplevel_decoration_configure(&surface, NULL, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
+ collect(&display, &notifications);
assert(notifications.count == 2);
uint32_t maximized[] = {XDG_TOPLEVEL_STATE_MAXIMIZED, XDG_TOPLEVEL_STATE_SUSPENDED};
configure(&surface, maximized, sizeof(maximized) / sizeof(*maximized));
+ collect(&display, &notifications);
assert(notifications.count == 3);
assert(notifications.state == (YASL_PRIVATE_STATE_MAXIMIZED | YASL_PRIVATE_STATE_SUSPENDED));
toplevel_decoration_configure(&surface, NULL, ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE);
+ collect(&display, &notifications);
assert(notifications.count == 4);
assert(notifications.state == (YASL_PRIVATE_STATE_CSD | YASL_PRIVATE_STATE_MAXIMIZED | YASL_PRIVATE_STATE_SUSPENDED));
@@ -72,19 +83,21 @@ int main(void)
XDG_TOPLEVEL_STATE_TILED_TOP, XDG_TOPLEVEL_STATE_TILED_BOTTOM};
for (size_t i = 0; i < sizeof(edges) / sizeof(*edges); i++) {
configure(&surface, &edges[i], 1);
+ collect(&display, &notifications);
assert(notifications.count == 5);
assert(notifications.state == (YASL_PRIVATE_STATE_CSD | YASL_PRIVATE_STATE_TILED));
}
configure(&surface, edges, 0);
+ collect(&display, &notifications);
assert(notifications.count == 6);
assert(notifications.state == YASL_PRIVATE_STATE_CSD);
- /* State still advances when applications have not installed callbacks. */
- wayland_surface_set_callbacks(&surface, NULL, NULL);
+ /* The authoritative state advances with the queued notification. */
configure(&surface, fullscreen, sizeof(fullscreen) / sizeof(*fullscreen));
assert(yasl_private_surface_state(&surface.base) ==
(YASL_PRIVATE_STATE_CSD | YASL_PRIVATE_STATE_FULLSCREEN | YASL_PRIVATE_STATE_ACTIVATED));
- assert(notifications.count == 6);
+ collect(&display, &notifications);
+ assert(notifications.count == 7);
/* External presentation has no SHM commit callback to acknowledge xdg
* configures. Apply geometry and acknowledge before renderer submission. */
@@ -106,5 +119,7 @@ int main(void)
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);
+ yasl_private_events_unregister(&surface.base);
+ yasl_private_events_close(&display);
return 0;
}
diff --git a/tests/wayland/test_tablet.c b/tests/wayland/test_tablet.c
index f47fbfa..0cce568 100644
--- a/tests/wayland/test_tablet.c
+++ b/tests/wayland/test_tablet.c
@@ -4,7 +4,7 @@
static struct yasl_private_event next_raw(struct wayland_surface *surface)
{
struct yasl_private_event event;
- assert(yasl_private_surface_poll_event(&surface->base, &event));
+ assert(input_queue_pop(&surface->input, &event));
assert(event.surface == &surface->base);
return event;
}
@@ -111,9 +111,9 @@ int main(void)
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));
+ assert(!input_queue_pop(&surface.input, &unused));
pointer_frame(&seat, NULL);
- assert(!yasl_private_surface_poll_event(&surface.base, &unused));
+ assert(!input_queue_pop(&surface.input, &unused));
/* Finger scrolling carries pixel offsets and coherent gesture phases. */
pointer_axis_source(&seat, NULL, WL_POINTER_AXIS_SOURCE_FINGER);
@@ -152,7 +152,7 @@ int main(void)
pointer_axis_value120(&seat, NULL, WL_POINTER_AXIS_VERTICAL_SCROLL, 60);
seat_pointer_reset(&seat);
pointer_frame(&seat, NULL);
- assert(!yasl_private_surface_poll_event(&surface.base, &unused));
+ assert(!input_queue_pop(&surface.input, &unused));
input_queue_clear(&surface.input);
return 0;
}
diff --git a/tests/x11/test_input.c b/tests/x11/test_input.c
index ccad859..a89812b 100644
--- a/tests/x11/test_input.c
+++ b/tests/x11/test_input.c
@@ -6,12 +6,14 @@
static void check_selection_encoding(struct x11_display *d, struct x11_surface *s)
{
+ struct yasl_private_event queued;
+ while (yasl_private_display_poll_event(&d->base, &queued)) {}
Window requestor = XCreateSimpleWindow(d->native, DefaultRootWindow(d->native),
0, 0, 1, 1, 0, 0, 0);
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_private_display_copy(&d->base, YASL_PRIVATE_CLIPBOARD, "café £");
+ yasl_private_clipboard_set(&d->base, YASL_PRIVATE_CLIPBOARD, "café £");
selection_request(d, &request);
Atom actual;
int format;
@@ -22,7 +24,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_private_display_copy(&d->base, YASL_PRIVATE_CLIPBOARD, "字");
+ yasl_private_clipboard_set(&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);
@@ -72,7 +74,7 @@ static void check_selection_encoding(struct x11_display *d, struct x11_surface *
XSelectionEvent reply = {.requestor = pending->window, .property = property};
selection_notify(d, &reply);
struct yasl_private_event event;
- assert(yasl_private_surface_poll_event(&s->base, &event));
+ assert(yasl_private_display_poll_event(&d->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_PRIVATE_TRANSFER_OK) {
@@ -85,7 +87,7 @@ static void check_selection_encoding(struct x11_display *d, struct x11_surface *
pending->timeout = 0;
paste_timeout(pending, 0, PASTE_TIMEOUT_NS);
}
- assert(!yasl_private_surface_poll_event(&s->base, &event));
+ assert(!yasl_private_display_poll_event(&d->base, &event));
}
struct paste_request *rejected = calloc(1, sizeof(*rejected));
@@ -100,7 +102,7 @@ static void check_selection_encoding(struct x11_display *d, struct x11_surface *
XSelectionEvent no_property = {.requestor = rejected->window, .property = None};
selection_notify(d, &no_property);
struct yasl_private_event event;
- assert(yasl_private_surface_poll_event(&s->base, &event));
+ assert(yasl_private_display_poll_event(&d->base, &event));
assert(event.type == YASL_PRIVATE_EVENT_PASTE && event.paste.request_id == 99);
assert(event.paste.status == YASL_PRIVATE_TRANSFER_FAILED);
}
@@ -336,21 +338,21 @@ int main(void)
/* Native creation and keymap updates may already have queued focus or
* reset input on the shared display stream. Isolate this synthetic key. */
struct yasl_private_event event;
- while (yasl_private_surface_poll_event(surface, &event)) {}
+ while (yasl_private_display_poll_event(base, &event)) {}
XKeyEvent native = {.type = KeyPress, .display = d->native,
.window = s->window, .keycode = code};
key_event(s, &native, false);
- assert(yasl_private_surface_poll_event(surface, &event));
+ assert(yasl_private_display_poll_event(base, &event));
assert(event.type == YASL_PRIVATE_EVENT_KEY && event.key.key == YASL_KEY_A);
assert(event.key.codepoint == cases[i].label);
- assert(yasl_private_surface_poll_event(surface, &event));
+ assert(yasl_private_display_poll_event(base, &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_private_surface_poll_event(surface, &event));
+ assert(!yasl_private_display_poll_event(base, &event));
native.type = KeyRelease;
key_event(s, &native, false);
- assert(yasl_private_surface_poll_event(surface, &event) && event.type == YASL_PRIVATE_EVENT_KEY);
- assert(!yasl_private_surface_poll_event(surface, &event));
+ assert(yasl_private_display_poll_event(base, &event) && event.type == YASL_PRIVATE_EVENT_KEY);
+ assert(!yasl_private_display_poll_event(base, &event));
}
XChangeKeyboardMapping(d->native, code, width, saved, 1);
XSync(d->native, False);
diff --git a/tests/x11/test_state.c b/tests/x11/test_state.c
index 4696e60..0c36638 100644
--- a/tests/x11/test_state.c
+++ b/tests/x11/test_state.c
@@ -28,12 +28,15 @@ int state_property(Display *display, Window window, Atom property,
return Success;
}
-static void state_changed(struct yasl_surface *surface, uint32_t state, void *ud)
+static void collect(struct yasl_private_display *display)
{
- (void)ud;
- assert(yasl_private_surface_state(surface) == state);
- reported_state = state;
- notifications++;
+ struct yasl_private_event event;
+ while (yasl_private_display_poll_event(display, &event)) {
+ assert(event.type == YASL_PRIVATE_EVENT_WINDOW_STATE);
+ assert(yasl_private_surface_state(event.surface) == event.state.flags);
+ reported_state = event.state.flags;
+ notifications++;
+ }
}
/* Build an XSETTINGS blob in either byte order. */
@@ -98,35 +101,45 @@ int main(void)
display.native = (Display *)&display;
struct x11_surface surface = {.base = {.display = &display.base,
.state = YASL_PRIVATE_STATE_ACTIVATED}, .window = 42};
- set_callbacks(&surface.base, &(struct yasl_private_window_cbs){.state = state_changed}, NULL);
+ assert(yasl_private_events_open(&display.base));
+ assert(yasl_private_events_register(&surface.base));
properties[0] = display.fullscreen;
property_count = 1;
update_state(&surface);
+ collect(&display.base);
assert(notifications == 1);
assert(reported_state == (YASL_PRIVATE_STATE_FULLSCREEN | YASL_PRIVATE_STATE_ACTIVATED));
update_state(&surface);
+ collect(&display.base);
assert(notifications == 1);
/* Both maximized axes are required; activation survives property changes. */
properties[0] = display.maximized_h;
update_state(&surface);
+ collect(&display.base);
assert(notifications == 2 && reported_state == YASL_PRIVATE_STATE_ACTIVATED);
properties[1] = display.maximized_v;
property_count = 2;
update_state(&surface);
+ collect(&display.base);
assert(notifications == 3);
assert(reported_state == (YASL_PRIVATE_STATE_MAXIMIZED | YASL_PRIVATE_STATE_ACTIVATED));
properties[2] = display.fullscreen;
property_count = 3;
update_state(&surface);
+ collect(&display.base);
assert(notifications == 4);
assert(reported_state == (YASL_PRIVATE_STATE_FULLSCREEN | YASL_PRIVATE_STATE_MAXIMIZED | YASL_PRIVATE_STATE_ACTIVATED));
property_count = 0;
update_state(&surface);
+ collect(&display.base);
assert(notifications == 5 && reported_state == YASL_PRIVATE_STATE_ACTIVATED);
update_state(&surface);
+ collect(&display.base);
assert(notifications == 5);
+ yasl_private_events_unregister(&surface.base);
+ yasl_private_events_close(&display.base);
return 0;
}
diff --git a/tests/x11/test_tablet.c b/tests/x11/test_tablet.c
index be5da4c..8d9106e 100644
--- a/tests/x11/test_tablet.c
+++ b/tests/x11/test_tablet.c
@@ -24,31 +24,32 @@ struct drag_test_recorder {
struct yasl_private_vector2i last_pos;
};
-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_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_private_vector2i last_pos;
};
-static void on_test_drop(struct yasl_surface *s, enum yasl_private_drop_event ev,
- struct yasl_private_vector2i pos, void *ud)
+static void collect(struct yasl_private_display *display, struct yasl_surface *first,
+ struct yasl_surface *second, struct drag_test_recorder *a,
+ struct drag_test_recorder *b, struct drop_test_recorder *drop)
{
- (void)s;
- struct drop_test_recorder *rec = ud;
- rec->last_pos = pos;
- if (ev == YASL_PRIVATE_DROP_OVER) rec->over_count++;
- else if (ev == YASL_PRIVATE_DROP_LEAVE) rec->leave_count++;
+ struct yasl_private_event event;
+ while (yasl_private_display_poll_event(display, &event)) {
+ if (event.type == YASL_PRIVATE_EVENT_DRAG) {
+ assert(event.surface == first || event.surface == second);
+ struct drag_test_recorder *rec = event.surface == first ? a : b;
+ rec->last_pos = event.drag.pos;
+ if (event.drag.action == YASL_PRIVATE_DRAG_OVER) rec->over_count++;
+ else if (event.drag.action == YASL_PRIVATE_DRAG_LEAVE) rec->leave_count++;
+ else if (event.drag.action == YASL_PRIVATE_DRAG_DROP) rec->drop_count++;
+ } else if (event.type == YASL_PRIVATE_EVENT_DROP_HOVER) {
+ assert(event.surface == first);
+ drop->last_pos = event.drop.pos;
+ if (event.drop.action == YASL_PRIVATE_DROP_OVER) drop->over_count++;
+ else if (event.drop.action == YASL_PRIVATE_DROP_LEAVE) drop->leave_count++;
+ }
+ }
}
static void on_test_drag_end(void *ud, enum yasl_private_drag_end how)
@@ -81,7 +82,7 @@ static void test_x11_gaps(struct x11_display *d, struct x11_surface *s)
struct yasl_private_popup_spec valid_spec = {
.size = {100, 120},
.anchor = {30, 40, 50, 60},
- .beside = false,
+ .anchor_edges = 6, .gravity = 8, .constraints = 15,
.content_offset = {5, 10},
};
assert(popup_spec_valid(s, &valid_spec));
@@ -93,7 +94,7 @@ static void test_x11_gaps(struct x11_display *d, struct x11_surface *s)
/* 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},
@@ -118,7 +119,7 @@ static void test_x11_gaps(struct x11_display *d, struct x11_surface *s)
popup_calculate_position(d, s, &positioned, &x, &y, &actual_size);
assert(x == 1920 - actual_size.x && actual_size.x == 20);
- valid_spec.beside = true;
+ valid_spec.anchor_edges = 7;
popup_calculate_position(d, s, &valid_spec, &x, &y, &actual_size);
assert(x == 30 + 50 - 5);
assert(y == 40 - 10);
@@ -133,7 +134,7 @@ static void test_x11_gaps(struct x11_display *d, struct x11_surface *s)
struct yasl_private_popup_spec repo_spec = {
.size = {150, 180},
.anchor = {10, 20, 30, 40},
- .beside = false,
+ .anchor_edges = 6, .gravity = 8, .constraints = 15,
.content_offset = {0, 0},
};
assert(surface_popup_reposition(popup_base, &repo_spec));
@@ -149,10 +150,10 @@ 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_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);
+ struct drop_test_recorder drec = {0};
+ assert(yasl_private_events_open(&d->base));
+ assert(yasl_private_events_register(&s->base));
+ assert(yasl_private_events_register(&s2.base));
enum yasl_private_drag_end end_reason = (enum yasl_private_drag_end)-1;
struct yasl_private_drag_listener l = {.end = on_test_drag_end};
@@ -163,6 +164,7 @@ static void test_x11_gaps(struct x11_display *d, struct x11_surface *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);
+ collect(&d->base, &s->base, &s2.base, &rec1, &rec2, &drec);
assert(rec1.over_count == 1);
assert(rec1.last_pos.x == 12 && rec1.last_pos.y == 34);
@@ -171,6 +173,7 @@ static void test_x11_gaps(struct x11_display *d, struct x11_surface *s)
mev.event_x = 56.0;
mev.event_y = 78.0;
xi_event(d, &cookie);
+ collect(&d->base, &s->base, &s2.base, &rec1, &rec2, &drec);
assert(rec1.leave_count == 1);
assert(rec2.over_count == 1);
assert(rec2.last_pos.x == 56 && rec2.last_pos.y == 78);
@@ -179,6 +182,7 @@ static void test_x11_gaps(struct x11_display *d, struct x11_surface *s)
XIDeviceEvent rel = {.evtype = XI_ButtonRelease, .sourceid = 8, .event = 43, .detail = 1};
cookie = (XGenericEventCookie){.evtype = XI_ButtonRelease, .data = &rel};
xi_event(d, &cookie);
+ collect(&d->base, &s->base, &s2.base, &rec1, &rec2, &drec);
assert(rec2.drop_count == 1);
assert(end_reason == YASL_PRIVATE_DRAG_DROPPED);
assert(!d->drag.active);
@@ -188,8 +192,10 @@ static void test_x11_gaps(struct x11_display *d, struct x11_surface *s)
cookie = (XGenericEventCookie){.evtype = XI_Motion, .data = &mev};
mev.event = 42;
xi_event(d, &cookie);
+ collect(&d->base, &s->base, &s2.base, &rec1, &rec2, &drec);
assert(rec1.over_count == 2);
drag_cancel(&d->base);
+ collect(&d->base, &s->base, &s2.base, &rec1, &rec2, &drec);
assert(rec1.leave_count == 2);
assert(end_reason == YASL_PRIVATE_DRAG_CANCELLED);
assert(!d->drag.active);
@@ -203,9 +209,13 @@ static void test_x11_gaps(struct x11_display *d, struct x11_surface *s)
assert(end_reason == YASL_PRIVATE_DRAG_CANCELLED);
assert(!d->drag.active);
struct yasl_private_event reset_ev;
- assert(yasl_private_surface_poll_event(&s->base, &reset_ev));
+ /* The display stream also carries the reset of the second surface. */
+ do { assert(yasl_private_display_poll_event(&d->base, &reset_ev)); }
+ while (reset_ev.type != YASL_PRIVATE_EVENT_INPUT_RESET || reset_ev.surface != &s->base);
assert(reset_ev.type == YASL_PRIVATE_EVENT_INPUT_RESET);
+ collect(&d->base, &s->base, &s2.base, &rec1, &rec2, &drec);
+
/* 4. Drag image parameter */
uint32_t pixels[16] = {0xFF00FF00};
struct yasl_private_drag_image img = {.pixels = pixels, .size = {4, 4}, .hotspot = {2, 2}};
@@ -214,6 +224,8 @@ static void test_x11_gaps(struct x11_display *d, struct x11_surface *s)
assert(drag_carry(&s->base, (struct yasl_private_vector2i){10, 10}));
drag_cancel(&d->base);
+ collect(&d->base, &s->base, &s2.base, &rec1, &rec2, &drec);
+
/* 5. XDND drop-target events and URI parsing */
size_t out_len = 0;
char *parsed = parse_file_uris("file:///tmp/doc.txt\r\n", 21, &out_len);
@@ -236,9 +248,6 @@ static void test_x11_gaps(struct x11_display *d, struct x11_surface *s)
d->xdnd_drop = 13;
d->uri_list = 20;
- struct drop_test_recorder drec = {0};
- cbs1.drop = on_test_drop;
- set_callbacks(&s->base, &cbs1, &drec);
XClientMessageEvent enter_msg = {
.type = ClientMessage,
@@ -256,6 +265,7 @@ static void test_x11_gaps(struct x11_display *d, struct x11_surface *s)
.data.l = {99, 0, (100 << 16) | 200, 1000, 0},
};
handle_client_message(d, s, &pos_msg);
+ collect(&d->base, &s->base, &s2.base, &rec1, &rec2, &drec);
assert(drec.over_count == 1);
assert(drec.last_pos.x == 100 && drec.last_pos.y == 200);
@@ -266,10 +276,12 @@ static void test_x11_gaps(struct x11_display *d, struct x11_surface *s)
.data.l = {99, 0, 0, 0, 0},
};
handle_client_message(d, s, &leave_msg);
+ collect(&d->base, &s->base, &s2.base, &rec1, &rec2, &drec);
assert(drec.leave_count == 1);
handle_client_message(d, s, &enter_msg);
handle_client_message(d, s, &pos_msg);
+ collect(&d->base, &s->base, &s2.base, &rec1, &rec2, &drec);
assert(drec.over_count == 2);
XClientMessageEvent drop_msg = {
@@ -279,17 +291,22 @@ static void test_x11_gaps(struct x11_display *d, struct x11_surface *s)
.data.l = {99, 0, 1005, 0, 0},
};
handle_client_message(d, s, &drop_msg);
+ collect(&d->base, &s->base, &s2.base, &rec1, &rec2, &drec);
assert(drec.leave_count == 2);
assert(d->pending_drop.active);
/* 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(yasl_private_display_poll_event(&d->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"));
+ yasl_private_events_unregister(&s->base);
+ yasl_private_events_unregister(&s2.base);
+ yasl_private_events_close(&d->base);
+
/* Clean up s2 */
s->next = NULL;
input_queue_clear(&s->input);
diff --git a/tests/x11/test_tablet_native.c b/tests/x11/test_tablet_native.c
index 828082c..f4f8014 100644
--- a/tests/x11/test_tablet_native.c
+++ b/tests/x11/test_tablet_native.c
@@ -2,7 +2,10 @@
#define main tablet_example_main
#include "../../examples/tablet.c"
#undef main
-#include <common/private_native.h>
+#include <yasl/native/x11.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
@@ -55,41 +58,53 @@ static int connect_tool(const char *path)
return fd;
}
-static void native_draw(struct yasl_surface *surface, struct yasl_private_frame *frame, void *ud)
-{
- (void)surface;
- draw(ud, surface, frame);
-}
+struct canvas_state {
+ struct yasl_pen_payload pen;
+ uint32_t *pixels;
+ int width, height, painted_width, painted_height;
+ bool down;
+};
-static void native_configure(struct yasl_surface *surface, struct yasl_private_geometry geometry, void *ud)
+static void render_event(yasl_surface *surface, struct canvas_state *state, const yasl_event *event)
{
- input(ud, &(struct yasl_private_event){.surface = surface, .type = YASL_PRIVATE_EVENT_WINDOW_RESIZE,
- .resize = {.geometry = geometry}});
+ if (event->type == YASL_EVENT_PEN) {
+ state->pen = event->pen;
+ state->down = event->pen.in_contact;
+ }
+ state->pixels = canvas(surface, &state->width, &state->height,
+ &state->painted_width, &state->painted_height, false);
+ assert(state->pixels);
+ if (event->type == YASL_EVENT_PEN && state->down &&
+ (event->pen.action == YASL_PEN_DOWN || event->pen.action == YASL_PEN_MOVE)) {
+ double scale = yasl_surface_get_scale(surface);
+ stamp(state->pixels, state->width, state->height,
+ event->pen.x * scale, event->pen.y * scale,
+ (1.5 + 12 * event->pen.pressure) * scale, event->pen.tool == YASL_PEN_ERASER);
+ }
+ assert(yasl_cpu_present(surface));
}
-static void native_input(struct app *app, const struct yasl_private_event *event)
+static void drain(yasl_surface *surface, struct canvas_state *state)
{
- input(app, event);
+ yasl_event event;
+ int result;
+ while ((result = yasl_wait_event(&event, 0)) > 0)
+ render_event(surface, state, &event);
+ assert(result == 0);
}
-static void pump(int fd, struct yasl_private_display *display, struct yasl_surface *surface, struct app *app)
+static void pump(int fd, yasl_surface *surface, struct canvas_state *state)
{
xf86ITEventWaitForSync sync = {{sizeof(sync), XF86IT_EVENT_WAIT_FOR_SYNC}};
send_all(fd, &sync, sizeof(sync));
xf86ITResponseHeader response;
receive_all(fd, &response, sizeof(response));
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_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_private_surface_schedule_redraw(surface);
- }
- yasl_private_display_flush(display);
- assert(!app->failed);
+ /* The driver acknowledgment guarantees XI2 processing has finished. */
+ XSync(yasl_x11_display(surface), False);
+ drain(surface, state);
+ /* Public polling submits the CPU frame before the native readback. */
+ XSync(yasl_x11_display(surface), False);
}
static void set_eraser_property(Display *display)
@@ -116,23 +131,16 @@ 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_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_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);
+ struct canvas_state app = {0};
+ assert(yasl_set_backend(YASL_BACKEND_X11));
+ yasl_surface *surface = yasl_surface_create("YASL native pressure test", 500, 400, YASL_SURFACE_CPU);
+ assert(surface && (yasl_surface_features(surface) & YASL_CAP_TABLET));
+ Display *x = yasl_x11_display(surface);
+ Window window = (Window)yasl_x11_window(surface);
XMoveWindow(x, window, 0, 0);
XSetInputFocus(x, window, RevertToParent, CurrentTime);
XSync(x, False);
- assert(yasl_private_display_dispatch(display, 0) == 0);
- yasl_private_display_flush(display);
+ drain(surface, &app);
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};
@@ -143,52 +151,50 @@ int main(int argc, char **argv)
.is_prox_in = 1, .valuators = motion.valuators};
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_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);
+ pump(pen_fd, surface, &app);
+ assert(!app.down && app.pen.tool == YASL_PEN_PEN);
+ assert(app.pen.x == 150 && app.pen.y == 200);
+ assert(app.pixels[(size_t)200 * app.width + 150] == PAPER);
xf86ITEventButton button = {.header = {sizeof(button), XF86IT_EVENT_BUTTON},
.is_absolute = 1, .button = 1, .is_press = 1, .valuators = motion.valuators};
button.valuators.valuators[4] = 250; /* Driver pressure range is 0..1000. */
send_all(pen_fd, &button, sizeof(button));
- pump(pen_fd, display, surface, &app);
- assert(app.down && app.pointer.pen.pressure == 16384);
- assert(app.canvas[(size_t)200 * app.geometry.size.x + 150] == INK &&
- app.canvas[(size_t)200 * app.geometry.size.x + 170] == PAPER);
+ pump(pen_fd, surface, &app);
+ assert(app.down && fabs(app.pen.pressure - 0.25) < 0.001);
+ assert(app.pixels[(size_t)200 * app.width + 150] == INK &&
+ app.pixels[(size_t)200 * app.width + 160] == PAPER);
motion.valuators.mask[0] = 1 << 4; /* No position change. */
motion.valuators.valuators[4] = 1000;
send_all(pen_fd, &motion, sizeof(motion));
- pump(pen_fd, display, surface, &app);
- assert(app.down && app.pointer.pen.pressure == 65535);
- assert(app.canvas[(size_t)200 * app.geometry.size.x + 170] == INK);
+ pump(pen_fd, surface, &app);
+ assert(app.down && app.pen.pressure == 1.0);
+ assert(app.pixels[(size_t)200 * app.width + 160] == INK);
/* Check the actual window's pixels too, after the example presents. */
- XImage *image = XGetImage(x, window, 170, 200, 1, 1, AllPlanes, ZPixmap);
+ XImage *image = XGetImage(x, window, 160, 200, 1, 1, AllPlanes, ZPixmap);
assert(image && (XGetPixel(image, 0, 0) & 0xffffff) == (INK & 0xffffff));
XDestroyImage(image);
button.is_press = 0;
button.valuators.mask[0] = 0; /* Release omits all valuators. */
send_all(pen_fd, &button, sizeof(button));
- pump(pen_fd, display, surface, &app);
- assert(!app.down && !app.pointer.pen.pressure);
+ pump(pen_fd, surface, &app);
+ assert(!app.down && !app.pen.pressure);
send_all(eraser_fd, &proximity, sizeof(proximity));
button.is_press = 1;
button.valuators = proximity.valuators;
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_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);
+ pump(eraser_fd, surface, &app);
+ assert(app.down && app.pen.tool == YASL_PEN_ERASER && app.pen.pressure == 1.0);
+ assert(app.pixels[(size_t)200 * app.width + 150] == PAPER &&
+ app.pixels[(size_t)200 * app.width + 160] == PAPER);
button.is_press = 0;
send_all(eraser_fd, &button, sizeof(button));
- pump(eraser_fd, display, surface, &app);
- assert(!app.down && !app.pointer.pen.pressure);
+ pump(eraser_fd, surface, &app);
+ assert(!app.down && !app.pen.pressure);
close(pen_fd);
close(eraser_fd);
- free(app.canvas);
- yasl_private_surface_destroy(surface);
- yasl_private_display_close(display);
+ yasl_shutdown();
puts("Native Xorg pen pressure, stationary pressure, release, and eraser drawing passed.");
return 0;
}