--- xroach.c.orig 1991-06-06 12:12:07 UTC +++ xroach.c @@ -1,23 +1,31 @@ /* Xroach - A game of skill. Try to find the roaches under your windows. - + Copyright 1991 by J.T. Anderson jta@locus.com - + This program may be freely distributed provided that all copyright notices are retained. To build: - cc -o xroach roach.c -lX11 [-lsocketorwhatever] [-lm] [-l...] + cc -o xroach -lX11 -lm -I/usr/local/include/ -L/usr/local/lib xroach.c + + To run: + ./xroach -speed 2 -squish -rc brown -rgc yellowgreen + + Dedicated to Greg McFarlane (gregm@otc.otca.oz.au). + + Squish option contributed by Rick Petkiewizc (rick@locus.com). - Dedicated to Greg McFarlane. (gregm@otc.otca.oz.au) - - Squish option contributed by Rick Petkiewizc (rick@locus.com) - Virtual root code adapted from patch sent by Colin Rafferty who - borrowed it from Tom LaStrange. Several other folks sent similar + borrowed it from Tom LaStrange. Several other folks sent similar fixes. + + Some glitches removed by patch from Guus Sliepen (guus@sliepen.warande.net) + in 2001 (see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=102668#5). + + Last update: 2018-JAN-22 */ /* @(#)xroach.c 1.5 4/2/91 11:53:31 */ @@ -28,17 +36,9 @@ #include #include -#include -#include -#include - -#if __STDC__ #include -#else -long strtol(); -double strtod(); -char *getenv(); -#endif +#include +#include char Copyright[] = "Xroach\nCopyright 1991 J.T. Anderson"; @@ -47,30 +47,31 @@ char Copyright[] = "Xroach\nCopyright 19 typedef unsigned long Pixel; typedef int ErrorHandler(); -#define SCAMPER_EVENT (LASTEvent + 1) +#define SCAMPER_EVENT (LASTEvent + 1) #if !defined(GRAB_SERVER) -#define GRAB_SERVER 0 +#define GRAB_SERVER 0 #endif +char *display_name = NULL; Display *display; -int screen; -Window rootWin; -unsigned int display_width, display_height; -int center_x, center_y; GC gc; GC gutsGC; -char *display_name = NULL; -Pixel black, white; +int screen; +Pixel black; +unsigned int display_height; +unsigned int display_width; +Window rootWin; +Bool squishRoach = False; +Bool squishWinUp = False; int done = 0; -int eventBlock = 0; int errorVal = 0; -Bool squishRoach = False; +int eventBlock = 0; Pixmap squishMap; -Bool squishWinUp = False; -typedef struct Roach { +typedef struct Roach +{ RoachMap *rp; int index; float x; @@ -86,69 +87,72 @@ Roach *roaches; int maxRoaches = 10; int curRoaches = 0; float roachSpeed = 20.0; +float turnSpeed = 10.0; Region rootVisible = NULL; void Usage(); void SigHandler(); +Window FindRootWindow(); +int RandInt(int maxVal); +int RoachInRect(Roach *roach, int rx, int ry, int x, int y, unsigned int width, unsigned int height); +int RoachOverRect(Roach *roach, int rx, int ry, int x, int y, unsigned int width, unsigned int height); void AddRoach(); -void MoveRoach(); +void TurnRoach(Roach *roach); +void MoveRoach(int rx); void DrawRoaches(); void CoverRoot(); +int RoachErrors(XErrorEvent *err); int CalcRootVisible(); int MarkHiddenRoaches(); -Pixel AllocNamedColor(); -Window FindRootWindow(); +Pixel AllocNamedColor(char *colorName, Pixel dfltPix); +void checkSquish(XButtonEvent *buttonEvent); -void -main(ac, av) -int ac; -char *av[]; +int main(int ac, char *av[]) { - XGCValues xgcv; - int ax; char *arg; - RoachMap *rp; - int rx; - float angle; - XEvent ev; - char *roachColor = "black"; char *gutsColor = NULL; - int nVis; + char *roachColor = "black"; + float angle; int needCalc; + int nVis; + RoachMap *rp; Window squishWin; + XEvent ev; + XGCValues xgcv; XSetWindowAttributes xswa; - + /* Process command line options. */ - for (ax=1; axpixmap = XCreateBitmapFromData(display, rootWin, - rp->roachBits, rp->width, rp->height); - rp->sine = sin(angle); - rp->cosine = cos(angle); + for (int ax = 0; ax < 360; ax += ROACH_ANGLE) + { + int rx = ax / ROACH_ANGLE; + angle = (float) (rx * 0.261799387799); + rp = &roachPix[rx]; + rp->pixmap = XCreateBitmapFromData(display, + rootWin, + rp->roachBits, + (unsigned int) rp->width, + (unsigned int) rp->height); + rp->sine = (float) sin(angle); + rp->cosine = (float) cos(angle); } /* Create the squished pixmap */ - if (squishRoach) { - squishMap = XCreateBitmapFromData(display, rootWin, - squish_bits, squish_width, squish_height); - } + if (squishRoach) + squishMap = XCreateBitmapFromData(display, + rootWin, + squish_bits, + squish_width, + squish_height); - roaches = (Roach *)malloc(sizeof(Roach) * maxRoaches); + roaches = (Roach *) malloc(sizeof(Roach) * maxRoaches); gc = XCreateGC(display, rootWin, 0L, &xgcv); XSetForeground(display, gc, AllocNamedColor(roachColor, black)); XSetFillStyle(display, gc, FillStippled); - if (squishRoach && gutsColor != NULL) { + if (squishRoach && gutsColor != NULL) + { gutsGC = XCreateGC(display, rootWin, 0L, &xgcv); XSetForeground(display, gutsGC, AllocNamedColor(gutsColor, black)); XSetFillStyle(display, gutsGC, FillStippled); } else - gutsGC = gc; - + { + gutsGC = gc; + } + while (curRoaches < maxRoaches) - AddRoach(); - + AddRoach(); + XSelectInput(display, rootWin, ExposureMask | SubstructureNotifyMask); - if (squishRoach) { - xswa.event_mask = ButtonPressMask; - xswa.override_redirect = True; - squishWin = XCreateWindow(display, rootWin, 0, 0, - display_width, display_height, 0, - CopyFromParent, InputOnly, CopyFromParent, - CWOverrideRedirect | CWEventMask, &xswa); - XLowerWindow(display, squishWin); + if (squishRoach) + { + xswa.event_mask = ButtonPressMask; + xswa.override_redirect = True; + squishWin = XCreateWindow(display, + rootWin, + 0, 0, + display_width, display_height, + 0, + CopyFromParent, InputOnly, CopyFromParent, + CWOverrideRedirect | CWEventMask, + &xswa); + XLowerWindow(display, squishWin); } - + needCalc = 1; - while (!done) { - if (XPending(display)) { - XNextEvent(display, &ev); - } - else { - if (needCalc) { - needCalc = CalcRootVisible(); - } - if (needCalc) - nVis = 0; - else - nVis = MarkHiddenRoaches(); - if (nVis) { - ev.type = SCAMPER_EVENT; - if (!squishWinUp && squishRoach) { - XMapWindow(display, squishWin); - squishWinUp = True; - } - } - else { - if (squishWinUp && squishRoach) { - XUnmapWindow(display, squishWin); - squishWinUp = False; - } - if (needCalc == 0) - DrawRoaches(); - eventBlock = 1; - XNextEvent(display, &ev); - eventBlock = 0; - } - } - - switch (ev.type) { - - case SCAMPER_EVENT: - for (rx=0; rx= 1) { - rootWin = *newRoot; - } - if (newRoot) { - XFree(newRoot); - } - } - if (rootWin != realRoot) break; + XQueryTree(display, + rootWin, + &rootReturn, + &parentReturn, + &children, + &numChildren); + + for (int cx = 0; cx < numChildren; cx++) + { + newRoot = NULL; + nItems = 0; + + if (XGetWindowProperty(display, + children[cx], + swmVroot, + 0, + 1, + False, + XA_WINDOW, + &actualType, + &actualFormat, + &nItems, + &bytesAfter, + &newRoot) == Success && actualFormat != None) + { + if (nItems >= 1) + rootWin = *newRoot; + + if (newRoot) + XFree(newRoot); + } + + if (rootWin != realRoot) + break; } + XFree(children); - + return rootWin; } /* Generate random integer between 0 and maxVal-1. */ -int -RandInt(maxVal) -int maxVal; +int RandInt(int maxVal) { - return rand() % maxVal; + return rand() % maxVal; } /* Check for roach completely in specified rectangle. */ -int -RoachInRect(roach, rx, ry, x, y, width, height) -Roach *roach; -int rx; -int ry; -int x; -int y; -unsigned int width; -unsigned int height; +int RoachInRect(Roach *roach, int rx, int ry, int x, int y, unsigned int width, unsigned int height) { - if (rx < x) return 0; - if ((rx + roach->rp->width) > (x + width)) return 0; - if (ry < y) return 0; - if ((ry + roach->rp->height) > (y + height)) return 0; - + if (rx < x) + return 0; + + if ((rx + roach->rp->width) > (x + width)) + return 0; + + if (ry < y) + return 0; + + if ((ry + roach->rp->height) > (y + height)) + return 0; + return 1; } /* Check for roach overlapping specified rectangle. */ -int -RoachOverRect(roach, rx, ry, x, y, width, height) -Roach *roach; -int rx; -int ry; -int x; -int y; -unsigned int width; -unsigned int height; +int RoachOverRect(Roach *roach, int rx, int ry, int x, int y, unsigned int width, unsigned int height) { - if (rx >= (x + width)) return 0; - if ((rx + roach->rp->width) <= x) return 0; - if (ry >= (y + height)) return 0; - if ((ry + roach->rp->height) <= y) return 0; - + if (rx >= (x + width)) + return 0; + + if ((rx + roach->rp->width) <= x) + return 0; + + if (ry >= (y + height)) + return 0; + + if ((ry + roach->rp->height) <= y) + return 0; + return 1; } /* Give birth to a roach. */ -void -AddRoach() +void AddRoach() { Roach *r; - - if (curRoaches < maxRoaches) { - r = &roaches[curRoaches++]; - r->index = RandInt(ROACH_HEADINGS); - r->rp = &roachPix[r->index]; - r->x = RandInt(display_width - r->rp->width); - r->y = RandInt(display_height - r->rp->height); - r->intX = -1; - r->intY = -1; - r->hidden = 0; - r->steps = RandInt(200); - r->turnLeft = RandInt(100) >= 50; + + if (curRoaches < maxRoaches) + { + r = &roaches[curRoaches++]; + r->index = RandInt(ROACH_HEADINGS); + r->rp = &roachPix[r->index]; + r->x = RandInt(display_width - r->rp->width); + r->y = RandInt(display_height - r->rp->height); + r->intX = -1; + r->intY = -1; + r->hidden = 0; + r->steps = RandInt((int) turnSpeed); + r->turnLeft = RandInt(100) >= 50; } } /* Turn a roach. */ -void -TurnRoach(roach) -Roach *roach; +void TurnRoach(Roach *roach) { - if (roach->index != (roach->rp - roachPix)) return; + if (roach->index != (roach->rp - roachPix)) + return; - if (roach->turnLeft) { - roach->index += (RandInt(30) / 10) + 1; - if (roach->index >= ROACH_HEADINGS) - roach->index -= ROACH_HEADINGS; - } - else { - roach->index -= (RandInt(30) / 10) + 1; - if (roach->index < 0) - roach->index += ROACH_HEADINGS; + if (roach->turnLeft) + { + roach->index += (RandInt(30) / 10) + 1; + + if (roach->index >= ROACH_HEADINGS) + roach->index -= ROACH_HEADINGS; + } else + { + roach->index -= (RandInt(30) / 10) + 1; + + if (roach->index < 0) + roach->index += ROACH_HEADINGS; } } /* Move a roach. */ -void -MoveRoach(rx) -int rx; +void MoveRoach(int rx) { - Roach *roach; - Roach *r2; float newX; float newY; - int ii; - + Roach *roach; + roach = &roaches[rx]; newX = roach->x + (roachSpeed * roach->rp->cosine); newY = roach->y - (roachSpeed * roach->rp->sine); - - if (RoachInRect(roach, (int)newX, (int)newY, - 0, 0, display_width, display_height)) { - - roach->x = newX; - roach->y = newY; - if (roach->steps-- <= 0) { - TurnRoach(roach); - roach->steps = RandInt(200); - } + if (RoachInRect(roach, + (int) newX, (int) newY, + 0, 0, + display_width, display_height)) + { + roach->x = newX; + roach->y = newY; - for (ii=rx+1; iiintX, r2->intY, r2->rp->width, r2->rp->height)) { - - TurnRoach(roach); - } - } + if (roach->steps-- <= 0) + { + TurnRoach(roach); + roach->steps = RandInt((int) turnSpeed); + + /* + Previously, roaches would just go around in circles. + This makes their movement more interesting (and disgusting too!). + */ + if (RandInt(100) >= 80) + roach->turnLeft ^= 1; + } + + /* This is a kind of anti-collision algorithm which doesn't do what it is supposed to do, + it eats CPU time and sometimes makes roaches spin around very crazy. Therefore it is + commented out. + + for (int ii = rx + 2; ii < curRoaches; ii++) { + r2 = &roaches[ii]; + + if (RoachOverRect(roach, + (int) newX, (int) newY, + r2->intX, r2->intY, + (unsigned int) r2->rp->width, (unsigned int) r2->rp->height)) + TurnRoach(roach); + + } + */ } - else { - TurnRoach(roach); + else + { + TurnRoach(roach); } } - + /* Draw all roaches. */ -void -DrawRoaches() +void DrawRoaches() { Roach *roach; - int rx; - - for (rx=0; rxintX >= 0 && roach->rp != NULL) { - XClearArea(display, rootWin, roach->intX, roach->intY, - roach->rp->width, roach->rp->height, False); - } - } - - for (rx=0; rxhidden) { - roach->intX = roach->x; - roach->intY = roach->y; - roach->rp = &roachPix[roach->index]; - - XSetStipple(display, gc, roach->rp->pixmap); - XSetTSOrigin(display, gc, roach->intX, roach->intY); - XFillRectangle(display, rootWin, gc, - roach->intX, roach->intY, roach->rp->width, roach->rp->height); - } - else { - roach->intX = -1; - } + + for (int rx = 0; rx < curRoaches; rx++) + { + roach = &roaches[rx]; + + if (!roach->hidden) + { + XClearArea(display, + rootWin, + roach->intX, + roach->intY, + (unsigned int) roach->rp->width, + (unsigned int) roach->rp->height, + False); + + roach->intX = (int) roach->x; + roach->intY = (int) roach->y; + roach->rp = &roachPix[roach->index]; + + XSetStipple(display, gc, roach->rp->pixmap); + XSetTSOrigin(display, gc, roach->intX, roach->intY); + XFillRectangle(display, + rootWin, + gc, + roach->intX, + roach->intY, + (unsigned int) roach->rp->width, + (unsigned int) roach->rp->height); + } + else + { + roach->intX = -1; + } } } /* Cover root window to erase roaches. */ -void -CoverRoot() +void CoverRoot() { - XSetWindowAttributes xswa; long wamask; Window roachWin; - + XSetWindowAttributes xswa; + xswa.background_pixmap = ParentRelative; xswa.override_redirect = True; wamask = CWBackPixmap | CWOverrideRedirect; - roachWin = XCreateWindow(display, rootWin, 0, 0, - display_width, display_height, 0, CopyFromParent, - InputOutput, CopyFromParent, wamask, &xswa); + roachWin = XCreateWindow(display, rootWin, + 0, 0, + display_width, display_height, + 0, + CopyFromParent, InputOutput, CopyFromParent, + (unsigned long) wamask, &xswa); XLowerWindow(display, roachWin); XMapWindow(display, roachWin); XFlush(display); -} +} #if !GRAB_SERVER - -int -RoachErrors(dpy, err) -Display *dpy; -XErrorEvent *err; +int RoachErrors(XErrorEvent *err) { errorVal = err->error_code; - + return 0; } - #endif /* GRAB_SERVER */ /* - Calculate Visible region of root window. + Calculate visible region of root window. */ -int -CalcRootVisible() +int CalcRootVisible() { + int winX, winY; Region covered; Region visible; + unsigned int borderWidth; + unsigned int depth; + unsigned int nChildren; + unsigned int winHeight, winWidth; Window *children; - int nChildren; Window dummy; - XWindowAttributes wa; - int wx; XRectangle rect; - int winX, winY; - unsigned int winHeight, winWidth; - unsigned int borderWidth; - unsigned int depth; - + XWindowAttributes wa; + /* If we don't grab the server, the XGetWindowAttribute or XGetGeometry calls can abort us. On the other hand, the server grabs can make for @@ -628,64 +699,83 @@ CalcRootVisible() Get children of root. */ XQueryTree(display, rootWin, &dummy, &dummy, &children, &nChildren); - + /* For each mapped child, add the window rectangle to the covered region. */ covered = XCreateRegion(); - for (wx=0; wx