1 /* xscreensaver, Copyright (c) 1999, 2001, 2002 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
13 #include "screenhack.h"
16 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
18 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
20 #define countof(x) (sizeof(x)/sizeof(*(x)))
21 #define ABS(x) ((x)<0?-(x):(x))
23 static Bool transparent_p;
25 static unsigned long base_pixel, *plane_masks;
35 void (*draw) (Display *, Drawable, struct throbber *);
39 draw_star (Display *dpy, Drawable w, struct throbber *t)
44 int s = t->size / 0.383; /* trial and error, I forget how to derive this */
49 points[0].x = x + s * cos(o + 0.0*c); points[0].y = y + s * sin(o + 0.0*c);
50 points[1].x = x + s2 * cos(o + 0.1*c); points[1].y = y + s2 * sin(o + 0.1*c);
51 points[2].x = x + s * cos(o + 0.2*c); points[2].y = y + s * sin(o + 0.2*c);
52 points[3].x = x + s2 * cos(o + 0.3*c); points[3].y = y + s2 * sin(o + 0.3*c);
53 points[4].x = x + s * cos(o + 0.4*c); points[4].y = y + s * sin(o + 0.4*c);
54 points[5].x = x + s2 * cos(o + 0.5*c); points[5].y = y + s2 * sin(o + 0.5*c);
55 points[6].x = x + s * cos(o + 0.6*c); points[6].y = y + s * sin(o + 0.6*c);
56 points[7].x = x + s2 * cos(o + 0.7*c); points[7].y = y + s2 * sin(o + 0.7*c);
57 points[8].x = x + s * cos(o + 0.8*c); points[8].y = y + s * sin(o + 0.8*c);
58 points[9].x = x + s2 * cos(o + 0.9*c); points[9].y = y + s2 * sin(o + 0.9*c);
59 points[10] = points[0];
61 XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
65 draw_circle (Display *dpy, Drawable w, struct throbber *t)
67 XDrawArc (dpy, w, t->gc,
75 draw_hlines (Display *dpy, Drawable w, struct throbber *t)
77 XDrawLine (dpy, w, t->gc, 0,
78 t->y - t->size, t->max_size,
80 XDrawLine (dpy, w, t->gc, 0,
81 t->y + t->size, t->max_size,
86 draw_vlines (Display *dpy, Drawable w, struct throbber *t)
88 XDrawLine (dpy, w, t->gc,
90 t->x - t->size, t->max_size);
91 XDrawLine (dpy, w, t->gc,
93 t->x + t->size, t->max_size);
97 draw_corners (Display *dpy, Drawable w, struct throbber *t)
99 int s = (t->size + t->thickness) / 2;
102 points[0].x = 0; points[0].y = t->y - s;
103 points[1].x = t->x - s; points[1].y = t->y - s;
104 points[2].x = t->x - s; points[2].y = 0;
105 XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
107 points[0].x = 0; points[0].y = t->y + s;
108 points[1].x = t->x - s; points[1].y = t->y + s;
109 points[2].x = t->x - s; points[2].y = t->max_size;
110 XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
112 points[0].x = t->x + s; points[0].y = 0;
113 points[1].x = t->x + s; points[1].y = t->y - s;
114 points[2].x = t->max_size; points[2].y = t->y - s;
115 XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
117 points[0].x = t->x + s; points[0].y = t->max_size;
118 points[1].x = t->x + s; points[1].y = t->y + s;
119 points[2].x = t->max_size; points[2].y = t->y + s;
120 XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
124 static struct throbber *
125 make_throbber (Display *dpy, Drawable d, int w, int h, unsigned long pixel)
129 struct throbber *t = (struct throbber *) malloc (sizeof (*t));
133 t->speed = get_integer_resource ("speed", "Speed");
134 t->fuse = 1 + (random() % 4);
135 t->thickness = get_integer_resource ("thickness", "Thickness");
137 if (t->speed < 0) t->speed = -t->speed;
138 t->speed += (((random() % t->speed) / 2) - (t->speed / 2));
139 if (t->speed > 0) t->speed = -t->speed;
142 t->size = t->max_size;
144 t->size = t->thickness, t->speed = -t->speed;
146 flags = GCForeground;
149 gcv.foreground = ~0L;
150 gcv.plane_mask = base_pixel | plane_masks[random() % nplanes];
151 flags |= GCPlaneMask;
155 gcv.foreground = pixel;
158 gcv.line_width = t->thickness;
159 gcv.line_style = LineSolid;
160 gcv.cap_style = CapProjecting;
161 gcv.join_style = JoinMiter;
163 flags |= (GCLineWidth | GCLineStyle | GCCapStyle | GCJoinStyle);
164 t->gc = XCreateGC (dpy, d, flags, &gcv);
166 switch (random() % 11) {
167 case 0: case 1: case 2: case 3: t->draw = draw_star; break;
168 case 4: case 5: case 6: case 7: t->draw = draw_circle; break;
169 case 8: t->draw = draw_hlines; break;
170 case 9: t->draw = draw_vlines; break;
171 case 10: t->draw = draw_corners; break;
172 default: abort(); break;
179 throb (Display *dpy, Drawable window, struct throbber *t)
182 if (t->size <= (t->thickness / 2))
184 t->speed = -t->speed;
185 t->size += (t->speed * 2);
187 else if (t->size > t->max_size)
189 t->speed = -t->speed;
190 t->size += (t->speed * 2);
196 XFreeGC (dpy, t->gc);
197 memset (t, 0, sizeof(*t));
203 t->draw (dpy, window, t);
210 char *progclass = "Deluxe";
212 char *defaults [] = {
213 ".background: black",
214 ".foreground: white",
221 "*transparent: False",
222 "*doubleBuffer: True",
223 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
225 "*useDBEClear: True",
226 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
230 XrmOptionDescRec options [] = {
231 { "-delay", ".delay", XrmoptionSepArg, 0 },
232 { "-thickness", ".thickness", XrmoptionSepArg, 0 },
233 { "-count", ".count", XrmoptionSepArg, 0 },
234 { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
235 { "-speed", ".speed", XrmoptionSepArg, 0 },
236 { "-transparent", ".transparent", XrmoptionNoArg, "True" },
237 { "-opaque", ".transparent", XrmoptionNoArg, "False" },
238 { "-db", ".doubleBuffer", XrmoptionNoArg, "True" },
239 { "-no-db", ".doubleBuffer", XrmoptionNoArg, "False" },
244 screenhack (Display *dpy, Window window)
246 int count = get_integer_resource ("count", "Integer");
247 int delay = get_integer_resource ("delay", "Integer");
248 int ncolors = get_integer_resource ("ncolors", "Integer");
249 Bool dbuf = get_boolean_resource ("doubleBuffer", "Boolean");
250 Bool dbeclear_p = get_boolean_resource ("useDBEClear", "Boolean");
255 struct throbber **throbbers;
256 XWindowAttributes xgwa;
257 Pixmap b=0, ba=0, bb=0; /* double-buffer to reduce flicker */
258 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
259 XdbeBackBuffer backb = 0;
260 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
262 XGetWindowAttributes (dpy, window, &xgwa);
264 transparent_p = get_boolean_resource("transparent", "Transparent");
266 colors = (XColor *) calloc (sizeof(*colors), ncolors);
268 if (get_boolean_resource("mono", "Boolean"))
272 colors[0].pixel = get_pixel_resource("foreground", "Foreground",
275 else if (transparent_p)
277 nplanes = get_integer_resource ("planes", "Planes");
279 nplanes = (random() % (xgwa.depth-2)) + 2;
281 allocate_alpha_colors (xgwa.screen, xgwa.visual, xgwa.colormap,
282 &nplanes, True, &plane_masks,
287 "%s: couldn't allocate any color planes; turning transparency off.\n",
289 transparent_p = False;
296 make_random_colormap (dpy, xgwa.visual, xgwa.colormap,
297 colors, &ncolors, True, True, 0, True);
304 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
306 b = xdbe_get_backbuffer (dpy, window, XdbeBackground);
308 b = xdbe_get_backbuffer (dpy, window, XdbeUndefined);
310 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
314 ba = XCreatePixmap (dpy, window, xgwa.width, xgwa.height,xgwa.depth);
315 bb = XCreatePixmap (dpy, window, xgwa.width, xgwa.height,xgwa.depth);
324 throbbers = (struct throbber **) calloc (count, sizeof(struct throbber *));
325 for (i = 0; i < count; i++)
326 throbbers[i] = make_throbber (dpy, b, xgwa.width, xgwa.height,
327 colors[random() % ncolors].pixel);
329 gcv.foreground = get_pixel_resource ("background", "Background",
331 erase_gc = XCreateGC (dpy, b, GCForeground, &gcv);
333 if (ba) XFillRectangle (dpy, ba, erase_gc, 0, 0, xgwa.width, xgwa.height);
334 if (bb) XFillRectangle (dpy, bb, erase_gc, 0, 0, xgwa.width, xgwa.height);
339 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
341 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
343 XFillRectangle (dpy, b, erase_gc, 0, 0, xgwa.width, xgwa.height);
345 for (i = 0; i < count; i++)
346 if (throb (dpy, b, throbbers[i]) < 0)
347 throbbers[i] = make_throbber (dpy, b, xgwa.width, xgwa.height,
348 colors[random() % ncolors].pixel);
350 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
353 XdbeSwapInfo info[1];
354 info[0].swap_window = window;
355 info[0].swap_action = (dbeclear_p ? XdbeBackground : XdbeUndefined);
356 XdbeSwapBuffers (dpy, info, 1);
359 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
362 XCopyArea (dpy, b, window, erase_gc, 0, 0,
363 xgwa.width, xgwa.height, 0, 0);
364 b = (b == ba ? bb : ba);
368 screenhack_handle_events (dpy);