1 /* xscreensaver, Copyright (c) 1992-2006 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.
16 #import <Cocoa/Cocoa.h>
18 #import "grabscreen.h"
25 copy_framebuffer_to_ximage (CGDirectDisplayID cgdpy, XImage *xim,
26 int window_x, int window_y)
28 unsigned char *data = (unsigned char *)
29 CGDisplayAddressForPosition (cgdpy, window_x, window_y);
30 int bpp = CGDisplayBitsPerPixel (cgdpy);
31 int spp = CGDisplaySamplesPerPixel (cgdpy);
32 int bps = CGDisplayBitsPerSample (cgdpy);
33 int bpr = CGDisplayBytesPerRow (cgdpy);
36 int ximw = xim->width;
37 int ximh = xim->height;
39 unsigned long *odata = (unsigned long *) xim->data;
43 if (spp != 3) abort();
44 if (bps != 8) abort();
45 int xwpl = xim->bytes_per_line/4;
46 for (y = 0; y < ximh; y++) {
47 // We can do this because the frame buffer and XImage are both ARGB 32.
48 // Both PPC and Intel use ARGB, viewed in word order (not byte-order).
49 memcpy (odata, data, ximw * 4);
56 if (spp != 3) abort();
57 if (bps != 5) abort();
58 for (y = 0; y < ximh; y++) {
59 unsigned short *ip = (unsigned short *) data;
61 for (x = 0; x < ximw; x++) {
62 unsigned short p = *ip++;
63 // This should be ok on both PPC and Intel (ARGB, word order)
64 unsigned char r = (p >> 10) & 0x1F;
65 unsigned char g = (p >> 5) & 0x1F;
66 unsigned char b = (p ) & 0x1F;
67 r = (r << 3) | (r >> 2);
68 g = (g << 3) | (g >> 2);
69 b = (b << 3) | (b >> 2);
70 unsigned long pixel = 0xFF000000 | (r << 16) | (g << 8) | b;
71 // XPutPixel (xim, x, y, pixel);
80 /* Get the current palette of the display. */
81 CGDirectPaletteRef pal = CGPaletteCreateWithDisplay (cgdpy);
83 /* Map it to 32bpp pixels */
84 unsigned long map[256];
85 for (y = 0; y < 256; y++) {
86 CGDeviceColor c = CGPaletteGetColorAtIndex (pal, y);
87 unsigned char r = c.red * 255.0;
88 unsigned char g = c.green * 255.0;
89 unsigned char b = c.blue * 255.0;
90 unsigned long pixel = 0xFF000000 | (r << 16) | (g << 8) | b;
94 for (y = 0; y < ximh; y++) {
95 unsigned char *ip = data;
97 for (x = 0; x < ximw; x++) {
98 *odata++ = map[*ip++];
102 CGPaletteRelease (pal);
113 /* Loads an image into the Drawable, returning once the image is loaded.
116 osx_grab_desktop_image (Screen *screen, Window xwindow, Drawable drawable)
118 Display *dpy = DisplayOfScreen (screen);
119 XWindowAttributes xgwa;
120 NSView *nsview = jwxyz_window_view (xwindow);
121 NSWindow *nswindow = [nsview window];
122 int window_x, window_y;
125 // figure out where this window is on the screen
127 XGetWindowAttributes (dpy, xwindow, &xgwa);
128 XTranslateCoordinates (dpy, xwindow, RootWindowOfScreen (screen), 0, 0,
129 &window_x, &window_y, &unused);
131 // Use the size of the Drawable, not the Window.
135 unsigned int w, h, bbw, d;
136 XGetGeometry (dpy, drawable, &r, &x, &y, &w, &h, &bbw, &d);
141 // Create a tmp ximage to hold the screen data.
143 XImage *xim = XCreateImage (dpy, xgwa.visual, 32, ZPixmap, 0, 0,
144 xgwa.width, xgwa.height, 8, 0);
145 xim->data = (char *) malloc (xim->height * xim->bytes_per_line);
148 // Find the address in the frame buffer of the top left of this window.
150 CGDirectDisplayID cgdpy = 0;
153 // #### this isn't quite right for screen 2: it's offset slightly.
157 CGGetDisplaysWithPoint (p, 1, &cgdpy, &n);
161 // Paint a transparent "hole" in this window.
163 BOOL oopaque = [nswindow isOpaque];
164 [nswindow setOpaque:NO];
166 [[NSColor clearColor] set];
167 NSRectFill ([nsview frame]);
168 [[nswindow graphicsContext] flushGraphics];
171 // Without this, we get a dozen black scanlines at the top.
172 // #### But with this, the screen saver loops, because calling this
173 // seems to implicitly mark the display as non-idle!
174 // CGDisplayCaptureWithOptions (cgdpy, kCGCaptureNoFill);
176 // #### So let's try waiting for the vertical blank instead...
177 // Nope, that doesn't work.
179 // CGDisplayWaitForBeamPositionOutsideLines (cgdpy, 0,
180 // window_y + [nswindow frame].size.height);
182 // #### Ok, try a busy-wait?
186 // #### Ok, just fuckin' sleep!
191 // Pull the bits out of the frame buffer.
193 copy_framebuffer_to_ximage (cgdpy, xim, window_x, window_y);
195 // CGDisplayRelease (cgdpy);
197 // Make the window visible again.
199 [nswindow setOpaque:oopaque];
201 // Splat the XImage onto the target drawable (probably the window)
202 // and free the bits.
205 XPutImage (dpy, drawable, gc, xim, 0, 0, 0, 0, xim->width, xim->height);
210 /* Returns the EXIF rotation property of the image, if any.
213 exif_rotation (const char *filename)
215 /* This is a ridiculous amount of rigamarole to go through, but for some
216 reason the "Orientation" tag does not exist in the "NSImageEXIFData"
217 dictionary inside the NSBitmapImageRep of the NSImage. Several other
218 EXIF tags are there (e.g., shutter speed) but not orientation. WTF?
220 CFStringRef s = CFStringCreateWithCString (NULL, filename,
221 kCFStringEncodingUTF8);
222 CFURLRef url = CFURLCreateWithFileSystemPath (NULL, s,
223 kCFURLPOSIXPathStyle, 0);
224 CGImageSourceRef cgimg = CGImageSourceCreateWithURL (url, NULL);
225 if (! cgimg) return -1;
227 NSDictionary *props = (NSDictionary *)
228 CGImageSourceCopyPropertiesAtIndex (cgimg, 0, NULL);
229 int rot = [[props objectForKey:@"Orientation"] intValue];
237 /* Loads an image file and splats it onto the drawable.
238 The image is drawn as large as possible while preserving its aspect ratio.
239 If geom_ret is provided, the actual rectangle the rendered image takes
240 up will be returned there.
243 osx_load_image_file (Screen *screen, Window xwindow, Drawable drawable,
244 const char *filename, XRectangle *geom_ret)
246 NSImage *img = [[NSImage alloc] initWithContentsOfFile:
247 [NSString stringWithCString:filename
248 encoding:NSUTF8StringEncoding]];
252 jwxyz_draw_NSImage (DisplayOfScreen (screen), drawable, img, geom_ret,
253 exif_rotation (filename));