diff --git a/src/config/mod.rs b/src/config/mod.rs index 1253ce8d..f8e6d428 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -8,7 +8,25 @@ use cosmic_config::cosmic_config_derive::CosmicConfigEntry; use cosmic_config::{Config, CosmicConfigEntry}; use serde::{Deserialize, Serialize}; use std::collections::BTreeSet; -use std::sync::{LazyLock, Mutex, RwLock}; +use std::sync::{Arc, LazyLock, Mutex, PoisonError, RwLock, RwLockReadGuard}; + +/// ID for the `CosmicTk` config. +pub const ID: &str = "com.system76.CosmicTk"; + +const MONO_FAMILY_DEFAULT: &str = "Noto Sans Mono"; +const SANS_FAMILY_DEFAULT: &str = "Open Sans"; + +// Copyright 2024 System76 +// SPDX-License-Identifier: MPL-2.0 + +//! Configurations available to libcosmic applications. + +use crate::cosmic_theme::Density; +use cosmic_config::cosmic_config_derive::CosmicConfigEntry; +use cosmic_config::{Config, CosmicConfigEntry}; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeSet; +use std::sync::{LazyLock, Mutex, RwLock, RwLockReadGuard, Arc, PoisonError}; /// ID for the `CosmicTk` config. pub const ID: &str = "com.system76.CosmicTk"; @@ -17,100 +35,83 @@ const MONO_FAMILY_DEFAULT: &str = "Noto Sans Mono"; const SANS_FAMILY_DEFAULT: &str = "Open Sans"; /// Stores static strings of the family names for `iced::Font` compatibility. -pub static FAMILY_MAP: LazyLock>> = LazyLock::new(Mutex::default); +pub static FAMILY_MAP: LazyLock>>> = + LazyLock::new(|| Mutex::new(BTreeSet::new())); pub static COSMIC_TK: LazyLock> = LazyLock::new(|| { RwLock::new( - CosmicTk::config() - .map(|c| { - CosmicTk::get_entry(&c).unwrap_or_else(|(errors, mode)| { - for why in errors.into_iter().filter(cosmic_config::Error::is_err) { - if let cosmic_config::Error::GetKey(_, err) = &why { - if err.kind() == std::io::ErrorKind::NotFound { - // No system default config installed; don't error - continue; - } - } - tracing::error!(?why, "CosmicTk config entry error"); - } - mode - }) - }) - .unwrap_or_default(), - ) -}); + CosmicTk::config().map(|c| { + CosmicTk::get_entry(&c).unwrap_or_else(|(errors, mode)| { + for why in errors.into_iter().filter(cosmic_config::Error::is_err) { + if let cosmic_config::Error::GetKey(_, err) = &why { + if err.kind() == std::io::ErrorKind::NotFound { + continue; // No system default config installed + } + } + tracing::error!(?why, "CosmicTk config entry error"); + } + mode + }) + }) + .unwrap_or_default(), + ) + }); + +/// Helper to handle poisoned locks and reduce repetitive `.read().unwrap()`. +fn cosmic() -> RwLockReadGuard<'static, CosmicTk> { + COSMIC_TK.read().unwrap_or_else(|e| e.into_inner()) +} /// Apply the theme to other toolkits. -#[allow(clippy::missing_panics_doc)] pub fn apply_theme_global() -> bool { - COSMIC_TK.read().unwrap().apply_theme_global + cosmic().apply_theme_global } /// Show minimize button in window header. -#[allow(clippy::missing_panics_doc)] pub fn show_minimize() -> bool { - COSMIC_TK.read().unwrap().show_minimize + cosmic().show_minimize } /// Show maximize button in window header. -#[allow(clippy::missing_panics_doc)] pub fn show_maximize() -> bool { - COSMIC_TK.read().unwrap().show_maximize + cosmic().show_maximize } /// Preferred icon theme. -#[allow(clippy::missing_panics_doc)] -pub fn icon_theme() -> String { - COSMIC_TK.read().unwrap().icon_theme.clone() +pub fn icon_theme() -> &str { + &cosmic().icon_theme } /// Density of CSD/SSD header bars. -#[allow(clippy::missing_panics_doc)] pub fn header_size() -> Density { - COSMIC_TK.read().unwrap().header_size + cosmic().header_size } /// Interface density. -#[allow(clippy::missing_panics_doc)] pub fn interface_density() -> Density { - COSMIC_TK.read().unwrap().interface_density + cosmic().interface_density } -#[allow(clippy::missing_panics_doc)] -pub fn interface_font() -> FontConfig { - COSMIC_TK.read().unwrap().interface_font.clone() +/// Interface font. +pub fn interface_font() -> &FontConfig { + &cosmic().interface_font } -#[allow(clippy::missing_panics_doc)] -pub fn monospace_font() -> FontConfig { - COSMIC_TK.read().unwrap().monospace_font.clone() +/// Monospace font. +pub fn monospace_font() -> &FontConfig { + &cosmic().monospace_font } #[derive(Clone, CosmicConfigEntry, Debug, Eq, PartialEq)] #[version = 1] pub struct CosmicTk { - /// Apply the theme to other toolkits. pub apply_theme_global: bool, - - /// Show minimize button in window header. pub show_minimize: bool, - - /// Show maximize button in window header. pub show_maximize: bool, - - /// Preferred icon theme. pub icon_theme: String, - - /// Density of CSD/SSD header bars. pub header_size: Density, - - /// Interface density. pub interface_density: Density, - - /// Interface font family pub interface_font: FontConfig, - - /// Mono font family pub monospace_font: FontConfig, } @@ -156,19 +157,19 @@ pub struct FontConfig { impl From for iced::Font { fn from(font: FontConfig) -> Self { - let mut family_map = FAMILY_MAP.lock().unwrap(); + let mut family_map = FAMILY_MAP.lock().unwrap_or_else(|e| e.into_inner()); - let name: &'static str = family_map - .get(font.family.as_str()) - .copied() + let name: Arc = family_map + .get(&font.family.as_str().into()) + .cloned() .unwrap_or_else(|| { - let value = font.family.clone().leak(); - family_map.insert(value); + let value: Arc = Arc::from(font.family.clone()); + family_map.insert(Arc::clone(&value)); value }); Self { - family: iced::font::Family::Name(name), + family: iced::font::Family::Name(Box::leak(name.clone().into_boxed_str())), weight: font.weight, stretch: font.stretch, style: font.style,