grady@postgres (Steven Grady) (04/07/88)
At last, the infamous BOUNCE returns, in X11 this time! This one, however, has a new twist.. Steven grady@postgres.berkeley.edu ...!ucbvax!grady #include <stdio.h> #include <X11/Xlib.h> #include <signal.h> #include <math.h> /* X11 Bounce, by Steven Grady */ /* Compile with cc bounce.c -lX11 -lm */ #define abs(x) ((x) > 0 ? x : (-x)) struct window { Window win; XWindowAttributes winf; float v; int stopped; } *windows, *savedwins; Display *dpy; int totwin; float elast = 0.5, el, gravity = 2.0; int bottom; int beep; int dontfix = 0; int bye(); main(argc, argv) int argc; char **argv; { int e, i; struct window *wind; int c; extern int optind; extern char *optarg; int errflg = 0; while ((c = getopt(argc, argv, "sbg:e:")) != EOF) switch (c) { case 'b': beep++; break; case 'g': gravity = (float) atoi(optarg)/ 10.0; if (gravity < 0.0) { fprintf(stderr, "Try to control yourself, please. \n"); exit(1); } break; case 'e': elast = (float) atoi(optarg)/ 10.0; break; case 's': dontfix++; break; case '?': errflg++; break; } if (errflg) { fprintf(stderr, "usage: %s [-b] [-g gravity] [-e elasticity]", argv[0]); fprintf(stderr, " [-s] [display]\n"); fprintf(stderr, "\t-b: turn on beep -s: don't restore "); fprintf(stderr, "screen\n\tdefault g=20"); fprintf(stderr, "\tdefault e=5\n"); exit(1); } dpy = XOpenDisplay((optind < argc) ? argv[optind] : (char *) NULL); totwin = get_windows(); signal(SIGINT, bye); el = elast * 1.2; /* Make up for some of the rounding */ while (!all_stopped()) { for (i = 0; i < totwin; i++) { wind = &windows[i]; if (wind->stopped) continue; calc_windows(wind); disp_windows(wind); } XSync(dpy, 0); } if (!dontfix) { printf("Waiting for an interrupt..\n"); pause(); /* Never returns -- bye() does an exit() */ } } all_stopped() { int i; for (i = 0; i < totwin; i++) { if (!windows[i].stopped) return(0); } return(1); } stopped(w) struct window *w; { if (abs(w->v) < (float) gravity) { return((int) abs(bottom - (w->winf.y + w->winf.height)) < 10); } else return(0); } calc_windows(win) struct window *win; { int new_y; float new_v; new_y = win->winf.y + win->v; new_v = win->v + gravity; if (new_y+win->winf.height > bottom) { new_y = 2*bottom-(new_y+2*win->winf.height); if (beep) { /* This should be fixed */ XBell(dpy, (int) log((double) (win->v*win->v * sqrt((float) win->winf.height) / 30)) - 6); } new_v = -new_v*el; el *= 0.8; } win->winf.y = new_y; win->v = new_v; win->stopped = stopped(win); } int get_windows() { int n, i, j; Window *children, par, root; XWindowAttributes winf; XQueryTree(dpy, DefaultRootWindow(dpy), &root, &par, &children, &n); /* Malloc() never fails. Heh heh.. */ windows = malloc(n * sizeof(*windows)); savedwins = malloc(n * sizeof(*savedwins)); for (i = 0, j = 0; i < n; i++) { XGetWindowAttributes(dpy, children[i], &winf); if (winf.map_state == IsViewable) { windows[j].winf = winf; windows[j].win = children[i]; windows[j].v = 0.0; windows[j].stopped = 0; savedwins[j] = windows[j]; j++; } } /* Give allowance for a reasonable border */ bottom = DisplayHeight(dpy, DefaultScreen(dpy)) - 3; return(j); } disp_windows(win) struct window *win; { int i; XMoveWindow(dpy, win->win, win->winf.x, win->winf.y); XMapWindow(dpy, win->win); XFlush(dpy); } bye() { if (!dontfix) { fix(); } exit(0); } fix() { int i; struct window sw; for (i = 0; i < totwin; i++) { sw = savedwins[i]; XMoveWindow(dpy, sw.win, sw.winf.x, sw.winf.y); XMapWindow(dpy, sw.win); XFlush(dpy); } }