diff options
| author | salmonik <salmonik@tuta.io> | 2026-08-20 13:47:10 +0200 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-08-20 13:47:10 +0200 |
| commit | cb17c57452ccd2ccca77e99098402d4b9f61c0a5 (patch) | |
| tree | 6566e0ddaa764c6675e9a56f03772de345170992 /rsdos/src/main.rs | |
| parent | wm: integrate home terminal as window 0 + fix console focus after close (diff) | |
| download | rs-dos-cb17c57452ccd2ccca77e99098402d4b9f61c0a5.tar.gz rs-dos-cb17c57452ccd2ccca77e99098402d4b9f61c0a5.zip | |
wm: F1 spawns a windowed shell — real shell, not a duplicate
Architecture:
- vt: ACTIVE terminal redirect — when set, all gop_print!/put_char/write_str
go there instead of HOME. Terminal::from_buffer() renders into a
WM-owned pixel buffer.
- tty: read_line_from_queue() — canonical-mode line input from the task's
own message queue (TaskMsg::Key). Returns None on Close.
- shell: run_windowed() — same shell as the console but reads from the
message queue. Returns on ^D or window close.
- wm: F1 calls SPAWN_TERMINAL_CB (set by rsdos). No shell logic in the WM.
- rsdos: terminal_task callback + terminal_entry task — creates a 640x400
chrome window, wires up Terminal::from_buffer, sets ACTIVE, runs
shell::run_windowed(), cleans up on exit.
- shell: 'term' debug command that invokes the callback directly and
logs each step to serial.
Diffstat (limited to '')
| -rw-r--r-- | rsdos/src/main.rs | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/rsdos/src/main.rs b/rsdos/src/main.rs index 6d2fa4a..e5fb6dd 100644 --- a/rsdos/src/main.rs +++ b/rsdos/src/main.rs | |||
| @@ -420,10 +420,79 @@ pub unsafe extern "efiapi" fn efi_main(image_handle: Handle, system_table: *mut | |||
| 420 | t.set_window(id); | 420 | t.set_window(id); |
| 421 | } | 421 | } |
| 422 | rsnix::wm::spawn_input_pump(); | 422 | rsnix::wm::spawn_input_pump(); |
| 423 | // Register the terminal-spawn callback so F1 in the WM creates a | ||
| 424 | // windowed shell. The task lives here in rsdos (which depends on | ||
| 425 | // both rsnix and shell). | ||
| 426 | unsafe { | ||
| 427 | rsnix::wm::SPAWN_TERMINAL_CB = Some(terminal_task); | ||
| 428 | } | ||
| 423 | 429 | ||
| 424 | shell::run(); | 430 | shell::run(); |
| 425 | } | 431 | } |
| 426 | 432 | ||
| 433 | /// Callback registered with the WM for F1. Stores the spawn arguments | ||
| 434 | /// and spawns the terminal task (can't block the input pump). | ||
| 435 | static mut TERM_TITLE_BUF: [u8; 64] = [0u8; 64]; | ||
| 436 | static mut TERM_TITLE_LEN: usize = 0; | ||
| 437 | static mut TERM_W: usize = 0; | ||
| 438 | static mut TERM_H: usize = 0; | ||
| 439 | |||
| 440 | fn terminal_task(title: &str, w: usize, h: usize) { | ||
| 441 | rsnix::serial_println!("term: callback invoked title='{}' {}x{}", title, w, h); | ||
| 442 | // Copy title into static buffer so the spawned task can see it. | ||
| 443 | let bytes = title.as_bytes(); | ||
| 444 | let n = bytes.len().min(63); | ||
| 445 | unsafe { | ||
| 446 | TERM_TITLE_BUF[..n].copy_from_slice(&bytes[..n]); | ||
| 447 | TERM_TITLE_BUF[n] = 0; | ||
| 448 | TERM_TITLE_LEN = n; | ||
| 449 | TERM_W = w; | ||
| 450 | TERM_H = h; | ||
| 451 | } | ||
| 452 | match rsnix::sched::spawn(terminal_entry, "term") { | ||
| 453 | Some(id) => rsnix::serial_println!("term: spawned task {}", id), | ||
| 454 | None => rsnix::serial_println!("term: spawn FAILED"), | ||
| 455 | } | ||
| 456 | } | ||
| 457 | |||
| 458 | /// The actual terminal task — reads args from statics, creates a window, | ||
| 459 | /// and runs the shell. | ||
| 460 | fn terminal_entry() { | ||
| 461 | use rsnix::vt::Terminal; | ||
| 462 | let (w, h) = unsafe { (TERM_W, TERM_H) }; | ||
| 463 | let title = unsafe { core::str::from_utf8_unchecked(&TERM_TITLE_BUF[..TERM_TITLE_LEN]) }; | ||
| 464 | rsnix::serial_println!("term: entry title='{}' {}x{}", title, w, h); | ||
| 465 | let Some(win_id) = rsnix::wm::create_window(title, w, h) else { | ||
| 466 | rsnix::serial_println!("term: create_window FAILED"); | ||
| 467 | return; | ||
| 468 | }; | ||
| 469 | rsnix::serial_println!("term: win_id={}", win_id); | ||
| 470 | let Some((buf, ww, hh)) = rsnix::wm::buffer(win_id) else { | ||
| 471 | rsnix::serial_println!("term: buffer FAILED"); | ||
| 472 | rsnix::wm::destroy(win_id); | ||
| 473 | return; | ||
| 474 | }; | ||
| 475 | rsnix::serial_println!("term: buffer {:?} {}x{}", buf as *mut u32, ww, hh); | ||
| 476 | |||
| 477 | // Build a Terminal that renders into the WM-allocated buffer. | ||
| 478 | let mut term = Terminal::from_buffer(buf as *mut u32, ww, hh); | ||
| 479 | term.set_window(win_id); | ||
| 480 | rsnix::serial_println!("term: terminal created, entering shell"); | ||
| 481 | |||
| 482 | // Redirect all vt output (gop_print!, put_char, …) to this terminal. | ||
| 483 | rsnix::vt::set_active(&mut term as *mut Terminal); | ||
| 484 | |||
| 485 | // Run the shell — it owns input, line editing, and command execution. | ||
| 486 | shell::run_windowed(); | ||
| 487 | |||
| 488 | // Shell exited (^D or window close). Clean up. | ||
| 489 | rsnix::serial_println!("term: shell exited, cleaning up"); | ||
| 490 | rsnix::vt::set_active(core::ptr::null_mut()); | ||
| 491 | drop(term); | ||
| 492 | rsnix::wm::destroy(win_id); | ||
| 493 | rsnix::serial_println!("term: done"); | ||
| 494 | } | ||
| 495 | |||
| 427 | // --------------------------------------------------------------------------- | 496 | // --------------------------------------------------------------------------- |
| 428 | // Print a memory summary from the stashed memory map | 497 | // Print a memory summary from the stashed memory map |
| 429 | // --------------------------------------------------------------------------- | 498 | // --------------------------------------------------------------------------- |
