From http://www.jwz.org/xscreensaver/xscreensaver-5.35.tar.gz
[xscreensaver] / hacks / wander.c
1 /* wander, by Rick Campbell <rick@campbellcentral.org>, 19 December 1998.
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 <stdio.h>
13
14 #include "screenhack.h"
15 #include "colors.h"
16 #include "erase.h"
17
18 #define MAXIMUM_COLOR_COUNT (256)
19
20 struct state {
21   Display *dpy;
22   Window window;
23
24    unsigned int advance;
25    Bool         circles;
26    Colormap     color_map;
27    int          color_count;
28    int          color_index;
29    XColor       colors      [MAXIMUM_COLOR_COUNT];
30    GC           context;
31    unsigned int density;
32    int          depth;
33    int          height;
34    unsigned int length;
35    unsigned int reset;
36    Bool reset_p;
37    unsigned int size;
38    int          width;
39    int delay;
40
41   int x, y, last_x, last_y, width_1, height_1, length_limit, reset_limit;
42   unsigned long color;
43   Pixmap pixmap;
44
45   eraser_state *eraser;
46 };
47
48
49 static void *
50 wander_init (Display *dpy, Window window)
51 {
52     struct state *st = (struct state *) calloc (1, sizeof(*st));
53     XGCValues values;
54     XWindowAttributes attributes;
55
56     st->dpy = dpy;
57     st->window = window;
58     st->delay = get_integer_resource (st->dpy, "delay", "Integer");
59
60     XClearWindow (st->dpy, st->window);
61     XGetWindowAttributes (st->dpy, st->window, &attributes);
62     st->width = attributes.width;
63     st->height = attributes.height;
64     st->depth = attributes.depth;
65     st->color_map = attributes.colormap;
66     if (st->color_count)
67     {
68         free_colors (attributes.screen, st->color_map,
69                      st->colors, st->color_count);
70         st->color_count = 0;
71     }
72     st->context = XCreateGC (st->dpy, st->window, 0, &values);
73     st->color_count = MAXIMUM_COLOR_COUNT;
74     make_color_loop (attributes.screen, attributes.visual, st->color_map,
75                     0,   1, 1,
76                     120, 1, 1,
77                     240, 1, 1,
78                     st->colors, &st->color_count, True, False);
79     if (st->color_count <= 0)
80     {
81         st->color_count = 2;
82         st->colors [0].red = st->colors [0].green = st->colors [0].blue = 0;
83         st->colors [1].red = st->colors [1].green = st->colors [1].blue = 0xFFFF;
84         XAllocColor (st->dpy, st->color_map, &st->colors [0]);
85         XAllocColor (st->dpy, st->color_map, &st->colors [1]);
86     }
87     st->color_index = NRAND (st->color_count);
88     
89     st->advance = get_integer_resource (st->dpy, "advance", "Integer");
90     st->density = get_integer_resource (st->dpy, "density", "Integer");
91     if (st->density < 1) st->density = 1;
92     st->reset = get_integer_resource (st->dpy, "reset", "Integer");
93     if (st->reset < 100) st->reset = 100;
94     st->circles = get_boolean_resource (st->dpy, "circles", "Boolean");
95     st->size = get_integer_resource (st->dpy, "size", "Integer");
96     if (st->size < 1) st->size = 1;
97     st->width = st->width / st->size;
98     st->height = st->height / st->size;
99     st->length = get_integer_resource (st->dpy, "length", "Integer");
100     if (st->length < 1) st->length = 1;
101     XSetForeground (st->dpy, st->context, st->colors [st->color_index].pixel);
102
103
104     st->x = NRAND (st->width);
105     st->y = NRAND (st->height);
106     st->last_x = st->x;
107     st->last_y = st->y;
108     st->width_1 = st->width - 1;
109     st->height_1 = st->height - 1;
110     st->length_limit = st->length;
111     st->reset_limit = st->reset;
112     st->color_index = NRAND (st->color_count);
113     st->color = st->colors [NRAND (st->color_count)].pixel;
114     st->pixmap = XCreatePixmap (st->dpy, window, st->size,
115                             st->size, st->depth);
116
117     XSetForeground (st->dpy, st->context,
118                     BlackPixel (st->dpy, DefaultScreen (st->dpy)));
119     XFillRectangle (st->dpy, st->pixmap, st->context, 0, 0,
120                     st->width * st->size, st->height * st->size);
121     XSetForeground (st->dpy, st->context, st->color);
122     XFillArc (st->dpy, st->pixmap, st->context, 0, 0, st->size, st->size, 0, 360*64);
123
124     return st;
125 }
126
127
128 static unsigned long
129 wander_draw (Display *dpy, Window window, void *closure)
130 {
131   struct state *st = (struct state *) closure;
132   int i;
133
134   if (st->eraser) {
135     st->eraser = erase_window (st->dpy, st->window, st->eraser);
136     goto END;
137   }
138
139   for (i = 0; i < 2000; i++)
140     {
141       if (NRAND (st->density))
142         {
143           st->x = st->last_x;
144           st->y = st->last_y;
145         }
146       else
147         {
148           st->last_x = st->x;
149           st->last_y = st->y;
150           st->x += st->width_1  + NRAND (3);
151           while (st->x >= st->width)
152             st->x -= st->width;
153           st->y += st->height_1 + NRAND (3);
154           while (st->y >= st->height)
155             st->y -= st->height;
156         }
157
158       if (NRAND (st->length_limit) == 0)
159         {
160           if (st->advance == 0)
161             {
162               st->color_index = NRAND (st->color_count);
163             }
164           else
165             {
166               st->color_index = (st->color_index + st->advance) % st->color_count;
167             }
168           st->color = st->colors [st->color_index].pixel;
169           XSetForeground (st->dpy, st->context, st->color);
170           if (st->circles)
171             {
172               XFillArc (st->dpy, st->pixmap, st->context,
173                         0, 0, st->size, st->size, 0, 360 * 64);
174             }
175         }
176
177       if (st->reset_p || NRAND (st->reset_limit) == 0)
178         {
179           st->reset_p = 0;
180           st->eraser = erase_window (st->dpy, st->window, st->eraser);
181           st->color = st->colors [NRAND (st->color_count)].pixel;
182           st->x = NRAND (st->width);
183           st->y = NRAND (st->height);
184           st->last_x = st->x;
185           st->last_y = st->y;
186           if (st->circles)
187             {
188               XFillArc (st->dpy, st->pixmap, st->context, 0, 0, st->size, st->size, 0, 360*64);
189             }
190         }
191
192       if (st->size == 1)
193         {
194           XDrawPoint (st->dpy, st->window, st->context, st->x, st->y);
195         }
196       else
197         {
198           if (st->circles)
199             {
200               XCopyArea (st->dpy, st->pixmap, st->window, st->context, 0, 0, st->size, st->size,
201                          st->x * st->size, st->y * st->size);
202             }
203           else
204             {
205               XFillRectangle (st->dpy, st->window, st->context, st->x * st->size, st->y * st->size,
206                               st->size, st->size);
207             }
208         }
209     }
210
211  END:
212   return st->delay;
213 }
214
215
216 static void
217 wander_reshape (Display *dpy, Window window, void *closure, 
218                  unsigned int w, unsigned int h)
219 {
220   struct state *st = (struct state *) closure;
221   st->width  = w / st->size;
222   st->height = h / st->size;
223   st->width_1  = st->width - 1;
224   st->height_1 = st->height - 1;
225 }
226
227 static Bool
228 wander_event (Display *dpy, Window window, void *closure, XEvent *event)
229 {
230   struct state *st = (struct state *) closure;
231   if (screenhack_event_helper (dpy, window, event))
232     {
233       st->reset_p = 1;
234       return True;
235     }
236   return False;
237 }
238
239 static void
240 wander_free (Display *dpy, Window window, void *closure)
241 {
242   struct state *st = (struct state *) closure;
243   XFreeGC (st->dpy, st->context);
244   free (st);
245 }
246
247 static const char *wander_defaults [] =
248 {
249     ".background: black",
250     ".foreground: white",
251     ".fpsSolid:   true",
252     ".advance:    1",
253     ".density:    2",
254     ".length:     25000",
255     ".delay:      20000",
256     ".reset:      2500000",
257     ".circles:    False",
258     ".size:       1",
259 #ifdef HAVE_MOBILE
260   "*ignoreRotation: True",
261 #endif
262     0
263 };
264
265 static XrmOptionDescRec wander_options [] =
266 {
267     { "-advance", ".advance", XrmoptionSepArg, 0 },
268     { "-circles", ".circles",   XrmoptionNoArg, "True" },
269     { "-no-circles",".circles", XrmoptionNoArg, "False" },
270     { "-density", ".density", XrmoptionSepArg, 0 },
271     { "-length",  ".length",  XrmoptionSepArg, 0 },
272     { "-delay",   ".delay",   XrmoptionSepArg, 0 },
273     { "-reset",   ".reset",   XrmoptionSepArg, 0 },
274     { "-size",    ".size",    XrmoptionSepArg, 0 },
275     { 0, 0, 0, 0 }
276 };
277
278
279 XSCREENSAVER_MODULE ("Wander", wander)