NSApplicationDelegate prevent window if command line present - cocoa

I have a simple single window app, with a drop target on it for files. This works fine. However, I also want that when it is started with a command line, it just processes those files instead, rather than showing a window.
Is there a delegate method in NSApplicationDelegate that I can prevent the window from showing, process the files and quit the application in?

You can set the window not to show when loaded from the nib file. There's a setting in the inspector in the Interface builder.
Then you can show the window if necessary, using methods described in this documentation.
But this will still show the icon in the Dock while your app is processing the file.

You can prevent showing the main window like Yuji said. There's also a notification called applicationDidFinishLaunching:
There you can process your files and quit the application with [[NSApplication sharedApplication] terminate:self];

The most maintainable and simple approach I've seen to this is to put your commandline version in a separate executable as a simple Foundation program, and then make your Cocoa program just call it, handling the UI. Doing it this way gets rid of many of the things you'd need to work around. You can then install links to your commandline version where you like.
If you dislike using NSTask for this, then put your logic into a shared framework, and layer GUI and commandline apps on top of it.

Related

How do you create a NSWindowController for a xib-based (not storyboard-based) app?

I have an application that's not based on storyboards, but rather xib files. Main.xib contains the main application window. However, it's just a window. There's no NSWindowController. How can one be added?
Ok, figured it out. You simply add a new object to the scene, change its class to whichever NSWindowController subclass you want it to work with, attach the window to its output, then set an output to hold the window controller itself. I recommend on the app delegate.
I took things a step further by also changing the window to not show on launch, and I removed the window from the App Delegate (since it now has a reference to the window controller and thus the window indirectly already). This way I can center the window before actually showing it.
Only caveat to look out for is that you won't get the window-loading overrides since the window is handed to the VC, not loaded by it, so any code you need to run only when the window is set, simply override the window variable and add a didSet section. Works like a charm!
Still, I may try to dig deeper to see if I can update the Window controller to load the window normally so I can get those events as designed.

On OSX, how can I ensure that a command-line application shows up in the application switcher once it creates a window?

I'm working on a cross-platform command-line application (in C++ on
Win/Linux and ObjC++ on OSX) which sometimes creates an OpenGL
context. The OpenGL context and window creation code is obviously
different for the different platforms, but on OSX it's done through
NSOpenGLView and NSWindow. There's no nib, and it's not built with
Xcode (it uses a cross-platform build script).
On OSX, the window is created and works fine, but the OpenGL window
doesn't show up in the Application Switcher (Cmd-Tab). This means
that it's tricky to find the window if you 'lose it' behind other
windows, and can often only be found by going to Mission
Control/Expose.
My question is: is there a programmatic way (i.e. a message to send to
the NSWindow object or NSApplication) to ensure that a (unix-style)
command line application will show up in the Cmd-Tab list once the
window is created?
You need to transform the process from an accessory to a regular app. Call [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular].
Once you do that, though, the app will also have a menu bar when it's active. This is good because it's what users expect. However, you probably need to add appropriate items to the menus in that menu bar to get a decent user experience.
Your app will appear in the Dock as well as the Command-Tab application switcher. By default, an unbundled executable will get an icon that looks like a CRT display showing the word "exec". You can use [NSApp setApplicationIconImage:someImage] to set a better icon, although the Dock will revert to showing the generic executable icon briefly as the process exits.

How to detect if app was launched by double clicking on a file?

I need to detect if my application was launched in response to user double-clicking on a file or through Spotlight. I have to do something extra if it was invoked through Spotlight (or by double-clicking on the application icon) and don't have an input file to open. I don't have access to the NSApplicationDelegate object so I can't set a flag on applicaion:openFile(s):. In any case, I cannot wait indefinitely to check if those callbacks have happened. Is there any way I can query for the launch method from any arbitrary point in the code?
When you double-click an application's associated file, the application is launched from Finder by a call to Apple's Launch Services, with the function call to LSOpenURLsWithRole.
Spotlight, most likely, also uses Launch Services or directly calls Finder, so I think the answer is no, you won't be able to differentiate between launching via Finder or Spotlight.
Perhaps if you give more detail on what you're trying to achieve and why you need to differentiate between them, there may be another way of solving the problem.

Change activationPolicy: from startup

I have the following problem. There is a Cocoa app I have with UI, nib, etc. I need to be able to start the application in background or in foreground. In other words, I need NSApplicationActivationPolicyProhibited in the former and NSApplicationActivationPolicyRegular in the latter. Now...the decision of how to start depends on an argument pass to the startup of the app. So the code looks more or less like:
shouldBeBackground = // read this from argument - argv
if (shouldBeBackground) {
[NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];
} else {
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
[NSApp activateIgnoringOtherApps:YES];
// later on I do the makeKeyAndOrderFront:
}
Now the problem is with the Info.plist. If I put LSBackgroundOnly to 1 everything works as expected. But if I put it to 0 (or do not put the key), when the app starts it shows up the icon of the app in the dock for a couple of miliseconds and a little flash. I guess this is because the app is initialized with the default policy (starting to show the icon) and I switch it to background too late. This is also explained in: Cocoa - go to foreground/background programmatically
I know places WHERE to read the argument and do the previous IF even before I start cocoa or the app (for example, I can hook in MyOwnPrincipalClass +initialize), but even with that (even if I set the policy) it looks like the startup of Cocoa will set the default one. So it doesn't work.
The only solution I found is to put my IF at the beginning (before initialize cocoa) and depending on the argument, I write/modify the Info.plist (LSBackgroundOnly flag). This could work but it is a real hack. I would like to find a cleaner solution.
BTW, if I do the other way around: start up always as background and then make it foreground has a worst result since when going foreground the menubar of the app is not shown up automatically: you need to switch to another app and come back to make it appear....I searched in the internet and indeed it looks like a known bug/limitation.
BTW2: having 2 different binaries is not an option either.
Thanks for any help you can give me,
Just always startup as a background app at launch. Then if at startup you want to be a foreground app you can change the plist value programmatically, and then restart your application programmatically (you send an NSTask to launch your app before you terminate it). At app quit ensure that you are in background mode. Seems simple enough.

In a Cocoa OS X app, how can I make two windows open at startup?

My OS X app has two windows. I've put one in MainMenu.xib, and the other in SecondaryWindow.xib.
When I run my app, the window in MainMenu.xib shows. I also want the second window in SecondaryWindow.xib to show at startup. How do I achieve this? Was it a good idea to use a separate xib file for the second window?
If you'd like to do it without a line of code, add NSWindowController object to MainMenu.xib and write second xib's name to it's property. When MainMenu.xib is loaded, this window controller will be created and will load the second xib, causing the second window to pop up if it's configured to be visible on startup.
Or do it programmatically from e.g. applicationDidFinishLaunching: or awakeFromNib:.
Besides being an instrument for breaking UI into independent modules, separate xibs make it possible, for example, to unload some of them and save memory (e.g. when window is closed), or load one multiple times.
In your case, if both windows always have to be in memory, you can safely keep them in the same xib.

Resources