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