From a7fcd69897ae93e6c36eade82a6579280d013376 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Thu, 22 Oct 2026 00:58:08 +0100 Subject: [PATCH] Clarify constructor failures and borrowed API contracts --- compositor/src/activities.rs | 10 ++--- compositor/src/backends/direct.rs | 44 +++++++++---------- compositor/src/backends/direct/topology.rs | 17 ++++--- compositor/src/config.rs | 2 +- compositor/src/render/corner_tests.rs | 2 +- compositor/src/render/materials.rs | 6 +-- crates/ferese-activities/src/pomodoro.rs | 2 + crates/ferese-activities/src/store.rs | 7 +++ crates/ferese-animation/src/gesture.rs | 3 ++ crates/ferese-animation/src/settings.rs | 2 + .../ferese-animation/src/window_geometry.rs | 14 ++++++ crates/ferese-config/src/activities.rs | 7 +-- crates/ferese-config/src/document.rs | 5 +++ crates/ferese-config/src/families.rs | 3 ++ crates/ferese-config/src/file.rs | 1 + crates/ferese-config/src/theme.rs | 4 ++ crates/ferese-core/src/focus.rs | 2 + crates/ferese-core/src/output.rs | 8 ++++ crates/ferese-core/src/workspace.rs | 16 +++++++ crates/ferese-core/src/workspace_policy.rs | 4 ++ crates/ferese-ipc/src/activities.rs | 1 + crates/ferese-ipc/src/events.rs | 1 + crates/ferese-ipc/src/frame.rs | 1 + crates/ferese-ipc/src/media.rs | 4 ++ crates/ferese-ipc/src/xwayland.rs | 2 + crates/ferese-layout/src/layout_tree.rs | 9 ++++ crates/ferese-layout/src/scrolling.rs | 23 ++++++++-- crates/ferese-panel/src/adaptive.rs | 4 ++ crates/ferese-panel/src/lib.rs | 1 + crates/ferese-panel/src/morph.rs | 27 +++++++----- crates/ferese-panel/src/motion.rs | 13 +++--- crates/ferese-panel/src/outline.rs | 6 +-- crates/ferese-panel/src/panel/composition.rs | 23 ++++++++++ crates/ferese-panel/src/panel/geometry.rs | 1 + crates/ferese-panel/src/panel/layout.rs | 4 ++ crates/ferese-panel/src/panel/radius.rs | 5 +++ crates/ferese-panel/src/scene.rs | 25 +++++++---- crates/ferese-panel/src/shape.rs | 43 +++++++++++------- crates/ferese-theme-client/src/service.rs | 1 + crates/ferese-theme-model/src/color.rs | 8 ++++ crates/ferese-theme-model/src/families.rs | 2 + .../ferese-theme-model/src/resolved_theme.rs | 3 ++ crates/ferese-theme/src/button.rs | 1 + crates/ferese-theme/src/calendar.rs | 4 ++ crates/ferese-theme/src/contrast.rs | 6 +++ crates/ferese-theme/src/controls.rs | 13 ++++++ crates/ferese-theme/src/gallery.rs | 2 + crates/ferese-theme/src/geometry.rs | 1 + crates/ferese-theme/src/icons.rs | 1 + crates/ferese-theme/src/menus.rs | 5 +++ crates/ferese-theme/src/palette.rs | 7 +++ crates/ferese-theme/src/panel_surface.rs | 2 +- crates/ferese-theme/src/workspaces.rs | 4 ++ feresectl/src/activities.rs | 18 ++++---- shell/ferese-shell/src/panel_hub.rs | 4 +- 55 files changed, 332 insertions(+), 102 deletions(-) diff --git a/compositor/src/activities.rs b/compositor/src/activities.rs index 90fa60a..e80a8f7 100644 --- a/compositor/src/activities.rs +++ b/compositor/src/activities.rs @@ -51,7 +51,7 @@ impl Default for Engine { ), rules: Arc::new(RwLock::new(Arc::new(Rules { enabled: false, - matcher: ferese_config::activities::Matcher::new(&settings) + matcher: ferese_config::activities::Matcher::try_new(&settings) .expect("built-in rules"), }))), monitor: None, @@ -691,7 +691,7 @@ mod tests { .spawn() .unwrap(); let (owner, fd, _) = crate::ipc::activity_owner::inspect(child.id()).unwrap(); - let matched = ferese_config::activities::Matcher::new(&Default::default()) + let matched = ferese_config::activities::Matcher::try_new(&Default::default()) .unwrap() .matches("cargo test", "/tmp", &[]) .unwrap(); @@ -707,7 +707,7 @@ mod tests { let mut engine = Engine::default(); let (owner, fd, _) = crate::ipc::activity_owner::inspect(std::process::id()).unwrap(); let settings = ferese_config::activities::Settings::default(); - let matched = ferese_config::activities::Matcher::new(&settings) + let matched = ferese_config::activities::Matcher::try_new(&settings) .unwrap() .matches("cargo test", "/tmp/test", &[]) .unwrap(); @@ -859,7 +859,7 @@ mod tests { #[test] fn rule_is_pinned_across_atomic_reload_and_no_raw_metadata_is_published() { let settings = ferese_config::activities::Settings::default(); - let matched = ferese_config::activities::Matcher::new(&settings) + let matched = ferese_config::activities::Matcher::try_new(&settings) .unwrap() .matches("cargo test --secret", "/secret/cwd", &[]) .unwrap(); @@ -883,7 +883,7 @@ mod tests { replacement.rules[0].title = "Replacement".into(); engine.configure( &replacement, - ferese_config::activities::Matcher::new(&replacement).unwrap(), + ferese_config::activities::Matcher::try_new(&replacement).unwrap(), ); let after = engine.store.entries().next().unwrap(); assert_eq!(after.data.title, "cargo test"); diff --git a/compositor/src/backends/direct.rs b/compositor/src/backends/direct.rs index 96b4eda..6de252b 100644 --- a/compositor/src/backends/direct.rs +++ b/compositor/src/backends/direct.rs @@ -442,12 +442,11 @@ pub fn init(event_loop: &mut EventLoop, state: &mut Ferese) -> Result<() if let Some(token) = backend.power_retry.take() { handle.remove(token); } - backend - .presentation - .values_mut() - .for_each(PresentationClock::reset_timing); - backend.devices.values_mut().for_each(|device| { - device.outputs.values_mut().for_each(|output| { + for clock in backend.presentation.values_mut() { + clock.reset_timing(); + } + for device in backend.devices.values_mut() { + for output in device.outputs.values_mut() { output.gamma.suspend(); cancel_output_timers(&handle, output); output.surface.reset_buffers(); @@ -456,9 +455,9 @@ pub fn init(event_loop: &mut EventLoop, state: &mut Ferese) -> Result<() output.capture_texture = None; output.frame_pending = false; output.power.suspended(); - }); + } device.drm.pause(); - }); + } } state.display_presentation.clear(); @@ -2178,30 +2177,27 @@ fn send_frame_callbacks(state: &mut Ferese, output: &Output) { state.lock_frame_callbacks(output); return; } - state - .space - .elements() - .filter(|window| { - state - .windows - .ids() - .get(*window) - .is_some_and(|id| state.window_belongs_to_output(*id, output)) - }) - .for_each(|window| { - window.send_frame(output, state.start_time.elapsed(), None, |surface, _| { - eligible.get(&surface.into()).cloned() - }); + let visible_windows = state.space.elements().filter(|window| { + state + .windows + .ids() + .get(*window) + .is_some_and(|id| state.window_belongs_to_output(*id, output)) + }); + for window in visible_windows { + window.send_frame(output, state.start_time.elapsed(), None, |surface, _| { + eligible.get(&surface.into()).cloned() }); + } let layers = layer_map_for_output(output) .layers() .cloned() .collect::>(); - layers.iter().for_each(|layer| { + for layer in &layers { layer.send_frame(output, state.start_time.elapsed(), None, |surface, _| { eligible.get(&surface.into()).cloned() }); - }); + } state.send_cursor_frame(output); state.space.refresh(); state.popups.cleanup(); diff --git a/compositor/src/backends/direct/topology.rs b/compositor/src/backends/direct/topology.rs index e9508a0..f646675 100644 --- a/compositor/src/backends/direct/topology.rs +++ b/compositor/src/backends/direct/topology.rs @@ -2,11 +2,11 @@ use std::path::PathBuf; use super::{ - DrmNode, Duration, Ferese, HashMap, HashSet, Instant, OutputMode, Path, PresentationClock, - RegistrationToken, Scale, Session, TimeoutAction, Timer, all_gpus, cancel_output_timers, - drm_device_key, lid, monotonic_now, open_device, output_transform, refresh_connected_info, - refresh_monitor_policy, remember_applied_configuration, remove_device, rescan_device, - sync_battery_timer, transaction, validate_desired_outputs, + DrmNode, Duration, Ferese, HashMap, HashSet, Instant, OutputMode, Path, RegistrationToken, + Scale, Session, TimeoutAction, Timer, all_gpus, cancel_output_timers, drm_device_key, lid, + monotonic_now, open_device, output_transform, refresh_connected_info, refresh_monitor_policy, + remember_applied_configuration, remove_device, rescan_device, sync_battery_timer, transaction, + validate_desired_outputs, }; #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -203,10 +203,9 @@ pub(super) fn reconcile_outputs(state: &mut Ferese, reactivate: bool) { backend.topology.dirty = false; backend.output_error = None; if reactivate { - backend - .presentation - .values_mut() - .for_each(PresentationClock::reset_timing); + for clock in backend.presentation.values_mut() { + clock.reset_timing(); + } } if let Some(token) = backend.topology.retry_timer.take() { state.loop_handle.remove(token); diff --git a/compositor/src/config.rs b/compositor/src/config.rs index e16a6aa..cbcd8b1 100644 --- a/compositor/src/config.rs +++ b/compositor/src/config.rs @@ -149,7 +149,7 @@ impl Config { let binding_modes = self.binding_modes(&input_settings, &bindings)?; Ok(crate::RuntimeConfig { activity_settings: self.activities.clone(), - activity_matcher: ferese_config::activities::Matcher::new(&self.activities) + activity_matcher: ferese_config::activities::Matcher::try_new(&self.activities) .map_err(ConfigError::Binding)?, lock_idle: self.lock_screen.validate()?, night_light: self.night_light.validate().map_err(ConfigError::Binding)?, diff --git a/compositor/src/render/corner_tests.rs b/compositor/src/render/corner_tests.rs index 85b7f54..e832e33 100644 --- a/compositor/src/render/corner_tests.rs +++ b/compositor/src/render/corner_tests.rs @@ -344,7 +344,7 @@ fn panel_shader_matches_core_outlines_and_resets_for_popovers() { }, bounds, &groups, - PixelGrid::new(scale).unwrap(), + PixelGrid::try_new(scale).unwrap(), ) .unwrap(), ); diff --git a/compositor/src/render/materials.rs b/compositor/src/render/materials.rs index ae90bfc..b897ee4 100644 --- a/compositor/src/render/materials.rs +++ b/compositor/src/render/materials.rs @@ -896,7 +896,7 @@ mod region_geometry_tests { }, ferese_layout::Rect::new((320. - width) / 2., 0., width, 44.), &[], - PixelGrid::new(scale).unwrap(), + PixelGrid::try_new(scale).unwrap(), ) .unwrap(); let presentation = crate::effects::PanelPresentation { @@ -947,7 +947,7 @@ mod region_geometry_tests { use ferese_panel::shape::{AnchoredRadii, PixelGrid}; for scale in [1., 1.25, 1.5, 2.] { for edge in [ferese_panel::Edge::Top, ferese_panel::Edge::Bottom] { - let mut hub = Hub::new(Profile::default(), 34.).unwrap(); + let mut hub = Hub::try_new(Profile::default(), 34.).unwrap(); for mode in [Mode::Peek, Mode::Idle] { hub.retarget(mode, [400., 300.]).unwrap(); for frame in 0..160 { @@ -977,7 +977,7 @@ mod region_geometry_tests { }, bounds, &[], - PixelGrid::new(scale).unwrap(), + PixelGrid::try_new(scale).unwrap(), ) .unwrap(); // Reproduce the f32 transport and logical capture bounds used by native materials. diff --git a/crates/ferese-activities/src/pomodoro.rs b/crates/ferese-activities/src/pomodoro.rs index f04024b..3bfb60e 100644 --- a/crates/ferese-activities/src/pomodoro.rs +++ b/crates/ferese-activities/src/pomodoro.rs @@ -54,6 +54,7 @@ pub enum Phase { LongBreak, } impl Phase { + #[must_use] pub fn label(self) -> &'static str { match self { Self::Work => "Work", @@ -97,6 +98,7 @@ impl Session { deadline: Some(now.saturating_add(remaining_ms)), }) } + #[must_use] pub fn remaining(&self, now: Time) -> u64 { self.deadline .map_or(self.remaining_ms, |deadline| deadline.saturating_sub(now)) diff --git a/crates/ferese-activities/src/store.rs b/crates/ferese-activities/src/store.rs index 83b357b..0841daa 100644 --- a/crates/ferese-activities/src/store.rs +++ b/crates/ferese-activities/src/store.rs @@ -39,6 +39,7 @@ pub enum Value { } impl Value { + #[must_use] pub fn remaining_ms(&self, now: Time) -> Option { match self { Self::Countdown { @@ -245,6 +246,7 @@ pub struct Activity { } impl Activity { + #[must_use] pub fn eligible(&self, now: Time, dnd: bool) -> bool { now >= self.eligible_at && match self.state { @@ -256,6 +258,7 @@ impl Activity { } } + #[must_use] pub fn score(&self, now: Time, ceiling: u8) -> u16 { u16::from(self.data.priority.min(ceiling)) + if now < self.eligible_at.saturating_add(BOOST_MS) { @@ -280,6 +283,7 @@ pub struct Store { } impl Store { + #[must_use] pub fn new(session: u64) -> Self { Self { limits: Limits::default(), @@ -289,6 +293,7 @@ impl Store { } } + #[must_use] pub fn session(&self) -> u64 { self.session } @@ -297,6 +302,7 @@ impl Store { self.entries.values() } + #[must_use] pub fn resolve(&self, owner: Owner, local: &str) -> Option<&Id> { self.entries .keys() @@ -477,6 +483,7 @@ impl Store { before != self.entries.len() } + #[must_use] pub fn next_deadline(&self, now: Time) -> Option