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 /* Loads an image file and splats it onto the drawable.
211 The image is drawn as large as possible while preserving its aspect ratio.
212 If geom_ret is provided, the actual rectangle the rendered image takes
213 up will be returned there.
216 osx_load_image_file (Screen *screen, Window xwindow, Drawable drawable,
217 const char *filename, XRectangle *geom_ret)
219 NSImage *img = [[NSImage alloc] initWithContentsOfFile:
220 [NSString stringWithCString:filename
221 encoding:NSUTF8StringEncoding]];
225 jwxyz_draw_NSImage (DisplayOfScreen (screen), drawable, img, geom_ret);