JUCE6: Problems using native file chooser and FilePreviewComponent

I’m finally in the process of migrating my plugins from the last Juce5 version to Juce6. Most things worked out without issues, but I am seeing problems with my custom FilePreviewComponents and the native FileChoosers. Has something changed in Juce6? I am not seeing anything in the breaking change log.

On windows my FilePreviewComponent subclass doesn’t show up at all and instead some form of internal windows preview appears which is useless for my application.

On Mac OS X I see my component, but mouse events do not appear to work and I do not get the callback when file selection changes.

I then tried building the JUCE dialogsDemo example and when trying to open the native chooser the image preview is not working on OS X.
It does work with the JUCE chooser, but I don’t want to use that as IMHO the OS standard dialogs should be used to select files for multiple reasons.

It seems to me the FilePreviewComponent functionality is broken with native dialogs in multiple ways in Juce6. Has anyone had success with this?

On Windows, we switched to the newer IFileDialog API introduced in Vista, which provides a more familiar, modern-looking dialog view.

Unfortunately the newer IFileDialog doesn’t support the ‘hooks’ API which was previously used to provide the custom preview component. I don’t think there’s a perfect solution to this problem - the old file chooser looks very dated and doesn’t have the “recent/favourite folders” sidebar, but the new file chooser doesn’t support custom components. Perhaps we could look at adding some kind of option so that developers can choose between the old/new styles. Would that be an acceptable solution?

This sounds like a bug.

Thanks for the swift answer.

I think for the windows side, adding the change in the “breaking changes” file would be a great start. Then maybe there should be an assert or something similar if a custom component is passed into the current code. Right now it feels like juce is just ignoring the work I put into my custom component :slight_smile: . It would probably be best to deprecate/exclude the FilePreviewComponent on windows until there is a solution - that way it would break on compilation and not during testing.

I agree the old windows chooser dialog looks dated and the new one is a better choice. However not being able to use custom components might be a deal-breaker to many audio applications with custom sample/preset loading guis.
Surely that IFileDialog thing has some option for custom guis? Personally I wouldn’t mind coding something for windows only if JUCE had a way to add it without too much trouble. I think right now that would be quite terrible to do and probably mean coding the entire chooser from scratch.

I would prefer to use platform native custom file chooser extensions. The juce GUI inside the native GUI does look odd. At least in my case the custom chooser extensions are rather simple, but they are interactive - doing them for each platform would be ok and then they would visually fit the chooser - not to mention have different layouts that work good on all platforms.

Tried again. It works fine with the Juce chooser, but with native the whole custom component just acts like an area to drag the window around.

I made some more experiments on OS X and it is working better than I thought. Inside a plugin everything is fine, but on a standalone build, something blocks the mouse events. I was also wrong about the selection change callback. It does work. The problem is just mouse events/standalone/OSX and not appearing at all on windows due to the api switch.

There were a few issues with the macOS custom preview components, which I’ve addressed in these commits:

On windows, we’ll now use the old-style file chooser window if a custom preview window is requested, but use the new-style window otherwise:

1 Like

Thanks for the fixes. It’s much better now, but a few issues remain (on OSX 10.13).

The ProJucer DialogsDemo image preview demo still does not show up. My own preview component however does show up and works inside a plugin.

If I quit the host when a fileChooser is open inside a plugin (including a previewComponent), I get a crash on exit in Desktop::~Desktop() on the line

   jassert (desktopComponents.size() == 0);

I don’t have a machine running 10.13, but I tried building against the 10.13 SDK and couldn’t reproduce this issue. Note that the demo component is transparent, so if you didn’t actually select an image, the view would have remained empty.

Can you specify which platform, host, and plugin format you were using, please? I can’t reproduce this with VST3 or AU in Reaper or the AudioPluginHost. Are you definitely destructing the FileChooser instance before your AudioProcessor destructor runs?

Ah, I can reproduce this issue in Reaper now. I’ll investigate a fix.

Sorry about the first issue… It appears to work now. Maybe my recompile wasn’t as complete as I thought (blush).

I’m running OSX 10.13, AU format in AU Lab. I am not destructing the FileChooser instance. I run it modally and am expecting JUCE to cleanup the preview component in case the host is quit. Am I expecting wrong?
I just create an instance of FileChooser, add the preview component and call

	if (chooser.browseForFileToOpen(openSamplePreview.get())) {

Then I quit AULab and get the crash as the preview component doesn’t seem to be destroyed.

I tried again in Live and cannot reproduce it.

Ok. I’m glad to hear you were able to reproduce in Reaper because now I don’t seem to be able to do it in AU Lab anymore. In LIVE it’s not even possible to quit live while the dialog is open… so maybe there is some randomness included in the issue.

Maybe the crash only becomes visible with a debugger attached. That’s what happens for me in AU Lab. Without debugger, no crash and no log. When running from XCode I get the crash on quit. Actually it’s not a crash, but a jassert(), so this makes perfect sense.

So in fact it’s not a big problem, just some missing cleanup in an edge case and won’t matter to customers that won’t get the assert.

I dug into the crash a bit, and it seems like it happens due to the modal dialog box. If I make the FileChooser a data member of my PluginEditor, and launch it with launchAsync, it’s possible to quit the host while the dialog is open without hitting any assertions.

In more detail, it seems that running the FileChooser synchronously starts a new message loop at the point where the FileChooser is launched. If the app receives the ‘terminate’ event, this event is processed by this new ‘inner’ message loop, which runs the host’s terminate-handler. Then, the host may run the plugin’s destructor, even as the FileChooser modal loop is still running! This will lead to all sorts of problems, particularly use-after-free issues. Unfortunately there’s no way from within JUCE to prevent the host from processing the terminate event.

I’ve tried setting preventsApplicationTerminationWhenModal on the save panel, which helps in a few cases, but some hosts seem to override this. I’ve added a new jassert which warns if this behaviour has been hijacked.

All of this is to say: if it’s possible for you to switch your FileChoosers to run asynchronously rather than synchronously, I would highly recommend making that change as it will greatly improve the robustness of your plugin.

1 Like

Thank you for your work! And yes I think I can rewrite my code to use the asynchronous methods. The modal ones should maybe be banned in the long run. Lambdas do make asynchronous dialogs quite painless, and therefore the modal stuff is probably no longer needed.