summaryrefslogtreecommitdiff
path: root/README.md
blob: 52dea161d3169cb12548759d8715ea82482b8963 (plain)
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
# YASL (Yet Another Surface Library)

YASL is a minimal, modern, and high-performance desktop window surface library written in C.

It provides window creation, frame pacing, high-DPI scaling, and input routing without bundling audio, physics, or game engine components.

## Features

- **Lean Core**: No audio, no font rendering, and no widget toolkit overhead.
- **Wayland Protocol Coverage**:
  - `xdg-shell` toplevels and hierarchical popups (`xdg_popup` + `xdg_positioner`).
  - Fractional scaling via `wp_fractional_scale_v1` and `wp_viewporter`.
  - Presentation feedback and refresh rate timing via `wp_presentation` and `wp_fifo_v1`.
  - Cursor shapes via `wp_cursor_shape_device_v1`.
  - Graphics tablets and stylus input via `zwp_tablet_v2` (pressure, tilt, eraser).
  - Text Input Method (IME) composition via `zwp_text_input_v3`.
  - Primary selection and clipboard transfers via `wl_data_device` and `zwp_primary_selection_v1`.
  - Interactive client-side window move and resize triggers (`xdg_toplevel_move`, `xdg_toplevel_resize`).
- **macOS Cocoa & Metal**:
  - Native `NSWindow` and `CAMetalLayer` presentation.
  - Vsync pacing via `CADisplayLink`.
- **Zero Framework Leaks**:
  - Self-contained UTF-8 validation.
  - Self-contained event queue.
  - No terminal-specific telemetry or hardcoded application names.

## Backend selection

YASL selects the native window backend at runtime.
Leave `yasl_display_spec.backend` at zero to use this mode.
`YASL_BACKEND_AUTO` has the same effect.
You can also pass NULL as the display spec.

On Linux, YASL tries Wayland first in a Wayland session.
It uses `WAYLAND_DISPLAY`, `WAYLAND_SOCKET`, and `XDG_SESSION_TYPE` to detect that session.
In other sessions, it tries X11 first.
If the first backend cannot open, it tries the other built backend.
On macOS, it uses Cocoa.

Set `backend` to request one backend:

```c
struct yasl_display_spec spec = {
    .app_id = "org.example.app",
    .backend = YASL_BACKEND_X11,
};
struct yasl_display *display = yasl_display_open(loop, &spec);
```

Use `YASL_BACKEND_WAYLAND` to request Wayland.
Use `YASL_BACKEND_COCOA` to request Cocoa.
An explicit request never falls back to another backend.
Open returns NULL if the requested backend cannot open.
It sets `errno` to `ENOSYS` for a backend that was not built.
It sets `errno` to `EINVAL` for an invalid backend value.

Call `yasl_display_backend(display)` to read the selected backend.
All surfaces on a display use that backend.
Open separate displays to use Wayland and X11 in one process.
The public API needs no window system headers.
Use `yasl_display_caps()` to check optional features.

X11 supports CPU pixel buffers, keyboard and pointer input, and clipboard transfer.
It supports the primary selection and window placement.
It does not yet support YASL popups, drag operations, or IME preedit text.
Those features return their normal unsupported result.

The surface spec needs no native graphics device for CPU drawing.
On Cocoa, YASL creates its own Metal device for this mode.
An app that renders with Metal can supply its device through `graphics_device`.
That app submits and presents the native drawable.

The native display handle is a `wl_display *` on Wayland.
It is a `Display *` on X11.
The native surface handle is a `wl_surface *` on Wayland.
On X11, convert it to `Window` through `uintptr_t`.
On Cocoa, the native surface handle is the content `NSView *`.

## Building

Use a C23 compiler and Meson 1.6 or later.
Build with Meson and Ninja:

```sh
meson setup build
ninja -C build
ninja -C build test
```

Linux builds include each backend whose dependencies are installed.
Wayland needs `wayland-client`, `wayland-cursor`, and `xkbcommon`.
X11 needs `x11` and `xkbcommon`.
Use `-Dwayland=enabled` or `-Dx11=enabled` to require a backend.
Use `-Dwayland=disabled` or `-Dx11=disabled` to omit a backend.
At least one backend must be built.

To run the Linux window tests, install Weston and Xwayland.
Then run:

```sh
meson setup build-test -Dintegration_tests=true
meson test -C build-test --print-errorlogs
```

The tests start isolated display servers.
They test explicit requests, automatic selection, and fallback.
They also test both backends in one process.
On macOS, the same option runs native Cocoa window tests.
These tests need a desktop session.

## Quick Example

```c
#include <yasl/yasl.h>

static void on_draw(struct yasl_surface *s, struct yasl_frame *frame, void *ud)
{
    /* Present frame target */
    struct yasl_damage_list dmg = { .n = -1 };
    yasl_surface_present(s, &frame->target, &dmg);
}

int main(void)
{
    struct yasl_loop *loop = yasl_loop_create();
    struct yasl_display_spec dspec = { .app_id = "org.example.app" };
    struct yasl_display *d = yasl_display_open(loop, &dspec);

    struct yasl_surface_spec sspec = {
        .title = "YASL Application",
        .size = { .x = 800, .y = 600 },
    };
    struct yasl_surface *s = yasl_surface_create_toplevel(d, &sspec);
    struct yasl_surface_cbs cbs = { .draw = on_draw };
    yasl_surface_set_callbacks(s, &cbs, NULL);
    yasl_surface_schedule_redraw(s);

    while (true) {
        yasl_display_dispatch(d);
        struct yasl_input_event ev;
        while (yasl_surface_input_poll(s, &ev)) {
            /* Handle input */
        }
        yasl_display_flush(d);
    }
}
```

## License

MIT License.