feat(layout): add tabbed window groups and scrolling columns

This commit is contained in:
Samuel Onoja committed 2026-10-12 23:26:00 +01:00
1 parent 7d58eeb65d
commit bfa78f62f2
27 files changed
+1480 -47

No files matched your search

+36 -15
View File
@@ -44,7 +44,7 @@ pub(crate) fn init_font_loader(
event_loop.handle().insert_source(source, |event, _, state| {
if let channel::Event::Msg((family, font)) = event
&& state.overview.complete_font_load(&family, font)
&& state.overview.is_presenting()
&& (state.overview.is_presenting() || state.tab_bars.values().any(|bars| !bars.is_empty()))
{
crate::backends::direct::render_all(state);
}
@@ -60,20 +60,7 @@ pub(crate) fn init_font_loader(
// Rescan on a font change so newly installed fonts remain usable.
let mut database = fontdb::Database::new();
database.load_system_fonts();
let families = [fontdb::Family::Name(&family), fontdb::Family::SansSerif];
let font = database
.query(&fontdb::Query {
families: &families,
..Default::default()
})
.and_then(|id| {
database.with_face_data(id, |bytes, index| {
FontVec::try_from_vec_and_index(bytes.to_vec(), index)
.ok()
.map(FontArc::new)
})
})
.flatten();
let font = label_font(&database, &family);
if results.send((family, font)).is_err() {
break;
}
@@ -85,6 +72,32 @@ pub(crate) fn init_font_loader(
Ok(())
}
// fontdb's generic sans may name a font that is absent on this system.
// Resolve the requested family first, then use an installed text face.
fn label_font(database: &fontdb::Database, family: &str) -> Option<FontArc> {
let families = [
fontdb::Family::Name(family),
fontdb::Family::SansSerif,
fontdb::Family::Name("Noto Sans"),
fontdb::Family::Name("DejaVu Sans"),
fontdb::Family::Name("Liberation Sans"),
];
let preferred = database.query(&fontdb::Query {
families: &families,
..Default::default()
});
preferred
.into_iter()
.chain(database.faces().map(|face| face.id))
.find_map(|id| {
database.with_face_data(id, |bytes, index| {
let font = FontVec::try_from_vec_and_index(bytes.to_vec(), index).ok()?;
// Skip symbol-only fonts when searching the fallback faces.
(font.glyph_id('A').0 != 0 && font.glyph_id('0').0 != 0).then(|| FontArc::new(font))
})?
})
}
type LabelBuffer = (MemoryRenderBuffer, smithay::utils::Size<i32, smithay::utils::Buffer>);
type LabelStyle = (u64, [u32; 4]);
type OverviewStateLabel = HashMap<String, HashMap<LabelStyle, LabelBuffer>>;
@@ -1177,6 +1190,14 @@ mod tests {
font.expect("overview rendering tests require a system font")
}
#[test]
fn missing_label_font_falls_back_to_an_installed_text_font() {
let mut database = fontdb::Database::new();
database.load_system_fonts();
assert!(label_font(&database, "ferese-missing-font-fixture").is_some());
assert!(label_font(&fontdb::Database::new(), "sans-serif").is_none());
}
#[test]
fn font_reload_keeps_labels_until_current_result_arrives() {
let mut overview = OverviewState::with_font_family("first".into());