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