We were debugging some issues around opening files with a JUCE based macOS app by double clicking the file, dropping it on the application icon or passing the file as parameter on the command line.
These events all seem to trigger the NSApplication application:openFiles: method. Its implementation in juce_MessageManager_mac.mm looks like this:
addMethod (@selector (application:openFiles:), [] (id /*self*/, SEL, NSApplication*, NSArray* filenames)
{
if (auto* app = JUCEApplicationBase::getInstance())
{
StringArray files;
for (NSString* f in filenames)
files.add (quotedIfContainsSpaces (f));
if (files.size() > 0)
app->anotherInstanceStarted (files.joinIntoString (" "));
}
});
So we see, the JUCE reaction to receiving this event is concatenating the list of files passed to it and passing that to the anotherInstanceStarted callback. This also happens for the quite similar application:openFile: method and in the getUrl:withReplyEvent: which happens to an AppleEvent indicating that a URL should be handled by the application (as a sidenote, I was surprised why not simply NSApplication application:openURLs: was handled instead but there might be some good explanation for that).
This leads to anotherInstanceStarted being fired in a situation where there is only a single instance running, which is kind of unexpected and took us some time to understand.
My request here would be at least to clearly clarify this additional use-case of the callback in the member functions documentation, since it’s not obvious at all.
If you want to take it one step further would even suggest of adding a more targeted callback, inteded for that very use case containing a default implementation that forwards to anotherInstanceStarted to maintain backwards compatibility. Might be looking something like this
/** Might be invoked when the system asks the running application to handle certain files or URLs.
Use URL::isLocalFile() to find out if the resource is a local file.
To maintain backwards compatibility, this will forward the request as a concatenated whitespace
separated string to anotherInstanceStarted.
@note: This is currently only implemented on macOS.
*/
virtual void JUCEApplicationBase::openFileOrUrlRequested (std::span<const juce::URL> resourcesToOpen)
{
StringArray asStrings;
for (const auto& resource : resourcesToOpen)
asStrings.add (resource.toString (true)); // of course some quouting logik missing here
anotherInstanceStarted (asStrings.joinIntoString (" "));
}
Note: I didn’t check the implementation on any other platform but Windows where I’m not aware of a mechanism like that, that made me come to the conclusion that this might be a macOS only issue. The docs of anotherInstanceStarted however state that it is currently only implemented on Windows and Mac anyway so I didn’t dig futher.