5
votes

I want to set a certain window, from an external app (for example textedit), to be front most.

I can successfully get a reference to the app itself using GetFrontProcess, and check whether it is front most. If it is not, I can use setFrontProcess to make it focussed.

I can then use the the accessibility API to examine all the windows under that application. I am checking that a certain window exists, and if so I compare it against the front most window of the application:

//get the front window of textEditApp and store it in 'currentFrontWindow'
    AXUIElementCopyAttributeValue(textEditApp, kAXFocusedWindowAttribute, (CFTypeRef *)&currentFrontWindow);

If the window I am interested in is not frontmost, I need to set it so. I thought that I could use AXUIElement Set AttributeValue to do this but I am not getting any success. Below is how I have tried to do it.

//set the front window of textEditApp to be desiredFrontWindow
AXUIElementSetAttributeValue(textEditApp, kAXFocusedUIElementAttribute, desiredFrontWindow);

I have checked that the window exists, and the application is 'switched to' successfully. But why doesn't this line of code bring the specified window to the front?

Thanks.

3

3 Answers

8
votes

But why doesn't this line of code bring the specified window to the front?

Because you tried to set a read-only attribute.

In order to make a window frontmost, you need to set the appropriate property of the window. The same goes for an application: To make an application frontmost, you need to set the appropriate property of the application.

The Cocoa/Mac OS X name for the frontmost window is “the main window”. (See, for example, NSApplication's and NSWindow's methods relating to that concept.) Accessibility uses the same name, so to make a single window frontmost, set the value of its kAXMainAttribute to kCFBooleanTrue.

The way to make the application frontmost is similar: Set the value of its kAXFrontmostAttribute to kCFBooleanTrue. You'll need to do both of these to both set the frontmost window of the application and make the application active.

As far as I can tell, there is no way to bring only a single window of an application frontmost and give it session focus.

3
votes

I was able to accomplish this in an app I worked on by bringing the application to the front, then bringing a single window to the front.

First bringing the app to the front:

let currentPid = NSRunningApplication.currentApplication().processIdentifier
if let pid = (the pid of the app in question) where pid != currentPid {
  NSRunningApplication(processIdentifier: pid)?.activateWithOptions(.ActivateIgnoringOtherApps)
}

Then sending the window to the front:

let window = (window AXUIElement)
AXUIElementSetAttributeValue(window, NSAccessibilityMainAttribute, true)
1
votes

I recently discovered that, if you don't mind some Carbon, you can use SetFrontProcessWithOptions to bring a window to the front and give it focus if you pass kSetFrontProcessFrontWindowOnly as the second argument.