mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2026-08-17 16:34:54 -05:00
feat: enable adwaita by default, add theme selector and detection (#931)
* feat: enable adwaita by default * upd readme * bump feature gate to 1.5 * feat: always build with adwaita * wip: add breeze styles (not loaded yet) * feat: theme selector * feat: better theme selector * chore: cleanup readme * Update README.md * chore: drop old flatpak theme override * fix: set higher priority for custom css * use toggle for the theme selection * upd settings popover spacing/align --------- Co-authored-by: Ilya Zlobintsev <ilya.zl@protonmail.com>
This commit is contained in:
co-authored by
Ilya Zlobintsev
parent
ec0630c819
commit
3fbfb24d6e
Generated
+1
@@ -1742,6 +1742,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_norway",
|
||||
"serde_with",
|
||||
"thread-priority",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
|
||||
@@ -11,10 +11,6 @@ build-release:
|
||||
build-debug:
|
||||
cargo build -p lact
|
||||
|
||||
.PHONY: build-release-libadwaita
|
||||
build-release-libadwaita:
|
||||
cargo build -p lact --release --features=adw
|
||||
|
||||
.PHONY: build-release-headless
|
||||
build-release-headless:
|
||||
cargo build -p lact --release --no-default-features --features=nvidia
|
||||
|
||||
@@ -188,6 +188,7 @@ Dependencies:
|
||||
|
||||
- rust 1.76+
|
||||
- gtk 4.6+
|
||||
- libadwaita 1.5+
|
||||
- git
|
||||
- pkg-config
|
||||
- clang
|
||||
@@ -221,12 +222,6 @@ Headless build with no GUI:
|
||||
make build-release-headless
|
||||
```
|
||||
|
||||
Build GUI with libadwaita support:
|
||||
|
||||
```
|
||||
make build-release-libadwaita
|
||||
```
|
||||
|
||||
# Remote management
|
||||
|
||||
It's possible to have the LACT daemon running on one machine, and then manage it
|
||||
|
||||
@@ -85,23 +85,4 @@ WantedBy=multi-user.target\
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$GTK_THEME" ]; then
|
||||
set +e
|
||||
if [ "$(gsettings get org.gnome.desktop.interface gtk-theme)" = "'Adwaita'" ] && [ "$(gsettings get org.gnome.desktop.interface color-scheme)" = "'default'" ]; then
|
||||
COLOR_SCHEME=$(dbus-send --session --print-reply \
|
||||
--dest=org.freedesktop.portal.Desktop \
|
||||
/org/freedesktop/portal/desktop \
|
||||
org.freedesktop.portal.Settings.Read \
|
||||
string:"org.freedesktop.appearance" \
|
||||
string:"color-scheme" \
|
||||
| grep -oP '(?<=uint32 )\d+')
|
||||
|
||||
if [ "$COLOR_SCHEME" = "1" ]; then
|
||||
export GTK_THEME="Adwaita:dark"
|
||||
echo "Detected dark theme system setting, GTK theme overriden to $GTK_THEME"
|
||||
fi
|
||||
fi
|
||||
set -e
|
||||
fi
|
||||
|
||||
lact $@
|
||||
|
||||
+6
-6
@@ -7,7 +7,6 @@ edition = "2024"
|
||||
[features]
|
||||
default = []
|
||||
gtk-tests = []
|
||||
adw = ["dep:adw", "relm4/libadwaita"]
|
||||
bench = ["dep:divan"]
|
||||
|
||||
[dependencies]
|
||||
@@ -21,15 +20,16 @@ anyhow = { workspace = true }
|
||||
tracing-subscriber = { workspace = true }
|
||||
chrono = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_with = { workspace = true }
|
||||
serde_norway = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
indexmap = { workspace = true }
|
||||
gtk = { version = "0.10.0", package = "gtk4", features = ["v4_6"] }
|
||||
gtk = { version = "0.10.0", package = "gtk4", features = [
|
||||
"v4_6",
|
||||
] } # TODO: bump the feature to 4_14 and figure out all the deprecations
|
||||
|
||||
adw = { package = "libadwaita", version = "0.8.0", features = [
|
||||
"v1_4",
|
||||
], optional = true }
|
||||
relm4 = { version = "0.10.0", default-features = false }
|
||||
adw = { package = "libadwaita", version = "0.8.0", features = ["v1_5"] }
|
||||
relm4 = { version = "0.10.0", features = ["libadwaita"] }
|
||||
relm4-components = "0.10.0"
|
||||
|
||||
i18n-embed = { workspace = true }
|
||||
|
||||
@@ -248,6 +248,9 @@ profile-rule-process-name = Process Name:
|
||||
profile-rule-args-contain = Arguments Contain:
|
||||
profile-rule-specific-process = With a specific process:
|
||||
|
||||
theme = Theme
|
||||
theme-auto = Automatic
|
||||
|
||||
# Crash page
|
||||
crash-page-title = Application Crashed
|
||||
exit = Exit
|
||||
|
||||
+9
-2
@@ -28,7 +28,7 @@ use ext::RelmDefaultLauchable;
|
||||
use graphs_window::{GraphsWindow, GraphsWindowMsg};
|
||||
use gtk::{
|
||||
ApplicationWindow, ButtonsType, FileChooserAction, FileChooserDialog, MessageDialog,
|
||||
MessageType, ResponseType,
|
||||
MessageType, ResponseType, STYLE_PROVIDER_PRIORITY_APPLICATION,
|
||||
glib::{self, ControlFlow, clone},
|
||||
prelude::{
|
||||
BoxExt, ButtonExt, Cast, DialogExtManual, FileChooserExt, FileExt, GtkWindowExt,
|
||||
@@ -190,7 +190,14 @@ impl AsyncComponent for AppModel {
|
||||
root: Self::Root,
|
||||
sender: AsyncComponentSender<Self>,
|
||||
) -> AsyncComponentParts<Self> {
|
||||
relm4::set_global_css(styles::COMBINED_CSS);
|
||||
relm4::set_global_css_with_priority(
|
||||
styles::COMBINED_CSS,
|
||||
STYLE_PROVIDER_PRIORITY_APPLICATION,
|
||||
);
|
||||
|
||||
if let Err(err) = styles::apply_theme(CONFIG.read().theme) {
|
||||
error!("could not apply theme: {err:#}");
|
||||
}
|
||||
|
||||
let (daemon_client, conn_err) = match args.tcp_address {
|
||||
Some(remote_addr) => {
|
||||
|
||||
@@ -5,7 +5,12 @@ pub mod profile_rule_window;
|
||||
|
||||
use crate::{
|
||||
CONFIG, I18N,
|
||||
app::{APP_BROKER, header::profile_rule_window::ProfileEditParams, msg::AppMsg},
|
||||
app::{
|
||||
APP_BROKER,
|
||||
header::profile_rule_window::ProfileEditParams,
|
||||
msg::AppMsg,
|
||||
styles::{self, AppTheme},
|
||||
},
|
||||
config::{MAX_STATS_POLL_INTERVAL_MS, MIN_STATS_POLL_INTERVAL_MS},
|
||||
};
|
||||
use glib::clone;
|
||||
@@ -51,6 +56,7 @@ pub enum HeaderMsg {
|
||||
CreateProfile,
|
||||
ImportProfile,
|
||||
ClosePopover,
|
||||
ThemeSelected(AppTheme),
|
||||
}
|
||||
|
||||
#[relm4::component(pub)]
|
||||
@@ -153,7 +159,6 @@ impl Component for Header {
|
||||
set_popover = >k::Popover {
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Vertical,
|
||||
set_margin_horizontal: 5,
|
||||
|
||||
gtk::Button {
|
||||
set_label: &fl!(I18N, "show-historical-charts"),
|
||||
@@ -212,6 +217,8 @@ impl Component for Header {
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Horizontal,
|
||||
set_spacing: 5,
|
||||
set_margin_vertical: 5,
|
||||
set_halign: gtk::Align::Center,
|
||||
|
||||
gtk::Label {
|
||||
set_markup: &format!("<b>{}</b>", &fl!(I18N, "stats-update-interval")),
|
||||
@@ -229,6 +236,60 @@ impl Component for Header {
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
gtk::Separator {},
|
||||
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Horizontal,
|
||||
set_spacing: 5,
|
||||
set_halign: gtk::Align::Center,
|
||||
set_margin_top: 5,
|
||||
|
||||
gtk::Label {
|
||||
set_markup: &format!("<b>{}</b>", &fl!(I18N, "theme")),
|
||||
},
|
||||
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Horizontal,
|
||||
add_css_class: "linked",
|
||||
|
||||
#[name = "theme_auto_btn"]
|
||||
gtk::ToggleButton {
|
||||
set_label: &fl!(I18N, "theme-auto"),
|
||||
#[watch]
|
||||
set_active: CONFIG.read().theme == AppTheme::Automatic,
|
||||
connect_toggled[sender] => move |btn| {
|
||||
if btn.is_active() {
|
||||
sender.input(HeaderMsg::ThemeSelected(AppTheme::Automatic));
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
gtk::ToggleButton {
|
||||
set_label: "Adwaita",
|
||||
set_group: Some(&theme_auto_btn),
|
||||
#[watch]
|
||||
set_active: CONFIG.read().theme == AppTheme::Adwaita,
|
||||
connect_toggled[sender] => move |btn| {
|
||||
if btn.is_active() {
|
||||
sender.input(HeaderMsg::ThemeSelected(AppTheme::Adwaita));
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
gtk::ToggleButton {
|
||||
set_label: "Breeze",
|
||||
set_group: Some(&theme_auto_btn),
|
||||
#[watch]
|
||||
set_active: CONFIG.read().theme == AppTheme::Breeze,
|
||||
connect_toggled[sender] => move |btn| {
|
||||
if btn.is_active() {
|
||||
sender.input(HeaderMsg::ThemeSelected(AppTheme::Breeze));
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -476,6 +537,13 @@ impl Component for Header {
|
||||
HeaderMsg::DeviceInfo(info) => {
|
||||
self.device_flags = info.flags.clone();
|
||||
}
|
||||
HeaderMsg::ThemeSelected(theme) => {
|
||||
styles::apply_theme(theme).expect("Could not apply theme");
|
||||
|
||||
CONFIG.write().edit(|config| {
|
||||
config.theme = theme;
|
||||
});
|
||||
}
|
||||
}
|
||||
self.update_label();
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
.page-section-content {
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.page-section-children-box {
|
||||
margin: 10px;
|
||||
}
|
||||
}
|
||||
@@ -97,9 +97,7 @@ mod imp {
|
||||
#[local_ref]
|
||||
append = content_box {
|
||||
set_orientation: gtk::Orientation::Vertical,
|
||||
add_css_class: if cfg!(feature = "adw") { css::CARD } else { "page-section-content" },
|
||||
#[watch]
|
||||
add_css_class: if cfg!(feature = "adw") { "" } else { css::FRAME },
|
||||
add_css_class: css::CARD,
|
||||
|
||||
#[local_ref]
|
||||
append = children_box {
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
.clocks-frame > .page-section-content {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.clocks-frame .page-section-children-box {
|
||||
margin: 0;
|
||||
}
|
||||
@@ -13,5 +9,4 @@
|
||||
.clocks-frame-group .frame {
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,84 @@
|
||||
use gtk::{
|
||||
gio::{self, prelude::SettingsExt},
|
||||
style_context_add_provider_for_display, style_context_remove_provider_for_display,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cell::RefCell;
|
||||
|
||||
pub const COMBINED_CSS: &str = include_str!(concat!(env!("OUT_DIR"), "/combined.css"));
|
||||
|
||||
macro_rules! include_theme_str {
|
||||
($file:literal) => {
|
||||
include_str!(concat!(
|
||||
concat!(env!("CARGO_MANIFEST_DIR"), "/themes/",),
|
||||
$file
|
||||
))
|
||||
};
|
||||
}
|
||||
|
||||
const BREEZE_DARK_CSS: &str = include_theme_str!("breeze-dark.css");
|
||||
const BREEZE_LIGHT_CSS: &str = include_theme_str!("breeze-light.css");
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum AppTheme {
|
||||
#[default]
|
||||
Automatic,
|
||||
Adwaita,
|
||||
Breeze,
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static EXISTING_STYLE_PROVIDER: RefCell<Option<gtk::CssProvider>> = const { RefCell::new(None) };
|
||||
}
|
||||
|
||||
pub fn apply_theme(theme: AppTheme) -> anyhow::Result<()> {
|
||||
let display = gtk::gdk::Display::default().unwrap();
|
||||
|
||||
if let Some(existing_style_provider) = EXISTING_STYLE_PROVIDER.take() {
|
||||
style_context_remove_provider_for_display(&display, &existing_style_provider);
|
||||
}
|
||||
|
||||
let theme_css = match theme {
|
||||
AppTheme::Automatic => {
|
||||
let settings = gio::Settings::new("org.gnome.desktop.interface");
|
||||
let system_theme = settings.string("gtk-theme").to_ascii_lowercase();
|
||||
|
||||
if matches!(
|
||||
system_theme.as_str(),
|
||||
"breeze" | "breeze-light" | "breeze-dark"
|
||||
) {
|
||||
Some(breeze_css())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
AppTheme::Adwaita => None,
|
||||
AppTheme::Breeze => Some(breeze_css()),
|
||||
};
|
||||
|
||||
if let Some(css) = theme_css {
|
||||
let provider = gtk::CssProvider::new();
|
||||
#[allow(deprecated)]
|
||||
provider.load_from_data(css);
|
||||
|
||||
style_context_add_provider_for_display(&display, &provider, 900);
|
||||
|
||||
EXISTING_STYLE_PROVIDER.set(Some(provider));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn breeze_css() -> &'static str {
|
||||
let settings = gio::Settings::new("org.gnome.desktop.interface");
|
||||
match settings.string("color-scheme").as_str() {
|
||||
"prefer-dark" => BREEZE_DARK_CSS,
|
||||
"prefer-light" => BREEZE_LIGHT_CSS,
|
||||
_ => BREEZE_LIGHT_CSS,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
use crate::app::graphs_window::stat::StatType;
|
||||
use crate::app::{graphs_window::stat::StatType, styles::AppTheme};
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use serde_with::skip_serializing_none;
|
||||
use std::{collections::HashMap, env, fs, path::PathBuf};
|
||||
use tracing::{debug, error};
|
||||
|
||||
pub const MIN_STATS_POLL_INTERVAL_MS: i64 = 250;
|
||||
pub const MAX_STATS_POLL_INTERVAL_MS: i64 = 5000;
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct UiConfig {
|
||||
#[serde(default = "default_tab")]
|
||||
pub selected_tab: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub selected_gpu: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub plots_time_period: Option<u64>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub plots_per_row: Option<u64>,
|
||||
#[serde(
|
||||
default = "default_stats_poll_interval",
|
||||
@@ -23,6 +22,8 @@ pub struct UiConfig {
|
||||
pub stats_poll_interval_ms: i64,
|
||||
#[serde(default)]
|
||||
pub gpus: HashMap<String, UiGpuConfig>,
|
||||
#[serde(default)]
|
||||
pub theme: AppTheme,
|
||||
}
|
||||
|
||||
impl Default for UiConfig {
|
||||
@@ -34,6 +35,7 @@ impl Default for UiConfig {
|
||||
plots_per_row: None,
|
||||
stats_poll_interval_ms: default_stats_poll_interval(),
|
||||
gpus: HashMap::new(),
|
||||
theme: AppTheme::Automatic,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,509 @@
|
||||
/*
|
||||
* Breeze Dark color theme
|
||||
* Extracted from KDE Breeze-Dark GTK 4.0 theme
|
||||
* Only color properties — layout is left to libadwaita
|
||||
*/
|
||||
|
||||
/* ===================
|
||||
* Breeze color palette
|
||||
* =================== */
|
||||
|
||||
/* Foreground / text */
|
||||
@define-color theme_fg_color_breeze #fcfcfc;
|
||||
@define-color theme_text_color_breeze #fcfcfc;
|
||||
|
||||
/* Backgrounds */
|
||||
@define-color theme_bg_color_breeze #202326;
|
||||
@define-color theme_base_color_breeze #141618;
|
||||
@define-color content_view_bg_breeze #141618;
|
||||
|
||||
/* Selection / accent */
|
||||
@define-color theme_selected_bg_color_breeze #3daee9;
|
||||
@define-color theme_selected_fg_color_breeze #fcfcfc;
|
||||
@define-color theme_hovering_selected_bg_color_breeze #3daee9;
|
||||
@define-color theme_view_hover_decoration_color_breeze #3daee9;
|
||||
@define-color theme_view_active_decoration_color_breeze #3daee9;
|
||||
|
||||
/* Insensitive */
|
||||
@define-color insensitive_bg_color_breeze #1d2023;
|
||||
@define-color insensitive_fg_color_breeze rgba(229, 229, 229, 0.35);
|
||||
@define-color insensitive_base_color_breeze rgba(229, 229, 229, 0.35);
|
||||
@define-color insensitive_base_fg_color_breeze #121416;
|
||||
@define-color insensitive_selected_bg_color_breeze rgba(37, 164, 230, 0.35);
|
||||
@define-color insensitive_selected_fg_color_breeze rgba(229, 229, 229, 0.35);
|
||||
|
||||
/* Unfocused / backdrop */
|
||||
@define-color theme_unfocused_fg_color_breeze #fcfcfc;
|
||||
@define-color theme_unfocused_text_color_breeze #fcfcfc;
|
||||
@define-color theme_unfocused_bg_color_breeze #202326;
|
||||
@define-color theme_unfocused_base_color_breeze #141618;
|
||||
@define-color theme_unfocused_selected_bg_color_alt_breeze #3daee9;
|
||||
@define-color theme_unfocused_selected_bg_color_breeze rgba(61, 174, 233, 0.5);
|
||||
@define-color theme_unfocused_selected_fg_color_breeze #fcfcfc;
|
||||
@define-color theme_unfocused_view_text_color_breeze rgba(229, 229, 229, 0.35);
|
||||
@define-color theme_unfocused_view_bg_color_breeze #121416;
|
||||
@define-color insensitive_unfocused_selected_bg_color_breeze rgba(37, 164, 230, 0.35);
|
||||
@define-color insensitive_unfocused_fg_color_breeze rgba(229, 229, 229, 0.35);
|
||||
@define-color insensitive_unfocused_bg_color_breeze #1d2023;
|
||||
@define-color insensitive_unfocused_selected_fg_color_breeze rgba(229, 229, 229, 0.35);
|
||||
|
||||
/* Borders */
|
||||
@define-color borders_breeze #4c4e51;
|
||||
@define-color unfocused_borders_breeze #4c4e51;
|
||||
@define-color insensitive_borders_breeze rgba(69, 71, 74, 0.35);
|
||||
@define-color unfocused_insensitive_borders_breeze rgba(69, 71, 74, 0.35);
|
||||
|
||||
/* Buttons */
|
||||
@define-color theme_button_background_normal_breeze #292c30;
|
||||
@define-color theme_button_decoration_hover_breeze #3daee9;
|
||||
@define-color theme_button_decoration_focus_breeze #3daee9;
|
||||
@define-color theme_button_foreground_normal_breeze #fcfcfc;
|
||||
@define-color theme_button_foreground_active_breeze #fcfcfc;
|
||||
@define-color theme_button_background_insensitive_breeze rgba(37, 40, 44, 0.35);
|
||||
@define-color theme_button_decoration_hover_insensitive_breeze rgba(37, 164, 230, 0.35);
|
||||
@define-color theme_button_decoration_focus_insensitive_breeze rgba(37, 164, 230, 0.35);
|
||||
@define-color theme_button_foreground_insensitive_breeze rgba(229, 229, 229, 0.35);
|
||||
@define-color theme_button_foreground_active_insensitive_breeze rgba(229, 229, 229, 0.35);
|
||||
@define-color theme_button_background_backdrop_breeze #292c30;
|
||||
@define-color theme_button_decoration_hover_backdrop_breeze #3daee9;
|
||||
@define-color theme_button_decoration_focus_backdrop_breeze #3daee9;
|
||||
@define-color theme_button_foreground_backdrop_breeze #fcfcfc;
|
||||
@define-color theme_button_foreground_active_backdrop_breeze #fcfcfc;
|
||||
@define-color theme_button_background_backdrop_insensitive_breeze rgba(37, 40, 44, 0.35);
|
||||
@define-color theme_button_decoration_hover_backdrop_insensitive_breeze rgba(37, 164, 230, 0.35);
|
||||
@define-color theme_button_decoration_focus_backdrop_insensitive_breeze rgba(37, 164, 230, 0.35);
|
||||
@define-color theme_button_foreground_backdrop_insensitive_breeze rgba(229, 229, 229, 0.35);
|
||||
@define-color theme_button_foreground_active_backdrop_insensitive_breeze rgba(229, 229, 229, 0.35);
|
||||
|
||||
/* Status colors */
|
||||
@define-color warning_color_breeze #f67400;
|
||||
@define-color error_color_breeze #da4453;
|
||||
@define-color success_color_breeze #27ae60;
|
||||
@define-color warning_color_backdrop_breeze #f67400;
|
||||
@define-color error_color_backdrop_breeze #da4453;
|
||||
@define-color success_color_backdrop_breeze #27ae60;
|
||||
@define-color warning_color_insensitive_breeze rgba(224, 105, 0, 0.35);
|
||||
@define-color error_color_insensitive_breeze rgba(214, 46, 63, 0.35);
|
||||
@define-color success_color_insensitive_breeze rgba(35, 158, 87, 0.35);
|
||||
@define-color warning_color_insensitive_backdrop_breeze rgba(224, 105, 0, 0.35);
|
||||
@define-color error_color_insensitive_backdrop_breeze rgba(214, 46, 63, 0.35);
|
||||
@define-color success_color_insensitive_backdrop_breeze rgba(35, 158, 87, 0.35);
|
||||
|
||||
/* Links */
|
||||
@define-color link_color_breeze #1d99f3;
|
||||
@define-color link_visited_color_breeze #9b59b6;
|
||||
|
||||
/* Titlebar */
|
||||
@define-color theme_titlebar_background_breeze #272c31;
|
||||
@define-color theme_titlebar_foreground_breeze #fcfcfc;
|
||||
@define-color theme_titlebar_background_light_breeze #202326;
|
||||
@define-color theme_titlebar_foreground_backdrop_breeze #a1a9b1;
|
||||
@define-color theme_titlebar_background_backdrop_breeze #202428;
|
||||
@define-color theme_titlebar_foreground_insensitive_breeze rgba(229, 229, 229, 0.35);
|
||||
@define-color theme_titlebar_foreground_insensitive_backdrop_breeze rgba(144, 154, 163, 0.35);
|
||||
|
||||
/* Tooltips */
|
||||
@define-color tooltip_text_breeze #fcfcfc;
|
||||
@define-color tooltip_background_breeze #292c30;
|
||||
@define-color tooltip_border_breeze #535659;
|
||||
|
||||
|
||||
/* ==============================
|
||||
* libadwaita color overrides
|
||||
* ============================== */
|
||||
|
||||
/* Accent — Breeze KDE blue */
|
||||
@define-color accent_bg_color @theme_selected_bg_color_breeze;
|
||||
@define-color accent_fg_color @theme_selected_fg_color_breeze;
|
||||
@define-color accent_color @theme_selected_bg_color_breeze;
|
||||
|
||||
/* Window */
|
||||
@define-color window_bg_color @theme_bg_color_breeze;
|
||||
@define-color window_fg_color @theme_fg_color_breeze;
|
||||
|
||||
/* Views / content areas */
|
||||
@define-color view_bg_color @theme_base_color_breeze;
|
||||
@define-color view_fg_color @theme_text_color_breeze;
|
||||
|
||||
/* Headerbar */
|
||||
@define-color headerbar_bg_color @theme_titlebar_background_breeze;
|
||||
@define-color headerbar_fg_color @theme_titlebar_foreground_breeze;
|
||||
@define-color headerbar_border_color @theme_titlebar_foreground_breeze;
|
||||
@define-color headerbar_backdrop_color @theme_titlebar_background_backdrop_breeze;
|
||||
@define-color headerbar_shade_color rgba(0, 0, 0, 0.36);
|
||||
@define-color headerbar_darker_shade_color rgba(0, 0, 0, 0.9);
|
||||
|
||||
/* Sidebar */
|
||||
@define-color sidebar_bg_color @theme_button_background_normal_breeze;
|
||||
@define-color sidebar_fg_color @theme_fg_color_breeze;
|
||||
@define-color sidebar_backdrop_color #252830;
|
||||
@define-color sidebar_shade_color rgba(0, 0, 0, 0.25);
|
||||
@define-color sidebar_border_color rgba(0, 0, 0, 0.36);
|
||||
|
||||
/* Secondary sidebar */
|
||||
@define-color secondary_sidebar_bg_color #252830;
|
||||
@define-color secondary_sidebar_fg_color @theme_fg_color_breeze;
|
||||
@define-color secondary_sidebar_backdrop_color @theme_bg_color_breeze;
|
||||
@define-color secondary_sidebar_shade_color rgba(0, 0, 0, 0.25);
|
||||
@define-color secondary_sidebar_border_color rgba(0, 0, 0, 0.36);
|
||||
|
||||
/* Cards */
|
||||
@define-color card_bg_color rgba(255, 255, 255, 0.05);
|
||||
@define-color card_fg_color @theme_fg_color_breeze;
|
||||
@define-color card_shade_color rgba(0, 0, 0, 0.36);
|
||||
|
||||
/* Dialogs & popovers */
|
||||
@define-color dialog_bg_color @theme_button_background_normal_breeze;
|
||||
@define-color dialog_fg_color @theme_fg_color_breeze;
|
||||
@define-color popover_bg_color @theme_button_background_normal_breeze;
|
||||
@define-color popover_fg_color @theme_fg_color_breeze;
|
||||
@define-color popover_shade_color rgba(0, 0, 0, 0.25);
|
||||
|
||||
/* Thumbnails */
|
||||
@define-color thumbnail_bg_color #303338;
|
||||
@define-color thumbnail_fg_color @theme_fg_color_breeze;
|
||||
|
||||
/* Misc */
|
||||
@define-color shade_color rgba(0, 0, 0, 0.25);
|
||||
@define-color scrollbar_outline_color rgba(0, 0, 0, 0.5);
|
||||
|
||||
/* Status colors — libadwaita */
|
||||
@define-color destructive_bg_color @error_color_breeze;
|
||||
@define-color destructive_fg_color white;
|
||||
@define-color destructive_color @error_color_breeze;
|
||||
@define-color success_bg_color @success_color_breeze;
|
||||
@define-color success_fg_color white;
|
||||
@define-color success_color @success_color_breeze;
|
||||
@define-color warning_bg_color @warning_color_breeze;
|
||||
@define-color warning_fg_color white;
|
||||
@define-color warning_color @warning_color_breeze;
|
||||
@define-color error_bg_color @error_color_breeze;
|
||||
@define-color error_fg_color white;
|
||||
@define-color error_color @error_color_breeze;
|
||||
|
||||
|
||||
/* ==============================
|
||||
* GTK standard color aliases
|
||||
* ============================== */
|
||||
|
||||
@define-color theme_fg_color @theme_fg_color_breeze;
|
||||
@define-color theme_text_color @theme_text_color_breeze;
|
||||
@define-color theme_bg_color @theme_bg_color_breeze;
|
||||
@define-color theme_base_color @theme_base_color_breeze;
|
||||
@define-color theme_selected_bg_color @theme_selected_bg_color_breeze;
|
||||
@define-color theme_selected_fg_color @theme_selected_fg_color_breeze;
|
||||
@define-color insensitive_bg_color @insensitive_bg_color_breeze;
|
||||
@define-color insensitive_fg_color @insensitive_fg_color_breeze;
|
||||
@define-color insensitive_base_color @insensitive_base_color_breeze;
|
||||
@define-color theme_unfocused_fg_color @theme_unfocused_fg_color_breeze;
|
||||
@define-color theme_unfocused_text_color @theme_unfocused_text_color_breeze;
|
||||
@define-color theme_unfocused_bg_color @theme_unfocused_bg_color_breeze;
|
||||
@define-color theme_unfocused_base_color @theme_unfocused_base_color_breeze;
|
||||
@define-color theme_unfocused_selected_bg_color @theme_unfocused_selected_bg_color_breeze;
|
||||
@define-color theme_unfocused_selected_fg_color @theme_unfocused_selected_fg_color_breeze;
|
||||
@define-color unfocused_insensitive_color @insensitive_unfocused_bg_color_breeze;
|
||||
@define-color borders @borders_breeze;
|
||||
@define-color unfocused_borders @unfocused_borders_breeze;
|
||||
@define-color content_view_bg @content_view_bg_breeze;
|
||||
@define-color text_view_bg @content_view_bg_breeze;
|
||||
|
||||
|
||||
/* ==============================
|
||||
* Button shapes & colors
|
||||
* ============================== */
|
||||
|
||||
/* --- Regular buttons --- */
|
||||
|
||||
button {
|
||||
border-radius: 3px;
|
||||
outline: 1px solid @borders_breeze;
|
||||
outline-offset: -1px;
|
||||
background: @theme_button_background_normal_breeze;
|
||||
color: @theme_button_foreground_normal_breeze;
|
||||
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.125);
|
||||
text-shadow: none;
|
||||
-gtk-icon-shadow: none;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
outline-color: @theme_button_decoration_hover_breeze;
|
||||
}
|
||||
|
||||
button:active {
|
||||
box-shadow: none;
|
||||
background: alpha(@theme_button_decoration_hover_breeze, 0.333);
|
||||
}
|
||||
|
||||
button:checked {
|
||||
background: alpha(@theme_button_foreground_normal_breeze, 0.125);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
button:focus {
|
||||
outline-color: @theme_button_decoration_focus_breeze;
|
||||
}
|
||||
|
||||
button:backdrop {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
box-shadow: none;
|
||||
color: @theme_button_foreground_insensitive_breeze;
|
||||
outline-color: @insensitive_borders_breeze;
|
||||
background: @theme_button_background_insensitive_breeze;
|
||||
}
|
||||
|
||||
button:disabled:active,
|
||||
button:disabled:checked {
|
||||
color: @theme_button_foreground_active_insensitive_breeze;
|
||||
}
|
||||
|
||||
/* --- Suggested & destructive: subtle tint instead of solid fill --- */
|
||||
|
||||
button.suggested-action,
|
||||
button.flat.suggested-action {
|
||||
background-color: alpha(@theme_button_decoration_focus_breeze, 0.2);
|
||||
outline-color: mix(@theme_button_decoration_focus_breeze,
|
||||
mix(@theme_button_background_normal_breeze,
|
||||
@theme_button_foreground_normal_breeze, 0.333), 0.5);
|
||||
}
|
||||
|
||||
button.destructive-action,
|
||||
button.flat.destructive-action {
|
||||
background-color: alpha(@error_color_breeze, 0.2);
|
||||
outline-color: mix(@error_color_breeze,
|
||||
mix(@theme_button_background_normal_breeze,
|
||||
@theme_button_foreground_normal_breeze, 0.333), 0.5);
|
||||
}
|
||||
|
||||
button.suggested-action:hover {
|
||||
background-color: alpha(@theme_button_decoration_focus_breeze, 0.35);
|
||||
outline-color: @theme_button_decoration_focus_breeze;
|
||||
}
|
||||
|
||||
button.destructive-action:hover {
|
||||
background-color: alpha(@error_color_breeze, 0.35);
|
||||
outline-color: @error_color_breeze;
|
||||
}
|
||||
|
||||
button.suggested-action:active {
|
||||
background-color: alpha(@theme_button_decoration_focus_breeze, 0.5);
|
||||
}
|
||||
|
||||
button.destructive-action:active {
|
||||
background-color: alpha(@error_color_breeze, 0.5);
|
||||
}
|
||||
|
||||
/* --- Flat buttons --- */
|
||||
|
||||
button.flat {
|
||||
outline-color: transparent;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
button.flat:checked {
|
||||
outline-color: mix(@theme_button_background_normal_breeze,
|
||||
@theme_button_foreground_normal_breeze, 0.3);
|
||||
background-color: alpha(@theme_button_foreground_normal_breeze, 0.125);
|
||||
}
|
||||
|
||||
button.flat:hover {
|
||||
outline-color: @theme_button_decoration_hover_breeze;
|
||||
}
|
||||
|
||||
button.flat:active {
|
||||
outline-color: @theme_button_decoration_hover_breeze;
|
||||
background-color: alpha(@theme_button_decoration_hover_breeze, 0.333);
|
||||
}
|
||||
|
||||
/* --- Circular buttons --- */
|
||||
|
||||
button.circular {
|
||||
border-radius: 9999px;
|
||||
}
|
||||
|
||||
/* --- Headerbar buttons (flat by default, like Breeze) --- */
|
||||
|
||||
headerbar button:not(.suggested-action):not(.destructive-action) {
|
||||
outline-color: transparent;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
color: @theme_titlebar_foreground_breeze;
|
||||
}
|
||||
|
||||
headerbar button:not(.suggested-action):not(.destructive-action):checked {
|
||||
outline-color: mix(@theme_button_background_normal_breeze,
|
||||
@theme_button_foreground_normal_breeze, 0.3);
|
||||
background-color: alpha(@theme_button_foreground_normal_breeze, 0.125);
|
||||
}
|
||||
|
||||
headerbar button:not(.suggested-action):not(.destructive-action):hover {
|
||||
outline-color: @theme_button_decoration_hover_breeze;
|
||||
color: @theme_titlebar_foreground_breeze;
|
||||
background-color: alpha(@theme_button_foreground_normal_breeze, 0.08);
|
||||
}
|
||||
|
||||
headerbar button:not(.suggested-action):not(.destructive-action):active {
|
||||
outline-color: @theme_button_decoration_hover_breeze;
|
||||
background-color: alpha(@theme_button_decoration_hover_breeze, 0.333);
|
||||
}
|
||||
|
||||
headerbar button:not(.suggested-action):not(.destructive-action):focus {
|
||||
outline-color: @theme_button_decoration_focus_breeze;
|
||||
}
|
||||
|
||||
headerbar button:not(.suggested-action):not(.destructive-action):backdrop {
|
||||
color: @theme_titlebar_foreground_backdrop_breeze;
|
||||
}
|
||||
|
||||
headerbar button:not(.suggested-action):not(.destructive-action):backdrop:checked {
|
||||
outline-color: mix(@theme_button_background_normal_breeze,
|
||||
@theme_button_foreground_normal_breeze, 0.3);
|
||||
background-color: alpha(@theme_button_foreground_normal_breeze, 0.125);
|
||||
}
|
||||
|
||||
headerbar button:not(.suggested-action):not(.destructive-action):disabled {
|
||||
color: @theme_titlebar_foreground_insensitive_breeze;
|
||||
}
|
||||
|
||||
/* Headerbar tab buttons (stack switcher) — visible so they look interactive */
|
||||
|
||||
headerbar stackswitcher button:not(.suggested-action):not(.destructive-action):not(:checked) {
|
||||
outline-color: alpha(@borders_breeze, 0.6);
|
||||
background-color: alpha(@theme_button_foreground_normal_breeze, 0.06);
|
||||
}
|
||||
|
||||
headerbar stackswitcher button:not(.suggested-action):not(.destructive-action):not(:checked):hover {
|
||||
outline-color: @theme_button_decoration_hover_breeze;
|
||||
background-color: alpha(@theme_button_foreground_normal_breeze, 0.08);
|
||||
}
|
||||
|
||||
/* Headerbar linked buttons — restore regular button look */
|
||||
|
||||
headerbar .linked button {
|
||||
color: @theme_button_foreground_normal_breeze;
|
||||
outline-color: @borders_breeze;
|
||||
background: @theme_button_background_normal_breeze;
|
||||
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.125);
|
||||
}
|
||||
|
||||
/* --- SpinButton +/- buttons: flat, only icon colour changes on disable --- */
|
||||
|
||||
spinbutton:not(.vertical) button,
|
||||
spinbutton:not(.vertical) button:disabled {
|
||||
background: transparent;
|
||||
outline-color: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
spinbutton:not(.vertical) button:hover {
|
||||
color: @theme_view_hover_decoration_color_breeze;
|
||||
}
|
||||
|
||||
spinbutton:not(.vertical) button:active {
|
||||
background: alpha(@theme_button_decoration_hover_breeze, 0.333);
|
||||
}
|
||||
|
||||
spinbutton:not(.vertical) button:disabled {
|
||||
color: @theme_button_foreground_insensitive_breeze;
|
||||
}
|
||||
|
||||
/* --- Check & radio indicators --- */
|
||||
|
||||
check,
|
||||
radio {
|
||||
background-color: @theme_base_color_breeze;
|
||||
outline: 1px solid alpha(@theme_button_foreground_normal_breeze, 0.333);
|
||||
outline-offset: -1px;
|
||||
-gtk-icon-shadow: none;
|
||||
}
|
||||
|
||||
check {
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
radio {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
check:hover,
|
||||
radio:hover {
|
||||
outline-color: @theme_button_decoration_hover_breeze;
|
||||
}
|
||||
|
||||
check:focus,
|
||||
radio:focus {
|
||||
outline-color: @theme_button_decoration_focus_breeze;
|
||||
}
|
||||
|
||||
check:checked,
|
||||
check:indeterminate,
|
||||
radio:checked,
|
||||
radio:indeterminate {
|
||||
outline-color: @theme_button_decoration_hover_breeze;
|
||||
background-color: alpha(@theme_button_decoration_hover_breeze, 0.333);
|
||||
}
|
||||
|
||||
check:disabled,
|
||||
radio:disabled {
|
||||
background-color: alpha(@theme_base_color_breeze, 0.03);
|
||||
outline-color: alpha(@theme_button_foreground_normal_breeze, 0.222);
|
||||
}
|
||||
|
||||
check:checked:disabled,
|
||||
check:indeterminate:disabled,
|
||||
radio:checked:disabled,
|
||||
radio:indeterminate:disabled {
|
||||
background-color: alpha(@theme_button_foreground_normal_breeze, 0.03);
|
||||
outline-color: alpha(@theme_button_decoration_hover_breeze, 0.3);
|
||||
}
|
||||
|
||||
/* --- Switch --- */
|
||||
|
||||
switch {
|
||||
outline: 1px solid alpha(@theme_button_foreground_normal_breeze, 0.222);
|
||||
outline-offset: -1px;
|
||||
border-radius: 12px;
|
||||
background-color: alpha(@theme_button_foreground_normal_breeze, 0.05);
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
switch:checked {
|
||||
background: alpha(@theme_button_decoration_hover_breeze, 0.333);
|
||||
outline-color: @theme_button_decoration_hover_breeze;
|
||||
}
|
||||
|
||||
switch:disabled {
|
||||
background-color: alpha(@theme_button_foreground_normal_breeze, 0.03);
|
||||
}
|
||||
|
||||
switch:checked:disabled {
|
||||
background: alpha(@theme_button_decoration_hover_breeze, 0.222);
|
||||
outline-color: alpha(@theme_button_decoration_hover_breeze, 0.777);
|
||||
}
|
||||
|
||||
switch slider {
|
||||
outline: 1px solid @borders_breeze;
|
||||
outline-offset: -1px;
|
||||
border-radius: 12px;
|
||||
background: @theme_button_background_normal_breeze;
|
||||
box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.125);
|
||||
}
|
||||
|
||||
switch:hover slider {
|
||||
outline-color: @theme_button_decoration_hover_breeze;
|
||||
}
|
||||
|
||||
switch:focus slider {
|
||||
outline-color: @theme_button_decoration_focus_breeze;
|
||||
}
|
||||
|
||||
switch:disabled slider {
|
||||
box-shadow: none;
|
||||
color: @theme_button_foreground_insensitive_breeze;
|
||||
outline-color: @insensitive_borders_breeze;
|
||||
background: @theme_button_background_insensitive_breeze;
|
||||
}
|
||||
@@ -0,0 +1,509 @@
|
||||
/*
|
||||
* Breeze Light color theme
|
||||
* Extracted from KDE Breeze GTK 4.0 theme
|
||||
* Only color properties — layout is left to libadwaita
|
||||
*/
|
||||
|
||||
/* ===================
|
||||
* Breeze color palette
|
||||
* =================== */
|
||||
|
||||
/* Foreground / text */
|
||||
@define-color theme_fg_color_breeze #232629;
|
||||
@define-color theme_text_color_breeze #232629;
|
||||
|
||||
/* Backgrounds */
|
||||
@define-color theme_bg_color_breeze #eff0f1;
|
||||
@define-color theme_base_color_breeze white;
|
||||
@define-color content_view_bg_breeze white;
|
||||
|
||||
/* Selection / accent */
|
||||
@define-color theme_selected_bg_color_breeze #3daee9;
|
||||
@define-color theme_selected_fg_color_breeze white;
|
||||
@define-color theme_hovering_selected_bg_color_breeze #3daee9;
|
||||
@define-color theme_view_hover_decoration_color_breeze #3daee9;
|
||||
@define-color theme_view_active_decoration_color_breeze #3daee9;
|
||||
|
||||
/* Insensitive */
|
||||
@define-color insensitive_bg_color_breeze #d8dadd;
|
||||
@define-color insensitive_fg_color_breeze rgba(32, 35, 37, 0.35);
|
||||
@define-color insensitive_base_color_breeze rgba(32, 35, 37, 0.35);
|
||||
@define-color insensitive_base_fg_color_breeze #e8e8e8;
|
||||
@define-color insensitive_selected_bg_color_breeze rgba(37, 164, 230, 0.35);
|
||||
@define-color insensitive_selected_fg_color_breeze #e8e8e8;
|
||||
|
||||
/* Unfocused / backdrop */
|
||||
@define-color theme_unfocused_fg_color_breeze #232629;
|
||||
@define-color theme_unfocused_text_color_breeze #232629;
|
||||
@define-color theme_unfocused_bg_color_breeze #eff0f1;
|
||||
@define-color theme_unfocused_base_color_breeze white;
|
||||
@define-color theme_unfocused_selected_bg_color_alt_breeze #3daee9;
|
||||
@define-color theme_unfocused_selected_bg_color_breeze rgba(61, 174, 233, 0.5);
|
||||
@define-color theme_unfocused_selected_fg_color_breeze white;
|
||||
@define-color theme_unfocused_view_text_color_breeze rgba(32, 35, 37, 0.35);
|
||||
@define-color theme_unfocused_view_bg_color_breeze #e8e8e8;
|
||||
@define-color insensitive_unfocused_selected_bg_color_breeze rgba(37, 164, 230, 0.35);
|
||||
@define-color insensitive_unfocused_fg_color_breeze rgba(32, 35, 37, 0.35);
|
||||
@define-color insensitive_unfocused_bg_color_breeze #d8dadd;
|
||||
@define-color insensitive_unfocused_selected_fg_color_breeze #e8e8e8;
|
||||
|
||||
/* Borders */
|
||||
@define-color borders_breeze #c6c8c9;
|
||||
@define-color unfocused_borders_breeze #c6c8c9;
|
||||
@define-color insensitive_borders_breeze rgba(179, 182, 183, 0.35);
|
||||
@define-color unfocused_insensitive_borders_breeze rgba(179, 182, 183, 0.35);
|
||||
|
||||
/* Buttons */
|
||||
@define-color theme_button_background_normal_breeze #fcfcfc;
|
||||
@define-color theme_button_decoration_hover_breeze #3daee9;
|
||||
@define-color theme_button_decoration_focus_breeze #3daee9;
|
||||
@define-color theme_button_foreground_normal_breeze #232629;
|
||||
@define-color theme_button_foreground_active_breeze white;
|
||||
@define-color theme_button_background_insensitive_breeze #e5e5e5;
|
||||
@define-color theme_button_decoration_hover_insensitive_breeze rgba(37, 164, 230, 0.35);
|
||||
@define-color theme_button_decoration_focus_insensitive_breeze rgba(37, 164, 230, 0.35);
|
||||
@define-color theme_button_foreground_insensitive_breeze rgba(32, 35, 37, 0.35);
|
||||
@define-color theme_button_foreground_active_insensitive_breeze #e8e8e8;
|
||||
@define-color theme_button_background_backdrop_breeze #fcfcfc;
|
||||
@define-color theme_button_decoration_hover_backdrop_breeze #3daee9;
|
||||
@define-color theme_button_decoration_focus_backdrop_breeze #3daee9;
|
||||
@define-color theme_button_foreground_backdrop_breeze #232629;
|
||||
@define-color theme_button_foreground_active_backdrop_breeze white;
|
||||
@define-color theme_button_background_backdrop_insensitive_breeze #e5e5e5;
|
||||
@define-color theme_button_decoration_hover_backdrop_insensitive_breeze rgba(37, 164, 230, 0.35);
|
||||
@define-color theme_button_decoration_focus_backdrop_insensitive_breeze rgba(37, 164, 230, 0.35);
|
||||
@define-color theme_button_foreground_backdrop_insensitive_breeze rgba(32, 35, 37, 0.35);
|
||||
@define-color theme_button_foreground_active_backdrop_insensitive_breeze #e8e8e8;
|
||||
|
||||
/* Status colors */
|
||||
@define-color warning_color_breeze #f67400;
|
||||
@define-color error_color_breeze #da4453;
|
||||
@define-color success_color_breeze #27ae60;
|
||||
@define-color warning_color_backdrop_breeze #f67400;
|
||||
@define-color error_color_backdrop_breeze #da4453;
|
||||
@define-color success_color_backdrop_breeze #27ae60;
|
||||
@define-color warning_color_insensitive_breeze rgba(224, 105, 0, 0.35);
|
||||
@define-color error_color_insensitive_breeze rgba(214, 46, 63, 0.35);
|
||||
@define-color success_color_insensitive_breeze rgba(35, 158, 87, 0.35);
|
||||
@define-color warning_color_insensitive_backdrop_breeze rgba(224, 105, 0, 0.35);
|
||||
@define-color error_color_insensitive_backdrop_breeze rgba(214, 46, 63, 0.35);
|
||||
@define-color success_color_insensitive_backdrop_breeze rgba(35, 158, 87, 0.35);
|
||||
|
||||
/* Links */
|
||||
@define-color link_color_breeze #2980b9;
|
||||
@define-color link_visited_color_breeze #9b59b6;
|
||||
|
||||
/* Titlebar */
|
||||
@define-color theme_titlebar_background_breeze #e3e5e7;
|
||||
@define-color theme_titlebar_foreground_breeze #232629;
|
||||
@define-color theme_titlebar_background_light_breeze #eff0f1;
|
||||
@define-color theme_titlebar_foreground_backdrop_breeze #707d8a;
|
||||
@define-color theme_titlebar_background_backdrop_breeze #eff0f1;
|
||||
@define-color theme_titlebar_foreground_insensitive_breeze rgba(32, 35, 37, 0.35);
|
||||
@define-color theme_titlebar_foreground_insensitive_backdrop_breeze rgba(102, 114, 125, 0.35);
|
||||
|
||||
/* Tooltips */
|
||||
@define-color tooltip_text_breeze #232629;
|
||||
@define-color tooltip_background_breeze #f7f7f7;
|
||||
@define-color tooltip_border_breeze #cdcdce;
|
||||
|
||||
|
||||
/* ==============================
|
||||
* libadwaita color overrides
|
||||
* ============================== */
|
||||
|
||||
/* Accent — Breeze KDE blue */
|
||||
@define-color accent_bg_color @theme_selected_bg_color_breeze;
|
||||
@define-color accent_fg_color @theme_selected_fg_color_breeze;
|
||||
@define-color accent_color @theme_selected_bg_color_breeze;
|
||||
|
||||
/* Window */
|
||||
@define-color window_bg_color @theme_bg_color_breeze;
|
||||
@define-color window_fg_color @theme_fg_color_breeze;
|
||||
|
||||
/* Views / content areas */
|
||||
@define-color view_bg_color @theme_base_color_breeze;
|
||||
@define-color view_fg_color @theme_text_color_breeze;
|
||||
|
||||
/* Headerbar */
|
||||
@define-color headerbar_bg_color @theme_titlebar_background_breeze;
|
||||
@define-color headerbar_fg_color @theme_titlebar_foreground_breeze;
|
||||
@define-color headerbar_border_color @theme_titlebar_foreground_breeze;
|
||||
@define-color headerbar_backdrop_color @theme_titlebar_background_backdrop_breeze;
|
||||
@define-color headerbar_shade_color rgba(0, 0, 0, 0.07);
|
||||
@define-color headerbar_darker_shade_color rgba(0, 0, 0, 0.07);
|
||||
|
||||
/* Sidebar */
|
||||
@define-color sidebar_bg_color #e3e5e7;
|
||||
@define-color sidebar_fg_color @theme_fg_color_breeze;
|
||||
@define-color sidebar_backdrop_color #eaebec;
|
||||
@define-color sidebar_shade_color rgba(0, 0, 0, 0.07);
|
||||
@define-color sidebar_border_color rgba(0, 0, 0, 0.07);
|
||||
|
||||
/* Secondary sidebar */
|
||||
@define-color secondary_sidebar_bg_color #eaebec;
|
||||
@define-color secondary_sidebar_fg_color @theme_fg_color_breeze;
|
||||
@define-color secondary_sidebar_backdrop_color @theme_bg_color_breeze;
|
||||
@define-color secondary_sidebar_shade_color rgba(0, 0, 0, 0.07);
|
||||
@define-color secondary_sidebar_border_color rgba(0, 0, 0, 0.07);
|
||||
|
||||
/* Cards */
|
||||
@define-color card_bg_color white;
|
||||
@define-color card_fg_color @theme_fg_color_breeze;
|
||||
@define-color card_shade_color rgba(0, 0, 0, 0.07);
|
||||
|
||||
/* Dialogs & popovers */
|
||||
@define-color dialog_bg_color @theme_bg_color_breeze;
|
||||
@define-color dialog_fg_color @theme_fg_color_breeze;
|
||||
@define-color popover_bg_color white;
|
||||
@define-color popover_fg_color @theme_fg_color_breeze;
|
||||
@define-color popover_shade_color rgba(0, 0, 0, 0.07);
|
||||
|
||||
/* Thumbnails */
|
||||
@define-color thumbnail_bg_color white;
|
||||
@define-color thumbnail_fg_color @theme_fg_color_breeze;
|
||||
|
||||
/* Misc */
|
||||
@define-color shade_color rgba(0, 0, 0, 0.07);
|
||||
@define-color scrollbar_outline_color white;
|
||||
|
||||
/* Status colors — libadwaita */
|
||||
@define-color destructive_bg_color @error_color_breeze;
|
||||
@define-color destructive_fg_color white;
|
||||
@define-color destructive_color @error_color_breeze;
|
||||
@define-color success_bg_color @success_color_breeze;
|
||||
@define-color success_fg_color white;
|
||||
@define-color success_color @success_color_breeze;
|
||||
@define-color warning_bg_color @warning_color_breeze;
|
||||
@define-color warning_fg_color white;
|
||||
@define-color warning_color @warning_color_breeze;
|
||||
@define-color error_bg_color @error_color_breeze;
|
||||
@define-color error_fg_color white;
|
||||
@define-color error_color @error_color_breeze;
|
||||
|
||||
|
||||
/* ==============================
|
||||
* GTK standard color aliases
|
||||
* ============================== */
|
||||
|
||||
@define-color theme_fg_color @theme_fg_color_breeze;
|
||||
@define-color theme_text_color @theme_text_color_breeze;
|
||||
@define-color theme_bg_color @theme_bg_color_breeze;
|
||||
@define-color theme_base_color @theme_base_color_breeze;
|
||||
@define-color theme_selected_bg_color @theme_selected_bg_color_breeze;
|
||||
@define-color theme_selected_fg_color @theme_selected_fg_color_breeze;
|
||||
@define-color insensitive_bg_color @insensitive_bg_color_breeze;
|
||||
@define-color insensitive_fg_color @insensitive_fg_color_breeze;
|
||||
@define-color insensitive_base_color @insensitive_base_color_breeze;
|
||||
@define-color theme_unfocused_fg_color @theme_unfocused_fg_color_breeze;
|
||||
@define-color theme_unfocused_text_color @theme_unfocused_text_color_breeze;
|
||||
@define-color theme_unfocused_bg_color @theme_unfocused_bg_color_breeze;
|
||||
@define-color theme_unfocused_base_color @theme_unfocused_base_color_breeze;
|
||||
@define-color theme_unfocused_selected_bg_color @theme_unfocused_selected_bg_color_breeze;
|
||||
@define-color theme_unfocused_selected_fg_color @theme_unfocused_selected_fg_color_breeze;
|
||||
@define-color unfocused_insensitive_color @insensitive_unfocused_bg_color_breeze;
|
||||
@define-color borders @borders_breeze;
|
||||
@define-color unfocused_borders @unfocused_borders_breeze;
|
||||
@define-color content_view_bg @content_view_bg_breeze;
|
||||
@define-color text_view_bg @content_view_bg_breeze;
|
||||
|
||||
|
||||
/* ==============================
|
||||
* Button shapes & colors
|
||||
* ============================== */
|
||||
|
||||
/* --- Regular buttons --- */
|
||||
|
||||
button {
|
||||
border-radius: 3px;
|
||||
outline: 1px solid @borders_breeze;
|
||||
outline-offset: -1px;
|
||||
background: @theme_button_background_normal_breeze;
|
||||
color: @theme_button_foreground_normal_breeze;
|
||||
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.125);
|
||||
text-shadow: none;
|
||||
-gtk-icon-shadow: none;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
outline-color: @theme_button_decoration_hover_breeze;
|
||||
}
|
||||
|
||||
button:active {
|
||||
box-shadow: none;
|
||||
background: alpha(@theme_button_decoration_hover_breeze, 0.333);
|
||||
}
|
||||
|
||||
button:checked {
|
||||
background: alpha(@theme_button_foreground_normal_breeze, 0.125);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
button:focus {
|
||||
outline-color: @theme_button_decoration_focus_breeze;
|
||||
}
|
||||
|
||||
button:backdrop {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
box-shadow: none;
|
||||
color: @theme_button_foreground_insensitive_breeze;
|
||||
outline-color: @insensitive_borders_breeze;
|
||||
background: @theme_button_background_insensitive_breeze;
|
||||
}
|
||||
|
||||
button:disabled:active,
|
||||
button:disabled:checked {
|
||||
color: @theme_button_foreground_active_insensitive_breeze;
|
||||
}
|
||||
|
||||
/* --- Suggested & destructive: subtle tint instead of solid fill --- */
|
||||
|
||||
button.suggested-action,
|
||||
button.flat.suggested-action {
|
||||
background-color: alpha(@theme_button_decoration_focus_breeze, 0.2);
|
||||
outline-color: mix(@theme_button_decoration_focus_breeze,
|
||||
mix(@theme_button_background_normal_breeze,
|
||||
@theme_button_foreground_normal_breeze, 0.333), 0.5);
|
||||
}
|
||||
|
||||
button.destructive-action,
|
||||
button.flat.destructive-action {
|
||||
background-color: alpha(@error_color_breeze, 0.2);
|
||||
outline-color: mix(@error_color_breeze,
|
||||
mix(@theme_button_background_normal_breeze,
|
||||
@theme_button_foreground_normal_breeze, 0.333), 0.5);
|
||||
}
|
||||
|
||||
button.suggested-action:hover {
|
||||
background-color: alpha(@theme_button_decoration_focus_breeze, 0.35);
|
||||
outline-color: @theme_button_decoration_focus_breeze;
|
||||
}
|
||||
|
||||
button.destructive-action:hover {
|
||||
background-color: alpha(@error_color_breeze, 0.35);
|
||||
outline-color: @error_color_breeze;
|
||||
}
|
||||
|
||||
button.suggested-action:active {
|
||||
background-color: alpha(@theme_button_decoration_focus_breeze, 0.5);
|
||||
}
|
||||
|
||||
button.destructive-action:active {
|
||||
background-color: alpha(@error_color_breeze, 0.5);
|
||||
}
|
||||
|
||||
/* --- Flat buttons --- */
|
||||
|
||||
button.flat {
|
||||
outline-color: transparent;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
button.flat:checked {
|
||||
outline-color: mix(@theme_button_background_normal_breeze,
|
||||
@theme_button_foreground_normal_breeze, 0.3);
|
||||
background-color: alpha(@theme_button_foreground_normal_breeze, 0.125);
|
||||
}
|
||||
|
||||
button.flat:hover {
|
||||
outline-color: @theme_button_decoration_hover_breeze;
|
||||
}
|
||||
|
||||
button.flat:active {
|
||||
outline-color: @theme_button_decoration_hover_breeze;
|
||||
background-color: alpha(@theme_button_decoration_hover_breeze, 0.333);
|
||||
}
|
||||
|
||||
/* --- Circular buttons --- */
|
||||
|
||||
button.circular {
|
||||
border-radius: 9999px;
|
||||
}
|
||||
|
||||
/* --- Headerbar buttons (flat by default, like Breeze) --- */
|
||||
|
||||
headerbar button:not(.suggested-action):not(.destructive-action) {
|
||||
outline-color: transparent;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
color: @theme_titlebar_foreground_breeze;
|
||||
}
|
||||
|
||||
headerbar button:not(.suggested-action):not(.destructive-action):checked {
|
||||
outline-color: mix(@theme_button_background_normal_breeze,
|
||||
@theme_button_foreground_normal_breeze, 0.3);
|
||||
background-color: alpha(@theme_button_foreground_normal_breeze, 0.125);
|
||||
}
|
||||
|
||||
headerbar button:not(.suggested-action):not(.destructive-action):hover {
|
||||
outline-color: @theme_button_decoration_hover_breeze;
|
||||
color: @theme_titlebar_foreground_breeze;
|
||||
background-color: alpha(@theme_button_foreground_normal_breeze, 0.08);
|
||||
}
|
||||
|
||||
headerbar button:not(.suggested-action):not(.destructive-action):active {
|
||||
outline-color: @theme_button_decoration_hover_breeze;
|
||||
background-color: alpha(@theme_button_decoration_hover_breeze, 0.333);
|
||||
}
|
||||
|
||||
headerbar button:not(.suggested-action):not(.destructive-action):focus {
|
||||
outline-color: @theme_button_decoration_focus_breeze;
|
||||
}
|
||||
|
||||
headerbar button:not(.suggested-action):not(.destructive-action):backdrop {
|
||||
color: @theme_titlebar_foreground_backdrop_breeze;
|
||||
}
|
||||
|
||||
headerbar button:not(.suggested-action):not(.destructive-action):backdrop:checked {
|
||||
outline-color: mix(@theme_button_background_normal_breeze,
|
||||
@theme_button_foreground_normal_breeze, 0.3);
|
||||
background-color: alpha(@theme_button_foreground_normal_breeze, 0.125);
|
||||
}
|
||||
|
||||
headerbar button:not(.suggested-action):not(.destructive-action):disabled {
|
||||
color: @theme_titlebar_foreground_insensitive_breeze;
|
||||
}
|
||||
|
||||
/* Headerbar tab buttons (stack switcher) — visible so they look interactive */
|
||||
|
||||
headerbar stackswitcher button:not(.suggested-action):not(.destructive-action):not(:checked) {
|
||||
outline-color: alpha(@borders_breeze, 0.6);
|
||||
background-color: alpha(@theme_button_foreground_normal_breeze, 0.06);
|
||||
}
|
||||
|
||||
headerbar stackswitcher button:not(.suggested-action):not(.destructive-action):not(:checked):hover {
|
||||
outline-color: @theme_button_decoration_hover_breeze;
|
||||
background-color: alpha(@theme_button_foreground_normal_breeze, 0.08);
|
||||
}
|
||||
|
||||
/* Headerbar linked buttons — restore regular button look */
|
||||
|
||||
headerbar .linked button {
|
||||
color: @theme_button_foreground_normal_breeze;
|
||||
outline-color: @borders_breeze;
|
||||
background: @theme_button_background_normal_breeze;
|
||||
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.125);
|
||||
}
|
||||
|
||||
/* --- SpinButton +/- buttons: flat, only icon colour changes on disable --- */
|
||||
|
||||
spinbutton:not(.vertical) button,
|
||||
spinbutton:not(.vertical) button:disabled {
|
||||
background: transparent;
|
||||
outline-color: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
spinbutton:not(.vertical) button:hover {
|
||||
color: @theme_view_hover_decoration_color_breeze;
|
||||
}
|
||||
|
||||
spinbutton:not(.vertical) button:active {
|
||||
background: alpha(@theme_button_decoration_hover_breeze, 0.333);
|
||||
}
|
||||
|
||||
spinbutton:not(.vertical) button:disabled {
|
||||
color: @theme_button_foreground_insensitive_breeze;
|
||||
}
|
||||
|
||||
/* --- Check & radio indicators --- */
|
||||
|
||||
check,
|
||||
radio {
|
||||
background-color: @theme_base_color_breeze;
|
||||
outline: 1px solid alpha(@theme_button_foreground_normal_breeze, 0.333);
|
||||
outline-offset: -1px;
|
||||
-gtk-icon-shadow: none;
|
||||
}
|
||||
|
||||
check {
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
radio {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
check:hover,
|
||||
radio:hover {
|
||||
outline-color: @theme_button_decoration_hover_breeze;
|
||||
}
|
||||
|
||||
check:focus,
|
||||
radio:focus {
|
||||
outline-color: @theme_button_decoration_focus_breeze;
|
||||
}
|
||||
|
||||
check:checked,
|
||||
check:indeterminate,
|
||||
radio:checked,
|
||||
radio:indeterminate {
|
||||
outline-color: @theme_button_decoration_hover_breeze;
|
||||
background-color: alpha(@theme_button_decoration_hover_breeze, 0.333);
|
||||
}
|
||||
|
||||
check:disabled,
|
||||
radio:disabled {
|
||||
background-color: alpha(@theme_base_color_breeze, 0.03);
|
||||
outline-color: alpha(@theme_button_foreground_normal_breeze, 0.222);
|
||||
}
|
||||
|
||||
check:checked:disabled,
|
||||
check:indeterminate:disabled,
|
||||
radio:checked:disabled,
|
||||
radio:indeterminate:disabled {
|
||||
background-color: alpha(@theme_button_foreground_normal_breeze, 0.03);
|
||||
outline-color: alpha(@theme_button_decoration_hover_breeze, 0.3);
|
||||
}
|
||||
|
||||
/* --- Switch --- */
|
||||
|
||||
switch {
|
||||
outline: 1px solid alpha(@theme_button_foreground_normal_breeze, 0.222);
|
||||
outline-offset: -1px;
|
||||
border-radius: 12px;
|
||||
background-color: alpha(@theme_button_foreground_normal_breeze, 0.05);
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
switch:checked {
|
||||
background: alpha(@theme_button_decoration_hover_breeze, 0.333);
|
||||
outline-color: @theme_button_decoration_hover_breeze;
|
||||
}
|
||||
|
||||
switch:disabled {
|
||||
background-color: alpha(@theme_button_foreground_normal_breeze, 0.03);
|
||||
}
|
||||
|
||||
switch:checked:disabled {
|
||||
background: alpha(@theme_button_decoration_hover_breeze, 0.222);
|
||||
outline-color: alpha(@theme_button_decoration_hover_breeze, 0.777);
|
||||
}
|
||||
|
||||
switch slider {
|
||||
outline: 1px solid @borders_breeze;
|
||||
outline-offset: -1px;
|
||||
border-radius: 12px;
|
||||
background: @theme_button_background_normal_breeze;
|
||||
box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.125);
|
||||
}
|
||||
|
||||
switch:hover slider {
|
||||
outline-color: @theme_button_decoration_hover_breeze;
|
||||
}
|
||||
|
||||
switch:focus slider {
|
||||
outline-color: @theme_button_decoration_focus_breeze;
|
||||
}
|
||||
|
||||
switch:disabled slider {
|
||||
box-shadow: none;
|
||||
color: @theme_button_foreground_insensitive_breeze;
|
||||
outline-color: @insensitive_borders_breeze;
|
||||
background: @theme_button_background_insensitive_breeze;
|
||||
}
|
||||
@@ -5,7 +5,6 @@ edition = "2024"
|
||||
|
||||
[features]
|
||||
default = ["lact-gui", "nvidia"]
|
||||
adw = ["lact-gui/adw"]
|
||||
nvidia = ["lact-daemon/nvidia"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -9,7 +9,7 @@ metadata:
|
||||
source:
|
||||
- '../../../../LACT'
|
||||
provides: [ lact ]
|
||||
conflicts: [ lact, lact-libadwaita ]
|
||||
conflicts: [ lact ]
|
||||
depends:
|
||||
all: [ hwdata, vulkan-tools, clinfo ]
|
||||
debian-13+ubuntu-2404: [ libdrm-amdgpu1, libdrm2 ]
|
||||
|
||||
@@ -9,19 +9,19 @@ metadata:
|
||||
source:
|
||||
- '../../../../LACT'
|
||||
provides: [ lact ]
|
||||
conflicts: [ lact-headless, lact-libadwaita ]
|
||||
conflicts: [ lact-headless ]
|
||||
depends:
|
||||
all: [ hwdata, vulkan-tools, clinfo ]
|
||||
debian-13+ubuntu-2404: [ libgtk-4-1, libdrm2, libdrm-amdgpu1 ]
|
||||
fedora-42+fedora-43: [ gtk4, libdrm ]
|
||||
arch: [ gtk4, ocl-icd ]
|
||||
opensuse-tumbleweed: [ gtk4 ]
|
||||
debian-13+ubuntu-2404: [ libgtk-4-1, libdrm2, libdrm-amdgpu1, libadwaita-1-0 ]
|
||||
fedora-42+fedora-43: [ gtk4, libdrm, libadwaita ]
|
||||
arch: [ gtk4, ocl-icd, libadwaita ]
|
||||
opensuse-tumbleweed: [ gtk4, libadwaita-1-0 ]
|
||||
build_depends:
|
||||
all: [ curl, make, clang, git, vulkan-tools, clinfo ]
|
||||
debian-13+ubuntu-2404: [ libgtk-4-dev, pkg-config, build-essential, libdrm-dev, dbus ]
|
||||
fedora-42+fedora-43: [ gtk4-devel, gcc, libdrm-devel, dbus ]
|
||||
arch: [ gtk4, dbus, ocl-icd ]
|
||||
opensuse-tumbleweed: [ gtk4-devel, libdrm-devel ]
|
||||
debian-13+ubuntu-2404: [ libgtk-4-dev, pkg-config, build-essential, libdrm-dev, dbus, libadwaita-1-dev ]
|
||||
fedora-42+fedora-43: [ gtk4-devel, gcc, libdrm-devel, dbus, libadwaita-devel ]
|
||||
arch: [ gtk4, dbus, ocl-icd, libadwaita ]
|
||||
opensuse-tumbleweed: [ gtk4-devel, libdrm-devel, libadwaita-devel ]
|
||||
all_images: true
|
||||
env:
|
||||
RUSTUP_URL: https://sh.rustup.rs
|
||||
|
||||
Reference in New Issue
Block a user