http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.14.tar.gz
[xscreensaver] / hacks / deluxe.c
1 /* xscreensaver, Copyright (c) 1999, 2001, 2002 Jamie Zawinski <jwz@jwz.org>
2  *
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 
9  * implied warranty.
10  */
11
12 #include <math.h>
13 #include "screenhack.h"
14 #include "alpha.h"
15
16 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
17 # include "xdbe.h"
18 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
19
20 #define countof(x) (sizeof(x)/sizeof(*(x)))
21 #define ABS(x) ((x)<0?-(x):(x))
22
23 static Bool transparent_p;
24 static int nplanes;
25 static unsigned long base_pixel, *plane_masks;
26
27 struct throbber {
28   int x, y;
29   int size;
30   int max_size;
31   int thickness;
32   int speed;
33   int fuse;
34   GC gc;
35   void (*draw) (Display *, Drawable, struct throbber *);
36 };
37
38 static void
39 draw_star (Display *dpy, Drawable w, struct throbber *t)
40 {
41   XPoint points[11];
42   int x = t->x;
43   int y = t->y;
44   int s = t->size / 0.383;  /* trial and error, I forget how to derive this */
45   int s2 = t->size;
46   double c = M_PI * 2;
47   double o = -M_PI / 2;
48
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];
60
61   XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
62 }
63
64 static void
65 draw_circle (Display *dpy, Drawable w, struct throbber *t)
66 {
67   XDrawArc (dpy, w, t->gc,
68             t->x - t->size / 2,
69             t->y - t->size / 2,
70             t->size, t->size,
71             0, 360*64);
72 }
73
74 static void
75 draw_hlines (Display *dpy, Drawable w, struct throbber *t)
76 {
77   XDrawLine (dpy, w, t->gc, 0,
78              t->y - t->size, t->max_size,
79              t->y - t->size);
80   XDrawLine (dpy, w, t->gc, 0,
81              t->y + t->size, t->max_size,
82              t->y + t->size);
83 }
84
85 static void
86 draw_vlines (Display *dpy, Drawable w, struct throbber *t)
87 {
88   XDrawLine (dpy, w, t->gc,
89              t->x - t->size, 0,
90              t->x - t->size, t->max_size);
91   XDrawLine (dpy, w, t->gc,
92              t->x + t->size, 0,
93              t->x + t->size, t->max_size);
94 }
95
96 static void
97 draw_corners (Display *dpy, Drawable w, struct throbber *t)
98 {
99   int s = (t->size + t->thickness) / 2;
100   XPoint points[3];
101
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);
106
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);
111
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);
116
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);
121 }
122
123
124 static struct throbber *
125 make_throbber (Display *dpy, Drawable d, int w, int h, unsigned long pixel)
126 {
127   XGCValues gcv;
128   unsigned long flags;
129   struct throbber *t = (struct throbber *) malloc (sizeof (*t));
130   t->x = w / 2;
131   t->y = h / 2;
132   t->max_size = w;
133   t->speed = get_integer_resource ("speed", "Speed");
134   t->fuse = 1 + (random() % 4);
135   t->thickness = get_integer_resource ("thickness", "Thickness");
136
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;
140
141   if (random() % 4)
142     t->size = t->max_size;
143   else
144     t->size = t->thickness, t->speed = -t->speed;
145
146   flags = GCForeground;
147   if (transparent_p)
148     {
149       gcv.foreground = ~0L;
150       gcv.plane_mask = base_pixel | plane_masks[random() % nplanes];
151       flags |= GCPlaneMask;
152     }
153   else
154     {
155       gcv.foreground = pixel;
156     }
157
158   gcv.line_width = t->thickness;
159   gcv.line_style = LineSolid;
160   gcv.cap_style = CapProjecting;
161   gcv.join_style = JoinMiter;
162
163   flags |= (GCLineWidth | GCLineStyle | GCCapStyle | GCJoinStyle);
164   t->gc = XCreateGC (dpy, d, flags, &gcv);
165
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;
173   }
174
175   return t;
176 }
177
178 static int
179 throb (Display *dpy, Drawable window, struct throbber *t)
180 {
181   t->size += t->speed;
182   if (t->size <= (t->thickness / 2))
183     {
184       t->speed = -t->speed;
185       t->size += (t->speed * 2);
186     }
187   else if (t->size > t->max_size)
188     {
189       t->speed = -t->speed;
190       t->size += (t->speed * 2);
191       t->fuse--;
192     }
193
194   if (t->fuse <= 0)
195     {
196       XFreeGC (dpy, t->gc);
197       memset (t, 0, sizeof(*t));
198       free (t);
199       return -1;
200     }
201   else
202     {
203       t->draw (dpy, window, t);
204       return 0;
205     }
206 }
207
208
209 \f
210 char *progclass = "Deluxe";
211
212 char *defaults [] = {
213   ".background:         black",
214   ".foreground:         white",
215   "*delay:              5000",
216   "*count:              5",
217   "*thickness:          50",
218   "*speed:              15",
219   "*ncolors:            20",
220   "*nlayers:            0",
221   "*transparent:        False",
222   "*doubleBuffer:       True",
223 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
224   "*useDBE:             True",
225   "*useDBEClear:        True",
226 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
227   0
228 };
229
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" },
240   { 0, 0, 0, 0 }
241 };
242
243 void
244 screenhack (Display *dpy, Window window)
245 {
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");
251   XColor *colors = 0;
252   XGCValues gcv;
253   GC erase_gc = 0;
254   int i;
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 */
261
262   XGetWindowAttributes (dpy, window, &xgwa);
263
264   transparent_p = get_boolean_resource("transparent", "Transparent");
265
266   colors = (XColor *) calloc (sizeof(*colors), ncolors);
267
268   if (get_boolean_resource("mono", "Boolean"))
269     {
270     MONO:
271       ncolors = 1;
272       colors[0].pixel = get_pixel_resource("foreground", "Foreground",
273                                            dpy, xgwa.colormap);
274     }
275   else if (transparent_p)
276     {
277       nplanes = get_integer_resource ("planes", "Planes");
278       if (nplanes <= 0)
279         nplanes = (random() % (xgwa.depth-2)) + 2;
280
281       allocate_alpha_colors (xgwa.screen, xgwa.visual, xgwa.colormap,
282                              &nplanes, True, &plane_masks,
283                              &base_pixel);
284       if (nplanes <= 1)
285         {
286           fprintf (stderr,
287          "%s: couldn't allocate any color planes; turning transparency off.\n",
288                    progname);
289           transparent_p = False;
290           goto COLOR;
291         }
292     }
293   else
294     {
295     COLOR:
296       make_random_colormap (dpy, xgwa.visual, xgwa.colormap,
297                             colors, &ncolors, True, True, 0, True);
298       if (ncolors < 2)
299         goto MONO;
300     }
301
302   if (dbuf)
303     {
304 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
305       if (dbeclear_p)
306         b = xdbe_get_backbuffer (dpy, window, XdbeBackground);
307       else
308         b = xdbe_get_backbuffer (dpy, window, XdbeUndefined);
309       backb = b;
310 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
311
312       if (!b)
313         {
314           ba = XCreatePixmap (dpy, window, xgwa.width, xgwa.height,xgwa.depth);
315           bb = XCreatePixmap (dpy, window, xgwa.width, xgwa.height,xgwa.depth);
316           b = ba;
317         }
318     }
319   else
320     {
321       b = window;
322     }
323
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);
328
329   gcv.foreground = get_pixel_resource ("background", "Background",
330                                        dpy, xgwa.colormap);
331   erase_gc = XCreateGC (dpy, b, GCForeground, &gcv);
332
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);
335
336   while (1)
337     {
338       if (!dbeclear_p
339 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
340           || !backb
341 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
342           )
343         XFillRectangle (dpy, b, erase_gc, 0, 0, xgwa.width, xgwa.height);
344
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);
349
350 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
351       if (backb)
352         {
353           XdbeSwapInfo info[1];
354           info[0].swap_window = window;
355           info[0].swap_action = (dbeclear_p ? XdbeBackground : XdbeUndefined);
356           XdbeSwapBuffers (dpy, info, 1);
357         }
358       else
359 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
360       if (dbuf)
361         {
362           XCopyArea (dpy, b, window, erase_gc, 0, 0,
363                      xgwa.width, xgwa.height, 0, 0);
364           b = (b == ba ? bb : ba);
365         }
366
367       XSync (dpy, False);
368       screenhack_handle_events (dpy);
369       if (delay)
370         usleep (delay);
371     }
372 }