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