Command line arguments

Hi there!

I am developing an editor. As such, I need it to be able to open documents - a cool way to do this, would be for the user to drag a file over the application icon in the finder and/or dock.

Now, I have figured out how to make the bundle accept certain file types (the CFBundleTypeExtensions in info.plist). I would imagine that the file I drag over the app icon becomes a commandline argument for the application. Somewhere along the way, though, the commandline arguments become a baffling (for example) “-psn_0_167977” - all on the form “-psn_0_<*>” - even if I launch the application without dragging anyfile over… Where does this go wrong?

Thank you kindly!

  • A

That’s pretty strange, presumably these are some kind of reference to a clipboard object, though I’ve no idea how you’re supposed to retrieve them…

Oh… Right. I just realized that no matter what, the Juce forum is a wildly inappropriate place to ask that question.

Anyway, if (when) I figure out the solution, I could maybe put it here, so that Juce could do the right stuff - e.g. fish out the path or similar.

Thanks,

  • A

Sure - if you can point me in the right direction, it’s probably a really useful thing to add to the library.

Hi amygdala,

Not sure if you figured this one out, but if not (and for future searchers) the way to do this is actually (after hours of searching!) very simple with juce.

You put your file open handling code in your overridden:

JUCEApplication::anotherInstanceStarted (const String& commandLine)

and the commandLine passed into here will be the filename of the file dragged onto the app icon (or double clicked if an associated file).

The reason this works is because Juce DOES handle the ‘odoc’ apple event in the AppDelegateRedirector class in juce_mac_MessageManager.mm, and calls the JUCEApplication’s anotherInstanceStarted method with the filename.

Not totally obvious or documented, but works :stuck_out_tongue:

And yes it seems to work fine even if another instance isn’t already running, I guess the Mac Launch Services launches your app, then sends the odoc (Open Document) event to another instance of the delegate, which realises the first instance is already running and calls it’s ‘anotherInstanceStarted’ method.

Ah,

Although this works fine for single files, there’s a slight problem when you drag multiple files onto an apps icon, if the filenames have a space in them.

The code in the delegate to handle this (from juce_mac_MessageManager.mm) is:

[code]virtual void openFiles (NSArray* filenames)
{
StringArray files;
for (unsigned int i = 0; i < [filenames count]; ++i)
files.add (nsStringToJuce ((NSString*) [filenames objectAtIndex: i]));

    if (files.size() > 0 && JUCEApplication::getInstance() != 0)
    {
        JUCEApplication::getInstance()->anotherInstanceStarted (files.joinIntoString (T(" ")));
    }
}[/code]

as you can see that just adds a space between the filenames, so if you have two text files you’re dragging onto the app icon you’ll get anotherInstanceStarted() called with the parameter:

Jules, would it be possible to add quotes around the filenames (and escape the filenames) so this’d come thru as:

graf

This is absolutely wonderful!! Thank you so much for telling me this. Beer is on me!

  • A

Sorry, I’d forgotten to add those quotes - will do that now.

[quote=“graffiti”]Hi amygdala,

Not sure if you figured this one out, but if not (and for future searchers) the way to do this is actually (after hours of searching!) very simple with juce.

You put your file open handling code in your overridden:

JUCEApplication::anotherInstanceStarted (const String& commandLine)

and the commandLine passed into here will be the filename of the file dragged onto the app icon (or double clicked if an associated file).

The reason this works is because Juce DOES handle the ‘odoc’ apple event in the AppDelegateRedirector class in juce_mac_MessageManager.mm, and calls the JUCEApplication’s anotherInstanceStarted method with the filename.

Not totally obvious or documented, but works :stuck_out_tongue:

And yes it seems to work fine even if another instance isn’t already running, I guess the Mac Launch Services launches your app, then sends the odoc (Open Document) event to another instance of the delegate, which realises the first instance is already running and calls it’s ‘anotherInstanceStarted’ method.[/quote]

Hi graffiti and amygdala,
Which version of juce are you guys using. Because I have implemented “anotherInstanceStarted” but when my custom files are clicked I don’t get the file path. I just get a string of this form “-psn_0_159783”. Did you guys make any changes to info.plist of your application ? Any help on this matter will be highly appreciated.

Hi there,

As indicated above, the solution worked for me. I had done alot of different stuff to make it work before this solution came along, so maybe my success is a combination of all that. I di, however, edit the info.plist. It’s been a while, but I think maybe this could help you. The following is an extract of my info.plist, with a part that may be relevant - I am writing an audio editor, so the file-types I am interested in are .aif and .wav:

<key>CFBundleDocumentTypes</key>
	<array>
		<dict>
			<key>CFBundleTypeMIMETypes</key>
			<array>
				<string>audio/x-aiff</string>
				<string>audio/x-wav</string>
			</array>
			<key>CFBundleTypeExtensions</key>
			<array>
				<string>aif</string>
				<string>wav</string>
			</array>
			<key>CFBundleTypeRole</key>
			<string>Editor</string>
			<key>LSHandlerRank</key>
			<string>Owner</string>
			<key>CFBundleTypeIconFile</key>
			<string>SpeakerIcon</string>
			<key>LSTypeIsPackage</key>
			<false/>
		</dict>
	</array>

God speed!

There are two small problems…

  1. When the application includes a splash screen, the application does not forward the initial openFile message to anotherInstanceStarted.

  2. When opening a single file whose name includes a space, the filename is not quoted. There is no way to tell if the user asked to open one file with spaces or two files without. This is easy to solve, include

    virtual BOOL openFile (NSString* filename)
    {
        if (JUCEApplication::getInstance() != 0)
        {
            String juceFilename=nsStringToJuce (filename);
            if (juceFilename.containsChar (' '))
                juceFilename = juceFilename.quoted('"');                                                                               
            JUCEApplication::getInstance()->anotherInstanceStarted (juceFilename);                                                     
            return YES;                                                                                                                
        }                                                                                                                              
                                                                                                                                       
        return NO;                                                                                                                     
    }                                                                                                                                                

on line 71 of juce_mac_MessageManager.mm.

I’m sure this has been discussed elsewhere, but if you run a modal loop during the initialisation method, OSX refuses to send you any files until it has finished. As a workaround, either use a background thread, or just trigger a timer or async callback to do your modal stuff after the initialise method has finished.

And good idea about the quotes, thanks!