Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
// From https://stackoverflow.com/a/58985069/118631
@available(macOS 10.15, *)
func canRecordScreen() -> Bool {
let runningApplication = NSRunningApplication.current
let processIdentifier = runningApplication.processIdentifier
guard let windows = CGWindowListCopyWindowInfo([.optionOnScreenOnly], kCGNullWindowID)
as? [[String: AnyObject]] else
{
assertionFailure("Invalid window info")
return false
}
for window in windows {
// Get information for each window
guard let windowProcessIdentifier = (window[String(kCGWindowOwnerPID)] as? Int).flatMap(pid_t.init) else {
assertionFailure("Invalid window info")
continue
}
// Don't check windows owned by this process
if windowProcessIdentifier == processIdentifier {
continue
}
// Get process information for each window
guard let windowRunningApplication = NSRunningApplication(processIdentifier: windowProcessIdentifier) else {
// Ignore processes we don't have access to, such as WindowServer, which manages the windows named
// "Menubar" and "Backstop Menubar"
continue
}
if window[String(kCGWindowName)] as? String != nil {
if windowRunningApplication.executableURL?.lastPathComponent == "Dock" {
// Ignore the Dock, which provides the desktop picture
continue
} else {
return true
}
}
}
return false
}
@rudyrichter

This comment has been minimized.

Copy link

@rudyrichter rudyrichter commented Nov 22, 2019

    @available(macOS 10.15, *)
    func canRecordScreen() -> Bool {
        let runningApplication = NSRunningApplication.current
        let processIdentifier = runningApplication.processIdentifier
        guard let windows = CGWindowListCopyWindowInfo([.optionOnScreenOnly], kCGNullWindowID)
            as? [[String: AnyObject]],
            let _ = windows.first(where: { (window) -> Bool in
                guard let windowProcessIdentifier = (window[kCGWindowOwnerPID as String] as? Int).flatMap(pid_t.init),
                    windowProcessIdentifier != processIdentifier,
                    let windowRunningApplication = NSRunningApplication(processIdentifier: windowProcessIdentifier),
                    windowRunningApplication.executableURL?.lastPathComponent != "Dock",
                    let _ = window[String(kCGWindowName)] as? String else {
                        return false
                }
                
                return true
            }) else {
                return false
        }
        
        return true
    }
@soffes

This comment has been minimized.

Copy link
Owner Author

@soffes soffes commented Nov 22, 2019

For something this obscure, I think preserving the comments is worth it for the sake of future me. I’d wager the compiler will combine them all anyway in the optimize step.

@iby

This comment has been minimized.

Copy link

@iby iby commented Dec 4, 2019

@soffes Hey Sam, I left Craig a comment on SO, but was hoping if you could comment on this too? Will this work if there are no open windows? This is obviously an edge-case and there are plenty of other system windows hanging around, but just curios, whether this is a bulletproof solution when an app gets installed on a clean macOS and runs this check. Can there be a situation when there are simply no windows to determine this accurately?

@rudyrichter

This comment has been minimized.

Copy link

@rudyrichter rudyrichter commented Dec 4, 2019

@ianbytchek it should be, you'll end up getting windows for NSStatusItems, desktop icons and the like. Still would be great if Apple had added an API to query for screen recording authorization.

@iby

This comment has been minimized.

Copy link

@iby iby commented Dec 4, 2019

@rudyrichter Or at least a code snippet! Yes, I thought they might be also system-owned, but looks like they are fine. Thanks for the hint!

@soffes

This comment has been minimized.

Copy link
Owner Author

@soffes soffes commented Dec 4, 2019

@ianbytchek I haven't had any issues with it. Like Rudy said, I think there will always be some windows.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment