nx_nishios_events.nx source
↩ module page · 112 lines · 7254 B
1// nx_nishios_events.nx -- NishiOS GUI rung-3: an INPUT EVENT LOOP (interactivity).
2// A desktop you can't touch isn't an OS GUI. This adds the real loop: data-driven windows (a window
3// table), a click handler that RAISES the window under the cursor (focus -> z-order changes from the
4// event), and cursor tracking. It renders frame 0 (win "files" on top), processes a CLICK on the lower
5// "terminal" window, then renders frame 1 -- where that window is now raised to the front. The z-order
6// change between the two frames IS the proof the event loop works.
7// The event SOURCE is scripted here (the emu has no live PS/2 mouse; that driver is the wiring rung),
8// but the event-handling LOGIC -- hit-testing, focus-raise, cursor move, re-render -- is real.
9// KAT: frame0 overlap shows the top window; after the click, frame1 overlap shows the RAISED window;
10// the cursor moved to the click point; both frames exported as real BMPs.
11// HONEST SCOPE: scripted events + 2 windows. Live PS/2 input, drag, a full ASCII font, and wiring into
12// the boot kernel's framebuffer are the next rungs. No hw writes (Rule 26).
13// expect_exit: 0 license_tier: ORIGINAL
14import "nx_fb.nx"
15const K_MAGIC_192054: i64 = 192054
16
17func ev_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
18func ev_num(v: i64) -> i64 { let b: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 }
19
20// window table: stride 11 = [x,y,w,h, tr,tg,tb, br,bg,bb, z]
21// draw all windows back-to-front by z (selection order), so higher z occludes lower
22func draw_all(fb: *u8, W: i64, H: i64, font: *u8, idx: *u8, win: *i64, n: i64) -> i64 {
23 let used: *i64 = sys_mmap(n*8)
24 var i: i64=0
25 while i<n { used[i]=0; i=i+1 }
26 var slot: i64=0
27 while slot<n {
28 var best: i64=0-1
29 var bestz: i64=0
30 var j: i64=0
31 while j<n {
32 if used[j]==0 { if best<0 { best=j; bestz=win[j*11+10] } else { if win[j*11+10]<bestz { best=j; bestz=win[j*11+10] } } }
33 j=j+1
34 }
35 used[best]=1
36 let o: i64=best*11
37 fb_window(fb,W,H,font,idx, win[o],win[o+1],win[o+2],win[o+3], win[o+4],win[o+5],win[o+6], win[o+7],win[o+8],win[o+9])
38 slot=slot+1
39 }
40 return 0
41}
42
43// CLICK handler: find the topmost (max-z) window containing (px,py) and RAISE it above all others.
44func raise_win(win: *i64, n: i64, px: i64, py: i64) -> i64 {
45 var maxz: i64=0
46 var i: i64=0
47 while i<n { if win[i*11+10]>maxz { maxz=win[i*11+10] } i=i+1 }
48 var hit: i64=0-1
49 var hitz: i64=0-1
50 i=0
51 while i<n {
52 let o: i64=i*11
53 if px>=win[o] { if px<win[o]+win[o+2] { if py>=win[o+1] { if py<win[o+1]+win[o+3] { if win[o+10]>hitz { hit=i; hitz=win[o+10] } } } } }
54 i=i+1
55 }
56 if hit>=0 { win[hit*11+10]=maxz+1 }
57 return hit
58}
59
60func render_frame(fb: *u8, W: i64, H: i64, font: *u8, idx: *u8, win: *i64, n: i64, cx: i64, cy: i64, path: *u8) -> i64 {
61 var y: i64=0
62 while y<H { let r: i64=12-(10*y)/H; let g: i64=12+(48*y)/H; let b: i64=48+(32*y)/H; fb_rect(fb,W,H, 0,y, W,1, r,g,b); y=y+1 }
63 draw_all(fb,W,H,font,idx,win,n)
64 fb_rect(fb,W,H, 0,186, W,14, 25,25,40)
65 fb_cursor(fb,W,H,cx,cy)
66 return fb_bmp_save(fb,W,H,path)
67}
68
69func main() -> i64 {
70 ev_puts("NishiOS GUI rung-3: an INPUT EVENT LOOP (click-to-raise focus + cursor tracking)\n" as *u8)
71 let W: i64 = 320
72 let H: i64 = 200
73 let fb: *u8 = sys_mmap(W*H*3)
74 let font: *u8 = sys_mmap(64)
75 let idx: *u8 = sys_mmap(8)
76 fb_nishi_font(font, idx)
77
78 let win: *i64 = sys_mmap(2*11*8) as *i64
79 win[0]=40; win[1]=45; win[2]=130; win[3]=95; win[4]=40; win[5]=120; win[6]=60; win[7]=35; win[8]=35; win[9]=45; win[10]=1 // "terminal" -- BELOW (z=1)
80 win[11]=120; win[12]=80; win[13]=150; win[14]=95; win[15]=50; win[16]=80; win[17]=180; win[18]=200; win[19]=200; win[20]=215; win[21]=2 // "files" -- TOP (z=2)
81
82 // frame 0: initial desktop, cursor at (185,100)
83 let s0: i64 = render_frame(fb,W,H,font,idx,win,2, 185,100, "knowledge/status/nishios_ev0.bmp\x00")
84 let ov0: i64 = fb[(110*W+140)*3] as i64 // overlap pixel BEFORE the click
85
86 // INPUT EVENT: user clicks the lower "terminal" window at (60,110) and the cursor moves there
87 let clicked: i64 = raise_win(win, 2, 60, 110)
88
89 // frame 1: after the click -- the clicked window is raised, cursor follows
90 let s1: i64 = render_frame(fb,W,H,font,idx,win,2, 60,110, "knowledge/status/nishios_ev1.bmp\x00")
91 let ov1: i64 = fb[(110*W+140)*3] as i64 // overlap pixel AFTER the click
92 let cur1: i64 = fb[(110*W+60)*3] as i64 // cursor at the new position
93
94 let html: *u8 = "<!doctype html><html><body style=\x27margin:0;background:#0a0a12;color:#8af;font-family:monospace;text-align:center\x27><h3>NishiOS event loop: click-to-raise focus</h3><div style=\x27display:flex;gap:20px;justify-content:center\x27><div>before click (files on top)<br><img src=\x27nishios_ev0.bmp\x27 style=\x27image-rendering:pixelated;width:480px;border:1px solid #333\x27></div><div>after clicking terminal (raised)<br><img src=\x27nishios_ev1.bmp\x27 style=\x27image-rendering:pixelated;width:480px;border:1px solid #333\x27></div></div></body></html>\x00"
95 let hd: i64 = sys_openat_wr("knowledge/status/nishios_events.html\x00" as *u8, 0x1a4)
96 if hd>0 { var hn: i64=0; while html[hn]!=(0 as u8){hn=hn+1} sys_write(hd, html, hn); sys_close(hd) }
97
98 ev_puts(" clicked window index=" as *u8); ev_num(clicked); ev_puts(" overlap before=" as *u8); ev_num(ov0); ev_puts(" (200=files) -> after=" as *u8); ev_num(ov1); ev_puts(" (35=terminal raised)\n" as *u8)
99 ev_puts(" frames -> nishios_ev0.bmp + nishios_ev1.bmp + nishios_events.html\n" as *u8)
100
101 var pass: i64=0
102 var ttl: i64=0
103 ttl=ttl+1; ev_puts(" T1 frame0: 'files' window on top at overlap (==200): " as *u8); if ov0==200 { pass=pass+1; ev_puts("PASS\n" as *u8) } else { ev_puts("FAIL\n" as *u8) }
104 ttl=ttl+1; ev_puts(" T2 click RAISED 'terminal' -> frame1 overlap now ==35: " as *u8); if ov1==35 { pass=pass+1; ev_puts("PASS\n" as *u8) } else { ev_puts("FAIL\n" as *u8) }
105 ttl=ttl+1; ev_puts(" T3 cursor tracked to click point (white @60,110): " as *u8); if cur1==255 { pass=pass+1; ev_puts("PASS\n" as *u8) } else { ev_puts("FAIL\n" as *u8) }
106 ttl=ttl+1; ev_puts(" T4 the click hit the lower window (index 0): " as *u8); if clicked==0 { pass=pass+1; ev_puts("PASS\n" as *u8) } else { ev_puts("FAIL\n" as *u8) }
107 ttl=ttl+1; ev_puts(" T5 both frames exported as BMPs: " as *u8); if s0==K_MAGIC_192054 { if s1==K_MAGIC_192054 { pass=pass+1; ev_puts("PASS\n" as *u8) } else { ev_puts("FAIL\n" as *u8) } } else { ev_puts("FAIL\n" as *u8) }
108
109 ev_puts("NISHIOS-EVENTS-GATE passed " as *u8); ev_num(pass); ev_puts("/" as *u8); ev_num(ttl)
110 if pass==ttl { ev_puts(" verdict=GREEN (a real interactive event loop: click-to-raise + cursor tracking; open nishios_events.html to SEE before/after)\n" as *u8); sys_exit(0); return 0 }
111 ev_puts(" verdict=RED\n" as *u8); sys_exit(1); return 1
112}