简体   繁体   中英

How do find out if there is a full-screen app running on a specific NSScreen

In Cocoa/AppKit, given a screen from [NSScreen screens] , how can I find out if there's a full-screen app running on that specific screen? I'm mostly interested in apps that use the Cocoa APIs for full-screen, but if there's a solution that also encompasses other types of full-screen apps, even better. The solution needs be able to pass Mac App Store approval.

My specific use case involves a menu bar app ( NSStatusItem ) and figuring out whether or not a menubar is shown at all on [NSScreen mainScreen] in order to allow a global keyboard shortcut to show either a popover positioning on the status item (if it's visible) or a floating window if there's no visible status item.

NSScreens themselves don't seem to expose any information about windows/apps, and NSRunningApplication doesn't expose this information either.

Are there perhaps Carbon APIs for finding this out? For example, if I have a list of windows, I could iterate through them and see if any window frames match the screens' frame exactly. On the other hand, there might be apps that have a frame like that but run underneath other apps (like the Backdrop app, https://itunes.apple.com/us/app/backdrop/id411461952?mt=12 ), so an approach like this would need to look at window levels.

You can try the CGWindowList API, such as CGWindowListCopyWindowInfo() .

If you just want to know if the menu bar is showing, you should be able to check -[NSApplication currentSystemPresentationOptions] for NSApplicationPresentationAutoHideMenuBar or NSApplicationPresentationHideMenuBar . That method can also tell you if the active app is in Cocoa full-screen mode ( NSApplicationPresentationFullScreen ).

Here's a solution based on CGWindowListCopyWindowInfo in Swift.

func fullScreenWindows(fullScreen: Bool) -> [CGWindowID] {
    var winList: [CGWindowID] = []
    // if you want to get the windows in full screen, you MUST make sure the option excluding 'optionOnScreenOnly'
    let option: CGWindowListOption = fullScreen ? .excludeDesktopElements : [.excludeDesktopElements, .optionOnScreenOnly]
    guard let winArray: CFArray = CGWindowListCopyWindowInfo(option, kCGNullWindowID) else {
        return winList
    }
    for i in 0..<CFArrayGetCount(winArray) {
        
        // current window's info
        let winInfo = unsafeBitCast(CFArrayGetValueAtIndex(winArray, i), to: CFDictionary.self)
        
        // current window's bounds
        guard let boundsDict = (winInfo as NSDictionary)[kCGWindowBounds],
            let bounds = CGRect.init(dictionaryRepresentation: boundsDict as! CFDictionary) else {
            continue
        }
        
        // to check the window is in full screen or not
        guard __CGSizeEqualToSize(NSScreen.main!.frame.size, bounds.size) else {
            continue
        }
        
        // current window's id
        guard let winId = (winInfo as NSDictionary)[kCGWindowNumber] as? CGWindowID,
            winId == kCGNullWindowID else {
            continue
        }
        
        winList.append(winId)
    }
    return winList
}

Here's a solution based on CGWindowListCopyWindowInfo , as Ken Thomases suggested in his answer:

- (BOOL)fullScreenAppPresentOn:(NSScreen *)screen
{
    // Get all of the visible windows (across all running applications)
    NSArray<NSDictionary*> *windowInfoList = (__bridge_transfer id)CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID);

    // For each window, see if the bounds are the same size as the screen's frame
    for (int windowInfoListIndex = 0; windowInfoListIndex < (int)windowsInfoList.count; windowInfoListIndex++)
    {    
        NSDictionary *windowInfo = windowInfoList[windowInfoListIndex];

        CFDictionaryRef windowInfoRef = (__bridge CFDictionaryRef) windowInfo[(__bridge NSString *)kCGWindowBounds];
        CGRect windowBounds;
        CGRectMakeWithDictionaryRepresentation(windowInfoRef, &windowBounds);

        if (CGRectEqualToRect([screen frame], windowBounds))
        {
            return YES;
        }
    }

    return NO;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM