thcon/app/
gnome_shell.rs

1//! Switches between [GNOME Shell](https://wiki.gnome.org/Projects/GnomeShell) user themes, like
2//! the [User Themes extension](https://extensions.gnome.org/extension/19/user-themes/) does
3//!
4//! ## Usage: Linux & BSD
5//! GNOME Shell user themes require the [User Themes
6//! extension](https://extensions.gnome.org/extension/19/user-themes/) to be enabled.  Once that's
7//! done, simply provide the name of the theme as displayed in the User Themes extension config
8//! (either via GNOME Extensions or GNOME Tweaks), e.g.:
9//!
10//! ```toml
11//! [gnome-shell]
12//! light = "Arc"
13//! dark = "Arc-Dark-solid"
14//! ```
15//!
16//! ## Usage: Windows & macOS
17//! Currently unsupported.
18//!
19//! ## `thcon.toml` Schema
20//! Section: `gnome-shell`
21//!
22//! | Key | Type | Description | Default |
23//! | --- | ---- | ----------- | ------- |
24//! | `disabled` | boolean | `true` to disable theming of this app, otherwise `false` | `false` |
25//! | `dark` | string | The name of the theme (case-sensitive) to apply in dark mode | (none) |
26//! | `light` | string | The name of the theme (case-sensitive) to apply in light mode | (none) |
27//!
28
29use crate::config::Config as ThconConfig;
30use crate::operation::Operation;
31use crate::themeable::{ConfigError, ConfigState, Themeable};
32use crate::AppConfig;
33use crate::Disableable;
34
35use anyhow::{Context, Result};
36use gio::SettingsExt;
37use serde::Deserialize;
38
39#[derive(Debug, Deserialize, Disableable, AppConfig)]
40pub struct _Config {
41    light: String,
42    dark: String,
43    #[serde(default)]
44    disabled: bool,
45}
46
47pub struct GnomeShell {}
48
49impl Themeable for GnomeShell {
50    fn config_state(&self, config: &ThconConfig) -> ConfigState {
51        ConfigState::with_manual_config(config.gnome_shell.as_ref().map(|c| c.inner.as_ref()))
52    }
53
54    fn switch(&self, config: &ThconConfig, operation: &Operation) -> Result<()> {
55        let config = match self.config_state(config) {
56            ConfigState::NoDefault => {
57                return Err(ConfigError::RequiresManualConfig("gnome_shell").into())
58            }
59            ConfigState::Default => unreachable!(),
60            ConfigState::Disabled => return Ok(()),
61            ConfigState::Enabled => config.gnome_shell.as_ref().unwrap().unwrap_inner_left(),
62        };
63
64        let theme = match operation {
65            Operation::Darken => &config.dark,
66            Operation::Lighten => &config.light,
67        };
68
69        let gsettings = gio::Settings::new("org.gnome.shell.extensions.user-theme");
70        gsettings
71            .set_string("name", theme)
72            .map(|_| gio::Settings::sync())
73            .with_context(|| format!("Unable to apply GNOME Shell user theme '{}'", theme))
74    }
75}