From http://www.jwz.org/xscreensaver/xscreensaver-5.37.tar.gz
[xscreensaver] / hacks / bsod.c
index ce2e496916d38eae5328a860a4702f67cf7b8a60..534f30e13a23f54574ec761faf5d435d1dc852ef 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1998-2011 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1998-2017 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
@@ -40,6 +40,7 @@
 #include "apple2.h"
 
 #include <ctype.h>
+#include <time.h>
 
 #ifdef HAVE_XSHM_EXTENSION
 #include "xshm.h"
@@ -49,7 +50,7 @@
 # include <sys/utsname.h>
 #endif /* HAVE_UNAME */
 
-#if defined(HAVE_GDK_PIXBUF) || defined(HAVE_XPM) || defined(HAVE_COCOA)
+#if defined(HAVE_GDK_PIXBUF) || defined(HAVE_XPM) || defined(HAVE_JWXYZ)
 # define DO_XPM
 #endif
 
 # include "images/hmac.xpm"
 # include "images/osx_10_2.xpm"
 # include "images/osx_10_3.xpm"
+# include "images/android.xpm"
 #endif
 #include "images/atari.xbm"
 #include "images/mac.xbm"
 #include "images/macbomb.xbm"
+#include "images/apple.xbm"
 #include "images/atm.xbm"
 
 #undef countof
 #define countof(x) (sizeof((x))/sizeof((*x)))
 
+# undef MIN
+# undef MAX
+# define MIN(A,B) ((A)<(B)?(A):(B))
+# define MAX(A,B) ((A)>(B)?(A):(B))
+
 #undef EOF
 typedef enum { EOF=0, 
                LEFT, CENTER, RIGHT, 
                LEFT_FULL, CENTER_FULL, RIGHT_FULL, 
                COLOR, INVERT, MOVETO, MARGINS,
-               CURSOR_BLOCK, CURSOR_LINE, RECT, COPY, PIXMAP, IMG,
+               CURSOR_BLOCK, CURSOR_LINE, RECT, LINE, COPY, PIXMAP, IMG, FONT,
                PAUSE, CHAR_DELAY, LINE_DELAY,
                LOOP, RESET
 } bsod_event_type;
@@ -86,7 +94,7 @@ struct bsod_state {
   Display *dpy;
   Window window;
   XWindowAttributes xgwa;
-  XFontStruct *font;
+  XFontStruct *font, *fontA, *fontB, *fontC;
   unsigned long fg, bg;
   GC gc;
   int left_margin, right_margin;       /* for text wrapping */
@@ -227,6 +235,19 @@ struct bsod_state {
   (bst)->pos++; \
   } while (0)
 
+/* Draw a line.
+ */
+#define BSOD_LINE(bst,x,y,x2,y2,thick) do { \
+  ensure_queue (bst); \
+  (bst)->queue[(bst)->pos].type = LINE; \
+  (bst)->queue[(bst)->pos].arg1 = (void *) ((long) (x)); \
+  (bst)->queue[(bst)->pos].arg2 = (void *) ((long) (y)); \
+  (bst)->queue[(bst)->pos].arg3 = (void *) ((long) (x2)); \
+  (bst)->queue[(bst)->pos].arg4 = (void *) ((long) (y2)); \
+  (bst)->queue[(bst)->pos].arg5 = (void *) ((long) (thick)); \
+  (bst)->pos++; \
+  } while (0)
+
 /* Copy a rect from the window, to the window.
  */
 #define BSOD_COPY(bst,srcx,srcy,w,h,tox,toy) do { \
@@ -256,6 +277,15 @@ struct bsod_state {
   (bst)->pos++; \
   } while (0)
 
+/* Switch between fonts A, B and C.
+ */
+#define BSOD_FONT(bst,n) do { \
+  ensure_queue (bst); \
+  (bst)->queue[(bst)->pos].type = FONT; \
+  (bst)->queue[(bst)->pos].arg1 = (void *) ((long) (n)); \
+  (bst)->pos++; \
+  } while (0)
+
 /* Jump around in the state table.  You can use this as the last thing 
    in your state table to repeat the last N elements forever.
  */
@@ -516,6 +546,20 @@ bsod_pop (struct bsod_state *bst)
       bst->pos++;
       return 0;
     }
+  case LINE:
+    {
+      int x1 = (long) bst->queue[bst->pos].arg1;
+      int y1 = (long) bst->queue[bst->pos].arg2;
+      int x2 = (long) bst->queue[bst->pos].arg3;
+      int y2 = (long) bst->queue[bst->pos].arg4;
+      int t  = (long) bst->queue[bst->pos].arg5;
+      XGCValues gcv;
+      gcv.line_width = t;
+      XChangeGC (bst->dpy, bst->gc, GCLineWidth, &gcv);
+      XDrawLine (bst->dpy, bst->window, bst->gc, x1, y1, x2, y2);
+      bst->pos++;
+      return 0;
+    }
   case COPY:
   case PIXMAP:
     {
@@ -541,6 +585,18 @@ bsod_pop (struct bsod_state *bst)
       bst->pos++;
       return 0;
     }
+  case FONT:
+    {
+      switch ((long) bst->queue[bst->pos].arg1) {
+      case 0: bst->font = bst->fontA; break;
+      case 1: bst->font = bst->fontB; break;
+      case 2: bst->font = bst->fontC; break;
+      default: abort(); break;
+      }
+      XSetFont (bst->dpy, bst->gc, bst->font->fid);
+      bst->pos++;
+      return 0;
+    }
   case PAUSE:
     {
       long delay = (long) bst->queue[bst->pos].arg1;
@@ -642,7 +698,9 @@ make_bsod_state (Display *dpy, Window window,
   struct bsod_state *bst;
   char buf1[1024], buf2[1024];
   char buf3[1024], buf4[1024];
-  const char *font1, *font2;
+  char buf5[1024], buf6[1024];
+  char buf7[1024], buf8[1024];
+  const char *font1, *font2, *font3, *font4;
 
   bst = (struct bsod_state *) calloc (1, sizeof (*bst));
   bst->queue_size = 10;
@@ -659,7 +717,7 @@ make_bsod_state (Display *dpy, Window window,
        use ".bigFont" if it is loadable, else use ".bigFont2".
    */
   if (
-# ifdef USE_IPHONE
+# ifdef HAVE_MOBILE
       1
 # else
       bst->xgwa.height < 640
@@ -678,9 +736,31 @@ make_bsod_state (Display *dpy, Window window,
       sprintf (buf3, "%.100s.bigFont2", name);
       sprintf (buf4, "%.100s.bigFont2", class);
     }
+  sprintf (buf5, "%.100s.fontB", name);
+  sprintf (buf6, "%.100s.fontB", class);
+  sprintf (buf7, "%.100s.fontC", name);
+  sprintf (buf8, "%.100s.fontC", class);
 
   font1 = get_string_resource (dpy, buf1, buf2);
   font2 = get_string_resource (dpy, buf3, buf4);
+  font3 = get_string_resource (dpy, buf5, buf6);
+  font4 = get_string_resource (dpy, buf7, buf8);
+
+  /* If there was no ".mode.font2" resource also look for ".font2".
+     Under real X11, the wildcard does this, so this is redundant,
+     but jwxyz needs it because it doesn't implement wildcards.
+   */
+# define RES2(VAR, BUF1, BUF2) do {                          \
+    if (! VAR) {                                             \
+      VAR = get_string_resource (dpy,                        \
+                                strchr (BUF1, '.') + 1,     \
+                                strchr (BUF2, '.') + 1);    \
+    }} while(0)
+  RES2 (font1, buf1, buf2);
+  RES2 (font2, buf3, buf4);
+  RES2 (font3, buf5, buf6);
+  RES2 (font4, buf7, buf8);
+#undef RES2
 
   if (font1)
     bst->font = XLoadQueryFont (dpy, font1);
@@ -696,6 +776,17 @@ make_bsod_state (Display *dpy, Window window,
   if (! bst->font)
     abort();
 
+  if (font3)
+    bst->fontB = XLoadQueryFont (dpy, font3);
+  if (font4)
+    bst->fontC = XLoadQueryFont (dpy, font4);
+
+  if (! bst->fontB) bst->fontB = bst->font;
+  if (! bst->fontC) bst->fontC = bst->font;
+
+  bst->fontA = bst->font;
+
+
   gcv.font = bst->font->fid;
 
   sprintf (buf1, "%.100s.foreground", name);
@@ -708,8 +799,8 @@ make_bsod_state (Display *dpy, Window window,
                                                  buf1, buf2);
   bst->gc = XCreateGC (dpy, window, GCFont|GCForeground|GCBackground, &gcv);
 
-#ifdef HAVE_COCOA
-  jwxyz_XSetAntiAliasing (dpy, bst->gc, False);
+#ifdef HAVE_JWXYZ
+  jwxyz_XSetAntiAliasing (dpy, bst->gc, True);
 #endif
 
   bst->left_margin = bst->right_margin = 10;
@@ -808,11 +899,69 @@ windows_31 (Display *dpy, Window window)
   return bst;
 }
 
+static struct bsod_state *
+vmware (Display *dpy, Window window)
+{
+  struct bsod_state *bst = make_bsod_state (dpy, window, "vmware", "VMware");
+
+  unsigned long fg = bst->fg;
+  unsigned long bg = bst->bg;
+  unsigned long fg2 = get_pixel_resource (dpy, bst->xgwa.colormap,
+                                          "vmware.foreground2",
+                                          "vmware.foreground");
+  BSOD_COLOR (bst, fg2, bg);
+  BSOD_TEXT   (bst, LEFT,
+               "VMware ESX Server [Releasebuild-98103]\n");
+  BSOD_COLOR (bst, fg, bg);
+  BSOD_TEXT   (bst, LEFT,
+               "PCPU 1 locked up. Failed to ack TLB invalidate.\n"
+               "frame=0x3a37d98 ip=0x625e94 cr2=0x0 cr3=0x40c66000 cr4=0x16c\n"
+               "es=0xffffffff ds=0xffffffff fs=0xffffffff gs=0xffffffff\n"
+               "eax=0xffffffff ebx=0xffffffff ecx=0xffffffff edx=0xffffffff\n"
+               "ebp=0x3a37ef4 esi=0xffffffff edi=0xffffffff err=-1 eflags=0xffffffff\n"
+               "*0:1037/helper1-4 1:1107/vmm0:Fagi 2:1121/vmware-vm 3:1122/mks:Franc\n"
+               "0x3a37ef4:[0x625e94]Panic+0x17 stack: 0x833ab4, 0x3a37f10, 0x3a37f48\n"
+               "0x3a37f04:[0x625e94]Panic+0x17 stack: 0x833ab4, 0x1, 0x14a03a0\n"
+               "0x3a37f48:[0x64bfa4]TLBDoInvalidate+0x38f stack: 0x3a37f54, 0x40, 0x2\n"
+               "0x3a37f70:[0x66da4d]XMapForceFlush+0x64 stack: 0x0, 0x4d3a, 0x0\n"
+               "0x3a37fac:[0x652b8b]helpFunc+0x2d2 stack: 0x1, 0x14a4580, 0x0\n"
+               "0x3a37ffc:[0x750902]CpuSched_StartWorld+0x109 stack: 0x0, 0x0, 0x0\n"
+               "0x3a38000:[0x0]blk_dev+0xfd76461f stack: 0x0, 0x0, 0x0\n"
+               "VMK uptime: 7:05:43:45.014 TSC: 1751259712918392\n"
+               "Starting coredump to disk\n"); 
+  BSOD_CHAR_DELAY (bst, 10000);                
+  BSOD_TEXT (bst, LEFT,        "using slot 1 of 1... ");
+  BSOD_CHAR_DELAY (bst, 300000);
+  BSOD_TEXT (bst, LEFT, "9876");
+  BSOD_CHAR_DELAY (bst, 3000000);
+  BSOD_TEXT (bst, LEFT, "66665");
+  BSOD_CHAR_DELAY (bst, 100000);
+  BSOD_TEXT (bst, LEFT, "4321");
+  BSOD_CHAR_DELAY (bst, 0);
+  BSOD_TEXT (bst, LEFT, "Disk dump successfull.\n"
+               "Waiting for Debugger (world 1037)\n"
+               "Debugger is listening on serial port ...\n");
+  BSOD_CHAR_DELAY (bst, 10000);
+  BSOD_TEXT (bst, LEFT, "Press Escape to enter local debugger\n");
+  BSOD_CHAR_DELAY (bst, 10000);
+  BSOD_TEXT (bst, LEFT, "Remote debugger activated. Local debugger no longer available.\n");
+
+/*  BSOD_CURSOR (bst, CURSOR_LINE, 240000, 999999);*/
+               
+/*  bst->y = ((bst->xgwa.height -
+             ((bst->font->ascent + bst->font->descent) * 9))
+            / 2);*/
+
+  XClearWindow (dpy, window);
+  return bst;
+}
+
+
 
 static struct bsod_state *
 windows_nt (Display *dpy, Window window)
 {
-  struct bsod_state *bst = make_bsod_state (dpy, window, "windows", "Windows");
+  struct bsod_state *bst = make_bsod_state (dpy, window, "nt", "NT");
 
   BSOD_TEXT (bst, LEFT,
    "*** STOP: 0x0000001E (0x80000003,0x80106fc0,0x8025ea21,0xfd6829e8)\n"
@@ -1009,6 +1158,135 @@ windows_lh (Display *dpy, Window window)
 }
 
 
+static struct bsod_state *
+windows_10 (Display *dpy, Window window)
+{
+  struct bsod_state *bst = 
+    make_bsod_state (dpy, window, "win10", "Win10");
+
+  int qr_width  = 41;
+  int qr_height = 41;
+  static const unsigned char qr_bits[] = {
+    0xFF,0xFF,0xFF,0xFF,0xFF,0x01,0xFF,0xFF,0xFF,0xFF,0xFF,0x01,
+    0x03,0x9A,0x70,0xEE,0x80,0x01,0xFB,0x22,0xAA,0xA6,0xBE,0x01,
+    0x8B,0x8E,0x74,0xE7,0xA2,0x01,0x8B,0xEE,0x42,0xC4,0xA2,0x01,
+    0x8B,0x42,0x6E,0xED,0xA2,0x01,0xFB,0xDA,0x63,0xA6,0xBE,0x01,
+    0x03,0xAA,0xAA,0xAA,0x80,0x01,0xFF,0x8B,0xD8,0x9D,0xFF,0x01,
+    0x63,0x62,0xDA,0x1B,0x98,0x01,0x6F,0x67,0x98,0x9F,0xBC,0x01,
+    0x4F,0xCC,0x55,0x81,0x83,0x01,0xB7,0x6D,0xFF,0x68,0xB2,0x01,
+    0xC3,0x10,0x87,0x8B,0x96,0x01,0x6F,0xB1,0x91,0x58,0x94,0x01,
+    0xE3,0x36,0x88,0x84,0xB8,0x01,0x83,0x9B,0xFE,0x59,0xD7,0x01,
+    0x3B,0x74,0x98,0x5C,0xB4,0x01,0x37,0x75,0xDC,0x91,0xA6,0x01,
+    0x77,0xDE,0x01,0x54,0xBA,0x01,0xBB,0x6D,0x8B,0xB9,0xB5,0x01,
+    0x1F,0x06,0xBD,0x9B,0xB4,0x01,0xD3,0xBD,0x91,0x19,0x84,0x01,
+    0x0B,0x20,0xD8,0x91,0xB4,0x01,0x33,0x95,0xBC,0x0A,0xD5,0x01,
+    0xB3,0x60,0xDC,0xD9,0xB6,0x01,0xEF,0x77,0x18,0x09,0xA4,0x01,
+    0xA3,0xC2,0x95,0x51,0xB2,0x01,0xDF,0x63,0xDB,0xBE,0xB3,0x01,
+    0x03,0x08,0xC9,0x09,0xF0,0x01,0xFF,0xA3,0x19,0xBD,0xFB,0x01,
+    0x03,0x2E,0x84,0xA5,0xAA,0x01,0xFB,0x9A,0xFC,0x9B,0xBB,0x01,
+    0x8B,0x7E,0x9C,0x1D,0xB0,0x01,0x8B,0x6E,0x58,0xA1,0xDB,0x01,
+    0x8B,0xDA,0xD5,0x65,0xA2,0x01,0xFB,0x72,0xFB,0xE9,0xF0,0x01,
+    0x03,0x02,0x99,0x3B,0xB3,0x01,0xFF,0xFF,0xFF,0xFF,0xFF,0x01,
+    0xFF,0xFF,0xFF,0xFF,0xFF,0x01};
+  Pixmap pixmap;
+
+  const char *lines[] = {
+    ":(\n",
+    "\n",
+    "Your PC ran into a problem and needs to restart. We're just\n",
+    "collecting some error info, and then we'll restart for you.\n",
+    "\n",
+    "\n",
+    "\n",
+    "For more information about this issue and\n",
+    "possible fixes, visit\n",
+/*  "https://www.jwz.org/xscreensaver\n",*/
+    "http://youtu.be/-RjmN9RZyr4\n", 
+    "\n",
+    "If you call a support person, give them this info:\n",
+    "Stop code CRITICAL_PROCESS_DIED", 
+ };
+  int i, y = 0, y0 = 0;
+  int line_height0 = bst->fontB->ascent;
+  int line_height1 = bst->fontA->ascent + bst->fontA->descent;
+  int line_height2 = bst->fontC->ascent + bst->fontC->descent;
+  int line_height = line_height0;
+  int top, left0, left;
+  int stop = 60 + (random() % 39);
+
+  line_height1 *= 1.3;
+  line_height2 *= 1.5;
+
+  top = ((bst->xgwa.height - (line_height0 * 1 +
+                              line_height1 * 6 +
+                              line_height2 * 6))
+         / 2);
+
+  {
+    int dir, ascent, descent;
+    XCharStruct ov;
+    const char *s = lines[2];
+    XTextExtents (bst->fontA, s, strlen(s),
+                  &dir, &ascent, &descent, &ov);
+    left = left0 = (bst->xgwa.width - ov.width) / 2;
+  }
+
+  pixmap = XCreatePixmapFromBitmapData (dpy, window, (char *) qr_bits,
+                                        qr_width, qr_height,
+                                        bst->fg, bst->bg, bst->xgwa.depth);
+  for (i = 0; i < 2; i++)
+    {
+      pixmap = double_pixmap (dpy, bst->gc, bst->xgwa.visual, bst->xgwa.depth,
+                              pixmap, qr_width, qr_height);
+      qr_width *= 2;
+      qr_height *= 2;
+    }
+  bst->pixmap = pixmap;
+
+  y = top;
+  line_height = line_height0;
+  BSOD_FONT (bst, 1);
+  for (i = 0; i < countof(lines); i++)
+    {
+      BSOD_MOVETO (bst, left, y);
+      BSOD_TEXT (bst, LEFT, lines[i]);
+      y += line_height;
+      if (i == 0)
+        {
+          BSOD_FONT (bst, 0);
+          line_height = line_height1;
+        }
+      else if (i == 4)
+        {
+          y0 = y;
+          y += line_height / 2;
+          BSOD_PIXMAP (bst, 0, 0, qr_width, qr_height, left, y + line_height1);
+          BSOD_FONT (bst, 2);
+          line_height = line_height2;
+          left += qr_width + line_height2 / 2;
+# ifdef HAVE_MOBILE
+          y -= 14;
+# endif
+        }
+    }
+
+  left = left0;
+  BSOD_FONT (bst, 0);
+  for (i = 0; i <= stop; i++)
+    {
+      char buf[100];
+      sprintf (buf, "%d%% complete", i);
+      BSOD_MOVETO (bst, left, y0);
+      BSOD_TEXT (bst, LEFT, buf);
+      BSOD_PAUSE (bst, 85000);
+    }
+  BSOD_PAUSE (bst, 3000000);
+
+  XClearWindow (dpy, window);
+  return bst;
+}
+
+
 static struct bsod_state *
 windows_other (Display *dpy, Window window)
 {
@@ -1122,7 +1400,8 @@ sco (Display *dpy, Window window)
 static struct bsod_state *
 sparc_linux (Display *dpy, Window window)
 {
-  struct bsod_state *bst = make_bsod_state (dpy, window, "sco", "SCO");
+  struct bsod_state *bst = make_bsod_state (dpy, window, 
+                                            "sparclinux", "SparcLinux");
   bst->scroll_p = True;
   bst->y = bst->xgwa.height - bst->font->ascent - bst->font->descent;
 
@@ -1233,7 +1512,8 @@ amiga (Display *dpy, Window window)
                                &pix_w, &pix_h, 0);
 # endif /* DO_XPM */
 
-  if (pixmap && bst->xgwa.height > 600)        /* scale up the bitmap */
+  if (pixmap &&
+      MIN (bst->xgwa.width, bst->xgwa.height) > 600) /* scale up the bitmap */
     {
       pixmap = double_pixmap (dpy, bst->gc, bst->xgwa.visual, bst->xgwa.depth,
                               pixmap, pix_w, pix_h);
@@ -1604,7 +1884,7 @@ macx_10_0 (Display *dpy, Window window)
     pixmap = xpm_data_to_pixmap (dpy, window, (char **) happy_mac,
                                  &pix_w, &pix_h, &mask);
 
-# ifdef USE_IPHONE
+# ifdef HAVE_MOBILE
     if (pixmap)
       {
         pixmap = double_pixmap (dpy, bst->gc, bst->xgwa.visual,
@@ -1705,23 +1985,284 @@ macx_10_2 (Display *dpy, Window window, Bool v10_3_p)
 # endif /* DO_XPM */
 
 
+/* 2006 Mac Mini with MacOS 10.6 failing with a bad boot drive. By jwz.
+ */
+static struct bsod_state *
+mac_diskfail (Display *dpy, Window window)
+{
+  struct bsod_state *bst = make_bsod_state (dpy, window, "macdisk", "Mac");
+  int cw = (bst->font->per_char
+            ? bst->font->per_char['n'-bst->font->min_char_or_byte2].width
+            : bst->font->min_bounds.width);
+  int h = bst->font->ascent + bst->font->descent;
+  int L = (bst->xgwa.width - (cw * 80)) / 2;
+  int T = (bst->xgwa.height - (h  * 10)) / 2;
+
+  unsigned long fg = bst->fg;
+  unsigned long bg = bst->bg;
+  unsigned long bg2 = get_pixel_resource (dpy, bst->xgwa.colormap,
+                                          "macx.background",
+                                          "Mac.Background");
+  if (L < 0) L = 0;
+  if (T < 0) T = 0;
+
+  bst->wrap_p = True;
+  bst->scroll_p = True;
+
+  BSOD_COLOR(bst, bg2, bg);
+  BSOD_RECT (bst, True, 0, 0, bst->xgwa.width, bst->xgwa.height);
+  BSOD_PAUSE (bst, 3000000);
+
+  BSOD_COLOR(bst, bg, fg);
+  BSOD_RECT (bst, True, 0, 0, bst->xgwa.width, bst->xgwa.height);
+  BSOD_COLOR(bst, fg, bg);
+
+  BSOD_MARGINS (bst, L, L);
+  BSOD_MOVETO (bst, L, T);
+
+  BSOD_TEXT (bst, LEFT,
+             "efiboot loaded from device: Acpi(PNP0A03,0)/Pci*1F|2)/Ata"
+             "(Primary,Slave)/HD(Part\n"
+             "2,Sig8997E427-064E-4FE7-8CB9-F27A784B232C)\n"
+             "boot file path: \\System\\Library\\CoreServices\\boot.efi\n"
+             ".Loading kernel cache file 'System\\Library\\Caches\\"
+             "com.apple.kext.caches\\Startup\\\n"
+             "kernelcache_i386.2A14EC2C'\n"
+             "Loading 'mach_kernel'...\n"
+             );
+  BSOD_CHAR_DELAY (bst, 7000);
+  BSOD_TEXT (bst, LEFT,
+             ".....................\n"
+             );
+  BSOD_CHAR_DELAY (bst, 0);
+  BSOD_TEXT (bst, LEFT,
+             "root device uuid is 'B62181B4-6755-3C27-BFA1-49A0E053DBD6\n"
+             "Loading drivers...\n"
+             "Loading System\\Library\\Caches\\com.apple.kext.caches\\"
+             "Startup\\Extensions.mkext....\n"
+             );
+  BSOD_CHAR_DELAY (bst, 7000);
+  BSOD_TEXT (bst, LEFT,
+             "..............................................................."
+             ".................\n"
+             "..............................................................."
+             ".................\n"
+             "..............\n"
+             );
+  BSOD_INVERT (bst);
+  BSOD_RECT (bst, True, 0, 0, bst->xgwa.width, bst->xgwa.height);
+  BSOD_INVERT (bst);
+
+  BSOD_MARGINS (bst, 0, 0);
+  BSOD_MOVETO (bst, 0, h);
+
+  BSOD_CHAR_DELAY (bst, 0);
+  BSOD_LINE_DELAY (bst, 5000);
+  BSOD_TEXT (bst, LEFT,
+             "npvhash=4095\n"
+             "PRE enabled\n"
+             "Darwin Kernel Version 10.8.9: Tue Jun  7 16:33:36 PDT 2011;"
+             " root:xnu-1504.15.3~1/RELEASE_I386\n"
+             "vm_page_bootstrap: 508036 free pages and 16252 wired pages\n"
+             "standard timeslicing quantum is 10000 us\n"
+             "mig_table_max_displ = 73\n"
+             "AppleACPICPU: ProcessorId=0 LocalApicId=0 Enabled\n"
+             "AppleACPICPU: ProcessorId=1 LocalApicId=1 Enabled\n"
+             "calling npo_policy_init for Quarantine\n"
+             "Security policy loaded: Quaantine policy (Quarantine)\n"
+             "calling npo_policy_init for Sandbox\n"
+             "Security policy loaded: Seatbelt sandbox policy (Sandbox)\n"
+             "calling npo_policy_init for TMSafetyNet\n"
+             "Security policy loaded: Safety net for Time Machine "
+             "(TMSafetyNet)\n"
+             "Copyright (c) 1982, 1986, 1989, 1991, 1993\n"
+             "The Regents of the University of California. All rights "
+             "reserved.\n"
+             "\n"
+             "MAC Framework successfully initialized\n"
+             "using 10485 buffer headers and 4096 cluster IO buffer headers\n"
+             "IOAPIC: Version 0x20 Vectors 64:87\n"
+             "ACPI: System State [S0 S3 S4 S5] (S3)\n"
+             "PFM64 0x10000000, 0xf0000000\n"
+             "[ PCI configuration begin ]\n"
+             "PCI configuration changed (bridge=1 device=1 cardbus=0)\n"
+             "[ PCI configuration end, bridges 4 devices 17 ]\n"
+             "nbinit: done (64 MB memory set for nbuf pool)\n"
+             "rooting via boot-uuid from /chosen: "
+             "B62181B4-6755-3C27-BFA1-49A0E053DBD6\n"
+             "Waiting on <dict ID=\"0\"><key>IOProviderClass</key>"
+             "<string ID=\"1\">IOResources</string><key>IOResourceMatch</key>"
+             "<string ID=\"2\">boot-uuid-nedia</string></dict>\n"
+             "com.apple.AppleFSCCompressionTypeZlib kmod start\n"
+             "com.apple.AppleFSCCompressionTypeZlib kmod succeeded\n"
+             "AppleIntelCPUPowerManagementClient: ready\n"
+             "FireWire (OHCI) Lucent ID 5811  built-in now active, GUID "
+             "0019e3fffe97f8b4; max speed s400.\n"
+             "Got boot device = IOService:/AppleACPIPlatformExpert/PCI000/"
+             "AppleACPIPCI/SATA@1F,2/AppleAHCI/PRI202/IOAHCIDevice@0/"
+             "AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/"
+             "IOBlockStorageDriver/ST96812AS Media/IOGUIDPartitionScheme/"
+             "Customer02\n"
+             );
+  BSOD_PAUSE (bst, 1000000);
+  BSOD_TEXT (bst, LEFT,
+             "BSD root: Disk0s, major 14, minor 2\n"
+             "[Bluetooth::CSRHIDTransition] switchtoHCIMode (legacy)\n"
+             "[Bluetooth::CSRHIDTransition] transition complete.\n"
+             "CSRUSBBluetoothHCIController::setupHardware super returned 0\n"
+             );
+  BSOD_PAUSE (bst, 3000000);
+  BSOD_TEXT (bst, LEFT,
+             "disk0s2: I/O error.\n"
+             "0 [Level 3] [ReadUID 0] [Facility com.apple.system.fs] "
+             "[ErrType IO] [ErrNo 5] [IOType Read] [PBlkNum 48424] "
+             "[LBlkNum 1362] [FSLogMsgID 2009724291] [FSLogMsgOrder First]\n"
+             "0 [Level 3] [ReadUID 0] [Facility com.apple.system.fs] "
+             "[DevNode root_device] [MountPt /] [FSLogMsgID 2009724291] "
+             "[FSLogMsgOrder Last]\n"
+             "panic(cpu 0 caller 0x47f5ad): \"Process 1 exec of /sbin/launchd"
+             " failed, errno 5\\n\"0/SourceCache/xnu/xnu-1504.15.3/bsd/kern/"
+             "kern_exec.c:3145\n"
+             "Debugger called: <panic>\n"
+             "Backtrace (CPU 0), Frame : Return Address (4 potential args "
+             "on stack)\n"
+             "0x34bf3e48 : 0x21b837 (0x5dd7fc 0x34bf3e7c 0x223ce1 0x0)\n"
+             "0x34bf3e98 : 0x47f5ad (0x5cf950 0x831c08 0x5 0x0)\n"
+             "0x34bf3ef8 : 0x4696d2 (0x4800d20 0x1fe 0x45a69a0 0x80000001)\n"
+             "0x34bf3f38 : 0x48fee5 (0x46077a8 0x84baa0 0x34bf3f88 "
+             "0x34bf3f94)\n"
+             "0x34bf3f68 : 0x219432 (0x46077a8 0xffffff7f 0x0 0x227c4b)\n"
+             "0x34bf3fa8 : 0x2aacb4 (0xffffffff 0x1 0x22f8f5 0x227c4b)\n"
+             "0x34bf3fc8 : 0x2a1976 (0x0 0x0 0x2a17ab 0x4023ef0)\n"
+             "\n"
+             "BSD process name corresponding to current thread: init\n"
+             "\n"
+             "Mac OS version:\n"
+             "Not yet set\n"
+             "\n"
+             "Kernel version:\n"
+             "Darwin Kernel version 10.8.0: Tue Jun  7 16:33:36 PDT 2011; "
+             "root:xnu-1504.15-3~1/RELEASE_I386\n"
+             "System model name: Macmini1,1 (Mac-F4208EC0)\n"
+             "\n"
+             "System uptime in nanoseconds: 13239332027\n"
+             );
+  BSOD_CURSOR (bst, CURSOR_BLOCK, 500000, 999999);
+
+  XClearWindow (dpy, window);
+
+  return bst;
+}
+
+
+/* 2017 MacOS 10.12 interminable software update, by jwz.
+ */
+static struct bsod_state *
+macx_install (Display *dpy, Window window)
+{
+  struct bsod_state *bst = make_bsod_state (dpy, window, "macinstall", "MacX");
+
+  Pixmap pixmap = 0;
+  int pix_w = apple_width;
+  int pix_h = apple_height;
+  int x, y;
+  int bw1, bh1;
+  int bw2, bh2;
+
+  unsigned long fg = get_pixel_resource (dpy, bst->xgwa.colormap,
+                                         "macinstall.foreground",
+                                         "Mac.Foreground");
+  unsigned long bg = get_pixel_resource (dpy, bst->xgwa.colormap,
+                                         "macinstall.background",
+                                         "Mac.Background");
+  unsigned long fg2 = get_pixel_resource (dpy, bst->xgwa.colormap,
+                                         "macinstall.barForeground",
+                                         "Mac.Foreground");
+  unsigned long bg2 = get_pixel_resource (dpy, bst->xgwa.colormap,
+                                         "macinstall.barBackground",
+                                         "Mac.Background");
+  char buf[1024];
+  int lh = bst->font->ascent + bst->font->descent;
+  int i, min;
+  double pct;
+
+  pixmap = XCreatePixmapFromBitmapData (dpy, window, (char *) apple_bits,
+                                        apple_width, apple_height,
+                                        fg, bg, bst->xgwa.depth);
+  bst->pixmap = pixmap;
+
+  x = (bst->xgwa.width - pix_w) / 2;
+  y = (bst->xgwa.height) / 2  - pix_h;
+  if (y < 0) y = 0;
+
+  XSetLineAttributes (dpy, bst->gc, 1, LineSolid, CapRound, JoinMiter);
+
+  BSOD_COLOR(bst, bg, bg);
+  BSOD_RECT (bst, True, 0, 0, bst->xgwa.width, bst->xgwa.height);
+  BSOD_COLOR(bst, fg, bg);
+  BSOD_PIXMAP (bst, 0, 0, pix_w, pix_h, x, y);
+  y += pix_h * 2 - lh;
+
+  /* progress bar */
+  bw1 = pix_w * 2.5;
+  bh1 = lh * 0.66;
+  if (bh1 < 8) bh1 = 8;
+
+  x = (bst->xgwa.width - bw1) / 2;
+  BSOD_COLOR(bst, fg2, bg);
+  BSOD_LINE (bst, x,   y, x + bw1, y, bh1);
+
+  bw2 = bw1 - 1;
+  bh2 = bh1 - 4;
+  BSOD_COLOR(bst, bg2, bg);
+  BSOD_LINE (bst, x+1, y, x + bw2, y, bh2);
+
+  BSOD_COLOR(bst, fg, bg);
+  BSOD_LINE (bst, x,   y, x + 1, y, bh1);
+
+  pct = 5 + (random() % 40);
+  min = 5 + (random() % 40);
+
+  for (i = 0; i < 100; i++) {
+    pct += frand(0.3);
+    min += (random() % 3) - 1;  /* sometimes down, mostly up */
+
+    if (pct > 90) pct = 90;
+    BSOD_RECT (bst, True, x, y - bh1/2, bw1 * pct / 100, bh1);
+
+    sprintf (buf, "  Installing Software Update: about %d minutes.  ", min);
+    bst->y = y + lh * 3;
+    BSOD_TEXT (bst, CENTER, buf);
+    BSOD_PAUSE (bst, 1000000);
+  }
+
+  return bst;
+}
+
+
 static struct bsod_state *
 macx (Display *dpy, Window window)
 {
 # ifdef DO_XPM
-  switch (random() % 3) {
+  switch (1?4:random() % 5) {
   case 0: return macx_10_0 (dpy, window);        break;
   case 1: return macx_10_2 (dpy, window, False); break;
   case 2: return macx_10_2 (dpy, window, True);  break;
+  case 3: return mac_diskfail (dpy, window);     break;
+  case 4: return macx_install (dpy, window);     break;
   default: abort();
   }
 # else  /* !DO_XPM */
-  return macx_10_0 (dpy, window);
+  switch (random() % 3) {
+  case 0:  return macx_10_0 (dpy, window);    break;
+  case 1:  return macx_install (dpy, window); break;
+  default: return mac_diskfail (dpy, window); break;
+  }
 # endif /* !DO_XPM */
 }
 
 
-#ifndef HAVE_COCOA /* #### I have no idea how to implement this without
+#ifndef HAVE_JWXYZ /* #### I have no idea how to implement this without
                            real plane-masks.  I don't think it would look
                            right if done with alpha-transparency... */
 /* blit damage
@@ -1743,15 +2284,12 @@ blitdamage (Display *dpy, Window window)
   int w, h;
   int chunk_h, chunk_w;
   int steps;
-  long gc_mask = 0;
   int src_x, src_y;
   int x, y;
   
   w = bst->xgwa.width;
   h = bst->xgwa.height;
 
-  gc_mask = GCForeground;
-  
   XSetPlaneMask (dpy, bst->gc, random());
 
   steps = 50;
@@ -1784,7 +2322,7 @@ blitdamage (Display *dpy, Window window)
 
   return bst;
 }
-#endif /* !HAVE_COCOA */
+#endif /* !HAVE_JWXYZ */
 
 
 /*
@@ -2452,7 +2990,7 @@ hppa_linux (Display *dpy, Window window)
      { -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.97 $ 13 ports, "
+     { -1, "Serial: 8250/16550 driver $" "Revision: 1.100 $ 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" },
@@ -2811,7 +3349,7 @@ hvx (Display *dpy, Window window)
 static struct bsod_state *
 hpux (Display *dpy, Window window)
 {
-  struct bsod_state *bst = make_bsod_state (dpy, window, "hvx", "HVX");
+  struct bsod_state *bst = make_bsod_state (dpy, window, "hpux", "HPUX");
   const char *sysname;
   char buf[2048];
 
@@ -3664,6 +4202,226 @@ atm (Display *dpy, Window window)
 }
 
 
+/* An Android phone boot loader, by jwz.
+ */
+static struct bsod_state *
+android (Display *dpy, Window window)
+{
+  struct bsod_state *bst = make_bsod_state (dpy, window, "android", "Android");
+
+  unsigned long bg = get_pixel_resource (dpy, bst->xgwa.colormap,
+                                         "android.background",
+                                         "Android.Background");
+  unsigned long fg = get_pixel_resource (dpy, bst->xgwa.colormap,
+                                         "android.foreground",
+                                         "Android.Foreground");
+  unsigned long c1 = get_pixel_resource (dpy, bst->xgwa.colormap,
+                                         "android.color1",
+                                         "Android.Foreground");
+  unsigned long c2 = get_pixel_resource (dpy, bst->xgwa.colormap,
+                                         "android.color2",
+                                         "Android.Foreground");
+  unsigned long c3 = get_pixel_resource (dpy, bst->xgwa.colormap,
+                                         "android.color3",
+                                         "Android.Foreground");
+  unsigned long c4 = get_pixel_resource (dpy, bst->xgwa.colormap,
+                                         "android.color4",
+                                         "Android.Foreground");
+  unsigned long c5 = get_pixel_resource (dpy, bst->xgwa.colormap,
+                                         "android.color5",
+                                         "Android.Foreground");
+  unsigned long c6 = get_pixel_resource (dpy, bst->xgwa.colormap,
+                                         "android.color6",
+                                         "Android.Foreground");
+  unsigned long c7 = get_pixel_resource (dpy, bst->xgwa.colormap,
+                                         "android.color7",
+                                         "Android.Foreground");
+
+  const char *lines0[] = {
+    "Calculating... please wait\n",
+    "osbl:     0x499DF907\n",
+    "amss:     0x73162409\n",
+    "hboot:    0xE46C3327\n",
+    "boot:     0xBA570E7A\n",
+    "recovery: 0xC8BBA213\n",
+    "system:   0x87C3B1F0\n",
+    "\n",
+    "Press power key to go back.\n",
+  };
+
+  const char *lines1[] = {
+    "Checking SD card update...\n",
+    "",
+    "  SD Checking...\n",
+    "  Failed to open zipfile\n",
+    "  loading preload_content...\n",
+    "  [Caution] Preload Content Not Found\n",
+    "  loading HTCUpdateZipName image...\n",
+    "",
+    "  Checking...[PG46IMG.zip]\n",
+    "Please plug off USB\n",
+  };
+
+  const char *lines2[] = {
+    "  SD Checking...\n",
+    "  Loading...[PK76DIAG.zip]\n",
+    "  No image!\n",
+    "  Loading...[PK76DIAG.nbh]\n",
+    "  No image or wrong image!\n",
+    "  Loading...[PK76IMG.zip]\n",
+    "  No image!\n",
+    "  Loading...[PK76IMG.nbh]\n",
+    "  No image or wrong image!\n",
+    "  Loading...[PK76IMG.tar]\n",
+    "  No image!\n",
+    "  Loading...[PK76IMG.aes]\n",
+    "  No image!\n",
+    "  Loading...[PK76IMG.enc]\n",
+    "  No image!\n",
+  };
+
+  int cw = (bst->font->per_char
+            ? bst->font->per_char['n'-bst->font->min_char_or_byte2].width
+            : bst->font->min_bounds.width);
+  int line_height = bst->font->ascent + bst->font->descent;
+
+  int state = 0;
+
+  Pixmap pixmap = 0;
+  int pix_w = 0, pix_h = 0;
+
+# ifdef DO_XPM
+  pixmap = xpm_data_to_pixmap (dpy, window, (char **) android_skate,
+                               &pix_w, &pix_h, 0);
+  if (! pixmap) abort();
+  bst->pixmap = pixmap;
+# endif /* DO_XPM */
+
+  bst->left_margin = (bst->xgwa.width - (cw * 40)) / 2;
+  if (bst->left_margin < 0) bst->left_margin = 0;
+
+  while (1) {
+    unsigned long delay =
+      ((state == 0 || 
+        state == countof(lines0) ||
+        state == countof(lines0) + countof(lines1) ||
+        state == countof(lines0) + countof(lines1) + countof(lines2))
+                           ? 10000 : 0);
+    BSOD_LINE_DELAY (bst, delay);
+
+    if (state <= countof(lines0) + countof(lines1) + countof(lines2))
+      {
+        BSOD_COLOR (bst, bg, bg);
+        BSOD_RECT (bst, True, 0, 0, bst->xgwa.width, bst->xgwa.height);
+        BSOD_COLOR (bst, bg, c1);
+        BSOD_MOVETO (bst, bst->left_margin, bst->top_margin + line_height);
+        BSOD_TEXT (bst, LEFT, "*** UNLOCKED ***\n");
+        BSOD_COLOR (bst, c2, bg);
+        BSOD_TEXT (bst, LEFT, 
+                   "PRIMOU PVT SHIP S-OFF RL\n"
+                   "HBOOT-1.17.0000\n"
+                   "CPLD-None\n"
+                   "MICROP-None\n"
+                   "RADIO-3831.17.00.23_2\n"
+                   "eMMC-bootmode: disabled\n"
+                   "CPU-bootmode : disabled\n"
+                   "HW Secure boot: enabled\n"
+                   "MODEM PATH : OFF\n"
+                   "May 15 2012, 10:28:15\n"
+                   "\n");
+        BSOD_COLOR (bst, bg, c3);
+
+        if (pixmap)
+          {
+            int x = (bst->xgwa.width - pix_w) / 2;
+            int y = bst->xgwa.height - pix_h;
+            BSOD_PIXMAP (bst, 0, 0, pix_w, pix_h, x, y);
+          }
+      }
+
+    if (state == countof(lines0) ||
+        state == countof(lines0) + countof(lines1) ||
+        state == countof(lines0) + countof(lines1) + countof(lines2))
+      {
+        BSOD_TEXT (bst, LEFT, "HBOOT USB\n");
+        BSOD_COLOR (bst, c4, bg);
+        BSOD_TEXT (bst, LEFT,
+                   "\n"
+                   "<VOL UP> to previous item\n"
+                   "<VOL DOWN> to next item\n"
+                   "<POWER> to select item\n"
+                   "\n");
+        BSOD_COLOR (bst, c5, bg); BSOD_TEXT (bst, LEFT, "FASTBOOT\n");
+        BSOD_COLOR (bst, c6, bg); BSOD_TEXT (bst, LEFT, "RECOVERY\n");
+        BSOD_COLOR (bst, c7, bg); BSOD_TEXT (bst, LEFT, "FACTORY RESET\n");
+        BSOD_COLOR (bst, c3, bg); BSOD_TEXT (bst, LEFT, "SIMLOCK\n");
+        BSOD_COLOR (bst, bg, c3); BSOD_TEXT (bst, LEFT, "HBOOT USB\n");
+        BSOD_COLOR (bst, fg, bg); BSOD_TEXT (bst, LEFT, "IMAGE CRC\n");
+        BSOD_COLOR (bst, c3, bg); BSOD_TEXT (bst, LEFT, "SHOW BARCODE\n");
+        BSOD_PAUSE (bst, 3000000);
+      }
+    else if (state < countof(lines0))
+      {
+        BSOD_TEXT (bst, LEFT, "IMAGE CRC\n\n");
+        BSOD_COLOR (bst, c5, bg);
+        {
+          int i;
+          for (i = 0; i <= state; i++) {
+            const char *s = lines0[i];
+            BSOD_COLOR (bst, (strchr(s, ':') ? c7 : c3), bg);
+            BSOD_TEXT (bst, LEFT, s);
+          }
+        }
+        BSOD_PAUSE (bst, 500000);
+        if (state == countof(lines0)-1)
+          BSOD_PAUSE (bst, 2000000);
+      }
+    else if (state < countof(lines0) + countof(lines1))
+      {
+        BSOD_TEXT (bst, LEFT, "HBOOT\n\n");
+        BSOD_COLOR (bst, c5, bg);
+        {
+          int i;
+          for (i = countof(lines0); i <= state; i++) {
+            const char *s = lines1[i - countof(lines0)];
+            BSOD_COLOR (bst, (*s == ' ' ? c6 : c3), bg);
+            BSOD_TEXT (bst, LEFT, s);
+          }
+        }
+        BSOD_PAUSE (bst, 500000);
+        if (state == countof(lines0) + countof(lines1) - 1)
+          BSOD_PAUSE (bst, 2000000);
+      }
+    else if (state < countof(lines0) + countof(lines1) + countof(lines2))
+      {
+        BSOD_TEXT (bst, LEFT, "HBOOT USB\n\n");
+        BSOD_COLOR (bst, c5, bg);
+        {
+          int i;
+          for (i = countof(lines0) + countof(lines1); i <= state; i++) {
+            const char *s = lines2[i - countof(lines0) - countof(lines1)];
+            BSOD_COLOR (bst, (*s == ' ' ? c6 : c3), bg);
+            BSOD_TEXT (bst, LEFT, s);
+          }
+        }
+        BSOD_PAUSE (bst, 500000);
+        if (state == countof(lines0) + countof(lines1) + countof(lines2)-1)
+          BSOD_PAUSE (bst, 2000000);
+      }
+    else
+      break;
+
+    state++;
+  }
+
+  XClearWindow (dpy, window);
+
+  return bst;
+}
+
+
+
+
 /*****************************************************************************
  *****************************************************************************/
 
@@ -3675,6 +4433,7 @@ static const struct {
   { "Windows",         windows_31 },
   { "NT",              windows_nt },
   { "Win2K",           windows_other },
+  { "Win10",           windows_10 },
   { "Amiga",           amiga },
   { "Mac",             mac },
   { "MacsBug",         macsbug },
@@ -3686,7 +4445,7 @@ static const struct {
   { "SparcLinux",      sparc_linux },
   { "BSD",             bsd },
   { "Atari",           atari },
-#ifndef HAVE_COCOA
+#ifndef HAVE_JWXYZ
   { "BlitDamage",      blitdamage },
 #endif
   { "Solaris",         sparc_solaris },
@@ -3701,13 +4460,16 @@ static const struct {
   { "Apple2",          apple2crash },
   { "ATM",             atm },
   { "GLaDOS",          glados },
+  { "Android",         android },
+  { "VMware",          vmware },
 };
 
 
 struct driver_state {
   const char *name;
-  int only, which;
-  int delay;
+  int only, which, next_one;
+  int mode_duration;
+  int delay_remaining;
   time_t start;
   Bool debug_p, cycle_p;
   struct bsod_state *bst;
@@ -3717,7 +4479,7 @@ struct driver_state {
 static void
 hack_title (struct driver_state *dst)
 {
-# ifndef HAVE_COCOA
+# ifndef HAVE_JWXYZ
   char *oname = 0;
   XFetchName (dst->bst->dpy, dst->bst->window, &oname);
   if (oname && !strncmp (oname, "BSOD: ", 6)) {
@@ -3730,7 +4492,7 @@ hack_title (struct driver_state *dst)
     XStoreName (dst->bst->dpy, dst->bst->window, nname);
     free (nname);
   }
-# endif /* !HAVE_COCOA */
+# endif /* !HAVE_JWXYZ */
 }
 
 static void *
@@ -3739,12 +4501,13 @@ bsod_init (Display *dpy, Window window)
   struct driver_state *dst = (struct driver_state *) calloc (1, sizeof(*dst));
   char *s;
 
-  dst->delay = get_integer_resource (dpy, "delay", "Integer");
-  if (dst->delay < 3) dst->delay = 3;
+  dst->mode_duration = get_integer_resource (dpy, "delay", "Integer");
+  if (dst->mode_duration < 3) dst->mode_duration = 3;
 
   dst->debug_p = get_boolean_resource (dpy, "debug", "Boolean");
 
   dst->only = -1;
+  dst->next_one = -1;
   s = get_string_resource(dpy, "doOnly", "DoOnly");
   if (s && !strcasecmp (s, "cycle"))
     {
@@ -3780,7 +4543,7 @@ bsod_draw (Display *dpy, Window window, void *closure)
 
  AGAIN:
   now = time ((time_t *) 0);
-  time_left = dst->start + dst->delay - now;
+  time_left = dst->start + dst->mode_duration - now;
 
   if (dst->bst && dst->bst->img_loader)   /* still loading */
     {
@@ -3789,11 +4552,27 @@ bsod_draw (Display *dpy, Window window, void *closure)
       return 100000;
     }
 
+ DELAY_NOW:
+  /* Rather than returning a multi-second delay from the draw() routine,
+     meaning "don't call us again for N seconds", we quantize that down
+     to 1/10th second intervals so that it's more responsive to
+     rotate/reshape events.
+   */
+  if (dst->delay_remaining)
+    {
+      int inc = 10000;
+      int this_delay = MIN (dst->delay_remaining, inc);
+      dst->delay_remaining = MAX (0, dst->delay_remaining - inc);
+      return this_delay;
+    }
+
   if (! dst->bst && time_left > 0)     /* run completed; wait out the delay */
     {
       if (dst->debug_p)
         fprintf (stderr, "%s: %s: %d left\n", progname, dst->name, time_left);
-      return 500000;
+      dst->start = 0;
+      if (time_left > 5) time_left = 5;  /* Boooored now */
+      dst->delay_remaining = 1000000 * time_left;
     }
 
   else if (dst->bst)                   /* sub-mode currently running */
@@ -3803,12 +4582,15 @@ bsod_draw (Display *dpy, Window window, void *closure)
       if (time_left > 0)
         this_delay = bsod_pop (dst->bst);
 
-      /* XSync (dpy, False);  slows down char drawing too much on HAVE_COCOA */
+      /* XSync (dpy, False);  slows down char drawing too much on HAVE_JWXYZ */
 
       if (this_delay == 0)
         goto AGAIN;                    /* no delay, not expired: stay here */
       else if (this_delay >= 0)
-        return this_delay;             /* return; time to sleep */
+        {
+          dst->delay_remaining = this_delay;   /* return; time to sleep */
+          goto DELAY_NOW;
+        }
       else
         {                              /* sub-mode run completed or expired */
           if (dst->debug_p)
@@ -3820,7 +4602,9 @@ bsod_draw (Display *dpy, Window window, void *closure)
     }
   else                                 /* launch a new sub-mode */
     {
-      if (dst->cycle_p)
+      if (dst->next_one >= 0)
+        dst->which = dst->next_one, dst->next_one = -1;
+      else if (dst->cycle_p)
         dst->which = (dst->which + 1) % countof(all_modes);
       else if (dst->only >= 0)
         dst->which = dst->only;
@@ -3903,11 +4687,13 @@ bsod_reshape (Display *dpy, Window window, void *closure,
   if (dst->debug_p)
     fprintf (stderr, "%s: %s: reshape reset\n", progname, dst->name);
 
-  /* just pick a new mode and restart when the window is resized. */
+  /* just restart this mode and restart when the window is resized. */
   if (dst->bst)
     free_bsod_state (dst->bst);
   dst->bst = 0;
   dst->start = 0;
+  dst->delay_remaining = 0;
+  dst->next_one = dst->which;
   dst->name = "none";
   XClearWindow (dpy, window);
 }
@@ -3921,18 +4707,8 @@ bsod_event (Display *dpy, Window window, void *closure, XEvent *event)
 
   /* pick a new mode and restart when mouse clicked, or certain keys typed. */
 
-  if (event->type == ButtonPress)
-    return True;
-  else if (event->type == ButtonRelease)
+  if (screenhack_event_helper (dpy, window, event))
     reset_p = True;
-  else if (event->type == KeyPress)
-    {
-      KeySym keysym;
-      char c = 0;
-      XLookupString (&event->xkey, &c, 1, &keysym, 0);
-      if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
-        reset_p = True;
-    }
 
   if (reset_p)
     {
@@ -3942,6 +4718,7 @@ bsod_event (Display *dpy, Window window, void *closure, XEvent *event)
         free_bsod_state (dst->bst);
       dst->bst = 0;
       dst->start = 0;
+      dst->delay_remaining = 0;
       dst->name = "none";
       XClearWindow (dpy, window);
       return True;
@@ -3962,13 +4739,14 @@ bsod_free (Display *dpy, Window window, void *closure)
 
 
 static const char *bsod_defaults [] = {
-  "*delay:                30",
+  "*delay:                45",
   "*debug:                False",
 
   "*doOnly:               ",
   "*doWindows:            True",
   "*doNT:                 True",
   "*doWin2K:              True",
+  "*doWin10:              True",
   "*doAmiga:              True",
   "*doMac:                True",
   "*doMacsBug:            True",
@@ -3993,11 +4771,8 @@ static const char *bsod_defaults [] = {
   "*doNvidia:             True",
   "*doATM:                True",
   "*doGLaDOS:             True",
-
-  "*font:                 9x15bold",
-  "*font2:                -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
-  "*bigFont:              -*-courier-bold-r-*-*-*-180-*-*-m-*-*-*",
-  "*bigFont2:             -*-courier-bold-r-*-*-*-180-*-*-m-*-*-*",
+  "*doAndroid:            True",
+  "*doVMware:             True",
 
   ".foreground:                   White",
   ".background:                   Black",
@@ -4005,10 +4780,16 @@ static const char *bsod_defaults [] = {
   ".windows.foreground:           White",
   ".windows.background:           #0000AA",    /* EGA color 0x01. */
 
+  ".nt.foreground:        White",
+  ".nt.background:        #0000AA",    /* EGA color 0x01. */
+
   ".windowslh.foreground:  White",
   ".windowslh.background:  #AA0000",    /* EGA color 0x04. */
   ".windowslh.background2: #AAAAAA",    /* EGA color 0x07. */
 
+  ".win10.foreground:      White",
+  ".win10.background:      #1070AA",
+
   ".glaDOS.foreground:    White",
   ".glaDOS.background:    #0000AA",    /* EGA color 0x01. */
 
@@ -4022,8 +4803,6 @@ static const char *bsod_defaults [] = {
   ".atari.foreground:     Black",
   ".atari.background:     White",
 
-  ".macsbug.font:         -*-courier-medium-r-*-*-*-80-*-*-m-*-*-*",
-  ".macsbug.bigFont:      -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
   ".macsbug.foreground:           Black",
   ".macsbug.background:           White",
   ".macsbug.borderColor:   #AAAAAA",
@@ -4036,52 +4815,42 @@ static const char *bsod_defaults [] = {
   ".macx.textBackground:   Black",
   ".macx.background:      #888888",
 
-  ".sco.font:             -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  ".macinstall.barForeground: #C0C0C0",
+  ".macinstall.barBackground: #888888",
+
   ".sco.foreground:       White",
   ".sco.background:       Black",
 
-  ".hvx.font:             -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
   ".hvx.foreground:       White",
   ".hvx.background:       Black",
 
   ".linux.foreground:      White",
   ".linux.background:      Black",
 
-  ".hppalinux.bigFont:    -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
   ".hppalinux.foreground:  White",
   ".hppalinux.background:  Black",
 
-  ".sparclinux.bigFont:           -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
   ".sparclinux.foreground: White",
   ".sparclinux.background: Black",
 
-  ".bsd.font:             vga",
-  ".bsd.bigFont:          -sun-console-medium-r-*-*-22-*-*-*-m-*-*-*",
-  ".bsd.bigFont2:         -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
   ".bsd.foreground:       #c0c0c0",
   ".bsd.background:       Black",
 
-  ".solaris.font:          -sun-gallant-*-*-*-*-19-*-*-*-*-120-*-*",
   ".solaris.foreground:    Black",
   ".solaris.background:    White",
 
-  ".hpux.bigFont:         -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
   ".hpux.foreground:      White",
   ".hpux.background:      Black",
 
-  ".os390.bigFont:        -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
   ".os390.background:     Black",
   ".os390.foreground:     Red",
 
-  ".tru64.bigFont:        -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
   ".tru64.foreground:     White",
   ".tru64.background:     #0000AA",    /* EGA color 0x01. */
 
-  ".vms.bigFont:          -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
   ".vms.foreground:       White",
   ".vms.background:       Black",
 
-  ".msdos.bigFont:        -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
   ".msdos.foreground:     White",
   ".msdos.background:     Black",
 
@@ -4091,6 +4860,20 @@ static const char *bsod_defaults [] = {
   ".atm.foreground:       Black",
   ".atm.background:       #FF6600",
 
+  ".android.foreground:           Black",
+  ".android.background:           White",
+  ".android.color1:       #AA00AA", /* violet */
+  ".android.color2:       #336633", /* green1 */
+  ".android.color3:       #0000FF", /* blue */
+  ".android.color4:       #CC7744", /* orange */
+  ".android.color5:       #99AA55", /* green2 */
+  ".android.color6:       #66AA33", /* green3 */
+  ".android.color7:       #FF0000", /* red */
+
+  ".vmware.foreground:    White",
+  ".vmware.foreground2:           Yellow",
+  ".vmware.background:    #a700a8",    /* purple */
+
   "*dontClearRoot:         True",
 
   ANALOGTV_DEFAULTS
@@ -4099,15 +4882,124 @@ static const char *bsod_defaults [] = {
   "*useSHM:                True",
 #endif
 
-# ifdef USE_IPHONE
-  "*font:                 Courier-Bold 9",
-  ".amiga.font:                   Courier-Bold 12",
-  ".macsbug.font:         Courier-Bold 5",
-  ".sco.font:             Courier-Bold 9",
-  ".hvx.font:             Courier-Bold 9",
-  ".bsd.font:             Courier-Bold 9",
-  ".solaris.font:          Courier-Bold 6",
-# endif
+  "*fontB:                ",
+  "*fontC:                ",
+
+# if defined(USE_IPHONE)
+
+  "*font:                 PxPlus IBM VGA8 16, Courier-Bold 14",
+  "*bigFont:              ",
+  "*font2:                ",
+  "*bigFont2:             ",
+
+  ".mac.font:             Courier-Bold 18",
+  ".macsbug.font:         Courier-Bold 8",
+  ".macx.font:            Courier-Bold 14",
+  ".macdisk.font:         Courier-Bold 14",
+  ".macinstall.font:      Helvetica 12, Arial 12",
+  ".macinstall.bigFont:           Helvetica 12, Arial 12",
+  ".msdos.font:                   PxPlus IBM VGA8 32, Courier-Bold 28",
+  ".nt.font:              PxPlus IBM VGA8 12, Courier-Bold 10",
+  ".win10.font:                   Arial 12, Helvetica 12",
+  ".win10.bigFont:        Arial 12, Helvetica 12",
+  ".win10.fontB:          Arial 50, Helvetica 50",
+  ".win10.fontC:          Arial 9, Helvetica 9",
+  ".win10.bigFont2:       ",
+
+# elif defined(HAVE_ANDROID)
+
+  "*font:                 PxPlus IBM VGA8 16",
+  "*bigFont:              ",
+  "*font2:                ",
+  "*bigFont2:             ",
+
+  ".mac.font:             -*-courier-bold-r-*-*-*-180-*-*-m-*-*-*",
+  ".macsbug.font:         -*-courier-bold-r-*-*-*-80-*-*-m-*-*-*",
+  ".macx.font:            -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  ".macdisk.font:         -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  ".macinstall.font:      -*-helvetica-medium-r-*-*-*-120-*-*-*-*-*-*",
+  ".macinstall.bigFont:           -*-helvetica-medium-r-*-*-*-120-*-*-*-*-*-*",
+  ".msdos.font:                   PxPlus IBM VGA8 32",
+  ".nt.font:              PxPlus IBM VGA8 12",
+
+  ".win10.font:                   -*-helvetica-medium-r-*-*-*-120-*-*-*-*-*-*",
+  ".win10.bigFont:        -*-helvetica-medium-r-*-*-*-120-*-*-*-*-*-*",
+  ".win10.fontB:          -*-helvetica-medium-r-*-*-*-500-*-*-*-*-*-*",
+  ".win10.fontC:          -*-helvetica-medium-r-*-*-*-90-*-*-*-*-*-*",
+  ".win10.bigFont2:       ",
+
+# elif defined(HAVE_COCOA)
+
+  "*font:                 PxPlus IBM VGA8 8,  Courier-Bold 9",
+  "*bigFont:              PxPlus IBM VGA8 32, Courier-Bold 24",
+  "*font2:                ",
+  "*bigFont2:             ",
+
+  ".mac.font:             Monaco 10, Courier-Bold 9",
+  ".mac.bigFont:          Monaco 18, Courier-Bold 18",
+
+  ".macsbug.font:         Monaco 10, Courier-Bold 9",
+  ".macsbug.bigFont:      Monaco 24, Courier-Bold 24",
+
+  ".macx.font:            Courier-Bold 9",
+  ".macx.bigFont:         Courier-Bold 14",
+  ".macdisk.font:         Courier-Bold 9",
+  ".macdisk.bigFont:      Courier-Bold 18",
+  ".macinstall.font:      Helvetica 24, Arial 24",
+  ".macinstall.bigFont:           Helvetica 24, Arial 24",
+
+  ".hvx.bigFont:          PxPlus IBM VGA8 16, Courier-Bold 14",
+  ".hppalinux.bigFont:    PxPlus IBM VGA8 16, Courier-Bold 14",
+  ".solaris.bigFont:      PxPlus IBM VGA8 16, Courier-Bold 14",
+  ".linux.bigFont:        PxPlus IBM VGA8 16, Courier-Bold 14",
+  ".hpux.bigFont:         PxPlus IBM VGA8 16, Courier-Bold 14",
+  ".msdos.font:                   PxPlus IBM VGA8 16, Courier-Bold 14",
+
+  ".win10.font:                   Arial 24, Helvetica 24",
+  ".win10.bigFont:        Arial 24, Helvetica 24",
+  ".win10.fontB:          Arial 100, Helvetica 100",
+  ".win10.fontC:          Arial 16, Helvetica 16",
+  ".win10.bigFont2:       ",
+
+# else   /* X11 */
+
+  "*font:                 9x15bold",
+  "*font2:                -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
+  "*bigFont:              -*-courier-bold-r-*-*-*-180-*-*-m-*-*-*",
+  "*bigFont2:             -*-courier-bold-r-*-*-*-180-*-*-m-*-*-*",
+
+  ".macsbug.font:         -*-courier-medium-r-*-*-*-80-*-*-m-*-*-*",
+  ".macsbug.bigFont:      -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+
+  ".macdisk.font:         -*-courier-bold-r-*-*-*-80-*-*-m-*-*-*",
+  ".macdisk.bigFont:      -*-courier-bold-r-*-*-*-100-*-*-m-*-*-*",
+  ".macinstall.font:      -*-helvetica-medium-r-*-*-*-180-*-*-*-*-*-*",
+  ".macinstall.bigFont:           -*-helvetica-medium-r-*-*-*-180-*-*-*-*-*-*",
+
+  ".sco.font:             -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  ".hvx.font:             -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  ".hppalinux.bigFont:    -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  ".sparclinux.bigFont:           -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+
+  ".bsd.font:             vga",
+  ".bsd.bigFont:          -sun-console-medium-r-*-*-22-*-*-*-m-*-*-*",
+  ".bsd.bigFont2:         -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+
+  ".solaris.font:          -sun-gallant-*-*-*-*-19-*-*-*-*-120-*-*",
+  ".hpux.bigFont:         -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  ".os390.bigFont:        -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  ".tru64.bigFont:        -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  ".vms.bigFont:          -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+  ".msdos.bigFont:        -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
+
+  ".win10.font:                   -*-helvetica-medium-r-*-*-*-180-*-*-*-*-*-*",
+  ".win10.bigFont:        -*-helvetica-medium-r-*-*-*-180-*-*-*-*-*-*",
+  ".win10.fontB:          -*-helvetica-medium-r-*-*-*-240-*-*-*-*-*-*",
+  ".win10.fontC:          -*-helvetica-medium-r-*-*-*-140-*-*-*-*-*-*",
+  ".win10.font2:          ",
+  ".win10.bigFont2:       ",
+
+# endif  /* X11 */
 
   0
 };
@@ -4122,6 +5014,8 @@ static const XrmOptionDescRec bsod_options [] = {
   { "-no-nt",          ".doNT",                XrmoptionNoArg,  "False" },
   { "-2k",             ".doWin2K",             XrmoptionNoArg,  "True"  },
   { "-no-2k",          ".doWin2K",             XrmoptionNoArg,  "False" },
+  { "-win10",          ".doWin10",             XrmoptionNoArg,  "True"  },
+  { "-no-win10",       ".doWin10",             XrmoptionNoArg,  "False" },
   { "-amiga",          ".doAmiga",             XrmoptionNoArg,  "True"  },
   { "-no-amiga",       ".doAmiga",             XrmoptionNoArg,  "False" },
   { "-mac",            ".doMac",               XrmoptionNoArg,  "True"  },
@@ -4170,6 +5064,10 @@ static const XrmOptionDescRec bsod_options [] = {
   { "-no-atm",         ".doATM",               XrmoptionNoArg,  "False" },
   { "-glados",         ".doGLaDOS",            XrmoptionNoArg,  "True"  },
   { "-no-glados",      ".doGLaDOS",            XrmoptionNoArg,  "False" },
+  { "-android",                ".doAndroid",           XrmoptionNoArg,  "True"  },
+  { "-no-android",     ".doAndroid",           XrmoptionNoArg,  "False" },
+  { "-vmware",         ".doVMware",            XrmoptionNoArg,  "True"  },
+  { "-no-vmware",      ".doVMware",            XrmoptionNoArg,  "False" },
   ANALOGTV_OPTIONS
   { 0, 0, 0, 0 }
 };