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