#![cfg(all(feature = "wayland-portal", unix_desktop))]
use crate::compat::{lock, Instant, Mutex};
use std::time::Duration;
const CACHE_TTL: Duration = Duration::from_secs(2);
const METHOD_TIMEOUT: Duration = Duration::from_millis(400);
struct Cached {
at: Instant,
value: Option<u32>,
}
static COLOR_SCHEME: Mutex<Option<Cached>> = Mutex::new(None);
static CONTRAST: Mutex<Option<Cached>> = Mutex::new(None);
pub(crate) fn color_scheme() -> Option<bool> {
color_scheme_from(read_u32("color-scheme", &COLOR_SCHEME))
}
pub(crate) fn contrast() -> Option<bool> {
contrast_from(read_u32("contrast", &CONTRAST))
}
fn color_scheme_from(value: Option<u32>) -> Option<bool> {
match value? {
1 => Some(true),
2 => Some(false),
_ => None,
}
}
fn contrast_from(value: Option<u32>) -> Option<bool> {
value.map(|value| value == 1)
}
fn read_u32(key: &str, cache: &Mutex<Option<Cached>>) -> Option<u32> {
{
let guard = lock(cache);
if let Some(cached) = guard.as_ref() {
if cached.at.elapsed() < CACHE_TTL {
return cached.value;
}
}
}
let value = query(key);
*lock(cache) = Some(Cached { at: Instant::now(), value });
value
}
fn query(key: &str) -> Option<u32> {
let connection = zbus::blocking::connection::Builder::session()
.ok()?
.method_timeout(METHOD_TIMEOUT)
.build()
.ok()?;
let proxy = zbus::blocking::Proxy::new(
&connection,
"org.freedesktop.portal.Desktop",
"/org/freedesktop/portal/desktop",
"org.freedesktop.portal.Settings",
)
.ok()?;
let value: zbus::zvariant::OwnedValue =
proxy.call("Read", &("org.freedesktop.appearance", key)).ok()?;
value.downcast_ref::<u32>().ok()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_cached_reading_is_reused_until_it_expires() {
let cache = Mutex::new(Some(Cached { at: Instant::now(), value: Some(1) }));
assert_eq!(read_u32("color-scheme", &cache), Some(1));
assert_eq!(read_u32("color-scheme", &cache), Some(1));
}
#[test]
fn an_expired_reading_is_not_answered() {
let cache = Mutex::new(Some(Cached {
at: Instant::now() - CACHE_TTL - Duration::from_secs(1),
value: Some(2),
}));
assert_eq!(read_u32("color-scheme", &cache), None);
}
#[test]
fn the_scheme_mapping_distinguishes_no_preference_from_light() {
assert_eq!(color_scheme_from(Some(1)), Some(true));
assert_eq!(color_scheme_from(Some(2)), Some(false));
assert_eq!(color_scheme_from(Some(0)), None);
assert_eq!(color_scheme_from(None), None);
assert_eq!(contrast_from(Some(1)), Some(true));
assert_eq!(contrast_from(Some(0)), Some(false));
assert_eq!(contrast_from(None), None);
}
}