http://www.mirrorservice.org/sites/master.us.finkmirrors.net/distfiles/md5/fa43fdd68d...
[xscreensaver] / hacks / bsod.c
index a3b0a9cc5b18a9237dd3dcd19c3f1a32698ea346..450f10c18ff0cc90ccac35c96b4d0bb063ba126b 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1998 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1998-2003 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
  * Blue Screen of Death: the finest in personal computer emulation.
  * Concept cribbed from Stephen Martin <smartin@mks.com>;
  * 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,
- *         to simulate corruption of video ram?
- *      -  Should randomize the various hex numbers printed.
  */
 
 #include "screenhack.h"
+#include "xpm-pixmap.h"
 #include <stdio.h>
+#include <time.h>
+#include <sys/time.h>
 #include <X11/Xutil.h>
 
-#ifdef HAVE_XPM
-# include <X11/xpm.h>
-# include "images/amiga.xpm"
-#endif
+#ifdef HAVE_UNAME
+# include <sys/utsname.h>
+#endif /* HAVE_UNAME */
 
+#include "images/amiga.xpm"
 #include "images/atari.xbm"
 #include "images/mac.xbm"
+#include "images/macbomb.xbm"
+#include "images/hmac.xpm"
 
 
-static void
+static int
 draw_string (Display *dpy, Window window, GC gc, XGCValues *gcv,
             XFontStruct *font,
             int xoff, int yoff,
@@ -120,6 +117,8 @@ draw_string (Display *dpy, Window window, GC gc, XGCValues *gcv,
        }
       s++;
     }
+
+  return width * char_width;
 }
 
 
@@ -158,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);
@@ -182,8 +195,8 @@ bsod_sleep(Display *dpy, int seconds)
 }
 
 
-static void
-windows (Display *dpy, Window window, int delay, Bool w95p)
+static Bool
+windows (Display *dpy, Window window, int delay, int which)
 {
   XGCValues gcv;
   XWindowAttributes xgwa;
@@ -204,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"
@@ -250,15 +263,47 @@ windows (Display *dpy, Window window, int delay, Bool w95p)
    "contact your system administrator or technical support group."
      );
 
+  const char *w2ka =
+    ("*** STOP: 0x000000D1 (0xE1D38000,0x0000001C,0x00000000,0xF09D42DA)\n"
+     "DRIVER_IRQL_NOT_LESS_OR_EQUAL \n"
+     "\n"
+    "*** Address F09D42DA base at F09D4000, DateStamp 39f459ff - CRASHDD.SYS\n"
+     "\n"
+     "Beginning dump of physical memory\n");
+  const char *w2kb =
+    ("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.");
+
+  if (which < 0 || which > 2) abort();
+
+  /* kludge to lump Win2K and WinME together; seems silly to add another
+     preference/command line option just for this little one. */
+  if (which == 2 && (random() % 2))
+    which = 3;
+
+  if (!get_boolean_resource((which == 0 ? "doWindows" :
+                             which == 1 ? "doNT" :
+                             which == 2 ? "doWin2K" :
+                                          "doWin2K"), /* "doWinME" ? */
+                            "DoWindows"))
+    return False;
+
   XGetWindowAttributes (dpy, window, &xgwa);
 
   fontname = get_string_resource ((xgwa.height > 600
-                                  ? (w95p
-                                     ? "windows95.font2"
-                                     : "windowsNT.font2")
-                                  : (w95p
-                                     ? "windows95.font"
-                                     : "windowsNT.font")),
+                                  ? (which == 0 ? "windows95.font2" :
+                                      which == 1 ? "windowsNT.font2" :
+                                      which == 2 ? "windows2K.font2" :
+                                                   "windowsME.font2")
+                                  : (which == 0 ? "windows95.font" :
+                                     which == 1 ? "windowsNT.font" :
+                                     which == 2 ? "windows2K.font" :
+                                                   "windowsME.font")),
                                  "Windows.Font");
   if (!fontname || !*fontname) fontname = (char *)def_font;
   font = XLoadQueryFont (dpy, fontname);
@@ -268,14 +313,16 @@ windows (Display *dpy, Window window, int delay, Bool w95p)
     free (fontname);
 
   gcv.font = font->fid;
-  gcv.foreground = get_pixel_resource((w95p
-                                      ? "windows95.foreground"
-                                      : "windowsNT.foreground"),
+  gcv.foreground = get_pixel_resource((which == 0 ? "windows95.foreground" :
+                                      which == 1 ? "windowsNT.foreground" :
+                                      which == 2 ? "windows2K.foreground" :
+                                                    "windowsME.foreground"),
                                      "Windows.Foreground",
                                      dpy, xgwa.colormap);
-  gcv.background = get_pixel_resource((w95p
-                                      ? "windows95.background"
-                                      : "windowsNT.background"),
+  gcv.background = get_pixel_resource((which == 0 ? "windows95.background" :
+                                      which == 1 ? "windowsNT.background" :
+                                      which == 2 ? "windows2K.background" :
+                                                    "windowsME.background"),
                                      "Windows.Background",
                                      dpy, xgwa.colormap);
   XSetWindowBackground(dpy, window, gcv.background);
@@ -283,23 +330,60 @@ windows (Display *dpy, Window window, int delay, Bool w95p)
 
   gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
 
-  if (w95p)
+  if (which == 0)
     draw_string(dpy, window, gc, &gcv, font,
                0, 0, xgwa.width, xgwa.height, w95, 0);
-  else
+  else if (which == 1)
     draw_string(dpy, window, gc, &gcv, font, 0, 0, 10, 10, wnt, 750);
+  else if (which == 2)
+    {
+      int line_height = font->ascent + font->descent + 1;
+      int x = 20;
+      int y = (xgwa.height / 4);
+
+      draw_string(dpy, window, gc, &gcv, font, x, y, 10, 10, w2ka, 750);
+      y += line_height * 6;
+      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;
+      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;
 }
 
 /* SCO OpenServer 5 panic, by Tom Kelly <tom@ancilla.toronto.on.ca>
  */
-static void
-openserver (Display *dpy, Window window, int delay)
+static Bool
+sco (Display *dpy, Window window, int delay)
 {
   XGCValues gcv;
   XWindowAttributes xgwa;
@@ -307,10 +391,11 @@ openserver (Display *dpy, Window window, int delay)
   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 *openserver_panic =
-    ("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
-     "Unexpected trap in kernel mode:\n"
+  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"
@@ -321,22 +406,35 @@ openserver (Display *dpy, Window window, int delay)
      "\n"
      "PANIC: k_trap - kernel mode trap type 0x0000000E\n"
      "Trying to dump 5023 pages to dumpdev hd (1/41), 63 pages per '.'\n"
-     "...............................................................................\n"
-     "5023 pages dumped\n"
+    );
+  const char *sco_panic_2 =
+   ("...............................................................................\n"
+    );
+  const char *sco_panic_3 =
+    ("5023 pages dumped\n"
      "\n"
      "\n"
-     "**   Safe to Power Off   **\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
-                                  ? "openserver.font2"
-                                  : "openserver.font"),
-                                 "OpenServer.Font");
+                                  ? "sco.font2"
+                                  : "sco.font"),
+                                 "SCO.Font");
   if (!fontname || !*fontname) fontname = (char *)def_font;
   font = XLoadQueryFont (dpy, fontname);
   if (!font) font = XLoadQueryFont (dpy, def_font);
@@ -345,11 +443,11 @@ openserver (Display *dpy, Window window, int delay)
     free (fontname);
 
   gcv.font = font->fid;
-  gcv.foreground = get_pixel_resource(("openserver.foreground"),
-                                     "OpenServer.Foreground",
+  gcv.foreground = get_pixel_resource(("sco.foreground"),
+                                     "SCO.Foreground",
                                      dpy, xgwa.colormap);
-  gcv.background = get_pixel_resource(("openserver.background"),
-                                     "OpenServer.Background",
+  gcv.background = get_pixel_resource(("sco.background"),
+                                     "SCO.Background",
                                      dpy, xgwa.colormap);
   XSetWindowBackground(dpy, window, gcv.background);
   XClearWindow(dpy, window);
@@ -357,18 +455,53 @@ openserver (Display *dpy, Window window, int delay)
   gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
 
   draw_string(dpy, window, gc, &gcv, font,
-               0, 0, xgwa.width, xgwa.height, openserver_panic, 0);
-  XFreeGC(dpy, gc);
+             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 void
+static Bool
 sparc_linux (Display *dpy, Window window, int delay)
 {
   XGCValues gcv;
@@ -377,6 +510,8 @@ sparc_linux (Display *dpy, Window window, int delay)
   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"
@@ -397,10 +532,13 @@ sparc_linux (Display *dpy, Window window, int delay)
        "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:"
-
+       "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);
 
@@ -428,15 +566,162 @@ sparc_linux (Display *dpy, Window window, int delay)
   gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
 
   draw_string(dpy, window, gc, &gcv, font,
-               0, 0, xgwa.width, xgwa.height, linux_panic, 0);
+             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;
 }
 
-static void
+/* 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;
@@ -448,12 +733,17 @@ 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;
+  int string_width;
+  int margin;
 
   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
@@ -484,37 +774,10 @@ amiga (Display *dpy, Window window, int delay)
 
   height = (font->ascent + font->descent) * 6;
 
-#ifdef HAVE_XPM
-  {
-    XpmAttributes xpmattrs;
-    int result;
-    xpmattrs.valuemask = 0;
-
-# ifdef XpmCloseness
-    xpmattrs.valuemask |= XpmCloseness;
-    xpmattrs.closeness = 40000;
-# endif
-# ifdef XpmVisual
-    xpmattrs.valuemask |= XpmVisual;
-    xpmattrs.visual = xgwa.visual;
-# endif
-# ifdef XpmDepth
-    xpmattrs.valuemask |= XpmDepth;
-    xpmattrs.depth = xgwa.depth;
-# endif
-# ifdef XpmColormap
-    xpmattrs.valuemask |= XpmColormap;
-    xpmattrs.colormap = xgwa.colormap;
-# endif
-
-    result = XpmCreatePixmapFromData(dpy, window, amiga_hand,
-                                    &pixmap, 0 /* mask */, &xpmattrs);
-    if (!pixmap || (result != XpmSuccess && result != XpmColorError))
-      pixmap = 0;
-    pix_w = xpmattrs.width;
-    pix_h = xpmattrs.height;
-  }
-#endif /* HAVE_XPM */
+#if defined(HAVE_GDK_PIXBUF) || defined (HAVE_XPM)
+  pixmap = xpm_data_to_pixmap (dpy, window, (char **) amiga_hand,
+                               &pix_w, &pix_h, 0);
+#endif /* HAVE_GDK_PIXBUF || HAVE_XPM */
 
   if (pixmap && xgwa.height > 600)     /* scale up the bitmap */
     {
@@ -539,18 +802,24 @@ amiga (Display *dpy, Window window, int delay)
     }
 
   XFillRectangle(dpy, window, gc2, 0, 0, xgwa.width, height);
-  draw_string(dpy, window, gc, &gcv, font, 0, 0, xgwa.width, height, string,0);
-
+  margin = font->ascent;
+  string_width = draw_string(dpy, window, gc, &gcv, font,
+                             margin, 0,
+                             xgwa.width - (margin * 2), height,
+                             string, 0);
   {
     GC gca = gc;
     while (delay > 0)
       {
-       XFillRectangle(dpy, window, gca, 0, 0, xgwa.width, font->ascent);
-       XFillRectangle(dpy, window, gca, 0, 0, font->ascent, height);
-       XFillRectangle(dpy, window, gca, xgwa.width-font->ascent, 0,
-                      font->ascent, height);
-       XFillRectangle(dpy, window, gca, 0, height-font->ascent, xgwa.width,
-                      font->ascent);
+        int x2;
+       XFillRectangle(dpy, window, gca, 0, 0, xgwa.width, margin);
+       XFillRectangle(dpy, window, gca, 0, 0, margin, height);
+        XFillRectangle(dpy, window, gca,
+                       0, height - margin, xgwa.width, margin);
+        x2 = margin + string_width;
+        if (x2 < xgwa.width - margin) x2 = xgwa.width - margin;
+        XFillRectangle(dpy, window, gca, x2, 0, margin, height);
+
        gca = (gca == gc ? gc2 : gc);
        XSync(dpy, False);
        if (bsod_sleep(dpy, 1))
@@ -564,6 +833,7 @@ amiga (Display *dpy, Window window, int delay)
   XSync(dpy, False);
   XClearWindow(dpy, window);
   XFreeFont(dpy, font);
+  return True;
 }
 
 
@@ -577,7 +847,7 @@ amiga (Display *dpy, Window window, int delay)
        Perhaps somebody else can tell you more about it..  its just
        a quick hack :-}
  */
-static void
+static Bool
 atari (Display *dpy, Window window, int delay)
 {
        
@@ -589,9 +859,12 @@ atari (Display *dpy, Window window, int delay)
   Pixmap pixmap = 0;
   int pix_w = atari_width;
   int pix_h = atari_height;
-  int offset = atari_width + 2;
+  int offset;
   int i, x, y;
 
+  if (!get_boolean_resource("doAtari", "DoAtari"))
+    return False;
+
   XGetWindowAttributes (dpy, window, &xgwa);
 
   font = XLoadQueryFont (dpy, def_font);
@@ -609,11 +882,15 @@ atari (Display *dpy, Window window, int delay)
   gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
 
   pixmap = XCreatePixmapFromBitmapData(dpy, window, (char *) atari_bits,
-                                      atari_width, atari_height,
-                                      gcv.foreground,
-                                      gcv.background,
+                                      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;
@@ -624,21 +901,24 @@ atari (Display *dpy, Window window, int delay)
   }  
   
   for (i=7 ; i<10 ; i++) {
-    bsod_sleep(dpy, 1);
+    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);
-  bsod_sleep(dpy, delay);
   XClearWindow(dpy, window);
   XFreeFont(dpy, font);
+  return True;
 }
 
 
-static void
+static Bool
 mac (Display *dpy, Window window, int delay)
 {
   XGCValues gcv;
@@ -656,6 +936,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");
@@ -682,9 +965,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,
@@ -702,14 +982,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;
@@ -820,6 +1104,9 @@ 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);
@@ -921,85 +1208,1094 @@ macsbug (Display *dpy, Window window, int delay)
   XFreeGC(dpy, gc2);
   XClearWindow(dpy, window);
   XFreeFont(dpy, font);
+  return True;
+}
+
+static Bool
+mac1 (Display *dpy, Window window, int delay)
+{
+  XGCValues gcv;
+  XWindowAttributes xgwa;
+  GC gc;
+  Pixmap pixmap = 0;
+  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",
+                                     dpy, xgwa.colormap);
+  gcv.background = get_pixel_resource("mac1.background", "Mac.Background",
+                                     dpy, xgwa.colormap);
+  XSetWindowBackground(dpy, window, gcv.background);
+  XClearWindow(dpy, window);
+
+  gc = XCreateGC(dpy, window, GCForeground|GCBackground, &gcv);
+
+  pixmap = XCreatePixmapFromBitmapData(dpy, window, (char *) macbomb_bits,
+                                      macbomb_width, macbomb_height,
+                                      gcv.foreground,
+                                      gcv.background,
+                                      xgwa.depth);
+
+  {
+    int x = (xgwa.width - pix_w) / 2;
+    int y = (xgwa.height - pix_h) / 2;
+    if (y < 0) y = 0;
+    XFillRectangle (dpy, window, gc, 0, 0, xgwa.width, xgwa.height);
+    XSync(dpy, False);
+    if (bsod_sleep(dpy, 1))
+      goto DONE;
+    XCopyArea(dpy, pixmap, window, gc, 0, 0, pix_w, pix_h, x, y);
+  }
+
+ DONE:
+  XFreeGC(dpy, gc);
+  XFreePixmap(dpy, pixmap);
+  XSync(dpy, False);
+  bsod_sleep(dpy, delay);
+  XClearWindow(dpy, window);
+  return True;
 }
 
 
+static Bool
+macx (Display *dpy, Window window, int delay)
+{
+  XGCValues gcv;
+  XWindowAttributes xgwa;
+  char *fontname = 0;
+  const char *def_font = "fixed";
+  XFontStruct *font;
+  GC gc;
+
+  const char *macx_panic =
+   ("panic(cpu 0): Unable to find driver for this platform: "
+    "\"PowerMac 3,5\".\n"
+    "\n"
+    "backtrace: 0x0008c2f4 0x0002a7a0 0x001f0204 0x001d4e4c 0x001d4c5c "
+    "0x001a56cc 0x01d5dbc 0x001c621c 0x00037430 0x00037364\n"
+    "\n"
+    "\n"
+    "\n"
+    "No debugger configured - dumping debug information\n"
+    "\n"
+    "version string : Darwin Kernel Version 1.3:\n"
+    "Thu Mar  1 06:56:40 PST 2001; root:xnu/xnu-123.5.obj~1/RELEASE_PPC\n"
+    "\n"
+    "\n"
+    "\n"
+    "\n"
+    "DBAT0: 00000000 00000000\n"
+    "DBAT1: 00000000 00000000\n"
+    "DBAT2: 80001FFE 8000003A\n"
+    "DBAT3: 90001FFE 9000003A\n"
+    "MSR=00001030\n"
+    "backtrace: 0x0008c2f4 0x0002a7a0 0x001f0204 0x001d4e4c 0x001d4c5c "
+    "0x001a56cc 0x01d5dbc 0x001c621c 0x00037430 0x00037364\n"
+    "\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",
+                                      "MacX.Background",
+                                     dpy, xgwa.colormap);
+  XSetWindowBackground(dpy, window, gcv.background);
+  XClearWindow(dpy, window);
+
+  fontname = get_string_resource ((xgwa.height > 900
+                                  ? "macX.font2"
+                                  : "macX.font"),
+                                 "MacX.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("macsbug.foreground",
+                                     "MacsBug.Foreground",
+                                     dpy, xgwa.colormap);
+  gcv.background = get_pixel_resource("macsbug.background",
+                                     "MacsBug.Background",
+                                     dpy, xgwa.colormap);
+
+
+  gcv.foreground = get_pixel_resource("macX.textForeground",
+                                      "MacX.TextForeground",
+                                     dpy, xgwa.colormap);
+  gcv.background = get_pixel_resource("macX.textBackground",
+                                      "MacX.TextBackground",
+                                     dpy, xgwa.colormap);
+  gc = XCreateGC(dpy, window, GCForeground|GCBackground|GCFont, &gcv);
+
+#if defined(HAVE_GDK_PIXBUF) || defined (HAVE_XPM)
+  {
+    Pixmap pixmap = 0;
+    Pixmap mask = 0;
+    int x, y, pix_w, pix_h;
+    pixmap = xpm_data_to_pixmap (dpy, window, (char **) happy_mac,
+                                 &pix_w, &pix_h, &mask);
+
+    x = (xgwa.width - pix_w) / 2;
+    y = (xgwa.height - pix_h) / 2;
+    if (y < 0) y = 0;
+    XSync(dpy, False);
+    bsod_sleep(dpy, 2);
+    XSetClipMask (dpy, gc, mask);
+    XSetClipOrigin (dpy, gc, x, y);
+    XCopyArea (dpy, pixmap, window, gc, 0, 0, pix_w, pix_h, x, y);
+    XSetClipMask (dpy, gc, None);
+    XFreePixmap (dpy, pixmap);
+  }
+#endif /* HAVE_GDK_PIXBUF || HAVE_XPM */
+
+  bsod_sleep(dpy, 3);
+
+  {
+    const char *s;
+    int x = 0, y = 0;
+    int char_width, line_height;
+    char_width = (font->per_char
+                  ? font->per_char['n'-font->min_char_or_byte2].width
+                  : font->min_bounds.width);
+    line_height = font->ascent + font->descent;
+
+    s = macx_panic;
+    y = font->ascent;
+    while (*s)
+      {
+        int ox = x;
+        int oy = y;
+        if (*s == '\n' || x + char_width >= xgwa.width)
+          {
+            x = 0;
+            y += line_height;
+          }
+
+        if (*s == '\n')
+          {
+            /* Note that to get this goofy effect, they must be actually
+               emitting LF CR at the end of each line instead of CR LF!
+             */
+            XDrawImageString (dpy, window, gc, ox, oy, " ", 1);
+            XDrawImageString (dpy, window, gc, ox, y, " ", 1);
+          }
+        else
+          {
+            XDrawImageString (dpy, window, gc, x, y, s, 1);
+            x += char_width;
+          }
+        s++;
+      }
+  }
+
+  XFreeGC(dpy, gc);
+  XSync(dpy, False);
+  bsod_sleep(dpy, delay);
+  XClearWindow(dpy, window);
+  return True;
+}
+
+
+
+
 \f
-char *progclass = "BSOD";
+/* 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;
 
-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",
-
-  ".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",
+  XGetWindowAttributes(dpy, window, &xwa);
+
+  load_random_image (xwa.screen, window, window);
+
+  w = xwa.width;
+  h = xwa.height;
+
+  gc_mask = GCForeground;
   
-  ".OpenServer.font:    -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
-  ".OpenServer.font2:   -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
-  ".OpenServer.foreground: White",
-  ".OpenServer.background: Black",
+  gcv.plane_mask = random();
+  gc_mask |= GCPlaneMask;
   
-  ".SparcLinux.font:    -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
-  ".SparcLinux.font2:   -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  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);
+
+    if (bsod_sleep(dpy, 0))
+      goto DONE;
+  }
+
+  bsod_sleep(dpy, delay);
+
+ DONE:
+  XFreeGC(dpy, gc0);
+
+  return True;
+}
+
+\f
+/*
+ * SPARC Solaris panic. Should look pretty authentic on Solaris boxes.
+ * Anton Solovyev <solovam@earthlink.net>
+ */ 
+
+typedef struct
+{
+  Display *dpy;
+  Window window;
+  GC gc, erase_gc;
+  XFontStruct *xfs;
+  int sub_width;                /* Text subwindow width in pixels */
+  int sub_height;               /* Text subwindow height in pixels */
+  int sub_x;                    /* upper left corner of the text subwindow */
+  int sub_y;                    /* upper left corner of the text subwindow */
+  int char_width;               /* Char width in pixels */
+  int line_height;              /* Line height in pixels */
+  int columns;                  /* Number of columns in the text screen */
+  int x;                        /* horizontal position of the cursor */
+} scrolling_window;
+
+
+static scrolling_window *
+make_scrolling_window (Display *dpy, Window window,
+                       const char *name,
+                       Bool grab_screen_p)
+{
+  const char *def_font = "fixed";
+  scrolling_window* ts;
+  XWindowAttributes xgwa;
+  XGCValues gcv;
+  char* fn;
+  char buf1[100], buf2[100];
+
+  ts = malloc (sizeof (*ts));
+  ts->window = window;
+  ts->dpy = dpy;
+
+  ts->x = 0;
+
+  XGetWindowAttributes (dpy, window, &xgwa);
+
+  if (grab_screen_p)
+    {
+      ts->sub_width = xgwa.width * 0.8;
+      ts->sub_height = xgwa.height * 0.8;
+    }
+  else
+    {
+      ts->sub_width  = xgwa.width - 20;
+      ts->sub_height = xgwa.height - 20;
+      if (ts->sub_width  < 20) ts->sub_width  = 20;
+      if (ts->sub_height < 20) ts->sub_height = 20;
+    }
+
+  sprintf (buf1, "%.50s.font", name);
+  sprintf (buf2, "%.50s.Font", name);
+  fn = get_string_resource (buf1, buf2);
+  ts->xfs = XLoadQueryFont (dpy, fn);
+  if (!ts->xfs)
+    {
+      sprintf (buf1, "%.50s.font2", name);
+      fn = get_string_resource(buf1, buf2);
+      ts->xfs = XLoadQueryFont(dpy, fn);
+    }
+  if (!ts->xfs)
+    ts->xfs = XLoadQueryFont(dpy, def_font);
+  if (!ts->xfs)
+    exit (1);
+  gcv.font = ts->xfs->fid;
+  ts->char_width = (ts->xfs->per_char
+                    ? ts->xfs->per_char['n'-ts->xfs->min_char_or_byte2].width
+                    : ts->xfs->min_bounds.width);
+  ts->line_height = ts->xfs->ascent + ts->xfs->descent + 1;
+
+  ts->columns = ts->sub_width / ts->char_width;
+
+  ts->sub_x = (xgwa.width - ts->sub_width) / 2;
+  ts->sub_y = (xgwa.height - ts->sub_height) / 2;
+
+  if (!grab_screen_p) ts->sub_height += ts->sub_y, ts->sub_y = 0;
+
+  if (grab_screen_p)
+    load_random_image (xgwa.screen, window, window);
+
+  sprintf (buf1, "%.50s.background", name);
+  sprintf (buf2, "%.50s.Background", name);
+  gcv.background = get_pixel_resource (buf1, buf2, dpy, xgwa.colormap);
+
+  sprintf (buf1, "%.50s.foreground", name);
+  sprintf (buf2, "%.50s.Foreground", name);
+  gcv.foreground = get_pixel_resource (buf1, buf2, dpy, xgwa.colormap);
+
+  ts->gc = XCreateGC (dpy, window,
+                      GCForeground | GCBackground | GCFont,
+                      &gcv);
+  gcv.foreground = gcv.background;
+  ts->erase_gc = XCreateGC (dpy, window,
+                            GCForeground | GCBackground,
+                            &gcv);
+  XSetWindowBackground (dpy, window, gcv.background);
+  return(ts);
+}
+
+static void
+free_scrolling_window (scrolling_window* ts)
+{
+  XFreeGC (ts->dpy, ts->gc);
+  XFreeGC (ts->dpy, ts->erase_gc);
+  XFreeFont (ts->dpy, ts->xfs);
+  free (ts);
+}
+
+static void
+scrolling_putc (scrolling_window* ts, const char aChar)
+{
+  switch (aChar)
+    {
+    case '\n':
+      ts->x = 0;
+      XCopyArea (ts->dpy, ts->window, ts->window, ts->gc,
+                 ts->sub_x, ts->sub_y + ts->line_height,
+                 ts->sub_width, ts->sub_height,
+                 ts->sub_x, ts->sub_y);
+      XFillRectangle (ts->dpy, ts->window, ts->erase_gc,
+                      ts->sub_x, ts->sub_y + ts->sub_height - ts->line_height,
+                      ts->sub_width, ts->line_height);
+      break;
+    case '\b':
+      if(ts->x > 0)
+        ts->x--;
+      break;
+    default:
+      if (ts->x >= ts->columns)
+        scrolling_putc (ts, '\n');
+      XDrawImageString (ts->dpy, ts->window, ts->gc,
+                        (ts->sub_x +
+                         (ts->x * ts->char_width)
+                         - ts->xfs->min_bounds.lbearing),
+                        (ts->sub_y + ts->sub_height - ts->xfs->descent),
+                        &aChar, 1);
+      ts->x++;
+      break;
+    }
+}
+
+static Bool
+scrolling_puts (scrolling_window *ts, const char* aString, int delay)
+{
+  const char *c;
+  for (c = aString; *c; ++c)
+    {
+      scrolling_putc (ts, *c);
+      if (delay)
+        {
+          XSync(ts->dpy, 0);
+          usleep(delay);
+          if (bsod_sleep (ts->dpy, 0))
+            return True;
+        }
+    }
+  XSync (ts->dpy, 0);
+  return False;
+}
+
+static Bool
+sparc_solaris (Display* dpy, Window window, int delay)
+{
+  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"
+    " user address.\n"
+    "adb: trap type = 0x31\n"
+    "addr=0xf3880\n"
+    "pid=307, pc=0x100306e4, sp=0x2a10043ae81, tstate=0x4480001602,"
+    " context=0x87f\n"
+    "g1-g7: 1045b000, 32f, 10079440, 180, 300000ebde8, 0, 30000953a20\n"
+    "Begin traceback... sp = 2a10043ae81\n"
+    "Called from 100bd060, fp=2a10043af31, args=f3700 300008cc988 f3880 0"
+    " 1 300000ebde0.\n"
+    "Called from 101fe1bc, fp=2a10043b011, args=3000045a240 104465a0"
+    " 300008e47d0 300008e48fa 300008ae350 300008ae410\n"
+    "Called from 1007c520, fp=2a10043b0c1, args=300008e4878 300003596e8 0"
+    " 3000045a320 0 3000045a220\n"
+    "Called from 1007c498, fp=2a10043b171, args=1045a000 300007847f0 20"
+    " 3000045a240 1 0\n"
+    "Called from 1007972c, fp=2a10043b221, args=1 300009517c0 30000951e58 1"
+    " 300007847f0 0\n"
+    "Called from 10031e10, fp=2a10043b2d1, args=3000095b0c8 0 300009396a8"
+    " 30000953a20 0 1\n"
+    "Called from 10000bdd8, fp=ffffffff7ffff1c1, args=0 57 100131480"
+    " 100131480 10012a6e0 0\n"
+    "End traceback...\n"
+    "panic[cpu0]/thread=30000953a20: trap\n"
+    "syncing file systems...";
+  const char *msg2 =
+    " 1 done\n"
+    "dumping to /dev/dsk/c0t0d0s3, offset 26935296\n";
+  const char *msg3 =
+    ": 2803 pages dumped, compression ratio 2.88, dump succeeded\n";
+  const char *msg4 =
+    "rebooting...\n"
+    "Resetting ...";
+
+  scrolling_window *ts;
+  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);
+  if (bsod_sleep (dpy, 3))
+    goto DONE;
+
+  scrolling_puts (ts, msg2, 0);
+  if (bsod_sleep (dpy, 2))
+    goto DONE;
+
+  for (i = 1; i <= 100; ++i)
+    {
+      sprintf(buf, "\b\b\b\b\b\b\b\b\b\b\b%3d%% done", i);
+      scrolling_puts (ts, buf, 0);
+      if (bsod_sleep (dpy, -1))
+        goto DONE;
+    }
+
+  scrolling_puts (ts, msg3, 0);
+  if (bsod_sleep (dpy, 2))
+    goto DONE;
+
+  scrolling_puts (ts, msg4, 0);
+  if (bsod_sleep(dpy, 3))
+    goto DONE;
+
+  bsod_sleep (dpy, 3);
+
+ DONE:
+  free_scrolling_window (ts);
+
+  return True;
+}
+
+/* Linux panic and fsck, by jwz
+ */
+static Bool
+linux_fsck (Display *dpy, Window window, int delay)
+{
+  XWindowAttributes xgwa;
+  scrolling_window *ts;
+  int i;
+  const char *sysname;
+  char buf[1024];
+
+  const char *linux_panic[] = {
+   " kernel: Unable to handle kernel paging request at virtual "
+     "address 0000f0ad\n",
+   " kernel:  printing eip:\n",
+   " kernel: c01becd7\n",
+   " kernel: *pde = 00000000\n",
+   " kernel: Oops: 0000\n",
+   " kernel: CPU:    0\n",
+   " kernel: EIP:    0010:[<c01becd7>]    Tainted: P \n",
+   " kernel: EFLAGS: 00010286\n",
+   " kernel: eax: 0000ff00   ebx: ca6b7e00   ecx: ce1d7a60   edx: ce1d7a60\n",
+   " kernel: esi: ca6b7ebc   edi: 00030000   ebp: d3655ca0   esp: ca6b7e5c\n",
+   " kernel: ds: 0018   es: 0018   ss: 0018\n",
+   " kernel: Process crond (pid: 1189, stackpage=ca6b7000)\n",
+   " kernel: Stack: d3655ca0 ca6b7ebc 00030054 ca6b7e7c c01c1e5b "
+       "00000287 00000020 c01c1fbf \n",
+   "",
+   " kernel:        00005a36 000000dc 000001f4 00000000 00000000 "
+       "ce046d40 00000001 00000000 \n",
+   "", "", "",
+   " kernel:        ffffffff d3655ca0 d3655b80 00030054 c01bef93 "
+       "d3655ca0 ca6b7ebc 00030054 \n",
+   "", "", "",
+   " kernel: Call Trace:    [<c01c1e5b>] [<c01c1fbf>] [<c01bef93>] "
+       "[<c01bf02b>] [<c0134c4f>]\n",
+   "", "", "",
+   " kernel:   [<c0142562>] [<c0114f8c>] [<c0134de3>] [<c010891b>]\n",
+   " kernel: \n",
+   " kernel: Code: 2a 00 75 08 8b 44 24 2c 85 c0 74 0c 8b 44 24 58 83 48 18 "
+      "08 \n",
+   0
+  };
+
+  if (!get_boolean_resource("doLinux", "DoLinux"))
+    return False;
+
+  XGetWindowAttributes (dpy, window, &xgwa);
+  XSetWindowBackground (dpy, window, 
+                        get_pixel_resource("Linux.background",
+                                           "Linux.Background",
+                                           dpy, xgwa.colormap));
+  XClearWindow(dpy, window);
+
+  sysname = "linux";
+# 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 */
+
+
+  ts = make_scrolling_window (dpy, window, "Linux", False);
+
+  scrolling_puts (ts, "waiting for X server to shut down ", 0);
+  usleep (100000);
+  if (bsod_sleep (dpy, 0))
+    goto PANIC;
+  scrolling_puts (ts,
+                  "XIO:  fatal IO error 2 (broken pipe) on X server \":0.0\"\n"
+                  "        after 339471 requests (339471 known processed) "
+                  "with 0 events remaining\n",
+                  0);
+  if (scrolling_puts (ts, ".........\n", 300000))
+    goto PANIC;
+  if (bsod_sleep (dpy, 0))
+    goto PANIC;
+  scrolling_puts (ts,
+                  "xinit:  X server slow to shut down, sending KILL signal.\n",
+                  0);
+  scrolling_puts (ts, "waiting for server to die ", 0);
+  if (scrolling_puts (ts, "...\n", 300000))
+    goto PANIC;
+  if (bsod_sleep (dpy, 0))
+    goto PANIC;
+  scrolling_puts (ts, "xinit:  Can't kill server\n", 0);
+
+  if (bsod_sleep (dpy, 2))
+    goto PANIC;
+
+  sprintf (buf, "\n%s Login: ", sysname);
+  scrolling_puts (ts, buf, 0);
+  if (bsod_sleep (dpy, 1))
+    goto PANIC;
+  scrolling_puts (ts,
+    "\n\n"
+    "Parallelizing fsck version 1.22 (22-Jun-2001)\n"
+    "e2fsck 1.22, 22-Jun-2001 for EXT2 FS 0.5b, 95/08/09\n"
+    "Warning!  /dev/hda1 is mounted.\n"
+    "/dev/hda1 contains a file system with errors, check forced.\n",
+                0);
+  if (bsod_sleep (dpy, 1))
+    goto PANIC;
+
+  if (0 == random() % 2)
+  scrolling_puts (ts,
+     "Couldn't find ext2 superblock, trying backup blocks...\n"
+     "The filesystem size (according to the superblock) is 3644739 blocks\n"
+     "The physical size of the device is 3636706 blocks\n"
+     "Either the superblock or the partition table is likely to be corrupt!\n"
+     "Abort<y>? no\n",
+                0);
+  if (bsod_sleep (dpy, 1))
+    goto PANIC;
+
+ AGAIN:
+
+  scrolling_puts (ts, "Pass 1: Checking inodes, blocks, and sizes\n", 0);
+  if (bsod_sleep (dpy, 2))
+    goto PANIC;
+
+  i = (random() % 60) - 20;
+  while (--i > 0)
+    {
+      int b = random() % 0xFFFF;
+      sprintf (buf, "Deleted inode %d has zero dtime.  Fix<y>? yes\n\n", b);
+      scrolling_puts (ts, buf, 0);
+    }
+
+  i = (random() % 40) - 10;
+  if (i > 0)
+    {
+      int g = random() % 0xFFFF;
+      int b = random() % 0xFFFFFFF;
+
+      if (bsod_sleep (dpy, 1))
+        goto PANIC;
+
+      sprintf (buf, "Warning: Group %d's copy of the group descriptors "
+               "has a bad block (%d).\n", g, b);
+      scrolling_puts (ts, buf, 0);
+
+      b = random() % 0x3FFFFF;
+      while (--i > 0)
+        {
+          b += random() % 0xFFFF;
+          sprintf (buf,
+                   "Error reading block %d (Attempt to read block "
+                   "from filesystem resulted in short read) while doing "
+                   "inode scan.  Ignore error<y>?",
+                   b);
+          scrolling_puts (ts, buf, 0);
+          usleep (10000);
+          scrolling_puts (ts, " yes\n\n", 0);
+        }
+    }
+
+  if (0 == (random() % 10))
+    {
+
+      if (bsod_sleep (dpy, 1))
+        goto PANIC;
+
+      i = 3 + (random() % 10);
+      while (--i > 0)
+        scrolling_puts (ts, "Could not allocate 256 block(s) for inode table: "
+                        "No space left on device\n", 0);
+      scrolling_puts (ts, "Restarting e2fsck from the beginning...\n", 0);
+
+      if (bsod_sleep (dpy, 2))
+        goto PANIC;
+
+      goto AGAIN;
+    }
+
+  i = (random() % 20) - 5;
+
+  if (i > 0)
+    if (bsod_sleep (dpy, 1))
+      goto PANIC;
+
+  while (--i > 0)
+    {
+      int j = 5 + (random() % 10);
+      int w = random() % 4;
+
+      while (--j > 0)
+        {
+          int b = random() % 0xFFFFF;
+          int g = random() % 0xFFF;
+
+          if (0 == (random() % 10))
+            b = 0;
+          else if (0 == (random() % 10))
+            b = -1;
+
+          if (w == 0)
+            sprintf (buf,
+                     "Inode table for group %d not in group.  (block %d)\n"
+                     "WARNING: SEVERE DATA LOSS POSSIBLE.\n"
+                     "Relocate<y>?",
+                     g, b);
+          else if (w == 1)
+            sprintf (buf,
+                     "Block bitmap for group %d not in group.  (block %d)\n"
+                     "Relocate<y>?",
+                     g, b);
+          else if (w == 2)
+            sprintf (buf,
+                     "Inode bitmap %d for group %d not in group.\n"
+                     "Continue<y>?",
+                     b, g);
+          else /* if (w == 3) */
+            sprintf (buf,
+                     "Bad block %d in group %d's inode table.\n"
+                     "WARNING: SEVERE DATA LOSS POSSIBLE.\n"
+                     "Relocate<y>?",
+                     b, g);
+
+          scrolling_puts (ts, buf, 0);
+          scrolling_puts (ts, " yes\n\n", 0);
+        }
+      if (bsod_sleep (dpy, 0))
+        goto PANIC;
+      usleep (1000);
+    }
+
+
+  if (0 == random() % 10) goto PANIC;
+  scrolling_puts (ts, "Pass 2: Checking directory structure\n", 0);
+  if (bsod_sleep (dpy, 2))
+    goto PANIC;
+
+  i = (random() % 20) - 5;
+  while (--i > 0)
+    {
+      int n = random() % 0xFFFFF;
+      int o = random() % 0xFFF;
+      sprintf (buf, "Directory inode %d, block 0, offset %d: "
+               "directory corrupted\n"
+               "Salvage<y>? ",
+               n, o);
+      scrolling_puts (ts, buf, 0);
+      usleep (1000);
+      scrolling_puts (ts, " yes\n\n", 0);
+
+      if (0 == (random() % 100))
+        {
+          sprintf (buf, "Missing '.' in directory inode %d.\nFix<y>?", n);
+          scrolling_puts (ts, buf, 0);
+          usleep (1000);
+          scrolling_puts (ts, " yes\n\n", 0);
+        }
+
+      if (bsod_sleep (dpy, 0))
+        goto PANIC;
+    }
+
+  if (0 == random() % 10) goto PANIC;
+  scrolling_puts (ts,
+                  "Pass 3: Checking directory connectivity\n"
+                  "/lost+found not found.  Create? yes\n",
+                0);
+  if (bsod_sleep (dpy, 2))
+    goto PANIC;
+
+  /* Unconnected directory inode 4949 (/var/spool/squid/06/???)
+     Connect to /lost+found<y>? yes
+
+     '..' in /var/spool/squid/06/08 (20351) is <The NULL inode> (0), should be 
+     /var/spool/squid/06 (20350).
+     Fix<y>? yes
+
+     Unconnected directory inode 128337 (/var/spool/squid/06/???)
+     Connect to /lost+found<y>? yes
+   */
+
+
+  if (0 == random() % 10) goto PANIC;
+  scrolling_puts (ts, "Pass 4: Checking reference counts\n", 0);
+  if (bsod_sleep (dpy, 2))
+    goto PANIC;
+
+  /* Inode 2 ref count is 19, should be 20.  Fix<y>? yes
+
+     Inode 4949 ref count is 3, should be 2.  Fix<y>? yes
+
+        ...
+
+     Inode 128336 ref count is 3, should be 2.  Fix<y>? yes
+
+     Inode 128337 ref count is 3, should be 2.  Fix<y>? yes
+
+   */
+
+
+  if (0 == random() % 10) goto PANIC;
+  scrolling_puts (ts, "Pass 5: Checking group summary information\n", 0);
+  if (bsod_sleep (dpy, 2))
+    goto PANIC;
+
+  i = (random() % 200) - 50;
+  if (i > 0)
+    {
+      scrolling_puts (ts, "Block bitmap differences: ", 0);
+      while (--i > 0)
+        {
+          sprintf (buf, " %d", -(random() % 0xFFF));
+          scrolling_puts (ts, buf, 0);
+          usleep (1000);
+        }
+      scrolling_puts (ts, "\nFix? yes\n\n", 0);
+    }
+
+
+  i = (random() % 100) - 50;
+  if (i > 0)
+    {
+      scrolling_puts (ts, "Inode bitmap differences: ", 0);
+      while (--i > 0)
+        {
+          sprintf (buf, " %d", -(random() % 0xFFF));
+          scrolling_puts (ts, buf, 0);
+          usleep (1000);
+        }
+      scrolling_puts (ts, "\nFix? yes\n\n", 0);
+    }
+
+  i = (random() % 20) - 5;
+  while (--i > 0)
+    {
+      int g = random() % 0xFFFF;
+      int c = random() % 0xFFFF;
+      sprintf (buf,
+               "Free blocks count wrong for group #0 (%d, counted=%d).\nFix? ",
+               g, c);
+      scrolling_puts (ts, buf, 0);
+      usleep (1000);
+      scrolling_puts (ts, " yes\n\n", 0);
+      if (bsod_sleep (dpy, 0))
+        goto PANIC;
+    }
+
+ PANIC:
+
+  i = 0;
+  scrolling_puts (ts, "\n\n", 0);
+  while (linux_panic[i])
+    {
+      time_t t = time ((time_t *) 0);
+      struct tm *tm = localtime (&t);
+      char prefix[100];
+
+      if (*linux_panic[i])
+        {
+          strftime (prefix, sizeof(prefix)-1, "%b %d %k:%M:%S ", tm);
+          scrolling_puts (ts, prefix, 0);
+          scrolling_puts (ts, sysname, 0);
+          scrolling_puts (ts, linux_panic[i], 0);
+          XSync(dpy, False);
+          usleep(1000);
+        }
+      else
+        usleep (300000);
+
+      if (bsod_sleep (dpy, 0))
+        goto DONE;
+      i++;
+    }
+
+  if (bsod_sleep (dpy, 4))
+    goto DONE;
+
+
+  XSync(dpy, False);
+  bsod_sleep(dpy, delay);
+
+ DONE:
+  free_scrolling_window (ts);
+  XClearWindow(dpy, window);
+  return True;
+}
+
+
+\f
+char *progclass = "BSOD";
+
+char *defaults [] = {
+  "*delay:                30",
+
+  "*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",
+
+  ".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",
+
+  ".Linux.font:                   9x15bold",
+  ".Linux.font2:          -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  ".Linux.foreground: White",
+  ".Linux.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",
   0
 };
 
 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"  },
+  { "-no-2k",          ".doWin2K",             XrmoptionNoArg,  "False" },
+  { "-amiga",          ".doAmiga",             XrmoptionNoArg,  "True"  },
+  { "-no-amiga",       ".doAmiga",             XrmoptionNoArg,  "False" },
+  { "-mac",            ".doMac",               XrmoptionNoArg,  "True"  },
+  { "-no-mac",         ".doMac",               XrmoptionNoArg,  "False" },
+  { "-mac1",           ".doMac1",              XrmoptionNoArg,  "True"  },
+  { "-no-mac1",                ".doMac1",              XrmoptionNoArg,  "False" },
+  { "-no-macx",                ".doMacX",              XrmoptionNoArg,  "False" },
+  { "-atari",          ".doAtari",             XrmoptionNoArg,  "True"  },
+  { "-no-atari",       ".doAtari",             XrmoptionNoArg,  "False" },
+  { "-macsbug",                ".doMacsBug",           XrmoptionNoArg,  "True"  },
+  { "-no-macsbug",     ".doMacsBug",           XrmoptionNoArg,  "False" },
+  { "-sco",            ".doSCO",               XrmoptionNoArg,  "True"  },
+  { "-no-sco",         ".doSCO",               XrmoptionNoArg,  "False" },
+  { "-bsd",            ".doBSD",               XrmoptionNoArg,  "True"  },
+  { "-no-bsd",         ".doBSD",               XrmoptionNoArg,  "False" },
+  { "-linux",          ".doLinux",             XrmoptionNoArg,  "True" },
+  { "-no-linux",       ".doLinux",             XrmoptionNoArg,  "False" },
+  { "-sparclinux",     ".doSparcLinux",        XrmoptionNoArg,  "True"  },
+  { "-no-sparclinux",  ".doSparcLinux",        XrmoptionNoArg,  "False" },
+  { "-blitdamage",     ".doBlitDamage",        XrmoptionNoArg,  "True"  },
+  { "-no-blitdamage",  ".doBlitDamage",        XrmoptionNoArg,  "False" },
+  { "-solaris",                ".doSolaris",           XrmoptionNoArg,  "True"  },
+  { "-no-solaris",     ".doSolaris",           XrmoptionNoArg,  "False" },
   { 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() % 8;
-      j = i;
-
+      Bool did;
+      do {  i = (random() & 0xFF) % 15; } 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 5: openserver(dpy, window, delay); break;
-       case 6: sparc_linux(dpy, window, delay); break;
-       case 7: atari(dpy, window, delay); break;
+       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;
        }
-      XSync (dpy, True);
+      loop++;
+      if (loop > 100) j = -1;
+      if (loop > 200)
+        {
+          fprintf (stderr, "%s: no display modes enabled?\n", progname);
+          exit(-1);
+        }
+      if (!did) continue;
+      XSync (dpy, False);
+      j = i;
+      loop = 0;
     }
 }