3

我正在开发一个简单的 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 吗?或者我可以使用另一种方法吗?

4

1 回答 1

2

由于CGWindowListAPI 不公开屏幕 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 时,这两种技术都可能会出现问题。

于 2013-10-21T08:50:56.200 回答