f84f4919a6c3448734bea58c60348d5629bd430f
[xscreensaver] / hacks / xlockmore.c
1 /* xlockmore.c --- xscreensaver compatibility layer for xlockmore modules.
2  * xscreensaver, Copyright (c) 1997, 1998 Jamie Zawinski <jwz@netscape.com>
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation.  No representations are made about the suitability of this
9  * software for any purpose.  It is provided "as is" without express or 
10  * implied warranty.
11  *
12  * This file, along with xlockmore.h, make it possible to compile an xlockmore
13  * module into a standalone program, and thus use it with xscreensaver.
14  * By Jamie Zawinski <jwz@netscape.com> on 10-May-97; based on the ideas
15  * in the older xlock.h by Charles Hannum <mycroft@ai.mit.edu>.  (I had
16  * to redo it, since xlockmore has diverged so far from xlock...)
17  */
18
19 #include <stdio.h>
20 #include <math.h>
21 #include <string.h>
22 #include "screenhack.h"
23 #include "xlockmoreI.h"
24
25 #define countof(x) (sizeof((x))/sizeof(*(x)))
26
27 extern ModeSpecOpt xlockmore_opts[];
28 extern const char *app_defaults;
29
30 void
31 pre_merge_options (void)
32 {
33   int i, j;
34   char *s;
35
36   /* Translate the xlockmore `opts[]' argument to a form that
37      screenhack.c expects.
38    */
39   for (i = 0; i < xlockmore_opts->numopts; i++)
40     {
41       XrmOptionDescRec *old = &xlockmore_opts->opts[i];
42       XrmOptionDescRec *new = &options[i];
43
44       if (old->option[0] == '-')
45         new->option = old->option;
46       else
47         {
48           /* Convert "+foo" to "-no-foo". */
49           new->option = (char *) malloc (strlen(old->option) + 5);
50           strcpy (new->option, "-no-");
51           strcat (new->option, old->option + 1);
52         }
53
54       new->specifier = strrchr (old->specifier, '.');
55       if (!new->specifier) abort();
56
57       new->argKind = old->argKind;
58       new->value = old->value;
59     }
60
61   /* Add extra args, if they're mentioned in the defaults... */
62   {
63     char *args[] = { "-count", "-cycles", "-delay", "-ncolors",
64                      "-size", "-wireframe", "-use3d" };
65     for (j = 0; j < countof(args); j++)
66       if (strstr(app_defaults, args[j]+1))
67         {
68           XrmOptionDescRec *new = &options[i++];
69           new->option = args[j];
70           new->specifier = strdup(args[j]);
71           new->specifier[0] = '.';
72           if (!strcmp(new->option, "-wireframe"))
73             {
74               new->argKind = XrmoptionNoArg;
75               new->value = "True";
76               new = &options[i++];
77               new->option = "-no-wireframe";
78               new->specifier = options[i-2].specifier;
79               new->argKind = XrmoptionNoArg;
80               new->value = "False";
81             }
82           else if (!strcmp(new->option, "-use3d"))
83             {
84               new->option = "-3d";
85               new->argKind = XrmoptionNoArg;
86               new->value = "True";
87               new = &options[i++];
88               new->option = "-no-3d";
89               new->specifier = options[i-2].specifier;
90               new->argKind = XrmoptionNoArg;
91               new->value = "False";
92             }
93           else
94             {
95               new->argKind = XrmoptionSepArg;
96               new->value = 0;
97             }
98         }
99   }
100
101
102   /* Construct the kind of `defaults' that screenhack.c expects from
103      the xlockmore `vars[]' argument.
104    */
105   i = 0;
106
107   /* Put on the PROGCLASS.background/foreground resources. */
108   s = (char *) malloc(50);
109   strcpy (s, progclass);
110   strcat (s, ".background: black");
111   defaults [i++] = s;
112
113   s = (char *) malloc(50);
114   strcpy (s, progclass);
115   strcat (s, ".foreground: white");
116   defaults [i++] = s;
117
118   /* Copy the lines out of the `app_defaults' var and into this array. */
119   s = strdup (app_defaults);
120   while (s && *s)
121     {
122       defaults [i++] = s;
123       s = strchr(s, '\n');
124       if (s)
125         *s++ = 0;
126     }
127
128   /* Copy the defaults out of the `xlockmore_opts->' variable. */
129   for (j = 0; j < xlockmore_opts->numvarsdesc; j++)
130     {
131       const char *def = xlockmore_opts->vars[j].def;
132       if (!def) def = "False";
133       if (def == ((char*) 1)) def = "True";
134       s = (char *) malloc (strlen (xlockmore_opts->vars[j].name) +
135                            strlen (def) + 10);
136       strcpy (s, "*");
137       strcat (s, xlockmore_opts->vars[j].name);
138       strcat (s, ": ");
139       strcat (s, def);
140       defaults [i++] = s;
141     }
142
143   defaults [i] = 0;
144 }
145
146
147 static void
148 xlockmore_read_resources (void)
149 {
150   int i;
151   for (i = 0; i < xlockmore_opts->numvarsdesc; i++)
152     {
153       void  *var   = xlockmore_opts->vars[i].var;
154       Bool  *var_b = (Bool *)  var;
155       char **var_c = (char **) var;
156       int   *var_i = (int *) var;
157       float *var_f = (float *) var;
158
159       switch (xlockmore_opts->vars[i].type)
160         {
161         case t_String:
162           *var_c = get_string_resource (xlockmore_opts->vars[i].name,
163                                         xlockmore_opts->vars[i].classname);
164           break;
165         case t_Float:
166           *var_f = get_float_resource (xlockmore_opts->vars[i].name,
167                                        xlockmore_opts->vars[i].classname);
168           break;
169         case t_Int:
170           *var_i = get_integer_resource (xlockmore_opts->vars[i].name,
171                                          xlockmore_opts->vars[i].classname);
172           break;
173         case t_Bool:
174           *var_b = get_boolean_resource (xlockmore_opts->vars[i].name,
175                                          xlockmore_opts->vars[i].classname);
176           break;
177         default:
178           abort ();
179         }
180     }
181 }
182
183
184
185 void 
186 xlockmore_screenhack (Display *dpy, Window window,
187                       Bool want_writable_colors,
188                       Bool want_uniform_colors,
189                       Bool want_smooth_colors,
190                       Bool want_bright_colors,
191                       void (*hack_init) (ModeInfo *),
192                       void (*hack_draw) (ModeInfo *),
193                       void (*hack_free) (ModeInfo *))
194 {
195   ModeInfo mi;
196   XGCValues gcv;
197   XColor color;
198   int i;
199   time_t start, now;
200   int orig_pause;
201
202   memset(&mi, 0, sizeof(mi));
203   mi.dpy = dpy;
204   mi.window = window;
205   XGetWindowAttributes (dpy, window, &mi.xgwa);
206
207   color.flags = DoRed|DoGreen|DoBlue;
208   color.red = color.green = color.blue = 0;
209   if (!XAllocColor(dpy, mi.xgwa.colormap, &color))
210     abort();
211   mi.black = color.pixel;
212   color.red = color.green = color.blue = 0xFFFF;
213   if (!XAllocColor(dpy, mi.xgwa.colormap, &color))
214     abort();
215   mi.white = color.pixel;
216
217   if (mono_p)
218     {
219       static unsigned long pixels[2];
220       static XColor colors[2];
221     MONO:
222       mi.npixels = 2;
223       mi.pixels = pixels;
224       mi.colors = colors;
225       pixels[0] = mi.black;
226       pixels[1] = mi.white;
227       colors[0].flags = DoRed|DoGreen|DoBlue;
228       colors[1].flags = DoRed|DoGreen|DoBlue;
229       colors[0].red = colors[0].green = colors[0].blue = 0;
230       colors[1].red = colors[1].green = colors[1].blue = 0xFFFF;
231       mi.writable_p = False;
232     }
233   else
234     {
235       mi.npixels = get_integer_resource ("ncolors", "Integer");
236       if (mi.npixels <= 0)
237         mi.npixels = 64;
238       else if (mi.npixels > 256)
239         mi.npixels = 256;
240
241       mi.colors = (XColor *) calloc (mi.npixels, sizeof (*mi.colors));
242
243       mi.writable_p = want_writable_colors;
244
245       if (want_uniform_colors)
246         make_uniform_colormap (dpy, mi.xgwa.visual, mi.xgwa.colormap,
247                                mi.colors, &mi.npixels,
248                                True, &mi.writable_p, True);
249       else if (want_smooth_colors)
250         make_smooth_colormap (dpy, mi.xgwa.visual, mi.xgwa.colormap,
251                               mi.colors, &mi.npixels,
252                               True, &mi.writable_p, True);
253       else
254         make_random_colormap (dpy, mi.xgwa.visual, mi.xgwa.colormap,
255                               mi.colors, &mi.npixels,
256                               want_bright_colors,
257                               True, &mi.writable_p, True);
258
259       if (mi.npixels <= 2)
260         goto MONO;
261       else
262         {
263           int i;
264           mi.pixels = (unsigned long *)
265             calloc (mi.npixels, sizeof (*mi.pixels));
266           for (i = 0; i < mi.npixels; i++)
267             mi.pixels[i] = mi.colors[i].pixel;
268         }
269     }
270
271   gcv.foreground = mi.white;
272   gcv.background = mi.black;
273   mi.gc = XCreateGC(dpy, window, GCForeground|GCBackground, &gcv);
274
275   mi.fullrandom = True;
276
277   mi.pause      = get_integer_resource ("delay", "Usecs");
278
279   mi.cycles     = get_integer_resource ("cycles", "Int");
280   mi.batchcount = get_integer_resource ("count", "Int");
281   mi.size       = get_integer_resource ("size", "Int");
282
283 #if 0
284   decay = get_boolean_resource ("decay", "Boolean");
285   if (decay) mi.fullrandom = False;
286
287   trail = get_boolean_resource ("trail", "Boolean");
288   if (trail) mi.fullrandom = False;
289
290   grow = get_boolean_resource ("grow", "Boolean");
291   if (grow) mi.fullrandom = False;
292
293   liss = get_boolean_resource ("liss", "Boolean");
294   if (liss) mi.fullrandom = False;
295
296   ammann = get_boolean_resource ("ammann", "Boolean");
297   if (ammann) mi.fullrandom = False;
298
299   jong = get_boolean_resource ("jong", "Boolean");
300   if (jong) mi.fullrandom = False;
301
302   sine = get_boolean_resource ("sine", "Boolean");
303   if (sine) mi.fullrandom = False;
304 #endif
305
306   mi.threed = get_boolean_resource ("use3d", "Boolean");
307   mi.threed_delta = get_float_resource ("delta3d", "Boolean");
308   mi.threed_right_color = get_pixel_resource ("right3d", "Color", dpy,
309                                               mi.xgwa.colormap);
310   mi.threed_left_color = get_pixel_resource ("left3d", "Color", dpy,
311                                              mi.xgwa.colormap);
312   mi.threed_both_color = get_pixel_resource ("both3d", "Color", dpy,
313                                              mi.xgwa.colormap);
314   mi.threed_none_color = get_pixel_resource ("none3d", "Color", dpy,
315                                              mi.xgwa.colormap);
316
317   mi.wireframe_p = get_boolean_resource ("wireframe", "Boolean");
318   mi.root_p = (window == RootWindowOfScreen (mi.xgwa.screen));
319
320
321   if (mi.pause < 0)
322     mi.pause = 0;
323   else if (mi.pause > 100000000)
324     mi.pause = 100000000;
325   orig_pause = mi.pause;
326
327   xlockmore_read_resources ();
328
329   XClearWindow (dpy, window);
330
331   i = 0;
332   start = time((time_t) 0);
333
334   hack_init (&mi);
335   do {
336     hack_draw (&mi);
337     XSync(dpy, False);
338     if (mi.pause)
339       usleep(mi.pause);
340     mi.pause = orig_pause;
341
342     if (hack_free)
343       {
344         if (i++ > (mi.batchcount / 4) &&
345             (start + 5) < (now = time((time_t) 0)))
346           {
347             i = 0;
348             start = now;
349             hack_free (&mi);
350             hack_init (&mi);
351             XSync(dpy, False);
352           }
353       }
354
355   } while (1);
356 }