HippoMan
HippoMan

Reputation: 155

MacOSX Lion: how to move a named window using CoreGraphics, without AppleScript?

Using CoreGraphics in a cocoa objective-c program running under Lion, I'd like to move a named window that is owned by a different process. I know I can do this via an auxiliary AppleScript method via ASOC, but I want to perform this task entirely within cocoa using CoreGraphics (or at least entirely within C or objective-c), and without any AppleScript, at all.

I know how to locate a named window of a named process using the code below, but once I get the info for that window, I haven't been able to figure out how to move it (see the comment "What do I do here ... ?" within this code). Could someone point me to some docs or make a suggestion as to how I can proceed?

Thanks in advance.

+(boolean_t)moveWindow:(NSString*)windowName ofProcess:(NSString*)processName to:(CGPoint*)location {

    boolean_t result = false;

    if (windowName == nil || processName == nil || location == nil) {
        return (result);
    }

    CFArrayRef windows = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
    CFIndex   nWindows = CFArrayGetCount(windows);

    for (CFIndex i = 0; i < nWindows; i++) {
        CFDictionaryRef windict = CFArrayGetValueAtIndex(windows, i);
        CFNumberRef winOwnerPidRef = CFDictionaryGetValue(windict, kCGWindowOwnerPID);
        if (winOwnerPidRef == nil) {
            continue;
        }
        pid_t winOwnerPid = 0;
        CFNumberGetValue(winOwnerPidRef, kCFNumberSInt32Type, (int*)&winOwnerPid);
        if (winOwnerPid < 1) {
            continue;
        }
        ProcessSerialNumber winOwnerPSN;
        GetProcessForPID(winOwnerPid, &winOwnerPSN);

        NSString* winOwner = nil;

        ProcessSerialNumber psn;
        psn.lowLongOfPSN  = kNoProcess;
        psn.highLongOfPSN = 0;

        while (winOwner == nil && GetNextProcess(&psn) == noErr) {

            if (psn.lowLongOfPSN  != winOwnerPSN.lowLongOfPSN ||
                psn.highLongOfPSN != winOwnerPSN.highLongOfPSN) {
                continue;
            }
            CFStringRef procName = NULL;
            if (CopyProcessName(&psn, &procName) == noErr) {
                winOwner = (NSString*) procName;
            }
            CFRelease(procName);
        }

        if (winOwner == nil || [winOwner compare:processName] != NSOrderedSame) {
            continue;
        }

        CFStringRef winNameRef = CFDictionaryGetValue(windict, kCGWindowName);
        NSString* winName = (NSString*) winNameRef;
        if (winName != nil && [winName compare:windowName] == NSOrderedSame) {
            // ********************************************** //
            // What do I do here in order to move the window? //
            // ********************************************** //
            result = true;
            break;
        }
    }

    return (result);
}

Upvotes: 0

Views: 427

Answers (1)

MyztikJenz
MyztikJenz

Reputation: 1646

You can move the windows of other applications using Accessibility. Take a look at AXUIElementCreateApplication() and AXUIElementSetAttributeValue() with the attribute kAXPositionAttribute.

Note that Accessibility will need to be enabled (check "Enable access for assistive devices" in Universal Access Preferences) or your process will need to be trusted (see AXMakeProcessTrusted())

Upvotes: 1

Related Questions