1 /* grab-ximage.c --- grab the screen to an XImage for use with OpenGL.
2 * xscreensaver, Copyright (c) 2001, 2003 Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
21 #include <X11/Xutil.h>
22 #include <GL/gl.h> /* only for GLfloat */
24 #include "grabscreen.h"
27 extern char *progname;
29 #include <X11/Xutil.h>
33 #define MAX(a,b) ((a)>(b)?(a):(b))
36 #define countof(x) (sizeof((x))/sizeof((*x)))
38 /* return the next larger power of 2. */
42 static unsigned int pow2[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,
43 2048, 4096, 8192, 16384, 32768, 65536 };
45 for (j = 0; j < countof(pow2); j++)
46 if (pow2[j] >= i) return pow2[j];
47 abort(); /* too big! */
51 /* Given a bitmask, returns the position and width of the field.
54 decode_mask (unsigned int mask, unsigned int *pos_ret, unsigned int *size_ret)
57 for (i = 0; i < 32; i++)
62 for (; i < 32; i++, j++)
63 if (! (mask & (1L << i)))
71 /* Given a value and a field-width, expands the field to fill out 8 bits.
74 spread_bits (unsigned char value, unsigned char width)
79 case 7: return (value << 1) | (value >> 6);
80 case 6: return (value << 2) | (value >> 4);
81 case 5: return (value << 3) | (value >> 2);
82 case 4: return (value << 4) | (value);
83 case 3: return (value << 5) | (value << 2) | (value >> 2);
84 case 2: return (value << 6) | (value << 4) | (value);
85 default: abort(); break;
93 union { int i; char c[sizeof(int)]; } u;
100 screen_to_ximage_1 (Screen *screen, Window window, Pixmap pixmap)
102 Display *dpy = DisplayOfScreen (screen);
103 XWindowAttributes xgwa;
104 int win_width, win_height;
105 int tex_width, tex_height;
107 XGetWindowAttributes (dpy, window, &xgwa);
108 win_width = xgwa.width;
109 win_height = xgwa.height;
111 /* GL texture sizes must be powers of two. */
112 tex_width = to_pow2(win_width);
113 tex_height = to_pow2(win_height);
115 /* Convert the server-side Pixmap to a client-side GL-ordered XImage.
118 XImage *ximage1, *ximage2;
121 ximage1 = XGetImage (dpy, pixmap, 0, 0, win_width, win_height, ~0L,
123 XFreePixmap (dpy, pixmap);
126 ximage2 = XCreateImage (dpy, xgwa.visual, 32, ZPixmap, 0, 0,
127 tex_width, tex_height, 32, 0);
129 ximage2->data = (char *) calloc (tex_height, ximage2->bytes_per_line);
132 Screen *dscreen = DefaultScreenOfDisplay (dpy);
133 Visual *dvisual = DefaultVisualOfScreen (dscreen);
134 if (visual_class (dscreen, dvisual) == PseudoColor ||
135 visual_class (dscreen, dvisual) == GrayScale)
137 Colormap cmap = DefaultColormapOfScreen(dscreen);
138 int ncolors = visual_cells (dscreen, dvisual);
140 colors = (XColor *) calloc (sizeof (*colors), ncolors+1);
141 for (i = 0; i < ncolors; i++)
143 XQueryColors (dpy, cmap, colors, ncolors);
147 /* Translate the server-ordered image to a client-ordered image.
151 unsigned int crpos=0, cgpos=0, cbpos=0, capos=0; /* bitfield positions */
152 unsigned int srpos=0, sgpos=0, sbpos=0;
153 unsigned int srmsk=0, sgmsk=0, sbmsk=0;
154 unsigned int srsiz=0, sgsiz=0, sbsiz=0;
157 unsigned char spread_map[3][256];
159 if (colors == 0) /* truecolor */
161 srmsk = ximage2->red_mask;
162 sgmsk = ximage2->green_mask;
163 sbmsk = ximage2->blue_mask;
165 decode_mask (srmsk, &srpos, &srsiz);
166 decode_mask (sgmsk, &sgpos, &sgsiz);
167 decode_mask (sbmsk, &sbpos, &sbsiz);
170 /* Note that unlike X, which is endianness-agnostic (since any XImage
171 can have its own specific bit ordering, with the server reversing
172 things as necessary) OpenGL pretends everything is client-side, so
173 we need to pack things in "RGBA" order on the client machine,
174 regardless of its endianness.
177 crpos = 24, cgpos = 16, cbpos = 8, capos = 0;
179 crpos = 0, cgpos = 8, cbpos = 16, capos = 24;
181 if (colors == 0) /* truecolor */
183 for (i = 0; i < 256; i++)
185 spread_map[0][i] = spread_bits (i, srsiz);
186 spread_map[1][i] = spread_bits (i, sgsiz);
187 spread_map[2][i] = spread_bits (i, sbsiz);
191 for (y = 0; y < win_height; y++)
193 int y2 = (win_height-1-y); /* Texture maps are upside down. */
194 for (x = 0; x < win_width; x++)
196 unsigned long sp = XGetPixel (ximage1, x, y2);
197 unsigned char sr, sg, sb;
202 sr = colors[sp].red & 0xFF;
203 sg = colors[sp].green & 0xFF;
204 sb = colors[sp].blue & 0xFF;
208 sr = (sp & srmsk) >> srpos;
209 sg = (sp & sgmsk) >> sgpos;
210 sb = (sp & sbmsk) >> sbpos;
212 sr = spread_map[0][sr];
213 sg = spread_map[1][sg];
214 sb = spread_map[2][sb];
217 cp = ((sr << crpos) |
222 XPutPixel (ximage2, x, y, cp);
227 if (pixmap) XFreePixmap (dpy, pixmap);
228 if (colors) free (colors);
229 free (ximage1->data);
231 XDestroyImage (ximage1);
234 fprintf(stderr, "%s: grabbed %dx%d window 0x%lx to %dx%d texture\n",
235 progname, win_width, win_height, (unsigned long) window,
236 tex_width, tex_height);
244 /* Returns an XImage structure containing an image of the desktop.
245 (As a side-effect, that image *may* be painted onto the given Window.)
246 This XImage will be 32 bits per pixel, 8 each per R, G, and B, with the
247 extra byte set to 0xFF.
250 screen_to_ximage (Screen *screen, Window window, char **filename_return)
252 Display *dpy = DisplayOfScreen (screen);
254 XWindowAttributes xgwa;
256 XGetWindowAttributes (dpy, window, &xgwa);
257 pixmap = XCreatePixmap (dpy, window, xgwa.width, xgwa.height, xgwa.depth);
258 load_random_image (screen, window, pixmap, filename_return);
260 return screen_to_ximage_1 (screen, window, pixmap);
265 void (*callback) (Screen *, Window, XImage *,
266 const char *name, void *closure, double cvt_time);
272 /* Returns the current time in seconds as a double.
278 # ifdef GETTIMEOFDAY_TWO_ARGS
280 gettimeofday(&now, &tzp);
285 return (now.tv_sec + ((double) now.tv_usec * 0.000001));
290 img_cb (Screen *screen, Window window, Drawable drawable,
291 const char *name, void *closure)
294 double cvt_time = double_time();
295 img_closure *data = (img_closure *) closure;
296 /* copy closure data to stack and free the original before running cb */
297 img_closure dd = *data;
298 memset (data, 0, sizeof (*data));
301 ximage = screen_to_ximage_1 (screen, window, dd.pixmap);
302 dd.callback (screen, window, ximage, name, dd.closure, cvt_time);
306 /* Like the above, but loads the image in the background and runs the
307 given callback once it has been loaded.
309 #include <X11/Intrinsic.h>
310 extern XtAppContext app;
313 fork_screen_to_ximage (Screen *screen, Window window,
314 void (*callback) (Screen *, Window, XImage *,
320 Display *dpy = DisplayOfScreen (screen);
321 XWindowAttributes xgwa;
322 img_closure *data = (img_closure *) calloc (1, sizeof(*data));
323 data->callback = callback;
324 data->closure = closure;
326 XGetWindowAttributes (dpy, window, &xgwa);
327 data->pixmap = XCreatePixmap (dpy, window, xgwa.width, xgwa.height,
329 fork_load_random_image (screen, window, data->pixmap, img_cb, data);