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

@@ -11,8 +11,9 @@ pub mod server;
#[path = "tests/mod.rs"]
mod tests;
use libkos::display::{self, CELL_HEIGHT, CELL_WIDTH};
use libkos::display::{self, Canvas};
use libkos::input::{InputEvent, Key};
use port_framebuffer::Framebuffer;
use libkos::syscall;
use types::badge::Badge;
use types::bounded::CapSlot;
@@ -23,6 +24,9 @@ use types::terminal::{KEYS_BIT, TIMER_BIT};
const EP: CapSlot = CapSlot::const_new(0);
const DISPLAY: CapSlot = CapSlot::const_new(1);
const CELL_WIDTH: usize = raster::font::WIDTH as usize;
const CELL_HEIGHT: usize = raster::font::HEIGHT as usize;
const FG: Color = Color::rgb(220, 220, 220);
const BG: Color = Color::rgb(16, 16, 24);
/// Output is shown at most this long after it is written. The timebase is
@@ -30,12 +34,9 @@ const BG: Color = Color::rgb(16, 16, 24);
const FLUSH_DELAY: u64 = 20 * 10_000;
struct Screen {
/// Bound to the serving thread: the display signals it with
/// `KEYS_BIT`, the flush timer with `TIMER_BIT`.
notify: CapSlot,
/// The terminal's window, all of which scrolls.
canvas: Canvas,
timer: CapSlot,
/// The screen's height, all of which scrolls.
height: Dimension,
}
/// A key as the line editor wants it, if it is one.
@@ -56,21 +57,22 @@ fn at(col: usize, row: usize) -> (ScreenCoord, ScreenCoord) {
impl server::Console for Screen {
fn draw_row(&mut self, row: usize, text: &[u8]) {
let (x, y) = at(0, row);
display::draw_text(DISPLAY, x, y, FG, BG, text);
raster::draw_text(&mut self.canvas, x, y, FG, BG, text);
}
fn draw_cursor(&mut self, col: usize, row: usize, under: u8) {
let (x, y) = at(col, row);
display::draw_text(DISPLAY, x, y, BG, FG, &[under]);
raster::draw_text(&mut self.canvas, x, y, BG, FG, &[under]);
}
fn flush(&mut self) {
display::flush(DISPLAY);
self.canvas.flush();
}
fn scroll(&mut self, rows: usize) {
let by = Dimension::new(u16::try_from(rows * CELL_HEIGHT).unwrap_or(u16::MAX));
display::scroll(DISPLAY, ScreenCoord::new(0), self.height, by, BG);
let height = self.canvas.height();
self.canvas.scroll_up(ScreenCoord::new(0), height, by, BG);
}
fn flush_later(&mut self) {
@@ -79,7 +81,7 @@ impl server::Console for Screen {
}
fn poll_key(&mut self) -> Option<u8> {
while let Some(event) = display::poll_input(DISPLAY) {
while let Some(event) = display::poll_input(self.canvas.window()) {
if let Some(key) = byte(event) {
return Some(key);
}
@@ -95,11 +97,6 @@ impl server::Console for Screen {
let _ = syscall::reply_saved(reply, words, None);
}
fn take_focus(&mut self) {
display::subscribe(DISPLAY, self.notify, Badge::new(KEYS_BIT));
display::clear(DISPLAY, BG);
}
fn interrupt(&mut self, notification: CapSlot) {
let _ = syscall::signal(notification);
}
@@ -119,14 +116,17 @@ pub fn run() -> ! {
libkos::println!("terminal: no timer, exiting");
syscall::exit();
};
if !display::subscribe(DISPLAY, notify, Badge::new(KEYS_BIT)) {
libkos::println!("terminal: no input focus, exiting");
let Some(mut canvas) = display::open(DISPLAY, b"Terminal").and_then(|w| Canvas::attach(w.window)) else {
libkos::println!("terminal: no window, exiting");
syscall::exit();
};
if !display::subscribe(canvas.window(), notify, Badge::new(KEYS_BIT)) {
libkos::println!("terminal: no input, exiting");
syscall::exit();
}
let (w, h) = display::get_dimensions(DISPLAY);
display::clear(DISPLAY, BG);
let cols = w.raw() as usize / CELL_WIDTH;
let rows = h.raw() as usize / CELL_HEIGHT;
let mut srv = server::TerminalServer::new(Screen { notify, timer, height: h }, cols, rows);
canvas.clear(BG);
let cols = canvas.width().raw() as usize / CELL_WIDTH;
let rows = canvas.height().raw() as usize / CELL_HEIGHT;
let mut srv = server::TerminalServer::new(Screen { canvas, timer }, cols, rows);
server_framework::serve(&mut srv, EP)
}