[MacOS][winit] File dialog doesn't open when the application is started from a fullscreen terminal
Hi,
Really great library, love it!
I found a weird behavior that you can see on the screenshot:
Here, I pressed S and the file dialog is in fact open. I can confirm that because my touchbar gives me two choices:
- Cancel
- Save
How To Reproduce
- Open a terminal in fullscreen
- Reach the
winit-example - Run
cargo run - Press
S
Is the file dialog opening behind another window? That can happen even on Windows and Linux. I just tried the "simple" example on Linux (Ubuntu 20.04 LTS) from a full-screen console window. The dialog opened in front of the console window, but if you click on the console window, the console window comes to the front and hides the dialog.
I get that sometimes with my ui-mock test program.. Sometimes the dialog will open behind the main window by itself.
This is a serious problem with rfd. Modal dialogs stall out the parent window, but there's no guarantee the dialog is on top. If the parent window is full screen, you're stuck. Huge problem for game-type programs, where you usuallly have a full screen window with no system close or cancel buttons. If the dialog gets stuck behind that, there's no easy way to get it in front. Modal dialogs need a force-to-front capability.
It might be better to use an async dialog, but, from other issues, that appears to not work on Mac and may have memory corruption problems on Windows.
Unrelated to the described issue, macOS backend supports window parenting (windows as well), so the issue is just about the edge case with full-screen window in the back. On the other hand, the issue described by you is referring to the lack of parenting support in GTK3 and XDG-portal backends. (xdg portal one is already tracked issue, GTK I'm not even sure if it is possible, and I want to faze it out anyway)
Also, not sure what you are referring to, when saying that macos async backend is not working.
I haven't tried on MacOS. That's based on the RFD documentation:
macOS async dialogs require an NSApplication instance, so the dialog is only truly async when opened in windowed environment like winit or SDL2. Otherwise, it will fallback to sync dialog. It is also recommended to spawn dialogs on your main thread. RFD can run dialogs from any thread but it is only possible in a windowed app and it adds a little bit of overhead. So it is recommended to spawn on main and await in other thread. Non-windowed apps will never be able to spawn async dialogs or from threads other than the main thread.
I understood all those disclaimers to mean "Async doesn't really work right on MacOS". However, all I want to do is pop up a dialog async while using winit, although possibly with winit asking for full screen. Will that case work reliably on Linux, Windows, and Mac? And in async mode, is there some way I can get the file picker to reliably display in front of the main window? Even if the user clicks on the main window while the file picker is displayed? Thanks.
What this does means is: you have to have a macOS event loop running in your process, so it can dispatch async events, it also allows us to ask the even loop to run stuff on the main thread. Every winit app already has one running, as winit EventLoop is just a wrapper around it. So all of those disclaimers are targeted at CLI apps only.
As for feature set of async dialogs, it should be the same as sync ones:
- macOs is an exception as async allows us to use more modern sheet modal dialog.
- GTK3 async/sync dialogs share the configuration of the dialog code.
- XDG Portal sync dialogs are just a
block_on(async_version_of_the_dialog())as XDG Portal is awesome and the API is async first. - Windows async dialogs are wrappers around sync versions.
As for parenting:
- macOs: This issue is the only one I know about so far, it should just open permanently attached sheet dialog, moving it moves the parent window as well, etc.
- GTK3: No parenting at all / XDG Portal: Parenting support in progress upstream.
- windows: Parent window is set by RFD, I don't remember exactly how does windows treat full-screen parent windows, but it should work.
Thanks, that's very helpful. I now have async file pickers working on both Windows and Linux. Have not been able to test on Mac yet.
Still have trouble with the file dialog getting behind the main window, though. Winit offers set_always_on_top(&self, always_on_top: bool), which you could call, but I can't, because it's not my window.
Current workaround:

Could you try disabling default gtk3 feature and enabling the xdg-portal one, neither one supports parenting in RFD but perhaps portal one will have better z-ordering
Actually, for both Windows and Linux, the file picker normally comes up in front of the main window in async mode. So default Z-ordering is OK. The only problem is that if the user clicks on the main window while the file picker is still launching, the main window becomes the front window and the file picker comes up in back. This tends to happen when opening a file in a large directory, which slows the file picker.
Winit has
pub fn set_always_on_top(&self, always_on_top: bool)
and
pub fn focus_window(&self)
for forcing a window to the front. But it lacks the opposite operations for telling a window to go to the back of the program's windows and get out of the way. So there's nothing I can call on my side to force my window into background.
It's a frustrating area. Egui, winit, rfd, and the platform-native systems are all interacting here, and not quite playing well together. For now, I'll put up the warning message when the file picker is supposed to be in front, but a more elegant solution would be nice.
The proper way to keep the dialog on top is to set its parent window, all platforms except Linux should support that already, if it is not the case open an issue. Even if you decide to use the always on top hack, keep in mind that all modern Linux compositors don't have a concept of allways_on_top or focus_window. You have to set the parent of a dialog, and that is WIP upstream (#46)
Thanks: Now calling "set_parent" for the async file dialog.
-
Windows (well, Wine 7): works perfectly. File dialog stays in front, even if the parent window is clicked upon.
-
Ubuntu 20.04 LTS (Gnome, X): has no effect. File dialog appears on top by default but clicking on the parent window will bring the parent window to the front, hiding the file dialog.
-
Mac - untested. If someone wants to build ui-mock on Mac, please do so.
This is good enough for now. The Windows users won't have a problem. Linux users expect the window manager to be troublesome and are tolerant of UI problems. Per above notes, work is underway for the Linux side. So, thanks.
Yeha, the thing with linux is there is no system dialog, everyone has their own dialogs, so GTK3 was in practice a fallback, but XDG Portal standard solved that problem now, so as soon as rust xdg portal ecosystem matures a bit we will use it to parent a window, and the window manager will handle the rest.