cosmic/config/
mod.rs

1// Copyright 2024 System76 <info@system76.com>
2// SPDX-License-Identifier: MPL-2.0
3
4//! Configurations available to libcosmic applications.
5
6use crate::cosmic_theme::Density;
7use cosmic_config::cosmic_config_derive::CosmicConfigEntry;
8use cosmic_config::{Config, CosmicConfigEntry};
9use serde::{Deserialize, Serialize};
10use std::collections::BTreeSet;
11use std::sync::{LazyLock, Mutex, RwLock};
12
13/// ID for the `CosmicTk` config.
14pub const ID: &str = "com.system76.CosmicTk";
15
16const MONO_FAMILY_DEFAULT: &str = "Noto Sans Mono";
17const SANS_FAMILY_DEFAULT: &str = "Open Sans";
18
19/// Stores static strings of the family names for `iced::Font` compatibility.
20pub static FAMILY_MAP: LazyLock<Mutex<BTreeSet<&'static str>>> = LazyLock::new(Mutex::default);
21
22pub static COSMIC_TK: LazyLock<RwLock<CosmicTk>> = LazyLock::new(|| {
23    RwLock::new(
24        CosmicTk::config()
25            .map(|c| {
26                CosmicTk::get_entry(&c).unwrap_or_else(|(errors, mode)| {
27                    for why in errors.into_iter().filter(cosmic_config::Error::is_err) {
28                        if let cosmic_config::Error::GetKey(_, err) = &why {
29                            if err.kind() == std::io::ErrorKind::NotFound {
30                                // No system default config installed; don't error
31                                continue;
32                            }
33                        }
34                        tracing::error!(?why, "CosmicTk config entry error");
35                    }
36                    mode
37                })
38            })
39            .unwrap_or_default(),
40    )
41});
42
43/// Apply the theme to other toolkits.
44#[allow(clippy::missing_panics_doc)]
45pub fn apply_theme_global() -> bool {
46    COSMIC_TK.read().unwrap().apply_theme_global
47}
48
49/// Show minimize button in window header.
50#[allow(clippy::missing_panics_doc)]
51pub fn show_minimize() -> bool {
52    COSMIC_TK.read().unwrap().show_minimize
53}
54
55/// Show maximize button in window header.
56#[allow(clippy::missing_panics_doc)]
57pub fn show_maximize() -> bool {
58    COSMIC_TK.read().unwrap().show_maximize
59}
60
61/// Preferred icon theme.
62#[allow(clippy::missing_panics_doc)]
63pub fn icon_theme() -> String {
64    COSMIC_TK.read().unwrap().icon_theme.clone()
65}
66
67/// Density of CSD/SSD header bars.
68#[allow(clippy::missing_panics_doc)]
69pub fn header_size() -> Density {
70    COSMIC_TK.read().unwrap().header_size
71}
72
73/// Interface density.
74#[allow(clippy::missing_panics_doc)]
75pub fn interface_density() -> Density {
76    COSMIC_TK.read().unwrap().interface_density
77}
78
79#[allow(clippy::missing_panics_doc)]
80pub fn interface_font() -> FontConfig {
81    COSMIC_TK.read().unwrap().interface_font.clone()
82}
83
84#[allow(clippy::missing_panics_doc)]
85pub fn monospace_font() -> FontConfig {
86    COSMIC_TK.read().unwrap().monospace_font.clone()
87}
88
89#[derive(Clone, CosmicConfigEntry, Debug, Eq, PartialEq)]
90#[version = 1]
91pub struct CosmicTk {
92    /// Apply the theme to other toolkits.
93    pub apply_theme_global: bool,
94
95    /// Show minimize button in window header.
96    pub show_minimize: bool,
97
98    /// Show maximize button in window header.
99    pub show_maximize: bool,
100
101    /// Preferred icon theme.
102    pub icon_theme: String,
103
104    /// Density of CSD/SSD header bars.
105    pub header_size: Density,
106
107    /// Interface density.
108    pub interface_density: Density,
109
110    /// Interface font family
111    pub interface_font: FontConfig,
112
113    /// Mono font family
114    pub monospace_font: FontConfig,
115}
116
117impl Default for CosmicTk {
118    fn default() -> Self {
119        Self {
120            apply_theme_global: false,
121            show_minimize: true,
122            show_maximize: true,
123            icon_theme: String::from("Cosmic"),
124            header_size: Density::Standard,
125            interface_density: Density::Standard,
126            interface_font: FontConfig {
127                family: SANS_FAMILY_DEFAULT.to_owned(),
128                weight: iced::font::Weight::Normal,
129                stretch: iced::font::Stretch::Normal,
130                style: iced::font::Style::Normal,
131            },
132            monospace_font: FontConfig {
133                family: MONO_FAMILY_DEFAULT.to_owned(),
134                weight: iced::font::Weight::Normal,
135                stretch: iced::font::Stretch::Normal,
136                style: iced::font::Style::Normal,
137            },
138        }
139    }
140}
141
142impl CosmicTk {
143    #[inline]
144    pub fn config() -> Result<Config, cosmic_config::Error> {
145        Config::new(ID, Self::VERSION)
146    }
147}
148
149#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
150pub struct FontConfig {
151    pub family: String,
152    pub weight: iced::font::Weight,
153    pub stretch: iced::font::Stretch,
154    pub style: iced::font::Style,
155}
156
157impl From<FontConfig> for iced::Font {
158    fn from(font: FontConfig) -> Self {
159        let mut family_map = FAMILY_MAP.lock().unwrap();
160
161        let name: &'static str = family_map
162            .get(font.family.as_str())
163            .copied()
164            .unwrap_or_else(|| {
165                let value = font.family.clone().leak();
166                family_map.insert(value);
167                value
168            });
169
170        Self {
171            family: iced::font::Family::Name(name),
172            weight: font.weight,
173            stretch: font.stretch,
174            style: font.style,
175        }
176    }
177}