Screen capture before screen saver initializes

Hi everyone,

One common screen saver idiom is to transform what was on the screen before the screen saver initialized. I was wondering if it’s possible to copy the screen render to a texture so I can transform it in the screen saver.

There’s a few ways to go about this. One, is to create a gl::Fbo that is the same size as the screen, and when you want to capture to it, you just bind it and then call your usual render function. Another (much slower) way is to call copyWindowSurface() which copies the front buffer to a CPU side Surface. Ordinarily I’d recommend the fast method, but in this particular use case, it’s a safe assumption that no one is using the app when you’re about to capture the screen, so the slower but easier method might be more appropriate.

As far as I know, copyWindowSurface() only works in the window itself, so it can’t capture the desktop to transform it. The FBO method might work though.

Oh sorry, i thought you meant a screensaver / attract loop within your application. Are you intending to implement a screensaver separately that uses a texture from your application? In that case, you could always write the results of copyWindowSurface() to disk and have your screensaver read from the same file, or use a texture sharing protocol like Spout on windows or Syphon on mac.

Sorry, I don’t think I explained myself very clearly. I want to write a screen saver program that snapshots whatever is on the desktop the instant before the screen saver initializes so I can use it as a texture. There’s plenty of screen savers that do this so it must be possible somehow.

Assuming you’re on windows, have a look at the GetScreenShot function here. Even if it doesn’t work, it’s roughly how you’ll have to go about it.

Since I’m on mac, here’s how you might do it for OSX:

#include "cinder/cocoa/CinderCocoa.h"
#include <CoreGraphics/CoreGraphics.h>

ci::SurfaceRef TakeScreenShot ( const ci::Area& bounds )
{
    CGRect area = CGRectMake ( bounds.x1, bounds.y1, bounds.getWidth(), bounds.getHeight() );
    CGImageRef screenShot = CGWindowListCreateImage ( area, kCGWindowListOptionOnScreenOnly, kCGNullWindowID, kCGWindowImageDefault );
    
    auto result = ci::Surface::create ( cocoa::createImageSource( screenShot ) );
    CGImageRelease ( screenShot );
    
    return result;
}

Hey, this worked! Thank you so much!

Ah, spoke too soon. OSX crashes when this function is called from the screen saver after it’s installed. I wonder if it’s some kind of security issue.