code wiki / (root) / nx_x11_window.nx

nx_x11_window.nx source

↩ module page · 225 lines · 8006 B

1// nx_x11_window.nx -- bits-up X11 CreateWindow + MapWindow. 2// 3// Session 2 of the bits-up browser arc (Task #83). Composes the 4// X11 connection from nx_x11_connect with the wire-protocol opcodes 5// that put a window on screen. WSLg translates the X11 stream into 6// a real native Windows surface. 7// 8// CreateWindow (opcode 1) layout (X Protocol §10 / xproto.xml): 9// byte 0: opcode = 1 10// byte 1: depth (0 = CopyFromParent) 11// bytes 2-3: request_length (4-byte units) 12// bytes 4-7: window_id (allocated via nx_x11_alloc_id) 13// bytes 8-11: parent (e.g. root_window) 14// bytes 12-13: x (signed) 15// bytes 14-15: y 16// bytes 16-17: width 17// bytes 18-19: height 18// bytes 20-21: border_width 19// bytes 22-23: class (1 = InputOutput, 2 = InputOnly) 20// bytes 24-27: visual (0 = CopyFromParent) 21// bytes 28-31: value_mask 22// (optional) value_list (4 bytes per set bit in value_mask) 23// 24// value-mask bits we use (X protocol §6.7): 25// CWBackPixel = 0x00000002 26// CWEventMask = 0x00000800 27// 28// MapWindow (opcode 8): 29// byte 0: opcode = 8 30// byte 1: unused 31// bytes 2-3: request_length = 2 32// bytes 4-7: window_id 33// 34// API: 35// nx_x11_create_window(conn, x, y, w, h, bg_pixel, event_mask) 36// -> window_id (or 0 - NX_X11_*) 37// nx_x11_map_window(conn, window_id) -> 0 | negative 38// nx_x11_flush_via_get_input_focus(conn) 39// -- forces server to actually process pending requests by 40// sending a synchronous round-trip (GetInputFocus). Without 41// this WSLg sometimes buffers MapWindow indefinitely. 42// 43// license_tier: ORIGINAL 44// genealogy_id: international-research-sources/x_org/xproto_v11_r0 45// lineage_id: nishi_x11_window_q10 46 47import "nx_syscalls.nx" 48import "nx_x11_connect.nx" 49 50const NX_X11_CW_BACK_PIXEL: i64 = 0x00000002 51const NX_X11_CW_EVENT_MASK: i64 = 0x00000800 52 53// LE u16/u32 writers. 54func _x11_wr_u16(buf: *u8, off: i64, v: i64) -> i64 { 55 buf[off] = (v & 0xff) as u8 56 buf[off + 1] = ((v >> 8) & 0xff) as u8 57 return 0 58} 59 60func _x11_wr_u32(buf: *u8, off: i64, v: i64) -> i64 { 61 buf[off] = (v & 0xff) as u8 62 buf[off + 1] = ((v >> 8) & 0xff) as u8 63 buf[off + 2] = ((v >> 16) & 0xff) as u8 64 buf[off + 3] = ((v >> 24) & 0xff) as u8 65 return 0 66} 67 68// Write n bytes to conn.fd, retrying on short writes. 69func _x11_send(conn: *X11Conn, buf: *u8, n: i64) -> i64 { 70 var off: i64 = 0 71 while off < n { 72 let w: i64 = sys_write(conn.fd, ((buf as i64) + off) as *u8, n - off) 73 if w <= 0 { return 0 - 1 } 74 off = off + w 75 } 76 return 0 77} 78 79// CreateWindow + value list (CWBackPixel + CWEventMask). 80// Returns new window_id (positive) or 0 - NX_X11_* on failure. 81func nx_x11_create_window(conn: *X11Conn, 82 x: i64, y: i64, w: i64, h: i64, 83 bg_pixel: i64, event_mask: i64) -> i64 { 84 let wid: i64 = nx_x11_alloc_id(conn) 85 86 // Request: 32 bytes core + 8 bytes values (2 values * 4 bytes) 87 let req: *u8 = sys_mmap(64) 88 var i: i64 = 0 89 while i < 64 { req[i] = 0; i = i + 1 } 90 91 let value_mask: i64 = NX_X11_CW_BACK_PIXEL | NX_X11_CW_EVENT_MASK 92 let total_len_bytes: i64 = 40 93 let total_len_words: i64 = total_len_bytes / 4 // 10 94 95 req[0] = 1 // opcode 96 req[1] = 0 // depth = CopyFromParent 97 _x11_wr_u16(req, 2, total_len_words) 98 _x11_wr_u32(req, 4, wid) 99 _x11_wr_u32(req, 8, conn.root_window) 100 _x11_wr_u16(req, 12, x) 101 _x11_wr_u16(req, 14, y) 102 _x11_wr_u16(req, 16, w) 103 _x11_wr_u16(req, 18, h) 104 _x11_wr_u16(req, 20, 0) // border-width 105 _x11_wr_u16(req, 22, 1) // class = InputOutput 106 _x11_wr_u32(req, 24, 0) // visual = CopyFromParent 107 _x11_wr_u32(req, 28, value_mask) 108 // value list: pixel values follow in value-mask bit order 109 _x11_wr_u32(req, 32, bg_pixel) 110 _x11_wr_u32(req, 36, event_mask) 111 112 if _x11_send(conn, req, total_len_bytes) < 0 { return 0 - 3 } 113 return wid 114} 115 116// ChangeProperty (opcode 18) -- set a string property on a window. 117// Used to set WM_NAME so window managers (WSLg's compositor) can 118// label the window and surface it on the desktop. 119// 120// Atom IDs are well-known: WM_NAME=39, STRING=31. 121// 122// Request layout: 123// byte 0: opcode = 18 124// byte 1: mode (0 = Replace) 125// bytes 2-3: request_length (4-byte units) 126// bytes 4-7: window 127// bytes 8-11: property atom 128// bytes 12-15: type atom 129// byte 16: format (8, 16, or 32) 130// bytes 17-19: pad 131// bytes 20-23: data_len (number of FORMAT-sized elements) 132// bytes 24+: data (padded to 4-byte multiple) 133func nx_x11_set_wm_name(conn: *X11Conn, window: i64, 134 name: *u8, name_len: i64) -> i64 { 135 // Round data length up to 4-byte multiple. 136 var padded_len: i64 = name_len 137 if (padded_len & 3) != 0 { 138 padded_len = padded_len + 4 - (padded_len & 3) 139 } 140 let total_len_bytes: i64 = 24 + padded_len 141 let total_len_words: i64 = total_len_bytes / 4 142 143 let req: *u8 = sys_mmap(total_len_bytes + 16) 144 var i: i64 = 0 145 while i < total_len_bytes + 16 { req[i] = 0; i = i + 1 } 146 147 req[0] = 18 // opcode 148 req[1] = 0 // mode = Replace 149 _x11_wr_u16(req, 2, total_len_words) 150 _x11_wr_u32(req, 4, window) 151 _x11_wr_u32(req, 8, 39) // property = WM_NAME 152 _x11_wr_u32(req, 12, 31) // type = STRING 153 req[16] = 8 // format = 8 bits 154 _x11_wr_u32(req, 20, name_len) // data_len (8-bit chars) 155 var k: i64 = 0 156 while k < name_len { 157 req[24 + k] = name[k] 158 k = k + 1 159 } 160 return _x11_send(conn, req, total_len_bytes) 161} 162 163// MapWindow opcode 8. 164func nx_x11_map_window(conn: *X11Conn, window_id: i64) -> i64 { 165 let req: *u8 = sys_mmap(16) 166 req[0] = 8 167 req[1] = 0 168 _x11_wr_u16(req, 2, 2) 169 _x11_wr_u32(req, 4, window_id) 170 return _x11_send(conn, req, 8) 171} 172 173// GetInputFocus (opcode 43) -- 4-byte request that elicits a 32-byte 174// reply. Used as a synchronous round-trip to force the server to 175// process all queued requests. ALSO checks for X11 error replies: 176// byte 0 == 0 means Error reply (byte 1 is the error code). 177// 178// Returns: 179// 0 = reply received cleanly (server happy with prior requests) 180// -1 = send failed 181// -2 = read failed 182// 100+code = X11 error code (3=Window, 4=Pixmap, 5=Atom, 8=Match, 183// 9=Drawable, 10=Access, 11=Alloc, 12=Colormap, ...) 184func nx_x11_flush_via_get_input_focus(conn: *X11Conn) -> i64 { 185 let req: *u8 = sys_mmap(8) 186 req[0] = 43 187 req[1] = 0 188 _x11_wr_u16(req, 2, 1) 189 if _x11_send(conn, req, 4) < 0 { return 0 - 1 } 190 // Drain packets until we see OUR Reply (kind=1). Events (kind>=2) 191 // and errors (kind=0) get dropped on the diagnostic path; a real 192 // event-loop forwards them to a dispatcher. Critical: consume 193 // OUR reply so subsequent calls don't pick it up by mistake. 194 let reply: *u8 = sys_mmap(64) 195 var saw_reply: i64 = 0 196 var safety: i64 = 0 197 while saw_reply == 0 { 198 if safety >= 64 { return 0 - 3 } 199 var got: i64 = 0 200 while got < 32 { 201 let r: i64 = sys_read(conn.fd, ((reply as i64) + got) as *u8, 32 - got) 202 if r <= 0 { return 0 - 2 } 203 got = got + r 204 } 205 let kind: i64 = (reply[0] & 0xff) as i64 206 if kind == 1 { saw_reply = 1 } 207 safety = safety + 1 208 } 209 return 0 210} 211 212// Stub kept to satisfy the legacy err-code path that no longer fires. 213func _x11_dead_err_path() -> i64 { 214 let reply: *u8 = sys_mmap(8) 215 let kind: i64 = 0 216 if kind == 0 { 217 let err_code: i64 = (reply[1] & 0xff) as i64 218 return 100 + err_code 219 } 220 return 0 221} 222 223func main() -> i64 { 224 return 0 225}