Closed rednoah closed 8 years ago
I wasn't aware of this issue. Can you post a simple test case that demonstrates the deadlock?
On specific MBP models (the most expensive ones with dedicated GPU, so few people have those), it'll deadlock every time when you call dispatch_sync
running NSOpenPanel.runModal
from the Swing EDT, but on most Mac computers (including mine) it'll never happen. It may or may not have something to do with calling NSOpenPanel.runModal
in a sandboxed application.
It should be reproducible with your NativeFileDialog
code, unless Worker.post
somehow works around the issue.
The NativeFileDialog code uses the Foxtrot framework to allow you to block the current event on the EDT without blocking the others. Basically it spawns a new EDT that continues to process the event queue while your particular event is blocked.
So, yes Worker.post() works around the issue.
Calling NSOpenPanel.runModal() should never be called directly on the Swing EDT. It should run on the cocoa main thread (i.e. inside dispatch_async()). Technically wrapping it in dispatch_sync() solves that problem (runs on main thread) but because it causes the EDT to block until it is done, it can lead a lockup.
Maybe you could add a few comments to your example usage, to make it clear that NativeFileDialog
must not be used on the EDT, and that Worker.post()
must be used:
https://gist.github.com/shannah/65007754c2b0f8add4f7#file-example_directory_dialog-java
OK. I added a comment in the javadocs.
@shannah would be excellent if you added a check of sorts if the NativeFileDialog is created the right way. I had some issues with it, because I somehow overlooked your comment in the docs :)
Thanks :)
@b005t3r Even better would be to just implement the Worker inside the setVisible method. I'll update it when I get a chance.
@shannah that would be fantastic :)
BTW, there's one more thing needed if you want to use FoxTrot's Worker for this thing. It turns out that in 2024 you can't just access whatever you want via the reflection API, so you need to start your VM with these two params to allow acceess to whatever Worker is accessing:
--add-opens=java.desktop/java.awt=ALL-UNNAMED
--add-opens=java.desktop/sun.awt=ALL-UNNAMED
If you're calling
dispatch_sync
there's a chance that it'll freeze the application, especially on the high-end MBPs with dedicated GPU and automatic graphics switching. I guess the Swing/Cocoa EDTs somehow end up waiting for each other, in certain rare cases.The problem can be solved by using Cocoa
dispatch_async
and AWTSecondaryLoop
instead: https://docs.oracle.com/javase/8/docs/api/java/awt/SecondaryLoop.htmlThere goes a few sleepless nights... I hope this helps someone!