+/* A crash spotted on a cash machine circa 2006, by jwz. I didn't note
+ what model it was; probably a Tranax Mini-Bank 1000 or similar vintage.
+ */
+static struct bsod_state *
+atm (Display *dpy, Window window)
+{
+ struct bsod_state *bst = make_bsod_state (dpy, window, "atm", "ATM");
+
+ Pixmap pixmap = 0;
+ int pix_w = atm_width;
+ int pix_h = atm_height;
+ int x, y, i = 0;
+ float scale = 0.48;
+
+ XClearWindow (dpy, window);
+
+ pixmap = XCreatePixmapFromBitmapData (dpy, window, (char *) atm_bits,
+ atm_width, atm_height,
+ bst->fg, bst->bg, bst->xgwa.depth);
+
+ while (pix_w <= bst->xgwa.width * scale &&
+ pix_h <= bst->xgwa.height * scale)
+ {
+ pixmap = double_pixmap (dpy, bst->gc, bst->xgwa.visual, bst->xgwa.depth,
+ pixmap, pix_w, pix_h);
+ pix_w *= 2;
+ pix_h *= 2;
+ i++;
+ }
+
+ x = (bst->xgwa.width - pix_w) / 2;
+ y = (bst->xgwa.height - pix_h) / 2;
+ if (y < 0) y = 0;
+
+ if (i > 0)
+ {
+ int j;
+ XSetForeground (dpy, bst->gc,
+ get_pixel_resource (dpy, bst->xgwa.colormap,
+ "atm.background",
+ "ATM.Background"));
+ for (j = -1; j < pix_w; j += i+1)
+ XDrawLine (bst->dpy, pixmap, bst->gc, j, 0, j, pix_h);
+ for (j = -1; j < pix_h; j += i+1)
+ XDrawLine (bst->dpy, pixmap, bst->gc, 0, j, pix_w, j);
+ }
+
+ XCopyArea (dpy, pixmap, window, bst->gc, 0, 0, pix_w, pix_h, x, y);
+
+ XFreePixmap (dpy, pixmap);
+
+ return bst;
+}
+
+
+/* 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;
+}
+
+
+
+
+/*****************************************************************************
+ *****************************************************************************/
+
+
+static const struct {
+ const char *name;
+ struct bsod_state * (*fn) (Display *, Window);
+} all_modes[] = {
+ { "Windows", windows_31 },
+ { "NT", windows_nt },
+ { "Win2K", windows_other },
+ { "Amiga", amiga },
+ { "Mac", mac },
+ { "MacsBug", macsbug },
+ { "Mac1", mac1 },
+ { "MacX", macx },
+ { "SCO", sco },
+ { "HVX", hvx },
+ { "HPPALinux", hppa_linux },
+ { "SparcLinux", sparc_linux },
+ { "BSD", bsd },
+ { "Atari", atari },
+#ifndef HAVE_COCOA
+ { "BlitDamage", blitdamage },
+#endif
+ { "Solaris", sparc_solaris },
+ { "Linux", linux_fsck },
+ { "HPUX", hpux },
+ { "OS390", os390 },
+ { "Tru64", tru64 },
+ { "VMS", vms },
+ { "OS2", os2 },
+ { "MSDOS", msdos },
+ { "Nvidia", nvidia },
+ { "Apple2", apple2crash },
+ { "ATM", atm },
+ { "GLaDOS", glados },
+ { "Android", android },
+};
+
+
+struct driver_state {
+ const char *name;
+ int only, which;
+ int delay;
+ time_t start;
+ Bool debug_p, cycle_p;
+ struct bsod_state *bst;
+};
+
+
+static void
+hack_title (struct driver_state *dst)
+{
+# ifndef HAVE_COCOA
+ char *oname = 0;
+ XFetchName (dst->bst->dpy, dst->bst->window, &oname);
+ if (oname && !strncmp (oname, "BSOD: ", 6)) {
+ char *tail = oname + 4;
+ char *s = strchr (tail+1, ':');
+ char *nname;
+ if (s) tail = s;
+ nname = malloc (strlen (tail) + strlen (dst->name) + 20);
+ sprintf (nname, "BSOD: %s%s", dst->name, tail);
+ XStoreName (dst->bst->dpy, dst->bst->window, nname);
+ free (nname);
+ }
+# endif /* !HAVE_COCOA */
+}
+
+static void *
+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->debug_p = get_boolean_resource (dpy, "debug", "Boolean");
+
+ dst->only = -1;
+ s = get_string_resource(dpy, "doOnly", "DoOnly");
+ if (s && !strcasecmp (s, "cycle"))
+ {
+ dst->which = -1;
+ dst->cycle_p = True;
+ }
+ else if (s && *s)
+ {
+ int count = countof(all_modes);
+ for (dst->only = 0; dst->only < count; dst->only++)
+ if (!strcasecmp (s, all_modes[dst->only].name))
+ break;
+ if (dst->only >= count)
+ {
+ fprintf (stderr, "%s: unknown -only mode: \"%s\"\n", progname, s);
+ dst->only = -1;
+ }
+ }
+ if (s) free (s);
+
+ dst->name = "none";
+ dst->which = -1;
+ return dst;
+}
+
+
+static unsigned long
+bsod_draw (Display *dpy, Window window, void *closure)
+{
+ struct driver_state *dst = (struct driver_state *) closure;
+ time_t now;
+ int time_left;
+
+ AGAIN:
+ now = time ((time_t *) 0);
+ time_left = dst->start + dst->delay - now;
+
+ if (dst->bst && dst->bst->img_loader) /* still loading */
+ {
+ dst->bst->img_loader =
+ load_image_async_simple (dst->bst->img_loader, 0, 0, 0, 0, 0);
+ return 100000;
+ }
+
+ 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;
+ }
+
+ else if (dst->bst) /* sub-mode currently running */
+ {
+ int this_delay = -1;
+
+ if (time_left > 0)
+ this_delay = bsod_pop (dst->bst);
+
+ /* XSync (dpy, False); slows down char drawing too much on HAVE_COCOA */
+
+ if (this_delay == 0)
+ goto AGAIN; /* no delay, not expired: stay here */
+ else if (this_delay >= 0)
+ return this_delay; /* return; time to sleep */
+ else
+ { /* sub-mode run completed or expired */
+ if (dst->debug_p)
+ fprintf (stderr, "%s: %s: done\n", progname, dst->name);
+ free_bsod_state (dst->bst);
+ dst->bst = 0;
+ return 0;
+ }
+ }
+ else /* launch a new sub-mode */
+ {
+ if (dst->cycle_p)
+ dst->which = (dst->which + 1) % countof(all_modes);
+ else if (dst->only >= 0)
+ dst->which = dst->only;
+ else
+ {
+ int count = countof(all_modes);
+ int i;
+
+ for (i = 0; i < 200; i++)
+ {
+ char name[100], class[100];
+ int new_mode = (random() & 0xFF) % count;
+
+ if (i < 100 && new_mode == dst->which)
+ continue;
+
+ sprintf (name, "do%s", all_modes[new_mode].name);
+ sprintf (class, "Do%s", all_modes[new_mode].name);
+
+ if (get_boolean_resource (dpy, name, class))
+ {
+ dst->which = new_mode;
+ break;
+ }
+ }
+
+ if (i >= 200)
+ {
+ fprintf (stderr, "%s: no display modes enabled?\n", progname);
+ /* exit (-1); */
+ dst->which = dst->only = 0;
+ }
+ }
+
+ if (dst->debug_p)
+ fprintf (stderr, "%s: %s: launch\n", progname,
+ all_modes[dst->which].name);
+
+ /* Run the mode setup routine...
+ */
+ if (dst->bst) abort();
+ dst->name = all_modes[dst->which].name;
+ dst->bst = all_modes[dst->which].fn (dpy, window);
+ dst->start = (dst->bst ? time ((time_t *) 0) : 0);
+
+ /* Reset the structure run state to the beginning,
+ and do some sanitization of the cursor position
+ before the first run.
+ */
+ if (dst->bst)
+ {
+ if (dst->debug_p)
+ fprintf (stderr, "%s: %s: queue size: %d (%d)\n", progname,
+ dst->name, dst->bst->pos, dst->bst->queue_size);
+
+ hack_title (dst);
+ dst->bst->pos = 0;
+ dst->bst->x = dst->bst->current_left = dst->bst->left_margin;
+
+ if (dst->bst->y < dst->bst->top_margin + dst->bst->font->ascent)
+ dst->bst->y = dst->bst->top_margin + dst->bst->font->ascent;
+ }
+ }
+
+ return 0;
+}
+
+
+static void
+bsod_reshape (Display *dpy, Window window, void *closure,
+ unsigned int w, unsigned int h)
+{
+ struct driver_state *dst = (struct driver_state *) closure;
+
+ if (dst->bst &&
+ w == dst->bst->xgwa.width &&
+ h == dst->bst->xgwa.height)
+ return;
+
+ 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. */
+ if (dst->bst)
+ free_bsod_state (dst->bst);
+ dst->bst = 0;
+ dst->start = 0;
+ dst->name = "none";
+ XClearWindow (dpy, window);
+}
+
+
+static Bool
+bsod_event (Display *dpy, Window window, void *closure, XEvent *event)
+{
+ struct driver_state *dst = (struct driver_state *) closure;
+ Bool reset_p = False;
+
+ /* pick a new mode and restart when mouse clicked, or certain keys typed. */
+
+ if (screenhack_event_helper (dpy, window, event))
+ reset_p = True;
+
+ if (reset_p)
+ {
+ if (dst->debug_p)
+ fprintf (stderr, "%s: %s: manual reset\n", progname, dst->name);
+ if (dst->bst)
+ free_bsod_state (dst->bst);
+ dst->bst = 0;
+ dst->start = 0;
+ dst->name = "none";
+ XClearWindow (dpy, window);
+ return True;
+ }
+ else
+ return False;
+}
+
+
+static void
+bsod_free (Display *dpy, Window window, void *closure)
+{
+ struct driver_state *dst = (struct driver_state *) closure;
+ if (dst->bst)
+ free_bsod_state (dst->bst);
+ free (dst);
+}
+
+
+static const char *bsod_defaults [] = {
+ "*delay: 45",
+ "*debug: False",