Skip to content

Commit 91a4c92

Browse files
committed
Added support for accent-color property from XDG Desktop Portal
1 parent ec641c7 commit 91a4c92

File tree

8 files changed

+105
-14
lines changed

8 files changed

+105
-14
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
77
## [Unreleased]
88

99
### Added
10+
- Integration with system accent color setting through [XDG Desktop Portal](https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Settings.html).
11+
Requires `Accent` feature to be included at compile time, compatible `xdg-desktop-portal` set and running for `org.freedesktop.impl.portal.Settings` (like `xdg-desktop-portal-kde`) and `-C` or `--accent` flag.
1012
- New sidebar to quickly swap between audio outputs.
1113
- `.sass` and `.scss` styles will be compiled using the system `sass` compiler binary if `Sass` feature was not enabled at the compile time. Style compilation time is much longer, but the resulting binary is around 2mb smaller in size. (https://sass-lang.com/install)
1214

README.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ Currently, it supports only `pulseaudio` and `pipewire` (through the pulseaudio
99
![Preview](https://user-images.githubusercontent.com/2061234/270078395-6454be21-aa09-4da2-8a07-3a3c9b41138f.png)
1010

1111
## Usage
12-
```sh
13-
Usage: mixxc [-w <width>] [-h <height>] [-s <spacing>] [-a <anchor...>] [-A] [-m <margin...>] [-M] [-b <bar>] [-u <userstyle>] [-k] [-i] [-x <max-volume>] [-P] [-v]
12+
```
13+
Usage: mixxc [-w <width>] [-h <height>] [-s <spacing>] [-a <anchor...>] [-A] [-C] [-m <margin...>] [-M] [-b <bar>] [-u <userstyle>] [-k] [-i] [-x <max-volume>] [-P] [-v]
1414
1515
Minimalistic volume mixer.
1616
@@ -20,6 +20,7 @@ Options:
2020
-s, --spacing spacing between clients
2121
-a, --anchor screen anchor point: (t)op, (b)ottom, (l)eft, (r)ight
2222
-A, --active show only active sinks
23+
-C, --accent inherit accent color from the system's settings
2324
-m, --margin margin distance for each anchor point
2425
-M, --master enable master volume slider
2526
-b, --bar volume slider orientation: (h)orizontal, (v)ertical
@@ -92,6 +93,7 @@ GTK_DEBUG=1 mixxc
9293

9394
## Features
9495
Some features can be enabled at compile time.
96+
* [Accent](https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Settings.html) - Inherits the accent color from the system's settings.
9597
* [Sass](https://sass-lang.com/) - Allows you to use SCSS instead of CSS.
9698
* [Wayland](https://wayland.freedesktop.org/) - Uses wlr-layer-shell to imitate window positioning.
9799
* [X11](https://www.x.org/) - Sets WM hints and properties, and repositions the window.

doc/mixxc.1

+6
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ r, right
3131
.El
3232
.It Fl A , Fl \-active
3333
Sliders that are associated with paused media players will be hidden and reappear only when playback is resumed.
34+
.It Fl C , Fl \-accent
35+
Reads an accent-color property from the system settings
36+
.Xr xdg-settings 1
37+
and applies the color to the user style.
3438
.It Fl m , Fl \-margin Ar px
3539
Distance that window will keep from each anchor point respectively.
3640
.It Fl M , Fl \-master
@@ -93,6 +97,8 @@ Every GTK related message will be ignored and not printed if GTK_DEBUG variable
9397
Here's a list of features that can be included or excluded at compile time.
9498
Excluding some of them might lead to a smaller binary size and performance improvements.
9599
.Bl -ohang
100+
.It - Accent
101+
Support for system accent color.
96102
.It - Sass
97103
Support for CSS supersets.
98104
.It - X11

src/accent.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ use zbus::zvariant::{OwnedValue, Structure};
66
default_service = "org.freedesktop.portal.Desktop",
77
default_path = "/org/freedesktop/portal/desktop",
88
interface = "org.freedesktop.portal.Settings",
9-
async_name = "Portal"
9+
async_name = "Settings"
1010
)]
11-
trait Settings {
11+
pub trait Settings {
1212
fn read(&self, namespace: &str, key: &str) -> zbus::Result<OwnedValue>;
1313
}
1414

@@ -18,7 +18,7 @@ pub enum Scheme {
1818
Light,
1919
}
2020

21-
impl Portal<'_> {
21+
impl Settings<'_> {
2222
async fn appearance(&self, key: &str) -> Result<OwnedValue, Error> {
2323
self.read("org.freedesktop.appearance", key)
2424
.await
@@ -29,6 +29,7 @@ impl Portal<'_> {
2929
.map_err(Into::into)
3030
}
3131

32+
#[allow(dead_code)]
3233
pub async fn scheme(&self) -> Result<Scheme, Error> {
3334
let reply = self.appearance("color-scheme").await?;
3435

src/app.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use smallvec::SmallVec;
1515
use tokio_util::sync::CancellationToken;
1616

1717
use crate::anchor::Anchor;
18+
use crate::style::{self, StyleSettings};
1819
use crate::widgets::sliderbox::{SliderBox, SliderMessage, Sliders};
1920
use crate::server::{self, AudioServer, AudioServerEnum, Kind, MessageClient, MessageOutput, VolumeLevels};
2021
use crate::widgets::switchbox::{SwitchBox, Switches};
@@ -45,6 +46,9 @@ pub struct Config {
4546
pub per_process: bool,
4647
pub userstyle: Option<std::path::PathBuf>,
4748

49+
#[cfg(feature = "Accent")]
50+
pub accent: bool,
51+
4852
pub server: AudioServerEnum,
4953
}
5054

@@ -149,19 +153,24 @@ impl AsyncComponent for App {
149153
let server = Arc::new(config.server);
150154

151155
sender.oneshot_command(async move {
156+
let mut settings = StyleSettings::default();
157+
158+
#[cfg(feature = "Accent")]
159+
{ settings.accent = config.accent; }
160+
152161
let style = match config.userstyle {
153-
Some(p) => crate::style::read(p).await,
162+
Some(p) => style::read(p).await,
154163
None => {
155164
let config_dir = crate::config_dir().await.unwrap();
156-
crate::style::find(config_dir).await
165+
style::find(config_dir, settings).await
157166
},
158167
};
159168

160169
let style = match style {
161170
Ok(s) => s,
162171
Err(e) => {
163172
eprintln!("{}", e);
164-
crate::style::default()
173+
style::default(settings).await
165174
}
166175
};
167176

src/error.rs

+6
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ pub enum CacheError {
104104
#[cfg(feature = "Accent")]
105105
#[derive(Error, Debug)]
106106
pub enum ZbusError {
107+
#[error("Couldn't establish a connection with the session bus\n{e}")]
108+
Connect { e: zbus::Error },
109+
110+
#[error("Couldn't create a proxy to access the bus interface\n{e}")]
111+
Proxy { e: zbus::Error },
112+
107113
#[error("Unable to read `{key}` from `{namespace}, make sure that your `xdg-desktop-portal` supports it and configured correctly`\n{e}")]
108114
Read { e: zbus::Error, namespace: String, key: String },
109115

src/main.rs

+8
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ struct Args {
3030
#[argh(switch, short = 'A', long = "active")]
3131
active_only: bool,
3232

33+
#[cfg(feature = "Accent")]
34+
/// inherit accent color from the system's settings
35+
#[argh(switch, short = 'C', long = "accent")]
36+
accent: bool,
37+
3338
/// margin distance for each anchor point
3439
#[argh(option, short = 'm', long = "margin")]
3540
margins: Vec<i32>,
@@ -106,6 +111,9 @@ fn main() -> Result<(), Error> {
106111
per_process: args.per_process,
107112
userstyle: args.userstyle,
108113

114+
#[cfg(feature = "Accent")]
115+
accent: args.accent,
116+
109117
server: server::pulse::Pulse::new().into(),
110118
});
111119

src/style.rs

+63-6
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@ use tokio::io::AsyncWriteExt;
77

88
use crate::error::{StyleError, Error};
99

10-
pub async fn find(path: impl Into<PathBuf>) -> Result<Cow<'static, str>, Error> {
10+
#[derive(Default, Copy, Clone)]
11+
pub struct StyleSettings {
12+
#[cfg(feature = "Accent")]
13+
pub accent: bool,
14+
}
15+
16+
pub async fn find(path: impl Into<PathBuf>, settings: StyleSettings) -> Result<Cow<'static, str>, Error> {
1117
let mut path = path.into();
1218

1319
path.push("style");
@@ -24,20 +30,39 @@ pub async fn find(path: impl Into<PathBuf>) -> Result<Cow<'static, str>, Error>
2430

2531
path.set_extension("css");
2632

27-
match path.exists() {
33+
let s = match path.exists() {
2834
true => read(path).await,
29-
false => write_default(path).await,
35+
false => write_default(path, StyleSettings::default()).await,
36+
};
37+
38+
#[cfg(feature = "Accent")]
39+
if settings.accent {
40+
if let Ok(s) = s {
41+
return apply_accent(s).await;
42+
}
3043
}
44+
45+
s
3146
}
3247

33-
pub fn default() -> Cow<'static, str> {
48+
pub async fn default(settings: StyleSettings) -> Cow<'static, str> {
3449
static DEFAULT_STYLE: &str = include_str!("../style/default.css");
50+
51+
#[cfg(feature = "Accent")]
52+
if settings.accent {
53+
let s = Cow::Borrowed(DEFAULT_STYLE);
54+
55+
if let Ok(s) = apply_accent(s).await {
56+
return s;
57+
}
58+
}
59+
3560
Cow::Borrowed(DEFAULT_STYLE)
3661
}
3762

38-
async fn write_default(path: impl AsRef<Path>) -> Result<Cow<'static, str>, Error> {
63+
async fn write_default(path: impl AsRef<Path>, settings: StyleSettings) -> Result<Cow<'static, str>, Error> {
3964
let path = path.as_ref();
40-
let style = default();
65+
let style = default(settings).await;
4166

4267
let mut fd = File::create(path)
4368
.await.map_err(|e| StyleError::Create { e, path: path.to_owned() })?;
@@ -146,3 +171,35 @@ async fn cache(path: impl AsRef<Path>, style: &str, time: std::time::SystemTime)
146171
f.into_std().await.set_modified(time)
147172
.map_err(|e| CacheError::MTime { e, path: path.to_owned() })
148173
}
174+
175+
#[cfg(feature = "Accent")]
176+
async fn apply_accent(s: Cow<'static, str>) -> Result<Cow<'static, str>, Error> {
177+
use crate::accent;
178+
use crate::error::ZbusError;
179+
180+
fn find_and_replace(s: &str, r: u8, g: u8, b: u8) -> Option<String> {
181+
let mut s = s.to_owned();
182+
183+
let start = s.find("--accent:")?;
184+
let end = s[start..].find(';')?;
185+
186+
s.replace_range(
187+
start..start + end,
188+
&format!("--accent:#{r:02X}{g:02X}{b:02X}"));
189+
190+
Some(s)
191+
}
192+
193+
let conn = zbus::Connection::session().await
194+
.map_err(|e| ZbusError::Connect { e })?;
195+
196+
let settings = accent::Settings::new(&conn).await
197+
.map_err(|e| ZbusError::Proxy { e })?;
198+
199+
let (r, g, b) = settings.accent().await?;
200+
201+
match find_and_replace(&s, r, g, b).map(Cow::Owned) {
202+
Some(s) => Ok(s),
203+
None => Ok(s),
204+
}
205+
}

0 commit comments

Comments
 (0)