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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
|
/**
* @file
* Portable desktop surfaces, CPU drawing, input, and display dispatch.
*
* All calls and callbacks use the display's opening thread (the main thread on
* Cocoa), unless explicitly documented otherwise. Userdata is borrowed; callback
* tables and creation specs are copied. Do not recursively dispatch/flush or
* destroy a display/loop while dispatch or a callback is active. Destroy child
* popups before parents, surfaces before displays, displays before borrowed loops.
* Surface destruction from its own callback is supported; stop using it immediately.
*
* Zero-initialize option and callback structs before setting fields. Pointers to
* destroyed objects are invalid, even for getters and destroy functions. NULL
* handling is documented per function; it does not make freed pointers safe.
* Only functions explicitly documenting errno guarantee a diagnostic there.
* Other boolean results report success/availability; void setters are best effort.
*
* Toplevel creation sizes use logical pixels. Geometry, framebuffers, pointer
* positions, damage, IME carets, popup specs, and drag offsets use device pixels.
* Coordinates have their origin at the upper left; x grows right and y grows down.
* Scale is an integer ratio with YASL_SCALE_UNIT (120) representing 1x.
* See the application guide for the dispatch/poll/flush cycle and backend limits.
*/
#ifndef YASL_H
#define YASL_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <limits.h>
#include <float.h>
#include <math.h>
#include "yasl/timing.h"
#include "yasl/keycodes.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Public shared-library symbol visibility annotation. */
#if defined(_WIN32) || defined(__CYGWIN__)
#if defined(YASL_BUILD_SHARED)
#define YASL_API __declspec(dllexport)
#elif defined(YASL_SHARED)
#define YASL_API __declspec(dllimport)
#else
#define YASL_API
#endif
#elif defined(__GNUC__) && __GNUC__ >= 4
#define YASL_API __attribute__((visibility("default")))
#else
#define YASL_API
#endif
struct yasl_display;
struct yasl_surface;
struct yasl_loop;
/* Geometry */
/** A two-dimensional integer size, position, or offset; units depend on the caller. */
struct yasl_vector2i {
/** Horizontal coordinate or width. */
int x;
/** Vertical coordinate or height. */
int y;
};
/** Two-dimensional fractional offset; units depend on the containing structure. */
struct yasl_vector2d {
/** Horizontal component. */
double x;
/** Vertical component. */
double y;
};
/** Integer rectangle; origin is upper left and extents must be nonnegative. */
struct yasl_rect2i {
/** Left coordinate. */
int x;
/** Top coordinate. */
int y;
/** Nonnegative horizontal extent. */
int width;
/** Nonnegative vertical extent. */
int height;
};
/** Scale numerator representing 1x. */
#define YASL_SCALE_UNIT 120
/** Backend minimum logical dimension used when constraining toplevel sizes. */
#define YASL_MIN_LOGICAL_PX 64
/* Nearest integer, ties away from zero. Zero scale returns zero; finite
* out-of-range results saturate. Non-finite logical coordinates return zero. */
/** Convert a logical coordinate to device pixels, rounding ties away from zero.
* @param logical Logical coordinate; non-finite values return zero.
* @param scale_120 Scale numerator; zero returns zero.
* @return Rounded device coordinate, saturated to the range of int.
*/
static inline int yasl_scale_to_device(double logical, uint32_t scale_120)
{
if (!scale_120 || !(logical >= -DBL_MAX && logical <= DBL_MAX)) return 0;
double px = (scale_120 == YASL_SCALE_UNIT) ? logical : (logical * ((double)scale_120 / YASL_SCALE_UNIT));
if (px >= INT_MAX) return INT_MAX;
if (px <= INT_MIN) return INT_MIN;
return (int)(px + copysign(0.5, px));
}
/** Convert a device coordinate to logical pixels, rounding ties away from zero.
* @param device Device coordinate.
* @param scale_120 Scale numerator; zero returns zero.
* @return Rounded logical coordinate, saturated to the range of int.
*/
static inline int yasl_scale_to_logical(int device, uint32_t scale_120)
{
if (!scale_120) return 0;
if (scale_120 == YASL_SCALE_UNIT) return device;
int64_t px = (int64_t)device * YASL_SCALE_UNIT;
int64_t half = (int64_t)(scale_120 / 2);
int64_t bias = (px < 0) ? -half : half;
px = (px + bias) / scale_120;
if (px > INT_MAX) return INT_MAX;
if (px < INT_MIN) return INT_MIN;
return (int)px;
}
/* Capabilities */
/** Optional backend/server features, returned as a bitmask by yasl_display_caps(). */
enum yasl_display_cap : uint32_t {
YASL_CAP_POPUPS = 1 << 0, /**< Popup creation and placement. */
YASL_CAP_DRAG = 1 << 1, /**< Surface-drag source and target support. */
YASL_CAP_DRAG_CARRY = 1 << 2, /**< Carry a toplevel during a drag. */
YASL_CAP_PLACE_WINDOW = 1 << 3, /**< Place a window relative to the pointer. */
YASL_CAP_PRIMARY_SELECTION = 1 << 4, /**< Separate primary selection. */
YASL_CAP_CSD = 1 << 5, /**< Backend advertises client decoration support; check each action result. */
YASL_CAP_NATIVE_GRAPHICS = 1 << 6, /**< Application-managed native rendering. */
YASL_CAP_FRAME_PACING = 1 << 7, /**< Compositor/display-driven draws. */
/* Backend/protocol supports tablet axes, independent of attached hardware. */
YASL_CAP_TABLET = 1 << 8, /**< Tablet protocol support, independent of attached hardware. */
};
/** Independent selections. An unsupported selection never aliases the clipboard. */
enum yasl_selection : uint8_t {
YASL_CLIPBOARD, /**< Explicit copy/paste selection. */
YASL_PRIMARY, /**< Independent primary selection, if supported. */
};
/** Reported surface state flags; absent flags may also mean unsupported state. */
enum yasl_surface_state : uint32_t {
YASL_STATE_FULLSCREEN = 1 << 0, /**< Fullscreen. */
YASL_STATE_MAXIMIZED = 1 << 1, /**< Maximized. */
YASL_STATE_ACTIVATED = 1 << 2, /**< Active window. */
YASL_STATE_SUSPENDED = 1 << 3, /**< Compositor reports suspension. */
YASL_STATE_CSD = 1 << 4, /**< Backend reports client-side decorations. */
};
/** System cursor shapes. HIDDEN preserves pointer input; NONE is its compatibility alias. */
enum yasl_cursor {
YASL_CURSOR_ARROW, /**< Default arrow. */
YASL_CURSOR_TEXT, /**< Text insertion. */
YASL_CURSOR_LINK, /**< Link/pointer hand. */
YASL_CURSOR_CROSSHAIR, /**< Crosshair. */
YASL_CURSOR_MOVE, /**< Move in any direction. */
YASL_CURSOR_RESIZE_NWSE, /**< Northwest/southeast resize. */
YASL_CURSOR_RESIZE_NESW, /**< Northeast/southwest resize. */
YASL_CURSOR_RESIZE_EW, /**< Horizontal resize. */
YASL_CURSOR_RESIZE_NS, /**< Vertical resize. */
YASL_CURSOR_HIDDEN, /**< Hidden system cursor; pointer input continues. */
YASL_CURSOR_NONE = YASL_CURSOR_HIDDEN, /**< Compatibility alias for HIDDEN. */
};
/** Valid interactive resize edges; combinations are restricted to the named values. */
enum yasl_resize_edge : uint32_t {
YASL_EDGE_NONE = 0, /**< No resize edge; rejected by interactive resize. */
YASL_EDGE_TOP = 1, /**< Top edge. */
YASL_EDGE_BOTTOM = 2, /**< Bottom edge. */
YASL_EDGE_LEFT = 4, /**< Left edge. */
YASL_EDGE_TOP_LEFT = 5, /**< Top-left corner. */
YASL_EDGE_BOTTOM_LEFT = 6, /**< Bottom-left corner. */
YASL_EDGE_RIGHT = 8, /**< Right edge. */
YASL_EDGE_TOP_RIGHT = 9, /**< Top-right corner. */
YASL_EDGE_BOTTOM_RIGHT = 10, /**< Bottom-right corner. */
};
/* Damage & Framebuffer
* CPU pixels are tightly packed premultiplied ARGB8888 (0xAARRGGBB).
* Size, pointer positions, IME caret and damage use device pixels; surface
* toplevel creation sizes use logical pixels. Damage is a hint: backends may upload
* the whole frame. Every pixel must contain valid content on each draw.
*/
/** Maximum number of damage rectangles in one presentation. */
#define YASL_DAMAGE_MAX 64
/** Damage hints for one presentation; every target still needs complete valid pixels. */
struct yasl_damage_list {
/** -1: full target; 0: no damaged rectangles; otherwise number of rects. */
int n;
/** Reserved hint; callers may leave zero. Core presentation uses rects. */
struct yasl_rect2i bounds;
/** First n rectangles, in device pixels; ignored for n == -1. */
struct yasl_rect2i rects[YASL_DAMAGE_MAX];
};
/** Borrowed draw target, valid only for the current draw callback. Never free pixels. */
struct yasl_framebuffer {
/** Opaque draw identity. Preserve it and all target fields when copying. */
uint64_t generation;
/** Writable premultiplied ARGB8888, row stride size.x * sizeof(uint32_t); may be NULL for native rendering. */
uint32_t *pixels;
/** Target extent in device pixels. */
struct yasl_vector2i size;
};
/** One draw invocation. Do not retain its pointer after the callback returns. */
struct yasl_frame {
/** Surface being drawn. */
struct yasl_surface *surface;
/** Target to initialize and present before returning. */
struct yasl_framebuffer target;
};
/* Drag and Drop */
/** Target notifications for YASL surface drags, separate from external file drops. */
enum yasl_drag_event {
YASL_DRAG_OVER, /**< Surface drag entered or moved over the target. */
YASL_DRAG_LEAVE, /**< Surface drag left the target. */
YASL_DRAG_DROP, /**< Surface drag dropped on the target. */
};
/** External text/file drag hover notifications; completed data arrives through input. */
enum yasl_drop_event {
YASL_DROP_OVER, /**< External data drag entered or moved over the target. */
YASL_DROP_LEAVE, /**< External data drag left the target. */
};
/** Source-side drag completion; DROPPED does not prove application-level acceptance. */
enum yasl_drag_end {
YASL_DRAG_DROPPED, /**< Drag ended in a drop; not an application acceptance receipt. */
YASL_DRAG_CANCELLED, /**< Drag canceled, including display close. */
};
/** Copied drag icon in tightly packed premultiplied 0xAARRGGBB device pixels. */
struct yasl_drag_image {
/** Copied pixel array; required when an image is supplied. */
const uint32_t *pixels;
/** Positive width and height in device pixels. */
struct yasl_vector2i size;
/** Pointer position within the image, in device pixels. */
struct yasl_vector2i hotspot;
};
/** Copied drag completion listener; userdata remains owned by the application. */
struct yasl_drag_listener {
/** Called exactly once after a successful start, possibly synchronously on cancel/close. */
void (*end)(void *ud, enum yasl_drag_end how);
};
/** Configured device-pixel content size and the corresponding display scale. */
struct yasl_geometry {
/** Current content extent in device pixels. */
struct yasl_vector2i size;
/** Positive scale numerator; 120 means 1x and 180 means 1.5x. */
uint32_t scale_120;
};
/* Input Model */
/** Keyboard press, release, or autorepeat; releases must not insert text. */
enum yasl_key_action {
YASL_KEY_PRESS, /**< Key pressed. */
YASL_KEY_RELEASE, /**< Key released. */
YASL_KEY_REPEAT, /**< Key autorepeat. */
};
/** Modifier bitmask. SUPER is Command on macOS. */
enum yasl_mod : uint32_t {
YASL_MOD_SHIFT = 1 << 0, /**< Shift modifier. */
YASL_MOD_ALT = 1 << 1, /**< Alt/Option modifier. */
YASL_MOD_CTRL = 1 << 2, /**< Control modifier. */
YASL_MOD_SUPER = 1 << 3, /**< Super/Command modifier. */
YASL_MOD_CAPS = 1 << 4, /**< Caps Lock modifier. */
};
/** Pointer transition or motion type; fields are meaningful according to this tag. */
enum yasl_pointer_kind {
YASL_PTR_PRESS, /**< Button/tip pressed. */
YASL_PTR_RELEASE, /**< Button/tip released. */
YASL_PTR_MOTION, /**< Position or tablet axes changed. */
YASL_PTR_LEAVE, /**< Pointer/tool left the surface. */
YASL_PTR_SCROLL, /**< Scroll sample. */
};
/** Pointer source class; capability support does not imply an attached device. */
enum yasl_pointer_device {
YASL_PTR_DEV_MOUSE, /**< Mouse or trackpad pointer. */
YASL_PTR_DEV_TOUCH, /**< Touch translated into pointer input. */
YASL_PTR_DEV_PEN, /**< Tablet stylus. */
YASL_PTR_DEV_ERASER, /**< Tablet eraser tool. */
};
/** Normalized tablet axes; zero for unavailable axes and non-tablet devices. */
struct yasl_pointer_pen {
/** 0..65535 normalized to device range. Zero alone does not end contact. */
uint16_t pressure;
/** Degrees in -90..90; positive right. */
int8_t tilt_x;
/** Degrees in -90..90; positive down. */
int8_t tilt_y;
};
/** Physical keyboard transition with optional layout labels.
* key is independent of modifiers/layout and stable between press and release.
* codepoint and shifted are optional single Unicode scalars for the current
* layout at levels zero/one, not text input. Zero means unavailable, a control
* key, or a layout mapping that produces multiple characters. Native scancodes
* are backend-specific. Insert committed YASL_INPUT_TEXT into documents.
*/
struct yasl_key_event {
/** Portable physical key; YASL_KEY_UNKNOWN when unmapped. */
enum yasl_key key;
/** Press, release, or autorepeat. */
enum yasl_key_action action;
/** yasl_mod bitmask at this event. */
uint32_t mods;
/** Optional unshifted layout Unicode scalar; zero if unavailable. */
uint32_t codepoint;
/** Optional shifted layout Unicode scalar; zero if unavailable. */
uint32_t shifted;
/** Native code: Wayland evdev, X11 server keycode, Cocoa virtual keycode. */
uint32_t native_code;
};
/** Pointer sample. Pen and eraser events share this structure with mouse input.
Track contact with primary press/release, not pressure alone. Leave, focus loss,
and YASL_INPUT_RESET must cancel held application input state. This is not a
multi-contact touch API. Scroll offsets use fractional line units: positive x
means right and positive y means down, after system scroll preferences. */
struct yasl_mouse_event {
/** Surface-relative device-pixel position. */
struct yasl_vector2i pos;
/** Press/release: 0 primary/tip, 1 middle, 2 secondary. Unused for scroll. */
int16_t button;
/** Sample type. */
enum yasl_pointer_kind kind;
/** Mouse, touch, pen, or eraser. */
enum yasl_pointer_device device;
/** yasl_mod bitmask at this event. */
uint32_t mods;
/** Fractional line offsets, valid for SCROLL only; positive right/down. */
struct yasl_vector2d scroll;
/** Current tablet axes, including on pressure-only motion; missing axes are zero. */
struct yasl_pointer_pen pen;
};
/** Input union tag. RESET has no payload and requires clearing held state. */
enum yasl_input_kind {
YASL_INPUT_KEY, /**< key member. */
YASL_INPUT_MOUSE, /**< mouse member. */
YASL_INPUT_FOCUS, /**< focus member. */
YASL_INPUT_PASTE, /**< paste member. */
YASL_INPUT_DROP_FILES, /**< drop_files member. */
YASL_INPUT_TEXT, /**< text member, containing committed UTF-8. */
/* The input stream was interrupted (e.g. allocation failure or device
* removal). Clear held keys/buttons and composition state. */
YASL_INPUT_RESET, /**< No payload. Clear held keys/buttons and composition after an interruption. */
};
/** Keyboard focus transition; cancel held state when focus is lost. */
struct yasl_focus_event {
/** true on focus gain, false on loss. */
bool focused;
};
/** Committed UTF-8 text; insert this instead of deriving characters from key events. */
struct yasl_text_event {
/** Borrowed NUL-terminated UTF-8. */
const char *text;
/** Length in bytes excluding the terminating NUL. */
size_t len;
};
/** UTF-8 text received from an explicit selection request. */
struct yasl_paste_event {
/** Borrowed NUL-terminated UTF-8. */
const char *text;
/** Length in bytes excluding the terminating NUL. */
size_t len;
};
/** File URLs in text/uri-list form, separated by CRLF; not filesystem paths. */
struct yasl_drop_files_event {
/** Borrowed NUL-terminated text/uri-list; parse URLs and percent escapes. */
const char *files;
/** Length in bytes excluding the terminating NUL. */
size_t len;
};
/** One tagged input event; read only the union member selected by kind.
Payload strings follow yasl_surface_input_poll() lifetime rules. RESET carries
no union payload; clear keys, buttons, strokes, and composition state. */
struct yasl_input_event {
/** Recipient; can differ from the polled surface for routed popup input. */
struct yasl_surface *surface;
/** Selects the valid union member. */
enum yasl_input_kind kind;
/** Reserved for YASL; applications must not interpret it. */
uint32_t reserved;
union {
struct yasl_key_event key; /**< Keyboard payload. */
struct yasl_mouse_event mouse; /**< Pointer payload. */
struct yasl_focus_event focus; /**< Focus payload. */
struct yasl_text_event text; /**< Committed text payload. */
struct yasl_paste_event paste; /**< Selection text payload. */
struct yasl_drop_files_event drop_files; /**< File URL list payload. */
};
};
/* Ownership and threading
* All calls and callbacks run on the display's opening thread (main thread on
* Cocoa). Displays borrow supplied loops; destroy surfaces before displays,
* popups before parents, and displays before their supplied loop.
* Specs, strings, callback tables and drag listeners are copied during calls.
* Userdata is borrowed until callbacks are removed or the object/drag ends.
* Surface destruction is allowed from its callbacks; display/loop destruction
* during dispatch or callbacks is not supported.
*/
/* Callbacks */
/** Optional display notifications. NULL callback members are ignored. */
struct yasl_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 surface notifications, copied by yasl_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. */
struct yasl_surface_cbs {
/** Initialize the entire target and optionally present. Requested through schedule_redraw/flush. */
void (*draw)(struct yasl_surface *s, struct yasl_frame *frame, void *ud);
/** Configured size/scale changed; reallocate application content and request a redraw. */
void (*configure)(struct yasl_surface *s, struct yasl_geometry geometry, void *ud);
/** Window/popup close request; application is responsible for destruction. */
void (*close)(struct yasl_surface *s, void *ud);
/** Reported yasl_surface_state bitmask changed. */
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_drag_event ev,
struct yasl_vector2i pos, void *ud);
/** External data-drag hover or leave; pos is in device pixels. */
void (*drop)(struct yasl_surface *s, enum yasl_drop_event ev,
struct yasl_vector2i pos, void *ud);
};
/* Display Lifecycle */
/** Runtime backend choice. AUTO selects a native backend and allows fallback. */
enum yasl_backend {
YASL_BACKEND_AUTO = 0, /**< Choose native backend with fallback. */
YASL_BACKEND_WAYLAND, /**< Require Wayland. */
YASL_BACKEND_X11, /**< Require X11. */
YASL_BACKEND_COCOA, /**< Require Cocoa. */
};
/** Display options. Zero-initialize for automatic backend selection. */
struct yasl_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_display_cbs *cbs;
/** Borrowed display callback userdata. */
void *ud;
/** Zero/AUTO chooses native backend; explicit choices never fall back. */
enum yasl_backend backend;
};
/* Return NULL and set errno if the requested backend cannot open. */
/**
* Open a desktop connection and its event machinery.
* @param loop Borrowed loop, or NULL to create a display-owned loop.
* @param spec Copied options, or NULL for automatic backend selection and defaults.
* @return An owned display, or NULL with errno set. EINVAL means an invalid backend;
* ENOSYS means the requested backend was not built; ENODEV is the fallback when
* opening fails without a more specific platform error. Explicit choices never
* fall back. Close with yasl_display_close() after destroying its surfaces.
*/
YASL_API struct yasl_display *yasl_display_open(struct yasl_loop *loop,
const struct yasl_display_spec *spec);
/**
* Read the selected backend.
* @param d Display, or NULL.
* @return The actual backend, or YASL_BACKEND_AUTO for NULL.
*/
YASL_API enum yasl_backend yasl_display_backend(const struct yasl_display *d);
/**
* Close a display and release its owned loop, if any.
* @param d Display to close, or NULL for no action.
* Destroy all surfaces first. Cancels an active drag and may invoke its end
* listener. Must not be called during dispatch or from a callback.
*/
YASL_API void yasl_display_close(struct yasl_display *d);
/**
* Query currently available optional features.
* @param d Display, or NULL.
* @return A bitmask of yasl_display_cap values, or zero for NULL.
* Capabilities describe backend/server support, not attached input hardware or
* permission to perform an operation at any arbitrary moment.
*/
YASL_API uint32_t yasl_display_caps(const struct yasl_display *d);
/* Process events, waiting at most timeout_ms: zero polls, negative waits.
* Pending input or redraw work returns immediately. Returns -1 on failure. */
/**
* Receive events and run ready loop sources.
* @param d Display to dispatch.
* @param timeout_ms Maximum wait in milliseconds: zero polls, negative waits indefinitely.
* @return A nonnegative backend-specific work count on success, or -1 with errno
* set on failure (EINVAL for NULL, EIO if no specific backend error is available).
* Do not interpret the count as the number of queued input events. Pending input
* or runnable redraw work prevents waiting. Drain input and call
* yasl_display_flush() after updating application state. Do not dispatch recursively.
*/
YASL_API int yasl_display_dispatch(struct yasl_display *d, int timeout_ms);
/**
* Draw scheduled surfaces and send pending display requests.
* @param d Display, or NULL for no action.
* May synchronously invoke draw and other callbacks. A paced surface may wait
* for its next display/compositor signal. This is not a GPU completion wait.
*/
YASL_API void yasl_display_flush(struct yasl_display *d);
/**
* Read the latest modifier state known to the backend.
* @param d Display, or NULL.
* @return A bitmask of yasl_mod values, or zero for NULL.
* For an individual event use its own mods field instead.
*/
YASL_API int yasl_display_modifiers(const struct yasl_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_CLIPBOARD or YASL_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.
*/
YASL_API void yasl_display_copy(struct yasl_display *d, enum yasl_selection sel, const char *text);
/**
* Request text delivery to a particular surface.
* @param d Display that owns target.
* @param sel YASL_CLIPBOARD or YASL_PRIMARY.
* @param target Destination surface; NULL or a surface on another display does nothing.
* Results arrive as YASL_INPUT_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.
*/
YASL_API void yasl_display_paste(struct yasl_display *d, enum yasl_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. */
/**
* Start a surface drag from a recent pointer press.
* @param d Display that owns origin.
* @param origin Origin surface.
* @param image Optional copied premultiplied ARGB8888 drag image, or NULL.
* @param l Optional copied completion listener, or NULL.
* @param ud Borrowed listener userdata until completion.
* @return true if started; false if unsupported, invalid, or not currently permitted.
* A successful start invokes a non-NULL end callback exactly once, including
* cancellation or display close. Failed starts do not invoke it. This API carries
* surfaces, not arbitrary MIME payloads; use application state to identify the item.
*/
YASL_API bool yasl_display_drag_start(struct yasl_display *d, struct yasl_surface *origin,
const struct yasl_drag_image *image,
const struct yasl_drag_listener *l, void *ud);
/**
* Cancel the active surface drag, if any.
* @param d Display, or NULL for no action.
* May invoke the end listener synchronously.
*/
YASL_API void yasl_display_drag_cancel(struct yasl_display *d);
/* Surface Lifecycle */
/** Toplevel options. Zero-initialize, then supply a positive logical-pixel size. */
struct yasl_surface_spec {
/** Copied UTF-8 title; NULL uses backend defaults. */
const char *title;
/** Requested logical-pixel width and height; both must be positive. */
struct yasl_vector2i size;
/** Request initial fullscreen; actual state is reported asynchronously. */
bool fullscreen;
/** Permit unpaced presentation where supported; a hint, not a guarantee. */
bool tearing;
};
/** Popup options, entirely in device pixels, including size.
The content rectangle excludes transparent margins/shadows used for placement.
An axis of content_size equal to zero extends to that axis of size. The offset
and resolved content size must fit in size. Anchor extents must be nonnegative.
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_popup_spec {
/** Full popup framebuffer extent in device pixels, including transparent margins. */
struct yasl_vector2i size;
/** Rectangle in parent framebuffer coordinates, in device pixels. */
struct yasl_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_vector2i content_offset;
/** Content extent; zero per axis extends to the corresponding size edge. */
struct yasl_vector2i content_size;
};
/**
* Create a resizable desktop window with CPU drawing targets.
* @param d Owning display.
* @param spec Required copied options; size is in logical pixels.
* @return An owned surface, or NULL with errno set. EINVAL means invalid options,
* including a nonpositive dimension, a dimension above 32767, or a buffer above
* INT32_MAX bytes. ENODEV is the fallback backend failure. Actual configured
* size may differ from the request. Install callbacks and schedule a redraw.
*/
YASL_API struct yasl_surface *yasl_surface_create_toplevel(struct yasl_display *d,
const struct yasl_surface_spec *spec);
/**
* Create an owned popup attached to a parent surface.
* @param parent Borrowed parent; destroy the popup before the parent.
* @param spec Required copied options, entirely in device pixels.
* @return A popup, or NULL with errno set: EINVAL for invalid options, ENOTSUP
* for missing popup support, or a backend error (ENODEV if none was supplied).
* Wayland requires a recent input serial for its popup grab. The backend may
* flip or slide placement to fit the screen. See yasl_popup_spec.
*/
YASL_API struct yasl_surface *yasl_surface_create_popup(struct yasl_surface *parent,
const struct yasl_popup_spec *spec);
/**
* Update a popup's geometry and placement.
* @param popup An existing popup.
* @param spec Required copied replacement options, in device pixels.
* @return true on success; false with errno set: EINVAL for invalid options,
* ENOTSUP for missing popup support, or a backend error (ENODEV if unspecified).
* Older Wayland popup protocol versions can reject repositioning.
*/
YASL_API bool yasl_surface_popup_reposition(struct yasl_surface *popup,
const struct yasl_popup_spec *spec);
/**
* Destroy a surface and cancel its surface timers and pending input.
* @param s Surface, or NULL for no action.
* Destroy child popups first. May be called from a surface callback; return from
* that callback without further use of the surface or its draw target. Every
* pointer or native handle obtained from this surface becomes invalid.
*/
YASL_API void yasl_surface_destroy(struct yasl_surface *s);
/**
* Get the display that owns a surface.
* @param s Surface, or NULL.
* @return A borrowed display, or NULL.
*/
YASL_API struct yasl_display *yasl_surface_display(const struct yasl_surface *s);
/**
* Replace the surface's callback table and userdata.
* @param s Surface, or NULL for no action.
* @param cbs Table copied by value; NULL removes all callbacks. NULL members are ignored.
* @param ud Borrowed userdata passed to the installed callbacks.
* Callbacks may run synchronously during this call; initialize userdata first.
* Use yasl_surface_geometry() to read current geometry; do not rely on receiving
* an initial configure callback when registering.
*/
YASL_API void yasl_surface_set_callbacks(struct yasl_surface *s,
const struct yasl_surface_cbs *cbs, void *ud);
/**
* Replace the window title with copied UTF-8 text.
* @param s Surface.
* @param title NUL-terminated UTF-8 title. Pass an empty string to clear it.
* Backends may truncate the title.
*/
YASL_API void yasl_surface_set_title(struct yasl_surface *s, const char *title);
/**
* Request a future draw callback, coalescing repeated requests.
* @param s Surface, or NULL for no action.
* Call yasl_display_flush() to service the request. Schedule again from draw to
* animate. Without YASL_CAP_FRAME_PACING, throttle animation with a timer.
*/
YASL_API void yasl_surface_schedule_redraw(struct yasl_surface *s);
/* Present exactly the target supplied to the current draw callback, at most
* once. Targets expire when that callback returns or the surface is destroyed.
* damage is required: n must be -1 or 0..YASL_DAMAGE_MAX. Rectangles must have
* nonnegative extents; they are clipped to the target. Invalid input returns
* false without consuming the frame. See yasl/native.h for native rendering. */
/**
* Submit the current draw target at most once.
* @param s Surface currently being drawn.
* @param fb Exact target from the current draw callback, including its generation.
* @param damage Required damage hint: n is -1 for all pixels or 0..YASL_DAMAGE_MAX.
* @return true if accepted; false for invalid, stale, already presented, or failed targets.
* Rectangles must have nonnegative extents and are clipped to the target. Invalid
* input does not consume the frame. All pixels must be initialized even with
* partial damage. The backend may upload all pixels. Success records submission,
* not confirmed scanout. The target expires when draw returns or s is destroyed.
*/
YASL_API bool yasl_surface_present(struct yasl_surface *s, const struct yasl_framebuffer *fb,
const struct yasl_damage_list *damage);
/* Event payload strings are library-owned, NUL-terminated, and valid until
* the next SUCCESSFUL poll on this surface or surface destruction. Dispatch,
* flush and unsuccessful polls do not invalidate them. Copy to keep longer. */
/**
* Remove one event from a surface's input queue without waiting.
* @param s Surface whose queue to drain.
* @param ev Required output event; unchanged when no event is available.
* @return true for an event, false for an empty queue or NULL arguments.
* Dispatch receives native input; polling only drains the queue. Read the union
* member selected by kind. Payload strings are borrowed, NUL-terminated, and
* valid until the next successful poll on this queue or its destruction; dispatch,
* flush, and unsuccessful polls do not invalidate them. On Wayland, popup pointer
* and keyboard input can be routed through the root parent's queue; inspect
* ev->surface to identify the receiving surface.
*/
YASL_API bool yasl_surface_input_poll(struct yasl_surface *s, struct yasl_input_event *ev);
/* Current device-pixel size and scale, matching the configure callback. */
/**
* Read current device-pixel size and scale together.
* @param s Surface, or NULL.
* @return Geometry matching configure callbacks; NULL gives zero size and unit scale.
*/
YASL_API struct yasl_geometry yasl_surface_geometry(const struct yasl_surface *s);
/**
* Read current window state.
* @param s Surface, or NULL.
* @return A bitmask of yasl_surface_state values, or zero for NULL.
* Flags are reported state, not requests; unsupported states are absent.
*/
YASL_API uint32_t yasl_surface_state(const struct yasl_surface *s);
/* Timing uses monotonic nanoseconds. Check source before treating timestamps
* as presentation confirmation. refresh/next_present are estimates. Without
* YASL_CAP_FRAME_PACING, redraws run on flush without display synchronization.
* Tearing may bypass pacing even when the capability is present. */
/**
* Read frame timing estimates and their provenance.
* @param s Surface, or NULL.
* @return Current timing, or a zero-initialized result for NULL.
* Timestamps use monotonic nanoseconds. Inspect source before treating a timestamp
* as confirmation of presentation. Refresh and next-present values are estimates.
*/
YASL_API struct yasl_timing yasl_surface_timing(const struct yasl_surface *s);
/**
* Get a nondecreasing animation timestamp aligned to estimated refresh.
* @param s Surface, or NULL.
* @param now Current monotonic nanoseconds, usually from yasl_loop_now_ns().
* @return Animation timestamp, or zero for NULL. Before timing is known, returns now.
* Use this to advance animations; it is not presentation feedback.
*/
YASL_API uint64_t yasl_surface_frame_time_ns(struct yasl_surface *s, uint64_t now);
/* Set the mouse and tablet cursor for this surface, including future entries.
* YASL_CURSOR_HIDDEN stays hidden until another cursor is selected. */
/**
* Select the surface's system mouse and tablet cursor.
* @param s Surface.
* @param cursor Cursor shape; YASL_CURSOR_HIDDEN hides the cursor without disabling input.
* The choice persists across motion and re-entry until another shape is selected.
*/
YASL_API void yasl_surface_set_cursor(struct yasl_surface *s, enum yasl_cursor cursor);
/**
* Set a backend window background hint.
* @param s Surface.
* @param bg Packed 0xAARRGGBB color; backends may ignore alpha or the entire hint.
* Does not initialize framebuffer pixels or replace drawing.
*/
YASL_API void yasl_surface_set_background_color(struct yasl_surface *s, uint32_t bg);
/* IME Support: preedit is borrowed until the next dispatch or destruction. */
/**
* Read the current uncommitted UTF-8 composition text.
* @param s Surface, or NULL.
* @return Borrowed NUL-terminated text, or NULL if absent/unsupported.
* Copy to retain across the next dispatch or surface destruction. Composition
* changes can schedule a redraw. Insert committed YASL_INPUT_TEXT into documents,
* not preedit text.
*/
YASL_API const char *yasl_surface_ime_preedit(const struct yasl_surface *s);
/**
* Read the cursor/selection range in the preedit string.
* @param s Surface.
* @param begin Required output UTF-8 byte offset for the range start.
* @param end Required output UTF-8 byte offset for the range end.
* @return true if available; false without changing outputs otherwise.
* Currently available on Wayland; Cocoa preedit text has no range result.
*/
YASL_API bool yasl_surface_ime_preedit_cursor(const struct yasl_surface *s, int *begin, int *end);
/**
* Place the composition candidate window near the application caret.
* @param s Surface.
* @param caret Caret rectangle relative to the surface, in device pixels.
* Update after caret motion or scale changes. Unsupported backends ignore it.
*/
YASL_API void yasl_surface_set_ime_caret(struct yasl_surface *s, struct yasl_rect2i caret);
/* Client-Side Decorations (CSD) Actions */
/**
* Ask the window system to begin an interactive move.
* @param s Toplevel surface, normally during handling of a pointer press.
* @return true if the request was issued; false if unsupported or not permitted.
* A recent input serial may be required. Success does not confirm a final position.
*/
YASL_API bool yasl_surface_start_interactive_move(struct yasl_surface *s);
/**
* Ask the window system to begin an interactive resize.
* @param s Toplevel surface, normally during handling of a pointer press.
* @param edge One nonzero yasl_resize_edge enumerator.
* @return true if issued; false for an invalid edge, missing support, or rejected request.
*/
YASL_API bool yasl_surface_start_interactive_resize(struct yasl_surface *s, enum yasl_resize_edge edge);
/**
* Ask the window system to display its window management menu.
* @param s Toplevel surface.
* @param pos Surface-relative position in device pixels.
* @return true if issued; false if unsupported or not currently permitted.
*/
YASL_API bool yasl_surface_show_window_menu(struct yasl_surface *s, struct yasl_vector2i pos);
/* Drag Support */
/**
* Attach a toplevel surface to the current surface drag.
* @param s Surface to carry; check YASL_CAP_DRAG_CARRY first.
* @param offset Device-pixel offset of the pointer within the carried surface.
* @return true if accepted; false if unsupported or no compatible drag is active.
*/
YASL_API bool yasl_surface_drag_carry(struct yasl_surface *s, struct yasl_vector2i offset);
/**
* Place a toplevel surface relative to the current pointer.
* @param s Surface; check YASL_CAP_PLACE_WINDOW first.
* @param at Device-pixel position within the surface to place under the pointer.
* @return true if issued; false if unsupported or unavailable.
*/
YASL_API bool yasl_surface_place_under_pointer(struct yasl_surface *s, struct yasl_vector2i at);
#ifdef __cplusplus
}
#endif
#endif /* YASL_H */
|