1 /* xlockmore.c --- xscreensaver compatibility layer for xlockmore modules.
2 * xscreensaver, Copyright (c) 1997, 1998, 2001, 2002, 2004, 2006
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...)
20 #include "xlockmoreI.h"
21 #include "screenhack.h"
24 # include <X11/Intrinsic.h>
25 #endif /* !HAVE_COCOA */
27 #define countof(x) (sizeof((x))/sizeof(*(x)))
29 #define MAX_COLORS (1L<<13)
31 extern struct xscreensaver_function_table *xscreensaver_function_table;
33 extern const char *progclass;
35 extern struct xlockmore_function_table xlockmore_function_table;
37 static void *xlockmore_init (Display *, Window,
38 struct xlockmore_function_table *);
39 static unsigned long xlockmore_draw (Display *, Window, void *);
40 static void xlockmore_reshape (Display *, Window, void *,
41 unsigned int w, unsigned int h);
42 static Bool xlockmore_event (Display *, Window, void *, XEvent *);
43 static void xlockmore_free (Display *, Window, void *);
47 xlockmore_setup (struct xscreensaver_function_table *xsft, void *arg)
49 struct xlockmore_function_table *xlmft =
50 (struct xlockmore_function_table *) arg;
53 XrmOptionDescRec *new_options;
55 const char *xlockmore_defaults;
56 ModeSpecOpt *xlockmore_opts = xlmft->opts;
61 xsft->init_cb = (void *(*) (Display *, Window)) xlockmore_init;
62 xsft->draw_cb = xlockmore_draw;
63 xsft->reshape_cb = xlockmore_reshape;
64 xsft->event_cb = xlockmore_event;
65 xsft->free_cb = xlockmore_free;
67 progclass = xlmft->progclass;
68 xlockmore_defaults = xlmft->defaults;
70 /* Translate the xlockmore `opts[]' argument to a form that
73 new_options = (XrmOptionDescRec *)
74 calloc (xlockmore_opts->numopts*3 + 100, sizeof (*new_options));
76 for (i = 0; i < xlockmore_opts->numopts; i++)
78 XrmOptionDescRec *old = &xlockmore_opts->opts[i];
79 XrmOptionDescRec *new = &new_options[i];
81 if (old->option[0] == '-')
82 new->option = old->option;
85 /* Convert "+foo" to "-no-foo". */
86 new->option = (char *) malloc (strlen(old->option) + 5);
87 strcpy (new->option, "-no-");
88 strcat (new->option, old->option + 1);
91 new->specifier = strrchr (old->specifier, '.');
92 if (!new->specifier) abort();
94 new->argKind = old->argKind;
95 new->value = old->value;
98 /* Add extra args, if they're mentioned in the defaults... */
100 char *args[] = { "-count", "-cycles", "-delay", "-ncolors",
101 "-size", "-font", "-wireframe", "-use3d", "-useSHM",
103 for (j = 0; j < countof(args); j++)
104 if (strstr(xlockmore_defaults, args[j]+1))
106 XrmOptionDescRec *new = &new_options[i++];
107 new->option = args[j];
108 new->specifier = strdup(args[j]);
109 new->specifier[0] = '.';
110 if (!strcmp(new->option, "-wireframe"))
112 new->argKind = XrmoptionNoArg;
114 new = &new_options[i++];
115 new->option = "-no-wireframe";
116 new->specifier = new_options[i-2].specifier;
117 new->argKind = XrmoptionNoArg;
118 new->value = "False";
120 else if (!strcmp(new->option, "-use3d"))
123 new->argKind = XrmoptionNoArg;
125 new = &new_options[i++];
126 new->option = "-no-3d";
127 new->specifier = new_options[i-2].specifier;
128 new->argKind = XrmoptionNoArg;
129 new->value = "False";
131 else if (!strcmp(new->option, "-useSHM"))
133 new->option = "-shm";
134 new->argKind = XrmoptionNoArg;
136 new = &new_options[i++];
137 new->option = "-no-shm";
138 new->specifier = new_options[i-2].specifier;
139 new->argKind = XrmoptionNoArg;
140 new->value = "False";
142 else if (!strcmp(new->option, "-showFPS"))
144 new->option = "-fps";
145 new->argKind = XrmoptionNoArg;
147 new = &new_options[i++];
148 new->option = "-no-fps";
149 new->specifier = new_options[i-2].specifier;
150 new->argKind = XrmoptionNoArg;
151 new->value = "False";
155 new->argKind = XrmoptionSepArg;
163 /* Construct the kind of `defaults' that screenhack.c expects from
164 the xlockmore `vars[]' argument.
168 new_defaults = (char **) calloc (1, xlockmore_opts->numvarsdesc * 10 + 100);
170 /* Put on the PROGCLASS.background/foreground resources. */
171 s = (char *) malloc(50);
174 strcpy (s, progclass);
176 strcat (s, ".background: black");
177 new_defaults [i++] = s;
179 s = (char *) malloc(50);
182 strcpy (s, progclass);
184 strcat (s, ".foreground: white");
185 new_defaults [i++] = s;
187 /* Copy the lines out of the `xlockmore_defaults' var and into this array. */
188 s = strdup (xlockmore_defaults);
191 new_defaults [i++] = s;
197 /* Copy the defaults out of the `xlockmore_opts->' variable. */
198 for (j = 0; j < xlockmore_opts->numvarsdesc; j++)
200 const char *def = xlockmore_opts->vars[j].def;
204 if (strlen(def) > 1000) abort();
206 s = (char *) malloc (strlen (xlockmore_opts->vars[j].name) +
209 strcat (s, xlockmore_opts->vars[j].name);
212 new_defaults [i++] = s;
214 /* Go through the list of resources and print a warning if there
218 char *onew = strdup (xlockmore_opts->vars[j].name);
219 const char *new = onew;
221 if ((s = strrchr (new, '.'))) new = s+1;
222 if ((s = strrchr (new, '*'))) new = s+1;
223 for (k = 0; k < i-1; k++)
225 char *oold = strdup (new_defaults[k]);
226 const char *old = oold;
227 if ((s = strchr (oold, ':'))) *s = 0;
228 if ((s = strrchr (old, '.'))) old = s+1;
229 if ((s = strrchr (old, '*'))) old = s+1;
230 if (!strcasecmp (old, new))
233 "%s: duplicate resource \"%s\": "
234 "set in both DEFAULTS and vars[]\n",
243 new_defaults [i] = 0;
245 xsft->progclass = progclass;
246 xsft->options = new_options;
247 xsft->defaults = (const char * const *) new_defaults;
252 xlockmore_read_resources (ModeInfo *mi)
254 Display *dpy = mi->dpy;
255 ModeSpecOpt *xlockmore_opts = mi->xlmft->opts;
257 for (i = 0; i < xlockmore_opts->numvarsdesc; i++)
259 void *var = xlockmore_opts->vars[i].var;
260 Bool *var_b = (Bool *) var;
261 char **var_c = (char **) var;
262 int *var_i = (int *) var;
263 float *var_f = (float *) var;
265 switch (xlockmore_opts->vars[i].type)
268 *var_c = get_string_resource (dpy, xlockmore_opts->vars[i].name,
269 xlockmore_opts->vars[i].classname);
272 *var_f = get_float_resource (dpy, xlockmore_opts->vars[i].name,
273 xlockmore_opts->vars[i].classname);
276 *var_i = get_integer_resource (dpy, xlockmore_opts->vars[i].name,
277 xlockmore_opts->vars[i].classname);
280 *var_b = get_boolean_resource (dpy, xlockmore_opts->vars[i].name,
281 xlockmore_opts->vars[i].classname);
291 xlockmore_init (Display *dpy, Window window,
292 struct xlockmore_function_table *xlmft)
294 ModeInfo *mi = (ModeInfo *) calloc (1, sizeof(*mi));
307 XGetWindowAttributes (dpy, window, &mi->xgwa);
311 /* In Cocoa-based xscreensaver, all hacks run in the same address space,
312 so each one needs to get its own screen number. We just use a global
313 counter for that, instead of actually trying to figure out which
314 monitor each window is on. Also, the embedded "preview" view counts
317 Note that the screen number will increase each time the saver is
318 restarted (e.g., each time preferences are changed!) So we just
319 keep pushing the num_screens number up as needed, and assume that
320 no more than 10 simultanious copies will be running at once...
323 static int screen_tick = 0;
324 mi->num_screens = 10;
325 mi->screen_number = screen_tick++;
326 if (screen_tick >= mi->num_screens)
327 mi->num_screens += 10;
331 #else /* !HAVE_COCOA -- real Xlib */
333 /* In Xlib-based xscreensaver, each hack runs in its own address space,
334 so each one only needs to be aware of one screen.
337 mi->screen_number = 0;
339 { /* kludge for DEBUG_PAIR */
340 static int screen_tick = 0;
347 root_p = (window == RootWindowOfScreen (mi->xgwa.screen));
349 /* Everybody gets motion events, just in case. */
350 XSelectInput (dpy, window, (mi->xgwa.your_event_mask | PointerMotionMask));
352 #endif /* !HAVE_COCOA */
354 color.flags = DoRed|DoGreen|DoBlue;
355 color.red = color.green = color.blue = 0;
356 if (!XAllocColor(dpy, mi->xgwa.colormap, &color))
358 mi->black = color.pixel;
359 color.red = color.green = color.blue = 0xFFFF;
360 if (!XAllocColor(dpy, mi->xgwa.colormap, &color))
362 mi->white = color.pixel;
366 static unsigned long pixels[2];
367 static XColor colors[2];
371 mi->pixels = (unsigned long *)
372 calloc (mi->npixels, sizeof (*mi->pixels));
374 mi->colors = (XColor *)
375 calloc (mi->npixels, sizeof (*mi->colors));
376 pixels[0] = mi->black;
377 pixels[1] = mi->white;
378 colors[0].flags = DoRed|DoGreen|DoBlue;
379 colors[1].flags = DoRed|DoGreen|DoBlue;
380 colors[0].red = colors[0].green = colors[0].blue = 0;
381 colors[1].red = colors[1].green = colors[1].blue = 0xFFFF;
382 mi->writable_p = False;
386 mi->npixels = get_integer_resource (dpy, "ncolors", "Integer");
387 if (mi->npixels <= 0)
389 else if (mi->npixels > MAX_COLORS)
390 mi->npixels = MAX_COLORS;
392 mi->colors = (XColor *) calloc (mi->npixels, sizeof (*mi->colors));
394 mi->writable_p = mi->xlmft->want_writable_colors;
396 switch (mi->xlmft->desired_color_scheme)
398 case color_scheme_uniform:
399 make_uniform_colormap (dpy, mi->xgwa.visual, mi->xgwa.colormap,
400 mi->colors, &mi->npixels,
401 True, &mi->writable_p, True);
403 case color_scheme_smooth:
404 make_smooth_colormap (dpy, mi->xgwa.visual, mi->xgwa.colormap,
405 mi->colors, &mi->npixels,
406 True, &mi->writable_p, True);
408 case color_scheme_bright:
409 case color_scheme_default:
410 make_random_colormap (dpy, mi->xgwa.visual, mi->xgwa.colormap,
411 mi->colors, &mi->npixels,
412 (mi->xlmft->desired_color_scheme ==
413 color_scheme_bright),
414 True, &mi->writable_p, True);
420 if (mi->npixels <= 2)
424 mi->pixels = (unsigned long *)
425 calloc (mi->npixels, sizeof (*mi->pixels));
426 for (i = 0; i < mi->npixels; i++)
427 mi->pixels[i] = mi->colors[i].pixel;
431 gcv.foreground = mi->white;
432 gcv.background = mi->black;
433 mi->gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
435 mi->fullrandom = True;
437 mi->pause = get_integer_resource (dpy, "delay", "Usecs");
439 mi->cycles = get_integer_resource (dpy, "cycles", "Int");
440 mi->batchcount = get_integer_resource (dpy, "count", "Int");
441 mi->size = get_integer_resource (dpy, "size", "Int");
443 mi->threed = get_boolean_resource (dpy, "use3d", "Boolean");
444 mi->threed_delta = get_float_resource (dpy, "delta3d", "Float");
445 mi->threed_right_color = get_pixel_resource (dpy,
446 mi->xgwa.colormap, "right3d", "Color");
447 mi->threed_left_color = get_pixel_resource (dpy,
448 mi->xgwa.colormap, "left3d", "Color");
449 mi->threed_both_color = get_pixel_resource (dpy,
450 mi->xgwa.colormap, "both3d", "Color");
451 mi->threed_none_color = get_pixel_resource (dpy,
452 mi->xgwa.colormap, "none3d", "Color");
454 mi->wireframe_p = get_boolean_resource (dpy, "wireframe", "Boolean");
456 mi->fps_p = get_boolean_resource (dpy, "showFPS", "Boolean");
457 #ifdef HAVE_XSHM_EXTENSION
458 mi->use_shm = get_boolean_resource (dpy, "useSHM", "Boolean");
459 #endif /* !HAVE_XSHM_EXTENSION */
463 else if (mi->pause > 100000000)
464 mi->pause = 100000000;
465 orig_pause = mi->pause;
467 /* If this hack uses fonts (meaning, mentioned "font" in DEFAULTS)
470 char *name = get_string_resource (dpy, "font", "Font");
473 XFontStruct *f = XLoadQueryFont (dpy, name);
474 const char *def1 = "-*-times-bold-r-normal-*-180-*";
475 const char *def2 = "fixed";
478 fprintf (stderr, "%s: font %s does not exist, using %s\n",
479 progname, name, def1);
480 f = XLoadQueryFont (dpy, def1);
484 fprintf (stderr, "%s: font %s does not exist, using %s\n",
485 progname, def1, def2);
486 f = XLoadQueryFont (dpy, def2);
488 if (f) XSetFont (dpy, mi->gc, f->fid);
489 if (f) XFreeFont (dpy, f);
494 xlockmore_read_resources (mi);
496 XClearWindow (dpy, window);
498 mi->xlmft->hack_init (mi);
504 xlockmore_draw (Display *dpy, Window window, void *closure)
506 ModeInfo *mi = (ModeInfo *) closure;
508 unsigned long orig_pause = mi->pause;
509 unsigned long this_pause;
511 mi->xlmft->hack_draw (mi);
513 this_pause = mi->pause;
514 mi->pause = orig_pause;
520 xlockmore_reshape (Display *dpy, Window window, void *closure,
521 unsigned int w, unsigned int h)
523 ModeInfo *mi = (ModeInfo *) closure;
524 if (mi->xlmft->hack_reshape)
526 XGetWindowAttributes (dpy, window, &mi->xgwa);
527 mi->xlmft->hack_reshape (mi, mi->xgwa.width, mi->xgwa.height);
532 xlockmore_event (Display *dpy, Window window, void *closure, XEvent *event)
534 ModeInfo *mi = (ModeInfo *) closure;
535 if (mi->xlmft->hack_handle_events)
537 mi->xlmft->hack_handle_events (mi, event);
538 /* Since xlockmore hacks don't tell us whether they handled the
539 event, assume they handled buttons (so we don't beep) but that
540 they didn't handle anything else (so that "q" still quits).
542 return (event->xany.type == ButtonPress);
549 xlockmore_free (Display *dpy, Window window, void *closure)
551 ModeInfo *mi = (ModeInfo *) closure;
552 if (mi->xlmft->hack_free)
553 mi->xlmft->hack_free (mi);
561 XFreeGC (dpy, mi->gc);
562 free_colors (dpy, mi->xgwa.colormap, mi->colors, mi->npixels);