1 /* xlockmore.c --- xscreensaver compatibility layer for xlockmore modules.
2 * xscreensaver, Copyright (c) 1997, 1998, 2001, 2002, 2004
3 * Jamie Zawinski <jwz@jwz.org>
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation. No representations are made about the suitability of this
10 * software for any purpose. It is provided "as is" without express or
13 * This file, along with xlockmore.h, make it possible to compile an xlockmore
14 * module into a standalone program, and thus use it with xscreensaver.
15 * By Jamie Zawinski <jwz@jwz.org> on 10-May-97; based on the ideas
16 * in the older xlock.h by Charles Hannum <mycroft@ai.mit.edu>. (I had
17 * to redo it, since xlockmore has diverged so far from xlock...)
25 #include "screenhack.h"
26 #include "xlockmoreI.h"
27 #include <X11/Intrinsic.h>
29 #define countof(x) (sizeof((x))/sizeof(*(x)))
31 #define MAX_COLORS (1L<<13)
33 extern XtAppContext app;
34 extern ModeSpecOpt xlockmore_opts[];
35 extern const char *app_defaults;
38 pre_merge_options (void)
43 /* Translate the xlockmore `opts[]' argument to a form that
46 for (i = 0; i < xlockmore_opts->numopts; i++)
48 XrmOptionDescRec *old = &xlockmore_opts->opts[i];
49 XrmOptionDescRec *new = &options[i];
51 if (old->option[0] == '-')
52 new->option = old->option;
55 /* Convert "+foo" to "-no-foo". */
56 new->option = (char *) malloc (strlen(old->option) + 5);
57 strcpy (new->option, "-no-");
58 strcat (new->option, old->option + 1);
61 new->specifier = strrchr (old->specifier, '.');
62 if (!new->specifier) abort();
64 new->argKind = old->argKind;
65 new->value = old->value;
68 /* Add extra args, if they're mentioned in the defaults... */
70 char *args[] = { "-count", "-cycles", "-delay", "-ncolors",
71 "-size", "-font", "-wireframe", "-use3d", "-useSHM",
73 for (j = 0; j < countof(args); j++)
74 if (strstr(app_defaults, args[j]+1))
76 XrmOptionDescRec *new = &options[i++];
77 new->option = args[j];
78 new->specifier = strdup(args[j]);
79 new->specifier[0] = '.';
80 if (!strcmp(new->option, "-wireframe"))
82 new->argKind = XrmoptionNoArg;
85 new->option = "-no-wireframe";
86 new->specifier = options[i-2].specifier;
87 new->argKind = XrmoptionNoArg;
90 else if (!strcmp(new->option, "-use3d"))
93 new->argKind = XrmoptionNoArg;
96 new->option = "-no-3d";
97 new->specifier = options[i-2].specifier;
98 new->argKind = XrmoptionNoArg;
101 else if (!strcmp(new->option, "-useSHM"))
103 new->option = "-shm";
104 new->argKind = XrmoptionNoArg;
107 new->option = "-no-shm";
108 new->specifier = options[i-2].specifier;
109 new->argKind = XrmoptionNoArg;
110 new->value = "False";
112 else if (!strcmp(new->option, "-showFPS"))
114 new->option = "-fps";
115 new->argKind = XrmoptionNoArg;
118 new->option = "-no-fps";
119 new->specifier = options[i-2].specifier;
120 new->argKind = XrmoptionNoArg;
121 new->value = "False";
125 new->argKind = XrmoptionSepArg;
132 /* Construct the kind of `defaults' that screenhack.c expects from
133 the xlockmore `vars[]' argument.
137 /* Put on the PROGCLASS.background/foreground resources. */
138 s = (char *) malloc(50);
139 strcpy (s, progclass);
140 strcat (s, ".background: black");
143 s = (char *) malloc(50);
144 strcpy (s, progclass);
145 strcat (s, ".foreground: white");
148 /* Copy the lines out of the `app_defaults' var and into this array. */
149 s = strdup (app_defaults);
158 /* Copy the defaults out of the `xlockmore_opts->' variable. */
159 for (j = 0; j < xlockmore_opts->numvarsdesc; j++)
161 const char *def = xlockmore_opts->vars[j].def;
165 if (strlen(def) > 1000) abort();
167 s = (char *) malloc (strlen (xlockmore_opts->vars[j].name) +
170 strcat (s, xlockmore_opts->vars[j].name);
175 /* Go through the list of resources and print a warning if there
179 char *onew = strdup (xlockmore_opts->vars[j].name);
180 const char *new = onew;
183 if ((s = strrchr (new, '.'))) new = s+1;
184 if ((s = strrchr (new, '*'))) new = s+1;
185 for (k = 0; k < i-1; k++)
187 char *oold = strdup (defaults[k]);
188 const char *old = oold;
189 if ((s = strchr (oold, ':'))) *s = 0;
190 if ((s = strrchr (old, '.'))) old = s+1;
191 if ((s = strrchr (old, '*'))) old = s+1;
192 if (!strcasecmp (old, new))
195 "%s: duplicate resource \"%s\": "
196 "set in both DEFAULTS and vars[]\n",
210 xlockmore_read_resources (void)
213 for (i = 0; i < xlockmore_opts->numvarsdesc; i++)
215 void *var = xlockmore_opts->vars[i].var;
216 Bool *var_b = (Bool *) var;
217 char **var_c = (char **) var;
218 int *var_i = (int *) var;
219 float *var_f = (float *) var;
221 switch (xlockmore_opts->vars[i].type)
224 *var_c = get_string_resource (xlockmore_opts->vars[i].name,
225 xlockmore_opts->vars[i].classname);
228 *var_f = get_float_resource (xlockmore_opts->vars[i].name,
229 xlockmore_opts->vars[i].classname);
232 *var_i = get_integer_resource (xlockmore_opts->vars[i].name,
233 xlockmore_opts->vars[i].classname);
236 *var_b = get_boolean_resource (xlockmore_opts->vars[i].name,
237 xlockmore_opts->vars[i].classname);
247 xlockmore_handle_events (ModeInfo *mi,
248 void (*reshape) (ModeInfo *, int, int),
249 Bool (*hook) (ModeInfo *, XEvent *))
251 if (XtAppPending (app) & (XtIMTimer|XtIMAlternateInput))
252 XtAppProcessEvent (app, XtIMTimer|XtIMAlternateInput);
254 while (XPending (mi->dpy))
257 XNextEvent (mi->dpy, &event);
258 if (reshape && event.xany.type == ConfigureNotify)
260 XGetWindowAttributes (mi->dpy, mi->window, &mi->xgwa);
261 reshape (mi, mi->xgwa.width, mi->xgwa.height);
263 else if (hook && hook (mi, &event))
268 screenhack_handle_event (mi->dpy, &event);
275 xlockmore_screenhack (Display *dpy, Window window,
276 Bool want_writable_colors,
277 Bool want_uniform_colors,
278 Bool want_smooth_colors,
279 Bool want_bright_colors,
280 unsigned long event_mask,
281 void (*hack_init) (ModeInfo *),
282 void (*hack_draw) (ModeInfo *),
283 void (*hack_reshape) (ModeInfo *, int, int),
284 Bool (*hack_handle_events) (ModeInfo *, XEvent *),
285 void (*hack_free) (ModeInfo *))
295 memset(&mi, 0, sizeof(mi));
298 XGetWindowAttributes (dpy, window, &mi.xgwa);
299 root_p = (window == RootWindowOfScreen (mi.xgwa.screen));
301 /* If this is the root window, don't allow ButtonPress to be selected.
302 Bad Things Happen. */
304 event_mask &= (~(ButtonPressMask|ButtonReleaseMask));
306 /* If this hack wants additional events, select them. */
307 if (event_mask && ! (mi.xgwa.your_event_mask & event_mask))
308 XSelectInput (dpy, window, (mi.xgwa.your_event_mask | event_mask));
310 color.flags = DoRed|DoGreen|DoBlue;
311 color.red = color.green = color.blue = 0;
312 if (!XAllocColor(dpy, mi.xgwa.colormap, &color))
314 mi.black = color.pixel;
315 color.red = color.green = color.blue = 0xFFFF;
316 if (!XAllocColor(dpy, mi.xgwa.colormap, &color))
318 mi.white = color.pixel;
322 static unsigned long pixels[2];
323 static XColor colors[2];
328 pixels[0] = mi.black;
329 pixels[1] = mi.white;
330 colors[0].flags = DoRed|DoGreen|DoBlue;
331 colors[1].flags = DoRed|DoGreen|DoBlue;
332 colors[0].red = colors[0].green = colors[0].blue = 0;
333 colors[1].red = colors[1].green = colors[1].blue = 0xFFFF;
334 mi.writable_p = False;
338 mi.npixels = get_integer_resource ("ncolors", "Integer");
341 else if (mi.npixels > MAX_COLORS)
342 mi.npixels = MAX_COLORS;
344 mi.colors = (XColor *) calloc (mi.npixels, sizeof (*mi.colors));
346 mi.writable_p = want_writable_colors;
348 if (want_uniform_colors)
349 make_uniform_colormap (dpy, mi.xgwa.visual, mi.xgwa.colormap,
350 mi.colors, &mi.npixels,
351 True, &mi.writable_p, True);
352 else if (want_smooth_colors)
353 make_smooth_colormap (dpy, mi.xgwa.visual, mi.xgwa.colormap,
354 mi.colors, &mi.npixels,
355 True, &mi.writable_p, True);
357 make_random_colormap (dpy, mi.xgwa.visual, mi.xgwa.colormap,
358 mi.colors, &mi.npixels,
360 True, &mi.writable_p, True);
366 mi.pixels = (unsigned long *)
367 calloc (mi.npixels, sizeof (*mi.pixels));
368 for (i = 0; i < mi.npixels; i++)
369 mi.pixels[i] = mi.colors[i].pixel;
373 gcv.foreground = mi.white;
374 gcv.background = mi.black;
375 mi.gc = XCreateGC(dpy, window, GCForeground|GCBackground, &gcv);
377 mi.fullrandom = True;
379 mi.pause = get_integer_resource ("delay", "Usecs");
381 mi.cycles = get_integer_resource ("cycles", "Int");
382 mi.batchcount = get_integer_resource ("count", "Int");
383 mi.size = get_integer_resource ("size", "Int");
385 mi.threed = get_boolean_resource ("use3d", "Boolean");
386 mi.threed_delta = get_float_resource ("delta3d", "Boolean");
387 mi.threed_right_color = get_pixel_resource ("right3d", "Color", dpy,
389 mi.threed_left_color = get_pixel_resource ("left3d", "Color", dpy,
391 mi.threed_both_color = get_pixel_resource ("both3d", "Color", dpy,
393 mi.threed_none_color = get_pixel_resource ("none3d", "Color", dpy,
396 mi.wireframe_p = get_boolean_resource ("wireframe", "Boolean");
398 mi.fps_p = get_boolean_resource ("showFPS", "Boolean");
399 #ifdef HAVE_XSHM_EXTENSION
400 mi.use_shm = get_boolean_resource ("useSHM", "Boolean");
401 #endif /* !HAVE_XSHM_EXTENSION */
405 else if (mi.pause > 100000000)
406 mi.pause = 100000000;
407 orig_pause = mi.pause;
409 /* If this hack uses fonts (meaning, mentioned "font" in DEFAULTS)
412 char *name = get_string_resource ("font", "Font");
415 XFontStruct *f = XLoadQueryFont (dpy, name);
416 const char *def1 = "-*-times-bold-r-normal-*-180-*";
417 const char *def2 = "fixed";
420 fprintf (stderr, "%s: font %s does not exist, using %s\n",
421 progname, name, def1);
422 f = XLoadQueryFont (dpy, def1);
426 fprintf (stderr, "%s: font %s does not exist, using %s\n",
427 progname, def1, def2);
428 f = XLoadQueryFont (dpy, def2);
430 if (f) XSetFont (dpy, mi.gc, f->fid);
431 if (f) XFreeFont (dpy, f);
435 xlockmore_read_resources ();
437 XClearWindow (dpy, window);
440 start = time((time_t) 0);
446 xlockmore_handle_events (&mi, hack_reshape, hack_handle_events);
449 mi.pause = orig_pause;
453 if (i++ > (mi.batchcount / 4) &&
454 (start + 5) < (now = time((time_t) 0)))