diff --git a/Cargo.lock b/Cargo.lock index 7f057d12..31bbfaaa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -695,6 +695,7 @@ version = "0.1.0" dependencies = [ "cosmic-panel-config", "libcosmic", + "log", "ron", "serde", ] diff --git a/applet/Cargo.toml b/applet/Cargo.toml index 9666fbf9..d71603f0 100644 --- a/applet/Cargo.toml +++ b/applet/Cargo.toml @@ -10,3 +10,4 @@ libcosmic = { git = "https://github.com/pop-os/libcosmic/", rev = "5765053", def ron = { version = "0.8" } serde = { version = "1.0" } cosmic-panel-config = { git = "https://github.com/pop-os/cosmic-panel", rev = "6cef482" } +log = { version = "0.4" } \ No newline at end of file diff --git a/applet/src/lib.rs b/applet/src/lib.rs index 2b4d6a80..a6a5fa44 100644 --- a/applet/src/lib.rs +++ b/applet/src/lib.rs @@ -1,10 +1,15 @@ +use std::sync::Arc; + use cosmic::{ + cosmic_config::{config_subscription, CosmicConfigEntry}, + cosmic_theme::util::CssColor, iced::{ - alignment::{Horizontal, Vertical}, - wayland::InitialSurface, - widget::{self, Container}, - window, Limits, Color, Element, Length, Rectangle, Settings, + alignment::{Horizontal, Vertical}, + wayland::InitialSurface, + widget::{self, Container}, + window, Color, Element, Length, Limits, Rectangle, Settings, }, + iced_futures::Subscription, iced_style, iced_widget, sctk, theme::Button, Renderer, @@ -15,6 +20,7 @@ use iced_widget::runtime::command::platform_specific::wayland::{ popup::{SctkPopupSettings, SctkPositioner}, window::SctkWindowSettings, }; +use log::error; use sctk::reexports::protocols::xdg::shell::client::xdg_positioner::{Anchor, Gravity}; pub use cosmic_panel_config; @@ -199,4 +205,52 @@ impl CosmicAppletHelper { grab: true, } } + + pub fn theme(&self) -> cosmic::theme::Theme { + match self.background { + CosmicPanelBackground::ThemeDefault | CosmicPanelBackground::Color(_) => { + let Ok(helper) = cosmic::cosmic_config::Config::new( + cosmic::cosmic_theme::NAME, + cosmic::cosmic_theme::Theme::::version() as u64, + ) else { + return cosmic::theme::Theme::dark(); + }; + let t = cosmic::cosmic_theme::Theme::get_entry(&helper) + .map(|t| t.into_srgba()) + .unwrap_or_else(|(errors, theme)| { + for err in errors { + error!("{:?}", err); + } + theme.into_srgba() + }); + cosmic::theme::Theme::custom(Arc::new(t)) + } + CosmicPanelBackground::Dark => cosmic::theme::Theme::dark(), + CosmicPanelBackground::Light => cosmic::theme::Theme::light(), + } + } + + pub fn theme_subscription(&self, id: u64) -> Subscription { + match self.background { + CosmicPanelBackground::ThemeDefault | CosmicPanelBackground::Color(_) => { + config_subscription::>( + id, + cosmic::cosmic_theme::NAME.into(), + cosmic::cosmic_theme::Theme::::version() as u64, + ) + .map(|(_, res)| { + let theme = + res.map(|theme| theme.into_srgba()) + .unwrap_or_else(|(errors, theme)| { + for err in errors { + error!("{:?}", err); + } + theme.into_srgba() + }); + cosmic::theme::Theme::custom(Arc::new(theme)) + }) + } + CosmicPanelBackground::Dark | CosmicPanelBackground::Light => Subscription::none(), + } + } } diff --git a/cosmic-app-list/src/app.rs b/cosmic-app-list/src/app.rs index 6bbfe294..324b1050 100755 --- a/cosmic-app-list/src/app.rs +++ b/cosmic-app-list/src/app.rs @@ -267,6 +267,7 @@ enum Message { StopListeningForDnd, IncrementSubscriptionCtr, ConfigUpdated(AppListConfig), + Theme(Theme), } #[derive(Debug, Clone, Default)] @@ -368,6 +369,8 @@ impl Application for CosmicAppList { fn new(_flags: ()) -> (Self, Command) { let config = config::AppListConfig::load().unwrap_or_default(); + let helper = CosmicAppletHelper::default(); + let theme = helper.theme(); let mut self_ = CosmicAppList { favorite_list: desktop_info_for_app_ids(config.favorites.clone()) .into_iter() @@ -378,7 +381,9 @@ impl Application for CosmicAppList { desktop_info: e, }) .collect(), + applet_helper: helper, config, + theme, ..Default::default() }; self_.item_ctr = self_.favorite_list.len() as u32; @@ -835,6 +840,9 @@ impl Application for CosmicAppList { self.favorite_list = new_list; } + Message::Theme(t) => { + self.theme = t; + } } Command::none() } @@ -1051,6 +1059,7 @@ impl Application for CosmicAppList { fn subscription(&self) -> Subscription { Subscription::batch(vec![ + self.applet_helper.theme_subscription(0).map(Message::Theme), toplevel_subscription(self.subscription_ctr).map(|e| Message::Toplevel(e.1)), events_with(|e, _| match e { cosmic::iced_runtime::core::Event::PlatformSpecific( diff --git a/cosmic-applet-audio/src/main.rs b/cosmic-applet-audio/src/main.rs index ed94dc0b..aca8d9ef 100644 --- a/cosmic-applet-audio/src/main.rs +++ b/cosmic-applet-audio/src/main.rs @@ -16,10 +16,7 @@ use cosmic::iced::{ }; use cosmic::iced_style::application::{self, Appearance}; use cosmic::{Element, Theme}; -use cosmic_time::{ - once_cell::sync::Lazy, - anim, chain, id, Timeline, Instant, -}; +use cosmic_time::{anim, chain, id, once_cell::sync::Lazy, Instant, Timeline}; use iced::wayland::popup::{destroy_popup, get_popup}; use iced::widget::container; @@ -79,6 +76,7 @@ enum Message { TogglePopup, ToggleMediaControlsInTopPanel(chain::Toggler, bool), Frame(Instant), + Theme(Theme), } impl Application for Audio { @@ -88,6 +86,8 @@ impl Application for Audio { type Flags = (); fn new(_flags: ()) -> (Audio, Command) { + let applet_helper = CosmicAppletHelper::default(); + let theme = applet_helper.theme(); ( Audio { is_open: IsOpen::None, @@ -96,6 +96,8 @@ impl Application for Audio { outputs: vec![], inputs: vec![], icon_name: "audio-volume-high-symbolic".to_string(), + applet_helper, + theme, ..Default::default() }, Command::none(), @@ -123,9 +125,7 @@ impl Application for Audio { fn update(&mut self, message: Message) -> Command { match message { - Message::Frame(now) => { - self.timeline.now(now) - }, + Message::Frame(now) => self.timeline.now(now), Message::TogglePopup => { if let Some(p) = self.popup.take() { return destroy_popup(p); @@ -276,14 +276,19 @@ impl Application for Audio { self.timeline.set_chain(chain).start(); self.show_media_controls_in_top_panel = enabled; } + Message::Theme(t) => { + self.theme = t; + } }; Command::none() } fn subscription(&self) -> Subscription { - Subscription::batch(vec![pulse::connect().map(Message::Pulse), - self.timeline.as_subscription().map(Message::Frame), + Subscription::batch(vec![ + self.applet_helper.theme_subscription(0).map(Message::Theme), + pulse::connect().map(Message::Pulse), + self.timeline.as_subscription().map(Message::Frame), ]) } @@ -389,13 +394,15 @@ impl Application for Audio { .padding([12, 24]) .width(Length::Fill), container( - anim!( // toggler - SHOW_MEDIA_CONTROLS, - &self.timeline, - Some(fl!("show-media-controls")), - self.show_media_controls_in_top_panel, - Message::ToggleMediaControlsInTopPanel, - ).text_size(14) + anim!( + // toggler + SHOW_MEDIA_CONTROLS, + &self.timeline, + Some(fl!("show-media-controls")), + self.show_media_controls_in_top_panel, + Message::ToggleMediaControlsInTopPanel, + ) + .text_size(14) ) .padding([0, 24]), container(divider::horizontal::light()) diff --git a/cosmic-applet-battery/src/app.rs b/cosmic-applet-battery/src/app.rs index 55bf46b8..02e9d9b6 100644 --- a/cosmic-applet-battery/src/app.rs +++ b/cosmic-applet-battery/src/app.rs @@ -23,10 +23,7 @@ use cosmic::theme::Svg; use cosmic::widget::{button, divider, icon}; use cosmic::{Element, Theme}; use cosmic_applet::{applet_button_theme, CosmicAppletHelper}; -use cosmic_time::{ - once_cell::sync::Lazy, - anim, chain, id, Timeline, Instant, -}; +use cosmic_time::{anim, chain, id, once_cell::sync::Lazy, Instant, Timeline}; use log::error; use std::time::Duration; @@ -96,6 +93,7 @@ enum Message { Profile(Power), SelectProfile(Power), Frame(Instant), + Theme(Theme), } impl Application for CosmicBatteryApplet { @@ -105,9 +103,13 @@ impl Application for CosmicBatteryApplet { type Flags = (); fn new(_flags: ()) -> (Self, Command) { + let applet_helper = CosmicAppletHelper::default(); + let theme = applet_helper.theme(); ( CosmicBatteryApplet { icon_name: "battery-symbolic".to_string(), + applet_helper, + theme, ..Default::default() }, Command::none(), @@ -220,6 +222,9 @@ impl Application for CosmicBatteryApplet { let _ = tx.send(PowerProfileRequest::Set(profile)); } } + Message::Theme(t) => { + self.theme = t; + } } Command::none() } @@ -320,7 +325,8 @@ impl Application for CosmicBatteryApplet { .width(Length::Fill) .padding([0, 12]), container( - anim!( //toggler + anim!( + //toggler MAX_CHARGE, &self.timeline, fl!("max-charge"), @@ -384,6 +390,7 @@ impl Application for CosmicBatteryApplet { fn subscription(&self) -> Subscription { Subscription::batch(vec![ + self.applet_helper.theme_subscription(0).map(Message::Theme), device_subscription(0).map( |( _, diff --git a/cosmic-applet-bluetooth/src/app.rs b/cosmic-applet-bluetooth/src/app.rs index 9438205e..2fac47a8 100644 --- a/cosmic-applet-bluetooth/src/app.rs +++ b/cosmic-applet-bluetooth/src/app.rs @@ -53,6 +53,7 @@ enum Message { Request(BluerRequest), Cancel, Confirm, + Theme(Theme), } impl Application for CosmicBluetoothApplet { @@ -62,9 +63,13 @@ impl Application for CosmicBluetoothApplet { type Flags = (); fn new(_flags: ()) -> (Self, Command) { + let applet_helper = CosmicAppletHelper::default(); + let theme = applet_helper.theme(); ( CosmicBluetoothApplet { icon_name: "bluetooth-symbolic".to_string(), + theme, + applet_helper, ..Default::default() }, Command::none(), @@ -267,6 +272,9 @@ impl Application for CosmicBluetoothApplet { ); } } + Message::Theme(t) => { + self.theme = t; + } } Command::none() } @@ -513,7 +521,10 @@ impl Application for CosmicBluetoothApplet { } fn subscription(&self) -> Subscription { - bluetooth_subscription(0).map(|(_, e)| Message::BluetoothEvent(e)) + Subscription::batch(vec![ + self.applet_helper.theme_subscription(0).map(Message::Theme), + bluetooth_subscription(0).map(|(_, e)| Message::BluetoothEvent(e)), + ]) } fn theme(&self) -> Theme { diff --git a/cosmic-applet-graphics/src/window.rs b/cosmic-applet-graphics/src/window.rs index 4f4687ee..910a8bcc 100644 --- a/cosmic-applet-graphics/src/window.rs +++ b/cosmic-applet-graphics/src/window.rs @@ -3,6 +3,7 @@ use crate::fl; use crate::graphics::{get_current_graphics, set_graphics, Graphics}; use cosmic::iced::wayland::popup::{destroy_popup, get_popup}; use cosmic::iced::Color; +use cosmic::iced_futures::Subscription; use cosmic::iced_runtime::core::alignment::Horizontal; use cosmic::iced_runtime::core::Alignment; use cosmic::iced_style::application::{self, Appearance}; @@ -55,6 +56,7 @@ pub enum Message { SelectGraphicsMode(Graphics), TogglePopup, PopupClosed(window::Id), + Theme(Theme), } impl Application for Window { @@ -64,7 +66,13 @@ impl Application for Window { type Theme = Theme; fn new(_flags: ()) -> (Self, Command) { - let window = Window::default(); + let applet_helper = CosmicAppletHelper::default(); + let theme = applet_helper.theme(); + let window = Window { + theme, + applet_helper, + ..Default::default() + }; (window, Command::perform(dbus::init(), Message::DBusInit)) } @@ -74,6 +82,9 @@ impl Application for Window { fn update(&mut self, message: Message) -> iced::Command { match message { + Message::Theme(t) => { + self.theme = t; + } Message::SelectGraphicsMode(new) => { if let Some((_, proxy)) = self.dbus.as_ref() { let prev = self @@ -383,6 +394,9 @@ impl Application for Window { .into() } } + fn subscription(&self) -> Subscription { + self.applet_helper.theme_subscription(0).map(Message::Theme) + } fn close_requested(&self, id: window::Id) -> Self::Message { if id != window::Id(0) { diff --git a/cosmic-applet-network/src/app.rs b/cosmic-applet-network/src/app.rs index 8a26ffd8..4a8f85a9 100644 --- a/cosmic-applet-network/src/app.rs +++ b/cosmic-applet-network/src/app.rs @@ -158,6 +158,7 @@ pub(crate) enum Message { Password(String), SubmitPassword, Frame(Instant), + Theme(Theme), // Errored(String), } @@ -168,9 +169,13 @@ impl Application for CosmicNetworkApplet { type Flags = (); fn new(_flags: ()) -> (Self, Command) { + let applet_helper = CosmicAppletHelper::default(); + let theme = applet_helper.theme(); ( CosmicNetworkApplet { icon_name: "network-offline-symbolic".to_string(), + theme, + applet_helper, ..Default::default() }, Command::none(), @@ -183,6 +188,9 @@ impl Application for CosmicNetworkApplet { fn update(&mut self, message: Message) -> Command { match message { + Message::Theme(t) => { + self.theme = t; + } Message::Frame(now) => self.timeline.now(now), Message::TogglePopup => { if let Some(p) = self.popup.take() { @@ -725,6 +733,7 @@ impl Application for CosmicNetworkApplet { if let Some(conn) = self.conn.as_ref() { Subscription::batch(vec![ + self.applet_helper.theme_subscription(0).map(Message::Theme), timeline, network_sub, active_conns_subscription(0, conn.clone()) diff --git a/cosmic-applet-notifications/src/main.rs b/cosmic-applet-notifications/src/main.rs index dabc637e..481050a0 100644 --- a/cosmic-applet-notifications/src/main.rs +++ b/cosmic-applet-notifications/src/main.rs @@ -42,6 +42,7 @@ enum Message { Settings, Ignore, Frame(Instant), + Theme(Theme), } impl Application for Notifications { @@ -51,8 +52,12 @@ impl Application for Notifications { type Flags = (); fn new(_flags: ()) -> (Notifications, Command) { + let applet_helper = CosmicAppletHelper::default(); + let theme = applet_helper.theme(); ( Notifications { + applet_helper, + theme, icon_name: "notification-alert-symbolic".to_string(), ..Default::default() }, @@ -80,11 +85,18 @@ impl Application for Notifications { } fn subscription(&self) -> Subscription { - self.timeline.as_subscription().map(Message::Frame) + Subscription::batch(vec![ + self.applet_helper.theme_subscription(0).map(Message::Theme), + self.timeline.as_subscription().map(Message::Frame), + ]) } fn update(&mut self, message: Message) -> Command { match message { + Message::Theme(t) => { + self.theme = t; + Command::none() + } Message::Frame(now) => { self.timeline.now(now); Command::none() diff --git a/cosmic-applet-power/src/main.rs b/cosmic-applet-power/src/main.rs index a1888a1e..d1009d51 100644 --- a/cosmic-applet-power/src/main.rs +++ b/cosmic-applet-power/src/main.rs @@ -74,6 +74,7 @@ enum Message { Cancel, Closed(window::Id), Zbus(Result<(), zbus::Error>), + Theme(Theme), } impl Application for Power { @@ -83,8 +84,12 @@ impl Application for Power { type Flags = (); fn new(_flags: ()) -> (Power, Command) { + let applet_helper = CosmicAppletHelper::default(); + let theme = applet_helper.theme(); ( Power { + applet_helper, + theme, icon_name: "system-shutdown-symbolic".to_string(), ..Default::default() }, @@ -112,19 +117,26 @@ impl Application for Power { } fn subscription(&self) -> Subscription { - events_with(|e, _status| match e { - cosmic::iced::Event::PlatformSpecific(PlatformSpecific::Wayland( - wayland::Event::Layer(LayerEvent::Unfocused, ..), - )) => Some(Message::Cancel), - // cosmic::iced::Event::PlatformSpecific(PlatformSpecific::Wayland( - // wayland::Event::Seat(wayland::SeatEvent::Leave, _), - // )) => Some(Message::Cancel), - _ => None, - }) + Subscription::batch(vec![ + self.applet_helper.theme_subscription(0).map(Message::Theme), + events_with(|e, _status| match e { + cosmic::iced::Event::PlatformSpecific(PlatformSpecific::Wayland( + wayland::Event::Layer(LayerEvent::Unfocused, ..), + )) => Some(Message::Cancel), + // cosmic::iced::Event::PlatformSpecific(PlatformSpecific::Wayland( + // wayland::Event::Seat(wayland::SeatEvent::Leave, _), + // )) => Some(Message::Cancel), + _ => None, + }), + ]) } fn update(&mut self, message: Message) -> Command { match message { + Message::Theme(t) => { + self.theme = t; + Command::none() + } Message::TogglePopup => { if let Some(p) = self.popup.take() { destroy_popup(p) diff --git a/cosmic-applet-time/src/main.rs b/cosmic-applet-time/src/main.rs index 33984e5c..955c3985 100644 --- a/cosmic-applet-time/src/main.rs +++ b/cosmic-applet-time/src/main.rs @@ -71,6 +71,7 @@ enum Message { Tick, Ignore, Rectangle(RectangleUpdate), + Theme(Theme), } impl Application for Time { @@ -80,7 +81,16 @@ impl Application for Time { type Flags = (); fn new(_flags: ()) -> (Time, Command) { - (Time::default(), Command::none()) + let applet_helper = CosmicAppletHelper::default(); + let theme = applet_helper.theme(); + ( + Time { + applet_helper, + theme, + ..Default::default() + }, + Command::none(), + ) } fn title(&self) -> String { @@ -118,6 +128,7 @@ impl Application for Time { .expect("Setting nanoseconds to 0 should always be possible."); let wait = 1.max((next - now).num_milliseconds()); Subscription::batch(vec![ + self.applet_helper.theme_subscription(0).map(Message::Theme), rectangle_tracker_subscription(0).map(|e| Message::Rectangle(e.1)), time::every(Duration::from_millis( wait.try_into().unwrap_or(FALLBACK_DELAY), @@ -128,6 +139,10 @@ impl Application for Time { fn update(&mut self, message: Message) -> Command { match message { + Message::Theme(t) => { + self.theme = t; + Command::none() + } Message::TogglePopup => { if let Some(p) = self.popup.take() { destroy_popup(p) diff --git a/cosmic-applet-workspaces/src/components/app.rs b/cosmic-applet-workspaces/src/components/app.rs index d819d0ac..14cd9908 100644 --- a/cosmic-applet-workspaces/src/components/app.rs +++ b/cosmic-applet-workspaces/src/components/app.rs @@ -52,6 +52,7 @@ enum Message { WorkspaceUpdate(WorkspacesUpdate), WorkspacePressed(ObjectId), WheelScrolled(ScrollDelta), + Theme(Theme), Errored, } @@ -69,7 +70,7 @@ impl Application for IcedWorkspacesApplet { PanelAnchor::Left | PanelAnchor::Right => Layout::Column, PanelAnchor::Top | PanelAnchor::Bottom => Layout::Row, }, - theme: Default::default(), + theme: applet_helper.theme(), workspaces: Vec::new(), workspace_tx: Default::default(), helper: Default::default(), @@ -124,6 +125,7 @@ impl Application for IcedWorkspacesApplet { } } Message::Errored => {} + Message::Theme(t) => self.theme = t, } Command::none() } @@ -182,6 +184,7 @@ impl Application for IcedWorkspacesApplet { fn subscription(&self) -> Subscription { Subscription::batch( vec![ + self.helper.theme_subscription(0).map(Message::Theme), workspaces(0).map(|e| Message::WorkspaceUpdate(e.1)), subscription::events_with(|e, _| match e { Mouse(mouse::Event::WheelScrolled { delta }) => { diff --git a/cosmic-panel-button/src/main.rs b/cosmic-panel-button/src/main.rs index 6a2da55e..4afa2f1c 100644 --- a/cosmic-panel-button/src/main.rs +++ b/cosmic-panel-button/src/main.rs @@ -3,6 +3,7 @@ use cosmic::{ iced::{self, wayland::InitialSurface, Application}, iced_runtime::core::window, iced_style::application, + theme::Theme, }; use cosmic_applet::CosmicAppletHelper; use freedesktop_desktop_entry::DesktopEntry; @@ -17,11 +18,14 @@ struct Desktop { struct Button { desktop: Desktop, + applet_helper: CosmicAppletHelper, + theme: Theme, } #[derive(Debug, Clone)] enum Msg { Press, + Theme(Theme), } impl iced::Application for Button { @@ -31,7 +35,16 @@ impl iced::Application for Button { type Flags = Desktop; fn new(desktop: Desktop) -> (Self, iced::Command) { - (Button { desktop }, iced::Command::none()) + let applet_helper = CosmicAppletHelper::default(); + let theme = applet_helper.theme(); + ( + Button { + desktop, + applet_helper, + theme, + }, + iced::Command::none(), + ) } fn title(&self) -> String { @@ -52,16 +65,19 @@ impl iced::Application for Button { } fn subscription(&self) -> iced::Subscription { - iced::Subscription::none() + self.applet_helper.theme_subscription(0).map(Msg::Theme) } fn update(&mut self, message: Msg) -> iced::Command { match message { Msg::Press => { let _ = Command::new("sh").arg("-c").arg(&self.desktop.exec).spawn(); - iced::Command::none() + } + Msg::Theme(t) => { + self.theme = t; } } + iced::Command::none() } fn view(&self, _id: window::Id) -> cosmic::Element {