pub fn portal_prefers_dark() -> Option<bool> {
let conn = zbus::blocking::Connection::session().ok()?;
let reply = conn
.call_method(
Some("org.freedesktop.portal.Desktop"),
"/org/freedesktop/portal/desktop",
Some("org.freedesktop.portal.Settings"),
"Read",
&("org.freedesktop.appearance", "color-scheme"),
)
.ok()?;
let value: zbus::zvariant::OwnedValue = reply.body().deserialize().ok()?;
match scheme_u32(&value) {
Some(1) => Some(true),
Some(2) => Some(false),
_ => None,
}
}
fn scheme_u32(v: &zbus::zvariant::Value) -> Option<u32> {
use zbus::zvariant::Value;
match v {
Value::U32(n) => Some(*n),
Value::U8(n) => Some(*n as u32),
Value::I32(n) => Some(*n as u32),
Value::Value(inner) => scheme_u32(inner),
_ => None,
}
}
pub fn spawn_watch(on_change: impl Fn(bool) + Send + 'static) {
std::thread::Builder::new()
.name("telar-color-scheme".to_string())
.spawn(move || {
let Ok(conn) = zbus::blocking::Connection::session() else {
return;
};
let Ok(proxy) = zbus::blocking::Proxy::new(
&conn,
"org.freedesktop.portal.Desktop",
"/org/freedesktop/portal/desktop",
"org.freedesktop.portal.Settings",
) else {
return;
};
let Ok(signals) = proxy.receive_signal("SettingChanged") else {
return;
};
for msg in signals {
let Ok((namespace, key, value)) =
msg.body()
.deserialize::<(String, String, zbus::zvariant::OwnedValue)>()
else {
continue;
};
if namespace == "org.freedesktop.appearance" && key == "color-scheme" {
if let Some(n) = scheme_u32(&value) {
on_change(n == 1);
}
}
}
})
.ok();
}