summaryrefslogtreecommitdiffstats
path: root/OSX/grabclient-osx.m
diff options
context:
space:
mode:
Diffstat (limited to 'OSX/grabclient-osx.m')
-rw-r--r--OSX/grabclient-osx.m464
1 files changed, 0 insertions, 464 deletions
diff --git a/OSX/grabclient-osx.m b/OSX/grabclient-osx.m
deleted file mode 100644
index 7bfdcb4..0000000
--- a/OSX/grabclient-osx.m
+++ /dev/null
@@ -1,464 +0,0 @@
-/* xscreensaver, Copyright (c) 1992-2018 Jamie Zawinski <jwz@jwz.org>
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation. No representations are made about the suitability of this
- * software for any purpose. It is provided "as is" without express or
- * implied warranty.
- */
-
-/* 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 <stdlib.h>
-#import <stdint.h>
-#ifndef USE_IPHONE
-# import <Cocoa/Cocoa.h>
-#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.
-
- This version of the code works on 10.4, but is flaky. There is
- a better way to do it on 10.5 and newer, but taking this path,
- then we are being compiled against the 10.4 SDK instead of the
- 10.5 SDK, and the newer API is not available to us.
- */
-
-static void
-copy_framebuffer_to_ximage (CGDirectDisplayID cgdpy, XImage *xim,
- int window_x, int window_y)
-{
- unsigned char *data = (unsigned char *)
- CGDisplayAddressForPosition (cgdpy, window_x, window_y);
- int bpp = CGDisplayBitsPerPixel (cgdpy);
- int spp = CGDisplaySamplesPerPixel (cgdpy);
- int bps = CGDisplayBitsPerSample (cgdpy);
- int bpr = CGDisplayBytesPerRow (cgdpy);
-
- int y;
- int ximw = xim->width;
- int ximh = xim->height;
-
- uint32_t *odata = (uint32_t *) xim->data;
-
- switch (bpp) {
- case 32:
- if (spp != 3) abort();
- if (bps != 8) abort();
- int xwpl = xim->bytes_per_line/4;
- for (y = 0; y < ximh; y++) {
- // We can do this because the frame buffer and XImage are both ARGB 32.
- // Both PPC and Intel use ARGB, viewed in word order (not byte-order).
- memcpy (odata, data, ximw * 4);
- odata += xwpl;
- data += bpr;
- }
- break;
-
- case 16:
- if (spp != 3) abort();
- if (bps != 5) abort();
- for (y = 0; y < ximh; y++) {
- uint16_t *ip = (uint16_t *) data;
- int x;
- for (x = 0; x < ximw; x++) {
- uint16_t p = *ip++;
- // This should be ok on both PPC and Intel (ARGB, word order)
- unsigned char r = (p >> 10) & 0x1F;
- unsigned char g = (p >> 5) & 0x1F;
- unsigned char b = (p ) & 0x1F;
- r = (r << 3) | (r >> 2);
- g = (g << 3) | (g >> 2);
- b = (b << 3) | (b >> 2);
- uint32_t pixel = 0xFF000000 | (r << 16) | (g << 8) | b;
- // XPutPixel (xim, x, y, pixel);
- *odata++ = pixel;
- }
- data += bpr;
- }
- break;
-
- case 8:
- {
- /* Get the current palette of the display. */
- CGDirectPaletteRef pal = CGPaletteCreateWithDisplay (cgdpy);
-
- /* Map it to 32bpp pixels */
- uint32_t map[256];
- for (y = 0; y < 256; y++) {
- CGDeviceColor c = CGPaletteGetColorAtIndex (pal, y);
- unsigned char r = c.red * 255.0;
- unsigned char g = c.green * 255.0;
- unsigned char b = c.blue * 255.0;
- uint32_t pixel = 0xFF000000 | (r << 16) | (g << 8) | b;
- map[y] = pixel;
- }
-
- for (y = 0; y < ximh; y++) {
- unsigned char *ip = data;
- int x;
- for (x = 0; x < ximw; x++) {
- *odata++ = map[*ip++];
- }
- data += bpr;
- }
- CGPaletteRelease (pal);
- }
- break;
-
- default:
- abort();
- break;
- }
-}
-
-
-/* Loads an image into the Drawable, returning once the image is loaded.
- */
-Bool
-osx_grab_desktop_image (Screen *screen, Window xwindow, Drawable drawable,
- XRectangle *geom_ret)
-{
- Display *dpy = DisplayOfScreen (screen);
- NSView *nsview = jwxyz_window_view (xwindow);
- NSWindow *nswindow = [nsview window];
- XWindowAttributes xgwa;
- int window_x, window_y;
- Window unused;
-
- // Figure out where this window is on the screen.
- //
- XGetWindowAttributes (dpy, xwindow, &xgwa);
- XTranslateCoordinates (dpy, xwindow, RootWindowOfScreen (screen), 0, 0,
- &window_x, &window_y, &unused);
-
- // Use the size of the Drawable, not the Window.
- {
- Window r;
- int x, y;
- unsigned int w, h, bbw, d;
- XGetGeometry (dpy, drawable, &r, &x, &y, &w, &h, &bbw, &d);
- xgwa.width = w;
- xgwa.height = h;
- }
-
- // Create a tmp ximage to hold the screen data.
- //
- XImage *xim = XCreateImage (dpy, xgwa.visual, 32, ZPixmap, 0, 0,
- xgwa.width, xgwa.height, 8, 0);
- xim->data = (char *) malloc (xim->height * xim->bytes_per_line);
-
-
- // Find the address in the frame buffer of the top left of this window.
- //
- CGDirectDisplayID cgdpy = 0;
- {
- CGPoint p;
- // #### this isn't quite right for screen 2: it's offset slightly.
- p.x = window_x;
- p.y = window_y;
- CGDisplayCount n;
- CGGetDisplaysWithPoint (p, 1, &cgdpy, &n);
- if (!cgdpy) abort();
- }
-
- // Paint a transparent "hole" in this window.
- //
- BOOL oopaque = [nswindow isOpaque];
- [nswindow setOpaque:NO];
-
- [[NSColor clearColor] set];
- NSRectFill ([nsview frame]);
- [[nswindow graphicsContext] flushGraphics];
-
-
- // Without this, we get a dozen black scanlines at the top.
- // #### But with this, the screen saver loops, because calling this
- // seems to implicitly mark the display as non-idle!
- // CGDisplayCaptureWithOptions (cgdpy, kCGCaptureNoFill);
-
- // #### So let's try waiting for the vertical blank instead...
- // Nope, that doesn't work.
- //
- // CGDisplayWaitForBeamPositionOutsideLines (cgdpy, 0,
- // window_y + [nswindow frame].size.height);
-
- // #### Ok, try a busy-wait?
- // Nope.
- //
-
- // #### Ok, just fuckin' sleep!
- //
- usleep (100000);
-
-
- // Pull the bits out of the frame buffer.
- //
- copy_framebuffer_to_ximage (cgdpy, xim, window_x, window_y);
-
- // CGDisplayRelease (cgdpy);
-
- // Make the window visible again.
- //
- [nswindow setOpaque:oopaque];
-
- // Splat the XImage onto the target drawable (probably the window)
- // and free the bits.
- //
- 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;
-}
-
-
-#else /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
-
- 10.5+ code.
-
- This version of the code is simpler and more reliable, but
- uses an API that only exist on 10.5 and newer, so we can only
- use it if when being compiled against the 10.5 SDK or later.
- */
-
-extern float jwxyz_scale (Window); /* jwxyzI.h */
-
-/* Loads an image into the Drawable, returning once the image is loaded.
- */
-Bool
-osx_grab_desktop_image (Screen *screen, Window xwindow, Drawable drawable,
- XRectangle *geom_ret)
-{
- Display *dpy = DisplayOfScreen (screen);
- NSView *nsview = jwxyz_window_view (xwindow);
- XWindowAttributes xgwa;
- int window_x, window_y;
- Window unused;
-
- // Figure out where this window is on the screen.
- //
- XGetWindowAttributes (dpy, xwindow, &xgwa);
- XTranslateCoordinates (dpy, xwindow, RootWindowOfScreen (screen), 0, 0,
- &window_x, &window_y, &unused);
-
- // Grab only the rectangle of the screen underlying this window.
- //
- CGRect cgrect;
- double s = jwxyz_scale (xwindow);
- cgrect.origin.x = window_x;
- cgrect.origin.y = window_y;
- cgrect.size.width = xgwa.width / s;
- cgrect.size.height = xgwa.height / s;
-
- /* 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.
-
- Oct 2016: Surprise, this trick no longer works on MacOS 10.12. Sigh.
- */
-
- CGWindowID windowNumber = (CGWindowID) nsview.window.windowNumber;
-
- {
- CFArrayRef L = CGWindowListCopyWindowInfo (kCGWindowListOptionOnScreenOnly,
- kCGNullWindowID);
-
- CFIndex n = CFArrayGetCount(L);
- for (int i = 0; i < n; i++) {
- NSDictionary *dict = (NSDictionary *) CFArrayGetValueAtIndex(L, i);
-
- // loginwindow creates multiple toplevel windows. Grab the lowest one.
- if(![([dict objectForKey:(NSString *)kCGWindowOwnerName])
- compare:@"loginwindow"]) {
- windowNumber = ((NSNumber *)[dict objectForKey:
- (NSString *)kCGWindowNumber]).intValue;
- }
- }
- CFRelease (L);
- }
-
- // Grab a screen shot of those windows below this one
- // (hey, X11 can't do that!)
- //
- CGImageRef img =
- CGWindowListCreateImage (cgrect,
- kCGWindowListOptionOnScreenBelowWindow,
- windowNumber,
- kCGWindowImageDefault);
-
- if (! img) return False;
-
- // Render the grabbed CGImage into the Drawable.
- 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
- EXIF tags are there (e.g., shutter speed) but not orientation. WTF?
- */
- CFStringRef s = CFStringCreateWithCString (NULL, filename,
- kCFStringEncodingUTF8);
- CFURLRef url = CFURLCreateWithFileSystemPath (NULL, s,
- kCFURLPOSIXPathStyle, 0);
- CGImageSourceRef cgimg = CGImageSourceCreateWithURL (url, NULL);
- if (! cgimg) return -1;
-
- NSDictionary *props = (NSDictionary *)
- CGImageSourceCopyPropertiesAtIndex (cgimg, 0, NULL);
- int rot = [[props objectForKey:@"Orientation"] intValue];
- CFRelease (cgimg);
- 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.
- If geom_ret is provided, the actual rectangle the rendered image takes
- up will be returned there.
- */
-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]];
- if (!img)
- return False;
-
- jwxyz_draw_NSImage_or_CGImage (DisplayOfScreen (screen), drawable,
- True, img, geom_ret,
- exif_rotation (filename));
- [img release];
- return True;
-
-# else /* USE_IPHONE */
-
- /* This is handled differently: see grabclient.c and grabclient-ios.m. */
- return False;
-
-# endif /* USE_IPHONE */
-}