windowNumbersWithOptions:on Yosemite无法返回我的应用程序的NSPanel窗口

时间:2015-06-17 19:03:20

标签: cocoa nswindow z-order nspanel

我有一个基于文档的应用程序,带有一个主文档窗口和几个显示相关信息的“卫星”NSPanel窗口。它们不是浮动的,它们可以(并且确实)成为关键,并且似乎与主窗口位于同一层。

我尝试实现这样的显示/隐藏操作:如果面板不可见 - 显示它。如果它是可见的,但不是正面 - 让它前面。如果它是可见的并且正面 - 隐藏它。

为此,我需要知道NSPanel是否是“最前面的”。遗憾的是,没有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];
}

唉,我收到的数组只包含一个数字 - 用于我的主文档窗口。我可以在“窗口”菜单中看到我的面板,我可以点击它们将它们带到前面,我可以关闭它们并使用它们 - 但我无法通过windowNumbersWithOptions获取它们的数字:

任何人的想法?

2 个答案:

答案 0 :(得分:1)

它没有在任何地方说明这一点,但是通过NSWindowNumberListAllApplications返回的少量窗口来判断它看起来像windowNumbersWithOptions只返回正常级别的窗口或者应用某种类型的过滤而不是包括其他窗户。最好的选择是NSApplication实例的orderedWindows属性,但是因为你提到的面板被警告:

  

数组中只包含通常可编写脚本的窗口。例如,不包括面板。

最好记住两种方法都依赖于Quartz API并且可能使用CGWindowListCopyWindowInfo - 在最坏的情况下,您可以转到较低级别并使用它。

答案 1 :(得分:0)

Following the given suggestions, I finally came out with the following, which seems to work for me reasonably.

/* 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;
}