1use 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
13pub const ID: &str = "com.system76.CosmicTk";
15
16const MONO_FAMILY_DEFAULT: &str = "Noto Sans Mono";
17const SANS_FAMILY_DEFAULT: &str = "Open Sans";
18
19pub 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 continue;
32 }
33 }
34 tracing::error!(?why, "CosmicTk config entry error");
35 }
36 mode
37 })
38 })
39 .unwrap_or_default(),
40 )
41});
42
43#[allow(clippy::missing_panics_doc)]
45pub fn apply_theme_global() -> bool {
46 COSMIC_TK.read().unwrap().apply_theme_global
47}
48
49#[allow(clippy::missing_panics_doc)]
51pub fn show_minimize() -> bool {
52 COSMIC_TK.read().unwrap().show_minimize
53}
54
55#[allow(clippy::missing_panics_doc)]
57pub fn show_maximize() -> bool {
58 COSMIC_TK.read().unwrap().show_maximize
59}
60
61#[allow(clippy::missing_panics_doc)]
63pub fn icon_theme() -> String {
64 COSMIC_TK.read().unwrap().icon_theme.clone()
65}
66
67#[allow(clippy::missing_panics_doc)]
69pub fn header_size() -> Density {
70 COSMIC_TK.read().unwrap().header_size
71}
72
73#[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 pub apply_theme_global: bool,
94
95 pub show_minimize: bool,
97
98 pub show_maximize: bool,
100
101 pub icon_theme: String,
103
104 pub header_size: Density,
106
107 pub interface_density: Density,
109
110 pub interface_font: FontConfig,
112
113 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}