e86efe267677fd4462f7e83ecd7e5bd3121abcf6
[xscreensaver] / hacks / bsod.c
1 /* xscreensaver, Copyright (c) 1998-2001 Jamie Zawinski <jwz@jwz.org>
2  *
3  * Permission to use, copy, modify, distribute, and sell this software and its
4  * documentation for any purpose is hereby granted without fee, provided that
5  * the above copyright notice appear in all copies and that both that
6  * copyright notice and this permission notice appear in supporting
7  * documentation.  No representations are made about the suitability of this
8  * software for any purpose.  It is provided "as is" without express or 
9  * implied warranty.
10  *
11  * Blue Screen of Death: the finest in personal computer emulation.
12  * Concept cribbed from Stephen Martin <smartin@mks.com>;
13  * this version written by jwz, 4-Jun-98.
14  *
15  *   TODO:
16  *      -  Should simulate a Unix kernel panic and reboot.
17  *      -  Making various boot noises would be fun, too.
18  *      -  Should randomize the various hex numbers printed.
19  */
20
21 #include "screenhack.h"
22 #include <stdio.h>
23 #include <X11/Xutil.h>
24
25 #ifdef HAVE_XPM
26 # include <X11/xpm.h>
27 # include "images/amiga.xpm"
28 #endif
29
30 #include "images/atari.xbm"
31 #include "images/mac.xbm"
32
33
34 static void
35 draw_string (Display *dpy, Window window, GC gc, XGCValues *gcv,
36              XFontStruct *font,
37              int xoff, int yoff,
38              int win_width, int win_height,
39              const char *string, int delay)
40 {
41   int x, y;
42   int width = 0, height = 0, cw = 0;
43   int char_width, line_height;
44
45   const char *s = string;
46   const char *se = string;
47
48   /* This pretty much assumes fixed-width fonts */
49   char_width = (font->per_char
50                 ? font->per_char['n'-font->min_char_or_byte2].width
51                 : font->min_bounds.width);
52   line_height = font->ascent + font->descent + 1;
53
54   while (1)
55     {
56       if (*s == '\n' || !*s)
57         {
58           height++;
59           if (cw > width) width = cw;
60           cw = 0;
61           if (!*s) break;
62         }
63       else
64         cw++;
65       s++;
66     }
67
68   x = (win_width - (width * char_width)) / 2;
69   y = (win_height - (height * line_height)) / 2;
70
71   if (x < 0) x = 2;
72   if (y < 0) y = 2;
73
74   x += xoff;
75   y += yoff;
76
77   se = s = string;
78   while (1)
79     {
80       if (*s == '\n' || !*s)
81         {
82           int off = 0;
83           Bool flip = False;
84
85           if (*se == '@' || *se == '_')
86             {
87               if (*se == '@') flip = True;
88               se++;
89               off = (char_width * (width - (s - se))) / 2;
90             }
91
92           if (flip)
93             {
94               XSetForeground(dpy, gc, gcv->background);
95               XSetBackground(dpy, gc, gcv->foreground);
96             }
97
98           if (s != se)
99             XDrawImageString(dpy, window, gc, x+off, y+font->ascent, se, s-se);
100
101           if (flip)
102             {
103               XSetForeground(dpy, gc, gcv->foreground);
104               XSetBackground(dpy, gc, gcv->background);
105             }
106
107           se = s;
108           y += line_height;
109           if (!*s) break;
110           se = s+1;
111
112           if (delay)
113             {
114               XSync(dpy, False);
115               usleep(delay);
116             }
117         }
118       s++;
119     }
120 }
121
122
123 static Pixmap
124 double_pixmap(Display *dpy, GC gc, Visual *visual, int depth, Pixmap pixmap,
125              int pix_w, int pix_h)
126 {
127   int x, y;
128   Pixmap p2 = XCreatePixmap(dpy, pixmap, pix_w*2, pix_h*2, depth);
129   XImage *i1 = XGetImage(dpy, pixmap, 0, 0, pix_w, pix_h, ~0L, ZPixmap);
130   XImage *i2 = XCreateImage(dpy, visual, depth, ZPixmap, 0, 0,
131                             pix_w*2, pix_h*2, 8, 0);
132   i2->data = (char *) calloc(i2->height, i2->bytes_per_line);
133   for (y = 0; y < pix_h; y++)
134     for (x = 0; x < pix_w; x++)
135       {
136         unsigned long p = XGetPixel(i1, x, y);
137         XPutPixel(i2, x*2,   y*2,   p);
138         XPutPixel(i2, x*2+1, y*2,   p);
139         XPutPixel(i2, x*2,   y*2+1, p);
140         XPutPixel(i2, x*2+1, y*2+1, p);
141       }
142   free(i1->data); i1->data = 0;
143   XDestroyImage(i1);
144   XPutImage(dpy, p2, gc, i2, 0, 0, 0, 0, i2->width, i2->height);
145   free(i2->data); i2->data = 0;
146   XDestroyImage(i2);
147   XFreePixmap(dpy, pixmap);
148   return p2;
149 }
150
151
152 /* Sleep for N seconds and return False.  But if a key or mouse event is
153    seen, discard all pending key or mouse events, and return True.
154  */
155 static Bool
156 bsod_sleep(Display *dpy, int seconds)
157 {
158   int q = seconds * 4;
159   int quantum = 250000;
160
161   if (seconds == -1)
162     q = 1, quantum = 100000;
163
164   do
165     {
166       XSync(dpy, False);
167       while (XPending (dpy))
168         {
169           XEvent event;
170           XNextEvent (dpy, &event);
171           if (event.xany.type == ButtonPress)
172             return True;
173           if (event.xany.type == KeyPress)
174             {
175               KeySym keysym;
176               char c = 0;
177               XLookupString (&event.xkey, &c, 1, &keysym, 0);
178               if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
179                 return True;
180             }
181           screenhack_handle_event (dpy, &event);
182         }
183
184       if (q > 0)
185         {
186           q--;
187           usleep(quantum);
188         }
189     }
190   while (q > 0);
191
192   return False; 
193 }
194
195
196 static Bool
197 windows (Display *dpy, Window window, int delay, Bool w95p)
198 {
199   XGCValues gcv;
200   XWindowAttributes xgwa;
201   char *fontname;
202   const char *def_font = "fixed";
203   XFontStruct *font;
204   GC gc;
205
206   const char *w95 =
207     ("@Windows\n"
208      "A fatal exception 0E has occured at F0AD:42494C4C\n"
209      "the current application will be terminated.\n"
210      "\n"
211      "* Press any key to terminate the current application.\n"
212      "* Press CTRL+ALT+DELETE again to restart your computer.\n"
213      "  You will lose any unsaved information in all applications.\n"
214      "\n"
215      "\n"
216      "_Press any key to continue");
217
218   const char *wnt = /* from Jim Niemira <urmane@urmane.org> */
219     ("*** STOP: 0x0000001E (0x80000003,0x80106fc0,0x8025ea21,0xfd6829e8)\n"
220    "Unhandled Kernel exception c0000047 from fa8418b4 (8025ea21,fd6829e8)\n"
221    "\n"
222    "Dll Base Date Stamp - Name             Dll Base Date Stamp - Name\n"
223    "80100000 2be154c9 - ntoskrnl.exe       80400000 2bc153b0 - hal.dll\n"
224    "80258000 2bd49628 - ncrc710.sys        8025c000 2bd49688 - SCSIPORT.SYS \n"
225    "80267000 2bd49683 - scsidisk.sys       802a6000 2bd496b9 - Fastfat.sys\n"
226    "fa800000 2bd49666 - Floppy.SYS         fa810000 2bd496db - Hpfs_Rec.SYS\n"
227    "fa820000 2bd49676 - Null.SYS           fa830000 2bd4965a - Beep.SYS\n"
228    "fa840000 2bdaab00 - i8042prt.SYS       fa850000 2bd5a020 - SERMOUSE.SYS\n"
229    "fa860000 2bd4966f - kbdclass.SYS       fa870000 2bd49671 - MOUCLASS.SYS\n"
230    "fa880000 2bd9c0be - Videoprt.SYS       fa890000 2bd49638 - NCC1701E.SYS\n"
231    "fa8a0000 2bd4a4ce - Vga.SYS            fa8b0000 2bd496d0 - Msfs.SYS\n"
232    "fa8c0000 2bd496c3 - Npfs.SYS           fa8e0000 2bd496c9 - Ntfs.SYS\n"
233    "fa940000 2bd496df - NDIS.SYS           fa930000 2bd49707 - wdlan.sys\n"
234    "fa970000 2bd49712 - TDI.SYS            fa950000 2bd5a7fb - nbf.sys\n"
235    "fa980000 2bd72406 - streams.sys        fa9b0000 2bd4975f - ubnb.sys\n"
236    "fa9c0000 2bd5bfd7 - usbser.sys         fa9d0000 2bd4971d - netbios.sys\n"
237    "fa9e0000 2bd49678 - Parallel.sys       fa9f0000 2bd4969f - serial.SYS\n"
238    "faa00000 2bd49739 - mup.sys            faa40000 2bd4971f - SMBTRSUP.SYS\n"
239    "faa10000 2bd6f2a2 - srv.sys            faa50000 2bd4971a - afd.sys\n"
240    "faa60000 2bd6fd80 - rdr.sys            faaa0000 2bd49735 - bowser.sys\n"
241    "\n"
242    "Address dword dump Dll Base                                      - Name\n"
243    "801afc20 80106fc0 80106fc0 00000000 00000000 80149905 : "
244      "fa840000 - i8042prt.SYS\n"
245    "801afc24 80149905 80149905 ff8e6b8c 80129c2c ff8e6b94 : "
246      "8025c000 - SCSIPORT.SYS\n"
247    "801afc2c 80129c2c 80129c2c ff8e6b94 00000000 ff8e6b94 : "
248      "80100000 - ntoskrnl.exe\n"
249    "801afc34 801240f2 80124f02 ff8e6df4 ff8e6f60 ff8e6c58 : "
250      "80100000 - ntoskrnl.exe\n"
251    "801afc54 80124f16 80124f16 ff8e6f60 ff8e6c3c 8015ac7e : "
252      "80100000 - ntoskrnl.exe\n"
253    "801afc64 8015ac7e 8015ac7e ff8e6df4 ff8e6f60 ff8e6c58 : "
254      "80100000 - ntoskrnl.exe\n"
255    "801afc70 80129bda 80129bda 00000000 80088000 80106fc0 : "
256      "80100000 - ntoskrnl.exe\n"
257    "\n"
258    "Kernel Debugger Using: COM2 (Port 0x2f8, Baud Rate 19200)\n"
259    "Restart and set the recovery options in the system control panel\n"
260    "or the /CRASHDEBUG system start option. If this message reappears,\n"
261    "contact your system administrator or technical support group."
262      );
263
264   if (!get_boolean_resource((w95p? "doWindows" : "doNT"), "DoWindows"))
265     return False;
266
267   XGetWindowAttributes (dpy, window, &xgwa);
268
269   fontname = get_string_resource ((xgwa.height > 600
270                                    ? (w95p
271                                       ? "windows95.font2"
272                                       : "windowsNT.font2")
273                                    : (w95p
274                                       ? "windows95.font"
275                                       : "windowsNT.font")),
276                                   "Windows.Font");
277   if (!fontname || !*fontname) fontname = (char *)def_font;
278   font = XLoadQueryFont (dpy, fontname);
279   if (!font) font = XLoadQueryFont (dpy, def_font);
280   if (!font) exit(-1);
281   if (fontname && fontname != def_font)
282     free (fontname);
283
284   gcv.font = font->fid;
285   gcv.foreground = get_pixel_resource((w95p
286                                        ? "windows95.foreground"
287                                        : "windowsNT.foreground"),
288                                       "Windows.Foreground",
289                                       dpy, xgwa.colormap);
290   gcv.background = get_pixel_resource((w95p
291                                        ? "windows95.background"
292                                        : "windowsNT.background"),
293                                       "Windows.Background",
294                                       dpy, xgwa.colormap);
295   XSetWindowBackground(dpy, window, gcv.background);
296   XClearWindow(dpy, window);
297
298   gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
299
300   if (w95p)
301     draw_string(dpy, window, gc, &gcv, font,
302                 0, 0, xgwa.width, xgwa.height, w95, 0);
303   else
304     draw_string(dpy, window, gc, &gcv, font, 0, 0, 10, 10, wnt, 750);
305
306   XFreeGC(dpy, gc);
307   XSync(dpy, False);
308   bsod_sleep(dpy, delay);
309   XClearWindow(dpy, window);
310   XFreeFont(dpy, font);
311   return True;
312 }
313
314 /* SCO OpenServer 5 panic, by Tom Kelly <tom@ancilla.toronto.on.ca>
315  */
316 static Bool
317 sco (Display *dpy, Window window, int delay)
318 {
319   XGCValues gcv;
320   XWindowAttributes xgwa;
321   char *fontname;
322   const char *def_font = "fixed";
323   XFontStruct *font;
324   GC gc;
325   int lines_1 = 0, lines_2 = 0, lines_3 = 0, lines_4 = 0;
326   const char *s;
327
328   const char *sco_panic_1 =
329     ("Unexpected trap in kernel mode:\n"
330      "\n"
331      "cr0 0x80010013     cr2  0x00000014     cr3 0x00000000  tlb  0x00000000\n"
332      "ss  0x00071054    uesp  0x00012055     efl 0x00080888  ipl  0x00000005\n"
333      "cs  0x00092585     eip  0x00544a4b     err 0x004d4a47  trap 0x0000000E\n"
334      "eax 0x0045474b     ecx  0x0042544b     edx 0x57687920  ebx  0x61726520\n"
335      "esp 0x796f7520     ebp  0x72656164     esi 0x696e6720  edi  0x74686973\n"
336      "ds  0x3f000000     es   0x43494c48     fs  0x43525343  gs   0x4f4d4b53\n"
337      "\n"
338      "PANIC: k_trap - kernel mode trap type 0x0000000E\n"
339      "Trying to dump 5023 pages to dumpdev hd (1/41), 63 pages per '.'\n"
340     );
341   const char *sco_panic_2 =
342    ("...............................................................................\n"
343     );
344   const char *sco_panic_3 =
345     ("5023 pages dumped\n"
346      "\n"
347      "\n"
348      );
349   const char *sco_panic_4 =
350     ("**   Safe to Power Off   **\n"
351      "           - or -\n"
352      "** Press Any Key to Reboot **\n"
353     );
354
355   if (!get_boolean_resource("doSCO", "DoSCO"))
356     return False;
357
358   for (s = sco_panic_1; *s; s++) if (*s == '\n') lines_1++;
359   for (s = sco_panic_2; *s; s++) if (*s == '\n') lines_2++;
360   for (s = sco_panic_3; *s; s++) if (*s == '\n') lines_3++;
361   for (s = sco_panic_4; *s; s++) if (*s == '\n') lines_4++;
362
363   XGetWindowAttributes (dpy, window, &xgwa);
364
365   fontname = get_string_resource ((xgwa.height > 600
366                                    ? "sco.font2"
367                                    : "sco.font"),
368                                   "SCO.Font");
369   if (!fontname || !*fontname) fontname = (char *)def_font;
370   font = XLoadQueryFont (dpy, fontname);
371   if (!font) font = XLoadQueryFont (dpy, def_font);
372   if (!font) exit(-1);
373   if (fontname && fontname != def_font)
374     free (fontname);
375
376   gcv.font = font->fid;
377   gcv.foreground = get_pixel_resource(("sco.foreground"),
378                                       "SCO.Foreground",
379                                       dpy, xgwa.colormap);
380   gcv.background = get_pixel_resource(("sco.background"),
381                                       "SCO.Background",
382                                       dpy, xgwa.colormap);
383   XSetWindowBackground(dpy, window, gcv.background);
384   XClearWindow(dpy, window);
385
386   gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
387
388   draw_string(dpy, window, gc, &gcv, font,
389               10, xgwa.height - ((lines_1 + lines_2 + lines_3 + lines_4 + 1) *
390                                  (font->ascent + font->descent + 1)),
391               10, 10,
392               sco_panic_1, 0);
393   XSync(dpy, False);
394   for (s = sco_panic_2; *s; s++)
395     {
396       char *ss = strdup(sco_panic_2);
397       ss[s - sco_panic_2] = 0;
398       draw_string(dpy, window, gc, &gcv, font,
399                   10, xgwa.height - ((lines_2 + lines_3 + lines_4 + 1) *
400                                      (font->ascent + font->descent + 1)),
401                   10, 10,
402                   ss, 0);
403       XSync(dpy, False);
404       free(ss);
405       if (bsod_sleep (dpy, -1))
406         goto DONE;
407     }
408
409   draw_string(dpy, window, gc, &gcv, font,
410               10, xgwa.height - ((lines_3 + lines_4 + 1) *
411                                  (font->ascent + font->descent + 1)),
412               10, 10,
413               sco_panic_3, 0);
414   XSync(dpy, False);
415   if (bsod_sleep(dpy, 1))
416     goto DONE;
417   draw_string(dpy, window, gc, &gcv, font,
418               10, xgwa.height - ((lines_4 + 1) *
419                                  (font->ascent + font->descent + 1)),
420               10, 10,
421               sco_panic_4, 0);
422   XSync(dpy, False);
423
424   bsod_sleep(dpy, delay);
425  DONE:
426   XClearWindow(dpy, window);
427   XFreeGC(dpy, gc);
428   XFreeFont(dpy, font);
429   return True;
430 }
431
432
433 /* Linux (sparc) panic, by Tom Kelly <tom@ancilla.toronto.on.ca>
434  */
435 static Bool
436 sparc_linux (Display *dpy, Window window, int delay)
437 {
438   XGCValues gcv;
439   XWindowAttributes xgwa;
440   char *fontname;
441   const char *def_font = "fixed";
442   XFontStruct *font;
443   GC gc;
444   int lines = 1;
445   const char *s;
446
447   const char *linux_panic =
448     ("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
449         "Unable to handle kernel paging request at virtual address f0d4a000\n"
450         "tsk->mm->context = 00000014\n"
451         "tsk->mm->pgd = f26b0000\n"
452         "              \\|/ ____ \\|/\n"
453         "              \"@'/ ,. \\`@\"\n"
454         "              /_| \\__/ |_\\\n"
455         "                 \\__U_/\n"
456         "gawk(22827): Oops\n"
457         "PSR: 044010c1 PC: f001c2cc NPC: f001c2d0 Y: 00000000\n"
458         "g0: 00001000 g1: fffffff7 g2: 04401086 g3: 0001eaa0\n"
459         "g4: 000207dc g5: f0130400 g6: f0d4a018 g7: 00000001\n"
460         "o0: 00000000 o1: f0d4a298 o2: 00000040 o3: f1380718\n"
461         "o4: f1380718 o5: 00000200 sp: f1b13f08 ret_pc: f001c2a0\n"
462         "l0: efffd880 l1: 00000001 l2: f0d4a230 l3: 00000014\n"
463         "l4: 0000ffff l5: f0131550 l6: f012c000 l7: f0130400\n"
464         "i0: f1b13fb0 i1: 00000001 i2: 00000002 i3: 0007c000\n"
465         "i4: f01457c0 i5: 00000004 i6: f1b13f70 i7: f0015360\n"
466         "Instruction DUMP:\n"
467     );
468
469   if (!get_boolean_resource("doSparcLinux", "DoSparcLinux"))
470     return False;
471
472   for (s = linux_panic; *s; s++) if (*s == '\n') lines++;
473
474   XGetWindowAttributes (dpy, window, &xgwa);
475
476   fontname = get_string_resource ((xgwa.height > 600
477                                    ? "sparclinux.font2"
478                                    : "sparclinux.font"),
479                                   "SparcLinux.Font");
480   if (!fontname || !*fontname) fontname = (char *)def_font;
481   font = XLoadQueryFont (dpy, fontname);
482   if (!font) font = XLoadQueryFont (dpy, def_font);
483   if (!font) exit(-1);
484   if (fontname && fontname != def_font)
485     free (fontname);
486
487   gcv.font = font->fid;
488   gcv.foreground = get_pixel_resource(("sparclinux.foreground"),
489                                       "SparcLinux.Foreground",
490                                       dpy, xgwa.colormap);
491   gcv.background = get_pixel_resource(("sparclinux.background"),
492                                       "SparcLinux.Background",
493                                       dpy, xgwa.colormap);
494   XSetWindowBackground(dpy, window, gcv.background);
495   XClearWindow(dpy, window);
496
497   gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
498
499   draw_string(dpy, window, gc, &gcv, font,
500               10, xgwa.height - (lines * (font->ascent + font->descent + 1)),
501               10, 10,
502               linux_panic, 0);
503   XFreeGC(dpy, gc);
504   XSync(dpy, False);
505   bsod_sleep(dpy, delay);
506   XClearWindow(dpy, window);
507   XFreeFont(dpy, font);
508   return True;
509 }
510
511 /* BSD Panic by greywolf@starwolf.com - modeled after the Linux panic above.
512    By Grey Wolf <greywolf@siteROCK.com>
513  */
514 static Bool
515 bsd (Display *dpy, Window window, int delay)
516 {
517   XGCValues gcv;
518   XWindowAttributes xgwa;
519   char *fontname;
520   const char *def_font = "fixed";
521   XFontStruct *font;
522   GC gc;
523   int lines = 1;
524   int i, n, b;
525   const char *rbstr, *panicking;
526   char syncing[80], bbuf[5], *bp;
527
528   const char *panicstr[] =
529    {"panic: ifree: freeing free inode",
530     "panic: blkfree: freeing free block",
531     "panic: improbability coefficient below zero",
532     "panic: cgsixmmap",
533     "panic: crazy interrupts",
534     "panic: nmi",
535     "panic: attempted windows install",
536     "panic: don't",
537     "panic: free inode isn't",
538     "panic: cpu_fork: curproc",
539     "panic: malloc: out of space in kmem_map",
540     "panic: vogon starship detected",
541     "panic: teleport chamber: out of order",
542     "panic: Brain fried - core dumped"};
543      
544   if (!get_boolean_resource("doBSD", "DoBSD"))
545     return False;
546
547   for (i = 0; i < sizeof(syncing); i++)
548     syncing[i] = 0;
549
550   i = (random() & 0xffff) % (sizeof(panicstr) / sizeof(*panicstr));
551
552   panicking = panicstr[i];
553   strcpy(syncing, "Syncing disks: ");
554
555   b = (random() & 0xff) % 40;
556   for (n = 0; (n < 20) && (b > 0); n++)
557     {
558       if (i)
559         {
560           i = (random() & 0x7);
561           b -= (random() & 0xff) % 20;
562           if (b < 0)
563             b = 0;
564         }
565       sprintf (bbuf, "%d ", b);
566       strcat (syncing, bbuf);
567     }
568
569   if (b)
570     rbstr = "damn!";
571   else
572     rbstr = "sunk!";
573
574   lines = 5;
575
576   XGetWindowAttributes (dpy, window, &xgwa);
577
578   fontname = get_string_resource ((xgwa.height > 600
579                                    ? "bsd.font2"
580                                    : "bsd.font"),
581                                   "BSD.Font");
582   if (!fontname || !*fontname) fontname = (char *)def_font;
583   font = XLoadQueryFont (dpy, fontname);
584   if (!font) font = XLoadQueryFont (dpy, def_font);
585   if (!font) exit(-1);
586   if (fontname && fontname != def_font)
587     free (fontname);
588
589   gcv.font = font->fid;
590   gcv.foreground = get_pixel_resource(("bsd.foreground"),
591                                       "BSD.Foreground",
592                                       dpy, xgwa.colormap);
593   gcv.background = get_pixel_resource(("bsd.background"),
594                                       "BSD.Background",
595                                       dpy, xgwa.colormap);
596   XSetWindowBackground(dpy, window, gcv.background);
597   XClearWindow(dpy, window);
598
599   gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
600
601   draw_string(dpy, window, gc, &gcv, font,
602               10, xgwa.height - (lines * (font->ascent + font->descent + 1)),
603               10, 10,
604               panicking, 0);
605   XSync(dpy, False);
606   lines--;
607
608   for (bp = syncing; *bp;)
609     {
610       char *bsd_bufs, oc = 0;
611       for (;*bp && (*bp != ' '); bp++)
612         ;
613       if (*bp == ' ')
614         {
615           oc = *bp;
616           *bp = 0;
617         }
618       bsd_bufs = strdup(syncing);
619       draw_string(dpy, window, gc, &gcv, font,
620                   10,
621                   xgwa.height - (lines * (font->ascent + font->descent + 1)),
622                   10, 10,
623                   bsd_bufs, 0);
624       XSync(dpy, False);
625       free(bsd_bufs);
626       if (oc)
627         *bp = oc;
628       if (bsod_sleep(dpy, -1))
629         goto DONE;
630       bp++;
631     }
632
633   lines--;
634   
635   draw_string(dpy, window, gc, &gcv, font,
636               10, xgwa.height - (lines * (font->ascent + font->descent + 1)),
637               10, 10,
638               rbstr, 0);
639   lines--;
640   draw_string(dpy, window, gc, &gcv, font,
641               10, xgwa.height - (lines * (font->ascent + font->descent + 1)),
642               10, 10,
643               "Rebooting", 0);
644
645   XFreeGC(dpy, gc);
646   XSync(dpy, False);
647   bsod_sleep(dpy, delay);
648
649 DONE:
650   XClearWindow(dpy, window);
651   XFreeFont(dpy, font);
652   return True;
653 }
654
655 static Bool
656 amiga (Display *dpy, Window window, int delay)
657 {
658   XGCValues gcv;
659   XWindowAttributes xgwa;
660   char *fontname;
661   const char *def_font = "fixed";
662   XFontStruct *font;
663   GC gc, gc2;
664   int height;
665   unsigned long fg, bg, bg2;
666   Pixmap pixmap = 0;
667   int pix_w = 0, pix_h = 0;
668
669   const char *string =
670     ("_Software failure.  Press left mouse button to continue.\n"
671      "_Guru Meditation #00000003.00C01570");
672
673   if (!get_boolean_resource("doAmiga", "DoAmiga"))
674     return False;
675
676   XGetWindowAttributes (dpy, window, &xgwa);
677
678   fontname = get_string_resource ((xgwa.height > 600
679                                    ? "amiga.font2" : "amiga.font"),
680                                   "Amiga.Font");
681   if (!fontname || !*fontname) fontname = (char *)def_font;
682   font = XLoadQueryFont (dpy, fontname);
683   if (!font) font = XLoadQueryFont (dpy, def_font);
684   if (!font) exit(-1);
685   if (fontname && fontname != def_font)
686     free (fontname);
687
688   gcv.font = font->fid;
689   fg = gcv.foreground = get_pixel_resource("amiga.foreground",
690                                            "Amiga.Foreground",
691                                            dpy, xgwa.colormap);
692   bg = gcv.background = get_pixel_resource("amiga.background",
693                                            "Amiga.Background",
694                                            dpy, xgwa.colormap);
695   bg2 = get_pixel_resource("amiga.background2", "Amiga.Background",
696                            dpy, xgwa.colormap);
697   XSetWindowBackground(dpy, window, bg2);
698   XClearWindow(dpy, window);
699
700   gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
701   gcv.background = fg; gcv.foreground = bg;
702   gc2 = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
703
704   height = (font->ascent + font->descent) * 6;
705
706 #ifdef HAVE_XPM
707   {
708     XpmAttributes xpmattrs;
709     int result;
710     xpmattrs.valuemask = 0;
711
712 # ifdef XpmCloseness
713     xpmattrs.valuemask |= XpmCloseness;
714     xpmattrs.closeness = 40000;
715 # endif
716 # ifdef XpmVisual
717     xpmattrs.valuemask |= XpmVisual;
718     xpmattrs.visual = xgwa.visual;
719 # endif
720 # ifdef XpmDepth
721     xpmattrs.valuemask |= XpmDepth;
722     xpmattrs.depth = xgwa.depth;
723 # endif
724 # ifdef XpmColormap
725     xpmattrs.valuemask |= XpmColormap;
726     xpmattrs.colormap = xgwa.colormap;
727 # endif
728
729     result = XpmCreatePixmapFromData(dpy, window, amiga_hand,
730                                      &pixmap, 0 /* mask */, &xpmattrs);
731     if (!pixmap || (result != XpmSuccess && result != XpmColorError))
732       pixmap = 0;
733     pix_w = xpmattrs.width;
734     pix_h = xpmattrs.height;
735   }
736 #endif /* HAVE_XPM */
737
738   if (pixmap && xgwa.height > 600)      /* scale up the bitmap */
739     {
740       pixmap = double_pixmap(dpy, gc, xgwa.visual, xgwa.depth,
741                              pixmap, pix_w, pix_h);
742       pix_w *= 2;
743       pix_h *= 2;
744     }
745
746   if (pixmap)
747     {
748       int x = (xgwa.width - pix_w) / 2;
749       int y = ((xgwa.height - pix_h) / 2);
750       XCopyArea(dpy, pixmap, window, gc, 0, 0, pix_w, pix_h, x, y);
751
752       XSync(dpy, False);
753       bsod_sleep(dpy, 2);
754
755       XCopyArea(dpy, pixmap, window, gc, 0, 0, pix_w, pix_h, x, y + height);
756       XClearArea(dpy, window, 0, 0, xgwa.width, y + height, False);
757       XFreePixmap(dpy, pixmap);
758     }
759
760   XFillRectangle(dpy, window, gc2, 0, 0, xgwa.width, height);
761   draw_string(dpy, window, gc, &gcv, font, 0, 0, xgwa.width, height, string,0);
762
763   {
764     GC gca = gc;
765     while (delay > 0)
766       {
767         XFillRectangle(dpy, window, gca, 0, 0, xgwa.width, font->ascent);
768         XFillRectangle(dpy, window, gca, 0, 0, font->ascent, height);
769         XFillRectangle(dpy, window, gca, xgwa.width-font->ascent, 0,
770                        font->ascent, height);
771         XFillRectangle(dpy, window, gca, 0, height-font->ascent, xgwa.width,
772                        font->ascent);
773         gca = (gca == gc ? gc2 : gc);
774         XSync(dpy, False);
775         if (bsod_sleep(dpy, 1))
776           break;
777         delay--;
778       }
779   }
780
781   XFreeGC(dpy, gc);
782   XFreeGC(dpy, gc2);
783   XSync(dpy, False);
784   XClearWindow(dpy, window);
785   XFreeFont(dpy, font);
786   return True;
787 }
788
789
790 /* Atari ST, by Marcus Herbert <rhoenie@nobiscum.de>
791    Marcus had this to say:
792
793         Though I still have my Atari somewhere, I hardly remember
794         the meaning of the bombs. I think 9 bombs was "bus error" or
795         something like that.  And you often had a few bombs displayed
796         quickly and then the next few ones coming up step by step.
797         Perhaps somebody else can tell you more about it..  its just
798         a quick hack :-}
799  */
800 static Bool
801 atari (Display *dpy, Window window, int delay)
802 {
803         
804   XGCValues gcv;
805   XWindowAttributes xgwa;
806   const char *def_font = "fixed";
807   XFontStruct *font;
808   GC gc;
809   Pixmap pixmap = 0;
810   int pix_w = atari_width;
811   int pix_h = atari_height;
812   int offset;
813   int i, x, y;
814
815   if (!get_boolean_resource("doAtari", "DoAtari"))
816     return False;
817
818   XGetWindowAttributes (dpy, window, &xgwa);
819
820   font = XLoadQueryFont (dpy, def_font);
821   if (!font) exit(-1);
822                 
823   gcv.font = font->fid;
824   gcv.foreground = get_pixel_resource("atari.foreground", "Atari.Foreground",
825                                       dpy, xgwa.colormap);
826   gcv.background = get_pixel_resource("atari.background", "Atari.Background",
827                                       dpy, xgwa.colormap);
828
829   XSetWindowBackground(dpy, window, gcv.background);
830   XClearWindow(dpy, window);
831
832   gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
833
834   pixmap = XCreatePixmapFromBitmapData(dpy, window, (char *) atari_bits,
835                                        pix_w, pix_h,
836                                        gcv.foreground, gcv.background,
837                                        xgwa.depth);
838   pixmap = double_pixmap(dpy, gc, xgwa.visual, xgwa.depth,
839                          pixmap, pix_w, pix_h);
840   pix_w *= 2;
841   pix_h *= 2;
842
843   offset = pix_w + 2;
844   x = 5;
845   y = (xgwa.height - (xgwa.height / 5));
846   if (y < 0) y = 0;
847
848   for (i=0 ; i<7 ; i++) {
849     XCopyArea(dpy, pixmap, window, gc, 0, 0, pix_w, pix_h,
850               (x + (i*offset)), y);
851   }  
852   
853   for (i=7 ; i<10 ; i++) {
854     if (bsod_sleep(dpy, 1))
855       goto DONE;
856     XCopyArea(dpy, pixmap, window, gc, 0, 0, pix_w, pix_h,
857               (x + (i*offset)), y);
858   }
859
860   bsod_sleep(dpy, delay);
861  DONE:
862   XFreePixmap(dpy, pixmap);
863   XFreeGC(dpy, gc);
864   XSync(dpy, False);
865   XClearWindow(dpy, window);
866   XFreeFont(dpy, font);
867   return True;
868 }
869
870
871 static Bool
872 mac (Display *dpy, Window window, int delay)
873 {
874   XGCValues gcv;
875   XWindowAttributes xgwa;
876   char *fontname;
877   const char *def_font = "fixed";
878   XFontStruct *font;
879   GC gc;
880   Pixmap pixmap = 0;
881   int pix_w = mac_width;
882   int pix_h = mac_height;
883   int offset = mac_height * 4;
884   int i;
885
886   const char *string = ("0 0 0 0 0 0 0 F\n"
887                         "0 0 0 0 0 0 0 3");
888
889   if (!get_boolean_resource("doMac", "DoMac"))
890     return False;
891
892   XGetWindowAttributes (dpy, window, &xgwa);
893
894   fontname = get_string_resource ("mac.font", "Mac.Font");
895   if (!fontname || !*fontname) fontname = (char *)def_font;
896   font = XLoadQueryFont (dpy, fontname);
897   if (!font) font = XLoadQueryFont (dpy, def_font);
898   if (!font) exit(-1);
899   if (fontname && fontname != def_font)
900     free (fontname);
901
902   gcv.font = font->fid;
903   gcv.foreground = get_pixel_resource("mac.foreground", "Mac.Foreground",
904                                       dpy, xgwa.colormap);
905   gcv.background = get_pixel_resource("mac.background", "Mac.Background",
906                                       dpy, xgwa.colormap);
907   XSetWindowBackground(dpy, window, gcv.background);
908   XClearWindow(dpy, window);
909
910   gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
911
912   pixmap = XCreatePixmapFromBitmapData(dpy, window, (char *) mac_bits,
913                                        mac_width, mac_height,
914                                        gcv.foreground,
915                                        gcv.background,
916                                        xgwa.depth);
917
918   for(i = 0; i < 2; i++)
919     {
920       pixmap = double_pixmap(dpy, gc, xgwa.visual, xgwa.depth,
921                              pixmap, pix_w, pix_h);
922       pix_w *= 2; pix_h *= 2;
923     }
924
925   {
926     int x = (xgwa.width - pix_w) / 2;
927     int y = (((xgwa.height + offset) / 2) -
928              pix_h -
929              (font->ascent + font->descent) * 2);
930     if (y < 0) y = 0;
931     XCopyArea(dpy, pixmap, window, gc, 0, 0, pix_w, pix_h, x, y);
932     XFreePixmap(dpy, pixmap);
933   }
934
935   draw_string(dpy, window, gc, &gcv, font, 0, 0,
936               xgwa.width, xgwa.height + offset, string, 0);
937
938   XFreeGC(dpy, gc);
939   XSync(dpy, False);
940   bsod_sleep(dpy, delay);
941   XClearWindow(dpy, window);
942   XFreeFont(dpy, font);
943   return True;
944 }
945
946 static Bool
947 macsbug (Display *dpy, Window window, int delay)
948 {
949   XGCValues gcv;
950   XWindowAttributes xgwa;
951   char *fontname;
952   const char *def_font = "fixed";
953   XFontStruct *font;
954   GC gc, gc2;
955
956   int char_width, line_height;
957   int col_right, row_top, row_bottom, page_right, page_bottom, body_top;
958   int xoff, yoff;
959
960   const char *left = ("    SP     \n"
961                       " 04EB0A58  \n"
962                       "58 00010000\n"
963                       "5C 00010000\n"
964                       "   ........\n"
965                       "60 00000000\n"
966                       "64 000004EB\n"
967                       "   ........\n"
968                       "68 0000027F\n"
969                       "6C 2D980035\n"
970                       "   ....-..5\n"
971                       "70 00000054\n"
972                       "74 0173003E\n"
973                       "   ...T.s.>\n"
974                       "78 04EBDA76\n"
975                       "7C 04EBDA8E\n"
976                       "   .S.L.a.U\n"
977                       "80 00000000\n"
978                       "84 000004EB\n"
979                       "   ........\n"
980                       "88 00010000\n"
981                       "8C 00010000\n"
982                       "   ...{3..S\n"
983                       "\n"
984                       "\n"
985                       " CurApName \n"
986                       "  Finder   \n"
987                       "\n"
988                       " 32-bit VM \n"
989                       "SR Smxnzvc0\n"
990                       "D0 04EC0062\n"
991                       "D1 00000053\n"
992                       "D2 FFFF0100\n"
993                       "D3 00010000\n"
994                       "D4 00010000\n"
995                       "D5 04EBDA76\n"
996                       "D6 04EBDA8E\n"
997                       "D7 00000001\n"
998                       "\n"
999                       "A0 04EBDA76\n"
1000                       "A1 04EBDA8E\n"
1001                       "A2 A0A00060\n"
1002                       "A3 027F2D98\n"
1003                       "A4 027F2E58\n"
1004                       "A5 04EC04F0\n"
1005                       "A6 04EB0A86\n"
1006                       "A7 04EB0A58");
1007   const char *bottom = ("  _A09D\n"
1008                         "     +00884    40843714     #$0700,SR         "
1009                         "                  ; A973        | A973\n"
1010                         "     +00886    40843765     *+$0400           "
1011                         "                                | 4A1F\n"
1012                         "     +00888    40843718     $0004(A7),([0,A7[)"
1013                         "                  ; 04E8D0AE    | 66B8");
1014
1015 #if 0
1016   const char *body = ("Bus Error at 4BF6D6CC\n"
1017                       "while reading word from 4BF6D6CC in User data space\n"
1018                       " Unable to access that address\n"
1019                       "  PC: 2A0DE3E6\n"
1020                       "  Frame Type: B008");
1021 #else
1022   const char * body = ("PowerPC unmapped memory exception at 003AFDAC "
1023                                                 "BowelsOfTheMemoryMgr+04F9C\n"
1024                       " Calling chain using A6/R1 links\n"
1025                       "  Back chain  ISA  Caller\n"
1026                       "  00000000    PPC  28C5353C  __start+00054\n"
1027                       "  24DB03C0    PPC  28B9258C  main+0039C\n"
1028                       "  24DB0350    PPC  28B9210C  MainEvent+00494\n"
1029                       "  24DB02B0    PPC  28B91B40  HandleEvent+00278\n"
1030                       "  24DB0250    PPC  28B83DAC  DoAppleEvent+00020\n"
1031                       "  24DB0210    PPC  FFD3E5D0  "
1032                                                 "AEProcessAppleEvent+00020\n"
1033                       "  24DB0132    68K  00589468\n"
1034                       "  24DAFF8C    68K  00589582\n"
1035                       "  24DAFF26    68K  00588F70\n"
1036                       "  24DAFEB3    PPC  00307098  "
1037                                                 "EmToNatEndMoveParams+00014\n"
1038                       "  24DAFE40    PPC  28B9D0B0  DoScript+001C4\n"
1039                       "  24DAFDD0    PPC  28B9C35C  RunScript+00390\n"
1040                       "  24DAFC60    PPC  28BA36D4  run_perl+000E0\n"
1041                       "  24DAFC10    PPC  28BC2904  perl_run+002CC\n"
1042                       "  24DAFA80    PPC  28C18490  Perl_runops+00068\n"
1043                       "  24DAFA30    PPC  28BE6CC0  Perl_pp_backtick+000FC\n"
1044                       "  24DAF9D0    PPC  28BA48B8  Perl_my_popen+00158\n"
1045                       "  24DAF980    PPC  28C5395C  sfclose+00378\n"
1046                       "  24DAF930    PPC  28BA568C  free+0000C\n"
1047                       "  24DAF8F0    PPC  28BA6254  pool_free+001D0\n"
1048                       "  24DAF8A0    PPC  FFD48F14  DisposePtr+00028\n"
1049                       "  24DAF7C9    PPC  00307098  "
1050                                                 "EmToNatEndMoveParams+00014\n"
1051                       "  24DAF780    PPC  003AA180  __DisposePtr+00010");
1052 #endif
1053
1054   const char *s;
1055   int body_lines = 1;
1056
1057   if (!get_boolean_resource("doMacsBug", "DoMacsBug"))
1058     return False;
1059
1060   for (s = body; *s; s++) if (*s == '\n') body_lines++;
1061
1062   XGetWindowAttributes (dpy, window, &xgwa);
1063
1064   fontname = get_string_resource ((xgwa.height > 850
1065                                    ? "macsbug.font3"
1066                                    : (xgwa.height > 700
1067                                       ? "macsbug.font2"
1068                                       : "macsbug.font")),
1069                                   "MacsBug.Font");
1070   if (!fontname || !*fontname) fontname = (char *)def_font;
1071   font = XLoadQueryFont (dpy, fontname);
1072   if (!font) font = XLoadQueryFont (dpy, def_font);
1073   if (!font) exit(-1);
1074   if (fontname && fontname != def_font)
1075     free (fontname);
1076
1077   gcv.font = font->fid;
1078   gcv.foreground = get_pixel_resource("macsbug.foreground",
1079                                       "MacsBug.Foreground",
1080                                       dpy, xgwa.colormap);
1081   gcv.background = get_pixel_resource("macsbug.background",
1082                                       "MacsBug.Background",
1083                                       dpy, xgwa.colormap);
1084
1085   gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
1086
1087   gcv.foreground = gcv.background;
1088   gc2 = XCreateGC(dpy, window, GCForeground, &gcv);
1089
1090   XSetWindowBackground(dpy, window,
1091                        get_pixel_resource("macsbug.borderColor",
1092                                           "MacsBug.BorderColor",
1093                                           dpy, xgwa.colormap));
1094   XClearWindow(dpy, window);
1095
1096   char_width = (font->per_char
1097                 ? font->per_char['n'-font->min_char_or_byte2].width
1098                 : font->min_bounds.width);
1099   line_height = font->ascent + font->descent + 1;
1100
1101   col_right = char_width * 12;
1102   page_bottom = line_height * 47;
1103
1104   if (page_bottom > xgwa.height) page_bottom = xgwa.height;
1105
1106   row_bottom = page_bottom - line_height;
1107   row_top = row_bottom - (line_height * 4);
1108   page_right = col_right + (char_width * 88);
1109   body_top = row_top - (line_height * body_lines);
1110
1111   page_bottom += 2;
1112   row_bottom += 2;
1113   body_top -= 4;
1114
1115   xoff = (xgwa.width - page_right) / 2;
1116   yoff = (xgwa.height - page_bottom) / 2;
1117   if (xoff < 0) xoff = 0;
1118   if (yoff < 0) yoff = 0;
1119
1120   XFillRectangle(dpy, window, gc2, xoff, yoff, page_right, page_bottom);
1121
1122   draw_string(dpy, window, gc, &gcv, font, xoff, yoff, 10, 10, left, 0);
1123   draw_string(dpy, window, gc, &gcv, font, xoff+col_right, yoff+row_top,
1124               10, 10, bottom, 0);
1125
1126   XFillRectangle(dpy, window, gc, xoff + col_right, yoff, 2, page_bottom);
1127   XDrawLine(dpy, window, gc,
1128             xoff+col_right, yoff+row_top, xoff+page_right, yoff+row_top);
1129   XDrawLine(dpy, window, gc,
1130             xoff+col_right, yoff+row_bottom, xoff+page_right, yoff+row_bottom);
1131   XDrawRectangle(dpy, window, gc,  xoff, yoff, page_right, page_bottom);
1132
1133   if (body_top > 4)
1134     body_top = 4;
1135
1136   draw_string(dpy, window, gc, &gcv, font,
1137               xoff + col_right + char_width, yoff + body_top, 10, 10, body,
1138               500);
1139
1140   while (delay > 0)
1141     {
1142       XDrawLine(dpy, window, gc,
1143                 xoff+col_right+(char_width/2)+2, yoff+row_bottom+3,
1144                 xoff+col_right+(char_width/2)+2, yoff+page_bottom-3);
1145       XSync(dpy, False);
1146       usleep(666666L);
1147       XDrawLine(dpy, window, gc2,
1148                 xoff+col_right+(char_width/2)+2, yoff+row_bottom+3,
1149                 xoff+col_right+(char_width/2)+2, yoff+page_bottom-3);
1150       XSync(dpy, False);
1151       usleep(333333L);
1152       if (bsod_sleep(dpy, 0))
1153         break;
1154       delay--;
1155     }
1156
1157   XFreeGC(dpy, gc);
1158   XFreeGC(dpy, gc2);
1159   XClearWindow(dpy, window);
1160   XFreeFont(dpy, font);
1161   return True;
1162 }
1163
1164 \f
1165 /* blit damage
1166  *
1167  * by Martin Pool <mbp@samba.org>, Feb 2000.
1168  *
1169  * This is meant to look like the preferred failure mode of NCD
1170  * Xterms.  The parameters for choosing what to copy where might not
1171  * be quite right, but it looks about ugly enough.
1172  */
1173 static Bool
1174 blitdamage (Display *dpy, Window window, int delay)
1175 {
1176   XGCValues gcv;
1177   XWindowAttributes xwa;
1178   GC gc0;
1179   int i;
1180   int delta_x = 0, delta_y = 0;
1181   int w, h;
1182   int chunk_h, chunk_w;
1183   int steps;
1184   long gc_mask = 0;
1185   int src_x, src_y;
1186   int x, y;
1187   
1188   if (!get_boolean_resource("doBlitDamage", "DoBlitDamage"))
1189     return False;
1190
1191   XGetWindowAttributes(dpy, window, &xwa);
1192
1193   grab_screen_image(xwa.screen, window);
1194
1195   w = xwa.width;
1196   h = xwa.height;
1197
1198   gc_mask = GCForeground;
1199   
1200   gcv.plane_mask = random();
1201   gc_mask |= GCPlaneMask;
1202   
1203   gc0 = XCreateGC(dpy, window, gc_mask, &gcv);
1204
1205   steps = 50;
1206   chunk_w = w / (random() % 1 + 1);
1207   chunk_h = h / (random() % 1 + 1);
1208   if (random() & 0x1000) 
1209     delta_y = random() % 600;
1210   if (!delta_y || (random() & 0x2000))
1211     delta_x = random() % 600;
1212   src_x = 0; 
1213   src_y = 0; 
1214   x = 0;
1215   y = 0;
1216   
1217   for (i = 0; i < steps; i++) {
1218     if (x + chunk_w > w) 
1219       x -= w;
1220     else
1221       x += delta_x;
1222     
1223     if (y + chunk_h > h)
1224       y -= h;
1225     else
1226       y += delta_y;
1227     
1228     XCopyArea(dpy, window, window, gc0,
1229               src_x, src_y, 
1230               chunk_w, chunk_h,
1231               x, y);
1232
1233     bsod_sleep(dpy, 0);
1234   }
1235
1236   bsod_sleep(dpy, delay);
1237
1238   XFreeGC(dpy, gc0);
1239
1240   return True;
1241 }
1242
1243 \f
1244 /*
1245  * SPARC Solaris panic. Should look pretty authentic on Solaris boxes.
1246  * Anton Solovyev <solovam@earthlink.net>
1247  */ 
1248
1249 static int solaris_max_scroll = 10;
1250
1251 typedef struct
1252 {
1253   Display *dpy;
1254   Window window;
1255   GC gc;
1256   Pixmap subwindow;             /* The text subwindow */
1257   XFontStruct *xfs;
1258   int width;                    /* Window width in pixels */
1259   int height;                   /* Window height in pixels */
1260   int sub_width;                /* Text subwindow width in pixels */
1261   int sub_height;               /* Text subwindow height in pixels */
1262   int sub_x;                    /* upper left corner of the text subwindow */
1263   int sub_y;                    /* upper left corner of the text subwindow */
1264   int char_width;               /* Char width in pixels */
1265   int line_height;              /* Line height in pixels */
1266   int columns;                  /* Number of columns in the text screen */
1267   int lines;                    /* Number of lines in the text screen */
1268   int x;                        /* position of the cursor */
1269   int y;                        /* position of the cursor */
1270 } solaris_console;
1271
1272
1273 static solaris_console *
1274 make_solaris_console (Display *dpy, Window window)
1275 {
1276   const char *def_font = "fixed";
1277   solaris_console* ts;
1278
1279   XWindowAttributes xgwa;
1280   XGCValues gcv;
1281   char* fontname;
1282
1283   ts = malloc(sizeof(solaris_console));
1284
1285   ts->window = window;
1286   ts->dpy = dpy;
1287
1288   ts->x = 0;
1289   ts->y = 0;
1290
1291   XGetWindowAttributes (dpy, window, &xgwa);
1292   ts->width = xgwa.width;
1293   ts->height = xgwa.height;
1294   ts->sub_width = ts->width * 0.8;
1295   ts->sub_height = ts->height * 0.8;
1296
1297   fontname = get_string_resource ("solaris.font", "Solaris.Font");
1298   ts->xfs = XLoadQueryFont (dpy, fontname);
1299   if (!ts->xfs)
1300     {
1301       fontname = get_string_resource("solaris.font2", "Solaris.Font");
1302       ts->xfs = XLoadQueryFont(dpy, fontname);
1303     }
1304   if (!ts->xfs)
1305     ts->xfs = XLoadQueryFont(dpy, def_font);
1306   if (!ts->xfs)
1307     {
1308       fprintf (stderr, "Can't load font\n");
1309       XFreeFont (dpy, ts->xfs);
1310       free (ts);
1311       exit (1);
1312     }
1313   gcv.font = ts->xfs->fid;
1314   ts->char_width = (ts->xfs->per_char
1315                     ? ts->xfs->per_char[ts->xfs->min_char_or_byte2 +
1316                                        ts->xfs->default_char].width
1317                     : ts->xfs->max_bounds.width);
1318   ts->line_height = ts->xfs->ascent + ts->xfs->descent + 1;
1319
1320   ts->columns = ts->sub_width / ts->char_width;
1321   ts->lines = ts->sub_height / ts->line_height;
1322
1323   ts->sub_x = (ts->width - ts->sub_width) / 2;
1324   ts->sub_y = (ts->height - ts->sub_height) / 2;
1325
1326   ts->subwindow = XCreatePixmap (dpy, window, ts->sub_width,
1327                                  ts->sub_height * (solaris_max_scroll + 1),
1328                                  xgwa.depth);
1329   grab_screen_image (xgwa.screen, window);
1330   gcv.function = GXcopy;
1331   gcv.background = XBlackPixel (dpy, XDefaultScreen(dpy));
1332   gcv.foreground = XWhitePixel (dpy, XDefaultScreen(dpy));
1333   ts->gc = XCreateGC (dpy, window,
1334                       GCFunction | GCBackground | GCForeground | GCFont,
1335                       &gcv);
1336   XCopyArea (dpy, window, ts->subwindow, ts->gc,
1337              ts->sub_x, ts->sub_y, ts->sub_width, ts->sub_height,
1338              0, 0);
1339   XFillRectangle (dpy, ts->subwindow, ts->gc, 0, ts->sub_height,
1340                   ts->sub_width, ts->sub_height * solaris_max_scroll);
1341
1342   gcv.background = XWhitePixel (dpy, XDefaultScreen (dpy));
1343   gcv.foreground = XBlackPixel (dpy, XDefaultScreen (dpy));
1344   XChangeGC (dpy, ts->gc, GCBackground | GCForeground, &gcv);
1345
1346   return(ts);
1347 }
1348
1349 static void
1350 free_solaris_console (solaris_console* ts)
1351 {
1352   XFreePixmap (ts->dpy, ts->subwindow);
1353   XFreeGC (ts->dpy, ts->gc);
1354   XFreeFont (ts->dpy, ts->xfs);
1355   free (ts);
1356 }
1357
1358 static void
1359 solaris_draw (solaris_console* ts)
1360 {
1361   XCopyArea (ts->dpy, ts->subwindow, ts->window, ts->gc, 0,
1362              (ts->y + 1) * ts->line_height, ts->sub_width,
1363              ts->sub_height, ts->sub_x, ts->sub_y);
1364 }
1365
1366 static void
1367 solaris_putc (solaris_console* ts, const char aChar)
1368 {
1369   if (ts->y >= solaris_max_scroll * ts->lines)
1370     return;
1371
1372   if (!ts->y && !ts->x)
1373     solaris_draw (ts);
1374
1375   switch (aChar)
1376     {
1377     case '\n':
1378       ts->y++;
1379       ts->x = 0;
1380       solaris_draw (ts);
1381       break;
1382     case '\b':
1383       if(ts->x > 0)
1384         ts->x--;
1385       break;
1386     default:
1387       XDrawImageString (ts->dpy, ts->subwindow, ts->gc,
1388                         (ts->x * ts->char_width -
1389                          ts->xfs->min_bounds.lbearing),
1390                         (ts->sub_height + (ts->y + 1) *
1391                          ts->line_height - ts->xfs->descent),
1392                         &aChar, 1);
1393       XCopyArea (ts->dpy, ts->subwindow, ts->window, ts->gc,
1394                  ts->x * ts->char_width,
1395                  ts->y * ts->line_height + ts->sub_height,
1396                  ts->xfs->max_bounds.rbearing - ts->xfs->min_bounds.lbearing,
1397                  ts->line_height, ts->sub_x + ts->x * ts->char_width,
1398                  ts->sub_y + ts->sub_height - ts->line_height);
1399       ts->x++;
1400       if (ts->x >= ts->columns)
1401         {
1402           ts->x = 0;
1403           solaris_putc(ts, '\n');
1404         }
1405       break;
1406     }
1407 }
1408
1409 static void
1410 solaris_puts (solaris_console* ts, const char* aString, int delay)
1411 {
1412   const char *c;
1413   for (c = aString; *c; ++c)
1414     {
1415       solaris_putc (ts, *c);
1416       if (delay)
1417         {
1418           XSync(ts->dpy, 0);
1419           usleep(delay);
1420         }
1421     }
1422   XSync (ts->dpy, 0);
1423 }
1424
1425 static Bool
1426 sparc_solaris (Display* dpy, Window window, int delay)
1427 {
1428   const char *msg1 =
1429     "BAD TRAP: cpu=0 type=0x31 rp=0x2a10043b5e0 addr=0xf3880 mmu_fsr=0x0\n"
1430     "BAD TRAP occured in module \"unix\" due to an illegal access to a"
1431     " user address.\n"
1432     "adb: trap type = 0x31\n"
1433     "addr=0xf3880\n"
1434     "pid=307, pc=0x100306e4, sp=0x2a10043ae81, tstate=0x4480001602,"
1435     " context=0x87f\n"
1436     "g1-g7: 1045b000, 32f, 10079440, 180, 300000ebde8, 0, 30000953a20\n"
1437     "Begin traceback... sp = 2a10043ae81\n"
1438     "Called from 100bd060, fp=2a10043af31, args=f3700 300008cc988 f3880 0"
1439     " 1 300000ebde0.\n"
1440     "Called from 101fe1bc, fp=2a10043b011, args=3000045a240 104465a0"
1441     " 300008e47d0 300008e48fa 300008ae350 300008ae410\n"
1442     "Called from 1007c520, fp=2a10043b0c1, args=300008e4878 300003596e8 0"
1443     " 3000045a320 0 3000045a220\n"
1444     "Called from 1007c498, fp=2a10043b171, args=1045a000 300007847f0 20"
1445     " 3000045a240 1 0\n"
1446     "Called from 1007972c, fp=2a10043b221, args=1 300009517c0 30000951e58 1"
1447     " 300007847f0 0\n"
1448     "Called from 10031e10, fp=2a10043b2d1, args=3000095b0c8 0 300009396a8"
1449     " 30000953a20 0 1\n"
1450     "Called from 10000bdd8, fp=ffffffff7ffff1c1, args=0 57 100131480"
1451     " 100131480 10012a6e0 0\n"
1452     "End traceback...\n"
1453     "panic[cpu0]/thread=30000953a20: trap\n"
1454     "syncing file systems...";
1455   const char *msg2 =
1456     " 1 done\n"
1457     "dumping to /dev/dsk/c0t0d0s3, offset 26935296\n";
1458   const char *msg3 =
1459     ": 2803 pages dumped, compression ratio 2.88, dump succeeded\n";
1460   const char *msg4 =
1461     "rebooting...\n"
1462     "Resetting ...";
1463
1464   solaris_console* ts;
1465   int i;
1466   char buf[256];
1467
1468   if (!get_boolean_resource("doSolaris", "DoSolaris"))
1469     return False;
1470
1471   ts = make_solaris_console (dpy, window);
1472
1473   solaris_puts (ts, msg1, 0);
1474   bsod_sleep (dpy, 3);
1475
1476   solaris_puts (ts, msg2, 0);
1477   bsod_sleep (dpy, 2);
1478
1479   for (i = 1; i <= 100; ++i)
1480     {
1481       sprintf(buf, "\b\b\b\b\b\b\b\b\b\b\b%3d%% done", i);
1482       solaris_puts(ts, buf, 0);
1483       usleep(100000);
1484     }
1485
1486   solaris_puts (ts, msg3, 0);
1487   bsod_sleep (dpy, 2);
1488
1489   solaris_puts (ts, msg4, 0);
1490   bsod_sleep(dpy, 3);
1491
1492   XFillRectangle (ts->dpy, ts->window, ts->gc, 0, 0,
1493                   ts->width, ts->height);
1494
1495   bsod_sleep (dpy, 3);
1496
1497   free_solaris_console (ts);
1498
1499   return True;
1500 }
1501
1502 \f
1503 char *progclass = "BSOD";
1504
1505 char *defaults [] = {
1506   "*delay:                 30",
1507
1508   "*doWindows:             True",
1509   "*doNT:                  True",
1510   "*doAmiga:               True",
1511   "*doMac:                 True",
1512   "*doAtari:               False",      /* boring */
1513   "*doMacsBug:             True",
1514   "*doSCO:                 True",
1515   "*doBSD:                 False",      /* boring */
1516   "*doSparcLinux:          False",      /* boring */
1517   "*doBlitDamage:          True",
1518   "*doSolaris:             True",
1519
1520   ".Windows.font:          -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
1521   ".Windows.font2:         -*-courier-bold-r-*-*-*-180-*-*-m-*-*-*",
1522   ".Windows.foreground:    White",
1523   ".Windows.background:    Blue",
1524
1525   ".Amiga.font:            -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
1526   ".Amiga.font2:           -*-courier-bold-r-*-*-*-180-*-*-m-*-*-*",
1527   ".Amiga.foreground:      Red",
1528   ".Amiga.background:      Black",
1529   ".Amiga.background2:     White",
1530
1531   ".Mac.font:              -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
1532   ".Mac.foreground:        PaleTurquoise1",
1533   ".Mac.background:        Black",
1534
1535   ".Atari.foreground:      Black",
1536   ".Atari.background:      White",
1537
1538   ".MacsBug.font:          -*-courier-medium-r-*-*-*-100-*-*-m-*-*-*",
1539   ".MacsBug.font2:         -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
1540   ".MacsBug.font3:         -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
1541   ".MacsBug.foreground:    Black",
1542   ".MacsBug.background:    White",
1543   ".MacsBug.borderColor:   #AAAAAA",
1544
1545   ".SCO.font:              -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
1546   ".SCO.font2:             -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
1547   ".SCO.foreground:        White",
1548   ".SCO.background:        Black",
1549
1550   ".SparcLinux.font:       -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
1551   ".SparcLinux.font2:      -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
1552   ".SparcLinux.foreground: White",
1553   ".SparcLinux.background: Black",
1554
1555   ".BSD.font:               vga",
1556   ".BSD.font:               -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
1557   ".BSD.font2:              -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
1558 /* ".BSD.font2:             -sun-console-medium-r-*-*-22-*-*-*-m-*-*-*", */
1559   ".BSD.foreground:         #c0c0c0",
1560   ".BSD.background:         Black",
1561
1562   ".Solaris.font:           -sun-gallant-*-*-*-*-19-*-*-*-*-120-*-*",
1563   ".Solaris.font2:          -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
1564   "*dontClearRoot:          True",
1565   0
1566 };
1567
1568 XrmOptionDescRec options [] = {
1569   { "-delay",           ".delay",               XrmoptionSepArg, 0 },
1570   { "-windows",         ".doWindows",           XrmoptionNoArg,  "True"  },
1571   { "-no-windows",      ".doWindows",           XrmoptionNoArg,  "False" },
1572   { "-nt",              ".doNT",                XrmoptionNoArg,  "True"  },
1573   { "-no-nt",           ".doNT",                XrmoptionNoArg,  "False" },
1574   { "-amiga",           ".doAmiga",             XrmoptionNoArg,  "True"  },
1575   { "-no-amiga",        ".doAmiga",             XrmoptionNoArg,  "False" },
1576   { "-mac",             ".doMac",               XrmoptionNoArg,  "True"  },
1577   { "-no-mac",          ".doMac",               XrmoptionNoArg,  "False" },
1578   { "-atari",           ".doAtari",             XrmoptionNoArg,  "True"  },
1579   { "-no-atari",        ".doAtari",             XrmoptionNoArg,  "False" },
1580   { "-macsbug",         ".doMacsBug",           XrmoptionNoArg,  "True"  },
1581   { "-no-macsbug",      ".doMacsBug",           XrmoptionNoArg,  "False" },
1582   { "-sco",             ".doSCO",               XrmoptionNoArg,  "True"  },
1583   { "-no-sco",          ".doSCO",               XrmoptionNoArg,  "False" },
1584   { "-bsd",             ".doBSD",               XrmoptionNoArg,  "True"  },
1585   { "-no-bsd",          ".doBSD",               XrmoptionNoArg,  "False" },
1586   { "-sparclinux",      ".doSparcLinux",        XrmoptionNoArg,  "True"  },
1587   { "-no-sparclinux",   ".doSparcLinux",        XrmoptionNoArg,  "False" },
1588   { "-blitdamage",      ".doBlitDamage",        XrmoptionNoArg,  "True"  },
1589   { "-no-blitdamage",   ".doBlitDamage",        XrmoptionNoArg,  "False" },
1590   { "-solaris",         ".doSolaris",           XrmoptionNoArg,  "True"  },
1591   { "-no-solaris",      ".doSolaris",           XrmoptionNoArg,  "False" },
1592   { 0, 0, 0, 0 }
1593 };
1594
1595
1596 void
1597 screenhack (Display *dpy, Window window)
1598 {
1599   int loop = 0;
1600   int i = -1;
1601   int j = -1;
1602   int delay = get_integer_resource ("delay", "Integer");
1603   if (delay < 3) delay = 3;
1604
1605   if (!get_boolean_resource ("root", "Boolean"))
1606     {
1607       XWindowAttributes xgwa;
1608       XGetWindowAttributes (dpy, window, &xgwa);
1609       XSelectInput (dpy, window,
1610                     xgwa.your_event_mask | KeyPressMask | ButtonPressMask);
1611     }
1612
1613   while (1)
1614     {
1615       Bool did;
1616       do {  i = (random() & 0xFF) % 11; } while (i == j);
1617       switch (i)
1618         {
1619         case 0: did = windows(dpy, window, delay, True); break;
1620         case 1: did = windows(dpy, window, delay, False); break;
1621         case 2: did = amiga(dpy, window, delay); break;
1622         case 3: did = mac(dpy, window, delay); break;
1623         case 4: did = macsbug(dpy, window, delay); break;
1624         case 5: did = sco(dpy, window, delay); break;
1625         case 6: did = sparc_linux(dpy, window, delay); break;
1626         case 7: did = bsd(dpy, window, delay); break;
1627         case 8: did = atari(dpy, window, delay); break;
1628         case 9: did = blitdamage(dpy, window, delay); break;
1629         case 10: did = sparc_solaris(dpy, window, delay); break;
1630         default: abort(); break;
1631         }
1632       loop++;
1633       if (loop > 100) j = -1;
1634       if (loop > 200)
1635         {
1636           fprintf (stderr, "%s: no display modes enabled?\n", progname);
1637           exit(-1);
1638         }
1639       if (!did) continue;
1640       XSync (dpy, False);
1641       j = i;
1642       loop = 0;
1643     }
1644 }