14

If you call CGWindowListCopyWindowInfo(), the CFDictionaryRef that you get back contains a number of keys and values. One of these is kCGWindowSharingState, which has three possible values:

Window Sharing Constants
Specifies whether and how windows are shared between applications.

enum {
   kCGWindowSharingNone      = 0,
   kCGWindowSharingReadOnly  = 1,
   kCGWindowSharingReadWrite = 2
};

Nearly all of the windows on my system are kCGWindowSharingReadOnly, and the SonOfGrab screen-shot sample program avoids trying to capture kCGWindowSharingNone windows, but I couldn't find a good description of what those states are intended to be used for.

A simple test seems to show that several of the apps that come with OS X do have windows that are set to kCGWindowSharingNone, in particular Notes and iBooks. As far as I could tell from a quick test, having the window set to kCGWindowSharingNone doesn't actually prevent CGWindowListCreateImage() from capturing an image of that window. There are no windows that I was able to find that have kCGWindowSharingReadWrite set as their sharing mode.

Is all of this explained somewhere in the documentation, and I just missed it, or is it just more barely-documented Core Graphics functionality? Is there a good reason to not try to capture kCGWindowSharingNone windows, and will I be setting myself up for trouble in the future if I try to do so?


Further investigation has shown that when a Cocoa app calls

[NSWindow setSharingType:]

That sets kCGWindowSharingStateNone on the window, and prevents it from being captured by CGWindowListCreateImage(). There also some other windows that have kCGWindowSharingStateNone set, but which can be successfully captured - in particular, iBooks creates a window like this.

This is presumably a bug in iBooks, or in whatever API it's calling (since it doesn't call the NSWindow API).

Mus
  • 7,290
  • 24
  • 86
  • 130
Mark Bessey
  • 19,598
  • 4
  • 47
  • 69

1 Answers1

8

If you're going to ignore a window's sharing state you should be prepared to have some windows behave just as the API specifies and, apparently according to your own research, some not.

Higher up in the Cocoa APIs, NSWindow has a sharingType property. Setting that to NSWindowSharingTypeNone makes the corresponding CGWindow have a sharing type of kCGWindowSharingNone.

When I change this property on a window in my own application, it does prevent other applications from using the CGWindow API to capture the window’s contents. The documentation for CGWindowListCreateImage seems to also be correct.

Any windows that are onscreen but whose sharing setting is set to kCGWindowSharingNone are skipped and not included in the resulting image.

When I take a multi-window screenshot that should include the private window, that window is missing from the screenshot.


A reason one might do this in your own application is to prevent graphical content from being copied out.

I don’t know why iBooks and Notes exhibit the behavior you describe. I could imagine Apple not wanting a user to be able to copy content from an iBook, but that's clearly not happening, and doesn't make sense for Notes (incidentally, Notes' window seems to be normal in 10.10.2).

I am not aware of any way to take advantage of the read/write type for a window’s content.

Fabian
  • 6,973
  • 2
  • 26
  • 27
  • "Notes" seems to switch back and forth between NSWindowSharingTypeNone and NSWindowSharingTypeReadOnly on 10.9.5, but what triggers that is unclear. Also, I just tried with SonOfGrab, and it captures the iBooks window just fine as part of the image when it captures a screenshot (with CGWindowListCreateImage), despite iBooks having set its window as kCGWindowSharingNone. I'll have to check this on 10.10 - maybe something's different there. – Mark Bessey Jan 02 '15 at 20:11
  • Right. Apple Apps with windows that appear to be private don't behave as such. But when I use `NSWindowSharingTypeNone` on my own windows, Grab, SonOfGrab, and my own window capturing code fully respect the window's privacy. – Fabian Jan 02 '15 at 20:33
  • Okay, that's just bizarre. Maybe that flag is *also* getting set somewhere else when you use the NSWindow methods. – Mark Bessey Jan 03 '15 at 00:50
  • I just verified that iBooks *does not* call [NSWindow setSharingType:]. They must be using some other API to get the sharing flags set to None. I guess I'll have to actually check to see whether the window can be captured in order to determine whether it's "really" private. – Mark Bessey Jan 03 '15 at 01:32
  • iBooks can be captured, so it's not really private. I just offered the idea of keeping content private as something that makes sense in iBooks. It would also make sense in iTunes, but they employ some other mechanism to keep you from grabbing a continuous stream of images off a movie. – Fabian Jan 03 '15 at 05:15