Can a Cocoa app's executable steal focus from caller? - cocoa

Say I have a standard Cocoa Application call Foo.app (like the one you get just by choosing New Project > Cocoa Application in Xcode), if I open the app via a terminal using:
open Foo.app/
Then I see Foo's name on the status bar up top and its window is in focus, in front of all other apps.
If instead I directly call from the terminal the executable buried in the .app folder, like:
Foo.app/Contents/MacOS/Foo
Nothing appears to happen. On inspection the app has indeed opened but it is not in focus (the terminal still is), I have to find it on the dock or find its window.
Is there any way for the Foo application to make sure its in focus when its run? Even if its run via its executable as described above?

Your app can "steal focus" by calling
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
See the NSApplication docs for more info.

did you mean to type:
open -a /Applications/Foo.app/
note the -a option

If you're asking how to give your app (that you're writing) this behavior -- within applicationWillFinishLaunching: you could call [NSApp activateIgnoringOtherApps:YES].

perhaps AppleScript?
tell application "TextEdit"
activate
end tell

There are (at least) three different ways you open (and interact with) Applications from the Terminal.
you can launch any Application (that is registered in LaunchServices) from the Terminal by typing open -a ApplicationName (note that you do not need the trailing ".app" or give any path)
you can open an application giving its specific path by typing open /path/to/ApplicationName.app (you will rarely need that, given that the applications is likely already registered in LaunchServices)
you can open and interact with the executable if you type open /path/to/ApplicationName.app/Contents/MacOS/ApplicationName. The difference here is that for some Applications, you can pass arguments or interact with them afterwards on your command line. Go ahead and try open /Applications/Mail.app/Contents/MacOS/Mail for example - it will give you a debugging log in return.
you can interact with some applications even without using "open" by directly calling their executable; try /Applications/Firefox.app/Contents/MacOS/firefox-bin —help for example.
So if you do want to make sure the command-line-launched application is in focus, use either method 1 or 2.

Related

Do executable files always open a terminal window on MacOS?

I'm on MacOS X, and I'm pretty new to app-bundle-type things. I am writing a program that opens a window and registers mouse input -- not a command line tool. When I compile my code (written in C, if that is important) into an executable file (a "unix executable file") and then run that file directly (by double clicking it, for example), a terminal window pops up, and then the program's window pops up. Likewise, if I navigate to the directory of the executable and open it from the command line, it pops open /another/ terminal window and then the program's window.
However, if I wrap the executable in a bundle (thus, I suppose, turning it into a proper "app"), then when I run the app, either by double clicking or from the command line, the program's window opens and no new terminal window is created. Is this merely a property of the "app bundle"'s architecture? Or is there a way that I can run the raw executable without incurring another terminal window? I suspect that I'm misunderstanding something fundamental. Thanks in advance!
I believe what you're seeing is correct. In order for a separate window to not pop-up, you'd need to encapsulate it into a bundle.
Launching by double-clicking a bundle, or using the 'open' command from Terminal uses Apple's Launch Services, which maintains a list of known (registered) applications. When an application (bundle) is introduced to the system, it is registered with Launch Services and associated with its URI (e.g. com.apple.calculator), which is present in the bundle's Info.plist
Other items in the Info.plist tell launch services how to handle the application, such as checking if the minimum or maximum version of the OS has been exceeded, or whether or not to display a dock item.
A lone binary doesn't have an associated Info.plist manifest, so its behaviour can't be varied and a Terminal window is opened.
Bare executable files are essentially treated as documents by Launch Services (the framework that the Finder, Dock, and open command use when you open stuff). The application which handles such documents is Terminal. So, when you open an executable in that fashion, it launches Terminal if it's not already running and tells it to open the document. Terminal does this by opening a new shell window and auto-typing the path to the "document" as a command line.
Launch Services handles bundled apps as, well, apps. If the app is already running, it activates it and possibly has it open a new untitled window. Otherwise, it launches it.
As Rob Napier notes in the comments, if you run an executable directly from the command line (or if some already-running app launches it using NSTask or fork+exec), it will simply run. Launch Services won't be involved, so Terminal will not be asked to open the executable as a document.

Is there a way for a windows-subsystem application to offer optional console output?

I have a Windows application application that is normally GUI-only and declares the WINDOWS subsystem. It doesn't open a console window when launched.
Alas, I would like to offer additional console output when the application happens to be started from console window (say, from interactive cmd.exe).
Is there a way of detecting if some process "up the chain" has an open console, and to attach to that console?
The closest I've found is a way to explicitly open a console for a gui application, but I don't want to open a console if there isn't one already there.
At first glance it seems like the AttachConsole() function will let you attach to the console of your parent process:
AttachConsole(ATTACH_PARENT_PROCESS);
If the process doesn't actually have a console the function will fail with ERROR_INVALID_HANDLE. The function will also fail if your parent process no longer exists. If it fails you can then call AllocConsole() to create your own.
I've never tried this so don't actually know if it will work or not :)

Running Applescript: WorkFlowServiceRunner will not terminate

I am trying to make a keyboard shortcut to launch terminal in OS X Mountain Lion.
After some research I found out that I can use Automator to achieve this:
http://mac.tutsplus.com/tutorials/tips-shortcuts/how-to-launch-any-app-with-a-keyboard-shortcut/
It works, but I noticed that whenever I launch a terminal using this method, a process called WorkFlowServiceRunner starts and never terminates. To make matters worse when I launch more terminals (or launch different applications using shortcuts, again, through Automator) multiple WorkFlowServiceRunner processes start and quickly eat up the memory.
I've also tried writing my own applescripts but the problem does not go away. This clearly looks like a memory leak. Is this a bug in OS X Automator? Is there a way to write an applescript so that the WorkFlowServiceRunner terminates after doing its job (e.g. launch a terminal)? Automator seems to be the most "native" way of getting this done and I do not want to use any 3rd party apps.
I have noticed this from time to time.
One way around it would be to make your own service apps with a Cocoa-AppleScript Applet.
It is not very hard to do. And I will try and guide you through it. It should only take you a couple of minutes.
Step 1.
Open your Application Applescript Editor. And go to the "File" Menu -> "New from Template" -> Cocoa-AppleScript Applet.app
Step 2,
Paste this code into the new documents.
property NSWorkspace : class "NSWorkspace"
tell current application's NSApp to setServicesProvider_(me)
NSUpdateDynamicServices()
my runAService()
on runAService()
NSWorkspace's sharedWorkspace()'s launchAppWithBundleIdentifier_options_additionalEventParamDescriptor_launchIdentifier_("com.apple.Terminal", current application's NSWorkspaceLaunchDefault, missing value, missing value)
tell me to quit
end runAService
Step 3,
Compile
(click this to compile)
and Save the app.
*Make sure the show startup screen is unchecked in the Save dialogue.
Giving the app a name like LaunchTerminal.app
Step 4,
Click the "Bundle Contents" button on the top right hand side of the document.
This will open the applications contents view.
Click the Action button and then "Reveal in finder" sub menu.
step 5,
In the contents folder that opens in the finder you will see a file name "info.plist"
Open Terminal.app and type and run this code using the path to this file:
BUT make sure you do not include the ".plist" part of the name when entering it in Terminal.app
/usr/bin/defaults write /Users/YourUserNameHere/myServiceApps/LaunchTerminal.app/Contents/Info NSServices -array-add '{NSMenuItem={default="Launch Terminal";}; NSMessage="runAService"; NSSendTypes=();}'
( You can drag n drop the file into terminal to get the posix path string )
The path part looks like this: /Users/YourUserNameHere/myServiceApps/LaunchTerminal.app/Contents/Info
This code should add an array to the plist file which is part of the apps way of broadcasting it has a service.
step 6,
Compile and Save the App again.
Just to make sure it picks up the changes. ( I found I had to do this even though I should not have to)
step 7,
Double click the app to run it for the first time.
The App will quit straight away. But the first run should have broadcast that it has a service that should be registered with the system
step 8,
Open system Preferences and go to Services -> General (section)
And you will see the "Launch Terminal" service.
Set up your short cut as normal.
Hope this helps..
UPDATE :
I noticed that the tell application "Terminal" to activate. Would not open my default Window groups if I had closed them all and quit Terminal before. The normal behaviour if I have done this is for my default window group to open. ( I have two Tabs open at startup each cd'd to a different path).
So I have change the open application to a cocoa way of doing it.
A do shell script with open the/application/path/. will work also.
Try using Butler or QuicKeys. They both have endless "Trial periods."

Close App A when App B closes: Mac OS X 10.7.3

Say I have two applications running; App A and App B. What would be the easiest way (or indeed is there anyway) to get App B to close automatically when App A is closed? Note that neither of the apps in question have been developed by me and so I have no control over their internal behaviour.
I am open to any suggestions including those that entail the use of Applescript, Automator, Terminal commands and BASH scripting. I would even consider developing a lightweight Mac OS X application to achieve this.
If you don't need B to exit immediately - if it's OK to wait a few seconds - then you could schedule a periodic background task (using cron or even just iCal) that does something like this:
if not exists (processes where name is A)
tell application B to quit
end if
Another option, if you want an immediate response, would be to wrap App A in a script that launches it, waits for it to terminate, and then terminates B (osascript -e "tell application B to quit"). Then you could just always use that script to launch A.
You could even insert the script into the application bundle so that double-clicking runs your script. You would do this by doing "show package contents" on the application, replacing the <CFBundleExecutable> in <app>\Contents\info.plist with your script name, and dropping that script into <app>\Contents\MacOS. Then have the script just run the executable that is already there.
Fantastic question. I spent about 10 minutes looking for an old project where I had registered for notifications for when applications quit but couldn't easily find my code. But I did find a potential alternative for you.
If you download Apple's AppList sample code project, you'll see that it is observing the list of NSRunningApplications and when an app quits, it removes that app from the list of running apps in the window. You can take the technique they're using there and when you detect your "application A" quits, you can send a "quit" Apple Event to "application B".
Since you are running Lion, you can use a Cocoa-AppleScript to access Cocoa methods to add your application as an observer, getting notifications when applications quit.
For example, create a new application from the AppleScript Editor > File > New from Template > Cocoa-AppleScript applet. In the run handler, add the application as an observer to get notifications when an application quits:
set theNotice to current application's NSWorkspaceDidTerminateApplicationNotification
tell current application's NSWorkspace's sharedWorkspace's notificationCenter
addObserver_selector_name_object_(me, "appQuitNotification:", theNotice, missing value)
end tell
Next, add an appQuitNotification handler (this is the handler selector specified in addObserver_selector_name_object_ above), something like:
on appQuitNotification_(aNotification) -- an application quit
-- aNotification's userInfo record contains an NSRunningApplication instance that we can get properties from
set theApplication to (aNotification's userInfo's NSWorkspaceApplicationKey's localizedName()) as text
say "application " & theApplication & " quit" -- for testing
if theApplication is "this" then tell application "that" to quit -- or whatever
end appQuitNotification_
...and you are done. As long as your application is running, it will get notifications from the system when an application quits. Note that these Cocoa-AppleScript applications can't be run directly from the script editor, so they can be a bit of a pain to debug since there is no event log to look at - you will need to add your own dialogs or whatever.

Force window to front/focus?

I'm writing an MacOSX bundled app in GLFW.
When the window pops up, I want it to be on top of all the other windows. I also want it to grab focus (I'm coding in vim, and I type ":make run" -- and I after that, I want to interact with the app).
Question:
1) Is there some API call I can use to make this happen?
2) Is there some configuration I can do in MacOSX to say something like "the program named blah, have it steal focus on startup"?
Thanks!
The cocoa API is [NSWindow makeKeyAndOrderFront:] there's probably something similar you can do from your library.
If you wrap your built executable in a application bundle, then you should be able to open it in the terminal (e.g. via the open command) and the focus will automatically switch to it.
Note that you will probably need to package your application in a bundle anyway.
First, you need to package it because that is what the GLFW FAQ says.
I personally found this to be necessary because, at least in GLFW currently available on github (commit 3e78), atop Mac OS X 10.7.5, the keyboard handling is stolen by the terminal if you don't have the executable sitting in an app bundle.
I witnessed the keyboard-input-stealing behavior occurring even when I manually switched the mouse focus to the window that popped up when I ran the binary. That is, the keystrokes I typed still ended up in the terminal window.
You can test this behavior yourself on your own system by taking one of the example apps for GLFW, like Triangle.app, copy its binary to a different directory, like /tmp/, and then run the binary from there. Here is a demonstration of the distinction I am making.
% pwd
/Users/pnkfelix/Dev/OpenGL/glfw/objdir/examples/Triangle.app/Contents/MacOS
% ./Triangle
(The open command works too:)
% open ../../../Triangle.app
In the above scenarios, hitting ESC with the triangle window focused made it quit, as expected.
However, the problem comes when the program is not sitting in an bundle:
% cp ./Triangle /tmp
% /tmp/Triangle
^[^[^[^[^[^[^
In this scenario, hitting ESC with the triangle window focused passed the keystroke to the terminal window that launched the program. (That is what the ^[ glyphs are -- the terminal responding to the ESC keystrokes it has received.)
The good news is, it is relatively easy to wrap a built executable in a bundle.
For example, when I was doing other experiments with binding the GLFW library, I found the following Makefile rule sufficed for constructing a makeshift bundle from an executable:
test: Triangle.app
open Triangle.app
Triangle.app: Triangle.app/Contents/MacOS/Triangle
Triangle.app/Contents/MacOS/Triangle: triangle
mkdir -p Triangle.app/Contents/MacOS
cp $< $#
(note that the 8-space indented commands above should not be copied verbatim, but rather rewritten as tabs as required for Makefiles).
However, please note that the above Makefile rule is not the official structure for application bundles, and shouldn't be trusted for anything except personal experimentation. Apple has the documentation on how to officially package your application in a bundle, so you should take the time to do whatever steps they describe before you release anything you produce into the wild. (For example, the Makefile rules listed above make no attempt to generate an Info.plist file, which is one of the required components according to Apple's documentation.)

Resources