fix: Use globals instead of thread-locals

Better support for multi-threaded applications,
especially cosmic-comp rendering in parallel on
multiple threads, each potentially accessing
global configurations such as the active theme,
icon_theme and more...
This commit is contained in:
Victoria Brekenfeld 2024-08-02 20:00:16 +02:00 committed by Michael Murphy
parent f655710d55
commit b40839638a
16 changed files with 183 additions and 216 deletions

View file

@ -218,15 +218,14 @@ where
self.app self.app
.core() .core()
.watch_config::<cosmic_theme::Theme>( .watch_config::<cosmic_theme::Theme>(
if THEME if if let ThemeType::System { prefer_dark, .. } =
.with(|t| { THEME.lock().unwrap().theme_type
if let ThemeType::System { prefer_dark, .. } = t.borrow().theme_type { {
prefer_dark prefer_dark
} else { } else {
None None
} }
}) .unwrap_or_else(|| self.app.core().system_theme_mode.is_dark)
.unwrap_or_else(|| self.app.core().system_theme_mode.is_dark)
{ {
cosmic_theme::DARK_THEME_ID cosmic_theme::DARK_THEME_ID
} else { } else {
@ -427,14 +426,11 @@ impl<T: Application> Cosmic<T> {
}; };
} }
THEME.with(move |t| { THEME.lock().unwrap().set_theme(theme.theme_type);
let mut cosmic_theme = t.borrow_mut();
cosmic_theme.set_theme(theme.theme_type);
});
} }
Message::SystemThemeChange(keys, theme) => { Message::SystemThemeChange(keys, theme) => {
let cur_is_dark = THEME.with(|t| t.borrow().theme_type.is_dark()); let cur_is_dark = THEME.lock().unwrap().theme_type.is_dark();
// Ignore updates if the current theme mode does not match. // Ignore updates if the current theme mode does not match.
if cur_is_dark != theme.cosmic().is_dark { if cur_is_dark != theme.cosmic().is_dark {
return iced::Command::none(); return iced::Command::none();
@ -443,8 +439,8 @@ impl<T: Application> Cosmic<T> {
// Record the last-known system theme in event that the current theme is custom. // Record the last-known system theme in event that the current theme is custom.
self.app.core_mut().system_theme = theme.clone(); self.app.core_mut().system_theme = theme.clone();
let portal_accent = self.app.core().portal_accent; let portal_accent = self.app.core().portal_accent;
THEME.with(move |t| { {
let mut cosmic_theme = t.borrow_mut(); let mut cosmic_theme = THEME.lock().unwrap();
// Only apply update if the theme is set to load a system theme // Only apply update if the theme is set to load a system theme
if let ThemeType::System { if let ThemeType::System {
@ -466,7 +462,7 @@ impl<T: Application> Cosmic<T> {
cosmic_theme.set_theme(new_theme.theme_type); cosmic_theme.set_theme(new_theme.theme_type);
} }
}); }
return cmd; return cmd;
} }
@ -485,13 +481,13 @@ impl<T: Application> Cosmic<T> {
if !keys.contains(&"is_dark") { if !keys.contains(&"is_dark") {
return iced::Command::none(); return iced::Command::none();
} }
if THEME.with(|t| match t.borrow().theme_type { if match THEME.lock().unwrap().theme_type {
ThemeType::System { ThemeType::System {
theme: _, theme: _,
prefer_dark, prefer_dark,
} => prefer_dark.is_some(), } => prefer_dark.is_some(),
_ => false, _ => false,
}) { } {
return iced::Command::none(); return iced::Command::none();
} }
let mut cmds = vec![self.app.system_theme_mode_update(&keys, &mode)]; let mut cmds = vec![self.app.system_theme_mode_update(&keys, &mode)];
@ -523,13 +519,13 @@ impl<T: Application> Cosmic<T> {
}; };
core.system_theme = new_theme.clone(); core.system_theme = new_theme.clone();
THEME.with(move |t| { {
let mut cosmic_theme = t.borrow_mut(); let mut cosmic_theme = THEME.lock().unwrap();
// Only apply update if the theme is set to load a system theme // Only apply update if the theme is set to load a system theme
if let ThemeType::System { theme: _, .. } = cosmic_theme.theme_type { if let ThemeType::System { theme: _, .. } = cosmic_theme.theme_type {
cosmic_theme.set_theme(new_theme.theme_type); cosmic_theme.set_theme(new_theme.theme_type);
} }
}); }
} }
return Command::batch(cmds); return Command::batch(cmds);
} }
@ -552,13 +548,13 @@ impl<T: Application> Cosmic<T> {
#[cfg(feature = "xdg-portal")] #[cfg(feature = "xdg-portal")]
Message::DesktopSettings(crate::theme::portal::Desktop::ColorScheme(s)) => { Message::DesktopSettings(crate::theme::portal::Desktop::ColorScheme(s)) => {
use ashpd::desktop::settings::ColorScheme; use ashpd::desktop::settings::ColorScheme;
if THEME.with(|t| match t.borrow().theme_type { if match THEME.lock().unwrap().theme_type {
ThemeType::System { ThemeType::System {
theme: _, theme: _,
prefer_dark, prefer_dark,
} => prefer_dark.is_some(), } => prefer_dark.is_some(),
_ => false, _ => false,
}) { } {
return iced::Command::none(); return iced::Command::none();
} }
let is_dark = match s { let is_dark = match s {
@ -579,14 +575,14 @@ impl<T: Application> Cosmic<T> {
crate::theme::system_light() crate::theme::system_light()
}; };
core.system_theme = new_theme.clone(); core.system_theme = new_theme.clone();
THEME.with(move |t| { {
let mut cosmic_theme = t.borrow_mut(); let mut cosmic_theme = THEME.lock().unwrap();
// Only apply update if the theme is set to load a system theme // Only apply update if the theme is set to load a system theme
if let ThemeType::System { theme: _, .. } = cosmic_theme.theme_type { if let ThemeType::System { theme: _, .. } = cosmic_theme.theme_type {
cosmic_theme.set_theme(new_theme.theme_type); cosmic_theme.set_theme(new_theme.theme_type);
} }
}); }
} }
} }
#[cfg(feature = "xdg-portal")] #[cfg(feature = "xdg-portal")]
@ -602,8 +598,8 @@ impl<T: Application> Cosmic<T> {
return iced::Command::none(); return iced::Command::none();
} }
THEME.with(move |t| { {
let mut cosmic_theme = t.borrow_mut(); let mut cosmic_theme = THEME.lock().unwrap();
// Only apply update if the theme is set to load a system theme // Only apply update if the theme is set to load a system theme
if let ThemeType::System { if let ThemeType::System {
@ -616,7 +612,7 @@ impl<T: Application> Cosmic<T> {
prefer_dark, prefer_dark,
}); });
} }
}); }
} }
#[cfg(feature = "xdg-portal")] #[cfg(feature = "xdg-portal")]
Message::DesktopSettings(crate::theme::portal::Desktop::Contrast(_)) => { Message::DesktopSettings(crate::theme::portal::Desktop::Contrast(_)) => {
@ -631,7 +627,7 @@ impl<T: Application> Cosmic<T> {
crate::icon_theme::set_default(config.icon_theme.clone()); crate::icon_theme::set_default(config.icon_theme.clone());
} }
crate::config::COSMIC_TK.with(|tk| *tk.borrow_mut() = config); *crate::config::COSMIC_TK.lock().unwrap() = config;
} }
Message::Focus(f) => { Message::Focus(f) => {

View file

@ -48,7 +48,6 @@ pub mod message {
pub use self::command::Command; pub use self::command::Command;
pub use self::core::Core; pub use self::core::Core;
pub use self::settings::Settings; pub use self::settings::Settings;
use crate::config::CosmicTk;
use crate::prelude::*; use crate::prelude::*;
use crate::theme::THEME; use crate::theme::THEME;
use crate::widget::{context_drawer, id_container, menu, nav_bar, popover}; use crate::widget::{context_drawer, id_container, menu, nav_bar, popover};
@ -58,7 +57,6 @@ use iced::Subscription;
use iced::{multi_window::Application as IcedApplication, window}; use iced::{multi_window::Application as IcedApplication, window};
#[cfg(any(not(feature = "winit"), not(feature = "multi-window")))] #[cfg(any(not(feature = "winit"), not(feature = "multi-window")))]
use iced::{window, Application as IcedApplication}; use iced::{window, Application as IcedApplication};
use iced_core::mouse;
pub use message::Message; pub use message::Message;
use url::Url; use url::Url;
#[cfg(feature = "single-instance")] #[cfg(feature = "single-instance")]
@ -87,10 +85,7 @@ pub(crate) fn iced_settings<App: Application>(
crate::icon_theme::set_default(crate::config::icon_theme()); crate::icon_theme::set_default(crate::config::icon_theme());
} }
THEME.with(move |t| { THEME.lock().unwrap().set_theme(settings.theme.theme_type);
let mut cosmic_theme = t.borrow_mut();
cosmic_theme.set_theme(settings.theme.theme_type);
});
let mut iced = iced::Settings::with_flags((core, flags)); let mut iced = iced::Settings::with_flags((core, flags));

View file

@ -375,10 +375,7 @@ pub fn run<App: Application>(autosize: bool, flags: App::Flags) -> iced::Result
core.set_window_width(width); core.set_window_width(width);
core.set_window_height(height); core.set_window_height(height);
THEME.with(move |t| { THEME.lock().unwrap().set_theme(settings.theme.theme_type);
let mut cosmic_theme = t.borrow_mut();
cosmic_theme.set_theme(settings.theme.theme_type);
});
let mut iced = iced::Settings::with_flags((core, flags)); let mut iced = iced::Settings::with_flags((core, flags));
@ -435,11 +432,7 @@ pub fn padded_control<'a, Message>(
} }
pub fn menu_control_padding() -> Padding { pub fn menu_control_padding() -> Padding {
THEME let guard = THEME.lock().unwrap();
.with(|t| { let cosmic = guard.cosmic();
let t = t.borrow(); [cosmic.space_xxs(), cosmic.space_m()].into()
let cosmic = t.cosmic();
[cosmic.space_xxs(), cosmic.space_m()]
})
.into()
} }

View file

@ -6,53 +6,60 @@
use cosmic_config::cosmic_config_derive::CosmicConfigEntry; use cosmic_config::cosmic_config_derive::CosmicConfigEntry;
use cosmic_config::{Config, CosmicConfigEntry}; use cosmic_config::{Config, CosmicConfigEntry};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::cell::RefCell; use std::sync::{LazyLock, Mutex};
use std::rc::Rc;
/// ID for the `CosmicTk` config. /// ID for the `CosmicTk` config.
pub const ID: &str = "com.system76.CosmicTk"; pub const ID: &str = "com.system76.CosmicTk";
thread_local! { pub static COSMIC_TK: LazyLock<Mutex<CosmicTk>> = LazyLock::new(|| {
pub static COSMIC_TK: RefCell<CosmicTk> = RefCell::new(CosmicTk::config() Mutex::new(
.map(|c| { CosmicTk::config()
CosmicTk::get_entry(&c).unwrap_or_else(|(errors, mode)| { .map(|c| {
for why in errors { CosmicTk::get_entry(&c).unwrap_or_else(|(errors, mode)| {
tracing::error!(?why, "CosmicTk config entry error"); for why in errors {
} tracing::error!(?why, "CosmicTk config entry error");
mode }
}) mode
}) })
.unwrap_or_default()) })
} .unwrap_or_default(),
)
});
/// Apply the theme to other toolkits. /// Apply the theme to other toolkits.
#[allow(clippy::missing_panics_doc)]
pub fn apply_theme_global() -> bool { pub fn apply_theme_global() -> bool {
COSMIC_TK.with(|tk| tk.borrow().apply_theme_global) COSMIC_TK.lock().unwrap().apply_theme_global
} }
/// Show minimize button in window header. /// Show minimize button in window header.
#[allow(clippy::missing_panics_doc)]
pub fn show_minimize() -> bool { pub fn show_minimize() -> bool {
COSMIC_TK.with(|tk| tk.borrow().show_minimize) COSMIC_TK.lock().unwrap().show_minimize
} }
/// Show maximize button in window header. /// Show maximize button in window header.
#[allow(clippy::missing_panics_doc)]
pub fn show_maximize() -> bool { pub fn show_maximize() -> bool {
COSMIC_TK.with(|tk| tk.borrow().show_maximize) COSMIC_TK.lock().unwrap().show_maximize
} }
/// Preferred icon theme. /// Preferred icon theme.
#[allow(clippy::missing_panics_doc)]
pub fn icon_theme() -> String { pub fn icon_theme() -> String {
COSMIC_TK.with(|tk| tk.borrow().icon_theme.clone()) COSMIC_TK.lock().unwrap().icon_theme.clone()
} }
/// Density of CSD/SSD header bars. /// Density of CSD/SSD header bars.
#[allow(clippy::missing_panics_doc)]
pub fn header_size() -> Density { pub fn header_size() -> Density {
COSMIC_TK.with(|tk| tk.borrow().header_size) COSMIC_TK.lock().unwrap().header_size
} }
/// Interface density. /// Interface density.
#[allow(clippy::missing_panics_doc)]
pub fn interface_density() -> Density { pub fn interface_density() -> Density {
COSMIC_TK.with(|tk| tk.borrow().interface_density) COSMIC_TK.lock().unwrap().interface_density
} }
#[derive(Clone, CosmicConfigEntry, Debug, Eq, PartialEq)] #[derive(Clone, CosmicConfigEntry, Debug, Eq, PartialEq)]

View file

@ -4,22 +4,21 @@
//! Select the preferred icon theme. //! Select the preferred icon theme.
use std::borrow::Cow; use std::borrow::Cow;
use std::cell::RefCell; use std::sync::Mutex;
pub const COSMIC: &str = "Cosmic"; pub const COSMIC: &str = "Cosmic";
thread_local! { pub(crate) static DEFAULT: Mutex<Cow<'static, str>> = Mutex::new(Cow::Borrowed(COSMIC));
/// The fallback icon theme to search if no icon theme was specified.
pub(crate) static DEFAULT: RefCell<Cow<'static, str>> = RefCell::new(COSMIC.into());
}
/// The fallback icon theme to search if no icon theme was specified. /// The fallback icon theme to search if no icon theme was specified.
#[must_use] #[must_use]
#[allow(clippy::missing_panics_doc)]
pub fn default() -> String { pub fn default() -> String {
DEFAULT.with(|theme| theme.borrow().to_string()) DEFAULT.lock().unwrap().to_string()
} }
/// Set the fallback icon theme to search when loading system icons. /// Set the fallback icon theme to search when loading system icons.
#[allow(clippy::missing_panics_doc)]
pub fn set_default(name: impl Into<Cow<'static, str>>) { pub fn set_default(name: impl Into<Cow<'static, str>>) {
DEFAULT.with(|theme| *theme.borrow_mut() = name.into()); *DEFAULT.lock().unwrap() = name.into();
} }

View file

@ -15,8 +15,7 @@ use cosmic_theme::Component;
use cosmic_theme::LayeredTheme; use cosmic_theme::LayeredTheme;
use iced_futures::Subscription; use iced_futures::Subscription;
use std::cell::RefCell; use std::sync::{Arc, Mutex};
use std::sync::Arc;
#[cfg(feature = "dbus-config")] #[cfg(feature = "dbus-config")]
use cosmic_config::dbus; use cosmic_config::dbus;
@ -46,18 +45,21 @@ lazy_static::lazy_static! {
}; };
} }
thread_local! { pub(crate) static THEME: Mutex<Theme> = Mutex::new(Theme {
pub(crate) static THEME: RefCell<Theme> = RefCell::new(Theme { theme_type: ThemeType::Dark, layer: cosmic_theme::Layer::Background }); theme_type: ThemeType::Dark,
} layer: cosmic_theme::Layer::Background,
});
/// Currently-defined theme. /// Currently-defined theme.
#[allow(clippy::missing_panics_doc)]
pub fn active() -> Theme { pub fn active() -> Theme {
THEME.with(|theme| theme.borrow().clone()) THEME.lock().unwrap().clone()
} }
/// Currently-defined theme type. /// Currently-defined theme type.
#[allow(clippy::missing_panics_doc)]
pub fn active_type() -> ThemeType { pub fn active_type() -> ThemeType {
THEME.with(|theme| theme.borrow().theme_type.clone()) THEME.lock().unwrap().theme_type.clone()
} }
/// Whether the active theme has a dark preference. /// Whether the active theme has a dark preference.

View file

@ -31,95 +31,85 @@ pub fn icon<'a, Message>(handle: impl Into<Handle>) -> Button<'a, Message> {
impl<'a, Message> Button<'a, Message> { impl<'a, Message> Button<'a, Message> {
pub fn new(icon: Icon) -> Self { pub fn new(icon: Icon) -> Self {
crate::theme::THEME.with(|theme_cell| { let guard = crate::theme::THEME.lock().unwrap();
let theme = theme_cell.borrow(); let theme = guard.cosmic();
let theme = theme.cosmic(); let padding = theme.space_xxs();
let padding = theme.space_xxs();
Self { Self {
id: Id::unique(), id: Id::unique(),
label: Cow::Borrowed(""), label: Cow::Borrowed(""),
tooltip: Cow::Borrowed(""), tooltip: Cow::Borrowed(""),
on_press: None, on_press: None,
width: Length::Shrink, width: Length::Shrink,
height: Length::Shrink, height: Length::Shrink,
padding: Padding::from(padding), padding: Padding::from(padding),
spacing: theme.space_xxxs(), spacing: theme.space_xxxs(),
icon_size: if icon.handle.symbolic { 16 } else { 24 }, icon_size: if icon.handle.symbolic { 16 } else { 24 },
line_height: 20, line_height: 20,
font_size: 14, font_size: 14,
font_weight: Weight::Normal, font_weight: Weight::Normal,
style: Style::Icon, style: Style::Icon,
variant: icon, variant: icon,
} }
})
} }
/// Applies the **Extra Small** button size preset. /// Applies the **Extra Small** button size preset.
pub fn extra_small(mut self) -> Self { pub fn extra_small(mut self) -> Self {
crate::theme::THEME.with(|theme_cell| { let guard = crate::theme::THEME.lock().unwrap();
let theme = theme_cell.borrow(); let theme = guard.cosmic();
let theme = theme.cosmic();
self.font_size = 14; self.font_size = 14;
self.font_weight = Weight::Normal; self.font_weight = Weight::Normal;
self.icon_size = 16; self.icon_size = 16;
self.line_height = 20; self.line_height = 20;
self.padding = Padding::from(theme.space_xxs()); self.padding = Padding::from(theme.space_xxs());
self.spacing = theme.space_xxxs(); self.spacing = theme.space_xxxs();
});
self self
} }
/// Applies the **Medium** button size preset. /// Applies the **Medium** button size preset.
pub fn medium(mut self) -> Self { pub fn medium(mut self) -> Self {
crate::theme::THEME.with(|theme_cell| { let guard = crate::theme::THEME.lock().unwrap();
let theme = theme_cell.borrow(); let theme = guard.cosmic();
let theme = theme.cosmic();
self.font_size = 24; self.font_size = 24;
self.font_weight = Weight::Normal; self.font_weight = Weight::Normal;
self.icon_size = 32; self.icon_size = 32;
self.line_height = 32; self.line_height = 32;
self.padding = Padding::from(theme.space_xs()); self.padding = Padding::from(theme.space_xs());
self.spacing = theme.space_xxs(); self.spacing = theme.space_xxs();
});
self self
} }
/// Applies the **Large** button size preset. /// Applies the **Large** button size preset.
pub fn large(mut self) -> Self { pub fn large(mut self) -> Self {
crate::theme::THEME.with(|theme_cell| { let guard = crate::theme::THEME.lock().unwrap();
let theme = theme_cell.borrow(); let theme = guard.cosmic();
let theme = theme.cosmic();
self.font_size = 28; self.font_size = 28;
self.font_weight = Weight::Normal; self.font_weight = Weight::Normal;
self.icon_size = 40; self.icon_size = 40;
self.line_height = 36; self.line_height = 36;
self.padding = Padding::from(theme.space_xs()); self.padding = Padding::from(theme.space_xs());
self.spacing = theme.space_xxs(); self.spacing = theme.space_xxs();
});
self self
} }
/// Applies the **Extra Large** button size preset. /// Applies the **Extra Large** button size preset.
pub fn extra_large(mut self) -> Self { pub fn extra_large(mut self) -> Self {
crate::theme::THEME.with(|theme_cell| { let guard = crate::theme::THEME.lock().unwrap();
let theme = theme_cell.borrow(); let theme = guard.cosmic();
let theme = theme.cosmic(); let padding = theme.space_xs();
let padding = theme.space_xs();
self.font_size = 32; self.font_size = 32;
self.font_weight = Weight::Light; self.font_weight = Weight::Light;
self.icon_size = 56; self.icon_size = 56;
self.line_height = 44; self.line_height = 44;
self.padding = Padding::from(padding); self.padding = Padding::from(padding);
self.spacing = theme.space_xxs(); self.spacing = theme.space_xxs();
});
self self
} }

View file

@ -44,7 +44,7 @@ pub struct Appearance {
impl Appearance { impl Appearance {
// TODO: `Radius` is not `const fn` compatible. // TODO: `Radius` is not `const fn` compatible.
pub fn new() -> Self { pub fn new() -> Self {
let rad_0 = THEME.with(|t| t.borrow().cosmic().corner_radii.radius_0); let rad_0 = THEME.lock().unwrap().cosmic().corner_radii.radius_0;
Self { Self {
shadow_offset: Vector::new(0.0, 0.0), shadow_offset: Vector::new(0.0, 0.0),
background: None, background: None,

View file

@ -51,26 +51,24 @@ impl Text {
impl<'a, Message> Button<'a, Message> { impl<'a, Message> Button<'a, Message> {
pub fn new(text: Text) -> Self { pub fn new(text: Text) -> Self {
crate::theme::THEME.with(|theme_cell| { let guard = crate::theme::THEME.lock().unwrap();
let theme = theme_cell.borrow(); let theme = guard.cosmic();
let theme = theme.cosmic(); Self {
Self { id: Id::unique(),
id: Id::unique(), label: Cow::Borrowed(""),
label: Cow::Borrowed(""), tooltip: Cow::Borrowed(""),
tooltip: Cow::Borrowed(""), on_press: None,
on_press: None, width: Length::Shrink,
width: Length::Shrink, height: Length::Fixed(theme.space_l().into()),
height: Length::Fixed(theme.space_l().into()), padding: Padding::from([0, theme.space_s()]),
padding: Padding::from([0, theme.space_s()]), spacing: theme.space_xxxs(),
spacing: theme.space_xxxs(), icon_size: 16,
icon_size: 16, line_height: 20,
line_height: 20, font_size: 14,
font_size: 14, font_weight: Weight::Normal,
font_weight: Weight::Normal, style: Style::Standard,
style: Style::Standard, variant: text,
variant: text, }
}
})
} }
pub fn leading_icon(mut self, icon: impl Into<icon::Handle>) -> Self { pub fn leading_icon(mut self, icon: impl Into<icon::Handle>) -> Self {

View file

@ -423,7 +423,7 @@ impl<'a, Message: 'a + Clone> Widget<Message, crate::Theme, crate::Renderer>
renderer.with_layer(parent_bounds, |renderer| { renderer.with_layer(parent_bounds, |renderer| {
let selection_background = theme.selection_background(); let selection_background = theme.selection_background();
let c_rad = THEME.with(|t| t.borrow().cosmic().corner_radii); let c_rad = THEME.lock().unwrap().cosmic().corner_radii;
// NOTE: Workaround to round the border of the unselected, unhovered image. // NOTE: Workaround to round the border of the unselected, unhovered image.
if !self.selected && !is_mouse_over { if !self.selected && !is_mouse_over {

View file

@ -177,11 +177,7 @@ fn padded_control<'a, Message>(
} }
fn menu_control_padding() -> Padding { fn menu_control_padding() -> Padding {
crate::theme::THEME let guard = crate::theme::THEME.lock().unwrap();
.with(|t| { let cosmic = guard.cosmic();
let t = t.borrow(); [cosmic.space_xxs(), cosmic.space_m()].into()
let cosmic = t.cosmic();
[cosmic.space_xxs(), cosmic.space_m()]
})
.into()
} }

View file

@ -287,7 +287,7 @@ where
copied_to_clipboard_label: T, copied_to_clipboard_label: T,
) -> ColorPicker<'a, Message> { ) -> ColorPicker<'a, Message> {
let on_update = self.on_update; let on_update = self.on_update;
let spacing = THEME.with(|t| t.borrow().cosmic().spacing); let spacing = THEME.lock().unwrap().cosmic().spacing;
let mut inner = column![ let mut inner = column![
// segmented buttons // segmented buttons
segmented_control::horizontal(self.model) segmented_control::horizontal(self.model)
@ -595,7 +595,7 @@ where
let bounds = canvas_layout.bounds(); let bounds = canvas_layout.bounds();
// Draw the handle on the saturation value canvas // Draw the handle on the saturation value canvas
let t = THEME.with(|t| t.borrow().clone()); let t = THEME.lock().unwrap().clone();
let t = t.cosmic(); let t = t.cosmic();
let handle_radius = f32::from(t.space_xs()) / 2.0; let handle_radius = f32::from(t.space_xs()) / 2.0;
let (x, y) = ( let (x, y) = (
@ -779,7 +779,7 @@ pub fn color_button<'a, Message: 'static>(
color: Option<Color>, color: Option<Color>,
icon_portion: Length, icon_portion: Length,
) -> crate::widget::Button<'a, Message> { ) -> crate::widget::Button<'a, Message> {
let spacing = THEME.with(|t| t.borrow().cosmic().spacing); let spacing = THEME.lock().unwrap().cosmic().spacing;
button(if color.is_some() { button(if color.is_some() {
Element::from(vertical_space(Length::Fixed(f32::from(spacing.space_s)))) Element::from(vertical_space(Length::Fixed(f32::from(spacing.space_s))))

View file

@ -67,11 +67,7 @@ impl<'a, Message: Clone + 'static> From<Dialog<'a, Message>> for Element<'a, Mes
space_s, space_s,
space_xxs, space_xxs,
.. ..
} = theme::THEME.with(|theme_cell| { } = theme::THEME.lock().unwrap().cosmic().spacing;
let theme = theme_cell.borrow();
let theme = theme.cosmic();
theme.spacing
});
let mut content_col = widget::column::with_capacity(3 + dialog.controls.len() * 2); let mut content_col = widget::column::with_capacity(3 + dialog.controls.len() * 2);
content_col = content_col.push(widget::text::title3(dialog.title)); content_col = content_col.push(widget::text::title3(dialog.title));

View file

@ -75,38 +75,35 @@ impl Named {
lookup.find() lookup.find()
}; };
crate::icon_theme::DEFAULT.with(|theme| { let theme = crate::icon_theme::DEFAULT.lock().unwrap();
let theme = theme.borrow(); let themes = if theme.as_ref() == crate::icon_theme::COSMIC {
vec![theme.as_ref()]
} else {
vec![theme.as_ref(), crate::icon_theme::COSMIC]
};
let themes = if theme.as_ref() == crate::icon_theme::COSMIC { let mut result = themes.iter().find_map(|t| locate(t, name));
vec![theme.as_ref()]
} else {
vec![theme.as_ref(), crate::icon_theme::COSMIC]
};
let mut result = themes.iter().find_map(|t| locate(t, name)); // On failure, attempt to locate fallback icon.
if result.is_none() {
// On failure, attempt to locate fallback icon. if matches!(fallback, Some(IconFallback::Default)) {
if result.is_none() { for new_name in name.rmatch_indices('-').map(|(pos, _)| &name[..pos]) {
if matches!(fallback, Some(IconFallback::Default)) { result = themes.iter().find_map(|t| locate(t, new_name));
for new_name in name.rmatch_indices('-').map(|(pos, _)| &name[..pos]) { if result.is_some() {
result = themes.iter().find_map(|t| locate(t, new_name)); break;
if result.is_some() {
break;
}
} }
} else if let Some(IconFallback::Names(fallbacks)) = fallback { }
for fallback in fallbacks { } else if let Some(IconFallback::Names(fallbacks)) = fallback {
result = themes.iter().find_map(|t| locate(t, fallback)); for fallback in fallbacks {
if result.is_some() { result = themes.iter().find_map(|t| locate(t, fallback));
break; if result.is_some() {
} break;
} }
} }
} }
}
result result
})
} }
#[cfg(windows)] #[cfg(windows)]

View file

@ -1361,7 +1361,7 @@ where
bounds.y = bounds.y + bounds.height - width; bounds.y = bounds.y + bounds.height - width;
bounds.height = width; bounds.height = width;
let rad_0 = THEME.with(|t| t.borrow().cosmic().corner_radii.radius_0); let rad_0 = THEME.lock().unwrap().cosmic().corner_radii.radius_0;
renderer.fill_quad( renderer.fill_quad(
renderer::Quad { renderer::Quad {
bounds, bounds,

View file

@ -92,7 +92,7 @@ pub fn search_input<'a, Message>(
where where
Message: Clone + 'static, Message: Clone + 'static,
{ {
let spacing = THEME.with(|t| t.borrow().cosmic().space_xxs()); let spacing = THEME.lock().unwrap().cosmic().space_xxs();
TextInput::new(placeholder, value) TextInput::new(placeholder, value)
.padding([0, spacing, 0, spacing]) .padding([0, spacing, 0, spacing])
@ -117,7 +117,7 @@ pub fn secure_input<'a, Message>(
where where
Message: Clone + 'static, Message: Clone + 'static,
{ {
let spacing = THEME.with(|t| t.borrow().cosmic().space_xxs()); let spacing = THEME.lock().unwrap().cosmic().space_xxs();
let mut input = TextInput::new(placeholder, value) let mut input = TextInput::new(placeholder, value)
.padding([0, spacing, 0, spacing]) .padding([0, spacing, 0, spacing])
.style(crate::theme::TextInput::Default) .style(crate::theme::TextInput::Default)
@ -156,7 +156,7 @@ pub fn inline_input<'a, Message>(
where where
Message: Clone + 'static, Message: Clone + 'static,
{ {
let spacing = THEME.with(|t| t.borrow().cosmic().space_xxs()); let spacing = THEME.lock().unwrap().cosmic().space_xxs();
TextInput::new(placeholder, value) TextInput::new(placeholder, value)
.style(crate::theme::TextInput::Inline) .style(crate::theme::TextInput::Inline)
@ -223,7 +223,7 @@ where
/// - a placeholder, /// - a placeholder,
/// - the current value /// - the current value
pub fn new(placeholder: impl Into<Cow<'a, str>>, value: impl Into<Cow<'a, str>>) -> Self { pub fn new(placeholder: impl Into<Cow<'a, str>>, value: impl Into<Cow<'a, str>>) -> Self {
let spacing = THEME.with(|t| t.borrow().cosmic().space_xxs()); let spacing = THEME.lock().unwrap().cosmic().space_xxs();
let v: Cow<'a, str> = value.into(); let v: Cow<'a, str> = value.into();
TextInput { TextInput {
@ -486,7 +486,7 @@ where
} }
pub fn on_clear(self, on_clear: Message) -> Self { pub fn on_clear(self, on_clear: Message) -> Self {
let spacing = THEME.with(|t| t.borrow().cosmic().space_xxs()); let spacing = THEME.lock().unwrap().cosmic().space_xxs();
self.trailing_icon( self.trailing_icon(
crate::widget::icon::from_name("edit-clear-symbolic") crate::widget::icon::from_name("edit-clear-symbolic")
@ -992,7 +992,7 @@ pub fn layout<Message>(
tree: &mut Tree, tree: &mut Tree,
) -> layout::Node { ) -> layout::Node {
let limits = limits.width(width); let limits = limits.width(width);
let spacing = THEME.with(|t| t.borrow().cosmic().space_xxs()); let spacing = THEME.lock().unwrap().cosmic().space_xxs();
let mut nodes = Vec::with_capacity(3); let mut nodes = Vec::with_capacity(3);
let text_pos = if let Some(label) = label { let text_pos = if let Some(label) = label {
@ -2186,9 +2186,7 @@ pub fn draw<'a, Message>(
let font = font.unwrap_or_else(|| renderer.default_font()); let font = font.unwrap_or_else(|| renderer.default_font());
let size = size.unwrap_or_else(|| renderer.default_size().0); let size = size.unwrap_or_else(|| renderer.default_size().0);
let radius_0 = THEME let radius_0 = THEME.lock().unwrap().cosmic().corner_radii.radius_0.into();
.with(|t| t.borrow().cosmic().corner_radii.radius_0)
.into();
let (cursor, offset) = if let Some(focus) = &state.is_focused { let (cursor, offset) = if let Some(focus) = &state.is_focused {
match state.cursor.state(value) { match state.cursor.state(value) {
cursor::State::Index(position) => { cursor::State::Index(position) => {