feat(theme): themes as files (theme crate: toml subset + ints, contrast check, wire); whimsy dark + light; display reads themes/, serves THEME/THEME_NAME, init SET_THEME -> THEME_CHANGED to all windows, bar themed; k-ui follows; settings appearance; init keeps choice in sealed users/<id>/settings/, reapplies at sign-in + display restart
This commit is contained in:
@@ -9,6 +9,12 @@ 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(0x0180_0000);
|
||||
/// The longest theme file read.
|
||||
const THEME_BYTES: usize = 4096;
|
||||
|
||||
libkos::entry!(main);
|
||||
|
||||
@@ -38,7 +44,47 @@ fn subscribe_to_input() -> Option<CapSlot> {
|
||||
}
|
||||
|
||||
fn server<F: port_framebuffer::Framebuffer>(fb: F, input: Option<CapSlot>) -> display_server::server::DisplayServer<F, display_server::host::KernelHost> {
|
||||
display_server::server::DisplayServer::new(fb, display_server::host::KernelHost::new(EP, input))
|
||||
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)]
|
||||
|
||||
Reference in New Issue
Block a user