http://apple.doit.wisc.edu/mirrors/amug/linux/linuxppc/sources/tarballs/xscreensaver...
[xscreensaver] / hacks / deluxe.c
1 /* xscreensaver, Copyright (c) 1999 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
15 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
16 # include "xdbe.h"
17 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
18
19 #define countof(x) (sizeof(x)/sizeof(*(x)))
20 #define ABS(x) ((x)<0?-(x):(x))
21
22 struct throbber {
23   int x, y;
24   int size;
25   int max_size;
26   int thickness;
27   int speed;
28   int fuse;
29   GC gc;
30   void (*draw) (Display *, Drawable, struct throbber *);
31 };
32
33 static void
34 draw_star (Display *dpy, Drawable w, struct throbber *t)
35 {
36   XPoint points[11];
37   int x = t->x;
38   int y = t->y;
39   int s = t->size / 0.383;  /* trial and error, I forget how to derive this */
40   int s2 = t->size;
41   double c = M_PI * 2;
42   double o = -M_PI / 2;
43
44   points[0].x = x + s  * cos(o + 0.0*c); points[0].y = y + s  * sin(o + 0.0*c);
45   points[1].x = x + s2 * cos(o + 0.1*c); points[1].y = y + s2 * sin(o + 0.1*c);
46   points[2].x = x + s  * cos(o + 0.2*c); points[2].y = y + s  * sin(o + 0.2*c);
47   points[3].x = x + s2 * cos(o + 0.3*c); points[3].y = y + s2 * sin(o + 0.3*c);
48   points[4].x = x + s  * cos(o + 0.4*c); points[4].y = y + s  * sin(o + 0.4*c);
49   points[5].x = x + s2 * cos(o + 0.5*c); points[5].y = y + s2 * sin(o + 0.5*c);
50   points[6].x = x + s  * cos(o + 0.6*c); points[6].y = y + s  * sin(o + 0.6*c);
51   points[7].x = x + s2 * cos(o + 0.7*c); points[7].y = y + s2 * sin(o + 0.7*c);
52   points[8].x = x + s  * cos(o + 0.8*c); points[8].y = y + s  * sin(o + 0.8*c);
53   points[9].x = x + s2 * cos(o + 0.9*c); points[9].y = y + s2 * sin(o + 0.9*c);
54   points[10] = points[0];
55
56   XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
57 }
58
59 static void
60 draw_circle (Display *dpy, Drawable w, struct throbber *t)
61 {
62   XDrawArc (dpy, w, t->gc,
63             t->x - t->size / 2,
64             t->y - t->size / 2,
65             t->size, t->size,
66             0, 360*64);
67 }
68
69 static void
70 draw_hlines (Display *dpy, Drawable w, struct throbber *t)
71 {
72   XDrawLine (dpy, w, t->gc, 0,
73              t->y - t->size, t->max_size,
74              t->y - t->size);
75   XDrawLine (dpy, w, t->gc, 0,
76              t->y + t->size, t->max_size,
77              t->y + t->size);
78 }
79
80 static void
81 draw_vlines (Display *dpy, Drawable w, struct throbber *t)
82 {
83   XDrawLine (dpy, w, t->gc,
84              t->x - t->size, 0,
85              t->x - t->size, t->max_size);
86   XDrawLine (dpy, w, t->gc,
87              t->x + t->size, 0,
88              t->x + t->size, t->max_size);
89 }
90
91 static void
92 draw_corners (Display *dpy, Drawable w, struct throbber *t)
93 {
94   int s = (t->size + t->thickness) / 2;
95   XPoint points[3];
96
97   points[0].x = 0;        points[0].y = t->y - s;
98   points[1].x = t->x - s; points[1].y = t->y - s;
99   points[2].x = t->x - s; points[2].y = 0;
100   XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
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 = t->max_size;
105   XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
106
107   points[0].x = t->x + s;    points[0].y = 0;
108   points[1].x = t->x + s;    points[1].y = t->y - s;
109   points[2].x = t->max_size; points[2].y = t->y - s;
110   XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
111
112   points[0].x = t->x + s;    points[0].y = t->max_size;
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
118
119 static struct throbber *
120 make_throbber (Display *dpy, Drawable d, int w, int h, unsigned long pixel)
121 {
122   XGCValues gcv;
123   struct throbber *t = (struct throbber *) malloc (sizeof (*t));
124   t->x = w / 2;
125   t->y = h / 2;
126   t->max_size = w;
127   t->speed = get_integer_resource ("speed", "Speed");
128   t->fuse = 1 + (random() % 4);
129   t->thickness = get_integer_resource ("thickness", "Thickness");
130
131   if (t->speed < 0) t->speed = -t->speed;
132   t->speed += (((random() % t->speed) / 2) - (t->speed / 2));
133   if (t->speed > 0) t->speed = -t->speed;
134
135   if (random() % 4)
136     t->size = t->max_size;
137   else
138     t->size = t->thickness, t->speed = -t->speed;
139
140   gcv.foreground = pixel;
141   gcv.line_width = t->thickness;
142   gcv.line_style = LineSolid;
143   gcv.cap_style = CapProjecting;
144   gcv.join_style = JoinMiter;
145   t->gc = XCreateGC (dpy, d,
146                      (GCForeground|GCLineWidth|GCLineStyle|
147                       GCCapStyle|GCJoinStyle),
148                      &gcv);
149
150   switch (random() % 11) {
151   case 0: case 1: case 2: case 3: t->draw = draw_star; break;
152   case 4: case 5: case 6: case 7: t->draw = draw_circle; break;
153   case 8: t->draw = draw_hlines; break;
154   case 9: t->draw = draw_vlines; break;
155   case 10: t->draw = draw_corners; break;
156   default: abort(); break;
157   }
158
159   return t;
160 }
161
162 static int
163 throb (Display *dpy, Drawable window, struct throbber *t)
164 {
165   t->size += t->speed;
166   if (t->size <= (t->thickness / 2))
167     {
168       t->speed = -t->speed;
169       t->size += (t->speed * 2);
170     }
171   else if (t->size > t->max_size)
172     {
173       t->speed = -t->speed;
174       t->size += (t->speed * 2);
175       t->fuse--;
176     }
177
178   if (t->fuse <= 0)
179     {
180       XFreeGC (dpy, t->gc);
181       memset (t, 0, sizeof(*t));
182       free (t);
183       return -1;
184     }
185   else
186     {
187       t->draw (dpy, window, t);
188       return 0;
189     }
190 }
191
192
193 \f
194 char *progclass = "Deluxe";
195
196 char *defaults [] = {
197   ".background:         black",
198   ".foreground:         white",
199   "*delay:              5000",
200   "*count:              5",
201   "*thickness:          50",
202   "*speed:              15",
203   "*ncolors:            20",
204   "*doubleBuffer:       True",
205 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
206   "*useDBE:             True",
207 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
208   0
209 };
210
211 XrmOptionDescRec options [] = {
212   { "-delay",           ".delay",       XrmoptionSepArg, 0 },
213   { "-thickness",       ".thickness",   XrmoptionSepArg, 0 },
214   { "-count",           ".count",       XrmoptionSepArg, 0 },
215   { "-ncolors",         ".ncolors",     XrmoptionSepArg, 0 },
216   { "-speed",           ".speed",       XrmoptionSepArg, 0 },
217   { "-db",              ".doubleBuffer", XrmoptionNoArg,  "True" },
218   { "-no-db",           ".doubleBuffer", XrmoptionNoArg,  "False" },
219   { 0, 0, 0, 0 }
220 };
221
222 void
223 screenhack (Display *dpy, Window window)
224 {
225   int count = get_integer_resource ("count", "Integer");
226   int delay = get_integer_resource ("delay", "Integer");
227   int ncolors = get_integer_resource ("ncolors", "Integer");
228   Bool dbuf = get_boolean_resource ("doubleBuffer", "Boolean");
229   XColor colors[255];
230   XGCValues gcv;
231   GC erase_gc = 0;
232   int i;
233   struct throbber **throbbers;
234   XWindowAttributes xgwa;
235   Pixmap b=0, ba=0, bb=0;       /* double-buffer to reduce flicker */
236 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
237   XdbeBackBuffer backb = 0;
238 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
239
240   XGetWindowAttributes (dpy, window, &xgwa);
241
242   if (get_boolean_resource("mono", "Boolean"))
243     {
244     MONO:
245       ncolors = 1;
246       colors[0].pixel = get_pixel_resource("foreground", "Foreground",
247                                            dpy, xgwa.colormap);
248     }
249   else
250     {
251       make_random_colormap (dpy, xgwa.visual, xgwa.colormap,
252                             colors, &ncolors, True, True, 0, True);
253       if (ncolors < 2)
254         goto MONO;
255     }
256
257   if (dbuf)
258     {
259 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
260       b = backb = xdbe_get_backbuffer (dpy, window, XdbeUndefined);
261 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
262
263       if (!b)
264         {
265           ba = XCreatePixmap (dpy, window, xgwa.width, xgwa.height,xgwa.depth);
266           bb = XCreatePixmap (dpy, window, xgwa.width, xgwa.height,xgwa.depth);
267           b = ba;
268         }
269     }
270   else
271     {
272       b = window;
273     }
274
275   throbbers = (struct throbber **) calloc (count, sizeof(struct throbber *));
276   for (i = 0; i < count; i++)
277     throbbers[i] = make_throbber (dpy, b, xgwa.width, xgwa.height,
278                                   colors[random() % ncolors].pixel);
279
280   gcv.foreground = get_pixel_resource ("background", "Background",
281                                        dpy, xgwa.colormap);
282   erase_gc = XCreateGC (dpy, b, GCForeground, &gcv);
283
284   if (ba) XFillRectangle (dpy, ba, erase_gc, 0, 0, xgwa.width, xgwa.height);
285   if (bb) XFillRectangle (dpy, bb, erase_gc, 0, 0, xgwa.width, xgwa.height);
286
287   while (1)
288     {
289       XFillRectangle (dpy, b, erase_gc, 0, 0, xgwa.width, xgwa.height);
290
291       for (i = 0; i < count; i++)
292         if (throb (dpy, b, throbbers[i]) < 0)
293           throbbers[i] = make_throbber (dpy, b, xgwa.width, xgwa.height,
294                                         colors[random() % ncolors].pixel);
295
296 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
297       if (backb)
298         {
299           XdbeSwapInfo info[1];
300           info[0].swap_window = window;
301           info[0].swap_action = XdbeUndefined;
302           XdbeSwapBuffers (dpy, info, 1);
303         }
304       else
305 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
306       if (dbuf)
307         {
308           XCopyArea (dpy, b, window, erase_gc, 0, 0,
309                      xgwa.width, xgwa.height, 0, 0);
310           b = (b == ba ? bb : ba);
311         }
312
313       XSync (dpy, False);
314       screenhack_handle_events (dpy);
315       if (delay)
316         usleep (delay);
317     }
318 }