feat(display): windows: full-screen, F1 cycles, OS bar (names, front, user); canvas-only (display-owned buffers, 4 max, reused); launchers OPEN (pm per app, terminal own), window caps minted by display; FORGET on launcher death via init courier; raster crate (font, chunked text); F-keys in input; terminal+snake on canvas; REDRAW gone

This commit is contained in:
2026-10-28 02:48:39 +01:00
parent d04dcfffa1
commit 864f039bc7
45 changed files with 1382 additions and 824 deletions

View File

@@ -2,7 +2,8 @@
//! server, so a blocking call to it could wait on itself. Text goes into a
//! ring; a thread of init's own takes it to the log and waits there when
//! the log is down, instead of init. Until that thread runs (early boot),
//! init prints to the console directly.
//! init prints to the console directly. The same thread carries the few
//! messages init sends other servers it restarts (`post`).
use core::fmt;
use core::sync::atomic::{AtomicU8, AtomicUsize, Ordering};
@@ -20,6 +21,31 @@ static LOST: AtomicUsize = AtomicUsize::new(0);
/// The printer's notification, once it runs.
static WAKE: AtomicUsize = AtomicUsize::new(usize::MAX);
/// Messages waiting: an endpoint slot and four words each.
const POSTS: usize = 16;
static POSTED: [[AtomicUsize; 5]; POSTS] = [const { [const { AtomicUsize::new(0) }; 5] }; POSTS];
static POST_HEAD: AtomicUsize = AtomicUsize::new(0);
static POST_TAIL: AtomicUsize = AtomicUsize::new(0);
/// Has `words` called to `ep` by the printer thread, so init never waits
/// on it; dropped (and said so) if too many are waiting.
pub(crate) fn post(ep: CapSlot, words: [usize; 4]) {
let tail = POST_TAIL.load(Ordering::Relaxed);
if tail - POST_HEAD.load(Ordering::Acquire) == POSTS || wake().is_none() {
crate::outln!("init: a message to a server was dropped");
return;
}
let slot = &POSTED[tail % POSTS];
slot[0].store(ep.value() as usize, Ordering::Relaxed);
for (w, v) in slot[1..].iter().zip(words) {
w.store(v, Ordering::Relaxed);
}
POST_TAIL.store(tail + 1, Ordering::Release);
if let Some(wake) = wake() {
let _ = syscall::signal(wake);
}
}
fn wake() -> Option<CapSlot> {
u8::try_from(WAKE.load(Ordering::Acquire)).ok().and_then(CapSlot::new)
}
@@ -87,6 +113,17 @@ fn printer(_: &'static AtomicUsize) -> ! {
if lost > 0 {
libkos::println!("init: {} bytes of output lost while the log was down", lost);
}
while POST_HEAD.load(Ordering::Relaxed) != POST_TAIL.load(Ordering::Acquire) {
let head = POST_HEAD.load(Ordering::Relaxed);
let slot = &POSTED[head % POSTS];
let words = core::array::from_fn(|i| slot[i + 1].load(Ordering::Relaxed));
let ep = u8::try_from(slot[0].load(Ordering::Relaxed)).ok().and_then(CapSlot::new);
POST_HEAD.store(head + 1, Ordering::Release);
if let Some(ep) = ep {
// Waits while that server is down; init goes on.
let _ = syscall::request(ep, words);
}
}
}
}