CGWindowListCopyWindowInfo:多个屏幕和更改属性

时间:2013-10-20 08:55:32

标签: objective-c macos

我正在研究一个简单的Mac应用程序,可以检测外部屏幕何时拔出,保存所有窗口的位置,再次插入外部屏幕后,将所有窗口恢复到原始位置。 (我知道那里已有应用程序,我只是很好奇这是怎么做的)

经过大量搜索后,我终于设法通过

获取所有窗口
NSArray *openWindows = [[NSWorkspace sharedWorkspace] runningApplications];
CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);

这会返回类似

的内容
{
    kCGWindowAlpha = 1;
    kCGWindowBounds =         {
        Height = 22;
        Width = 279;
        X = 1559;
        Y = 0;
    };
    kCGWindowIsOnscreen = 1;
    kCGWindowLayer = 25;
    kCGWindowMemoryUsage = 13596;
    kCGWindowName = "";
    kCGWindowNumber = 18;
    kCGWindowOwnerName = SystemUIServer;
    kCGWindowOwnerPID = 260;
    kCGWindowSharingState = 1;
    kCGWindowStoreType = 2;
},
    {
    kCGWindowAlpha = 0;
    kCGWindowBounds =         {
        Height = 22;
        Width = 1920;
        X = 0;
        Y = 0;
    };
    kCGWindowIsOnscreen = 1;
    kCGWindowLayer = 25;
    kCGWindowMemoryUsage = 5404;
    kCGWindowNumber = 19;
    kCGWindowOwnerName = SystemUIServer;
    kCGWindowOwnerPID = 260;
    kCGWindowSharingState = 1;
    kCGWindowStoreType = 2;
},

然后我会遍历数组并查看每个单独的窗口

 for (int i = 0; i < CFArrayGetCount(windowList); i++) {
    CFDictionaryRef ref = CFArrayGetValueAtIndex(windowList, i);

    NSLog(@"%@", CFDictionaryGetValue(ref, kCGWindowBounds));
}

但这就是我遇到的问题,在使用多个屏幕时,我怎么能首先知道窗口在哪个屏幕上。 其次,我怎样才能在以后调整窗口界限?每个应用程序都有自己的ID吗?或者我可以使用另一种方法吗?

1 个答案:

答案 0 :(得分:2)

由于CGWindowList API不公开屏幕ID,您必须根据屏幕边界检查窗口边界:

NSArray* windowList = (__bridge NSArray*)CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
uint32_t maxDisplayCount = 10;
CGDirectDisplayID onlineDisplayIDs[maxDisplayCount];
uint32_t displayCount;
CGGetOnlineDisplayList(maxDisplayCount, (CGDirectDisplayID*)&onlineDisplayIDs, &displayCount);
for(uint32_t i = 0; i < displayCount; ++i)
{
    CGRect dspyRect = CGDisplayBounds(onlineDisplayIDs[i]);
    for(NSDictionary* windowDict in windowList)
    {
        CGRect windowRect;
        CGRectMakeWithDictionaryRepresentation((__bridge CFDictionaryRef)(windowDict[(id)kCGWindowBounds]), &windowRect);
        if(CGRectContainsRect(dspyRect, windowRect))
        {
            NSLog(@"window %@ is on screen with ID:%d", windowDict[(id)kCGWindowName], onlineDisplayIDs[i]);
        }
    }
}

上面的代码执行一个天真的检查,测试一个窗口是否完整在特定的屏幕上 如果窗口的某个部分覆盖该屏幕,则OS X认为属于屏幕的窗口。 (OS X版本之间的这种行为也略有改变)

要移动窗口,您可以使用Apple EventsCocoa Accessibility APIs 请注意,Cocoa Accessibility要求您使用“系统偏好设置”中的“启用辅助设备访问” 启用App Sandboxing时,这两种技术都可能出现问题。