1 /* grab-ximage.c --- grab the screen to an XImage for use with OpenGL.
2 * xscreensaver, Copyright (c) 2001 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
20 #include <X11/Xutil.h>
21 #include <GL/gl.h> /* only for GLfloat */
23 #include "grabscreen.h"
26 extern char *progname;
28 #include <X11/Xutil.h>
31 #define MAX(a,b) ((a)>(b)?(a):(b))
34 #define countof(x) (sizeof((x))/sizeof((*x)))
36 /* return the next larger power of 2. */
40 static unsigned int pow2[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,
41 2048, 4096, 8192, 16384, 32768, 65536 };
43 for (j = 0; j < countof(pow2); j++)
44 if (pow2[j] >= i) return pow2[j];
45 abort(); /* too big! */
49 /* Given a bitmask, returns the position and width of the field.
52 decode_mask (unsigned int mask, unsigned int *pos_ret, unsigned int *size_ret)
55 for (i = 0; i < 32; i++)
60 for (; i < 32; i++, j++)
61 if (! (mask & (1L << i)))
69 /* Given a value and a field-width, expands the field to fill out 8 bits.
72 spread_bits (unsigned char value, unsigned char width)
77 case 7: return (value << 1) | (value >> 6);
78 case 6: return (value << 2) | (value >> 4);
79 case 5: return (value << 3) | (value >> 2);
80 case 4: return (value << 4) | (value);
81 case 3: return (value << 5) | (value << 2) | (value >> 2);
82 case 2: return (value << 6) | (value << 4) | (value);
83 default: abort(); break;
88 /* Returns an XImage structure containing an image of the desktop.
89 (As a side-effect, that image will be painted onto the given Window.)
90 This XImage will be 32 bits per pixel, 8 each per R, G, and B, with the
91 extra byte set to 0xFF.
94 screen_to_ximage (Screen *screen, Window window)
96 Display *dpy = DisplayOfScreen (screen);
97 XWindowAttributes xgwa;
98 int win_width, win_height;
99 int tex_width, tex_height;
101 grab_screen_image (screen, window);
103 XGetWindowAttributes (dpy, window, &xgwa);
104 win_width = xgwa.width;
105 win_height = xgwa.height;
107 /* GL texture sizes must be powers of two. */
108 tex_width = to_pow2(win_width);
109 tex_height = to_pow2(win_height);
111 /* Convert the server-side Drawable to a client-side GL-ordered XImage.
114 XImage *ximage1, *ximage2;
117 ximage1 = XGetImage (dpy, window, 0, 0, win_width, win_height, ~0L,
119 ximage2 = XCreateImage (dpy, xgwa.visual, 32, ZPixmap, 0, 0,
120 tex_width, tex_height, 32, 0);
122 ximage2->data = (char *) calloc (tex_height, ximage2->bytes_per_line);
125 Screen *dscreen = DefaultScreenOfDisplay (dpy);
126 Visual *dvisual = DefaultVisualOfScreen (dscreen);
127 if (visual_class (dscreen, dvisual) == PseudoColor ||
128 visual_class (dscreen, dvisual) == GrayScale)
130 Colormap cmap = DefaultColormapOfScreen(dscreen);
131 int ncolors = visual_cells (dscreen, dvisual);
133 colors = (XColor *) calloc (sizeof (*colors), ncolors+1);
134 for (i = 0; i < ncolors; i++)
136 XQueryColors (dpy, cmap, colors, ncolors);
140 /* Translate the server-ordered image to a client-ordered image.
144 int crpos, cgpos, cbpos, capos; /* bitfield positions */
145 int srpos, sgpos, sbpos;
146 int srmsk, sgmsk, sbmsk;
147 int srsiz, sgsiz, sbsiz;
150 unsigned char spread_map[3][256];
152 srmsk = ximage1->red_mask;
153 sgmsk = ximage1->green_mask;
154 sbmsk = ximage1->blue_mask;
156 decode_mask (srmsk, &srpos, &srsiz);
157 decode_mask (sgmsk, &sgpos, &sgsiz);
158 decode_mask (sbmsk, &sbpos, &sbsiz);
160 /* Note that unlike X, which is endianness-agnostic (since any XImage
161 can have its own specific bit ordering, with the server reversing
162 things as necessary) OpenGL pretends everything is client-side, so
163 we need to pack things in "RGBA" order on the client machine,
164 regardless of its endianness.
166 crpos = 0, cgpos = 8, cbpos = 16, capos = 24;
168 for (i = 0; i < 256; i++)
170 spread_map[0][i] = spread_bits (i, srsiz);
171 spread_map[1][i] = spread_bits (i, sgsiz);
172 spread_map[2][i] = spread_bits (i, sbsiz);
175 for (y = 0; y < win_height; y++)
177 int y2 = (win_height-1-y); /* Texture maps are upside down. */
178 for (x = 0; x < win_width; x++)
180 unsigned long sp = XGetPixel (ximage1, x, y2);
181 unsigned char sr, sg, sb;
186 sr = colors[sp].red & 0xFF;
187 sg = colors[sp].green & 0xFF;
188 sb = colors[sp].blue & 0xFF;
192 sr = (sp & srmsk) >> srpos;
193 sg = (sp & sgmsk) >> sgpos;
194 sb = (sp & sbmsk) >> sbpos;
196 sr = spread_map[0][sr];
197 sg = spread_map[1][sg];
198 sb = spread_map[2][sb];
201 cp = ((sr << crpos) |
206 XPutPixel (ximage2, x, y, cp);
211 if (colors) free (colors);
212 free (ximage1->data);
214 XDestroyImage (ximage1);
217 fprintf(stderr, "%s: grabbed %dx%d window 0x%lx to %dx%d texture\n",
218 progname, win_width, win_height, (unsigned long) window,
219 tex_width, tex_height);