Move shell configuration out of desktop core

This commit is contained in:
Samuel Onoja committed 2026-10-02 23:54:27 +01:00
1 parent f5de30d037
commit c3acb5af5a
14 files changed
+73 -36

No files matched your search

Generated
-2
View File
@@ -1693,7 +1693,6 @@ name = "ferese-core"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ferese-layout", "ferese-layout",
"jiff",
"serde", "serde",
] ]
@@ -1781,7 +1780,6 @@ name = "ferese-shell"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ferese-config", "ferese-config",
"ferese-core",
"ferese-ipc", "ferese-ipc",
"ferese-protocols", "ferese-protocols",
"ferese-theme", "ferese-theme",
+2 -2
View File
@@ -30,11 +30,11 @@ use crate::window_rules::{WindowRule, WindowRuleConfig};
#[derive(Debug, Default, Deserialize)] #[derive(Debug, Default, Deserialize)]
pub struct Config { pub struct Config {
#[serde(default)] #[serde(default)]
notifications: ferese_core::notifications::NotificationConfig, notifications: ferese_config::notifications::NotificationConfig,
#[serde(default)] #[serde(default)]
lock_screen: crate::session_lock::IdleSettings, lock_screen: crate::session_lock::IdleSettings,
#[serde(default)] #[serde(default)]
desktop_widgets: ferese_core::desktop::DesktopWidgets, desktop_widgets: ferese_config::desktop::DesktopWidgets,
#[serde(default)] #[serde(default)]
pub(crate) autostart: Vec<DaemonConfig>, pub(crate) autostart: Vec<DaemonConfig>,
#[serde(default)] #[serde(default)]
File renamed without changes.
+2
View File
@@ -1,4 +1,6 @@
pub mod desktop;
pub mod families; pub mod families;
pub mod notifications;
pub mod presets; pub mod presets;
pub mod theme; pub mod theme;
-1
View File
@@ -8,4 +8,3 @@ rust-version.workspace = true
[dependencies] [dependencies]
ferese-layout = { path = "../ferese-layout" } ferese-layout = { path = "../ferese-layout" }
serde = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] }
jiff.workspace = true
-2
View File
@@ -1,6 +1,4 @@
pub mod desktop;
mod focus; mod focus;
pub mod notifications;
mod output; mod output;
mod workspace; mod workspace;
mod workspace_policy; mod workspace_policy;
@@ -0,0 +1,41 @@
"""Keep production dependencies within the boundaries in ADR 0004."""
import pathlib
import tomllib
import unittest
ROOT = pathlib.Path(__file__).resolve().parents[2]
def dependency_graph():
workspace = tomllib.loads((ROOT / "Cargo.toml").read_text())
graph = {}
for member in workspace["workspace"]["members"]:
manifest = tomllib.loads((ROOT / member / "Cargo.toml").read_text())
dependencies = set(manifest.get("dependencies", {}))
for target in manifest.get("target", {}).values():
dependencies.update(target.get("dependencies", {}))
graph[manifest["package"]["name"]] = dependencies
return graph
def reachable(graph, package):
seen = set()
pending = list(graph.get(package, ()))
while pending:
dependency = pending.pop()
if dependency not in seen:
seen.add(dependency)
pending.extend(graph.get(dependency, ()))
return seen
class ComponentBoundaries(unittest.TestCase):
def test_shell_does_not_depend_on_core(self):
self.assertNotIn("ferese-core", reachable(dependency_graph(), "ferese-shell"))
def test_transitive_dependencies_are_checked(self):
self.assertIn("core", reachable({"shell": {"helper"}, "helper": {"core"}}, "shell"))
if __name__ == "__main__":
unittest.main()
-1
View File
@@ -9,7 +9,6 @@ rust-version.workspace = true
ferese-ipc = { path = "../../crates/ferese-ipc" } ferese-ipc = { path = "../../crates/ferese-ipc" }
ferese-theme = { path = "../../crates/ferese-theme" } ferese-theme = { path = "../../crates/ferese-theme" }
ferese-config = { path = "../../crates/ferese-config" } ferese-config = { path = "../../crates/ferese-config" }
ferese-core = { path = "../../crates/ferese-core" }
ferese-protocols = { path = "../../crates/ferese-protocols", default-features = false, features = ["client"] } ferese-protocols = { path = "../../crates/ferese-protocols", default-features = false, features = ["client"] }
jiff.workspace = true jiff.workspace = true
libc.workspace = true libc.workspace = true
+5 -5
View File
@@ -7,8 +7,8 @@ const DEFAULT_BACKGROUND: [u8; 3] = [11, 15, 20];
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub(crate) struct ShellConfig { pub(crate) struct ShellConfig {
pub(crate) notifications: ferese_core::notifications::NotificationConfig, pub(crate) notifications: ferese_config::notifications::NotificationConfig,
pub(crate) desktop_widgets: ferese_core::desktop::DesktopWidgets, pub(crate) desktop_widgets: ferese_config::desktop::DesktopWidgets,
pub(crate) animations: crate::motion::Settings, pub(crate) animations: crate::motion::Settings,
pub(crate) font_family: Option<String>, pub(crate) font_family: Option<String>,
pub(crate) wallpaper: WallpaperConfig, pub(crate) wallpaper: WallpaperConfig,
@@ -157,9 +157,9 @@ pub(crate) enum WallpaperMode {
#[derive(Debug, Default, Deserialize)] #[derive(Debug, Default, Deserialize)]
struct FereseConfig { struct FereseConfig {
#[serde(default)] #[serde(default)]
notifications: ferese_core::notifications::NotificationConfig, notifications: ferese_config::notifications::NotificationConfig,
#[serde(default)] #[serde(default)]
desktop_widgets: ferese_core::desktop::DesktopWidgets, desktop_widgets: ferese_config::desktop::DesktopWidgets,
#[serde(default)] #[serde(default)]
animations: crate::motion::Settings, animations: crate::motion::Settings,
#[serde(default)] #[serde(default)]
@@ -595,7 +595,7 @@ mod tests {
.desktop_widgets .desktop_widgets
.clock; .clock;
assert!(clock.enabled); assert!(clock.enabled);
assert_eq!(clock.anchor, ferese_core::desktop::Anchor::BottomRight); assert_eq!(clock.anchor, ferese_config::desktop::Anchor::BottomRight);
assert!(parse_test_source("desktop-widgets {\n clock {\n opacity 1.1\n }\n}\n").is_err()); assert!(parse_test_source("desktop-widgets {\n clock {\n opacity 1.1\n }\n}\n").is_err());
assert!(parse_test_source("desktop-widgets {\n clock {\n time-format \"%\"\n }\n}\n").is_err()); assert!(parse_test_source("desktop-widgets {\n clock {\n time-format \"%\"\n }\n}\n").is_err());
} }
+13 -13
View File
@@ -172,7 +172,7 @@ impl FereseShell {
if save { if save {
if drag.id.is_none() { if drag.id.is_none() {
let clock = &mut self.config.desktop_widgets.clock; let clock = &mut self.config.desktop_widgets.clock;
clock.anchor = ferese_core::desktop::Anchor::TopLeft; clock.anchor = ferese_config::desktop::Anchor::TopLeft;
clock.margin_x = drag.position.x.round() as i32; clock.margin_x = drag.position.x.round() as i32;
clock.margin_y = drag.position.y.round() as i32; clock.margin_y = drag.position.y.round() as i32;
for entry in &self.outputs { for entry in &self.outputs {
@@ -192,7 +192,7 @@ impl FereseShell {
.iter_mut() .iter_mut()
.find(|note| Some(&note.id) == drag.id.as_ref()) .find(|note| Some(&note.id) == drag.id.as_ref())
{ {
note.anchor = ferese_core::desktop::Anchor::TopLeft; note.anchor = ferese_config::desktop::Anchor::TopLeft;
note.margin_x = drag.position.x.round() as i32; note.margin_x = drag.position.x.round() as i32;
note.margin_y = drag.position.y.round() as i32; note.margin_y = drag.position.y.round() as i32;
@@ -285,9 +285,9 @@ impl FereseShell {
return text("").into(); return text("").into();
}; };
let alignment = match note.alignment { let alignment = match note.alignment {
ferese_core::desktop::Alignment::Left => alignment::Horizontal::Left, ferese_config::desktop::Alignment::Left => alignment::Horizontal::Left,
ferese_core::desktop::Alignment::Center => alignment::Horizontal::Center, ferese_config::desktop::Alignment::Center => alignment::Horizontal::Center,
ferese_core::desktop::Alignment::Right => alignment::Horizontal::Right, ferese_config::desktop::Alignment::Right => alignment::Horizontal::Right,
}; };
let font = configured_font( let font = configured_font(
note.font_family note.font_family
@@ -477,14 +477,14 @@ impl FereseShell {
} }
pub(super) fn view_clock_content(&self) -> Element<'_, cosmic::Action<Message>> { pub(super) fn view_clock_content(&self) -> Element<'_, cosmic::Action<Message>> {
use ferese_core::desktop::Alignment as ClockAlignment; use ferese_config::desktop::Alignment as ClockAlignment;
let clock = &self.config.desktop_widgets.clock; let clock = &self.config.desktop_widgets.clock;
let alignment = match clock.alignment { let alignment = match clock.alignment {
ClockAlignment::Left => alignment::Horizontal::Left, ClockAlignment::Left => alignment::Horizontal::Left,
ClockAlignment::Center => alignment::Horizontal::Center, ClockAlignment::Center => alignment::Horizontal::Center,
ClockAlignment::Right => alignment::Horizontal::Right, ClockAlignment::Right => alignment::Horizontal::Right,
}; };
let pixel = clock.style == ferese_core::desktop::ClockStyle::Pixel; let pixel = clock.style == ferese_config::desktop::ClockStyle::Pixel;
let custom_font = clock.font_family.as_deref().filter(|family| !family.trim().is_empty()); let custom_font = clock.font_family.as_deref().filter(|family| !family.trim().is_empty());
let mut font = configured_font(if pixel { let mut font = configured_font(if pixel {
custom_font.or(Some("Cantarell")) custom_font.or(Some("Cantarell"))
@@ -668,7 +668,7 @@ pub(super) fn clamp_note_position(
) )
} }
pub(super) fn note_origin(note: &ferese_core::desktop::StickyNote, output: (i32, i32)) -> cosmic::iced::Point { pub(super) fn note_origin(note: &ferese_config::desktop::StickyNote, output: (i32, i32)) -> cosmic::iced::Point {
widget_origin( widget_origin(
note.anchor, note.anchor,
note.margin_x, note.margin_x,
@@ -679,13 +679,13 @@ pub(super) fn note_origin(note: &ferese_core::desktop::StickyNote, output: (i32,
} }
pub(super) fn widget_origin( pub(super) fn widget_origin(
anchor: ferese_core::desktop::Anchor, anchor: ferese_config::desktop::Anchor,
margin_x: i32, margin_x: i32,
margin_y: i32, margin_y: i32,
size: (u32, u32), size: (u32, u32),
output: (i32, i32), output: (i32, i32),
) -> cosmic::iced::Point { ) -> cosmic::iced::Point {
use ferese_core::desktop::Anchor as A; use ferese_config::desktop::Anchor as A;
let x = match anchor { let x = match anchor {
A::TopLeft | A::CenterLeft | A::BottomLeft => margin_x as f32, A::TopLeft | A::CenterLeft | A::BottomLeft => margin_x as f32,
A::TopRight | A::CenterRight | A::BottomRight => output.0 as f32 - size.0 as f32 - margin_x as f32, A::TopRight | A::CenterRight | A::BottomRight => output.0 as f32 - size.0 as f32 - margin_x as f32,
@@ -699,16 +699,16 @@ pub(super) fn widget_origin(
clamp_note_position(cosmic::iced::Point::new(x, y), output, size) clamp_note_position(cosmic::iced::Point::new(x, y), output, size)
} }
pub(super) fn clock_placement(clock: &ferese_core::desktop::Clock) -> (Anchor, IcedMargin) { pub(super) fn clock_placement(clock: &ferese_config::desktop::Clock) -> (Anchor, IcedMargin) {
widget_placement(clock.anchor, clock.margin_x, clock.margin_y) widget_placement(clock.anchor, clock.margin_x, clock.margin_y)
} }
pub(super) fn widget_placement( pub(super) fn widget_placement(
position: ferese_core::desktop::Anchor, position: ferese_config::desktop::Anchor,
margin_x: i32, margin_x: i32,
margin_y: i32, margin_y: i32,
) -> (Anchor, IcedMargin) { ) -> (Anchor, IcedMargin) {
use ferese_core::desktop::Anchor as Position; use ferese_config::desktop::Anchor as Position;
let horizontal = match position { let horizontal = match position {
Position::TopLeft | Position::CenterLeft | Position::BottomLeft => Anchor::LEFT, Position::TopLeft | Position::CenterLeft | Position::BottomLeft => Anchor::LEFT,
Position::TopRight | Position::CenterRight | Position::BottomRight => Anchor::RIGHT, Position::TopRight | Position::CenterRight | Position::BottomRight => Anchor::RIGHT,
+3 -3
View File
@@ -1047,9 +1047,9 @@ mod tests {
#[test] #[test]
fn note_drag_origin_and_bounds_use_logical_output_coordinates() { fn note_drag_origin_and_bounds_use_logical_output_coordinates() {
use cosmic::iced::Point; use cosmic::iced::Point;
let mut note = ferese_core::desktop::StickyNote::default(); let mut note = ferese_config::desktop::StickyNote::default();
assert_eq!(super::note_origin(&note, (1920, 1080)), Point::new(1552., 80.)); assert_eq!(super::note_origin(&note, (1920, 1080)), Point::new(1552., 80.));
note.anchor = ferese_core::desktop::Anchor::Center; note.anchor = ferese_config::desktop::Anchor::Center;
assert_eq!(super::note_origin(&note, (1920, 1080)), Point::new(800., 420.)); assert_eq!(super::note_origin(&note, (1920, 1080)), Point::new(800., 420.));
assert_eq!( assert_eq!(
super::clamp_note_position(Point::new(-20., 1200.), (1920, 1080), (320, 240)), super::clamp_note_position(Point::new(-20., 1200.), (1920, 1080), (320, 240)),
@@ -1063,7 +1063,7 @@ mod tests {
#[test] #[test]
fn desktop_clock_anchor_margins_match_only_anchored_edges() { fn desktop_clock_anchor_margins_match_only_anchored_edges() {
use ferese_core::desktop::{Anchor as Position, Clock}; use ferese_config::desktop::{Anchor as Position, Clock};
let clock = Clock { let clock = Clock {
anchor: Position::BottomRight, anchor: Position::BottomRight,
margin_x: 30, margin_x: 30,
+1 -1
View File
@@ -133,6 +133,6 @@ desktop-widgets {
let notes = crate::config::parse_source(&source).unwrap().desktop_widgets.notes; let notes = crate::config::parse_source(&source).unwrap().desktop_widgets.notes;
assert_eq!(notes[0].text, "one\ntwo"); assert_eq!(notes[0].text, "one\ntwo");
assert_eq!((notes[0].margin_x, notes[0].margin_y), (50, 60)); assert_eq!((notes[0].margin_x, notes[0].margin_y), (50, 60));
assert_eq!(notes[0].anchor, ferese_core::desktop::Anchor::TopLeft); assert_eq!(notes[0].anchor, ferese_config::desktop::Anchor::TopLeft);
} }
} }
+6 -6
View File
@@ -192,11 +192,11 @@ pub struct Service {
} }
impl Service { impl Service {
fn start(config: &ferese_core::notifications::NotificationConfig) -> Self { fn start(config: &ferese_config::notifications::NotificationConfig) -> Self {
Self::connect(config, None) Self::connect(config, None)
} }
fn connect(config: &ferese_core::notifications::NotificationConfig, address: Option<String>) -> Self { fn connect(config: &ferese_config::notifications::NotificationConfig, address: Option<String>) -> Self {
let timeout = Arc::new(std::sync::atomic::AtomicU32::new(config.timeout_ms)); let timeout = Arc::new(std::sync::atomic::AtomicU32::new(config.timeout_ms));
let worker_timeout = timeout.clone(); let worker_timeout = timeout.clone();
let (sender, events) = tokio::sync::mpsc::channel(256); let (sender, events) = tokio::sync::mpsc::channel(256);
@@ -269,7 +269,7 @@ struct Toast {
} }
pub struct Center { pub struct Center {
config: ferese_core::notifications::NotificationConfig, config: ferese_config::notifications::NotificationConfig,
service: Service, service: Service,
pub ready: bool, pub ready: bool,
pub dnd: bool, pub dnd: bool,
@@ -282,7 +282,7 @@ pub struct Center {
} }
impl Center { impl Center {
pub fn new(config: ferese_core::notifications::NotificationConfig) -> Self { pub fn new(config: ferese_config::notifications::NotificationConfig) -> Self {
Self { Self {
service: Service::start(&config), service: Service::start(&config),
ready: false, ready: false,
@@ -304,7 +304,7 @@ impl Center {
.try_send(Command::Local(title.into(), body.into())); .try_send(Command::Local(title.into(), body.into()));
} }
pub fn configure(&mut self, config: ferese_core::notifications::NotificationConfig) { pub fn configure(&mut self, config: ferese_config::notifications::NotificationConfig) {
if self.config.do_not_disturb != config.do_not_disturb { if self.config.do_not_disturb != config.do_not_disturb {
self.dnd = config.do_not_disturb; self.dnd = config.do_not_disturb;
} }
@@ -617,7 +617,7 @@ impl Center {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use ferese_core::notifications::NotificationConfig; use ferese_config::notifications::NotificationConfig;
use super::*; use super::*;