Hey,
I was looking to use nfd or native file dialog, with iced. But it can only be accessed from the main thread, but when I access it from the main thread, the whole application freezes. Any alternatives, or ways to prevent it?
I'm allowing myself to just post a quick remark here.
On some platform, it's idiomatic to spawn a process to do this (e.g xdg-file-dialog), that might be a workaround of interest to you, in case the original issue is hard to solve.
But it can only be accessed from the main thread
Do you have a source explaining this limitation? Is it a platform limitation or a library one? I can't seem to find any mentions in nfd-rs or nativefiledialog.
I tried to invoke the nfd rs function when a message was formed on the main thread. But the application froze, so I figured a way around, may not be efficient, I put the nfd rs in a new process and spawned a child process. This way the application didn't freeze.
@emmanuelantony2000 You may be able to run it in a background thread with Command and a spawn_blocking future.
I was able to get this working without much issue by converting the nfd example into an async function, and calling it with a Command when the relevant button is pressed. I could try to put together a minimal example if it helps.
Here is the function that contains the nfd call in current code: https://github.com/aevyrie/tolstack/blob/6401ceab532c7433f343504cdc2cca190da87599/src/io/dialogs.rs#L5
And here is the update code that creates a Command and passes the new state to the top level application Loaded state when the "Open" button is pressed. This is similar to the iced todoMVC example.
https://github.com/aevyrie/tolstack/blob/6401ceab532c7433f343504cdc2cca190da87599/src/main.rs#L128
@aevyrie Glad to hear! Just a small nitpick, you should probably wrap the nfd call using spawn_blocking. A Future should never block!
@hecrj Great feedback, thank you!
@hecrj I attempted to add this, until I realized it's marked as an unstable feature, and started poking around.
According to this, spawn_blocking is no longer needed and deprecated in async_std:
https://async.rs/blog/stop-worrying-about-blocking-the-new-async-std-runtime/
The new runtime detects blocking automatically. We don鈥檛 need spawn_blocking anymore and can simply deprecate it.
@aevyrie That didn't end up landing after a lot of controversy: https://github.com/async-rs/async-std/pull/631
Gotcha, so do I need to enable unstable to get this to work then? It says it's private, and import seems to be behind these feature flags:
#[cfg(any(feature = "unstable", test))]
pub use spawn_blocking::spawn_blocking;
#[cfg(not(any(feature = "unstable", test)))]
pub(crate) use spawn_blocking::spawn_blocking;
Sorry, haven't used this before.
Yes, I believe so. You could also switch to tokio if you are not relying on any async-std libraries.
When I try using nfd with spawn_blocking, the app pinicked:
2020-06-11 23:53:14.968 nacho-zip[27954:3218461] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'NSWindow drag regions should only be invalidated on the Main Thread!'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff367b2be7 __exceptionPreprocess + 250
1 libobjc.A.dylib 0x00007fff6f58a5bf objc_exception_throw + 48
2 CoreFoundation 0x00007fff367db3dc -[NSException raise] + 9
3 AppKit 0x00007fff339d9ddc -[NSWindow(NSWindow_Theme) _postWindowNeedsToResetDragMarginsUnlessPostingDisabled] + 310
4 AppKit 0x00007fff339c1842 -[NSWindow _initContent:styleMask:backing:defer:contentView:] + 1416
5 AppKit 0x00007fff33ba25a5 -[NSPanel _initContent:styleMask:backing:defer:contentView:] + 50
6 AppKit 0x00007fff339c12b3 -[NSWindow initWithContentRect:styleMask:backing:defer:] + 42
7 AppKit 0x00007fff33ba255a -[NSPanel initWithContentRect:styleMask:backing:defer:] + 64
8 AppKit 0x00007fff3439f446 -[NSSavePanel initWithContentRect:styleMask:backing:defer:] + 97
9 AppKit 0x00007fff343a76f2 -[NSOpenPanel initWithContentRect:styleMask:backing:defer:] + 151
10 AppKit 0x00007fff33cfeb52 -[NSPanel init] + 75
11 AppKit 0x00007fff3439f3de -[NSSavePanel init] + 80
12 AppKit 0x00007fff340bd13b +[NSSavePanel(Instantiation) _crunchyRawUnbonedPanel] + 74
13 nacho-zip 0x000000010692f219 NFD_OpenDialog + 105
14 nacho-zip 0x000000010692a507 _ZN3nfd11open_dialog17hd530ae8eab34252cE + 1079
15 nacho-zip 0x000000010692a0b7 _ZN3nfd16open_file_dialog17h613856e1d957b0f7E + 39
16 nacho-zip 0x00000001068cd17f _ZN74_$LT$nacho_zip..nacho..Nacho$u20$as$u20$iced..application..Application$GT$6update28_$u7b$$u7b$closure$u7d$$u7d$28_$u7b$$u7b$closure$u7d$$u7d$17h18480f23c4ce3529E + 63
17 nacho-zip 0x00000001068f4375 _ZN9async_std4task14spawn_blocking14spawn_blocking28_$u7b$$u7b$closure$u7d$$u7d$17hff9da1016e8df429E + 85
18 nacho-zip 0x00000001068cc3e6 _ZN97_$LT$core..future..from_generator..GenFuture$LT$T$GT$$u20$as$u20$core..future..future..Future$GT$4poll17h2b896161b75148e3E + 134
19 nacho-zip 0x00000001068e8df0 _ZN10async_task3raw28RawTask$LT$F$C$R$C$S$C$T$GT$3run17h1d4402aa42b1318bE + 704
20 nacho-zip 0x000000010713ff13 _ZN10async_task4task13Task$LT$T$GT$3run17h4a7dbbcfc1c80b3eE + 99
21 nacho-zip 0x000000010710dbb1 _ZN4smol8blocking16BlockingExecutor9main_loop28_$u7b$$u7b$closure$u7d$$u7d$17hd5ebaa64fc453a4fE + 17
22 nacho-zip 0x0000000107126944 _ZN3std9panicking3try7do_call17h0b5ce9680977a9baE + 52
23 nacho-zip 0x000000010712bf8d __rust_try + 29
24 nacho-zip 0x00000001071267f0 _ZN3std9panicking3try17h8cc628ff394fb332E + 80
25 nacho-zip 0x0000000107140f48 _ZN3std5panic12catch_unwind17h657047b9b158abd2E + 24
26 nacho-zip 0x000000010710d804 _ZN4smol8blocking16BlockingExecutor9main_loop17h035995cce19e3fbbE + 372
27 nacho-zip 0x000000010710df14 _ZN4smol8blocking16BlockingExecutor9grow_pool28_$u7b$$u7b$closure$u7d$$u7d$28_$u7b$$u7b$closure$u7d$$u7d$17hd965991da4f559f7E + 20
28 nacho-zip 0x00000001071435c1 _ZN4smol7context5enter17h957120a9cbf13db7E + 17
29 nacho-zip 0x000000010710df3d _ZN4smol8blocking16BlockingExecutor9grow_pool28_$u7b$$u7b$closure$u7d$$u7d$17h81109feea65923d2E + 29
30 nacho-zip 0x0000000107126791 _ZN3std10sys_common9backtrace28__rust_begin_short_backtrace17h78be719b54aeefc7E + 17
31 nacho-zip 0x000000010711ab31 _ZN3std6thread7Builder15spawn_unchecked28_$u7b$$u7b$closure$u7d$$u7d$28_$u7b$$u7b$closure$u7d$$u7d$17hcb19ae9eeb48aa18E + 17
32 nacho-zip 0x000000010713fd11 _ZN101_$LT$std..panic..AssertUnwindSafe$LT$F$GT$$u20$as$u20$core..ops..function..FnOnce$LT$$LP$$RP$$GT$$GT$9call_once17he31b93dfdff7c6cbE + 17
33 nacho-zip 0x000000010712699a _ZN3std9panicking3try7do_call17h815673f7e6f18001E + 42
34 nacho-zip 0x000000010712bf8d __rust_try + 29
35 nacho-zip 0x00000001071268b5 _ZN3std9panicking3try17hef3c6cd1dd6e696aE + 69
36 nacho-zip 0x0000000107140f71 _ZN3std5panic12catch_unwind17h8e09845f9674f991E + 17
37 nacho-zip 0x000000010711a9b6 _ZN3std6thread7Builder15spawn_unchecked28_$u7b$$u7b$closure$u7d$$u7d$17hc058cf9594bfc4aeE + 230
38 nacho-zip 0x0000000107120121 _ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17hb69d886f423b793dE + 17
39 nacho-zip 0x000000010718daed _ZN3std3sys4unix6thread6Thread3new12thread_start17h15652ee16771ed61E + 45
40 libsystem_pthread.dylib 0x00007fff70936109 _pthread_start + 148
41 libsystem_pthread.dylib 0x00007fff70931b8b thread_start + 15
)
libc++abi.dylib: terminating with uncaught exception of type NSException
Process finished with exit code 134 (interrupted by signal 6: SIGABRT)
Looks like macOS requires some methods being called on the main thread. But if I use block_in_place, the entire app hangs.
Hey @balthild, I tried the same thing and faced the exact same issue, while blocking. So I tried doing the same thing in a different app (process) and getting the inputs to the former app using the std process module. It worked for me fine.
@emmanuelantony2000 Thanks! It's a great workaround.
Using nfd-rs with std::process (and tokio::process/async_std::process) has some problems. The file dialog is shown behind the app window, and does not focusable. If I package my app in an .app bundle, the file dialog becomes focusable but a console icon will appear on the dock.
I've switched to tinyfiledialogs. The library handles thread safety itself and it works fine with both spawn_blocking and block_in_place.
Edit: be attention, tinyfiledialogs have a scary security bug on Linux. See: https://github.com/jdm/tinyfiledialogs-rs/issues/19
Any chance of sharing a link to working code for this?
Thanks in advance
If your app targets GNU/Linux and Windows only, you could go ahend for nfd-rs or nfd2. It works well with spawn_blocking and block_in_place.
let result = tokio::task::block_in_place(|| nfd2::open_file_dialog(None, None));
// or
let result = tokio::task::spawn_blocking(|| nfd2::open_file_dialog(None, None)).await;
If your app targets macOS and Windows, yo could use tinyfiledialogs. The API of tinyfiledialogs is similar to nfd-rs. But do not use it in GNU/Linux or you will be likely to get an ACE vulnerability.
Edit: be attention, tinyfiledialogs have a scary security bug on Linux. See: jdm/tinyfiledialogs-rs#19
Hi, I am the author of tinyfiledialogs. I've just corrected this security issue in version 3.8.0.
tinyfiledialogs now detects the single and double quotes in titles, messages and various parameters.
The dialogs are still displayed but the faulty parameters are replaced with a warning.
Let me now if I can help. thanks.