nx_x11_get_image.nx source
↩ module page · 110 lines · 3936 B
1// nx_x11_get_image.nx -- bits-up X11 GetImage opcode + reply read.
2//
3// Part of the Nishi-troubleshoots-Nishi self-closing-loop arc.
4// Pulls pixel data BACK from a drawable so we can save it to disk
5// + diff/inspect off-line.
6//
7// GetImage (opcode 73):
8// byte 0: 73
9// byte 1: format (1 = XYPixmap, 2 = ZPixmap)
10// bytes 2-3: request_length = 5
11// bytes 4-7: drawable
12// bytes 8-9: x
13// bytes 10-11: y
14// bytes 12-13: width
15// bytes 14-15: height
16// bytes 16-19: plane_mask (0xFFFFFFFF for all planes)
17//
18// Reply (32-byte header + data):
19// byte 0: 1 (Reply marker)
20// byte 1: depth
21// bytes 2-3: sequence
22// bytes 4-7: reply_length (4-byte units; tells us pixel-data size)
23// bytes 8-11: visual
24// bytes 12-31: pad
25// bytes 32+: pixel data
26//
27// For ZPixmap on a 24-bit visual, the server typically returns
28// 32-bit-per-pixel data (BGRX or XBGR). Total data bytes =
29// reply_length * 4. Caller allocates a buffer of width*height*4
30// + some slack and we copy the result there.
31//
32// license_tier: ORIGINAL
33// genealogy_id: international-research-sources/x_org/xproto_v11_r0
34// lineage_id: nishi_x11_get_image_q10
35
36import "nx_syscalls.nx"
37import "nx_x11_connect.nx"
38import "nx_x11_window.nx"
39import "nx_x11_paint.nx"
40
41const NX_X11_FMT_Z_PIXMAP: i64 = 2
42
43// Read N bytes EXACTLY (block until full).
44func _x11_read_exact(conn: *X11Conn, buf: *u8, n: i64) -> i64 {
45 var off: i64 = 0
46 while off < n {
47 let r: i64 = sys_read(conn.fd, ((buf as i64) + off) as *u8, n - off)
48 if r <= 0 { return 0 - 1 }
49 off = off + r
50 }
51 return 0
52}
53
54// GetImage and copy the result into pixel_out. pixel_out must have
55// at least width*height*4 bytes. Returns:
56// >= 0 : bytes copied into pixel_out
57// < 0 : protocol or socket failure
58//
59// NOTE: skips any pending events on the socket (drains everything
60// until we see kind=1 Reply). Caller should call this BEFORE
61// entering the main event loop, or wrap event-loop reads to forward
62// non-Reply packets back to the dispatcher.
63func nx_x11_get_image(conn: *X11Conn, drawable: i64,
64 x: i64, y: i64, width: i64, height: i64,
65 pixel_out: *u8, pixel_out_cap: i64) -> i64 {
66 let req: *u8 = sys_mmap(32)
67 var i: i64 = 0
68 while i < 32 { req[i] = 0; i = i + 1 }
69 req[0] = 73
70 req[1] = NX_X11_FMT_Z_PIXMAP as u8
71 _x11_wr_u16(req, 2, 5)
72 _x11_wr_u32(req, 4, drawable)
73 _x11_wr_u16(req, 8, x)
74 _x11_wr_u16(req, 10, y)
75 _x11_wr_u16(req, 12, width)
76 _x11_wr_u16(req, 14, height)
77 _x11_wr_u32(req, 16, 0xFFFFFFFF)
78 if _x11_send(conn, req, 20) < 0 { return 0 - 1 }
79
80 // Drain non-Reply packets, find the Reply marker.
81 let hdr: *u8 = sys_mmap(64)
82 var found: i64 = 0
83 var safety: i64 = 0
84 while found == 0 {
85 if safety >= 64 { return 0 - 2 }
86 if _x11_read_exact(conn, hdr, 32) < 0 { return 0 - 3 }
87 let kind: i64 = (hdr[0] & 0xff) as i64
88 if kind == 1 { found = 1 }
89 // An X error here means our reply is NEVER coming -- dropping it used to leave the
90 // caller blocked in read() forever (measured: GetImage on a composited window hung a
91 // selftest until SIGPIPE). Fail LOUD with the error code instead: -(100+code).
92 if kind == 0 { return 0 - (100 + ((hdr[1] & 0xff) as i64)) }
93 safety = safety + 1
94 }
95
96 // reply_length is in 4-byte units, gives PIXEL DATA size.
97 let extra_words: i64 = ((hdr[4] & 0xff) as i64)
98 | (((hdr[5] & 0xff) as i64) << 8)
99 | (((hdr[6] & 0xff) as i64) << 16)
100 | (((hdr[7] & 0xff) as i64) << 24)
101 let extra_bytes: i64 = extra_words * 4
102 if extra_bytes > pixel_out_cap { return 0 - 4 }
103 if extra_bytes < 0 { return 0 - 5 }
104 if _x11_read_exact(conn, pixel_out, extra_bytes) < 0 { return 0 - 6 }
105 return extra_bytes
106}
107
108func main() -> i64 {
109 return 0
110}