LWJGL / lwjgl3

LWJGL is a Java library that enables cross-platform access to popular native APIs useful in the development of graphics (OpenGL, Vulkan, bgfx), audio (OpenAL, Opus), parallel computing (OpenCL, CUDA) and XR (OpenVR, LibOVR, OpenXR) applications.
https://www.lwjgl.org
BSD 3-Clause "New" or "Revised" License
4.73k stars 632 forks source link

Native File Dialog crash on macOS with Swing #697

Open qurben opened 2 years ago

qurben commented 2 years ago

Version

3.3.0

Platform

macOS x64

JDK

Oracle Java SE 16.0.1+9-24

Module

lwjgl-nfd

Bug description

Using NFD_OpenDialog on Mac from an action listener inside the swing dispatcher thread causes a NSInternalInconsistencyException which crashes the application. On other platforms (Windows/Linux) the code executes as expected.

Is this an error in 1) my code, 2) lwjgl-nfd or 3) nativefiledialog?

See https://github.com/qurben/lwjgl-nfd-testing for a simple example.

Stacktrace or crash log output

`2021-11-17 22:10:59.668 java[484:7119] *** 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                      0x00007fff4e11207d __exceptionPreprocess + 256
    1   libobjc.A.dylib                     0x00007fff7888ba17 objc_exception_throw + 48
    2   CoreFoundation                      0x00007fff4e12bbdd -[NSException raise] + 9
    3   AppKit                              0x00007fff4b6d15ca -[NSWindow(NSWindow_Theme) _postWindowNeedsToResetDragMarginsUnlessPostingDisabled] + 317
    4   AppKit                              0x00007fff4b6ce9f7 -[NSWindow _initContent:styleMask:backing:defer:contentView:] + 1479
    5   AppKit                              0x00007fff4b78dd95 -[NSPanel _initContent:styleMask:backing:defer:contentView:] + 50
    6   AppKit                              0x00007fff4b6ce42a -[NSWindow initWithContentRect:styleMask:backing:defer:] + 45
    7   AppKit                              0x00007fff4b78dd4a -[NSPanel initWithContentRect:styleMask:backing:defer:] + 64
    8   AppKit                              0x00007fff4bda54f5 -[NSSavePanel initWithContentRect:styleMask:backing:defer:] + 592
    9   AppKit                              0x00007fff4b99fdec +[NSSavePanel _crunchyRawUnbonedPanel] + 550
    10  liblwjgl_nfd.dylib                  0x000000012f5285f2 liblwjgl_nfd.dylib + 5618
    11  ???                                 0x0000000118ed7c7b 0x0 + 4713184379
)
libc++abi.dylib: terminating with uncaught exception of type NSException
Abort trap: 6
qurben commented 2 years ago

So according to the error something should be done from the main thread, but I am not sure if it is possible to do this from Java code.

https://stackoverflow.com/questions/53916139/terminating-app-due-to-uncaught-exception-when-i-run-my-cpp-file

Sylvyrfysh commented 2 years ago

You'll want to add the -XstartOnFirstThread argument either to the VM Arguments or the command line, depending on where you're running your code from.

qurben commented 2 years ago

Thanks for the response! With -XstartOnFirstThread the application doesn't seem to start. (I sadly do not have direct access to a mac where I can do testing on, got someone to test it with this flag)

qurben commented 2 years ago

I did come across this one, where it is mentioned that:

You can’t use Swing with lwjgl3 on OSX. As far as I know, there isn’t a way around that still.

Is that also what is happening here?

Sylvyrfysh commented 2 years ago

I believe so, and if I remember correctly (I may well not), the backend for both Swing and GLFW/GL cannot be used by both at the same time, causing hangups. Someone else would know better though, I am by no means a Mac expert.

Spasi commented 2 years ago

The problem is AWT (heavyweight, implemented on top of OS-specific APIs), not Swing (lightweight, implemented in Java on top of AWT).

The GLFW binary bundled with LWJGL does not contain any "Java-awareness" features, it's almost identical to what you'd get when building the upsteam project. It does not know anything about another windowing toolkit competing for the event loop on the main thread. It cannot interoperate with AWT.

However, there is apparently a way to modify GLFW to make it play nice with AWT, see https://github.com/badlogic/glfw/commit/1c213479bdf3e2a5ae68e4200e9d2fcd6ad31e27 and https://github.com/libgdx/libgdx/pull/6673. As always, impressive heroics by @badlogic. Technically, you could grab that binary and make LWJGL use it with Configuration.GLFW_LIBRARY_NAME (or -Dorg.lwjgl.glfw.libname=), right now. It is possible that LWJGL will adopt such a solution in the future (maybe by shipping two GLFW binaries on macOS), but I'm waiting to hear how it actually works in practice and seeing how hard it'll be to keep in sync with upstream changes.

badlogic commented 2 years ago

We've used this approach in Spine for years (with an outdated GLFW version). It basically just pushes all GLFW ooerations onto the main thread and waits synchronously for completion. Keeping this up-to-date with uostream GLFW is a very low maintenance burden.

On Wed, Nov 17, 2021, 21:24 Ioannis Tsakpinis @.***> wrote:

The problem is AWT (heavyweight, implemented on top of OS-specific APIs), not Swing (lightweight, implemented in Java on top of AWT).

The GLFW binary bundled with LWJGL does not contain any "Java-awareness" features, it's almost identical to what you'd get when building the upsteam project. It does not know anything about another windowing toolkit competing for the event loop on the main thread. It cannot interoperate with AWT.

However, there is apparently a way to modify GLFW to make it play nice with AWT, see @.*** https://github.com/badlogic/glfw/commit/1c213479bdf3e2a5ae68e4200e9d2fcd6ad31e27 and libgdx/libgdx#6673 https://github.com/libgdx/libgdx/pull/6673. As always, impressive heroics by @badlogic https://github.com/badlogic. Technically, you could grab that binary and make LWJGL use it with Configuration.GLFW_LIBRARY_NAME (or -Dorg.lwjgl.glfw.libname=), right now. It is possible that LWJGL will adopt such a solution in the future (maybe by shipping two GLFW binaries on macOS), but I'm waiting to hear how it actually works in practice and seeing how hard it'll be to keep in sync with upstream changes.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/LWJGL/lwjgl3/issues/697#issuecomment-971959659, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAD5QBHMW3HYX6RTOD546JDUMQFRTANCNFSM5IHPIW5A . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

qurben commented 2 years ago

Thanks! I'll look into that.

One thing that I not yet completely understand is what the role of glfw is when loading lwjgl-nfd. What I understand is that glfw is used in conjunction with OpenGL, but native file dialog does not interact with OpenGL (from what I've seen). Or am I approaching this the wrong way?

Spasi commented 2 years ago

NFD knows nothing about AWT (or GLFW) either. It works with [NSApplication sharedApplication], which the NSApplication created by either AWT or GLFW. However, it's still Cocoa code that needs to run on the main/first thread and a Swing event handler won't run on that.

Why use NFD though? Aren't the existing Java file choosers good enough?

qurben commented 2 years ago

I wanted a native file chooser for my project, with the option to add file filters. NFD and JavaFx seem to be the only ones offering this. Loading JavaFx for just the file chooser is a bit much for my project.

Would TinyFD have the same problems on mac?

badlogic commented 2 years ago

I've used tinfd successfully with my Glfw fork on macOS. Didn't try nfd.

On Thu, Nov 18, 2021, 10:39 Gerben Oolbekkink @.***> wrote:

I wanted a native file chooser for my project, with the option to add file filters. NFD and JavaFx seem to be the only ones offering this. Loading JavaFx for just the file chooser is a bit much for my project.

Would TinyFD have the same problems on mac?

  • JFileChooser (Swing): Supports file filters, Custom ui, slow for large directories.
  • FileDialog (AWT): Does not support file filters (on Windows at leas). Looks native.
  • FileChooser (JavaFX): Most complete version, can be plugged into Swing. But JavaFx is quite heavy and multi platform builds are not really an option. (works on mac?)
  • NFD(LWJGL): Supports file filters. Native file chooser. Can create multi platform jar.
  • TinyFD (LWJGL): Supports basic file filters. Native file chooser. Can create multi platform jar.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/LWJGL/lwjgl3/issues/697#issuecomment-972696249, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAD5QBFKRYA323677ZBYLXDUMTCW5ANCNFSM5IHPIW5A . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

qurben commented 2 years ago

So tinyfd uses applescript instead of cocoa on mac. It spawns a new process to show the filechooser, this circumvents the main thread problems.

elect86 commented 2 years ago

Hasn't anyone tried to get this resolved directly upstream?