1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
# Surface and input guide
## Lifetime, threads, and errors
The first successful `yasl_surface_create` or `yasl_gl_surface_create` initializes
shared native state. Subsequent surfaces share one backend. Optional `yasl_set_app_id`
and `yasl_set_backend` configure the next initialization; they fail after initialization.
Destroying the final surface preserves shared state. `yasl_shutdown` destroys remaining
surfaces, releases the backend, and restores defaults. Release application-owned GPU
objects before their surface or shutdown. Parent destruction destroys popup descendants.
Creation, window operations, event pumping, and shutdown use the first creation's
thread, which must be the main thread on Cocoa. GL context binding/drawing/swapping
may use a rendering thread; detach its context before destroying the window. The
application synchronizes renderer state/geometry and joins workers before shutdown.
`yasl_wake` is thread-safe and does nothing before initialization or after shutdown.
Constructors return NULL on failure; fallible mutations return bool. Event reads
return 1 for an event, 0 for empty/timeout/wake, -1 for failure. `yasl_get_error`
returns a stable per-thread error and static description; `yasl_get_native_error`
returns supplementary native diagnostics. Success does not clear a preceding error.
Valid-object size/scale/userdata getters return ordinary values. Destroyed pointers
are invalid. Strings passed to creation and setters are copied; userdata is borrowed.
## Events and coordinates
`yasl_poll_event` and `yasl_wait_event` process native events and consume one shared
FIFO. No manual dispatch/flush cycle. A failed/empty read leaves output unchanged.
Wait timeout zero polls, negative waits for work, positive milliseconds bound waiting.
A wake can return zero. Polling before initialization returns zero; waiting reports
NOT_INITIALIZED. Close and quit are requests; the application decides how to respond.
Display loss is a terminal native failure; destroy resources and shut down.
Read the union member selected by type. Events own their text through
`yasl_event_release`, independently of later polls and source destruction. Release
every successful event exactly once; numeric events need no allocation to release.
Do not duplicate event ownership by shallow copying. Event surface pointers remain
borrowed and become invalid when their surface is destroyed. Undelivered events for
a destroyed surface are canceled. Sequence orders capture by YASL, not OS causality.
Timestamps use monotonic nanoseconds; native_time states whether normalized native
sample timing was available or capture time was used.
Creation dimensions, pointer/pen coordinates, popup placement, caret, and CSD actions
use logical content units. Fractional positions use doubles. Image dimensions,
byte stride, framebuffer size, and damage use device pixels. Query actual framebuffer
extent for swapchain/viewport sizing; scale alone need not determine integer rounding.
Request functions report acceptance, while geometry/state events report actual results.
There is no portable absolute window-position promise. State's known mask distinguishes
reported false from unavailable state fields.
## Rendering
GPU creation (flags zero) does not create a device, context, or software framebuffer.
One presenter attaches to each surface. Incompatible second attachments fail.
- Vulkan: inject vkGetInstanceProcAddr, query instance extensions and flags through
the live GPU surface, create the instance, then `yasl_vulkan_create_surface`.
The application owns VkInstance/VkDevice/queues/swapchains/VkSurfaceKHR, handles
image acquisition, synchronization and recreation, and presents with Vulkan.
- Metal: `yasl_metal_layer` returns a borrowed CAMetalLayer on Cocoa. YASL owns
the native view/layer and updates its dimensions. The app sets device/pixel format,
obtains drawables, and submits/presents commands. No additional YASL present call.
- GL: `yasl_gl_surface_create` accepts title, dimensions, flags, a per-call int
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.
- 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;
explicit lists must be nonempty. Initial submission and changed extent require full
images. Later patches update the retained submitted image. Source bytes are copied
before return, so the app may reuse/free them. Native uploads may copy the entire
retained image, but never unsubmitted source changes. `yasl_cpu_read_pixels` reads
that submitted CPU image, not the composited screen.
GPU creation/presentation uses native requests directly; YASL acknowledges Wayland
configuration before external GPU submission. Native refresh events can be handled
in the ordinary loop. An optional refresh callback permits drawing while the native
window system remains in a modal resize path. It runs only during pumping and never
recursively; it may query geometry and render, but must not pump, create/destroy
surfaces, or shut down. Geometry events may not yet have been consumed, so query
current geometry there. Without a hook, CPU exposes reuse committed pixels and GPU
redraw waits for the application's loop to resume.
## Keyboard, pen, and scrolling
Physical YASL_KEY names identify US keyboard positions independent of layout.
Layout labels support shortcuts; committed UTF-8 TEXT is for document insertion.
Keys and text need not correspond one-to-one. Input RESET/focus loss cancels held
application input. Keep pointer and pen streams separate to avoid duplicate strokes.
PEN events carry connection-local device/tool IDs, tool type, proximity/contact,
button transitions, coherent position and axes. Pressure is 0..1; zero does not end
contact. Tilt uses degrees -90..90; rotation uses clockwise degrees; distance is
normalized, not a physical unit. Axis validity distinguishes unavailable from zero.
Changed masks indicate native updates. Tools/axes depend on hardware and backend;
IDs do not guarantee persistent hardware serials. Pen-generated mouse duplicates
are suppressed where recognized; do not treat tool class as a multi-contact API.
SCROLL preserves wheel-line and precise-pixel values with validity, source, phase,
and momentum metadata where supplied. Applications choose layout pixels per wheel
line. X11 supplies native wheel/smooth valuator data where available. Missing native
metadata stays explicitly unavailable instead of being inferred.
## Text input, clipboard, popups, and drags
Activate text input for a text control with `yasl_surface_set_text_input`. Set purpose,
caret, and copied UTF-8 surrounding text/selection/revision through direct setters.
Snapshot offsets and TEXT_EDIT replacement ranges are UTF-8 bytes; COMPOSITION is
uncommitted preedit. Apply a matching-revision edit once, update your snapshot, and
ignore/rebase stale edits. Activation generation distinguishes controls. Ordinary key
text remains TEXT. Never insert preedit as committed document text. Wayland requires
text-input-v3 for native IME; absence is reported as unsupported. Cocoa translates
native UTF-16 replacement/deletion to snapshot UTF-8 ranges. X11 XIM supplies ordinary
text/preedit but cannot promise surrounding-text replacement support.
Clipboard set copies UTF-8; read returns a nonzero request ID and later CLIPBOARD
completion with OK, UNAVAILABLE, or FAILED. Empty successful text is distinct from
failure. Destroying the target cancels transfer and delivery. Primary selection stays
independent and reports unsupported where unavailable. Linux external transfers time
out after 30 seconds; X11 currently lacks INCR for large transfers. File drops carry
URI-list text; `yasl_drop_next_path` decodes supported local paths into caller buffers.
Popup arguments use logical parent anchor coordinates, anchor/gravity directions,
and flip/slide/resize constraint bits. Popup size includes its content. Destroying a
parent retires descendants too. Native grabs, CSD moves/resizes, menus, and surface
drags require a live triggering press event; unsupported/expired input fails explicitly.
Surface drags support application tab/window carry; they are not an arbitrary MIME
source API. Check operation results even when feature bits advertise support.
## Backend limits
Wayland support varies by compositor protocols; no portable absolute placement or
minimized-state query is assumed. X11 currently reports unit scale and lacks an
implemented relative-pointer lock. Cocoa requires macOS 14+; native Metal/GL and
Objective-C paths require validation on macOS. EGL/wayland-egl and Vulkan SDK support
are independently optional at build time. Feature bits describe implementation/
server support, not guaranteed permission or attached hardware. The current work was
compiled and tested on Linux; macOS validation remains a separate required check.
|