1 /* xscreensaver, Copyright (c) 1992-1997 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 /* Rotate a bitmap using using bitblts.
13 The bitmap must be square, and must be a power of 2 in size.
14 This was translated from SmallTalk code which appeared in the
15 August 1981 issue of Byte magazine.
17 The input bitmap may be non-square, it is padded and centered
18 with the background color. Another way would be to subdivide
19 the bitmap into square components and rotate them independently
20 (and preferably in parallel), but I don't think that would be as
23 It's too bad almost nothing uses blitter hardware these days,
24 or this might actually win.
27 #include "screenhack.h"
32 # ifndef PIXEL_ALREADY_TYPEDEFED
33 # define PIXEL_ALREADY_TYPEDEFED /* Sigh, Xmu/Drawing.h needs this... */
39 # include <X11/Xmu/Drawing.h>
41 # include <Xmu/Drawing.h>
45 #include "images/som.xbm"
49 static unsigned int size;
50 static Pixmap self, temp, mask;
51 static GC SET, CLR, CPY, IOR, AND, XOR;
53 static int delay, delay2;
56 static unsigned int fg, bg;
58 static void display (Pixmap);
60 #define copy_all_to(from, xoff, yoff, to, gc) \
61 XCopyArea (dpy, (from), (to), (gc), 0, 0, \
62 size-(xoff), size-(yoff), (xoff), (yoff))
64 #define copy_all_from(to, xoff, yoff, from, gc) \
65 XCopyArea (dpy, (from), (to), (gc), (xoff), (yoff), \
66 size-(xoff), size-(yoff), 0, 0)
71 int qwad; /* fuckin' C, man... who needs namespaces? */
72 XFillRectangle (dpy, mask, CLR, 0, 0, size, size);
73 XFillRectangle (dpy, mask, SET, 0, 0, size>>1, size>>1);
74 for (qwad = size>>1; qwad > 0; qwad>>=1)
76 if (delay) usleep (delay);
77 copy_all_to (mask, 0, 0, temp, CPY); /* 1 */
78 copy_all_to (mask, 0, qwad, temp, IOR); /* 2 */
79 copy_all_to (self, 0, 0, temp, AND); /* 3 */
80 copy_all_to (temp, 0, 0, self, XOR); /* 4 */
81 copy_all_from (temp, qwad, 0, self, XOR); /* 5 */
82 copy_all_from (self, qwad, 0, self, IOR); /* 6 */
83 copy_all_to (temp, qwad, 0, self, XOR); /* 7 */
84 copy_all_to (self, 0, 0, temp, CPY); /* 8 */
85 copy_all_from (temp, qwad, qwad, self, XOR); /* 9 */
86 copy_all_to (mask, 0, 0, temp, AND); /* A */
87 copy_all_to (temp, 0, 0, self, XOR); /* B */
88 copy_all_to (temp, qwad, qwad, self, XOR); /* C */
89 copy_all_from (mask, qwad>>1, qwad>>1, mask, AND); /* D */
90 copy_all_to (mask, qwad, 0, mask, IOR); /* E */
91 copy_all_to (mask, 0, qwad, mask, IOR); /* F */
97 read_bitmap (char *bitmap_name, int *widthP, int *heightP)
100 XWindowAttributes xgwa;
101 XpmAttributes xpmattrs;
103 xpmattrs.valuemask = 0;
106 XGetWindowAttributes (dpy, window, &xgwa);
109 xpmattrs.valuemask |= XpmCloseness;
110 xpmattrs.closeness = 40000;
113 xpmattrs.valuemask |= XpmVisual;
114 xpmattrs.visual = xgwa.visual;
117 xpmattrs.valuemask |= XpmDepth;
118 xpmattrs.depth = xgwa.depth;
121 xpmattrs.valuemask |= XpmColormap;
122 xpmattrs.colormap = xgwa.colormap;
125 result = XpmReadFileToPixmap (dpy, window, bitmap_name, &bitmap, 0,
130 fprintf (stderr, "%s: warning: xpm color substitution performed\n",
134 *widthP = xpmattrs.width;
135 *heightP = xpmattrs.height;
142 fprintf (stderr, "%s: xpm: color allocation failed\n", progname);
145 fprintf (stderr, "%s: xpm: out of memory\n", progname);
148 fprintf (stderr, "%s: xpm: unknown error code %d\n", progname, result);
158 bitmap = XmuLocateBitmapFile (DefaultScreenOfDisplay (dpy), bitmap_name,
159 0, 0, widthP, heightP, &xh, &yh);
162 fprintf (stderr, "%s: couldn't find bitmap %s\n", progname,
166 b2 = XmuCreatePixmapFromBitmap (dpy, window, bitmap, *widthP, *heightP,
168 XFreePixmap (dpy, bitmap);
174 "%s: your vendor doesn't ship the standard Xmu library.\n",
176 fprintf (stderr, "\tWe can't load XBM files without it.\n");
184 read_screen (Display *dpy, Window window, int *widthP, int *heightP)
187 XWindowAttributes xgwa;
190 XGetWindowAttributes (dpy, window, &xgwa);
191 *widthP = xgwa.width;
192 *heightP = xgwa.height;
194 grab_screen_image(xgwa.screen, window);
195 p = XCreatePixmap(dpy, window, *widthP, *heightP, xgwa.depth);
196 gcv.function = GXcopy;
197 gc = XCreateGC (dpy, window, GCFunction, &gcv);
198 XCopyArea (dpy, window, p, gc, 0, 0, *widthP, *heightP, 0, 0);
200 /* Reset the window's background color... */
201 XSetWindowBackground (dpy, window,
202 get_pixel_resource ("background", "Background",
203 dpy, xgwa.colormap));
204 XCopyArea (dpy, p, window, gc, 0, 0, *widthP, *heightP, 0, 0);
212 to_pow2(int n, Bool up)
214 /* sizeof(Dimension) == 2. */
215 int powers_of_2[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,
216 2048, 4096, 8192, 16384, 32768, 65536 };
218 if (n > 65536) size = 65536;
219 while (n >= powers_of_2[i]) i++;
220 if (n == powers_of_2[i-1])
223 return powers_of_2[up ? i : i-1];
229 XWindowAttributes xgwa;
236 XGetWindowAttributes (dpy, window, &xgwa);
237 cmap = xgwa.colormap;
240 fg = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
241 bg = get_pixel_resource ("background", "Background", dpy, cmap);
242 delay = get_integer_resource ("delay", "Integer");
243 delay2 = get_integer_resource ("delay2", "Integer");
244 if (delay < 0) delay = 0;
245 if (delay2 < 0) delay2 = 0;
246 bitmap_name = get_string_resource ("bitmap", "Bitmap");
247 if (! bitmap_name || !*bitmap_name)
248 bitmap_name = "(default)";
250 if (!strcmp (bitmap_name, "(default)"))
254 bitmap = XCreatePixmapFromBitmapData (dpy, window, (char *) som_bits,
255 width, height, fg, bg, depth);
256 scale_up = True; /* definitely. */
258 else if (!strcmp (bitmap_name, "(screen)"))
260 bitmap = read_screen (dpy, window, &width, &height);
261 scale_up = True; /* maybe? */
265 read_bitmap (bitmap_name, &width, &height);
266 scale_up = True; /* probably? */
269 size = (width < height) ? height : width; /* make it square */
270 size = to_pow2(size, scale_up); /* round up to power of 2 */
271 { /* don't exceed screen size */
272 int s = XScreenNumberOfScreen(xgwa.screen);
273 int w = to_pow2(XDisplayWidth(dpy, s), False);
274 int h = to_pow2(XDisplayHeight(dpy, s), False);
275 if (size > w) size = w;
276 if (size > h) size = h;
279 self = XCreatePixmap (dpy, window, size, size, depth);
280 temp = XCreatePixmap (dpy, window, size, size, depth);
281 mask = XCreatePixmap (dpy, window, size, size, depth);
282 gcv.foreground = (depth == 1 ? 1 : (~0));
283 gcv.function=GXset; SET = XCreateGC(dpy,self,GCFunction|GCForeground,&gcv);
284 gcv.function=GXclear;CLR = XCreateGC(dpy,self,GCFunction|GCForeground,&gcv);
285 gcv.function=GXcopy; CPY = XCreateGC(dpy,self,GCFunction|GCForeground,&gcv);
286 gcv.function=GXor; IOR = XCreateGC(dpy,self,GCFunction|GCForeground,&gcv);
287 gcv.function=GXand; AND = XCreateGC(dpy,self,GCFunction|GCForeground,&gcv);
288 gcv.function=GXxor; XOR = XCreateGC(dpy,self,GCFunction|GCForeground,&gcv);
290 gcv.foreground = gcv.background = bg;
291 gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
292 /* Clear self to the background color (not to 0, which CLR does.) */
293 XFillRectangle (dpy, self, gc, 0, 0, size, size);
294 XSetForeground (dpy, gc, fg);
296 XCopyArea (dpy, bitmap, self, CPY, 0, 0, width, height,
297 (size - width)>>1, (size - height)>>1);
298 XFreePixmap(dpy, bitmap);
302 screenhack_handle_events (dpy);
306 display (Pixmap pixmap)
308 XWindowAttributes xgwa;
309 static int last_w = 0, last_h = 0;
310 XGetWindowAttributes (dpy, window, &xgwa);
311 if (xgwa.width != last_w || xgwa.height != last_h)
313 XClearWindow (dpy, window);
315 last_h = xgwa.height;
319 XCopyArea (dpy, pixmap, window, gc, 0, 0, size, size,
320 (xgwa.width-size)>>1, (xgwa.height-size)>>1);
323 XCopyPlane (dpy, pixmap, window, gc, 0, 0, size, size,
324 (xgwa.width-size)>>1, (xgwa.height-size)>>1, 1);
326 XDrawRectangle (dpy, window, gc,
327 ((xgwa.width-size)>>1)-1, ((xgwa.height-size)>>1)-1,
331 screenhack_handle_events (dpy);
335 char *progclass = "BlitSpin";
337 char *defaults [] = {
338 ".background: black",
339 ".foreground: white",
342 "*bitmap: (default)",
343 "*geometry: 512x512",
347 XrmOptionDescRec options [] = {
348 { "-delay", ".delay", XrmoptionSepArg, 0 },
349 { "-delay2", ".delay2", XrmoptionSepArg, 0 },
350 { "-bitmap", ".bitmap", XrmoptionSepArg, 0 },
351 { "-grab-screen", ".bitmap", XrmoptionNoArg, "(screen)" },
356 screenhack (Display *d, Window w)
361 if (delay2) usleep (delay2 * 2);
365 screenhack_handle_events (d);
366 if (delay2) usleep (delay2);