Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Color scheme change notifications #10

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
/target
/examples/*/target
Cargo.lock
.vscode
9 changes: 9 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,22 @@ description = "Detect if dark mode or light mode is enabled"
readme = "README.md"
build = "build.rs"

[dependencies]
anyhow = "1.0.52"

[dev-dependencies]
tokio = { version = "1.23.0", features = ["full"] }

[target.'cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd", target_os = "openbsd"))'.dependencies]
detect-desktop-environment = "0.2"
dconf_rs = "0.3"
dirs = "4.0"
zbus = "3.0"
zvariant = "3.6"
rust-ini = "0.18"
ashpd = { git = "https://github.com/bilelmoussaoui/ashpd", branch = "master" }
crossbeam = "0.8.2"
tokio = { version = "1.23.0", features = ["full"] }

[target.'cfg(windows)'.dependencies]
winreg = "0.10"
Expand Down
10 changes: 10 additions & 0 deletions examples/color_scheme.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#[tokio::main]
async fn main() {
let proxy = ashpd::desktop::settings::Settings::new().await.unwrap();
let color_scheme = proxy.color_scheme().await.unwrap();
match color_scheme {
ashpd::desktop::settings::ColorScheme::PreferDark => println!("Dark"),
ashpd::desktop::settings::ColorScheme::PreferLight => println!("Light"),
ashpd::desktop::settings::ColorScheme::NoPreference => println!("Default"),
};
}
12 changes: 12 additions & 0 deletions examples/notify.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use anyhow::Ok;
use dark_light::*;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
let (tx, mut rx) = tokio::sync::mpsc::channel(4);
notify(tx).await?;
while let Some(mode) = rx.recv().await {
println!("{:?}", mode)
}
Ok(())
}
96 changes: 0 additions & 96 deletions src/freedesktop.rs

This file was deleted.

59 changes: 59 additions & 0 deletions src/freedesktop/detect.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use anyhow::Context;
use detect_desktop_environment::DesktopEnvironment;
use ini::Ini;
use std::path::{Path, PathBuf};

use crate::Mode;

const XDG_KDEGLOBALS: &str = "/etc/xdg/kdeglobals";

fn detect_gtk(pattern: &str) -> Mode {
match dconf_rs::get_string(pattern) {
Ok(theme) => Mode::from(theme.to_lowercase().contains("dark")),
Err(_) => Mode::Default,
}
}

fn detect_kde(path: &str) -> anyhow::Result<Mode> {
let cfg = Ini::load_from_file(path)?;
let section = cfg.section(Some("Colors:Window")).with_context(|| "Failed to get section Colors:Window")?;
let values = section.get("BackgroundNormal").with_context(|| "Failed to get BackgroundNormal inside Colors:Window")?;
let rgb = values
.split(',')
.map(|s| s.parse::<u32>().unwrap_or(255))
.collect::<Vec<u32>>();
let rgb = if rgb.len() >= 3 {
rgb
} else {
vec![255, 255, 255]
};
let (r, g, b) = (rgb[0], rgb[1], rgb[2]);
Ok(Mode::from_rgb(r, g, b))
}

fn legacy_detect() -> anyhow::Result<Mode> {
let mode = match DesktopEnvironment::detect() {
DesktopEnvironment::Kde => {
let path = if Path::new(XDG_KDEGLOBALS).exists() {
PathBuf::from(XDG_KDEGLOBALS)
} else {
dirs::home_dir().unwrap().join(".config/kdeglobals")
};
edfloreshz marked this conversation as resolved.
Show resolved Hide resolved
detect_kde(path.to_str().unwrap())?
}
DesktopEnvironment::Cinnamon => detect_gtk("/org/cinnamon/desktop/interface/gtk-theme"),
DesktopEnvironment::Gnome => detect_gtk("/org/gnome/desktop/interface/gtk-theme"),
DesktopEnvironment::Mate => detect_gtk("/org/mate/desktop/interface/gtk-theme"),
DesktopEnvironment::Unity => detect_gtk("/org/gnome/desktop/interface/gtk-theme"),
_ => Mode::Default,
};
Ok(mode)
}

pub fn detect() -> Mode {
match legacy_detect() {
Ok(mode) => mode,
Err(_) => Mode::Default,
}
}

17 changes: 17 additions & 0 deletions src/freedesktop/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use ashpd::desktop::settings::{Settings, ColorScheme};

use crate::Mode;

pub mod detect;
pub mod notify;

async fn get_freedesktop_color_scheme() -> anyhow::Result<Mode> {
let proxy = Settings::new().await?;
let color_scheme = proxy.color_scheme().await?;
let mode = match color_scheme {
ColorScheme::PreferDark => Mode::Dark,
ColorScheme::PreferLight => Mode::Light,
ColorScheme::NoPreference => Mode::Default,
};
Ok(mode)
}
41 changes: 41 additions & 0 deletions src/freedesktop/notify.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@

use tokio::sync::mpsc::Sender;
use ashpd::desktop::settings::{Settings, ColorScheme};

use crate::{Mode, detect};

use super::get_freedesktop_color_scheme;

pub async fn notify(tx: Sender<crate::Mode>) -> anyhow::Result<()> {
if get_freedesktop_color_scheme().await.is_ok() {
tokio::spawn(freedesktop_watch(tx));
} else {
eprintln!("Unable to start proxy, falling back to legacy...");
tokio::spawn(non_freedesktop_watch(tx));
}
Ok(())
}

async fn freedesktop_watch(tx: Sender<Mode>) -> anyhow::Result<()> {
let proxy = Settings::new().await?;
while let Ok(color_scheme) = proxy.receive_color_scheme_changed().await {
let mode = match color_scheme {
ColorScheme::NoPreference => Mode::Default,
ColorScheme::PreferDark => Mode::Dark,
ColorScheme::PreferLight => Mode::Light,
};
tx.send(mode).await?;
}
Comment on lines +21 to +28
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bilelmoussaoui I'm unsure if this is the correct way of using the receive_color_scheme_changed method.

Ok(())
}

async fn non_freedesktop_watch(tx: Sender<Mode>) -> anyhow::Result<()> {
let mut mode = detect();
loop {
let new_mode = detect();
if mode != new_mode {
mode = new_mode;
tx.send(mode).await?;
}
}
}
11 changes: 9 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#[cfg(target_os = "macos")]
mod macos;

#[cfg(target_os = "macos")]
use macos as platform;

Expand Down Expand Up @@ -63,6 +64,8 @@ mod platform {
}
}

use tokio::sync::mpsc::Sender;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Mode {
/// Dark mode
Expand All @@ -81,7 +84,7 @@ impl Mode {
Mode::Light
}
}
fn rgb(r: u32, g: u32, b: u32) -> Self {
fn from_rgb(r: u32, g: u32, b: u32) -> Self {
let window_background_gray = (r * 11 + g * 16 + b * 5) / 32;
if window_background_gray < 192 {
Self::Dark
Expand All @@ -93,5 +96,9 @@ impl Mode {

/// Detect if light mode or dark mode is enabled. If the mode can’t be detected, fall back to [`Mode::Default`].
pub fn detect() -> Mode {
platform::detect()
platform::detect::detect()
}

pub async fn notify(tx: Sender<crate::Mode>) -> anyhow::Result<()> {
platform::notify::notify(tx).await
}
File renamed without changes.
2 changes: 2 additions & 0 deletions src/macos/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod detect;
pub mod notify;
5 changes: 5 additions & 0 deletions src/macos/notify.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use crate::Mode;

pub async fn notify(callback: &dyn Fn(Mode)) -> anyhow::Result<()> {
todo!()
}
File renamed without changes.
2 changes: 2 additions & 0 deletions src/windows/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod detect;
pub mod notify;
12 changes: 12 additions & 0 deletions src/windows/notify.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use std::sync::mpsc::Sender;

const duration: std::time::Duration = std::time::Duration::from_secs(1);

pub async fn notify(tx: Sender<crate::Mode>) -> anyhow::Result<()> {
tx.send(crate::Mode::Default)?;
std::thread::sleep(duration);
tx.send(crate::Mode::Light)?;
std::thread::sleep(duration);
tx.send(crate::Mode::Dark)?;
Ok(())
}