X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fxlockmore.c;h=00994ac878d93763e22f2a28f69e00e473afda34;hb=aa75c7476aeaa84cf3abc192b376a8b03c325213;hp=a1e71aa2e1f449809f7a42fdee5a690b0607d747;hpb=6bb727f03bff0389fbb1349d7df4c9d8d7532959;p=xscreensaver diff --git a/hacks/xlockmore.c b/hacks/xlockmore.c index a1e71aa2..00994ac8 100644 --- a/hacks/xlockmore.c +++ b/hacks/xlockmore.c @@ -1,5 +1,5 @@ /* xlockmore.c --- xscreensaver compatibility layer for xlockmore modules. - * xscreensaver, Copyright (c) 1997 Jamie Zawinski + * xscreensaver, Copyright (c) 1997-2014 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -11,35 +11,71 @@ * * This file, along with xlockmore.h, make it possible to compile an xlockmore * module into a standalone program, and thus use it with xscreensaver. - * By Jamie Zawinski on 10-May-97; based on the ideas + * By Jamie Zawinski on 10-May-97; based on the ideas * in the older xlock.h by Charles Hannum . (I had * to redo it, since xlockmore has diverged so far from xlock...) */ -#include -#include -#include -#include "screenhack.h" #include "xlockmoreI.h" +#include "screenhack.h" + +#ifndef HAVE_JWXYZ +# include +#endif /* !HAVE_JWXYZ */ #define countof(x) (sizeof((x))/sizeof(*(x))) -extern ModeSpecOpt xlockmore_opts[]; -extern const char *app_defaults; +#define MAX_COLORS (1L<<13) + +extern struct xscreensaver_function_table *xscreensaver_function_table; + +extern const char *progclass; + +extern struct xlockmore_function_table xlockmore_function_table; + +static void *xlockmore_init (Display *, Window, + struct xlockmore_function_table *); +static unsigned long xlockmore_draw (Display *, Window, void *); +static void xlockmore_reshape (Display *, Window, void *, + unsigned int w, unsigned int h); +static Bool xlockmore_event (Display *, Window, void *, XEvent *); +static void xlockmore_free (Display *, Window, void *); + void -pre_merge_options (void) +xlockmore_setup (struct xscreensaver_function_table *xsft, void *arg) { + struct xlockmore_function_table *xlmft = + (struct xlockmore_function_table *) arg; int i, j; char *s; + XrmOptionDescRec *new_options; + char **new_defaults; + const char *xlockmore_defaults; + ModeSpecOpt *xlockmore_opts = xlmft->opts; + +# undef ya_rand_init + ya_rand_init (0); + + xsft->init_cb = (void *(*) (Display *, Window)) xlockmore_init; + xsft->draw_cb = xlockmore_draw; + xsft->reshape_cb = xlockmore_reshape; + xsft->event_cb = xlockmore_event; + xsft->free_cb = xlockmore_free; + + progclass = xlmft->progclass; + xlockmore_defaults = xlmft->defaults; /* Translate the xlockmore `opts[]' argument to a form that screenhack.c expects. */ + new_options = (XrmOptionDescRec *) + calloc (xlockmore_opts->numopts*3 + 100, sizeof (*new_options)); + for (i = 0; i < xlockmore_opts->numopts; i++) { XrmOptionDescRec *old = &xlockmore_opts->opts[i]; - XrmOptionDescRec *new = &options[i]; + XrmOptionDescRec *new = &new_options[i]; if (old->option[0] == '-') new->option = old->option; @@ -61,11 +97,11 @@ pre_merge_options (void) /* Add extra args, if they're mentioned in the defaults... */ { char *args[] = { "-count", "-cycles", "-delay", "-ncolors", - "-size", "-wireframe", "-use3d" }; + "-size", "-font", "-wireframe", "-use3d", "-useSHM" }; for (j = 0; j < countof(args); j++) - if (strstr(app_defaults, args[j]+1)) + if (strstr(xlockmore_defaults, args[j]+1)) { - XrmOptionDescRec *new = &options[i++]; + XrmOptionDescRec *new = &new_options[i++]; new->option = args[j]; new->specifier = strdup(args[j]); new->specifier[0] = '.'; @@ -73,9 +109,9 @@ pre_merge_options (void) { new->argKind = XrmoptionNoArg; new->value = "True"; - new = &options[i++]; + new = &new_options[i++]; new->option = "-no-wireframe"; - new->specifier = options[i-1].specifier; + new->specifier = new_options[i-2].specifier; new->argKind = XrmoptionNoArg; new->value = "False"; } @@ -84,9 +120,20 @@ pre_merge_options (void) new->option = "-3d"; new->argKind = XrmoptionNoArg; new->value = "True"; - new = &options[i++]; + new = &new_options[i++]; new->option = "-no-3d"; - new->specifier = options[i-1].specifier; + new->specifier = new_options[i-2].specifier; + new->argKind = XrmoptionNoArg; + new->value = "False"; + } + else if (!strcmp(new->option, "-useSHM")) + { + new->option = "-shm"; + new->argKind = XrmoptionNoArg; + new->value = "True"; + new = &new_options[i++]; + new->option = "-no-shm"; + new->specifier = new_options[i-2].specifier; new->argKind = XrmoptionNoArg; new->value = "False"; } @@ -99,27 +146,36 @@ pre_merge_options (void) } + /* Construct the kind of `defaults' that screenhack.c expects from the xlockmore `vars[]' argument. */ i = 0; + new_defaults = (char **) calloc (1, xlockmore_opts->numvarsdesc * 10 + 1000); + /* Put on the PROGCLASS.background/foreground resources. */ s = (char *) malloc(50); + *s = 0; +# ifndef HAVE_JWXYZ strcpy (s, progclass); +# endif strcat (s, ".background: black"); - defaults [i++] = s; + new_defaults [i++] = s; s = (char *) malloc(50); + *s = 0; +# ifndef HAVE_JWXYZ strcpy (s, progclass); +# endif strcat (s, ".foreground: white"); - defaults [i++] = s; + new_defaults [i++] = s; - /* Copy the lines out of the `app_defaults' var and into this array. */ - s = strdup (app_defaults); + /* Copy the lines out of the `xlockmore_defaults' var and into this array. */ + s = strdup (xlockmore_defaults); while (s && *s) { - defaults [i++] = s; + new_defaults [i++] = s; s = strchr(s, '\n'); if (s) *s++ = 0; @@ -129,24 +185,61 @@ pre_merge_options (void) for (j = 0; j < xlockmore_opts->numvarsdesc; j++) { const char *def = xlockmore_opts->vars[j].def; - if (!def) def = "False"; - if (def == ((char*) 1)) def = "True"; + + if (!def) abort(); + if (!*def) abort(); + if (strlen(def) > 1000) abort(); + s = (char *) malloc (strlen (xlockmore_opts->vars[j].name) + strlen (def) + 10); strcpy (s, "*"); strcat (s, xlockmore_opts->vars[j].name); strcat (s, ": "); strcat (s, def); - defaults [i++] = s; + new_defaults [i++] = s; + + /* Go through the list of resources and print a warning if there + are any duplicates. + */ + { + char *onew = strdup (xlockmore_opts->vars[j].name); + const char *new = onew; + int k; + if ((s = strrchr (new, '.'))) new = s+1; + if ((s = strrchr (new, '*'))) new = s+1; + for (k = 0; k < i-1; k++) + { + char *oold = strdup (new_defaults[k]); + const char *old = oold; + if ((s = strchr (oold, ':'))) *s = 0; + if ((s = strrchr (old, '.'))) old = s+1; + if ((s = strrchr (old, '*'))) old = s+1; + if (!strcasecmp (old, new)) + { + fprintf (stderr, + "%s: duplicate resource \"%s\": " + "set in both DEFAULTS and vars[]\n", + progname, old); + } + free (oold); + } + free (onew); + } } - defaults [i] = 0; + new_defaults [i] = 0; + + xsft->progclass = progclass; + xsft->options = new_options; + xsft->defaults = (const char * const *) new_defaults; } static void -xlockmore_read_resources (void) +xlockmore_read_resources (ModeInfo *mi) { + Display *dpy = mi->dpy; + ModeSpecOpt *xlockmore_opts = mi->xlmft->opts; int i; for (i = 0; i < xlockmore_opts->numvarsdesc; i++) { @@ -159,19 +252,19 @@ xlockmore_read_resources (void) switch (xlockmore_opts->vars[i].type) { case t_String: - *var_c = get_string_resource (xlockmore_opts->vars[i].name, + *var_c = get_string_resource (dpy, xlockmore_opts->vars[i].name, xlockmore_opts->vars[i].classname); break; case t_Float: - *var_f = get_float_resource (xlockmore_opts->vars[i].name, + *var_f = get_float_resource (dpy, xlockmore_opts->vars[i].name, xlockmore_opts->vars[i].classname); break; case t_Int: - *var_i = get_integer_resource (xlockmore_opts->vars[i].name, + *var_i = get_integer_resource (dpy, xlockmore_opts->vars[i].name, xlockmore_opts->vars[i].classname); break; case t_Bool: - *var_b = get_boolean_resource (xlockmore_opts->vars[i].name, + *var_b = get_boolean_resource (dpy, xlockmore_opts->vars[i].name, xlockmore_opts->vars[i].classname); break; default: @@ -181,176 +274,286 @@ xlockmore_read_resources (void) } - -void -xlockmore_screenhack (Display *dpy, Window window, - Bool want_writable_colors, - Bool want_uniform_colors, - Bool want_smooth_colors, - Bool want_bright_colors, - void (*hack_init) (ModeInfo *), - void (*hack_draw) (ModeInfo *), - void (*hack_free) (ModeInfo *)) +static void * +xlockmore_init (Display *dpy, Window window, + struct xlockmore_function_table *xlmft) { - ModeInfo mi; + ModeInfo *mi = (ModeInfo *) calloc (1, sizeof(*mi)); XGCValues gcv; XColor color; int i; - time_t start, now; - int orig_pause; + Bool root_p; - memset(&mi, 0, sizeof(mi)); - mi.dpy = dpy; - mi.window = window; - XGetWindowAttributes (dpy, window, &mi.xgwa); + if (! xlmft) + abort(); + mi->xlmft = xlmft; + + mi->dpy = dpy; + mi->window = window; + XGetWindowAttributes (dpy, window, &mi->xgwa); + +#ifdef HAVE_JWXYZ + +# if 0 + /* In Cocoa and Android-based xscreensaver, all hacks run in the + same address space, so each one needs to get its own screen + number. Believe what jwxyz says about screen counts and numbers. + */ + mi->num_screens = ScreenCount (dpy); + mi->screen_number = XScreenNumberOfScreen (mi->xgwa.screen); +# else + /* No, that doesn't work. + The xlockmore docs/HACKERS.GUIDE says that xlock modes are supposed to + support repeated calls to init_*() for the same screen in the same + session, but in practice, a number of them blow up if you do that. + So instead we're stuck with a world where on OSX/iOS, we have to + increment the screen number every time the hack is run. Arrgh. + */ + mi->num_screens = 40; + mi->screen_number = xlmft->screen_count; + if (mi->screen_number >= mi->num_screens) abort(); + xlmft->screen_count++; +# endif + root_p = True; + +#else /* real Xlib */ + + /* In Xlib-based xscreensaver, each hack runs in its own address space, + so each one only needs to be aware of one screen. + */ + mi->num_screens = 1; + mi->screen_number = 0; + + { /* kludge for DEBUG_PAIR */ + static int screen_tick = 0; + mi->num_screens++; + if (screen_tick) + mi->screen_number++; + screen_tick++; + } + root_p = (window == RootWindowOfScreen (mi->xgwa.screen)); + + /* Everybody gets motion events, just in case. */ + XSelectInput (dpy, window, (mi->xgwa.your_event_mask | PointerMotionMask)); + +#endif /* !HAVE_JWXYZ */ + color.flags = DoRed|DoGreen|DoBlue; color.red = color.green = color.blue = 0; - if (!XAllocColor(dpy, mi.xgwa.colormap, &color)) + if (!XAllocColor(dpy, mi->xgwa.colormap, &color)) abort(); - mi.black = color.pixel; + mi->black = color.pixel; color.red = color.green = color.blue = 0xFFFF; - if (!XAllocColor(dpy, mi.xgwa.colormap, &color)) + if (!XAllocColor(dpy, mi->xgwa.colormap, &color)) abort(); - mi.white = color.pixel; + mi->white = color.pixel; if (mono_p) { - static unsigned long pixels[2]; static XColor colors[2]; MONO: - mi.npixels = 2; - mi.pixels = pixels; - mi.colors = colors; - pixels[0] = mi.black; - pixels[1] = mi.white; + mi->npixels = 2; + if (! mi->pixels) + mi->pixels = (unsigned long *) + calloc (mi->npixels, sizeof (*mi->pixels)); + if (!mi->colors) + mi->colors = (XColor *) + calloc (mi->npixels, sizeof (*mi->colors)); colors[0].flags = DoRed|DoGreen|DoBlue; colors[1].flags = DoRed|DoGreen|DoBlue; colors[0].red = colors[0].green = colors[0].blue = 0; colors[1].red = colors[1].green = colors[1].blue = 0xFFFF; - mi.writable_p = False; + mi->writable_p = False; } else { - mi.npixels = get_integer_resource ("ncolors", "Integer"); - if (mi.npixels <= 0) - mi.npixels = 64; - else if (mi.npixels > 256) - mi.npixels = 256; - - mi.colors = (XColor *) calloc (mi.npixels, sizeof (*mi.colors)); - - mi.writable_p = want_writable_colors; - - if (want_uniform_colors) - make_uniform_colormap (dpy, mi.xgwa.visual, mi.xgwa.colormap, - mi.colors, &mi.npixels, - True, &mi.writable_p, True); - else if (want_smooth_colors) - make_smooth_colormap (dpy, mi.xgwa.visual, mi.xgwa.colormap, - mi.colors, &mi.npixels, - True, &mi.writable_p, True); - else - make_random_colormap (dpy, mi.xgwa.visual, mi.xgwa.colormap, - mi.colors, &mi.npixels, - want_bright_colors, - True, &mi.writable_p, True); - - if (mi.npixels <= 2) + mi->npixels = get_integer_resource (dpy, "ncolors", "Integer"); + if (mi->npixels <= 0) + mi->npixels = 64; + else if (mi->npixels > MAX_COLORS) + mi->npixels = MAX_COLORS; + + mi->colors = (XColor *) calloc (mi->npixels, sizeof (*mi->colors)); + + mi->writable_p = mi->xlmft->want_writable_colors; + + switch (mi->xlmft->desired_color_scheme) + { + case color_scheme_uniform: + make_uniform_colormap (mi->xgwa.screen, mi->xgwa.visual, + mi->xgwa.colormap, + mi->colors, &mi->npixels, + True, &mi->writable_p, True); + break; + case color_scheme_smooth: + make_smooth_colormap (mi->xgwa.screen, mi->xgwa.visual, + mi->xgwa.colormap, + mi->colors, &mi->npixels, + True, &mi->writable_p, True); + break; + case color_scheme_bright: + case color_scheme_default: + make_random_colormap (mi->xgwa.screen, mi->xgwa.visual, + mi->xgwa.colormap, + mi->colors, &mi->npixels, + (mi->xlmft->desired_color_scheme == + color_scheme_bright), + True, &mi->writable_p, True); + break; + default: + abort(); + } + + if (mi->npixels <= 2) goto MONO; else { - int i; - mi.pixels = (unsigned long *) - calloc (mi.npixels, sizeof (*mi.pixels)); - for (i = 0; i < mi.npixels; i++) - mi.pixels[i] = mi.colors[i].pixel; + mi->pixels = (unsigned long *) + calloc (mi->npixels, sizeof (*mi->pixels)); + for (i = 0; i < mi->npixels; i++) + mi->pixels[i] = mi->colors[i].pixel; } } - gcv.foreground = mi.white; - gcv.background = mi.black; - mi.gc = XCreateGC(dpy, window, GCForeground|GCBackground, &gcv); - - mi.fullrandom = True; - - mi.pause = get_integer_resource ("delay", "Usecs"); - - mi.cycles = get_integer_resource ("cycles", "Int"); - mi.batchcount = get_integer_resource ("count", "Int"); - mi.size = get_integer_resource ("size", "Int"); - -#if 0 - decay = get_boolean_resource ("decay", "Boolean"); - if (decay) mi.fullrandom = False; + gcv.foreground = mi->white; + gcv.background = mi->black; + mi->gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv); + + mi->fullrandom = True; + + mi->pause = get_integer_resource (dpy, "delay", "Usecs"); + + mi->cycles = get_integer_resource (dpy, "cycles", "Int"); + mi->batchcount = get_integer_resource (dpy, "count", "Int"); + mi->size = get_integer_resource (dpy, "size", "Int"); + + mi->threed = get_boolean_resource (dpy, "use3d", "Boolean"); + mi->threed_delta = get_float_resource (dpy, "delta3d", "Float"); + mi->threed_right_color = get_pixel_resource (dpy, + mi->xgwa.colormap, "right3d", "Color"); + mi->threed_left_color = get_pixel_resource (dpy, + mi->xgwa.colormap, "left3d", "Color"); + mi->threed_both_color = get_pixel_resource (dpy, + mi->xgwa.colormap, "both3d", "Color"); + mi->threed_none_color = get_pixel_resource (dpy, + mi->xgwa.colormap, "none3d", "Color"); + + mi->wireframe_p = get_boolean_resource (dpy, "wireframe", "Boolean"); + mi->root_p = root_p; +#ifdef HAVE_XSHM_EXTENSION + mi->use_shm = get_boolean_resource (dpy, "useSHM", "Boolean"); +#endif /* !HAVE_XSHM_EXTENSION */ + mi->fps_p = get_boolean_resource (dpy, "doFPS", "DoFPS"); + mi->recursion_depth = -1; /* see fps.c */ + + if (mi->pause < 0) + mi->pause = 0; + else if (mi->pause > 100000000) + mi->pause = 100000000; + + /* If this hack uses fonts (meaning, mentioned "font" in DEFAULTS) + then load it. */ + { + char *name = get_string_resource (dpy, "font", "Font"); + if (name) + { + XFontStruct *f = XLoadQueryFont (dpy, name); + const char *def1 = "-*-helvetica-bold-r-normal-*-180-*"; + const char *def2 = "fixed"; + if (!f) + { + fprintf (stderr, "%s: font %s does not exist, using %s\n", + progname, name, def1); + f = XLoadQueryFont (dpy, def1); + } + if (!f) + { + fprintf (stderr, "%s: font %s does not exist, using %s\n", + progname, def1, def2); + f = XLoadQueryFont (dpy, def2); + } + if (f) XSetFont (dpy, mi->gc, f->fid); + if (f) XFreeFont (dpy, f); + free (name); + } + } - trail = get_boolean_resource ("trail", "Boolean"); - if (trail) mi.fullrandom = False; + xlockmore_read_resources (mi); - grow = get_boolean_resource ("grow", "Boolean"); - if (grow) mi.fullrandom = False; + XClearWindow (dpy, window); - liss = get_boolean_resource ("liss", "Boolean"); - if (liss) mi.fullrandom = False; + mi->xlmft->hack_init (mi); - ammann = get_boolean_resource ("ammann", "Boolean"); - if (ammann) mi.fullrandom = False; + return mi; +} - jong = get_boolean_resource ("jong", "Boolean"); - if (jong) mi.fullrandom = False; +static unsigned long +xlockmore_draw (Display *dpy, Window window, void *closure) +{ + ModeInfo *mi = (ModeInfo *) closure; - sine = get_boolean_resource ("sine", "Boolean"); - if (sine) mi.fullrandom = False; -#endif + unsigned long orig_pause = mi->pause; + unsigned long this_pause; - mi.threed = get_boolean_resource ("use3d", "Boolean"); - mi.threed_delta = get_float_resource ("delta3d", "Boolean"); - mi.threed_right_color = get_pixel_resource ("right3d", "Color", dpy, - mi.xgwa.colormap); - mi.threed_left_color = get_pixel_resource ("left3d", "Color", dpy, - mi.xgwa.colormap); - mi.threed_both_color = get_pixel_resource ("both3d", "Color", dpy, - mi.xgwa.colormap); - mi.threed_none_color = get_pixel_resource ("none3d", "Color", dpy, - mi.xgwa.colormap); + mi->xlmft->hack_draw (mi); - mi.wireframe_p = get_boolean_resource ("wireframe", "Boolean"); - mi.root_p = (window == RootWindowOfScreen (mi.xgwa.screen)); + this_pause = mi->pause; + mi->pause = orig_pause; + return this_pause; +} - if (mi.pause < 0) - mi.pause = 0; - else if (mi.pause > 100000000) - mi.pause = 100000000; - orig_pause = mi.pause; +static void +xlockmore_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + ModeInfo *mi = (ModeInfo *) closure; + if (mi && mi->xlmft->hack_reshape) + { + XGetWindowAttributes (dpy, window, &mi->xgwa); + mi->xlmft->hack_reshape (mi, mi->xgwa.width, mi->xgwa.height); + } +} - xlockmore_read_resources (); +static Bool +xlockmore_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + ModeInfo *mi = (ModeInfo *) closure; + if (mi && mi->xlmft->hack_handle_events) + return mi->xlmft->hack_handle_events (mi, event); + else + return False; +} - XClearWindow (dpy, window); +void +xlockmore_do_fps (Display *dpy, Window w, fps_state *fpst, void *closure) +{ + ModeInfo *mi = (ModeInfo *) closure; + fps_compute (fpst, 0, mi ? mi->recursion_depth : -1); + fps_draw (fpst); +} - i = 0; - start = time((time_t) 0); - hack_init (&mi); - do { - hack_draw (&mi); - XSync(dpy, False); - if (mi.pause) - usleep(mi.pause); - mi.pause = orig_pause; +static void +xlockmore_free (Display *dpy, Window window, void *closure) +{ + /* Most of the xlockmore/GL hacks don't have `free' functions, and of + those that do have them, they're incomplete or buggy. So, fuck it. + Under X11, we're about to exit anyway, and it doesn't matter. + On OSX, we'll leak a little. Beats crashing. + */ +#if 0 + ModeInfo *mi = (ModeInfo *) closure; + if (mi->xlmft->hack_free) + mi->xlmft->hack_free (mi); - if (hack_free) - { - if (i++ > (mi.batchcount / 4) && - (start + 5) < (now = time((time_t) 0))) - { - i = 0; - start = now; - hack_free (&mi); - hack_init (&mi); - XSync(dpy, False); - } - } + XFreeGC (dpy, mi->gc); + free_colors (dpy, mi->xgwa.colormap, mi->colors, mi->npixels); + free (mi->colors); + free (mi->pixels); - } while (1); + free (mi); +#endif } +