windowNumbersWithOptions: on Yosemite 我的应用程序 return NSPanel windows 失败
windowNumbersWithOptions: on Yosemite fails to return NSPanel windows of my application
我有一个基于文档的应用程序,有一个主文档 window 和几个 "satellite" NSPanel windows 显示相关信息。它们不是浮动的,它们可以(并且确实)成为关键,并且似乎与主要 window.
在同一层
我尝试像这样实现 show/hide 操作:如果面板不可见 - 显示它。如果它是可见的,但不是前面的 - 把它放在前面。如果它可见且在前面 - 隐藏它。
为此,我需要知道 NSPanel 是否为 "frontmost"。遗憾的是,没有 NSWindow API 存在。为此,我尝试使用 windowNumbersWithOptions
来比较面板的 z 顺序。
-(void) togglePanelVisibility:(PMXPanelController *)panelController {
NSPanel *panel = [panelController window];
if ([panel isVisible]) {
NSArray *windowNumbers = [NSWindow windowNumbersWithOptions:0];
if ([panel windowNumber] == [[windowNumbers firstObject] integerValue]) {
[panel orderOut:self];
}
else {
[panel makeKeyAndOrderFront:self];
}
} else
[panelController showWindow:self];
}
唉,我收到的数组只包含一个数字 - 用于我的主文档 window。我可以在 "Window" 菜单中看到我的面板,我可以单击它们将它们置于最前面,我可以关闭它们并使用它们 - 但我无法通过 windowNumbersWithOptions:
有人有想法吗?
它在任何地方都没有说明这一点,但是从 NSWindowNumberListAllApplications
返回的少量 windows 来看,它看起来像 windowNumbersWithOptions
只有 returns windows 从正常级别或应用某种不包括其他 windows 的过滤。最好的替代方案是 NSApplication
实例的 orderedWindows
属性,但由于您已经提到面板被警告:
Only windows that are typically scriptable are included in the array. For example, panels are not included.
最好记住这两种方法都依赖于 Quartz API 并且可能使用 CGWindowListCopyWindowInfo
– 在最坏的情况下,您可以转到较低级别并使用它。
按照给定的建议,我终于得出了以下结论,这对我来说似乎很有效。
/* Here is the logic: If panel of panelController is frontMost - hide it.
If it is visible, but not frontMost - bring it to front.
If it is not visible - Show it, and bring it to front. */
-(void) togglePanelVisibility:(PMXPanelController *)panelController
{
NSWindow *panel = [panelController window];
if ([panel isVisible]) {
BOOL panelIsFront = [self isPanelFront:panel];
if (panelIsFront)
[panel orderOut:self];
else
[panel makeKeyAndOrderFront:self];
} else
[panelController showWindow:self];
}
// Attempt to determine if a given panel (window) is front window
-(BOOL) isPanelFront:(NSWindow *)panel
{
BOOL panelIsFront = NO;
#if 0
// This simple implementation won't work because orderedWindows don't contain panels.
panelIsFront = [panel isEqualTo:[[NSApp orderedWindows] firstObject]];
// This used to work, but broke on OS X 10.10 Yosemite. I only receive my main window.
panelIsFront = ([panel windowNumber] == [[[NSWindow windowNumbersWithOptions:0] firstObject] integerValue]);
#endif
// Last resort, - using CoreGraphics window list. Seems to work on all systems up to 10.10.4
NSMutableArray *windowNumbers = [NSMutableArray arrayWithCapacity:32]; // I rely on window numbers to determine "frontness".
CFArrayRef windowInfoArray = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
for (NSDictionary* nswindowsdescription in (__bridge NSArray*)windowInfoArray) {
NSNumber *windowLayer = (NSNumber*)[nswindowsdescription objectForKey:(NSString *)kCGWindowLayer];
if (windowLayer.integerValue != 0) // filter out windows not in our normal window layer.
continue;
NSNumber* windowid = (NSNumber*)[nswindowsdescription objectForKey:(NSString *)kCGWindowNumber];
if(windowid)
[windowNumbers addObject:windowid];
}
CFRelease(windowInfoArray);
panelIsFront = ([panel windowNumber] == [[windowNumbers firstObject] integerValue]);
return panelIsFront;
}
我有一个基于文档的应用程序,有一个主文档 window 和几个 "satellite" NSPanel windows 显示相关信息。它们不是浮动的,它们可以(并且确实)成为关键,并且似乎与主要 window.
在同一层我尝试像这样实现 show/hide 操作:如果面板不可见 - 显示它。如果它是可见的,但不是前面的 - 把它放在前面。如果它可见且在前面 - 隐藏它。
为此,我需要知道 NSPanel 是否为 "frontmost"。遗憾的是,没有 NSWindow API 存在。为此,我尝试使用 windowNumbersWithOptions
来比较面板的 z 顺序。
-(void) togglePanelVisibility:(PMXPanelController *)panelController {
NSPanel *panel = [panelController window];
if ([panel isVisible]) {
NSArray *windowNumbers = [NSWindow windowNumbersWithOptions:0];
if ([panel windowNumber] == [[windowNumbers firstObject] integerValue]) {
[panel orderOut:self];
}
else {
[panel makeKeyAndOrderFront:self];
}
} else
[panelController showWindow:self];
}
唉,我收到的数组只包含一个数字 - 用于我的主文档 window。我可以在 "Window" 菜单中看到我的面板,我可以单击它们将它们置于最前面,我可以关闭它们并使用它们 - 但我无法通过 windowNumbersWithOptions:
有人有想法吗?
它在任何地方都没有说明这一点,但是从 NSWindowNumberListAllApplications
返回的少量 windows 来看,它看起来像 windowNumbersWithOptions
只有 returns windows 从正常级别或应用某种不包括其他 windows 的过滤。最好的替代方案是 NSApplication
实例的 orderedWindows
属性,但由于您已经提到面板被警告:
Only windows that are typically scriptable are included in the array. For example, panels are not included.
最好记住这两种方法都依赖于 Quartz API 并且可能使用 CGWindowListCopyWindowInfo
– 在最坏的情况下,您可以转到较低级别并使用它。
按照给定的建议,我终于得出了以下结论,这对我来说似乎很有效。
/* Here is the logic: If panel of panelController is frontMost - hide it.
If it is visible, but not frontMost - bring it to front.
If it is not visible - Show it, and bring it to front. */
-(void) togglePanelVisibility:(PMXPanelController *)panelController
{
NSWindow *panel = [panelController window];
if ([panel isVisible]) {
BOOL panelIsFront = [self isPanelFront:panel];
if (panelIsFront)
[panel orderOut:self];
else
[panel makeKeyAndOrderFront:self];
} else
[panelController showWindow:self];
}
// Attempt to determine if a given panel (window) is front window
-(BOOL) isPanelFront:(NSWindow *)panel
{
BOOL panelIsFront = NO;
#if 0
// This simple implementation won't work because orderedWindows don't contain panels.
panelIsFront = [panel isEqualTo:[[NSApp orderedWindows] firstObject]];
// This used to work, but broke on OS X 10.10 Yosemite. I only receive my main window.
panelIsFront = ([panel windowNumber] == [[[NSWindow windowNumbersWithOptions:0] firstObject] integerValue]);
#endif
// Last resort, - using CoreGraphics window list. Seems to work on all systems up to 10.10.4
NSMutableArray *windowNumbers = [NSMutableArray arrayWithCapacity:32]; // I rely on window numbers to determine "frontness".
CFArrayRef windowInfoArray = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
for (NSDictionary* nswindowsdescription in (__bridge NSArray*)windowInfoArray) {
NSNumber *windowLayer = (NSNumber*)[nswindowsdescription objectForKey:(NSString *)kCGWindowLayer];
if (windowLayer.integerValue != 0) // filter out windows not in our normal window layer.
continue;
NSNumber* windowid = (NSNumber*)[nswindowsdescription objectForKey:(NSString *)kCGWindowNumber];
if(windowid)
[windowNumbers addObject:windowid];
}
CFRelease(windowInfoArray);
panelIsFront = ([panel windowNumber] == [[windowNumbers firstObject] integerValue]);
return panelIsFront;
}