commit 8acfafa
shar
·
2026-06-24 04:42:54 +0000 UTC
parent cdd869a
shm: create shared mem like protocol for buffers
3 files changed,
+750,
-1
+3,
-1
1@@ -4,11 +4,13 @@
2 .dependencies = .{
3 .panthera = .{
4 .url = "https://tangled.org/shar.tngl.sh/panthera/archive/main.tar.gz",
5- .hash = "panthera-0.0.0-GJ5Ew-zrBgAC_fcxweavj5y1jHvpGbWRMP7TjOF_Cezo",
6+ .hash = "panthera-0.0.0-GJ5Ew7rrBgANMDHJLwaDlGSX2-Xl6tTLWemKLV03CQwA",
7 },
8 },
9 .minimum_zig_version = "0.16.0",
10 .paths = .{
11+ "compositor/src/altaica_shm.zig",
12+ "compositor/src/protocol.zig",
13 "compositor/src/wire.zig",
14 "tools/scanner.zig",
15 "protocol",
+306,
-0
1@@ -0,0 +1,306 @@
2+extern "env" fn log_error(ptr: [*]const u8, len: u32) void;
3+
4+const MAX_PIXELS = 2 * 1024 * 1024;
5+const MAX_POOLS = 32;
6+const MAX_BUFFERS = 64;
7+const MAX_FREE = 64;
8+
9+const FreeBlock = struct { offset: usize, size: usize };
10+
11+pub const Pool = struct {
12+ id: u32,
13+ client_id: u32,
14+ width: u32,
15+ height: u32,
16+ format: u32,
17+ pixels: []u32,
18+ pixel_offset: usize,
19+};
20+
21+const BufferRef = struct {
22+ pool_id: u32,
23+ pool_client: u32,
24+ x: u32, y: u32,
25+ w: u32, h: u32,
26+};
27+
28+var pixel_heap: [MAX_PIXELS]u32 align(4) = undefined;
29+var pixel_used: usize = 0;
30+var free_blocks: [MAX_FREE]FreeBlock = undefined;
31+var free_count: u32 = 0;
32+
33+fn allocPixels(count: usize) ?[]u32 {
34+ // Check free list first
35+ for (0..free_count) |i| {
36+ const fb = free_blocks[i];
37+ if (fb.size >= count) {
38+ const slice = pixel_heap[fb.offset..fb.offset + count];
39+ if (fb.size == count) {
40+ // Exact match — remove from free list
41+ var j = i;
42+ while (j + 1 < free_count) : (j += 1) free_blocks[j] = free_blocks[j + 1];
43+ free_count -= 1;
44+ } else {
45+ free_blocks[i] = .{ .offset = fb.offset + count, .size = fb.size - count };
46+ }
47+ return slice;
48+ }
49+ }
50+ // Bump allocate
51+ if (pixel_used + count > MAX_PIXELS) {
52+ const msg = "altaica_shm: pixel heap full\n";
53+ log_error(msg, msg.len);
54+ return null;
55+ }
56+ const slice = pixel_heap[pixel_used..pixel_used + count];
57+ pixel_used += count;
58+ return slice;
59+}
60+
61+fn freePixels(offset: usize, size: usize) void {
62+ if (size == 0) return;
63+ // Coalesce with adjacent free blocks
64+ for (0..free_count) |i| {
65+ const fb = free_blocks[i];
66+ const fb_end = fb.offset + fb.size;
67+ if (fb_end == offset) {
68+ free_blocks[i] = .{ .offset = fb.offset, .size = fb.size + size };
69+ // Check if this now connects to another block
70+ for (0..free_count) |j| {
71+ if (j == i) continue;
72+ const fj = free_blocks[j];
73+ const fj_end = fj.offset + fj.size;
74+ if (fj_end == fb.offset) {
75+ free_blocks[i].offset = fj.offset;
76+ free_blocks[i].size += fj.size;
77+ var k = j;
78+ while (k + 1 < free_count) : (k += 1) free_blocks[k] = free_blocks[k + 1];
79+ free_count -= 1;
80+ break;
81+ }
82+ }
83+ return;
84+ }
85+ if (offset == fb_end) {
86+ free_blocks[i] = .{ .offset = fb.offset, .size = fb.size + size };
87+ // Check adjacency forward
88+ const new_end = free_blocks[i].offset + free_blocks[i].size;
89+ for (0..free_count) |j| {
90+ if (j == i) continue;
91+ const fj = free_blocks[j];
92+ if (fj.offset == new_end) {
93+ free_blocks[i].size += fj.size;
94+ var k = j;
95+ while (k + 1 < free_count) : (k += 1) free_blocks[k] = free_blocks[k + 1];
96+ free_count -= 1;
97+ break;
98+ }
99+ }
100+ return;
101+ }
102+ }
103+ // Append new free block
104+ if (free_count < MAX_FREE) {
105+ free_blocks[free_count] = .{ .offset = offset, .size = size };
106+ free_count += 1;
107+ }
108+}
109+
110+fn pixelsOffset(pixels: []u32) usize {
111+ const heap_start = @intFromPtr(&pixel_heap);
112+ const pix_start = @intFromPtr(pixels.ptr);
113+ return pix_start - heap_start;
114+}
115+
116+pub const FORMAT_ARGB8888: u32 = 0;
117+pub const FORMAT_XRGB8888: u32 = 1;
118+
119+fn isValidFormat(fmt: u32) bool {
120+ return fmt == FORMAT_ARGB8888 or fmt == FORMAT_XRGB8888;
121+}
122+
123+fn formatHasAlpha(fmt: u32) bool {
124+ return fmt == FORMAT_ARGB8888;
125+}
126+
127+var pools: [MAX_POOLS]?Pool = [_]?Pool{null} ** MAX_POOLS;
128+var buffers: [MAX_BUFFERS]?BufferRef = [_]?BufferRef{null} ** MAX_BUFFERS;
129+
130+pub fn findPool(client_id: u32, pool_id: u32) ?*Pool {
131+ for (&pools) |*maybe| {
132+ const p = &(maybe.* orelse continue);
133+ if (p.client_id == client_id and p.id == pool_id) return p;
134+ }
135+ return null;
136+}
137+
138+pub fn createPool(client_id: u32, id: u32, width: u32, height: u32, format: u32) bool {
139+ if (!isValidFormat(format)) {
140+ const msg = "altaica_shm: invalid format\n";
141+ log_error(msg, msg.len);
142+ return false;
143+ }
144+ for (&pools) |*maybe| {
145+ if (maybe.* == null) {
146+ const pixels = allocPixels(width * height) orelse {
147+ const msg = "altaica_shm: pixel heap full\n";
148+ log_error(msg, msg.len);
149+ return false;
150+ };
151+ @memset(pixels, if (formatHasAlpha(format)) 0x00000000 else 0xFF000000);
152+ maybe.* = Pool{
153+ .id = id, .client_id = client_id,
154+ .width = width, .height = height,
155+ .format = format, .pixels = pixels,
156+ .pixel_offset = pixelsOffset(pixels),
157+ };
158+ return true;
159+ }
160+ }
161+ const msg = "altaica_shm: no free pool slots\n";
162+ log_error(msg, msg.len);
163+ return false;
164+}
165+
166+pub fn destroyPool(client_id: u32, pool_id: u32) void {
167+ for (&pools) |*maybe| {
168+ const p = &(maybe.* orelse continue);
169+ if (p.client_id == client_id and p.id == pool_id) {
170+ // Free all buffers referencing this pool
171+ for (&buffers) |*b| {
172+ const bref = b.* orelse continue;
173+ if (bref.pool_id == pool_id and bref.pool_client == client_id) {
174+ b.* = null;
175+ }
176+ }
177+ // Free pixel memory
178+ freePixels(p.pixel_offset, p.width * p.height);
179+ maybe.* = null;
180+ return;
181+ }
182+ }
183+}
184+
185+pub fn resizePool(client_id: u32, pool_id: u32, new_w: u32, new_h: u32) bool {
186+ const pool = findPool(client_id, pool_id) orelse return false;
187+ const new_count = new_w * new_h;
188+ const old_count = pool.width * pool.height;
189+ if (new_count <= old_count) {
190+ pool.width = new_w;
191+ pool.height = new_h;
192+ return true;
193+ }
194+ const old_offset = pool.pixel_offset;
195+ const new_pixels = allocPixels(new_count) orelse return false;
196+ const copy_rows = @min(pool.height, new_h);
197+ const copy_cols = @min(pool.width, new_w);
198+ for (0..copy_rows) |row| {
199+ for (0..copy_cols) |col| {
200+ new_pixels[row * new_w + col] = pool.pixels[row * pool.width + col];
201+ }
202+ }
203+ for (old_count..new_count) |i| new_pixels[i] = 0xFF000000;
204+ freePixels(old_offset, old_count);
205+ pool.pixels = new_pixels;
206+ pool.pixel_offset = pixelsOffset(new_pixels);
207+ pool.width = new_w;
208+ pool.height = new_h;
209+ return true;
210+}
211+
212+pub fn uploadPixels(client_id: u32, pool_id: u32, x: u32, y: u32, w: u32, h: u32, data: []const u8) void {
213+ const pool = findPool(client_id, pool_id) orelse return;
214+ if (x + w > pool.width or y + h > pool.height) return;
215+ if (data.len < w * h * 4) return;
216+
217+ for (0..h) |row| {
218+ const dst_row = y + row;
219+ for (0..w) |col| {
220+ const dst_col = x + col;
221+ const si = (row * w + col) * 4;
222+ const a = data[si + 3];
223+ const r = data[si + 2];
224+ const g = data[si + 1];
225+ const b = data[si + 0];
226+ const di = dst_row * pool.width + dst_col;
227+ pool.pixels[di] = (@as(u32, a) << 24) | (@as(u32, r) << 16) | (@as(u32, g) << 8) | b;
228+ }
229+ }
230+}
231+
232+pub fn findBuffer(idx: u32) ?BufferRef {
233+ if (idx >= MAX_BUFFERS) return null;
234+ return buffers[idx];
235+}
236+
237+pub fn allocBufferIdx() ?u32 {
238+ for (&buffers, 0..) |*maybe, i| {
239+ if (maybe.* == null) {
240+ return @as(u32, @intCast(i));
241+ }
242+ }
243+ return null;
244+}
245+
246+pub fn setBuffer(idx: u32, ref: BufferRef) void {
247+ if (idx < MAX_BUFFERS) buffers[idx] = ref;
248+}
249+
250+pub fn freeBuffer(idx: u32) void {
251+ if (idx < MAX_BUFFERS) buffers[idx] = null;
252+}
253+
254+/// Copy a sub-region from pool to a destination surface with different strides
255+pub fn copyRegion(
256+ pool_id: u32,
257+ pool_client: u32,
258+ dst: []u32,
259+ dst_stride: u32,
260+ src_x: u32,
261+ src_y: u32,
262+ w: u32,
263+ h: u32,
264+ dst_x: u32,
265+ dst_y: u32,
266+) bool {
267+ const pool = findPool(pool_client, pool_id) orelse return false;
268+ if (src_x + w > pool.width or src_y + h > pool.height) return false;
269+ for (0..h) |row| {
270+ for (0..w) |col| {
271+ const si = (src_y + row) * pool.width + (src_x + col);
272+ const di = (dst_y + row) * dst_stride + (dst_x + col);
273+ if (di >= dst.len) return false;
274+ dst[di] = pool.pixels[si];
275+ }
276+ }
277+ return true;
278+}
279+
280+pub fn copyFromPool(pool_id: u32, pool_client: u32, dst: []u32, w: u32, h: u32, sx: u32, sy: u32) bool {
281+ const pool = findPool(pool_client, pool_id) orelse return false;
282+ if (sx + w > pool.width or sy + h > pool.height) return false;
283+ if (dst.len < w * h) return false;
284+ for (0..h) |row| {
285+ for (0..w) |col| {
286+ const si = (sy + row) * pool.width + (sx + col);
287+ dst[row * w + col] = pool.pixels[si];
288+ }
289+ }
290+ return true;
291+}
292+
293+pub fn copyFromPoolScaled(pool_id: u32, pool_client: u32, dst: []u32, dst_w: u32, dst_h: u32, src_x: u32, src_y: u32, src_w: u32, src_h: u32) bool {
294+ const pool = findPool(pool_client, pool_id) orelse return false;
295+ if (src_x + src_w > pool.width or src_y + src_h > pool.height) return false;
296+ if (dst.len < dst_w * dst_h) return false;
297+ if (src_w == 0 or src_h == 0 or dst_w == 0 or dst_h == 0) return false;
298+ for (0..dst_h) |dy| {
299+ const sy = (dy * src_h) / dst_h;
300+ for (0..dst_w) |dx| {
301+ const sx = (dx * src_w) / dst_w;
302+ const si = (src_y + sy) * pool.width + (src_x + sx);
303+ dst[dy * dst_w + dx] = pool.pixels[si];
304+ }
305+ }
306+ return true;
307+}
+441,
-0
1@@ -0,0 +1,441 @@
2+const wire = @import("wire.zig");
3+const ArgType = wire.ArgType;
4+
5+pub const Interface = enum(u8) {
6+ altaica_shm,
7+ altaica_shm_pool,
8+ wl_buffer,
9+ wl_callback,
10+ wl_compositor,
11+ wl_data_device,
12+ wl_data_device_manager,
13+ wl_data_offer,
14+ wl_data_source,
15+ wl_display,
16+ wl_fixes,
17+ wl_keyboard,
18+ wl_output,
19+ wl_pointer,
20+ wl_region,
21+ wl_registry,
22+ wl_seat,
23+ wl_shell,
24+ wl_shell_surface,
25+ wl_shm,
26+ wl_shm_pool,
27+ wl_subcompositor,
28+ wl_subsurface,
29+ wl_surface,
30+ wl_touch,
31+ wp_viewport,
32+ wp_viewporter,
33+ xdg_popup,
34+ xdg_positioner,
35+ xdg_surface,
36+ xdg_toplevel,
37+ xdg_wm_base,
38+};
39+
40+pub const MessageSig = struct {
41+ opcode: u16,
42+ args: []const ArgType,
43+};
44+
45+pub fn requestSig(iface: Interface, opcode: u16) ?[]const ArgType {
46+ const sigs = requestSigs(iface);
47+ for (sigs) |s| if (s.opcode == opcode) return s.args;
48+ return null;
49+}
50+
51+pub fn eventSig(iface: Interface, opcode: u16) ?[]const ArgType {
52+ const sigs = eventSigs(iface);
53+ for (sigs) |s| if (s.opcode == opcode) return s.args;
54+ return null;
55+}
56+
57+fn requestSigs(iface: Interface) []const MessageSig {
58+ return switch (iface) {
59+ .altaica_shm => &.{
60+ .{ .opcode = 0, .args = &.{.new_id, .int, .int, .uint} },
61+ },
62+ .altaica_shm_pool => &.{
63+ .{ .opcode = 0, .args = &.{.int, .int, .int, .int} },
64+ .{ .opcode = 1, .args = &.{.new_id, .int, .int, .int, .int} },
65+ .{ .opcode = 2, .args = &.{.int, .int} },
66+ .{ .opcode = 3, .args = &.{} },
67+ },
68+ .wl_buffer => &.{
69+ .{ .opcode = 0, .args = &.{} },
70+ },
71+ .wl_callback => &.{},
72+ .wl_compositor => &.{
73+ .{ .opcode = 0, .args = &.{.new_id} },
74+ .{ .opcode = 1, .args = &.{.new_id} },
75+ .{ .opcode = 2, .args = &.{} },
76+ },
77+ .wl_data_device => &.{
78+ .{ .opcode = 0, .args = &.{.object, .object, .object, .uint} },
79+ .{ .opcode = 1, .args = &.{.object, .uint} },
80+ .{ .opcode = 2, .args = &.{} },
81+ },
82+ .wl_data_device_manager => &.{
83+ .{ .opcode = 0, .args = &.{.new_id} },
84+ .{ .opcode = 1, .args = &.{.new_id, .object} },
85+ .{ .opcode = 2, .args = &.{} },
86+ },
87+ .wl_data_offer => &.{
88+ .{ .opcode = 0, .args = &.{.uint, .string} },
89+ .{ .opcode = 1, .args = &.{.string, .fd} },
90+ .{ .opcode = 2, .args = &.{} },
91+ .{ .opcode = 3, .args = &.{} },
92+ .{ .opcode = 4, .args = &.{.uint, .uint} },
93+ },
94+ .wl_data_source => &.{
95+ .{ .opcode = 0, .args = &.{.string} },
96+ .{ .opcode = 1, .args = &.{} },
97+ .{ .opcode = 2, .args = &.{.uint} },
98+ },
99+ .wl_display => &.{
100+ .{ .opcode = 0, .args = &.{.new_id} },
101+ .{ .opcode = 1, .args = &.{.new_id} },
102+ },
103+ .wl_fixes => &.{
104+ .{ .opcode = 0, .args = &.{} },
105+ .{ .opcode = 1, .args = &.{.object} },
106+ .{ .opcode = 2, .args = &.{.object, .uint} },
107+ },
108+ .wl_keyboard => &.{
109+ .{ .opcode = 0, .args = &.{} },
110+ },
111+ .wl_output => &.{
112+ .{ .opcode = 0, .args = &.{} },
113+ },
114+ .wl_pointer => &.{
115+ .{ .opcode = 0, .args = &.{.uint, .object, .int, .int} },
116+ .{ .opcode = 1, .args = &.{} },
117+ },
118+ .wl_region => &.{
119+ .{ .opcode = 0, .args = &.{} },
120+ .{ .opcode = 1, .args = &.{.int, .int, .int, .int} },
121+ .{ .opcode = 2, .args = &.{.int, .int, .int, .int} },
122+ },
123+ .wl_registry => &.{
124+ .{ .opcode = 0, .args = &.{.uint, .new_id} },
125+ },
126+ .wl_seat => &.{
127+ .{ .opcode = 0, .args = &.{.new_id} },
128+ .{ .opcode = 1, .args = &.{.new_id} },
129+ .{ .opcode = 2, .args = &.{.new_id} },
130+ .{ .opcode = 3, .args = &.{} },
131+ },
132+ .wl_shell => &.{
133+ .{ .opcode = 0, .args = &.{.new_id, .object} },
134+ },
135+ .wl_shell_surface => &.{
136+ .{ .opcode = 0, .args = &.{.uint} },
137+ .{ .opcode = 1, .args = &.{.object, .uint} },
138+ .{ .opcode = 2, .args = &.{.object, .uint, .uint} },
139+ .{ .opcode = 3, .args = &.{} },
140+ .{ .opcode = 4, .args = &.{.object, .int, .int, .uint} },
141+ .{ .opcode = 5, .args = &.{.uint, .uint, .object} },
142+ .{ .opcode = 6, .args = &.{.object, .uint, .object, .int, .int, .uint} },
143+ .{ .opcode = 7, .args = &.{.object} },
144+ .{ .opcode = 8, .args = &.{.string} },
145+ .{ .opcode = 9, .args = &.{.string} },
146+ },
147+ .wl_shm => &.{
148+ .{ .opcode = 0, .args = &.{.new_id, .fd, .int} },
149+ .{ .opcode = 1, .args = &.{} },
150+ },
151+ .wl_shm_pool => &.{
152+ .{ .opcode = 0, .args = &.{.new_id, .int, .int, .int, .int, .uint} },
153+ .{ .opcode = 1, .args = &.{} },
154+ .{ .opcode = 2, .args = &.{.int} },
155+ },
156+ .wl_subcompositor => &.{
157+ .{ .opcode = 0, .args = &.{} },
158+ .{ .opcode = 1, .args = &.{.new_id, .object, .object} },
159+ },
160+ .wl_subsurface => &.{
161+ .{ .opcode = 0, .args = &.{} },
162+ .{ .opcode = 1, .args = &.{.int, .int} },
163+ .{ .opcode = 2, .args = &.{.object} },
164+ .{ .opcode = 3, .args = &.{.object} },
165+ .{ .opcode = 4, .args = &.{} },
166+ .{ .opcode = 5, .args = &.{} },
167+ },
168+ .wl_surface => &.{
169+ .{ .opcode = 0, .args = &.{} },
170+ .{ .opcode = 1, .args = &.{.object, .int, .int} },
171+ .{ .opcode = 2, .args = &.{.int, .int, .int, .int} },
172+ .{ .opcode = 3, .args = &.{.new_id} },
173+ .{ .opcode = 4, .args = &.{.object} },
174+ .{ .opcode = 5, .args = &.{.object} },
175+ .{ .opcode = 6, .args = &.{} },
176+ .{ .opcode = 7, .args = &.{.int} },
177+ .{ .opcode = 8, .args = &.{.int} },
178+ .{ .opcode = 9, .args = &.{.int, .int, .int, .int} },
179+ .{ .opcode = 10, .args = &.{.int, .int} },
180+ .{ .opcode = 11, .args = &.{.new_id} },
181+ },
182+ .wl_touch => &.{
183+ .{ .opcode = 0, .args = &.{} },
184+ },
185+ .wp_viewport => &.{
186+ .{ .opcode = 0, .args = &.{} },
187+ .{ .opcode = 1, .args = &.{.fixed, .fixed, .fixed, .fixed} },
188+ .{ .opcode = 2, .args = &.{.int, .int} },
189+ },
190+ .wp_viewporter => &.{
191+ .{ .opcode = 0, .args = &.{} },
192+ .{ .opcode = 1, .args = &.{.new_id, .object} },
193+ },
194+ .xdg_popup => &.{
195+ .{ .opcode = 0, .args = &.{} },
196+ .{ .opcode = 1, .args = &.{.object, .uint} },
197+ .{ .opcode = 2, .args = &.{.object, .uint} },
198+ },
199+ .xdg_positioner => &.{
200+ .{ .opcode = 0, .args = &.{} },
201+ .{ .opcode = 1, .args = &.{.int, .int} },
202+ .{ .opcode = 2, .args = &.{.int, .int, .int, .int} },
203+ .{ .opcode = 3, .args = &.{.uint} },
204+ .{ .opcode = 4, .args = &.{.uint} },
205+ .{ .opcode = 5, .args = &.{.uint} },
206+ .{ .opcode = 6, .args = &.{.int, .int} },
207+ .{ .opcode = 7, .args = &.{} },
208+ .{ .opcode = 8, .args = &.{.int, .int} },
209+ .{ .opcode = 9, .args = &.{.uint} },
210+ },
211+ .xdg_surface => &.{
212+ .{ .opcode = 0, .args = &.{} },
213+ .{ .opcode = 1, .args = &.{.new_id} },
214+ .{ .opcode = 2, .args = &.{.new_id, .object, .object} },
215+ .{ .opcode = 3, .args = &.{.int, .int, .int, .int} },
216+ .{ .opcode = 4, .args = &.{.uint} },
217+ },
218+ .xdg_toplevel => &.{
219+ .{ .opcode = 0, .args = &.{} },
220+ .{ .opcode = 1, .args = &.{.object} },
221+ .{ .opcode = 2, .args = &.{.string} },
222+ .{ .opcode = 3, .args = &.{.string} },
223+ .{ .opcode = 4, .args = &.{.object, .uint, .int, .int} },
224+ .{ .opcode = 5, .args = &.{.object, .uint} },
225+ .{ .opcode = 6, .args = &.{.object, .uint, .uint} },
226+ .{ .opcode = 7, .args = &.{.int, .int} },
227+ .{ .opcode = 8, .args = &.{.int, .int} },
228+ .{ .opcode = 9, .args = &.{} },
229+ .{ .opcode = 10, .args = &.{} },
230+ .{ .opcode = 11, .args = &.{.object} },
231+ .{ .opcode = 12, .args = &.{} },
232+ .{ .opcode = 13, .args = &.{} },
233+ },
234+ .xdg_wm_base => &.{
235+ .{ .opcode = 0, .args = &.{} },
236+ .{ .opcode = 1, .args = &.{.new_id} },
237+ .{ .opcode = 2, .args = &.{.new_id, .object} },
238+ .{ .opcode = 3, .args = &.{.uint} },
239+ },
240+ };
241+}
242+
243+fn eventSigs(iface: Interface) []const MessageSig {
244+ return switch (iface) {
245+ .altaica_shm => &.{},
246+ .altaica_shm_pool => &.{},
247+ .wl_buffer => &.{
248+ .{ .opcode = 0, .args = &.{} },
249+ },
250+ .wl_callback => &.{
251+ .{ .opcode = 0, .args = &.{.uint} },
252+ },
253+ .wl_compositor => &.{},
254+ .wl_data_device => &.{
255+ .{ .opcode = 0, .args = &.{.new_id} },
256+ .{ .opcode = 1, .args = &.{.uint, .object, .fixed, .fixed, .object} },
257+ .{ .opcode = 2, .args = &.{} },
258+ .{ .opcode = 3, .args = &.{.uint, .fixed, .fixed} },
259+ .{ .opcode = 4, .args = &.{} },
260+ .{ .opcode = 5, .args = &.{.object} },
261+ },
262+ .wl_data_device_manager => &.{},
263+ .wl_data_offer => &.{
264+ .{ .opcode = 0, .args = &.{.string} },
265+ .{ .opcode = 1, .args = &.{.uint} },
266+ .{ .opcode = 2, .args = &.{.uint} },
267+ },
268+ .wl_data_source => &.{
269+ .{ .opcode = 0, .args = &.{.string} },
270+ .{ .opcode = 1, .args = &.{.string, .fd} },
271+ .{ .opcode = 2, .args = &.{} },
272+ .{ .opcode = 3, .args = &.{} },
273+ .{ .opcode = 4, .args = &.{} },
274+ .{ .opcode = 5, .args = &.{.uint} },
275+ },
276+ .wl_display => &.{
277+ .{ .opcode = 0, .args = &.{.object, .uint, .string} },
278+ .{ .opcode = 1, .args = &.{.uint} },
279+ },
280+ .wl_fixes => &.{},
281+ .wl_keyboard => &.{
282+ .{ .opcode = 0, .args = &.{.uint, .fd, .uint} },
283+ .{ .opcode = 1, .args = &.{.uint, .object, .array} },
284+ .{ .opcode = 2, .args = &.{.uint, .object} },
285+ .{ .opcode = 3, .args = &.{.uint, .uint, .uint, .uint} },
286+ .{ .opcode = 4, .args = &.{.uint, .uint, .uint, .uint, .uint} },
287+ .{ .opcode = 5, .args = &.{.int, .int} },
288+ },
289+ .wl_output => &.{
290+ .{ .opcode = 0, .args = &.{.int, .int, .int, .int, .int, .string, .string, .int} },
291+ .{ .opcode = 1, .args = &.{.uint, .int, .int, .int} },
292+ .{ .opcode = 2, .args = &.{} },
293+ .{ .opcode = 3, .args = &.{.int} },
294+ .{ .opcode = 4, .args = &.{.string} },
295+ .{ .opcode = 5, .args = &.{.string} },
296+ },
297+ .wl_pointer => &.{
298+ .{ .opcode = 0, .args = &.{.uint, .object, .fixed, .fixed} },
299+ .{ .opcode = 1, .args = &.{.uint, .object} },
300+ .{ .opcode = 2, .args = &.{.uint, .fixed, .fixed} },
301+ .{ .opcode = 3, .args = &.{.uint, .uint, .uint, .uint} },
302+ .{ .opcode = 4, .args = &.{.uint, .uint, .fixed} },
303+ .{ .opcode = 5, .args = &.{} },
304+ .{ .opcode = 6, .args = &.{.uint} },
305+ .{ .opcode = 7, .args = &.{.uint, .uint} },
306+ .{ .opcode = 8, .args = &.{.uint, .int} },
307+ .{ .opcode = 9, .args = &.{.uint, .int} },
308+ .{ .opcode = 10, .args = &.{.uint, .uint} },
309+ .{ .opcode = 11, .args = &.{.fixed, .fixed} },
310+ },
311+ .wl_region => &.{},
312+ .wl_registry => &.{
313+ .{ .opcode = 0, .args = &.{.uint, .string, .uint} },
314+ .{ .opcode = 1, .args = &.{.uint} },
315+ },
316+ .wl_seat => &.{
317+ .{ .opcode = 0, .args = &.{.uint} },
318+ .{ .opcode = 1, .args = &.{.string} },
319+ },
320+ .wl_shell => &.{},
321+ .wl_shell_surface => &.{
322+ .{ .opcode = 0, .args = &.{.uint} },
323+ .{ .opcode = 1, .args = &.{.uint, .int, .int} },
324+ .{ .opcode = 2, .args = &.{} },
325+ },
326+ .wl_shm => &.{
327+ .{ .opcode = 0, .args = &.{.uint} },
328+ },
329+ .wl_shm_pool => &.{},
330+ .wl_subcompositor => &.{},
331+ .wl_subsurface => &.{},
332+ .wl_surface => &.{
333+ .{ .opcode = 0, .args = &.{.object} },
334+ .{ .opcode = 1, .args = &.{.object} },
335+ .{ .opcode = 2, .args = &.{.int} },
336+ .{ .opcode = 3, .args = &.{.uint} },
337+ },
338+ .wl_touch => &.{
339+ .{ .opcode = 0, .args = &.{.uint, .uint, .object, .int, .fixed, .fixed} },
340+ .{ .opcode = 1, .args = &.{.uint, .uint, .int} },
341+ .{ .opcode = 2, .args = &.{.uint, .int, .fixed, .fixed} },
342+ .{ .opcode = 3, .args = &.{} },
343+ .{ .opcode = 4, .args = &.{} },
344+ .{ .opcode = 5, .args = &.{.int, .fixed, .fixed} },
345+ .{ .opcode = 6, .args = &.{.int, .fixed} },
346+ },
347+ .wp_viewport => &.{},
348+ .wp_viewporter => &.{},
349+ .xdg_popup => &.{
350+ .{ .opcode = 0, .args = &.{.int, .int, .int, .int} },
351+ .{ .opcode = 1, .args = &.{} },
352+ .{ .opcode = 2, .args = &.{.uint} },
353+ },
354+ .xdg_positioner => &.{},
355+ .xdg_surface => &.{
356+ .{ .opcode = 0, .args = &.{.uint} },
357+ },
358+ .xdg_toplevel => &.{
359+ .{ .opcode = 0, .args = &.{.int, .int, .array} },
360+ .{ .opcode = 1, .args = &.{} },
361+ .{ .opcode = 2, .args = &.{.int, .int} },
362+ .{ .opcode = 3, .args = &.{.array} },
363+ },
364+ .xdg_wm_base => &.{
365+ .{ .opcode = 0, .args = &.{.uint} },
366+ },
367+ };
368+}
369+
370+pub fn globalName(iface: Interface) []const u8 {
371+ return switch (iface) {
372+ .altaica_shm => "altaica_shm",
373+ .altaica_shm_pool => "altaica_shm_pool",
374+ .wl_buffer => "wl_buffer",
375+ .wl_callback => "wl_callback",
376+ .wl_compositor => "wl_compositor",
377+ .wl_data_device => "wl_data_device",
378+ .wl_data_device_manager => "wl_data_device_manager",
379+ .wl_data_offer => "wl_data_offer",
380+ .wl_data_source => "wl_data_source",
381+ .wl_display => "wl_display",
382+ .wl_fixes => "wl_fixes",
383+ .wl_keyboard => "wl_keyboard",
384+ .wl_output => "wl_output",
385+ .wl_pointer => "wl_pointer",
386+ .wl_region => "wl_region",
387+ .wl_registry => "wl_registry",
388+ .wl_seat => "wl_seat",
389+ .wl_shell => "wl_shell",
390+ .wl_shell_surface => "wl_shell_surface",
391+ .wl_shm => "wl_shm",
392+ .wl_shm_pool => "wl_shm_pool",
393+ .wl_subcompositor => "wl_subcompositor",
394+ .wl_subsurface => "wl_subsurface",
395+ .wl_surface => "wl_surface",
396+ .wl_touch => "wl_touch",
397+ .wp_viewport => "wp_viewport",
398+ .wp_viewporter => "wp_viewporter",
399+ .xdg_popup => "xdg_popup",
400+ .xdg_positioner => "xdg_positioner",
401+ .xdg_surface => "xdg_surface",
402+ .xdg_toplevel => "xdg_toplevel",
403+ .xdg_wm_base => "xdg_wm_base",
404+ };
405+}
406+
407+pub fn globalVersion(iface: Interface) u32 {
408+ return switch (iface) {
409+ .altaica_shm => 1,
410+ .altaica_shm_pool => 1,
411+ .wl_buffer => 1,
412+ .wl_callback => 1,
413+ .wl_compositor => 7,
414+ .wl_data_device => 4,
415+ .wl_data_device_manager => 4,
416+ .wl_data_offer => 4,
417+ .wl_data_source => 4,
418+ .wl_display => 1,
419+ .wl_fixes => 2,
420+ .wl_keyboard => 11,
421+ .wl_output => 4,
422+ .wl_pointer => 11,
423+ .wl_region => 7,
424+ .wl_registry => 1,
425+ .wl_seat => 11,
426+ .wl_shell => 1,
427+ .wl_shell_surface => 1,
428+ .wl_shm => 2,
429+ .wl_shm_pool => 2,
430+ .wl_subcompositor => 1,
431+ .wl_subsurface => 1,
432+ .wl_surface => 7,
433+ .wl_touch => 11,
434+ .wp_viewport => 1,
435+ .wp_viewporter => 1,
436+ .xdg_popup => 7,
437+ .xdg_positioner => 7,
438+ .xdg_surface => 7,
439+ .xdg_toplevel => 7,
440+ .xdg_wm_base => 7,
441+ };
442+}