diff --git a/examples/cosmic/src/window.rs b/examples/cosmic/src/window.rs index 213af78..964d2f9 100644 --- a/examples/cosmic/src/window.rs +++ b/examples/cosmic/src/window.rs @@ -1,7 +1,10 @@ /// Copyright 2022 System76 // SPDX-License-Identifier: MPL-2.0 use cosmic::{ - cosmic_config::config_subscription, + cosmic_theme::{ + palette::{rgb::Rgb, Srgba}, + ThemeBuilder, + }, font::load_fonts, iced::{self, Application, Command, Length, Subscription}, iced::{ @@ -10,7 +13,7 @@ use cosmic::{ window::{self, close, drag, minimize, toggle_maximize}, }, keyboard_nav, - theme::{self, CosmicTheme, Theme}, + theme::{self, Theme}, widget::{ header_bar, icon, list, nav_bar, nav_bar_toggle, scrollable, segmented_button, settings, warning, IconSource, @@ -18,9 +21,7 @@ use cosmic::{ Element, ElementExt, }; use cosmic_time::{Instant, Timeline}; -use log::error; use std::{ - borrow::Cow, cell::RefCell, rc::Rc, sync::{ @@ -163,7 +164,6 @@ pub struct Window { warning_message: String, scale_factor: f64, scale_factor_string: String, - system_theme: Arc, timeline: Rc>, } @@ -209,7 +209,6 @@ pub enum Message { ToggleNavBarCondensed, ToggleWarning, FontsLoaded, - SystemTheme(CosmicTheme), Tick(Instant), } @@ -389,17 +388,6 @@ impl Application for Window { Subscription::batch(vec![ window_break.map(|_| Message::CondensedViewToggle), keyboard_nav::subscription().map(Message::KeyboardNav), - config_subscription::<_, CosmicTheme>(0, Cow::from("com.system76.CosmicTheme"), 1).map( - |(_, update)| match update { - Ok(t) => Message::SystemTheme(t), - Err((errors, t)) => { - for error in errors { - error!("{:?}", error); - } - Message::SystemTheme(t) - } - }, - ), self.timeline .borrow() .as_subscription() @@ -429,7 +417,18 @@ impl Application for Window { demo::ThemeVariant::Dark => Theme::dark(), demo::ThemeVariant::HighContrastDark => Theme::dark_hc(), demo::ThemeVariant::HighContrastLight => Theme::light_hc(), - demo::ThemeVariant::Custom => Theme::custom(self.system_theme.clone()), + demo::ThemeVariant::Custom => Theme::custom(Arc::new( + ThemeBuilder::light() + .bg_color(Srgba::new(1.0, 0.9, 0.9, 1.0)) + .text_tint(Rgb::new(0.0, 1.0, 0.0)) + .neutral_tint(Rgb::new(0.0, 0.5, 1.0)) + .accent(Rgb::new(0.5, 0.1, 0.5)) + .success(Rgb::new(0.0, 0.5, 0.3)) + .warning(Rgb::new(0.894, 0.816, 0.039)) + .destructive(Rgb::new(0.890, 0.145, 0.420)) + .build(), + )), + demo::ThemeVariant::System => cosmic::theme::theme(), }; } Some(demo::Output::ToggleWarning) => self.toggle_warning(), @@ -460,9 +459,6 @@ impl Application for Window { }, Message::ToggleWarning => self.toggle_warning(), Message::FontsLoaded => {} - Message::SystemTheme(t) => { - self.system_theme = Arc::new(t); - } Message::Tick(instant) => self.timeline.borrow_mut().now(instant), } ret diff --git a/examples/cosmic/src/window/demo.rs b/examples/cosmic/src/window/demo.rs index d5402a4..85e396d 100644 --- a/examples/cosmic/src/window/demo.rs +++ b/examples/cosmic/src/window/demo.rs @@ -27,6 +27,7 @@ pub enum ThemeVariant { HighContrastDark, HighContrastLight, Custom, + System, } impl From<&ThemeType> for ThemeVariant { @@ -37,6 +38,7 @@ impl From<&ThemeType> for ThemeVariant { ThemeType::HighContrastDark => ThemeVariant::HighContrastDark, ThemeType::HighContrastLight => ThemeVariant::HighContrastLight, ThemeType::Custom(_) => ThemeVariant::Custom, + ThemeType::System(_) => ThemeVariant::System, } } } @@ -210,8 +212,9 @@ impl State { ThemeVariant::Light, ThemeVariant::Dark, ThemeVariant::HighContrastLight, - ThemeVariant::HighContrastLight, + ThemeVariant::HighContrastDark, ThemeVariant::Custom, + ThemeVariant::System, ] .into_iter() .fold( diff --git a/examples/cosmic/src/window/desktop.rs b/examples/cosmic/src/window/desktop.rs index f20722f..3b3858d 100644 --- a/examples/cosmic/src/window/desktop.rs +++ b/examples/cosmic/src/window/desktop.rs @@ -193,7 +193,7 @@ impl State { } fn view_desktop_wallpaper<'a>(&'a self, window: &'a Window) -> Element<'a, Message> { - let mut image_paths: Vec = Vec::new(); + let image_paths: Vec = Vec::new(); /* //TODO: load image paths, do this asynchronously somehow if let Ok(entries) = std::fs::read_dir("/usr/share/backgrounds") { diff --git a/examples/cosmic/src/window/editor.rs b/examples/cosmic/src/window/editor.rs index e272050..6c027c0 100644 --- a/examples/cosmic/src/window/editor.rs +++ b/examples/cosmic/src/window/editor.rs @@ -1,5 +1,4 @@ -use apply::Apply; -use cosmic::iced::widget::{horizontal_space, row, scrollable}; +use cosmic::iced::widget::{horizontal_space, row}; use cosmic::iced::{Alignment, Length}; use cosmic::widget::{button, segmented_button, view_switcher}; use cosmic::{theme, Element}; @@ -60,7 +59,7 @@ impl State { self.pages.remove(id); } - pub(super) fn view<'a>(&'a self, window: &'a super::Window) -> Element<'a, Message> { + pub(super) fn view<'a>(&'a self, _window: &'a super::Window) -> Element<'a, Message> { let tabs = view_switcher::horizontal(&self.pages) .show_close_icon_on_hover(true) .on_activate(Message::Activate) diff --git a/src/app/core.rs b/src/app/core.rs index 73d0534..79f09a4 100644 --- a/src/app/core.rs +++ b/src/app/core.rs @@ -40,7 +40,7 @@ pub struct Core { /// Scaling factor used by the application scale_factor: f32, - pub theme: Theme, + pub system_theme: Theme, pub(crate) title: String, pub window: Window, } @@ -56,7 +56,7 @@ impl Default for Core { toggled_condensed: true, }, scale_factor: 1.0, - theme: theme::theme(), + system_theme: theme::theme(), title: String::new(), window: Window { can_fullscreen: false, diff --git a/src/app/cosmic.rs b/src/app/cosmic.rs index 6069d3c..9b6bab9 100644 --- a/src/app/cosmic.rs +++ b/src/app/cosmic.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: MPL-2.0 use super::{command, Application, ApplicationExt, Core, Subscription}; -use crate::theme::{self, Theme}; +use crate::theme::{self, Theme, ThemeType, THEME}; use crate::widget::nav_bar; use crate::{keyboard_nav, Element}; #[cfg(feature = "wayland")] @@ -36,6 +36,8 @@ pub enum Message { ScaleFactor(f32), /// Requests theme changes. ThemeChange(Theme), + /// Notification of system theme changes. + SystemThemeChange(Theme), /// Toggles visibility of the nav bar. ToggleNavBar, /// Toggles the condensed status of the nav bar. @@ -146,14 +148,14 @@ where .map(Message::KeyboardNav) .map(super::Message::Cosmic), theme::subscription(0) - .map(Message::ThemeChange) + .map(Message::SystemThemeChange) .map(super::Message::Cosmic), window_events.map(super::Message::Cosmic), ]) } fn theme(&self) -> Self::Theme { - self.app.core().theme.clone() + THEME.with(|t| t.borrow().clone()) } #[cfg(feature = "wayland")] @@ -267,12 +269,32 @@ impl Cosmic { } Message::ThemeChange(theme) => { - self.app.core_mut().theme = theme; + // our system theme is always receiving updates so we should use it instead + let theme = if matches!(theme.theme_type, ThemeType::System(_)) { + self.app.core().system_theme.clone() + } else { + theme + }; + + THEME.with(move |t| { + let mut cosmic_theme = t.borrow_mut(); + cosmic_theme.set_theme(theme.theme_type); + }); } Message::ScaleFactor(factor) => { self.app.core_mut().set_scale_factor(factor); } + Message::SystemThemeChange(theme) => { + self.app.core_mut().system_theme = theme.clone(); + THEME.with(move |t| { + let mut cosmic_theme = t.borrow_mut(); + // only apply update if the theme is set to load a system theme + if matches!(cosmic_theme.theme_type, ThemeType::System(_)) { + cosmic_theme.set_theme(theme.theme_type); + } + }); + } } iced::Command::none() diff --git a/src/app/mod.rs b/src/app/mod.rs index 6cc6e63..f37571f 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -33,6 +33,7 @@ pub mod message { pub use self::core::Core; pub use self::settings::Settings; +use crate::theme::THEME; use crate::widget::nav_bar; use crate::{Element, ElementExt}; use apply::Apply; @@ -58,7 +59,10 @@ pub fn run(settings: Settings, flags: App::Flags) -> iced::Res core.set_scale_factor(settings.scale_factor); core.set_window_width(settings.size.0); core.set_window_height(settings.size.1); - core.theme = settings.theme; + THEME.with(move |t| { + let mut cosmic_theme = t.borrow_mut(); + cosmic_theme.set_theme(settings.theme.theme_type); + }); let mut iced = iced::Settings::with_flags((core, flags)); diff --git a/src/theme/mod.rs b/src/theme/mod.rs index 2fb5e8c..eddcc77 100644 --- a/src/theme/mod.rs +++ b/src/theme/mod.rs @@ -4,6 +4,7 @@ pub mod expander; mod segmented_button; +use std::cell::RefCell; use std::f32::consts::PI; use std::hash::Hash; use std::hash::Hasher; @@ -64,6 +65,10 @@ lazy_static::lazy_static! { }; } +thread_local! { + pub(crate) static THEME: RefCell = RefCell::new(Theme { theme_type: ThemeType::Dark, layer: cosmic_theme::Layer::Background }); +} + #[derive(Debug, Clone, PartialEq, Default)] pub enum ThemeType { #[default] @@ -72,6 +77,7 @@ pub enum ThemeType { HighContrastDark, HighContrastLight, Custom(Arc), + System(Arc), } #[derive(Debug, Clone, PartialEq, Default)] @@ -88,7 +94,7 @@ impl Theme { ThemeType::Light => &COSMIC_LIGHT, ThemeType::HighContrastDark => &COSMIC_HC_DARK, ThemeType::HighContrastLight => &COSMIC_HC_LIGHT, - ThemeType::Custom(ref t) => t.as_ref(), + ThemeType::Custom(ref t) | ThemeType::System(ref t) => t.as_ref(), } } @@ -132,6 +138,14 @@ impl Theme { } } + #[must_use] + pub fn system(theme: Arc) -> Self { + Self { + theme_type: ThemeType::System(theme), + ..Default::default() + } + } + /// get current container /// can be used in a component that is intended to be a child of a `CosmicContainer` #[must_use] @@ -142,6 +156,11 @@ impl Theme { cosmic_theme::Layer::Secondary => &self.cosmic().secondary, } } + + /// set the theme + pub fn set_theme(&mut self, theme: ThemeType) { + self.theme_type = theme; + } } impl LayeredTheme for Theme { @@ -1215,7 +1234,7 @@ pub fn theme() -> Theme { } theme }); - crate::theme::Theme::custom(Arc::new(t)) + crate::theme::Theme::system(Arc::new(t)) } pub fn subscription(id: u64) -> Subscription { @@ -1231,7 +1250,8 @@ pub fn subscription(id: u64) -> Subscription { } theme }); - crate::theme::Theme::custom(Arc::new(theme)) + + crate::theme::Theme::system(Arc::new(theme)) }) }