code wiki / (root) / nx_nishios_gui.nx

nx_nishios_gui.nx source

↩ module page · 141 lines · 9381 B

1// nx_nishios_gui.nx -- NishiOS GUI rung-1: the kernel DRAWS A DESKTOP into a framebuffer + exports it 2// as a REAL viewable image. On real x86 a kernel gets a linear framebuffer (VESA/VBE or UEFI GOP) and 3// draws pixels into it. This models exactly that: a 320x200 RGB framebuffer + kernel drawing primitives 4// (clear / filled rect / bitmap-font text), used to render a NishiOS desktop -- title bar, a window with 5// its own title strip, a logo, a taskbar with a start button -- then writes it out as a genuine 24-bit 6// BMP (BITMAPFILEHEADER+BITMAPINFOHEADER, BGR bottom-up) you can open in any image viewer / browser, plus 7// an HTML wrapper for the "window". This is the GUI you can SEE, drawn by our own code, not a mockup. 8// KAT: the framebuffer holds the expected desktop pixels (bg / title bar / window fill / rendered text) 9// and the BMP is well-formed ('BM', correct filesize, 24bpp). 10// HONEST SCOPE: a STATIC render (no mouse/event-loop/input yet). A live compositor with input + a real 11// framebuffer device wired into the boot kernel are the next rungs. No hw writes (Rule 26). 12// expect_exit: 0 license_tier: ORIGINAL 13import "nx_syscalls.nx" 14import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc) 15const K_MAGIC_2835: i64 = 2835 16 17func gui_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 18// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer 19// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the 20// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls). 21// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign. 22func gui_num(v: i64) -> i64 { nxi_out(v); return 0 } 23 24// --- framebuffer primitives (what the kernel does to the linear framebuffer) --- 25func setpx(fb: *u8, W: i64, H: i64, x: i64, y: i64, r: i64, g: i64, b: i64) -> i64 { 26 if x>=0 { if x<W { if y>=0 { if y<H { let i: i64=(y*W+x)*3; fb[i]=r as u8; fb[i+1]=g as u8; fb[i+2]=b as u8 } } } } 27 return 0 28} 29func fill_rect(fb: *u8, W: i64, H: i64, x: i64, y: i64, w: i64, h: i64, r: i64, g: i64, b: i64) -> i64 { 30 var yy: i64=0 31 while yy<h { var xx: i64=0; while xx<w { setpx(fb,W,H,x+xx,y+yy,r,g,b); xx=xx+1 } yy=yy+1 } 32 return 0 33} 34// draw one 8x8 glyph at (x,y), each glyph pixel a scale x scale block 35func draw_char(fb: *u8, W: i64, H: i64, x: i64, y: i64, g: *u8, scale: i64, r: i64, gg: i64, b: i64) -> i64 { 36 var row: i64=0 37 while row<8 { 38 let bits: i64 = g[row] as i64 39 var col: i64=0 40 while col<8 { 41 if ((bits >> (7-col)) & 1) == 1 { fill_rect(fb,W,H, x+col*scale, y+row*scale, scale, scale, r,gg,b) } 42 col=col+1 43 } 44 row=row+1 45 } 46 return 0 47} 48func draw_text(fb: *u8, W: i64, H: i64, font: *u8, idx: *u8, n: i64, x: i64, y: i64, scale: i64, r: i64, g: i64, b: i64) -> i64 { 49 var k: i64=0 50 while k<n { 51 let gi: i64 = idx[k] as i64 52 draw_char(fb,W,H, x + k*9*scale, y, ((font as i64) + gi*8) as *u8, scale, r,g,b) 53 k=k+1 54 } 55 return 0 56} 57// install one 8-row glyph into the font table 58func gly(f: *u8, i: i64, r0: i64, r1: i64, r2: i64, r3: i64, r4: i64, r5: i64, r6: i64, r7: i64) -> i64 { 59 let o: i64=i*8 60 f[o]=r0 as u8; f[o+1]=r1 as u8; f[o+2]=r2 as u8; f[o+3]=r3 as u8; f[o+4]=r4 as u8; f[o+5]=r5 as u8; f[o+6]=r6 as u8; f[o+7]=r7 as u8 61 return 0 62} 63func put32(buf: *u8, o: i64, v: i64) -> i64 { buf[o]=(v & 0xFF) as u8; buf[o+1]=((v>>8)&0xFF) as u8; buf[o+2]=((v>>16)&0xFF) as u8; buf[o+3]=((v>>24)&0xFF) as u8; return o+4 } 64func put16(buf: *u8, o: i64, v: i64) -> i64 { buf[o]=(v & 0xFF) as u8; buf[o+1]=((v>>8)&0xFF) as u8; return o+2 } 65 66func main() -> i64 { 67 gui_puts("NishiOS GUI rung-1: the kernel draws a desktop into a framebuffer -> real BMP image\n" as *u8) 68 let W: i64 = 320 69 let H: i64 = 200 70 let fb: *u8 = sys_mmap(W*H*3) 71 72 // font: N I S H O (indices 0..4); "NISHIOS" = N I S H I O S 73 let font: *u8 = sys_mmap(64) 74 gly(font,0, 0x81,0xC1,0xA1,0x91,0x89,0x85,0x83,0x81) // N 75 gly(font,1, 0x7C,0x10,0x10,0x10,0x10,0x10,0x7C,0x00) // I 76 gly(font,2, 0x7E,0x80,0x80,0x7C,0x02,0x02,0x7C,0x00) // S 77 gly(font,3, 0x81,0x81,0x81,0xFF,0x81,0x81,0x81,0x00) // H 78 gly(font,4, 0x7C,0x82,0x82,0x82,0x82,0x82,0x7C,0x00) // O 79 let idx: *u8 = sys_mmap(8) 80 idx[0]=0 as u8; idx[1]=1 as u8; idx[2]=2 as u8; idx[3]=3 as u8; idx[4]=1 as u8; idx[5]=4 as u8; idx[6]=2 as u8 // N I S H I O S 81 82 // --- render the NishiOS desktop --- 83 fill_rect(fb,W,H, 0,0, W,H, 0,40,60) // desktop background (dark teal) 84 fill_rect(fb,W,H, 0,0, W,20, 30,30,120) // top title bar 85 draw_text(fb,W,H, font, idx, 7, 6,3, 2, 255,255,255) // "NISHIOS" in the title bar (white, scale 2) 86 fill_rect(fb,W,H, 50,45, 220,120, 210,210,220) // a window (light gray) 87 fill_rect(fb,W,H, 50,45, 220,16, 60,60,160) // the window's own title strip 88 draw_text(fb,W,H, font, idx, 7, 54,47, 1, 235,235,245) // window title text (small) 89 draw_text(fb,W,H, font, idx, 7, 66,95, 2, 20,20,60) // window body logo (dark, scale 2) 90 fill_rect(fb,W,H, 0,185, W,15, 20,20,40) // taskbar 91 fill_rect(fb,W,H, 4,187, 34,11, 80,200,80) // a green "start" button 92 93 // --- export as a real 24-bit BMP (BGR, bottom-up) --- 94 let rowbytes: i64 = W*3 95 let pixbytes: i64 = rowbytes*H 96 let filesize: i64 = 54 + pixbytes 97 let buf: *u8 = sys_mmap(filesize + 16) 98 buf[0]=66 as u8; buf[1]=77 as u8 // 'B','M' 99 var o: i64=2 100 o=put32(buf,o,filesize); o=put32(buf,o,0); o=put32(buf,o,54) // file header 101 o=put32(buf,o,40); o=put32(buf,o,W); o=put32(buf,o,H); o=put16(buf,o,1); o=put16(buf,o,24) // info header 102 o=put32(buf,o,0); o=put32(buf,o,pixbytes); o=put32(buf,o,K_MAGIC_2835); o=put32(buf,o,K_MAGIC_2835); o=put32(buf,o,0); o=put32(buf,o,0) 103 var fy: i64=0 104 while fy<H { 105 let srcrow: i64 = H-1-fy // BMP is bottom-up 106 var x: i64=0 107 while x<W { 108 let i: i64=(srcrow*W+x)*3 109 buf[o]=fb[i+2]; buf[o+1]=fb[i+1]; buf[o+2]=fb[i]; o=o+3 // BGR 110 x=x+1 111 } 112 fy=fy+1 113 } 114 let fd: i64 = sys_openat_wr("knowledge/status/nishios_gui.bmp\x00" as *u8, 0x1a4) 115 if fd<=0 { gui_puts("GUI RED: cannot write bmp\n" as *u8); sys_exit(1); return 1 } 116 sys_write(fd, buf, filesize); sys_close(fd) 117 // HTML wrapper so it opens as a "window" (2x pixelated) 118 let html: *u8 = "<!doctype html><html><body style=\x27margin:0;background:#0a0a12;display:flex;align-items:center;justify-content:center;height:100vh\x27><div><img src=\x27nishios_gui.bmp\x27 style=\x27image-rendering:pixelated;width:640px;border:1px solid #333\x27><div style=\x27color:#8af;font-family:monospace;text-align:center;margin-top:8px\x27>NishiOS desktop -- drawn by the kernel into a 320x200 framebuffer, exported BMP</div></div></body></html>\x00" 119 let hd: i64 = sys_openat_wr("knowledge/status/nishios_gui.html\x00" as *u8, 0x1a4) 120 if hd>0 { var hn: i64=0; while html[hn]!=(0 as u8){hn=hn+1} sys_write(hd, html, hn); sys_close(hd) } 121 122 gui_puts(" rendered desktop -> knowledge/status/nishios_gui.bmp (" as *u8); gui_num(filesize); gui_puts(" bytes) + nishios_gui.html\n" as *u8) 123 124 // --- KAT --- 125 var pass: i64=0 126 var ttl: i64=0 127 let p_bg: i64 = (40*W+2)*3 128 ttl=ttl+1; gui_puts(" T1 desktop background drawn (0,40,60): " as *u8); if (fb[p_bg] as i64)==0 { if (fb[p_bg+1] as i64)==40 { if (fb[p_bg+2] as i64)==60 { pass=pass+1; gui_puts("PASS\n" as *u8) } else { gui_puts("FAIL\n" as *u8) } } else { gui_puts("FAIL\n" as *u8) } } else { gui_puts("FAIL\n" as *u8) } 129 let p_tb: i64 = (10*W+200)*3 130 ttl=ttl+1; gui_puts(" T2 title bar drawn (30,30,120): " as *u8); if (fb[p_tb] as i64)==30 { if (fb[p_tb+2] as i64)==120 { pass=pass+1; gui_puts("PASS\n" as *u8) } else { gui_puts("FAIL\n" as *u8) } } else { gui_puts("FAIL\n" as *u8) } 131 let p_win: i64 = (150*W+150)*3 132 ttl=ttl+1; gui_puts(" T3 window drawn (210,210,220): " as *u8); if (fb[p_win] as i64)==210 { if (fb[p_win+2] as i64)==220 { pass=pass+1; gui_puts("PASS\n" as *u8) } else { gui_puts("FAIL\n" as *u8) } } else { gui_puts("FAIL\n" as *u8) } 133 // title text: 'N' row0 col0 is set -> pixel (6,3) is white 134 let p_tx: i64 = (3*W+6)*3 135 ttl=ttl+1; gui_puts(" T4 title text 'NISHIOS' rendered (white glyph pixel @6,3): " as *u8); if (fb[p_tx] as i64)==255 { if (fb[p_tx+1] as i64)==255 { pass=pass+1; gui_puts("PASS\n" as *u8) } else { gui_puts("FAIL\n" as *u8) } } else { gui_puts("FAIL\n" as *u8) } 136 ttl=ttl+1; gui_puts(" T5 BMP well-formed ('BM', size, 24bpp): " as *u8); if buf[0]==(66 as u8) { if buf[1]==(77 as u8) { if (buf[28] as i64)==24 { pass=pass+1; gui_puts("PASS\n" as *u8) } else { gui_puts("FAIL\n" as *u8) } } else { gui_puts("FAIL\n" as *u8) } } else { gui_puts("FAIL\n" as *u8) } 137 138 gui_puts("NISHIOS-GUI-GATE passed " as *u8); gui_num(pass); gui_puts("/" as *u8); gui_num(ttl) 139 if pass==ttl { gui_puts(" verdict=GREEN (the kernel drew a real desktop to a framebuffer; open nishios_gui.bmp/html to SEE it)\n" as *u8); sys_exit(0); return 0 } 140 gui_puts(" verdict=RED\n" as *u8); sys_exit(1); return 1 141}