1 /* xlockmore.c --- xscreensaver compatibility layer for xlockmore modules.
2 * xscreensaver, Copyright (c) 1997-2011 Jamie Zawinski <jwz@jwz.org>
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
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...)
19 #include "xlockmoreI.h"
20 #include "screenhack.h"
23 # include <X11/Intrinsic.h>
24 #endif /* !HAVE_COCOA */
26 #define countof(x) (sizeof((x))/sizeof(*(x)))
28 #define MAX_COLORS (1L<<13)
30 extern struct xscreensaver_function_table *xscreensaver_function_table;
32 extern const char *progclass;
34 extern struct xlockmore_function_table xlockmore_function_table;
36 static void *xlockmore_init (Display *, Window,
37 struct xlockmore_function_table *);
38 static unsigned long xlockmore_draw (Display *, Window, void *);
39 static void xlockmore_reshape (Display *, Window, void *,
40 unsigned int w, unsigned int h);
41 static Bool xlockmore_event (Display *, Window, void *, XEvent *);
42 static void xlockmore_free (Display *, Window, void *);
46 xlockmore_setup (struct xscreensaver_function_table *xsft, void *arg)
48 struct xlockmore_function_table *xlmft =
49 (struct xlockmore_function_table *) arg;
52 XrmOptionDescRec *new_options;
54 const char *xlockmore_defaults;
55 ModeSpecOpt *xlockmore_opts = xlmft->opts;
60 xsft->init_cb = (void *(*) (Display *, Window)) xlockmore_init;
61 xsft->draw_cb = xlockmore_draw;
62 xsft->reshape_cb = xlockmore_reshape;
63 xsft->event_cb = xlockmore_event;
64 xsft->free_cb = xlockmore_free;
66 progclass = xlmft->progclass;
67 xlockmore_defaults = xlmft->defaults;
69 /* Translate the xlockmore `opts[]' argument to a form that
72 new_options = (XrmOptionDescRec *)
73 calloc (xlockmore_opts->numopts*3 + 100, sizeof (*new_options));
75 for (i = 0; i < xlockmore_opts->numopts; i++)
77 XrmOptionDescRec *old = &xlockmore_opts->opts[i];
78 XrmOptionDescRec *new = &new_options[i];
80 if (old->option[0] == '-')
81 new->option = old->option;
84 /* Convert "+foo" to "-no-foo". */
85 new->option = (char *) malloc (strlen(old->option) + 5);
86 strcpy (new->option, "-no-");
87 strcat (new->option, old->option + 1);
90 new->specifier = strrchr (old->specifier, '.');
91 if (!new->specifier) abort();
93 new->argKind = old->argKind;
94 new->value = old->value;
97 /* Add extra args, if they're mentioned in the defaults... */
99 char *args[] = { "-count", "-cycles", "-delay", "-ncolors",
100 "-size", "-font", "-wireframe", "-use3d", "-useSHM" };
101 for (j = 0; j < countof(args); j++)
102 if (strstr(xlockmore_defaults, args[j]+1))
104 XrmOptionDescRec *new = &new_options[i++];
105 new->option = args[j];
106 new->specifier = strdup(args[j]);
107 new->specifier[0] = '.';
108 if (!strcmp(new->option, "-wireframe"))
110 new->argKind = XrmoptionNoArg;
112 new = &new_options[i++];
113 new->option = "-no-wireframe";
114 new->specifier = new_options[i-2].specifier;
115 new->argKind = XrmoptionNoArg;
116 new->value = "False";
118 else if (!strcmp(new->option, "-use3d"))
121 new->argKind = XrmoptionNoArg;
123 new = &new_options[i++];
124 new->option = "-no-3d";
125 new->specifier = new_options[i-2].specifier;
126 new->argKind = XrmoptionNoArg;
127 new->value = "False";
129 else if (!strcmp(new->option, "-useSHM"))
131 new->option = "-shm";
132 new->argKind = XrmoptionNoArg;
134 new = &new_options[i++];
135 new->option = "-no-shm";
136 new->specifier = new_options[i-2].specifier;
137 new->argKind = XrmoptionNoArg;
138 new->value = "False";
142 new->argKind = XrmoptionSepArg;
150 /* Construct the kind of `defaults' that screenhack.c expects from
151 the xlockmore `vars[]' argument.
155 new_defaults = (char **) calloc (1, xlockmore_opts->numvarsdesc * 10 + 1000);
157 /* Put on the PROGCLASS.background/foreground resources. */
158 s = (char *) malloc(50);
161 strcpy (s, progclass);
163 strcat (s, ".background: black");
164 new_defaults [i++] = s;
166 s = (char *) malloc(50);
169 strcpy (s, progclass);
171 strcat (s, ".foreground: white");
172 new_defaults [i++] = s;
174 /* Copy the lines out of the `xlockmore_defaults' var and into this array. */
175 s = strdup (xlockmore_defaults);
178 new_defaults [i++] = s;
184 /* Copy the defaults out of the `xlockmore_opts->' variable. */
185 for (j = 0; j < xlockmore_opts->numvarsdesc; j++)
187 const char *def = xlockmore_opts->vars[j].def;
191 if (strlen(def) > 1000) abort();
193 s = (char *) malloc (strlen (xlockmore_opts->vars[j].name) +
196 strcat (s, xlockmore_opts->vars[j].name);
199 new_defaults [i++] = s;
201 /* Go through the list of resources and print a warning if there
205 char *onew = strdup (xlockmore_opts->vars[j].name);
206 const char *new = onew;
208 if ((s = strrchr (new, '.'))) new = s+1;
209 if ((s = strrchr (new, '*'))) new = s+1;
210 for (k = 0; k < i-1; k++)
212 char *oold = strdup (new_defaults[k]);
213 const char *old = oold;
214 if ((s = strchr (oold, ':'))) *s = 0;
215 if ((s = strrchr (old, '.'))) old = s+1;
216 if ((s = strrchr (old, '*'))) old = s+1;
217 if (!strcasecmp (old, new))
220 "%s: duplicate resource \"%s\": "
221 "set in both DEFAULTS and vars[]\n",
230 new_defaults [i] = 0;
232 xsft->progclass = progclass;
233 xsft->options = new_options;
234 xsft->defaults = (const char * const *) new_defaults;
239 xlockmore_read_resources (ModeInfo *mi)
241 Display *dpy = mi->dpy;
242 ModeSpecOpt *xlockmore_opts = mi->xlmft->opts;
244 for (i = 0; i < xlockmore_opts->numvarsdesc; i++)
246 void *var = xlockmore_opts->vars[i].var;
247 Bool *var_b = (Bool *) var;
248 char **var_c = (char **) var;
249 int *var_i = (int *) var;
250 float *var_f = (float *) var;
252 switch (xlockmore_opts->vars[i].type)
255 *var_c = get_string_resource (dpy, xlockmore_opts->vars[i].name,
256 xlockmore_opts->vars[i].classname);
259 *var_f = get_float_resource (dpy, xlockmore_opts->vars[i].name,
260 xlockmore_opts->vars[i].classname);
263 *var_i = get_integer_resource (dpy, xlockmore_opts->vars[i].name,
264 xlockmore_opts->vars[i].classname);
267 *var_b = get_boolean_resource (dpy, xlockmore_opts->vars[i].name,
268 xlockmore_opts->vars[i].classname);
278 xlockmore_init (Display *dpy, Window window,
279 struct xlockmore_function_table *xlmft)
281 ModeInfo *mi = (ModeInfo *) calloc (1, sizeof(*mi));
293 XGetWindowAttributes (dpy, window, &mi->xgwa);
297 /* In Cocoa-based xscreensaver, all hacks run in the same address space,
298 so each one needs to get its own screen number. We just use a global
299 counter for that, instead of actually trying to figure out which
300 monitor each window is on. Also, the embedded "preview" view counts
303 Note that the screen number will increase each time the saver is
304 restarted (e.g., each time preferences are changed!) So we just
305 keep pushing the num_screens number up as needed, and assume that
306 no more than 10 simultanious copies will be running at once...
309 static int screen_tick = 0;
310 mi->num_screens = 10;
311 mi->screen_number = screen_tick++;
312 if (screen_tick >= mi->num_screens)
313 mi->num_screens += 10;
317 #else /* !HAVE_COCOA -- real Xlib */
319 /* In Xlib-based xscreensaver, each hack runs in its own address space,
320 so each one only needs to be aware of one screen.
323 mi->screen_number = 0;
325 { /* kludge for DEBUG_PAIR */
326 static int screen_tick = 0;
333 root_p = (window == RootWindowOfScreen (mi->xgwa.screen));
335 /* Everybody gets motion events, just in case. */
336 XSelectInput (dpy, window, (mi->xgwa.your_event_mask | PointerMotionMask));
338 #endif /* !HAVE_COCOA */
340 color.flags = DoRed|DoGreen|DoBlue;
341 color.red = color.green = color.blue = 0;
342 if (!XAllocColor(dpy, mi->xgwa.colormap, &color))
344 mi->black = color.pixel;
345 color.red = color.green = color.blue = 0xFFFF;
346 if (!XAllocColor(dpy, mi->xgwa.colormap, &color))
348 mi->white = color.pixel;
352 static unsigned long pixels[2];
353 static XColor colors[2];
357 mi->pixels = (unsigned long *)
358 calloc (mi->npixels, sizeof (*mi->pixels));
360 mi->colors = (XColor *)
361 calloc (mi->npixels, sizeof (*mi->colors));
362 pixels[0] = mi->black;
363 pixels[1] = mi->white;
364 colors[0].flags = DoRed|DoGreen|DoBlue;
365 colors[1].flags = DoRed|DoGreen|DoBlue;
366 colors[0].red = colors[0].green = colors[0].blue = 0;
367 colors[1].red = colors[1].green = colors[1].blue = 0xFFFF;
368 mi->writable_p = False;
372 mi->npixels = get_integer_resource (dpy, "ncolors", "Integer");
373 if (mi->npixels <= 0)
375 else if (mi->npixels > MAX_COLORS)
376 mi->npixels = MAX_COLORS;
378 mi->colors = (XColor *) calloc (mi->npixels, sizeof (*mi->colors));
380 mi->writable_p = mi->xlmft->want_writable_colors;
382 switch (mi->xlmft->desired_color_scheme)
384 case color_scheme_uniform:
385 make_uniform_colormap (dpy, mi->xgwa.visual, mi->xgwa.colormap,
386 mi->colors, &mi->npixels,
387 True, &mi->writable_p, True);
389 case color_scheme_smooth:
390 make_smooth_colormap (dpy, mi->xgwa.visual, mi->xgwa.colormap,
391 mi->colors, &mi->npixels,
392 True, &mi->writable_p, True);
394 case color_scheme_bright:
395 case color_scheme_default:
396 make_random_colormap (dpy, mi->xgwa.visual, mi->xgwa.colormap,
397 mi->colors, &mi->npixels,
398 (mi->xlmft->desired_color_scheme ==
399 color_scheme_bright),
400 True, &mi->writable_p, True);
406 if (mi->npixels <= 2)
410 mi->pixels = (unsigned long *)
411 calloc (mi->npixels, sizeof (*mi->pixels));
412 for (i = 0; i < mi->npixels; i++)
413 mi->pixels[i] = mi->colors[i].pixel;
417 gcv.foreground = mi->white;
418 gcv.background = mi->black;
419 mi->gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
421 mi->fullrandom = True;
423 mi->pause = get_integer_resource (dpy, "delay", "Usecs");
425 mi->cycles = get_integer_resource (dpy, "cycles", "Int");
426 mi->batchcount = get_integer_resource (dpy, "count", "Int");
427 mi->size = get_integer_resource (dpy, "size", "Int");
429 mi->threed = get_boolean_resource (dpy, "use3d", "Boolean");
430 mi->threed_delta = get_float_resource (dpy, "delta3d", "Float");
431 mi->threed_right_color = get_pixel_resource (dpy,
432 mi->xgwa.colormap, "right3d", "Color");
433 mi->threed_left_color = get_pixel_resource (dpy,
434 mi->xgwa.colormap, "left3d", "Color");
435 mi->threed_both_color = get_pixel_resource (dpy,
436 mi->xgwa.colormap, "both3d", "Color");
437 mi->threed_none_color = get_pixel_resource (dpy,
438 mi->xgwa.colormap, "none3d", "Color");
440 mi->wireframe_p = get_boolean_resource (dpy, "wireframe", "Boolean");
442 #ifdef HAVE_XSHM_EXTENSION
443 mi->use_shm = get_boolean_resource (dpy, "useSHM", "Boolean");
444 #endif /* !HAVE_XSHM_EXTENSION */
445 mi->fps_p = get_boolean_resource (dpy, "doFPS", "DoFPS");
446 mi->recursion_depth = -1; /* see fps.c */
450 else if (mi->pause > 100000000)
451 mi->pause = 100000000;
453 /* If this hack uses fonts (meaning, mentioned "font" in DEFAULTS)
456 char *name = get_string_resource (dpy, "font", "Font");
459 XFontStruct *f = XLoadQueryFont (dpy, name);
460 const char *def1 = "-*-helvetica-bold-r-normal-*-180-*";
461 const char *def2 = "fixed";
464 fprintf (stderr, "%s: font %s does not exist, using %s\n",
465 progname, name, def1);
466 f = XLoadQueryFont (dpy, def1);
470 fprintf (stderr, "%s: font %s does not exist, using %s\n",
471 progname, def1, def2);
472 f = XLoadQueryFont (dpy, def2);
474 if (f) XSetFont (dpy, mi->gc, f->fid);
475 if (f) XFreeFont (dpy, f);
480 xlockmore_read_resources (mi);
482 XClearWindow (dpy, window);
484 mi->xlmft->hack_init (mi);
490 xlockmore_draw (Display *dpy, Window window, void *closure)
492 ModeInfo *mi = (ModeInfo *) closure;
494 unsigned long orig_pause = mi->pause;
495 unsigned long this_pause;
497 mi->xlmft->hack_draw (mi);
499 this_pause = mi->pause;
500 mi->pause = orig_pause;
506 xlockmore_reshape (Display *dpy, Window window, void *closure,
507 unsigned int w, unsigned int h)
509 ModeInfo *mi = (ModeInfo *) closure;
510 if (mi && mi->xlmft->hack_reshape)
512 XGetWindowAttributes (dpy, window, &mi->xgwa);
513 mi->xlmft->hack_reshape (mi, mi->xgwa.width, mi->xgwa.height);
518 xlockmore_event (Display *dpy, Window window, void *closure, XEvent *event)
520 ModeInfo *mi = (ModeInfo *) closure;
521 if (mi && mi->xlmft->hack_handle_events)
522 return mi->xlmft->hack_handle_events (mi, event);
528 xlockmore_do_fps (Display *dpy, Window w, fps_state *fpst, void *closure)
530 ModeInfo *mi = (ModeInfo *) closure;
531 fps_compute (fpst, 0, mi ? mi->recursion_depth : -1);
537 xlockmore_free (Display *dpy, Window window, void *closure)
539 /* Most of the xlockmore/GL hacks don't have `free' functions, and of
540 those that do have them, they're incomplete or buggy. So, fuck it.
541 Under X11, we're about to exit anyway, and it doesn't matter.
542 On OSX, we'll leak a little. Beats crashing.
545 ModeInfo *mi = (ModeInfo *) closure;
546 if (mi->xlmft->hack_free)
547 mi->xlmft->hack_free (mi);
549 XFreeGC (dpy, mi->gc);
550 free_colors (dpy, mi->xgwa.colormap, mi->colors, mi->npixels);