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