http://ftp.ksu.edu.tw/FTP/FreeBSD/distfiles/xscreensaver-4.20.tar.gz
[xscreensaver] / hacks / bsod.c
index 2ac1ab721b4ab837705a66aaa5522601f985aa2b..eb1fee355e06a7dd36e11abaf6f345c914364a1f 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1998-2002 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1998-2005 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
  * this version written by jwz, 4-Jun-98.
  */
 
+#include <math.h>
 #include "screenhack.h"
 #include "xpm-pixmap.h"
+#include "apple2.h"
 #include <stdio.h>
+#include <ctype.h>
 #include <time.h>
 #include <sys/time.h>
 #include <X11/Xutil.h>
 
+#ifdef HAVE_XSHM_EXTENSION
+#include "xshm.h"
+#endif
+
 #ifdef HAVE_UNAME
 # include <sys/utsname.h>
 #endif /* HAVE_UNAME */
@@ -30,6 +37,8 @@
 #include "images/macbomb.xbm"
 #include "images/hmac.xpm"
 
+#undef countof
+#define countof(x) (sizeof((x))/sizeof((*x)))
 
 static int
 draw_string (Display *dpy, Window window, GC gc, XGCValues *gcv,
@@ -195,7 +204,7 @@ bsod_sleep(Display *dpy, int seconds)
 }
 
 
-static Bool
+static void
 windows (Display *dpy, Window window, int delay, int which)
 {
   XGCValues gcv;
@@ -217,6 +226,12 @@ windows (Display *dpy, Window window, int delay, int which)
      "\n"
      "_Press any key to continue");
 
+# ifdef __GNUC__
+  __extension__   /* don't warn about "string length is greater than the
+                     length ISO C89 compilers are required to support"
+                     in the following string constant... */
+# endif
+
   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"
@@ -274,23 +289,71 @@ windows (Display *dpy, Window window, int delay, int which)
     ("Physical memory dump complete. Contact your system administrator or\n"
      "technical support group.\n");
 
+  const char *wmea =
+    ("    Windows protection error.  You need to restart your computer.");
+  const char *wmeb =
+    ("    System halted.");
+
+# ifdef __GNUC__
+  __extension__   /* don't warn about "string length is greater than the
+                     length ISO C89 compilers are required to support"
+                     in the following string constant... */
+# endif
+
+  const char *wxpa = /* From Wm. Rhodes <xscreensaver@27.org> */
+    ("A problem has been detected and windows has been shut down to prevent "
+      "damage\n"
+      "to your computer.\n"
+      "\n"
+      "If this is the first time you've seen this Stop error screen,\n"
+      "restart your computer. If this screen appears again, follow\n"
+      "these steps:\n"
+      "\n"
+      "Check to be sure you have adequate disk space. If a driver is\n"
+      "identified in the Stop message, disable the driver or check\n"
+      "with the manufacturer for driver updates. Try changing video\n"
+      "adapters.\n"
+      "\n"
+      "Check with your hardware vendor for any BIOS updates. Disable\n"
+      "BIOS memory options such as caching or shadowing. If you need\n"
+      "to use Safe Mode to remove or disable components, restart your\n"
+      "computer, press F8 to select Advanced Startup Options, and then\n"
+      "select Safe Mode.\n"
+      "\n"
+      "Technical information:\n"
+      "\n"
+      "*** STOP: 0x0000007E (0xC0000005,0xF88FF190,0x0xF8975BA0,0xF89758A0)\n"
+      "\n"
+      "\n"
+      "***  EPUSBDSK.sys - Address F88FF190 base at FF88FE000, datestamp "
+      "3b9f3248\n"
+      "\n"
+      "Beginning dump of physical memory\n");
+  const char *wxpb =
+    ("Physical memory dump complete.\n"
+     "Contact your system administrator or technical support group for "
+     "further\n"
+     "assitance.\n"
+     );
+
   if (which < 0 || which > 2) abort();
 
-  if (!get_boolean_resource((which == 0 ? "doWindows" :
-                             which == 1 ? "doNT" :
-                                          "doWin2K"),
-                            "DoWindows"))
-    return False;
+  /* kludge to lump Win2K, WinME, and WinXP together; seems silly to add
+     another preference/command line option just for these little ones. */
+  if (which == 2 && (random() % 2))
+    which = 3 + (random() % 2);
 
   XGetWindowAttributes (dpy, window, &xgwa);
 
   fontname = get_string_resource ((xgwa.height > 600
                                   ? (which == 0 ? "windows95.font2" :
                                       which == 1 ? "windowsNT.font2" :
-                                                   "windows2K.font2")
+                                      which == 2 ? "windows2K.font2" :
+                                                   "windowsME.font2")
                                   : (which == 0 ? "windows95.font" :
                                      which == 1 ? "windowsNT.font" :
-                                                   "windows2K.font")),
+                                     which == 2 ? "windows2K.font" :
+                                                   "windowsME.font")),
                                  "Windows.Font");
   if (!fontname || !*fontname) fontname = (char *)def_font;
   font = XLoadQueryFont (dpy, fontname);
@@ -302,12 +365,14 @@ windows (Display *dpy, Window window, int delay, int which)
   gcv.font = font->fid;
   gcv.foreground = get_pixel_resource((which == 0 ? "windows95.foreground" :
                                       which == 1 ? "windowsNT.foreground" :
-                                                    "windows2K.foreground"),
+                                      which == 2 ? "windows2K.foreground" :
+                                                    "windowsME.foreground"),
                                      "Windows.Foreground",
                                      dpy, xgwa.colormap);
   gcv.background = get_pixel_resource((which == 0 ? "windows95.background" :
                                       which == 1 ? "windowsNT.background" :
-                                                    "windows2K.background"),
+                                      which == 2 ? "windows2K.background" :
+                                                    "windowsME.background"),
                                      "Windows.Background",
                                      dpy, xgwa.colormap);
   XSetWindowBackground(dpy, window, gcv.background);
@@ -320,7 +385,7 @@ windows (Display *dpy, Window window, int delay, int which)
                0, 0, xgwa.width, xgwa.height, w95, 0);
   else if (which == 1)
     draw_string(dpy, window, gc, &gcv, font, 0, 0, 10, 10, wnt, 750);
-  else
+  else if (which == 2)
     {
       int line_height = font->ascent + font->descent + 1;
       int x = 20;
@@ -331,18 +396,71 @@ windows (Display *dpy, Window window, int delay, int which)
       bsod_sleep(dpy, 4);
       draw_string(dpy, window, gc, &gcv, font, x, y, 10, 10, w2kb, 750);
     }
+  else if (which == 3)
+    {
+      int line_height = font->ascent + font->descent + 1;
+      int x = 4;
+      int y = 4;
+      draw_string(dpy, window, gc, &gcv, font, x, y, 10, 10, wxpa, 750);
+      y += line_height * 26;
+      bsod_sleep(dpy, 4);
+      draw_string(dpy, window, gc, &gcv, font, x, y, 10, 10, wxpb, 750);
+    }
+  else if (which == 4)
+    {
+      int line_height = font->ascent + font->descent;
+      int x = 0;
+      int y = (xgwa.height - line_height * 3) / 2;
+      draw_string (dpy, window, gc, &gcv, font, x, y, 10, 10, wmea, 0);
+      y += line_height * 2;
+      x = draw_string (dpy, window, gc, &gcv, font, x, y, 10, 10, wmeb, 0);
+      y += line_height;
+      while (delay > 0)
+        {
+          XDrawImageString (dpy, window, gc, x, y, "_", 1);
+          XSync(dpy, False);
+          usleep(120000L);
+          XDrawImageString (dpy, window, gc, x, y, " ", 1);
+          XSync(dpy, False);
+          usleep(120000L);
+          if (bsod_sleep(dpy, 0))
+            delay = 0;
+          else
+            delay--;
+        }
+    }
+  else
+    abort();
 
   XFreeGC(dpy, gc);
   XSync(dpy, False);
   bsod_sleep(dpy, delay);
   XClearWindow(dpy, window);
   XFreeFont(dpy, font);
-  return True;
 }
 
+static void
+windows_31 (Display *dpy, Window window, int delay)
+{
+  windows (dpy, window, delay, 0);
+}
+
+static void
+windows_nt (Display *dpy, Window window, int delay)
+{
+  windows (dpy, window, delay, 1);
+}
+
+static void
+windows_2k (Display *dpy, Window window, int delay)
+{
+  windows (dpy, window, delay, 2);
+}
+
+
 /* SCO OpenServer 5 panic, by Tom Kelly <tom@ancilla.toronto.on.ca>
  */
-static Bool
+static void
 sco (Display *dpy, Window window, int delay)
 {
   XGCValues gcv;
@@ -354,6 +472,12 @@ sco (Display *dpy, Window window, int delay)
   int lines_1 = 0, lines_2 = 0, lines_3 = 0, lines_4 = 0;
   const char *s;
 
+# ifdef __GNUC__
+  __extension__   /* don't warn about "string length is greater than the
+                     length ISO C89 compilers are required to support"
+                     in the following string constant... */
+# endif
+
   const char *sco_panic_1 =
     ("Unexpected trap in kernel mode:\n"
      "\n"
@@ -368,7 +492,8 @@ sco (Display *dpy, Window window, int delay)
      "Trying to dump 5023 pages to dumpdev hd (1/41), 63 pages per '.'\n"
     );
   const char *sco_panic_2 =
-   ("...............................................................................\n"
+   ("................................................................."
+    "..............\n"
     );
   const char *sco_panic_3 =
     ("5023 pages dumped\n"
@@ -381,9 +506,6 @@ sco (Display *dpy, Window window, int delay)
      "** 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++;
@@ -455,13 +577,12 @@ sco (Display *dpy, Window window, int delay)
   XClearWindow(dpy, window);
   XFreeGC(dpy, gc);
   XFreeFont(dpy, font);
-  return True;
 }
 
 
 /* Linux (sparc) panic, by Tom Kelly <tom@ancilla.toronto.on.ca>
  */
-static Bool
+static void
 sparc_linux (Display *dpy, Window window, int delay)
 {
   XGCValues gcv;
@@ -473,6 +594,12 @@ sparc_linux (Display *dpy, Window window, int delay)
   int lines = 1;
   const char *s;
 
+# ifdef __GNUC__
+  __extension__   /* don't warn about "string length is greater than the
+                     length ISO C89 compilers are required to support"
+                     in the following string constant... */
+# endif
+
   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"
@@ -495,9 +622,6 @@ sparc_linux (Display *dpy, Window window, int delay)
        "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);
@@ -534,13 +658,12 @@ sparc_linux (Display *dpy, Window window, int delay)
   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
+static void
 bsd (Display *dpy, Window window, int delay)
 {
   XGCValues gcv;
@@ -570,9 +693,6 @@ bsd (Display *dpy, Window window, int delay)
     "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;
 
@@ -678,10 +798,9 @@ bsd (Display *dpy, Window window, int delay)
 DONE:
   XClearWindow(dpy, window);
   XFreeFont(dpy, font);
-  return True;
 }
 
-static Bool
+static void
 amiga (Display *dpy, Window window, int delay)
 {
   XGCValues gcv;
@@ -701,9 +820,6 @@ amiga (Display *dpy, Window window, int delay)
     ("_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
@@ -793,7 +909,6 @@ amiga (Display *dpy, Window window, int delay)
   XSync(dpy, False);
   XClearWindow(dpy, window);
   XFreeFont(dpy, font);
-  return True;
 }
 
 
@@ -807,7 +922,7 @@ amiga (Display *dpy, Window window, int delay)
        Perhaps somebody else can tell you more about it..  its just
        a quick hack :-}
  */
-static Bool
+static void
 atari (Display *dpy, Window window, int delay)
 {
        
@@ -822,9 +937,6 @@ atari (Display *dpy, Window window, int delay)
   int offset;
   int i, x, y;
 
-  if (!get_boolean_resource("doAtari", "DoAtari"))
-    return False;
-
   XGetWindowAttributes (dpy, window, &xgwa);
 
   font = XLoadQueryFont (dpy, def_font);
@@ -874,11 +986,10 @@ atari (Display *dpy, Window window, int delay)
   XSync(dpy, False);
   XClearWindow(dpy, window);
   XFreeFont(dpy, font);
-  return True;
 }
 
 
-static Bool
+static void
 mac (Display *dpy, Window window, int delay)
 {
   XGCValues gcv;
@@ -896,9 +1007,6 @@ 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");
@@ -950,10 +1058,9 @@ mac (Display *dpy, Window window, int delay)
   bsod_sleep(dpy, delay);
   XClearWindow(dpy, window);
   XFreeFont(dpy, font);
-  return True;
 }
 
-static Bool
+static void
 macsbug (Display *dpy, Window window, int delay)
 {
   XGCValues gcv;
@@ -967,6 +1074,12 @@ macsbug (Display *dpy, Window window, int delay)
   int col_right, row_top, row_bottom, page_right, page_bottom, body_top;
   int xoff, yoff;
 
+# ifdef __GNUC__
+  __extension__   /* don't warn about "string length is greater than the
+                     length ISO C89 compilers are required to support"
+                     in the following string constant... */
+# endif
+
   const char *left = ("    SP     \n"
                      " 04EB0A58  \n"
                      "58 00010000\n"
@@ -1029,6 +1142,13 @@ macsbug (Display *dpy, Window window, int delay)
                      "  PC: 2A0DE3E6\n"
                      "  Frame Type: B008");
 #else
+
+# ifdef __GNUC__
+  __extension__   /* don't warn about "string length is greater than the
+                     length ISO C89 compilers are required to support"
+                     in the following string constant... */
+# endif
+
   const char * body = ("PowerPC unmapped memory exception at 003AFDAC "
                                                "BowelsOfTheMemoryMgr+04F9C\n"
                      " Calling chain using A6/R1 links\n"
@@ -1064,9 +1184,6 @@ macsbug (Display *dpy, Window window, int delay)
   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);
@@ -1168,10 +1285,9 @@ macsbug (Display *dpy, Window window, int delay)
   XFreeGC(dpy, gc2);
   XClearWindow(dpy, window);
   XFreeFont(dpy, font);
-  return True;
 }
 
-static Bool
+static void
 mac1 (Display *dpy, Window window, int delay)
 {
   XGCValues gcv;
@@ -1181,9 +1297,6 @@ mac1 (Display *dpy, Window window, int delay)
   int pix_w = macbomb_width;
   int pix_h = macbomb_height;
 
-  if (!get_boolean_resource("doMac1", "DoMac1"))
-    return False;
-
   XGetWindowAttributes (dpy, window, &xgwa);
 
   gcv.foreground = get_pixel_resource("mac1.foreground", "Mac.Foreground",
@@ -1218,11 +1331,10 @@ mac1 (Display *dpy, Window window, int delay)
   XSync(dpy, False);
   bsod_sleep(dpy, delay);
   XClearWindow(dpy, window);
-  return True;
 }
 
 
-static Bool
+static void
 macx (Display *dpy, Window window, int delay)
 {
   XGCValues gcv;
@@ -1232,6 +1344,12 @@ macx (Display *dpy, Window window, int delay)
   XFontStruct *font;
   GC gc;
 
+# ifdef __GNUC__
+  __extension__   /* don't warn about "string length is greater than the
+                     length ISO C89 compilers are required to support"
+                     in the following string constant... */
+# endif
+
   const char *macx_panic =
    ("panic(cpu 0): Unable to find driver for this platform: "
     "\"PowerMac 3,5\".\n"
@@ -1259,9 +1377,6 @@ macx (Display *dpy, Window window, int delay)
     "\n"
     "panic: We are hanging here...\n");
 
-  if (!get_boolean_resource("doMacX", "DoMacX"))
-    return False;
-
   XGetWindowAttributes (dpy, window, &xgwa);
 
   gcv.background = get_pixel_resource("macX.background",
@@ -1363,12 +1478,8 @@ macx (Display *dpy, Window window, int delay)
   XSync(dpy, False);
   bsod_sleep(dpy, delay);
   XClearWindow(dpy, window);
-  return True;
 }
 
-
-
-
 \f
 /* blit damage
  *
@@ -1378,7 +1489,7 @@ macx (Display *dpy, Window window, int delay)
  * Xterms.  The parameters for choosing what to copy where might not
  * be quite right, but it looks about ugly enough.
  */
-static Bool
+static void
 blitdamage (Display *dpy, Window window, int delay)
 {
   XGCValues gcv;
@@ -1393,12 +1504,9 @@ blitdamage (Display *dpy, Window window, int delay)
   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);
+  load_random_image (xwa.screen, window, window, NULL, NULL);
 
   w = xwa.width;
   h = xwa.height;
@@ -1446,8 +1554,177 @@ blitdamage (Display *dpy, Window window, int delay)
 
  DONE:
   XFreeGC(dpy, gc0);
+}
+
+\f
+/* nvidia, by jwz.
+ *
+ * This is what happens if an Nvidia card goes into some crazy text mode.
+ * Most often seen on the second screen of a dual-head system when the
+ * proper driver isn't loaded.
+ */
+typedef struct { int fg; int bg; int bit; Bool blink; } nvcell;
+
+static void
+nvspatter (nvcell *grid, int rows, int cols, int ncolors, int nbits,
+           Bool fill_p)
+{
+  int max = rows * cols;
+  int from = fill_p ?   0 : random() % (max - 1);
+  int len  = fill_p ? max : random() % (cols * 4);
+  int to = from + len;
+  int i;
+  Bool noisy = ((random() % 4) == 0);
+  Bool diag = (noisy || fill_p) ? 0 : ((random() % 4) == 0);
+
+  int fg = random() % ncolors;
+  int bg = random() % ncolors;
+  int blink = ((random() % 4) == 0);
+  int bit = (random() % nbits);
+
+  if (to > max) to = max;
+
+  if (diag)
+    {
+      int src = random() % (rows * cols);
+      int len2 = (cols / 2) - (random() % 5);
+      int j = src;
+      for (i = from; i < to; i++, j++)
+        {
+          if (j > src + len2 || j >= max)
+            j = src;
+          if (i >= max) abort();
+          if (j >= max) abort();
+          grid[j] = grid[i];
+        }
+    }
+  else
+    for (i = from; i < to; i++)
+      {
+        nvcell *cell = &grid[i];
+        cell->fg = fg;
+        cell->bg = bg;
+        cell->bit = bit;
+        cell->blink = blink;
+
+        if (noisy)
+          {
+            fg = random() % ncolors;
+            bg = random() % ncolors;
+            blink = ((random() % 8) == 0);
+          }
+      }
+}
+
+
+static void
+nvidia (Display *dpy, Window window, int delay)
+{
+  XGCValues gcv;
+  XWindowAttributes xgwa;
+  int cols, rows;
+  int cellw, cellh;
+  unsigned long colors[256];
+  int ncolors;
+  GC gc, gc1 = 0;
+  int x, y, i;
+  int tick = 0;
+  nvcell *grid;
+  Pixmap bits[5];
+
+  XGetWindowAttributes (dpy, window, &xgwa);
+
+  cols = 80;
+  rows = 25;
+  cellw = xgwa.width  / cols;
+  cellh = xgwa.height / rows;
+  if (cellw < 8 || cellh < 18)
+    cellw = 8, cellh = 18;
+  cols = (xgwa.width  / cellw) + 1;
+  rows = (xgwa.height / cellh) + 1;
+
+  grid = (nvcell *) calloc (sizeof(*grid), rows * cols);
+  gc = XCreateGC (dpy, window, 0, &gcv);
+
+  /* Allocate colors
+   */
+  ncolors = 16;
+  for (i = 0; i < ncolors; i++)
+    {
+      XColor c;
+      c.red   = random() & 0xFFFF;
+      c.green = random() & 0xFFFF;
+      c.blue  = random() & 0xFFFF;
+      c.flags = DoRed|DoGreen|DoBlue;
+      XAllocColor (dpy, xgwa.colormap, &c);
+      colors[i] = c.pixel;
+    }
+
+  /* Construct corrupted character bitmaps
+   */
+  for (i = 0; i < countof(bits); i++)
+    {
+      int j;
+
+      bits[i] = XCreatePixmap (dpy, window, cellw, cellh, 1);
+      if (!gc1) gc1 = XCreateGC (dpy, bits[i], 0, &gcv);
+
+      XSetForeground (dpy, gc1, 0);
+      XFillRectangle (dpy, bits[i], gc1, 0, 0, cellw, cellh);
+      XSetForeground (dpy, gc1, ~0L);
+
+      if ((random() % 40) != 0)
+        for (j = 0; j < ((cellw * cellh) / 16); j++)
+          XFillRectangle (dpy, bits[i], gc1,
+                          (random() % (cellw-2)) & ~1,
+                          (random() % (cellh-2)) & ~1,
+                          2, 2);
+    }
+
+  /* Randomize the grid
+   */
+  nvspatter (grid, rows, cols, ncolors, countof(bits), True);
+  for (i = 0; i < 20; i++)
+    nvspatter (grid, rows, cols, ncolors, countof(bits), False);
+
+
+  /* Redisplay loop: blink 3x/second
+   */
+  while (1)
+    {
+      for (y = 0; y < rows; y++)
+        for (x = 0; x < cols; x++)
+          {
+            nvcell *cell = &grid[y * cols + x];
+            unsigned long fg = colors[cell->fg];
+            unsigned long bg = colors[cell->bg];
+            Bool flip = cell->blink && (tick & 1);
+            XSetForeground (dpy, gc, flip ? fg : bg);
+            XSetBackground (dpy, gc, flip ? bg : fg);
+            XCopyPlane (dpy, bits[cell->bit], window, gc,
+                        0, 0, cellw, cellh,
+                        x * cellw, y * cellh, 1L);
+          }
+
+      if ((random() % 5) == 0)    /* change the display */
+        nvspatter (grid, rows, cols, ncolors, countof(bits), False);
+
+      XSync (dpy, False);
+      usleep (333333);
+      if (bsod_sleep(dpy, 0))
+        goto DONE;
+      if (tick / 3 >= delay)
+        goto DONE;
+      tick++;
+    }
 
-  return True;
+ DONE:
+  XFreeColors (dpy, xgwa.colormap, colors, ncolors, 0);
+  for (i = 0; i < countof(bits); i++)
+    XFreePixmap (dpy, bits[i]);
+  XFreeGC (dpy, gc);
+  XFreeGC (dpy, gc1);
+  free (grid);
 }
 
 \f
@@ -1534,7 +1811,7 @@ make_scrolling_window (Display *dpy, Window window,
   if (!grab_screen_p) ts->sub_height += ts->sub_y, ts->sub_y = 0;
 
   if (grab_screen_p)
-    grab_screen_image (xgwa.screen, window);
+    load_random_image (xgwa.screen, window, window, NULL, NULL);
 
   sprintf (buf1, "%.50s.background", name);
   sprintf (buf2, "%.50s.Background", name);
@@ -1579,6 +1856,8 @@ scrolling_putc (scrolling_window* ts, const char aChar)
                       ts->sub_x, ts->sub_y + ts->sub_height - ts->line_height,
                       ts->sub_width, ts->line_height);
       break;
+    case '\r':
+      ts->x = 0;
     case '\b':
       if(ts->x > 0)
         ts->x--;
@@ -1616,12 +1895,18 @@ scrolling_puts (scrolling_window *ts, const char* aString, int delay)
   return False;
 }
 
-static Bool
+static void
 sparc_solaris (Display* dpy, Window window, int delay)
 {
+# ifdef __GNUC__
+  __extension__   /* don't warn about "string length is greater than the
+                     length ISO C89 compilers are required to support"
+                     in the following string constant... */
+# endif
+
   const char *msg1 =
     "BAD TRAP: cpu=0 type=0x31 rp=0x2a10043b5e0 addr=0xf3880 mmu_fsr=0x0\n"
-    "BAD TRAP occured in module \"unix\" due to an illegal access to a"
+    "BAD TRAP occurred in module \"unix\" due to an illegal access to a"
     " user address.\n"
     "adb: trap type = 0x31\n"
     "addr=0xf3880\n"
@@ -1659,9 +1944,6 @@ sparc_solaris (Display* dpy, Window window, int delay)
   int i;
   char buf[256];
 
-  if (!get_boolean_resource("doSolaris", "DoSolaris"))
-    return False;
-
   ts = make_scrolling_window (dpy, window, "Solaris", True);
 
   scrolling_puts (ts, msg1, 0);
@@ -1692,13 +1974,11 @@ sparc_solaris (Display* dpy, Window window, int delay)
 
  DONE:
   free_scrolling_window (ts);
-
-  return True;
 }
 
 /* Linux panic and fsck, by jwz
  */
-static Bool
+static void
 linux_fsck (Display *dpy, Window window, int delay)
 {
   XWindowAttributes xgwa;
@@ -1740,9 +2020,6 @@ linux_fsck (Display *dpy, Window window, int delay)
    0
   };
 
-  if (!get_boolean_resource("doLinux", "DoLinux"))
-    return False;
-
   XGetWindowAttributes (dpy, window, &xgwa);
   XSetWindowBackground (dpy, window, 
                         get_pixel_resource("Linux.background",
@@ -2056,7 +2333,7 @@ linux_fsck (Display *dpy, Window window, int delay)
 
       if (*linux_panic[i])
         {
-          strftime (prefix, sizeof(prefix)-1, "%b %d %k:%M:%S ", tm);
+          strftime (prefix, sizeof(prefix)-1, "%b %d %H:%M:%S ", tm);
           scrolling_puts (ts, prefix, 0);
           scrolling_puts (ts, sysname, 0);
           scrolling_puts (ts, linux_panic[i], 0);
@@ -2081,103 +2358,1295 @@ linux_fsck (Display *dpy, Window window, int delay)
  DONE:
   free_scrolling_window (ts);
   XClearWindow(dpy, window);
-  return True;
 }
 
-
 \f
-char *progclass = "BSOD";
 
-char *defaults [] = {
-  "*delay:                30",
+/*
+ * Linux (hppa) panic, by Stuart Brady <sdbrady@ntlworld.com>
+ * Output courtesy of M. Grabert
+ */
+static void
+hppa_linux (Display *dpy, Window window, int delay)
+{
+  XWindowAttributes xgwa;
+  scrolling_window *ts;
+  int i=0;
+  const char *sysname;
+  long int linedelay=0;
+
+# ifdef __GNUC__
+  __extension__   /* don't warn about "string length is greater than the
+                     length ISO C89 compilers are required to support"
+                     in the following string constant... */
+# endif
+
+  struct { long int delay; const char *string; } linux_panic[] =
+    {{ 0, "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
+          "\n\n\n\n\n\n\n\n\n\n\n\n\n" },
+     { 0, "Linux version 2.6.0-test11-pa2 (root@%s) "
+          "(gcc version 3.3.2 (Debian)) #2 Mon Dec 8 06:09:27 GMT 2003\n" },
+     { 4000, "FP[0] enabled: Rev 1 Model 16\n" },
+     { 10, "The 32-bit Kernel has started...\n" },
+     { -1, "Determining PDC firmware type: System Map.\n" },
+     { -1, "model 00005bb0 00000481 00000000 00000002 7778df9f 100000f0 "
+           "00000008 000000b2 000000b2\n" },
+     { -1, "vers  00000203\n" },
+     { -1, "CPUID vers 17 rev 7 (0x00000227)\n" },
+     { -1, "capabilities 0x3\n" },
+     { -1, "model 9000/785/C3000\n" },
+     { -1, "Total Memory: 1024 Mb\n" },
+     { -1, "On node 0 totalpages: 262144\n" },
+     { -1, "  DMA zone: 262144 pages, LIFO batch:16\n" },
+     { -1, "  Normal zone: 0 pages, LIFO batch:1\n" },
+     { -1, "  HighMem zone: 0 pages, LIFO batch:1\n" },
+     { -1, "LCD display at f05d0008,f05d0000 registered\n" },
+     { -1, "Building zonelist for node : 0\n" },
+     { -1, "Kernel command line: ide=nodma root=/dev/sda3 HOME=/ ip=off "
+           "console=ttyS0 TERM=vt102 palo_kernel=2/vmlinux-2.6\n" },
+     { -1, "ide_setup: ide=nodmaIDE: Prevented DMA\n" },
+     { -1, "PID hash table entries: 16 (order 4: 128 bytes)\n" },
+     {500, "Console: colour dummy device 160x64\n" },
+     { 10, "Memory: 1034036k available\n" },
+     { -1, "Calibrating delay loop... 796.67 BogoMIPS\n" },
+     { -1, "Dentry cache hash table entries: 131072 (order: 7, 524288 "
+           "bytes)\n" },
+     { -1, "Inode-cache hash table entries: 65536 (order: 6, 262144 "
+           "bytes)\n" },
+     { -1, "Mount-cache hash table entries: 512 (order: 0, 4096 bytes)\n" },
+     { -1, "POSIX conformance testing by UNIFIX\n" },
+     { -1, "NET: Registered protocol family 16\n" },
+     { 100, "Searching for devices...\n" },
+     { 25, "Found devices:\n" },
+     { 10, "1. Astro BC Runway Port at 0xfed00000 [10] "
+           "{ 12, 0x0, 0x582, 0x0000b }\n" },
+     { -1, "2. Elroy PCI Bridge at 0xfed30000 [10/0] "
+           "{ 13, 0x0, 0x782, 0x0000a }\n" },
+     { -1, "3. Elroy PCI Bridge at 0xfed32000 [10/1] "
+           "{ 13, 0x0, 0x782, 0x0000a }\n" },
+     { -1, "4. Elroy PCI Bridge at 0xfed38000 [10/4] "
+           "{ 13, 0x0, 0x782, 0x0000a }\n" },
+     { -1, "5. Elroy PCI Bridge at 0xfed3c000 [10/6] "
+           "{ 13, 0x0, 0x782, 0x0000a }\n" },
+     { -1, "6. AllegroHigh W at 0xfffa0000 [32] "
+           "{ 0, 0x0, 0x5bb, 0x00004 }\n" },
+     { -1, "7. Memory at 0xfed10200 [49] { 1, 0x0, 0x086, 0x00009 }\n" },
+     { -1, "CPU(s): 1 x PA8500 (PCX-W) at 400.000000 MHz\n" },
+     { -1, "SBA found Astro 2.1 at 0xfed00000\n" },
+     { -1, "lba version TR2.1 (0x2) found at 0xfed30000\n" },
+     { -1, "lba version TR2.1 (0x2) found at 0xfed32000\n" },
+     { -1, "lba version TR2.1 (0x2) found at 0xfed38000\n" },
+     { -1, "lba version TR2.1 (0x2) found at 0xfed3c000\n" },
+     { 100, "SCSI subsystem initialized\n" },
+     { 10, "drivers/usb/core/usb.c: registered new driver usbfs\n" },
+     { -1, "drivers/usb/core/usb.c: registered new driver hub\n" },
+     { -1, "ikconfig 0.7 with /proc/config*\n" },
+     { -1, "Initializing Cryptographic API\n" },
+     { 250, "SuperIO: probe of 0000:00:0e.0 failed with error -1\n" },
+     { 20, "SuperIO: Found NS87560 Legacy I/O device at 0000:00:0e.1 "
+           "(IRQ 64)\n" },
+     { -1, "SuperIO: Serial port 1 at 0x3f8\n" },
+     { -1, "SuperIO: Serial port 2 at 0x2f8\n" },
+     { -1, "SuperIO: Parallel port at 0x378\n" },
+     { -1, "SuperIO: Floppy controller at 0x3f0\n" },
+     { -1, "SuperIO: ACPI at 0x7e0\n" },
+     { -1, "SuperIO: USB regulator enabled\n" },
+     { -1, "SuperIO: probe of 0000:00:0e.2 failed with error -1\n" },
+     { -1, "Soft power switch enabled, polling @ 0xf0400804.\n" },
+     { -1, "pty: 256 Unix98 ptys configured\n" },
+     { -1, "Generic RTC Driver v1.07\n" },
+     { -1, "Serial: 8250/16550 driver $Revision: 1.63 $ 13 ports, "
+           "IRQ sharing disabled\n" },
+     { -1, "ttyS0 at I/O 0x3f8 (irq = 0) is a 16550A\n" },
+     { -1, "ttyS1 at I/O 0x2f8 (irq = 0) is a 16550A\n" },
+     { -1, "Linux Tulip driver version 1.1.13 (May 11, 2002)\n" },
+     { 150, "tulip0: no phy info, aborting mtable build\n" },
+     { 10, "tulip0:  MII transceiver #1 config 1000 status 782d "
+           "advertising 01e1.\n" },
+     { -1, "eth0: Digital DS21143 Tulip rev 65 at 0xf4008000, "
+           "00:10:83:F9:B4:34, IRQ 66.\n" },
+     { -1, "Uniform Multi-Platform E-IDE driver Revision: 7.00alpha2\n" },
+     { -1, "ide: Assuming 33MHz system bus speed for PIO modes; "
+           "override with idebus=xx\n" },
+     { 100, "SiI680: IDE controller at PCI slot 0000:01:06.0\n" },
+     { 10, "SiI680: chipset revision 2\n" },
+     { -1, "SiI680: BASE CLOCK == 133\n" },
+     { -1, "SiI680: 100% native mode on irq 128\n" },
+     { -1, "    ide0: MMIO-DMA at 0xf4800000-0xf4800007 -- "
+           "Error, MMIO ports already in use.\n" },
+     { -1, "    ide1: MMIO-DMA at 0xf4800008-0xf480000f -- "
+           "Error, MMIO ports already in use.\n" },
+     { 5, "hda: TS130220A2, ATA DISK drive\n" },
+     { -1, "      _______________________________\n" },
+     { -1, "     < Your System ate a SPARC! Gah! >\n" },
+     { -1, "      -------------------------------\n" },
+     { -1, "             \\   ^__^\n" },
+     { -1, "              \\  (xx)\\_______\n" },
+     { -1, "                 (__)\\       )\\/\\\n" },
+     { -1, "                  U  ||----w |\n" },
+     { -1, "                     ||     ||\n" },
+     { -1, "swapper (pid 1): Breakpoint (code 0)\n" },
+     { -1, "\n" },
+     { -1, "     YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI\n" },
+     { -1, "PSW: 00000000000001001111111100001111 Not tainted\n" },
+     { -1, "r00-03  4d6f6f21 1032f010 10208f34 103fc2e0\n" },
+     { -1, "r04-07  103fc230 00000001 00000001 0000000f\n" },
+     { -1, "r08-11  103454f8 000f41fa 372d3980 103ee404\n" },
+     { -1, "r12-15  3ccbf700 10344810 103ee010 f0400004\n" },
+     { -1, "r16-19  f00008c4 f000017c f0000174 00000000\n" },
+     { -1, "r20-23  fed32840 fed32800 00000000 0000000a\n" },
+     { -1, "r24-27  0000ffa0 000000ff 103fc2e0 10326010\n" },
+     { -1, "r28-31  00000000 00061a80 4ff98340 10208f34\n" },
+     { -1, "sr0-3   00000000 00000000 00000000 00000000\n" },
+     { -1, "sr4-7   00000000 00000000 00000000 00000000\n" },
+     { -1, "\n" },
+     { -1, "IASQ: 00000000 00000000 IAOQ: 00000000 00000004\n" },
+     { -1, " IIR: 00000000    ISR: 00000000  IOR: 00000000\n" },
+     { -1, " CPU:        0   CR30: 4ff98000 CR31: 1037c000\n" },
+     { -1, " ORIG_R28: 55555555\n" },
+     { -1, " IAOQ[0]: 0x0\n" },
+     { -1, " IAOQ[1]: 0x4\n" },
+     { -1, " RP(r2): probe_hwif+0x218/0x44c\n" },
+     { -1, "Kernel panic: Attempted to kill init!\n" },
+     { 0, NULL }};
 
-  "*doWindows:            True",
-  "*doNT:                 True",
-  "*doWin2K:              True",
-  "*doAmiga:              True",
-  "*doMac:                True",
-  "*doMacsBug:            True",
-  "*doMac1:               True",
-  "*doMacX:               True",
-  "*doSCO:                True",
-  "*doAtari:              False",      /* boring */
-  "*doBSD:                False",      /* boring */
-  "*doLinux:              True",
-  "*doSparcLinux:         False",      /* boring */
-  "*doBlitDamage:          True",
-  "*doSolaris:             True",
+  XGetWindowAttributes (dpy, window, &xgwa);
+  XSetWindowBackground (dpy, window, 
+                        get_pixel_resource("HPPALinux.background",
+                                           "HPPALinux.Background",
+                                           dpy, xgwa.colormap));
+  XClearWindow(dpy, window);
 
-  ".Windows.font:         -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
-  ".Windows.font2:        -*-courier-bold-r-*-*-*-180-*-*-m-*-*-*",
-  ".Windows.foreground:           White",
-  ".Windows.background:           #0000AA",    /* EGA color 0x01. */
+  sysname = "hppa";
+# ifdef HAVE_UNAME
+  {
+    struct utsname uts;
+    char *s;
+    if (uname (&uts) >= 0)
+      sysname = uts.nodename;
+    s = strchr (sysname, '.');
+    if (s) *s = 0;
+  }
+# endif        /* !HAVE_UNAME */
 
-  ".Amiga.font:                   -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
-  ".Amiga.font2:          -*-courier-bold-r-*-*-*-180-*-*-m-*-*-*",
-  ".Amiga.foreground:     Red",
-  ".Amiga.background:     Black",
-  ".Amiga.background2:    White",
+  /* Insert current host name into banner on line 2 */
+  {
+    static char ss[1024];
+    sprintf (ss, linux_panic[1].string, sysname);
+    linux_panic[1].string = ss;
+  }
 
-  ".Mac.font:             -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
-  ".Mac.foreground:       PaleTurquoise1",
-  ".Mac.background:       Black",
+  ts = make_scrolling_window (dpy, window, "HPPALinux", False);
 
-  ".Atari.foreground:     Black",
-  ".Atari.background:     White",
+  usleep (100000);
+  while (linux_panic[i].string)
+    {
+      if (linux_panic[i].delay != -1)
+        linedelay = linux_panic[i].delay * 1000;
+      usleep (linedelay);
+      scrolling_puts (ts, linux_panic[i].string, 0);
+      XSync(dpy, False);
+      if (bsod_sleep (dpy, 0))
+        goto DONE;
+      i++;
+    }
 
-  ".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",
+  if (bsod_sleep (dpy, 4))
+    goto DONE;
 
-  ".mac1.foreground:      Black",
-  ".mac1.background:      White",
+  XSync(dpy, False);
+  bsod_sleep(dpy, delay);
 
-  ".macX.textForeground:   White",
-  ".macX.textBackground:   Black",
-  ".macX.background:      #888888",
-  ".macX.font:            -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
-  ".macX.font2:                   -*-courier-bold-r-*-*-*-240-*-*-m-*-*-*",
+ DONE:
+  free_scrolling_window (ts);
+  XClearWindow(dpy, window);
+}
 
-  ".SCO.font:             -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
-  ".SCO.font2:            -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
-  ".SCO.foreground:       White",
-  ".SCO.background:       Black",
+/* VMS by jwz (text sent by Roland Barmettler <roli@barmettler.net>)
+ */
+static void
+vms (Display *dpy, Window window, int delay)
+{
+  XWindowAttributes xgwa;
+  scrolling_window *ts;
+  const char *sysname;
+  int char_delay = 0;
+  int dot_delay = 40000;
+  int chunk_delay = 500000;
+  char *s, *s1;
+  int i;
+  int arg_count;
+
+# ifdef __GNUC__
+  __extension__   /* don't warn about "string length is greater than the
+                     length ISO C89 compilers are required to support"
+                     in the following string constant... */
+# endif
+
+  const char *lines[] = {
+    "%CNXMAN,  Lost connection to system #\n"
+    "%SHADOW-I-VOLPROC, DSA0: shadow master has changed.  "
+    "Dump file WILL be written if system crashes.\n"
+    "\n",
+    "",
+
+    "%CNXMAN,  Quorum lost, blocking activity\n"
+    "%CNXMAN,  Timed-out lost connection to system #\n"
+    "%CNXMAN,  Timed-out lost connection to system #\n"
+    "%CNXMAN,  Timed-out lost connection to system #\n"
+    "%CNXMAN,  Proposing reconfiguration of the VMScluster\n",
+    "",
+
+    "%CNXMAN,  Removed from VMScluster system #\n"
+    "%CNXMAN,  Removed from VMScluster system #\n"
+    "%CNXMAN,  Removed from VMScluster system #\n"
+    "%CNXMAN,  Completing VMScluster state transition\n",
 
-  ".Linux.font:                   9x15bold",
-  ".Linux.font2:          -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
-  ".Linux.foreground: White",
-  ".Linux.background: Black",
+    "\n"
+    "**** OpenVMS (TM) Alpha Operating system V7.3-1   - BUGCHECK ****\n"
+    "\n"
+    "** Bugcheck code = 000005DC: CLUEXIT, Node voluntarily exiting "
+    "VMScluster\n"
+    "** Crash CPU: 00    Primary CPU: 00    Active CPUs: 00000001\n"
+    "** Current Process = NULL\n"
+    "** Current PSB ID = 00000001\n"
+    "** Image Name =\n"
+    "\n"
+    "** Dumping error log buffers to HBVS unit 0\n"
+    "**** Unable to dump error log buffers to remaining shadow set members\n"
+    "** Error log buffers not dumped to HBVS unit 200\n"
+    "\n"
+    "** Dumping memory to HBVS unit 0\n"
+    "**** Starting compressed selective memory dump at #...\n",
 
-  ".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",
-
-  ".Solaris.font:           -sun-gallant-*-*-*-*-19-*-*-*-*-120-*-*",
-  ".Solaris.font2:          -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
-  ".Solaris.foreground:     Black",
-  ".Solaris.background:     White",
-  "*dontClearRoot:          True",
-  0
-};
+    "\n"
+    "**** Memory dump complete - not all processes or global pages saved\n",
 
-XrmOptionDescRec options [] = {
-  { "-delay",          ".delay",               XrmoptionSepArg, 0 },
-  { "-windows",                ".doWindows",           XrmoptionNoArg,  "True"  },
-  { "-no-windows",     ".doWindows",           XrmoptionNoArg,  "False" },
-  { "-nt",             ".doNT",                XrmoptionNoArg,  "True"  },
-  { "-no-nt",          ".doNT",                XrmoptionNoArg,  "False" },
-  { "-2k",             ".doWin2K",             XrmoptionNoArg,  "True"  },
+    "\n"
+    "halted CPU 0\n",
+    "",
+
+    "\n"
+    "halt code = 5\n"
+    "HALT instruction executed\n"
+    "PC = ffffffff800c3884\n",
+
+    "\n"
+    "CPU 0 booting\n",
+
+    "\n"
+    "resetting all I/O buses\n"
+    "\n"
+    "\n"
+    };
+  char *args[8];
+  int ids[3];
+
+  XGetWindowAttributes (dpy, window, &xgwa);
+  ts = make_scrolling_window (dpy, window, "VMS", False);
+  XClearWindow(dpy,window);
+  ts->sub_x = 0;
+  ts->sub_y = 0;
+  ts->sub_width = xgwa.width;
+  ts->sub_height = xgwa.height;
+
+  sysname = "VMS001";
+# ifdef HAVE_UNAME
+  {
+    struct utsname uts;
+    if (uname (&uts) >= 0)
+      sysname = uts.nodename;
+    s = strchr (sysname, '.');
+    if (s) *s = 0;
+  }
+# endif        /* !HAVE_UNAME */
+
+  args[0] = malloc (strlen(sysname) + 7);
+  strcpy (args[0], sysname);
+  args[0][5] = 0;
+
+  /* Pick three numbers, 1-9, no overlaps. */
+  ids[0] = 1 + (random() % 9);
+  do { ids[1] = 1 + (random() % 9); } while (ids[1]==ids[0]);
+  do { ids[2] = 1 + (random() % 9); } while (ids[2]==ids[0] || ids[2]==ids[1]);
+
+  i = strlen(args[0])-1;
+  if (i < 6) i++;
+  args[0][i] = '0' + ids[0];
+  args[0][i+1] = 0;
+
+  for (s = args[0]; *s; s++)
+    if (isalpha(*s)) *s = toupper (*s);
+
+  args[1] = strdup (args[0]);
+  args[2] = strdup (args[0]); args[2][i] = '0' + ids[1];
+  args[3] = strdup (args[0]); args[3][i] = '0' + ids[2];
+
+  args[4] = strdup (args[1]);
+  args[5] = strdup (args[2]);
+  args[6] = strdup (args[3]);
+
+  {
+    time_t t = time ((time_t *) 0);
+    struct tm *tm = localtime (&t);
+    args[7] = malloc (30);
+    strftime (args[7], 29, "%d-%b-%Y %H:%M", tm);
+    for (s = args[7]; *s; s++)
+      if (isalpha(*s)) *s = toupper (*s);
+  }
+
+  arg_count = 0;
+  for (i = 0; i < countof(lines); i++)
+    {
+      const char *fmt = lines[i];
+      if (! strcmp (fmt, "..."))
+        {
+          int steps = 180 + (random() % 60);
+          while (--steps >= 0)
+            {
+              scrolling_puts (ts, ".", 0);
+              XSync (dpy, False);
+              usleep (dot_delay);
+              if (bsod_sleep (dpy, 0))
+                goto DONE;
+            }
+        }
+      else
+        {
+          char *fmt2 = malloc (strlen (fmt) * 2 + 1);
+          for (s = (char *) fmt, s1 = fmt2; *s; s++)
+            {
+              if (*s == '#')
+                {
+                  strcpy (s1, args[arg_count++]);
+                  s1 += strlen(s1);
+                }
+              else
+                *s1++ = *s;
+            }
+          *s1 = 0;
+          scrolling_puts (ts, fmt2, char_delay);
+          free (fmt2);
+          usleep (chunk_delay);
+          if (bsod_sleep (dpy, 0))
+            goto DONE;
+        }
+    }
+
+  XSync(dpy, False);
+  bsod_sleep(dpy, delay);
+
+ DONE:
+  free_scrolling_window (ts);
+  for (i = 0; i < countof (args); i++)
+    free (args[i]);
+}
+
+
+/* HVX (formerly GCOS6) and TPS6 crash
+   by Brian Garratt <brian-m.garratt@bull.co.uk>
+
+   GCOS6 is a Unix-like operating system developed by Honeywell in the
+   1970s in collaboration with MIT and AT&T (who called their version
+   UNIX).  Both are very much like MULTICS which Honeywell got from GE.
+
+   HVX ("High-performance Virtual System on Unix") is an AIX application
+   which emulates GCOS6 hardware on RS6000-like machines.
+ */
+static void
+hvx (Display *dpy, Window window, int delay)
+{
+  XWindowAttributes xgwa;
+  scrolling_window *ts;
+
+  int delay1 = 10000;
+  int delay2 = 100000;
+  const char *hvx_panic_1 =
+    ("(TP) Trap no E   Effective address 00000000   Instruction D7DE\n"
+     "(TP)  Registers :\n"
+     "(TP)  B1 -> B7  03801B02  00000000  03880D45  038BABDB  0388AFFD"
+     "  0389B3F8  03972317\n"
+     "(TP)  R1 -> R7  0001  0007  F10F  090F  0020  0106  0272\n"
+     "(TP)  P I Z M1  0388A18B  3232  0000 FF00\n"
+     "(TP) Program counter is at offset 0028 from string YTPAD\n"
+     "(TP) User id of task which trapped is LT 626\n"
+     "(TP)?\n"
+     );
+  const char *hvx_panic_2 =
+    ("\n"
+     "(TP)?\n"
+     "Core dumps initiated for selected HVX processes ...\n"
+     "Core dumps complete.\n"
+     "Fri Jul 19 15:53:09 2002\n"
+     "Live registers for cp 0:\n"
+     " P    =     7de3  IW=0000     I=32    CI=30000000   S=80006013"
+     "   IV=aa0      Level=13\n"
+     " R1-7 =       1f      913       13        4        8        0        0\n"
+     " B1-7 =   64e71b      a93      50e   64e73c     6c2c     7000      b54\n"
+     "Memory dump starting to file /var/hvx/dp01/diag/Level2 ...\n"
+     "Memory dump complete.\n"
+    );
+
+  XGetWindowAttributes (dpy, window, &xgwa);
+  ts = make_scrolling_window (dpy, window, "HVX", False);
+  XClearWindow(dpy, window);
+
+  scrolling_puts (ts, hvx_panic_1,         delay1);
+  if (bsod_sleep(dpy, 1)) goto DONE;
+  scrolling_puts (ts, " TP CLOSE ALL",     delay2);
+  scrolling_puts (ts, "\n(TP)?\n",         delay1);
+  if (bsod_sleep(dpy, 1)) goto DONE;
+  scrolling_puts (ts, " TP ABORT -LT ALL", delay2);
+  scrolling_puts (ts, "\n(TP)?\n",         delay1);
+  if (bsod_sleep(dpy, 1)) goto DONE;
+  scrolling_puts (ts, "  TP STOP KILL",    delay2);
+  scrolling_puts (ts, hvx_panic_2,         delay1);
+
+  bsod_sleep(dpy, delay);
+ DONE:
+  XClearWindow(dpy, window);
+}
+
+
+\f
+
+/* HPUX panic, by Tobias Klausmann <klausman@schwarzvogel.de>
+ */
+
+static void
+hpux (Display* dpy, Window window, int delay)
+{
+  XWindowAttributes xgwa;
+  scrolling_window *ts;
+  const char *sysname;
+  char buf[2048];
+
+# ifdef __GNUC__
+  __extension__   /* don't warn about "string length is greater than the
+                     length ISO C89 compilers are required to support"
+                     in the following string constant... */
+# endif
+
+  const char *msg1 =
+   "Console Login:\n"
+   "\n"
+   "     ******* Unexpected HPMC/TOC. Processor HPA FFFFFFFF'"
+   "FFFA0000 *******\n"
+   "                              GENERAL REGISTERS:\n"
+   "r00/03 00000000'00000000 00000000'00000000 00000000'00000000 00000000'"
+   "006C76C0\n"
+   "r04/07 00000000'00000001 00000000'0126E328 00000000'00000000 00000000'"
+   "0122B640\n"
+   "r08/11 00000000'00000000 00000000'0198CFC0 00000000'000476FE 00000000'"
+   "00000001\n"
+   "r12/15 00000000'40013EE8 00000000'08000080 00000000'4002530C 00000000'"
+   "4002530C\n"
+   "r16/19 00000000'7F7F2A00 00000000'00000001 00000000'00000000 00000000'"
+   "00000000\n"
+   "r20/23 00000000'006C8048 00000000'00000001 00000000'00000000 00000000'"
+   "00000000\n"
+   "r24/27 00000000'00000000 00000000'00000000 00000000'00000000 00000000'"
+   "00744378\n"
+   "r28/31 00000000'00000000 00000000'007DD628 00000000'0199F2B0 00000000'"
+   "00000000\n"
+   "                              CONTROL REGISTERS:\n"
+   "sr0/3  00000000'0F3B4000 00000000'0C2A2000 00000000'016FF800 00000000'"
+   "00000000\n"
+   "sr4/7  00000000'00000000 00000000'016FF800 00000000'0DBF1400 00000000'"
+   "00000000\n"
+   "pcq =  00000000'00000000.00000000'00104950 00000000'00000000.00000000'"
+   "00104A14\n"
+   "isr =  00000000'10240006 ior = 00000000'67D9E220 iir = 08000240 rctr = "
+   "7FF10BB6\n"
+   "\n"
+   "pid reg cr8/cr9    00007700'0000B3A9 00000000'0000C5D8\n"
+   "pid reg cr12/cr13  00000000'00000000 00000000'00000000\n"
+   "ipsw = 000000FF'080CFF1F iva = 00000000'0002C000 sar = 3A ccr = C0\n"
+   "tr0/3  00000000'006C76C0 00000000'00000001 00000000'00000000 00000000'"
+   "7F7CE000\n"
+   "tr4/7  00000000'03790000 0000000C'4FB68340 00000000'C07EE13F 00000000'"
+   "0199F2B0\n"
+   "eiem = FFFFFFF0'FFFFFFFF eirr = 80000000'00000000 itmr = 0000000C'"
+   "4FD8EDE1\n"
+   "cr1/4  00000000'00000000 00000000'00000000 00000000'00000000 00000000'"
+   "00000000\n"
+   "cr5/7  00000000'00000000 00000000'00000000 00000000'"
+   "00000000\n"
+   "                           MACHINE CHECK PARAMETERS:\n"
+   "Check Type = 00000000 CPU STATE = 9E000001 Cache Check = 00000000\n"
+   "TLB Check = 00000000 Bus Check = 00000000 PIM State = ? SIU "
+   "Status = ????????\n"
+   "Assists = 00000000 Processor = 00000000\n"
+   "Slave Addr = 00000000'00000000 Master Addr = 00000000'00000000\n"
+   "\n"
+   "\n"
+   "TOC,    pcsq.pcoq = 0'0.0'104950   , isr.ior = 0'10240006.0'67d9e220\n"
+   "@(#)B2352B/9245XB HP-UX (B.11.00) #1: Wed Nov  5 22:38:19 PST 1997\n"
+   "Transfer of control: (display==0xd904, flags==0x0)\n"
+   "\n"
+   "\n"
+   "\n"
+   "*** A system crash has occurred.  (See the above messages for details.)\n"
+   "*** The system is now preparing to dump physical memory to disk, for use\n"
+   "*** in debugging the crash.\n"
+   "\n"
+   "*** The dump will be a SELECTIVE dump:  40 of 256 megabytes.\n"
+   "*** To change this dump type, press any key within 10 seconds.\n"
+   "*** Proceeding with selective dump.\n"
+   "\n"
+   "*** The dump may be aborted at any time by pressing ESC.\n";
+  const char *msg2 =
+   "\n*** System rebooting.\n";
+
+  XGetWindowAttributes (dpy, window, &xgwa);
+  ts = make_scrolling_window (dpy, window, "HPUX", False);
+  XClearWindow(dpy,window);
+  ts->columns = 10000;  /* never wrap */
+  ts->sub_x = 0;
+  ts->sub_y = 0;
+  ts->sub_width = xgwa.width;
+  ts->sub_height = xgwa.height;
+
+  sysname = "HPUX";
+# ifdef HAVE_UNAME
+  {
+    struct utsname uts;
+    char *s;
+    if (uname (&uts) >= 0)
+      sysname = uts.nodename;
+    s = strchr (sysname, '.');
+    if (s) *s = 0;
+  }
+# endif        /* !HAVE_UNAME */
+
+  if (bsod_sleep (dpy, 1))
+    goto DONE;
+  
+  scrolling_puts (ts,
+                  "                                                       "
+                  "                                                       "
+                  "                                                       \n",
+                  0);
+  sprintf (buf, "%.100s [HP Release B.11.00] (see /etc/issue)\n", sysname);
+  scrolling_puts (ts, buf, 0);
+  if (bsod_sleep (dpy, 1))
+    goto DONE;
+  scrolling_puts (ts, msg1, 0);
+  {
+    int i;
+    int steps = 11;
+    int size = 40;
+    for (i = 0; i <= steps; i++)
+      {
+        if (i > steps) i = steps;
+        sprintf (buf, 
+               "*** Dumping: %3d%% complete (%d of 40 MB) (device 64:0x2)\r",
+                 i * 100 / steps,
+                 i * size / steps);
+        scrolling_puts (ts, buf, 0);
+        XSync (dpy, False);
+        usleep (1500000);
+        if (bsod_sleep (dpy, 0))
+          goto DONE;
+      }
+  }
+
+  scrolling_puts (ts, msg2, 0);
+
+  XSync(dpy, False);
+  bsod_sleep(dpy, delay);
+
+ DONE:
+  free_scrolling_window (ts);
+}
+
+\f
+
+/* IBM OS/390 aka MVS aka z/OS.
+   Text from Dan Espen <dane@mk.telcordia.com>.
+   Apparently this isn't actually a crash, just a random session...
+   But who can tell.
+ */
+
+static void
+os390 (Display* dpy, Window window, int delay)
+{
+  GC gc;
+  XGCValues gcv;
+  XWindowAttributes xgwa;
+  scrolling_window *ts;
+  int i;
+
+  const char *msg[] = {
+   "* ISPF Subtask abend *\n",
+   "SPF      ENDED DUE TO ERROR+\n",
+   "READY\n",
+   "\n",
+   "IEA995I SYMPTOM DUMP OUTPUT\n",
+   "  USER COMPLETION CODE=0222\n",
+   " TIME=23.00.51  SEQ=03210  CPU=0000  ASID=00AE\n",
+   " PSW AT TIME OF ERROR  078D1000   859DAF18  ILC 2  INTC 0D\n",
+   "   NO ACTIVE MODULE FOUND\n",
+   "   NAME=UNKNOWN\n",
+   "   DATA AT PSW  059DAF12 - 00181610  0A0D9180  70644710\n",
+   "   AR/GR 0: 00000000/80000000   1: 00000000/800000DE\n",
+   "         2: 00000000/196504DC   3: 00000000/00037A78\n",
+   "         4: 00000000/00037B78   5: 00000000/0003351C\n",
+   "         6: 00000000/0000F0AD   7: 00000000/00012000\n",
+   "         8: 00000000/059DAF10   9: 00000000/0002D098\n",
+   "         A: 00000000/059D9F10   B: 00000000/059D8F10\n",
+   "         C: 00000000/859D7F10   D: 00000000/00032D60\n",
+   "         E: 00000000/00033005   F: 01000002/00000041\n",
+   " END OF SYMPTOM DUMP\n",
+   "ISPS014 - ** Logical screen request failed - abend 0000DE **\n",
+   "ISPS015 - ** Contact your system programmer or dialog developer.**\n",
+   "*** ISPF Main task abend ***\n",
+   "IEA995I SYMPTOM DUMP OUTPUT\n",
+   "  USER COMPLETION CODE=0222\n",
+   " TIME=23.00.52  SEQ=03211  CPU=0000  ASID=00AE\n",
+   " PSW AT TIME OF ERROR  078D1000   8585713C  ILC 2  INTC 0D\n",
+   "   ACTIVE LOAD MODULE           ADDRESS=05855000  OFFSET=0000213C\n",
+   "   NAME=ISPMAIN\n",
+   "   DATA AT PSW  05857136 - 00181610  0A0D9180  D3304770\n",
+   "   GR 0: 80000000   1: 800000DE\n",
+   "      2: 00015260   3: 00000038\n",
+   "      4: 00012508   5: 00000000\n",
+   "      6: 000173AC   7: FFFFFFF8\n",
+   "      8: 05858000   9: 00012CA0\n",
+   "      A: 05857000   B: 05856000\n",
+   "      C: 85855000   D: 00017020\n",
+   "      E: 85857104   F: 00000000\n",
+   " END OF SYMPTOM DUMP\n",
+   "READY\n",
+   "***_\n"
+  };
+
+  XGetWindowAttributes (dpy, window, &xgwa);
+  ts = make_scrolling_window (dpy, window, "OS390", False);
+  ts->columns = 10000;  /* never wrap */
+  ts->sub_x = 0;
+  ts->sub_y = 0;
+  ts->sub_width = xgwa.width;
+  ts->sub_height = xgwa.height;
+
+  gcv.foreground = get_pixel_resource ("390.background", "390.Background",
+                                       dpy, xgwa.colormap);
+  gc = XCreateGC (dpy, window, GCForeground, &gcv);
+  XFillRectangle (dpy, window, gc, 0, 0, xgwa.width, xgwa.height);
+  XFreeGC (dpy, gc);
+
+  for (i = 0; i < countof (msg); i++)
+    {
+      scrolling_puts (ts, msg[i], 0);
+      usleep (100000);
+      if (bsod_sleep(dpy, 0)) goto DONE;
+    }
+
+  XSync(dpy, False);
+  bsod_sleep(dpy, delay);
+DONE:
+  free_scrolling_window (ts);
+}
+
+
+\f
+
+/* Compaq Tru64 Unix panic, by jwz as described by
+   Tobias Klausmann <klausman@schwarzvogel.de>
+ */
+
+static void
+tru64 (Display* dpy, Window window, int delay)
+{
+  XWindowAttributes xgwa;
+  scrolling_window *ts;
+  const char *sysname;
+  char buf[2048];
+
+# ifdef __GNUC__
+  __extension__   /* don't warn about "string length is greater than the
+                     length ISO C89 compilers are required to support"
+                     in the following string constant... */
+# endif
+
+  const char *msg1 =
+   ("panic (cpu 0): trap: illegal instruction\n"
+    "kernel inst fault=gentrap, ps=0x5, pc=0xfffffc0000593878, inst=0xaa\n"
+    "kernel inst fault=gentrap, ps=0x5, pc=0xfffffc0000593878, inst=0xaa\n"
+    "                                                                   \n"
+    "DUMP: blocks available:  1571600\n"
+    "DUMP: blocks wanted:      100802 (partial compressed dump) [OKAY]\n"
+    "DUMP: Device     Disk Blocks Available\n"
+    "DUMP: ------     ---------------------\n"
+    "DUMP: 0x1300023  1182795 - 1571597 (of 1571598) [primary swap]\n"
+    "DUMP.prom: Open: dev 0x5100041, block 2102016: SCSI 0 11 0 2 200 0 0\n"
+    "DUMP: Writing header... [1024 bytes at dev 0x1300023, block 1571598]\n"
+    "DUMP: Writing data");
+  const char *msg2 =
+   ("DUMP: Writing header... [1024 bytes at dev 0x1300023, block 1571598]\n"
+    "DUMP: crash dump complete.\n"
+    "kernel inst fault=gentrap, ps=0x5, pc=0xfffffc0000593878, inst=0xaa\n"
+    "                                                                   \n"
+    "DUMP: second crash dump skipped: 'dump_savecnt' enforced.\n");
+  const char *msg3 =
+   ("\n"
+    "halted CPU 0\n"
+    "\n"
+    "halt code = 5\n"
+    "HALT instruction executed\n"
+    "PC = fffffc00005863b0\n");
+  const char *msg4 =
+   ("\n"   
+    "CPU 0 booting\n"
+    "\n"
+    "\n"
+    "\n");
+
+  XGetWindowAttributes (dpy, window, &xgwa);
+  ts = make_scrolling_window (dpy, window, "Tru64", False);
+  XClearWindow(dpy,window);
+  ts->columns = 10000;  /* never wrap */
+  ts->sub_x = 0;
+  ts->sub_y = 0;
+  ts->sub_width = xgwa.width;
+  ts->sub_height = xgwa.height;
+
+  sysname = "127.0.0.1";
+# ifdef HAVE_UNAME
+  {
+    struct utsname uts;
+    if (uname (&uts) >= 0)
+      sysname = uts.nodename;
+  }
+# endif        /* !HAVE_UNAME */
+
+  if (bsod_sleep (dpy, 1))
+    goto DONE;
+  
+      
+
+  sprintf (buf,
+           "Compaq Tru64 UNIX V5.1B (Rev. 2650) (%.100s) console\n"
+           "\n"
+           "login: ",
+           sysname);
+  scrolling_puts (ts, buf, 0);
+  if (bsod_sleep (dpy, 6))
+    goto DONE;
+
+  scrolling_puts (ts, msg1, 0);
+  {
+    int i;
+    int steps = 4 + (random() % 8);
+    for (i = 0; i < steps; i++)
+      {
+        scrolling_puts (ts, ".", 0);
+        XSync (dpy, False);
+        if (bsod_sleep (dpy, 1))
+          goto DONE;
+      }
+    sprintf (buf, "[%dMB]\n", steps);
+    scrolling_puts (ts, buf, 0);
+  }
+
+  scrolling_puts (ts, msg2, 0);
+  XSync(dpy, False);
+  if (bsod_sleep (dpy, 4))
+    goto DONE;
+
+  scrolling_puts (ts, msg3, 0);
+  XSync(dpy, False);
+  if (bsod_sleep (dpy, 3))
+    goto DONE;
+
+  scrolling_puts (ts, msg4, 0);
+  XSync(dpy, False);
+  bsod_sleep(dpy, delay);
+
+ DONE:
+  free_scrolling_window (ts);
+}
+
+
+\f
+/*
+ * Simulate various Apple ][ crashes. The memory map encouraged many programs
+ * to use the primary hi-res video page for various storage, and the secondary
+ * hi-res page for active display. When it crashed into Applesoft or the
+ * monitor, it would revert to the primary page and you'd see memory garbage on
+ * the screen. Also, it was common for copy-protected games to use the primary
+ * text page for important code, because that made it really hard to
+ * reverse-engineer them. The result often looked like what this generates.
+ *
+ * The Apple ][ logic and video hardware is in apple2.c. The TV is emulated by
+ * analogtv.c for maximum realism
+ *
+ * Trevor Blackwell <tlb@tlb.org> 
+ */
+
+static char * apple2_basic_errors[]={
+  "BREAK",
+  "NEXT WITHOUT FOR",
+  "SYNTAX ERROR",
+  "RETURN WITHOUT GOSUB",
+  "ILLEGAL QUANTITY",
+  "OVERFLOW",
+  "OUT OF MEMORY",
+  "BAD SUBSCRIPT ERROR",
+  "DIVISION BY ZERO",
+  "STRING TOO LONG",
+  "FORMULA TOO COMPLEX",
+  "UNDEF'D FUNCTION",
+  "OUT OF DATA"
+#if 0
+  ,
+  "DEFAULT ARGUMENTS ARE NOT ALLOWED IN DECLARATION OF FRIEND "
+  "TEMPLATE SPECIALIZATION"
+#endif
+
+};
+static char * apple2_dos_errors[]={
+  "VOLUME MISMATCH",
+  "I/O ERROR",
+  "DISK FULL",
+  "NO BUFFERS AVAILABLE",
+  "PROGRAM TOO LARGE",
+};
+
+void a2controller_crash(apple2_sim_t *sim, int *stepno,
+                        double *next_actiontime)
+{
+  apple2_state_t *st=sim->st;
+  char *s;
+  int i;
+
+  struct mydata {
+    int fillptr;
+    int fillbyte;
+  } *mine;
+
+  if (!sim->controller_data)
+    sim->controller_data = calloc(sizeof(struct mydata),1);
+  mine=(struct mydata *) sim->controller_data;
+  
+  switch(*stepno) {
+  case 0:
+    
+    a2_init_memory_active(sim);
+    sim->dec->powerup = 1000.0;
+
+    if (random()%3==0) {
+      st->gr_mode=0;
+      *next_actiontime+=0.4;
+      *stepno=100;
+    }
+    else if (random()%4==0) {
+      st->gr_mode=A2_GR_LORES;
+      if (random()%3==0) st->gr_mode |= A2_GR_FULL;
+      *next_actiontime+=0.4;
+      *stepno=100;
+    }
+    else if (random()%2==0) {
+      st->gr_mode=A2_GR_HIRES;
+      *stepno=300;
+    }
+    else {
+      st->gr_mode=A2_GR_HIRES;
+      *next_actiontime+=0.4;
+      *stepno=100;
+    }
+    break;
+
+  case 100:
+    /* An illegal instruction or a reset caused it to drop into the
+       assembly language monitor, where you could disassemble code & view
+       data in hex. */
+    if (random()%3==0) {
+      char ibytes[128];
+      char itext[128];
+      int addr=0xd000+random()%0x3000;
+      sprintf(ibytes,
+              "%02X",random()%0xff);
+      sprintf(itext,
+              "???");
+      sprintf(sim->printing_buf,
+              "\n\n"
+              "%04X: %-15s %s\n"
+              " A=%02X X=%02X Y=%02X S=%02X F=%02X\n"
+              "*",
+              addr,ibytes,itext,
+              random()%0xff, random()%0xff,
+              random()%0xff, random()%0xff,
+              random()%0xff);
+      sim->printing=sim->printing_buf;
+      a2_goto(st,23,1);
+      if (st->gr_mode) {
+        *stepno=180;
+      } else {
+        *stepno=200;
+      }
+      sim->prompt='*';
+      *next_actiontime += 2.0 + (random()%1000)*0.0002;
+    }
+    else {
+      /* Lots of programs had at least their main functionality in
+         Applesoft Basic, which had a lot of limits (memory, string
+         length, etc) and would sometimes crash unexpectedly. */
+      sprintf(sim->printing_buf,
+              "\n"
+              "\n"
+              "\n"
+              "?%s IN %d\n"
+              "\001]",
+              apple2_basic_errors[random() %
+                                  (sizeof(apple2_basic_errors)
+                                   /sizeof(char *))],
+              (1000*(random()%(random()%59+1)) +
+               100*(random()%(random()%9+1)) +
+               5*(random()%(random()%199+1)) +
+               1*(random()%(random()%(random()%2+1)+1))));
+      sim->printing=sim->printing_buf;
+      a2_goto(st,23,1);
+      *stepno=110;
+      sim->prompt=']';
+      *next_actiontime += 2.0 + (random()%1000)*0.0002;
+    }
+    break;
+
+  case 110:
+    if (random()%3==0) {
+      /* This was how you reset the Basic interpreter. The sort of
+         incantation you'd have on a little piece of paper taped to the
+         side of your machine */
+      sim->typing="CALL -1370";
+      *stepno=120;
+    }
+    else if (random()%2==0) {
+      sim->typing="CATALOG\n";
+      *stepno=170;
+    }
+    else {
+      *next_actiontime+=1.0;
+      *stepno=999;
+    }
+    break;
+
+  case 120:
+    *stepno=130;
+    *next_actiontime += 0.5;
+    break;
+
+  case 130:
+    st->gr_mode=0;
+    a2_cls(st);
+    a2_goto(st,0,16);
+    for (s="APPLE ]["; *s; s++) a2_printc(st,*s);
+    a2_goto(st,23,0);
+    a2_printc(st,']');
+    *next_actiontime+=1.0;
+    *stepno=999;
+    break;
+
+  case 170:
+    if (random()%50==0) {
+      sprintf(sim->printing_buf,
+              "\nDISK VOLUME 254\n\n"
+              " A 002 HELLO\n"
+              "\n"
+              "]");
+      sim->printing=sim->printing_buf;
+    }
+    else {
+      sprintf(sim->printing_buf,"\n?%s\n]",
+              apple2_dos_errors[random()%
+                                (sizeof(apple2_dos_errors) /
+                                 sizeof(char *))]);
+      sim->printing=sim->printing_buf;
+    }
+    *stepno=999;
+    *next_actiontime+=1.0;
+    break;
+
+  case 180:
+    if (random()%2==0) {
+      /* This was how you went back to text mode in the monitor */
+      sim->typing="FB4BG";
+      *stepno=190;
+    } else {
+      *next_actiontime+=1.0;
+      *stepno=999;
+    }
+    break;
+
+  case 190:
+    st->gr_mode=0;
+    a2_invalidate(st);
+    a2_printc(st,'\n');
+    a2_printc(st,'*');
+    *stepno=200;
+    *next_actiontime+=2.0;
+    break;
+
+  case 200:
+    /* This reset things into Basic */
+    if (random()%2==0) {
+      sim->typing="FAA6G";
+      *stepno=120;
+    }
+    else {
+      *stepno=999;
+      *next_actiontime+=sim->delay;
+    }
+    break;
+
+  case 300:
+    for (i=0; i<1500; i++) {
+      a2_poke(st, mine->fillptr, mine->fillbyte);
+      mine->fillptr++;
+      mine->fillbyte = (mine->fillbyte+1)&0xff;
+    }
+    *next_actiontime += 0.08;
+    /* When you hit c000, it changed video settings */
+    if (mine->fillptr>=0xc000) {
+      a2_invalidate(st);
+      st->gr_mode=0;
+    }
+    /* And it seemed to reset around here, I dunno why */
+    if (mine->fillptr>=0xcf00) *stepno=130;
+    break;
+
+  case 999:
+    break;
+
+  case A2CONTROLLER_FREE:
+    free(mine);
+    break;
+  }
+}
+
+static void
+apple2crash (Display* dpy, Window window, int delay)
+{
+  apple2 (dpy, window, delay, a2controller_crash);
+}
+
+/* MS-DOS, by jwz
+ */
+static void
+msdos (Display *dpy, Window window, int delay)
+{
+  XWindowAttributes xgwa;
+  scrolling_window *ts;
+
+  int delay1 = 10000;
+  int delay2 = 200000;
+
+# define CURSOR "_\b \b"
+# define CURSOR2 CURSOR CURSOR CURSOR
+
+  XGetWindowAttributes (dpy, window, &xgwa);
+  ts = make_scrolling_window (dpy, window, "MSDOS", False);
+
+  XClearWindow(dpy, window);
+
+  scrolling_puts (ts, "C:\\WINDOWS>", delay1);
+  if (bsod_sleep(dpy, 1)) goto DONE;
+
+  scrolling_puts (ts, CURSOR2 "dir a:", delay2);
+  if (bsod_sleep(dpy, 1)) goto DONE;
+
+  scrolling_puts (ts, "\nNot ready reading drive A\nAbort, Retry, Fail?",
+                  delay1);
+  if (bsod_sleep(dpy, 1)) goto DONE;
+
+  scrolling_puts (ts, CURSOR2 "f", delay2);
+  if (bsod_sleep(dpy, 1)) goto DONE;
+
+  scrolling_puts (ts, "\n\n\nNot ready reading drive A\nAbort, Retry, Fail?",
+                  delay1);
+  if (bsod_sleep(dpy, 1)) goto DONE;
+
+  scrolling_puts (ts, CURSOR2 "f", delay2);
+  if (bsod_sleep(dpy, 1)) goto DONE;
+
+  scrolling_puts (ts, "\nVolume in drive A has no label\n\n"
+                  "Not ready reading drive A\nAbort, Retry, Fail?",
+                  delay1);
+  if (bsod_sleep(dpy, 1)) goto DONE;
+
+  scrolling_puts (ts, CURSOR2 "a", delay2);
+  if (bsod_sleep(dpy, 1)) goto DONE;
+
+  scrolling_puts (ts, "\n\nC:\\WINDOWS>", delay1);
+
+  {
+    time_t start = time((time_t *) 0);
+    while (start + delay > time((time_t *) 0))
+      if (scrolling_puts (ts, CURSOR, delay2))
+        break;
+  }
+
+ DONE:
+  XClearWindow(dpy, window);
+
+# undef CURSOR
+# undef CURSOR2
+}
+
+
+
+\f
+char *progclass = "BSOD";
+
+char *defaults [] = {
+  "*delay:                30",
+
+  "*doOnly:               ",
+  "*doWindows:            True",
+  "*doNT:                 True",
+  "*doWin2K:              True",
+  "*doAmiga:              True",
+  "*doMac:                True",
+  "*doMacsBug:            True",
+  "*doMac1:               True",
+  "*doMacX:               True",
+  "*doSCO:                True",
+  "*doAtari:              False",      /* boring */
+  "*doBSD:                False",      /* boring */
+  "*doLinux:              True",
+  "*doSparcLinux:         False",      /* boring */
+  "*doHPPALinux:          True",
+  "*doBlitDamage:          True",
+  "*doSolaris:             True",
+  "*doHPUX:                True",
+  "*doTru64:               True",
+  "*doApple2:              True",
+  "*doOS390:               True",
+  "*doVMS:                True",
+  "*doHVX:                True",
+  "*doMSDOS:              True",
+
+  ".Windows.font:         -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
+  ".Windows.font2:        -*-courier-bold-r-*-*-*-180-*-*-m-*-*-*",
+  ".Windows.foreground:           White",
+  ".Windows.background:           #0000AA",    /* EGA color 0x01. */
+
+  ".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",
+
+  ".mac1.foreground:      Black",
+  ".mac1.background:      White",
+
+  ".macX.textForeground:   White",
+  ".macX.textBackground:   Black",
+  ".macX.background:      #888888",
+  ".macX.font:            -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
+  ".macX.font2:                   -*-courier-bold-r-*-*-*-240-*-*-m-*-*-*",
+
+  ".SCO.font:             -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
+  ".SCO.font2:            -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  ".SCO.foreground:       White",
+  ".SCO.background:       Black",
+
+  ".HVX.font:             -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
+  ".HVX.font2:            -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  ".HVX.foreground:       White",
+  ".HVX.background:       Black",
+
+  ".Linux.font:                   9x15bold",
+  ".Linux.font2:          -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  ".Linux.foreground:      White",
+  ".Linux.background:      Black",
+
+  ".HPPALinux.font:       -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
+  ".HPPALinux.font2:      -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  ".HPPALinux.foreground:  White",
+  ".HPPALinux.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",
+
+  ".Solaris.font:          -sun-gallant-*-*-*-*-19-*-*-*-*-120-*-*",
+  ".Solaris.font2:         -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  ".Solaris.foreground:    Black",
+  ".Solaris.background:    White",
+  "*dontClearRoot:         True",
+
+  ".HPUX.font:            9x15bold",
+  ".HPUX.font2:                   -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  ".HPUX.foreground:      White",
+  ".HPUX.background:      Black",
+
+  ".OS390.font:                   9x15bold",
+  ".OS390.font2:          -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  ".OS390.background:     Black",
+  ".OS390.foreground:     Red",
+
+  ".Tru64.font:                   9x15bold",
+  ".Tru64.font2:          -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  ".Tru64.foreground:     White",
+  ".Tru64.background:     #0000AA",    /* EGA color 0x01. */
+
+  "*apple2TVColor:         50",
+  "*apple2TVTint:          5",
+  "*apple2TVBrightness:    10",
+  "*apple2TVContrast:      90",
+  "*apple2SimulateUser:    True",
+
+  ".VMS.font:             9x15bold",
+  ".VMS.font2:            -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  ".VMS.foreground:       White",
+  ".VMS.background:       Black",
+
+  ".MSDOS.font:                   9x15bold",
+  ".MSDOS.font2:          -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  ".MSDOS.foreground:     White",
+  ".MSDOS.background:     Black",
+
+  ANALOGTV_DEFAULTS
+
+#ifdef HAVE_XSHM_EXTENSION
+  "*useSHM:                True",
+#endif
+  0
+};
+
+XrmOptionDescRec options [] = {
+  { "-delay",          ".delay",               XrmoptionSepArg, 0 },
+  { "-only",           ".doOnly",              XrmoptionSepArg, 0 },
+  { "-windows",                ".doWindows",           XrmoptionNoArg,  "True"  },
+  { "-no-windows",     ".doWindows",           XrmoptionNoArg,  "False" },
+  { "-nt",             ".doNT",                XrmoptionNoArg,  "True"  },
+  { "-no-nt",          ".doNT",                XrmoptionNoArg,  "False" },
+  { "-2k",             ".doWin2K",             XrmoptionNoArg,  "True"  },
   { "-no-2k",          ".doWin2K",             XrmoptionNoArg,  "False" },
   { "-amiga",          ".doAmiga",             XrmoptionNoArg,  "True"  },
   { "-no-amiga",       ".doAmiga",             XrmoptionNoArg,  "False" },
@@ -2185,67 +3654,135 @@ XrmOptionDescRec options [] = {
   { "-no-mac",         ".doMac",               XrmoptionNoArg,  "False" },
   { "-mac1",           ".doMac1",              XrmoptionNoArg,  "True"  },
   { "-no-mac1",                ".doMac1",              XrmoptionNoArg,  "False" },
+  { "-macx",           ".doMacX",              XrmoptionNoArg,  "True"  },
   { "-no-macx",                ".doMacX",              XrmoptionNoArg,  "False" },
   { "-atari",          ".doAtari",             XrmoptionNoArg,  "True"  },
   { "-no-atari",       ".doAtari",             XrmoptionNoArg,  "False" },
   { "-macsbug",                ".doMacsBug",           XrmoptionNoArg,  "True"  },
   { "-no-macsbug",     ".doMacsBug",           XrmoptionNoArg,  "False" },
+  { "-apple2",         ".doApple2",            XrmoptionNoArg,  "True"  },
+  { "-no-apple2",      ".doApple2",            XrmoptionNoArg,  "False" },
   { "-sco",            ".doSCO",               XrmoptionNoArg,  "True"  },
   { "-no-sco",         ".doSCO",               XrmoptionNoArg,  "False" },
+  { "-hvx",            ".doHVX",               XrmoptionNoArg,  "True"  },
+  { "-no-hvx",         ".doHVX",               XrmoptionNoArg,  "False" },
   { "-bsd",            ".doBSD",               XrmoptionNoArg,  "True"  },
   { "-no-bsd",         ".doBSD",               XrmoptionNoArg,  "False" },
-  { "-linux",          ".doLinux",             XrmoptionNoArg,  "True" },
+  { "-linux",          ".doLinux",             XrmoptionNoArg,  "True"  },
   { "-no-linux",       ".doLinux",             XrmoptionNoArg,  "False" },
+  { "-hppalinux",      ".doHPPALinux",         XrmoptionNoArg,  "True"  },
+  { "-no-hppalinux",   ".doHPPALinux",         XrmoptionNoArg,  "False" },
   { "-sparclinux",     ".doSparcLinux",        XrmoptionNoArg,  "True"  },
   { "-no-sparclinux",  ".doSparcLinux",        XrmoptionNoArg,  "False" },
   { "-blitdamage",     ".doBlitDamage",        XrmoptionNoArg,  "True"  },
   { "-no-blitdamage",  ".doBlitDamage",        XrmoptionNoArg,  "False" },
+  { "-nvidia",         ".doNvidia",            XrmoptionNoArg,  "True"  },
+  { "-no-nvidia",      ".doNvidia",            XrmoptionNoArg,  "False" },
   { "-solaris",                ".doSolaris",           XrmoptionNoArg,  "True"  },
   { "-no-solaris",     ".doSolaris",           XrmoptionNoArg,  "False" },
+  { "-hpux",           ".doHPUX",              XrmoptionNoArg,  "True"  },
+  { "-no-hpux",                ".doHPUX",              XrmoptionNoArg,  "False" },
+  { "-os390",          ".doOS390",             XrmoptionNoArg,  "True"  },
+  { "-no-os390",       ".doOS390",             XrmoptionNoArg,  "False" },
+  { "-tru64",          ".doHPUX",              XrmoptionNoArg,  "True"  },
+  { "-no-tru64",       ".doTru64",             XrmoptionNoArg,  "False" },
+  { "-vms",            ".doVMS",               XrmoptionNoArg,  "True"  },
+  { "-no-vms",         ".doVMS",               XrmoptionNoArg,  "False" },
+  { "-msdos",          ".doMSDOS",             XrmoptionNoArg,  "True"  },
+  { "-no-msdos",       ".doMSDOS",             XrmoptionNoArg,  "False" },
+  ANALOGTV_OPTIONS
   { 0, 0, 0, 0 }
 };
 
 
+static struct {
+  const char *name;
+  void (*fn) (Display *, Window, int delay);
+} all_modes[] = {
+  { "Windows",         windows_31 },
+  { "NT",              windows_nt },
+  { "Win2K",           windows_2k },
+  { "Amiga",           amiga },
+  { "Mac",             mac },
+  { "MacsBug",         macsbug },
+  { "Mac1",            mac1 },
+  { "MacX",            macx },
+  { "SCO",             sco },
+  { "HVX",             hvx },
+  { "HPPALinux",       hppa_linux },
+  { "SparcLinux",      sparc_linux },
+  { "BSD",             bsd },
+  { "Atari",           atari },
+  { "BlitDamage",      blitdamage },
+  { "Nvidia",          nvidia },
+  { "Solaris",         sparc_solaris },
+  { "Linux",           linux_fsck },
+  { "HPUX",            hpux },
+  { "OS390",           os390 },
+  { "Tru64",           tru64 },
+  { "Apple2",          apple2crash },
+  { "VMS",             vms },
+  { "MSDOS",           msdos },
+};
+
+
 void
 screenhack (Display *dpy, Window window)
 {
   int loop = 0;
   int i = -1;
   int j = -1;
+  int only = -1;
   int delay = get_integer_resource ("delay", "Integer");
   if (delay < 3) delay = 3;
 
+  {
+    char *s = get_string_resource("doOnly", "DoOnly");
+    if (s && *s)
+      {
+        int count = countof(all_modes);
+        for (only = 0; only < count; only++)
+          if (!strcasecmp (s, all_modes[only].name))
+            break;
+        if (only >= count)
+          {
+            fprintf (stderr, "%s: unknown -only mode: \"%s\"\n", progname, s);
+            only = -1;
+          }
+      }
+    if (s) free (s);
+  }
+
   if (!get_boolean_resource ("root", "Boolean"))
     {
       XWindowAttributes xgwa;
       XGetWindowAttributes (dpy, window, &xgwa);
       XSelectInput (dpy, window,
-                    xgwa.your_event_mask | KeyPressMask | ButtonPressMask);
+                    xgwa.your_event_mask |
+                    KeyPressMask | ButtonPressMask | ExposureMask);
     }
 
   while (1)
     {
       Bool did;
-      do {  i = (random() & 0xFF) % 15; } while (i == j);
-      switch (i)
-       {
-       case 0:  did = windows(dpy, window, delay, 0); break;
-       case 1:  did = windows(dpy, window, delay, 1); break;
-       case 2:  did = windows(dpy, window, delay, 2); break;
-       case 3:  did = amiga(dpy, window, delay); break;
-       case 4:  did = mac(dpy, window, delay); break;
-       case 5:  did = macsbug(dpy, window, delay); break;
-       case 6:  did = mac1(dpy, window, delay); break;
-       case 7:  did = macx(dpy, window, delay); break;
-       case 8:  did = sco(dpy, window, delay); break;
-       case 9:  did = sparc_linux(dpy, window, delay); break;
-       case 10: did = bsd(dpy, window, delay); break;
-       case 11: did = atari(dpy, window, delay); break;
-       case 12: did = blitdamage(dpy, window, delay); break;
-       case 13: did = sparc_solaris(dpy, window, delay); break;
-       case 14: did = linux_fsck(dpy, window, delay); break;
-       default: abort(); break;
-       }
+      int count = countof(all_modes);
+      char name[100], class[100];
+
+      if (only > 0)
+        i = only;
+      else
+        do {  i = (random() & 0xFF) % count; } while (i == j);
+
+      sprintf (name,  "do%s", all_modes[i].name);
+      sprintf (class, "Do%s", all_modes[i].name);
+
+      did = False;
+      if (only > 0 || get_boolean_resource(name, class))
+        {
+          all_modes[i].fn (dpy, window, delay);
+          did = True;
+        }
+
       loop++;
       if (loop > 100) j = -1;
       if (loop > 200)