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