/* -*- Mode: C; tab-width: 4 -*- */ /* lisa --- animated full-loop lissajous figures */ #if 0 static const char sccsid[] = "@(#)lisa.c 5.00 2000/11/01 xlockmore"; #endif /*- * Copyright (c) 1997, 2006 by Caleb Cullen. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation. * * This file is provided AS IS with no warranties of any kind. The author * shall have no liability with respect to the infringement of copyrights, * trade secrets or any patents by this file or any part thereof. In no * event will the author be liable for any lost revenue or profits or * other special, indirect and consequential damages. * * Revision History: * 23-Feb-2006: fixed color-cycling issues * 01-Nov-2000: Allocation checks * 10-May-1997: Compatible with xscreensaver * * The inspiration for this program, Lasp, was written by Adam B. Roach * in 1990, assisted by me, Caleb Cullen. It was written first in C, then * in assembly, and used pre-calculated data tables to graph lissajous * figures on 386 machines and lower. This version bears only superficial * resemblances to the original Lasp. * * The `lissie' module's source code was studied as an example of how * to incorporate a new module into xlock. Resemblances to it are * expected, but not intended to be plaigiaristic. * * February, 2006: 21st Century Update for Lisa * + fixed color-mapping: the 'beginning' of the loop always uses the * same (starting) pixel value, causing the loop's coloration to * appear solid rather than flickering as in the previous version * + all lines/points in a single color are drawn at once using XDrawLines() * or XDrawPoints(); the artifacting evident in the previous version * has been masked by the use of CapNotLast to separate individual drawn * areas with intentional "whitespace" (typically black) * + added many new elements to the Function[] array * + randomized selection of next function * + introduced concept of "rarely-chosen" functions * + cleaned up code somewhat, standardized capitalization, commented all * #directives with block labels */ #ifdef STANDALONE # define MODE_lisa # define DEFAULTS "*delay: 17000 \n" \ "*count: 1 \n" \ "*cycles: 768 \n" \ "*size: 500 \n" \ "*ncolors: 64 \n" \ "*fpsSolid: true \n" \ "*lowrez: True \n" \ # define UNIFORM_COLORS # define release_lisa 0 # define reshape_lisa 0 # define lisa_handle_event xlockmore_no_events # include "xlockmore.h" /* in xscreensaver distribution */ #else /* STANDALONE */ #include "xlock.h" /* in xlockmore distribution */ #endif /* STANDALONE */ #ifdef MODE_lisa #define DEF_ADDITIVE "True" static Bool additive; static XrmOptionDescRec opts[] = { {"-additive", ".lisa.additive", XrmoptionNoArg, "True"}, {"+additive", ".lisa.additive", XrmoptionNoArg, "False"} }; static argtype vars[] = { {&additive, "additive", "Additive", DEF_ADDITIVE, t_Bool} }; static OptionStruct desc[] = { {"-/+additive", "turn on/off additive functions mode"} }; ENTRYPOINT ModeSpecOpt lisa_opts = {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc}; #ifdef USE_MODULES ModStruct lisa_description = {"lisa", "init_lisa", "draw_lisa", (char *) NULL, "refresh_lisa", "change_lisa", "free_lisa", &lisa_opts, 17000, 1, 768, -1, 64, 1.0, "", "Shows animated lissajous figures", 0, NULL}; #endif #define DRAWLINES 1 /* #define FOLLOW_FUNC_ORDER 1 */ #define TWOLOOPS 1 #define XVMAX 10 /* Maximum velocities */ #define YVMAX 10 #define LISAMAXFUNCS 2 #define NUMSTDFUNCS 28 #define RAREFUNCMIN 25 #define RAREFUNCODDS 4 /* 1:n chance a rare function will be re-randomized */ #define MAXCYCLES 3 #define MINLISAS 1 #define STARTCOLOR 0 #define STARTFUNC 24 /* if negative, is upper-bound on randomization */ #define LINEWIDTH -8 /* if negative, is upper-bound on randomization */ #define LINESTYLE LineSolid /* an insane man might have fun with this :) */ #define LINECAP CapNotLast /* anything else looks pretty crappy */ #define LINEJOIN JoinBevel /* this ought to be fastest */ #define SET_COLOR() \ if (MI_NPIXELS(mi) > 2) { \ XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_PIXEL(mi, loop->color)); \ if (loop->cstep \ && pctr % loop->cstep == 0 \ && ++(loop->color) >= (unsigned) MI_NPIXELS(mi)) \ { loop->color=STARTCOLOR; } \ } else { XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi)); } #define GET_RADIUS(context) \ ((context->width > context->height)?context->height:context->width) * 3 / 8 #define CHECK_RADIUS(loop, context) \ if ((context->height / 2 > MI_SIZE(mi)) && (context->width / 2 > MI_SIZE(mi))) \ loop->radius = MI_SIZE(mi); \ if ((loop->radius < 0) || \ (loop->radius > loop->center.x) || \ (loop->radius > loop->center.y)) loop->radius = GET_RADIUS(context) #define PRINT_FUNC(funcptr) \ printf("new function -- #%d:\n\tx = sin(%gs) * sin(%gs)\n\ty = sin(%gt) * sin(%gt)\n", \ funcptr->index, \ funcptr->xcoeff[0], funcptr->xcoeff[1], \ funcptr->ycoeff[0], funcptr->ycoeff[1]) typedef struct lisafunc_struct { double xcoeff[2], ycoeff[2]; int nx, ny; int index; } lisafuncs; typedef struct lisa_struct { unsigned long color; int radius, dx, dy, nsteps, nfuncs, melting, cstep; double pistep, phi, theta; XPoint center, *lastpoint; lisafuncs *function[LISAMAXFUNCS]; int linewidth; } lisas; typedef struct lisacontext_struct { lisas *lissajous; int width, height, nlissajous, loopcount; int maxcycles; Bool painted; } lisacons; static lisacons *Lisa = (lisacons *) NULL; static lisafuncs Function[NUMSTDFUNCS] = { { {1.0, 2.0}, {1.0, 2.0}, 2, 2, 0}, { {1.0, 2.0}, {1.0, 1.0}, 2, 2, 1}, { {1.0, 3.0}, {1.0, 2.0}, 2, 2, 2}, { {1.0, 3.0}, {1.0, 3.0}, 2, 2, 3}, { {2.0, 4.0}, {1.0, 2.0}, 2, 2, 4}, { {1.0, 4.0}, {1.0, 3.0}, 2, 2, 5}, { {1.0, 4.0}, {1.0, 4.0}, 2, 2, 6}, { {1.0, 5.0}, {1.0, 5.0}, 2, 2, 7}, { {2.0, 5.0}, {2.0, 5.0}, 2, 2, 8}, { {1.0, 2.0}, {2.0, 5.0}, 2, 2, 9}, { {1.0, 2.0}, {3.0, 5.0}, 2, 2, 10}, { {1.0, 2.0}, {2.0, 3.0}, 2, 2, 11}, { {1.0, 3.0}, {2.0, 3.0}, 2, 2, 12}, { {2.0, 3.0}, {1.0, 3.0}, 2, 2, 13}, { {2.0, 4.0}, {1.0, 3.0}, 2, 2, 14}, { {1.0, 4.0}, {2.0, 3.0}, 2, 2, 15}, { {2.0, 4.0}, {2.0, 3.0}, 2, 2, 16}, { {1.0, 5.0}, {2.0, 3.0}, 2, 2, 17}, { {2.0, 5.0}, {2.0, 3.0}, 2, 2, 18}, { {1.0, 5.0}, {2.0, 5.0}, 2, 2, 19}, { {1.0, 3.0}, {2.0, 7.0}, 2, 2, 20}, { {2.0, 3.0}, {5.0, 7.0}, 2, 2, 21}, { {1.0, 2.0}, {3.0, 7.0}, 2, 2, 22}, { {2.0, 5.0}, {5.0, 7.0}, 2, 2, 23}, { {5.0, 7.0}, {5.0, 7.0}, 2, 2, 24}, { /* functions past here are 'rare' and won't */ {2.0, 7.0}, /* show up as often. tweak the #defines above */ {1.0, 7.0}, 2, 2, 25}, /* to see them more frequently */ { {2.0, 9.0}, {1.0, 7.0}, 2, 2, 26}, { {5.0, 11.0}, {2.0, 9.0}, 2, 2, 27} }; int xMaxLines; ENTRYPOINT void free_lisa(ModeInfo * mi) { lisacons *lc = &Lisa[MI_SCREEN(mi)]; while (lc->lissajous) { int lctr; for (lctr = 0; lctr < lc->nlissajous; lctr++) { (void) free((void *) lc->lissajous[lctr].lastpoint); } (void) free((void *) lc->lissajous); lc->lissajous = (lisas *) NULL; } } static Bool drawlisa(ModeInfo * mi, lisas * loop) { XPoint *np; XPoint *lp = loop->lastpoint; lisacons *lc = &Lisa[MI_SCREEN(mi)]; lisafuncs **lf = loop->function; int phase = lc->loopcount % loop->nsteps; int pctr, fctr, xctr, yctr, extra_points; double xprod, yprod, xsum, ysum; /* why carry this around in the struct when we can calculate it on demand? */ extra_points = loop->cstep - (loop->nsteps % loop->cstep); /* Allocate the np (new point) array (with padding) */ if ((np = (XPoint *) calloc(loop->nsteps+extra_points, sizeof (XPoint))) == NULL) { free_lisa(mi); return False; } /* Update the center */ loop->center.x += loop->dx; loop->center.y += loop->dy; CHECK_RADIUS(loop, lc); /* check for overlaps -- where the figure might go off the screen */ if ((loop->center.x - loop->radius) <= 0) { loop->center.x = loop->radius; loop->dx = NRAND(XVMAX); } else if ((loop->center.x + loop->radius) >= lc->width) { loop->center.x = lc->width - loop->radius; loop->dx = -NRAND(XVMAX); }; if ((loop->center.y - loop->radius) <= 0) { loop->center.y = loop->radius; loop->dy = NRAND(YVMAX); } else if ((loop->center.y + loop->radius) >= lc->height) { loop->center.y = lc->height - loop->radius; loop->dy = -NRAND(YVMAX); }; /* Now draw the points, and erase the ones from the last cycle */ for (pctr = 0; pctr < loop->nsteps; pctr++) { fctr = loop->nfuncs; loop->phi = (double) (pctr - phase) * loop->pistep; loop->theta = (double) (pctr + phase) * loop->pistep; xsum = ysum = 0; while (fctr--) { xctr = lf[fctr]->nx; yctr = lf[fctr]->ny; if (additive) { xprod = yprod = 0.0; while (xctr--) xprod += sin(lf[fctr]->xcoeff[xctr] * loop->theta); while (yctr--) yprod += sin(lf[fctr]->ycoeff[yctr] * loop->phi); if (loop->melting) { if (fctr) { xsum += xprod * (double) (loop->nsteps - loop->melting) / (double) loop->nsteps; ysum += yprod * (double) (loop->nsteps - loop->melting) / (double) loop->nsteps; } else { xsum += xprod * (double) loop->melting / (double) loop->nsteps; ysum += yprod * (double) loop->melting / (double) loop->nsteps; } } else { xsum = xprod; ysum = yprod; } if (!fctr) { xsum = xsum * (double) loop->radius / (double) lf[fctr]->nx; ysum = ysum * (double) loop->radius / (double) lf[fctr]->ny; } } else { if (loop->melting) { if (fctr) { yprod = xprod = (double) loop->radius * (double) (loop->nsteps - loop->melting) / (double) (loop->nsteps); } else { yprod = xprod = (double) loop->radius * (double) (loop->melting) / (double) (loop->nsteps); } } else { xprod = yprod = (double) loop->radius; } while (xctr--) xprod *= sin(lf[fctr]->xcoeff[xctr] * loop->theta); while (yctr--) yprod *= sin(lf[fctr]->ycoeff[yctr] * loop->phi); xsum += xprod; ysum += yprod; } } if ((loop->nfuncs > 1) && (!loop->melting)) { xsum /= (double) loop->nfuncs; ysum /= (double) loop->nfuncs; } xsum += (double) loop->center.x; ysum += (double) loop->center.y; np[pctr].x = (int) ceil(xsum); np[pctr].y = (int) ceil(ysum); } /* fill in extra points */ for (pctr=loop->nsteps; pctr < loop->nsteps+extra_points; pctr++) { np[pctr].x = np[pctr - loop->nsteps].x; np[pctr].y = np[pctr - loop->nsteps].y; } if (loop->melting) { if (!--loop->melting) { loop->nfuncs = 1; loop->function[0] = loop->function[1]; } } /* reset starting color each time to prevent ass-like appearance */ loop->color = STARTCOLOR; if (loop->cstep < xMaxLines) { /* printf("Drawing dashes\n"); */ for (pctr = 0; pctr < loop->nsteps; pctr+=loop->cstep) { #if defined DRAWLINES XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), loop->linewidth, LINESTYLE, LINECAP, LINEJOIN); /* erase the last cycle's point */ XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); XDrawLines(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), &lp[pctr], loop->cstep, CoordModeOrigin); /* Set the new color */ SET_COLOR(); /* plot this cycle's point */ XDrawLines(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), &np[pctr], loop->cstep, CoordModeOrigin); XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), 1, LINESTYLE, LINECAP, LINEJOIN); #else /* erase the last cycle's point */ XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); XDrawPoints(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), &lp[pctr], loop->cstep, CoordModeOrigin); /* Set the new color */ SET_COLOR(); /* plot this cycle's point */ XDrawPoints(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), &np[pctr], loop->cstep, CoordModeOrigin); #endif } } else { /* on my system, cstep is larger than 65532/2 if we get here */ for (pctr = 0; pctr < loop->nsteps; pctr++) { #if defined DRAWLINES XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), loop->linewidth, LINESTYLE, LINECAP, LINEJOIN); /* erase the last cycle's point */ XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), lp[pctr].x, lp[pctr].y, lp[(pctr + 1) % loop->nsteps].x, lp[(pctr + 1) % loop->nsteps].y); /* Set the new color */ SET_COLOR(); /* plot this cycle's point */ XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), np[pctr].x, np[pctr].y, np[(pctr + 1) % loop->nsteps].x, np[(pctr + 1) % loop->nsteps].y); XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), 1, LINESTYLE, LINECAP, LINEJOIN); #else /* DRAWLINES */ /* erase the last cycle's point */ XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), lp[pctr].x, lp[pctr].y); /* Set the new color */ SET_COLOR(); /* plot this cycle's point */ XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), np[pctr].x, np[pctr].y); #endif /* DRAWLINES */ } } (void) free((void *) lp); loop->lastpoint = np; return True; } static Bool initlisa(ModeInfo * mi, lisas * loop) { lisacons *lc = &Lisa[MI_SCREEN(mi)]; lisafuncs **lf = loop->function; XPoint *lp; int phase, pctr, fctr, xctr, yctr, extra_points; double xprod, yprod, xsum, ysum; xMaxLines = (XMaxRequestSize(MI_DISPLAY(mi))-3)/2; /* printf("Got xMaxLines = %d\n", xMaxLines); */ loop->nsteps = MI_CYCLES(mi); if (loop->nsteps == 0) loop->nsteps = 1; if (MI_NPIXELS(mi) > 2) { loop->color = STARTCOLOR; loop->cstep = (loop->nsteps > MI_NPIXELS(mi)) ? loop->nsteps / MI_NPIXELS(mi) : 1; } else { loop->color = MI_WHITE_PIXEL(mi); loop->cstep = 0; } extra_points = loop->cstep - (loop->nsteps % loop->cstep); lc->maxcycles = (MAXCYCLES * loop->nsteps) - 1; loop->cstep = ( loop->nsteps > MI_NPIXELS(mi) ) ? loop->nsteps / MI_NPIXELS(mi) : 1; /* printf("Got cstep = %d\n", loop->cstep); */ loop->melting = 0; loop->nfuncs = 1; loop->pistep = 2.0 * M_PI / (double) loop->nsteps; loop->center.x = lc->width / 2; loop->center.y = lc->height / 2; loop->radius = (int) MI_SIZE(mi); CHECK_RADIUS(loop, lc); loop->dx = NRAND(XVMAX); loop->dy = NRAND(YVMAX); loop->dx++; loop->dy++; #if defined STARTFUNC lf[0] = &Function[STARTFUNC]; #else /* STARTFUNC */ lf[0] = &Function[NRAND(NUMSTDFUNCS)]; #endif /* STARTFUNC */ if ((lp = loop->lastpoint = (XPoint *) calloc(loop->nsteps+extra_points, sizeof (XPoint))) == NULL) { free_lisa(mi); return False; } phase = lc->loopcount % loop->nsteps; #if defined DEBUG printf( "nsteps = %d\tcstep = %d\tmrs = %d\textra_points = %d\n", loop->nsteps, loop->cstep, xMaxLines, extra_points ); PRINT_FUNC(lf[0]); #endif /* DEBUG */ for (pctr = 0; pctr < loop->nsteps; pctr++) { loop->phi = (double) (pctr - phase) * loop->pistep; loop->theta = (double) (pctr + phase) * loop->pistep; fctr = loop->nfuncs; xsum = ysum = 0.0; while (fctr--) { xprod = yprod = (double) loop->radius; xctr = lf[fctr]->nx; yctr = lf[fctr]->ny; while (xctr--) xprod *= sin(lf[fctr]->xcoeff[xctr] * loop->theta); while (yctr--) yprod *= sin(lf[fctr]->ycoeff[yctr] * loop->phi); xsum += xprod; ysum += yprod; } if (loop->nfuncs > 1) { xsum /= 2.0; ysum /= 2.0; } xsum += (double) loop->center.x; ysum += (double) loop->center.y; lp[pctr].x = (int) ceil(xsum); lp[pctr].y = (int) ceil(ysum); } /* this fills in the extra points, so we can use segment-drawing calls */ for (pctr = loop->nsteps; pctr < loop->nsteps + extra_points; pctr++) { lp[pctr].x=lp[pctr - loop->nsteps].x; lp[pctr].y=lp[pctr - loop->nsteps].y; } #if defined DRAWLINES loop->linewidth = LINEWIDTH; /* #### make this a resource */ if (loop->linewidth == 0) loop->linewidth = 1; if (loop->linewidth < 0) loop->linewidth = NRAND(-loop->linewidth) + 1; XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), loop->linewidth, LINESTYLE, LINECAP, LINEJOIN); #endif /* DRAWLINES */ if ( loop->cstep < xMaxLines ) { /* we can send each color segment in a single request * because the max request length is long enough * and because we have padded out the array to have extra elements * to support calls which would otherwise fall off the end*/ for (pctr = 0; pctr < loop->nsteps; pctr+=loop->cstep) { /* Set the color */ SET_COLOR(); #if defined DRAWLINES XDrawLines(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), &lp[pctr], loop->cstep, CoordModeOrigin ); #else /* DRAWLINES */ XDrawPoints(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), &lp[pctr], loop->cstep, CoordModeOrigin ); #endif /* DRAWLINES */ } } else { /* do it one by one as before */ for (pctr = 0; pctr < loop->nsteps; pctr++ ) { SET_COLOR(); #if defined DRAWLINES XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), lp[pctr].x, lp[pctr].y, lp[pctr+1 % loop->nsteps].x, lp[pctr+1 % loop->nsteps].y); #else /* DRAWLINES */ XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), lp[pctr].x, lp[pctr].y); #endif /* DRAWLINES */ } } #if defined DRAWLINES XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), 1, LINESTYLE, LINECAP, LINEJOIN); #endif /* DRAWLINES */ return True; } static void refreshlisa(ModeInfo * mi) { lisacons *lc = &Lisa[MI_SCREEN(mi)]; int lctr; for (lctr = 0; lctr < lc->nlissajous; lctr++) { if (!drawlisa(mi, &lc->lissajous[lctr])) return; } } #ifndef STANDALONE ENTRYPOINT void refresh_lisa(ModeInfo * mi) { lisacons *lc; if (Lisa == NULL) return; lc = &Lisa[MI_SCREEN(mi)]; if (lc->lissajous == NULL) return; if (lc->painted) { lc->painted = False; MI_CLEARWINDOW(mi); refreshlisa(mi); } } #endif static void change_lisa(ModeInfo * mi) { lisas *loop; int lctr, newfunc; lisacons *lc; if (Lisa == NULL) return; lc = &Lisa[MI_SCREEN(mi)]; if (lc->lissajous == NULL) return; lc->loopcount = 0; for (lctr = 0; lctr < lc->nlissajous; lctr++) { loop = &lc->lissajous[lctr]; /* count through the loops we're drawing */ newfunc = NRAND(NUMSTDFUNCS); /* choose a new function at random */ #if defined FOLLOW_FUNC_ORDER loop->function[1] = &Function[(loop->function[0]->index + 1) % NUMSTDFUNCS]; #else /* FOLLOW_FUNC_ORDER */ if (newfunc == loop->function[0]->index) { ++newfunc; newfunc %= NUMSTDFUNCS; /* take the next if we got the one we have */ } if (newfunc >= RAREFUNCMIN \ && !(random() % RAREFUNCODDS) \ && (newfunc = NRAND(NUMSTDFUNCS)) == loop->function[0]->index) { ++newfunc; newfunc %= NUMSTDFUNCS; } loop->function[1] = /* set 2nd function pointer on the loop */ &Function[newfunc]; /* to the new function we just chose */ #endif /* FOLLOW_FUNC_ORDER */ #if defined DEBUG PRINT_FUNC(loop->function[1]); #endif /* DEBUG */ loop->melting = loop->nsteps - 1; /* melt the two functions together */ loop->nfuncs = 2; /* simultaneously for a full cycle */ } } ENTRYPOINT void init_lisa (ModeInfo * mi) { int lctr; lisacons *lc; MI_INIT (mi, Lisa); lc = &Lisa[MI_SCREEN(mi)]; lc->width = MI_WIDTH(mi); lc->height = MI_HEIGHT(mi); lc->loopcount = 0; lc->nlissajous = MI_COUNT(mi); if (lc->nlissajous <= 0) lc->nlissajous = 1; MI_CLEARWINDOW(mi); lc->painted = False; if (lc->lissajous == NULL) { if ((lc->lissajous = (lisas *) calloc(lc->nlissajous, sizeof (lisas))) == NULL) return; for (lctr = 0; lctr < lc->nlissajous; lctr++) { if (!initlisa(mi, &lc->lissajous[lctr])) return; lc->loopcount++; } } else { refreshlisa(mi); } } ENTRYPOINT void draw_lisa (ModeInfo * mi) { lisacons *lc; if (Lisa == NULL) return; lc = &Lisa[MI_SCREEN(mi)]; if (lc->lissajous == NULL) return; #ifdef HAVE_JWXYZ /* Don't second-guess Quartz's double-buffering */ XClearWindow (MI_DISPLAY(mi), MI_WINDOW(mi)); #endif MI_IS_DRAWN(mi) = True; lc->painted = True; if (++lc->loopcount > lc->maxcycles) { change_lisa(mi); } refreshlisa(mi); } XSCREENSAVER_MODULE ("Lisa", lisa) #endif /* MODE_lisa */