http://ftp.x.org/contrib/applications/xscreensaver-2.23.tar.gz
[xscreensaver] / hacks / bsod.c
1 /* xscreensaver, Copyright (c) 1998 Jamie Zawinski <jwz@netscape.com>
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/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 = (unsigned 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 void
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   XGetWindowAttributes (dpy, window, &xgwa);
253
254   fontname = get_string_resource ((xgwa.height > 600
255                                    ? (w95p
256                                       ? "windows95.font2"
257                                       : "windowsNT.font2")
258                                    : (w95p
259                                       ? "windows95.font"
260                                       : "windowsNT.font")),
261                                   "Windows.Font");
262   if (!fontname || !*fontname) fontname = (char *)def_font;
263   font = XLoadQueryFont (dpy, fontname);
264   if (!font) font = XLoadQueryFont (dpy, def_font);
265   if (!font) exit(-1);
266   if (fontname && fontname != def_font)
267     free (fontname);
268
269   gcv.font = font->fid;
270   gcv.foreground = get_pixel_resource((w95p
271                                        ? "windows95.foreground"
272                                        : "windowsNT.foreground"),
273                                       "Windows.Foreground",
274                                       dpy, xgwa.colormap);
275   gcv.background = get_pixel_resource((w95p
276                                        ? "windows95.background"
277                                        : "windowsNT.background"),
278                                       "Windows.Background",
279                                       dpy, xgwa.colormap);
280   XSetWindowBackground(dpy, window, gcv.background);
281   XClearWindow(dpy, window);
282
283   gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
284
285   if (w95p)
286     draw_string(dpy, window, gc, &gcv, font,
287                 0, 0, xgwa.width, xgwa.height, w95, 0);
288   else
289     draw_string(dpy, window, gc, &gcv, font, 0, 0, 10, 10, wnt, 750);
290
291   XFreeGC(dpy, gc);
292   XSync(dpy, False);
293   bsod_sleep(dpy, delay);
294   XClearWindow(dpy, window);
295   XFreeFont(dpy, font);
296 }
297
298 static void
299 amiga (Display *dpy, Window window, int delay)
300 {
301   XGCValues gcv;
302   XWindowAttributes xgwa;
303   char *fontname;
304   const char *def_font = "fixed";
305   XFontStruct *font;
306   GC gc, gc2;
307   int height;
308   unsigned long fg, bg, bg2;
309   Pixmap pixmap = 0;
310   int pix_w, pix_h;
311
312   const char *string =
313     ("_Software failure.  Press left mouse button to continue.\n"
314      "_Guru Meditation #00000003.00C01570");
315
316   XGetWindowAttributes (dpy, window, &xgwa);
317
318   fontname = get_string_resource ((xgwa.height > 600
319                                    ? "amiga.font2" : "amiga.font"),
320                                   "Amiga.Font");
321   if (!fontname || !*fontname) fontname = (char *)def_font;
322   font = XLoadQueryFont (dpy, fontname);
323   if (!font) font = XLoadQueryFont (dpy, def_font);
324   if (!font) exit(-1);
325   if (fontname && fontname != def_font)
326     free (fontname);
327
328   gcv.font = font->fid;
329   fg = gcv.foreground = get_pixel_resource("amiga.foreground",
330                                            "Amiga.Foreground",
331                                            dpy, xgwa.colormap);
332   bg = gcv.background = get_pixel_resource("amiga.background",
333                                            "Amiga.Background",
334                                            dpy, xgwa.colormap);
335   bg2 = get_pixel_resource("amiga.background2", "Amiga.Background",
336                            dpy, xgwa.colormap);
337   XSetWindowBackground(dpy, window, bg2);
338   XClearWindow(dpy, window);
339
340   gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
341   gcv.background = fg; gcv.foreground = bg;
342   gc2 = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
343
344   height = (font->ascent + font->descent) * 6;
345
346 #ifdef HAVE_XPM
347   {
348     XpmAttributes xpmattrs;
349     int result;
350     xpmattrs.valuemask = 0;
351
352 # ifdef XpmCloseness
353     xpmattrs.valuemask |= XpmCloseness;
354     xpmattrs.closeness = 40000;
355 # endif
356 # ifdef XpmVisual
357     xpmattrs.valuemask |= XpmVisual;
358     xpmattrs.visual = xgwa.visual;
359 # endif
360 # ifdef XpmDepth
361     xpmattrs.valuemask |= XpmDepth;
362     xpmattrs.depth = xgwa.depth;
363 # endif
364 # ifdef XpmColormap
365     xpmattrs.valuemask |= XpmColormap;
366     xpmattrs.colormap = xgwa.colormap;
367 # endif
368
369     result = XpmCreatePixmapFromData(dpy, window, amiga_hand,
370                                      &pixmap, 0 /* mask */, &xpmattrs);
371     if (!pixmap || (result != XpmSuccess && result != XpmColorError))
372       pixmap = 0;
373     pix_w = xpmattrs.width;
374     pix_h = xpmattrs.height;
375   }
376 #endif /* HAVE_XPM */
377
378   if (pixmap && xgwa.height > 600)      /* scale up the bitmap */
379     {
380       pixmap = double_pixmap(dpy, gc, xgwa.visual, xgwa.depth,
381                              pixmap, pix_w, pix_h);
382       pix_w *= 2;
383       pix_h *= 2;
384     }
385
386   if (pixmap)
387     {
388       int x = (xgwa.width - pix_w) / 2;
389       int y = ((xgwa.height - pix_h) / 2);
390       XCopyArea(dpy, pixmap, window, gc, 0, 0, pix_w, pix_h, x, y);
391
392       XSync(dpy, False);
393       bsod_sleep(dpy, 2);
394
395       XCopyArea(dpy, pixmap, window, gc, 0, 0, pix_w, pix_h, x, y + height);
396       XClearArea(dpy, window, 0, 0, xgwa.width, y + height, False);
397       XFreePixmap(dpy, pixmap);
398     }
399
400   XFillRectangle(dpy, window, gc2, 0, 0, xgwa.width, height);
401   draw_string(dpy, window, gc, &gcv, font, 0, 0, xgwa.width, height, string,0);
402
403   {
404     GC gca = gc;
405     while (delay > 0)
406       {
407         XFillRectangle(dpy, window, gca, 0, 0, xgwa.width, font->ascent);
408         XFillRectangle(dpy, window, gca, 0, 0, font->ascent, height);
409         XFillRectangle(dpy, window, gca, xgwa.width-font->ascent, 0,
410                        font->ascent, height);
411         XFillRectangle(dpy, window, gca, 0, height-font->ascent, xgwa.width,
412                        font->ascent);
413         gca = (gca == gc ? gc2 : gc);
414         XSync(dpy, False);
415         if (bsod_sleep(dpy, 1))
416           break;
417         delay--;
418       }
419   }
420
421   XFreeGC(dpy, gc);
422   XFreeGC(dpy, gc2);
423   XSync(dpy, False);
424   XClearWindow(dpy, window);
425   XFreeFont(dpy, font);
426 }
427
428
429 static void
430 mac (Display *dpy, Window window, int delay)
431 {
432   XGCValues gcv;
433   XWindowAttributes xgwa;
434   char *fontname;
435   const char *def_font = "fixed";
436   XFontStruct *font;
437   GC gc;
438   Pixmap pixmap = 0;
439   int pix_w = mac_width;
440   int pix_h = mac_height;
441   int offset = mac_height * 4;
442   int i;
443
444   const char *string = ("0 0 0 0 0 0 0 F\n"
445                         "0 0 0 0 0 0 0 3");
446
447   XGetWindowAttributes (dpy, window, &xgwa);
448
449   fontname = get_string_resource ("mac.font", "Mac.Font");
450   if (!fontname || !*fontname) fontname = (char *)def_font;
451   font = XLoadQueryFont (dpy, fontname);
452   if (!font) font = XLoadQueryFont (dpy, def_font);
453   if (!font) exit(-1);
454   if (fontname && fontname != def_font)
455     free (fontname);
456
457   gcv.font = font->fid;
458   gcv.foreground = get_pixel_resource("mac.foreground", "Mac.Foreground",
459                                       dpy, xgwa.colormap);
460   gcv.background = get_pixel_resource("mac.background", "Mac.Background",
461                                       dpy, xgwa.colormap);
462   XSetWindowBackground(dpy, window, gcv.background);
463   XClearWindow(dpy, window);
464
465   gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
466
467   pixmap = XCreatePixmapFromBitmapData(dpy, window, (char *) mac_bits,
468                                        mac_width, mac_height,
469                                        gcv.foreground,
470                                        gcv.background,
471                                        xgwa.depth);
472
473   draw_string(dpy, window, gc, &gcv, font, 0, 0,
474               xgwa.width, xgwa.height + offset, string, 0);
475
476   for(i = 0; i < 2; i++)
477     {
478       pixmap = double_pixmap(dpy, gc, xgwa.visual, xgwa.depth,
479                              pixmap, pix_w, pix_h);
480       pix_w *= 2; pix_h *= 2;
481     }
482
483   {
484     int x = (xgwa.width - pix_w) / 2;
485     int y = (((xgwa.height + offset) / 2) -
486              pix_h -
487              (font->ascent + font->descent) * 2);
488     if (y < 0) y = 0;
489     XCopyArea(dpy, pixmap, window, gc, 0, 0, pix_w, pix_h, x, y);
490     XFreePixmap(dpy, pixmap);
491   }
492
493   XFreeGC(dpy, gc);
494   XSync(dpy, False);
495   bsod_sleep(dpy, delay);
496   XClearWindow(dpy, window);
497   XFreeFont(dpy, font);
498 }
499
500 static void
501 macsbug (Display *dpy, Window window, int delay)
502 {
503   XGCValues gcv;
504   XWindowAttributes xgwa;
505   char *fontname;
506   const char *def_font = "fixed";
507   XFontStruct *font;
508   GC gc, gc2;
509
510   int char_width, line_height;
511   int col_right, row_top, row_bottom, page_right, page_bottom, body_top;
512   int xoff, yoff;
513
514   const char *left = ("    SP     \n"
515                       " 04EB0A58  \n"
516                       "58 00010000\n"
517                       "5C 00010000\n"
518                       "   ........\n"
519                       "60 00000000\n"
520                       "64 000004EB\n"
521                       "   ........\n"
522                       "68 0000027F\n"
523                       "6C 2D980035\n"
524                       "   ....-..5\n"
525                       "70 00000054\n"
526                       "74 0173003E\n"
527                       "   ...T.s.>\n"
528                       "78 04EBDA76\n"
529                       "7C 04EBDA8E\n"
530                       "   .S.L.a.U\n"
531                       "80 00000000\n"
532                       "84 000004EB\n"
533                       "   ........\n"
534                       "88 00010000\n"
535                       "8C 00010000\n"
536                       "   ...{3..S\n"
537                       "\n"
538                       "\n"
539                       " CurApName \n"
540                       "  Finder   \n"
541                       "\n"
542                       " 32-bit VM \n"
543                       "SR Smxnzvc0\n"
544                       "D0 04EC0062\n"
545                       "D1 00000053\n"
546                       "D2 FFFF0100\n"
547                       "D3 00010000\n"
548                       "D4 00010000\n"
549                       "D5 04EBDA76\n"
550                       "D6 04EBDA8E\n"
551                       "D7 00000001\n"
552                       "\n"
553                       "A0 04EBDA76\n"
554                       "A1 04EBDA8E\n"
555                       "A2 A0A00060\n"
556                       "A3 027F2D98\n"
557                       "A4 027F2E58\n"
558                       "A5 04EC04F0\n"
559                       "A6 04EB0A86\n"
560                       "A7 04EB0A58");
561   const char *bottom = ("  _A09D\n"
562                         "     +00884    40843714     #$0700,SR         "
563                         "                  ; A973        | A973\n"
564                         "     +00886    40843765     *+$0400           "
565                         "                                | 4A1F\n"
566                         "     +00888    40843718     $0004(A7),([0,A7[)"
567                         "                  ; 04E8D0AE    | 66B8");
568   const char *body = ("Bus Error at 4BF6D6CC\n"
569                       "while reading word from 4BF6D6CC in User data space\n"
570                       " Unable to access that address\n"
571                       "  PC: 2A0DE3E6\n"
572                       "  Frame Type: B008");
573   const char *s;
574   int body_lines = 1;
575
576   for (s = body; *s; s++) if (*s == '\n') body_lines++;
577
578   XGetWindowAttributes (dpy, window, &xgwa);
579
580   fontname = get_string_resource ((xgwa.height > 850
581                                    ? "macsbug.font3"
582                                    : (xgwa.height > 700
583                                       ? "macsbug.font2"
584                                       : "macsbug.font")),
585                                   "MacsBug.Font");
586   if (!fontname || !*fontname) fontname = (char *)def_font;
587   font = XLoadQueryFont (dpy, fontname);
588   if (!font) font = XLoadQueryFont (dpy, def_font);
589   if (!font) exit(-1);
590   if (fontname && fontname != def_font)
591     free (fontname);
592
593   gcv.font = font->fid;
594   gcv.foreground = get_pixel_resource("macsbug.foreground",
595                                       "MacsBug.Foreground",
596                                       dpy, xgwa.colormap);
597   gcv.background = get_pixel_resource("macsbug.background",
598                                       "MacsBug.Background",
599                                       dpy, xgwa.colormap);
600
601   gc = XCreateGC(dpy, window, GCFont|GCForeground|GCBackground, &gcv);
602
603   gcv.foreground = gcv.background;
604   gc2 = XCreateGC(dpy, window, GCForeground, &gcv);
605
606   XSetWindowBackground(dpy, window,
607                        get_pixel_resource("macsbug.borderColor",
608                                           "MacsBug.BorderColor",
609                                           dpy, xgwa.colormap));
610   XClearWindow(dpy, window);
611
612   char_width = (font->per_char
613                 ? font->per_char['n'-font->min_char_or_byte2].width
614                 : font->min_bounds.width);
615   line_height = font->ascent + font->descent + 1;
616
617   col_right = char_width * 12;
618   page_bottom = line_height * 47;
619
620   if (page_bottom > xgwa.height) page_bottom = xgwa.height;
621
622   row_bottom = page_bottom - line_height;
623   row_top = row_bottom - (line_height * 4);
624   page_right = col_right + (char_width * 88);
625   body_top = row_top - (line_height * body_lines);
626
627   page_bottom += 2;
628   row_bottom += 2;
629   body_top -= 4;
630
631   xoff = (xgwa.width - page_right) / 2;
632   yoff = (xgwa.height - page_bottom) / 2;
633   if (xoff < 0) xoff = 0;
634   if (yoff < 0) yoff = 0;
635
636   XFillRectangle(dpy, window, gc2, xoff, yoff, page_right, page_bottom);
637
638   draw_string(dpy, window, gc, &gcv, font, xoff, yoff, 10, 10, left, 0);
639   draw_string(dpy, window, gc, &gcv, font, xoff+col_right, yoff+row_top,
640               10, 10, bottom, 0);
641   draw_string(dpy, window, gc, &gcv, font,
642               xoff + col_right + char_width, yoff + body_top, 10, 10, body, 0);
643
644   XFillRectangle(dpy, window, gc, xoff + col_right, yoff, 2, page_bottom);
645   XDrawLine(dpy, window, gc,
646             xoff+col_right, yoff+row_top, xoff+page_right, yoff+row_top);
647   XDrawLine(dpy, window, gc,
648             xoff+col_right, yoff+row_bottom, xoff+page_right, yoff+row_bottom);
649   XDrawRectangle(dpy, window, gc,  xoff, yoff, page_right, page_bottom);
650
651   while (delay > 0)
652     {
653       XDrawLine(dpy, window, gc,
654                 xoff+col_right+(char_width/2)+2, yoff+row_bottom+3,
655                 xoff+col_right+(char_width/2)+2, yoff+page_bottom-3);
656       XSync(dpy, False);
657       usleep(666666L);
658       XDrawLine(dpy, window, gc2,
659                 xoff+col_right+(char_width/2)+2, yoff+row_bottom+3,
660                 xoff+col_right+(char_width/2)+2, yoff+page_bottom-3);
661       XSync(dpy, False);
662       usleep(333333L);
663       if (bsod_sleep(dpy, 0))
664         break;
665       delay--;
666     }
667
668   XFreeGC(dpy, gc);
669   XFreeGC(dpy, gc2);
670   XClearWindow(dpy, window);
671   XFreeFont(dpy, font);
672 }
673
674
675 \f
676 char *progclass = "BSOD";
677
678 char *defaults [] = {
679   "*delay:               30",
680
681   ".Windows.font:        -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
682   ".Windows.font2:       -*-courier-bold-r-*-*-*-180-*-*-m-*-*-*",
683   ".Windows.foreground:  White",
684   ".Windows.background:  Blue",
685
686   ".Amiga.font:          -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
687   ".Amiga.font2:         -*-courier-bold-r-*-*-*-180-*-*-m-*-*-*",
688   ".Amiga.foreground:    Red",
689   ".Amiga.background:    Black",
690   ".Amiga.background2:   White",
691
692   ".Mac.font:            -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
693   ".Mac.foreground:      PaleTurquoise1",
694   ".Mac.background:      Black",
695
696   ".MacsBug.font:        -*-courier-medium-r-*-*-*-100-*-*-m-*-*-*",
697   ".MacsBug.font2:       -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
698   ".MacsBug.font3:       -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*",
699   ".MacsBug.foreground:  Black",
700   ".MacsBug.background:  White",
701   ".MacsBug.borderColor: #AAAAAA",
702   0
703 };
704
705 XrmOptionDescRec options [] = {
706   { "-delay",           ".delay",               XrmoptionSepArg, 0 },
707   { 0, 0, 0, 0 }
708 };
709
710 void
711 screenhack (Display *dpy, Window window)
712 {
713   int i = -1;
714   int j = -1;
715   int delay = get_integer_resource ("delay", "Integer");
716   if (delay < 3) delay = 3;
717
718   if (!get_boolean_resource ("root", "Boolean"))
719     XSelectInput(dpy, window, KeyPressMask|ButtonPressMask);
720
721   while (1)
722     {
723       while (i == j) i = random() % 5;
724       j = i;
725
726       switch (i)
727         {
728         case 0: windows(dpy, window, delay, True); break;
729         case 1: windows(dpy, window, delay, False); break;
730         case 2: amiga(dpy, window, delay); break;
731         case 3: mac(dpy, window, delay); break;
732         case 4: macsbug(dpy, window, delay); break;
733         default: abort(); break;
734         }
735       XSync (dpy, True);
736     }
737 }