http://ftp.x.org/contrib/applications/xscreensaver-3.20.tar.gz
[xscreensaver] / hacks / sonar.c
index 3c492189ad505c093a57f8c46a666768892e9b23..c4169f663dbd362d0a02dc8d492f40fb951d38c9 100644 (file)
  * of bogies that move around on the scope while the ping sensor can be
  * used to display hosts on your network.
  *
- * The ping code is only compiled in if you define HAVE_PING, because, 
- * unfortunately, creating an ICMP socket is a privileged operation, the
- * program needs to be installed SUID root if you want to use the ping
- * mode. If you check the code you will see that this privilige is given up
- * immediately after the socket is created.
+ * The ping code is only compiled in if you define HAVE_ICMP or HAVE_ICMPHDR,
+ * because, unfortunately, different systems have different ways of creating
+ * these sorts of packets.
+ *
+ * Also: creating an ICMP socket is a privileged operation, so the program
+ * needs to be installed SUID root if you want to use the ping mode.  If you
+ * check the code you will see that this privilige is given up immediately
+ * after the socket is created.
  *
  * It should be easy to extend this code to support other sorts of sensors.
  * Some ideas:
@@ -25,7 +28,7 @@
  *   - plot the process table, by process size, cpu usage, or total time;
  *   - plot the logged on users by idle time or cpu usage.
  *
- * Copyright (C) 1998 by Stephen Martin (smartin@canada.com).
+ * Copyright (C) 1998 by Stephen Martin (smartin@vanderfleet-martin.net).
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
  * the above copyright notice appear in all copies and that both that
@@ -34,7 +37,7 @@
  * software for any purpose.  It is provided "as is" without express or 
  * implied warranty.
  *
- * $Revision: 1.6 $
+ * $Revision: 1.14 $
  *
  * Version 1.0 April 27, 1998.
  * - Initial version
  * - Now need to define HAVE_PING to compile in the ping stuff.
  */
 
+/* These are computed by configure now:
+   #define HAVE_ICMP
+   #define HAVE_ICMPHDR
+ */
+
+
 /* Include Files */
 
-#ifdef HAVE_PING
-#include <sys/ipc.h>
-#include <sys/shm.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <netinet/in_systm.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/ip_icmp.h>
-#include <netinet/udp.h>
-#include <arpa/inet.h>
-#include <signal.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <signal.h>
-#include <limits.h>
-#endif /* HAVE_PING */
-#include <math.h>
-#include <stdio.h>
 #include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
 #include "screenhack.h"
 #include "colors.h"
 #include "hsv.h"
-#include <X11/extensions/XShm.h>
+
+#if defined(HAVE_ICMP) || defined(HAVE_ICMPHDR)
+# include <unistd.h>
+# include <limits.h>
+# include <signal.h>
+# include <fcntl.h>
+# include <sys/types.h>
+# include <sys/time.h>
+# include <sys/ipc.h>
+# include <sys/shm.h>
+# include <sys/socket.h>
+# include <netinet/in_systm.h>
+# include <netinet/in.h>
+# include <netinet/ip.h>
+# include <netinet/ip_icmp.h>
+# include <netinet/udp.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+#endif /* HAVE_ICMP || HAVE_ICMPHDR */
+
 
 /* Defines */
 
-#ifndef MIN
-#define MIN(a,b) ((a)<(b)?(a - 50):(b - 10))
-#endif /* MIN */
+#undef MY_MIN
+#define MY_MIN(a,b) ((a)<(b)?(a - 50):(b - 10))
+
+#ifndef LINE_MAX
+# define LINE_MAX 2048
+#endif
+
+/* Frigging icmp */
+
+#if defined(HAVE_ICMP)
+# define HAVE_PING
+# define ICMP             icmp
+# define ICMP_TYPE(p)     (p)->icmp_type
+# define ICMP_CODE(p)     (p)->icmp_code
+# define ICMP_CHECKSUM(p) (p)->icmp_cksum
+# define ICMP_ID(p)       (p)->icmp_id
+# define ICMP_SEQ(p)      (p)->icmp_seq
+#elif defined(HAVE_ICMPHDR)
+# define HAVE_PING
+# define ICMP             icmphdr
+# define ICMP_TYPE(p)     (p)->type
+# define ICMP_CODE(p)     (p)->code
+# define ICMP_CHECKSUM(p) (p)->checksum
+# define ICMP_ID(p)       (p)->un.echo.id
+# define ICMP_SEQ(p)      (p)->un.echo.sequence
+#else
+# undef HAVE_PING
+#endif
 
 /* Forward References */
 
@@ -157,7 +192,7 @@ typedef struct {
        centrex, centrey, radius; /* Parts of the scope circle */
     Bogie *visable;            /* List of visable objects */
     int current;               /* Current position of sweep */
-
+    int sweepnum;               /* The current id of the sweep */
     int delay;                 /* how long between each frame of the anim */
 
 } sonar_info;
@@ -199,7 +234,6 @@ typedef struct {
 
 static int timer_expired;
 
-
 #endif /* HAVE_PING */
 
 /*
@@ -210,7 +244,7 @@ typedef struct sim_target {
     char *name;                        /* The name of the target */
     int nexttick;              /* The next tick that this will be seen */
     int nextdist;              /* The distance on that tick */
-    int movedlasttick;         /* Flag to indicate we just moved this one */
+    int movedonsweep;          /* The number of the sweep this last moved */
 } sim_target;
 
 /*
@@ -317,7 +351,7 @@ newBogie(char *name, int distance, int tick, int ttl)
     /* Allocate a bogie and initialize it */
 
     if ((new = (Bogie *) calloc(1, sizeof(Bogie))) == NULL) {
-       fprintf(stderr, "Out of Memory\n");
+       fprintf(stderr, "%s: Out of Memory\n", progname);
        return NULL;
     }
     new->name = name;
@@ -415,7 +449,8 @@ lookupHost(ping_target *target)
 
        struct hostent *hent = gethostbyname(target->name);
        if (hent == NULL) {
-           fprintf(stderr, "Could not resolve host %s\n", target->name);
+           fprintf(stderr, "%s: could not resolve host %s\n",
+                    progname, target->name);
            return 0;
        }
        memcpy(&iaddr->sin_addr, hent->h_addr_list[0],
@@ -448,11 +483,11 @@ newHost(char *name)
     /* Create the target */
 
     if ((target = calloc(1, sizeof(ping_target))) == NULL) {
-       fprintf(stderr, "Out of Memory\n");
+       fprintf(stderr, "%s: Out of Memory\n", progname);
        goto target_init_error;
     }
     if ((target->name = strdup(name)) == NULL) {
-       fprintf(stderr, "Out of Memory\n");
+       fprintf(stderr, "%s: Out of Memory\n", progname);
        goto target_init_error;
     }
 
@@ -500,7 +535,7 @@ readPingHostsFile(char *fname)
     /* Make sure we in fact have a file to process */
 
     if ((fname == NULL) || (fname[0] == '\0')) {
-       fprintf(stderr, "Invalid ping host file name\n");
+       fprintf(stderr, "%s: invalid ping host file name\n", progname);
        return NULL;
     }
 
@@ -508,7 +543,7 @@ readPingHostsFile(char *fname)
 
     if ((fp = fopen(fname, "r")) == NULL) {
        char msg[1024];
-       sprintf(msg, "Unable to open host file %s", fname);
+       sprintf(msg, "%s: unable to open host file %s", progname, fname);
        perror(msg);
        return NULL;
     }
@@ -537,12 +572,28 @@ readPingHostsFile(char *fname)
        else
            continue;
 
+        /* Check to see if the addr looks like an addr.  If not, assume
+           the addr is a name and there is no addr.  This way, we can
+           handle files whose lines have "xx.xx.xx.xx hostname" as their
+           first two tokens, and also files that have a hostname as their
+           first token (like .ssh/known_hosts and .rhosts.)
+         */
+        {
+          int i; char c;
+          if (4 != sscanf(addr, "%d.%d.%d.%d%c", &i, &i, &i, &i, &c))
+            {
+              name = addr;
+              addr = NULL;
+            }
+        }
+        /*printf ("\"%s\" \"%s\"\n", name, addr);*/
+
        /* Create a new target using first the name then the address */
 
        new = NULL;
        if (name != NULL)
            new = newHost(name);
-       if (new == NULL)
+       if (new == NULL && addr != NULL)
            new = newHost(addr);
 
        /* Add it to the list if we got one */
@@ -626,14 +677,14 @@ subnetHostsList(void)
     /* Get our hostname */
 
     if (gethostname(hostname, BUFSIZ)) {
-       fprintf(stderr, "Unable to get local hostname\n");
+       fprintf(stderr, "%s: unable to get local hostname\n", progname);
        return NULL;
     }
 
     /* Get our IP address and convert it to a string */
 
     if ((hent = gethostbyname(hostname)) == NULL) {
-       fprintf(stderr, "Unable to lookup our IP address\n");
+       fprintf(stderr, "%s: unable to lookup our IP address\n", progname);
        return NULL;
     }
     strcpy(address, inet_ntoa(*((struct in_addr *)hent->h_addr_list[0])));
@@ -641,13 +692,17 @@ subnetHostsList(void)
     /* Get a pointer to the last "." in the string */
 
     if ((p = strrchr(address, '.')) == NULL) {
-       fprintf(stderr, "Can't parse IP address %s\n", address);
+       fprintf(stderr, "%s: can't parse IP address %s\n", progname, address);
        return NULL;
     }
     p++;
 
     /* Construct targets for all addresses in this subnet */
 
+    /* #### jwz: actually, this is wrong, since it assumes a
+       netmask of 255.255.255.0.  But I'm not sure how to find
+       the local netmask.
+     */
     for (i = 254; i > 0; i--) {
        sprintf(p, "%d", i);
        new = newHost(address);
@@ -682,14 +737,16 @@ init_ping(void)
     /* Create the ping info structure */
 
     if ((pi = (ping_info *) calloc(1, sizeof(ping_info))) == NULL) {
-       fprintf(stderr, "Out of memory\n");
+       fprintf(stderr, "%s: Out of memory\n", progname);
        goto ping_init_error;
     }
 
     /* Create the ICMP socket and turn off SUID */
 
     if ((pi->icmpsock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
-       perror("Can't create ICMP socket");
+       char msg[1024];
+       sprintf(msg, "%s: can't create ICMP socket", progname);
+       perror(msg);
        fprintf(stderr,
          "%s: this program must be setuid to root for `ping mode' to work.\n",
                 progname);
@@ -728,14 +785,16 @@ init_ping(void)
 
        /* Unknown source */
 
-       fprintf(stderr, "Illegal pingSource: %s\n", src);
-       goto ping_init_error;
+       fprintf(stderr,
+               "%s: pingSource must be `file', `list', or `subnet', not: %s\n",
+                progname, src);
+        exit (1);
     }
 
     /* Make sure there is something to ping */
 
     if (pi->targets == NULL) {
-       fprintf(stderr, "Nothing to ping");
+       fprintf(stderr, "%s: nothing to ping", progname);
        goto ping_init_error;
     }
 
@@ -775,7 +834,7 @@ sendping(ping_info *pi, ping_target *pt)
     /* Local Variables */
 
     u_char *packet;
-    struct icmp *icmph;
+    struct ICMP *icmph;
     int result;
 
     /*
@@ -784,24 +843,24 @@ sendping(ping_info *pi, ping_target *pt)
      * name or do an address lookup when it comes back.
      */
 
-    int pcktsiz = sizeof(struct icmp) + sizeof(struct timeval) +
+    int pcktsiz = sizeof(struct ICMP) + sizeof(struct timeval) +
        strlen(pt->name) + 1;
 
     /* Create the ICMP packet */
 
     if ((packet = (u_char *) malloc(pcktsiz)) == (void *) 0)
        return;  /* Out of memory */
-    icmph = (struct icmp *) packet;
-    icmph->icmp_type = ICMP_ECHO;
-    icmph->icmp_code = 0;
-    icmph->icmp_cksum = 0;
-    icmph->icmp_id = pi->pid;
-    icmph->icmp_seq = pi->seq++;
-    gettimeofday((struct timeval *) &packet[sizeof(struct icmp)],
+    icmph = (struct ICMP *) packet;
+    ICMP_TYPE(icmph) = ICMP_ECHO;
+    ICMP_CODE(icmph) = 0;
+    ICMP_CHECKSUM(icmph) = 0;
+    ICMP_ID(icmph) = pi->pid;
+    ICMP_SEQ(icmph) = pi->seq++;
+    gettimeofday((struct timeval *) &packet[sizeof(struct ICMP)],
                 (struct timezone *) 0);
-    strcpy((char *) &packet[sizeof(struct icmp) + sizeof(struct timeval)],
+    strcpy((char *) &packet[sizeof(struct ICMP) + sizeof(struct timeval)],
           pt->name);
-    icmph->icmp_cksum = checksum((u_short *)packet, pcktsiz);
+    ICMP_CHECKSUM(icmph) = checksum((u_short *)packet, pcktsiz);
 
     /* Send it */
 
@@ -809,7 +868,7 @@ sendping(ping_info *pi, ping_target *pt)
                         &pt->address, sizeof(pt->address))) !=  pcktsiz) {
 #if 0
         char errbuf[BUFSIZ];
-        sprintf(errbuf, "Error sending ping to %s", pt->name);
+        sprintf(errbuf, "%s: error sending ping to %s", progname, pt->name);
        perror(errbuf);
 #endif
     }
@@ -866,6 +925,7 @@ checksum(u_short *packet, int size)
 
     if (nleft == 1) {
        *(u_char *)(&answer) = *(u_char *)w ;
+        *(1 + (u_char *)(&answer)) = 0;
        sum += answer;
     }
 
@@ -908,7 +968,7 @@ getping(sonar_info *si, ping_info *pi, int ttl)
     struct timeval *then;
     struct ip *ip;
     int iphdrlen;
-    struct icmp *icmph;
+    struct ICMP *icmph;
     Bogie *bl = NULL;
     Bogie *new;
     char *name;
@@ -921,7 +981,9 @@ getping(sonar_info *si, ping_info *pi, int ttl)
     sa.sa_flags = 0;
     sa.sa_handler = sigcatcher;
     if (sigaction(SIGALRM, &sa, 0) == -1) {
-       perror("Unable to trap sigalarm");
+       char msg[1024];
+       sprintf(msg, "%s: unable to trap SIGALRM", progname);
+       perror(msg);
        exit(1);
     }
 
@@ -945,19 +1007,25 @@ getping(sonar_info *si, ping_info *pi, int ttl)
 
        gettimeofday(&now, (struct timezone *) 0);
        ip = (struct ip *) packet;
+
        iphdrlen = ip->ip_hl << 2;
-       icmph = (struct icmp *) &packet[iphdrlen];
+        /* On DEC OSF1 4.0, the preceeding line needs to be
+           iphdrlen = (ip->ip_vhl & 0x0F) << 2;
+           but I don't know how to do this portably.  -- jwz.
+         */
+
+       icmph = (struct ICMP *) &packet[iphdrlen];
 
        /* Was the packet a reply?? */
 
-       if (icmph->icmp_type != ICMP_ECHOREPLY) {
+       if (ICMP_TYPE(icmph) != ICMP_ECHOREPLY) {
            /* Ignore anything but ICMP Replies */
            continue; /* Nope */
        }
 
        /* Was it for us? */
 
-       if (icmph->icmp_id != pi->pid) {
+       if (ICMP_ID(icmph) != pi->pid) {
            /* Ignore packets not set from us */
            continue; /* Nope */
        }
@@ -966,9 +1034,9 @@ getping(sonar_info *si, ping_info *pi, int ttl)
 
        if ((name =
             strdup((char *) &packet[iphdrlen + 
-                                   + sizeof(struct icmp)
+                                   + sizeof(struct ICMP)
                                    + sizeof(struct timeval)])) == NULL) {
-           fprintf(stderr, "Out of memory\n");
+           fprintf(stderr, "%s: Out of memory\n", progname);
            return bl;
        }
 
@@ -1001,7 +1069,7 @@ getping(sonar_info *si, ping_info *pi, int ttl)
        /* Compute the round trip time */
 
        then =  (struct timeval *) &packet[iphdrlen +
-                                         sizeof(struct icmp)];
+                                         sizeof(struct ICMP)];
        new->distance = delta(then, &now) / 100;
        if (new->distance == 0)
                new->distance = 2; /* HACK */
@@ -1027,6 +1095,11 @@ static Bogie *
 ping(sonar_info *si, void *vpi) 
 {
 
+    /*
+     * This tries to distribute the targets evely around the field of the
+     * sonar.
+     */
+
     ping_info *pi = (ping_info *) vpi;
     static ping_target *ptr = NULL;
 
@@ -1088,14 +1161,10 @@ init_sim(void)
     sim_info *si;
     int i;
 
-    /* Seed the random number generator */
-
-    srand((int) time(NULL));
-
     /* Create the simulation info structure */
 
     if ((si = (sim_info *) calloc(1, sizeof(sim_info))) == NULL) {
-       fprintf(stderr, "Out of memory\n");
+       fprintf(stderr, "%s: Out of memory\n", progname);
        return NULL;
     }
 
@@ -1105,7 +1174,7 @@ init_sim(void)
     if ((si->teamA = (sim_target *)calloc(si->numA, sizeof(sim_target)))
        == NULL) {
        free(si);
-       fprintf(stderr, "Out of Memory\n");
+       fprintf(stderr, "%s: Out of Memory\n", progname);
        return NULL;
     }
     si->teamAID = get_string_resource("teamAName", "TeamAName");
@@ -1113,12 +1182,13 @@ init_sim(void)
        if ((si->teamA[i].name = (char *) malloc(strlen(si->teamAID) + 4))
            == NULL) {
            free(si);
-           fprintf(stderr, "Out of Memory\n");
+           fprintf(stderr, "%s: Out of Memory\n", progname);
            return NULL;
        }
        sprintf(si->teamA[i].name, "%s%03d", si->teamAID, i+1);
-       si->teamA[i].nexttick = (int) (90.0 * rand() / RAND_MAX);
-       si->teamA[i].nextdist = (int) (100.0 * rand() / RAND_MAX);
+       si->teamA[i].nexttick = (int) (90.0 * random() / RAND_MAX);
+       si->teamA[i].nextdist = (int) (100.0 * random() / RAND_MAX);
+       si->teamA[i].movedonsweep = -1;
     }
 
     /* Team B */
@@ -1127,7 +1197,7 @@ init_sim(void)
     if ((si->teamB = (sim_target *)calloc(si->numB, sizeof(sim_target)))
        == NULL) {
        free(si);
-       fprintf(stderr, "Out of Memory\n");
+       fprintf(stderr, "%s: Out of Memory\n", progname);
        return NULL;
     }
     si->teamBID = get_string_resource("teamBName", "TeamBName");
@@ -1135,12 +1205,13 @@ init_sim(void)
        if ((si->teamB[i].name = (char *) malloc(strlen(si->teamBID) + 4))
            == NULL) {
            free(si);
-           fprintf(stderr, "Out of Memory\n");
+           fprintf(stderr, "%s: Out of Memory\n", progname);
            return NULL;
        }
        sprintf(si->teamB[i].name, "%s%03d", si->teamBID, i+1);
-       si->teamB[i].nexttick = (int) (90.0 * rand() / RAND_MAX);
-       si->teamB[i].nextdist = (int) (100.0 * rand() / RAND_MAX);
+       si->teamB[i].nexttick = (int) (90.0 * random() / RAND_MAX);
+       si->teamB[i].nextdist = (int) (100.0 * random() / RAND_MAX);
+       si->teamB[i].movedonsweep = -1;
     }
 
     /* Done */
@@ -1175,7 +1246,7 @@ init_sonar(Display *dpy, Window win)
     /* Create the Sonar information structure */
 
     if ((si = (sonar_info *) calloc(1, sizeof(sonar_info))) == NULL) {
-       fprintf(stderr, "Out of memory\n");
+       fprintf(stderr, "%s: Out of memory\n", progname);
        return NULL;
     }
 
@@ -1190,19 +1261,20 @@ init_sonar(Display *dpy, Window win)
     si->height = xwa.height;
     si->centrex = si->width / 2;
     si->centrey = si->height / 2;
-    si->maxx = si->centrex + MIN(si->centrex, si->centrey) - 10;
-    si->minx = si->centrex - MIN(si->centrex, si->centrey) + 10;
-    si->maxy = si->centrey + MIN(si->centrex, si->centrey) - 10;
-    si->miny = si->centrey - MIN(si->centrex, si->centrey) + 10;
+    si->maxx = si->centrex + MY_MIN(si->centrex, si->centrey) - 10;
+    si->minx = si->centrex - MY_MIN(si->centrex, si->centrey) + 10;
+    si->maxy = si->centrey + MY_MIN(si->centrex, si->centrey) - 10;
+    si->miny = si->centrey - MY_MIN(si->centrex, si->centrey) + 10;
     si->radius = si->maxx - si->centrex;
     si->current = 0;
+    si->sweepnum = 0;
 
     /* Get the font */
 
     if (((si->font = XLoadQueryFont(dpy, get_string_resource ("font", "Font")))
         == NULL) &&
        ((si->font = XLoadQueryFont(dpy, "fixed")) == NULL)) {
-       fprintf(stderr, "Can't load an appropriate font\n");
+       fprintf(stderr, "%s: can't load an appropriate font\n", progname);
        return NULL;
     }
 
@@ -1283,9 +1355,8 @@ updateLocation(sim_target *t)
 
     int xdist, xtick;
 
-    t->movedlasttick = 1;
-    xtick = (int) (3.0 * rand() / RAND_MAX) - 1;
-    xdist = (int) (11.0 * rand() / RAND_MAX) - 5;
+    xtick = (int) (3.0 * random() / RAND_MAX) - 1;
+    xdist = (int) (11.0 * random() / RAND_MAX) - 5;
     if (((t->nexttick + xtick) < 90) && ((t->nexttick + xtick) >= 0))
        t->nexttick += xtick;
     else
@@ -1322,29 +1393,30 @@ simulator(sonar_info *si, void *vinfo)
 
     for (i = 0; i < info->numA; i++) {
        t = &info->teamA[i];
-       if (!t->movedlasttick && (t->nexttick == (si->current * -1))) {
+       if ((t->movedonsweep != si->sweepnum) &&
+           (t->nexttick == (si->current * -1))) {
            new = newBogie(strdup(t->name), t->nextdist, si->current, TTL);
            if (list != NULL)
                new->next = list;
            list = new;
            updateLocation(t);
-       } else
-           t->movedlasttick = 0;
+           t->movedonsweep = si->sweepnum;
+       }
     }
 
     /* Team B */
 
     for (i = 0; i < info->numB; i++) {
        t = &info->teamB[i];
-       if (!t->movedlasttick && (t->nexttick == (si->current * -1))) {
+       if ((t->movedonsweep != si->sweepnum) &&
+           (t->nexttick == (si->current * -1))) {
            new = newBogie(strdup(t->name), t->nextdist, si->current, TTL);
            if (list != NULL)
                new->next = list;
            list = new;
-           t->movedlasttick = 1;
            updateLocation(t);
-       } else
-           t->movedlasttick = 0;
+           t->movedonsweep = si->sweepnum;
+       }
     }
 
     /* Done */
@@ -1421,7 +1493,8 @@ DrawBogie(sonar_info *si, int draw, char *name, int degrees,
 
     /* Compute the coordinates of the object */
 
-    distance = (log((double) distance) / 10.0) * si->radius;
+    if (distance != 0)
+      distance = (log((double) distance) / 10.0) * si->radius;
     x = ox + ((double) distance * cos(4.0 * ((double) degrees)/57.29578));
     y = oy - ((double) distance * sin(4.0 * ((double) degrees)/57.29578));
 
@@ -1654,7 +1727,7 @@ screenhack(Display *dpy, Window win)
        if ((sensor_info = (void *) init_sim()) == NULL)
            exit(1);
     } else {
-       fprintf(stderr, "Unsupported Sonar mode: %s\n", mode);
+       fprintf(stderr, "%s: unsupported Sonar mode: %s\n", progname, mode);
        fprintf(stderr,
                 "\tCurrently supported modes are `ping' and `simulation'\n");
        exit(1);
@@ -1677,11 +1750,14 @@ screenhack(Display *dpy, Window win)
         /* Set up and sleep for the next one */
 
        si->current = (si->current - 1) % 90;
+       if (si->current == 0)
+         si->sweepnum++;
        XSync (dpy, False);
        gettimeofday(&finish, (struct timezone *) 0);
        sleeptime = si->delay - delta(&start, &finish);
         screenhack_handle_events (dpy);
        if (sleeptime > 0L)
            usleep(sleeptime);
+
     }
 }