1 /* xlockmore.c --- xscreensaver compatibility layer for xlockmore modules.
2 * xscreensaver, Copyright (c) 1997-2008 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",
102 for (j = 0; j < countof(args); j++)
103 if (strstr(xlockmore_defaults, args[j]+1))
105 XrmOptionDescRec *new = &new_options[i++];
106 new->option = args[j];
107 new->specifier = strdup(args[j]);
108 new->specifier[0] = '.';
109 if (!strcmp(new->option, "-wireframe"))
111 new->argKind = XrmoptionNoArg;
113 new = &new_options[i++];
114 new->option = "-no-wireframe";
115 new->specifier = new_options[i-2].specifier;
116 new->argKind = XrmoptionNoArg;
117 new->value = "False";
119 else if (!strcmp(new->option, "-use3d"))
122 new->argKind = XrmoptionNoArg;
124 new = &new_options[i++];
125 new->option = "-no-3d";
126 new->specifier = new_options[i-2].specifier;
127 new->argKind = XrmoptionNoArg;
128 new->value = "False";
130 else if (!strcmp(new->option, "-useSHM"))
132 new->option = "-shm";
133 new->argKind = XrmoptionNoArg;
135 new = &new_options[i++];
136 new->option = "-no-shm";
137 new->specifier = new_options[i-2].specifier;
138 new->argKind = XrmoptionNoArg;
139 new->value = "False";
141 else if (!strcmp(new->option, "-showFPS"))
143 new->option = "-fps";
144 new->argKind = XrmoptionNoArg;
146 new = &new_options[i++];
147 new->option = "-no-fps";
148 new->specifier = new_options[i-2].specifier;
149 new->argKind = XrmoptionNoArg;
150 new->value = "False";
154 new->argKind = XrmoptionSepArg;
162 /* Construct the kind of `defaults' that screenhack.c expects from
163 the xlockmore `vars[]' argument.
167 new_defaults = (char **) calloc (1, xlockmore_opts->numvarsdesc * 10 + 100);
169 /* Put on the PROGCLASS.background/foreground resources. */
170 s = (char *) malloc(50);
173 strcpy (s, progclass);
175 strcat (s, ".background: black");
176 new_defaults [i++] = s;
178 s = (char *) malloc(50);
181 strcpy (s, progclass);
183 strcat (s, ".foreground: white");
184 new_defaults [i++] = s;
186 /* Copy the lines out of the `xlockmore_defaults' var and into this array. */
187 s = strdup (xlockmore_defaults);
190 new_defaults [i++] = s;
196 /* Copy the defaults out of the `xlockmore_opts->' variable. */
197 for (j = 0; j < xlockmore_opts->numvarsdesc; j++)
199 const char *def = xlockmore_opts->vars[j].def;
203 if (strlen(def) > 1000) abort();
205 s = (char *) malloc (strlen (xlockmore_opts->vars[j].name) +
208 strcat (s, xlockmore_opts->vars[j].name);
211 new_defaults [i++] = s;
213 /* Go through the list of resources and print a warning if there
217 char *onew = strdup (xlockmore_opts->vars[j].name);
218 const char *new = onew;
220 if ((s = strrchr (new, '.'))) new = s+1;
221 if ((s = strrchr (new, '*'))) new = s+1;
222 for (k = 0; k < i-1; k++)
224 char *oold = strdup (new_defaults[k]);
225 const char *old = oold;
226 if ((s = strchr (oold, ':'))) *s = 0;
227 if ((s = strrchr (old, '.'))) old = s+1;
228 if ((s = strrchr (old, '*'))) old = s+1;
229 if (!strcasecmp (old, new))
232 "%s: duplicate resource \"%s\": "
233 "set in both DEFAULTS and vars[]\n",
242 new_defaults [i] = 0;
244 xsft->progclass = progclass;
245 xsft->options = new_options;
246 xsft->defaults = (const char * const *) new_defaults;
251 xlockmore_read_resources (ModeInfo *mi)
253 Display *dpy = mi->dpy;
254 ModeSpecOpt *xlockmore_opts = mi->xlmft->opts;
256 for (i = 0; i < xlockmore_opts->numvarsdesc; i++)
258 void *var = xlockmore_opts->vars[i].var;
259 Bool *var_b = (Bool *) var;
260 char **var_c = (char **) var;
261 int *var_i = (int *) var;
262 float *var_f = (float *) var;
264 switch (xlockmore_opts->vars[i].type)
267 *var_c = get_string_resource (dpy, xlockmore_opts->vars[i].name,
268 xlockmore_opts->vars[i].classname);
271 *var_f = get_float_resource (dpy, xlockmore_opts->vars[i].name,
272 xlockmore_opts->vars[i].classname);
275 *var_i = get_integer_resource (dpy, xlockmore_opts->vars[i].name,
276 xlockmore_opts->vars[i].classname);
279 *var_b = get_boolean_resource (dpy, xlockmore_opts->vars[i].name,
280 xlockmore_opts->vars[i].classname);
290 xlockmore_init (Display *dpy, Window window,
291 struct xlockmore_function_table *xlmft)
293 ModeInfo *mi = (ModeInfo *) calloc (1, sizeof(*mi));
306 XGetWindowAttributes (dpy, window, &mi->xgwa);
310 /* In Cocoa-based xscreensaver, all hacks run in the same address space,
311 so each one needs to get its own screen number. We just use a global
312 counter for that, instead of actually trying to figure out which
313 monitor each window is on. Also, the embedded "preview" view counts
316 Note that the screen number will increase each time the saver is
317 restarted (e.g., each time preferences are changed!) So we just
318 keep pushing the num_screens number up as needed, and assume that
319 no more than 10 simultanious copies will be running at once...
322 static int screen_tick = 0;
323 mi->num_screens = 10;
324 mi->screen_number = screen_tick++;
325 if (screen_tick >= mi->num_screens)
326 mi->num_screens += 10;
330 #else /* !HAVE_COCOA -- real Xlib */
332 /* In Xlib-based xscreensaver, each hack runs in its own address space,
333 so each one only needs to be aware of one screen.
336 mi->screen_number = 0;
338 { /* kludge for DEBUG_PAIR */
339 static int screen_tick = 0;
346 root_p = (window == RootWindowOfScreen (mi->xgwa.screen));
348 /* Everybody gets motion events, just in case. */
349 XSelectInput (dpy, window, (mi->xgwa.your_event_mask | PointerMotionMask));
351 #endif /* !HAVE_COCOA */
353 color.flags = DoRed|DoGreen|DoBlue;
354 color.red = color.green = color.blue = 0;
355 if (!XAllocColor(dpy, mi->xgwa.colormap, &color))
357 mi->black = color.pixel;
358 color.red = color.green = color.blue = 0xFFFF;
359 if (!XAllocColor(dpy, mi->xgwa.colormap, &color))
361 mi->white = color.pixel;
365 static unsigned long pixels[2];
366 static XColor colors[2];
370 mi->pixels = (unsigned long *)
371 calloc (mi->npixels, sizeof (*mi->pixels));
373 mi->colors = (XColor *)
374 calloc (mi->npixels, sizeof (*mi->colors));
375 pixels[0] = mi->black;
376 pixels[1] = mi->white;
377 colors[0].flags = DoRed|DoGreen|DoBlue;
378 colors[1].flags = DoRed|DoGreen|DoBlue;
379 colors[0].red = colors[0].green = colors[0].blue = 0;
380 colors[1].red = colors[1].green = colors[1].blue = 0xFFFF;
381 mi->writable_p = False;
385 mi->npixels = get_integer_resource (dpy, "ncolors", "Integer");
386 if (mi->npixels <= 0)
388 else if (mi->npixels > MAX_COLORS)
389 mi->npixels = MAX_COLORS;
391 mi->colors = (XColor *) calloc (mi->npixels, sizeof (*mi->colors));
393 mi->writable_p = mi->xlmft->want_writable_colors;
395 switch (mi->xlmft->desired_color_scheme)
397 case color_scheme_uniform:
398 make_uniform_colormap (dpy, mi->xgwa.visual, mi->xgwa.colormap,
399 mi->colors, &mi->npixels,
400 True, &mi->writable_p, True);
402 case color_scheme_smooth:
403 make_smooth_colormap (dpy, mi->xgwa.visual, mi->xgwa.colormap,
404 mi->colors, &mi->npixels,
405 True, &mi->writable_p, True);
407 case color_scheme_bright:
408 case color_scheme_default:
409 make_random_colormap (dpy, mi->xgwa.visual, mi->xgwa.colormap,
410 mi->colors, &mi->npixels,
411 (mi->xlmft->desired_color_scheme ==
412 color_scheme_bright),
413 True, &mi->writable_p, True);
419 if (mi->npixels <= 2)
423 mi->pixels = (unsigned long *)
424 calloc (mi->npixels, sizeof (*mi->pixels));
425 for (i = 0; i < mi->npixels; i++)
426 mi->pixels[i] = mi->colors[i].pixel;
430 gcv.foreground = mi->white;
431 gcv.background = mi->black;
432 mi->gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
434 mi->fullrandom = True;
436 mi->pause = get_integer_resource (dpy, "delay", "Usecs");
438 mi->cycles = get_integer_resource (dpy, "cycles", "Int");
439 mi->batchcount = get_integer_resource (dpy, "count", "Int");
440 mi->size = get_integer_resource (dpy, "size", "Int");
442 mi->threed = get_boolean_resource (dpy, "use3d", "Boolean");
443 mi->threed_delta = get_float_resource (dpy, "delta3d", "Float");
444 mi->threed_right_color = get_pixel_resource (dpy,
445 mi->xgwa.colormap, "right3d", "Color");
446 mi->threed_left_color = get_pixel_resource (dpy,
447 mi->xgwa.colormap, "left3d", "Color");
448 mi->threed_both_color = get_pixel_resource (dpy,
449 mi->xgwa.colormap, "both3d", "Color");
450 mi->threed_none_color = get_pixel_resource (dpy,
451 mi->xgwa.colormap, "none3d", "Color");
453 mi->wireframe_p = get_boolean_resource (dpy, "wireframe", "Boolean");
455 mi->fps_p = get_boolean_resource (dpy, "showFPS", "Boolean");
456 #ifdef HAVE_XSHM_EXTENSION
457 mi->use_shm = get_boolean_resource (dpy, "useSHM", "Boolean");
458 #endif /* !HAVE_XSHM_EXTENSION */
462 else if (mi->pause > 100000000)
463 mi->pause = 100000000;
464 orig_pause = mi->pause;
466 /* If this hack uses fonts (meaning, mentioned "font" in DEFAULTS)
469 char *name = get_string_resource (dpy, "font", "Font");
472 XFontStruct *f = XLoadQueryFont (dpy, name);
473 const char *def1 = "-*-times-bold-r-normal-*-180-*";
474 const char *def2 = "fixed";
477 fprintf (stderr, "%s: font %s does not exist, using %s\n",
478 progname, name, def1);
479 f = XLoadQueryFont (dpy, def1);
483 fprintf (stderr, "%s: font %s does not exist, using %s\n",
484 progname, def1, def2);
485 f = XLoadQueryFont (dpy, def2);
487 if (f) XSetFont (dpy, mi->gc, f->fid);
488 if (f) XFreeFont (dpy, f);
493 xlockmore_read_resources (mi);
495 XClearWindow (dpy, window);
497 mi->xlmft->hack_init (mi);
503 xlockmore_draw (Display *dpy, Window window, void *closure)
505 ModeInfo *mi = (ModeInfo *) closure;
507 unsigned long orig_pause = mi->pause;
508 unsigned long this_pause;
510 mi->xlmft->hack_draw (mi);
512 this_pause = mi->pause;
513 mi->pause = orig_pause;
519 xlockmore_reshape (Display *dpy, Window window, void *closure,
520 unsigned int w, unsigned int h)
522 ModeInfo *mi = (ModeInfo *) closure;
523 if (mi && mi->xlmft->hack_reshape)
525 XGetWindowAttributes (dpy, window, &mi->xgwa);
526 mi->xlmft->hack_reshape (mi, mi->xgwa.width, mi->xgwa.height);
531 xlockmore_event (Display *dpy, Window window, void *closure, XEvent *event)
533 ModeInfo *mi = (ModeInfo *) closure;
534 if (mi && mi->xlmft->hack_handle_events)
536 mi->xlmft->hack_handle_events (mi, event);
537 /* Since xlockmore hacks don't tell us whether they handled the
538 event, assume they handled buttons (so we don't beep) but that
539 they didn't handle anything else (so that "q" still quits).
541 return (event->xany.type == ButtonPress);
548 xlockmore_free (Display *dpy, Window window, void *closure)
550 ModeInfo *mi = (ModeInfo *) closure;
551 if (mi->xlmft->hack_free)
552 mi->xlmft->hack_free (mi);
560 XFreeGC (dpy, mi->gc);
561 free_colors (dpy, mi->xgwa.colormap, mi->colors, mi->npixels);