1 /* xscreensaver, Copyright (c) 1992-2009 Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
12 /* This is the OSX implementation of desktop-grabbing and image-loading.
17 #import <Cocoa/Cocoa.h>
19 #import "grabscreen.h"
26 copy_framebuffer_to_ximage (CGDirectDisplayID cgdpy, XImage *xim,
27 int window_x, int window_y)
29 unsigned char *data = (unsigned char *)
30 CGDisplayAddressForPosition (cgdpy, window_x, window_y);
31 int bpp = CGDisplayBitsPerPixel (cgdpy);
32 int spp = CGDisplaySamplesPerPixel (cgdpy);
33 int bps = CGDisplayBitsPerSample (cgdpy);
34 int bpr = CGDisplayBytesPerRow (cgdpy);
37 int ximw = xim->width;
38 int ximh = xim->height;
40 uint32_t *odata = (uint32_t *) xim->data;
44 if (spp != 3) abort();
45 if (bps != 8) abort();
46 int xwpl = xim->bytes_per_line/4;
47 for (y = 0; y < ximh; y++) {
48 // We can do this because the frame buffer and XImage are both ARGB 32.
49 // Both PPC and Intel use ARGB, viewed in word order (not byte-order).
50 memcpy (odata, data, ximw * 4);
57 if (spp != 3) abort();
58 if (bps != 5) abort();
59 for (y = 0; y < ximh; y++) {
60 uint16_t *ip = (uint16_t *) data;
62 for (x = 0; x < ximw; x++) {
64 // This should be ok on both PPC and Intel (ARGB, word order)
65 unsigned char r = (p >> 10) & 0x1F;
66 unsigned char g = (p >> 5) & 0x1F;
67 unsigned char b = (p ) & 0x1F;
68 r = (r << 3) | (r >> 2);
69 g = (g << 3) | (g >> 2);
70 b = (b << 3) | (b >> 2);
71 uint32_t pixel = 0xFF000000 | (r << 16) | (g << 8) | b;
72 // XPutPixel (xim, x, y, pixel);
81 /* Get the current palette of the display. */
82 CGDirectPaletteRef pal = CGPaletteCreateWithDisplay (cgdpy);
84 /* Map it to 32bpp pixels */
86 for (y = 0; y < 256; y++) {
87 CGDeviceColor c = CGPaletteGetColorAtIndex (pal, y);
88 unsigned char r = c.red * 255.0;
89 unsigned char g = c.green * 255.0;
90 unsigned char b = c.blue * 255.0;
91 uint32_t pixel = 0xFF000000 | (r << 16) | (g << 8) | b;
95 for (y = 0; y < ximh; y++) {
96 unsigned char *ip = data;
98 for (x = 0; x < ximw; x++) {
99 *odata++ = map[*ip++];
103 CGPaletteRelease (pal);
114 /* Loads an image into the Drawable, returning once the image is loaded.
117 osx_grab_desktop_image (Screen *screen, Window xwindow, Drawable drawable)
119 Display *dpy = DisplayOfScreen (screen);
120 XWindowAttributes xgwa;
121 NSView *nsview = jwxyz_window_view (xwindow);
122 NSWindow *nswindow = [nsview window];
123 int window_x, window_y;
126 // figure out where this window is on the screen
128 XGetWindowAttributes (dpy, xwindow, &xgwa);
129 XTranslateCoordinates (dpy, xwindow, RootWindowOfScreen (screen), 0, 0,
130 &window_x, &window_y, &unused);
132 // Use the size of the Drawable, not the Window.
136 unsigned int w, h, bbw, d;
137 XGetGeometry (dpy, drawable, &r, &x, &y, &w, &h, &bbw, &d);
142 // Create a tmp ximage to hold the screen data.
144 XImage *xim = XCreateImage (dpy, xgwa.visual, 32, ZPixmap, 0, 0,
145 xgwa.width, xgwa.height, 8, 0);
146 xim->data = (char *) malloc (xim->height * xim->bytes_per_line);
149 // Find the address in the frame buffer of the top left of this window.
151 CGDirectDisplayID cgdpy = 0;
154 // #### this isn't quite right for screen 2: it's offset slightly.
158 CGGetDisplaysWithPoint (p, 1, &cgdpy, &n);
162 // Paint a transparent "hole" in this window.
164 BOOL oopaque = [nswindow isOpaque];
165 [nswindow setOpaque:NO];
167 [[NSColor clearColor] set];
168 NSRectFill ([nsview frame]);
169 [[nswindow graphicsContext] flushGraphics];
172 // Without this, we get a dozen black scanlines at the top.
173 // #### But with this, the screen saver loops, because calling this
174 // seems to implicitly mark the display as non-idle!
175 // CGDisplayCaptureWithOptions (cgdpy, kCGCaptureNoFill);
177 // #### So let's try waiting for the vertical blank instead...
178 // Nope, that doesn't work.
180 // CGDisplayWaitForBeamPositionOutsideLines (cgdpy, 0,
181 // window_y + [nswindow frame].size.height);
183 // #### Ok, try a busy-wait?
187 // #### Ok, just fuckin' sleep!
192 // Pull the bits out of the frame buffer.
194 copy_framebuffer_to_ximage (cgdpy, xim, window_x, window_y);
196 // CGDisplayRelease (cgdpy);
198 // Make the window visible again.
200 [nswindow setOpaque:oopaque];
202 // Splat the XImage onto the target drawable (probably the window)
203 // and free the bits.
206 XPutImage (dpy, drawable, gc, xim, 0, 0, 0, 0, xim->width, xim->height);
211 /* Returns the EXIF rotation property of the image, if any.
214 exif_rotation (const char *filename)
216 /* This is a ridiculous amount of rigamarole to go through, but for some
217 reason the "Orientation" tag does not exist in the "NSImageEXIFData"
218 dictionary inside the NSBitmapImageRep of the NSImage. Several other
219 EXIF tags are there (e.g., shutter speed) but not orientation. WTF?
221 CFStringRef s = CFStringCreateWithCString (NULL, filename,
222 kCFStringEncodingUTF8);
223 CFURLRef url = CFURLCreateWithFileSystemPath (NULL, s,
224 kCFURLPOSIXPathStyle, 0);
225 CGImageSourceRef cgimg = CGImageSourceCreateWithURL (url, NULL);
226 if (! cgimg) return -1;
228 NSDictionary *props = (NSDictionary *)
229 CGImageSourceCopyPropertiesAtIndex (cgimg, 0, NULL);
230 int rot = [[props objectForKey:@"Orientation"] intValue];
238 /* Loads an image file and splats it onto the drawable.
239 The image is drawn as large as possible while preserving its aspect ratio.
240 If geom_ret is provided, the actual rectangle the rendered image takes
241 up will be returned there.
244 osx_load_image_file (Screen *screen, Window xwindow, Drawable drawable,
245 const char *filename, XRectangle *geom_ret)
247 NSImage *img = [[NSImage alloc] initWithContentsOfFile:
248 [NSString stringWithCString:filename
249 encoding:NSUTF8StringEncoding]];
253 jwxyz_draw_NSImage (DisplayOfScreen (screen), drawable, img, geom_ret,
254 exif_rotation (filename));