(OS X)检测前端应用程序何时进入全屏模式

Tho*_*ann 7 macos

我正在编写一个"UIElement"应用程序,它在屏幕一侧显示一个状态窗口,类似于Dock.

现在,当一个程序占据整个屏幕时,我需要隐藏我的状态窗口,就像Dock一样.

我有什么选择来检测这个和反向事件?

我想,以避免通过定时事件投票,也不能使用无证技巧(如建议在这里)

什么行不通:

  • 为事件注册Carbon事件处理程序kEventAppSystemUIModeChanged是不够的 - 它可以检测VLC的全屏模式,但不能用于在窗口右上角使用新的全屏窗口小部件的现代Cocoa应用程序.

  • 类似地,通过观察对currentSystemPresentationOptions属性的更改,遵循Apple关于NSApplication presentationOptions API的说明也没有帮助 - 再次,它仅通知VLC的全屏模式,而不是关于使用窗口'右上方全屏小部件的应用程序.

  • 监视对屏幕配置的更改CGDisplayRegisterReconfigurationCallback不起作用,因为这些全屏模式没有任何回调.

Tho*_*ann 5

根据@Chuck 的建议,我想出了一个可行的解决方案,但可能并非万无一失。

该解决方案基于以下假设:10.7 的新窗口全屏模式将这些窗口移动到新的屏幕空间。因此,我们订阅活动空间更改的通知。在该通知处理程序中,我们检查窗口列表以检测是否包含菜单栏。如果不是,则可能意味着我们处于全屏空间中。

根据查克的想法,检查“菜单栏”窗口是否存在是我能想到的最好的测试。不过,我不太喜欢它,因为它对内部管理窗口的命名和存在做出了假设。

以下是 AppDelegate.m 内部的测试代码,其中还包括其他应用程序范围全屏模式的测试:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    NSApplication *app = [NSApplication sharedApplication];

    // Observe full screen mode from apps setting SystemUIMode
    // or invoking 'setPresentationOptions'
    [app addObserver:self
          forKeyPath:@"currentSystemPresentationOptions"
             options:NSKeyValueObservingOptionNew
             context:NULL];

    // Observe full screen mode from apps using a separate space
    // (i.e. those providing the fullscreen widget at the right
    // of their window title bar).
    [[[NSWorkspace sharedWorkspace] notificationCenter]
        addObserverForName:NSWorkspaceActiveSpaceDidChangeNotification
        object:NULL queue:NULL
        usingBlock:^(NSNotification *note)
        {
            // The active space changed.
            // Now we need to detect if this is a fullscreen space.
            // Let's look at the windows...
            NSArray *windows = CFBridgingRelease(CGWindowListCopyWindowInfo
                        (kCGWindowListOptionOnScreenOnly, kCGNullWindowID));
            //NSLog(@"active space change: %@", windows);

            // We detect full screen spaces by checking if there's a menubar
            // in the window list.
            // If not, we assume it's in fullscreen mode.
            BOOL hasMenubar = NO;
            for (NSDictionary *d in windows) {
                if ([d[@"kCGWindowOwnerName"] isEqualToString:@"Window Server"]
                 && [d[@"kCGWindowName"] isEqualToString:@"Menubar"]) {
                    hasMenubar = YES;
                    break;
                }
            }
            NSLog(@"fullscreen: %@", hasMenubar ? @"No" : @"Yes");
        }
     ];
}

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    if ([keyPath isEqual:@"currentSystemPresentationOptions"]) {
        NSLog(@"currentSystemPresentationOptions: %@", [change objectForKey:NSKeyValueChangeNewKey]); // a value of 4 indicates fullscreen mode
    }
}
Run Code Online (Sandbox Code Playgroud)