Frans
Frans

Reputation: 780

How to access the pixel buffer of an NSWindow in OSX?

I'm looking for a way to grab the contents of a window like CamTwist 'Desktop+' feature. This can grab any window, even when its in the background.

Apple's OpenGLScreenCapture sample shows how to capture from the main screen but not from hidden surfaces.

Any idea how CamTwist gets access to the pixel buffer of an NSWindow?

Upvotes: 6

Views: 2966

Answers (2)

Mecki
Mecki

Reputation: 133059

AFAIK you cannot do that using official API. Of course this is possible, otherwise how would Apple implement Exposé otherwise? Here you can find a header that people have created by reverse engineering Apple's code; use it at your own risk (being a private API, any of those calls might change with any release from Apple at any time and without any notification) and don't expect Apple will let you into their App Store, if you are using it :-) As you can see, you can use this API to get a list of all windows (including hidden ones) of all applications and you can even manipulate them; though what you are really allowed to do may depend on your app privileges. And here's code that shows how you can use this private API, to capture the content of any window you like. Please note that the code works differently depending on OS version, there is a way how to do it pre-10.5 and how to do it post-10.5, so if you are targeting older systems, be sure you also implement both ways. The final API calls being used to really get the image are not private, BTW, they are found in the official SDK headers, only the way how you get a reference to a window that does not belong to your current process is private.

Update: Starting with 10.5 the important function to copy WindowIDs from the window server has been made public by Apple; so it is not private API any longer. However, it was already possible to retrieve those WindowIDs prior to 10.5, but the header hasn't been public at that time and still not all functions found in the reversed engineered header have been made public, yet.

Upvotes: 4

NSGod
NSGod

Reputation: 22948

AFAIK, the official APIs can be found in CGWindow.h as part of CoreGraphics:

/* Create an image containing a composite of the specified set of windows
   contained within a rectangular area. The set of windows is specified
   using options from `CGWindowListOption', along with an optional
   additional window ID.

   The windows list options are:

   --- kCGWindowListOptionAll, kCGWindowListOptionOnScreenOnly: Use all
   on-screen windows in this user session to construct the image. The
   parameter `windowID' should be `kCGNullWindowID'.

   --- kCGWindowListOptionOnScreenAboveWindow: Use all on-screen windows in
   this user session above the window specified by `windowID', ordered from
   front to back, to construct the image. To include the window specified by
   `windowID', add the flag `kCGWindowListOptionIncludingWindow'.

   --- kCGWindowListOptionOnScreenBelowWindow: Use all on-screen windows in
   this user session below the window specified by `windowID', ordered from
   front to back, to construct the image. To include the window specified by
   `windowID', add the flag `kCGWindowListOptionIncludingWindow'.

   --- kCGWindowListOptionIncludingWindow: Use only the window specified by
   `windowID' to construct the image.

   The parameter `screenBounds' specifies the rectangle in screen space
   (origin at the upper-left; y-value increasing downward). Setting
   `screenBounds' to `CGRectInfinite' will include all the windows on the
   entire desktop. Setting `screenBounds' to `CGRectNull' will use the
   bounding box of the specified windows as the screen space rectangle.

break

   /* The parameter `imageOptions' allows you to specify whether the window
   frame ornamentation, such as a shadow or similar effect, should be
   included or excluded in the bounds calculation when `CGRectNull' is
   specified for the window bounds.

   If no windows meet the specified criteria, or the windows can't be read,
   then a transparent black image will be returned.

   Any on-screen window with sharing type `kCGWindowSharingNone' will not
   be included in the image.

   This function returns NULL if the caller is not running within a Quartz
   GUI session or the window server is disabled. */

CG_EXTERN CGImageRef CGWindowListCreateImage(CGRect screenBounds,
  CGWindowListOption listOption, CGWindowID windowID,
  CGWindowImageOption imageOption)
  CG_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA);

/* Create an image containing a composite of the specified set of windows
   contained within a rectangular area à la `CGWindowListCreateImage'. The
   set of windows is specified by `windowArray', an array of window IDs. */

CG_EXTERN CGImageRef CGWindowListCreateImageFromArray(CGRect screenBounds,
  CFArrayRef windowArray, CGWindowImageOption imageOption)
  CG_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA);

Sorry, could not find a link to the documentation on Apple's site. However, they do appear to have sample code in Son of Grab.

Upvotes: 6

Related Questions