nx_x11_screenshot.nx source
↩ module page · 67 lines · 2318 B
1// nx_x11_screenshot.nx -- capture a drawable's pixels and drop them
2// to a PPM file Claude (or any image viewer) can open.
3//
4// Self-closing-loop primitive: "Nishi troubleshoots Nishi natively."
5// Composes nx_x11_get_image (pull pixels back from the server) with
6// nx_ppm_writer (encode + write). Used by every visible bits-up
7// demo so we can verify renderings without asking the user "did
8// you see X?"
9//
10// API:
11// nx_x11_save_drawable_as_ppm(conn, drawable, w, h, path) -> 0 | <0
12//
13// license_tier: ORIGINAL
14// lineage_id: nishi_x11_screenshot_q10
15
16import "nx_syscalls.nx"
17import "nx_x11_connect.nx"
18import "nx_x11_get_image.nx"
19import "nx_ppm_writer.nx"
20
21// Capture w*h pixels from the top-left of `drawable` and write a PPM
22// P6 file at `path`. Returns 0 on success, negative on failure.
23func nx_x11_save_drawable_as_ppm(conn: *X11Conn, drawable: i64,
24 width: i64, height: i64,
25 path: *u8) -> i64 {
26 // Allocate buffer for the BGRX response (4 bytes/pixel).
27 let bgrx_cap: i64 = width * height * 4 + 64
28 let bgrx: *u8 = sys_mmap(bgrx_cap + 64)
29 let got: i64 = nx_x11_get_image(conn, drawable, 0, 0, width, height,
30 bgrx, bgrx_cap)
31 if got < 0 { return 0 - 10 }
32
33 // Transcode BGRX -> RGB (3 bytes/pixel) so we can pass to
34 // ppm_write_p6. Top-down rows preserved.
35 let rgb_bytes: i64 = width * height * 3
36 let rgb: *u8 = sys_mmap(rgb_bytes + 64)
37 var y: i64 = 0
38 while y < height {
39 var x: i64 = 0
40 while x < width {
41 let po: i64 = (y * width + x) * 4
42 let ro: i64 = (y * width + x) * 3
43 rgb[ro + 0] = bgrx[po + 2] // R
44 rgb[ro + 1] = bgrx[po + 1] // G
45 rgb[ro + 2] = bgrx[po + 0] // B
46 x = x + 1
47 }
48 y = y + 1
49 }
50
51 // Build PPM buffer (header + binary pixels).
52 let ppm_cap: i64 = 64 + rgb_bytes
53 let ppm: *u8 = sys_mmap(ppm_cap + 64)
54 let n: i64 = ppm_write_p6(ppm, ppm_cap, width, height, rgb)
55 if n < 0 { return 0 - 20 }
56
57 // Write to file.
58 let fd: i64 = sys_openat_wr(path, 0x1A4) // 0644
59 if fd < 0 { return 0 - 30 }
60 sys_write(fd, ppm, n)
61 sys_close(fd)
62 return 0
63}
64
65func main() -> i64 {
66 return 0
67}