feat(cosmic-theme): produce QPalette ini for more compatibility
This commit is contained in:
parent
413e63f62a
commit
f06d15ae35
3 changed files with 303 additions and 20 deletions
|
|
@ -46,8 +46,10 @@ impl Theme {
|
||||||
pub fn write_exports(&self) -> Result<(), OutputError> {
|
pub fn write_exports(&self) -> Result<(), OutputError> {
|
||||||
let gtk_res = self.write_gtk4();
|
let gtk_res = self.write_gtk4();
|
||||||
let qt_res = self.write_qt();
|
let qt_res = self.write_qt();
|
||||||
|
let qt56ct_res = self.write_qt56ct();
|
||||||
gtk_res?;
|
gtk_res?;
|
||||||
qt_res?;
|
qt_res?;
|
||||||
|
qt56ct_res?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -56,8 +58,10 @@ impl Theme {
|
||||||
pub fn reset_exports() -> Result<(), OutputError> {
|
pub fn reset_exports() -> Result<(), OutputError> {
|
||||||
let gtk_res = Theme::reset_gtk();
|
let gtk_res = Theme::reset_gtk();
|
||||||
let qt_res = Theme::reset_qt();
|
let qt_res = Theme::reset_qt();
|
||||||
|
let qt56ct_res = Theme::reset_qt56ct();
|
||||||
gtk_res?;
|
gtk_res?;
|
||||||
qt_res?;
|
qt_res?;
|
||||||
|
qt56ct_res?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
use crate::Theme;
|
use crate::Theme;
|
||||||
use configparser::ini::Ini;
|
use configparser::ini::Ini;
|
||||||
|
use palette::{Mix, Srgba, WithAlpha, blend::Compose, rgb::Rgba};
|
||||||
use std::{
|
use std::{
|
||||||
fs::{self, File},
|
fs::{self, File},
|
||||||
|
io::Write,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
|
vec,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{OutputError, qt_settings_ini_style};
|
use super::{OutputError, qt_settings_ini_style};
|
||||||
|
|
@ -15,7 +18,117 @@ impl Theme {
|
||||||
/// Increment this value when changes to qt{5,6}ct.conf are needed.
|
/// Increment this value when changes to qt{5,6}ct.conf are needed.
|
||||||
/// If the config's version is outdated, we update several sections.
|
/// If the config's version is outdated, we update several sections.
|
||||||
/// Otherwise, only the light/dark mode is updated.
|
/// Otherwise, only the light/dark mode is updated.
|
||||||
const COSMIC_QT_VERSION: u64 = 1;
|
const COSMIC_QT_VERSION: u64 = 2;
|
||||||
|
|
||||||
|
/// Produces a QPalette ini file for qt5ct and qt6ct.
|
||||||
|
///
|
||||||
|
/// Example file: https://github.com/trialuser02/qt6ct/blob/master/colors/airy.conf
|
||||||
|
#[must_use]
|
||||||
|
#[cold]
|
||||||
|
pub fn as_qpalette(&self) -> String {
|
||||||
|
let lightest = if self.is_dark {
|
||||||
|
self.background.on
|
||||||
|
} else {
|
||||||
|
self.background.base
|
||||||
|
};
|
||||||
|
let darkest = if self.is_dark {
|
||||||
|
self.background.base
|
||||||
|
} else {
|
||||||
|
self.background.on
|
||||||
|
};
|
||||||
|
let active = QPaletteGroup {
|
||||||
|
window_text: self.background.on,
|
||||||
|
button: self.button.base,
|
||||||
|
light: self.button.base.mix(lightest, 0.1),
|
||||||
|
midlight: self.button.base.mix(lightest, 0.05),
|
||||||
|
dark: self.button.base.mix(darkest, 0.1),
|
||||||
|
mid: self.button.base.mix(darkest, 0.05),
|
||||||
|
text: self.background.component.on,
|
||||||
|
bright_text: lightest,
|
||||||
|
button_text: self.button.on,
|
||||||
|
base: self.background.component.base,
|
||||||
|
window: self.background.base,
|
||||||
|
shadow: darkest,
|
||||||
|
// selection colors are swapped to fix menu bar contrast
|
||||||
|
highlight: self.background.component.selected_text,
|
||||||
|
highlighted_text: self.background.component.selected,
|
||||||
|
link: self.link_button.on,
|
||||||
|
link_visited: self.link_button.on.mix(self.secondary.component.base, 0.2),
|
||||||
|
alternate_base: self.background.base.mix(self.accent.base, 0.05),
|
||||||
|
no_role: self.background.component.disabled,
|
||||||
|
tool_tip_base: self.background.component.base,
|
||||||
|
tool_tip_text: self.background.component.on,
|
||||||
|
placeholder_text: self.background.component.on.with_alpha(0.5),
|
||||||
|
};
|
||||||
|
let inactive = QPaletteGroup {
|
||||||
|
window_text: active.window_text.with_alpha(0.8),
|
||||||
|
text: active.text.with_alpha(0.8),
|
||||||
|
highlighted_text: active.highlighted_text.with_alpha(0.8),
|
||||||
|
tool_tip_text: active.tool_tip_text.with_alpha(0.8),
|
||||||
|
..active
|
||||||
|
};
|
||||||
|
let disabled = QPaletteGroup {
|
||||||
|
button: self.button.disabled,
|
||||||
|
text: self.background.component.on_disabled,
|
||||||
|
button_text: self.button.on_disabled,
|
||||||
|
base: self.background.component.disabled,
|
||||||
|
highlighted_text: active.highlighted_text.with_alpha(0.5),
|
||||||
|
link: self.link_button.on_disabled,
|
||||||
|
link_visited: self
|
||||||
|
.link_button
|
||||||
|
.on_disabled
|
||||||
|
.mix(self.secondary.component.disabled, 0.2),
|
||||||
|
alternate_base: self.background.base.mix(self.accent.disabled, 0.05),
|
||||||
|
tool_tip_base: self.background.component.disabled,
|
||||||
|
tool_tip_text: self.background.component.on_disabled,
|
||||||
|
placeholder_text: self.background.component.on_disabled.with_alpha(0.5),
|
||||||
|
..inactive
|
||||||
|
};
|
||||||
|
|
||||||
|
format!(
|
||||||
|
r#"# GENERATED BY COSMIC
|
||||||
|
|
||||||
|
[ColorScheme]
|
||||||
|
active_colors={}
|
||||||
|
disabled_colors={}
|
||||||
|
inactive_colors={}
|
||||||
|
"#,
|
||||||
|
active.as_list(),
|
||||||
|
disabled.as_list(),
|
||||||
|
inactive.as_list(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes the QPalette ini files to:
|
||||||
|
/// - `~/.config/qt6ct/colors/`
|
||||||
|
/// - `~/.config/qt5ct/colors/`
|
||||||
|
#[cold]
|
||||||
|
pub fn write_qt56ct(&self) -> Result<(), OutputError> {
|
||||||
|
let qpalette = self.as_qpalette();
|
||||||
|
let qt5ct_res = self.write_ct("qt5ct", &qpalette);
|
||||||
|
let qt6ct_res = self.write_ct("qt6ct", &qpalette);
|
||||||
|
qt5ct_res?;
|
||||||
|
qt6ct_res?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
#[cold]
|
||||||
|
fn write_ct(&self, ct: &str, qpalette: &str) -> Result<(), OutputError> {
|
||||||
|
let file_path = Self::get_qpalette_path(ct, self.is_dark)?;
|
||||||
|
let tmp_file_path = file_path.with_extension("conf.new");
|
||||||
|
|
||||||
|
let mut tmp_file = File::create(&tmp_file_path).map_err(OutputError::Io)?;
|
||||||
|
let res = tmp_file
|
||||||
|
.write_all(qpalette.as_bytes())
|
||||||
|
.and_then(|_| tmp_file.flush())
|
||||||
|
.and_then(|_| std::fs::rename(&tmp_file_path, file_path));
|
||||||
|
if let Err(e) = res {
|
||||||
|
_ = std::fs::remove_file(&tmp_file_path);
|
||||||
|
return Err(OutputError::Io(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Edits qt{5,6}ct.conf to use COSMIC styles if needed.
|
/// Edits qt{5,6}ct.conf to use COSMIC styles if needed.
|
||||||
#[cold]
|
#[cold]
|
||||||
|
|
@ -39,7 +152,7 @@ impl Theme {
|
||||||
.map_err(OutputError::Ini)?
|
.map_err(OutputError::Ini)?
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
let color_scheme_path = Self::get_qt_colors_path(is_dark)?;
|
let color_scheme_path = Self::get_qpalette_path(ct, is_dark)?;
|
||||||
let icon_theme = if is_dark { "breeze-dark" } else { "breeze" };
|
let icon_theme = if is_dark { "breeze-dark" } else { "breeze" };
|
||||||
|
|
||||||
ini.set(
|
ini.set(
|
||||||
|
|
@ -91,11 +204,48 @@ impl Theme {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reset the applied qt56ct config by removing COSMIC-specific entries from the config file.
|
||||||
|
#[cold]
|
||||||
|
pub fn reset_qt56ct() -> Result<(), OutputError> {
|
||||||
|
let qt5ct_res = Self::reset_ct("qt5ct");
|
||||||
|
let qt6ct_res = Self::reset_ct("qt6ct");
|
||||||
|
qt5ct_res?;
|
||||||
|
qt6ct_res?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
#[cold]
|
||||||
|
fn reset_ct(ct: &str) -> 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();
|
||||||
|
if old_version == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
ini.remove_key("Appearance", "cosmic_qt_version");
|
||||||
|
ini.remove_key("Appearance", "color_scheme_path");
|
||||||
|
ini.remove_key("Appearance", "icon_theme");
|
||||||
|
|
||||||
|
ini.pretty_write(path, &qt_settings_ini_style())
|
||||||
|
.map_err(OutputError::Io)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the file paths of the form `~/.config/ct/ct.conf`:
|
/// Returns the file paths of the form `~/.config/ct/ct.conf`:
|
||||||
/// e.g. `~/.config/qt6ct/qt6ct.conf`.
|
/// e.g. `~/.config/qt6ct/qt6ct.conf`.
|
||||||
///
|
///
|
||||||
/// The file and its parent directory are created if they don't exist.
|
/// The file and its parent directory are created if they don't exist.
|
||||||
|
#[cold]
|
||||||
fn get_conf_path(ct: &str) -> Result<PathBuf, OutputError> {
|
fn get_conf_path(ct: &str) -> Result<PathBuf, OutputError> {
|
||||||
|
assert!(ct == "qt5ct" || ct == "qt6ct");
|
||||||
|
|
||||||
let Some(mut config_dir) = dirs::config_dir() else {
|
let Some(mut config_dir) = dirs::config_dir() else {
|
||||||
return Err(OutputError::MissingConfigDir);
|
return Err(OutputError::MissingConfigDir);
|
||||||
};
|
};
|
||||||
|
|
@ -111,4 +261,131 @@ impl Theme {
|
||||||
|
|
||||||
Ok(file_path)
|
Ok(file_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a path like `~/.config/qt6ct/colors/CosmicDark.conf`
|
||||||
|
///
|
||||||
|
/// Its parent directory is created if it doesn't exist.
|
||||||
|
#[cold]
|
||||||
|
fn get_qpalette_path(ct: &str, is_dark: bool) -> Result<PathBuf, OutputError> {
|
||||||
|
assert!(ct == "qt5ct" || ct == "qt6ct");
|
||||||
|
|
||||||
|
let Some(mut config_dir) = dirs::config_dir() else {
|
||||||
|
return Err(OutputError::MissingConfigDir);
|
||||||
|
};
|
||||||
|
config_dir.push(&ct);
|
||||||
|
config_dir.push("colors");
|
||||||
|
if !config_dir.exists() {
|
||||||
|
fs::create_dir_all(&config_dir).map_err(OutputError::Io)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let file_name = if is_dark {
|
||||||
|
"CosmicDark.conf"
|
||||||
|
} else {
|
||||||
|
"CosmicLight.conf"
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(config_dir.join(file_name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Defines the different symbolic color roles used in current GUIs.
|
||||||
|
///
|
||||||
|
/// qt5ct and qt6ct consume this as a list of colors, ordered by ColorRole:
|
||||||
|
/// - https://doc.qt.io/qt-6/qpalette.html#ColorRole-enum
|
||||||
|
/// - https://doc.qt.io/archives/qt-5.15/qpalette.html#ColorRole-enum
|
||||||
|
struct QPaletteGroup {
|
||||||
|
/// A general foreground color.
|
||||||
|
window_text: Srgba,
|
||||||
|
/// The general button background color.
|
||||||
|
button: Srgba,
|
||||||
|
/// Lighter than [button] color, used mostly for 3D bevel and shadow effects.
|
||||||
|
light: Srgba,
|
||||||
|
/// Between [button] and [light], used mostly for 3D bevel and shadow effects.
|
||||||
|
midlight: Srgba,
|
||||||
|
/// Darker than [button], used mostly for 3D bevel and shadow effects.
|
||||||
|
dark: Srgba,
|
||||||
|
/// Between [button] and [dark], used mostly for 3D bevel and shadow effects.
|
||||||
|
mid: Srgba,
|
||||||
|
/// The foreground color used with [base].
|
||||||
|
text: Srgba,
|
||||||
|
/// A text color that is very different from [window_text], and contrasts well with e.g. [dark].
|
||||||
|
/// Typically used for text that needs to be drawn where [text] or [window_text] would give poor contrast, such as on pressed push buttons.
|
||||||
|
bright_text: Srgba,
|
||||||
|
/// A foreground color used with the [button] color.
|
||||||
|
button_text: Srgba,
|
||||||
|
/// Used mostly as the background color for text entry widgets, but can also be used for other painting -
|
||||||
|
/// such as the background of combobox drop down lists and toolbar handles.
|
||||||
|
base: Srgba,
|
||||||
|
/// A general background color.
|
||||||
|
window: Srgba,
|
||||||
|
/// A very dark color, used mostly for 3D bevel and shadow effects.
|
||||||
|
/// Opaque black by default.
|
||||||
|
shadow: Srgba,
|
||||||
|
/// A color to indicate a selected item or the current item.
|
||||||
|
highlight: Srgba,
|
||||||
|
/// A text color that contrasts with [highlight].
|
||||||
|
highlighted_text: Srgba,
|
||||||
|
/// A text color used for unvisited hyperlinks.
|
||||||
|
link: Srgba,
|
||||||
|
/// A text color used for already visited hyperlinks.
|
||||||
|
link_visited: Srgba,
|
||||||
|
/// Used as the alternate background color in views with alternating row colors.
|
||||||
|
alternate_base: Srgba,
|
||||||
|
/// No role; this special role is often used to indicate that a role has not been assigned.
|
||||||
|
no_role: Srgba,
|
||||||
|
/// Used as the background color for QToolTip and QWhatsThis.
|
||||||
|
/// Tool tips use the inactive color group of QPalette, because tool tips are not active windows.
|
||||||
|
tool_tip_base: Srgba,
|
||||||
|
/// Used as the foreground color for QToolTip and QWhatsThis.
|
||||||
|
/// Tool tips use the inactive color group of QPalette, because tool tips are not active windows.
|
||||||
|
tool_tip_text: Srgba,
|
||||||
|
/// Used as the placeholder color for various text input widgets.
|
||||||
|
placeholder_text: Srgba,
|
||||||
|
// /// [accent] only exists since Qt 6.6. Including it here breaks qt5ct.
|
||||||
|
// /// When omitted, it defaults to [highlight].
|
||||||
|
// accent: Srgba,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl QPaletteGroup {
|
||||||
|
/// Returns a comma-separated list of the colors as hex codes.
|
||||||
|
/// E.g. `#ff000000, #ffdcdcdc, ...`
|
||||||
|
///
|
||||||
|
/// Any transparent colors are flattened with [base] to avoid issues with
|
||||||
|
/// the Fusion style.
|
||||||
|
fn as_list(&self) -> String {
|
||||||
|
let colors = vec![
|
||||||
|
to_argb_hex(self.window_text.over(self.base)),
|
||||||
|
to_argb_hex(self.button.over(self.base)),
|
||||||
|
to_argb_hex(self.light.over(self.base)),
|
||||||
|
to_argb_hex(self.midlight.over(self.base)),
|
||||||
|
to_argb_hex(self.dark.over(self.base)),
|
||||||
|
to_argb_hex(self.mid.over(self.base)),
|
||||||
|
to_argb_hex(self.text.over(self.base)),
|
||||||
|
to_argb_hex(self.bright_text.over(self.base)),
|
||||||
|
to_argb_hex(self.button_text.over(self.base)),
|
||||||
|
to_argb_hex(self.base.over(self.base)),
|
||||||
|
to_argb_hex(self.window.over(self.base)),
|
||||||
|
to_argb_hex(self.shadow.over(self.base)),
|
||||||
|
to_argb_hex(self.highlight.over(self.base)),
|
||||||
|
to_argb_hex(self.highlighted_text.over(self.base)),
|
||||||
|
to_argb_hex(self.link.over(self.base)),
|
||||||
|
to_argb_hex(self.link_visited.over(self.base)),
|
||||||
|
to_argb_hex(self.alternate_base.over(self.base)),
|
||||||
|
to_argb_hex(self.no_role.over(self.base)),
|
||||||
|
to_argb_hex(self.tool_tip_base.over(self.base)),
|
||||||
|
to_argb_hex(self.tool_tip_text.over(self.base)),
|
||||||
|
to_argb_hex(self.placeholder_text.over(self.base)),
|
||||||
|
];
|
||||||
|
colors.join(", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts a color to a hex string in the format `#AARRGGBB`.
|
||||||
|
/// Do not use [to_hex] since that uses the format `RRGGBBAA`.
|
||||||
|
fn to_argb_hex(c: Srgba) -> String {
|
||||||
|
let c_u8: Rgba<palette::encoding::Srgb, u8> = c.into_format();
|
||||||
|
format!(
|
||||||
|
"#{:02x}{:02x}{:02x}{:02x}",
|
||||||
|
c_u8.alpha, c_u8.red, c_u8.green, c_u8.blue
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,11 @@ impl Theme {
|
||||||
/// Produces a color scheme ini file for Qt.
|
/// Produces a color scheme ini file for Qt.
|
||||||
///
|
///
|
||||||
/// Some high-level documentation for this file can be found at:
|
/// Some high-level documentation for this file can be found at:
|
||||||
/// https://web.archive.org/web/20250402234329/https://docs.kde.org/stable5/en/plasma-workspace/kcontrol/colors/
|
/// - https://api.kde.org/kcolorscheme.html
|
||||||
|
/// - https://web.archive.org/web/20250402234329/https://docs.kde.org/stable5/en/plasma-workspace/kcontrol/colors/
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[cold]
|
#[cold]
|
||||||
pub fn as_qt(&self) -> String {
|
pub fn as_kcolorscheme(&self) -> String {
|
||||||
// Usually, disabled elements will have strongly reduced contrast and are often notably darker or lighter
|
// Usually, disabled elements will have strongly reduced contrast and are often notably darker or lighter
|
||||||
let disabled_color_effects = IniColorEffects {
|
let disabled_color_effects = IniColorEffects {
|
||||||
color: self.button.disabled,
|
color: self.button.disabled,
|
||||||
|
|
@ -41,7 +42,7 @@ impl Theme {
|
||||||
|
|
||||||
let bg = self.background.base;
|
let bg = self.background.base;
|
||||||
// the background container
|
// the background container
|
||||||
let view_colors = IniColors {
|
let window_colors = IniColors {
|
||||||
background_alternate: bg.mix(self.accent.base, 0.05),
|
background_alternate: bg.mix(self.accent.base, 0.05),
|
||||||
background_normal: bg,
|
background_normal: bg,
|
||||||
decoration_focus: self.accent_text_color(),
|
decoration_focus: self.accent_text_color(),
|
||||||
|
|
@ -56,16 +57,17 @@ impl Theme {
|
||||||
foreground_visited: self.accent_text_color(),
|
foreground_visited: self.accent_text_color(),
|
||||||
};
|
};
|
||||||
// components inside the background container
|
// components inside the background container
|
||||||
let window_colors = IniColors {
|
let view_colors = IniColors {
|
||||||
background_alternate: self.background.component.base.mix(self.accent.base, 0.05),
|
background_alternate: self.background.component.base.mix(self.accent.base, 0.05),
|
||||||
background_normal: self.background.component.base,
|
background_normal: self.background.component.base,
|
||||||
..view_colors
|
..window_colors
|
||||||
};
|
};
|
||||||
|
|
||||||
// selected text and items
|
// selected text and items
|
||||||
let selection_colors = {
|
let selection_colors = {
|
||||||
let selected = self.background.component.selected;
|
// selection colors are swapped to fix menu bar contrast
|
||||||
let selected_text = self.background.component.selected_text;
|
let selected = self.background.component.selected_text;
|
||||||
|
let selected_text = self.background.component.selected;
|
||||||
IniColors {
|
IniColors {
|
||||||
background_alternate: selected.mix(bg, 0.5),
|
background_alternate: selected.mix(bg, 0.5),
|
||||||
background_normal: selected,
|
background_normal: selected,
|
||||||
|
|
@ -116,10 +118,10 @@ impl Theme {
|
||||||
};
|
};
|
||||||
|
|
||||||
// headers in cosmic don't have a background
|
// headers in cosmic don't have a background
|
||||||
let header_colors = &view_colors;
|
let header_colors = &window_colors;
|
||||||
let header_colors_inactive = &view_colors;
|
let header_colors_inactive = &window_colors;
|
||||||
// tool tips, "What's This" tips, and similar elements
|
// tool tips, "What's This" tips, and similar elements
|
||||||
let tooltip_colors = &window_colors;
|
let tooltip_colors = &view_colors;
|
||||||
|
|
||||||
let general_color_scheme = if self.is_dark {
|
let general_color_scheme = if self.is_dark {
|
||||||
"CosmicDark"
|
"CosmicDark"
|
||||||
|
|
@ -198,7 +200,7 @@ widgetStyle=qt6ct-style
|
||||||
format_ini_colors(&tooltip_colors, bg),
|
format_ini_colors(&tooltip_colors, bg),
|
||||||
format_ini_colors(&view_colors, bg),
|
format_ini_colors(&view_colors, bg),
|
||||||
format_ini_colors(&window_colors, bg),
|
format_ini_colors(&window_colors, bg),
|
||||||
format_ini_wm_colors(&view_colors, self.is_dark),
|
format_ini_wm_colors(&window_colors, self.is_dark),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -212,14 +214,14 @@ widgetStyle=qt6ct-style
|
||||||
/// Returns an `OutputError` if there is an error writing the colors file.
|
/// Returns an `OutputError` if there is an error writing the colors file.
|
||||||
#[cold]
|
#[cold]
|
||||||
pub fn write_qt(&self) -> Result<(), OutputError> {
|
pub fn write_qt(&self) -> Result<(), OutputError> {
|
||||||
let colors = self.as_qt();
|
let kcolorscheme = self.as_kcolorscheme();
|
||||||
let file_path = Self::get_qt_colors_path(self.is_dark)?;
|
let file_path = Self::get_kcolorscheme_path(self.is_dark)?;
|
||||||
let tmp_file_path = file_path.with_extension("colors.new");
|
let tmp_file_path = file_path.with_extension("colors.new");
|
||||||
|
|
||||||
// Write to tmp_file_path first, then move it to file_path
|
// Write to tmp_file_path first, then move it to file_path
|
||||||
let mut tmp_file = File::create(&tmp_file_path).map_err(OutputError::Io)?;
|
let mut tmp_file = File::create(&tmp_file_path).map_err(OutputError::Io)?;
|
||||||
let res = tmp_file
|
let res = tmp_file
|
||||||
.write_all(colors.as_bytes())
|
.write_all(kcolorscheme.as_bytes())
|
||||||
.and_then(|_| tmp_file.flush())
|
.and_then(|_| tmp_file.flush())
|
||||||
.and_then(|_| std::fs::rename(&tmp_file_path, file_path));
|
.and_then(|_| std::fs::rename(&tmp_file_path, file_path));
|
||||||
if let Err(e) = res {
|
if let Err(e) = res {
|
||||||
|
|
@ -245,7 +247,7 @@ widgetStyle=qt6ct-style
|
||||||
let kdeglobals_file = config_dir.join("kdeglobals");
|
let kdeglobals_file = config_dir.join("kdeglobals");
|
||||||
let mut kdeglobals_ini = Self::read_ini(&kdeglobals_file)?;
|
let mut kdeglobals_ini = Self::read_ini(&kdeglobals_file)?;
|
||||||
|
|
||||||
let src_file = Self::get_qt_colors_path(is_dark)?;
|
let src_file = Self::get_kcolorscheme_path(is_dark)?;
|
||||||
let src_ini = Self::read_ini(&src_file)?;
|
let src_ini = Self::read_ini(&src_file)?;
|
||||||
|
|
||||||
Self::backup_non_cosmic_kdeglobals(&kdeglobals_ini, &kdeglobals_file)
|
Self::backup_non_cosmic_kdeglobals(&kdeglobals_ini, &kdeglobals_file)
|
||||||
|
|
@ -288,7 +290,7 @@ widgetStyle=qt6ct-style
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_dark = false; // doesn't matter since we're only reading keys
|
let is_dark = false; // doesn't matter since we're only reading keys
|
||||||
let src_file = Self::get_qt_colors_path(is_dark)?;
|
let src_file = Self::get_kcolorscheme_path(is_dark)?;
|
||||||
let src_ini = Self::read_ini(&src_file)?;
|
let src_ini = Self::read_ini(&src_file)?;
|
||||||
|
|
||||||
for (section, key_value) in src_ini.get_map_ref() {
|
for (section, key_value) in src_ini.get_map_ref() {
|
||||||
|
|
@ -303,8 +305,8 @@ widgetStyle=qt6ct-style
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a path like `~/.config/color-schemes/CosmicDark.colors`
|
/// Gets a path like `~/.local/share/color-schemes/CosmicDark.colors`
|
||||||
pub fn get_qt_colors_path(is_dark: bool) -> Result<PathBuf, OutputError> {
|
fn get_kcolorscheme_path(is_dark: bool) -> Result<PathBuf, OutputError> {
|
||||||
let Some(mut data_dir) = dirs::data_dir() else {
|
let Some(mut data_dir) = dirs::data_dir() else {
|
||||||
return Err(OutputError::MissingDataDir);
|
return Err(OutputError::MissingDataDir);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue