What exactly should I pass to -[NSApp activateIgnoringOtherApps:] to get my application to start "naturally" in comparison to most other OS X apps?
Asked Answered
R

1

5

When I learned how to start NSApplications on my own, the code I used (based on here and here) did

[NSApp activateIgnoringOtherApps:YES];

which forces the app to the front at startup.

I'd like to know what most other apps do. I want to be able to run programs both directly from the binary and from an app bundle, and I'm not using Xcode to build this (raw building). So I'd rather this act naturally, so to speak.

The docs do say Finder issues NO, but... why Finder? Isn't this a method that's run from within the process, not outside? (I'm not in control of the choice.) And what about the Dock and other possible entry points?

I even went so far as to disassemble 10.8's NSApplicationMain() to see what it did, but as far as I can tell from the 32-bit version, unless this "light launch" thing issues this selector, this selector is never called.

Is there an answer to this question? Thanks... and sorry if this is confusing; I tried to word it as clearly as possible.

Radiotelephony answered 14/8, 2014 at 22:24 Comment(0)
S
16

Apps normally do not call -activateIgnoringOtherApps: at all. And, generally speaking, shouldn't. Certainly, it wouldn't be in NSApplicationMain(), which is too early and fairly distantly related to actual app start-up.

Apps are normally launched by Launch Services (which is what is used by the Finder, the Dock, and /usr/bin/open, as well as any other app that might open yours or a document which yours handles). Roughly what happens is that Launch Services deactivates the app which called it to open something else and then, in the launched app, Cocoa's internals do something like (but not necessarily identical to) [NSApp activateIgnoringOtherApps:NO]. In this way, the launched app only activates if nothing else was activated in the interval between those two events. If that interval is long (because something was slow) and the user switched to something else in the meantime, you don't want to steal focus from whatever they switched to.

You should only call [NSApp activateIgnoringOtherApps:YES] in response to a user request to activate your app in a context which won't include the automatic deactivation of the current app by Launch Services. For example, if you have a command-line program which transforms itself into a GUI app (using -[NSApplication setActivationPolicy:] or the deprecated TransformProcessType()), then the user running that tool means they want it active. But Terminal is active and won't be deactivated spontaneously just by virtue of having run your program. So, the program has to steal focus.

If your program is a bundled app, then running it from the command line should be done with /usr/bin/open rather than directly executing the executable inside the bundle. Then, you don't need to call -activateIgnoringOtherApps: at all and the question of what value to pass is moot.

Spittle answered 14/8, 2014 at 22:56 Comment(2)
Ah, thanks for that explanation (better than the ones I've found so far). So I take it there's no way to tell the difference between an app started directly from the Terminal and one started by Launch Services?Radiotelephony
Not reliably. It used to be the case that Launch Services passed an argument of the form -psn_<digits>, but it no longer does. You could pass special arguments when you invoke from the command-line and behave differently based on that. Then you could include a script in your app to invoke its main executable with those arguments and invoke the script instead of the main executable.Spittle

© 2022 - 2024 — McMap. All rights reserved.