feat: configure qt5ct and qt6ct
This commit is contained in:
parent
7ba564795a
commit
3b1452d354
4 changed files with 145 additions and 27 deletions
|
|
@ -29,3 +29,4 @@ cosmic-config = { path = "../cosmic-config/", default-features = false, features
|
|||
] }
|
||||
dirs.workspace = true
|
||||
thiserror = "2.0.16"
|
||||
configparser = "3.1.0"
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ use crate::Theme;
|
|||
/// Module for outputting the Cosmic gtk4 theme type as CSS
|
||||
pub mod gtk4_output;
|
||||
|
||||
/// Module for configuring qt5ct and qt6ct to use our qt theme
|
||||
pub mod qt56ct_output;
|
||||
/// Module for outputting the Cosmic qt theme type as kdeglobals
|
||||
pub mod qt_output;
|
||||
|
||||
|
|
@ -21,6 +23,8 @@ pub enum OutputError {
|
|||
MissingDataDir,
|
||||
#[error("Serde Error: {0}")]
|
||||
Serde(#[from] serde_json::Error),
|
||||
#[error("Ini Error: {0}")]
|
||||
Ini(String),
|
||||
}
|
||||
|
||||
impl Theme {
|
||||
|
|
@ -28,9 +32,11 @@ impl Theme {
|
|||
pub fn apply_exports(&self) -> Result<(), OutputError> {
|
||||
let gtk_res = Theme::apply_gtk(self.is_dark);
|
||||
let qt_res = Theme::apply_qt(self.is_dark);
|
||||
let qt56ct_res = Theme::apply_qt56ct(self.is_dark);
|
||||
let vs_res = self.clone().apply_vs_code();
|
||||
gtk_res?;
|
||||
qt_res?;
|
||||
qt56ct_res?;
|
||||
vs_res?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -41,8 +47,10 @@ impl Theme {
|
|||
pub fn apply_exports_static(is_dark: bool) -> Result<(), OutputError> {
|
||||
let gtk_res = Theme::apply_gtk(is_dark);
|
||||
let qt_res = Theme::apply_qt(is_dark);
|
||||
let qt56ct_res = Theme::apply_qt56ct(is_dark);
|
||||
gtk_res?;
|
||||
qt_res?;
|
||||
qt56ct_res?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
113
cosmic-theme/src/output/qt56ct_output.rs
Normal file
113
cosmic-theme/src/output/qt56ct_output.rs
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
use crate::Theme;
|
||||
use configparser::ini::Ini;
|
||||
use std::{
|
||||
fs::{self, File},
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
use super::OutputError;
|
||||
|
||||
impl Theme {
|
||||
/// The "version" of this theme.
|
||||
///
|
||||
/// To avoid repeatedly overwriting the user's config, we use a version system.
|
||||
///
|
||||
/// Increment this value when changes to qt{5,6}ct.conf are needed.
|
||||
/// If the config's version is outdated, we update several sections.
|
||||
/// Otherwise, only the light/dark mode is updated.
|
||||
const COSMIC_QT_VERSION: u64 = 1;
|
||||
|
||||
/// Edits qt{5,6}ct.conf to use COSMIC styles if needed.
|
||||
#[cold]
|
||||
pub fn apply_qt56ct(is_dark: bool) -> Result<(), OutputError> {
|
||||
let qt5ct_res = Self::apply_ct("qt5ct", is_dark);
|
||||
let qt6ct_res = Self::apply_ct("qt6ct", is_dark);
|
||||
qt5ct_res?;
|
||||
qt6ct_res?;
|
||||
Ok(())
|
||||
}
|
||||
#[must_use]
|
||||
#[cold]
|
||||
fn apply_ct(ct: &str, is_dark: bool) -> Result<(), OutputError> {
|
||||
let path = Self::get_conf_path(ct)?;
|
||||
let file_content = fs::read_to_string(&path).map_err(OutputError::Io)?;
|
||||
let mut ini = Ini::new_cs();
|
||||
ini.read(file_content).map_err(OutputError::Ini)?;
|
||||
|
||||
let old_version = ini
|
||||
.getuint("Appearance", "cosmic_qt_version")
|
||||
.map_err(OutputError::Ini)?
|
||||
.unwrap_or_default();
|
||||
|
||||
let color_scheme_path = Self::get_qt_colors_path(is_dark)?;
|
||||
let icon_theme = if is_dark { "breeze-dark" } else { "breeze" };
|
||||
|
||||
ini.set(
|
||||
"Appearance",
|
||||
"cosmic_qt_version",
|
||||
Some(Theme::COSMIC_QT_VERSION.to_string()),
|
||||
);
|
||||
|
||||
if old_version < Theme::COSMIC_QT_VERSION {
|
||||
// Config is outdated, update it unconditionally!
|
||||
|
||||
ini.setstr(
|
||||
"Appearance",
|
||||
"color_scheme_path",
|
||||
color_scheme_path.to_str(),
|
||||
);
|
||||
// Enable the above color scheme, instead of using the default color scheme of e.g. Breeze
|
||||
ini.setstr("Appearance", "custom_palette", Some("true"));
|
||||
// COSMIC icons are stuck in light mode, so use breeze icons instead
|
||||
ini.setstr("Appearance", "icon_theme", Some(icon_theme));
|
||||
// Use COSMIC dialogs instead of KDE's
|
||||
ini.setstr("Appearance", "standard_dialogs", Some("xdgdesktopportal"));
|
||||
|
||||
// TODO: Add fonts section to match COSMIC
|
||||
} else {
|
||||
// Config is not outdated, check before updating light/dark mode only!
|
||||
|
||||
let old_color_scheme_path = ini
|
||||
.get("Appearance", "color_scheme_path")
|
||||
.unwrap_or_else(|| "CosmicPlease".to_owned());
|
||||
if old_color_scheme_path.contains("Cosmic") {
|
||||
ini.setstr(
|
||||
"Appearance",
|
||||
"color_scheme_path",
|
||||
color_scheme_path.to_str(),
|
||||
);
|
||||
}
|
||||
|
||||
let old_icon_theme = ini
|
||||
.get("Appearance", "icon_theme")
|
||||
.unwrap_or_else(|| "breeze".to_owned());
|
||||
if old_icon_theme.contains("breeze") {
|
||||
ini.setstr("Appearance", "icon_theme", Some(icon_theme));
|
||||
}
|
||||
}
|
||||
|
||||
ini.write(path).map_err(OutputError::Io)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the file paths of the form `~/.config/ct/ct.conf`:
|
||||
/// e.g. `~/.config/qt6ct/qt6ct.conf`.
|
||||
///
|
||||
/// The file and its parent directory are created if they don't exist.
|
||||
fn get_conf_path(ct: &str) -> Result<PathBuf, OutputError> {
|
||||
let Some(mut config_dir) = dirs::config_dir() else {
|
||||
return Err(OutputError::MissingConfigDir);
|
||||
};
|
||||
config_dir.push(&ct);
|
||||
if !config_dir.exists() {
|
||||
fs::create_dir_all(&config_dir).map_err(OutputError::Io)?;
|
||||
}
|
||||
|
||||
let file_path = config_dir.join(ct.to_owned() + ".conf");
|
||||
if !file_path.exists() {
|
||||
File::create_new(&file_path).map_err(OutputError::Io)?;
|
||||
}
|
||||
|
||||
Ok(file_path)
|
||||
}
|
||||
}
|
||||
|
|
@ -125,7 +125,7 @@ impl Theme {
|
|||
} else {
|
||||
"COSMIC Light"
|
||||
};
|
||||
// COSMIC icons are stuck in light mode, so use breeze instead
|
||||
// COSMIC icons are stuck in light mode, so use breeze icons instead
|
||||
let icons_theme = if self.is_dark {
|
||||
"breeze-dark"
|
||||
} else {
|
||||
|
|
@ -207,22 +207,7 @@ widgetStyle=qt6ct-style
|
|||
#[cold]
|
||||
pub fn write_qt(&self) -> Result<(), OutputError> {
|
||||
let colors = self.as_qt();
|
||||
let Some(mut data_dir) = dirs::data_dir() else {
|
||||
return Err(OutputError::MissingDataDir);
|
||||
};
|
||||
|
||||
let file_name = if self.is_dark {
|
||||
"CosmicDark.colors"
|
||||
} else {
|
||||
"CosmicLight.colors"
|
||||
};
|
||||
|
||||
data_dir.push("color-schemes");
|
||||
if !data_dir.exists() {
|
||||
std::fs::create_dir_all(&data_dir).map_err(OutputError::Io)?;
|
||||
}
|
||||
|
||||
let file_path = data_dir.join(file_name);
|
||||
let file_path = Self::get_qt_colors_path(self.is_dark)?;
|
||||
let tmp_file_path = file_path.with_extension("colors.new");
|
||||
|
||||
// Write to tmp_file_path first, then move it to file_path
|
||||
|
|
@ -251,16 +236,7 @@ widgetStyle=qt6ct-style
|
|||
let Some(config_dir) = dirs::config_dir() else {
|
||||
return Err(OutputError::MissingConfigDir);
|
||||
};
|
||||
let Some(mut data_dir) = dirs::data_dir() else {
|
||||
return Err(OutputError::MissingDataDir);
|
||||
};
|
||||
data_dir.push("color-schemes");
|
||||
|
||||
let src_file = data_dir.join(if is_dark {
|
||||
"CosmicDark.colors"
|
||||
} else {
|
||||
"CosmicLight.colors"
|
||||
});
|
||||
let src_file = Self::get_qt_colors_path(is_dark)?;
|
||||
|
||||
let kdeglobals_file = config_dir.join("kdeglobals");
|
||||
|
||||
|
|
@ -304,6 +280,26 @@ widgetStyle=qt6ct-style
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Gets a path like `~/.config/color-schemes/CosmicDark.colors`
|
||||
pub fn get_qt_colors_path(is_dark: bool) -> Result<PathBuf, OutputError> {
|
||||
let Some(mut data_dir) = dirs::data_dir() else {
|
||||
return Err(OutputError::MissingDataDir);
|
||||
};
|
||||
|
||||
let file_name = if is_dark {
|
||||
"CosmicDark.colors"
|
||||
} else {
|
||||
"CosmicLight.colors"
|
||||
};
|
||||
|
||||
data_dir.push("color-schemes");
|
||||
if !data_dir.exists() {
|
||||
std::fs::create_dir_all(&data_dir).map_err(OutputError::Io)?;
|
||||
}
|
||||
|
||||
Ok(data_dir.join(file_name))
|
||||
}
|
||||
|
||||
#[cold]
|
||||
fn backup_non_cosmic_kdeglobals(path: &Path) -> io::Result<()> {
|
||||
if !Self::is_cosmic_kdeglobals(path)?.unwrap_or(true) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue