home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume18 / xsplinefun / part01 / xsplinefun.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-14  |  17.1 KB  |  762 lines

  1. /* xsplinefun.c - X11 version of spline fun #3
  2. **
  3. ** Displays colorful moving splines in the X11 root window.
  4. **
  5. ** Copyright (C) 1992 by Jef Poskanzer
  6. **
  7. ** Permission to use, copy, modify, and distribute this software and its
  8. ** documentation for any purpose and without fee is hereby granted, provided
  9. ** that the above copyright notice appear in all copies and that both that
  10. ** copyright notice and this permission notice appear in supporting
  11. ** documentation.  This software is provided "as is" without express or
  12. ** implied warranty.
  13. */
  14.  
  15. #include <stdio.h>
  16. #include <errno.h>
  17. #include <malloc.h>
  18. #include <signal.h>
  19. #include <pwd.h>
  20. #include <sys/types.h>
  21. #include <sys/time.h>
  22. #include <sys/ioctl.h>
  23.  
  24. #if defined(SYSV) || defined(SVR4)
  25. #include <string.h>
  26. #define index strchr
  27. #include <sys/termio.h>
  28. #else /*SYSV*/
  29. #include <strings.h>
  30. #endif /*SYSV*/
  31.  
  32. #include <X11/Xlib.h>
  33. #include <X11/Xutil.h>
  34. #include <X11/Xatom.h>
  35. #include <X11/Xresource.h>
  36. #define XTSTRINGDEFINES
  37. #include <X11/StringDefs.h>
  38.  
  39.  
  40. /* Definitions. */
  41.  
  42. #define X_CLASS "Xsplinefun"
  43.  
  44. #define DEFAULT_MAX_COLORS 256
  45. #define DEFAULT_LOOPS_PER_SECOND 50
  46.  
  47. #define MIN_COLORS 4
  48. #define INITIAL_LOOPS_PER_SLEEP 10
  49. #define MIN_LOOPS_PER_SLEEP 1
  50. #define INITIAL_SLEEP_USECS 100000
  51. #define MIN_SLEEP_USECS 50000
  52.  
  53. #define POINTS 5
  54. #define MAX_DELTA 3
  55. #define MAX_COLOR_DELTA (3*256)
  56.  
  57. #define SPLINE_THRESH 5
  58.  
  59.  
  60. /* Externals. */
  61.  
  62. extern char* getenv();
  63. extern long random();
  64.  
  65.  
  66. /* Forward routines. */
  67.  
  68. static void x_init();
  69. static void x_alloc_colors();
  70. static void x_cleanup();
  71. static Window VirtualRootWindowOfScreen();
  72. static void x_rdb_init();
  73. static char* x_get_resource();
  74. static int x_str_to_bool();
  75. static void stealth();
  76. static void main_loop();
  77. static void sigcatch();
  78. static void init_timing();
  79. static void timing();
  80. static void init_splines();
  81. static void rotate_colormap();
  82. static void new_color();
  83. static void move_splines();
  84. static void XDrawSpline();
  85.  
  86.  
  87. /* Routines. */
  88.  
  89. static char* argv0;
  90. static char* app_name;
  91. static int forwards, backwards;
  92. static int max_colors;
  93. static int loops_per_second;
  94.  
  95. static int loops_per_sleep;
  96. static int sleep_usecs;
  97.  
  98. void
  99. main( argc, argv )
  100.     int argc;
  101.     char* argv[];
  102.     {
  103.     char* rval;
  104.     char* usage = "usage: %s [-display d] [-forwards|-backwards] [-maxcolors n] [-loops n] [-id]\n";
  105.  
  106.     argv0 = argv[0];
  107.     app_name = "xsplinefun";
  108.     forwards = backwards = False;
  109.     max_colors = DEFAULT_MAX_COLORS;
  110.     loops_per_second = DEFAULT_LOOPS_PER_SECOND;
  111.     loops_per_sleep = INITIAL_LOOPS_PER_SLEEP;
  112.     sleep_usecs = INITIAL_SLEEP_USECS;
  113.  
  114.     /* Parse args and initialize X stuff. */
  115.     x_init( &argc, argv );
  116.  
  117.     /* Check usage. */
  118.     if ( argc != 1 )
  119.     {
  120.     (void) fprintf( stderr, usage, argv[0] );
  121.     exit( 1 );
  122.     }
  123.  
  124.     /* Check rotation. */
  125.     rval = x_get_resource( "rotation", "Rotation" );
  126.     if ( rval != (char*) 0 )
  127.     if ( rval[0] == 'f' || rval[0] == 'F' )
  128.         forwards = True;
  129.     else if ( rval[0] == 'b' || rval[0] == 'B' )
  130.         backwards = True;
  131.  
  132.     /* Check max colors. */
  133.     rval = x_get_resource( "maxcolors", "Maxcolors" );
  134.     if ( rval != (char*) 0 )
  135.     max_colors = atoi(rval);
  136.     x_alloc_colors();
  137.  
  138.     /* Check loops. */
  139.     rval = x_get_resource( "loops", "Loops" );
  140.     if ( rval != (char*) 0 )
  141.     loops_per_second = atoi(rval);
  142.  
  143.     /* Initialize the random number generator. */
  144.     srandom( (int) ( time( (long*) 0 ) ^ getpid() ) );
  145.  
  146.     /* Initialize the splines. */
  147.     init_splines();
  148.  
  149.     /* Fork, if necessary. */
  150.     rval = x_get_resource( "id", "Id" );
  151.     if ( rval != (char*) 0 )
  152.     if ( x_str_to_bool( rval ) )
  153.         stealth();
  154.  
  155.     /* Main loop. */
  156.     main_loop();
  157.     
  158.     /* Done. */
  159.     x_cleanup();
  160.     exit( 0 );
  161.     }
  162.  
  163.  
  164. /* X stuff. */
  165.  
  166. static Display* display = (Display*) 0;
  167. static int screennum;
  168. static Screen* screen;
  169. static Window root;
  170. static int width, height;
  171. static int depth;
  172. static GC gc;
  173. static Colormap cmap;
  174. static int ncolors;
  175. static unsigned long pixels[DEFAULT_MAX_COLORS];
  176.  
  177. static void
  178. x_init( argcP, argv )
  179.     int* argcP;
  180.     char** argv;
  181.     {
  182.     char* display_name;
  183.     char* rval;
  184.     int i, d;
  185.  
  186.     /* Scan args looking for -display. */
  187.     display_name = (char*) 0;
  188.     for ( i = 1; i + 1 < *argcP; ++i )
  189.     {
  190.     if ( strcmp( argv[i], "-display" ) == 0 ||
  191.          strcmp( argv[i], "-displa" ) == 0 ||
  192.          strcmp( argv[i], "-displ" ) == 0 ||
  193.          strcmp( argv[i], "-disp" ) == 0 ||
  194.          strcmp( argv[i], "-dis" ) == 0 ||
  195.          strcmp( argv[i], "-di" ) == 0 ||
  196.          strcmp( argv[i], "-d" ) == 0 )
  197.         {
  198.         display_name = argv[i + 1];
  199.         for ( i = i + 2; i <= *argcP; ++i )
  200.         argv[i - 2] = argv[i];
  201.         *argcP -= 2;
  202.         break;
  203.         }
  204.     }
  205.  
  206.     display = XOpenDisplay( display_name );
  207.     if ( display == (Display*) 0 )
  208.     {
  209.     (void) fprintf(
  210.         stderr, "%s: can't open display \"%s\"\n", argv0,
  211.         XDisplayName( display_name ) );
  212.     exit( 1 );
  213.     }
  214.  
  215.     screennum = DefaultScreen( display );
  216.     screen = ScreenOfDisplay( display, DefaultScreen( display ) );
  217.     root = VirtualRootWindowOfScreen( screen );
  218.     width = WidthOfScreen( screen );
  219.     height = HeightOfScreen( screen );
  220.     depth = DefaultDepthOfScreen( screen );
  221.     if ( depth <= 1 )
  222.     {
  223.     (void) fprintf(
  224.         stderr, "%s: screen depth must be greater than 1\n", argv0 );
  225.     exit( 1 );
  226.     }
  227.     gc = XCreateGC( display, root, 0, (XGCValues*) 0 );
  228.     cmap = DefaultColormapOfScreen( screen );
  229.  
  230.     x_rdb_init( argcP, argv );
  231.  
  232.     rval = x_get_resource( XtNname, "Name" );
  233.     if ( rval != (char*) 0 )
  234.     app_name = rval;
  235.  
  236.     rval = x_get_resource( "synchronous", "Synchronous" );
  237.     if ( rval != (char*) 0 )
  238.     if ( x_str_to_bool( rval ) )
  239.         XSynchronize( display, True );
  240.     }
  241.  
  242. static void
  243. x_alloc_colors()
  244.     {
  245.     for ( ncolors = max_colors; ncolors >= MIN_COLORS; --ncolors )
  246.     if ( XAllocColorCells(
  247.         display, cmap, False, (unsigned long*) 0, 0, pixels, ncolors ) )
  248.         break;
  249.     if ( ncolors < MIN_COLORS )
  250.     {
  251.     (void) fprintf( stderr, "%s: can't allocate enough colors\n", argv0 );
  252.     exit( 1 );
  253.     }
  254.     if ( ncolors < max_colors )
  255.     (void) fprintf(
  256.         stderr, "%s: only %d colors available\n", argv0, ncolors );
  257.     }
  258.  
  259. static void
  260. x_cleanup()
  261.     {
  262.     XClearArea( display, root, 0, 0, width, height, True );
  263.     XFreeColors( display, cmap, pixels, ncolors, (unsigned long) 0 );
  264.     XFreeGC( display, gc );
  265.     XCloseDisplay( display );
  266.     }
  267.  
  268.  
  269. /* From vroot.h by Andreas Stolcke. */
  270.  
  271. static Window
  272. VirtualRootWindowOfScreen( screenP )
  273.     Screen* screenP;
  274.     {
  275.     static Window root = (Window) 0;
  276.     Display* dpy = DisplayOfScreen( screenP );
  277.     Atom __SWM_VROOT = None;
  278.     int i;
  279.     Window rootReturn, parentReturn;
  280.     Window* children;
  281.     unsigned int numChildren;
  282.  
  283.     root = RootWindowOfScreen( screenP );
  284.  
  285.     /* Go look for a virtual root. */
  286.     __SWM_VROOT = XInternAtom( dpy, "__SWM_VROOT", False );
  287.     if ( XQueryTree(
  288.          dpy, root, &rootReturn, &parentReturn, &children,
  289.          &numChildren ) )
  290.     {
  291.     for ( i = 0; i < numChildren; ++i )
  292.         {
  293.         Atom actual_type;
  294.         int actual_format;
  295.         unsigned long nitems, bytesafter;
  296.         Window* newRoot = (Window*) 0;
  297.  
  298.         if ( XGetWindowProperty(
  299.              dpy, children[i], __SWM_VROOT, 0, 1, False, XA_WINDOW,
  300.              &actual_type, &actual_format, &nitems, &bytesafter,
  301.              (unsigned char**) &newRoot ) == Success && newRoot )
  302.         {
  303.         root = *newRoot;
  304.         break;
  305.         }
  306.         }
  307.     if ( children )
  308.         XFree( (char*) children );
  309.     }
  310.  
  311.     return root;
  312.     }
  313.  
  314.  
  315. /* X resources stuff. */
  316.  
  317. static XrmDatabase rdb;
  318.  
  319. static XrmOptionDescRec x_options[] = {
  320.     { "-forwards",       "*rotation",       XrmoptionNoArg,  (caddr_t) "f" },
  321.     { "-backwards",      "*rotation",       XrmoptionNoArg,  (caddr_t) "b" },
  322.     { "-maxcolors",      "*maxcolors",      XrmoptionSepArg, (caddr_t) 0 },
  323.     { "-loops",          "*loops",          XrmoptionSepArg, (caddr_t) 0 },
  324.     { "-id",             "*id",             XrmoptionNoArg,  (caddr_t) "on" },
  325.     { "-name",           ".name",           XrmoptionSepArg, (caddr_t) 0 },
  326.     { "-synchronous",    "*synchronous",    XrmoptionNoArg,  (caddr_t) "on" },
  327.     { "-xrm",            (char*) 0,         XrmoptionResArg, (caddr_t) 0 },
  328.     };
  329.  
  330. static void
  331. x_rdb_init( argcP, argv )
  332.     int* argcP;
  333.     char** argv;
  334.     {
  335.     char* resource_string;
  336.     char* xenv;
  337.     XrmDatabase xenv_rdb;
  338.  
  339.     XrmInitialize();
  340.  
  341.     /* Look for resource databases on server. */
  342.     resource_string = XResourceManagerString( display );
  343.     if ( resource_string != (char*) 0 )
  344.     rdb = XrmGetStringDatabase( resource_string );
  345.     else
  346.     {
  347.     /* No server databases, try ~/.Xdefaults */
  348.     char* cp;
  349.     char buf[500];
  350.  
  351.     cp = getenv( "HOME" );
  352.     if ( cp != (char*) 0 )
  353.         (void) strcpy( buf, cp );
  354.     else
  355.         {
  356.         struct passwd* pw;
  357.  
  358.         cp = getenv( "USER" );
  359.         if ( cp != (char*) 0 )
  360.         pw = getpwnam( cp );
  361.         else
  362.         pw = getpwuid( getuid() );
  363.         if ( pw != (struct passwd*) 0 )
  364.         (void) strcpy( buf, pw->pw_dir );
  365.         else
  366.         (void) strcpy( buf, "." );    /* best we can do */
  367.         }
  368.     (void) strcat( buf, "/.Xdefaults" );
  369.     rdb = XrmGetFileDatabase( buf );
  370.     }
  371.  
  372.     /* Merge in XENVIRONMENT, if any. */
  373.     xenv = getenv( "XENVIRONMENT" );
  374.     if ( xenv != (char*) 0 )
  375.     {
  376.     xenv_rdb = XrmGetFileDatabase( xenv );
  377.     XrmMergeDatabases( xenv_rdb, &rdb );
  378.     }
  379.  
  380.     /* And add command line options. */
  381.     XrmParseCommand(
  382.     &rdb, x_options, sizeof(x_options) / sizeof(*x_options),
  383.     app_name, argcP, argv );
  384.     }
  385.  
  386. static char*
  387. x_get_resource( name, class )
  388.     char* name;
  389.     char* class;
  390.     {
  391.     char rname[500], rclass[500];
  392.     char* type;
  393.     XrmValue value;
  394.  
  395.     (void) sprintf( rname, "%s.%s", app_name, name );
  396.     (void) sprintf( rclass, "%s.%s", X_CLASS, class );
  397.     if ( XrmGetResource( rdb, rname, rclass, &type, &value ) == True )
  398.     if ( strcmp( type, XtRString ) == 0 )
  399.         return (char*) value.addr;
  400.     return (char*) 0;
  401.     }
  402.  
  403. static int
  404. x_str_to_bool( str )
  405.     char* str;
  406.     {
  407.     if ( strcmp( str, "True" ) == 0 ||
  408.          strcmp( str, "true" ) == 0 ||
  409.          strcmp( str, "Yes" ) == 0 ||
  410.          strcmp( str, "yes" ) == 0 ||
  411.          strcmp( str, "On" ) == 0 ||
  412.          strcmp( str, "on" ) == 0 ||
  413.          strcmp( str, "Si" ) == 0 ||
  414.          strcmp( str, "si" ) == 0 ||
  415.          strcmp( str, "Da" ) == 0 ||
  416.          strcmp( str, "da" ) == 0 ||
  417.          strcmp( str, "T" ) == 0 ||
  418.          strcmp( str, "t" ) == 0 ||
  419.          strcmp( str, "Y" ) == 0 ||
  420.          strcmp( str, "y" ) == 0 ||
  421.          strcmp( str, "1" ) == 0 )
  422.     return True;
  423.     return False;
  424.     }
  425.  
  426.  
  427. /* Generic application stuff. */
  428.  
  429. static void
  430. stealth()
  431.     {
  432.     int pid, tty;
  433.  
  434.     pid = fork();
  435.     if ( pid < 0 )
  436.     {
  437.     perror( "fork" );
  438.     exit( 1 );
  439.     }
  440.     else if ( pid > 0 )
  441.     /* Parent just exits. */
  442.     exit( 0 );
  443.     (void) printf( "%d\n", getpid() );
  444.     (void) fflush( stdout );
  445.  
  446.     /* Go stealth (ditch our controlling tty). */
  447.     tty = open( "/dev/tty", 0 );
  448.     if ( tty < 0 )
  449.     {
  450.     /* ENXIO means that there is no controlling terminal, so we don't
  451.     ** have to detach anything.
  452.     */
  453.         if ( errno != ENXIO )
  454.         {
  455.         (void) fprintf( stderr, "%s: ", argv0 );
  456.         perror( "/dev/tty open" );
  457.         exit( 1 );
  458.         }
  459.     }
  460.     else
  461.     {
  462. #ifdef TIOCNOTTY
  463.     if ( ioctl( tty, TIOCNOTTY, 0 ) < 0 )
  464.         {
  465.         (void) fprintf( stderr, "%s: ", argv0 );
  466.         perror( "TIOCNOTTY ioctl" );
  467.         exit( 1 );
  468.         }
  469. #endif /*TIOCNOTTY*/
  470.     (void) close( tty );
  471.     }
  472.     }
  473.  
  474. static int goflag;
  475. static int loops;
  476.  
  477. static void
  478. sigcatch()
  479.     {
  480.     goflag = 0;
  481.     }
  482.  
  483. static int then_loops;
  484. static time_t then;
  485.  
  486. static void
  487. init_timing()
  488.     {
  489.     then = time( (time_t*) 0 );
  490.     then_loops = 0;
  491.     }
  492.  
  493. static void
  494. timing()
  495.     {
  496.     float ratio;
  497.     int t;
  498.     time_t now;
  499.  
  500.     if ( sleep_usecs > 0 && loops_per_sleep > 0 &&
  501.      loops % loops_per_sleep == 0 )
  502.     {
  503.     XFlush( display );
  504.     usleep( sleep_usecs );
  505.     if ( loops_per_second > 0 )
  506.         {
  507.         now = time( (time_t*) 0 );
  508.         if ( now != then )
  509.         {
  510.         if ( then_loops != 0 )
  511.             {
  512.             ratio = (float) ( loops - then_loops ) /
  513.                 (float) loops_per_second;
  514.             if ( ratio > 1.0 )
  515.             {
  516.             /* We're going too fast. */
  517.             t = loops_per_sleep / ratio;
  518.             if ( t >= MIN_LOOPS_PER_SLEEP )
  519.                 loops_per_sleep = t;
  520.             else
  521.                 sleep_usecs *= ratio;
  522.             }
  523.             else if ( ratio < 1.0 )
  524.             {
  525.             /* We're going too slow. */
  526.             t = sleep_usecs * ratio;
  527.             if ( t >= MIN_SLEEP_USECS )
  528.                 sleep_usecs = t;
  529.             else
  530.                 {
  531.                 loops_per_sleep /= ratio;
  532.                 if ( loops_per_sleep > 3 * loops_per_second )
  533.                 loops_per_sleep = 0;    /* give up */
  534.                 }
  535.             }
  536.             }
  537.         then_loops = loops;
  538.         then = now;
  539.         }
  540.         }
  541.     }
  542.     }
  543.  
  544. static void
  545. main_loop()
  546.     {
  547.     /* Set up for signal catching. */
  548.     goflag = 1;
  549.     (void) signal( SIGHUP, sigcatch );
  550.     (void) signal( SIGINT, sigcatch );
  551.     (void) signal( SIGTERM, sigcatch );
  552.  
  553.     /* Do it. */
  554.     for ( loops = 1; goflag; ++loops )
  555.     {
  556.     move_splines();
  557.     timing();
  558.     }
  559.     }
  560.  
  561.  
  562. /* Spline-fun smarts. */
  563.  
  564. static int x[POINTS], y[POINTS], dx[POINTS], dy[POINTS];
  565. static int nred, ngreen, nblue, dred, dgreen, dblue;
  566. static int color;
  567. static XColor xcolors[DEFAULT_MAX_COLORS];
  568.  
  569. static void
  570. init_splines()
  571.     {
  572.     int i;
  573.  
  574.     /* Initialize points. */
  575.     for ( i = 0; i < POINTS; ++i )
  576.     {
  577.     x[i] = random() % width;
  578.     y[i] = random() % height;
  579.     dx[i] = random() % ( MAX_DELTA * 2 ) - MAX_DELTA;
  580.     if ( dx[i] <= 0 ) --dx[i];
  581.     dy[i] = random() % ( MAX_DELTA * 2 ) - MAX_DELTA;
  582.     if ( dy[i] <= 0 ) --dy[i];
  583.     }
  584.  
  585.     /* Initalize colors. */
  586.     for ( color = 0; color < ncolors; ++color )
  587.     {
  588.     xcolors[color].red = xcolors[color].green = xcolors[color].blue = 0;
  589.     xcolors[color].pixel = pixels[color];
  590.     xcolors[color].flags = DoRed|DoGreen|DoBlue;
  591.     }
  592.     color = 0;
  593.     nred = ngreen = nblue = 0;
  594.     dred = random() % ( MAX_COLOR_DELTA * 2 ) - MAX_COLOR_DELTA;
  595.     if ( dred <= 0 ) --dred;
  596.     dgreen = random() % ( MAX_COLOR_DELTA * 2 ) - MAX_COLOR_DELTA;
  597.     if ( dgreen <= 0 ) --dgreen;
  598.     dblue = random() % ( MAX_COLOR_DELTA * 2 ) - MAX_COLOR_DELTA;
  599.     if ( dblue <= 0 ) --dblue;
  600.     }
  601.  
  602. static void
  603. rotate_colormap()
  604.     {
  605.     int t, i;
  606.  
  607.     if ( forwards )
  608.     {
  609.     t = xcolors[0].pixel;
  610.     for ( i = 0; i < ncolors - 1; ++i )
  611.         xcolors[i].pixel = xcolors[i + 1].pixel;
  612.     xcolors[ncolors - 1].pixel = t;
  613.     XStoreColors(display, cmap, xcolors, ncolors );
  614.     }
  615.     else if ( backwards )
  616.     {
  617.     t = xcolors[ncolors - 1].pixel;
  618.     for ( i = ncolors - 1; i > 0; --i )
  619.         xcolors[i].pixel = xcolors[i - 1].pixel;
  620.     xcolors[0].pixel = t;
  621.     XStoreColors(display, cmap, xcolors, ncolors );
  622.     }
  623.     }
  624.  
  625. static void
  626. new_color()
  627.     {
  628.     int t;
  629.  
  630.     for ( ; ; )
  631.     {
  632.     t = (int) nred + dred;
  633.     if ( t >= 0 && t < 65536 ) break;
  634.     dred = random() % ( MAX_COLOR_DELTA * 2 ) - MAX_COLOR_DELTA;
  635.     if ( dred <= 0 ) --dred;
  636.     }
  637.     xcolors[color].red = nred = t;
  638.     for ( ; ; )
  639.     {
  640.     t = (int) ngreen + dgreen;
  641.     if ( t >= 0 && t < 65536 ) break;
  642.     dgreen = random() % ( MAX_COLOR_DELTA * 2 ) - MAX_COLOR_DELTA;
  643.     if ( dgreen <= 0 ) --dgreen;
  644.     }
  645.     xcolors[color].green = ngreen = t;
  646.     for ( ; ; )
  647.     {
  648.     t = (int) nblue + dblue;
  649.     if ( t >= 0 && t < 65536 ) break;
  650.     dblue = random() % ( MAX_COLOR_DELTA * 2 ) - MAX_COLOR_DELTA;
  651.     if ( dblue <= 0 ) --dblue;
  652.     }
  653.     xcolors[color].blue = nblue = t;
  654.     XStoreColor(display, cmap, &(xcolors[color]) );
  655.     XSetForeground( display, gc, xcolors[color].pixel );
  656.     if ( ++color >= ncolors ) color -= ncolors;
  657.     }
  658.  
  659. static void
  660. move_splines()
  661.     {
  662.     int i, t, px, py, zx, zy, nx, ny;
  663.  
  664.     /* Rotate colormap if necessary. */
  665.     rotate_colormap();
  666.  
  667.     /* Choose new color. */
  668.     new_color();
  669.  
  670.     /* Backwards rotation requires two new colors each loop. */
  671.     if ( backwards )
  672.     new_color();
  673.  
  674.     /* Move the points. */
  675.     for ( i = 0; i < POINTS; i++ )
  676.     {
  677.     for ( ; ; )
  678.         {
  679.         t = x[i] + dx[i];
  680.         if ( t >= 0 && t < width ) break;
  681.         dx[i] = random() % ( MAX_DELTA * 2 ) - MAX_DELTA;
  682.         if ( dx[i] <= 0 ) --dx[i];
  683.         }
  684.     x[i] = t;
  685.     for ( ; ; )
  686.         {
  687.         t = y[i] + dy[i];
  688.         if ( t >= 0 && t < height ) break;
  689.         dy[i] = random() % ( MAX_DELTA * 2 ) - MAX_DELTA;
  690.         if ( dy[i] <= 0 ) --dy[i];
  691.         }
  692.     y[i] = t;
  693.     }
  694.  
  695.     /* Draw the figure. */
  696.     px = zx = ( x[0] + x[POINTS-1] ) / 2;
  697.     py = zy = ( y[0] + y[POINTS-1] ) / 2;
  698.     for ( i = 0; i < POINTS-1; ++i )
  699.     {
  700.     nx = ( x[i+1] + x[i] ) / 2;
  701.     ny = ( y[i+1] + y[i] ) / 2;
  702.     XDrawSpline( display, root, gc, px, py, x[i], y[i], nx, ny );
  703.     px = nx;
  704.     py = ny;
  705.     }
  706.     XDrawSpline(
  707.     display, root, gc, px, py, x[POINTS-1], y[POINTS-1], zx, zy );
  708.     }
  709.  
  710.  
  711. /* X spline routine. */
  712.  
  713. #define abs(x) ((x) < 0 ? -(x) : (x))
  714.  
  715. static void
  716. XDrawSpline( display, d, gc, x0, y0, x1, y1, x2, y2 )
  717. Display* display;
  718. Drawable d;
  719. GC gc;
  720. int x0, y0, x1, y1, x2, y2;
  721.     {
  722.     register int xa, ya, xb, yb, xc, yc, xp, yp;
  723.  
  724.     xa = ( x0 + x1 ) / 2;
  725.     ya = ( y0 + y1 ) / 2;
  726.     xc = ( x1 + x2 ) / 2;
  727.     yc = ( y1 + y2 ) / 2;
  728.     xb = ( xa + xc ) / 2;
  729.     yb = ( ya + yc ) / 2;
  730.  
  731.     xp = ( x0 + xb ) / 2;
  732.     yp = ( y0 + yb ) / 2;
  733.     if ( abs( xa - xp ) + abs( ya - yp ) > SPLINE_THRESH )
  734.     XDrawSpline( display, d, gc, x0, y0, xa, ya, xb, yb );
  735.     else
  736.     XDrawLine( display, d, gc, x0, y0, xb, yb );
  737.  
  738.     xp = ( x2 + xb ) / 2;
  739.     yp = ( y2 + yb ) / 2;
  740.     if ( abs( xc - xp ) + abs( yc - yp ) > SPLINE_THRESH )
  741.     XDrawSpline( display, d, gc, xb, yb, xc, yc, x2, y2 );
  742.     else
  743.     XDrawLine( display, d, gc, xb, yb, x2, y2 );
  744.     }
  745.  
  746.  
  747. #ifdef SYSV
  748.  
  749. /* Most SysV's don't have a usleep.  Sone of them have select. */
  750.  
  751. usleep( usecs )
  752. int usecs;
  753.     {
  754.     struct timeval timeout;
  755.  
  756.     timeout.tv_sec = usecs / 1000000;
  757.     timeout.tv_usec = usecs % 1000000;
  758.     select( 0, 0, 0, 0, &timeout );
  759.     }
  760.  
  761. #endif /*SYSV*/
  762.