2
votes

I'm trying to figure out what file is currently open inside of other active applications on Mac OSX. I know that I can find the current applications open via:

NSWorkspace *ws = [[NSWorkspace alloc] init];

NSArray *apps = [ws runningApplications];

// loop through the apps and get the localizedName

However, the "runningApplications" (NSRunningApplication) doesn't provide me with anything related to what's open within that application. So let's say the user has Sublime Text 2 open. I'd like to access that app and see what document(s) (and the related path for that document(s)) they currently have open in it.

I know that applescript and scripting bridge are "options" however, the problem I see with those 2 is the following:

  • Scripting Bridge requires that you generate and add header files from each application you want to interface with. The problem with this for me is that my application doesn't know what apps the user has in advance. XCode(5) doesn't seem to allow me to generate those on install (i.e. loop thru user's app directory and add the apps) or anything either.

  • AppleScript, while not as dependent upon knowing what apps you want to work with, doesn't work with all apps. Only certain ones support it.

The end goal here is to be able to look at what apps the user currently has open and get information on what those applications have open at that moment.

Edit: For example - If the user has "/some/dir/example.txt" open with "Text Edit", I'd like to be able to grab that information.

4

4 Answers

3
votes

To implement your requirement, you'll need major work with several APIs. We implemented this and it took us several weeks to get it done. Here some hints:

  • use NSRunningApplication to get the Unix-PID
  • use AppleScript and AXAPI to get the windows and their document.
    unixPID = 12345  -- insert the number here
    tell application id "com.apple.systemevents"
        try
            tell (application processes where unix id is unixPID)
                with timeout of 5 seconds
                    repeat with thiWind in every window
                        set isMain to value of attribute "AXMain" of thiWind
                        if isMain then
                            return value of attribute "AXDocument" of thiWind
                            exit repeat
                        end if
                    end repeat
                end timeout
            end tell
        end try
    end tell
  • alternatively / additionally use CGWindow.h to iterate thru windows of all apps, then use the windows id and a specific script for each app. e.g.:
tell application id "com.apple.TextEdit"
    try
        set mydoc to document of window id 1234 -- insert window number here
        return path of mydoc
    end try
end tell

To see an example how it would perform, check out our app. The functionality is really hard to maintain and does work in the most cases. See how other apps should be implemented on this page in the Developer Section.

See it in action:

  • Add a folder with various documents to Raskin (eg. word, numbers, text, photoshop, ...)
  • open these documents in their app
  • most documents will show a badge where they are open
  • then you can use cmd-alt-R or cmd-alt-scroll to get from any open document back to the Surface of Raskin exposing this file

Open In Badge on a Text Document

1
votes

You can use lsof command. it will return list of open files.

Have a look at this post

1
votes

You can use the lsof (list open files) command to obtain the information you want. The command will produce output designed to be read by other programs, and you can execute from an application using NSTask/NSPipe.

HTH

Addendum: Some things are priceless...

I see you've opened a bounty, but some things just can't be bought... Have you considered what you are asking?

Consider what lsof is doing - it is reporting the files the OS has open for an application; the application itself is a black box, the OS maintains information on open files and lsof can access it.

You wish to peer inside the application's black box and determine the files the application knows about on behalf of the user. Such a file may not be "open" in the OS sense at all - the application may have opened it, read in the contents, and then closed it. How do you think it might be possible to discover that? From a black box?

It is possible that, say, NSDocument is instrumented to provide this information, but even if so how might you access NSDocument data structures from outside an application? And what if the application is not using NSDocument?

Grab the TextEdit sample code from Apple and do not read it. Run it in under Xcode for a while and open some files. Now hit the debug pause button. Using debugger commands (and the debugger can call methods in the application) try to discover the list of open files. You can read any documentation on NSDocument you like to aid you. If you can find the pathnames you've the start of a solution (as one way or another anything the debugger can do you can do from an application, but it may not be trivial).

Another approach: Default Folder uses a helper application which tracks usage of open and save dialogs. Other programs patch other system APIs. If you take a similar approach you maybe could design a helper which tracks use of certain NSDocument APIs and maintains a list of "open" documents in that way. It would of course only work for NSDocument based applications, and only for ones launched when the helper was running (so you need a daemon).

In summary: What you're asking is not necessarily impossible, but it is certainly far from trivial (unless the frameworks are instrumented to provide this information, the lack of answers suggests not). Consider what you are trying to achieve that let you to ask this question, can you accomplish that task another way?

HTH

1
votes

I would recommend that you look at the Accessibility API. With the Accessibility API, you can walk through a tree of accessibility objects. The Application is the top most part of the tree. You can then walk through all of the applications menus, particular the Window menu item which typically has an array of documents that are available in an application. The Accessibility API does require that the process is trusted and has rights to look at other applications. To do a cursory test so that you can feel confident the API has what you need, use the accessibility inspector tool that ships with Xcode (at least 5.+). When you turn this on, you can look at all the objects that an OSX application makes available. I use Sublime Text as well. It will show you what files are in use, if each file is in its own window.