[comp.windows.x] x11 bounce

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);
	}
}