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:
99
crates/servers/display-server/src/host.rs
Normal file
99
crates/servers/display-server/src/host.rs
Normal file
@@ -0,0 +1,99 @@
|
||||
//! `Host` on the kernel: window buffers are regions of the display's own,
|
||||
//! made once per slot and reused (a region lives as long as its owner), so
|
||||
//! the display's memory has a fixed ceiling whatever apps do.
|
||||
|
||||
use libkos::syscall;
|
||||
use libkos::window::Window;
|
||||
use types::address::{ByteOffset, VirtualAddress};
|
||||
use types::badge::Badge;
|
||||
use types::bounded::{CapSlot, PageCount};
|
||||
use types::display::Color;
|
||||
use types::display::window::PIXEL_BYTES;
|
||||
use types::mapping::PagePerms;
|
||||
use types::permission::{Permission, PermissionSet};
|
||||
|
||||
use crate::server::Host;
|
||||
use crate::windows::MAX_WINDOWS;
|
||||
|
||||
/// Where slot `i`'s buffer is mapped in the display: 4 MiB apart, room for
|
||||
/// a 1280x800 window.
|
||||
const BUFFERS_VA: usize = 0x0080_0000;
|
||||
const BUFFER_SPAN: usize = 0x0040_0000;
|
||||
const PAGE: usize = 4096;
|
||||
|
||||
pub struct KernelHost {
|
||||
/// The display's own endpoint, which window capabilities are minted
|
||||
/// from.
|
||||
ep: CapSlot,
|
||||
input: Option<CapSlot>,
|
||||
buffers: [Option<(CapSlot, Window)>; MAX_WINDOWS],
|
||||
}
|
||||
|
||||
impl KernelHost {
|
||||
pub fn new(ep: CapSlot, input: Option<CapSlot>) -> Self {
|
||||
Self { ep, input, buffers: [None; MAX_WINDOWS] }
|
||||
}
|
||||
}
|
||||
|
||||
impl Host for KernelHost {
|
||||
fn buffer(&mut self, index: usize, pixels: usize) -> Option<CapSlot> {
|
||||
let slot = self.buffers.get_mut(index)?;
|
||||
if slot.is_none() {
|
||||
let bytes = (pixels * PIXEL_BYTES).min(BUFFER_SPAN);
|
||||
let pages = PageCount::new(u16::try_from(bytes.div_ceil(PAGE)).ok()?)?;
|
||||
let region = syscall::create_region(pages).ok()?;
|
||||
let va = VirtualAddress::from_raw(BUFFERS_VA + index * BUFFER_SPAN);
|
||||
match libkos::window::map(region, va, PagePerms::ReadWrite) {
|
||||
Ok(window) => *slot = Some((region, window)),
|
||||
Err(_) => {
|
||||
syscall::drop_cap(region);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
slot.as_ref().map(|(region, _)| *region)
|
||||
}
|
||||
|
||||
fn blank(&mut self, index: usize) {
|
||||
if let Some((_, window)) = self.buffers.get(index).and_then(Option::as_ref) {
|
||||
window.fill_u32(ByteOffset::ZERO, window.len() / PIXEL_BYTES, 0);
|
||||
}
|
||||
}
|
||||
|
||||
fn read(&self, index: usize, from: usize, out: &mut [Color]) {
|
||||
let Some((_, window)) = self.buffers.get(index).and_then(Option::as_ref) else { return };
|
||||
for (i, px) in out.iter_mut().enumerate() {
|
||||
let at = (from + i) * PIXEL_BYTES;
|
||||
if at + PIXEL_BYTES > window.len() {
|
||||
return;
|
||||
}
|
||||
*px = Color::from_raw(window.read::<u32>(ByteOffset::new(at)));
|
||||
}
|
||||
}
|
||||
|
||||
fn reclaim(&mut self, index: usize) {
|
||||
if let Some((region, _)) = self.buffers.get(index).and_then(Option::as_ref) {
|
||||
// Every copy handed out goes, and with it every mapping of one.
|
||||
let _ = syscall::revoke(*region);
|
||||
}
|
||||
}
|
||||
|
||||
fn mint(&mut self, badge: usize) -> Option<CapSlot> {
|
||||
let perms = PermissionSet::empty().with(Permission::Execute).with(Permission::Delegate);
|
||||
syscall::mint(self.ep, Badge::new(badge), perms).ok()
|
||||
}
|
||||
|
||||
fn revoke(&mut self, cap: CapSlot) {
|
||||
let _ = syscall::revoke(cap);
|
||||
syscall::drop_cap(cap);
|
||||
}
|
||||
|
||||
fn signal(&mut self, notify: CapSlot) {
|
||||
let _ = syscall::signal(notify);
|
||||
}
|
||||
|
||||
fn input(&mut self) -> Option<[usize; 4]> {
|
||||
let event = syscall::request(self.input?, [types::input::POLL_EVENT, 0, 0, 0]).ok()?;
|
||||
(event[0] != 0).then_some(event)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user