-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Subscriptions Implemented callback functions for freedesktop and non-freedesktop. Partitioned freedesktop into a module. New module structure Implemented new module structure to macOS and Windows Fix for doc test Ensured that all possible cases are being handled within `Mode` match. * Async notify `notify` is now an async function. Modified example to use `tokio` Renamed `Mode::rgb` to `Mode::from_rgb` `freedesktop_watch` now uses `ashpd` beta. Changed signature for `notify` function in macOS and Windows files. * Converted examples to individual crates * Example implementation * Re-include ashpd * Fix merge issue * Implemented channels for Linux notify - Updated ashpd * Code improvements - Removed Settings struct as it was not necessary. - Removed `Settings` parameter from `freedesktop_watch`. - `get_freedesktop_color_scheme` matches `ColorScheme` instead of `u32` * Using legacy fallback When the settings proxy is unable to init, legacy is used as fallback. * Upgraded ashpd - Upgraded to the master branch of ashpd - Moved the thread spawning to `notify` - Made the async methods return `anyhow::Result<T>` * Using `xdg` crate. - Using xdg to find config files on Linux/BSD systems. - Quality of life improvements * Removed tokio dependency - Cleaned Cargo.toml - Modified notify to take a closure. * Formatting applied * Fix todo methods for macOS and Windows * Move websys to new module structure * Discard unused parameter. - Fix wasm issue. * Improvements - Moved RGB logic to a single file. - Added documentation. * Subscriptions 📰 - Added ThemeWatcher, a new struct which allows users to subscribe and receive notifications when the theme changes. - New crate organization. * Currently only Windows has been implemented. * Currently only tokio has been implemented, we can add new implementations as features in the future. * Subscriptions 📰 - Added support for Freedesktop. * Added default implementaton for other platforms. * Subscriptions ⚡ - Added generic implementation for all platforms except freedesktop. * Updated dependencies 🎁 * Streams 🌊 - Switched notify implementation to use streams. * Update example. * Stream can now wait - The stream is now using Poll::Pending to wait for a new event instead of returning a value when waiting.
- Loading branch information
1 parent
0b41b1c
commit 77ae434
Showing
19 changed files
with
390 additions
and
106 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,4 @@ | ||
/target | ||
/examples/*/target | ||
Cargo.lock | ||
.vscode |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
use futures::StreamExt; | ||
|
||
#[tokio::main] | ||
async fn main() -> anyhow::Result<()> { | ||
while let Some(mode) = dark_light::subscribe().await?.next().await { | ||
println!("System theme changed: {:?}", mode); | ||
} | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,97 +1,73 @@ | ||
//! Detect if dark mode or light mode is enabled. | ||
//! | ||
//! # Examples | ||
//! | ||
//! ``` | ||
//! let mode = dark_light::detect(); | ||
//! | ||
//! match mode { | ||
//! // Dark mode | ||
//! dark_light::Mode::Dark => {}, | ||
//! // Light mode | ||
//! dark_light::Mode::Light => {}, | ||
//! // Unspecified | ||
//! dark_light::Mode::Default => {}, | ||
//! } | ||
//! ``` | ||
#[cfg(target_os = "macos")] | ||
mod macos; | ||
#[cfg(target_os = "macos")] | ||
use macos as platform; | ||
|
||
#[cfg(target_os = "windows")] | ||
mod windows; | ||
#[cfg(target_os = "windows")] | ||
use windows as platform; | ||
|
||
#[cfg(any( | ||
target_os = "linux", | ||
target_os = "freebsd", | ||
target_os = "dragonfly", | ||
target_os = "netbsd", | ||
target_os = "openbsd" | ||
))] | ||
mod freedesktop; | ||
#[cfg(any( | ||
target_os = "linux", | ||
target_os = "freebsd", | ||
target_os = "dragonfly", | ||
target_os = "netbsd", | ||
target_os = "openbsd" | ||
))] | ||
use freedesktop as platform; | ||
|
||
#[cfg(target_arch = "wasm32")] | ||
mod websys; | ||
#[cfg(target_arch = "wasm32")] | ||
use websys as platform; | ||
|
||
#[cfg(not(any( | ||
target_os = "macos", | ||
target_os = "windows", | ||
target_os = "linux", | ||
target_os = "freebsd", | ||
target_os = "dragonfly", | ||
target_os = "netbsd", | ||
target_os = "openbsd", | ||
target_arch = "wasm32" | ||
)))] | ||
mod platform { | ||
pub fn detect() -> crate::Mode { | ||
super::Mode::Light | ||
} | ||
} | ||
|
||
#[derive(Copy, Clone, PartialEq, Eq, Debug)] | ||
pub enum Mode { | ||
/// Dark mode | ||
Dark, | ||
/// Light mode | ||
Light, | ||
/// Unspecified | ||
Default, | ||
} | ||
|
||
impl Mode { | ||
fn from(b: bool) -> Self { | ||
if b { | ||
Mode::Dark | ||
} else { | ||
Mode::Light | ||
} | ||
} | ||
fn 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 | ||
} else { | ||
Self::Light | ||
} | ||
} | ||
} | ||
|
||
/// 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() | ||
} | ||
//! Detect if dark mode or light mode is enabled. | ||
//! | ||
//! # Examples | ||
//! | ||
//! ``` | ||
//! let mode = dark_light::detect(); | ||
//! | ||
//! match mode { | ||
//! // Dark mode | ||
//! dark_light::Mode::Dark => {}, | ||
//! // Light mode | ||
//! dark_light::Mode::Light => {}, | ||
//! // Unspecified | ||
//! dark_light::Mode::Default => {}, | ||
//! } | ||
//! ``` | ||
mod platforms; | ||
use platforms::platform; | ||
|
||
mod utils; | ||
#[cfg(any( | ||
target_os = "linux", | ||
target_os = "freebsd", | ||
target_os = "dragonfly", | ||
target_os = "netbsd", | ||
target_os = "openbsd" | ||
))] | ||
use utils::rgb::Rgb; | ||
|
||
/// Enum representing dark mode, light mode, or unspecified. | ||
#[derive(Copy, Clone, PartialEq, Eq, Debug)] | ||
pub enum Mode { | ||
/// Dark mode | ||
Dark, | ||
/// Light mode | ||
Light, | ||
/// Unspecified | ||
Default, | ||
} | ||
|
||
impl Mode { | ||
#[allow(dead_code)] | ||
fn from_bool(b: bool) -> Self { | ||
if b { | ||
Mode::Dark | ||
} else { | ||
Mode::Light | ||
} | ||
} | ||
|
||
#[cfg(any( | ||
target_os = "linux", | ||
target_os = "freebsd", | ||
target_os = "dragonfly", | ||
target_os = "netbsd", | ||
target_os = "openbsd" | ||
))] | ||
/// Convert an RGB color to [`Mode`]. The color is converted to grayscale, and if the grayscale value is less than 192, [`Mode::Dark`] is returned. Otherwise, [`Mode::Light`] is returned. | ||
fn from_rgb(rgb: Rgb) -> Self { | ||
let window_background_gray = (rgb.0 * 11 + rgb.1 * 16 + rgb.2 * 5) / 32; | ||
if window_background_gray < 192 { | ||
Self::Dark | ||
} else { | ||
Self::Light | ||
} | ||
} | ||
} | ||
|
||
/// Detect if light mode or dark mode is enabled. If the mode can’t be detected, fall back to [`Mode::Default`]. | ||
pub use platform::detect::detect; | ||
/// Notifies the user if the system theme has been changed. | ||
pub use platform::notify::subscribe; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
use detect_desktop_environment::DesktopEnvironment; | ||
|
||
use crate::Mode; | ||
|
||
use super::{dconf_detect, kde_detect, CINNAMON, GNOME, MATE}; | ||
|
||
pub fn detect() -> Mode { | ||
NonFreeDesktop::detect() | ||
} | ||
|
||
/// Detects the color scheme on a platform. | ||
trait ColorScheme { | ||
fn detect() -> Mode; | ||
} | ||
|
||
/// Represents the FreeDesktop platform. | ||
struct FreeDesktop; | ||
|
||
/// Represents non FreeDesktop platforms. | ||
struct NonFreeDesktop; | ||
|
||
/// Detects the color scheme on FreeDesktop platforms. It makes use of the DBus interface. | ||
impl ColorScheme for FreeDesktop { | ||
fn detect() -> Mode { | ||
todo!() | ||
} | ||
} | ||
|
||
/// Detects the color scheme on non FreeDesktop platforms, having a custom implementation for each desktop environment. | ||
impl ColorScheme for NonFreeDesktop { | ||
fn detect() -> Mode { | ||
match DesktopEnvironment::detect() { | ||
Some(mode) => match mode { | ||
DesktopEnvironment::Kde => match kde_detect() { | ||
Ok(mode) => mode, | ||
Err(_) => Mode::Default, | ||
}, | ||
DesktopEnvironment::Cinnamon => dconf_detect(CINNAMON), | ||
DesktopEnvironment::Gnome => dconf_detect(GNOME), | ||
DesktopEnvironment::Mate => dconf_detect(MATE), | ||
DesktopEnvironment::Unity => dconf_detect(GNOME), | ||
_ => Mode::Default, | ||
}, | ||
None => Mode::Default, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
use std::str::FromStr; | ||
|
||
use anyhow::Context; | ||
use ini::Ini; | ||
|
||
use crate::{utils::rgb::Rgb, Mode}; | ||
|
||
pub mod detect; | ||
pub mod notify; | ||
|
||
const MATE: &str = "/org/mate/desktop/interface/gtk-theme"; | ||
const GNOME: &str = "/org/gnome/desktop/interface/gtk-theme"; | ||
const CINNAMON: &str = "/org/cinnamon/desktop/interface/gtk-theme"; | ||
|
||
fn dconf_detect(path: &str) -> Mode { | ||
match dconf_rs::get_string(path) { | ||
Ok(theme) => { | ||
if theme.to_lowercase().contains("dark") { | ||
Mode::Dark | ||
} else { | ||
Mode::Light | ||
} | ||
} | ||
Err(_) => Mode::Default, | ||
} | ||
} | ||
|
||
fn kde_detect() -> anyhow::Result<Mode> { | ||
let xdg = xdg::BaseDirectories::new()?; | ||
let path = xdg | ||
.find_config_file("kdeglobals") | ||
.context("Path not found")?; | ||
let cfg = Ini::load_from_file(path)?; | ||
let properties = cfg | ||
.section(Some("Colors:Window")) | ||
.context("Failed to get section Colors:Window")?; | ||
let background = properties | ||
.get("BackgroundNormal") | ||
.context("Failed to get BackgroundNormal inside Colors:Window")?; | ||
let rgb = Rgb::from_str(background).unwrap(); | ||
Ok(Mode::from_rgb(rgb)) | ||
} | ||
|
||
impl From<ashpd::desktop::settings::ColorScheme> for Mode { | ||
fn from(value: ashpd::desktop::settings::ColorScheme) -> Self { | ||
match value { | ||
ashpd::desktop::settings::ColorScheme::NoPreference => Mode::Default, | ||
ashpd::desktop::settings::ColorScheme::PreferDark => Mode::Dark, | ||
ashpd::desktop::settings::ColorScheme::PreferLight => Mode::Light, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
use ashpd::desktop::settings::{ColorScheme, Settings}; | ||
use futures::{stream, Stream, StreamExt}; | ||
use std::task::Poll; | ||
|
||
use crate::{detect, Mode}; | ||
|
||
pub async fn subscribe() -> anyhow::Result<impl Stream<Item = Mode> + Send> { | ||
let stream = if get_freedesktop_color_scheme().await.is_ok() { | ||
let proxy = Settings::new().await?; | ||
proxy | ||
.receive_color_scheme_changed() | ||
.await? | ||
.map(Mode::from) | ||
.boxed() | ||
} else { | ||
let mut last_mode = detect(); | ||
stream::poll_fn(move |ctx| -> Poll<Option<Mode>> { | ||
let current_mode = detect(); | ||
if current_mode != last_mode { | ||
last_mode = current_mode; | ||
Poll::Ready(Some(current_mode)) | ||
} else { | ||
ctx.waker().wake_by_ref(); | ||
Poll::Pending | ||
} | ||
}) | ||
.boxed() | ||
}; | ||
|
||
Ok(stream) | ||
} | ||
|
||
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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
pub mod detect; | ||
pub mod notify; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
use std::task::Poll; | ||
|
||
use futures::{stream, Stream}; | ||
|
||
use crate::{detect, Mode}; | ||
|
||
pub async fn subscribe() -> anyhow::Result<impl Stream<Item = Mode> + Send> { | ||
let mut last_mode = detect(); | ||
|
||
let stream = stream::poll_fn(move |ctx| -> Poll<Option<Mode>> { | ||
let current_mode = detect(); | ||
|
||
if current_mode != last_mode { | ||
last_mode = current_mode; | ||
Poll::Ready(Some(current_mode)) | ||
} else { | ||
ctx.waker().wake_by_ref(); | ||
Poll::Pending | ||
} | ||
}); | ||
|
||
Ok(stream) | ||
} |
Oops, something went wrong.