diff --git a/compositor/src/handlers/window_capture.rs b/compositor/src/handlers/window_capture.rs index ff04b05..2597293 100644 --- a/compositor/src/handlers/window_capture.rs +++ b/compositor/src/handlers/window_capture.rs @@ -242,12 +242,11 @@ impl Ferese { scale, cursor.map(|rect| (&*self, rect)), ) - } else if let Some(mut backend) = self.direct_backend.take() { + } else { + let mut backend = self.direct_backend.take()?; let result = backend.capture_window_frame(self, &window, &output, cursor); self.direct_backend = Some(backend); result - } else { - return None; }; let pixels = result.ok()?; if let Some(toplevel) = window.toplevel() { diff --git a/compositor/src/input_capture.rs b/compositor/src/input_capture.rs index f8a91cb..ccd9e4a 100644 --- a/compositor/src/input_capture.rs +++ b/compositor/src/input_capture.rs @@ -126,7 +126,7 @@ fn crossed(barrier: &Barrier, edge: Edge, from: (f64, f64), to: (f64, f64)) -> O } else { from.0 + (to.0 - from.0) * fraction }; - (fraction >= 0.0 && fraction <= 1.0 && along >= start && along < end).then_some(fraction) + ((0.0..=1.0).contains(&fraction) && along >= start && along < end).then_some(fraction) } struct Session { diff --git a/compositor/src/winit.rs b/compositor/src/winit.rs index 1646a69..f8fdab0 100644 --- a/compositor/src/winit.rs +++ b/compositor/src/winit.rs @@ -193,7 +193,7 @@ pub(crate) fn capture_window_frame( return Err("Incomplete window readback".into()); } let mut pixels = source[..bytes].to_vec(); - for pixel in pixels.chunks_exact_mut(4) { + for pixel in pixels.as_chunks_mut::<4>().0 { pixel.swap(0, 2); let alpha = pixel[3] as u16; for channel in &mut pixel[..3] { diff --git a/crates/ferese-config/src/theme.rs b/crates/ferese-config/src/theme.rs index 4375122..bb70b46 100644 --- a/crates/ferese-config/src/theme.rs +++ b/crates/ferese-config/src/theme.rs @@ -534,14 +534,12 @@ pub fn resolve_with_context( .get("geometry") .and_then(|value| value.get("shell_radius")) .is_none() - { - if let Some(radius) = document + && let Some(radius) = document .get("appearance.corner_radius") .and_then(Value::as_f64) .or_else(|| document.get("theme.geometry.top_bar_radius").and_then(Value::as_f64)) - { - tokens.geometry.shell_radius = radius; - } + { + tokens.geometry.shell_radius = radius; } let mut value = serde_json::to_value(&tokens).map_err(|e| e.to_string())?; for file in [&policy.file, &selection.file].into_iter().flatten() { @@ -646,10 +644,10 @@ pub fn theme_path(directory: &Path, path: &Path) -> PathBuf { } else { directory.join(path) }; - if let (Some(parent), Some(name)) = (path.parent(), path.file_name()) { - if let Ok(parent) = parent.canonicalize() { - return parent.join(name); - } + if let (Some(parent), Some(name)) = (path.parent(), path.file_name()) + && let Ok(parent) = parent.canonicalize() + { + return parent.join(name); } path } diff --git a/crates/ferese-theme/src/controls.rs b/crates/ferese-theme/src/controls.rs index 24ec8f0..e0dff11 100644 --- a/crates/ferese-theme/src/controls.rs +++ b/crates/ferese-theme/src/controls.rs @@ -130,6 +130,34 @@ fn styled_button(p: Palette, selected: bool, navigation: bool) -> theme::Button } } +/// Authentication actions use normal text while enabled and muted text while disabled. +/// Keep the disabled fill neutral so contrast correction cannot make it look active. +pub fn authentication_button(palette: Palette) -> theme::Button { + let paint = move |enabled: bool, interaction: f32, focused: bool| { + let (fill, foreground) = if enabled { + let candidate = mix(palette.accent, palette.text, interaction); + crate::accent_pair(crate::composite(candidate, palette.card), palette.text) + } else { + (crate::composite(palette.card, palette.background), palette.muted) + }; + button::Style { + background: Some(Background::Color(fill)), + text_color: Some(foreground), + icon_color: Some(foreground), + border_radius: palette.radius.into(), + outline_width: if focused { 1. } else { 0. }, + outline_color: foreground, + ..Default::default() + } + }; + theme::Button::Custom { + active: Box::new(move |focused, _| paint(true, 0., focused)), + hovered: Box::new(move |focused, _| paint(true, 0.06, focused)), + pressed: Box::new(move |focused, _| paint(true, 0.12, focused)), + disabled: Box::new(move |_| paint(false, 0., false)), + } +} + pub fn authentication_input(palette: Palette) -> theme::TextInput { let text = palette.text; let muted = palette.muted; @@ -268,6 +296,40 @@ pub fn filled_button(fill: Color, foreground: Color, radius: f32, opacity: f32) mod tests { use super::*; + #[test] + fn authentication_button_does_not_reverse_enabled_and_disabled_text() { + use cosmic::widget::button::Catalog; + + let palette = Palette { + appearance: ferese_config::theme::Appearance::Dark, + background: Color::from_rgb8(17, 24, 33), + sidebar: Color::from_rgb8(17, 24, 33), + card: Color::from_rgb8(17, 24, 33), + accent: Color::from_rgb8(61, 123, 230), + on_accent: Color::from_rgb8(17, 24, 33), + text: Color::from_rgb8(244, 247, 251), + muted: Color::from_rgb8(135, 147, 162), + error: Color::from_rgb8(235, 98, 98), + radius: 10., + }; + let theme = palette.native_theme(); + let class = authentication_button(palette); + for style in [ + theme.active(false, false, &class), + theme.hovered(false, false, &class), + theme.pressed(false, false, &class), + ] { + assert_eq!(style.text_color, Some(palette.text)); + let Some(Background::Color(fill)) = style.background else { + panic!("No fill") + }; + assert!(crate::contrast(fill, palette.text) >= 4.5); + } + let disabled = theme.disabled(&class); + assert_eq!(disabled.text_color, Some(palette.muted)); + assert_eq!(disabled.background, Some(Background::Color(palette.card))); + } + #[test] fn switch_thumb_remains_readable_in_every_preset_and_state() { for preset in crate::PRESETS { diff --git a/crates/ferese-theme/src/gallery.rs b/crates/ferese-theme/src/gallery.rs index 7bb7e60..e9246d3 100644 --- a/crates/ferese-theme/src/gallery.rs +++ b/crates/ferese-theme/src/gallery.rs @@ -309,16 +309,15 @@ impl Widget for Radio<'_, M> { if !iced_accessibility::IdEq::eq(&id.0, &self.id.0) { return; } - if matches!(request.action, accesskit::Action::Focus | accesskit::Action::Click) { - if let Some(message) = self + if matches!(request.action, accesskit::Action::Focus | accesskit::Action::Click) + && let Some(message) = self .navigate .as_ref() .and_then(|navigate| navigate(&keyboard::key::Named::Enter)) - { - shell.publish(message); - shell.capture_event(); - return; - } + { + shell.publish(message); + shell.capture_event(); + return; } } if matches!(event, Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))) { @@ -344,12 +343,11 @@ impl Widget for Radio<'_, M> { key: keyboard::Key::Named(key), .. }) = event + && let Some(message) = self.navigate.as_ref().and_then(|navigate| navigate(key)) { - if let Some(message) = self.navigate.as_ref().and_then(|navigate| navigate(key)) { - shell.publish(message); - shell.capture_event(); - return; - } + shell.publish(message); + shell.capture_event(); + return; } } self.content.as_widget_mut().update( diff --git a/crates/ferese-theme/src/service.rs b/crates/ferese-theme/src/service.rs index 407ce78..09c30c4 100644 --- a/crates/ferese-theme/src/service.rs +++ b/crates/ferese-theme/src/service.rs @@ -44,10 +44,10 @@ fn stream() -> impl cosmic::iced::futures::Stream { }); while receive.changed().await.is_ok() { let snapshot = receive.borrow_and_update().clone(); - if let Some(snapshot) = snapshot { - if output.send(snapshot).await.is_err() { - return; - } + if let Some(snapshot) = snapshot + && output.send(snapshot).await.is_err() + { + return; } } drop(cancellation); diff --git a/feresectl/src/autostart.rs b/feresectl/src/autostart.rs index 8ada136..eaf1cd1 100644 --- a/feresectl/src/autostart.rs +++ b/feresectl/src/autostart.rs @@ -53,10 +53,10 @@ pub(crate) fn run() -> Result<(), Box> { if !enabled(&entry, &desktop) { continue; } - if let Some(program) = entry.get("TryExec").filter(|program| !program.is_empty()) { - if !available(program) { - continue; - } + if let Some(program) = entry.get("TryExec").filter(|program| !program.is_empty()) + && !available(program) + { + continue; } let parent = std::process::id() as libc::pid_t; let mut command = Command::new("timeout"); diff --git a/portal/src/desktop.rs b/portal/src/desktop.rs index f729382..8bc54bb 100644 --- a/portal/src/desktop.rs +++ b/portal/src/desktop.rs @@ -702,7 +702,7 @@ fn update_wallpaper(image: &Path, target: &str) -> Result<(), String> { } fn edit_wallpaper(path: &Path, image: &Path, target: &str) -> Result<(), String> { - let source = match std::fs::read_to_string(&path) { + let source = match std::fs::read_to_string(path) { Ok(source) => source, Err(error) if error.kind() == std::io::ErrorKind::NotFound => String::new(), Err(error) => return Err(error.to_string()), @@ -736,7 +736,7 @@ fn edit_wallpaper(path: &Path, image: &Path, target: &str) -> Result<(), String> let mut temp = tempfile::NamedTempFile::new_in(parent).map_err(|error| error.to_string())?; std::io::Write::write_all(&mut temp, document.to_string().as_bytes()).map_err(|error| error.to_string())?; temp.as_file().sync_all().map_err(|error| error.to_string())?; - if std::fs::read_to_string(&path).unwrap_or_default() != source { + if std::fs::read_to_string(path).unwrap_or_default() != source { return Err("Configuration changed; please try again".into()); } temp.persist(path).map_err(|error| error.to_string())?; diff --git a/portal/src/inhibit.rs b/portal/src/inhibit.rs index 8174ee1..953db2d 100644 --- a/portal/src/inhibit.rs +++ b/portal/src/inhibit.rs @@ -148,17 +148,16 @@ impl Inhibit { ("screensaver-active".into(), Value::from(locked).try_into().unwrap()), ("session-state".into(), Value::from(phase).try_into().unwrap()), ]); - if let Ok(emitter) = SignalEmitter::new(&connection, PATH) { - if Self::state_changed( + if let Ok(emitter) = SignalEmitter::new(&connection, PATH) + && Self::state_changed( &emitter, OwnedObjectPath::try_from(path.clone()).unwrap(), values, ) .await .is_err() - { - break; - } + { + break; } } *last = Some((locked, phase, revision, token)); @@ -344,7 +343,7 @@ impl Inhibit { { Ok(2) } else { - let attempt = async { + async { let bridge = Bridge::connect().map_err(zbus::fdo::Error::Failed)?; let result = tokio::select! { biased; @@ -403,8 +402,7 @@ impl Inhibit { } } } - .await; - attempt + .await }; drop(monitors); self.requests.end(connection, &handle).await; diff --git a/portal/src/input_capture.rs b/portal/src/input_capture.rs index c4bb4c1..901fe69 100644 --- a/portal/src/input_capture.rs +++ b/portal/src/input_capture.rs @@ -165,13 +165,11 @@ impl InputCapture { if let Some(position) = event["cursor_position"] .as_array() .filter(|position| position.len() == 2) - { - if let Ok(position) = + && let Ok(position) = Value::from((position[0].as_f64().unwrap_or(0.0), position[1].as_f64().unwrap_or(0.0))) .try_to_owned() - { - options.insert("cursor_position".into(), position); - } + { + options.insert("cursor_position".into(), position); } Self::activated(&emitter, path.clone(), options).await } diff --git a/portal/src/settings.rs b/portal/src/settings.rs index d450213..edc62d3 100644 --- a/portal/src/settings.rs +++ b/portal/src/settings.rs @@ -128,10 +128,10 @@ impl Settings { } async fn read(&self, namespace: &str, key: &str) -> zbus::fdo::Result { - if namespace == APPEARANCE { - if let Some(value) = self.0.read().await.values().remove(key) { - return Ok(value); - } + if namespace == APPEARANCE + && let Some(value) = self.0.read().await.values().remove(key) + { + return Ok(value); } Err(zbus::fdo::Error::InvalidArgs("Unknown setting".into())) } diff --git a/shell/ferese-lock/src/appearance.rs b/shell/ferese-lock/src/appearance.rs index e009253..c1638b0 100644 --- a/shell/ferese-lock/src/appearance.rs +++ b/shell/ferese-lock/src/appearance.rs @@ -55,7 +55,7 @@ impl Appearance { .unwrap_or(fallback) .to_owned() }; - let palette = ferese_theme::Palette::from_resolved(&theme); + let palette = ferese_theme::Palette::from_resolved(theme); let font = string("theme.typography.font_family", "Inter"); let background = string("theme.background.path", ferese_config::default_wallpaper()); let path = string("theme.background.lock_path", &background); diff --git a/shell/ferese-polkit-agent/src/prompt.rs b/shell/ferese-polkit-agent/src/prompt.rs index 1778f85..61afc2d 100644 --- a/shell/ferese-polkit-agent/src/prompt.rs +++ b/shell/ferese-polkit-agent/src/prompt.rs @@ -321,7 +321,7 @@ impl cosmic::Application for Prompt { }); } let action = button::custom(ferese_theme::text("Authenticate", palette.font).size(13)) - .class(ferese_theme::accent_button()) + .class(ferese_theme::controls::authentication_button(palette.palette())) .height(Length::Fixed(36.)) .padding([8, 16]) .on_press_maybe((!self.waiting && !self.answer.is_empty()).then_some(Message::Submit)); diff --git a/shell/ferese-settings/src/main.rs b/shell/ferese-settings/src/main.rs index 451dc60..d3929c5 100644 --- a/shell/ferese-settings/src/main.rs +++ b/shell/ferese-settings/src/main.rs @@ -793,10 +793,8 @@ impl cosmic::Application for App { if !fields.is_empty() { let mut group = column([]).spacing(1); - if self.page == Page::Appearance { - if self.auto_details { - group = group.push(self.auto_controls()); - } + if self.page == Page::Appearance && self.auto_details { + group = group.push(self.auto_controls()); } for field in fields { if self.page == Page::Appearance diff --git a/shell/ferese-shell/src/main.rs b/shell/ferese-shell/src/main.rs index f9fb1a0..5c95537 100644 --- a/shell/ferese-shell/src/main.rs +++ b/shell/ferese-shell/src/main.rs @@ -425,27 +425,25 @@ impl cosmic::Application for FereseShell { } self.theme_error = snapshot.error; } - return self.apply_config(config); - } - Message::ThemeMode(mode) => { - return cosmic::task::future(async move { - let result = tokio::task::spawn_blocking(move || { - let mut connection = ferese_ipc::theme::Connection::connect().map_err(|e| e.to_string())?; - connection - .call("theme-set-mode", serde_json::json!({"mode": mode})) - .map(|_| ()) - }) - .await - .unwrap_or_else(|e| Err(e.to_string())); - cosmic::Action::App(Message::ThemeModeSet(result)) - }); + self.apply_config(config) } + Message::ThemeMode(mode) => cosmic::task::future(async move { + let result = tokio::task::spawn_blocking(move || { + let mut connection = ferese_ipc::theme::Connection::connect().map_err(|e| e.to_string())?; + connection + .call("theme-set-mode", serde_json::json!({"mode": mode})) + .map(|_| ()) + }) + .await + .unwrap_or_else(|e| Err(e.to_string())); + cosmic::Action::App(Message::ThemeModeSet(result)) + }), Message::ThemeModeSet(result) => { if let Err(error) = result { self.notifications .service_error("Appearance could not be changed", &error); } - return Task::none(); + Task::none() } Message::BeginNoteEdit(id) => { let mut tasks = vec![self.finish_note_edit()]; diff --git a/shell/ferese-shell/src/system_modal.rs b/shell/ferese-shell/src/system_modal.rs index 74df97c..ba467cd 100644 --- a/shell/ferese-shell/src/system_modal.rs +++ b/shell/ferese-shell/src/system_modal.rs @@ -547,7 +547,6 @@ impl FereseShell { surface.regions.clone(), self.config.theme.material_radius, ) - .into() } else { content };