Get Desktop background image

In a WWDC 2019 "Advances in macOS Security" at 18:40 there is the following code

func getDesktopWindowIds() -> [CGWindowID] {
  let windows = CGWindowListCopyWindowInfo([.optionOnScreenOnly], kCGNullWindowID)! as! [[String: AnyObject]]
  let DesktopWindowLevel = CGWindowLevelForKey(.desktopWindow)-1
  let DesktopWindows = windows.filter {
    let windowLevel = $0[kCGWindowLayer as String] as! CGWindowLevel
    return windowLevel == desktopWindowLevel
  }
  return desktopWindows.map {
    $0[kCGWindowNumber as String] as! CGWindowID
  }
}

to find the CGWindowID of the Desktop background. This works, but when you then try to get the CGImage for that CGWindowID with

let cgImage = CGWindowListCreateImage(CGRectNull, [.optionIncludingWindow], cgWin, [.bestResolution])

cgImage does get a reference, however it's just a gray image. Not the Desktop picture.

It's clear from the documentation that ScreenCaptureKit should be used.

However, if used I get multiple warnings to the user, the most concerning one states:

"App" would like to record this computer's screen and audio.

This is not true! I do nothing with audio and to say a capture is a recording is also misleading.

Is there way to achieve what use to work before macOS 27? Or a way to change/avoid this misleading warning? Is there a reason why this warning is needed for capturing the Desktop background where before it was explicitly allowed?

Answered by DTS Engineer in 908439022

Thanks for tracking down where that code came from, and for posting your ScreenCaptureKit version.

What you describe is a change between releases: the same CGWindowListCreateImage call returned the desktop picture through macOS 26 and returns a gray image on macOS 27. I don't have a way to get the earlier result on macOS 27, and I can't comment on the reasons behind the change.

I also can't offer a way to capture with ScreenCaptureKit without the alert. The alert is how the person grants that access.

I suggest filing two separate Feedback Assistant reports:

  • one about the CGWindowListCreateImage change, showing what it returns for the same desktop background window on macOS 26 and on macOS 27
  • one about the Screen Recording alerts your app triggers, describing their text and what your app captures

Please post the Feedback numbers here so we can make sure they get routed to the right team. If you're not familiar with filing reports, take a look at Bug Reporting: How and Why?

For the first-run problem, the Capturing screen content in macOS sample notes: "After you grant permission, you need to restart the app to enable capture."

I also replied in your related thread, ScreenCaptureKit is NOT a full replacement for CGWindowListCreateImage, which covers the sharing picker and an enhancement request for a narrower grant.

Hide Icons is on MAS. The line that use to work is Hider.swift, 121.

guard let cgImage = CGWindowListCreateImage(CGRectNull, [.optionIncludingWindow], cgWin, [.bestResolution]) else { return }

where cgWin is the CGWindowID of the Desktop background found from above. cgImage is a reference to some gray background on macOS 27.

let cgImage = CGWindowListCreateImage(CGRectNull, [.optionIncludingWindow], cgWin, [.bestResolution])

Why do you set the screenBounds property to CGRectNull? Besides, this function is deprecated. Though it's a bit difficult to use, why don't you use the ScreenCaptureKit framework, instead?

I used CGRectNull because that is what Apple suggested to use in the WWDC'19 talk.

Yes, I can replace it using ScreenCaptureKit. I came up with the following:

    @available(macOS 27.0, *)
    private func refreshDesktopImage( cgWin: CGWindowID, win: MyWindow, onScreen: Bool) {
        let scale = win.screen?.backingScaleFactor ?? 1
        Task {
            do {
                // false is important: include Finder/Dock/Desktop windows.
                let content = try await SCShareableContent.excludingDesktopWindows( false, onScreenWindowsOnly: false)
                guard let desktopWindow = content.windows.first(where: { $0.windowID == cgWin }) else { return }

                let config = SCStreamConfiguration()
                config.width = Int((desktopWindow.frame.width * scale).rounded())
                config.height = Int((desktopWindow.frame.height * scale).rounded())
                config.showsCursor = false

                let cgImage = try await SCScreenshotManager.captureImage( contentFilter: SCContentFilter( desktopIndependentWindow: desktopWindow), configuration: config)

                await MainActor.run {
                    // Avoid applying an old async result to a reused window.
                    guard self.myDesktops[cgWin] === win else { return }

                    win.lastGoodImage = cgImage
                    let image = NSImage(cgImage: cgImage, size: .zero)
                    win.setWin( imageView: NSImageView(image: image), onScreen: onScreen, hidden: self.hidden)
                }
            } catch {
                NSLog("Desktop capture failed: \(error)")
            }
        }
    }

And while this works, it also throws up two Alert dialogs and numerous dialogs after it redirects the User to System Settings to toggle. Furthermore, those Alerts are completely misleading to what the app is doing. The app is NOT recording audio and is simply taking a snapshot of the Desktop background.

I also have an annoying bug in on first run, it doesn't even capture the actual background picture.

Here are the two dialogs that appear when Desktop background image is captured: and

Thanks for tracking down where that code came from, and for posting your ScreenCaptureKit version.

What you describe is a change between releases: the same CGWindowListCreateImage call returned the desktop picture through macOS 26 and returns a gray image on macOS 27. I don't have a way to get the earlier result on macOS 27, and I can't comment on the reasons behind the change.

I also can't offer a way to capture with ScreenCaptureKit without the alert. The alert is how the person grants that access.

I suggest filing two separate Feedback Assistant reports:

  • one about the CGWindowListCreateImage change, showing what it returns for the same desktop background window on macOS 26 and on macOS 27
  • one about the Screen Recording alerts your app triggers, describing their text and what your app captures

Please post the Feedback numbers here so we can make sure they get routed to the right team. If you're not familiar with filing reports, take a look at Bug Reporting: How and Why?

For the first-run problem, the Capturing screen content in macOS sample notes: "After you grant permission, you need to restart the app to enable capture."

I also replied in your related thread, ScreenCaptureKit is NOT a full replacement for CGWindowListCreateImage, which covers the sharing picker and an enhancement request for a narrower grant.

FB25105074 CGWindowListCreateImage change in macOS 27

FB25105277 ScreenCaptureKit should not invoke TCC for Desktop background/wallpaper windows