feat(cosmic-theme): add apply_gtk_decoration_layout helper

Writes the gtk-decoration-layout key to ~/.config/gtk-{3,4}.0/settings.ini
and best-effort updates GNOME's button-layout GSettings key for apps that
still consult it. Factors out write_gtk_settings_key for reuse.

Leyoda 2026 – GPLv3
This commit is contained in:
Lionel DARNIS 2026-05-05 09:29:47 +02:00
parent 597aba3e9f
commit ef8f69134f

View file

@ -1,12 +1,13 @@
use crate::composite::over;
use crate::steps::steps;
use crate::{Component, Theme};
use palette::rgb::Rgba;
use palette::{Darken, IntoColor, Lighten, Srgba, WithAlpha};
use std::fs::{self, File};
use std::io::{self, Write};
use std::num::NonZeroUsize;
use std::path::Path;
use crate::{Component, Theme, composite::over, steps::steps};
use configparser::ini::Ini;
use palette::{Darken, IntoColor, Lighten, Srgba, WithAlpha, rgb::Rgba};
use std::{
fs::{self, File},
io::{self, Write},
num::NonZeroUsize,
path::Path,
process::Command,
};
use super::{OutputError, to_rgba};
@ -218,6 +219,50 @@ impl Theme {
Ok(())
}
/// Apply the preferred GTK client-side decoration button layout.
///
/// This writes the GTK 3/4 `settings.ini` value used by GTK header bars and
/// also best-effort updates GNOME's `button-layout` GSettings key for apps
/// that still consult it.
///
/// # Errors
///
/// Returns an `OutputError` if the GTK settings files cannot be written.
#[cold]
pub fn apply_gtk_decoration_layout(buttons_at_start: bool) -> Result<(), OutputError> {
let Some(config_dir) = dirs::config_dir() else {
return Err(OutputError::MissingConfigDir);
};
let layout = if buttons_at_start {
"close,minimize,maximize:"
} else {
":minimize,maximize,close"
};
for gtk_version in ["gtk-3.0", "gtk-4.0"] {
let gtk_dir = config_dir.join(gtk_version);
fs::create_dir_all(&gtk_dir).map_err(OutputError::Io)?;
Self::write_gtk_settings_key(
&gtk_dir.join("settings.ini"),
"gtk-decoration-layout",
layout,
)?;
}
// best-effort: gsettings is absent on non-GNOME systems
let _ = Command::new("gsettings")
.args([
"set",
"org.gnome.desktop.wm.preferences",
"button-layout",
layout,
])
.status();
Ok(())
}
/// Reset the applied gtk css
///
/// # Errors
@ -257,6 +302,20 @@ impl Theme {
Ok(())
}
#[cold]
fn write_gtk_settings_key(path: &Path, key: &str, value: &str) -> Result<(), OutputError> {
let mut ini = Ini::new_cs();
if path.exists() {
let file_content = fs::read_to_string(path).map_err(OutputError::Io)?;
ini.read(file_content).map_err(OutputError::Ini)?;
}
ini.setstr("Settings", key, Some(value));
ini.pretty_write(path, &super::qt_settings_ini_style())
.map_err(OutputError::Io)
}
fn is_cosmic_css(path: &Path, cosmic_css: &Path) -> io::Result<Option<bool>> {
if !path.exists() {
return Ok(None);