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

Notifications #26

Merged
merged 25 commits into from
Apr 13, 2024
Merged

Notifications #26

merged 25 commits into from
Apr 13, 2024

Conversation

edfloreshz
Copy link
Collaborator

@edfloreshz edfloreshz commented Dec 30, 2022

Implements a subscribe function that returns a stream that yields a new mode every time a theme change is detected in the OS.

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    while let Some(event) = dark_light::subscribe().await?.next().await {
        if let Event::ThemeChanged(mode) = event {
            println!("System theme changed: {:?}", mode);
        }
    }

    Ok(())
}

Closes #3

@edfloreshz edfloreshz mentioned this pull request Dec 30, 2022
6 tasks
src/freedesktop/notify.rs Outdated Show resolved Hide resolved
Copy link

@BlackHoleFox BlackHoleFox left a comment

Choose a reason for hiding this comment

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

This is just a driveby review from someone who wants to use this crate in a project, disregard what you or the crate owner would like to:

src/freedesktop/notify.rs Outdated Show resolved Hide resolved
async fn non_freedesktop_watch(tx: Sender<Mode>) -> anyhow::Result<()> {
let mut mode = detect();
loop {
let new_mode = detect();

Choose a reason for hiding this comment

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

Is this a busy loop?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, I'm still figuring out a way to replace this loop with something better, suggestions are welcome.

src/macos/notify.rs Outdated Show resolved Hide resolved
src/windows/notify.rs Outdated Show resolved Hide resolved
@edfloreshz edfloreshz self-assigned this Aug 13, 2023
@edfloreshz edfloreshz added the enhancement New feature or request label Aug 13, 2023
@edfloreshz
Copy link
Collaborator Author

The Linux implementation should be good to go, macOS and Windows still need some work.

@frewsxcv could you help me test these changes?

src/freedesktop/notify.rs Outdated Show resolved Hide resolved
Copy link

@d2weber d2weber left a comment

Choose a reason for hiding this comment

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

I just pointed out a few things noted. Sidenote: I authored the #152 and #153 that landed in ashpd to return the stream (also because I was interested in color scheme changes). Note that while testing I encountered duplicate change messages that you might want to mitigate.

use super::{CINNAMON, GNOME, MATE};

pub fn detect() -> Mode {
match legacy_detect() {
Copy link

Choose a reason for hiding this comment

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

You might also want to check for the freedesktop.portal color theme by blocking on this async fn https://docs.rs/ashpd/latest/ashpd/desktop/settings/struct.Settings.html#method.color_scheme

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Is there a way to do this without locking the crate to a specific runtime?

Copy link

Choose a reason for hiding this comment

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

Not sure which would be the right way to do that. Maybe using block_on from async_io and switch to tokois if the tokio feature is enabled (that's the way, zbus offers it's blocking APIs).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thanks, I'll implement more runtimes it once we test with tokio.

src/lib.rs Show resolved Hide resolved
@edfloreshz
Copy link
Collaborator Author

I encountered this as well using KDE Plasma, oddly I could not replicate this when switching the color scheme using the terminal.

@edfloreshz edfloreshz force-pushed the notifications branch 2 times, most recently from 5751efd to f7ac529 Compare August 14, 2023 01:52
@d2weber
Copy link

d2weber commented Aug 17, 2023

I encountered this as well using KDE Plasma, oddly I could not replicate this when switching the color scheme using the terminal.

For me there are duplicates also when I use gsettings set org.gnome.desktop.interface color-scheme \'default\'

@edfloreshz
Copy link
Collaborator Author

I tried with Color Scheme Simulator and I wasn't able to replicate the issue. This may be related either to how DEs handle the color scheme change or ashpd.

@bilelmoussaoui
Copy link

It is not related to ashpd, it is a portal backend issue. As they listen to changes happening on the host and forward them through the portal, the signal ends up being emitted twice

@edfloreshz edfloreshz force-pushed the notifications branch 3 times, most recently from f4e93ed to f5e7a95 Compare February 5, 2024 10:47
@edfloreshz
Copy link
Collaborator Author

edfloreshz commented Feb 5, 2024

I haven't tested on macOS but Windows and Linux are working fine.

The current implementation is using tokio but we could implement other runtimes in the future.

@frewsxcv Would you mind taking a look?

Copy link

@d2weber d2weber left a comment

Choose a reason for hiding this comment

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

I Just took a quick look on this.

I'm thinking about, what a ThemeWatcher really is, and I believe it really is just a Stream. So the most obvious interface to me would be similar to ashpd's: a function returning a stream. I don't know how difficult it is to implement for platforms that are not supported by ashpd. An advantage might be, that the only dependency needed would be stream_utils.

@edfloreshz
Copy link
Collaborator Author

edfloreshz commented Feb 7, 2024

@d2weber is this what you had in mind?

use std::task::Poll;

use futures::{stream, Stream};

use crate::{detect, Mode};

#[derive(Debug)]
pub enum Event<T> {
    ThemeChanged(T),
    Waiting,
}

pub fn subscribe() -> impl Stream<Item = Event<Mode>> + Send {
    let mut last_mode = detect();

    stream::poll_fn(move |_| -> Poll<Option<Event<Mode>>> {
        let current_mode = detect();

        if current_mode != last_mode {
            last_mode = current_mode;
            Poll::Ready(Some(Event::ThemeChanged(current_mode)))
        } else {
            Poll::Ready(Some(Event::Waiting))
        }
    })
}

This is how you would consume it.

let mut stream = subscribe();

while let Some(event) = stream.next().await {
    if let Event::ThemeChanged(mode) = event {
        println!("System theme changed: {:?}", mode);
    }
}

I was returning an Option<Mode> but I wrapped it in a custom enum to make it clear what was happening.

@edfloreshz edfloreshz requested review from Be-ing and removed request for BlackHoleFox February 11, 2024 04:54
@edfloreshz edfloreshz force-pushed the notifications branch 2 times, most recently from bb379d9 to ccbbe8a Compare February 11, 2024 05:57
@edfloreshz
Copy link
Collaborator Author

I re-implemented this to use futures and Stream as it makes more sense that way.

If someone could help me review before merging I'd appreciate it.

@BlackHoleFox
Copy link

saw that a review was requested of me the other day, can probably get to this sometime during the week if that works?

Definitely think a Stream is the right idea for this :)

- Removed Settings struct as it was not necessary.
- Removed `Settings` parameter from `freedesktop_watch`.
- `get_freedesktop_color_scheme` matches `ColorScheme` instead of `u32`
When the settings proxy is unable to init, legacy is used as fallback.
- Upgraded to the master branch of ashpd
- Moved the thread spawning to `notify`
- Made the async methods return `anyhow::Result<T>`
- Using xdg to find config files on Linux/BSD systems.
- Quality of life improvements
- Cleaned Cargo.toml
- Modified notify to take a closure.
- Fix wasm issue.
- Moved RGB logic to a single file.
- Added documentation.
- 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.
- Added support for Freedesktop.
- Added generic implementation for all platforms except freedesktop.
- Switched notify implementation to use streams.
- The stream is now using Poll::Pending to wait for a new event instead of returning a value when waiting.
@edfloreshz edfloreshz merged commit 77ae434 into frewsxcv:main Apr 13, 2024
4 checks passed
@jacksongoode
Copy link

jacksongoode commented Jul 24, 2024

@edfloreshz Was there a reason tokio was added as a dependency here? It seems it's only being used in the example?

Also curious why zbus was bumped down?

@edfloreshz
Copy link
Collaborator Author

Yeah, it was added as a dev-dependency to showcase the example.

As for zbus, that might've been an oversight on my end.

@nickolasclarke
Copy link

@edfloreshz the latest build is from April 3, but this was merged 10 days later. Could you cut a new release?

@edfloreshz
Copy link
Collaborator Author

Made an issue to keep track of this: #38

@d2weber
Copy link

d2weber commented Jul 25, 2024

Also curious why zbus was bumped down?

Zbus has become a transient dependency through ashpd

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add new function that takes a callback which gets run whenever dark/light mode changes
7 participants