Skip navigation.
 
mlRe: Capturing windows in an NSImage
FROM : Andrew Farmer
DATE : Thu Jul 20 04:08:35 2006

On 19 Jul 06, at 14:31, Eric Summers wrote:
> I'm trying to figure out how programs like Apple's Grab screen capture
> application get an image of other application windows.  I thought 
> of using
> an AppleEvent to get the bounds of the windows then capturing the 
> data using
> a big transparent window, but that wouldn't work if the window is 
> hidden.
> Grab will get the image data even if the window is hidden.  Anyone 
> know how
> the Grab application works?


Yes!

http://www.objective-cocoa.org/forum/index.php?topic=1556.msg15898

The post is in French; here's a copy of the code and a translation of 
the
comments, for the list archive and the non-Francophones in the crowd:


NSImage *GrabWindow(int wid)
{
    // Get a context-ID
    int cid = [NSApp contextID];

    // Get the coordinates of the window
    CGRect cgrect;
    CGSGetWindowBounds(cid, wid, &cgrect);

    // Transform CGRect to NSRect
    NSRect nsrect;
    nsrect.origin.x = cgrect.origin.x;
    nsrect.origin.y = cgrect.origin.y;
    nsrect.size.width  = cgrect.size.width;
    nsrect.size.height = cgrect.size.height;

    // Create an NSImage
    NSImage *img = [[NSImage alloc] initWithSize:nsrect.size];

    // Write to the graphical context of the image
    [img lockFocus];

    // Get the grafport for the image
    void *grafport = [[NSGraphicsContext currentContext] graphicsPort];

    // Copy the contents of the window to the graphic context
    cgrect.origin = CGPointZero;
    CGContextCopyWindowCaptureContentsToRect(grafport, cgrect, cid, 
wid, 0);

    // Release the graphic context
    [img unlockFocus];

    // End of procedure: return the image
    return [img autorelease];
}


Note that this invokes a couple of private functions:

OSStatus CGSGetWindowBounds(int cid, int wid, CGRect *ret);

void CGContextCopyWindowCaptureContentsToRect(void *grafport, CGRect 
rect,
                int cid, int wid, int zero);

No, I don't know what the last parameter is for. The only program I 
know of
that uses CGCWCCTR - screencapture - always passes a constant zero 
for the
last argument.


There's also another useful function that gets invoked in the 
screencapture
tool:

OSStatus CGSFindWindowByGeometry(int cid, int zero, int one, int 
zero_again,
                CGPoint *screen_point, CGPoint *window_coords_out,
                int *wid_out, int *cid_out);

This'll take a point in screen coordinates, specified by 
screen_point, and
return the window ID of the frontmost window at that point (in 
wid_out), the
WindowServer connection ID of that application (in cid_out), and the
transformed coordinates of that point within the window (in 
window_coords_out).
There's actually no public *or* private API for the "click to select 
a window"
interface that you get in screencapture; the tool just creates 
translucent
overlay windows itself.

(Google actually isn't aware of any prior documentation for this 
function.)


Oh, and remember that these are highly private interfaces. They will 
probably
break on OS updates, particularly big ones. Don't complain to Apple 
when they
do.

Related mailsAuthorDate
mlCapturing windows in an NSImage Eric Summers Jul 19, 23:31
mlRe: Capturing windows in an NSImage Ryan Britton Jul 20, 02:14
mlRe: Re: Capturing windows in an NSImage Eric Summers Jul 20, 02:25
mlRe: Capturing windows in an NSImage Ryan Britton Jul 20, 02:30
mlRe: Re: Capturing windows in an NSImage Eric Summers Jul 20, 03:57
mlRe: Capturing windows in an NSImage Andrew Farmer Jul 20, 04:08
mlRe: Capturing windows in an NSImage John C. Randolph Jul 20, 10:44