#![no_std] #![forbid(unsafe_code)] #![no_main] extern crate libkos; use types::bounded::CapSlot; /// Where init put them (see init's manifest: own endpoint, then `uses`). const EP: CapSlot = CapSlot::const_new(0); const INPUT: CapSlot = CapSlot::const_new(1); /// `themes/`, read-only. const THEMES: CapSlot = CapSlot::const_new(2); /// Where storage's buffer is mapped while the themes are read. const STORAGE_BUF_VA: types::address::VirtualAddress = types::address::VirtualAddress::from_raw(0x1800_0000); /// The longest theme file read. const THEME_BYTES: usize = 4096; libkos::entry!(main); fn main() { // Init hands over the GPU, or nothing if the machine has none. let dev = libkos::device::receive_device(EP); let input = subscribe_to_input(); if let Some(fb) = dev.mmio.and_then(driver_framebuffer_virtio::VirtioFramebuffer::try_new) { run_virtio(fb, input); } libkos::println!("display: no GPU, running headless"); run_headless(input); } /// Has the input server signal this thread whenever events arrive; the /// server then passes them on to the app in focus. fn subscribe_to_input() -> Option { use types::badge::Badge; use types::permission::{Permission, PermissionSet}; let notify = libkos::syscall::create_notification().ok()?; libkos::syscall::bind_notification(notify).ok()?; let signal = PermissionSet::empty().with(Permission::Write).with(Permission::Delegate); let copy = libkos::syscall::mint(notify, Badge::NONE, signal).ok()?; let sent = libkos::syscall::call(INPUT, [types::input::SUBSCRIBE, 0, 0, 0], Some(copy.into())); libkos::syscall::drop_cap(copy); sent.ok().map(|_| INPUT) } fn server(fb: F, input: Option) -> display_server::server::DisplayServer { display_server::server::DisplayServer::new(fb, display_server::host::KernelHost::new(EP, input), themes()) } /// Every theme in `themes/` that reads and passes contrast; the built-in /// one if none does. fn themes() -> display_server::themes::Themes { let mut themes = display_server::themes::Themes::new(); let Ok(mut fs) = libkos::fs::Storage::attach(THEMES, STORAGE_BUF_VA) else { libkos::println!("display: no themes folder; the built-in theme only"); return themes; }; let mut names = [([0u8; types::storage::DIR_NAME_SIZE], 0usize); display_server::themes::MAX_THEMES]; let mut found = 0; let _ = fs.list_dir(b"", |e| { if !e.is_dir && e.name().ends_with(b".toml") && found < names.len() { names[found] = (e.name, e.name_len); found += 1; } }); let mut text = [0u8; THEME_BYTES]; for (name, len) in &names[..found] { let name = &name[..*len]; let read = fs.open(name).and_then(|h| { let n = fs.read(h, &mut text); let _ = fs.close(h); n }); let shown = core::str::from_utf8(name).unwrap_or("?"); match read.ok().and_then(|n| core::str::from_utf8(&text[..n]).ok()) { Some(t) => { if let Err(e) = themes.add(t) { libkos::println!("display: theme {} refused: {:?}", shown, e); } } None => libkos::println!("display: cannot read theme {}", shown), } } fs.detach(); // Storage has few connections to give; this one is done with. let _ = libkos::fs::release(THEMES); themes } #[inline(never)] fn run_virtio(fb: driver_framebuffer_virtio::VirtioFramebuffer, input: Option) -> ! { let mut srv = server(fb, input); server_framework::serve(&mut srv, EP) } /// No GPU: clients still get answers (and the dimensions they draw for); /// pixels go nowhere. struct Headless; impl port_framebuffer::Framebuffer for Headless { fn width(&self) -> types::display::Dimension { types::display::Dimension::new(640) } fn height(&self) -> types::display::Dimension { types::display::Dimension::new(480) } fn write_pixel(&mut self, _: types::display::ScreenCoord, _: types::display::ScreenCoord, _: types::display::Color) {} fn fill_rect( &mut self, _: types::display::ScreenCoord, _: types::display::ScreenCoord, _: types::display::Dimension, _: types::display::Dimension, _: types::display::Color, ) { } fn clear(&mut self, _: types::display::Color) {} fn flush(&mut self) {} fn scroll_up( &mut self, _: types::display::ScreenCoord, _: types::display::Dimension, _: types::display::Dimension, _: types::display::Color, ) { } } #[inline(never)] fn run_headless(input: Option) -> ! { let mut srv = server(Headless, input); server_framework::serve(&mut srv, EP) }