slint-ui / slint

Slint is a declarative GUI toolkit to build native user interfaces for Rust, C++, or JavaScript apps.
https://slint.dev
Other
17.36k stars 589 forks source link

Callbacks for invoke_from_event_loop() and Weak::upgrade_in_event_loop() should support return values #5329

Open npwoods opened 4 months ago

npwoods commented 4 months ago

Is there a reason that callbacks for invoke_from_event_loop() and Weak::upgrade_in_event_loop() do not support return values?

Currently I have to write code that looks like this:

let cancelled = Arc::new(AtomicBool::new(false));
let cancelled_clone = cancelled.clone();

dialog_weak
    .upgrade_in_event_loop(move |dialog| {
        ...
        cancelled_clone.store(dialog.get_cancelled(), Ordering::Relaxed);
    })
    .unwrap();
let cancelled = cancelled.load(Ordering::Relaxed);

It would be great if I could do this:

let cancelled = dialog_weak
    .upgrade_in_event_loop(move |dialog| {
        ...
        dialog.get_cancelled()
    })
    .unwrap();

Of course, the return value would have to support Send but that sort of thing goes with the territory.

ogoffart commented 4 months ago

They could return a Future such as slint::JoinHandle. This would unfortunately be a breaking change, I think. So If we want to have support of this before Slint 2.0, it would need to be another function name.

ogoffart commented 4 months ago

Note that the code that you wrote with an atomic will not work, because the callback will be run in another thread and can be run after you check the cancelled

As of now, you can use tokio channel.

For example (untested, please let me know if you find mistakes)

let (tx, rx) = tokio::sync::mpsc::channel(1);
dialog_weak.upgrade_in_event_loop(move |dialog| {
   let c = dalog.get_cancelled();
   tx.send(c).unwrap();
}).unwrap();

let cancelled = rx.recv().await.unwrap();

You can use std's channel if you don't want to use async channel.

npwoods commented 4 months ago

Yes, I learned (the hard way) that what I proposed wouldn't work - and yes there are plenty of ways to snake a return value out of such a callback, but none of them would be as convenient as a hypothetical invoke_from_event_loop_with_retval() function or the equivalent.

I'll defer to you guys what should happen to this specific GitHub issue