3

I'm looking for a way to determine the second frontmost app. Here's what I mean by that.

Let's say I launch three apps in this order: Xcode, Interface Builder, and my application. If I press Command-tab, I should see four applications in the switcher: (from left to right) my application, Interface Builder, Xcode, and Finder.

Let's then say that I switch to Finder. The new order in the app switcher is: Finder, my application, Interface Builder, and Xcode.

If I then switch back to my application, the order is now my application, Finder, Interface Builder, and Xcode.

I'm looking for an API whereby I can call it and get back that at launch time Interface Builder is the second frontmost app, but that when I switch back to it, it is now Finder.

If it makes any different, my app won't actually appear in the app switcher, since it will be an agent application (LSUIElement = YES).

Is there an API that can do this? The only alternative I've found is to have a timer running that continuously monitors what the activeApplication is, according to NSWorkspace. This works well, except during launch. I'd like to know the second frontmost application at launch, if possible.

Any ideas?

Dave DeLong
  • 242,470
  • 58
  • 448
  • 498
  • I'm guessing the Dock uses the continuous monitoring method, but you could theoretically quit the Dock and see if that causes the order to scramble. If even the Dock can't determine the order at launch, then at least you can stop wasting time trying. :) – Brian Webster Apr 19 '17 at 00:41
  • 1
    Possible duplicate of [Getting the list of running applications ordered by last use](https://stackoverflow.com/questions/945033/getting-the-list-of-running-applications-ordered-by-last-use) – Jon Schneider Mar 31 '19 at 03:06

3 Answers3

2

It's true there are no public APIs, but there are STABLE APIs. And since they're in the public CoreServices, Apple won't move them anywhere soon.

Darwin's "lsappinfo visibleProcessList" does exactly that. It's closed source, but a clone "lsdtrip" (http://NewOSXBook.com/tools/lsdtrip.html) is fully open source and mimics this functionality

(morpheus@Bifröst (/tmp) %./lsdtrip.x86 visible                                                       0x0-0xb00b   /System/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal
0x0-0xc00c   /Applications/Safari.app/Contents/MacOS/Safari
0x0-0xab3ab3 /System/Applications/System Preferences.app/Contents/MacOS/System Preferences
0x0-0xa93a93 /System/Applications/Preview.app/Contents/MacOS/Preview
0x0-0xa9da9d /System/Applications/FaceTime.app/Contents/MacOS/FaceTime
0x0-0x4d14d1 /System/Applications/Messages.app/Contents/MacOS/Messages
0x0-0x18018  /System/Library/CoreServices/Finder.app/Contents/MacOS/Finder
0x0-0x81f81f /Applications/VMware Fusion.app/Contents/MacOS/VMware Fusion
0x0-0x13013  /System/Applications/Music.app/Contents/MacOS/Music

The 0x-... values are ASNs (Application Serial numbers), and the path names are the process names.

You (at least at this point) do you need an entitlement. lsdtrip has been working reliably since Darwin 12 (macOS 10.8) to the present day. Other APIs can be used for notification of switches, so you won't need to resort to timers (which would be wasteful of CPU/battery and may miss out)

Technologeeks
  • 7,674
  • 25
  • 36
1

There is definitely no such public API that would allow you to just get what you want.

When it comes to the case "I want it no matter what", there are several things that come in mind:

  1. Let your app be a real agent, in terms of lifetime. Create a launch.plist for it and place it into /Library/LaunchAgents and it would start with the user login, so you could not miss apps launched, and start to monitor activeAppChange event from the very beginning of user session. If it is not convenient to make this from your app itself, create a helper app, that would be doing this, and use IPC to pass that info. This is the lawful-good way.

  2. There could be some luck with the windows order, but there also could be some cases it misses. Try CGWindowListCopyWindowInfo (not all windows are NSWindow), you can find the process id corresponding to each window, and the list is promised to be in frontmost reversed order. This could be a little hacky (I mean, there is an accesibility framework with its actions, some apps could stay always on top, etc), let's call it neutral.

  3. Take all your reversing skills and see, what Apple can offer to you. If the app switcher displays apps in the order you want - find it's binary and try to determine, how does it works. There is also a comment with some LS private API in other stackoverflow thread you already have.

The problem with case (3), is even if you find the needed private API, you can use it only at your own risk. Apple will not let you go into Appstore with this (or even worse, they could let you, but ban after some time), they could remove it or rename or change its behavior or place at any time, so this is not reliable solution. However, sometimes it is the only choise, so this could be an evil way.

Arthur Bulakaiev
  • 1,207
  • 8
  • 17
-1

You'll probably be able to assemble the information from:

Process Manager Reference (GetFrontProcess(), GetNextProcess())

Foundation.framework/Headers/NSGraphics.h (NSCountWindows(), NSWindowList())
Quartz Window Services Reference
CoreGraphics.framework/Headers/CGWindow.h
code.google.com CGSPrivate.h
www.cocoadev.com CoreGraphicsPrivate

johne
  • 6,760
  • 2
  • 24
  • 25
  • 2
    After some more research with this, it turns out that the Process Manager's order of processes is totally different from the Dock's order of apps. =( – Dave DeLong Jul 22 '09 at 14:29