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