ftp://ftp.smr.ru/pub/0/FreeBSD/releases/distfiles/xscreensaver-3.16.tar.gz
[xscreensaver] / hacks / bsod.c
1 /* xscreensaver, Copyright (c) 1998 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  *      -  Maybe scatter some random bits across the screen,
19  *         to simulate corruption of video ram?
20  *      -  Should randomize the various hex numbers printed.
21  */
22
23 #include "screenhack.h"
24 #include <stdio.h>
25 #include <X11/Xutil.h>
26
27 #ifdef HAVE_XPM
28 # include <X11/xpm.h>
29 # include "images/amiga.xpm"
30 #endif
31
32 #include "images/atari.xbm"
33 #include "images/mac.xbm"
34
35
36 static void
37 draw_string (Display *dpy, Window window, GC gc, XGCValues *gcv,
38              XFontStruct *font,
39              int xoff, int yoff,
40              int win_width, int win_height,
41              const char *string, int delay)
42 {
43   int x, y;
44   int width = 0, height = 0, cw = 0;
45   int char_width, line_height;
46
47   const char *s = string;
48   const char *se = string;
49
50   /* This pretty much assumes fixed-width fonts */
51   char_width = (font->per_char
52                 ? font->per_char['n'-font->min_char_or_byte2].width
53                 : font->min_bounds.width);
54   line_height = font->ascent + font->descent + 1;
55
56   while (1)
57     {
58       if (*s == '\n' || !*s)
59         {
60           height++;
61           if (cw > width) width = cw;
62           cw = 0;
63           if (!*s) break;
64         }
65       else
66         cw++;
67       s++;
68     }
69
70   x = (win_width - (width * char_width)) / 2;
71   y = (win_height - (height * line_height)) / 2;
72
73   if (x < 0) x = 2;
74   if (y < 0) y = 2;
75
76   x += xoff;
77   y += yoff;
78
79   se = s = string;
80   while (1)
81     {
82       if (*s == '\n' || !*s)
83         {
84           int off = 0;
85           Bool flip = False;
86
87           if (*se == '@' || *se == '_')
88             {
89               if (*se == '@') flip = True;
90               se++;
91               off = (char_width * (width - (s - se))) / 2;
92             }
93
94           if (flip)
95             {
96               XSetForeground(dpy, gc, gcv->background);
97               XSetBackground(dpy, gc, gcv->foreground);
98             }
99
100           if (s != se)
101             XDrawImageString(dpy, window, gc, x+off, y+font->ascent, se, s-se);
102
103           if (flip)
104             {
105               XSetForeground(dpy, gc, gcv->foreground);
106               XSetBackground(dpy, gc, gcv->background);
107             }
108
109           se = s;
110           y += line_height;
111           if (!*s) break;
112           se = s+1;
113
114           if (delay)
115             {
116               XSync(dpy, False);
117               usleep(delay);
118             }
119         }
120       s++;
121     }
122 }
123
124
125 static Pixmap
126 double_pixmap(Display *dpy, GC gc, Visual *visual, int depth, Pixmap pixmap,
127              int pix_w, int pix_h)
128 {
129   int x, y;
130   Pixmap p2 = XCreatePixmap(dpy, pixmap, pix_w*2, pix_h*2, depth);
131   XImage *i1 = XGetImage(dpy, pixmap, 0, 0, pix_w, pix_h, ~0L, ZPixmap);
132   XImage *i2 = XCreateImage(dpy, visual, depth, ZPixmap, 0, 0,
133                             pix_w*2, pix_h*2, 8, 0);
134   i2->data = (char *) calloc(i2->height, i2->bytes_per_line);
135   for (y = 0; y < pix_h; y++)
136     for (x = 0; x < pix_w; x++)
137       {
138         unsigned long p = XGetPixel(i1, x, y);
139         XPutPixel(i2, x*2,   y*2,   p);
140         XPutPixel(i2, x*2+1, y*2,   p);
141         XPutPixel(i2, x*2,   y*2+1, p);
142         XPutPixel(i2, x*2+1, y*2+1, p);
143       }
144   free(i1->data); i1->data = 0;
145   XDestroyImage(i1);
146   XPutImage(dpy, p2, gc, i2, 0, 0, 0, 0, i2->width, i2->height);
147   free(i2->data); i2->data = 0;
148   XDestroyImage(i2);
149   XFreePixmap(dpy, pixmap);
150   return p2;
151 }
152
153
154 /* Sleep for N seconds and return False.  But if a key or mouse event is
155    seen, discard all pending key or mouse events, and return True.
156  */
157 static Bool
158 bsod_sleep(Display *dpy, int seconds)
159 {
160   int q = seconds * 4;
161   int quantum = 250000;
162
163   if (seconds == -1)
164     q = 1, quantum = 100000;
165
166   do
167     {
168       XSync(dpy, False);
169       while (XPending (dpy))
170         {
171           XEvent event;
172           XNextEvent (dpy, &event);
173           if (event.xany.type == ButtonPress)
174             return True;
175           if (event.xany.type == KeyPress)
176             {
177               KeySym keysym;
178               char c = 0;
179               XLookupString (&event.xkey, &c, 1, &keysym, 0);
180               if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
181                 return True;
182             }
183           screenhack_handle_event (dpy, &event);
184         }
185
186       if (q > 0)
187         {
188           q--;
189           usleep(quantum);
190         }
191     }
192   while (q > 0);
193
194   return False; 
195 }
196
197
198 static Bool
199 windows (Display *dpy, Window window, int delay, Bool w95p)
200 {
201   XGCValues gcv;
202   XWindowAttributes xgwa;
203   char *fontname;
204   const char *def_font = "fixed";
205   XFontStruct *font;
206   GC gc;
207
208   const char *w95 =
209     ("@Windows\n"
210      "A fatal exception 0E has occured at F0AD:42494C4C\n"
211      "the current application will be terminated.\n"
212      "\n"
213      "* Press any key to terminate the current application.\n"
214      "* Press CTRL+ALT+DELETE again to restart your computer.\n"
215      "  You will lose any unsaved information in all applications.\n"
216      "\n"
217      "\n"
218      "_Press any key to continue");
219
220   const char *wnt =
221     ("*** STOP: 0x0000001E (0x80000003,0x80106fc0,0x8025ea21,0xfd6829e8)\n"
222    "Unhandled Kernel exception c0000047 from fa8418b4 (8025ea21,fd6829e8)\n"
223    "\n"
224    "Dll Base Date Stamp - Name             Dll Base Date Stamp - Name\n"
225    "80100000 2be154c9 - ntoskrnl.exe       80400000 2bc153b0 - hal.dll\n"
226    "80258000 2bd49628 - ncrc710.sys        8025c000 2bd49688 - SCSIPORT.SYS \n"
227    "80267000 2bd49683 - scsidisk.sys       802a6000 2bd496b9 - Fastfat.sys\n"
228    "fa800000 2bd49666 - Floppy.SYS         fa810000 2bd496db - Hpfs_Rec.SYS\n"
229    "fa820000 2bd49676 - Null.SYS           fa830000 2bd4965a - Beep.SYS\n"
230    "fa840000 2bdaab00 - i8042prt.SYS       fa850000 2bd5a020 - SERMOUSE.SYS\n"
231    "fa860000 2bd4966f - kbdclass.SYS       fa870000 2bd49671 - MOUCLASS.SYS\n"
232    "fa880000 2bd9c0be - Videoprt.SYS       fa890000 2bd49638 - NCC1701E.SYS\n"
233    "fa8a0000 2bd4a4ce - Vga.SYS            fa8b0000 2bd496d0 - Msfs.SYS\n"
234    "fa8c0000 2bd496c3 - Npfs.SYS           fa8e0000 2bd496c9 - Ntfs.SYS\n"
235    "fa940000 2bd496df - NDIS.SYS           fa930000 2bd49707 - wdlan.sys\n"
236    "fa970000 2bd49712 - TDI.SYS            fa950000 2bd5a7fb - nbf.sys\n"
237    "fa980000 2bd72406 - streams.sys        fa9b0000 2bd4975f - ubnb.sys\n"
238    "fa9c0000 2bd5bfd7 - usbser.sys         fa9d0000 2bd4971d - netbios.sys\n"
239    "fa9e0000 2bd49678 - Parallel.sys       fa9f0000 2bd4969f - serial.SYS\n"
240    "faa00000 2bd49739 - mup.sys            faa40000 2bd4971f - SMBTRSUP.SYS\n"
241    "faa10000 2bd6f2a2 - srv.sys            faa50000 2bd4971a - afd.sys\n"
242    "faa60000 2bd6fd80 - rdr.sys            faaa0000 2bd49735 - bowser.sys\n"
243    "\n"
244    "Address dword dump Dll Base                                      - Name\n"
245    "801afc20 80106fc0 80106fc0 00000000 00000000 80149905 : "
246      "fa840000 - i8042prt.SYS\n"
247    "801afc24 80149905 80149905 ff8e6b8c 80129c2c ff8e6b94 : "
248      "8025c000 - SCSIPORT.SYS\n"
249    "801afc2c 80129c2c 80129c2c ff8e6b94 00000000 ff8e6b94 : "
250      "80100000 - ntoskrnl.exe\n"
251    "801afc34 801240f2 80124f02 ff8e6df4 ff8e6f60 ff8e6c58 : "
252      "80100000 - ntoskrnl.exe\n"
253    "801afc54 80124f16 80124f16 ff8e6f60 ff8e6c3c 8015ac7e : "
254      "80100000 - ntoskrnl.exe\n"
255    "801afc64 8015ac7e 8015ac7e ff8e6df4 ff8e6f60 ff8e6c58 : "
256      "80100000 - ntoskrnl.exe\n"
257    "801afc70 80129bda 80129bda 00000000 80088000 80106fc0 : "
258      "80100000 - ntoskrnl.exe\n"
259    "\n"
260    "Kernel Debugger Using: COM2 (Port 0x2f8, Baud Rate 19200)\n"
261    "Restart and set the recovery options in the system control panel\n"
262    "or the /CRASHDEBUG system start option. If this message reappears,\n"
263    "contact your system administrator or technical support group."
264      );
265
266   if (!get_boolean_resource((w95p? "doWindows" : "doNT"), "DoWindows"))
267     return False;
268
269   XGetWindowAttributes (dpy, window, &xgwa);
270
271   fontname = get_string_resource ((xgwa.height > 600
272                                    ? (w95p
273                                       ? "windows95.font2"
274                                       : "windowsNT.font2")
275                                    : (w95p
276                                       ? "windows95.font"
277                                       : "windowsNT.font")),
278                                   "Windows.Font");
279   if (!fontname || !*fontname) fontname = (char *)def_font;
280   font = XLoadQueryFont (dpy, fontname);
281   if (!font) font = XLoadQueryFont (dpy, def_font);
282   if (!font) exit(-1);
283   if (fontname && fontname != def_font)
284     free (fontname);
285
286   gcv.font = font->fid;
287   gcv.foreground = get_pixel_resource((w95p
288                                        ? "windows95.foreground"
289                                        : "windowsNT.foreground"),
290                                       "Windows.Foreground",
291                                       dpy, xgwa.colormap);
292   gcv.background = get_pixel_resource((w95p
293                                        ? "windows95.background"
294                                        : "windowsNT.background"),
295                                       "Windows.Background",
296                                       dpy, xgwa.colormap);
297   XSetWindowBackground(dpy, window, gcv.background);
298   XClearWindow(dpy, window);
299
300   gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
301
302   if (w95p)
303     draw_string(dpy, window, gc, &gcv, font,
304                 0, 0, xgwa.width, xgwa.height, w95, 0);
305   else
306     draw_string(dpy, window, gc, &gcv, font, 0, 0, 10, 10, wnt, 750);
307
308   XFreeGC(dpy, gc);
309   XSync(dpy, False);
310   bsod_sleep(dpy, delay);
311   XClearWindow(dpy, window);
312   XFreeFont(dpy, font);
313   return True;
314 }
315
316 /* SCO OpenServer 5 panic, by Tom Kelly <tom@ancilla.toronto.on.ca>
317  */
318 static Bool
319 sco (Display *dpy, Window window, int delay)
320 {
321   XGCValues gcv;
322   XWindowAttributes xgwa;
323   char *fontname;
324   const char *def_font = "fixed";
325   XFontStruct *font;
326   GC gc;
327   int lines_1 = 0, lines_2 = 0, lines_3 = 0, lines_4 = 0;
328   const char *s;
329
330   const char *sco_panic_1 =
331     ("Unexpected trap in kernel mode:\n"
332      "\n"
333      "cr0 0x80010013     cr2  0x00000014     cr3 0x00000000  tlb  0x00000000\n"
334      "ss  0x00071054    uesp  0x00012055     efl 0x00080888  ipl  0x00000005\n"
335      "cs  0x00092585     eip  0x00544a4b     err 0x004d4a47  trap 0x0000000E\n"
336      "eax 0x0045474b     ecx  0x0042544b     edx 0x57687920  ebx  0x61726520\n"
337      "esp 0x796f7520     ebp  0x72656164     esi 0x696e6720  edi  0x74686973\n"
338      "ds  0x3f000000     es   0x43494c48     fs  0x43525343  gs   0x4f4d4b53\n"
339      "\n"
340      "PANIC: k_trap - kernel mode trap type 0x0000000E\n"
341      "Trying to dump 5023 pages to dumpdev hd (1/41), 63 pages per '.'\n"
342     );
343   const char *sco_panic_2 =
344    ("...............................................................................\n"
345     );
346   const char *sco_panic_3 =
347     ("5023 pages dumped\n"
348      "\n"
349      "\n"
350      );
351   const char *sco_panic_4 =
352     ("**   Safe to Power Off   **\n"
353      "           - or -\n"
354      "** Press Any Key to Reboot **\n"
355     );
356
357   if (!get_boolean_resource("doSCO", "DoSCO"))
358     return False;
359
360   for (s = sco_panic_1; *s; s++) if (*s == '\n') lines_1++;
361   for (s = sco_panic_2; *s; s++) if (*s == '\n') lines_2++;
362   for (s = sco_panic_3; *s; s++) if (*s == '\n') lines_3++;
363   for (s = sco_panic_4; *s; s++) if (*s == '\n') lines_4++;
364
365   XGetWindowAttributes (dpy, window, &xgwa);
366
367   fontname = get_string_resource ((xgwa.height > 600
368                                    ? "sco.font2"
369                                    : "sco.font"),
370                                   "SCO.Font");
371   if (!fontname || !*fontname) fontname = (char *)def_font;
372   font = XLoadQueryFont (dpy, fontname);
373   if (!font) font = XLoadQueryFont (dpy, def_font);
374   if (!font) exit(-1);
375   if (fontname && fontname != def_font)
376     free (fontname);
377
378   gcv.font = font->fid;
379   gcv.foreground = get_pixel_resource(("sco.foreground"),
380                                       "SCO.Foreground",
381                                       dpy, xgwa.colormap);
382   gcv.background = get_pixel_resource(("sco.background"),
383                                       "SCO.Background",
384                                       dpy, xgwa.colormap);
385   XSetWindowBackground(dpy, window, gcv.background);
386   XClearWindow(dpy, window);
387
388   gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
389
390   draw_string(dpy, window, gc, &gcv, font,
391               10, xgwa.height - ((lines_1 + lines_2 + lines_3 + lines_4 + 1) *
392                                  (font->ascent + font->descent + 1)),
393               10, 10,
394               sco_panic_1, 0);
395   XSync(dpy, False);
396   for (s = sco_panic_2; *s; s++)
397     {
398       char *ss = strdup(sco_panic_2);
399       ss[s - sco_panic_2] = 0;
400       draw_string(dpy, window, gc, &gcv, font,
401                   10, xgwa.height - ((lines_2 + lines_3 + lines_4 + 1) *
402                                      (font->ascent + font->descent + 1)),
403                   10, 10,
404                   ss, 0);
405       XSync(dpy, False);
406       free(ss);
407       if (bsod_sleep (dpy, -1))
408         goto DONE;
409     }
410
411   draw_string(dpy, window, gc, &gcv, font,
412               10, xgwa.height - ((lines_3 + lines_4 + 1) *
413                                  (font->ascent + font->descent + 1)),
414               10, 10,
415               sco_panic_3, 0);
416   XSync(dpy, False);
417   if (bsod_sleep(dpy, 1))
418     goto DONE;
419   draw_string(dpy, window, gc, &gcv, font,
420               10, xgwa.height - ((lines_4 + 1) *
421                                  (font->ascent + font->descent + 1)),
422               10, 10,
423               sco_panic_4, 0);
424   XSync(dpy, False);
425
426   bsod_sleep(dpy, delay);
427  DONE:
428   XClearWindow(dpy, window);
429   XFreeGC(dpy, gc);
430   XFreeFont(dpy, font);
431   return True;
432 }
433
434
435 /* Linux (sparc) panic, by Tom Kelly <tom@ancilla.toronto.on.ca>
436  */
437 static Bool
438 sparc_linux (Display *dpy, Window window, int delay)
439 {
440   XGCValues gcv;
441   XWindowAttributes xgwa;
442   char *fontname;
443   const char *def_font = "fixed";
444   XFontStruct *font;
445   GC gc;
446   int lines = 1;
447   const char *s;
448
449   const char *linux_panic =
450     ("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
451         "Unable to handle kernel paging request at virtual address f0d4a000\n"
452         "tsk->mm->context = 00000014\n"
453         "tsk->mm->pgd = f26b0000\n"
454         "              \\|/ ____ \\|/\n"
455         "              \"@'/ ,. \\`@\"\n"
456         "              /_| \\__/ |_\\\n"
457         "                 \\__U_/\n"
458         "gawk(22827): Oops\n"
459         "PSR: 044010c1 PC: f001c2cc NPC: f001c2d0 Y: 00000000\n"
460         "g0: 00001000 g1: fffffff7 g2: 04401086 g3: 0001eaa0\n"
461         "g4: 000207dc g5: f0130400 g6: f0d4a018 g7: 00000001\n"
462         "o0: 00000000 o1: f0d4a298 o2: 00000040 o3: f1380718\n"
463         "o4: f1380718 o5: 00000200 sp: f1b13f08 ret_pc: f001c2a0\n"
464         "l0: efffd880 l1: 00000001 l2: f0d4a230 l3: 00000014\n"
465         "l4: 0000ffff l5: f0131550 l6: f012c000 l7: f0130400\n"
466         "i0: f1b13fb0 i1: 00000001 i2: 00000002 i3: 0007c000\n"
467         "i4: f01457c0 i5: 00000004 i6: f1b13f70 i7: f0015360\n"
468         "Instruction DUMP:\n"
469     );
470
471   if (!get_boolean_resource("doSparcLinux", "DoSparcLinux"))
472     return False;
473
474   for (s = linux_panic; *s; s++) if (*s == '\n') lines++;
475
476   XGetWindowAttributes (dpy, window, &xgwa);
477
478   fontname = get_string_resource ((xgwa.height > 600
479                                    ? "sparclinux.font2"
480                                    : "sparclinux.font"),
481                                   "SparcLinux.Font");
482   if (!fontname || !*fontname) fontname = (char *)def_font;
483   font = XLoadQueryFont (dpy, fontname);
484   if (!font) font = XLoadQueryFont (dpy, def_font);
485   if (!font) exit(-1);
486   if (fontname && fontname != def_font)
487     free (fontname);
488
489   gcv.font = font->fid;
490   gcv.foreground = get_pixel_resource(("sparclinux.foreground"),
491                                       "SparcLinux.Foreground",
492                                       dpy, xgwa.colormap);
493   gcv.background = get_pixel_resource(("sparclinux.background"),
494                                       "SparcLinux.Background",
495                                       dpy, xgwa.colormap);
496   XSetWindowBackground(dpy, window, gcv.background);
497   XClearWindow(dpy, window);
498
499   gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
500
501   draw_string(dpy, window, gc, &gcv, font,
502               10, xgwa.height - (lines * (font->ascent + font->descent + 1)),
503               10, 10,
504               linux_panic, 0);
505   XFreeGC(dpy, gc);
506   XSync(dpy, False);
507   bsod_sleep(dpy, delay);
508   XClearWindow(dpy, window);
509   XFreeFont(dpy, font);
510   return True;
511 }
512
513 static Bool
514 amiga (Display *dpy, Window window, int delay)
515 {
516   XGCValues gcv;
517   XWindowAttributes xgwa;
518   char *fontname;
519   const char *def_font = "fixed";
520   XFontStruct *font;
521   GC gc, gc2;
522   int height;
523   unsigned long fg, bg, bg2;
524   Pixmap pixmap = 0;
525   int pix_w = 0, pix_h = 0;
526
527   const char *string =
528     ("_Software failure.  Press left mouse button to continue.\n"
529      "_Guru Meditation #00000003.00C01570");
530
531   if (!get_boolean_resource("doAmiga", "DoAmiga"))
532     return False;
533
534   XGetWindowAttributes (dpy, window, &xgwa);
535
536   fontname = get_string_resource ((xgwa.height > 600
537                                    ? "amiga.font2" : "amiga.font"),
538                                   "Amiga.Font");
539   if (!fontname || !*fontname) fontname = (char *)def_font;
540   font = XLoadQueryFont (dpy, fontname);
541   if (!font) font = XLoadQueryFont (dpy, def_font);
542   if (!font) exit(-1);
543   if (fontname && fontname != def_font)
544     free (fontname);
545
546   gcv.font = font->fid;
547   fg = gcv.foreground = get_pixel_resource("amiga.foreground",
548                                            "Amiga.Foreground",
549                                            dpy, xgwa.colormap);
550   bg = gcv.background = get_pixel_resource("amiga.background",
551                                            "Amiga.Background",
552                                            dpy, xgwa.colormap);
553   bg2 = get_pixel_resource("amiga.background2", "Amiga.Background",
554                            dpy, xgwa.colormap);
555   XSetWindowBackground(dpy, window, bg2);
556   XClearWindow(dpy, window);
557
558   gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
559   gcv.background = fg; gcv.foreground = bg;
560   gc2 = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
561
562   height = (font->ascent + font->descent) * 6;
563
564 #ifdef HAVE_XPM
565   {
566     XpmAttributes xpmattrs;
567     int result;
568     xpmattrs.valuemask = 0;
569
570 # ifdef XpmCloseness
571     xpmattrs.valuemask |= XpmCloseness;
572     xpmattrs.closeness = 40000;
573 # endif
574 # ifdef XpmVisual
575     xpmattrs.valuemask |= XpmVisual;
576     xpmattrs.visual = xgwa.visual;
577 # endif
578 # ifdef XpmDepth
579     xpmattrs.valuemask |= XpmDepth;
580     xpmattrs.depth = xgwa.depth;
581 # endif
582 # ifdef XpmColormap
583     xpmattrs.valuemask |= XpmColormap;
584     xpmattrs.colormap = xgwa.colormap;
585 # endif
586
587     result = XpmCreatePixmapFromData(dpy, window, amiga_hand,
588                                      &pixmap, 0 /* mask */, &xpmattrs);
589     if (!pixmap || (result != XpmSuccess && result != XpmColorError))
590       pixmap = 0;
591     pix_w = xpmattrs.width;
592     pix_h = xpmattrs.height;
593   }
594 #endif /* HAVE_XPM */
595
596   if (pixmap && xgwa.height > 600)      /* scale up the bitmap */
597     {
598       pixmap = double_pixmap(dpy, gc, xgwa.visual, xgwa.depth,
599                              pixmap, pix_w, pix_h);
600       pix_w *= 2;
601       pix_h *= 2;
602     }
603
604   if (pixmap)
605     {
606       int x = (xgwa.width - pix_w) / 2;
607       int y = ((xgwa.height - pix_h) / 2);
608       XCopyArea(dpy, pixmap, window, gc, 0, 0, pix_w, pix_h, x, y);
609
610       XSync(dpy, False);
611       bsod_sleep(dpy, 2);
612
613       XCopyArea(dpy, pixmap, window, gc, 0, 0, pix_w, pix_h, x, y + height);
614       XClearArea(dpy, window, 0, 0, xgwa.width, y + height, False);
615       XFreePixmap(dpy, pixmap);
616     }
617
618   XFillRectangle(dpy, window, gc2, 0, 0, xgwa.width, height);
619   draw_string(dpy, window, gc, &gcv, font, 0, 0, xgwa.width, height, string,0);
620
621   {
622     GC gca = gc;
623     while (delay > 0)
624       {
625         XFillRectangle(dpy, window, gca, 0, 0, xgwa.width, font->ascent);
626         XFillRectangle(dpy, window, gca, 0, 0, font->ascent, height);
627         XFillRectangle(dpy, window, gca, xgwa.width-font->ascent, 0,
628                        font->ascent, height);
629         XFillRectangle(dpy, window, gca, 0, height-font->ascent, xgwa.width,
630                        font->ascent);
631         gca = (gca == gc ? gc2 : gc);
632         XSync(dpy, False);
633         if (bsod_sleep(dpy, 1))
634           break;
635         delay--;
636       }
637   }
638
639   XFreeGC(dpy, gc);
640   XFreeGC(dpy, gc2);
641   XSync(dpy, False);
642   XClearWindow(dpy, window);
643   XFreeFont(dpy, font);
644   return True;
645 }
646
647
648 /* Atari ST, by Marcus Herbert <rhoenie@nobiscum.de>
649    Marcus had this to say:
650
651         Though I still have my Atari somewhere, I hardly remember
652         the meaning of the bombs. I think 9 bombs was "bus error" or
653         something like that.  And you often had a few bombs displayed
654         quickly and then the next few ones coming up step by step.
655         Perhaps somebody else can tell you more about it..  its just
656         a quick hack :-}
657  */
658 static Bool
659 atari (Display *dpy, Window window, int delay)
660 {
661         
662   XGCValues gcv;
663   XWindowAttributes xgwa;
664   const char *def_font = "fixed";
665   XFontStruct *font;
666   GC gc;
667   Pixmap pixmap = 0;
668   int pix_w = atari_width;
669   int pix_h = atari_height;
670   int offset;
671   int i, x, y;
672
673   if (!get_boolean_resource("doAtari", "DoAtari"))
674     return False;
675
676   XGetWindowAttributes (dpy, window, &xgwa);
677
678   font = XLoadQueryFont (dpy, def_font);
679   if (!font) exit(-1);
680                 
681   gcv.font = font->fid;
682   gcv.foreground = get_pixel_resource("atari.foreground", "Atari.Foreground",
683                                       dpy, xgwa.colormap);
684   gcv.background = get_pixel_resource("atari.background", "Atari.Background",
685                                       dpy, xgwa.colormap);
686
687   XSetWindowBackground(dpy, window, gcv.background);
688   XClearWindow(dpy, window);
689
690   gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
691
692   pixmap = XCreatePixmapFromBitmapData(dpy, window, (char *) atari_bits,
693                                        pix_w, pix_h,
694                                        gcv.foreground, gcv.background,
695                                        xgwa.depth);
696   pixmap = double_pixmap(dpy, gc, xgwa.visual, xgwa.depth,
697                          pixmap, pix_w, pix_h);
698   pix_w *= 2;
699   pix_h *= 2;
700
701   offset = pix_w + 2;
702   x = 5;
703   y = (xgwa.height - (xgwa.height / 5));
704   if (y < 0) y = 0;
705
706   for (i=0 ; i<7 ; i++) {
707     XCopyArea(dpy, pixmap, window, gc, 0, 0, pix_w, pix_h,
708               (x + (i*offset)), y);
709   }  
710   
711   for (i=7 ; i<10 ; i++) {
712     if (bsod_sleep(dpy, 1))
713       goto DONE;
714     XCopyArea(dpy, pixmap, window, gc, 0, 0, pix_w, pix_h,
715               (x + (i*offset)), y);
716   }
717
718   bsod_sleep(dpy, delay);
719  DONE:
720   XFreePixmap(dpy, pixmap);
721   XFreeGC(dpy, gc);
722   XSync(dpy, False);
723   XClearWindow(dpy, window);
724   XFreeFont(dpy, font);
725   return True;
726 }
727
728
729 static Bool
730 mac (Display *dpy, Window window, int delay)
731 {
732   XGCValues gcv;
733   XWindowAttributes xgwa;
734   char *fontname;
735   const char *def_font = "fixed";
736   XFontStruct *font;
737   GC gc;
738   Pixmap pixmap = 0;
739   int pix_w = mac_width;
740   int pix_h = mac_height;
741   int offset = mac_height * 4;
742   int i;
743
744   const char *string = ("0 0 0 0 0 0 0 F\n"
745                         "0 0 0 0 0 0 0 3");
746
747   if (!get_boolean_resource("doMac", "DoMac"))
748     return False;
749
750   XGetWindowAttributes (dpy, window, &xgwa);
751
752   fontname = get_string_resource ("mac.font", "Mac.Font");
753   if (!fontname || !*fontname) fontname = (char *)def_font;
754   font = XLoadQueryFont (dpy, fontname);
755   if (!font) font = XLoadQueryFont (dpy, def_font);
756   if (!font) exit(-1);
757   if (fontname && fontname != def_font)
758     free (fontname);
759
760   gcv.font = font->fid;
761   gcv.foreground = get_pixel_resource("mac.foreground", "Mac.Foreground",
762                                       dpy, xgwa.colormap);
763   gcv.background = get_pixel_resource("mac.background", "Mac.Background",
764                                       dpy, xgwa.colormap);
765   XSetWindowBackground(dpy, window, gcv.background);
766   XClearWindow(dpy, window);
767
768   gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
769
770   pixmap = XCreatePixmapFromBitmapData(dpy, window, (char *) mac_bits,
771                                        mac_width, mac_height,
772                                        gcv.foreground,
773                                        gcv.background,
774                                        xgwa.depth);
775
776   for(i = 0; i < 2; i++)
777     {
778       pixmap = double_pixmap(dpy, gc, xgwa.visual, xgwa.depth,
779                              pixmap, pix_w, pix_h);
780       pix_w *= 2; pix_h *= 2;
781     }
782
783   {
784     int x = (xgwa.width - pix_w) / 2;
785     int y = (((xgwa.height + offset) / 2) -
786              pix_h -
787              (font->ascent + font->descent) * 2);
788     if (y < 0) y = 0;
789     XCopyArea(dpy, pixmap, window, gc, 0, 0, pix_w, pix_h, x, y);
790     XFreePixmap(dpy, pixmap);
791   }
792
793   draw_string(dpy, window, gc, &gcv, font, 0, 0,
794               xgwa.width, xgwa.height + offset, string, 0);
795
796   XFreeGC(dpy, gc);
797   XSync(dpy, False);
798   bsod_sleep(dpy, delay);
799   XClearWindow(dpy, window);
800   XFreeFont(dpy, font);
801   return True;
802 }
803
804 static Bool
805 macsbug (Display *dpy, Window window, int delay)
806 {
807   XGCValues gcv;
808   XWindowAttributes xgwa;
809   char *fontname;
810   const char *def_font = "fixed";
811   XFontStruct *font;
812   GC gc, gc2;
813
814   int char_width, line_height;
815   int col_right, row_top, row_bottom, page_right, page_bottom, body_top;
816   int xoff, yoff;
817
818   const char *left = ("    SP     \n"
819                       " 04EB0A58  \n"
820                       "58 00010000\n"
821                       "5C 00010000\n"
822                       "   ........\n"
823                       "60 00000000\n"
824                       "64 000004EB\n"
825                       "   ........\n"
826                       "68 0000027F\n"
827                       "6C 2D980035\n"
828                       "   ....-..5\n"
829                       "70 00000054\n"
830                       "74 0173003E\n"
831                       "   ...T.s.>\n"
832                       "78 04EBDA76\n"
833                       "7C 04EBDA8E\n"
834                       "   .S.L.a.U\n"
835                       "80 00000000\n"
836                       "84 000004EB\n"
837                       "   ........\n"
838                       "88 00010000\n"
839                       "8C 00010000\n"
840                       "   ...{3..S\n"
841                       "\n"
842                       "\n"
843                       " CurApName \n"
844                       "  Finder   \n"
845                       "\n"
846                       " 32-bit VM \n"
847                       "SR Smxnzvc0\n"
848                       "D0 04EC0062\n"
849                       "D1 00000053\n"
850                       "D2 FFFF0100\n"
851                       "D3 00010000\n"
852                       "D4 00010000\n"
853                       "D5 04EBDA76\n"
854                       "D6 04EBDA8E\n"
855                       "D7 00000001\n"
856                       "\n"
857                       "A0 04EBDA76\n"
858                       "A1 04EBDA8E\n"
859                       "A2 A0A00060\n"
860                       "A3 027F2D98\n"
861                       "A4 027F2E58\n"
862                       "A5 04EC04F0\n"
863                       "A6 04EB0A86\n"
864                       "A7 04EB0A58");
865   const char *bottom = ("  _A09D\n"
866                         "     +00884    40843714     #$0700,SR         "
867                         "                  ; A973        | A973\n"
868                         "     +00886    40843765     *+$0400           "
869                         "                                | 4A1F\n"
870                         "     +00888    40843718     $0004(A7),([0,A7[)"
871                         "                  ; 04E8D0AE    | 66B8");
872
873 #if 0
874   const char *body = ("Bus Error at 4BF6D6CC\n"
875                       "while reading word from 4BF6D6CC in User data space\n"
876                       " Unable to access that address\n"
877                       "  PC: 2A0DE3E6\n"
878                       "  Frame Type: B008");
879 #else
880   const char * body = ("PowerPC unmapped memory exception at 003AFDAC "
881                                                 "BowelsOfTheMemoryMgr+04F9C\n"
882                       " Calling chain using A6/R1 links\n"
883                       "  Back chain  ISA  Caller\n"
884                       "  00000000    PPC  28C5353C  __start+00054\n"
885                       "  24DB03C0    PPC  28B9258C  main+0039C\n"
886                       "  24DB0350    PPC  28B9210C  MainEvent+00494\n"
887                       "  24DB02B0    PPC  28B91B40  HandleEvent+00278\n"
888                       "  24DB0250    PPC  28B83DAC  DoAppleEvent+00020\n"
889                       "  24DB0210    PPC  FFD3E5D0  "
890                                                 "AEProcessAppleEvent+00020\n"
891                       "  24DB0132    68K  00589468\n"
892                       "  24DAFF8C    68K  00589582\n"
893                       "  24DAFF26    68K  00588F70\n"
894                       "  24DAFEB3    PPC  00307098  "
895                                                 "EmToNatEndMoveParams+00014\n"
896                       "  24DAFE40    PPC  28B9D0B0  DoScript+001C4\n"
897                       "  24DAFDD0    PPC  28B9C35C  RunScript+00390\n"
898                       "  24DAFC60    PPC  28BA36D4  run_perl+000E0\n"
899                       "  24DAFC10    PPC  28BC2904  perl_run+002CC\n"
900                       "  24DAFA80    PPC  28C18490  Perl_runops+00068\n"
901                       "  24DAFA30    PPC  28BE6CC0  Perl_pp_backtick+000FC\n"
902                       "  24DAF9D0    PPC  28BA48B8  Perl_my_popen+00158\n"
903                       "  24DAF980    PPC  28C5395C  sfclose+00378\n"
904                       "  24DAF930    PPC  28BA568C  free+0000C\n"
905                       "  24DAF8F0    PPC  28BA6254  pool_free+001D0\n"
906                       "  24DAF8A0    PPC  FFD48F14  DisposePtr+00028\n"
907                       "  24DAF7C9    PPC  00307098  "
908                                                 "EmToNatEndMoveParams+00014\n"
909                       "  24DAF780    PPC  003AA180  __DisposePtr+00010");
910 #endif
911
912   const char *s;
913   int body_lines = 1;
914
915   if (!get_boolean_resource("doMacsBug", "DoMacsBug"))
916     return False;
917
918   for (s = body; *s; s++) if (*s == '\n') body_lines++;
919
920   XGetWindowAttributes (dpy, window, &xgwa);
921
922   fontname = get_string_resource ((xgwa.height > 850
923                                    ? "macsbug.font3"
924                                    : (xgwa.height > 700
925                                       ? "macsbug.font2"
926                                       : "macsbug.font")),
927                                   "MacsBug.Font");
928   if (!fontname || !*fontname) fontname = (char *)def_font;
929   font = XLoadQueryFont (dpy, fontname);
930   if (!font) font = XLoadQueryFont (dpy, def_font);
931   if (!font) exit(-1);
932   if (fontname && fontname != def_font)
933     free (fontname);
934
935   gcv.font = font->fid;
936   gcv.foreground = get_pixel_resource("macsbug.foreground",
937                                       "MacsBug.Foreground",
938                                       dpy, xgwa.colormap);
939   gcv.background = get_pixel_resource("macsbug.background",
940                                       "MacsBug.Background",
941                                       dpy, xgwa.colormap);
942
943   gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
944
945   gcv.foreground = gcv.background;
946   gc2 = XCreateGC(dpy, window, GCForeground, &gcv);
947
948   XSetWindowBackground(dpy, window,
949                        get_pixel_resource("macsbug.borderColor",
950                                           "MacsBug.BorderColor",
951                                           dpy, xgwa.colormap));
952   XClearWindow(dpy, window);
953
954   char_width = (font->per_char
955                 ? font->per_char['n'-font->min_char_or_byte2].width
956                 : font->min_bounds.width);
957   line_height = font->ascent + font->descent + 1;
958
959   col_right = char_width * 12;
960   page_bottom = line_height * 47;
961
962   if (page_bottom > xgwa.height) page_bottom = xgwa.height;
963
964   row_bottom = page_bottom - line_height;
965   row_top = row_bottom - (line_height * 4);
966   page_right = col_right + (char_width * 88);
967   body_top = row_top - (line_height * body_lines);
968
969   page_bottom += 2;
970   row_bottom += 2;
971   body_top -= 4;
972
973   xoff = (xgwa.width - page_right) / 2;
974   yoff = (xgwa.height - page_bottom) / 2;
975   if (xoff < 0) xoff = 0;
976   if (yoff < 0) yoff = 0;
977
978   XFillRectangle(dpy, window, gc2, xoff, yoff, page_right, page_bottom);
979
980   draw_string(dpy, window, gc, &gcv, font, xoff, yoff, 10, 10, left, 0);
981   draw_string(dpy, window, gc, &gcv, font, xoff+col_right, yoff+row_top,
982               10, 10, bottom, 0);
983
984   XFillRectangle(dpy, window, gc, xoff + col_right, yoff, 2, page_bottom);
985   XDrawLine(dpy, window, gc,
986             xoff+col_right, yoff+row_top, xoff+page_right, yoff+row_top);
987   XDrawLine(dpy, window, gc,
988             xoff+col_right, yoff+row_bottom, xoff+page_right, yoff+row_bottom);
989   XDrawRectangle(dpy, window, gc,  xoff, yoff, page_right, page_bottom);
990
991   if (body_top > 4)
992     body_top = 4;
993
994   draw_string(dpy, window, gc, &gcv, font,
995               xoff + col_right + char_width, yoff + body_top, 10, 10, body,
996               500);
997
998   while (delay > 0)
999     {
1000       XDrawLine(dpy, window, gc,
1001                 xoff+col_right+(char_width/2)+2, yoff+row_bottom+3,
1002                 xoff+col_right+(char_width/2)+2, yoff+page_bottom-3);
1003       XSync(dpy, False);
1004       usleep(666666L);
1005       XDrawLine(dpy, window, gc2,
1006                 xoff+col_right+(char_width/2)+2, yoff+row_bottom+3,
1007                 xoff+col_right+(char_width/2)+2, yoff+page_bottom-3);
1008       XSync(dpy, False);
1009       usleep(333333L);
1010       if (bsod_sleep(dpy, 0))
1011         break;
1012       delay--;
1013     }
1014
1015   XFreeGC(dpy, gc);
1016   XFreeGC(dpy, gc2);
1017   XClearWindow(dpy, window);
1018   XFreeFont(dpy, font);
1019   return True;
1020 }
1021
1022
1023 \f
1024 char *progclass = "BSOD";
1025
1026 char *defaults [] = {
1027   "*delay:                 30",
1028
1029   "*doWindows:             True",
1030   "*doNT:                  True",
1031   "*doAmiga:               True",
1032   "*doMac:                 True",
1033   "*doAtari:               False",      /* boring */
1034   "*doMacsBug:             True",
1035   "*doSCO:                 True",
1036   "*doSparcLinux:          False",      /* boring */
1037
1038   ".Windows.font:          -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
1039   ".Windows.font2:         -*-courier-bold-r-*-*-*-180-*-*-m-*-*-*",
1040   ".Windows.foreground:    White",
1041   ".Windows.background:    Blue",
1042
1043   ".Amiga.font:            -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
1044   ".Amiga.font2:           -*-courier-bold-r-*-*-*-180-*-*-m-*-*-*",
1045   ".Amiga.foreground:      Red",
1046   ".Amiga.background:      Black",
1047   ".Amiga.background2:     White",
1048
1049   ".Mac.font:              -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
1050   ".Mac.foreground:        PaleTurquoise1",
1051   ".Mac.background:        Black",
1052
1053   ".Atari.foreground:      Black",
1054   ".Atari.background:      White",
1055
1056   ".MacsBug.font:          -*-courier-medium-r-*-*-*-100-*-*-m-*-*-*",
1057   ".MacsBug.font2:         -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
1058   ".MacsBug.font3:         -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
1059   ".MacsBug.foreground:    Black",
1060   ".MacsBug.background:    White",
1061   ".MacsBug.borderColor:   #AAAAAA",
1062   
1063   ".SCO.font:              -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
1064   ".SCO.font2:             -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
1065   ".SCO.foreground:        White",
1066   ".SCO.background:        Black",
1067   
1068   ".SparcLinux.font:       -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
1069   ".SparcLinux.font2:      -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
1070   ".SparcLinux.foreground: White",
1071   ".SparcLinux.background: Black",
1072   0
1073 };
1074
1075 XrmOptionDescRec options [] = {
1076   { "-delay",           ".delay",               XrmoptionSepArg, 0 },
1077   { 0, 0, 0, 0 }
1078 };
1079
1080
1081 void
1082 screenhack (Display *dpy, Window window)
1083 {
1084   int loop = 0;
1085   int i = -1;
1086   int j = -1;
1087   int delay = get_integer_resource ("delay", "Integer");
1088   if (delay < 3) delay = 3;
1089
1090   if (!get_boolean_resource ("root", "Boolean"))
1091     {
1092       XWindowAttributes xgwa;
1093       XGetWindowAttributes (dpy, window, &xgwa);
1094       XSelectInput (dpy, window,
1095                     xgwa.your_event_mask | KeyPressMask | ButtonPressMask);
1096     }
1097
1098   while (1)
1099     {
1100       Bool did;
1101       do {  i = (random() & 0xFF) % 8; } while (i == j);
1102       switch (i)
1103         {
1104         case 0: did = windows(dpy, window, delay, True); break;
1105         case 1: did = windows(dpy, window, delay, False); break;
1106         case 2: did = amiga(dpy, window, delay); break;
1107         case 3: did = mac(dpy, window, delay); break;
1108         case 4: did = macsbug(dpy, window, delay); break;
1109         case 5: did = sco(dpy, window, delay); break;
1110         case 6: did = sparc_linux(dpy, window, delay); break;
1111         case 7: did = atari(dpy, window, delay); break;
1112         default: abort(); break;
1113         }
1114       loop++;
1115       if (loop > 100) j = -1;
1116       if (loop > 200) exit(-1);
1117       if (!did) continue;
1118       XSync (dpy, False);
1119       j = i;
1120       loop = 0;
1121     }
1122 }