X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=OSX%2Fosxgrabscreen.m;h=c7f4f15b686902b3185744abf1f3f06eef74c001;hb=aa75c7476aeaa84cf3abc192b376a8b03c325213;hp=2c7fc8b998c173651c152a33963ba20eb2cacfaa;hpb=3243731044b944673630b55e16674c191b026f84;p=xscreensaver diff --git a/OSX/osxgrabscreen.m b/OSX/osxgrabscreen.m index 2c7fc8b9..c7f4f15b 100644 --- a/OSX/osxgrabscreen.m +++ b/OSX/osxgrabscreen.m @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1992-2009 Jamie Zawinski +/* xscreensaver, Copyright (c) 1992-2012 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -10,18 +10,36 @@ */ /* This is the OSX implementation of desktop-grabbing and image-loading. + This code is invoked by "utils/grabclient.c", which is linked directly + in to each screen saver bundle. + + X11-based builds of the savers do not use this code (even on MacOS). + This is used only by the Cocoa build of the savers. */ #import #import -#import -#import "jwxyz.h" +#ifndef USE_IPHONE +# import +#else +# import "SaverRunner.h" +#endif +#import "jwxyz-cocoa.h" #import "grabscreen.h" #import "colorbars.h" #import "resources.h" #import "usleep.h" +#ifdef USE_IPHONE +# define NSImage UIImage +#endif + + +#ifndef MAC_OS_X_VERSION_10_6 +# define MAC_OS_X_VERSION_10_6 1060 /* undefined in 10.4 SDK, grr */ +#endif + #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 /* 10.4 code. @@ -123,8 +141,9 @@ copy_framebuffer_to_ximage (CGDirectDisplayID cgdpy, XImage *xim, /* Loads an image into the Drawable, returning once the image is loaded. */ -void -osx_grab_desktop_image (Screen *screen, Window xwindow, Drawable drawable) +Bool +osx_grab_desktop_image (Screen *screen, Window xwindow, Drawable drawable, + XRectangle *geom_ret) { Display *dpy = DisplayOfScreen (screen); NSView *nsview = jwxyz_window_view (xwindow); @@ -212,9 +231,49 @@ osx_grab_desktop_image (Screen *screen, Window xwindow, Drawable drawable) // Splat the XImage onto the target drawable (probably the window) // and free the bits. // - GC gc = 0; + XGCValues gcv; + GC gc = XCreateGC (dpy, drawable, 0, &gcv); XPutImage (dpy, drawable, gc, xim, 0, 0, 0, 0, xim->width, xim->height); + XFreeGC (dpy, gc); + + if (geom_ret) { + geom_ret->x = 0; + geom_ret->y = 0; + geom_ret->width = xim->width; + geom_ret->height = xim->height; + } + XDestroyImage (xim); + return True; +} + + +#elif defined(USE_IPHONE) + + /* What a hack! + + On iOS, our application delegate, SaverRunner, grabs an image + of itself as a UIImage before mapping the XScreenSaverView. + In this code, we ask SaverRunner for that UIImage, then copy + it to the root window. + */ + +Bool +osx_grab_desktop_image (Screen *screen, Window xwindow, Drawable drawable, + XRectangle *geom_ret) +{ + SaverRunner *s = + (SaverRunner *) [[UIApplication sharedApplication] delegate]; + if (! s) + return False; + if (! [s isKindOfClass:[SaverRunner class]]) + return False; + UIImage *img = [s screenshot]; + if (! img) + return False; + jwxyz_draw_NSImage_or_CGImage (DisplayOfScreen (screen), drawable, + True, img, geom_ret, 0); + return True; } @@ -229,8 +288,9 @@ osx_grab_desktop_image (Screen *screen, Window xwindow, Drawable drawable) /* Loads an image into the Drawable, returning once the image is loaded. */ -void -osx_grab_desktop_image (Screen *screen, Window xwindow, Drawable drawable) +Bool +osx_grab_desktop_image (Screen *screen, Window xwindow, Drawable drawable, + XRectangle *geom_ret) { Display *dpy = DisplayOfScreen (screen); NSView *nsview = jwxyz_window_view (xwindow); @@ -252,6 +312,19 @@ osx_grab_desktop_image (Screen *screen, Window xwindow, Drawable drawable) cgrect.size.width = xgwa.width; cgrect.size.height = xgwa.height; + /* If a password is required to unlock the screen, a large black + window will be on top of all of the desktop windows by the time + we reach here, making the screen-grab rather uninteresting. If + we move ourselves temporarily below the login-window windows + before capturing the image, we capture the real desktop as + intended. + */ + + // save our current level so we can restore it later + int oldLevel = [[nsview window] level]; + + [[nsview window] setLevel:CGWindowLevelForKey(kCGPopUpMenuWindowLevelKey)]; + // Grab a screen shot of those windows below this one // (hey, X11 can't do that!) // @@ -261,22 +334,58 @@ osx_grab_desktop_image (Screen *screen, Window xwindow, Drawable drawable) [[nsview window] windowNumber], kCGWindowImageDefault); + // put us back above the login windows so the screensaver is visible. + [[nsview window] setLevel:oldLevel]; + + if (! img) return False; + // Render the grabbed CGImage into the Drawable. - if (img) { - jwxyz_draw_NSImage_or_CGImage (DisplayOfScreen (screen), drawable, - False, img, NULL, 0); - CGImageRelease (img); - } + jwxyz_draw_NSImage_or_CGImage (DisplayOfScreen (screen), drawable, + False, img, geom_ret, 0); + CGImageRelease (img); + return True; } #endif /* 10.5+ code */ +# ifndef USE_IPHONE + /* Returns the EXIF rotation property of the image, if any. */ static int exif_rotation (const char *filename) { + /* As of 10.6, NSImage rotates according to EXIF by default: + http://developer.apple.com/mac/library/releasenotes/cocoa/appkit.html + So this function should return -1 when *running* on 10.6 systems. + But when running against older systems, we need to examine the image + to figure out its rotation. + */ + +# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 /* 10.6 SDK */ + + /* When we have compiled against the 10.6 SDK, we know that we are + running on a 10.6 or later system. + */ + return -1; + +# else /* Compiled against 10.5 SDK or earlier */ + + /* If this selector exists, then we are running against a 10.6 runtime + that does automatic EXIF rotation (despite the fact that we were + compiled against the 10.5 or earlier SDK). So in that case, this + function should no-op. + */ + if ([NSImage instancesRespondToSelector: + @selector(initWithDataIgnoringOrientation:)]) + return -1; + + /* Otherwise, go ahead and figure out what the rotational characteristics + of this image are. */ + + + /* This is a ridiculous amount of rigamarole to go through, but for some reason the "Orientation" tag does not exist in the "NSImageEXIFData" dictionary inside the NSBitmapImageRep of the NSImage. Several other @@ -296,8 +405,13 @@ exif_rotation (const char *filename) CFRelease (url); CFRelease (s); return rot; + +# endif /* 10.5 */ } +# endif /* USE_IPHONE */ + + /* Loads an image file and splats it onto the drawable. The image is drawn as large as possible while preserving its aspect ratio. @@ -308,6 +422,10 @@ Bool osx_load_image_file (Screen *screen, Window xwindow, Drawable drawable, const char *filename, XRectangle *geom_ret) { +# ifndef USE_IPHONE + + if (!filename || !*filename) return False; + NSImage *img = [[NSImage alloc] initWithContentsOfFile: [NSString stringWithCString:filename encoding:NSUTF8StringEncoding]]; @@ -315,9 +433,15 @@ osx_load_image_file (Screen *screen, Window xwindow, Drawable drawable, return False; jwxyz_draw_NSImage_or_CGImage (DisplayOfScreen (screen), drawable, - True, img, geom_ret, + True, img, geom_ret, exif_rotation (filename)); [img release]; return True; -} +# else /* USE_IPHONE */ + + /* This is handled differently: see grabclient.c and iosgrabimage.m. */ + return False; + +# endif /* USE_IPHONE */ +}