psst
psst copied to clipboard
Detect light/dark OS theme
This adds an option to use the System preferences to set the theme at launch. It uses the dark-light crate to do so.
This is my very first time touching Rust, Druid, and frankly any sort of native GUI framework. While it should be relatively simple to have a long-running process to call setup_system_theme
or similar continuously, it is not clear to me where that is best done within Druid. Unfortunately, dark-light
does not have a method check and yield state change asynchronously. If you can point me in the right direction for where to put an infinite loop like that, I'll gladly update this PR.
Hi @nickolasclarke, thanks a lot for the PR! We were trying hard to zvoid having zbus
in the dependency tree, as it drags a ton a stuff inside, slowing down the build :( Maybe we could add an off-by-default feature for this, or use a different library? What do you think?
I think either would work. I'll poke around for another library that does this cross-platform.
@jpochyla coming back to this, it looks like zbus + zvariant are only used in the freedesktop based GUIs, which we could use the the dbus crate which may be a bit lighter? Otherwise, I am unsure on how to implement this cleaner.
@jpochyla bumping this. Any thoughts on my latest comment?
@nickolasclarke I can have a look at this and see if we can merge it!
Edit: I made some small code structure changes based off a previous dark/light theme PR. The last thing I would want to see if its possible is to detect the dark/light theme when selected. If you change the system setting and then reselect "System" it doesn't reflect the new system setting.
@jacksongoode yeah, I called that out in my PR. I wasnt sure at the time on how to get dark-light to asynchronously yield whenever the system state changes. AS such, I was going to just put an infinite watcher loop in, but was not sure on the best place for it.
Also @jpochyla didn't want zbus, so I did some research for alternative crates and found dbus. I could refactor this PR to use that, though I am not sure if that addresses the concerns about making build times blow up.
Comparing build times from main, (~7, ~30, ~12min) I don't think this PR actually increases the build times dramatically? If you want to compare this a little bit more you can but I feel somewhat comfortable allowing dark-light
for now. I think the one thing that would be nice, instead of a watcher, could you make it such that the selection of system and the theme options causes a trigger to check the current system light or dark state? I don't think we need constant polling, just maybe when a selection is made.
@jacksongoode fine by me. Iirc, it did do that at the time, I'll try this again to see current state. But if you did select system, it would not update again once the system theme changes. I ran into this with my system automatically changing theme and light temperature based on sunrise and sunset. As such, I think a constant poller would be required.
Chatgpt suggests something along these lines for zbus:
use zbus::{Connection, Result, proxy};
#[proxy(
interface = "org.freedesktop.appearance",
default_service = "org.freedesktop.appearance",
default_path = "/org/freedesktop/appearance"
)]
trait Appearance {
async fn get(&self, property: &str) -> Result<String>;
#[dbus_proxy(signal)]
async fn property_changed(&self, property: &str, value: &str);
}
// Although we use `async-std` here, you can use any async runtime of choice.
#[async_std::main]
async fn main() -> Result<()> {
let connection = Connection::session().await?;
// `proxy` macro creates `AppearanceProxy` based on `Appearance` trait.
let proxy = AppearanceProxy::new(&connection).await?;
// Subscribe to the `PropertyChanged` signal and provide a callback function.
proxy.connect_property_changed(|property, value| {
println!("{} changed to {}", property, value);
Ok(())
})?;
// Wait forever.
loop {
async_std::task::sleep(std::time::Duration::from_secs(1)).await;
}
}
I'll see if light-dark supports this already.
I was just reviewing other rust projects using zbus. I think a lot are migrating from dbus to zbus. I think this is fine generally. I think we need to use the use_zbus
feature of the souvlaki
package.
I'd like someone to test this version on Linux and make sure it works!
I'll actually test it today on arm Linux.
I did sleuth through the light-dark
crate to see if it had this property_changed
watcher functionality we would need, but I did not see it. If I get some time this weekend, I'll try to implement it here.
@nickolasclarke I believe we need to wait for this to get merged https://github.com/frewsxcv/rust-dark-light/pull/26
@jacksongoode ahh, good find.
Well that PR got merged so once they update, we should try again!