1 /* xscreensaver, Copyright (c) 1992-1997, 2003 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"
28 #include "xpm-pixmap.h"
31 #include "images/som.xbm"
35 static unsigned int size;
36 static Pixmap self, temp, mask;
37 static GC SET, CLR, CPY, IOR, AND, XOR;
39 static int delay, delay2;
42 static unsigned int fg, bg;
44 static void display (Pixmap);
46 #define copy_all_to(from, xoff, yoff, to, gc) \
47 XCopyArea (dpy, (from), (to), (gc), 0, 0, \
48 size-(xoff), size-(yoff), (xoff), (yoff))
50 #define copy_all_from(to, xoff, yoff, from, gc) \
51 XCopyArea (dpy, (from), (to), (gc), (xoff), (yoff), \
52 size-(xoff), size-(yoff), 0, 0)
57 int qwad; /* fuckin' C, man... who needs namespaces? */
58 XFillRectangle (dpy, mask, CLR, 0, 0, size, size);
59 XFillRectangle (dpy, mask, SET, 0, 0, size>>1, size>>1);
60 for (qwad = size>>1; qwad > 0; qwad>>=1)
62 if (delay) usleep (delay);
63 copy_all_to (mask, 0, 0, temp, CPY); /* 1 */
64 copy_all_to (mask, 0, qwad, temp, IOR); /* 2 */
65 copy_all_to (self, 0, 0, temp, AND); /* 3 */
66 copy_all_to (temp, 0, 0, self, XOR); /* 4 */
67 copy_all_from (temp, qwad, 0, self, XOR); /* 5 */
68 copy_all_from (self, qwad, 0, self, IOR); /* 6 */
69 copy_all_to (temp, qwad, 0, self, XOR); /* 7 */
70 copy_all_to (self, 0, 0, temp, CPY); /* 8 */
71 copy_all_from (temp, qwad, qwad, self, XOR); /* 9 */
72 copy_all_to (mask, 0, 0, temp, AND); /* A */
73 copy_all_to (temp, 0, 0, self, XOR); /* B */
74 copy_all_to (temp, qwad, qwad, self, XOR); /* C */
75 copy_all_from (mask, qwad>>1, qwad>>1, mask, AND); /* D */
76 copy_all_to (mask, qwad, 0, mask, IOR); /* E */
77 copy_all_to (mask, 0, qwad, mask, IOR); /* F */
83 read_screen (Display *dpy, Window window, int *widthP, int *heightP)
86 XWindowAttributes xgwa;
89 XGetWindowAttributes (dpy, window, &xgwa);
91 *heightP = xgwa.height;
93 p = XCreatePixmap(dpy, window, *widthP, *heightP, xgwa.depth);
94 gcv.function = GXcopy;
95 gc = XCreateGC (dpy, window, GCFunction, &gcv);
97 load_random_image (xgwa.screen, window, p, NULL);
99 /* Reset the window's background color... */
100 XSetWindowBackground (dpy, window,
101 get_pixel_resource ("background", "Background",
102 dpy, xgwa.colormap));
103 XCopyArea (dpy, p, window, gc, 0, 0, *widthP, *heightP, 0, 0);
111 to_pow2(int n, Bool up)
113 /* sizeof(Dimension) == 2. */
114 int powers_of_2[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,
115 2048, 4096, 8192, 16384, 32768, 65536 };
117 if (n > 65536) size = 65536;
118 while (n >= powers_of_2[i]) i++;
119 if (n == powers_of_2[i-1])
122 return powers_of_2[up ? i : i-1];
128 XWindowAttributes xgwa;
135 XGetWindowAttributes (dpy, window, &xgwa);
136 cmap = xgwa.colormap;
139 fg = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
140 bg = get_pixel_resource ("background", "Background", dpy, cmap);
141 delay = get_integer_resource ("delay", "Integer");
142 delay2 = get_integer_resource ("delay2", "Integer");
143 if (delay < 0) delay = 0;
144 if (delay2 < 0) delay2 = 0;
145 bitmap_name = get_string_resource ("bitmap", "Bitmap");
146 if (! bitmap_name || !*bitmap_name)
147 bitmap_name = "(default)";
149 if (!strcmp (bitmap_name, "(default)"))
153 bitmap = XCreatePixmapFromBitmapData (dpy, window, (char *) som_bits,
154 width, height, fg, bg, depth);
155 scale_up = True; /* definitely. */
157 else if (!strcmp (bitmap_name, "(screen)"))
159 bitmap = read_screen (dpy, window, &width, &height);
160 scale_up = True; /* maybe? */
164 bitmap = xpm_file_to_pixmap (dpy, window, bitmap_name,
166 scale_up = True; /* probably? */
169 size = (width < height) ? height : width; /* make it square */
170 size = to_pow2(size, scale_up); /* round up to power of 2 */
171 { /* don't exceed screen size */
172 int s = XScreenNumberOfScreen(xgwa.screen);
173 int w = to_pow2(XDisplayWidth(dpy, s), False);
174 int h = to_pow2(XDisplayHeight(dpy, s), False);
175 if (size > w) size = w;
176 if (size > h) size = h;
179 self = XCreatePixmap (dpy, window, size, size, depth);
180 temp = XCreatePixmap (dpy, window, size, size, depth);
181 mask = XCreatePixmap (dpy, window, size, size, depth);
182 gcv.foreground = (depth == 1 ? 1 : (~0));
183 gcv.function=GXset; SET = XCreateGC(dpy,self,GCFunction|GCForeground,&gcv);
184 gcv.function=GXclear;CLR = XCreateGC(dpy,self,GCFunction|GCForeground,&gcv);
185 gcv.function=GXcopy; CPY = XCreateGC(dpy,self,GCFunction|GCForeground,&gcv);
186 gcv.function=GXor; IOR = XCreateGC(dpy,self,GCFunction|GCForeground,&gcv);
187 gcv.function=GXand; AND = XCreateGC(dpy,self,GCFunction|GCForeground,&gcv);
188 gcv.function=GXxor; XOR = XCreateGC(dpy,self,GCFunction|GCForeground,&gcv);
190 gcv.foreground = gcv.background = bg;
191 gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
192 /* Clear self to the background color (not to 0, which CLR does.) */
193 XFillRectangle (dpy, self, gc, 0, 0, size, size);
194 XSetForeground (dpy, gc, fg);
196 XCopyArea (dpy, bitmap, self, CPY, 0, 0, width, height,
197 (size - width)>>1, (size - height)>>1);
198 XFreePixmap(dpy, bitmap);
202 screenhack_handle_events (dpy);
206 display (Pixmap pixmap)
208 XWindowAttributes xgwa;
209 static int last_w = 0, last_h = 0;
210 XGetWindowAttributes (dpy, window, &xgwa);
211 if (xgwa.width != last_w || xgwa.height != last_h)
213 XClearWindow (dpy, window);
215 last_h = xgwa.height;
218 XCopyArea (dpy, pixmap, window, gc, 0, 0, size, size,
219 (xgwa.width-size)>>1, (xgwa.height-size)>>1);
221 XCopyPlane (dpy, pixmap, window, gc, 0, 0, size, size,
222 (xgwa.width-size)>>1, (xgwa.height-size)>>1, 1);
224 XDrawRectangle (dpy, window, gc,
225 ((xgwa.width-size)>>1)-1, ((xgwa.height-size)>>1)-1,
229 screenhack_handle_events (dpy);
233 char *progclass = "BlitSpin";
235 char *defaults [] = {
236 ".background: black",
237 ".foreground: white",
240 "*bitmap: (default)",
241 "*geometry: 512x512",
245 XrmOptionDescRec options [] = {
246 { "-delay", ".delay", XrmoptionSepArg, 0 },
247 { "-delay2", ".delay2", XrmoptionSepArg, 0 },
248 { "-bitmap", ".bitmap", XrmoptionSepArg, 0 },
249 { "-grab-screen", ".bitmap", XrmoptionNoArg, "(screen)" },
254 screenhack (Display *d, Window w)
259 if (delay2) usleep (delay2 * 2);
263 screenhack_handle_events (d);
264 if (delay2) usleep (delay2);