需求是在主窗口旁边展示新弹出的窗口,无论主窗口被移动到了什么位置,新的窗口需要在主窗口旁边展示。这里需要用到Quartz Window Services接口合集,该api提供有关由 macOS 窗口服务器管理的窗口的信息。
CFArrayRef CGWindowListCopyWindowInfo(CGWindowListOption option, CGWindowID relativeToWindow);
参数
option
描述要返回哪些窗口词典的选项。典型的选项让您返回所有窗口或参数中指定窗口上方或下方的窗口的字典。有关详细信息,请参阅窗口列表选项常量。relativeToWindow
relativeToWindow
在确定要返回哪些其他窗口字典时用作参考点的窗口 ID。对于不需要参考窗口的选项,此参数可以是.kCGNullWindowID
返回值
一个类型数组,每个类型都包含有关当前用户会话中的一个窗口的信息。如果没有符合所需条件的窗口,该函数将返回一个空数组。如果您从 GUI 安全会话外部或没有窗口服务器运行时调用此函数,则此函数返回。CFDictionaryRefNULL
此函数获取有关当前用户会话中一个或多个窗口配置的详细信息。例如,可以使用此函数获取窗口的边界、窗口 ID 以及有关窗口服务器如何管理它的信息。有关字典中可能存在的键和值的列表,可以参阅Required Window List Keys和Optional Window List Keys。
具体实现代码如下:
- (NSRect) caculatePosition
{
NSWindow *window = [自己的主窗口];
NSScreen *screen = window.screen;
NSArray *windows = (__bridge NSArray *) CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
for (NSDictionary *dir in windows) {
CGRect windowRect;
CGRectMakeWithDictionaryRepresentation((__bridge CFDictionaryRef) dir[(id) kCGWindowBounds], &windowRect);
NSRect rect = [self cgWindowRectToScreenRect:windowRect];
if([dir[@"kCGWindowOwnerName"] isEqualToString:@"自己应用窗口名称"]){
CGFloat originX = rect.origin.x;
if(windowRect.origin.x-windowRect.size.width-60 < 0){
originX = rect.origin.x+APP_WITDH+60;
}else{
originX = rect.origin.x-APP_WITDH-60;
}
return CGRectMake(originX, rect.origin.y+APP_HEIGHT-230, 320, 230);
}
}
return CGRectNull;
}
- (NSRect)cgWindowRectToScreenRect:(CGRect)windowRect
{
NSRect mainRect = [NSScreen mainScreen].frame;
//NSRect snipRect = screen.frame;
for (NSScreen *screen in [NSScreen screens]) {
if ((int) screen.frame.origin.x == 0 && (int) screen.frame.origin.y == 0) {
mainRect = screen.frame;
}
}
NSRect rect = NSMakeRect(windowRect.origin.x, mainRect.size.height - windowRect.size.height - windowRect.origin.y, windowRect.size.width, windowRect.size.height);
return rect;
}