Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OSX / Objective-C Window Management: manipulate the frames & visibility of other applications

I would like to create a system tool / application which has the capacity to aid in window management. I'm trying to find documentation about the following topics, if they are indeed possible given the security sandboxing of OSX.

  • Show a list of running applications with the name & icon, and allow the user to choose one
  • Manipulate the frame(s) of said application's windows (eg, resize, reposition) from my app (with animations -- though I assume this will be trivial once I can perform the actual change)
  • Hide or show these applications from task managers, etc.
  • Be able to launch (or terminate) instances of the given application

It seems to me that Quicksilver accomplishes many of these things, but the lack of AppStore availability makes me wonder if it possible to do this while remaining in the OSX sandbox.

like image 936
Zane Claes Avatar asked Jun 09 '13 14:06

Zane Claes


1 Answers

There are a lot of pieces of software out there that do window management. You can check out a tiling window manager I've been hacking on called Amethyst. The basic idea behind software like this relies on Accessibility (which you can find documentation for here). As a quick overview the APIs work by acquiring references to accessibility elements (applications, windows, buttons, text fields, etc.) which have properties (hidden, position, size, etc.), some of which are writable.

As an example let's say that you wanted to move all windows in every running application to the upper left corner of the screen. That code might look like

for (NSRunningApplication *runningApplication in [[NSWorkspace sharedWorkspace] runningApplications]) {
    AXUIElementRef applicationRef = AXUIElementCreateApplication([runningApplication processIdentifier]);
    CFArrayRef applicationWindows;
    AXUIElementCopyAttributeValues(applicationRef, kAXWindowsAttribute, 0, 100, &applicationWindows);

    if (!applicationWindows) continue;

    for (CFIndex i = 0; i < CFArrayGetCount(applicationWindows); ++i) {
        AXUIElementRef windowRef = CFArrayGetValueAtIndex(applicationWindows, i);
        CGPoint upperLeft = { .x = 0, .y = 0 };
        AXValueRef positionRef = AXValueCreate(kAXValueCGPointType, &upperLeft);
        AXUIElementSetAttributeValue(windowRef, kAXPositionAttribute, positionRef);
    }
}

Which illustrates how you get references to applications and their windows, how to copy attributes from an accessibility element, and how to set attributes of an accessibility element.

There are a variety of notifications documented in NSWorkspace for the launching and termination of applications, and the accessibility framework also has a sense of notifications for things like an application creating or destroying windows, or a window miniaturizing or deminiaturizing.

Animating the window changes is non-trivial and I haven't figured out how to do it yet, though it may be possible. It may not be possible at all without hitting private APIs. But the other things you have listed should be possible. Hiding an application, for example, could be done by setting the kAXHiddenAttribute on the application accessibility element. Launching an application can actually be done via -[NSWorkspace launchApplication:].

Note that the use of accessibility necessitates that the user have Enable access for assistive devices turned on in System Preferences > Accessibility.

like image 77
ianyh Avatar answered Oct 07 '22 12:10

ianyh