From 6cee540bdbb571485cd5e519f89f389faebd0495 Mon Sep 17 00:00:00 2001 From: Zygo Blaxell Date: Mon, 2 Mar 2009 00:43:05 -0500 Subject: [PATCH] http://www.archive.org/download/tucows_10294_XScreenSaver/xscreensaver-4.10.tar.gz -rw-r--r-- 1 zblaxell zblaxell 3593957 Feb 26 17:16 xscreensaver-4.10.tar.gz 335680994fcd74261192cca060e2b3ffdd6f0c10 xscreensaver-4.10.tar.gz --- README | 6 + configure | 5 +- configure.in | 5 +- driver/XScreenSaver.ad.in | 8 +- driver/XScreenSaver_ad.h | 4 +- driver/demo-Gtk.c | 14 +- driver/lock.c | 6 +- driver/screensaver-properties.desktop.in | 7 +- driver/subprocs.c | 6 + driver/timers.c | 13 + driver/xscreensaver-command.man | 2 +- driver/xscreensaver-demo.man | 2 +- driver/xscreensaver-getimage-file | 3 +- driver/xscreensaver-getimage-file.man | 2 +- driver/xscreensaver-getimage-video.man | 2 +- driver/xscreensaver-getimage.c | 22 +- driver/xscreensaver-getimage.man | 2 +- driver/xscreensaver.man | 2 +- hacks/Makefile.in | 14 +- hacks/bsod.c | 1997 +++++++++- hacks/bsod.man | 42 +- hacks/cloudlife.c | 338 ++ hacks/compile_axp.com | 1 + hacks/compile_decc.com | 1 + hacks/config/README | 4 +- hacks/config/bsod.xml | 3 + hacks/config/cloudlife.xml | 32 + hacks/config/glplanet.xml | 2 +- hacks/config/jigglypuff.xml | 87 + hacks/config/klein.xml | 8 +- hacks/config/superquadrics.xml | 2 +- hacks/eruption.c | 127 +- hacks/flow.c | 3 +- hacks/glx/Makefile.in | 20 +- hacks/glx/endgame.c | 38 +- hacks/glx/glslideshow.c | 6 +- hacks/glx/glslideshow.man | 7 +- hacks/glx/jigglypuff.c | 647 +++- hacks/glx/jigglypuff.man | 121 + hacks/glx/klein.c | 424 +++ hacks/glx/klein.man | 59 + hacks/glx/lavalite.c | 5 +- hacks/images/jigglymap.xpm | 350 ++ hacks/maze.c | 2 +- hacks/metaballs.c | 2 + hacks/speedmine.c | 5 + hacks/webcollage | 17 +- hacks/xmatrix.c | 497 ++- hacks/xmatrix.man | 2 +- po/ChangeLog | 141 +- po/POTFILES.in | 4 +- po/ca.po | 1024 +++-- po/da.po | 239 +- po/de.po | 2770 ++++++++------ po/es.po | 413 +- po/et.po | 11 +- po/fi.po | 1024 +++-- po/fr.po | 3168 +++++++++------- po/hu.po | 2073 ++++++---- po/it.po | 1024 +++-- po/ja.po | 1193 +++--- po/ko.po | 1167 +++--- po/nl.po | 4384 ++++++---------------- po/no.po | 2932 +++++---------- po/pl.po | 1155 +++--- po/pt.po | 1244 +++--- po/pt_BR.po | 1024 +++-- po/ru.po | 1665 ++++---- po/sk.po | 1202 +++--- po/sv.po | 1373 ++++--- po/vi.po | 51 +- po/zh_CN.po | 1236 +++--- po/zh_TW.po | 1204 +++--- setup.com | 1 + utils/version.h | 2 +- xscreensaver.lsm | 10 +- xscreensaver.spec | 2 +- 77 files changed, 21100 insertions(+), 15610 deletions(-) create mode 100644 hacks/cloudlife.c create mode 100644 hacks/config/cloudlife.xml create mode 100644 hacks/config/jigglypuff.xml create mode 100644 hacks/glx/jigglypuff.man create mode 100644 hacks/glx/klein.c create mode 100644 hacks/glx/klein.man create mode 100644 hacks/images/jigglymap.xpm diff --git a/README b/README index 2c8e5ddf..9f7aa97a 100644 --- a/README +++ b/README @@ -70,6 +70,12 @@ the XScreenSaver FAQ about that: http://www.jwz.org/xscreensaver/faq.html ============ +Changes since 4.09: * New hacks, `cloudlife' and `klein'. + * Added Apple ][+, HPUX, and OS/390 sessions to BSOD. + * Added some Matrix Reloaded text to `xmatrix'. + * Updates to `webcollage', `eruption', `jigglypuff', + `metaballs', and `endgame'. + * Completely ignore the `memoryLimit' setting now. Changes since 4.08: * New hacks, `flyingtoasters', `bouncingcow', `jigglypuff', and `glslideshow'. * More models in `engine'. diff --git a/configure b/configure index dc1a7e47..a3ee8c5d 100755 --- a/configure +++ b/configure @@ -19282,7 +19282,10 @@ if test "$gtk2_halfassed" != no ; then fi -if test "$with_gnome_req" = yes -a "$have_gnome" = no ; then +if test "$with_gnome_req" = yes -a "$have_gnome" = no \ + -a "$have_gtk2" = no; then + # don't issue this warning if we have GTK2 -- in that case, the + # Gnome-specific code isn't needed. warn 'Use of the Gnome Control Panel was requested, but the necessary' warn2 'headers and/or libraries were not found.' fi diff --git a/configure.in b/configure.in index f9ba1a78..a2337930 100644 --- a/configure.in +++ b/configure.in @@ -3710,7 +3710,10 @@ if test "$gtk2_halfassed" != no ; then fi -if test "$with_gnome_req" = yes -a "$have_gnome" = no ; then +if test "$with_gnome_req" = yes -a "$have_gnome" = no \ + -a "$have_gtk2" = no; then + # don't issue this warning if we have GTK2 -- in that case, the + # Gnome-specific code isn't needed. warn 'Use of the Gnome Control Panel was requested, but the necessary' warn2 'headers and/or libraries were not found.' fi diff --git a/driver/XScreenSaver.ad.in b/driver/XScreenSaver.ad.in index 28763d8f..ff59ab96 100644 --- a/driver/XScreenSaver.ad.in +++ b/driver/XScreenSaver.ad.in @@ -4,8 +4,8 @@ ! a screen saver and locker for the X window system ! by Jamie Zawinski ! -! version 4.09 -! 17-Mar-2003 +! version 4.10 +! 20-May-2003 ! ! See "man xscreensaver" for more info. The latest version is always ! available at http://www.jwz.org/xscreensaver/ @@ -290,6 +290,7 @@ popsquares -root \n\ barcode -root \n\ piecewise -root \n\ + cloudlife -root \n\ color: bubbles -root \n\ - default-n: webcollage -root \n\ - default-n: "WebCollage (whacked)" \ @@ -345,7 +346,8 @@ @GL_KLUDGE@ GL: atunnel -root \n\ @GL_KLUDGE@ GL: flyingtoasters -root \n\ @GL_KLUDGE@ GL: bouncingcow -root \n\ -@GL_KLUDGE@ GL: jigglypuff -root \n\ +@GL_KLUDGE@ GL: jigglypuff -root -random \n\ +@GL_KLUDGE@ GL: klein -root -random \n\ - GL: glslideshow -root \n\ \ - xdaliclock -root -builtin3 -cycle \n\ diff --git a/driver/XScreenSaver_ad.h b/driver/XScreenSaver_ad.h index e524b955..67450449 100644 --- a/driver/XScreenSaver_ad.h +++ b/driver/XScreenSaver_ad.h @@ -192,6 +192,7 @@ popsquares -root \\n\ barcode -root \\n\ piecewise -root \\n\ + cloudlife -root \\n\ color: bubbles -root \\n\ - default-n: webcollage -root \\n\ - default-n: \"WebCollage (whacked)\" \ @@ -247,7 +248,8 @@ GL: atunnel -root \\n\ GL: flyingtoasters -root \\n\ GL: bouncingcow -root \\n\ - GL: jigglypuff -root \\n\ + GL: jigglypuff -root -random \\n\ + GL: klein -root -random \\n\ - GL: glslideshow -root \\n\ \ - xdaliclock -root -builtin3 -cycle \\n\ diff --git a/driver/demo-Gtk.c b/driver/demo-Gtk.c index a85bdbc0..1d7e91fd 100644 --- a/driver/demo-Gtk.c +++ b/driver/demo-Gtk.c @@ -300,16 +300,14 @@ ensure_selected_item_visible (GtkWidget *widget) selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); if (!gtk_tree_selection_get_selected (selection, &model, &iter)) - return; - - path = gtk_tree_model_get_path (model, &iter); + path = gtk_tree_path_new_first (); + else + path = gtk_tree_model_get_path (model, &iter); -# if 0 - gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (widget), - path, NULL, FALSE, 0.0, 0.0); -# else gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget), path, NULL, FALSE); -# endif + + gtk_tree_path_free (path); + #else /* !HAVE_GTK2 */ GtkScrolledWindow *scroller = 0; diff --git a/driver/lock.c b/driver/lock.c index 47c1b4ee..529bf862 100644 --- a/driver/lock.c +++ b/driver/lock.c @@ -407,7 +407,11 @@ make_passwd_window (saver_info *si) attrmask, &attrs); XSetWindowBackground (si->dpy, si->passwd_dialog, pw->background); - pw->logo_pixmap = xscreensaver_logo (ssi->screen, ssi->current_visual, + /* We use the default visual, not ssi->visual, so that the logo pixmap's + visual matches that of the si->passwd_dialog window. */ + pw->logo_pixmap = xscreensaver_logo (ssi->screen, + /* ssi->current_visual, */ + DefaultVisualOfScreen(screen), si->passwd_dialog, cmap, pw->background, &pw->logo_pixels, &pw->logo_npixels, diff --git a/driver/screensaver-properties.desktop.in b/driver/screensaver-properties.desktop.in index 541ddd8f..ee6cd7e4 100644 --- a/driver/screensaver-properties.desktop.in +++ b/driver/screensaver-properties.desktop.in @@ -1,9 +1,8 @@ [Desktop Entry] -Exec=xscreensaver-demo --crapplet -TryExec=xscreensaver-demo +Exec=xscreensaver-demo Icon=xscreensaver.xpm -Terminal=0 +Terminal=false _Name=Screensaver _Comment=Change screensaver properties Type=Application -Categories=Applications;Settings; +Categories=Application;Settings;AdvancedSettings; diff --git a/driver/subprocs.c b/driver/subprocs.c index b6948e87..527f379d 100644 --- a/driver/subprocs.c +++ b/driver/subprocs.c @@ -88,6 +88,12 @@ extern saver_info *global_si_kludge; /* I hate C so much... */ static void limit_subproc_memory (int address_space_limit, Bool verbose_p) { + +/* This has caused way more problems than it has solved... + Let's just completely ignore the "memoryLimit" option now. + */ +#undef HAVE_SETRLIMIT + #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_AS) struct rlimit r; diff --git a/driver/timers.c b/driver/timers.c index 7e9baaac..4b5b570f 100644 --- a/driver/timers.c +++ b/driver/timers.c @@ -740,6 +740,19 @@ sleep_until_idle (saver_info *si, Bool until_idle_p) break; fprintf (stderr,"%s: %d: %s on 0x%lx", blurb(), i, type, (unsigned long) window); + + /* Be careful never to do this unless in -debug mode, as + this could expose characters from the unlock password. */ + if (p->debug_p && event.xany.type == KeyPress) + { + KeySym keysym; + char c = 0; + XLookupString (&event.xkey, &c, 1, &keysym, 0); + fprintf (stderr, " (%s%s)", + (event.xkey.send_event ? "synthetic " : ""), + XKeysymToString (keysym)); + } + if (x == -1) fprintf (stderr, "\n"); else diff --git a/driver/xscreensaver-command.man b/driver/xscreensaver-command.man index 7c211f44..18484e90 100644 --- a/driver/xscreensaver-command.man +++ b/driver/xscreensaver-command.man @@ -11,7 +11,7 @@ .if n .sp 1 .if t .sp .5 .. -.TH XScreenSaver 1 "17-Mar-2003 (4.09)" "X Version 11" +.TH XScreenSaver 1 "20-May-2003 (4.10)" "X Version 11" .SH NAME xscreensaver-command - control a running xscreensaver process .SH SYNOPSIS diff --git a/driver/xscreensaver-demo.man b/driver/xscreensaver-demo.man index dadb9c0f..c76141af 100644 --- a/driver/xscreensaver-demo.man +++ b/driver/xscreensaver-demo.man @@ -11,7 +11,7 @@ .if n .sp 1 .if t .sp .5 .. -.TH XScreenSaver 1 "17-Mar-2003 (4.09)" "X Version 11" +.TH XScreenSaver 1 "20-May-2003 (4.10)" "X Version 11" .SH NAME xscreensaver-demo - interactively control the background xscreensaver daemon .SH SYNOPSIS diff --git a/driver/xscreensaver-getimage-file b/driver/xscreensaver-getimage-file index 140d08a8..f7f4c874 100755 --- a/driver/xscreensaver-getimage-file +++ b/driver/xscreensaver-getimage-file @@ -24,6 +24,7 @@ # Created: 12-Apr-01. require 5; +#require v5.6; use diagnostics; use strict; @@ -50,7 +51,7 @@ BEGIN { my $progname = $0; $progname =~ s@.*/@@g; -my $version = q{ $Revision: 1.11 $ }; $version =~ s/^[^0-9]+([0-9.]+).*$/$1/; +my $version = q{ $Revision: 1.12 $ }; $version =~ s/^[^0-9]+([0-9.]+).*$/$1/; my $verbose = 0; diff --git a/driver/xscreensaver-getimage-file.man b/driver/xscreensaver-getimage-file.man index 4d7cd69f..38c38c7b 100644 --- a/driver/xscreensaver-getimage-file.man +++ b/driver/xscreensaver-getimage-file.man @@ -1,4 +1,4 @@ -.TH XScreenSaver 1 "17-Mar-2003 (4.09)" "X Version 11" +.TH XScreenSaver 1 "20-May-2003 (4.10)" "X Version 11" .SH NAME xscreensaver-getimage-file - put a randomly-selected image on the root window .SH SYNOPSIS diff --git a/driver/xscreensaver-getimage-video.man b/driver/xscreensaver-getimage-video.man index 8dca75e6..8c0d24fd 100644 --- a/driver/xscreensaver-getimage-video.man +++ b/driver/xscreensaver-getimage-video.man @@ -1,4 +1,4 @@ -.TH XScreenSaver 1 "17-Mar-2003 (4.09)" "X Version 11" +.TH XScreenSaver 1 "20-May-2003 (4.10)" "X Version 11" .SH NAME xscreensaver-getimage-video - put a video frame on the root window .SH SYNOPSIS diff --git a/driver/xscreensaver-getimage.c b/driver/xscreensaver-getimage.c index 599c50cd..47247686 100644 --- a/driver/xscreensaver-getimage.c +++ b/driver/xscreensaver-getimage.c @@ -43,6 +43,7 @@ #include "colorbars.h" #include "visual.h" #include "prefs.h" +#include "version.h" #include "vroot.h" #ifdef HAVE_GDK_PIXBUF @@ -1331,7 +1332,9 @@ mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks, #define USAGE "usage: %s [ -options... ] window-id [pixmap-id]\n" \ "\n" \ - " This program puts an image on the given window or pixmap.\n" \ + " %s\n" \ + "\n" \ + " %s puts an image on the given window or pixmap.\n" \ "\n" \ " It is used by those xscreensaver demos that operate on images.\n" \ " The image may be a file loaded from disk, a frame grabbed from\n" \ @@ -1362,6 +1365,7 @@ main (int argc, char **argv) Screen *screen; char *oprogname = progname; char *file = 0; + char version[255]; Window window = (Window) 0; Drawable drawable = (Drawable) 0; @@ -1382,6 +1386,20 @@ main (int argc, char **argv) # error Error! This file definitely needs vroot.h! # endif + /* Get the version number, for error messages. */ + { + char *v = (char *) strdup(strchr(screensaver_id, ' ')); + char *s1, *s2, *s3, *s4; + s1 = (char *) strchr(v, ' '); s1++; + s2 = (char *) strchr(s1, ' '); + s3 = (char *) strchr(v, '('); s3++; + s4 = (char *) strchr(s3, ')'); + *s2 = 0; + *s4 = 0; + sprintf (version, "Part of XScreenSaver %s -- %s.", s1, s3); + free(v); + } + /* We must read exactly the same resources as xscreensaver. That means we must have both the same progclass *and* progname, at least as far as the resource database is concerned. So, @@ -1473,7 +1491,7 @@ main (int argc, char **argv) fprintf (stderr, "\n%s: unparsable window/pixmap ID: \"%s\"\n", progname, argv[i]); LOSE: - fprintf (stderr, USAGE, progname); + fprintf (stderr, USAGE, progname, version, progname); exit (1); } } diff --git a/driver/xscreensaver-getimage.man b/driver/xscreensaver-getimage.man index a6a716c6..ca978bf6 100644 --- a/driver/xscreensaver-getimage.man +++ b/driver/xscreensaver-getimage.man @@ -1,4 +1,4 @@ -.TH XScreenSaver 1 "17-Mar-2003 (4.09)" "X Version 11" +.TH XScreenSaver 1 "20-May-2003 (4.10)" "X Version 11" .SH NAME xscreensaver-getimage - put some randomly-selected image on the root window .SH SYNOPSIS diff --git a/driver/xscreensaver.man b/driver/xscreensaver.man index d5cf9bbc..5d9c4ba0 100644 --- a/driver/xscreensaver.man +++ b/driver/xscreensaver.man @@ -11,7 +11,7 @@ .if n .sp 1 .if t .sp .5 .. -.TH XScreenSaver 1 "17-Mar-2003 (4.09)" "X Version 11" +.TH XScreenSaver 1 "20-May-2003 (4.10)" "X Version 11" .SH NAME xscreensaver - extensible screen saver framework, plus locking .SH SYNOPSIS diff --git a/hacks/Makefile.in b/hacks/Makefile.in index 770db831..a487ef40 100644 --- a/hacks/Makefile.in +++ b/hacks/Makefile.in @@ -97,7 +97,7 @@ SRCS = attraction.c blitspin.c bouboule.c braid.c bubbles.c \ xpm-pixmap.c webcollage-helper.c twang.c apollonian.c \ euler2d.c juggle.c polyominoes.c thornbird.c fluidballs.c \ anemone.c halftone.c metaballs.c eruption.c popsquares.c \ - barcode.c piecewise.c + barcode.c piecewise.c cloudlife.c SCRIPTS = vidwhacker webcollage OBJS = attraction.o blitspin.o bouboule.o braid.o bubbles.o \ @@ -122,7 +122,7 @@ OBJS = attraction.o blitspin.o bouboule.o braid.o bubbles.o \ xpm-pixmap.o webcollage-helper.o twang.o apollonian.o \ euler2d.o juggle.o polyominoes.o thornbird.o fluidballs.o \ anemone.o halftone.o metaballs.o eruption.o popsquares.o \ - barcode.o piecewise.o + barcode.o piecewise.o cloudlife.o NEXES = attraction blitspin bouboule braid bubbles decayscreen deco \ drift flag flame forest vines galaxy grav greynetic halo \ @@ -139,7 +139,7 @@ NEXES = attraction blitspin bouboule braid bubbles decayscreen deco \ nerverot xrayswarm hyperball zoom whirlwindwarp rotzoomer \ whirlygig speedmine vermiculate twang apollonian euler2d \ juggle polyominoes thornbird fluidballs anemone halftone \ - metaballs eruption popsquares barcode piecewise \ + metaballs eruption popsquares barcode piecewise cloudlife \ @JPEG_EXES@ SEXES = sonar JPEG_EXES = webcollage-helper @@ -622,8 +622,8 @@ interference: interference.o $(HACK_OBJS) $(COL) $(SHM) $(DBE) truchet: truchet.o $(HACK_OBJS) $(COL) $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(HACK_LIBS) -bsod: bsod.o $(HACK_OBJS) $(GRAB) $(XPM) - $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(GRAB) $(XPM) $(XPM_LIBS) +bsod: bsod.o $(HACK_OBJS) $(GRAB) $(SHM) $(XPM) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(GRAB) $(SHM) $(XPM) $(XPM_LIBS) distort: distort.o $(HACK_OBJS) $(GRAB) $(SHM) $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(GRAB) $(SHM) $(HACK_LIBS) @@ -745,6 +745,8 @@ barcode: barcode.o $(HACK_OBJS) $(HSV) piecewise: piecewise.o $(HACK_OBJS) $(COL) $(DBE) $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(DBE) $(HACK_LIBS) +cloudlife: cloudlife.o $(HACK_OBJS) $(COL) $(DBE) + $(CC_HACK) -o $@ $@.o $(HACK_OBJS) $(COL) $(DBE) $(HACK_LIBS) # The rules for those hacks which follow the `xlockmore' API. # @@ -969,6 +971,8 @@ bumps.o: ../config.h bumps.o: $(srcdir)/screenhack.h ccurve.o: ../config.h ccurve.o: $(srcdir)/screenhack.h +cloudlife.o: ../config.h +cloudlife.o: $(srcdir)/screenhack.h compass.o: ../config.h compass.o: $(srcdir)/screenhack.h coral.o: ../config.h diff --git a/hacks/bsod.c b/hacks/bsod.c index 450f10c1..b2bd3844 100644 --- a/hacks/bsod.c +++ b/hacks/bsod.c @@ -13,6 +13,7 @@ * this version written by jwz, 4-Jun-98. */ +#include #include "screenhack.h" #include "xpm-pixmap.h" #include @@ -20,6 +21,10 @@ #include #include +#ifdef HAVE_XSHM_EXTENSION +#include "xshm.h" +#endif + #ifdef HAVE_UNAME # include #endif /* HAVE_UNAME */ @@ -30,6 +35,8 @@ #include "images/macbomb.xbm" #include "images/hmac.xpm" +#undef countof +#define countof(x) (sizeof((x))/sizeof((*x))) static int draw_string (Display *dpy, Window window, GC gc, XGCValues *gcv, @@ -195,7 +202,7 @@ bsod_sleep(Display *dpy, int seconds) } -static Bool +static void windows (Display *dpy, Window window, int delay, int which) { XGCValues gcv; @@ -286,13 +293,6 @@ windows (Display *dpy, Window window, int delay, int which) if (which == 2 && (random() % 2)) which = 3; - if (!get_boolean_resource((which == 0 ? "doWindows" : - which == 1 ? "doNT" : - which == 2 ? "doWin2K" : - "doWin2K"), /* "doWinME" ? */ - "DoWindows")) - return False; - XGetWindowAttributes (dpy, window, &xgwa); fontname = get_string_resource ((xgwa.height > 600 @@ -377,12 +377,30 @@ windows (Display *dpy, Window window, int delay, int which) bsod_sleep(dpy, delay); XClearWindow(dpy, window); XFreeFont(dpy, font); - return True; } +static void +windows_31 (Display *dpy, Window window, int delay) +{ + windows (dpy, window, delay, 0); +} + +static void +windows_nt (Display *dpy, Window window, int delay) +{ + windows (dpy, window, delay, 1); +} + +static void +windows_2k (Display *dpy, Window window, int delay) +{ + windows (dpy, window, delay, 2); +} + + /* SCO OpenServer 5 panic, by Tom Kelly */ -static Bool +static void sco (Display *dpy, Window window, int delay) { XGCValues gcv; @@ -408,7 +426,8 @@ sco (Display *dpy, Window window, int delay) "Trying to dump 5023 pages to dumpdev hd (1/41), 63 pages per '.'\n" ); const char *sco_panic_2 = - ("...............................................................................\n" + ("................................................................." + "..............\n" ); const char *sco_panic_3 = ("5023 pages dumped\n" @@ -421,9 +440,6 @@ sco (Display *dpy, Window window, int delay) "** Press Any Key to Reboot **\n" ); - if (!get_boolean_resource("doSCO", "DoSCO")) - return False; - for (s = sco_panic_1; *s; s++) if (*s == '\n') lines_1++; for (s = sco_panic_2; *s; s++) if (*s == '\n') lines_2++; for (s = sco_panic_3; *s; s++) if (*s == '\n') lines_3++; @@ -495,13 +511,12 @@ sco (Display *dpy, Window window, int delay) XClearWindow(dpy, window); XFreeGC(dpy, gc); XFreeFont(dpy, font); - return True; } /* Linux (sparc) panic, by Tom Kelly */ -static Bool +static void sparc_linux (Display *dpy, Window window, int delay) { XGCValues gcv; @@ -535,9 +550,6 @@ sparc_linux (Display *dpy, Window window, int delay) "Instruction DUMP:\n" ); - if (!get_boolean_resource("doSparcLinux", "DoSparcLinux")) - return False; - for (s = linux_panic; *s; s++) if (*s == '\n') lines++; XGetWindowAttributes (dpy, window, &xgwa); @@ -574,13 +586,12 @@ sparc_linux (Display *dpy, Window window, int delay) bsod_sleep(dpy, delay); XClearWindow(dpy, window); XFreeFont(dpy, font); - return True; } /* BSD Panic by greywolf@starwolf.com - modeled after the Linux panic above. By Grey Wolf */ -static Bool +static void bsd (Display *dpy, Window window, int delay) { XGCValues gcv; @@ -610,9 +621,6 @@ bsd (Display *dpy, Window window, int delay) "panic: teleport chamber: out of order", "panic: Brain fried - core dumped"}; - if (!get_boolean_resource("doBSD", "DoBSD")) - return False; - for (i = 0; i < sizeof(syncing); i++) syncing[i] = 0; @@ -718,10 +726,9 @@ bsd (Display *dpy, Window window, int delay) DONE: XClearWindow(dpy, window); XFreeFont(dpy, font); - return True; } -static Bool +static void amiga (Display *dpy, Window window, int delay) { XGCValues gcv; @@ -741,9 +748,6 @@ amiga (Display *dpy, Window window, int delay) ("_Software failure. Press left mouse button to continue.\n" "_Guru Meditation #00000003.00C01570"); - if (!get_boolean_resource("doAmiga", "DoAmiga")) - return False; - XGetWindowAttributes (dpy, window, &xgwa); fontname = get_string_resource ((xgwa.height > 600 @@ -833,7 +837,6 @@ amiga (Display *dpy, Window window, int delay) XSync(dpy, False); XClearWindow(dpy, window); XFreeFont(dpy, font); - return True; } @@ -847,7 +850,7 @@ amiga (Display *dpy, Window window, int delay) Perhaps somebody else can tell you more about it.. its just a quick hack :-} */ -static Bool +static void atari (Display *dpy, Window window, int delay) { @@ -862,9 +865,6 @@ atari (Display *dpy, Window window, int delay) int offset; int i, x, y; - if (!get_boolean_resource("doAtari", "DoAtari")) - return False; - XGetWindowAttributes (dpy, window, &xgwa); font = XLoadQueryFont (dpy, def_font); @@ -914,11 +914,10 @@ atari (Display *dpy, Window window, int delay) XSync(dpy, False); XClearWindow(dpy, window); XFreeFont(dpy, font); - return True; } -static Bool +static void mac (Display *dpy, Window window, int delay) { XGCValues gcv; @@ -936,9 +935,6 @@ mac (Display *dpy, Window window, int delay) const char *string = ("0 0 0 0 0 0 0 F\n" "0 0 0 0 0 0 0 3"); - if (!get_boolean_resource("doMac", "DoMac")) - return False; - XGetWindowAttributes (dpy, window, &xgwa); fontname = get_string_resource ("mac.font", "Mac.Font"); @@ -990,10 +986,9 @@ mac (Display *dpy, Window window, int delay) bsod_sleep(dpy, delay); XClearWindow(dpy, window); XFreeFont(dpy, font); - return True; } -static Bool +static void macsbug (Display *dpy, Window window, int delay) { XGCValues gcv; @@ -1104,9 +1099,6 @@ macsbug (Display *dpy, Window window, int delay) const char *s; int body_lines = 1; - if (!get_boolean_resource("doMacsBug", "DoMacsBug")) - return False; - for (s = body; *s; s++) if (*s == '\n') body_lines++; XGetWindowAttributes (dpy, window, &xgwa); @@ -1208,10 +1200,9 @@ macsbug (Display *dpy, Window window, int delay) XFreeGC(dpy, gc2); XClearWindow(dpy, window); XFreeFont(dpy, font); - return True; } -static Bool +static void mac1 (Display *dpy, Window window, int delay) { XGCValues gcv; @@ -1221,9 +1212,6 @@ mac1 (Display *dpy, Window window, int delay) int pix_w = macbomb_width; int pix_h = macbomb_height; - if (!get_boolean_resource("doMac1", "DoMac1")) - return False; - XGetWindowAttributes (dpy, window, &xgwa); gcv.foreground = get_pixel_resource("mac1.foreground", "Mac.Foreground", @@ -1258,11 +1246,10 @@ mac1 (Display *dpy, Window window, int delay) XSync(dpy, False); bsod_sleep(dpy, delay); XClearWindow(dpy, window); - return True; } -static Bool +static void macx (Display *dpy, Window window, int delay) { XGCValues gcv; @@ -1299,9 +1286,6 @@ macx (Display *dpy, Window window, int delay) "\n" "panic: We are hanging here...\n"); - if (!get_boolean_resource("doMacX", "DoMacX")) - return False; - XGetWindowAttributes (dpy, window, &xgwa); gcv.background = get_pixel_resource("macX.background", @@ -1403,12 +1387,8 @@ macx (Display *dpy, Window window, int delay) XSync(dpy, False); bsod_sleep(dpy, delay); XClearWindow(dpy, window); - return True; } - - - /* blit damage * @@ -1418,7 +1398,7 @@ macx (Display *dpy, Window window, int delay) * Xterms. The parameters for choosing what to copy where might not * be quite right, but it looks about ugly enough. */ -static Bool +static void blitdamage (Display *dpy, Window window, int delay) { XGCValues gcv; @@ -1433,9 +1413,6 @@ blitdamage (Display *dpy, Window window, int delay) int src_x, src_y; int x, y; - if (!get_boolean_resource("doBlitDamage", "DoBlitDamage")) - return False; - XGetWindowAttributes(dpy, window, &xwa); load_random_image (xwa.screen, window, window); @@ -1486,8 +1463,6 @@ blitdamage (Display *dpy, Window window, int delay) DONE: XFreeGC(dpy, gc0); - - return True; } @@ -1619,6 +1594,8 @@ scrolling_putc (scrolling_window* ts, const char aChar) ts->sub_x, ts->sub_y + ts->sub_height - ts->line_height, ts->sub_width, ts->line_height); break; + case '\r': + ts->x = 0; case '\b': if(ts->x > 0) ts->x--; @@ -1656,7 +1633,7 @@ scrolling_puts (scrolling_window *ts, const char* aString, int delay) return False; } -static Bool +static void sparc_solaris (Display* dpy, Window window, int delay) { const char *msg1 = @@ -1699,9 +1676,6 @@ sparc_solaris (Display* dpy, Window window, int delay) int i; char buf[256]; - if (!get_boolean_resource("doSolaris", "DoSolaris")) - return False; - ts = make_scrolling_window (dpy, window, "Solaris", True); scrolling_puts (ts, msg1, 0); @@ -1732,13 +1706,11 @@ sparc_solaris (Display* dpy, Window window, int delay) DONE: free_scrolling_window (ts); - - return True; } /* Linux panic and fsck, by jwz */ -static Bool +static void linux_fsck (Display *dpy, Window window, int delay) { XWindowAttributes xgwa; @@ -1780,9 +1752,6 @@ linux_fsck (Display *dpy, Window window, int delay) 0 }; - if (!get_boolean_resource("doLinux", "DoLinux")) - return False; - XGetWindowAttributes (dpy, window, &xgwa); XSetWindowBackground (dpy, window, get_pixel_resource("Linux.background", @@ -2121,7 +2090,1743 @@ linux_fsck (Display *dpy, Window window, int delay) DONE: free_scrolling_window (ts); XClearWindow(dpy, window); - return True; +} + + + +/* HPUX panic, by Tobias Klausmann + */ + +static void +hpux (Display* dpy, Window window, int delay) +{ + GC gc; + XGCValues gcv; + XWindowAttributes xgwa; + scrolling_window *ts; + const char *sysname; + char buf[2048]; + + const char *msg1 = + "Console Login:\n" + "\n" + " ******* Unexpected HPMC/TOC. Processor HPA FFFFFFFF'" + "FFFA0000 *******\n" + " GENERAL REGISTERS:\n" + "r00/03 00000000'00000000 00000000'00000000 00000000'00000000 00000000'" + "006C76C0\n" + "r04/07 00000000'00000001 00000000'0126E328 00000000'00000000 00000000'" + "0122B640\n" + "r08/11 00000000'00000000 00000000'0198CFC0 00000000'000476FE 00000000'" + "00000001\n" + "r12/15 00000000'40013EE8 00000000'08000080 00000000'4002530C 00000000'" + "4002530C\n" + "r16/19 00000000'7F7F2A00 00000000'00000001 00000000'00000000 00000000'" + "00000000\n" + "r20/23 00000000'006C8048 00000000'00000001 00000000'00000000 00000000'" + "00000000\n" + "r24/27 00000000'00000000 00000000'00000000 00000000'00000000 00000000'" + "00744378\n" + "r28/31 00000000'00000000 00000000'007DD628 00000000'0199F2B0 00000000'" + "00000000\n" + " CONTROL REGISTERS:\n" + "sr0/3 00000000'0F3B4000 00000000'0C2A2000 00000000'016FF800 00000000'" + "00000000\n" + "sr4/7 00000000'00000000 00000000'016FF800 00000000'0DBF1400 00000000'" + "00000000\n" + "pcq = 00000000'00000000.00000000'00104950 00000000'00000000.00000000'" + "00104A14\n" + "isr = 00000000'10240006 ior = 00000000'67D9E220 iir = 08000240 rctr = " + "7FF10BB6\n" + "\n" + "pid reg cr8/cr9 00007700'0000B3A9 00000000'0000C5D8\n" + "pid reg cr12/cr13 00000000'00000000 00000000'00000000\n" + "ipsw = 000000FF'080CFF1F iva = 00000000'0002C000 sar = 3A ccr = C0\n" + "tr0/3 00000000'006C76C0 00000000'00000001 00000000'00000000 00000000'" + "7F7CE000\n" + "tr4/7 00000000'03790000 0000000C'4FB68340 00000000'C07EE13F 00000000'" + "0199F2B0\n" + "eiem = FFFFFFF0'FFFFFFFF eirr = 80000000'00000000 itmr = 0000000C'" + "4FD8EDE1\n" + "cr1/4 00000000'00000000 00000000'00000000 00000000'00000000 00000000'" + "00000000\n" + "cr5/7 00000000'00000000 00000000'00000000 00000000'" + "00000000\n" + " MACHINE CHECK PARAMETERS:\n" + "Check Type = 00000000 CPU STATE = 9E000001 Cache Check = 00000000\n" + "TLB Check = 00000000 Bus Check = 00000000 PIM State = ? SIU " + "Status = ????????\n" + "Assists = 00000000 Processor = 00000000\n" + "Slave Addr = 00000000'00000000 Master Addr = 00000000'00000000\n" + "\n" + "\n" + "TOC, pcsq.pcoq = 0'0.0'104950 , isr.ior = 0'10240006.0'67d9e220\n" + "@(#)B2352B/9245XB HP-UX (B.11.00) #1: Wed Nov 5 22:38:19 PST 1997\n" + "Transfer of control: (display==0xd904, flags==0x0)\n" + "\n" + "\n" + "\n" + "*** A system crash has occurred. (See the above messages for details.)\n" + "*** The system is now preparing to dump physical memory to disk, for use\n" + "*** in debugging the crash.\n" + "\n" + "*** The dump will be a SELECTIVE dump: 40 of 256 megabytes.\n" + "*** To change this dump type, press any key within 10 seconds.\n" + "*** Proceeding with selective dump.\n" + "\n" + "*** The dump may be aborted at any time by pressing ESC.\n"; + const char *msg2 = + "\n*** System rebooting.\n"; + + XGetWindowAttributes (dpy, window, &xgwa); + ts = make_scrolling_window (dpy, window, "HPUX", False); + ts->columns = 10000; /* never wrap */ + ts->sub_x = 0; + ts->sub_y = 0; + ts->sub_width = xgwa.width; + ts->sub_height = xgwa.height; + + sysname = "HPUX"; +# ifdef HAVE_UNAME + { + struct utsname uts; + char *s; + if (uname (&uts) >= 0) + sysname = uts.nodename; + s = strchr (sysname, '.'); + if (s) *s = 0; + } +# endif /* !HAVE_UNAME */ + + gcv.foreground = get_pixel_resource ("HPUX.foreground", "HPUX.Foreground", + dpy, xgwa.colormap); + gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv); + XFillRectangle (dpy, window, gc, 0, 0, xgwa.width, xgwa.height); + if (bsod_sleep (dpy, 1)) + goto DONE; + + scrolling_puts (ts, + " " + " " + " \n", + 0); + sprintf (buf, "%.100s [HP Release B.11.00] (see /etc/issue)\n", sysname); + scrolling_puts (ts, buf, 0); + if (bsod_sleep (dpy, 1)) + goto DONE; + scrolling_puts (ts, msg1, 0); + { + int i; + int steps = 11; + int size = 40; + for (i = 0; i <= steps; i++) + { + if (i > steps) i = steps; + sprintf (buf, + "*** Dumping: %3d%% complete (%d of 40 MB) (device 64:0x2)\r", + i * 100 / steps, + i * size / steps); + scrolling_puts (ts, buf, 0); + XSync (dpy, False); + usleep (1500000); + if (bsod_sleep (dpy, 0)) + goto DONE; + } + } + + scrolling_puts (ts, msg2, 0); + + XSync(dpy, False); + bsod_sleep(dpy, delay); + + DONE: + free_scrolling_window (ts); +} + + + +/* IBM OS/390 aka MVS aka z/OS. + Text from Dan Espen . + Apparently this isn't actually a crash, just a random session... + But who can tell. + */ + +static void +os390 (Display* dpy, Window window, int delay) +{ + GC gc; + XGCValues gcv; + XWindowAttributes xgwa; + scrolling_window *ts; + int i; + + const char *msg[] = { + "* ISPF Subtask abend *\n", + "SPF ENDED DUE TO ERROR+\n", + "READY\n", + "\n", + "IEA995I SYMPTOM DUMP OUTPUT\n", + " USER COMPLETION CODE=0222\n", + " TIME=23.00.51 SEQ=03210 CPU=0000 ASID=00AE\n", + " PSW AT TIME OF ERROR 078D1000 859DAF18 ILC 2 INTC 0D\n", + " NO ACTIVE MODULE FOUND\n", + " NAME=UNKNOWN\n", + " DATA AT PSW 059DAF12 - 00181610 0A0D9180 70644710\n", + " AR/GR 0: 00000000/80000000 1: 00000000/800000DE\n", + " 2: 00000000/196504DC 3: 00000000/00037A78\n", + " 4: 00000000/00037B78 5: 00000000/0003351C\n", + " 6: 00000000/0000F0AD 7: 00000000/00012000\n", + " 8: 00000000/059DAF10 9: 00000000/0002D098\n", + " A: 00000000/059D9F10 B: 00000000/059D8F10\n", + " C: 00000000/859D7F10 D: 00000000/00032D60\n", + " E: 00000000/00033005 F: 01000002/00000041\n", + " END OF SYMPTOM DUMP\n", + "ISPS014 - ** Logical screen request failed - abend 0000DE **\n", + "ISPS015 - ** Contact your system programmer or dialog developer.**\n", + "*** ISPF Main task abend ***\n", + "IEA995I SYMPTOM DUMP OUTPUT\n", + " USER COMPLETION CODE=0222\n", + " TIME=23.00.52 SEQ=03211 CPU=0000 ASID=00AE\n", + " PSW AT TIME OF ERROR 078D1000 8585713C ILC 2 INTC 0D\n", + " ACTIVE LOAD MODULE ADDRESS=05855000 OFFSET=0000213C\n", + " NAME=ISPMAIN\n", + " DATA AT PSW 05857136 - 00181610 0A0D9180 D3304770\n", + " GR 0: 80000000 1: 800000DE\n", + " 2: 00015260 3: 00000038\n", + " 4: 00012508 5: 00000000\n", + " 6: 000173AC 7: FFFFFFF8\n", + " 8: 05858000 9: 00012CA0\n", + " A: 05857000 B: 05856000\n", + " C: 85855000 D: 00017020\n", + " E: 85857104 F: 00000000\n", + " END OF SYMPTOM DUMP\n", + "READY\n", + "***_\n" + }; + + XGetWindowAttributes (dpy, window, &xgwa); + ts = make_scrolling_window (dpy, window, "OS390", False); + ts->columns = 10000; /* never wrap */ + ts->sub_x = 0; + ts->sub_y = 0; + ts->sub_width = xgwa.width; + ts->sub_height = xgwa.height; + + gcv.foreground = get_pixel_resource ("390.background", "390.Background", + dpy, xgwa.colormap); + gc = XCreateGC (dpy, window, GCForeground, &gcv); + XFillRectangle (dpy, window, gc, 0, 0, xgwa.width, xgwa.height); + XFreeGC (dpy, gc); + + for (i = 0; i < countof (msg); i++) + { + scrolling_puts (ts, msg[i], 0); + usleep (100000); + if (bsod_sleep(dpy, 0)) goto DONE; + } + + XSync(dpy, False); + bsod_sleep(dpy, delay); +DONE: + free_scrolling_window (ts); +} + + + +/* + * Simulate various Apple II crashes. The memory map encouraged many + * programs to use the primary hi-res video page for various storage, + * and the secondary hi-res page for active display. When it crashed + * into Applesoft or the monitor, it would revert to the primary page + * and you'd see memory garbage on the screen. Also, it was common for + * copy-protected games to use the primary text page for important + * code, because that made it really hard to reverse-engineer them. The + * result often looked like what this generates. + * + * Sometimes an imaginary user types some of the standard commands to + * recover from crashes. You can turn off BSOD*apple2SimulateUser to + * prevent this. + * + * It simulates the following characteristics of standard television + * monitors: + * + * - Realistic rendering of a composite video signal + * - Compression & brightening on the right, as the scan gets truncated + * because of saturation in the flyback transformer + * - Blooming of the picture dependent on brightness + * - Overscan, cutting off a few pixels on the left side. + * - Colored text in mixed graphics/text modes + * + * It's amazing how much it makes your high-end monitor look like at + * large late-70s TV. All you need is to put a big "Solid State" logo + * in curly script on it and you'd be set. + * + * Trevor Blackwell + */ + +/* + * Implementation notes: + * + * There are roughly 3 parts to this hack: + * + * - emulation of A2 Basic and Monitor. Not much more than printing random + * plausible messages. Here we work in the A2 memory space. + * + * - emulation of the A2's video output section, which shifted bits out of main + * memory at a 14 MHz dot clock rate, sort of. You could only read one byte + * per MHz, so there were various schemes for turning 8 bits into 14 screen + * pixels. + * + * - simulation of an NTSC television, which turned the bits into colored + * graphics and text. + * + * The A2 had 3 display modes: text, lores, and hires. Text was 40x24, and it + * disabled color in the TV. Lores gave you 40x48 graphics blocks, using the + * same memory as the text screen. Each could be one of 16 colors. Hires gave + * you 280x192 pixels. Odd pixels were blue or purple, and even pixels were + * orange or green depending on the setting of the high bit in each byte. + * + * The graphics modes could also have 4 lines of text at the bottom. This was + * fairly unreadable if you had a color monitor. + * + * Each mode had 2 different screens using different memory space. In hires + * mode this was sometimes used for double buffering, but more often the lower + * screen was full of code/data and the upper screen was used for display, so + * you got random garbage on the screen. + * + * In DirectColor or TrueColor modes, it generates pixel values directly from + * RGB values it calculates across each scan line. In PseudoColor mode, it + * consider each possible pattern of 5 preceding bit values in each possible + * position modulo 4 and allocates a color for each. A few things, like the + * brightening on the right side as the horizontal trace slows down, aren't + * done in PseudoColor. + * + * The text font is based on X's standard 6x10 font, with a few tweaks like + * putting a slash across the zero. + * + * I'd like to add a bit of visible retrace, but it conflicts with being able + * to bitcopy the image when fast scrolling. After another couple of CPU + * generations, we could probably regenerate the whole image from scratch every + * time. On a P4 2 GHz it can manage this fine for blinking text, but scrolling + * looks too slow. + */ + +static char * apple2_basic_errors[]={ + "BREAK", + "NEXT WITHOUT FOR", + "SYNTAX ERROR", + "RETURN WITHOUT GOSUB", + "ILLEGAL QUANTITY", + "OVERFLOW", + "OUT OF MEMORY", + "BAD SUBSCRIPT ERROR", + "DIVISION BY ZERO", + "STRING TOO LONG", + "FORMULA TOO COMPLEX", + "UNDEF'D FUNCTION", + "OUT OF DATA" +}; +static char * apple2_dos_errors[]={ + "VOLUME MISMATCH", + "I/O ERROR", + "DISK FULL", + "NO BUFFERS AVAILABLE", + "PROGRAM TOO LARGE", +}; + +struct apple2_state { + char hireslines[192][40]; + char textlines[24][40]; + int gr_text; + enum { + A2_GR_FULL=1, + A2_GR_LORES=2, + A2_GR_HIRES=4 + } gr_mode; + int cursx; + int cursy; + int blink; + int rowimage[24]; +}; + +enum { + A2_SP_ROWMASK=1023, + A2_SP_PUT=1024, + A2_SP_COPY=2048, +}; + +static void +a2_scroll(struct apple2_state *st) +{ + int i; + int top=(st->gr_mode&(A2_GR_LORES|A2_GR_HIRES)) ? 20 : 0; + if ((st->gr_mode&A2_GR_FULL) && (st->gr_mode&A2_GR_HIRES)) return; + if (st->gr_mode&A2_GR_FULL) top=0; + for (i=top; i<23; i++) { + if (memcmp(st->textlines[i],st->textlines[i+1],40)) { + memcpy(st->textlines[i],st->textlines[i+1],40); + st->rowimage[i]=st->rowimage[i+1]; + } + } + memset(st->textlines[23],0xe0,40); + st->rowimage[23]=-1; +} + +static void +a2_printc(struct apple2_state *st, char c) +{ + st->textlines[st->cursy][st->cursx] |= 0xc0; /* turn off blink */ + if (c=='\n') { + if (st->cursy==23) { + a2_scroll(st); + } else { + st->rowimage[st->cursy]=-1; + st->cursy++; + st->rowimage[st->cursy]=-1; + } + st->cursx=0; + } else { + st->textlines[st->cursy][st->cursx]=c ^ 0xc0; + st->rowimage[st->cursy]=-1; + st->cursx++; + if (st->cursx==40) { + if (st->cursy==23) { + a2_scroll(st); + } else { + st->rowimage[st->cursy]=-1; + st->cursy++; + st->rowimage[st->cursy]=-1; + } + st->cursx=0; + } + } + st->textlines[st->cursy][st->cursx] &= 0x7f; /* turn on blink */ +} + +static void +a2_goto(struct apple2_state *st, int r, int c) +{ + st->textlines[st->cursy][st->cursx] |= 0xc0; /* turn off blink */ + st->cursy=r; + st->cursx=c; + st->textlines[st->cursy][st->cursx] &= 0x7f; /* turn on blink */ +} + +static void +a2_cls(struct apple2_state *st) +{ + int i; + for (i=0; i<24; i++) { + memset(st->textlines[i],0xe0,40); + st->rowimage[i]=-1; + } +} + +static void +a2_invalidate(struct apple2_state *st) +{ + int i; + for (i=0; i<24; i++) { + st->rowimage[i]=-1; + } +} + +static void +a2_poke(struct apple2_state *st, int addr, int val) +{ + + if (addr>=0x400 && addr<0x800) { + /* text memory */ + int row=((addr&0x380)/0x80) + ((addr&0x7f)/0x28)*8; + int col=(addr&0x7f)%0x28; + if (row<24 && col<40) { + st->textlines[row][col]=val; + if (!(st->gr_mode&(A2_GR_HIRES)) || + (!(st->gr_mode&(A2_GR_FULL)) && row>=20)) { + st->rowimage[row]=-1; + } + } + } + else if (addr>=0x2000 && addr<0x4000) { + int row=(((addr&0x1c00) / 0x400) * 1 + + ((addr&0x0380) / 0x80) * 8 + + ((addr&0x0078) / 0x28) * 64); + int col=((addr&0x07f)%0x28); + if (row<192 && col<40) { + st->hireslines[row][col]=val; + if (st->gr_mode&A2_GR_HIRES) { + st->rowimage[row/8]=-1; + } + } + } +} + +/* This table lists fixes for characters that differ from the standard 6x10 + font. Each encodes a pixel, as (charindex*7 + x) + (y<<10) + (value<<15) + where value is 0 for white and 1 for black. */ +static unsigned short a2_fixfont[] = { + /* Fix $ */ 0x8421, 0x941d, + /* Fix % */ 0x8024, 0x0028, 0x8425, 0x0426, 0x0825, 0x1027, 0x1426, 0x9427, + 0x1824, 0x9828, + /* Fix * */ 0x8049, 0x8449, 0x8849, 0x0c47, 0x0c48, 0x0c4a, 0x0c4b, 0x9049, + 0x9449, 0x9849, + /* Fix , */ 0x9057, 0x1458, 0x9856, 0x1857, 0x1c56, + /* Fix . */ 0x1465, 0x1864, 0x1866, 0x1c65, + /* Fix / */ 0x006e, 0x186a, + /* Fix 0 */ 0x8874, 0x8c73, 0x9072, + /* Fix 1 */ 0x0878, 0x1878, 0x187c, + /* Fix 5 */ 0x8895, 0x0c94, 0x0c95, + /* Fix 6 */ 0x809f, 0x8c9c, 0x109c, + /* Fix 7 */ 0x8ca4, 0x0ca5, 0x90a3, 0x10a4, + /* Fix 9 */ 0x08b3, 0x8cb3, 0x98b0, + /* Fix : */ 0x04b9, 0x08b8, 0x08ba, 0x0cb9, 0x90b9, 0x14b9, 0x18b8, 0x18b9, + 0x18ba, 0x1cb9, + /* Fix ; */ 0x04c0, 0x08bf, 0x08c1, 0x0cc0, 0x90c0, 0x14c1, 0x98bf, 0x18c0, + 0x1cbf, + /* Fix < */ 0x80c8, 0x00c9, 0x84c7, 0x04c8, 0x88c6, 0x08c7, 0x8cc5, 0x0cc6, + 0x90c6, 0x10c7, + 0x94c7, 0x14c8, 0x98c8, 0x18c9, + /* Fix > */ 0x80d3, 0x00d4, 0x84d4, 0x04d5, 0x88d5, 0x08d6, 0x8cd6, 0x0cd7, + 0x90d5, 0x10d6, + 0x94d4, 0x14d5, 0x98d3, 0x18d4, + /* Fix @ */ 0x88e3, 0x08e4, 0x8ce4, 0x98e5, + /* Fix B */ 0x84ef, 0x04f0, 0x88ef, 0x08f0, 0x8cef, 0x90ef, 0x10f0, 0x94ef, + 0x14f0, + /* Fix D */ 0x84fd, 0x04fe, 0x88fd, 0x08fe, 0x8cfd, 0x0cfe, 0x90fd, 0x10fe, + 0x94fd, 0x14fe, + /* Fix G */ 0x8116, 0x0516, 0x9916, + /* Fix J */ 0x0129, 0x012a, 0x052a, 0x852b, 0x092a, 0x892b, 0x0d2a, 0x8d2b, + 0x112a, 0x912b, + 0x152a, 0x952b, 0x992a, + /* Fix M */ 0x853d, 0x853f, 0x093d, 0x893e, 0x093f, + /* Fix Q */ 0x915a, 0x155a, 0x955b, 0x155c, 0x195b, 0x995c, 0x1d5c, + /* Fix V */ 0x8d7b, 0x0d7c, 0x0d7e, 0x8d7f, 0x917b, 0x117c, 0x117e, 0x917f, + /* Fix [ */ 0x819e, 0x81a2, 0x859e, 0x899e, 0x8d9e, 0x919e, 0x959e, 0x999e, + 0x99a2, + /* Fix \ */ 0x01a5, 0x19a9, + /* Fix ] */ 0x81ac, 0x81b0, 0x85b0, 0x89b0, 0x8db0, 0x91b0, 0x95b0, 0x99ac, + 0x99b0, + /* Fix ^ */ 0x01b5, 0x05b4, 0x05b6, 0x09b3, 0x89b5, 0x09b7, 0x8db4, 0x8db6, + 0x91b3, 0x91b7, + /* Fix _ */ 0x9db9, 0x9dbf, + 0, +}; + +struct ntsc_dec { + char pattern[600]; + int ntscy[600]; + int ntsci[600]; + int ntscq[600]; + int multi[600]; + int multq[600]; + int brightness_control; +}; + +/* + First generate the I and Q reference signals, which we'll multiply by the + input signal to accomplish the demodulation. Normally they are shifted 33 + degrees from the colorburst. I think this was convenient for + inductor-capacitor-vacuum tube implementation. + + The tint control, FWIW, just adds a phase shift to the chroma signal, and + the color control controls the amplitude. + + In text modes (colormode==0) the system disabled the color burst, and no + color was detected by the monitor. + + freq_error gives a mismatch between the built-in oscillator and the TV's + colorbust. Older II Plus machines seemed to occasionally get instability + problems -- the crystal oscillator was a single transistor if I remember + correctly -- and the frequency would vary enough that the tint would change + across the width of the screen. The left side would be in correct tint + because it had just gotten resynchronized with the color burst. +*/ +static void +ntsc_set_demod(struct ntsc_dec *it, double tint_control, + double color_control, double brightness_control, + double freq_error, + int colormode) +{ + int i; + + it->brightness_control=(int)(1024.0*brightness_control); + + for (i=0; i<600; i++) { + double phase=90.0-90.0*i + freq_error*i/600.0 + tint_control; + it->multi[i]=(int)(-cos(3.1415926/180.0*(phase-303)) * 65536.0 * + color_control * colormode * 4); + it->multq[i]=(int)(cos(3.1415926/180.0*(phase-33)) * 65536.0 * + color_control * colormode * 4); + } +} + +/* Here we model the analog circuitry of an NTSC television. Basically, it + splits the signal into 3 signals: Y, I and Q. Y corresponds to luminance, + and you get it by low-pass filtering the input signal to below 3.57 MHz. + + I and Q are the in-phase and quadrature components of the 3.57 MHz + subcarrier. We get them by multiplying by cos(3.57 MHz*t) and sin(3.57 + MHz*t), and low-pass filtering. Because the eye has less resolution in some + colors than others, the I component gets low-pass filtered at 1.5 MHz and + the Q at 0.5 MHz. The I component is approximately orange-blue, and Q is + roughly purple-green. See http://www.ntsc-tv.com for details. + */ +static void +ntsc_to_yiq(struct ntsc_dec *it) +{ + int i; + int fyx[10],fyy[10]; + int fix[10],fiy[10]; + int fqx[10],fqy[10]; + int pixghost; + int iny,ini,inq,pix,blank; + + for (i=0; i<10; i++) fyx[i]=fyy[i]=fix[i]=fiy[i]=fqx[i]=fqy[i]=0.0; + pixghost=0; + for (i=0; i<600; i++) { + /* Get the video out signal, and add a teeny bit of ghosting, typical of RF + monitor cables. This corresponds to a pretty long cable, but looks right + to me. */ + pix=it->pattern[i]*1024; + if (i>=20) pixghost += it->pattern[i-20]*15; + if (i>=30) pixghost -= it->pattern[i-30]*15; + pix += pixghost; + + /* Get Y, I, Q before filtering */ + iny=pix; + ini=(pix*it->multi[i])>>16; + inq=(pix*it->multq[i])>>16; + + blank = (i>=7 && i<596 ? it->brightness_control : -200); + + /* Now filter them. These are infinite impulse response filters calculated + by the script at http://www-users.cs.york.ac.uk/~fisher/mkfilter. This + is fixed-point integer DSP, son. No place for wimps. We do it in integer + because you can count on integer being faster on most CPUs. We care + about speed because we need to recalculate every time we blink text, and + when we spew random bytes into screen memory. This is roughly 16.16 + fixed point arithmetic, but we scale some filter values up by a few bits + to avoid some nasty precision errors. */ + + /* Filter y at with a 4-pole low-pass Butterworth filter at 3.5 MHz + with an extra zero at 3.5 MHz, from + mkfilter -Bu -Lp -o 4 -a 2.1428571429e-01 0 -Z 2.5e-01 -l + Delay about 2 */ + + fyx[0] = fyx[1]; fyx[1] = fyx[2]; fyx[2] = fyx[3]; + fyx[3] = fyx[4]; fyx[4] = fyx[5]; fyx[5] = fyx[6]; + fyx[6] = (iny * 1897) >> 13; + fyy[0] = fyy[1]; fyy[1] = fyy[2]; fyy[2] = fyy[3]; + fyy[3] = fyy[4]; fyy[4] = fyy[5]; fyy[5] = fyy[6]; + fyy[6] = (fyx[0]+fyx[6]) + 4*(fyx[1]+fyx[5]) + 7*(fyx[2]+fyx[4]) + 8*fyx[3] + + ((-151*fyy[2] + 8115*fyy[3] - 38312*fyy[4] + 36586*fyy[5]) >> 16); + if (i>=2) it->ntscy[i-2] = blank + (fyy[6]>>3); + + /* Filter I and Q at 1.5 MHz. 3 pole Butterworth from + mkfilter -Bu -Lp -o 3 -a 1.0714285714e-01 0 + Delay about 3. + + The NTSC spec says the Q value should be filtered at 0.5 MHz at the + transmit end, But the Apple's video circuitry doesn't any such thing. + AFAIK, oldish televisions (before comb filters) simply applied a 1.5 MHz + filter to both after the demodulator. + */ + + fix[0] = fix[1]; fix[1] = fix[2]; fix[2] = fix[3]; + fix[3] = (ini * 1413) >> 14; + fiy[0] = fiy[1]; fiy[1] = fiy[2]; fiy[2] = fiy[3]; + fiy[3] = (fix[0]+fix[3]) + 3*(fix[1]+fix[2]) + + ((16559*fiy[0] - 72008*fiy[1] + 109682*fiy[2]) >> 16); + if (i>=3) it->ntsci[i-3] = fiy[3]>>2; + + fqx[0] = fqx[1]; fqx[1] = fqx[2]; fqx[2] = fqx[3]; + fqx[3] = (inq * 1413) >> 14; + fqy[0] = fqy[1]; fqy[1] = fqy[2]; fqy[2] = fqy[3]; + fqy[3] = (fqx[0]+fqx[3]) + 3*(fqx[1]+fqx[2]) + + ((16559*fqy[0] - 72008*fqy[1] + 109682*fqy[2]) >> 16); + if (i>=3) it->ntscq[i-3] = fqy[3]>>2; + + } + for (; i<610; i++) { + if (i-2<600) it->ntscy[i-2]=0; + if (i-3<600) it->ntsci[i-3]=0; + if (i-9<600) it->ntscq[i-9]=0; + } +} + +enum { + A2_CMAP_HISTBITS=5, + A2_CMAP_LEVELS=2, + A2_CMAP_OFFSETS=4, +}; + +#define A2_CMAP_INDEX(COLORMODE, LEVEL, HIST, OFFSET) \ +((((COLORMODE)*A2_CMAP_LEVELS+(LEVEL))<class; + red_shift=red_invprec=green_shift=green_invprec=blue_shift=blue_invprec=-1; + if (visclass == TrueColor || xgwa.visual->class == DirectColor) { + use_cmap=0; + use_color=!mono_p; + } + else if (visclass == PseudoColor || visclass == StaticColor) { + use_cmap=1; + use_color=!mono_p; + } + else { + use_cmap=1; + use_color=0; + } + + /* The Apple II screen was 280x192, sort of. We expand the width to 300 + pixels to allow for overscan. We then pick a size within the window + that's an integer multiple of 300x192. The small case happens when + we're displaying in a subwindow. Then it ends up showing the center + of the screen, which is OK. */ + w=xgwa.width; + h = (xgwa.height/192)*192; + if (w<300) w=300; + if (h==0) h=192; + + dec=(struct ntsc_dec *)malloc(sizeof(struct ntsc_dec)); + + if (use_cmap) { + int hist,offset,level; + int colorprec=8; + + cmap_again: + n_colors=0; + /* Typically allocates 214 distinct colors, but will scale back its + ambitions pretty far if it can't get them */ + for (colormode=0; colormode<=use_color; colormode++) { + ntsc_set_demod(dec, tint_control, color_control, brightness_control, + 0.0, colormode); + for (level=0; level<2; level++) { + for (hist=0; hist<(1<pattern[i]=0; + for (i=0; ipattern[64+offset-i]=(hist>>i)&1; + } + + ntsc_to_yiq(dec); + interpy=dec->ntscy[63+offset]; + interpi=dec->ntsci[63+offset]; + interpq=dec->ntscq[63+offset]; + + r=(interpy + ((+68128*interpi+40894*interpq)>>16))*levelmult; + g=(interpy + ((-18087*interpi-41877*interpq)>>16))*levelmult; + b=(interpy + ((-72417*interpi+113312*interpq)>>16))*levelmult; + if (r<0) r=0; + if (r>65535) r=65535; + if (g<0) g=0; + if (g>65535) g=65535; + if (b<0) b=0; + if (b>65535) b=65535; + + col.red=r & precmask; + col.green=g & precmask; + col.blue=b & precmask; + col.pixel=0; + if (!XAllocColor(dpy, xgwa.colormap, &col)) { + XFreeColors(dpy, xgwa.colormap, colors, n_colors, 0L); + n_colors=0; + colorprec--; + if (colorprec<3) { + goto bailout; + } + goto cmap_again; + } + colors[n_colors++]=col.pixel; + } + } + } + } + } else { + /* Is there a standard way to do this? Does this handle all cases? */ + int shift, prec; + for (shift=0; shift<32; shift++) { + for (prec=1; prec<16 && prec<32-shift; prec++) { + unsigned long mask=(0xffffUL>>(16-prec)) << shift; + if (red_shift<0 && mask==xgwa.visual->red_mask) + red_shift=shift, red_invprec=16-prec; + if (green_shift<0 && mask==xgwa.visual->green_mask) + green_shift=shift, green_invprec=16-prec; + if (blue_shift<0 && mask==xgwa.visual->blue_mask) + blue_shift=shift, blue_invprec=16-prec; + } + } + if (red_shift<0 || green_shift<0 || blue_shift<0) { + if (0) fprintf(stderr,"Can't figure out color space\n"); + goto bailout; + } + raw_rgb=(short *)calloc(w*3, sizeof(short)); + } + + gcv.background=0; + gc = XCreateGC(dpy, window, GCBackground, &gcv); + XSetWindowBackground(dpy, window, gcv.background); + XClearWindow(dpy,window); + + screen_xo=(xgwa.width-w)/2; + screen_yo=(xgwa.height-h)/2; + + if (use_shm) { +#ifdef HAVE_XSHM_EXTENSION + image = create_xshm_image (dpy, xgwa.visual, xgwa.depth, ZPixmap, 0, + &shm_info, w, h); +#endif + if (!image) { + fprintf(stderr, "create_xshm_image failed\n"); + use_shm=0; + } + } + if (!image) { + image = XCreateImage(dpy, xgwa.visual, xgwa.depth, ZPixmap, 0, 0, + w, h, 8, 0); + image->data = (char *)calloc(image->height, image->bytes_per_line); + } + + st=(struct apple2_state *)calloc(1,sizeof(struct apple2_state)); + + /* + Generate the font. It used a 5x7 font which looks a lot like the standard X + 6x10 font, with a few differences. So we render up all the uppercase + letters of 6x10, and make a few tweaks (like putting a slash across the + zero) according to fixfont. + */ + { + const char *def_font="6x10"; + XFontStruct *font; + Pixmap text_pm; + GC gc; + + font = XLoadQueryFont (dpy, def_font); + if (!font) { + fprintf(stderr,"Can't load font %s\n",def_font); + goto bailout; + } + + text_pm=XCreatePixmap(dpy, window, 64*7, 8, xgwa.depth); + + gcv.foreground=1; + gcv.background=0; + gcv.font=font->fid; + gc=XCreateGC(dpy, text_pm, GCFont|GCBackground|GCForeground, &gcv); + + XSetForeground(dpy, gc, 0); + XFillRectangle(dpy, text_pm, gc, 0, 0, 64*7, 8); + XSetForeground(dpy, gc, 1); + for (i=0; i<64; i++) { + char c=32+i; + int x=7*i+1; + int y=7; + if (c=='0') { + c='O'; + XDrawString(dpy, text_pm, gc, x, y, &c, 1); + } else { + XDrawString(dpy, text_pm, gc, x, y, &c, 1); + } + } + text_im = XGetImage(dpy, text_pm, 0, 0, 64*7, 8, ~0L, ZPixmap); + XFreeGC(dpy, gc); + XFreePixmap(dpy, text_pm); + + for (i=0; a2_fixfont[i]; i++) { + XPutPixel(text_im, a2_fixfont[i]&0x3ff, + (a2_fixfont[i]>>10)&0xf, + (a2_fixfont[i]>>15)&1); + } + } + + /* + Simulate plausible initial memory contents. + */ + { + int addr=0; + while (addr<0x4000) { + int n; + + switch (random()%4) { + case 0: + case 1: + n=random()%500; + for (i=0; iwidth); + for (i=0; i<100; i++) { + for (y=0; y<8; y++) { + c=0; + for (j=0; j<8; j++) { + c |= XGetPixel(text_im, (x+j)%text_im->width, y)<width); + } + break; + + case 3: + if (addr>0x2000) { + n=random()%200; + for (i=0; ibits_per_rgb>=8) { + flutter_tint=1; + } + else if (random()%3==0) { + flutter_horiz_desync=1; + } + + crtload[0]=0.0; + stepno=0; + a2_goto(st,23,0); + gettimeofday(&basetime_tv, NULL); + if (random()%2==0) basetime_tv.tv_sec -= 1; /* random blink phase */ + next_actiontime=0.0; + fillptr=fillbyte=0; + while (1) { + double curtime,blinkphase; + int startdisplayrow=0; + int cheapdisplay=0; + int nodelay=0; + { + struct timeval curtime_tv; + gettimeofday(&curtime_tv, NULL); + curtime=(curtime_tv.tv_sec - basetime_tv.tv_sec) + + 0.000001*(curtime_tv.tv_usec - basetime_tv.tv_usec); + } + if (curtime>delay) goto finished; + + if (bsod_sleep(dpy,0)) goto finished; + + if (flutter_tint && st->gr_mode && !printing) { + /* Oscillator instability. Look for freq_error below. We should only do + this with color depth>=8, since otherwise you see pixels changing. */ + freq_error_inc += (-0.10*freq_error_inc + + ((int)(random()&0xff)-0x80) * 0.01); + freq_error += freq_error_inc; + a2_invalidate(st); + nodelay=1; + } + else if (flutter_horiz_desync) { + /* Horizontal sync during vertical sync instability. */ + horiz_desync += (-0.10*(horiz_desync-3.0) + + ((int)(random()&0xff)-0x80) * + ((int)(random()&0xff)-0x80) * + ((int)(random()&0xff)-0x80) * 0.0000003); + for (i=0; i<3; i++) st->rowimage[i]=-1; + nodelay=1; + } + + /* It's super-important to get the cursor/text flash out at exactly the + right time, or it looks wrong. So if we're almost due for a blink, wait + for it so we don't miss it in the middle of a screen update. */ + blinkphase=curtime/0.8; + if (blinkphase-floor(blinkphase)>0.7 && !printing && !nodelay) { + /* We're about to blink */ + int delay = ((1.0-(blinkphase-floor(blinkphase)))*0.8) * 1000000; + if (delay<1000) delay=1000; + usleep(delay); + continue; + } + + /* The blinking rate was controlled by 555 timer with a resistor/capacitor + time constant. Because the capacitor was electrolytic, the flash rate + varied somewhat between machines. I'm guessing 1.6 seconds/cycle was + reasonable. (I soldered a resistor in mine to make it blink faster.) */ + i=st->blink; + st->blink=((int)blinkphase)&1; + if (st->blink!=i && !(st->gr_mode&A2_GR_FULL)) { + int downcounter=0; + /* For every row with blinking text, set the changed flag. This basically + works great except with random screen garbage in text mode, when we + end up redrawing the whole screen every second */ + for (row=(st->gr_mode ? 20 : 0); row<24; row++) { + for (col=0; col<40; col++) { + c=st->textlines[row][col]; + if ((c & 0xc0) == 0x40) { + downcounter=4; + break; + } + } + if (downcounter>0) { + st->rowimage[row]=-1; + downcounter--; + } + } + st->rowimage[st->cursy]=-1; + startdisplayrow=random()%24; + } + else if (next_actiontime > curtime && !printing && !nodelay) { + int delay = (next_actiontime-curtime)*1000000; + + if (delay>100000) delay=100000; + if (delay<1000) delay=1000; + usleep(delay); + continue; + } + + if (printing) { + cheapdisplay=1; + while (*printing) { + if (*printing=='\001') { /* pause */ + printing++; + for (i=20; i<24; i++) st->rowimage[i]=-1; + break; + } + else if (*printing=='\n') { + a2_printc(st,*printing); + printing++; + break; + } + else { + a2_printc(st,*printing); + printing++; + } + } + if (!*printing) printing=NULL; + } + else if (curtime >= next_actiontime) { + if (typing) { + /* If we're in the midst of typing a string, emit a character with + random timing. */ + a2_printc(st, *typing); + if (*typing=='\n') { + next_actiontime = curtime; + } else { + next_actiontime = curtime + (random()%1000)*0.0003 + 0.3; + } + typing++; + + if (!*typing) typing=NULL; + + } + else { + next_actiontime=curtime; + + switch(stepno) { + case 0: + a2_invalidate(st); + if (0) { + /* + For testing color rendering. The spec is: + red grn blu + 0 black 0 0 0 + 1 red 227 30 96 + 2 dk blue 96 78 189 + 3 purple 255 68 253 + 4 dk green 0 163 96 + 5 gray 156 156 156 + 6 med blue 20 207 253 + 7 lt blue 208 195 255 + 8 brown 96 114 3 + 9 orange 255 106 60 + 10 grey 156 156 156 + 11 pink 255 160 208 + 12 lt green 20 245 60 + 13 yellow 208 221 141 + 14 aqua 114 255 208 + 15 white 255 255 255 + */ + st->gr_mode=A2_GR_LORES; + for (row=0; row<24; row++) { + for (col=0; col<40; col++) { + st->textlines[row][col]=(row&15)*17; + } + } + next_actiontime+=0.4; + stepno=88; + } + else if (random()%3==0) { + st->gr_mode=0; + next_actiontime+=0.4; + stepno=88; + } + else if (random()%4==0) { + st->gr_mode=A2_GR_LORES; + if (random()%3==0) st->gr_mode |= A2_GR_FULL; + next_actiontime+=0.4; + stepno=88; + } + else if (random()%2==0) { + st->gr_mode=A2_GR_HIRES; + stepno=73; + } + else { + st->gr_mode=A2_GR_HIRES; + next_actiontime+=0.4; + stepno=88; + } + break; + + case 88: + /* An illegal instruction or a reset caused it to drop into the + assembly language monitor, where you could disassemble code & view + data in hex. */ + if (random()%3==0) { + char ibytes[128]; + char itext[128]; + int addr=0xd000+random()%0x3000; + sprintf(ibytes, + "%02X",random()%0xff); + sprintf(itext, + "???"); + sprintf(printbuf, + "\n\n" + "%04X: %-15s %s\n" + " A=%02X X=%02X Y=%02X S=%02X F=%02X\n" + "*", + addr,ibytes,itext, + random()%0xff, random()%0xff, + random()%0xff, random()%0xff, + random()%0xff); + printing=printbuf; + a2_goto(st,23,1); + if (st->gr_mode) { + stepno=11; + } else { + stepno=13; + } + prompt='*'; + next_actiontime += 2.0 + (random()%1000)*0.0002; + } + else { + /* Lots of programs had at least their main functionality in + Applesoft Basic, which had a lot of limits (memory, string + length, etc) and would sometimes crash unexpectedly. */ + sprintf(printbuf, + "\n" + "\n" + "\n" + "?%s IN %d\n" + "\001]", + apple2_basic_errors[random() % + (sizeof(apple2_basic_errors) + /sizeof(char *))], + (1000*(random()%(random()%59+1)) + + 100*(random()%(random()%9+1)) + + 5*(random()%(random()%199+1)) + + 1*(random()%(random()%(random()%2+1)+1)))); + printing=printbuf; + a2_goto(st,23,1); + stepno=1; + prompt=']'; + next_actiontime += 2.0 + (random()%1000)*0.0002; + } + break; + + case 1: + if (simulate_user && random()%3==0) { + /* This was how you reset the Basic interpreter. The sort of + incantation you'd have on a little piece of paper taped to the + side of your machine */ + typing="CALL -1370"; + stepno=2; + } + else if (simulate_user && random()%2==0) { + typing="CATALOG\n"; + stepno=22; + } + else { + next_actiontime+=1.0; + stepno=6; + } + break; + + case 2: + stepno=3; + next_actiontime += 0.5; + break; + + case 3: + st->gr_mode=0; + a2_cls(st); + a2_goto(st,0,16); + for (s="APPLE ]["; *s; s++) a2_printc(st,*s); + a2_goto(st,23,0); + a2_printc(st,']'); + next_actiontime+=1.0; + stepno=6; + break; + + case 6: + if (simulate_user && random()%50==0 && 0) { /* disabled, too goofy */ + typing="10 PRINT \"TRS-80S SUCK!!!\"\n" + "]20 GOTO 10\n" + "]RUN"; + stepno=7; + } + else { + stepno=8; + next_actiontime += delay; + } + break; + + case 7: + for (i=0; i<30; i++) { + for (s="\nTRS-80S SUCK"; *s; s++) a2_printc(st,*s); + } + stepno=8; + next_actiontime+=delay; + + case 8: + break; + + case 22: + if (random()%50==0) { + sprintf(printbuf,"\nDISK VOLUME 254\n\n" + " A 002 HELLO\n" + "\n" + "]"); + printing=printbuf; + } + else { + sprintf(printbuf,"\n?%s\n]", + apple2_dos_errors[random()% + (sizeof(apple2_dos_errors) / + sizeof(char *))]); + printing=printbuf; + } + stepno=6; + next_actiontime+=1.0; + break; + + case 11: + if (simulate_user && random()%2==0) { + /* This was how you went back to text mode in the monitor */ + typing="FB4BG"; + stepno=12; + } else { + next_actiontime+=1.0; + stepno=6; + } + break; + + case 12: + st->gr_mode=0; + a2_invalidate(st); + a2_printc(st,'\n'); + a2_printc(st,'*'); + stepno=13; + next_actiontime+=2.0; + break; + + case 13: + /* This reset things into Basic */ + if (simulate_user && random()%2==0) { + typing="FAA6G"; + stepno=2; + } + else { + stepno=8; + next_actiontime+=delay; + } + break; + + case 73: + for (i=0; i<1500; i++) { + a2_poke(st, fillptr, fillbyte); + fillptr++; + fillbyte = (fillbyte+1)&0xff; + } + next_actiontime += 0.08; + /* When you hit c000, it changed video settings */ + if (fillptr>=0xc000) { + a2_invalidate(st); + st->gr_mode=0; + } + /* And it seemed to reset around here, I dunno why */ + if (fillptr>=0xcf00) stepno=3; + break; + } + } + } + + /* Now, we turn the data in the Apple II video into a screen display. This + is interesting because of the interaction with the NTSC color decoding + in a color television. */ + + colormode=use_color && st->gr_mode!=0; + if (!use_cmap) { + ntsc_set_demod(dec, tint_control, color_control, brightness_control, + freq_error, colormode); + } + imgrow=0; + for (textrow=0; textrow<24; textrow++) { + if (st->rowimage[textrow] == textrow) { + screen_plan[textrow]=0; + } + else if (cheapdisplay && st->rowimage[textrow]>=0 && + textrow<21 && st->rowimage[textrow]<21 && + st->rowimage[textrow]>=2 && textrow>=2 && + (st->rowimage[textrow]+1)*h/24 + screen_xo <= xgwa.height) { + screen_plan[textrow]= A2_SP_COPY | st->rowimage[textrow]; + for (i=0; i<8; i++) { + crtload[textrow*8+i]=crtload[st->rowimage[textrow]*8+i]; + } + startdisplayrow=0; + } + else { + st->rowimage[textrow]=imgrow; + screen_plan[textrow]=imgrow | A2_SP_PUT; + + for (row=textrow*8; rowpattern,0,sizeof(dec->pattern)); + pp=dec->pattern+20; + + if ((st->gr_mode&A2_GR_HIRES) && (row<160 || + (st->gr_mode&A2_GR_FULL))) { + + /* Emulate the mysterious pink line, due to a bit getting + stuck in a shift register between the end of the last + row and the beginning of this one. */ + if ((st->hireslines[row][0] & 0x80) && + (st->hireslines[row][39]&0x40)) { + pp[-1]=1; + } + + for (col=0; col<40; col++) { + u_char b=st->hireslines[row][col]; + int shift=(b&0x80)?0:1; + + /* Each of the low 7 bits in hires mode corresponded to 2 dot + clocks, shifted by one if the high bit was set. */ + for (i=0; i<7; i++) { + pp[shift+1] = pp[shift] =(b>>i)&1; + pp+=2; + } + } + } + else if ((st->gr_mode&A2_GR_LORES) && (row<160 || + (st->gr_mode&A2_GR_FULL))) { + for (col=0; col<40; col++) { + u_char nib=(st->textlines[textrow][col] >> (((row/4)&1)*4))&0xf; + /* The low or high nybble was shifted out one bit at a time. */ + for (i=0; i<14; i++) { + *pp = (nib>>((col*14+i)&3))&1; + pp++; + } + } + } + else { + for (col=0; col<40; col++) { + int rev; + c=st->textlines[textrow][col]; + /* hi bits control inverse/blink as follows: + 0x00: inverse + 0x40: blink + 0x80: normal + 0xc0: normal */ + rev=!(c&0x80) && (!(c&0x40) || st->blink); + + for (i=0; i<7; i++) { + for (i=0; i<7; i++) { + unsigned long pix=XGetPixel(text_im, + ((c&0x3f)^0x20)*7+i, row%8); + pp[1] = pp[2] = pix^rev; + pp+=2; + } + } + } + } + + /* + Interpolate the 600-dotclock line into however many horizontal + screen pixels we're using, and convert to RGB. + + We add some 'bloom', variations in the horizontal scan width with + the amount of brightness, extremely common on period TV sets. They + had a single oscillator which generated both the horizontal scan + and (during the horizontal retrace interval) the high voltage for + the electron beam. More brightness meant more load on the + oscillator, which caused an decrease in horizontal deflection. Look + for (bloomthisrow). + + Also, the A2 did a bad job of generating horizontal sync pulses + during the vertical blanking interval. This, and the fact that the + horizontal frequency was a bit off meant that TVs usually went a + bit out of sync during the vertical retrace, and the top of the + screen would be bent a bit to the left or right. Look for + (shiftthisrow). + + We also add a teeny bit of left overscan, just enough to be + annoying, but you can still read the left column of text. + + We also simulate compression & brightening on the right side of the + screen. Most TVs do this, but you don't notice because they + overscan so it's off the right edge of the CRT. But the A2 video + system used so much of the horizontal scan line that you had to + crank the horizontal width down in order to not lose the right few + characters, and you'd see the compression on the right + edge. Associated with compression is brightening; since the + electron beam was scanning slower, the same drive signal hit the + phosphor harder. Look for (squishright_i) and (squishdiv). + */ + + for (i=j=0; i<600; i++) { + j += dec->pattern[i]; + } + crtload[row] = (crtload[row>1 ? row-1 : 0]) * 0.98 + 0.02*(j/600.0) + + (row>180 ? (row-180)*(row-180)*0.0005 : 0.0); + bloomthisrow = -10.0 * crtload[row]; + shiftthisrow=((row<18) ? ((18-row)*(18-row)* 0.002 + (18-row)*0.05) + * horiz_desync : 0.0); + + scanstart_i=(int)((bloomthisrow+shiftthisrow+18.0)*65536.0); + if (scanstart_i<0) scanstart_i=0; + if (scanstart_i>30*65536) scanstart_i=30*65536; + scanend_i=599*65536; + squishright_i=scanstart_i + 530*65536; + squishdiv=w/15; + pixrate=(int)((560.0-2.0*bloomthisrow)*65536.0/w); + + if (use_cmap) { + for (y=ytop; y=3) && + !(y==ybot-1 && ybot-ytop>=5)); + int hist=0; + int histi=0; + + pixmultinc=pixrate; + for (x=0, i=scanstart_i; + x>16); + int offset=pati&3; + while (pati>=histi) { + hist=(((hist<<1) & ((1<pattern[histi]); + histi++; + } + XPutPixel(image, x, y, + colors[A2_CMAP_INDEX(colormode,level,hist,offset)]); + if (i >= squishright_i) { + pixmultinc += pixmultinc/squishdiv; + } + } + for ( ; x>16; + int r,g,b; + + int interpy=((dec->ntscy[pati]*invpixfrac + + dec->ntscy[pati+1]*pixfrac)>>16); + int interpi=((dec->ntsci[pati]*invpixfrac + + dec->ntsci[pati+1]*pixfrac)>>16); + int interpq=((dec->ntscq[pati]*invpixfrac + + dec->ntscq[pati+1]*pixfrac)>>16); + + /* + According to the NTSC spec, Y,I,Q are generated as: + + y=0.30 r + 0.59 g + 0.11 b + i=0.60 r - 0.28 g - 0.32 b + q=0.21 r - 0.52 g + 0.31 b + + So if you invert the implied 3x3 matrix you get what standard + televisions implement with a bunch of resistors (or directly in + the CRT -- don't ask): + + r = y + 0.948 i + 0.624 q + g = y - 0.276 i - 0.639 q + b = y - 1.105 i + 1.729 q + + These coefficients are below in 16.16 format. + */ + + r=((interpy + ((+68128*interpi+40894*interpq)>>16))*pixbright) + >>16; + g=((interpy + ((-18087*interpi-41877*interpq)>>16))*pixbright) + >>16; + b=((interpy + ((-72417*interpi+113312*interpq)>>16))*pixbright) + >>16; + if (r<0) r=0; + if (g<0) g=0; + if (b<0) b=0; + rrp[0]=r; + rrp[1]=g; + rrp[2]=b; + + if (i>=squishright_i) { + pixmultinc += pixmultinc/squishdiv; + pixbright += pixbright/squishdiv; + } + } + for ( ; xformat==ZPixmap && image->bits_per_pixel==32 && + sizeof(unsigned long)==4 && + image->byte_order==localbyteorder) { + unsigned long *pixelptr = + (unsigned long *) (image->data + y * image->bytes_per_line); + for (x=0, rrp=raw_rgb; x65535) ntscri=65535; + if (ntscgi>65535) ntscgi=65535; + if (ntscbi>65535) ntscbi=65535; + *pixelptr++ = ((ntscri>>red_invprec)<>green_invprec)<>blue_invprec)<format==ZPixmap && image->bits_per_pixel==16 && + sizeof(unsigned short)==2 && + image->byte_order==localbyteorder) { + unsigned short *pixelptr = + (unsigned short *)(image->data + y*image->bytes_per_line); + for (x=0, rrp=raw_rgb; x65535) ntscri=65535; + if (ntscgi>65535) ntscgi=65535; + if (ntscbi>65535) ntscbi=65535; + *pixelptr++ = ((ntscri>>red_invprec)<>green_invprec)<>blue_invprec)<65535) ntscri=65535; + if (ntscgi>65535) ntscgi=65535; + if (ntscbi>65535) ntscbi=65535; + pixel = ((ntscri>>red_invprec)<>green_invprec)<>blue_invprec)<rowimage[textrow]=textrow; + } + } + + finished: + XSync(dpy,False); + XClearWindow(dpy, window); + goto cleanup; + + bailout: + ; + + cleanup: + if (image) { + if (use_shm) { +#ifdef HAVE_XSHM_EXTENSION + destroy_xshm_image(dpy, image, &shm_info); +#endif + } else { + XDestroyImage(image); + } + image=NULL; + } + if (text_im) XDestroyImage(text_im); + if (gc) XFreeGC(dpy, gc); + if (st) free(st); + if (raw_rgb) free(raw_rgb); + if (dec) free(dec); + if (n_colors) XFreeColors(dpy, xgwa.colormap, colors, n_colors, 0L); } @@ -2131,6 +3836,7 @@ char *progclass = "BSOD"; char *defaults [] = { "*delay: 30", + "*doOnly: ", "*doWindows: True", "*doNT: True", "*doWin2K: True", @@ -2146,6 +3852,8 @@ char *defaults [] = { "*doSparcLinux: False", /* boring */ "*doBlitDamage: True", "*doSolaris: True", + "*doHPUX: True", + "*doApple2: True", ".Windows.font: -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*", ".Windows.font2: -*-courier-bold-r-*-*-*-180-*-*-m-*-*-*", @@ -2188,31 +3896,52 @@ char *defaults [] = { ".Linux.font: 9x15bold", ".Linux.font2: -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*", - ".Linux.foreground: White", - ".Linux.background: Black", + ".Linux.foreground: White", + ".Linux.background: Black", ".SparcLinux.font: -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*", ".SparcLinux.font2: -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*", ".SparcLinux.foreground: White", ".SparcLinux.background: Black", - ".BSD.font: vga", - ".BSD.font: -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*", - ".BSD.font2: -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*", -/* ".BSD.font2: -sun-console-medium-r-*-*-22-*-*-*-m-*-*-*", */ - ".BSD.foreground: #c0c0c0", - ".BSD.background: Black", - - ".Solaris.font: -sun-gallant-*-*-*-*-19-*-*-*-*-120-*-*", - ".Solaris.font2: -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*", - ".Solaris.foreground: Black", - ".Solaris.background: White", - "*dontClearRoot: True", + ".BSD.font: vga", + ".BSD.font: -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*", + ".BSD.font2: -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*", +/* ".BSD.font2: -sun-console-medium-r-*-*-22-*-*-*-m-*-*-*", */ + ".BSD.foreground: #c0c0c0", + ".BSD.background: Black", + + ".Solaris.font: -sun-gallant-*-*-*-*-19-*-*-*-*-120-*-*", + ".Solaris.font2: -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*", + ".Solaris.foreground: Black", + ".Solaris.background: White", + "*dontClearRoot: True", + + ".HPUX.font: 9x15bold", + ".HPUX.font2: -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*", + ".HPUX.foreground: Black", + ".HPUX.background: White", + + ".OS390.font: 9x15bold", + ".OS390.font2: -*-courier-bold-r-*-*-*-140-*-*-m-*-*-*", + ".OS390.background: Black", + ".OS390.foreground: Red", + + "*apple2TVColor: 50", + "*apple2TVTint: 5", + "*apple2TVBrightness: 10", + "*apple2TVContrast: 90", + "*apple2SimulateUser: True", + +#ifdef HAVE_XSHM_EXTENSION + "*useSHM: True", +#endif 0 }; XrmOptionDescRec options [] = { { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-only", ".doOnly", XrmoptionSepArg, 0 }, { "-windows", ".doWindows", XrmoptionNoArg, "True" }, { "-no-windows", ".doWindows", XrmoptionNoArg, "False" }, { "-nt", ".doNT", XrmoptionNoArg, "True" }, @@ -2225,16 +3954,19 @@ XrmOptionDescRec options [] = { { "-no-mac", ".doMac", XrmoptionNoArg, "False" }, { "-mac1", ".doMac1", XrmoptionNoArg, "True" }, { "-no-mac1", ".doMac1", XrmoptionNoArg, "False" }, + { "-macx", ".doMacX", XrmoptionNoArg, "True" }, { "-no-macx", ".doMacX", XrmoptionNoArg, "False" }, { "-atari", ".doAtari", XrmoptionNoArg, "True" }, { "-no-atari", ".doAtari", XrmoptionNoArg, "False" }, { "-macsbug", ".doMacsBug", XrmoptionNoArg, "True" }, { "-no-macsbug", ".doMacsBug", XrmoptionNoArg, "False" }, + { "-apple2", ".doApple2", XrmoptionNoArg, "True" }, + { "-no-apple2", ".doApple2", XrmoptionNoArg, "False" }, { "-sco", ".doSCO", XrmoptionNoArg, "True" }, { "-no-sco", ".doSCO", XrmoptionNoArg, "False" }, { "-bsd", ".doBSD", XrmoptionNoArg, "True" }, { "-no-bsd", ".doBSD", XrmoptionNoArg, "False" }, - { "-linux", ".doLinux", XrmoptionNoArg, "True" }, + { "-linux", ".doLinux", XrmoptionNoArg, "True" }, { "-no-linux", ".doLinux", XrmoptionNoArg, "False" }, { "-sparclinux", ".doSparcLinux", XrmoptionNoArg, "True" }, { "-no-sparclinux", ".doSparcLinux", XrmoptionNoArg, "False" }, @@ -2242,19 +3974,66 @@ XrmOptionDescRec options [] = { { "-no-blitdamage", ".doBlitDamage", XrmoptionNoArg, "False" }, { "-solaris", ".doSolaris", XrmoptionNoArg, "True" }, { "-no-solaris", ".doSolaris", XrmoptionNoArg, "False" }, + { "-hpux", ".doHPUX", XrmoptionNoArg, "True" }, + { "-no-hpux", ".doHPUX", XrmoptionNoArg, "False" }, + { "-os390", ".doOS390", XrmoptionNoArg, "True" }, + { "-no-os390", ".doOS390", XrmoptionNoArg, "False" }, { 0, 0, 0, 0 } }; +static struct { + const char *name; + void (*fn) (Display *, Window, int delay); +} all_modes[] = { + { "Windows", windows_31 }, + { "Nt", windows_nt }, + { "2k", windows_2k }, + { "Amiga", amiga }, + { "Mac", mac }, + { "MacsBug", macsbug }, + { "Mac1", mac1 }, + { "MacX", macx }, + { "SCO", sco }, + { "SparcLinux", sparc_linux }, + { "BSD", bsd }, + { "Atari", atari }, + { "BlitDamage", blitdamage }, + { "Solaris", sparc_solaris }, + { "Linux", linux_fsck }, + { "HPUX", hpux }, + { "OS390", os390 }, + { "Apple2", apple2 }, +}; + + void screenhack (Display *dpy, Window window) { int loop = 0; int i = -1; int j = -1; + int only = -1; int delay = get_integer_resource ("delay", "Integer"); if (delay < 3) delay = 3; + { + char *s = get_string_resource("doOnly", "DoOnly"); + if (s && *s) + { + int count = countof(all_modes); + for (only = 0; only < count; only++) + if (!strcasecmp (s, all_modes[only].name)) + break; + if (only >= count) + { + fprintf (stderr, "%s: unknown -only mode: \"%s\"\n", progname, s); + only = -1; + } + } + if (s) free (s); + } + if (!get_boolean_resource ("root", "Boolean")) { XWindowAttributes xgwa; @@ -2266,26 +4045,24 @@ screenhack (Display *dpy, Window window) while (1) { Bool did; - do { i = (random() & 0xFF) % 15; } while (i == j); - switch (i) - { - case 0: did = windows(dpy, window, delay, 0); break; - case 1: did = windows(dpy, window, delay, 1); break; - case 2: did = windows(dpy, window, delay, 2); break; - case 3: did = amiga(dpy, window, delay); break; - case 4: did = mac(dpy, window, delay); break; - case 5: did = macsbug(dpy, window, delay); break; - case 6: did = mac1(dpy, window, delay); break; - case 7: did = macx(dpy, window, delay); break; - case 8: did = sco(dpy, window, delay); break; - case 9: did = sparc_linux(dpy, window, delay); break; - case 10: did = bsd(dpy, window, delay); break; - case 11: did = atari(dpy, window, delay); break; - case 12: did = blitdamage(dpy, window, delay); break; - case 13: did = sparc_solaris(dpy, window, delay); break; - case 14: did = linux_fsck(dpy, window, delay); break; - default: abort(); break; - } + int count = countof(all_modes); + char name[100], class[100]; + + if (only > 0) + i = only; + else + do { i = (random() & 0xFF) % count; } while (i == j); + + sprintf (name, "do%s", all_modes[i].name); + sprintf (class, "Do%s", all_modes[i].name); + + did = False; + if (only > 0 || get_boolean_resource(name, class)) + { + all_modes[i].fn (dpy, window, delay); + did = True; + } + loop++; if (loop > 100) j = -1; if (loop > 200) diff --git a/hacks/bsod.man b/hacks/bsod.man index d3cbbe81..b3ddb902 100644 --- a/hacks/bsod.man +++ b/hacks/bsod.man @@ -27,9 +27,9 @@ program is the finest in personal computer emulation. .I bsod steps through a set of screens, each one a recreation of a different failure mode of an operating system. Systems depicted include Microsoft's Windows 95 -and Windows NT, Commodore-Amiga's AmigaDOS 1.3, SPARC Linux, SCO UNIX, the -Apple Macintosh (both the MacsBug debugger and the rarer "Sad Mac"), and the -Atari ST. +and Windows NT, Commodore-Amiga's AmigaDOS 1.3, SPARC Linux, SCO UNIX, +HPUX, IBM OS/360, the Apple Macintosh (both the MacsBug debugger and the +rarer "Sad Mac"), the Atari ST, and the Apple ][+. .PP .SH OPTIONS .I bsod @@ -53,6 +53,9 @@ or the id number (decimal or hex) of a specific visual. .TP 8 .B \-delay \fIdelay\fP The delay between displaying one crash and another. +.TP 8 +.B \-only \fIwhich\fP +Tell it to run only one mode, e.g., \fI\-only HPUX\fP. .SH ENVIRONMENT .PP .TP 8 @@ -72,23 +75,25 @@ hacks are displayed and which aren't. .BR doMac , .BR doMac1 , .BR doMacsBug , +.BR doMacX , .BR doSCO , .BR doAtari , .BR doBSD , .BR doLinux , .BR doSparcLinux , .BR doBlitDamage , +.BR doSolaris , +.BR doHPUX , +.BR doOS390 , and -.BR doSolaris . -Each of these is a Boolean resource, they all default to true, except for -doSparcLinux and doAtari, which are turned off by default, because they're -really not all that interesting looking unless you're a fan of those systems. -There aren't command-line options for these, so to change them, you'll need -to add entries to your .Xdefaults file, or use the -xrm option. -For example, to tell bsod not to show the NT crash: -.EX -bsod -xrm '*doNT: false' -.EE +.BR doApple2 . +Each of these is a Boolean resource, they all default to true, except +for doAtari, doBSD, and doSparcLinux, which are turned off by default, +because they're really not all that interesting looking unless you're a +fan of those systems. + +There are command-line options for all of these: +e.g., \fI\-bsd\fP, \fI\-no-bsd\fP. .SH BUGS Unlike the systems that the images are borrowed from, .I bsod @@ -97,16 +102,11 @@ does not require a reboot after running. .I bsod should also emulate more systems, but systems with interesting crash graphics are not as common as one might hope. - -One I'd really like to see is a Unix system getting a kernel panic, -rebooting, and running -.BR fsck (8). .SH SEE ALSO .BR X (1), .BR xscreensaver (1), .BR http://www.microsoft.com/ , .BR http://www.apple.com/ , -and .BR http://www.sco.com/ , .BR http://www.kernel.org/ , and @@ -116,10 +116,10 @@ Microsoft Windows, Microsoft Windows 95, and Microsoft Windows NT are all registered trademarks of Microsoft Corporation. Apple Macintosh is a registered trademark of Apple Computer. Amiga is a registered trademark of Amiga International, Inc. Atari ST is probably a trademark, too, but it's -hard to tell who owns it. Linux is a registered trademark of Linus Torvalds, +hard to tell who owns it. Linux is a registered trademark of Linus Torvalds, but it isn't his fault. .SH COPYRIGHT -Copyright \(co 1998 by Jamie Zawinski. Permission to use, copy, modify, +Copyright \(co 1998-2003 by Jamie Zawinski. Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice @@ -129,4 +129,4 @@ express or implied warranty. No animals were harmed during the testing of these simulations. Always mount a scratch monkey. .SH AUTHOR Concept cribbed from Stephen Martin . This version is by -Jamie Zawinski . +Jamie Zawinski , with contributions from many others. diff --git a/hacks/cloudlife.c b/hacks/cloudlife.c new file mode 100644 index 00000000..368eb9d5 --- /dev/null +++ b/hacks/cloudlife.c @@ -0,0 +1,338 @@ +/* cloudlife by Don Marti + * + * Based on Conway's Life, but with one rule change to make it a better + * screensaver: cells have a max age. + * + * When a cell exceeds the max age, it counts as 3 for populating the next + * generation. This makes long-lived formations explode instead of just + * sitting there burning a hole in your screen. + * + * Cloudlife only draws one pixel of each cell per tick, whether the cell is + * alive or dead. So gliders look like little comets. + + * Based on several examples from the hacks directory of: + + * xscreensaver, Copyright (c) 1997, 1998, 2002 Jamie Zawinski + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + */ + +#include "screenhack.h" +#include +#include + +#ifndef MAX_WIDTH +#include +#define MAX_WIDTH SHRT_MAX +#endif + +#ifdef TIME_ME +#include +#endif + +/* this program goes faster if some functions are inline. The following is + * borrowed from ifs.c */ +#if !defined( __GNUC__ ) && !defined(__cplusplus) && !defined(c_plusplus) +#undef inline +#define inline /* */ +#endif + +typedef struct { + unsigned int height; + unsigned int width; + unsigned int max_age; + unsigned int cell_size; + unsigned char *cells; + unsigned char *new_cells; +} field; + +static void +*xrealloc(void *p, size_t size) +{ + void *ret; + if ((ret = realloc(p, size)) == NULL) { + fprintf(stderr, "%s: out of memory\n", progname); + exit(1); + } + return ret; +} + +field +*init_field(void) +{ + field *f = xrealloc(NULL, sizeof(field)); + f->height = 0; + f->width = 0; + f->cell_size = get_integer_resource("cellSize", "Integer"); + f->max_age = get_integer_resource("maxAge", "Integer"); + f->cells = NULL; + f->new_cells = NULL; + return f; +} + +void +resize_field(field * f, unsigned int w, unsigned int h) +{ + f->width = w; + f->height = h; + + f->cells = xrealloc(f->cells, + w * sizeof(unsigned char) * + h * sizeof(unsigned char)); + f->new_cells = + xrealloc(f->new_cells, + w * sizeof(unsigned char) * h * sizeof(unsigned char)); +} + +inline unsigned char +*cell_at(field * f, unsigned int x, unsigned int y) +{ + return (f->cells + x * sizeof(unsigned char) + + y * f->width * sizeof(unsigned char)); +} + +inline unsigned char +*new_cell_at(field * f, unsigned int x, unsigned int y) +{ + return (f->new_cells + x * sizeof(unsigned char) + + y * f->width * sizeof(unsigned char)); +} + +static void +draw_field(Display * dpy, + Window window, Colormap cmap, GC fgc, GC bgc, field * f) +{ + unsigned int x, y; + unsigned int rx, ry = 0; /* random amount to offset the dot */ + unsigned int size = 1 << f->cell_size; + unsigned int mask = size - 1; + static XPoint fg_points[MAX_WIDTH]; + static XPoint bg_points[MAX_WIDTH]; + unsigned int fg_count, bg_count; + + /* columns 0 and width-1 are off screen and not drawn. */ + for (y = 1; y < f->height - 1; y++) { + fg_count = 0; + bg_count = 0; + + /* rows 0 and height-1 are off screen and not drawn. */ + for (x = 1; x < f->width - 1; x++) { + rx = random(); + ry = rx >> f->cell_size; + rx &= mask; + ry &= mask; + + if (*cell_at(f, x, y)) { + fg_points[fg_count].x = (short) x *size - rx - 1; + fg_points[fg_count].y = (short) y *size - ry - 1; + fg_count++; + } else { + bg_points[bg_count].x = (short) x *size - rx - 1; + bg_points[bg_count].y = (short) y *size - ry - 1; + bg_count++; + } + } + XDrawPoints(dpy, window, fgc, fg_points, fg_count, + CoordModeOrigin); + XDrawPoints(dpy, window, bgc, bg_points, bg_count, + CoordModeOrigin); + } +} + +inline unsigned int +cell_value(unsigned char c, unsigned int age) +{ + if (!c) { + return 0; + } else if (c > age) { + return (3); + } else { + return (1); + } +} + +inline unsigned int +is_alive(field * f, unsigned int x, unsigned int y) +{ + unsigned int count; + unsigned int i, j; + unsigned char *p; + + count = 0; + + for (i = x - 1; i <= x + 1; i++) { + for (j = y - 1; j <= y + 1; j++) { + if (y != j || x != i) { + count += cell_value(*cell_at(f, i, j), f->max_age); + } + } + } + + p = cell_at(f, x, y); + if (*p) { + if (count == 2 || count == 3) { + return ((*p) + 1); + } else { + return (0); + } + } else { + if (count == 3) { + return (1); + } else { + return (0); + } + } +} + +unsigned int +do_tick(field * f) +{ + unsigned int x, y; + unsigned int count = 0; + for (x = 1; x < f->width - 1; x++) { + for (y = 1; y < f->height - 1; y++) { + count += *new_cell_at(f, x, y) = is_alive(f, x, y); + } + } + memcpy(f->cells, f->new_cells, f->width * sizeof(unsigned char) * + f->height * sizeof(unsigned char)); + return count; +} + + +unsigned int +random_cell(unsigned int p) +{ + int r = random() & 0xff; + + if (r < p) { + return (1); + } else { + return (0); + } +} + +void +populate_field(field * f, unsigned int p) +{ + unsigned int x, y; + + for (x = 0; x < f->width; x++) { + for (y = 0; y < f->height; y++) { + *cell_at(f, x, y) = random_cell(p); + } + } +} + +void +populate_edges(field * f, unsigned int p) +{ + unsigned int i; + + for (i = f->width; i--;) { + *cell_at(f, i, 0) = random_cell(p); + *cell_at(f, i, f->height - 1) = random_cell(p); + } + + for (i = f->height; i--;) { + *cell_at(f, f->width - 1, i) = random_cell(p); + *cell_at(f, 0, i) = random_cell(p); + } +} + + +char *progclass = "Cloudlife"; + +char *defaults[] = { + ".background: black", + ".foreground: blue", + "*cycleDelay: 25000", + "*maxAge: 64", + "*initialDensity: 160", + "*cellSize: 3", + 0 +}; + +XrmOptionDescRec options[] = { + {"-background", ".background", XrmoptionSepArg, 0}, + {"-foreground", ".foreground", XrmoptionSepArg, 0}, + {"-cycle-delay", ".cycleDelay", XrmoptionSepArg, 0}, + {"-cell-size", ".cellSize", XrmoptionSepArg, 0}, + {"-initial-density", ".initialDensity", XrmoptionSepArg, 0}, + {"-max-age", ".maxAge", XrmoptionSepArg, 0}, + {0, 0, 0, 0} +}; + +void screenhack(Display * dpy, Window window) +{ + field *f = init_field(); + +#ifdef TIME_ME + time_t start_time = time(NULL); +#endif + + unsigned int cycles = 0; + + GC fgc, bgc; + XGCValues gcv; + XWindowAttributes xgwa; + + unsigned int cycle_delay = (unsigned int) + get_integer_resource("cycleDelay", "Integer"); + unsigned int density = (unsigned int) + get_integer_resource("initialDensity", "Integer") & 0xff; + XGetWindowAttributes(dpy, window, &xgwa); + + gcv.foreground = get_pixel_resource("foreground", "Foreground", + dpy, xgwa.colormap); + fgc = XCreateGC(dpy, window, GCForeground, &gcv); + + gcv.foreground = get_pixel_resource("background", "Background", + dpy, xgwa.colormap); + bgc = XCreateGC(dpy, window, GCForeground, &gcv); + + while (1) { + XGetWindowAttributes(dpy, window, &xgwa); + if (f->height != xgwa.height / (1 << f->cell_size) + 2 || + f->width != xgwa.width / (1 << f->cell_size) + 2) { + + resize_field(f, xgwa.width / (1 << f->cell_size) + 2, + xgwa.height / (1 << f->cell_size) + 2); + populate_field(f, density); + } + + screenhack_handle_events(dpy); + + draw_field(dpy, window, xgwa.colormap, fgc, bgc, f); + + if (do_tick(f) < (f->height + f->width) / 4) { + populate_field(f, density); + } + + if (cycles % (f->max_age /2) == 0) { + populate_edges(f, density); + do_tick(f); + populate_edges(f, 0); + } + + XSync(dpy, False); + + cycles++; + + if (cycle_delay) + usleep(cycle_delay); + +#ifdef TIME_ME + if (cycles % f->max_age == 0) { + printf("%g s.\n", + ((time(NULL) - start_time) * 1000.0) / cycles); + } +#endif + } +} diff --git a/hacks/compile_axp.com b/hacks/compile_axp.com index cd28741c..0612b7b1 100644 --- a/hacks/compile_axp.com +++ b/hacks/compile_axp.com @@ -12,6 +12,7 @@ $ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS $ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BUBBLES-DEFAULT.C $ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BUMPS.C $ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) CCURVE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) CLOUDLIFE.C $ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) COMPASS.C $ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) CORAL.C $ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) CRITICAL.C diff --git a/hacks/compile_decc.com b/hacks/compile_decc.com index cd28741c..0612b7b1 100644 --- a/hacks/compile_decc.com +++ b/hacks/compile_decc.com @@ -12,6 +12,7 @@ $ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS $ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BUBBLES-DEFAULT.C $ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) BUMPS.C $ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) CCURVE.C +$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) CLOUDLIFE.C $ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) COMPASS.C $ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) CORAL.C $ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H,STANDALONE)/INCL=([],[-],[-.UTILS]) CRITICAL.C diff --git a/hacks/config/README b/hacks/config/README index 6d4496e7..4ce15db9 100644 --- a/hacks/config/README +++ b/hacks/config/README @@ -4,8 +4,8 @@ a screen saver and locker for the X window system by Jamie Zawinski - version 4.09 - 17-Mar-2003 + version 4.10 + 20-May-2003 http://www.jwz.org/xscreensaver/ diff --git a/hacks/config/bsod.xml b/hacks/config/bsod.xml index 2688d12d..0194d561 100644 --- a/hacks/config/bsod.xml +++ b/hacks/config/bsod.xml @@ -18,6 +18,7 @@ + @@ -25,8 +26,10 @@ + + diff --git a/hacks/config/cloudlife.xml b/hacks/config/cloudlife.xml new file mode 100644 index 00000000..8be35928 --- /dev/null +++ b/hacks/config/cloudlife.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + <_description> + +Generates cloud-like formations based on a variant of Conway's Life The +difference is that cells have a maximum age, after which they count as +3 for populating the next generation. This makes long-lived formations +explode instead of just sitting there burning a hole in your screen. +Written by Don Marti. + + diff --git a/hacks/config/glplanet.xml b/hacks/config/glplanet.xml index 4534d241..d4352cc1 100644 --- a/hacks/config/glplanet.xml +++ b/hacks/config/glplanet.xml @@ -15,7 +15,7 @@