http://ftp.x.org/contrib/applications/xscreensaver-3.26.tar.gz
[xscreensaver] / hacks / bsod.c
index e127ea1b8a0c9139876d334be34f4931a3f00b44..2e45e6d82bdfbd95dbe5db9dfb94091d433347cf 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1998 Jamie Zawinski <jwz@netscape.com>
+/* xscreensaver, Copyright (c) 1998, 2000 Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -13,7 +13,6 @@
  * this version written by jwz, 4-Jun-98.
  *
  *   TODO:
- *      -  Should have a "macsbug" mode.
  *      -  Should simulate a Unix kernel panic and reboot.
  *      -  Making various boot noises would be fun, too.
  *      -  Maybe scatter some random bits across the screen,
@@ -30,6 +29,7 @@
 # include "images/amiga.xpm"
 #endif
 
+#include "images/atari.xbm"
 #include "images/mac.xbm"
 
 
@@ -131,7 +131,7 @@ double_pixmap(Display *dpy, GC gc, Visual *visual, int depth, Pixmap pixmap,
   XImage *i1 = XGetImage(dpy, pixmap, 0, 0, pix_w, pix_h, ~0L, ZPixmap);
   XImage *i2 = XCreateImage(dpy, visual, depth, ZPixmap, 0, 0,
                            pix_w*2, pix_h*2, 8, 0);
-  i2->data = (unsigned char *) calloc(i2->height, i2->bytes_per_line);
+  i2->data = (char *) calloc(i2->height, i2->bytes_per_line);
   for (y = 0; y < pix_h; y++)
     for (x = 0; x < pix_w; x++)
       {
@@ -157,22 +157,36 @@ double_pixmap(Display *dpy, GC gc, Visual *visual, int depth, Pixmap pixmap,
 static Bool
 bsod_sleep(Display *dpy, int seconds)
 {
-  XEvent event;
   int q = seconds * 4;
-  int mask = KeyPressMask|ButtonPressMask;
+  int quantum = 250000;
+
+  if (seconds == -1)
+    q = 1, quantum = 100000;
+
   do
     {
       XSync(dpy, False);
-      if (XCheckMaskEvent(dpy, mask, &event))
-       {
-         while (XCheckMaskEvent(dpy, mask, &event))
-           ;
-         return True;
-       }
+      while (XPending (dpy))
+        {
+          XEvent event;
+          XNextEvent (dpy, &event);
+          if (event.xany.type == ButtonPress)
+            return True;
+          if (event.xany.type == KeyPress)
+            {
+              KeySym keysym;
+              char c = 0;
+              XLookupString (&event.xkey, &c, 1, &keysym, 0);
+              if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
+                return True;
+            }
+          screenhack_handle_event (dpy, &event);
+        }
+
       if (q > 0)
        {
          q--;
-         usleep(250000);
+         usleep(quantum);
        }
     }
   while (q > 0);
@@ -181,7 +195,7 @@ bsod_sleep(Display *dpy, int seconds)
 }
 
 
-static void
+static Bool
 windows (Display *dpy, Window window, int delay, Bool w95p)
 {
   XGCValues gcv;
@@ -203,7 +217,7 @@ windows (Display *dpy, Window window, int delay, Bool w95p)
      "\n"
      "_Press any key to continue");
 
-  const char *wnt =
+  const char *wnt = /* from Jim Niemira <urmane@urmane.org> */
     ("*** STOP: 0x0000001E (0x80000003,0x80106fc0,0x8025ea21,0xfd6829e8)\n"
    "Unhandled Kernel exception c0000047 from fa8418b4 (8025ea21,fd6829e8)\n"
    "\n"
@@ -249,6 +263,9 @@ windows (Display *dpy, Window window, int delay, Bool w95p)
    "contact your system administrator or technical support group."
      );
 
+  if (!get_boolean_resource((w95p? "doWindows" : "doNT"), "DoWindows"))
+    return False;
+
   XGetWindowAttributes (dpy, window, &xgwa);
 
   fontname = get_string_resource ((xgwa.height > 600
@@ -293,9 +310,351 @@ windows (Display *dpy, Window window, int delay, Bool w95p)
   bsod_sleep(dpy, delay);
   XClearWindow(dpy, window);
   XFreeFont(dpy, font);
+  return True;
 }
 
-static void
+/* SCO OpenServer 5 panic, by Tom Kelly <tom@ancilla.toronto.on.ca>
+ */
+static Bool
+sco (Display *dpy, Window window, int delay)
+{
+  XGCValues gcv;
+  XWindowAttributes xgwa;
+  char *fontname;
+  const char *def_font = "fixed";
+  XFontStruct *font;
+  GC gc;
+  int lines_1 = 0, lines_2 = 0, lines_3 = 0, lines_4 = 0;
+  const char *s;
+
+  const char *sco_panic_1 =
+    ("Unexpected trap in kernel mode:\n"
+     "\n"
+     "cr0 0x80010013     cr2  0x00000014     cr3 0x00000000  tlb  0x00000000\n"
+     "ss  0x00071054    uesp  0x00012055     efl 0x00080888  ipl  0x00000005\n"
+     "cs  0x00092585     eip  0x00544a4b     err 0x004d4a47  trap 0x0000000E\n"
+     "eax 0x0045474b     ecx  0x0042544b     edx 0x57687920  ebx  0x61726520\n"
+     "esp 0x796f7520     ebp  0x72656164     esi 0x696e6720  edi  0x74686973\n"
+     "ds  0x3f000000     es   0x43494c48     fs  0x43525343  gs   0x4f4d4b53\n"
+     "\n"
+     "PANIC: k_trap - kernel mode trap type 0x0000000E\n"
+     "Trying to dump 5023 pages to dumpdev hd (1/41), 63 pages per '.'\n"
+    );
+  const char *sco_panic_2 =
+   ("...............................................................................\n"
+    );
+  const char *sco_panic_3 =
+    ("5023 pages dumped\n"
+     "\n"
+     "\n"
+     );
+  const char *sco_panic_4 =
+    ("**   Safe to Power Off   **\n"
+     "           - or -\n"
+     "** Press Any Key to Reboot **\n"
+    );
+
+  if (!get_boolean_resource("doSCO", "DoSCO"))
+    return False;
+
+  for (s = sco_panic_1; *s; s++) if (*s == '\n') lines_1++;
+  for (s = sco_panic_2; *s; s++) if (*s == '\n') lines_2++;
+  for (s = sco_panic_3; *s; s++) if (*s == '\n') lines_3++;
+  for (s = sco_panic_4; *s; s++) if (*s == '\n') lines_4++;
+
+  XGetWindowAttributes (dpy, window, &xgwa);
+
+  fontname = get_string_resource ((xgwa.height > 600
+                                  ? "sco.font2"
+                                  : "sco.font"),
+                                 "SCO.Font");
+  if (!fontname || !*fontname) fontname = (char *)def_font;
+  font = XLoadQueryFont (dpy, fontname);
+  if (!font) font = XLoadQueryFont (dpy, def_font);
+  if (!font) exit(-1);
+  if (fontname && fontname != def_font)
+    free (fontname);
+
+  gcv.font = font->fid;
+  gcv.foreground = get_pixel_resource(("sco.foreground"),
+                                     "SCO.Foreground",
+                                     dpy, xgwa.colormap);
+  gcv.background = get_pixel_resource(("sco.background"),
+                                     "SCO.Background",
+                                     dpy, xgwa.colormap);
+  XSetWindowBackground(dpy, window, gcv.background);
+  XClearWindow(dpy, window);
+
+  gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
+
+  draw_string(dpy, window, gc, &gcv, font,
+             10, xgwa.height - ((lines_1 + lines_2 + lines_3 + lines_4 + 1) *
+                                 (font->ascent + font->descent + 1)),
+             10, 10,
+             sco_panic_1, 0);
+  XSync(dpy, False);
+  for (s = sco_panic_2; *s; s++)
+    {
+      char *ss = strdup(sco_panic_2);
+      ss[s - sco_panic_2] = 0;
+      draw_string(dpy, window, gc, &gcv, font,
+                  10, xgwa.height - ((lines_2 + lines_3 + lines_4 + 1) *
+                                     (font->ascent + font->descent + 1)),
+                  10, 10,
+                  ss, 0);
+      XSync(dpy, False);
+      free(ss);
+      if (bsod_sleep (dpy, -1))
+        goto DONE;
+    }
+
+  draw_string(dpy, window, gc, &gcv, font,
+             10, xgwa.height - ((lines_3 + lines_4 + 1) *
+                                 (font->ascent + font->descent + 1)),
+             10, 10,
+             sco_panic_3, 0);
+  XSync(dpy, False);
+  if (bsod_sleep(dpy, 1))
+    goto DONE;
+  draw_string(dpy, window, gc, &gcv, font,
+             10, xgwa.height - ((lines_4 + 1) *
+                                 (font->ascent + font->descent + 1)),
+             10, 10,
+             sco_panic_4, 0);
+  XSync(dpy, False);
+
+  bsod_sleep(dpy, delay);
+ DONE:
+  XClearWindow(dpy, window);
+  XFreeGC(dpy, gc);
+  XFreeFont(dpy, font);
+  return True;
+}
+
+
+/* Linux (sparc) panic, by Tom Kelly <tom@ancilla.toronto.on.ca>
+ */
+static Bool
+sparc_linux (Display *dpy, Window window, int delay)
+{
+  XGCValues gcv;
+  XWindowAttributes xgwa;
+  char *fontname;
+  const char *def_font = "fixed";
+  XFontStruct *font;
+  GC gc;
+  int lines = 1;
+  const char *s;
+
+  const char *linux_panic =
+    ("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
+       "Unable to handle kernel paging request at virtual address f0d4a000\n"
+       "tsk->mm->context = 00000014\n"
+       "tsk->mm->pgd = f26b0000\n"
+       "              \\|/ ____ \\|/\n"
+       "              \"@'/ ,. \\`@\"\n"
+       "              /_| \\__/ |_\\\n"
+       "                 \\__U_/\n"
+       "gawk(22827): Oops\n"
+       "PSR: 044010c1 PC: f001c2cc NPC: f001c2d0 Y: 00000000\n"
+       "g0: 00001000 g1: fffffff7 g2: 04401086 g3: 0001eaa0\n"
+       "g4: 000207dc g5: f0130400 g6: f0d4a018 g7: 00000001\n"
+       "o0: 00000000 o1: f0d4a298 o2: 00000040 o3: f1380718\n"
+       "o4: f1380718 o5: 00000200 sp: f1b13f08 ret_pc: f001c2a0\n"
+       "l0: efffd880 l1: 00000001 l2: f0d4a230 l3: 00000014\n"
+       "l4: 0000ffff l5: f0131550 l6: f012c000 l7: f0130400\n"
+       "i0: f1b13fb0 i1: 00000001 i2: 00000002 i3: 0007c000\n"
+       "i4: f01457c0 i5: 00000004 i6: f1b13f70 i7: f0015360\n"
+       "Instruction DUMP:\n"
+    );
+
+  if (!get_boolean_resource("doSparcLinux", "DoSparcLinux"))
+    return False;
+
+  for (s = linux_panic; *s; s++) if (*s == '\n') lines++;
+
+  XGetWindowAttributes (dpy, window, &xgwa);
+
+  fontname = get_string_resource ((xgwa.height > 600
+                                  ? "sparclinux.font2"
+                                  : "sparclinux.font"),
+                                 "SparcLinux.Font");
+  if (!fontname || !*fontname) fontname = (char *)def_font;
+  font = XLoadQueryFont (dpy, fontname);
+  if (!font) font = XLoadQueryFont (dpy, def_font);
+  if (!font) exit(-1);
+  if (fontname && fontname != def_font)
+    free (fontname);
+
+  gcv.font = font->fid;
+  gcv.foreground = get_pixel_resource(("sparclinux.foreground"),
+                                     "SparcLinux.Foreground",
+                                     dpy, xgwa.colormap);
+  gcv.background = get_pixel_resource(("sparclinux.background"),
+                                     "SparcLinux.Background",
+                                     dpy, xgwa.colormap);
+  XSetWindowBackground(dpy, window, gcv.background);
+  XClearWindow(dpy, window);
+
+  gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
+
+  draw_string(dpy, window, gc, &gcv, font,
+             10, xgwa.height - (lines * (font->ascent + font->descent + 1)),
+             10, 10,
+             linux_panic, 0);
+  XFreeGC(dpy, gc);
+  XSync(dpy, False);
+  bsod_sleep(dpy, delay);
+  XClearWindow(dpy, window);
+  XFreeFont(dpy, font);
+  return True;
+}
+
+/* BSD Panic by greywolf@starwolf.com - modeled after the Linux panic above.
+   By Grey Wolf <greywolf@siteROCK.com>
+ */
+static Bool
+bsd (Display *dpy, Window window, int delay)
+{
+  XGCValues gcv;
+  XWindowAttributes xgwa;
+  char *fontname;
+  const char *def_font = "fixed";
+  XFontStruct *font;
+  GC gc;
+  int lines = 1;
+  int i, n, b;
+  const char *rbstr, *panicking;
+  char syncing[80], bbuf[5], *bp;
+
+  const char *panicstr[] =
+   {"panic: ifree: freeing free inode",
+    "panic: blkfree: freeing free block",
+    "panic: improbability coefficient below zero",
+    "panic: cgsixmmap",
+    "panic: crazy interrupts",
+    "panic: nmi",
+    "panic: attempted windows install",
+    "panic: don't",
+    "panic: free inode isn't",
+    "panic: cpu_fork: curproc",
+    "panic: malloc: out of space in kmem_map",
+    "panic: vogon starship detected",
+    "panic: teleport chamber: out of order",
+    "panic: Brain fried - core dumped"};
+     
+  if (!get_boolean_resource("doBSD", "DoBSD"))
+    return False;
+
+  for (i = 0; i < sizeof(syncing); i++)
+    syncing[i] = 0;
+
+  i = (random() & 0xffff) % (sizeof(panicstr) / sizeof(*panicstr));
+
+  panicking = panicstr[i];
+  strcpy(syncing, "Syncing disks: ");
+
+  b = (random() & 0xff) % 40;
+  for (n = 0; (n < 20) && (b > 0); n++)
+    {
+      if (i)
+        {
+          i = (random() & 0x7);
+          b -= (random() & 0xff) % 20;
+          if (b < 0)
+            b = 0;
+        }
+      sprintf (bbuf, "%d ", b);
+      strcat (syncing, bbuf);
+    }
+
+  if (b)
+    rbstr = "damn!";
+  else
+    rbstr = "sunk!";
+
+  lines = 5;
+
+  XGetWindowAttributes (dpy, window, &xgwa);
+
+  fontname = get_string_resource ((xgwa.height > 600
+                                  ? "bsd.font2"
+                                  : "bsd.font"),
+                                 "BSD.Font");
+  if (!fontname || !*fontname) fontname = (char *)def_font;
+  font = XLoadQueryFont (dpy, fontname);
+  if (!font) font = XLoadQueryFont (dpy, def_font);
+  if (!font) exit(-1);
+  if (fontname && fontname != def_font)
+    free (fontname);
+
+  gcv.font = font->fid;
+  gcv.foreground = get_pixel_resource(("bsd.foreground"),
+                                     "BSD.Foreground",
+                                     dpy, xgwa.colormap);
+  gcv.background = get_pixel_resource(("bsd.background"),
+                                     "BSD.Background",
+                                     dpy, xgwa.colormap);
+  XSetWindowBackground(dpy, window, gcv.background);
+  XClearWindow(dpy, window);
+
+  gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
+
+  draw_string(dpy, window, gc, &gcv, font,
+             10, xgwa.height - (lines * (font->ascent + font->descent + 1)),
+             10, 10,
+             panicking, 0);
+  XSync(dpy, False);
+  lines--;
+
+  for (bp = syncing; *bp;)
+    {
+      char *bsd_bufs, oc = 0;
+      for (;*bp && (*bp != ' '); bp++)
+        ;
+      if (*bp == ' ')
+        {
+          oc = *bp;
+          *bp = 0;
+        }
+      bsd_bufs = strdup(syncing);
+      draw_string(dpy, window, gc, &gcv, font,
+                  10,
+                  xgwa.height - (lines * (font->ascent + font->descent + 1)),
+                  10, 10,
+                  bsd_bufs, 0);
+      XSync(dpy, False);
+      free(bsd_bufs);
+      if (oc)
+       *bp = oc;
+      if (bsod_sleep(dpy, -1))
+        goto DONE;
+      bp++;
+    }
+
+  lines--;
+  
+  draw_string(dpy, window, gc, &gcv, font,
+             10, xgwa.height - (lines * (font->ascent + font->descent + 1)),
+             10, 10,
+             rbstr, 0);
+  lines--;
+  draw_string(dpy, window, gc, &gcv, font,
+             10, xgwa.height - (lines * (font->ascent + font->descent + 1)),
+             10, 10,
+             "Rebooting", 0);
+
+  XFreeGC(dpy, gc);
+  XSync(dpy, False);
+  bsod_sleep(dpy, delay);
+
+DONE:
+  XClearWindow(dpy, window);
+  XFreeFont(dpy, font);
+  return True;
+}
+
+static Bool
 amiga (Display *dpy, Window window, int delay)
 {
   XGCValues gcv;
@@ -307,12 +666,15 @@ amiga (Display *dpy, Window window, int delay)
   int height;
   unsigned long fg, bg, bg2;
   Pixmap pixmap = 0;
-  int pix_w, pix_h;
+  int pix_w = 0, pix_h = 0;
 
   const char *string =
     ("_Software failure.  Press left mouse button to continue.\n"
      "_Guru Meditation #00000003.00C01570");
 
+  if (!get_boolean_resource("doAmiga", "DoAmiga"))
+    return False;
+
   XGetWindowAttributes (dpy, window, &xgwa);
 
   fontname = get_string_resource ((xgwa.height > 600
@@ -423,10 +785,92 @@ amiga (Display *dpy, Window window, int delay)
   XSync(dpy, False);
   XClearWindow(dpy, window);
   XFreeFont(dpy, font);
+  return True;
 }
 
 
-static void
+/* Atari ST, by Marcus Herbert <rhoenie@nobiscum.de>
+   Marcus had this to say:
+
+       Though I still have my Atari somewhere, I hardly remember
+       the meaning of the bombs. I think 9 bombs was "bus error" or
+       something like that.  And you often had a few bombs displayed
+       quickly and then the next few ones coming up step by step.
+       Perhaps somebody else can tell you more about it..  its just
+       a quick hack :-}
+ */
+static Bool
+atari (Display *dpy, Window window, int delay)
+{
+       
+  XGCValues gcv;
+  XWindowAttributes xgwa;
+  const char *def_font = "fixed";
+  XFontStruct *font;
+  GC gc;
+  Pixmap pixmap = 0;
+  int pix_w = atari_width;
+  int pix_h = atari_height;
+  int offset;
+  int i, x, y;
+
+  if (!get_boolean_resource("doAtari", "DoAtari"))
+    return False;
+
+  XGetWindowAttributes (dpy, window, &xgwa);
+
+  font = XLoadQueryFont (dpy, def_font);
+  if (!font) exit(-1);
+                
+  gcv.font = font->fid;
+  gcv.foreground = get_pixel_resource("atari.foreground", "Atari.Foreground",
+                                     dpy, xgwa.colormap);
+  gcv.background = get_pixel_resource("atari.background", "Atari.Background",
+                                     dpy, xgwa.colormap);
+
+  XSetWindowBackground(dpy, window, gcv.background);
+  XClearWindow(dpy, window);
+
+  gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
+
+  pixmap = XCreatePixmapFromBitmapData(dpy, window, (char *) atari_bits,
+                                      pix_w, pix_h,
+                                      gcv.foreground, gcv.background,
+                                      xgwa.depth);
+  pixmap = double_pixmap(dpy, gc, xgwa.visual, xgwa.depth,
+                        pixmap, pix_w, pix_h);
+  pix_w *= 2;
+  pix_h *= 2;
+
+  offset = pix_w + 2;
+  x = 5;
+  y = (xgwa.height - (xgwa.height / 5));
+  if (y < 0) y = 0;
+
+  for (i=0 ; i<7 ; i++) {
+    XCopyArea(dpy, pixmap, window, gc, 0, 0, pix_w, pix_h,
+             (x + (i*offset)), y);
+  }  
+  
+  for (i=7 ; i<10 ; i++) {
+    if (bsod_sleep(dpy, 1))
+      goto DONE;
+    XCopyArea(dpy, pixmap, window, gc, 0, 0, pix_w, pix_h,
+             (x + (i*offset)), y);
+  }
+
+  bsod_sleep(dpy, delay);
+ DONE:
+  XFreePixmap(dpy, pixmap);
+  XFreeGC(dpy, gc);
+  XSync(dpy, False);
+  XClearWindow(dpy, window);
+  XFreeFont(dpy, font);
+  return True;
+}
+
+
+static Bool
 mac (Display *dpy, Window window, int delay)
 {
   XGCValues gcv;
@@ -444,6 +888,9 @@ mac (Display *dpy, Window window, int delay)
   const char *string = ("0 0 0 0 0 0 0 F\n"
                        "0 0 0 0 0 0 0 3");
 
+  if (!get_boolean_resource("doMac", "DoMac"))
+    return False;
+
   XGetWindowAttributes (dpy, window, &xgwa);
 
   fontname = get_string_resource ("mac.font", "Mac.Font");
@@ -470,9 +917,6 @@ mac (Display *dpy, Window window, int delay)
                                       gcv.background,
                                       xgwa.depth);
 
-  draw_string(dpy, window, gc, &gcv, font, 0, 0,
-             xgwa.width, xgwa.height + offset, string, 0);
-
   for(i = 0; i < 2; i++)
     {
       pixmap = double_pixmap(dpy, gc, xgwa.visual, xgwa.depth,
@@ -490,14 +934,18 @@ mac (Display *dpy, Window window, int delay)
     XFreePixmap(dpy, pixmap);
   }
 
+  draw_string(dpy, window, gc, &gcv, font, 0, 0,
+             xgwa.width, xgwa.height + offset, string, 0);
+
   XFreeGC(dpy, gc);
   XSync(dpy, False);
   bsod_sleep(dpy, delay);
   XClearWindow(dpy, window);
   XFreeFont(dpy, font);
+  return True;
 }
 
-static void
+static Bool
 macsbug (Display *dpy, Window window, int delay)
 {
   XGCValues gcv;
@@ -565,14 +1013,52 @@ macsbug (Display *dpy, Window window, int delay)
                        "                                | 4A1F\n"
                        "     +00888    40843718     $0004(A7),([0,A7[)"
                        "                  ; 04E8D0AE    | 66B8");
+
+#if 0
   const char *body = ("Bus Error at 4BF6D6CC\n"
                      "while reading word from 4BF6D6CC in User data space\n"
                      " Unable to access that address\n"
                      "  PC: 2A0DE3E6\n"
                      "  Frame Type: B008");
+#else
+  const char * body = ("PowerPC unmapped memory exception at 003AFDAC "
+                                               "BowelsOfTheMemoryMgr+04F9C\n"
+                     " Calling chain using A6/R1 links\n"
+                     "  Back chain  ISA  Caller\n"
+                     "  00000000    PPC  28C5353C  __start+00054\n"
+                     "  24DB03C0    PPC  28B9258C  main+0039C\n"
+                     "  24DB0350    PPC  28B9210C  MainEvent+00494\n"
+                     "  24DB02B0    PPC  28B91B40  HandleEvent+00278\n"
+                     "  24DB0250    PPC  28B83DAC  DoAppleEvent+00020\n"
+                     "  24DB0210    PPC  FFD3E5D0  "
+                                               "AEProcessAppleEvent+00020\n"
+                     "  24DB0132    68K  00589468\n"
+                     "  24DAFF8C    68K  00589582\n"
+                     "  24DAFF26    68K  00588F70\n"
+                     "  24DAFEB3    PPC  00307098  "
+                                               "EmToNatEndMoveParams+00014\n"
+                     "  24DAFE40    PPC  28B9D0B0  DoScript+001C4\n"
+                     "  24DAFDD0    PPC  28B9C35C  RunScript+00390\n"
+                     "  24DAFC60    PPC  28BA36D4  run_perl+000E0\n"
+                     "  24DAFC10    PPC  28BC2904  perl_run+002CC\n"
+                     "  24DAFA80    PPC  28C18490  Perl_runops+00068\n"
+                     "  24DAFA30    PPC  28BE6CC0  Perl_pp_backtick+000FC\n"
+                     "  24DAF9D0    PPC  28BA48B8  Perl_my_popen+00158\n"
+                     "  24DAF980    PPC  28C5395C  sfclose+00378\n"
+                     "  24DAF930    PPC  28BA568C  free+0000C\n"
+                     "  24DAF8F0    PPC  28BA6254  pool_free+001D0\n"
+                     "  24DAF8A0    PPC  FFD48F14  DisposePtr+00028\n"
+                     "  24DAF7C9    PPC  00307098  "
+                                               "EmToNatEndMoveParams+00014\n"
+                     "  24DAF780    PPC  003AA180  __DisposePtr+00010");
+#endif
+
   const char *s;
   int body_lines = 1;
 
+  if (!get_boolean_resource("doMacsBug", "DoMacsBug"))
+    return False;
+
   for (s = body; *s; s++) if (*s == '\n') body_lines++;
 
   XGetWindowAttributes (dpy, window, &xgwa);
@@ -638,8 +1124,6 @@ macsbug (Display *dpy, Window window, int delay)
   draw_string(dpy, window, gc, &gcv, font, xoff, yoff, 10, 10, left, 0);
   draw_string(dpy, window, gc, &gcv, font, xoff+col_right, yoff+row_top,
              10, 10, bottom, 0);
-  draw_string(dpy, window, gc, &gcv, font,
-             xoff + col_right + char_width, yoff + body_top, 10, 10, body, 0);
 
   XFillRectangle(dpy, window, gc, xoff + col_right, yoff, 2, page_bottom);
   XDrawLine(dpy, window, gc,
@@ -648,6 +1132,13 @@ macsbug (Display *dpy, Window window, int delay)
            xoff+col_right, yoff+row_bottom, xoff+page_right, yoff+row_bottom);
   XDrawRectangle(dpy, window, gc,  xoff, yoff, page_right, page_bottom);
 
+  if (body_top > 4)
+    body_top = 4;
+
+  draw_string(dpy, window, gc, &gcv, font,
+             xoff + col_right + char_width, yoff + body_top, 10, 10, body,
+             500);
+
   while (delay > 0)
     {
       XDrawLine(dpy, window, gc,
@@ -669,6 +1160,86 @@ macsbug (Display *dpy, Window window, int delay)
   XFreeGC(dpy, gc2);
   XClearWindow(dpy, window);
   XFreeFont(dpy, font);
+  return True;
+}
+
+\f
+/* blit damage
+ *
+ * by Martin Pool <mbp@samba.org>, Feb 2000.
+ *
+ * This is meant to look like the preferred failure mode of NCD
+ * Xterms.  The parameters for choosing what to copy where might not
+ * be quite right, but it looks about ugly enough.
+ */
+static Bool
+blitdamage (Display *dpy, Window window, int delay)
+{
+  XGCValues gcv;
+  XWindowAttributes xwa;
+  GC gc0;
+  int i;
+  int delta_x = 0, delta_y = 0;
+  int w, h;
+  int chunk_h, chunk_w;
+  int steps;
+  long gc_mask = 0;
+  int src_x, src_y;
+  int x, y;
+  
+  if (!get_boolean_resource("doBlitDamage", "DoBlitDamage"))
+    return False;
+
+  XGetWindowAttributes(dpy, window, &xwa);
+
+  grab_screen_image(xwa.screen, window);
+
+  w = xwa.width;
+  h = xwa.height;
+
+  gc_mask = GCForeground;
+  
+  gcv.plane_mask = random();
+  gc_mask |= GCPlaneMask;
+  
+  gc0 = XCreateGC(dpy, window, gc_mask, &gcv);
+
+  steps = 50;
+  chunk_w = w / (random() % 1 + 1);
+  chunk_h = h / (random() % 1 + 1);
+  if (random() & 0x1000) 
+    delta_y = random() % 600;
+  if (!delta_y || (random() & 0x2000))
+    delta_x = random() % 600;
+  src_x = 0; 
+  src_y = 0; 
+  x = 0;
+  y = 0;
+  
+  for (i = 0; i < steps; i++) {
+    if (x + chunk_w > w) 
+      x -= w;
+    else
+      x += delta_x;
+    
+    if (y + chunk_h > h)
+      y -= h;
+    else
+      y += delta_y;
+    
+    XCopyArea(dpy, window, window, gc0,
+             src_x, src_y, 
+             chunk_w, chunk_h,
+             x, y);
+
+    bsod_sleep(dpy, 0);
+  }
+
+  bsod_sleep(dpy, delay);
+
+  XFreeGC(dpy, gc0);
+
+  return True;
 }
 
 
@@ -676,29 +1247,60 @@ macsbug (Display *dpy, Window window, int delay)
 char *progclass = "BSOD";
 
 char *defaults [] = {
-  "*delay:              30",
-
-  ".Windows.font:       -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
-  ".Windows.font2:      -*-courier-bold-r-*-*-*-180-*-*-m-*-*-*",
-  ".Windows.foreground:         White",
-  ".Windows.background:         Blue",
-
-  ".Amiga.font:                 -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
-  ".Amiga.font2:        -*-courier-bold-r-*-*-*-180-*-*-m-*-*-*",
-  ".Amiga.foreground:   Red",
-  ".Amiga.background:   Black",
-  ".Amiga.background2:  White",
-
-  ".Mac.font:           -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
-  ".Mac.foreground:     PaleTurquoise1",
-  ".Mac.background:     Black",
-
-  ".MacsBug.font:       -*-courier-medium-r-*-*-*-100-*-*-m-*-*-*",
-  ".MacsBug.font2:      -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
-  ".MacsBug.font3:      -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
-  ".MacsBug.foreground:         Black",
-  ".MacsBug.background:         White",
-  ".MacsBug.borderColor: #AAAAAA",
+  "*delay:                30",
+
+  "*doWindows:            True",
+  "*doNT:                 True",
+  "*doAmiga:              True",
+  "*doMac:                True",
+  "*doAtari:              False",      /* boring */
+  "*doMacsBug:            True",
+  "*doSCO:                True",
+  "*doBSD:                False",      /* boring */
+  "*doSparcLinux:         False",      /* boring */
+  "*doBlitDamage:          True",
+
+  ".Windows.font:         -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
+  ".Windows.font2:        -*-courier-bold-r-*-*-*-180-*-*-m-*-*-*",
+  ".Windows.foreground:           White",
+  ".Windows.background:           Blue",
+
+  ".Amiga.font:                   -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
+  ".Amiga.font2:          -*-courier-bold-r-*-*-*-180-*-*-m-*-*-*",
+  ".Amiga.foreground:     Red",
+  ".Amiga.background:     Black",
+  ".Amiga.background2:    White",
+
+  ".Mac.font:             -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
+  ".Mac.foreground:       PaleTurquoise1",
+  ".Mac.background:       Black",
+
+  ".Atari.foreground:     Black",
+  ".Atari.background:     White",
+
+  ".MacsBug.font:         -*-courier-medium-r-*-*-*-100-*-*-m-*-*-*",
+  ".MacsBug.font2:        -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
+  ".MacsBug.font3:        -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  ".MacsBug.foreground:           Black",
+  ".MacsBug.background:           White",
+  ".MacsBug.borderColor:   #AAAAAA",
+  
+  ".SCO.font:             -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
+  ".SCO.font2:            -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  ".SCO.foreground:       White",
+  ".SCO.background:       Black",
+  
+  ".SparcLinux.font:      -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
+  ".SparcLinux.font2:     -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  ".SparcLinux.foreground: White",
+  ".SparcLinux.background: Black",
+
+  ".BSD.font:              vga",
+  ".BSD.font:              -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
+  ".BSD.font2:             -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+/* ".BSD.font2:                    -sun-console-medium-r-*-*-22-*-*-*-m-*-*-*", */
+  ".BSD.foreground:        #c0c0c0",
+  ".BSD.background:        Black",
   0
 };
 
@@ -707,31 +1309,48 @@ XrmOptionDescRec options [] = {
   { 0, 0, 0, 0 }
 };
 
+
 void
 screenhack (Display *dpy, Window window)
 {
+  int loop = 0;
   int i = -1;
   int j = -1;
   int delay = get_integer_resource ("delay", "Integer");
   if (delay < 3) delay = 3;
 
   if (!get_boolean_resource ("root", "Boolean"))
-    XSelectInput(dpy, window, KeyPressMask|ButtonPressMask);
+    {
+      XWindowAttributes xgwa;
+      XGetWindowAttributes (dpy, window, &xgwa);
+      XSelectInput (dpy, window,
+                    xgwa.your_event_mask | KeyPressMask | ButtonPressMask);
+    }
 
   while (1)
     {
-      while (i == j) i = random() % 5;
-      j = i;
-
+      Bool did;
+      do {  i = (random() & 0xFF) % 10; } while (i == j);
       switch (i)
        {
-       case 0: windows(dpy, window, delay, True); break;
-       case 1: windows(dpy, window, delay, False); break;
-       case 2: amiga(dpy, window, delay); break;
-       case 3: mac(dpy, window, delay); break;
-       case 4: macsbug(dpy, window, delay); break;
+       case 0: did = windows(dpy, window, delay, True); break;
+       case 1: did = windows(dpy, window, delay, False); break;
+       case 2: did = amiga(dpy, window, delay); break;
+       case 3: did = mac(dpy, window, delay); break;
+       case 4: did = macsbug(dpy, window, delay); break;
+       case 5: did = sco(dpy, window, delay); break;
+       case 6: did = sparc_linux(dpy, window, delay); break;
+       case 7: did = bsd(dpy, window, delay); break;
+       case 8: did = atari(dpy, window, delay); break;
+       case 9: did = blitdamage(dpy, window, delay); break;
        default: abort(); break;
        }
-      XSync (dpy, True);
+      loop++;
+      if (loop > 100) j = -1;
+      if (loop > 200) exit(-1);
+      if (!did) continue;
+      XSync (dpy, False);
+      j = i;
+      loop = 0;
     }
 }