ftp://ftp.ntnu.no/old/pub/X11/R5contrib/xscreensaver-1.17.tar.gz
authorZygo Blaxell <zblaxell@hungrycats.org>
Mon, 2 Mar 2009 05:42:18 +0000 (00:42 -0500)
committerZygo Blaxell <zblaxell@hungrycats.org>
Mon, 2 Mar 2009 05:42:18 +0000 (00:42 -0500)
-rw-r--r-- 1 zblaxell zblaxell 108551 Feb 27 14:00 xscreensaver-1.17.tar.gz
db81f5a260a152f79d884bcf855c7cf287e32b0f  xscreensaver-1.17.tar.gz

79 files changed:
Imakefile [new file with mode: 0644]
README [new file with mode: 0644]
config.h [new file with mode: 0644]
driver/.gdbinit [new file with mode: 0644]
driver/Imakefile [new file with mode: 0644]
driver/README [new file with mode: 0644]
driver/XScreenSaver.ad [new file with mode: 0644]
driver/demo.c [new file with mode: 0644]
driver/dialogs.c [new file with mode: 0644]
driver/dialogs.xd [new file with mode: 0644]
driver/lock.c [new file with mode: 0644]
driver/subprocs.c [new file with mode: 0644]
driver/timers.c [new file with mode: 0644]
driver/visual.c [new file with mode: 0644]
driver/windows.c [new file with mode: 0644]
driver/xscreensaver-command.c [new file with mode: 0644]
driver/xscreensaver-command.man [new file with mode: 0644]
driver/xscreensaver.c [new file with mode: 0644]
driver/xscreensaver.h [new file with mode: 0644]
driver/xscreensaver.man [new file with mode: 0644]
hacks/.gdbinit [new file with mode: 0644]
hacks/Imakefile [new file with mode: 0644]
hacks/README [new file with mode: 0644]
hacks/attraction.c [new file with mode: 0644]
hacks/attraction.man [new file with mode: 0644]
hacks/blitspin.c [new file with mode: 0644]
hacks/blitspin.man [new file with mode: 0644]
hacks/greynetic.c [new file with mode: 0644]
hacks/greynetic.man [new file with mode: 0644]
hacks/halo.c [new file with mode: 0644]
hacks/halo.man [new file with mode: 0644]
hacks/helix.c [new file with mode: 0644]
hacks/helix.man [new file with mode: 0644]
hacks/hopalong.c [new file with mode: 0644]
hacks/hopalong.man [new file with mode: 0644]
hacks/hypercube.c [new file with mode: 0644]
hacks/hypercube.man [new file with mode: 0644]
hacks/imsmap.c [new file with mode: 0644]
hacks/imsmap.man [new file with mode: 0644]
hacks/maze.c [new file with mode: 0644]
hacks/maze.man [new file with mode: 0644]
hacks/noseguy.c [new file with mode: 0644]
hacks/noseguy.man [new file with mode: 0644]
hacks/noses/nose.0.left [new file with mode: 0644]
hacks/noses/nose.0.right [new file with mode: 0644]
hacks/noses/nose.1.left [new file with mode: 0644]
hacks/noses/nose.1.right [new file with mode: 0644]
hacks/noses/nose.down [new file with mode: 0644]
hacks/noses/nose.front [new file with mode: 0644]
hacks/noses/nose.left.front [new file with mode: 0644]
hacks/noses/nose.right.front [new file with mode: 0644]
hacks/pyro.c [new file with mode: 0644]
hacks/pyro.man [new file with mode: 0644]
hacks/qix.c [new file with mode: 0644]
hacks/qix.man [new file with mode: 0644]
hacks/rocks.c [new file with mode: 0644]
hacks/rocks.man [new file with mode: 0644]
hacks/rorschach.c [new file with mode: 0644]
hacks/rorschach.man [new file with mode: 0644]
hacks/screenhack.c [new file with mode: 0644]
hacks/screenhack.h [new file with mode: 0644]
hacks/slidescreen.c [new file with mode: 0644]
hacks/slidescreen.man [new file with mode: 0644]
hacks/vroot.h [new file with mode: 0644]
hacks/xlock.h [new file with mode: 0644]
hacks/xroger-hack.c [new file with mode: 0644]
hacks/xroger.man [new file with mode: 0644]
screenblank.txt [new file with mode: 0644]
utils/Imakefile [new file with mode: 0644]
utils/README [new file with mode: 0644]
utils/ad2c [new file with mode: 0755]
utils/fade.c [new file with mode: 0644]
utils/hsv.c [new file with mode: 0644]
utils/resources.c [new file with mode: 0644]
utils/spline.c [new file with mode: 0644]
utils/spline.h [new file with mode: 0644]
utils/usleep.c [new file with mode: 0644]
utils/version.h [new file with mode: 0644]
utils/xroger.c [new file with mode: 0644]

diff --git a/Imakefile b/Imakefile
new file mode 100644 (file)
index 0000000..baa81b1
--- /dev/null
+++ b/Imakefile
@@ -0,0 +1,44 @@
+/*
+ * Imakefile file for xscreensaver, Copyright (c) 1991-1993 Jamie Zawinski.
+ *
+ * You should not need to edit this file; edit config.h instead.
+ *
+ */
+
+#include "config.h"
+
+       TARFILES = README Imakefile config.h screenblank.txt
+            TAR = gnutar
+
+all:: utils/Makefile driver/Makefile hacks/Makefile
+       cd utils  ; $(MAKE) $@ CC="$(CC)" CCOPTIONS="$(CCOPTIONS)" CDEBUGFLAGS="$(CDEBUGFLAGS)"
+       cd driver ; $(MAKE) $@ CC="$(CC)" CCOPTIONS="$(CCOPTIONS)" CDEBUGFLAGS="$(CDEBUGFLAGS)"
+       cd hacks  ; $(MAKE) $@ CC="$(CC)" CCOPTIONS="$(CCOPTIONS)" CDEBUGFLAGS="$(CDEBUGFLAGS)"
+
+clean install install.man:: utils/Makefile driver/Makefile hacks/Makefile
+       cd utils  ; $(MAKE) $@
+       cd driver ; $(MAKE) $@
+       cd hacks  ; $(MAKE) $@
+
+Makefiles:: utils/Makefile driver/Makefile hacks/Makefile
+
+utils/Makefile: utils/Imakefile config.h
+       cd utils  ; $(IMAKE_CMD) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT_DIR)/utils
+driver/Makefile: driver/Imakefile config.h
+       cd driver ; $(IMAKE_CMD) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT_DIR)/driver
+hacks/Makefile: hacks/Imakefile config.h
+       cd hacks  ; $(IMAKE_CMD) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT_DIR)/hacks
+
+# This really makes me sick...
+tar: utils/Makefile driver/Makefile hacks/Makefile
+       @NAME=`sed -n                                                       \
+  's/[^0-9]*\([0-9].[0-9]*\).*/xscreensaver-\1/p' utils/version.h` ;       \
+  rm -f $$NAME ; ln -s . $$NAME ;                                          \
+  echo creating tar file $${NAME}.tar.Z... ;                               \
+   $(TAR) -vchf - `echo $(TARFILES)                                        \
+   \`cd driver ; make echo_tarfiles | sed 's|^|driver/|g;s| | driver/|g'\`  \
+   \`cd utils  ; make echo_tarfiles | sed 's|^|utils/|g; s| | utils/|g'\`   \
+   \`cd hacks  ; make echo_tarfiles | sed 's|^|hacks/|g; s| | hacks/|g'\`   \
+   | sed "s|^|$$NAME/|g; s| | $$NAME/|g" `                                 \
+   | compress > $${NAME}.tar.Z ;                                           \
+  rm $$NAME
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..2783d60
--- /dev/null
+++ b/README
@@ -0,0 +1,77 @@
+
+See config.h for configuration parameters.  To build, do the usual:
+
+       xmkmf ; make ; make install ; make install.man
+
+The xscreensaver program waits until the keyboard and mouse have been idle
+for a period, and then runs a graphics demo chosen at random.  It turns off
+as soon as there is any mouse or keyboard activity.
+
+The purpose of xscreensaver is to display pretty pictures on your screen 
+when it is not in use, in keeping with the philosophy that unattended 
+monitors should always be doing something interesting, just like they do 
+in the movies.
+
+However, xscreensaver can also be used as a screen locker, to prevent
+others from using your terminal while your are away.
+
+The benefit that this program has over the combination of the xlock and
+xautolock programs is the ease with which new graphics hacks can be
+installed: you don't need to recompile this program to add a new display
+mode, you just change some resource settings.  Any program which can be
+invoked in such a way that it draws on the root window of the screen can
+now be used as a screensaver without modification [*].  The programs that
+are being run as screensavers don't need to have any special knowledge
+about what it means to be a screensaver.
+
+The XIdle extension will be used if you have it (win win.)
+
+Unfortunately, locking doesn't work if you don't have Motif.
+
+Also included are several graphics hacks for use as screensavers.  There's
+nothing magic about these: they're just programs that draw on the root
+window, which are pointed at by the screensaver's default resource settings.
+
+   qix         - My own implementation of this, with many more options
+                 than you would have thought qix could have.
+   helix       - Generates spirally "stringart" patterns.
+   rorschach   - Random inkblot patterns.
+   attraction  - A bouncing ball demo, or a qix-like demo, or a wild
+                 color-cycling thing, with some odd rules.
+   greynetic   - Random colored/stippled rectangles.
+   rocks       - Flying through an asteroid field.
+   blitspin    - Rotate a bitmap using bitblts.
+   imsmap      - Generates random maps or cloud formations.
+   hypercube   - 2d projection of a hypercube rotating on all four axes.
+   slidescreen - Divides the screen into a grid and plays a 16-puzzle on it.
+   halo                - Random circular patterns.
+   pyro                - Fireworks.  Looks a lot like the version in xlock.
+   hopalong    - Fractals.  I snarfed this code from xlock.
+   noseguy     - A guy with a big nose wanders around the screen saying
+                 things.  I snarfed this code from xnlock.
+   maze                - This is the X maze demo modified to take a -root option
+                 so that it works with xscreensaver.
+
+All of these will pop up their own window unless given that -root option.
+See their man pages for more details.
+
+Other reasonable things to use as screensavers, if you have them, are
+
+  xdaliclock -root -builtin2   - melting digital clock
+  xswarm -r 2>&-               - swimming sperm
+  xwave -root                  - random 3d graphs
+  xbouncebits                  - bounce arbitrary bitmaps around
+  ico -r                       - it's dull, but it's there
+  xv -root file.gif -quit      - they don't all have to animate!
+  xsplinefun                   - bouncing splines
+  kaleid -root                 - qix-like kaleidescope patterns
+  xfishtank -c black -d -r 1   - fish (use version 2.0 or later)
+
+You can get all of these from export.lcs.mit.edu.  If you know of (or write)
+any other interesting programs that can be used as screensavers, please let
+me know!
+
+       -- Jamie Zawinski <jwz@lucid.com>
+
+[*] It may be necessary to include "vroot.h" in the program, but that would
+be necessary for it to work with virtual-root window managers anyway.
diff --git a/config.h b/config.h
new file mode 100644 (file)
index 0000000..6ec75c8
--- /dev/null
+++ b/config.h
@@ -0,0 +1,77 @@
+/*
+ * Config file for xscreensaver, Copyright (c) 1991-1993 Jamie Zawinski.
+ * This file is included by the various Imakefiles.
+ */
+
+/*  Uncomment the following line if you have the XIdle extension installed.
+ *  XIdle comes on the X11r5 contrib tape, in .../contrib/extensions/xidle/.
+ *  Installing it is the morally superior thing to do, but xscreensaver will
+ *  work without it.
+ */
+#define HAVE_XIDLE
+
+/*  Uncomment the following line if you don't have Motif.  If you don't have
+ *  Motif, then the screensaver won't have any dialog boxes, which means
+ *  that it won't be compiled with support for demo-mode or display-locking.
+ */
+/* #define NO_MOTIF */
+
+/* Uncomment the following line if for some reason the locking code doesn't
+ * work (for example, if you don't have the crypt() system call, or if you
+ * don't use standard passwd files.)
+ */
+/* #define NO_LOCKING */
+
+/*  Uncomment the following line if your system doesn't have the select()
+ *  system call.
+ */
+/* #define NO_SELECT */
+
+/*  Uncomment the following line if your system doesn't have the setuid(),
+ *  setregid(), and getpwnam() library routines.
+ *
+ *  WARNING: if you do this, it will be unsafe to run xscreensaver as root
+ *  (which probably means you can't have it be started by xdm.)  If you are
+ *  on such a system, please try to find the corresponding way to do this,
+ *  and then tell me what it is.
+ */
+/* #define NO_SETUID */
+
+
+/*  You may need to edit these to correspond to where Motif is installed.
+ */
+#ifndef NO_MOTIF
+  MOTIFINCLUDES = /* -I... */
+ MOTIFLDOPTIONS = /* -L... */
+      MOTIFLIBS = -lXm
+#endif
+
+/*  On some systems, only programs running as root can use the getpwent()
+    library routine.  This means that, in order for locking to work, the
+    screensaver must be installed as setuid to root.  Define this to make
+    that happen.  (You must run "make install" as root for it to work.)
+ */
+#if defined(HPArchitecture) /* What other systems need this?  Let me know. */
+# define INSTALL_SETUID
+#endif
+
+#ifdef HPArchitecture
+      CCOPTIONS = -Aa -D_HPUX_SOURCE   /* eat me */
+# if (ProjectX <= 4)
+  MOTIFINCLUDES = -I/usr/include/Motif1.1
+ MOTIFLDOPTIONS = -L/usr/lib/Motif1.1
+# else /* R5 */
+  MOTIFINCLUDES = -I/usr/include/Motif1.2
+ MOTIFLDOPTIONS = -L/usr/lib/Motif1.2
+# endif /* R5 */
+#endif /* HPArchitecture */
+
+#ifdef MacIIArchitecture
+      CCOPTIONS = -D_POSIX_SOURCE
+#endif /* MacIIArchitecture */
+
+#if (ProjectX <= 4)
+# define R5ISMS -DXPointer="char*"
+#else /* r5 or better */
+# define R5ISMS
+#endif
diff --git a/driver/.gdbinit b/driver/.gdbinit
new file mode 100644 (file)
index 0000000..6757459
--- /dev/null
@@ -0,0 +1,25 @@
+# If you're debugging xscreensaver and you are running a virtual root window
+# manager, you'd better let the process handle these signals: it remaps the
+# virtual root window when they arrive.  If you don't do this, your window
+# manager will be hosed.
+#
+# Also, gdb copes badly with breakpoints in functions that are called on the
+# other side of a fork().  The Trace/BPT traps cause the spawned process to
+# die.
+#
+#handle 1 pass nostop
+#handle 3 pass nostop
+#handle 4 pass nostop
+#handle 6 pass nostop
+#handle 7 pass nostop
+#handle 8 pass nostop
+#handle 9 pass nostop
+#handle 10 pass nostop
+#handle 11 pass nostop
+#handle 12 pass nostop
+#handle 13 pass nostop
+#handle 15 pass nostop
+#handle 19 pass nostop
+b exit
+set args -verbose -idelay 0 -lock
+#b purify_stop_here
diff --git a/driver/Imakefile b/driver/Imakefile
new file mode 100644 (file)
index 0000000..59eaf6f
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Imakefile file for xscreensaver, Copyright (c) 1993 Jamie Zawinski.
+ *
+ * You should not need to edit this file; edit ../config.h instead.
+ *
+ */
+
+#include "../config.h"
+
+#if defined(NO_MOTIF) && !defined(NO_LOCKING)
+# define NO_LOCKING
+#endif
+
+#ifdef NO_LOCKING
+# undef INSTALL_SETUID
+#endif
+
+#ifdef HAVE_XIDLE
+# define XIDLE_DEF -DHAVE_XIDLE
+#else
+# define XIDLE_DEF
+#endif
+
+#ifdef NO_LOCKING
+# define LOCKING_DEF -DNO_LOCKING
+#else
+# define LOCKING_DEF
+#endif
+
+#ifdef NO_SETUID
+# define SETUID_DEF -DNO_SETUID
+#else
+# define SETUID_DEF
+#endif
+
+#ifdef NO_MOTIF
+# define MOTIF_DEF -DNO_MOTIF
+# define MOTIF_SRC
+# define MOTIF_OBJ
+# define MOTIF_LIB
+# define MOTIF_INC
+#else
+# define MOTIF_DEF
+# define MOTIF_SRC $(DBOX_SRCS) $(UTILS)/xroger.c
+# define MOTIF_OBJ $(DBOX_OBJS) $(UTILS)/xroger.o
+# define MOTIF_LIB $(MOTIFLDOPTIONS) $(MOTIFLIBS)
+# define MOTIF_INC $(MOTIFINCLUDES)
+#endif
+
+          UTILS = ../utils
+       INCLUDES = -I$(UTILS) MOTIF_INC
+        DEFINES = SETUID_DEF XIDLE_DEF MOTIF_DEF LOCKING_DEF R5ISMS
+      SAVERLIBS = $(XMULIB) $(XTOOLLIB) $(EXTENSIONLIB) $(XLIB) -lm
+       COMMLIBS = $(XLIB) -lm
+      UTIL_SRCS = $(UTILS)/resources.c $(UTILS)/fade.c $(UTILS)/usleep.c
+      UTIL_OBJS = $(UTILS)/resources.o $(UTILS)/fade.o $(UTILS)/usleep.o
+      DBOX_SRCS = dialogs.c demo.c lock.c
+      DBOX_OBJS = dialogs.o demo.o lock.o
+      SAVERSRCS = xscreensaver.c visual.c timers.c subprocs.c windows.c
+      SAVEROBJS = xscreensaver.o visual.o timers.o subprocs.o windows.o
+          SRCS1 = $(SAVERSRCS) MOTIF_SRC $(UTIL_SRCS)
+          OBJS1 = $(SAVEROBJS) MOTIF_OBJ $(UTIL_OBJS)
+       COMMSRCS = xscreensaver-command.c
+       COMMOBJS = xscreensaver-command.o
+          SRCS2 = $(COMMSRCS)
+          OBJS2 = $(COMMOBJS)
+            MEN = xscreensaver.man xscreensaver-command.man
+       TARFILES = README Imakefile $(SAVERSRCS) $(DBOX_SRCS) $(COMMSRCS) \
+                  xscreensaver.h XScreenSaver.ad dialogs.xd $(MEN) .gdbinit
+
+#if defined(HPArchitecture) && !defined(NO_LOCKING)
+EXTRA_LIBRARIES = -lXhp11      /* for XHPDisableReset() */
+#endif
+
+all:: xscreensaver xscreensaver-command
+
+echo_tarfiles:
+       @echo $(TARFILES)
+
+PROGRAMS = xscreensaver xscreensaver-command
+
+#ifdef INSTALL_SETUID
+#undef  InstallProgram
+#define InstallProgram(p,d) InstallProgramWithFlags(p,d,$(INSTUIDFLAGS))
+#endif
+
+ComplexProgramTarget_1(xscreensaver,MOTIF_LIB $(SAVERLIBS),)
+
+#ifdef INSTALL_SETUID
+#undef  InstallProgram
+#define InstallProgram(p,d) InstallProgramWithFlags(p,d,)
+#endif
+
+ComplexProgramTarget_2(xscreensaver-command,$(COMMLIBS),)
+
+InstallAppDefaults(XScreenSaver)
+
+xscreensaver.o: XScreenSaver.ad.h $(UTILS)/version.h
+xscreensaver-command.o: $(UTILS)/version.h
+
+demo.o: $(UTILS)/version.h
+lock.o: $(UTILS)/version.h
+
+/* build this before calling makedepend */
+depend:: XScreenSaver.ad.h
+
+XScreenSaver.ad.h: XScreenSaver.ad
+       $(UTILS)/ad2c XScreenSaver.ad > XScreenSaver.ad.h
+
+clean::
+       $(RM) XScreenSaver.ad.h
diff --git a/driver/README b/driver/README
new file mode 100644 (file)
index 0000000..df64793
--- /dev/null
@@ -0,0 +1,6 @@
+
+This directory contains the source for xscreensaver and xscreensaver-command,
+the screensaver driver, and the program for externally controlling it.  Some
+stuff from the ../utils/ directory is used here as well.
+
+If you have compilation problems, check the parameters in ../config.h.
diff --git a/driver/XScreenSaver.ad b/driver/XScreenSaver.ad
new file mode 100644 (file)
index 0000000..8e2aae1
--- /dev/null
@@ -0,0 +1,149 @@
+! app-defaults file for XScreenSaver by Jamie Zawinski.
+
+*timeout:      10
+*cycle:                10
+*lockTimeout:  0
+*passwdTimeout:        30
+*nice:         10
+*lock:         False
+*verbose:      False
+*fade:         True
+*unfade:       False
+*fadeSeconds:  1
+*fadeTicks:    75
+
+! Turning on "installColormap" interacts erratically with twm and tvtwm,
+! but seems to work fine with mwm and olwm.  Try it and see.
+!
+*installColormap: False
+
+! Programs on this list apply all the time.
+*programs:     qix -root                                               \n\
+               qix -root -solid -delay 0 -segments 100                 \n\
+               qix -root -linear -count 10 -size 100 -segments 200     \n\
+               attraction -root -mode balls                            \n\
+               attraction -root -mode lines -points 3 -segments 200    \n\
+               attraction -root -mode splines -segments 300            \n\
+               attraction -root -mode lines -radius 300                \
+                       -orbit -vmult 0.5                               \n\
+               pyro -root                                              \n\
+               helix -root                                             \n\
+               rorschach -root -offset 7                               \n\
+               hopalong -root                                          \n\
+               greynetic -root                                         \n\
+               xroger -root                                            \n\
+               imsmap -root                                            \n\
+               slidescreen -root                                       \n\
+               hypercube -root                                         \n\
+               halo -root                                              \n\
+               maze -root                                              \n
+
+! Programs on this list are run only for monochrome screens.
+*monoPrograms: qix -root -linear -count 5 -size 200 -spread 30         \
+                       -segments 75 -solid -xor                        \n\
+               rocks -root                                             \n\
+               noseguy -root                                           \n
+
+! Programs on this list are run only for color (really, non-mono) screens.
+*colorPrograms:        qix -root -count 4 -solid -transparent                  \n\
+               qix -root -count 5 -solid -transparent -linear          \
+                       -segments 250 -size 100                         \n\
+               attraction -root -mode polygons                         \n\
+               attraction -root -mode filled-splines -segments 0       \n\
+               attraction -root -glow -points 10                       \n\
+               rocks -root -fg darksalmon                              \n\
+               noseguy -root -fg yellow -bg gray30                     \n
+
+
+! Some other screenhacks that you might want to track down:
+!
+!              xdaliclock -root -builtin2                              \n\
+!              xswarm -r 2>&-                                          \n\
+!              xwave -root                                             \n\
+!              xbouncebits ...                                         \n\
+!              ico -r                                                  \n\
+!              xsplinefun                                              \n\
+!              kaleid -root                                            \n\
+!              xfishtank -c black -d -r 2                              \n\
+
+
+! Resources for the dialog boxes:
+! 
+*fontList:                       *-helvetica-medium-r-*-*-*-120-*-*-*-iso8859-1
+*demoDialog*label1.fontList:     *-helvetica-medium-r-*-*-*-140-*-*-*-iso8859-1
+*passwdDialog*fontList:          *-helvetica-medium-r-*-*-*-140-*-*-*-iso8859-1
+*XmList.fontList:                  *-courier-medium-r-*-*-*-120-*-*-*-iso8859-1
+*XmTextField.fontList:             *-courier-medium-r-*-*-*-120-*-*-*-iso8859-1
+*passwdDialog.passwdText.fontList: *-courier-medium-r-*-*-*-120-*-*-*-iso8859-1
+
+*XmDialogShell*foreground:             black
+*XmDialogShell*background:             gray90
+*XmDialogShell*XmTextField.foreground: black
+*XmDialogShell*XmTextField.background: white
+*XmDialogShell*demoList.foreground:    black
+*XmDialogShell*demoList.background:    white
+*XmDialogShell*rogerLabel.foreground:  red3
+*XmDialogShell*rogerLabel.background:  white
+
+*XmDialogShell.title:          XScreenSaver
+*allowShellResize:             True
+*autoUnmanage:                 False
+
+! This doesn't work.  Motif ignores it if there is a scroll-list!
+*demoDialog.maxWidth:          600
+
+*label1.labelString:           XScreenSaver %s
+*label2.labelString: Copyright Â© 1991-1993 by Jamie Zawinski <jwz@lucid.com>
+*demoList.visibleItemCount:    10
+*demoList.automaticSelection:  True
+*next.labelString:             Run Next
+*prev.labelString:             Run Previous
+*edit.labelString:             Edit Parameters
+*done.labelString:             Exit Demo Mode
+*restart.labelString:          Reinitialize
+
+*resourcesLabel.labelString:   XScreenSaver Parameters
+
+! *timeoutLabel.labelString:   Timeout Minutes
+! *cycleLabel.labelString:     Cycle Seconds
+! *fadeSecondsLabel.labelString:Fade Seconds
+! *fadeTicksLabel.labelString: Fade Ticks
+! *lockLabel.labelString:      Lock Timeout
+! *passwdLabel.labelString:    Password Timeout
+! *resourcesForm*XmTextField.columns:  5
+
+*timeoutLabel.labelString:     Saver Timeout
+*cycleLabel.labelString:       Cycle Timeout
+*fadeSecondsLabel.labelString: Fade Duration
+*fadeTicksLabel.labelString:   Fade Ticks
+*lockLabel.labelString:                Lock Timeout
+*passwdLabel.labelString:      Password Timeout
+*resourcesForm*XmTextField.columns:    8
+
+*verboseToggle.labelString:    Verbose
+*cmapToggle.labelString:       Install Colormap
+*fadeToggle.labelString:       Fade Colormap
+*unfadeToggle.labelString:     Unfade Colormap
+*lockToggle.labelString:       Require Password
+*resourcesDone.labelString:    Done
+*resourcesCancel.labelString:  Cancel
+
+*passwdLabel1.labelString:     XScreenSaver %s
+*passwdLabel2.labelString:     This display is locked.
+*passwdLabel3.labelString:     Please type %s's password to unlock it.
+*passwdDone.labelString:       Done
+*passwdCancel.labelString:     Cancel
+
+*passwdLabel1.alignment:       ALIGNMENT_BEGINNING
+*passwdLabel2.alignment:       ALIGNMENT_BEGINNING
+*passwdLabel3.alignment:       ALIGNMENT_BEGINNING
+*rogerLabel.width:             150
+
+! You probably won't need to change these.  They aren't consulted if the
+! XIdle extension is being used.
+!
+*pointerPollTime:      5
+*initialDelay:         30
+*windowCreationTimeout:        30
+
+*bourneShell:          /bin/sh
diff --git a/driver/demo.c b/driver/demo.c
new file mode 100644 (file)
index 0000000..ec95724
--- /dev/null
@@ -0,0 +1,591 @@
+/* xscreensaver, Copyright (c) 1993 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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 <X11/Intrinsic.h>
+
+#if !__STDC__
+# define _NO_PROTO
+#endif
+
+#include <Xm/Xm.h>
+#include <Xm/Text.h>
+#include <Xm/List.h>
+#include <Xm/ToggleB.h>
+
+#include "xscreensaver.h"
+#include <stdio.h>
+
+extern Time timeout, cycle, lock_timeout, passwd_timeout;
+extern int fade_seconds, fade_ticks;
+extern Bool verbose_p, install_cmap_p, fade_p, unfade_p;
+extern Bool lock_p, locking_disabled_p;
+
+static void demo_mode_hack P((char *));
+static void demo_mode_done P((void));
+
+extern void demo_mode_restart_process ();
+
+extern Widget demo_dialog;
+extern Widget label1;
+extern Widget text_line;
+extern Widget demo_form;
+extern Widget demo_list;
+extern Widget next, prev, done, restart, edit;
+
+extern Widget resources_dialog;
+extern Widget resources_form;
+extern Widget res_done, res_cancel;
+extern Widget timeout_text, cycle_text, fade_text, ticks_text;
+extern Widget lock_time_text, passwd_time_text;
+extern Widget verbose_toggle, cmap_toggle, fade_toggle, unfade_toggle,
+  lock_toggle;
+
+extern create_demo_dialog ();
+extern create_resources_dialog ();
+
+static void
+focus_fuckus (dialog)
+     Widget dialog;
+{
+  XSetInputFocus (XtDisplay (dialog), XtWindow (dialog),
+                 RevertToParent, CurrentTime);
+}
+
+static void
+raise_screenhack_dialog ()
+{
+  XMapRaised (XtDisplay (demo_dialog), XtWindow (demo_dialog));
+  if (resources_dialog)
+    XMapRaised (XtDisplay (resources_dialog), XtWindow (resources_dialog));
+  focus_fuckus (resources_dialog ? resources_dialog : demo_dialog);
+}
+
+static void
+destroy_screenhack_dialogs ()
+{
+  if (demo_dialog) XtDestroyWidget (demo_dialog);
+  if (resources_dialog) XtDestroyWidget (resources_dialog);
+  demo_dialog = resources_dialog = 0;
+}
+
+static void
+text_cb (button, client_data, call_data)
+     Widget button;
+     XtPointer client_data, call_data;
+{
+  char *line = XmTextGetString (button);
+  demo_mode_hack (line);
+}
+
+
+static void
+select_cb (button, client_data, call_data)
+     Widget button;
+     XtPointer client_data, call_data;
+{
+  char **hacks = (char **) client_data;
+  XmListCallbackStruct *lcb = (XmListCallbackStruct *) call_data;
+  XmTextSetString (text_line, hacks [lcb->item_position - 1]);
+  if (lcb->reason == XmCR_DEFAULT_ACTION)
+    text_cb (text_line, 0, 0);
+  focus_fuckus (demo_dialog);
+}
+
+static void
+next_cb (button, client_data, call_data)
+     Widget button;
+     XtPointer client_data, call_data;
+{
+  int *pos_list;
+  int pos_count;
+  if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count))
+    XmListSelectPos (demo_list, 1, True);
+  else
+    {
+      int pos = pos_list [0];
+      XmListSelectPos (demo_list, pos + 1, True);
+      XtFree ((char *) pos_list);
+      if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count))
+       abort ();
+      if (pos_list [0] == pos)
+       XmListSelectPos (demo_list, 1, True);
+      XtFree ((char *) pos_list);
+    }
+  text_cb (text_line, 0, 0);
+}
+
+static void
+prev_cb (button, client_data, call_data)
+     Widget button;
+     XtPointer client_data, call_data;
+{
+  int *pos_list;
+  int pos_count;
+  if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count))
+    XmListSelectPos (demo_list, 0, True);
+  else
+    {
+      XmListSelectPos (demo_list, pos_list [0] - 1, True);
+      XtFree ((char *) pos_list);
+    }
+  text_cb (text_line, 0, 0);
+}
+
+
+static void pop_resources_dialog ();
+static void make_resources_dialog ();
+
+static void
+edit_cb (button, client_data, call_data)
+     Widget button;
+     XtPointer client_data, call_data;
+{
+  Widget parent = (Widget) client_data;
+  if (! resources_dialog)
+    make_resources_dialog (parent);
+  pop_resources_dialog ();
+}
+
+static void
+done_cb (button, client_data, call_data)
+     Widget button;
+     XtPointer client_data, call_data;
+{
+  demo_mode_done ();
+}
+
+
+static void
+restart_cb (button, client_data, call_data)
+     Widget button;
+     XtPointer client_data, call_data;
+{
+  demo_mode_restart_process ();
+}
+
+void
+pop_up_dialog_box (dialog, form, where)
+     Widget dialog, form;
+     int where;
+{
+  /* I'm sure this is the wrong way to pop up a dialog box, but I can't
+     figure out how else to do it.
+
+     It's important that the screensaver dialogs not get decorated or
+     otherwise reparented by the window manager, because they need to be
+     children of the *real* root window, not the WM's virtual root, in
+     order for us to guarentee tha they are visible above the screensaver
+     window itself.
+   */
+  Arg av [100];
+  int ac = 0;
+  Dimension sw, sh, x, y, w, h;
+  XtRealizeWidget (form);
+  sw = WidthOfScreen (XtScreen (dialog));
+  sh = HeightOfScreen (XtScreen (dialog));
+  ac = 0;
+  XtSetArg (av [ac], XmNwidth, &w); ac++;
+  XtSetArg (av [ac], XmNheight, &h); ac++;
+  XtGetValues (form, av, ac);
+  switch (where)
+    {
+    case 0:    /* center it in the top-right quadrant */
+      x = (sw/2 + w) / 2 + (sw/2) - w;
+      y = (sh/2 + h) / 2 - h;
+      break;
+    case 1:    /* center it in the bottom-right quadrant */
+      x = (sw/2 + w) / 2 + (sw/2) - w;
+      y = (sh/2 + h) / 2 + (sh/2) - h;
+      break;
+    case 2:    /* center it on the screen */
+      x = (sw + w) / 2 - w;
+      y = (sh + h) / 2 - h;
+      break;
+    default:
+      abort ();
+    }
+  if (x + w > sw) x = sw - w;
+  if (y + h > sh) y = sh - h;
+  ac = 0;
+  XtSetArg (av [ac], XmNx, x); ac++;
+  XtSetArg (av [ac], XmNy, y); ac++;
+  XtSetArg (av [ac], XtNoverrideRedirect, True); ac++;
+  XtSetArg (av [ac], XmNdefaultPosition, False); ac++;
+  /* I wonder whether this does anything useful? */
+/* XtSetArg (av [ac], XmNdialogStyle, XmDIALOG_SYSTEM_MODAL); ac++; */
+  XtSetValues (dialog, av, ac);
+  XtSetValues (form, av, ac);
+  XtManageChild (form);
+
+  focus_fuckus (dialog);
+}
+
+
+static void
+make_screenhack_dialog (parent, hacks)
+     Widget parent;
+     char **hacks;
+{
+  char buf [255];
+  Arg av[10];
+  int ac;
+  char *label;
+  Dimension max_w = 0;
+  XmString xm_label = 0;
+  XmString new_xm_label;
+
+  create_demo_dialog (parent);
+  ac = 0;
+  XtSetArg (av [ac], XmNlabelString, &xm_label); ac++;
+  XtGetValues (label1, av, ac);
+  XmStringGetLtoR (xm_label, XmSTRING_DEFAULT_CHARSET, &label);
+  if (!strcmp (label, XtName (label1)))
+    strcpy (buf, "ERROR: RESOURCES ARE NOT INSTALLED CORRECTLY");
+  else
+    sprintf (buf, label, screensaver_version);
+  new_xm_label = XmStringCreate (buf, XmSTRING_DEFAULT_CHARSET);
+  ac = 0;
+  XtSetArg (av [ac], XmNlabelString, new_xm_label); ac++;
+  XtSetValues (label1, av, ac);
+  XmStringFree (new_xm_label);
+  XtFree (label);
+
+  XtAddCallback (demo_list, XmNbrowseSelectionCallback, select_cb,
+                hacks);
+  XtAddCallback (demo_list, XmNdefaultActionCallback, select_cb,
+                hacks);
+
+  XtAddCallback (text_line, XmNactivateCallback, text_cb, 0);
+  XtAddCallback (next, XmNactivateCallback, next_cb, 0);
+  XtAddCallback (prev, XmNactivateCallback, prev_cb, 0);
+  XtAddCallback (done, XmNactivateCallback, done_cb, 0);
+  XtAddCallback (restart, XmNactivateCallback, restart_cb, 0);
+  XtAddCallback (edit, XmNactivateCallback, edit_cb, parent);
+
+  for (; *hacks; hacks++)
+    {
+      XmString xmstr = XmStringCreate (*hacks, XmSTRING_DEFAULT_CHARSET);
+      XmListAddItem (demo_list, xmstr, 0);
+      /* XmListSelectPos (widget, i, False); */
+      XmStringFree (xmstr);
+    }
+
+#if 0
+  /* Dialogs that have scroll-lists don't obey maxWidth!  Fuck!!  Hack it. */
+  ac = 0;
+  XtSetArg (av [ac], XmNmaxWidth, &max_w); ac++;
+  XtGetValues (demo_dialog, av, ac); /* great, this SEGVs */
+#endif
+
+  pop_up_dialog_box (demo_dialog, demo_form, 0);
+}
+
+\f
+/* the Screensaver Parameters dialog */
+
+static struct resources {
+  int timeout, cycle, secs, ticks, lock_time, passwd_time;
+  int verb, cmap, fade, unfade, lock_p;
+} res;
+
+
+extern int parse_time ();
+
+static void 
+hack_time_cb (dpy, line, store, sec_p)
+     Display *dpy;
+     char *line;
+     int *store;
+     Bool sec_p;
+{
+  if (*line)
+    {
+      int value;
+      value = parse_time (line, sec_p, True);
+      if (value < 0)
+       /*XBell (dpy, 0)*/;
+      else
+       *store = value;
+    }
+}
+
+static void
+res_sec_cb (button, client_data, call_data)
+     Widget button;
+     XtPointer client_data, call_data;
+{
+  hack_time_cb (XtDisplay (button), XmTextGetString (button),
+               (int *) client_data, True);
+}
+
+static void
+res_min_cb (button, client_data, call_data)
+     Widget button;
+     XtPointer client_data, call_data;
+{
+  hack_time_cb (XtDisplay (button), XmTextGetString (button),
+               (int *) client_data, False);
+}
+
+static void
+res_int_cb (button, client_data, call_data)
+     Widget button;
+     XtPointer client_data, call_data;
+{
+  char *line = XmTextGetString (button);
+  int *store = (int *) client_data;
+  unsigned int value;
+  char c;
+  if (! *line)
+    ;
+  else if (sscanf (line, "%u%c", &value, &c) != 1)
+    XBell (XtDisplay (button), 0);
+  else
+    *store = value;
+}
+
+static void
+res_bool_cb (button, client_data, call_data)
+     Widget button;
+     XtPointer client_data, call_data;
+{
+  int *store = (int *) client_data;
+  *store = ((XmToggleButtonCallbackStruct *) call_data)->set;
+}
+
+static void
+res_cancel_cb (button, client_data, call_data)
+     Widget button;
+     XtPointer client_data, call_data;
+{
+  XtDestroyWidget (resources_dialog);
+  resources_dialog = 0;
+  raise_screenhack_dialog ();
+}
+
+
+static void
+res_done_cb (button, client_data, call_data)
+     Widget button;
+     XtPointer client_data, call_data;
+{
+  res_cancel_cb (button, client_data, call_data);
+
+  if (res.timeout < 10) res.timeout = 10;
+  if (res.cycle < 2) res.cycle = 2;
+  if (res.passwd_time < 2) res.passwd_time = 30;
+
+  timeout = res.timeout * 1000;
+  cycle = res.cycle * 1000;
+  lock_timeout = res.lock_time * 1000;
+  passwd_timeout = res.passwd_time * 1000;
+  fade_seconds = res.secs;
+  fade_ticks = res.ticks;
+  verbose_p = res.verb;
+  install_cmap_p = res.cmap;
+  fade_p = res.fade;
+  unfade_p = res.unfade;
+  lock_p = res.lock_p;
+}
+
+
+static void
+make_resources_dialog (parent)
+     Widget parent;
+{
+  Arg av[10];
+  int ac;
+
+  create_resources_dialog (parent);
+
+  XtAddCallback (res_done, XmNactivateCallback, res_done_cb, 0);
+  XtAddCallback (res_cancel, XmNactivateCallback, res_cancel_cb, 0);
+
+#define CB(widget,type,slot) \
+       XtAddCallback ((widget), XmNvalueChangedCallback, (type), (slot))
+  CB (timeout_text,    res_min_cb,  &res.timeout);
+  CB (cycle_text,      res_min_cb,  &res.cycle);
+  CB (fade_text,       res_sec_cb,  &res.secs);
+  CB (ticks_text,      res_int_cb,  &res.ticks);
+  CB (lock_time_text,  res_min_cb,  &res.lock_time);
+  CB (passwd_time_text,        res_sec_cb,  &res.passwd_time);
+  CB (verbose_toggle,  res_bool_cb, &res.verb);
+  CB (cmap_toggle,     res_bool_cb, &res.cmap);
+  CB (fade_toggle,     res_bool_cb, &res.fade);
+  CB (unfade_toggle,   res_bool_cb, &res.unfade);
+  CB (lock_toggle,     res_bool_cb, &res.lock_p);
+#undef CB
+  ac = 0;
+  XtSetArg (av[ac], XmNsensitive, False); ac++;
+
+  if (locking_disabled_p)
+    {
+      XtSetValues (passwd_time_text, av, ac);
+      XtSetValues (lock_time_text, av, ac);
+      XtSetValues (lock_toggle, av, ac);
+    }
+  if (CellsOfScreen (XtScreen (parent)) <= 2)
+    {
+      XtSetValues (fade_text, av, ac);
+      XtSetValues (ticks_text, av, ac);
+      XtSetValues (cmap_toggle, av, ac);
+      XtSetValues (fade_toggle, av, ac);
+      XtSetValues (unfade_toggle, av, ac);
+    }
+}
+
+
+static void
+fmt_time (buf, s, min_p)
+     char *buf;
+     unsigned int s;
+     int min_p;
+{
+  unsigned int h = 0, m = 0;
+  if (s >= 60)
+    {
+      m += (s / 60);
+      s %= 60;
+    }
+  if (m >= 60)
+    {
+      h += (m / 60);
+      m %= 60;
+    }
+/*
+  if (min_p && h == 0 && s == 0)
+    sprintf (buf, "%u", m);
+  else if (!min_p && h == 0 && m == 0)
+    sprintf (buf, "%u", s);
+  else
+  if (h == 0)
+    sprintf (buf, "%u:%02u", m, s);
+  else
+*/
+    sprintf (buf, "%u:%02u:%02u", h, m, s);
+}
+
+static void
+pop_resources_dialog ()
+{
+  char buf [100];
+
+  res.timeout = timeout / 1000;
+  res.cycle = cycle / 1000;
+  res.lock_time = lock_timeout / 1000;
+  res.passwd_time = passwd_timeout / 1000;
+  res.secs = fade_seconds;
+  res.ticks = fade_ticks;
+  res.verb = verbose_p;
+  res.cmap = install_cmap_p;
+  res.fade = fade_p;
+  res.unfade = unfade_p;
+  res.lock_p = (lock_p && !locking_disabled_p);
+
+  fmt_time (buf, res.timeout, 1);     XmTextSetString (timeout_text, buf);
+  fmt_time (buf, res.cycle, 1);       XmTextSetString (cycle_text, buf);
+  fmt_time (buf, res.lock_time, 1);   XmTextSetString (lock_time_text, buf);
+  fmt_time (buf, res.passwd_time, 0); XmTextSetString (passwd_time_text, buf);
+  fmt_time (buf, res.secs, 0);        XmTextSetString (fade_text, buf);
+  sprintf (buf, "%u", res.ticks);     XmTextSetString (ticks_text, buf);
+
+  XmToggleButtonSetState (verbose_toggle, res.verb, True);
+  XmToggleButtonSetState (cmap_toggle, res.cmap, True);
+  XmToggleButtonSetState (fade_toggle, res.fade, True);
+  XmToggleButtonSetState (unfade_toggle, res.unfade, True);
+  XmToggleButtonSetState (lock_toggle, res.lock_p, True);
+
+  pop_up_dialog_box (resources_dialog, resources_form, 1);
+}
+
+\f
+/* The code on this page isn't actually Motif-specific */
+
+Bool dbox_up_p = False;
+Bool demo_mode_p = False;
+
+extern XtAppContext app;
+extern Widget toplevel_shell;
+extern Bool use_xidle;
+extern Time notice_events_timeout;
+
+extern char **screenhacks;
+extern char *demo_hack;
+
+extern void notice_events_timer P((XtPointer closure, void *timer));
+extern Bool handle_clientmessage P((/*XEvent *, Bool*/));
+
+void
+demo_mode ()
+{
+  dbox_up_p = True;
+  initialize_screensaver_window ();
+  raise_window (True, False);
+  make_screenhack_dialog (toplevel_shell, screenhacks);
+  while (demo_mode_p)
+    {
+      XEvent event;
+      XtAppNextEvent (app, &event);
+      switch (event.xany.type)
+       {
+       case 0:         /* synthetic "timeout" event */
+         break;
+
+       case ClientMessage:
+         handle_clientmessage (&event, False);
+         break;
+
+       case CreateNotify:
+#ifdef HAVE_XIDLE
+         if (! use_xidle)
+#endif
+           XtAppAddTimeOut (app, notice_events_timeout, notice_events_timer,
+                            (XtPointer) event.xcreatewindow.window);
+         break;
+
+       case ButtonPress:
+       case ButtonRelease:
+         if (!XtWindowToWidget (dpy, event.xbutton.window))
+           raise_screenhack_dialog ();
+         /* fall through */
+
+       default:
+         XtDispatchEvent (&event);
+         break;
+       }
+    }
+  destroy_screenhack_dialogs ();
+  initialize_screensaver_window ();
+  unblank_screen ();
+}
+
+static void
+demo_mode_hack (hack)
+     char *hack;
+{
+  if (! demo_mode_p) abort ();
+  kill_screenhack ();
+  if (! demo_hack)
+    blank_screen ();
+  demo_hack = hack;
+  spawn_screenhack (False);
+}
+
+static void
+demo_mode_done ()
+{
+  kill_screenhack ();
+  if (demo_hack)
+    unblank_screen ();
+  demo_mode_p = False;
+  dbox_up_p = False;
+  demo_hack = 0;
+}
diff --git a/driver/dialogs.c b/driver/dialogs.c
new file mode 100644 (file)
index 0000000..a1184e1
--- /dev/null
@@ -0,0 +1,741 @@
+
+/*
+** Generated by X-Designer 
+*/
+/*
+**LIBS: -lXm -lXt -lX11
+*/
+
+#if !__STDC__
+# define _NO_PROTO
+#endif
+
+#include <X11/Xatom.h>
+#include <X11/Intrinsic.h>
+#include <X11/Shell.h>
+
+#include <Xm/Xm.h>
+#include <Xm/DialogS.h>
+#include <Xm/DrawnB.h>
+#include <Xm/Form.h>
+#include <Xm/Label.h>
+#include <Xm/List.h>
+#include <Xm/PushB.h>
+#include <Xm/ScrollBar.h>
+#include <Xm/Separator.h>
+#include <Xm/TextF.h>
+#include <Xm/ToggleB.h>
+
+
+Widget passwd_dialog;
+Widget passwd_form;
+Widget roger_label;
+Widget passwd_label1;
+Widget passwd_label3;
+Widget passwd_text;
+Widget passwd_done;
+Widget passwd_cancel;
+
+Widget resources_dialog;
+Widget resources_form;
+Widget timeout_text;
+Widget cycle_text;
+Widget fade_text;
+Widget ticks_text;
+Widget lock_time_text;
+Widget passwd_time_text;
+Widget verbose_toggle;
+Widget cmap_toggle;
+Widget fade_toggle;
+Widget unfade_toggle;
+Widget lock_toggle;
+Widget res_done;
+Widget res_cancel;
+
+Widget demo_dialog;
+Widget demo_form;
+Widget label1;
+Widget label2;
+Widget text_area;
+Widget demo_list;
+Widget text_line;
+Widget vline;
+Widget next;
+Widget prev;
+Widget edit;
+Widget done;
+Widget restart;
+Widget spacer;
+
+
+create_passwd_dialog( parent )
+Widget parent;
+{
+       Display *display = XtDisplay ( parent );
+       Widget children[8];      /* Children to manage */
+       Arg al[64];           /* Arg List */
+       register int ac = 0;      /* Arg Count */
+       char from_s [256];    /* For font list conversion */
+       XrmValue from_value, to_value; /* ditto */
+       int fg, bg;           /* colour values for pixmaps */ 
+       XmString *list_items; /* For list items */
+       int list_item;        /* Index for list_items */
+       XmString xmstrings[15];    /* temporary storage for XmStrings */
+       Widget widget4;
+       Widget widget7;
+
+       passwd_dialog = XmCreateDialogShell ( parent, "passwdDialog", al, ac );
+       passwd_form = XmCreateForm ( passwd_dialog, "passwdForm", al, ac );
+       roger_label = XmCreateDrawnButton ( passwd_form, "rogerLabel", al, ac );
+       passwd_label1 = XmCreateLabel ( passwd_form, "passwdLabel1", al, ac );
+       widget4 = XmCreateLabel ( passwd_form, "passwdLabel2", al, ac );
+       passwd_label3 = XmCreateLabel ( passwd_form, "passwdLabel3", al, ac );
+       passwd_text = XmCreateTextField ( passwd_form, "passwdText", al, ac );
+       widget7 = XmCreateSeparator ( passwd_form, "widget7", al, ac );
+       passwd_done = XmCreatePushButton ( passwd_form, "passwdDone", al, ac );
+       passwd_cancel = XmCreatePushButton ( passwd_form, "passwdCancel", al, ac );
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 4); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 4); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 4); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
+        XtSetValues ( roger_label,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 4); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 4); ac++;
+       XtSetArg(al[ac], XmNbottomWidget, widget4); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 4); ac++;
+       XtSetArg(al[ac], XmNleftWidget, roger_label); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNrightOffset, 4); ac++;
+        XtSetValues ( passwd_label1,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 4); ac++;
+       XtSetArg(al[ac], XmNbottomWidget, passwd_label3); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 4); ac++;
+       XtSetArg(al[ac], XmNleftWidget, roger_label); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNrightOffset, 4); ac++;
+        XtSetValues ( widget4,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 4); ac++;
+       XtSetArg(al[ac], XmNbottomWidget, passwd_text); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 4); ac++;
+       XtSetArg(al[ac], XmNleftWidget, roger_label); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNrightOffset, 30); ac++;
+        XtSetValues ( passwd_label3,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 4); ac++;
+       XtSetArg(al[ac], XmNbottomWidget, widget7); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 4); ac++;
+       XtSetArg(al[ac], XmNleftWidget, roger_label); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNrightOffset, 4); ac++;
+        XtSetValues ( passwd_text,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 4); ac++;
+       XtSetArg(al[ac], XmNbottomWidget, passwd_done); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 0); ac++;
+       XtSetArg(al[ac], XmNleftWidget, roger_label); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNrightOffset, 0); ac++;
+        XtSetValues ( widget7,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 4); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 4); ac++;
+       XtSetArg(al[ac], XmNleftWidget, roger_label); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
+        XtSetValues ( passwd_done,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 4); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 4); ac++;
+       XtSetArg(al[ac], XmNleftWidget, passwd_done); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
+        XtSetValues ( passwd_cancel,al, ac );
+       ac = 0;
+       children[ac++] = roger_label;
+       children[ac++] = passwd_label1;
+       children[ac++] = widget4;
+       children[ac++] = passwd_label3;
+       children[ac++] = passwd_text;
+       children[ac++] = widget7;
+       children[ac++] = passwd_done;
+       children[ac++] = passwd_cancel;
+       XtManageChildren(children, ac);
+       ac = 0;
+}
+
+
+
+create_resources_dialog( parent )
+Widget parent;
+{
+       Display *display = XtDisplay ( parent );
+       Widget children[22];      /* Children to manage */
+       Arg al[64];           /* Arg List */
+       register int ac = 0;      /* Arg Count */
+       char from_s [256];    /* For font list conversion */
+       XrmValue from_value, to_value; /* ditto */
+       int fg, bg;           /* colour values for pixmaps */ 
+       XmString *list_items; /* For list items */
+       int list_item;        /* Index for list_items */
+       XmString xmstrings[15];    /* temporary storage for XmStrings */
+       Widget widget12;
+       Widget widget13;
+       Widget widget14;
+       Widget widget15;
+       Widget widget16;
+       Widget widget17;
+       Widget widget18;
+       Widget widget48;
+       Widget widget29;
+
+       resources_dialog = XmCreateDialogShell ( parent, "resourcesDialog", al, ac );
+       resources_form = XmCreateForm ( resources_dialog, "resourcesForm", al, ac );
+       widget12 = XmCreateLabel ( resources_form, "resourcesLabel", al, ac );
+       widget13 = XmCreateSeparator ( resources_form, "widget13", al, ac );
+       XtSetArg(al[ac], XmNalignment, XmALIGNMENT_END); ac++;
+       widget14 = XmCreateLabel ( resources_form, "timeoutLabel", al, ac );
+       ac = 0;
+       XtSetArg(al[ac], XmNalignment, XmALIGNMENT_END); ac++;
+       widget15 = XmCreateLabel ( resources_form, "cycleLabel", al, ac );
+       ac = 0;
+       XtSetArg(al[ac], XmNalignment, XmALIGNMENT_END); ac++;
+       widget16 = XmCreateLabel ( resources_form, "fadeSecondsLabel", al, ac );
+       ac = 0;
+       XtSetArg(al[ac], XmNalignment, XmALIGNMENT_END); ac++;
+       widget17 = XmCreateLabel ( resources_form, "fadeTicksLabel", al, ac );
+       ac = 0;
+       XtSetArg(al[ac], XmNalignment, XmALIGNMENT_END); ac++;
+       widget18 = XmCreateLabel ( resources_form, "lockLabel", al, ac );
+       ac = 0;
+       XtSetArg(al[ac], XmNalignment, XmALIGNMENT_END); ac++;
+       widget48 = XmCreateLabel ( resources_form, "passwdLabel", al, ac );
+       ac = 0;
+       timeout_text = XmCreateTextField ( resources_form, "timeoutText", al, ac );
+       cycle_text = XmCreateTextField ( resources_form, "cycleText", al, ac );
+       fade_text = XmCreateTextField ( resources_form, "fadeSecondsText", al, ac );
+       ticks_text = XmCreateTextField ( resources_form, "fadeTicksText", al, ac );
+       lock_time_text = XmCreateTextField ( resources_form, "passwdText", al, ac );
+       passwd_time_text = XmCreateTextField ( resources_form, "lockText", al, ac );
+       XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
+       verbose_toggle = XmCreateToggleButton ( resources_form, "verboseToggle", al, ac );
+       ac = 0;
+       XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
+       cmap_toggle = XmCreateToggleButton ( resources_form, "cmapToggle", al, ac );
+       ac = 0;
+       XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
+       fade_toggle = XmCreateToggleButton ( resources_form, "fadeToggle", al, ac );
+       ac = 0;
+       XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
+       unfade_toggle = XmCreateToggleButton ( resources_form, "unfadeToggle", al, ac );
+       ac = 0;
+       XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
+       lock_toggle = XmCreateToggleButton ( resources_form, "lockToggle", al, ac );
+       ac = 0;
+       widget29 = XmCreateSeparator ( resources_form, "widget29", al, ac );
+       res_done = XmCreatePushButton ( resources_form, "resourcesDone", al, ac );
+       res_cancel = XmCreatePushButton ( resources_form, "resourcesCancel", al, ac );
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 4); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 4); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNrightOffset, 4); ac++;
+        XtSetValues ( widget12,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 4); ac++;
+       XtSetArg(al[ac], XmNtopWidget, widget12); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 0); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNrightOffset, 0); ac++;
+        XtSetValues ( widget13,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 4); ac++;
+       XtSetArg(al[ac], XmNtopWidget, widget13); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNbottomWidget, timeout_text); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 20); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNrightOffset, 4); ac++;
+       XtSetArg(al[ac], XmNrightWidget, timeout_text); ac++;
+        XtSetValues ( widget14,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 0); ac++;
+       XtSetArg(al[ac], XmNtopWidget, cycle_text); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 0); ac++;
+       XtSetArg(al[ac], XmNbottomWidget, cycle_text); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 20); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNrightOffset, 4); ac++;
+       XtSetArg(al[ac], XmNrightWidget, cycle_text); ac++;
+        XtSetValues ( widget15,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 0); ac++;
+       XtSetArg(al[ac], XmNtopWidget, fade_text); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 0); ac++;
+       XtSetArg(al[ac], XmNbottomWidget, fade_text); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 20); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNrightOffset, 4); ac++;
+       XtSetArg(al[ac], XmNrightWidget, fade_text); ac++;
+        XtSetValues ( widget16,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 0); ac++;
+       XtSetArg(al[ac], XmNtopWidget, ticks_text); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 0); ac++;
+       XtSetArg(al[ac], XmNbottomWidget, ticks_text); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 20); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNrightOffset, 4); ac++;
+       XtSetArg(al[ac], XmNrightWidget, ticks_text); ac++;
+        XtSetValues ( widget17,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 0); ac++;
+       XtSetArg(al[ac], XmNtopWidget, lock_time_text); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 0); ac++;
+       XtSetArg(al[ac], XmNbottomWidget, lock_time_text); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 19); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNrightOffset, 4); ac++;
+       XtSetArg(al[ac], XmNrightWidget, lock_time_text); ac++;
+        XtSetValues ( widget18,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 0); ac++;
+       XtSetArg(al[ac], XmNtopWidget, passwd_time_text); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 0); ac++;
+       XtSetArg(al[ac], XmNbottomWidget, passwd_time_text); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 14); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNrightOffset, 4); ac++;
+       XtSetArg(al[ac], XmNrightWidget, passwd_time_text); ac++;
+        XtSetValues ( widget48,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 4); ac++;
+       XtSetArg(al[ac], XmNtopWidget, widget13); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 141); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
+        XtSetValues ( timeout_text,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 2); ac++;
+       XtSetArg(al[ac], XmNtopWidget, timeout_text); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 0); ac++;
+       XtSetArg(al[ac], XmNleftWidget, timeout_text); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
+        XtSetValues ( cycle_text,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 2); ac++;
+       XtSetArg(al[ac], XmNtopWidget, cycle_text); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 0); ac++;
+       XtSetArg(al[ac], XmNleftWidget, cycle_text); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
+        XtSetValues ( fade_text,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 2); ac++;
+       XtSetArg(al[ac], XmNtopWidget, fade_text); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 0); ac++;
+       XtSetArg(al[ac], XmNleftWidget, fade_text); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
+        XtSetValues ( ticks_text,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 2); ac++;
+       XtSetArg(al[ac], XmNtopWidget, ticks_text); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 0); ac++;
+       XtSetArg(al[ac], XmNleftWidget, ticks_text); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
+        XtSetValues ( lock_time_text,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 4); ac++;
+       XtSetArg(al[ac], XmNtopWidget, lock_time_text); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 0); ac++;
+       XtSetArg(al[ac], XmNleftWidget, lock_time_text); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
+        XtSetValues ( passwd_time_text,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 4); ac++;
+       XtSetArg(al[ac], XmNtopWidget, widget13); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 0); ac++;
+       XtSetArg(al[ac], XmNbottomWidget, timeout_text); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 20); ac++;
+       XtSetArg(al[ac], XmNleftWidget, timeout_text); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNrightOffset, 20); ac++;
+        XtSetValues ( verbose_toggle,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 0); ac++;
+       XtSetArg(al[ac], XmNtopWidget, cycle_text); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 0); ac++;
+       XtSetArg(al[ac], XmNbottomWidget, cycle_text); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 0); ac++;
+       XtSetArg(al[ac], XmNleftWidget, verbose_toggle); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNrightOffset, 20); ac++;
+        XtSetValues ( cmap_toggle,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 0); ac++;
+       XtSetArg(al[ac], XmNtopWidget, fade_text); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 0); ac++;
+       XtSetArg(al[ac], XmNbottomWidget, fade_text); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 0); ac++;
+       XtSetArg(al[ac], XmNleftWidget, cmap_toggle); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNrightOffset, 20); ac++;
+        XtSetValues ( fade_toggle,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 0); ac++;
+       XtSetArg(al[ac], XmNtopWidget, ticks_text); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 0); ac++;
+       XtSetArg(al[ac], XmNbottomWidget, ticks_text); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 0); ac++;
+       XtSetArg(al[ac], XmNleftWidget, fade_toggle); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNrightOffset, 20); ac++;
+        XtSetValues ( unfade_toggle,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 0); ac++;
+       XtSetArg(al[ac], XmNtopWidget, lock_time_text); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 0); ac++;
+       XtSetArg(al[ac], XmNbottomWidget, lock_time_text); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 0); ac++;
+       XtSetArg(al[ac], XmNleftWidget, unfade_toggle); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNrightOffset, 20); ac++;
+        XtSetValues ( lock_toggle,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 0); ac++;
+       XtSetArg(al[ac], XmNtopWidget, passwd_time_text); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 4); ac++;
+       XtSetArg(al[ac], XmNbottomWidget, res_done); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+        XtSetValues ( widget29,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 4); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 4); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
+        XtSetValues ( res_done,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 4); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 4); ac++;
+       XtSetArg(al[ac], XmNleftWidget, res_done); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
+        XtSetValues ( res_cancel,al, ac );
+       ac = 0;
+       children[ac++] = widget12;
+       children[ac++] = widget13;
+       children[ac++] = widget14;
+       children[ac++] = widget15;
+       children[ac++] = widget16;
+       children[ac++] = widget17;
+       children[ac++] = widget18;
+       children[ac++] = widget48;
+       children[ac++] = timeout_text;
+       children[ac++] = cycle_text;
+       children[ac++] = fade_text;
+       children[ac++] = ticks_text;
+       children[ac++] = lock_time_text;
+       children[ac++] = passwd_time_text;
+       children[ac++] = verbose_toggle;
+       children[ac++] = cmap_toggle;
+       children[ac++] = fade_toggle;
+       children[ac++] = unfade_toggle;
+       children[ac++] = lock_toggle;
+       children[ac++] = widget29;
+       children[ac++] = res_done;
+       children[ac++] = res_cancel;
+       XtManageChildren(children, ac);
+       ac = 0;
+}
+
+
+
+create_demo_dialog( parent )
+Widget parent;
+{
+       Display *display = XtDisplay ( parent );
+       Widget children[11];      /* Children to manage */
+       Arg al[64];           /* Arg List */
+       register int ac = 0;      /* Arg Count */
+       char from_s [256];    /* For font list conversion */
+       XrmValue from_value, to_value; /* ditto */
+       int fg, bg;           /* colour values for pixmaps */ 
+       XmString *list_items; /* For list items */
+       int list_item;        /* Index for list_items */
+       XmString xmstrings[15];    /* temporary storage for XmStrings */
+
+       demo_dialog = XmCreateDialogShell ( parent, "demoDialog", al, ac );
+       demo_form = XmCreateForm ( demo_dialog, "demoForm", al, ac );
+       label1 = XmCreateLabel ( demo_form, "label1", al, ac );
+       label2 = XmCreateLabel ( demo_form, "label2", al, ac );
+       demo_list = XmCreateScrolledList ( demo_form, "demoList", al, ac );
+       text_area = XtParent ( demo_list );
+
+       text_line = XmCreateTextField ( demo_form, "textLine", al, ac );
+       vline = XmCreateSeparator ( demo_form, "vline", al, ac );
+       next = XmCreatePushButton ( demo_form, "next", al, ac );
+       prev = XmCreatePushButton ( demo_form, "prev", al, ac );
+       edit = XmCreatePushButton ( demo_form, "edit", al, ac );
+       done = XmCreatePushButton ( demo_form, "done", al, ac );
+       restart = XmCreatePushButton ( demo_form, "restart", al, ac );
+       xmstrings[0] = XmStringCreateLtoR(" ", (XmStringCharSet)XmSTRING_DEFAULT_CHARSET);
+       XtSetArg(al[ac], XmNlabelString, xmstrings[0]); ac++;
+       spacer = XmCreateLabel ( demo_form, "spacer", al, ac );
+       ac = 0;
+       XmStringFree ( xmstrings [ 0 ] );
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 5); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 4); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNrightOffset, 4); ac++;
+        XtSetValues ( label1,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 4); ac++;
+       XtSetArg(al[ac], XmNtopWidget, label1); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 4); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNrightOffset, 4); ac++;
+        XtSetValues ( label2,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 4); ac++;
+       XtSetArg(al[ac], XmNtopWidget, label2); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 4); ac++;
+       XtSetArg(al[ac], XmNbottomWidget, text_line); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 4); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNrightOffset, 4); ac++;
+        XtSetValues ( text_area,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 4); ac++;
+       XtSetArg(al[ac], XmNbottomWidget, vline); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 4); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNrightOffset, 4); ac++;
+        XtSetValues ( text_line,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 4); ac++;
+       XtSetArg(al[ac], XmNbottomWidget, next); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 4); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNrightOffset, 4); ac++;
+        XtSetValues ( vline,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 4); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 3); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
+        XtSetValues ( next,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 0); ac++;
+       XtSetArg(al[ac], XmNtopWidget, next); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 4); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 4); ac++;
+       XtSetArg(al[ac], XmNleftWidget, next); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
+        XtSetValues ( prev,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 0); ac++;
+       XtSetArg(al[ac], XmNtopWidget, prev); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 4); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 4); ac++;
+       XtSetArg(al[ac], XmNleftWidget, prev); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
+        XtSetValues ( edit,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 0); ac++;
+       XtSetArg(al[ac], XmNtopWidget, edit); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 4); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 4); ac++;
+       XtSetArg(al[ac], XmNleftWidget, edit); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
+        XtSetValues ( done,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 0); ac++;
+       XtSetArg(al[ac], XmNtopWidget, done); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 4); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 4); ac++;
+       XtSetArg(al[ac], XmNleftWidget, done); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
+        XtSetValues ( restart,al, ac );
+       ac = 0;
+
+       XtSetArg(al[ac], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); ac++;
+       XtSetArg(al[ac], XmNtopOffset, 0); ac++;
+       XtSetArg(al[ac], XmNtopWidget, restart); ac++;
+       XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNbottomOffset, 4); ac++;
+       XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
+       XtSetArg(al[ac], XmNleftOffset, 4); ac++;
+       XtSetArg(al[ac], XmNleftWidget, restart); ac++;
+       XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
+       XtSetArg(al[ac], XmNrightOffset, 4); ac++;
+        XtSetValues ( spacer,al, ac );
+       ac = 0;
+       XtManageChild(demo_list);
+       children[ac++] = label1;
+       children[ac++] = label2;
+       children[ac++] = text_line;
+       children[ac++] = vline;
+       children[ac++] = next;
+       children[ac++] = prev;
+       children[ac++] = edit;
+       children[ac++] = done;
+       children[ac++] = restart;
+       children[ac++] = spacer;
+       XtManageChildren(children, ac);
+       ac = 0;
+}
+
+
diff --git a/driver/dialogs.xd b/driver/dialogs.xd
new file mode 100644 (file)
index 0000000..6e56333
--- /dev/null
@@ -0,0 +1,569 @@
+module 'XScreenSaver'
+applicationName = 'XScreenSaver';
+generateNameC = 'dialogs.c';
+generateNameUIL = '';
+generateNameResDB = 'dialogs.ad';
+generateUidFile = '';
+generateMask = 1507557;
+useMask = 1;
+value
+object 'passwd_dialog' : XmDialogShell {
+       arguments {
+       name = 'passwdDialog';
+       XmNtitle= 'XScreenSaver';
+       XmNallowShellResize= true;
+       };
+object 'passwd_form' : XmForm {
+       arguments {
+       name = 'passwdForm';
+       XmNautoUnmanage= false;
+       };
+object 'roger_label' : XmDrawnButton {
+       arguments {
+       name = 'rogerLabel';
+       XmNwidth= 150;
+       };
+};
+object 'passwd_label1' : XmLabel {
+       arguments {
+       name = 'passwdLabel1';
+       XmNlabelString= 'XScreenSaver %s';
+       XmNalignment= 0;
+       };
+};
+object '' : XmLabel {
+       arguments {
+       name = 'passwdLabel2';
+       XmNlabelString= 'This display is locked.';
+       XmNalignment= 0;
+       };
+};
+object 'passwd_label3' : XmLabel {
+       arguments {
+       name = 'passwdLabel3';
+       XmNlabelString= 'Please type %s\'s password to unlock it.';
+       XmNalignment= 0;
+       };
+};
+object 'passwd_text' : XmTextField {
+       arguments {
+       name = 'passwdText';
+       };
+};
+object '' : XmSeparator {
+       arguments {
+       };
+};
+object 'passwd_done' : XmPushButton {
+       arguments {
+       name = 'passwdDone';
+       XmNlabelString= 'Done';
+       };
+};
+object 'passwd_cancel' : XmPushButton {
+       arguments {
+       name = 'passwdCancel';
+       XmNlabelString= 'Cancel';
+       };
+};
+    attachments {
+    attachment {
+       XmNrightAttachment = 0 0 0;
+       XmNleftAttachment = 1 0 4;
+       XmNbottomAttachment = 1 0 4;
+       XmNtopAttachment = 1 0 4;
+    };
+    attachment {
+       XmNrightAttachment = 1 0 4;
+       XmNleftAttachment = 3 1 4;
+       XmNbottomAttachment = 3 3 4;
+       XmNtopAttachment = 1 0 4;
+    };
+    attachment {
+       XmNrightAttachment = 1 0 4;
+       XmNleftAttachment = 3 1 4;
+       XmNbottomAttachment = 3 4 4;
+       XmNtopAttachment = 0 0 0;
+    };
+    attachment {
+       XmNrightAttachment = 1 0 30;
+       XmNleftAttachment = 3 1 4;
+       XmNbottomAttachment = 3 5 4;
+       XmNtopAttachment = 0 0 0;
+    };
+    attachment {
+       XmNrightAttachment = 1 0 4;
+       XmNleftAttachment = 3 1 4;
+       XmNbottomAttachment = 3 6 4;
+       XmNtopAttachment = 0 0 0;
+    };
+    attachment {
+       XmNrightAttachment = 1 0 0;
+       XmNleftAttachment = 3 1 0;
+       XmNbottomAttachment = 3 7 4;
+       XmNtopAttachment = 0 0 0;
+    };
+    attachment {
+       XmNrightAttachment = 0 0 0;
+       XmNleftAttachment = 3 1 4;
+       XmNbottomAttachment = 1 0 4;
+       XmNtopAttachment = 0 0 0;
+    };
+    attachment {
+       XmNrightAttachment = 0 0 0;
+       XmNleftAttachment = 3 7 4;
+       XmNbottomAttachment = 1 0 4;
+       XmNtopAttachment = 0 0 0;
+    };
+    };
+};
+};
+object 'resources_dialog' : XmDialogShell {
+       arguments {
+       name = 'resourcesDialog';
+       XmNtitle= 'XScreenSaver';
+       XmNallowShellResize= true;
+       };
+object 'resources_form' : XmForm {
+       arguments {
+       name = 'resourcesForm';
+       XmNautoUnmanage= false;
+       };
+object '' : XmLabel {
+       arguments {
+       name = 'resourcesLabel';
+       XmNlabelString= 'XScreenSaver Parameters';
+       };
+};
+object '' : XmSeparator {
+       arguments {
+       };
+};
+object '' : XmLabel {
+       arguments {
+       name = 'timeoutLabel';
+       XmNlabelString= 'Timeout Minutes';
+       XmNalignment= * 2;
+       };
+};
+object '' : XmLabel {
+       arguments {
+       name = 'cycleLabel';
+       XmNlabelString= 'Cycle Seconds';
+       XmNalignment= * 2;
+       };
+};
+object '' : XmLabel {
+       arguments {
+       name = 'fadeSecondsLabel';
+       XmNlabelString= 'Fade Seconds';
+       XmNalignment= * 2;
+       };
+};
+object '' : XmLabel {
+       arguments {
+       name = 'fadeTicksLabel';
+       XmNlabelString= 'Fade Ticks';
+       XmNalignment= * 2;
+       };
+};
+object '' : XmLabel {
+       arguments {
+       name = 'lockLabel';
+       XmNlabelString= 'Lock Timeout';
+       XmNalignment= * 2;
+       };
+};
+object '' : XmLabel {
+       arguments {
+       name = 'passwdLabel';
+       XmNlabelString= 'Password Timeout';
+       XmNalignment= * 2;
+       };
+};
+object 'timeout_text' : XmTextField {
+       arguments {
+       name = 'timeoutText';
+       XmNcolumns= 5;
+       };
+};
+object 'cycle_text' : XmTextField {
+       arguments {
+       name = 'cycleText';
+       XmNcolumns= 5;
+       };
+};
+object 'fade_text' : XmTextField {
+       arguments {
+       name = 'fadeSecondsText';
+       XmNcolumns= 5;
+       };
+};
+object 'ticks_text' : XmTextField {
+       arguments {
+       name = 'fadeTicksText';
+       XmNcolumns= 5;
+       };
+};
+object 'lock_time_text' : XmTextField {
+       arguments {
+       name = 'passwdText';
+       XmNcolumns= 5;
+       };
+};
+object 'passwd_time_text' : XmTextField {
+       arguments {
+       name = 'lockText';
+       XmNcolumns= 5;
+       };
+};
+object 'verbose_toggle' : XmToggleButton {
+       arguments {
+       name = 'verboseToggle';
+       XmNlabelString= 'Verbose';
+       XmNalignment= * 0;
+       };
+};
+object 'cmap_toggle' : XmToggleButton {
+       arguments {
+       name = 'cmapToggle';
+       XmNlabelString= 'Install Colormap';
+       XmNalignment= * 0;
+       };
+};
+object 'fade_toggle' : XmToggleButton {
+       arguments {
+       name = 'fadeToggle';
+       XmNlabelString= 'Fade Colormap';
+       XmNalignment= * 0;
+       };
+};
+object 'unfade_toggle' : XmToggleButton {
+       arguments {
+       name = 'unfadeToggle';
+       XmNlabelString= 'Unfade Colormap';
+       XmNalignment= * 0;
+       };
+};
+object 'lock_toggle' : XmToggleButton {
+       arguments {
+       name = 'lockToggle';
+       XmNlabelString= 'Require Password';
+       XmNalignment= * 0;
+       };
+};
+object '' : XmSeparator {
+       arguments {
+       };
+};
+object 'res_done' : XmPushButton {
+       arguments {
+       name = 'resourcesDone';
+       XmNlabelString= 'Done';
+       };
+};
+object 'res_cancel' : XmPushButton {
+       arguments {
+       name = 'resourcesCancel';
+       XmNlabelString= 'Cancel';
+       };
+};
+    attachments {
+    attachment {
+       XmNrightAttachment = 1 0 4;
+       XmNleftAttachment = 1 0 4;
+       XmNtopAttachment = 1 0 4;
+    };
+    attachment {
+       XmNrightAttachment = 1 0 0;
+       XmNleftAttachment = 1 0 0;
+       XmNbottomAttachment = 0 0 0;
+       XmNtopAttachment = 3 1 4;
+    };
+    attachment {
+       XmNrightAttachment = 3 9 4;
+       XmNleftAttachment = 1 0 20;
+       XmNbottomAttachment = 4 9;
+       XmNtopAttachment = 3 2 4;
+    };
+    attachment {
+       XmNrightAttachment = 3 10 4;
+       XmNleftAttachment = 1 0 20;
+       XmNbottomAttachment = 4 10 0;
+       XmNtopAttachment = 4 10 0;
+    };
+    attachment {
+       XmNrightAttachment = 3 11 4;
+       XmNleftAttachment = 1 0 20;
+       XmNbottomAttachment = 4 11 0;
+       XmNtopAttachment = 4 11 0;
+    };
+    attachment {
+       XmNrightAttachment = 3 12 4;
+       XmNleftAttachment = 1 0 20;
+       XmNbottomAttachment = 4 12 0;
+       XmNtopAttachment = 4 12 0;
+    };
+    attachment {
+       XmNrightAttachment = 3 13 4;
+       XmNleftAttachment = 1 0 19;
+       XmNbottomAttachment = 4 13 0;
+       XmNtopAttachment = 4 13 0;
+    };
+    attachment {
+       XmNrightAttachment = 3 14 4;
+       XmNleftAttachment = 1 0 14;
+       XmNbottomAttachment = 4 14 0;
+       XmNtopAttachment = 4 14 0;
+    };
+    attachment {
+       XmNrightAttachment = 0 0 0;
+       XmNleftAttachment = 1 0 141;
+       XmNbottomAttachment = 0 0 0;
+       XmNtopAttachment = 3 2 4;
+    };
+    attachment {
+       XmNrightAttachment = 0 0 0;
+       XmNleftAttachment = 4 9 0;
+       XmNbottomAttachment = 0 0 0;
+       XmNtopAttachment = 3 9 2;
+    };
+    attachment {
+       XmNrightAttachment = 0 0 0;
+       XmNleftAttachment = 4 10 0;
+       XmNbottomAttachment = 0 0 0;
+       XmNtopAttachment = 3 10 2;
+    };
+    attachment {
+       XmNrightAttachment = 0 0 0;
+       XmNleftAttachment = 4 11 0;
+       XmNbottomAttachment = 0 0 0;
+       XmNtopAttachment = 3 11 2;
+    };
+    attachment {
+       XmNrightAttachment = 0 0 0;
+       XmNleftAttachment = 4 12 0;
+       XmNbottomAttachment = 0 0 0;
+       XmNtopAttachment = 3 12 2;
+    };
+    attachment {
+       XmNrightAttachment = 0 0 0;
+       XmNleftAttachment = 4 13 0;
+       XmNbottomAttachment = 0 0 0;
+       XmNtopAttachment = 3 13 4;
+    };
+    attachment {
+       XmNrightAttachment = 1 0 20;
+       XmNleftAttachment = 3 9 20;
+       XmNbottomAttachment = 4 9 0;
+       XmNtopAttachment = 3 2 4;
+    };
+    attachment {
+       XmNrightAttachment = 1 0 20;
+       XmNleftAttachment = 4 15 0;
+       XmNbottomAttachment = 4 10 0;
+       XmNtopAttachment = 4 10 0;
+    };
+    attachment {
+       XmNrightAttachment = 1 0 20;
+       XmNleftAttachment = 4 16 0;
+       XmNbottomAttachment = 4 11 0;
+       XmNtopAttachment = 4 11 0;
+    };
+    attachment {
+       XmNrightAttachment = 1 0 20;
+       XmNleftAttachment = 4 17 0;
+       XmNbottomAttachment = 4 12 0;
+       XmNtopAttachment = 4 12 0;
+    };
+    attachment {
+       XmNrightAttachment = 1 0 20;
+       XmNleftAttachment = 4 18 0;
+       XmNbottomAttachment = 4 13 0;
+       XmNtopAttachment = 4 13 0;
+    };
+    attachment {
+       XmNrightAttachment = 1 0;
+       XmNleftAttachment = 1 0;
+       XmNbottomAttachment = 3 21 4;
+       XmNtopAttachment = 3 14 0;
+    };
+    attachment {
+       XmNrightAttachment = 0 0 0;
+       XmNleftAttachment = 1 0 4;
+       XmNbottomAttachment = 1 0 4;
+       XmNtopAttachment = 0 0 0;
+    };
+    attachment {
+       XmNrightAttachment = 0 0 0;
+       XmNleftAttachment = 3 21 4;
+       XmNbottomAttachment = 1 0 4;
+       XmNtopAttachment = 0 0 0;
+    };
+    };
+};
+};
+object 'demo_dialog' : XmDialogShell {
+       arguments {
+       name = 'demoDialog';
+       XmNtitle= 'XScreenSaver';
+       XmNmaxWidth= 500;
+       XmNallowShellResize= true;
+       };
+object 'demo_form' : XmForm {
+       arguments {
+       name = 'demoForm';
+       XmNautoUnmanage= false;
+       };
+object 'label1' : XmLabel {
+       arguments {
+       name = 'label1';
+       XmNlabelString= 'XScreenSaver %s';
+       };
+};
+object 'label2' : XmLabel {
+       arguments {
+       name = 'label2';
+       XmNlabelString= 'Copyright Â© 1991-1993 by Jamie Zawinski <jwz@lucid.com>';
+       };
+};
+object 'text_area' : XmScrolledList {
+       arguments {
+       name = 'textArea';
+       };
+object '' : XmScrollBar {
+       arguments {
+       name = 'ListhScrollBar';
+       };
+};
+object '' : XmScrollBar {
+       arguments {
+       name = 'ListvScrollBar';
+       };
+};
+object 'demo_list' : XmList {
+       arguments {
+       name = 'demoList';
+       XmNvisibleItemCount= 10;
+       XmNautomaticSelection= true;
+       XmNlistSizePolicy= 2;
+       };
+};
+};
+object 'text_line' : XmTextField {
+       arguments {
+       name = 'textLine';
+       };
+};
+object 'vline' : XmSeparator {
+       arguments {
+       name = 'vline';
+       };
+};
+object 'next' : XmPushButton {
+       arguments {
+       name = 'next';
+       XmNlabelString= 'Run Next';
+       };
+};
+object 'prev' : XmPushButton {
+       arguments {
+       name = 'prev';
+       XmNlabelString= 'Run Previous';
+       };
+};
+object 'edit' : XmPushButton {
+       arguments {
+       name = 'edit';
+       XmNlabelString= 'Edit Parameters';
+       };
+};
+object 'done' : XmPushButton {
+       arguments {
+       name = 'done';
+       XmNlabelString= 'Exit Demo Mode';
+       };
+};
+object 'restart' : XmPushButton {
+       arguments {
+       name = 'restart';
+       XmNlabelString= 'Restart Screen Saver';
+       };
+};
+object 'spacer' : XmLabel {
+       arguments {
+       name = 'spacer';
+       XmNlabelString= * ' ';
+       };
+};
+    attachments {
+    attachment {
+       XmNrightAttachment = 1 0 4;
+       XmNleftAttachment = 1 0 4;
+       XmNbottomAttachment = 0 0 0;
+       XmNtopAttachment = 1 0 5;
+    };
+    attachment {
+       XmNrightAttachment = 1 0 4;
+       XmNleftAttachment = 1 0 4;
+       XmNbottomAttachment = 0 0 0;
+       XmNtopAttachment = 3 1 4;
+    };
+    attachment {
+       XmNrightAttachment = 1 0 4;
+       XmNleftAttachment = 1 0 4;
+       XmNbottomAttachment = 3 4 4;
+       XmNtopAttachment = 3 2 4;
+    };
+    attachment {
+       XmNrightAttachment = 1 0 4;
+       XmNleftAttachment = 1 0 4;
+       XmNbottomAttachment = 3 5 4;
+       XmNtopAttachment = 0 0 0;
+    };
+    attachment {
+       XmNrightAttachment = 1 0 4;
+       XmNleftAttachment = 1 0 4;
+       XmNbottomAttachment = 3 6 4;
+       XmNtopAttachment = 0 0 0;
+    };
+    attachment {
+       XmNrightAttachment = 0 0 0;
+       XmNleftAttachment = 1 0 3;
+       XmNbottomAttachment = 1 0 4;
+       XmNtopAttachment = 0 0 0;
+    };
+    attachment {
+       XmNrightAttachment = 0 0 0;
+       XmNleftAttachment = 3 6 4;
+       XmNbottomAttachment = 1 0 4;
+       XmNtopAttachment = 4 6 0;
+    };
+    attachment {
+       XmNrightAttachment = 0 0 0;
+       XmNleftAttachment = 3 7 4;
+       XmNbottomAttachment = 1 0 4;
+       XmNtopAttachment = 4 7 0;
+    };
+    attachment {
+       XmNrightAttachment = 0 0 0;
+       XmNleftAttachment = 3 8 4;
+       XmNbottomAttachment = 1 0 4;
+       XmNtopAttachment = 4 8 0;
+    };
+    attachment {
+       XmNrightAttachment = 0 0 0;
+       XmNleftAttachment = 3 9 4;
+       XmNbottomAttachment = 1 0 4;
+       XmNtopAttachment = 4 9 0;
+    };
+    attachment {
+       XmNrightAttachment = 1 0 4;
+       XmNleftAttachment = 3 10 4;
+       XmNbottomAttachment = 1 0 4;
+       XmNtopAttachment = 4 10 0;
+    };
+    };
+};
+};
+end module;
diff --git a/driver/lock.c b/driver/lock.c
new file mode 100644 (file)
index 0000000..48b2f52
--- /dev/null
@@ -0,0 +1,525 @@
+/* xscreensaver, Copyright (c) 1993 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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.
+ */
+
+#if __STDC__
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#endif
+
+#include <pwd.h>
+#include <stdio.h>
+
+#include <X11/Intrinsic.h>
+
+#if !__STDC__
+# define _NO_PROTO
+#endif
+
+#include <Xm/Xm.h>
+#include <Xm/List.h>
+#include <Xm/TextF.h>
+
+#include "xscreensaver.h"
+
+#ifndef NO_LOCKING
+
+Time passwd_timeout;
+
+extern char *screensaver_version;
+extern char *progname;
+extern XtAppContext app;
+extern Bool verbose_p;
+
+extern Widget passwd_dialog;
+extern Widget passwd_form;
+extern Widget roger_label;
+extern Widget passwd_label1;
+extern Widget passwd_label3;
+extern Widget passwd_text;
+extern Widget passwd_done;
+extern Widget passwd_cancel;
+
+extern create_passwd_dialog ();
+
+static enum { pw_read, pw_ok, pw_fail, pw_cancel, pw_time } passwd_state;
+static char typed_passwd [1024];
+
+static char root_passwd [255];
+static char user_passwd [255];
+
+Bool
+lock_init ()
+{
+  Bool ok = True;
+  struct passwd *p;
+  char *u;
+  p = getpwnam ("root");
+  if (p && p->pw_passwd && p->pw_passwd[0] != '*')
+    strcpy (root_passwd, p->pw_passwd);
+  else
+    {
+      fprintf (stderr, "%s: couldn't get root's password\n", progname);
+      strcpy (root_passwd, "*");
+    }
+
+  u = getlogin ();
+  if (u)
+    p = getpwnam (u);
+  else
+    {
+      /* getlogin() fails if not attached to a terminal;
+        in that case, use getpwuid(). */
+      p = getpwuid (getuid ());
+      u = p->pw_name;
+    }
+
+  if (p && p->pw_passwd && p->pw_passwd[0] != '*')
+    strcpy (user_passwd, p->pw_passwd);
+  else
+    {
+      fprintf (stderr, "%s: couldn't get password of \"%s\"\n", progname, u);
+      strcpy (user_passwd, "*");
+      ok = False;
+    }
+  return ok;
+}
+
+static void
+passwd_cancel_cb (button, client_data, call_data)
+     Widget button;
+     XtPointer client_data, call_data;
+{
+  passwd_state = pw_cancel;
+}
+
+static void
+passwd_done_cb (button, client_data, call_data)
+     Widget button;
+     XtPointer client_data, call_data;
+{
+  if (passwd_state != pw_read) return; /* already done */
+  if (!strcmp ((char *) crypt (typed_passwd, user_passwd), user_passwd))
+    passwd_state = pw_ok;
+  /* do not allow root to have empty passwd */
+  else if (typed_passwd [0] &&
+          !strcmp ((char *) crypt (typed_passwd, root_passwd), root_passwd))
+    passwd_state = pw_ok;
+  else
+    passwd_state = pw_fail;
+}
+
+#ifdef VERIFY_CALLBACK_WORKS
+
+  /* ####  It looks to me like adding any modifyVerify callback causes
+     ####  Motif 1.1.4 to free the the TextF_Value() twice.  I can't see
+     ####  the bug in the Motif source, but Purify complains, even if
+     ####  check_passwd_cb() is a no-op.
+   */
+
+static void 
+check_passwd_cb (button, client_data, call_data)
+     Widget button;
+     XtPointer client_data, call_data;
+{
+  XmTextVerifyCallbackStruct *vcb = (XmTextVerifyCallbackStruct *) call_data;
+
+  if (passwd_state != pw_read)
+    return;
+  else if (vcb->reason == XmCR_ACTIVATE)
+    {
+      passwd_done_cb (0, 0, 0);
+    }
+  else if (vcb->text->length > 1)      /* don't allow "paste" operations */
+    {
+      vcb->doit = False;
+    }
+  else if (vcb->text->ptr != 0)
+    {
+      int i;
+      strncat (typed_passwd, vcb->text->ptr, vcb->text->length);
+      typed_passwd [vcb->endPos + vcb->text->length] = 0;
+      for (i = 0; i < vcb->text->length; i++)
+       vcb->text->ptr [i] = '*';
+    }
+}
+
+#else /* !VERIFY_CALLBACK_WORKS */
+
+static void keypress();
+static void backspace();
+static void kill_line();
+static void done();
+
+static XtActionsRec actions[] = {{"keypress",  keypress},
+                                {"backspace", backspace},
+                                {"kill_line", kill_line},
+                                {"done",      done}
+                               };
+
+#if 0 /* oh fuck, why doesn't this work? */
+static char translations[] = "\
+<Key>BackSpace:                backspace()\n\
+<Key>Delete:           backspace()\n\
+Ctrl<Key>H:            backspace()\n\
+Ctrl<Key>U:            kill_line()\n\
+Ctrl<Key>X:            kill_line()\n\
+Ctrl<Key>J:            done()\n\
+Ctrl<Key>M:            done()\n\
+<Key>:                 keypress()\n\
+";
+#else
+static char translations[] = "<Key>:keypress()";
+#endif
+
+static void
+keypress (w, event, argv, argc)
+     Widget w;
+     XEvent *event;
+     String *argv;
+     Cardinal *argc;
+{
+  int i, j;
+  char s [sizeof (typed_passwd)];
+  int size = XLookupString ((XKeyEvent *) event, s, sizeof (s), 0, 0);
+  if (size != 1) return;
+
+  /* hack because I can't get translations to dance to my tune... */
+  if (*s == '\010') { backspace (w, event, argv, argc); return; }
+  if (*s == '\177') { backspace (w, event, argv, argc); return; }
+  if (*s == '\025') { kill_line (w, event, argv, argc); return; }
+  if (*s == '\030') { kill_line (w, event, argv, argc); return; }
+  if (*s == '\012') { done (w, event, argv, argc); return; }
+  if (*s == '\015') { done (w, event, argv, argc); return; }
+
+  i = j = strlen (typed_passwd);
+  typed_passwd [i] = *s;
+  s [++i] = 0;
+  while (i--)
+    s [i] = '*';
+  XmTextFieldSetString (passwd_text, s);
+  XmTextFieldSetInsertionPosition (passwd_text, j + 1);
+}
+
+static void
+backspace (w, event, argv, argc)
+     Widget w;
+     XEvent *event;
+     String *argv;
+     Cardinal *argc;
+{
+  char s [sizeof (typed_passwd)];
+  int i = strlen (typed_passwd);
+  int j = i;
+  if (i == 0)
+    return;
+  typed_passwd [--i] = 0;
+  s [i] = 0;
+  while (i--)
+    s [i] = '*';
+  XmTextFieldSetString (passwd_text, s);
+  XmTextFieldSetInsertionPosition (passwd_text, j + 1);
+}
+
+static void
+kill_line (w, event, argv, argc)
+     Widget w;
+     XEvent *event;
+     String *argv;
+     Cardinal *argc;
+{
+  memset (typed_passwd, 0, sizeof (typed_passwd));
+  XmTextFieldSetString (passwd_text, "");
+}
+
+static void
+done (w, event, argv, argc)
+     Widget w;
+     XEvent *event;
+     String *argv;
+     Cardinal *argc;
+{
+  passwd_done_cb (w, 0, 0);
+}
+
+#endif /* !VERIFY_CALLBACK_WORKS */
+
+static void
+format_into_label (widget, string)
+     Widget widget;
+     char *string;
+{
+  char *label;
+  char buf [255];
+  XmString xm_label = 0;
+  XmString new_xm_label;
+  Arg av[10];
+  int ac = 0;
+  XtSetArg (av [ac], XmNlabelString, &xm_label); ac++;
+  XtGetValues (widget, av, ac);
+  XmStringGetLtoR (xm_label, XmSTRING_DEFAULT_CHARSET, &label);
+  if (!strcmp (label, XtName (widget)))
+    strcpy (buf, "ERROR: RESOURCES ARE NOT INSTALLED CORRECTLY");
+  else
+    sprintf (buf, label, string);
+  new_xm_label = XmStringCreate (buf, XmSTRING_DEFAULT_CHARSET);
+  ac = 0;
+  XtSetArg (av [ac], XmNlabelString, new_xm_label); ac++;
+  XtSetValues (widget, av, ac);
+  XmStringFree (new_xm_label);
+  XtFree (label);
+}
+
+#if __STDC__
+extern void skull (Display *, Window, GC, GC, int, int, int, int);
+#endif
+
+static void
+roger (button, client_data, call_data)
+     Widget button;
+     XtPointer client_data, call_data;
+{
+  Display *dpy = XtDisplay (button);
+  Screen *screen = XtScreen (button);
+  Window window = XtWindow (button);
+  Arg av [10];
+  int ac = 0;
+  XGCValues gcv;
+  Colormap cmap;
+  GC draw_gc, erase_gc;
+  unsigned int fg, bg;
+  int x, y, size;
+  XWindowAttributes xgwa;
+  XGetWindowAttributes (dpy, window, &xgwa);
+  cmap = xgwa.colormap;
+  if (xgwa.width > xgwa.height) size = xgwa.height;
+  else size = xgwa.width;
+  if (size > 40) size -= 30;
+  x = (xgwa.width - size) / 2;
+  y = (xgwa.height - size) / 2;
+  XtSetArg (av [ac], XmNforeground, &fg); ac++;
+  XtSetArg (av [ac], XmNbackground, &bg); ac++;
+  XtGetValues (button, av, ac);
+  /* if it's black on white, swap it cause it looks better (hack hack) */
+  if (fg == BlackPixelOfScreen (screen) && bg == WhitePixelOfScreen (screen))
+    fg = WhitePixelOfScreen (screen), bg = BlackPixelOfScreen (screen);
+  gcv.foreground = bg;
+  erase_gc = XCreateGC (dpy, window, GCForeground, &gcv);
+  gcv.foreground = fg;
+  draw_gc = XCreateGC (dpy, window, GCForeground, &gcv);
+  XFillRectangle (dpy, window, erase_gc, 0, 0, xgwa.width, xgwa.height);
+  skull (dpy, window, draw_gc, erase_gc, x, y, size, size);
+  XFreeGC (dpy, draw_gc);
+  XFreeGC (dpy, erase_gc);
+}
+
+static void
+make_passwd_dialog (parent)
+     Widget parent;
+{
+  struct passwd *pw;
+  create_passwd_dialog (parent);
+
+  XtAddCallback (passwd_done, XmNactivateCallback, passwd_done_cb, 0);
+  XtAddCallback (passwd_cancel, XmNactivateCallback, passwd_cancel_cb, 0);
+  XtAddCallback (roger_label, XmNexposeCallback, roger, 0);
+
+#ifdef VERIFY_CALLBACK_WORKS
+  XtAddCallback (passwd_text, XmNmodifyVerifyCallback, check_passwd_cb, 0);
+  XtAddCallback (passwd_text, XmNactivateCallback, check_passwd_cb, 0);
+#else
+  XtAddCallback (passwd_text, XmNactivateCallback, passwd_done_cb, 0);
+  XtOverrideTranslations (passwd_text, XtParseTranslationTable (translations));
+#endif
+
+  pw = getpwuid (getuid ());
+  format_into_label (passwd_label3, (pw->pw_name ? pw->pw_name : "???"));
+  format_into_label (passwd_label1, screensaver_version);
+}
+
+
+extern void idle_timer ();
+
+static int passwd_idle_timer_tick;
+static XtIntervalId id;
+
+static void
+passwd_idle_timer (junk1, junk2)
+     void *junk1;
+     XtPointer junk2;
+{
+  Display *dpy = XtDisplay (passwd_form);
+  Window window = XtWindow (passwd_form);
+  static Dimension x, y, d, s, ss;
+  static GC gc = 0;
+  int max = passwd_timeout / 1000;
+
+  idle_timer (junk1, junk2);
+
+  if (passwd_idle_timer_tick == max)  /* first time */
+    {
+      Arg av [10];
+      int ac = 0;
+      XGCValues gcv;
+      unsigned long fg, bg;
+      XtSetArg (av [ac], XmNheight, &d); ac++;
+      XtGetValues (passwd_done, av, ac);
+      ac = 0;
+      XtSetArg (av [ac], XmNwidth, &x); ac++;
+      XtSetArg (av [ac], XmNheight, &y); ac++;
+      XtSetArg (av [ac], XmNforeground, &fg); ac++;
+      XtSetArg (av [ac], XmNbackground, &bg); ac++;
+      XtGetValues (passwd_form, av, ac);
+      x -= d;
+      y -= d;
+      d -= 4;
+      gcv.foreground = fg;
+      if (gc) XFreeGC (dpy, gc);
+      gc = XCreateGC (dpy, window, GCForeground, &gcv);
+      s = 360*64 / (passwd_idle_timer_tick - 1);
+      ss = 90*64;
+      XFillArc (dpy, window, gc, x, y, d, d, 0, 360*64);
+      XSetForeground (dpy, gc, bg);
+      x += 1;
+      y += 1;
+      d -= 2;
+    }
+
+  if (--passwd_idle_timer_tick)
+    {
+      id = XtAppAddTimeOut (app, 1000, passwd_idle_timer, 0);
+      XFillArc (dpy, window, gc, x, y, d, d, ss, s);
+      ss += s;
+    }
+}
+
+extern void pop_up_dialog_box ();
+extern int BadWindow_ehandler ();
+
+static Bool
+pop_passwd_dialog (parent)
+     Widget parent;
+{
+  Display *dpy = XtDisplay (passwd_dialog);
+  Window focus;
+  int revert_to;
+  typed_passwd [0] = 0;
+  passwd_state = pw_read;
+  XmTextFieldSetString (passwd_text, "");
+
+  XGetInputFocus (dpy, &focus, &revert_to);
+#ifndef DESTROY_WORKS
+  /* This fucker blows up if we destroy the widget.  I can't figure
+     out why.  The second destroy phase dereferences freed memory...
+     So we just keep it around; but unrealizing or unmanaging it
+     doesn't work right either, so we hack the window directly. FMH.
+   */
+  if (XtWindow (passwd_form))
+    XMapWindow (dpy, XtWindow (passwd_dialog));
+#endif
+  pop_up_dialog_box (passwd_dialog, passwd_form, 2);
+
+  XtManageChild (passwd_form);
+  XSetInputFocus (dpy, XtWindow (passwd_dialog), revert_to, CurrentTime);
+  XmProcessTraversal (passwd_text, 0);
+
+  passwd_idle_timer_tick = passwd_timeout / 1000;
+  id = XtAppAddTimeOut (app, 1000, passwd_idle_timer, 0);
+
+
+  XGrabServer (dpy);                           /* ############ DANGER! */
+
+  while (passwd_state == pw_read)
+    {
+      XEvent event;
+      XtAppNextEvent (app, &event);
+      /* wait for timer event */
+      if (event.xany.type == 0 && passwd_idle_timer_tick == 0)
+       passwd_state = pw_time;
+      XtDispatchEvent (&event);
+    }
+  XUngrabServer (dpy);
+  XSync (dpy, False);                          /* ###### (danger over) */
+
+  if (passwd_state != pw_time)
+    XtRemoveTimeOut (id);
+
+  if (passwd_state != pw_ok)
+    {
+      char *lose;
+      switch (passwd_state)
+       {
+       case pw_time: lose = "Timed out!"; break;
+       case pw_fail: lose = "Sorry!"; break;
+       case pw_cancel: lose = 0; break;
+       default: abort ();
+       }
+      XmProcessTraversal (passwd_cancel, 0); /* turn off I-beam */
+      if (lose)
+       {
+         XmTextFieldSetString (passwd_text, lose);
+         XmTextFieldSetInsertionPosition (passwd_text, strlen (lose) + 1);
+         passwd_idle_timer_tick = 1;
+         id = XtAppAddTimeOut (app, 3000, passwd_idle_timer, 0);
+         while (1)
+           {
+             XEvent event;
+             XtAppNextEvent (app, &event);
+             if (event.xany.type == 0 &&       /* wait for timer event */
+                 passwd_idle_timer_tick == 0)
+               break;
+             XtDispatchEvent (&event);
+           }
+       }
+    }
+  memset (typed_passwd, 0, sizeof (typed_passwd));
+  XmTextFieldSetString (passwd_text, "");
+  XtSetKeyboardFocus (parent, None);
+
+#ifndef DESTROY_WORKS
+  XtDestroyWidget (passwd_dialog);
+  passwd_dialog = 0;
+#else
+  XUnmapWindow (XtDisplay (passwd_dialog), XtWindow (passwd_dialog));
+#endif
+  {
+    int (*old_handler) ();
+    old_handler = XSetErrorHandler (BadWindow_ehandler);
+    /* I don't understand why this doesn't refocus on the old selected
+       window when MWM is running in click-to-type mode.  The value of
+       `focus' seems to be correct. */
+    XSetInputFocus (dpy, focus, revert_to, CurrentTime);
+    XSync (dpy, False);
+    XSetErrorHandler (old_handler);
+  }
+
+  return (passwd_state == pw_ok ? True : False);
+}
+
+Bool
+unlock_p (parent)
+     Widget parent;
+{
+  static Bool initted = False;
+  if (! initted)
+    {
+#ifndef VERIFY_CALLBACK_WORKS
+      XtAppAddActions (app, actions, XtNumber (actions));
+#endif
+      passwd_dialog = 0;
+      initted = True;
+    }
+  if (! passwd_dialog)
+    make_passwd_dialog (parent);
+  return pop_passwd_dialog (parent);
+}
+
+#endif /* !NO_LOCKING */
diff --git a/driver/subprocs.c b/driver/subprocs.c
new file mode 100644 (file)
index 0000000..e6a2812
--- /dev/null
@@ -0,0 +1,575 @@
+/* xscreensaver, Copyright (c) 1991-1993 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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.
+ */
+
+#if __STDC__
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#endif
+
+#include <stdio.h>
+
+#include <X11/Xlib.h>          /* not used for much... */
+
+#ifndef ESRCH
+#include <errno.h>
+#endif
+
+#include <sys/time.h>          /* sys/resource.h needs this for timeval */
+#include <sys/resource.h>      /* for setpriority() and PRIO_PROCESS */
+#include <sys/wait.h>          /* for waitpid() and associated macros */
+#include <signal.h>            /* for the signal names */
+
+extern char **environ;         /* why isn't this in some header file? */
+
+#ifndef NO_SETUID
+#include <pwd.h>               /* for getpwnam() and struct passwd */
+#include <grp.h>               /* for getgrgid() and struct group */
+#endif /* NO_SETUID */
+
+#if !defined(SIGCHLD) && defined(SIGCLD)
+#define SIGCHLD SIGCLD
+#endif
+
+#if __STDC__
+extern int putenv (const char *);      /* getenv() is in stdlib.h... */
+extern int kill (pid_t, int);          /* signal() is in sys/signal.h... */
+#endif
+
+# if defined(SVR4) || defined(SYSV)
+#  define random() rand()
+# else /* !totally-losing-SYSV */
+extern long random();                  /* rand() is in stdlib.h... */
+# endif /* !totally-losing-SYSV */
+
+
+#include "xscreensaver.h"
+
+/* this must be `sh', not whatever $SHELL happens to be. */
+char *shell;
+static pid_t pid = 0;
+char **screenhacks;
+int screenhacks_count;
+int current_hack = -1;
+char *demo_hack;
+int next_mode_p = 0;
+Bool locking_disabled_p = False;
+int nice_inferior = 0;
+
+extern Bool demo_mode_p;
+
+static void
+exec_screenhack (command)
+     char *command;
+{
+  char *tmp;
+  char buf [512];
+  char *av [5];
+  int ac = 0;
+
+  /* Close this fork's version of the display's fd.  It will open its own. */
+  close (ConnectionNumber (dpy));
+  
+  /* I don't believe what a sorry excuse for an operating system UNIX is!
+
+     - I want to spawn a process.
+     - I want to know it's pid so that I can kill it.
+     - I would like to receive a message when it dies of natural causes.
+     - I want the spawned process to have user-specified arguments.
+
+     The *only way* to parse arguments the way the shells do is to run a
+     shell (or duplicate what they do, which would be a *lot* of code.)
+
+     The *only way* to know the pid of the process is to fork() and exec()
+     it in the spawned side of the fork.
+
+     But if you're running a shell to parse your arguments, this gives you
+     the pid of the SHELL, not the pid of the PROCESS that you're actually
+     interested in, which is an *inferior* of the shell.  This also means
+     that the SIGCHLD you get applies to the shell, not its inferior.
+
+     So, the only solution other than implementing an argument parser here
+     is to force the shell to exec() its inferior.  What a fucking hack!
+     We prepend "exec " to the command string.
+   */
+  tmp = command;
+  command = (char *) malloc (strlen (tmp) + 6);
+  memcpy (command, "exec ", 5);
+  memcpy (command + 5, tmp, strlen (tmp) + 1);
+
+  /* Invoke the shell as "/bin/sh -c 'exec prog -arg -arg ...'" */
+  av [ac++] = shell;
+  av [ac++] = "-c";
+  av [ac++] = command;
+  av [ac++] = 0;
+  
+  if (verbose_p)
+    printf ("%s: spawning \"%s\" in pid %d.\n", progname, command, getpid ());
+
+#if defined(SYSV) || defined(__hpux)
+  {
+    int old_nice = nice (0);
+    int n = nice_inferior - old_nice;
+    errno = 0;
+    if (nice (n) == -1 && errno != 0)
+      {
+       sprintf (buf, "%s: %snice(%d) failed", progname,
+                (verbose_p ? "## " : ""), n);
+       perror (buf);
+      }
+  }
+#else /* !SYSV */
+#ifdef PRIO_PROCESS
+  if (setpriority (PRIO_PROCESS, getpid(), nice_inferior) != 0)
+    {
+      sprintf (buf, "%s: %ssetpriority(PRIO_PROCESS, %d, %d) failed",
+              progname, (verbose_p ? "## " : ""), getpid(), nice_inferior);
+      perror (buf);
+    }
+#else /* !PRIO_PROCESS */
+  if (nice_inferior != 0)
+    fprintf (stderr,
+          "%s: %sdon't know how to change process priority on this system.\n",
+            progname, (verbose_p ? "## " : ""));
+#endif /* !PRIO_PROCESS */
+#endif /* !SYSV */
+
+  /* Now overlay the current process with /bin/sh running the command.
+     If this returns, it's an error.
+   */
+  execve (av [0], av, environ);
+
+  sprintf (buf, "%s: %sexecve() failed", progname, (verbose_p ? "## " : ""));
+  perror (buf);
+  exit (1);    /* Note this this only exits a child fork.  */
+}
+
+/* to avoid a race between the main thread and the SIGCHLD handler */
+static int killing = 0;
+static Bool suspending = False;
+
+static char *current_hack_name P((void));
+
+static void
+await_child_death (killed)
+     Bool killed;
+{
+  Bool suspended_p = False;
+  int status;
+  pid_t kid;
+  killing = 1;
+  if (! pid)
+    return;
+
+  do
+    {
+      kid = waitpid (pid, &status, WUNTRACED);
+    }
+  while (kid == -1 && errno == EINTR);
+
+  if (kid == pid)
+    {
+      if (WIFEXITED (status))
+       {
+         int exit_status = WEXITSTATUS (status);
+         if (exit_status & 0x80)
+           exit_status |= ~0xFF;
+         if (exit_status != 0 && verbose_p)
+           printf ("%s: child pid %d (%s) exited abnormally (code %d).\n",
+                   progname, pid, current_hack_name (), exit_status);
+         else if (verbose_p)
+           printf ("%s: child pid %d (%s) exited normally.\n",
+                   progname, pid, current_hack_name ());
+       }
+      else if (WIFSIGNALED (status))
+       {
+         if (!killed || WTERMSIG (status) != SIGTERM)
+           fprintf (stderr,
+                    "%s: %schild pid %d (%s) terminated with signal %d!\n",
+                    progname, (verbose_p ? "## " : ""),
+                    pid, current_hack_name (), WTERMSIG (status));
+         else if (verbose_p)
+           printf ("%s: child pid %d (%s) terminated with SIGTERM.\n",
+                   progname, pid, current_hack_name ());
+       }
+      else if (suspending)
+       {
+         suspended_p = True;
+         suspending = False; /* complain if it happens twice */
+       }
+      else if (WIFSTOPPED (status))
+       {
+         suspended_p = True;
+         fprintf (stderr, "%s: %schild pid %d (%s) stopped with signal %d!\n",
+                  progname, (verbose_p ? "## " : ""), pid,
+                  current_hack_name (), WSTOPSIG (status));
+       }
+      else
+       fprintf (stderr, "%s: %schild pid %d (%s) died in a mysterious way!",
+                progname, (verbose_p ? "## " : ""), pid, current_hack_name());
+    }
+  else if (kid <= 0)
+    fprintf (stderr, "%s: %swaitpid(%d, ...) says there are no kids?  (%d)\n",
+            progname, (verbose_p ? "## " : ""), pid, kid);
+  else
+    fprintf (stderr, "%s: %swaitpid(%d, ...) says proc %d died, not %d?\n",
+            progname, (verbose_p ? "## " : ""), pid, kid, pid);
+  killing = 0;
+  if (suspended_p != True)
+    pid = 0;
+}
+
+static char *
+current_hack_name ()
+{
+  static char chn [1024];
+  char *hack = (demo_mode_p ? demo_hack : screenhacks [current_hack]);
+  int i;
+  for (i = 0; hack [i] != 0 && hack [i] != ' ' && hack [i] != '\t'; i++)
+    chn [i] = hack [i];
+  chn [i] = 0;
+  return chn;
+}
+
+#ifdef SIGCHLD
+static void
+sigchld_handler (sig)
+     int sig;
+{
+  if (killing)
+    return;
+  if (! pid)
+    abort ();
+  await_child_death (False);
+}
+#endif
+
+
+void
+init_sigchld ()
+{
+#ifdef SIGCHLD
+  if (((int) signal (SIGCHLD, sigchld_handler)) == -1)
+    {
+      char buf [255];
+      sprintf (buf, "%s: %scouldn't catch SIGCHLD", progname,
+              (verbose_p ? "## " : ""));
+      perror (buf);
+    }
+#endif
+}
+
+
+extern void raise_window P((Bool inhibit_fade, Bool between_hacks_p));
+
+void
+spawn_screenhack (first_time_p)
+     Bool first_time_p;
+{
+  raise_window (first_time_p, True);
+  XFlush (dpy);
+
+  if (screenhacks_count || demo_mode_p)
+    {
+      char *hack;
+      pid_t forked;
+      char buf [255];
+      int new_hack;
+      if (demo_mode_p)
+       {
+         hack = demo_hack;
+       }
+      else
+       {
+         if (screenhacks_count == 1)
+           new_hack = 0;
+         else if (next_mode_p == 1)
+           new_hack = (current_hack + 1) % screenhacks_count,
+           next_mode_p = 0;
+         else if (next_mode_p == 2)
+           {
+             new_hack = ((current_hack + screenhacks_count - 1)
+                         % screenhacks_count);
+             next_mode_p = 0;
+           }
+         else
+           while ((new_hack = random () % screenhacks_count) == current_hack)
+             ;
+         current_hack = new_hack;
+         hack = screenhacks[current_hack];
+       }
+
+      switch (forked = fork ())
+       {
+       case -1:
+         sprintf (buf, "%s: %scouldn't fork",
+                  progname, (verbose_p ? "## " : ""));
+         perror (buf);
+         restore_real_vroot ();
+         exit (1);
+       case 0:
+         exec_screenhack (hack); /* this does not return */
+         break;
+       default:
+         pid = forked;
+         break;
+       }
+    }
+}
+
+void
+kill_screenhack ()
+{
+  killing = 1;
+  if (! pid)
+    return;
+  if (kill (pid, SIGTERM) < 0)
+    {
+      if (errno == ESRCH)
+       {
+         /* Sometimes we don't get a SIGCHLD at all!  WTF?
+            It's a race condition.  It looks to me like what's happening is
+            something like: a subprocess dies of natural causes.  There is a
+            small window between when the process dies and when the SIGCHLD
+            is (would have been) delivered.  If we happen to try to kill()
+            the process during that time, the kill() fails, because the
+            process is already dead.  But! no SIGCHLD is delivered (perhaps
+            because the failed kill() has reset some state in the kernel?)
+            Anyway, if kill() says "No such process", then we have to wait()
+            for it anyway, because the process has already become a zombie.
+            I love Unix.
+          */
+         await_child_death (False);
+       }
+      else
+       {
+         char buf [255];
+         sprintf (buf, "%s: %scouldn't kill child process %d", progname,
+                  (verbose_p ? "## " : ""), pid);
+         perror (buf);
+       }
+    }
+  else
+    {
+      if (verbose_p)
+       printf ("%s: killing pid %d.\n", progname, pid);
+      await_child_death (True);
+    }
+}
+
+
+void
+suspend_screenhack (suspend_p)
+     Bool suspend_p;
+{
+  
+  suspending = suspend_p;
+  if (! pid)
+    ;
+  else if (kill (pid, (suspend_p ? SIGSTOP : SIGCONT)) < 0)
+    {
+      char buf [255];
+      sprintf (buf, "%s: %scouldn't %s child process %d", progname,
+              (verbose_p ? "## " : ""),
+              (suspend_p ? "suspend" : "resume"),
+              pid);
+      perror (buf);
+    }
+  else if (verbose_p)
+    printf ("%s: %s pid %d.\n", progname,
+           (suspend_p ? "suspending" : "resuming"), pid);
+}
+
+\f
+/* Restarting the xscreensaver process from scratch. */
+
+static char **saved_argv;
+
+void
+save_argv (argc, argv)
+     int argc;
+     char **argv;
+{
+  saved_argv = (char **) malloc ((argc + 2) * sizeof (char *));
+  saved_argv [argc] = 0;
+  while (argc--)
+    {
+      int i = strlen (argv [argc]) + 1;
+      saved_argv [argc] = (char *) malloc (i);
+      memcpy (saved_argv [argc], argv [argc], i);
+    }
+}
+
+void
+restart_process ()
+{
+  XCloseDisplay (dpy);
+  fflush (stdout);
+  fflush (stderr);
+  execvp (saved_argv [0], saved_argv);
+  fprintf (stderr, "%s: %scould not restart process: %s (%d)\n",
+          progname, (verbose_p ? "## " : ""),
+          (errno == E2BIG ? "arglist too big" :
+           errno == EACCES ? "could not execute" :
+           errno == EFAULT ? "memory fault" :
+           errno == EIO ? "I/O error" :
+           errno == ENAMETOOLONG ? "name too long" :
+           errno == ELOOP ? "too many symbolic links" :
+           errno == ENOENT ? "file no longer exists" :
+           errno == ENOTDIR ? "directory no longer exists" :
+           errno == ENOEXEC ? "bad executable file" :
+           errno == ENOMEM ? "out of memory" :
+           "execvp() returned unknown error code"),
+          errno);
+  exit (1);
+}
+
+void
+demo_mode_restart_process ()
+{
+  int i;
+  for (i = 0; saved_argv [i]; i++);
+  /* add the -demo switch; save_argv() left room for this. */
+  saved_argv [i] = "-demo";
+  saved_argv [i+1] = 0;
+  restart_process ();
+}
+
+void
+hack_environment ()
+{
+  /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
+     the spawned processes inherit is the same as the value of -display passed
+     in on our command line (which is not necessarily the same as what our
+     $DISPLAY variable is.)
+   */
+  char *s, buf [2048];
+  int i;
+  sprintf (buf, "DISPLAY=%s", DisplayString (dpy));
+  i = strlen (buf);
+  s = (char *) malloc (i+1);
+  strncpy (s, buf, i+1);
+  if (putenv (s))
+    abort ();
+}
+
+\f
+/* Change the uid/gid of the screensaver process, so that it is safe for it
+   to run setuid root (which it needs to do on some systems to read the 
+   encrypted passwords from the passwd file.)
+
+   hack_uid() is run before opening the X connection, so that XAuth works.
+   hack_uid_warn() is called after the connection is opened and the command
+   line arguments are parsed, so that the messages from hack_uid() get 
+   printed after we know whether we're in `verbose' mode.
+ */
+
+#ifndef NO_SETUID
+
+static int hack_uid_errno;
+static char hack_uid_buf [255], *hack_uid_error;
+
+void
+hack_uid ()
+{
+  /* If we've been run as setuid or setgid to someone else (most likely root)
+     turn off the extra permissions so that random user-specified programs
+     don't get special privileges.  (On some systems it might be necessary
+     to install this as setuid root in order to read the passwd file to
+     implement lock-mode...)
+  */
+  setgid (getgid ());
+  setuid (getuid ());
+
+  hack_uid_errno = 0;
+  hack_uid_error = 0;
+
+  /* If we're being run as root (as from xdm) then switch the user id
+     to something safe. */
+  if (getuid () == 0)
+    {
+      struct passwd *p = getpwnam ("nobody");
+      locking_disabled_p = True;
+      if (! p) p = getpwnam ("daemon");
+      if (! p) p = getpwnam ("bin");
+      if (! p) p = getpwnam ("sys");
+      if (! p)
+       {
+         hack_uid_error = "couldn't find safe uid; running as root.";
+         hack_uid_errno = -1;
+       }
+      else
+       {
+         struct group *g = getgrgid (p->pw_gid);
+         hack_uid_error = hack_uid_buf;
+         sprintf (hack_uid_error, "changing uid/gid to %s/%s (%d/%d).",
+                  p->pw_name, (g ? g->gr_name : "???"), p->pw_uid, p->pw_gid);
+
+         /* Change the gid to be a safe one.  If we can't do that, then
+            print a warning.  We change the gid before the uid so that we
+            change the gid while still root. */
+         if (setgid (p->pw_gid) != 0)
+           {
+             hack_uid_errno = errno;
+             sprintf (hack_uid_error, "couldn't set gid to %s (%d)",
+                      (g ? g->gr_name : "???"), p->pw_gid);
+           }
+
+         /* Now change the uid to be a safe one. */
+         if (setuid (p->pw_uid) != 0)
+           {
+             hack_uid_errno = errno;
+             sprintf (hack_uid_error, "couldn't set uid to %s (%d)",
+                      p->pw_name, p->pw_uid);
+           }
+       }
+    }
+#ifndef NO_LOCKING
+ else  /* disable locking if already being run as "someone else" */
+   {
+     struct passwd *p = getpwuid (getuid ());
+     if (!p ||
+        !strcmp (p->pw_name, "root") ||
+        !strcmp (p->pw_name, "nobody") ||
+        !strcmp (p->pw_name, "daemon") ||
+        !strcmp (p->pw_name, "bin") ||
+        !strcmp (p->pw_name, "sys"))
+       locking_disabled_p = True;
+   }
+#endif /* NO_LOCKING */
+}
+
+void
+hack_uid_warn ()
+{
+  if (! hack_uid_error)
+    ;
+  else if (hack_uid_errno == 0)
+    {
+      if (verbose_p)
+       printf ("%s: %s\n", progname, hack_uid_error);
+    }
+  else
+    {
+      char buf [255];
+      sprintf (buf, "%s: %s%s", progname, (verbose_p ? "## " : ""),
+              hack_uid_error);
+      if (hack_uid_errno == -1)
+       fprintf (stderr, "%s\n", buf);
+      else
+       {
+         errno = hack_uid_errno;
+         perror (buf);
+       }
+    }
+}
+
+#endif /* !NO_SETUID */
diff --git a/driver/timers.c b/driver/timers.c
new file mode 100644 (file)
index 0000000..64117ce
--- /dev/null
@@ -0,0 +1,351 @@
+/* xscreensaver, Copyright (c) 1991-1993 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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 <stdio.h>
+#include <X11/Xlib.h>
+#include <X11/Intrinsic.h>
+#include <X11/Xos.h>
+#include <X11/Xmu/Error.h>
+
+#ifdef HAVE_XIDLE
+#include <X11/extensions/xidle.h>
+#endif
+
+#include "xscreensaver.h"
+
+extern XtAppContext app;
+
+Time cycle;
+Time timeout;
+Time pointer_timeout;
+Time notice_events_timeout;
+
+extern Bool use_xidle;
+extern Bool dbox_up_p;
+extern Bool locked_p;
+extern Window screensaver_window;
+
+extern Bool handle_clientmessage P((/*XEvent *, Bool*/));
+
+static time_t last_activity_time; /* for non-XIdle mode */
+static XtIntervalId timer_id = 0;
+static XtIntervalId check_pointer_timer_id = 0;
+XtIntervalId cycle_id = 0;
+XtIntervalId lock_id = 0;
+
+void
+idle_timer (junk1, junk2)
+     void *junk1;
+     XtPointer junk2;
+{
+  /* What an amazingly shitty design.  Not only does Xt execute timeout
+     events from XtAppNextEvent() instead of from XtDispatchEvent(), but
+     there is no way to tell Xt to block until there is an X event OR a
+     timeout happens.  Once your timeout proc is called, XtAppNextEvent()
+     still won't return until a "real" X event comes in.
+
+     So this function pushes a stupid, gratuitous, unnecessary event back
+     on the event queue to force XtAppNextEvent to return Right Fucking Now.
+     When the code in sleep_until_idle() sees an event of type XAnyEvent,
+     which the server never generates, it knows that a timeout has occurred.
+   */
+  XEvent fake_event;
+  fake_event.type = 0; /* XAnyEvent type, ignored. */
+  fake_event.xany.display = dpy;
+  fake_event.xany.window  = 0;
+  XPutBackEvent (dpy, &fake_event);
+}
+
+
+static void
+notice_events (window, top_p)
+     Window window;
+     Bool top_p;
+{
+  XWindowAttributes attrs;
+  unsigned long events;
+  Window root, parent, *kids;
+  unsigned int nkids;
+
+  if (XtWindowToWidget (dpy, window))
+    /* If it's one of ours, don't mess up its event mask. */
+    return;
+
+  if (!XQueryTree (dpy, window, &root, &parent, &kids, &nkids))
+    return;
+  if (window == root)
+    top_p = False;
+
+  XGetWindowAttributes (dpy, window, &attrs);
+  events = ((attrs.all_event_masks | attrs.do_not_propagate_mask)
+           & KeyPressMask);
+
+  /* Select for SubstructureNotify on all windows.
+     Select for KeyPress on all windows that already have it selected.
+     Do we need to select for ButtonRelease?  I don't think so.
+   */
+  XSelectInput (dpy, window, SubstructureNotifyMask | events);
+
+  if (top_p && verbose_p && (events & KeyPressMask))
+    {
+      /* Only mention one window per tree (hack hack). */
+      printf ("%s: selected KeyPress on 0x%X\n", progname, window);
+      top_p = False;
+    }
+
+  if (kids)
+    {
+      while (nkids)
+       notice_events (kids [--nkids], top_p);
+      XFree ((char *) kids);
+    }
+}
+
+
+int
+BadWindow_ehandler (dpy, error)
+     Display *dpy;
+     XErrorEvent *error;
+{
+  /* When we notice a window being created, we spawn a timer that waits
+     30 seconds or so, and then selects events on that window.  This error
+     handler is used so that we can cope with the fact that the window
+     may have been destroyed <30 seconds after it was created.
+   */
+  if (error->error_code == BadWindow ||
+      error->error_code == BadDrawable)
+    return 0;
+  XmuPrintDefaultErrorMessage (dpy, error, stderr);
+  exit (1);
+}
+
+void
+notice_events_timer (closure, timer)
+     XtPointer closure;
+     void *timer;
+{
+  Window window = (Window) closure;
+  int (*old_handler) ();
+  old_handler = XSetErrorHandler (BadWindow_ehandler);
+  notice_events (window, True);
+  XSync (dpy, False);
+  XSetErrorHandler (old_handler);
+}
+
+
+/* When the screensaver is active, this timer will periodically change
+   the running program.
+ */
+void
+cycle_timer (junk1, junk2)
+     void *junk1;
+     XtPointer junk2;
+{
+  Time how_long = cycle;
+  if (dbox_up_p)
+    {
+      if (verbose_p)
+       printf ("%s: dbox up; delaying hack change.\n", progname);
+      how_long = 30000; /* 30 secs */
+    }
+  else
+    {
+      if (verbose_p)
+       printf ("%s: changing graphics hacks.\n", progname);
+      kill_screenhack ();
+      spawn_screenhack (False);
+    }
+  cycle_id = XtAppAddTimeOut (app, how_long, cycle_timer, 0);
+}
+
+
+void
+activate_lock_timer (junk1, junk2)
+     void *junk1;
+     XtPointer junk2;
+{
+  if (verbose_p)
+    printf ("%s: timed out; activating lock\n", progname);
+  locked_p = True;
+}
+
+
+/* Call this when user activity (or "simulated" activity) has been noticed.
+ */
+static void
+reset_timers ()
+{
+#ifdef DEBUG_TIMERS
+  if (verbose_p)
+    printf ("%s: restarting idle_timer (%d, %d)\n",
+           progname, timeout, timer_id);
+#endif
+  XtRemoveTimeOut (timer_id);
+  timer_id = XtAppAddTimeOut (app, timeout, idle_timer, 0);
+  if (cycle_id) abort ();
+
+  last_activity_time = time ((time_t *) 0);
+}
+
+/* When we aren't using XIdle, this timer is used to periodically wake up
+   and poll the mouse position, which is possibly more reliable than
+   selecting motion events on every window.
+ */
+static void
+check_pointer_timer (closure, this_timer)
+     void *closure;
+     XtPointer this_timer;
+{
+  static int last_root_x = -1;
+  static int last_root_y = -1;
+  static Window last_child = (Window) -1;
+  static unsigned int last_mask = 0;
+  Window root, child;
+  int root_x, root_y, x, y;
+  unsigned int mask;
+  XtIntervalId *timerP = (XtIntervalId *) closure;
+#ifdef HAVE_XIDLE
+  if (use_xidle)
+    abort ();
+#endif
+
+  *timerP = XtAppAddTimeOut (app, pointer_timeout, check_pointer_timer,
+                            closure);
+
+  XQueryPointer (dpy, screensaver_window, &root, &child,
+                &root_x, &root_y, &x, &y, &mask);
+  if (root_x == last_root_x && root_y == last_root_y &&
+      child == last_child && mask == last_mask)
+    return;
+
+#ifdef DEBUG_TIMERS
+  if (verbose_p && this_timer)
+    if (root_x == last_root_x && root_y == last_root_y && child == last_child)
+      printf ("%s: modifiers changed at %s.\n", progname, timestring ());
+    else
+      printf ("%s: pointer moved at %s.\n", progname, timestring ());
+#endif
+
+  last_root_x = root_x;
+  last_root_y = root_y;
+  last_child = child;
+  last_mask = mask;
+
+  reset_timers ();
+}
+
+
+void
+sleep_until_idle (until_idle_p)
+     Bool until_idle_p;
+{
+  XEvent event;
+
+  if (until_idle_p)
+    {
+      timer_id = XtAppAddTimeOut (app, timeout, idle_timer, 0);
+#ifdef HAVE_XIDLE
+      if (! use_xidle)
+#endif
+       /* start polling the mouse position */
+       check_pointer_timer (&check_pointer_timer_id, 0);
+    }
+
+  while (1)
+    {
+      XtAppNextEvent (app, &event);
+
+      switch (event.xany.type) {
+      case 0:          /* our synthetic "timeout" event has been signalled */
+       if (until_idle_p)
+         {
+           Time idle;
+#ifdef HAVE_XIDLE
+           if (use_xidle)
+             {
+               if (! XGetIdleTime (dpy, &idle))
+                 {
+                   fprintf (stderr, "%s: %sXGetIdleTime() failed.\n",
+                            progname, (verbose_p ? "## " : ""));
+                   exit (1);
+                 }
+             }
+           else
+#endif /* HAVE_XIDLE */
+             idle = 1000 * (last_activity_time - time ((time_t *) 0));
+           
+           if (idle >= timeout)
+             goto DONE;
+           else
+             timer_id = XtAppAddTimeOut (app, timeout - idle,
+                                         idle_timer, 0);
+         }
+       break;
+
+      case ClientMessage:
+       if (handle_clientmessage (&event, until_idle_p))
+         goto DONE;
+       break;
+
+      case CreateNotify:
+#ifdef HAVE_XIDLE
+       if (! use_xidle)
+#endif
+         XtAppAddTimeOut (app, notice_events_timeout, notice_events_timer,
+                          (XtPointer) event.xcreatewindow.window);
+       break;
+
+      case KeyPress:
+      case KeyRelease:
+      case ButtonPress:
+      case ButtonRelease:
+      case MotionNotify:
+
+#ifdef DEBUG_TIMERS
+       if (verbose_p)
+         {
+           if (event.xany.type == MotionNotify)
+             printf ("%s: MotionNotify at %s\n", progname, timestring ());
+           else if (event.xany.type == KeyPress)
+             printf ("%s: KeyPress seen on 0x%X at %s\n", progname,
+                     event.xkey.window, timestring ());
+         }
+#endif
+
+       /* We got a user event */
+       if (!until_idle_p)
+         goto DONE;
+       else
+         reset_timers ();
+       break;
+
+      default:
+       XtDispatchEvent (&event);
+      }
+    }
+ DONE:
+
+  if (check_pointer_timer_id)
+    {
+      XtRemoveTimeOut (check_pointer_timer_id);
+      check_pointer_timer_id = 0;
+    }
+  if (timer_id)
+    {
+      XtRemoveTimeOut (timer_id);
+      timer_id = 0;
+    }
+
+  if (until_idle_p && cycle_id)
+    abort ();
+
+  return;
+}
diff --git a/driver/visual.c b/driver/visual.c
new file mode 100644 (file)
index 0000000..b4ca972
--- /dev/null
@@ -0,0 +1,160 @@
+/* xscreensaver, Copyright (c) 1993 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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.
+ */
+
+/* This file contains some code for intelligently picking the best visual
+   (where "best" is somewhat biased in the direction of writable cells...)
+ */
+
+#if __STDC__
+#include <stdlib.h>
+#endif
+
+#include <stdio.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#ifndef isupper
+# define isupper(c)  ((c) >= 'A' && (c) <= 'Z')
+#endif
+#ifndef _tolower
+# define _tolower(c)  ((c) - 'A' + 'a')
+#endif
+
+extern char *progname;
+extern char *get_string_resource ();
+
+static Visual *
+pick_best_visual_of_class (display, visual_class)
+     Display *display;
+     int visual_class;
+{
+  XVisualInfo vi_in, *vi_out;
+  int out_count;
+
+  vi_in.class = visual_class;
+  vi_in.screen = DefaultScreen (display);
+  vi_out = XGetVisualInfo (display, VisualClassMask|VisualScreenMask,
+                          &vi_in, &out_count);
+  if (vi_out)
+    {       /* choose the 'best' one, if multiple */
+      int i, best;
+      Visual *visual;
+      for (i = 0, best = 0; i < out_count; i++)
+       if (vi_out [i].depth > vi_out [best].depth)
+         best = i;
+      visual = vi_out [best].visual;
+      XFree ((char *) vi_out);
+      return visual;
+    }
+  else
+    return 0;
+}
+
+static Visual *
+pick_best_visual (display)
+     Display *display;
+{
+  Visual *visual;
+  if (visual = pick_best_visual_of_class (display, PseudoColor))
+    return visual;
+  if (visual = pick_best_visual_of_class (display, DirectColor))
+    return visual;
+  if (visual = pick_best_visual_of_class (display, GrayScale))
+    return visual;
+  if (visual = pick_best_visual_of_class (display, StaticGray))
+    return visual;
+  return DefaultVisual (display, DefaultScreen (display));
+}
+
+
+static Visual *
+id_to_visual (dpy, id)
+     Display *dpy;
+     int id;
+{
+  XVisualInfo vi_in, *vi_out;
+  int out_count;
+  vi_in.screen = DefaultScreen (dpy);
+  vi_in.visualid = id;
+  vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
+                          &vi_in, &out_count);
+  if (vi_out)
+    {
+      Visual *v = vi_out[0].visual;
+      XFree ((char *) vi_out);
+      return v;
+    }
+  return 0;
+}
+
+int
+get_visual_depth (dpy, visual)
+     Display *dpy;
+     Visual *visual;
+{
+  XVisualInfo vi_in, *vi_out;
+  int out_count, d;
+  vi_in.screen = DefaultScreen (dpy);
+  vi_in.visualid = XVisualIDFromVisual (visual);
+  vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
+                          &vi_in, &out_count);
+  if (! vi_out) abort ();
+  d = vi_out [0].depth;
+  XFree ((char *) vi_out);
+  return d;
+}
+
+
+Visual *
+get_visual_resource (dpy, name, class)
+     Display *dpy;
+     char *name, *class;
+{
+  char c, *s = get_string_resource (name, class);
+  char *tmp;
+  int vclass;
+  int id;
+
+  if (s)
+    for (tmp = s; *tmp; tmp++)
+      if (isupper (*tmp)) *tmp = _tolower (*tmp);
+
+  if      (!s || !strcmp (s, "best"))  vclass = -1;
+  else if (!strcmp (s, "default"))     vclass = -2;
+  else if (!strcmp (s, "staticgray"))  vclass = StaticGray;
+  else if (!strcmp (s, "staticcolor")) vclass = StaticColor;
+  else if (!strcmp (s, "truecolor"))   vclass = TrueColor;
+  else if (!strcmp (s, "grayscale"))   vclass = GrayScale;
+  else if (!strcmp (s, "pseudocolor")) vclass = PseudoColor;
+  else if (!strcmp (s, "directcolor")) vclass = DirectColor;
+  else if (1 == sscanf (s, " %ld %c", &id, &c))   vclass = -3;
+  else if (1 == sscanf (s, " 0x%lx %c", &id, &c)) vclass = -3;
+  else
+    {
+      fprintf (stderr, "%s: unrecognized visual \"%s\".\n", progname, s);
+      vclass = -1;
+    }
+  if (s) free (s);
+
+  if (vclass == -1)
+    return pick_best_visual (dpy);
+  else if (vclass == -2)
+    return DefaultVisual (dpy, DefaultScreen (dpy));
+  else if (vclass == -3)
+    {
+      Visual *v = id_to_visual (dpy, id);
+      if (v) return v;
+      fprintf (stderr, "%s: no visual with id 0x%x.\n", progname, id);
+      return pick_best_visual (dpy);
+    }
+  else
+    return pick_best_visual_of_class (dpy, vclass);
+}
diff --git a/driver/windows.c b/driver/windows.c
new file mode 100644 (file)
index 0000000..1e4b22d
--- /dev/null
@@ -0,0 +1,611 @@
+/* xscreensaver, Copyright (c) 1991-1993 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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 <stdio.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/Xos.h>
+#include <X11/Xmu/SysUtil.h>
+
+#include <signal.h>            /* for the signal names */
+
+#include "xscreensaver.h"
+
+#if __STDC__
+extern int kill (pid_t, int);          /* signal() is in sys/signal.h... */
+#endif /* __STDC__ */
+
+extern Bool lock_p, demo_mode_p;
+
+Atom XA_VROOT, XA_XSETROOT_ID;
+Atom XA_SCREENSAVER_VERSION, XA_SCREENSAVER_ID;
+
+Window screensaver_window = 0;
+Cursor cursor;
+Colormap cmap, cmap2;
+Bool install_cmap_p;
+Bool fade_p, unfade_p;
+int fade_seconds, fade_ticks;
+
+static unsigned long black_pixel;
+static Window real_vroot, real_vroot_value;
+
+#define ALL_POINTER_EVENTS \
+       (ButtonPressMask | ButtonReleaseMask | EnterWindowMask | \
+        LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | \
+        Button1MotionMask | Button2MotionMask | Button3MotionMask | \
+        Button4MotionMask | Button5MotionMask | ButtonMotionMask)
+
+/* I don't really understand Sync vs Async, but these seem to work... */
+#define grab_kbd(win) \
+  XGrabKeyboard (dpy, (win), True, GrabModeSync, GrabModeAsync, CurrentTime)
+#define grab_mouse(win) \
+  XGrabPointer (dpy, (win), True, ALL_POINTER_EVENTS, \
+               GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime)
+
+void
+grab_keyboard_and_mouse ()
+{
+  Status status;
+  XSync (dpy, False);
+
+  if (demo_mode_p) return;
+
+  status = grab_kbd (screensaver_window);
+  if (status != GrabSuccess)
+    {  /* try again in a second */
+      sleep (1);
+      status = grab_kbd (screensaver_window);
+      if (status != GrabSuccess)
+       fprintf (stderr, "%s: %scouldn't grab keyboard!  (%d)\n",
+                progname, (verbose_p ? "## " : ""), status);
+    }
+  status = grab_mouse (screensaver_window);
+  if (status != GrabSuccess)
+    {  /* try again in a second */
+      sleep (1);
+      status = grab_mouse (screensaver_window);
+      if (status != GrabSuccess)
+       fprintf (stderr, "%s: %scouldn't grab pointer!  (%d)\n",
+                progname, (verbose_p ? "## " : ""), status);
+    }
+}
+
+void
+ungrab_keyboard_and_mouse ()
+{
+  XUngrabPointer (dpy, CurrentTime);
+  XUngrabKeyboard (dpy, CurrentTime);
+}
+
+
+void
+ensure_no_screensaver_running ()
+{
+  int i;
+  Window root = RootWindowOfScreen (screen);
+  Window root2, parent, *kids;
+  unsigned int nkids;
+  int (*old_handler) ();
+
+  old_handler = XSetErrorHandler (BadWindow_ehandler);
+
+  if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
+    abort ();
+  if (root != root2)
+    abort ();
+  if (parent)
+    abort ();
+  for (i = 0; i < nkids; i++)
+    {
+      Atom type;
+      int format;
+      unsigned long nitems, bytesafter;
+      char *version;
+
+      if (XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_VERSION, 0, 1,
+                             False, XA_STRING, &type, &format, &nitems,
+                             &bytesafter, (unsigned char **) &version)
+         == Success
+         && type != None)
+       {
+         char *id;
+         if (!XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_ID, 0, 512,
+                                  False, XA_STRING, &type, &format, &nitems,
+                                  &bytesafter, (unsigned char **) &id)
+             == Success
+             || type == None)
+           id = "???";
+
+         fprintf (stderr,
+      "%s: %salready running on display %s (window 0x%x)\n from process %s.\n",
+                  progname, (verbose_p ? "## " : ""), DisplayString (dpy),
+                  (int) kids [i], id);
+         exit (1);
+       }
+    }
+
+  if (kids) XFree ((char *) kids);
+  XSync (dpy, False);
+  XSetErrorHandler (old_handler);
+}
+
+
+void
+disable_builtin_screensaver ()
+{
+  int timeout, interval, prefer_blank, allow_exp;
+  XForceScreenSaver (dpy, ScreenSaverReset);
+  XGetScreenSaver (dpy, &timeout, &interval, &prefer_blank, &allow_exp);
+  if (timeout != 0)
+    {
+      XSetScreenSaver (dpy, 0, interval, prefer_blank, allow_exp);
+      printf ("%s%sisabling server builtin screensaver.\n\
+       You can re-enable it with \"xset s on\".\n",
+             (verbose_p ? "" : progname), (verbose_p ? "\n\tD" : ": d"));
+    }
+}
+
+\f
+/* Virtual-root hackery */
+
+#ifdef _VROOT_H_
+ERROR!  You must not include vroot.h in this file.
+#endif
+
+static void
+store_vroot_property (win, value)
+     Window win, value;
+{
+#if 0
+  printf ("%s: storing XA_VROOT = 0x%x (%s) = 0x%x (%s)\n", progname, 
+         win,
+         (win == screensaver_window ? "ScreenSaver" :
+          (win == real_vroot ? "VRoot" :
+           (win == real_vroot_value ? "Vroot_value" : "???"))),
+         value,
+         (value == screensaver_window ? "ScreenSaver" :
+          (value == real_vroot ? "VRoot" :
+           (value == real_vroot_value ? "Vroot_value" : "???"))));
+#endif
+  XChangeProperty (dpy, win, XA_VROOT, XA_WINDOW, 32, PropModeReplace,
+                  (unsigned char *) &value, 1);
+}
+
+static void
+remove_vroot_property (win)
+     Window win;
+{
+#if 0
+  printf ("%s: removing XA_VROOT from 0x%x (%s)\n", progname, win, 
+         (win == screensaver_window ? "ScreenSaver" :
+          (win == real_vroot ? "VRoot" :
+           (win == real_vroot_value ? "Vroot_value" : "???"))));
+#endif
+  XDeleteProperty (dpy, win, XA_VROOT);
+}
+
+
+static void
+kill_xsetroot_data ()
+{
+  Atom type;
+  int format;
+  unsigned long nitems, bytesafter;
+  Pixmap *dataP = 0;
+
+  /* If the user has been using xv or xsetroot as a screensaver (to display
+     an image on the screensaver window, as a kind of slideshow) then the
+     pixmap and its associated color cells have been put in RetainPermanent
+     CloseDown mode.  Since we're not destroying the xscreensaver window,
+     but merely unmapping it, we need to free these resources or those
+     colormap cells will stay allocated while the screensaver is off.  (We
+     could just delete the screensaver window and recreate it later, but
+     that could cause other problems.)  This code does an atomic read-and-
+     delete of the _XSETROOT_ID property, and if it held a pixmap, then we
+     cause the RetainPermanent resources of the client which created it
+     (and which no longer exists) to be freed.
+   */
+  if (XGetWindowProperty (dpy, screensaver_window, XA_XSETROOT_ID, 0, 1,
+                         True, AnyPropertyType, &type, &format, &nitems, 
+                         &bytesafter, (unsigned char **) &dataP)
+      == Success
+      && type != None)
+    {
+      if (dataP && *dataP && type == XA_PIXMAP && format == 32 &&
+         nitems == 1 && bytesafter == 0)
+       {
+         if (verbose_p)
+           printf ("%s: destroying xsetroot data (0x%X).\n",
+                   progname, *dataP);
+         XKillClient (dpy, *dataP);
+       }
+      else
+       fprintf (stderr, "%s: %sdeleted unrecognised _XSETROOT_ID property: \n\
+       %d, %d; type: %d, format: %d, nitems: %d, bytesafter %d\n",
+                progname, (verbose_p ? "## " : ""),
+                dataP, (dataP ? *dataP : 0), type,
+                format, nitems, bytesafter);
+    }
+}
+
+
+static void handle_signals P((Bool on_p));
+
+static void
+save_real_vroot ()
+{
+  int i;
+  Window root = RootWindowOfScreen (screen);
+  Window root2, parent, *kids;
+  unsigned int nkids;
+
+  real_vroot = 0;
+  real_vroot_value = 0;
+  if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
+    abort ();
+  if (root != root2)
+    abort ();
+  if (parent)
+    abort ();
+  for (i = 0; i < nkids; i++)
+    {
+      Atom type;
+      int format;
+      unsigned long nitems, bytesafter;
+      Window *vrootP = 0;
+
+      if (XGetWindowProperty (dpy, kids[i], XA_VROOT, 0, 1, False, XA_WINDOW,
+                             &type, &format, &nitems, &bytesafter,
+                             (unsigned char **) &vrootP)
+         != Success)
+       continue;
+      if (! vrootP)
+       continue;
+      if (real_vroot)
+       {
+         if (*vrootP == screensaver_window) abort ();
+         fprintf (stderr,
+           "%s: %smore than one virtual root window found (0x%x and 0x%x).\n",
+                  progname, (verbose_p ? "## " : ""),
+                  (int) real_vroot, (int) kids [i]);
+         exit (1);
+       }
+      real_vroot = kids [i];
+      real_vroot_value = *vrootP;
+    }
+
+  if (real_vroot)
+    {
+      handle_signals (True);
+      remove_vroot_property (real_vroot);
+      XSync (dpy, False);
+    }
+
+  XFree ((char *) kids);
+}
+
+static Bool
+restore_real_vroot_1 ()
+{
+  if (verbose_p && real_vroot)
+    printf ("%s: restoring __SWM_VROOT property on the real vroot (0x%x).\n",
+           progname, real_vroot);
+  remove_vroot_property (screensaver_window);
+  if (real_vroot)
+    {
+      store_vroot_property (real_vroot, real_vroot_value);
+      real_vroot = 0;
+      real_vroot_value = 0;
+      /* make sure the property change gets there before this process
+        terminates!  We might be doing this because we have intercepted
+        SIGTERM or something. */
+      XSync (dpy, False);
+      return True;
+    }
+  return False;
+}
+
+void
+restore_real_vroot ()
+{
+  if (restore_real_vroot_1 ())
+    handle_signals (False);
+}
+
+\f
+/* Signal hackery to ensure that the vroot doesn't get left in an 
+   inconsistent state
+ */
+
+static const char *sig_names [255] = { 0 };
+
+static void
+restore_real_vroot_handler (sig)
+     int sig;
+{
+  signal (sig, SIG_DFL);
+  if (restore_real_vroot_1 ())
+    fprintf (stderr, "\n%s: %s%s (%d) intercepted, vroot restored.\n",
+            progname, (verbose_p ? "## " : ""),
+            ((sig < sizeof(sig_names) && sig >= 0 && sig_names [sig])
+             ? sig_names [sig] : "unknown signal"),
+            sig);
+  kill (getpid (), sig);
+}
+
+
+static void
+catch_signal (sig, signame, on_p)
+     int sig;
+     char *signame;
+     Bool on_p;
+{
+  if (! on_p)
+    signal (sig, SIG_DFL);
+  else
+    {
+      sig_names [sig] = signame;
+      if (((int) signal (sig, restore_real_vroot_handler)) == -1)
+       {
+         char buf [255];
+         sprintf (buf, "%s: %scouldn't catch %s (%d)", progname,
+                  (verbose_p ? "## " : ""), signame, sig);
+         perror (buf);
+         restore_real_vroot ();
+         exit (1);
+       }
+    }
+}
+
+static void
+handle_signals (on_p)
+     Bool on_p;
+{
+#if 0
+  if (on_p) printf ("handling signals\n");
+  else printf ("unhandling signals\n");
+#endif
+
+  catch_signal (SIGHUP,  "SIGHUP",  on_p);
+  catch_signal (SIGINT,  "SIGINT",  on_p);
+  catch_signal (SIGQUIT, "SIGQUIT", on_p);
+  catch_signal (SIGILL,  "SIGILL",  on_p);
+  catch_signal (SIGTRAP, "SIGTRAP", on_p);
+  catch_signal (SIGIOT,  "SIGIOT",  on_p);
+  catch_signal (SIGABRT, "SIGABRT", on_p);
+#ifdef SIGEMT
+  catch_signal (SIGEMT,  "SIGEMT",  on_p);
+#endif
+  catch_signal (SIGFPE,  "SIGFPE",  on_p);
+  catch_signal (SIGBUS,  "SIGBUS",  on_p);
+  catch_signal (SIGSEGV, "SIGSEGV", on_p);
+  catch_signal (SIGSYS,  "SIGSYS",  on_p);
+  catch_signal (SIGTERM, "SIGTERM", on_p);
+#ifdef SIGXCPU
+  catch_signal (SIGXCPU, "SIGXCPU", on_p);
+#endif
+#ifdef SIGXFSZ
+  catch_signal (SIGXFSZ, "SIGXFSZ", on_p);
+#endif
+#ifdef SIGDANGER
+  catch_signal (SIGDANGER, "SIGDANGER", on_p);
+#endif
+}
+
+\f
+/* Managing the actual screensaver window */
+
+void
+initialize_screensaver_window ()
+{
+  /* This resets the screensaver window as fully as possible, since there's
+     no way of knowing what some random client may have done to us in the
+     meantime.  We could just destroy and recreate the window, but that has
+     its own set of problems...
+   */
+  XColor black;
+  XClassHint class_hints;
+  XSetWindowAttributes attrs;
+  unsigned long attrmask;
+  int width = WidthOfScreen (screen);
+  int height = HeightOfScreen (screen);
+  char id [2048];
+
+  if (cmap == DefaultColormapOfScreen (screen))
+    cmap = 0;
+
+  if ((install_cmap_p && !demo_mode_p) ||
+      (visual != DefaultVisualOfScreen (screen)))
+    {
+      if (! cmap)
+       {
+         cmap = XCreateColormap (dpy, RootWindowOfScreen (screen),
+                                 visual, AllocNone);
+         if (! XAllocColor (dpy, cmap, &black)) abort ();
+         black_pixel = black.pixel;
+       }
+    }
+  else
+    {
+      if (cmap)
+       {
+         XFreeColors (dpy, cmap, &black_pixel, 1, 0);
+         XFreeColormap (dpy, cmap);
+       }
+      cmap = DefaultColormapOfScreen (screen);
+      black_pixel = BlackPixelOfScreen (screen);
+    }
+
+  if (cmap2)
+    {
+      XFreeColormap (dpy, cmap2);
+      cmap2 = 0;
+    }
+
+  if (fade_p)
+    {
+      cmap2 = copy_colormap (dpy, cmap, 0);
+      if (! cmap2)
+       fade_p = unfade_p = 0;
+    }
+
+  attrmask = CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap;
+  attrs.override_redirect = True;
+  attrs.event_mask = (KeyPressMask | KeyReleaseMask |
+                     ButtonPressMask | ButtonReleaseMask |
+                     PointerMotionMask);
+  attrs.backing_store = NotUseful;
+  attrs.colormap = cmap;
+
+/*  if (demo_mode_p || lock_p || locked_p) width = width / 2;  #### */
+
+  if (screensaver_window)
+    {
+      XWindowChanges changes;
+      unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
+      changes.x = 0;
+      changes.y = 0;
+      changes.width = width;
+      changes.height = height;
+      changes.border_width = 0;
+
+      XConfigureWindow (dpy, screensaver_window, changesmask, &changes);
+      XChangeWindowAttributes (dpy, screensaver_window, attrmask, &attrs);
+    }
+  else
+    {
+      screensaver_window =
+       XCreateWindow (dpy, RootWindowOfScreen (screen), 0, 0, width, height,
+                      0, visual_depth, InputOutput, visual, attrmask,
+                      &attrs);
+    }
+
+  class_hints.res_name = progname;
+  class_hints.res_class = progclass;
+  XSetClassHint (dpy, screensaver_window, &class_hints);
+  XStoreName (dpy, screensaver_window, "screensaver");
+  XChangeProperty (dpy, screensaver_window, XA_SCREENSAVER_VERSION,
+                  XA_STRING, 8, PropModeReplace,
+                  (unsigned char *) screensaver_version,
+                  strlen (screensaver_version));
+
+  sprintf (id, "%d on host ", getpid ());
+  if (! XmuGetHostname (id + strlen (id), sizeof (id) - strlen (id) - 1))
+    strcat (id, "???");
+  XChangeProperty (dpy, screensaver_window, XA_SCREENSAVER_ID, XA_STRING, 8,
+                  PropModeReplace, (unsigned char *) id, strlen (id));
+
+  black.red = black.green = black.blue = 0;
+  if (!cursor)
+    {
+      Pixmap bit;
+      bit = XCreatePixmapFromBitmapData (dpy, screensaver_window, "\000", 1, 1,
+                                        BlackPixelOfScreen (screen),
+                                        BlackPixelOfScreen (screen), 1);
+      cursor = XCreatePixmapCursor (dpy, bit, bit, &black, &black, 0, 0);
+      XFreePixmap (dpy, bit);
+    }
+
+  XSetWindowBackground (dpy, screensaver_window, black_pixel);
+  if (! demo_mode_p)
+    XDefineCursor (dpy, screensaver_window, cursor);
+  else
+    XUndefineCursor (dpy, screensaver_window);
+}
+
+
+void 
+raise_window (inhibit_fade, between_hacks_p)
+     Bool inhibit_fade, between_hacks_p;
+{
+  initialize_screensaver_window ();
+
+  if (fade_p && !inhibit_fade && !demo_mode_p)
+    {
+      int grabbed;
+      Colormap current_map = (between_hacks_p
+                             ? cmap
+                             : DefaultColormapOfScreen (screen));
+      copy_colormap (dpy, current_map, cmap2);
+      XGrabServer (dpy);
+      /* grab and blacken mouse on the root window (saver not mapped yet) */
+      grabbed = grab_mouse (RootWindowOfScreen (screen));
+      /* fade what's on the screen to black */
+      XInstallColormap (dpy, cmap2);
+      fade_colormap (dpy, current_map, cmap2, fade_seconds, fade_ticks, True);
+      XClearWindow (dpy, screensaver_window);
+      XMapRaised (dpy, screensaver_window);
+      XInstallColormap (dpy, cmap);
+      if (grabbed == GrabSuccess)
+       XUngrabPointer (dpy, CurrentTime);
+      XUngrabServer (dpy);
+    }
+  else
+    {
+      XClearWindow (dpy, screensaver_window);
+      XMapRaised (dpy, screensaver_window);
+    }
+
+  if (install_cmap_p && !demo_mode_p)
+    XInstallColormap (dpy, cmap);
+}
+
+void
+blank_screen ()
+{
+  save_real_vroot ();
+  store_vroot_property (screensaver_window, screensaver_window);
+  raise_window (False, False);
+  grab_keyboard_and_mouse ();
+#ifdef __hpux
+  if (lock_p)
+    XHPDisableReset (dpy);     /* turn off C-Sh-Reset */
+#endif
+}
+
+void
+unblank_screen ()
+{
+  if (unfade_p && !demo_mode_p)
+    {
+      int grabbed;
+      Colormap default_map = DefaultColormapOfScreen (screen);
+      blacken_colormap (dpy, cmap2);
+      XGrabServer (dpy);
+      /* grab and blacken mouse on the root window. */
+      grabbed = grab_mouse (RootWindowOfScreen (screen));
+      XInstallColormap (dpy, cmap2);
+      XUnmapWindow (dpy, screensaver_window);
+      fade_colormap (dpy, default_map, cmap2, fade_seconds, fade_ticks, False);
+      XInstallColormap (dpy, default_map);
+      if (grabbed == GrabSuccess)
+       XUngrabPointer (dpy, CurrentTime);
+      XUngrabServer (dpy);
+    }
+  else
+    {
+      if (install_cmap_p && !demo_mode_p)
+       {
+         XClearWindow (dpy, screensaver_window); /* avoid technicolor */
+         XInstallColormap (dpy, DefaultColormapOfScreen (screen));
+       }
+      XUnmapWindow (dpy, screensaver_window);
+    }
+  kill_xsetroot_data ();
+  ungrab_keyboard_and_mouse ();
+  restore_real_vroot ();
+#ifdef __hpux
+  if (lock_p)
+    XHPEnableReset (dpy);      /* turn C-Sh-Reset back on */
+#endif
+}
diff --git a/driver/xscreensaver-command.c b/driver/xscreensaver-command.c
new file mode 100644 (file)
index 0000000..cf76a6f
--- /dev/null
@@ -0,0 +1,150 @@
+/* xscreensaver-command, Copyright (c) 1991-1993 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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 "version.h"
+#include <stdio.h>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/Xos.h>
+#if __STDC__
+# include <stdlib.h>
+#endif
+
+#ifdef _VROOT_H_
+ERROR! you must not include vroot.h in this file
+#endif
+
+static char *screensaver_version;
+static char *usage = "usage: %s -<switch>\n\
+\n\
+  This program provides external control of a running xscreensaver process.\n\
+  Version %s, copyright (c) 1991-1993 Jamie Zawinski <jwz@lucid.com>.\n\
+\n\
+  -demo                Enter interactive demo mode.\n\
+  -deactivate  Turns off the screensaver if it is on, as user input would.\n\
+  -activate    Turns it on as if the user had been idle for long enough.\n\
+  -cycle       Stops the current hack and runs a new one.\n\
+  -next                Like either -activate or -cycle, depending on which is more\n\
+               appropriate, except that the screenhack that will be run is\n\
+               the next one in the list of hacks, instead of a randomly-\n\
+               chosen one.  This option is good for looking at a demo of\n\
+               each of the hacks in place.\n\
+  -prev                Like -next, but goes in the other direction.\n\
+  -exit                Causes the screensaver process to exit.  It should be ok to\n\
+               just kill the process (NOT with -9!) but this is a slightly\n\
+               easier way.\n\
+  -restart     Causes the screensaver process to exit and then restart with\n\
+               the same command line arguments.  This is a good way of \n\
+               causing the screensaver to re-read the resource database.\n\
+  -lock         Same as -activate, but with immediate locking.\n\
+\n\
+  See the man page for more details.\n\n";
+
+static Window
+find_screensaver_window (dpy, progname)
+     Display *dpy;
+     char *progname;
+{
+  int i;
+  Window root = RootWindowOfScreen (DefaultScreenOfDisplay (dpy));
+  Window root2, parent, *kids;
+  unsigned int nkids;
+
+  if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
+    abort ();
+  if (root != root2)
+    abort ();
+  if (parent)
+    abort ();
+  if (! (kids && nkids))
+    abort ();
+  for (i = 0; i < nkids; i++)
+    {
+      Atom type;
+      int format;
+      unsigned long nitems, bytesafter;
+      char *version;
+
+      if (XGetWindowProperty (dpy, kids[i],
+                             XInternAtom (dpy, "_SCREENSAVER_VERSION", False),
+                             0, 1, False, XA_STRING,
+                             &type, &format, &nitems, &bytesafter,
+                             (unsigned char **) &version)
+         == Success
+         && type != None)
+       return kids[i];
+    }
+  fprintf (stderr, "%s: no screensaver is running on display %s", progname,
+          DisplayString (dpy));
+  exit (1);
+}
+
+
+#define USAGE() \
+ { fprintf (stderr, usage, argv[0], screensaver_version); exit (1); }
+
+void
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  Display *dpy;
+  Window window;
+  XEvent event;
+  int i;
+  char *message = 0, *dpyname = 0;
+  screensaver_version = malloc (5);
+  memcpy (screensaver_version, screensaver_id + 17, 4);
+  screensaver_version [4] = 0;
+  for (i = 1; i < argc; i++)
+    {
+      char *s = argv [i];
+      int L = strlen (s);
+      if (L < 2) USAGE ();
+      if (!strncmp (s, "-display", L))         dpyname = argv [++i];
+      else if (message) USAGE ()
+      else if (!strncmp (s, "-activate", L))   message = "ACTIVATE";
+      else if (!strncmp (s, "-deactivate", L)) message = "DEACTIVATE";
+      else if (!strncmp (s, "-cycle", L))      message = "CYCLE";
+      else if (!strncmp (s, "-next", L))       message = "NEXT";
+      else if (!strncmp (s, "-prev", L))       message = "PREV";
+      else if (!strncmp (s, "-exit", L))       message = "EXIT";
+      else if (!strncmp (s, "-restart", L))    message = "RESTART";
+      else if (!strncmp (s, "-demo", L))       message = "DEMO";
+      else if (!strncmp (s, "-lock", L))       message = "LOCK";
+      else USAGE ();
+    }
+  if (! message) USAGE ();
+  if (!dpyname) dpyname = (char *) getenv ("DISPLAY");
+  dpy = XOpenDisplay (dpyname);
+  if (!dpy)
+    {
+      fprintf (stderr, "%s: can't open display %s\n", argv[0],
+              (dpyname ? dpyname : "(null)"));
+      exit (1);
+    }
+  window = find_screensaver_window (dpy, argv[0]);
+
+  event.xany.type = ClientMessage;
+  event.xclient.display = dpy;
+  event.xclient.window = window;
+  event.xclient.message_type = XInternAtom (dpy, "SCREENSAVER", False);
+  event.xclient.format = 32;
+  event.xclient.data.l[0] = (long) XInternAtom (dpy, message, False);
+  if (! XSendEvent (dpy, window, False, 0L, &event))
+    {
+      fprintf (stderr, "%s: XSendEvent(dpy, 0x%x ...) failed.\n", argv [0],
+              (unsigned int) window);
+      exit (1);
+    }
+  XSync (dpy, 0);
+  exit (0);
+}
diff --git a/driver/xscreensaver-command.man b/driver/xscreensaver-command.man
new file mode 100644 (file)
index 0000000..92b0b2b
--- /dev/null
@@ -0,0 +1,110 @@
+.de EX         \"Begin example
+.ne 5
+.if n .sp 1
+.if t .sp .5
+.nf
+.in +.5i
+..
+.de EE
+.fi
+.in -.5i
+.if n .sp 1
+.if t .sp .5
+..
+.TH XScreenSaver 1 "22-mar-93" "X Version 11"
+.SH NAME
+xscreensaver-command - control a running xscreensaver process
+.SH SYNOPSIS
+.B xscreensaver-command
+[\-activate] [\-deactivate] [\-cycle] [\-next] [\-prev] [\-exit] [\-restart] [\-demo] [\-lock]
+.SH DESCRIPTION
+The \fIxscreensaver\-command\fP program controls a running \fIxscreensaver\fP
+process by sending it client-messages.
+.SH OPTIONS
+.I xscreensaver-command
+accepts the following options:
+.TP 8
+.B \-activate
+Tell the screensaver to turn on immediately (that is, pretend that the 
+user been idle for long enough.)  It will turn off as soon as there is
+any user activity, as usual.
+
+It is useful to run this from a menu; you may wish to run it as
+.EX
+sleep 5 ; xscreensaver-command -activate
+.EE
+to be sure that you have time to remove your hand from the mouse before
+the screensaver comes on.
+.TP 8
+.B \-deactivate
+Tell the screensaver to turn off, as if there had been user activity.
+If locking is enabled, then the screensaver will prompt for a password
+as usual.
+.TP 8
+.B \-cycle
+Tell the screensaver to change which graphics hack it is running, just
+as if the ``cycle'' timer had expired.
+.TP 8
+.B \-next
+This is like either \fI\-activate\fP or \fI\-cycle\fP, depending on which is
+more appropriate, except that the screenhack that will be run is the next
+one in the list of programs, instead of a randomly-chosen one.  This option
+is good for looking at a demo of each of the screensavers currently available.
+You might want to put this on a menu.
+.TP 8
+.B \-prev
+This is like \fI\-next\fP, but cycles in the other direction.
+.TP 8
+.B \-demo
+Cause the screensaver to enter its interactive demo mode, if it has been
+compiled with support for it.
+.TP 8
+.B \-lock
+Like \fI\-activate\fP, but a password will be required before the screensaver
+turns off, even if the screensaver's \fIlock\fP resource is false.  The 
+display will be locked immediately even if the screensaver's \fIlockTimeout\fP
+resource is non-zero.
+.TP 8
+.B \-exit
+Causes the screensaver process to exit gracefully.  This is a slightly
+safer way to kill the screensaver than by using \fIkill\fP.  
+
+Never use \fIkill -9\fP with \fIxscreensaver\fP while the screensaver is
+active.  If you are using a virtual root window manager, that can leave
+things in an inconsistent state, and you may need to restart your window
+manager to repair the damage.
+.TP 8
+.B \-restart
+Causes the screensaver process to exit and then restart with the same command
+line arguments.  This is a good way of causing the screensaver to re-read the
+resource database.
+
+If the screensaver is run from \fIxdm(1)\fP (that is, it is already running
+before you log in) then you may want to issue the ``restart'' command from 
+one of your startup scripts, so that the screensaver gets your resource
+settings instead of the default ones.
+.SH ENVIRONMENT
+.PP
+.TP 8
+.B DISPLAY
+to get the default host and display number.
+.TP 8
+.B PATH
+to find the executable to restart.
+.SH "SEE ALSO"
+.BR X (1),
+.BR xscreensaver (1)
+.SH BUGS
+Diagnostics are reported on the \fBstderr\fP of the \fIxscreensaver\fP
+process, not this process, so the caller of \fIxscreensaver-command\fP
+may not see the error messages.
+.SH COPYRIGHT
+Copyright \(co 1992, 1993 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
+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.
+.SH AUTHOR
+Jamie Zawinski <jwz@lucid.com>, 13-aug-92.
diff --git a/driver/xscreensaver.c b/driver/xscreensaver.c
new file mode 100644 (file)
index 0000000..54aee1d
--- /dev/null
@@ -0,0 +1,896 @@
+/* xscreensaver, Copyright (c) 1991-1993 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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 "version.h"
+
+/*   ========================================================================
+ *   First we wait until the keyboard and mouse become idle for the specified
+ *   amount of time.  We do this by periodically checking with the XIdle
+ *   server extension.
+ *
+ *   Then, we map a full screen black window.  
+ *
+ *   We place a __SWM_VROOT property on this window, so that newly-started
+ *   clients will think that this window is a "virtual root" window.
+ *
+ *   If there is an existing "virtual root" window (one that already had
+ *   an __SWM_VROOT property) then we remove that property from that window.
+ *   Otherwise, clients would see that window (the real virtual root) instead
+ *   of ours (the impostor.)
+ *
+ *   Then we pick a random program to run, and start it.  Two assumptions 
+ *   are made about this program: that it has been specified with whatever
+ *   command-line options are necessary to make it run on the root window;
+ *   and that it has been compiled with vroot.h, so that it is able to find
+ *   the root window when a virtual-root window manager (or this program) is
+ *   running.
+ *
+ *   Then, we wait for keyboard or mouse events to be generated on the window.
+ *   When they are, we kill the inferior process, unmap the window, and restore
+ *   the __SWM_VROOT property to the real virtual root window if there was one.
+ *
+ *   While we are waiting, we also set up timers so that, after a certain 
+ *   amount of time has passed, we can start a different screenhack.  We do
+ *   this by killing the running child process with SIGTERM, and then starting
+ *   a new one in the same way.
+ *
+ *   If there was a real virtual root, meaning that we removed the __SWM_VROOT
+ *   property from it, meaning we must (absolutely must) restore it before we
+ *   exit, then we set up signal handlers for most signals (SIGINT, SIGTERM,
+ *   etc.) that do this.  Most Xlib and Xt routines are not reentrant, so it
+ *   is not generally safe to call them from signal handlers; however, this
+ *   program spends most of its time waiting, so the window of opportunity 
+ *   when code could be called reentrantly is fairly small; and also, the worst
+ *   that could happen is that the call would fail.  If we've gotten one of
+ *   these signals, then we're on our way out anyway.  If we didn't restore the
+ *   __SWM_VROOT property, that would be very bad, so it's worth a shot.  Note
+ *   that this means that, if you're using a virtual-root window manager, you
+ *   can really fuck up the world by killing this process with "kill -9".
+ *
+ *   This program accepts ClientMessages of type SCREENSAVER; these messages
+ *   may contain the atom ACTIVATE or DEACTIVATE, meaning to turn the 
+ *   screensaver on or off now, regardless of the idleness of the user,
+ *   and a few other things.  The included "xscreensaver_command" program
+ *   sends these messsages.
+ *
+ *   If we don't have the XIdle extension, then we do the XAutoLock trick:
+ *   notice every window that gets created, and wait 30 seconds or so until
+ *   its creating process has settled down, and then select KeyPress events on
+ *   those windows which already select for KeyPress events.  It's important
+ *   that we not select KeyPress on windows which don't select them, because
+ *   that would interfere with event propagation.  This will break if any
+ *   program changes its event mask to contain KeyRelease or PointerMotion
+ *   more than 30 seconds after creating the window, but that's probably
+ *   pretty rare.
+ *   
+ *   The reason that we can't select KeyPresses on windows that don't have
+ *   them already is that, when dispatching a KeyPress event, X finds the
+ *   lowest (leafmost) window in the hierarchy on which *any* client selects
+ *   for KeyPress, and sends the event to that window.  This means that if a
+ *   client had a window with subwindows, and expected to receive KeyPress
+ *   events on the parent window instead of the subwindows, then that client
+ *   would malfunction if some other client selected KeyPress events on the
+ *   subwindows.  It is an incredible misdesign that one client can make
+ *   another client malfunction in this way.
+ *
+ *   To detect mouse motion, we periodically wake up and poll the mouse
+ *   position and button/modifier state, and notice when something has
+ *   changed.  We make this check every five seconds by default, and since the
+ *   screensaver timeout has a granularity of one minute, this makes the
+ *   chance of a false positive very small.  We could detect mouse motion in
+ *   the same way as keyboard activity, but that would suffer from the same
+ *   "client changing event mask" problem that the KeyPress events hack does.
+ *   I think polling is more reliable.
+ *
+ *   None of this crap happens if we're using the XIdle extension, so install
+ *   it if the description above sounds just too flaky to live.  It is, but
+ *   those are your choices.
+ *
+ *   Debugging hints:
+ *     - Have a second terminal handy.
+ *     - Be careful where you set your breakpoints, you don't want this to
+ *       stop under the debugger with the keyboard grabbed or the blackout
+ *       window exposed.
+ *     - you probably can't set breakpoints in functions that are called on
+ *       the other side of a call to fork() -- if your clients are dying 
+ *       with signal 5, Trace/BPT Trap, you're losing in this way.
+ *     - If you aren't using XIdle, don't leave this stopped under the
+ *       debugger for very long, or the X input buffer will get huge because
+ *       of the keypress events it's selecting for.  This can make your X
+ *       server wedge with "no more input buffers."
+ *       
+ *   ========================================================================
+ */
+
+#if __STDC__
+#include <stdlib.h>
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/Intrinsic.h>
+#include <X11/Xos.h>
+
+#ifdef HAVE_XIDLE
+#include <X11/extensions/xidle.h>
+#endif
+
+#include "xscreensaver.h"
+
+#if defined(SVR4) || defined(SYSV)
+# define srandom(i) srand((unsigned int)(i))
+#else
+extern void srandom P((int));          /* srand() is in stdlib.h... */
+#endif
+
+extern char *get_string_resource P((char *, char *));
+extern Bool get_boolean_resource P((char *, char *));
+extern int get_integer_resource P((char *, char *));
+extern unsigned int get_minutes_resource P((char *, char *));
+extern unsigned int get_seconds_resource P((char *, char *));
+
+extern Visual *get_visual_resource P((Display *, char *, char *));
+extern int get_visual_depth P((Display *, Visual *));
+
+extern void notice_events_timer P((XtPointer closure, void *timer));
+extern void cycle_timer P((void *junk1, XtPointer junk2));
+extern void activate_lock_timer P((void *junk1, XtPointer junk2));
+extern void sleep_until_idle P((Bool until_idle_p));
+
+extern void ensure_no_screensaver_running P((void));
+extern void initialize_screensaver_window P((void));
+extern void disable_builtin_screensaver P((void));
+
+extern void hack_environment P((void));
+extern void grab_keyboard_and_mouse P((void));
+extern void ungrab_keyboard_and_mouse P((void));
+
+extern void save_argv P((int argc, char **argv));
+
+
+char *screensaver_version;
+char *progname;
+char *progclass;
+XrmDatabase db;
+
+XtAppContext app;
+
+Display *dpy;
+Screen *screen;
+Visual *visual;
+int visual_depth;
+
+Widget toplevel_shell;
+
+Time lock_timeout;
+
+extern Time timeout;
+extern Time cycle;
+extern Time passwd_timeout;
+extern Time pointer_timeout;
+extern Time notice_events_timeout;
+extern XtIntervalId lock_id, cycle_id;
+
+Bool use_xidle;
+Bool verbose_p;
+Bool lock_p, locked_p;
+
+extern char **screenhacks;
+extern int screenhacks_count;
+extern char *shell;
+extern int nice_inferior;
+extern Window screensaver_window;
+extern Cursor cursor;
+extern Colormap cmap, cmap2;
+extern Bool fade_p, unfade_p;
+extern int fade_seconds, fade_ticks;
+extern Bool install_cmap_p;
+extern Bool locking_disabled_p;
+extern Bool demo_mode_p;
+extern Bool dbox_up_p;
+extern int next_mode_p;
+
+static time_t initial_delay;
+
+extern Atom XA_VROOT, XA_XSETROOT_ID;
+extern Atom XA_SCREENSAVER_VERSION, XA_SCREENSAVER_ID;
+
+static Atom XA_SCREENSAVER;
+static Atom XA_ACTIVATE, XA_DEACTIVATE, XA_CYCLE, XA_NEXT, XA_PREV;
+static Atom XA_EXIT, XA_RESTART, XA_DEMO, XA_LOCK;
+
+#ifdef NO_MOTIF /* kludge */
+Bool demo_mode_p = 0;
+Bool dbox_up_p = 0;
+Time passwd_timeout = 0;
+#endif
+
+\f
+#ifdef NO_DEMO_MODE
+# define demo_mode() abort()
+#else
+extern void demo_mode P((void));
+#endif
+\f
+static XrmOptionDescRec options [] = {
+  { "-timeout",                ".timeout",     XrmoptionSepArg, 0 },
+  { "-idelay",         ".initialDelay",XrmoptionSepArg, 0 },
+  { "-cycle",          ".cycle",       XrmoptionSepArg, 0 },
+  { "-visual",         ".visual",      XrmoptionSepArg, 0 },
+  { "-lock-timeout",   ".lockTimeout", XrmoptionSepArg, 0 },
+  { "-verbose",                ".verbose",     XrmoptionNoArg, "on" },
+  { "-silent",         ".verbose",     XrmoptionNoArg, "off" },
+  { "-xidle",          ".xidle",       XrmoptionNoArg, "on" },
+  { "-no-xidle",       ".xidle",       XrmoptionNoArg, "off" },
+  { "-lock",           ".lock",        XrmoptionNoArg, "on" },
+  { "-no-lock",                ".lock",        XrmoptionNoArg, "off" }
+};
+
+static char *defaults[] = {
+#include "XScreenSaver.ad.h"
+ 0
+};
+
+static void
+do_help ()
+{
+  printf ("\
+xscreensaver %s, copyright (c) 1991-1993 by Jamie Zawinski <jwz@lucid.com>.\n\
+The standard Xt command-line options are accepted; other options include:\n\
+\n\
+    -timeout <minutes>         when the screensaver should activate\n\
+    -cycle <minutes>           how long to let each hack run\n\
+    -idelay <seconds>          how long to sleep before startup\n\
+    -demo                      enter interactive demo mode on startup\n\
+    -verbose                   be loud\n\
+    -silent                    don't\n\
+    -xidle                     use the XIdle server extension\n\
+    -no-xidle                  don't\n\
+    -lock                      require a password before deactivating\n\
+    -no-lock                   don't\n\
+    -lock-timeout <minutes>    grace period before locking; default 0\n\
+    -help                      this message\n\
+\n\
+Use the `xscreensaver-command' program to control a running screensaver.\n\
+\n\
+The *programs, *colorPrograms, and *monoPrograms resources control which\n\
+graphics demos will be launched by the screensaver.  See the man page for\n\
+more details.\n\n",
+         screensaver_version);
+
+#ifdef NO_LOCKING
+  printf("Support for locking was not enabled at compile-time.\n");
+#endif
+#ifdef NO_DEMO_MODE
+  printf("Support for demo mode was not enabled at compile-time.\n");
+#endif
+#ifndef HAVE_XIDLE
+  printf("Support for the XIdle extension was not enabled at compile-time.\n");
+#endif
+
+  fflush (stdout);
+  exit (1);
+}
+
+
+static void
+get_screenhacks ()
+{
+  char *data[3];
+  int i, hacks_size = 10;
+
+  data[0] = get_string_resource ("programs", "Programs");
+  data[1] = ((CellsOfScreen (screen) <= 2)
+            ? get_string_resource ("monoPrograms", "MonoPrograms")
+            : get_string_resource ("colorPrograms", "ColorPrograms"));
+  data[2] = 0;
+  if (! data[0]) data[0] = data[1], data[1] = 0;
+
+  screenhacks = (char **) malloc (sizeof (char *) * hacks_size);
+  screenhacks_count = 0;
+
+  for (i = 0; data[i]; i++)
+    {
+      int j = 0;
+      char *d = data [i];
+      int size = strlen (d);
+      while (j < size)
+       {
+         int end, start = j;
+         if (d[j] == ' ' || d[j] == '\t' || d[j] == '\n' || d[j] == 0)
+           {
+             j++;
+             continue;
+           }
+         if (hacks_size <= screenhacks_count)
+           screenhacks = (char **) realloc (screenhacks,
+                                            (hacks_size = hacks_size * 2) *
+                                            sizeof (char *));
+         screenhacks [screenhacks_count++] = d + j;
+         while (d[j] != 0 && d[j] != '\n')
+           j++;
+         end = j;
+         while (j > start && (d[j-1] == ' ' || d[j-1] == '\t'))
+           j--;
+         d[j] = 0;
+         j = end + 1;
+       }
+    }
+
+  /* shrink all whitespace to one space, for the benefit of the "demo"
+     mode display.  We only do this when we can easily tell that the
+     whitespace is not significant (no shell metachars).
+   */
+  for (i = 0; i < screenhacks_count; i++)
+    {
+      char *s = screenhacks [i];
+      char *s2;
+      int L = strlen (s);
+      int j, k;
+      for (j = 0; j < L; j++)
+       {
+         switch (s[j])
+           {
+           case '\'': case '"': case '`': case '\\':
+             goto DONE;
+           case '\t':
+             s[j] = ' ';
+           case ' ':
+             k = 0;
+             for (s2 = s+j+1; *s2 == ' ' || *s2 == '\t'; s2++)
+               k++;
+             if (k > 0)
+               for (s2 = s + j + 1; *s2; s2++)
+                 s2 [0] = s2 [k];
+             break;
+           }
+       }
+    DONE:
+      ;
+    }
+
+  if (screenhacks_count)
+    {
+      /* Shrink down the screenhacks array to be only as big as it needs to.
+        This doesn't really matter at all. */
+      screenhacks = (char **)
+       realloc (screenhacks, ((screenhacks_count + 1) * sizeof(char *)));
+      screenhacks [screenhacks_count] = 0;
+    }
+  else
+    {
+      free (screenhacks);
+      screenhacks = 0;
+    }
+}
+
+
+static void
+get_resources ()
+{
+  visual         = get_visual_resource (dpy, "visual", "Visual");
+  timeout         = 1000 * get_minutes_resource ("timeout", "Time");
+  cycle           = 1000 * get_minutes_resource ("cycle",   "Time");
+  lock_timeout   = 1000 * get_minutes_resource ("lockTimeout", "Time");
+  nice_inferior   = get_integer_resource ("nice", "Nice");
+  verbose_p       = get_boolean_resource ("verbose", "Boolean");
+  lock_p          = get_boolean_resource ("lock", "Boolean");
+  install_cmap_p  = get_boolean_resource ("installColormap", "Boolean");
+  fade_p         = get_boolean_resource ("fade", "Boolean");
+  unfade_p       = get_boolean_resource ("unfade", "Boolean");
+  fade_seconds   = get_seconds_resource ("fadeSeconds", "Time");
+  fade_ticks     = get_integer_resource ("fadeTicks", "Integer");
+  shell           = get_string_resource ("bourneShell", "BourneShell");
+  initial_delay   = get_seconds_resource ("initialDelay", "Time");
+  passwd_timeout  = 1000 * get_seconds_resource ("passwdTimeout", "Time");
+  pointer_timeout = 1000 * get_seconds_resource ("pointerPollTime", "Time");
+  notice_events_timeout = 1000 * get_seconds_resource ("windowCreationTimeout",
+                                                      "Time");
+  if (timeout < 10000) timeout = 10000;
+  if (cycle < 2000) cycle = 2000;
+  if (passwd_timeout == 0) passwd_timeout = 30000;
+  if (pointer_timeout == 0) pointer_timeout = 5000;
+  if (notice_events_timeout == 0) notice_events_timeout = 10000;
+  if (fade_seconds == 0 || fade_ticks == 0) fade_p = False;
+  if (! fade_p) unfade_p = False;
+
+  visual_depth = get_visual_depth (dpy, visual);
+
+  if (visual_depth <= 1 || CellsOfScreen (screen) <= 2)
+    install_cmap_p = False;
+
+#ifdef NO_LOCKING
+  locking_disabled_p = True;
+  if (lock_p)
+    {
+      lock_p = False;
+      fprintf (stderr, "%s: %snot compiled with support for locking.\n",
+              progname, (verbose_p ? "## " : ""));
+    }
+#else  /* ! NO_LOCKING */
+  if (lock_p && locking_disabled_p)
+    {
+      fprintf (stderr, "%s: %slocking is disabled.\n", progname,
+              (verbose_p ? "## " : ""));
+      lock_p = False;
+    }
+#endif /* ! NO_LOCKING */
+
+  /* don't set use_xidle unless it is explicitly specified */
+  if (get_string_resource ("xidle", "Boolean"))
+    use_xidle = get_boolean_resource ("xidle", "Boolean");
+  else
+#ifdef HAVE_XIDLE      /* pick a default */
+    use_xidle = True;
+#else
+    use_xidle = False;
+#endif
+  get_screenhacks ();
+}
+
+char *
+timestring ()
+{
+  long now = time ((time_t *) 0);
+  char *str = (char *) ctime (&now);
+  char *nl = (char *) strchr (str, '\n');
+  if (nl) *nl = 0; /* take off that dang newline */
+  return str;
+}
+
+#ifdef NO_SETUID
+# define hack_uid()
+# define hack_uid_warn()
+#else /* !NO_SETUID */
+extern void hack_uid P((void));
+extern void hack_uid_warn P((void));
+#endif /* NO_SETUID */
+
+
+#ifndef NO_LOCKING
+extern Bool unlock_p P((Widget));
+extern Bool lock_init P((void));
+#endif
+
+static void initialize ();
+static void main_loop ();
+static void initialize ();
+
+void
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  initialize (argc, argv);
+  main_loop ();
+}
+
+
+static void
+initialize_connection (argc, argv)
+     int argc;
+     char **argv;
+{
+  toplevel_shell = XtAppInitialize (&app, progclass,
+                                   options, XtNumber (options),
+                                   &argc, argv, defaults, 0, 0);
+
+  dpy = XtDisplay (toplevel_shell);
+  screen = XtScreen (toplevel_shell);
+  db = XtDatabase (dpy);
+  XtGetApplicationNameAndClass (dpy, &progname, &progclass);
+
+  if (argc == 2 && !strcmp (argv[1], "-help"))
+    do_help ();
+  else if (argc > 1)
+    {
+      fprintf (stderr, "%s: unknown option %s\n", progname, argv [1]);
+      exit (1);
+    }
+  get_resources ();
+  hack_uid_warn ();
+  hack_environment ();
+  XA_VROOT = XInternAtom (dpy, "__SWM_VROOT", False);
+  XA_SCREENSAVER = XInternAtom (dpy, "SCREENSAVER", False);
+  XA_SCREENSAVER_VERSION = XInternAtom (dpy, "_SCREENSAVER_VERSION", False);
+  XA_SCREENSAVER_ID = XInternAtom (dpy, "_SCREENSAVER_ID", False);
+  XA_XSETROOT_ID = XInternAtom (dpy, "_XSETROOT_ID", False);
+  XA_ACTIVATE = XInternAtom (dpy, "ACTIVATE", False);
+  XA_DEACTIVATE = XInternAtom (dpy, "DEACTIVATE", False);
+  XA_RESTART = XInternAtom (dpy, "RESTART", False);
+  XA_CYCLE = XInternAtom (dpy, "CYCLE", False);
+  XA_NEXT = XInternAtom (dpy, "NEXT", False);
+  XA_PREV = XInternAtom (dpy, "PREV", False);
+  XA_EXIT = XInternAtom (dpy, "EXIT", False);
+  XA_DEMO = XInternAtom (dpy, "DEMO", False);
+  XA_LOCK = XInternAtom (dpy, "LOCK", False);
+}
+
+extern void init_sigchld P((void));
+
+static void
+initialize (argc, argv)
+     int argc;
+     char **argv;
+{
+  Bool initial_demo_mode_p = False;
+  screensaver_version = (char *) malloc (5);
+  memcpy (screensaver_version, screensaver_id + 17, 4);
+  screensaver_version [4] = 0;
+  progname = argv[0]; /* reset later; this is for the benefit of lock_init() */
+
+#ifdef NO_LOCKING
+  locking_disabled_p = True;
+#else
+  locking_disabled_p = False;
+  if (! lock_init ())  /* before hack_uid() for proper permissions */
+    locking_disabled_p = True;
+#endif
+
+  hack_uid ();
+  progclass = "XScreenSaver";
+
+  /* remove -demo switch before saving argv */
+  {
+    int i;
+    for (i = 1; i < argc; i++)
+      while (!strcmp ("-demo", argv [i]))
+       {
+         int j;
+         initial_demo_mode_p = True;
+         for (j = i; j < argc; j++)
+           argv [j] = argv [j+1];
+         argv [j] = 0;
+         argc--;
+         if (argc <= i) break;
+       }
+  }
+  save_argv (argc, argv);
+  initialize_connection (argc, argv);
+
+  ensure_no_screensaver_running ();
+  demo_mode_p = initial_demo_mode_p;
+  screensaver_window = 0;
+  cursor = 0;
+  initialize_screensaver_window ();
+  srandom ((int) time ((time_t *) 0));
+  cycle_id = 0;
+  lock_id = 0;
+  locked_p = False;
+  if (use_xidle)
+    {
+#ifdef HAVE_XIDLE
+      int first_event, first_error;
+      if (! XidleQueryExtension (dpy, &first_event, &first_error))
+       {
+         fprintf (stderr,
+                  "%s: display %s does not support the XIdle extension.\n",
+                  progname, DisplayString (dpy));
+         use_xidle = 0;
+       }
+#else
+      fprintf (stderr, "%s: not compiled with support for XIdle.\n",
+              progname);
+      use_xidle = 0;
+#endif
+    }
+
+  init_sigchld ();
+
+  if (verbose_p)
+    printf ("\
+%s %s, copyright (c) 1991-1993 by Jamie Zawinski <jwz@lucid.com>.\n\
+ pid = %d.\n", progname, screensaver_version, getpid ());
+
+  disable_builtin_screensaver ();
+
+  if (initial_demo_mode_p)
+    /* If the user wants demo mode, don't wait around before doing it. */
+    initial_delay = 0;
+
+#ifdef HAVE_XIDLE
+  if (! use_xidle)
+#endif
+    {
+      if (initial_delay)
+       {
+         if (verbose_p)
+           {
+             printf ("%s: waiting for %d second%s...", progname,
+                     initial_delay, (initial_delay == 1 ? "" : "s"));
+             fflush (stdout);
+           }
+         sleep (initial_delay);
+         if (verbose_p)
+           printf (" done.\n");
+       }
+      if (verbose_p)
+       {
+         printf ("%s: selecting events on extant windows...", progname);
+         fflush (stdout);
+       }
+      notice_events_timer ((XtPointer)
+                          RootWindowOfScreen (XtScreen (toplevel_shell)),
+                          0);
+      if (verbose_p)
+       printf (" done.\n");
+    }
+}
+
+
+extern void suspend_screenhack P((Bool suspend_p));
+
+static void
+main_loop ()
+{
+  while (1)
+    {
+      if (! demo_mode_p)
+       sleep_until_idle (True);
+
+      if (demo_mode_p)
+       demo_mode ();
+      else
+       {
+         if (verbose_p)
+           printf ("%s: user is idle; waking up at %s.\n", progname,
+                   timestring());
+         blank_screen ();
+         spawn_screenhack (True);
+         if (cycle)
+           cycle_id = XtAppAddTimeOut (app, cycle, cycle_timer, 0);
+
+#ifndef NO_LOCKING
+         if (lock_p && lock_timeout == 0)
+           locked_p = True;
+         if (lock_p && !locked_p)
+           /* locked_p might be true already because of ClientMessage */
+           lock_id = XtAppAddTimeOut (app,lock_timeout,activate_lock_timer,0);
+#endif
+
+       PASSWD_INVALID:
+
+         sleep_until_idle (False); /* until not idle */
+
+#ifndef NO_LOCKING
+         if (locked_p)
+           {
+             Bool val;
+             if (locking_disabled_p) abort ();
+             dbox_up_p = True;
+             ungrab_keyboard_and_mouse ();
+             suspend_screenhack (True);
+             XUndefineCursor (dpy, screensaver_window);
+             if (verbose_p)
+               printf ("%s: prompting for password.\n", progname);
+             val = unlock_p (toplevel_shell);
+             if (verbose_p && val == False)
+               printf ("%s: password incorrect!\n", progname);
+             dbox_up_p = False;
+             XDefineCursor (dpy, screensaver_window, cursor);
+             suspend_screenhack (False);
+             grab_keyboard_and_mouse ();
+             if (! val)
+               goto PASSWD_INVALID;
+             locked_p = False;
+           }
+#endif
+         unblank_screen ();
+         kill_screenhack ();
+         if (cycle_id)
+           {
+             XtRemoveTimeOut (cycle_id);
+             cycle_id = 0;
+           }
+#ifndef NO_LOCKING
+         if (lock_id)
+           {
+             XtRemoveTimeOut (lock_id);
+             lock_id = 0;
+           }
+#endif
+         if (verbose_p)
+           printf ("%s: user is active; going to sleep at %s.\n", progname,
+                   timestring ());
+       }
+    }
+}
+
+\f
+
+Bool
+handle_clientmessage (event, until_idle_p)
+     XEvent *event;
+     Bool until_idle_p;
+{
+  Atom type;
+  if (event->xclient.message_type != XA_SCREENSAVER)
+    {
+      char *str;
+      str = XGetAtomName (dpy, event->xclient.message_type);
+      fprintf (stderr, "%s: %sunrecognised ClientMessage type %s received\n",
+              progname, (verbose_p ? "## " : ""),
+              (str ? str : "(null)"));
+      if (str) XFree (str);
+    }
+  if (event->xclient.format != 32)
+    {
+      fprintf (stderr, "%s: %sClientMessage of format %d received, not 32\n",
+              progname, (verbose_p ? "## " : ""), event->xclient.format);
+    }
+  type = event->xclient.data.l[0];
+  if (type == XA_ACTIVATE)
+    {
+      if (until_idle_p)
+       {
+         if (verbose_p)
+           printf ("%s: ACTIVATE ClientMessage received.\n", progname);
+         return True;
+       }
+      fprintf (stderr,
+              "%s: %sClientMessage ACTIVATE received while already active.\n",
+              progname, (verbose_p ? "## " : ""));
+    }
+  else if (type == XA_DEACTIVATE)
+    {
+      if (! until_idle_p)
+       {
+         if (verbose_p)
+           printf ("%s: DEACTIVATE ClientMessage received.\n", progname);
+         return True;
+       }
+      fprintf (stderr,
+              "%s: %sClientMessage DEACTIVATE received while inactive.\n",
+              progname, (verbose_p ? "## " : ""));
+    }
+  else if (type == XA_CYCLE)
+    {
+      if (! until_idle_p)
+       {
+         if (verbose_p)
+           printf ("%s: CYCLE ClientMessage received.\n", progname);
+         if (cycle_id)
+           XtRemoveTimeOut (cycle_id);
+         cycle_id = 0;
+         cycle_timer (0, 0);
+         return False;
+       }
+      fprintf (stderr,
+              "%s: %sClientMessage CYCLE received while inactive.\n",
+              progname, (verbose_p ? "## " : ""));
+    }
+  else if (type == XA_NEXT || type == XA_PREV)
+    {
+      if (verbose_p)
+       printf ("%s: %s ClientMessage received.\n", progname,
+               (type == XA_NEXT ? "NEXT" : "PREV"));
+      next_mode_p = 1 + (type == XA_PREV);
+
+      if (! until_idle_p)
+       {
+         if (cycle_id)
+           XtRemoveTimeOut (cycle_id);
+         cycle_id = 0;
+         cycle_timer (0, 0);
+       }
+      else
+       return True;
+    }
+  else if (type == XA_EXIT)
+    {
+      /* Ignore EXIT message if the screen is locked. */
+      if (until_idle_p || !locked_p)
+       {
+         if (verbose_p)
+           printf ("%s: EXIT ClientMessage received.\n", progname);
+         if (! until_idle_p)
+           {
+             unblank_screen ();
+             kill_screenhack ();
+             XSync (dpy, False);
+           }
+         exit (0);
+       }
+      else
+       fprintf (stderr, "%s: %sEXIT ClientMessage received while locked.\n",
+                progname, (verbose_p ? "## " : ""));
+    }
+  else if (type == XA_RESTART)
+    {
+      /* The RESTART message works whether the screensaver is active or not,
+        unless the screen is locked, in which case it doesn't work.
+       */
+      if (until_idle_p || !locked_p)
+       {
+         if (verbose_p)
+           printf ("%s: RESTART ClientMessage received.\n", progname);
+         if (! until_idle_p)
+           {
+             unblank_screen ();
+             kill_screenhack ();
+             XSync (dpy, False);
+           }
+         restart_process ();
+       }
+      else
+       fprintf(stderr, "%s: %sRESTART ClientMessage received while locked.\n",
+               progname, (verbose_p ? "## " : ""));
+    }
+  else if (type == XA_DEMO)
+    {
+#ifdef NO_DEMO_MODE
+      fprintf (stderr,
+              "%s: %snot compiled with support for DEMO mode\n",
+              progname, (verbose_p ? "## " : ""));
+#else
+      if (until_idle_p)
+       {
+         if (verbose_p)
+           printf ("%s: DEMO ClientMessage received.\n", progname);
+         demo_mode_p = True;
+         return True;
+       }
+      fprintf (stderr,
+              "%s: %sDEMO ClientMessage received while active.\n",
+              progname, (verbose_p ? "## " : ""));
+#endif
+    }
+  else if (type == XA_LOCK)
+    {
+#ifdef NO_LOCKING
+      fprintf (stderr, "%s: %snot compiled with support for LOCK mode\n",
+              progname, (verbose_p ? "## " : ""));
+#else
+      if (locking_disabled_p)
+       fprintf (stderr,
+              "%s: %sLOCK ClientMessage received, but locking is disabled.\n",
+                progname, (verbose_p ? "## " : ""));
+      else if (locked_p)
+       fprintf (stderr,
+              "%s: %sLOCK ClientMessage received while already locked.\n",
+                progname, (verbose_p ? "## " : ""));
+      else
+       {
+         locked_p = True;
+         if (verbose_p) 
+           printf ("%s: LOCK ClientMessage received;%s locking.\n",
+                   progname, until_idle_p ? " activating and" : "");
+
+         if (lock_id)  /* we're doing it now, so lose the timeout */
+           {
+             XtRemoveTimeOut (lock_id);
+             lock_id = 0;
+           }
+
+         if (until_idle_p)
+           return True;
+       }
+#endif
+    }
+  else
+    {
+      char *str;
+      str = XGetAtomName (dpy, type);
+      if (str)
+       fprintf (stderr,
+                "%s: %sunrecognised screensaver ClientMessage %s received\n",
+                progname, (verbose_p ? "## " : ""), str);
+      else
+       fprintf (stderr,
+                "%s: %sunrecognised screensaver ClientMessage 0x%x received\n",
+                progname, (verbose_p ? "## " : ""),
+                event->xclient.data.l[0]);
+      if (str) XFree (str);
+    }
+  return False;
+}
diff --git a/driver/xscreensaver.h b/driver/xscreensaver.h
new file mode 100644 (file)
index 0000000..7bdc776
--- /dev/null
@@ -0,0 +1,55 @@
+/* xscreensaver, Copyright (c) 1993 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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.
+ */
+
+#if __STDC__
+# include <stdlib.h>
+# include <unistd.h>
+#endif
+
+#if __STDC__
+# define P(x)x
+#else
+# define P(x)()
+#endif
+
+#ifdef NO_MOTIF
+# define NO_DEMO_MODE
+# ifndef NO_LOCKING
+#  define NO_LOCKING
+# endif
+#endif
+
+extern char *progname, *progclass;
+extern char *screensaver_version;
+
+extern Display *dpy;
+extern Screen *screen;
+extern Visual *visual;
+extern int visual_depth;
+
+extern Bool verbose_p;
+
+extern void initialize_screensaver_window P(());
+extern void raise_window P((Bool inhibit_fade, Bool between_hacks_p));
+extern void blank_screen P(());
+extern void unblank_screen P((void));
+extern void restart_process P((void));
+
+extern void restore_real_vroot P((void));
+
+extern void spawn_screenhack P((Bool));
+extern void kill_screenhack P((void));
+
+extern Colormap copy_colormap P((Display *, Colormap, Colormap));
+extern void fade_colormap P((Display*, Colormap, Colormap, int, int, Bool));
+extern void blacken_colormap P((Display *, Colormap));
+
+extern int BadWindow_ehandler P((Display *dpy, XErrorEvent *error));
diff --git a/driver/xscreensaver.man b/driver/xscreensaver.man
new file mode 100644 (file)
index 0000000..a524d02
--- /dev/null
@@ -0,0 +1,442 @@
+.de EX         \"Begin example
+.ne 5
+.if n .sp 1
+.if t .sp .5
+.nf
+.in +.5i
+..
+.de EE
+.fi
+.in -.5i
+.if n .sp 1
+.if t .sp .5
+..
+.TH XScreenSaver 1 "22-mar-93" "X Version 11"
+.SH NAME
+xscreensaver - run graphics hacks after the user has been idle for a while
+.SH SYNOPSIS
+.B xscreensaver
+[\-display \fIhost:display.screen\fP] [\-timeout \fIint\fP] [\-cycle \fIint\fP] [\-nice \fIint\fP] [\-verbose] [\-silent] [\-xidle] [\-no-xidle] [\-lock] [\-no-lock] [\-lock\-timeout \fIint\fP] [\-demo] [\-xrm \fIresources\fP]
+.SH DESCRIPTION
+The \fIxscreensaver\fP program waits until the keyboard and mouse have been 
+idle for a period, and then runs a graphics demo chosen at random.  It 
+turns off as soon as there is any mouse or keyboard activity.
+
+This program can lock your terminal in order to prevent others from using it,
+though its default mode of operation is merely to display pretty pictures on
+your screen when it is not in use.  
+
+The benefit that this program has over the combination of the
+.BR xlock (1)
+and
+.BR xautolock (1)
+programs is the ease with which new graphics hacks can be installed.  You
+don't need to recompile (or even re-run) this program to add a new display
+mode.
+.SH OPTIONS
+.I xscreensaver
+accepts the following options:
+.TP 8
+.B \-timeout \fIminutes\fP
+The screensaver will activate after the keyboard and mouse have been idle
+for this many minutes.
+.TP 8
+.B \-cycle \fIminutes\fP
+After the screensaver has been running for this many minutes, the currently
+running sub-process will be killed (with \fBSIGTERM\fP), and a new one 
+started.  If this is 0, then the sub-process will not be killed; only one
+demo will run until the screensaver is deactivated by user activity.
+.TP 8
+.B \-nice \fIinteger\fP
+The sub-processes created by \fIxscreensaver\fP will be ``niced'' to this
+level, so that they do not consume cycles that are needed elsewhere.
+.TP 8
+.B \-verbose
+Print diagnostics.
+.TP 8
+.B \-silent
+
+.TP 8
+.B \-xidle
+Use the \fIXIdle\fP server extension to decide whether the user is idle.
+This is the default if \fIxscreensaver\fP has been compiled with support
+for XIdle.  The XIdle method is faster and more reliable than what will
+be done otherwise, so use it if you can.  
+.TP 8
+.B \-no\-xidle
+Don't use \fIXIdle\fP.
+.TP 8
+.B \-lock
+Enable locking: before the screensaver will turn off, it requires you to
+type the password of the person who launched the screensaver, or the root
+password.  (Note: this doesn't work if the screensaver is launched
+by
+.BR xdm (1)
+because it can't know the user-id of the logged-in user.)
+.TP 8
+.B \-no\-lock
+Disable locking.  This is the default.
+.TP 8
+.B \-lock\-timeout \fIminutes\fP
+This is how long after the screensaver activates that locking is enabled.
+For example, if this is 5, then any user activity within five minutes of
+the time when the screensaver activated will cause the screen to unblank
+without requiring a password.  After 5 minutes, a password will be
+required.  The default is 0, meaning that if locking is enabled, then
+a password will be required as soon as the screensaver activates.
+.TP 8
+.B \-demo
+Enter the interactive demo mode immediately after startup.  Normally
+demo mode is invoked via the
+.BR xscreensaver\-command (1)
+program.
+.SH X RESOURCES
+\fIxscreensaver\fP understands the following resources:
+.PP
+.TP 8
+.B timeout \fR(class \fBTime\fP)
+Same as the \fI\-timeout\fP command-line option.  Default 10 minutes.
+.TP 8
+.B cycle \fR(class \fBTime\fP)
+Same as the \fI\-cycle\fP command-line option.  Default 10 minutes.
+.TP 8
+.B nice \fR(class \fBNice\fP)
+Same as the \fI\-nice\fP command-line option.  Default 10.
+.TP 8
+.B verbose \fR(class \fBBoolean\fP)
+Same as the \fI\-verbose\fP command-line option.
+.TP 8
+.B xidle \fR(class \fBBoolean\fP)
+Same as the \fI\-xidle\fP command-line option.
+.TP 8
+.B lock \fR(class \fBBoolean\fP)
+Same as the \fI\-lock\fP command-line option.
+.TP 8
+.B lockTimeout \fR(class \fBTime\fP)
+Same as the \fI\-lock\-timeout\fP command-line option.
+.TP 8
+.B fade \fR(class \fBBoolean\fP)
+If this is true, then when the screensaver activates, the current contents
+of the screen will fade to black instead of simply winking out.  This only
+works on displays with writable colormaps.  Default true.  A fade will also
+be done when switching graphics hacks (when the \fIcycle\fP timer expires.)
+.TP 8
+.B unfade \fR(class \fBBoolean\fP)
+If this is true, then when the screensaver deactivates, the original contents
+of the screen will fade in from black instead of appearing immediately.  This
+only works on displays with writable colormaps, and if \fIfade\fP is true
+as well.  Default false.
+.TP 8
+.B fadeSeconds \fR(class \fBTime\fP)
+If \fIfade\fP is true, this is how long the fade will be in 
+seconds (default 1.)
+.TP 8
+.B fadeTicks \fR(class \fBInteger\fP)
+If \fIfade\fP is true, this is how many times a second the colormap will
+be changed to effect a fade.  Higher numbers yield smoother fades, but
+may make the fades take longer if your server isn't fast enough to keep
+up.  Default 75.
+.TP 8
+.B installColormap \fR(class \fBBoolean\fP)
+Whether a new colormap should be installed while the screensaver is on,
+so that the graphics hacks can get as many colors as possible.  Default
+false.
+.TP 8
+.B passwdTimeout \fR(class \fBTime\fP)
+If \fIlock\fP is true, this is how many seconds the password dialog box
+should be left on the screen before giving up (default 30.)  This should
+not be too large: the X server is grabbed for the duration that the password
+dialog box is up (for security purposes) and leaving the server grabbed for
+too long can cause problems.
+.TP 8
+.B programs \fR(class \fBPrograms\fP)
+The graphics hacks which \fIxscreensaver\fP runs when the user is idle.
+The value of this resource is a string, one \fIsh\fP command per line.
+Each line must contain exactly one command -- no semicolons.
+
+When the screensaver starts up, one of these is selected at random, and
+run.  After the \fIcycle\fP period expires, it is killed, and another
+is selected and run.
+
+If the value of this resource (and the applicable one of \fBcolorPrograms\fP
+or \fBmonoPrograms\fP) is empty, then no programs will be run; the screen
+will simply be made black.
+
+Note that you must escape the newlines; here is an example of how you
+might set this in your \fI.Xdefaults\fP file:
+.EX
+xscreensaver.programs:  \\
+        qix -root                        \\n\\
+        ico -r -faces -sleep 1 -obj ico  \\n\\
+        xdaliclock -builtin2 -root       \\n\\
+        xwave -root
+.EE
+To use a program as a screensaver, two things are required: that that
+program draw on the root window (or be able to be configured to draw on
+the root window); and that that program understand ``virtual root''
+windows, as used by virtual window managers such as \fItvtwm\fP.
+
+It is quite easy to make programs understand virtual roots if they
+don't already: you merely need to include the file \fI"vroot.h"\fP in
+them after the standard X includes, and recompile.  This file is distributed
+with X11r5, and is included with xscreensaver as well.
+.TP 8
+.B monoPrograms \fR(class \fBMonoPrograms\fP)
+This resource is appended to the value of the \fIprograms\fP resource if
+the display on which the screensaver is running is monochrome.
+.TP 8
+.B colorPrograms \fR(class \fBColorPrograms\fP)
+This resource is appended to the value of the \fIprograms\fP resource if
+the display on which the screensaver is running is not monochrome.
+.PP
+Normally you won't need to change the following resources:
+.TP 8
+.B bourneShell \fR(class \fBBourneShell\fP)
+The pathname of the shell that \fIxscreensaver\fP uses to start subprocesses.
+This must be whatever your local variant of \fB/bin/sh\fP is -- in particular,
+it must not be \fBcsh\fP.
+.TP 8
+.B windowCreationTimeout \fR(class \fBTime\fP)
+When \fIXIdle\fP is not in use, this controls the delay between when 
+windows are created and when \fIxscreensaver\fP selects events on them.
+Default 30 seconds.
+.TP 8
+.B pointerPollTime \fR(class \fBTime\fP)
+When \fIXIdle\fP is not in use, this controls how frequently \fIxscreensaver\fP
+checks to see if the mouse position or buttons have changed.  Default 5 seconds.
+.TP 8
+.B initialDelay \fR(class \fBTime\fP)
+When \fIXIdle\fP is not in use, \fIxscreensaver\fP will wait this many seconds
+before selecting events on existing windows, under the assumption that 
+\fIxscreensaver\fP is started during your login procedure, and the window 
+state may be in flux.  Default 30 seconds.
+.SH "HOW IT WORKS"
+When it is time to activate the screensaver, a full-screen black window is
+created.  This window is given the appropriate properties so that, to any 
+subsequently-created programs, it will appear to be a ``virtual root'' 
+window.  Because of this, any program which draws on the root window (and 
+which understands virtual roots) can be used as a screensaver.
+.PP
+When the user becomes active again, the screensaver window is unmapped and
+the running subprocess is killed by sending it \fBSIGTERM\fP.  This is also
+how the subprocesses are killed when the screensaver decides that it's time
+to run a different demo: the old one is killed and a new one is launched.
+.PP
+Before launching a subprocess, \fIxscreensaver\fP stores an appropriate value
+for \fB$DISPLAY\fP in the environment that the child will recieve.  (This is
+so that if you start \fIxscreensaver\fP with a \fI-display\fP argument, the
+programs which \fIxscreensaver\fP launches will draw on the same display.)
+.PP
+When the screensaver turns off, or is killed, care is taken to restore 
+the ``real'' virtual root window if there is one.  Because of this, it is
+important that you not kill the screensaver process with \fIkill -9\fP if
+you are running a virtual-root window manager.  If you kill it with \-9,
+you may need to restart your window manager to repair the damage.  This
+isn't an issue if you aren't running a virtual-root window manager.
+.PP
+For all the gory details, see the commentary at the top of xscreensaver.c.
+.PP
+You can control a running screensaver process by using the
+.BR xscreensaver\-command (1)
+program (which see.)
+.SH ENVIRONMENT
+.PP
+.TP 8
+.B DISPLAY
+to get the default host and display number.
+.TP 8
+.B XENVIRONMENT
+to get the name of a resource file that overrides the global resources
+stored in the RESOURCE_MANAGER property.
+.SH USING XDM(1)
+You can run \fIxscreensaver\fP from your xdm session, so that the 
+screensaver will run even when nobody is logged in on the console.  
+Simply add \fB"xscreensaver &"\fP to your \fI/usr/lib/X11/xdm/Xsetup\fP 
+file.  Because \fIxdm\fP grabs the keyboard, keypresses will not make 
+the screensaver deactivate, but any mouse activity will.
+.PP
+Users may want to add \fB"xscreensaver-command -restart"\fP to their 
+startup scripts, so that the screensaver will be reinitialized with
+their private resource settings when they log in.
+.PP
+It is safe to run this program as root (as \fIxdm\fP is likely to do.)  If 
+run as root, \fIxscreensaver\fP changes its effective user and group ids to
+something safe (like \fI"nobody"\fP) before connecting to the X server
+or launching user-specified programs.
+.PP
+Locking doesn't work if the screensaver is launched by \fIxdm\fP.  To get
+around this, you can run the screensaver from \fIxdm\fP without locking, 
+and kill and restart it from your personal X startup script to enable
+locking.
+.SH DEMO MODE
+If \fIxscreensaver\fP receives the \fBDEMO\fP ClientMessage, it pops up
+a dialog box from which you can examine and experiment with the screensaver's
+client programs.
+.PP
+Clicking left on an element in the scrolling list will place the indicated
+program and its args in the text field to be edited.  Edit the arguments and
+hit return to run the program with the parameters you have specified.
+.PP
+Double-clicking on an element in the scrolling list will run the indicated
+program immediately.
+.PP
+When a client program is launched, the dialog box is hidden.  Clicking
+any mouse button will re-expose the dialog box (but will not kill the 
+client program.)
+.TP 8
+.B Run Next
+Clicking this button will run the next program in the list after the 
+currently-selected one, and will scroll around to the top when it reaches
+the bottom.
+.TP 8
+.B Run Previous
+Opposite of Run Next; at the top, it scrolls around to the bottom.
+.TP 8
+.B Edit Parameters
+This pops up a second dialog box, in which you have the option to 
+interactively change most of the screensaver's operational parameters,
+such as its timeouts, and whether it should hack colormaps.  Changing
+these parameters here will affect only the running \fIxscreensaver\fP
+process; to make the changes permanent, you need to edit your X resource
+file.
+.TP 8
+.B Exit Demo Mode
+Returns to normal screensaver operation.
+.TP 8
+.B Reinitialize
+Causes the screensaver process to exit and then restart with the same 
+command-line arguments.  This causes the X resource database to be 
+re-read.  This is just like the \fI\-restart\fP argument to
+.BR xscreensaver\-command (1)
+except that when executed from this button, the screensaver will 
+automatically return to demo mode after restarting.
+.SH SEE ALSO
+.BR X (1),
+.BR xscreensaver\-command (1),
+.BR xlock (1),
+.BR xnlock (1),
+.BR xautolock (1),
+.BR xdm (1),
+.BR qix (1),
+.BR pyro (1),
+.BR helix (1),
+.BR rorschach (1),
+.BR hopalong (1),
+.BR attraction (1),
+.BR greynetic (1),
+.BR rocks (1),
+.BR noseguy (1),
+.BR blitspin (1),
+.BR imsmap (1),
+.BR slidescreen (1),
+.BR hypercube (1),
+.BR maze (1),
+.BR ico (1),
+.BR xdaliclock (1),
+.BR xbouncebits (1),
+.BR xswarm (1),
+.BR xwave (1),
+.BR xfishtank (1)
+.SH BUGS
+If you are not using \fIXIdle\fP, and an application does not 
+select \fBKeyPress\fP events on its non-leaf windows within the first
+30 seconds of their existence, but selects them later, then it is 
+possible that \fIxscreensaver\fP could interfere with the propagation
+of those events.  This isn't very likely, but this is the reason that
+it's a good idea to install the \fIXIdle\fP extension.
+.PP
+Although this program ``nices'' the subprocesses that it starts, 
+graphics-intensive subprograms can still overload the machine by causing
+the X server process itself (which is not ``niced'') to suck a lot of 
+cycles.  Care should be taken to slow down programs intended for use as 
+screensavers by inserting strategic calls to
+.BR sleep (3)
+or
+.BR usleep (3)
+\.
+
+Also, it will cause your X server to be pretty much permanently swapped in.
+(but the same is true of any program that draws periodically, like xclock or
+xload.)
+.PP
+If the subprocess is drawing too quickly and the connection to the X
+server is a slow one (such as an X terminal running over a phone line) then 
+the screensaver might not turn off right away when the user becomes active
+again (the
+.BR ico (1)
+demo has this problem if being run in full-speed mode).  This can be
+alleviated by inserting strategic calls to
+.BR XSync (3)
+in code intended for use as a screensaver.  This prevents too much graphics
+activity from being buffered up.
+.PP
+The screensaver only runs on the default screen of the display.  If you have
+more than one screen, you must run multiple screensaver processes, one for
+each screen.  (I don't actually know whether this works, because I don't 
+have access to a multi-screen machine.  Comments welcome.)
+.PP
+If you don't have Motif, you can't compile with support for locking or
+demo mode.
+.PP
+When the \fBRun Next\fP and \fBRun Previous\fP buttons are used, the selected
+item may not be visible in the window.  It's a Motif bug that selecting a
+different item doesn't scroll the list to show the new selected item.
+.PP
+Locking doesn't work if the screensaver is launched by \fIxdm\fP.
+.PP
+If you get an error message like ``couldn't get password of foo'' then 
+this probably means that you're on a system in which the
+.BR getpwent (3)
+library routine can only be effectively used by root.  If this is the case, 
+then \fIxscreensaver\fP must be installed as setuid to root.  Care has 
+been taken to make this a safe thing to do.
+.PP
+There need to be a lot more graphics hacks.  In particular, there should be
+a simulation of a Lavalite (tm).
+.PP
+The \fBinstallColormap\fP option doesn't work very well with the
+.BR twm (1)
+window manager and its descendants.  There is a race condition between the
+screensaver and this window manager, which can result in the screensaver's
+colormap not getting installed properly, meaning the graphics hacks will
+appear in essentially random colors.  The
+.BR mwm (1)
+and
+.BR olwm (1)
+window managers don't seem to have this problem.  The race condition exists
+because X apparently does not provide a way for an OverrideRedirect window to 
+have its own colormap, short of grabbing the server (which is neither a good 
+idea, nor really possible with the current design.)  What happens is that, as 
+soon as the screensaver installs its colormap, \fBtwm\fP responds to 
+the \fBColormapNotify\fP event that is generated by re-instaling the default
+colormap.  Apparently, \fBtwm\fP doesn't \fIalways\fP do this; it seems to do
+it regularly if the screensaver is activated from a menu item, but seems to
+not do it if the screensaver comes on of its own volition, or is activated
+from another console.  Any thoughts on this problem are welcome...
+.PP
+The \fBinstallColormap\fP option has no effect in "demo" mode, since the
+dialog boxes allocate their colors out of the screen's default colormap
+instead of the installed colormap.
+.PP
+For this same reason, locking doesn't work too well along 
+with \fBinstallColormap\fP; the dialog box's colors are random.
+.PP
+Apparently there are some problems with ``XView'' programs getting confused
+and thinking that the screensaver window is the real root window even when
+the screensaver is not active: ClientMessages intended for the window manager
+are sent to the screensaver window instead.  This could be solved by making
+xscreensaver forward all unrecognised ClientMessages to the real root window,
+but there may be other problems as well.
+.SH COPYRIGHT
+Copyright \(co 1992, 1993 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
+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.
+.SH AUTHOR
+Jamie Zawinski <jwz@lucid.com>, 13-aug-92.
+Please let me know if you find any bugs or make any improvements.
+
+Thanks to David Wojtowicz for implementing \fIlockTimeout\fP.
diff --git a/hacks/.gdbinit b/hacks/.gdbinit
new file mode 100644 (file)
index 0000000..0bd0142
--- /dev/null
@@ -0,0 +1,3 @@
+b exit
+b abort
+set args -geom =700x700+0+0
diff --git a/hacks/Imakefile b/hacks/Imakefile
new file mode 100644 (file)
index 0000000..daf08f3
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Imakefile file for xscreensaver, Copyright (c) 1993 Jamie Zawinski.
+ *
+ * You should not need to edit this file; edit ../config.h instead.
+ *
+ */
+
+#include "../config.h"
+
+          UTILS = ../utils
+       INCLUDES = -I$(UTILS)
+        DEFINES = R5ISMS
+EXTRA_LIBRARIES = $(XMULIB) $(XTOOLLIB) $(EXTENSIONLIB) $(XLIB) -lm
+          HACKS = attraction.c greynetic.c helix.c hopalong.c xroger-hack.c \
+                  noseguy.c pyro.c qix.c rocks.c rorschach.c blitspin.c \
+                  imsmap.c slidescreen.c maze.c hypercube.c halo.c
+            MEN = attraction.man greynetic.man helix.man hopalong.man \
+                  noseguy.man pyro.man xroger.man qix.man rocks.man \
+                  rorschach.man blitspin.man imsmap.man slidescreen.man \
+                  maze.man hypercube.man halo.man
+       TARFILES = README Imakefile screenhack.c $(HACKS) screenhack.h \
+                  vroot.h xlock.h $(MEN) .gdbinit noses/\*
+
+all::
+
+echo_tarfiles:
+       @echo $(TARFILES)
+
+#define        ScreenhackTarget(p,ps,deps)                                      @@\
+all:: p                                                                         @@\
+p: deps screenhack.h ps.o $(DEPLIBS)                                    @@\
+       RemoveTargetProgram($@)                                          @@\
+       $(CC) -o $@ $(LDOPTIONS) deps ps.o $(LDLIBS) $(EXTRA_LOAD_FLAGS) @@\
+                                                                        @@\
+InstallProgram(p,$(BINDIR))                                             @@\
+InstallManPage(p,$(MANDIR))                                             @@\
+clean::                                                                         @@\
+       $(RM) p
+
+HOBJS=screenhack.o $(UTILS)/resources.o $(UTILS)/usleep.o
+
+ScreenhackTarget (qix, qix, $(HOBJS) $(UTILS)/hsv.o)
+ScreenhackTarget (helix, helix, $(HOBJS) $(UTILS)/hsv.o)
+ScreenhackTarget (pyro, pyro, $(HOBJS) $(UTILS)/hsv.o)
+ScreenhackTarget (attraction, attraction, $(HOBJS) $(UTILS)/hsv.o $(UTILS)/spline.o)
+ScreenhackTarget (rorschach, rorschach, $(HOBJS) $(UTILS)/hsv.o)
+ScreenhackTarget (hopalong, hopalong, $(HOBJS) $(UTILS)/hsv.o)
+ScreenhackTarget (xroger, xroger-hack, $(HOBJS) $(UTILS)/hsv.o $(UTILS)/xroger.o)
+ScreenhackTarget (rocks, rocks, $(HOBJS))
+ScreenhackTarget (noseguy, noseguy, $(HOBJS))
+ScreenhackTarget (blitspin, blitspin, $(HOBJS))
+ScreenhackTarget (greynetic, greynetic, $(HOBJS))
+ScreenhackTarget (slidescreen, slidescreen, $(HOBJS))
+ScreenhackTarget (imsmap, imsmap, $(HOBJS) $(UTILS)/hsv.o)
+ScreenhackTarget (maze, maze, $(HOBJS) $(UTILS)/xroger.o)
+ScreenhackTarget (hypercube, hypercube, $(HOBJS))
+ScreenhackTarget (halo, halo, $(HOBJS) $(UTILS)/hsv.o)
diff --git a/hacks/README b/hacks/README
new file mode 100644 (file)
index 0000000..c5ebcd6
--- /dev/null
@@ -0,0 +1,9 @@
+
+This directory contains various graphics hacks.  These are independent from
+the xscreensaver program (in the ../driver/ directory) but some of them use
+the utility functions found in the ../utils/ directory.
+
+If you have compilation problems, check the parameters in ../config.h.
+
+The file xlock.h makes it really easy to turn `xlock' modules into standalone
+programs that can be used with xscreensaver; check it out.
diff --git a/hacks/attraction.c b/hacks/attraction.c
new file mode 100644 (file)
index 0000000..d178b21
--- /dev/null
@@ -0,0 +1,608 @@
+/* xscreensaver, Copyright (c) 1992 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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.
+ */
+
+/* Simulation of a pair of quasi-gravitational fields, maybe sorta kinda
+   a little like the strong and weak electromagnetic forces.  Derived from
+   a Lispm screensaver by John Pezaris <pz@mit.edu>.
+
+   John sez:
+
+   The simulation started out as a purely accurate gravitational simulation,
+   but, with constant simulation step size, I quickly realized the field being
+   simulated while grossly gravitational was, in fact, non-conservative.  It
+   also had the rather annoying behavior of dealing very badly with colliding
+   orbs.  Therefore, I implemented a negative-gravity region (with two
+   thresholds; as I read your code, you only implemented one) to prevent orbs
+   from every coming too close together, and added a viscosity factor if the
+   speed of any orb got too fast.  This provides a nice stable system with
+   interesting behavior.
+
+   I had experimented with a number of fields including the van der Waals
+   force (very interesting orbiting behavior) and 1/r^3 gravity (not as
+   interesting as 1/r^2).  An even normal viscosity (rather than the
+   thresholded version to bleed excess energy) is also not interesting.
+   The 1/r^2, -1/r^2, -10/r^2 thresholds proved not only robust but also
+   interesting -- the orbs never collided and the threshold viscosity fixed
+   the non-conservational problem.
+ */
+
+#include "screenhack.h"
+#include "spline.h"
+#include <stdio.h>
+#include <math.h>
+#if __STDC__
+#include <values.h>
+#endif
+
+struct ball {
+  float x, y;
+  float vx, vy;
+  float dx, dy;
+  float mass;
+  int size;
+  XColor color;
+  int hue;
+};
+
+static unsigned int default_fg_pixel;
+static struct ball *balls;
+static int npoints;
+static int threshold;
+static int delay;
+static int global_size;
+static int segments;
+static Bool glow_p;
+static Bool orbit_p;
+static XPoint *point_stack;
+static int point_stack_size, point_stack_fp, pixel_stack_fp, pixel_stack_size;
+static unsigned long *pixel_stack;
+static unsigned int color_shift;
+
+static enum object_mode {
+  ball_mode, line_mode, polygon_mode, spline_mode, spline_filled_mode,
+  tail_mode
+} mode;
+
+static enum color_mode {
+  cycle_mode, random_mode
+} cmode;
+
+static GC draw_gc, erase_gc;
+
+#define MAX_SIZE 16
+
+#define min(a,b) ((a)<(b)?(a):(b))
+#define max(a,b) ((a)>(b)?(a):(b))
+
+static void
+init_balls (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  int i;
+  XWindowAttributes xgwa;
+  XGCValues gcv;
+  int xlim, ylim, midx, midy, r, vx, vy;
+  double th;
+  Colormap cmap;
+  char *mode_str;
+  XGetWindowAttributes (dpy, window, &xgwa);
+  xlim = xgwa.width;
+  ylim = xgwa.height;
+  cmap = xgwa.colormap;
+  midx = xlim/2;
+  midy = ylim/2;
+  r = get_integer_resource ("radius", "Integer");
+  if (r <= 0 || r > min (xlim/2, ylim/2))
+    r = min (xlim/2, ylim/2) - 50;
+  vx = get_integer_resource ("vx", "Integer");
+  vy = get_integer_resource ("vy", "Integer");
+  npoints = get_integer_resource ("points", "Integer");
+  if (npoints < 1)
+    npoints = 3 + (random () % 5);
+  balls = (struct ball *) malloc (npoints * sizeof (struct ball));
+  segments = get_integer_resource ("segments", "Integer");
+  if (segments < 0) segments = 1;
+  threshold = get_integer_resource ("threshold", "Integer");
+  if (threshold < 0) threshold = 0;
+  delay = get_integer_resource ("delay", "Integer");
+    if (delay < 0) delay = 0;
+  global_size = get_integer_resource ("size", "Integer");
+  if (global_size < 0) global_size = 0;
+  glow_p = get_boolean_resource ("glow", "Boolean");
+  orbit_p = get_boolean_resource ("orbit", "Boolean");
+  color_shift = get_integer_resource ("colorShift", "Integer");
+  if (color_shift >= 360) color_shift = 5;
+
+  mode_str = get_string_resource ("mode", "Mode");
+  if (! mode_str) mode = ball_mode;
+  else if (!strcmp (mode_str, "balls")) mode = ball_mode;
+  else if (!strcmp (mode_str, "lines")) mode = line_mode;
+  else if (!strcmp (mode_str, "polygons")) mode = polygon_mode;
+  else if (!strcmp (mode_str, "tails")) mode = tail_mode;
+  else if (!strcmp (mode_str, "splines")) mode = spline_mode;
+  else if (!strcmp (mode_str, "filled-splines")) mode = spline_filled_mode;
+  else {
+    fprintf (stderr,
+            "%s: mode must be balls, lines, tails, polygons, splines, or\n\
+       filled-splines, not \"%s\"\n",
+            progname, mode_str);
+    exit (1);
+  }
+
+  mode_str = get_string_resource ("colorMode", "ColorMode");
+  if (! mode_str) cmode = cycle_mode;
+  else if (!strcmp (mode_str, "cycle")) cmode = cycle_mode;
+  else if (!strcmp (mode_str, "random")) cmode = random_mode;
+  else {
+    fprintf (stderr, "%s: colorMode must be cycle or random, not \"%s\"\n",
+            progname, mode_str);
+    exit (1);
+  }
+
+  if (mode != ball_mode && mode != tail_mode) glow_p = False;
+  
+  if (mode == polygon_mode && npoints < 3)
+    mode = line_mode;
+
+  if (mode != ball_mode)
+    {
+      int size = (segments ? segments : 1);
+      point_stack_size = size * (npoints + 1);
+      point_stack = (XPoint *) calloc (point_stack_size, sizeof (XPoint));
+      point_stack_fp = 0;
+      if (segments > 0)
+       pixel_stack_size = segments;
+      else
+       pixel_stack_size = (360 / color_shift);
+      pixel_stack = (unsigned long *)
+       calloc (pixel_stack_size, sizeof (unsigned int));
+      pixel_stack_fp = 0;
+    }
+
+  gcv.line_width = (mode == tail_mode
+                   ? (global_size ? global_size : (MAX_SIZE * 2 / 3))
+                   : 1);
+  gcv.cap_style = (mode == tail_mode ? CapRound : CapButt);
+
+  gcv.foreground = default_fg_pixel =
+    get_pixel_resource ("foreground", "Foreground", dpy, cmap);
+  draw_gc = XCreateGC (dpy, window, GCForeground|GCLineWidth|GCCapStyle, &gcv);
+  gcv.foreground = get_pixel_resource ("background", "Background", dpy, cmap);
+  erase_gc = XCreateGC (dpy, window, GCForeground|GCLineWidth|GCCapStyle,&gcv);
+
+  if (!mono_p && mode != ball_mode)
+    for (i = 0; i < pixel_stack_size; i++)
+      {
+       XColor color;
+       color.pixel = default_fg_pixel;
+       if (!XQueryColor (dpy, cmap, &color)) abort ();
+       if (!XAllocColor (dpy, cmap, &color)) abort ();
+       pixel_stack [i] = color.pixel;
+      }
+
+#define rand_size() min (MAX_SIZE, 8 + (random () % (MAX_SIZE - 9)))
+
+  if (orbit_p && !global_size)
+    /* To orbit, all objects must be the same mass, or the math gets
+       really hairy... */
+    global_size = rand_size ();
+
+  th = frand (M_PI+M_PI);
+  for (i = 0; i < npoints; i++)
+    {
+      int new_size = (global_size ? global_size : rand_size ());
+      balls [i].dx = 0;
+      balls [i].dy = 0;
+      balls [i].size = new_size;
+      balls [i].mass = (new_size * new_size * 10);
+      balls [i].x = midx + r * cos (i * ((M_PI+M_PI) / npoints) + th);
+      balls [i].y = midy + r * sin (i * ((M_PI+M_PI) / npoints) + th);
+      if (! orbit_p)
+       {
+         balls [i].vx = vx ? vx : ((6.0 - (random () % 11)) / 8.0);
+         balls [i].vy = vy ? vy : ((6.0 - (random () % 11)) / 8.0);
+       }
+      balls [i].color.pixel = default_fg_pixel;
+      balls [i].color.flags = DoRed | DoGreen | DoBlue;
+      if (!mono_p)
+       {
+         if (i != 0 && (glow_p || mode != ball_mode))
+           balls [i].hue = balls [0].hue;
+         else
+           balls [i].hue = random () % 360;
+         hsv_to_rgb (balls [i].hue, 1.0, 1.0,
+                     &balls [i].color.red, &balls [i].color.green,
+                     &balls [i].color.blue);
+         if (!XAllocColor (dpy, cmap, &balls [i].color))
+           mono_p = True; /* just give up */
+       }
+    }
+
+  if (orbit_p)
+    {
+      double a = 0;
+      double v;
+      double v_mult = get_float_resource ("vMult", "Float");
+      if (v_mult == 0.0) v_mult = 1.0;
+
+      for (i = 1; i < npoints; i++)
+       {
+          double _2ipi_n = (2 * i * M_PI / npoints);
+         double x = r * cos (_2ipi_n);
+         double y = r * sin (_2ipi_n);
+         double distx = r - x;
+         double dist2 = (distx * distx) + (y * y);
+          double dist = sqrt (dist2);
+          double a1 = ((balls[i].mass / dist2) *
+                       ((dist < threshold) ? -1.0 : 1.0) *
+                       (distx / dist));
+         a += a1;
+       }
+      if (a < 0.0)
+       {
+         fprintf (stderr, "%s: domain error: forces on balls too great\n",
+                  progname);
+         exit (-1);
+       }
+      v = sqrt (a * r) * v_mult;
+      for (i = 0; i < npoints; i++)
+       {
+         double k = ((2 * i * M_PI / npoints) + th);
+         balls [i].vx = -v * sin (k);
+         balls [i].vy =  v * cos (k);
+       }
+    }
+
+  if (mono_p) glow_p = False;
+  XClearWindow (dpy, window);
+}
+
+static void
+compute_force (i, dx_ret, dy_ret)
+     int i;
+     float *dx_ret, *dy_ret;
+{
+  int j;
+  *dx_ret = 0;
+  *dy_ret = 0;
+  for (j = 0; j < npoints; j++)
+    {
+      float x_dist, y_dist, dist, dist2;
+
+      if (i == j) continue;
+      x_dist = balls [j].x - balls [i].x;
+      y_dist = balls [j].y - balls [i].y;
+      dist2 = (x_dist * x_dist) + (y_dist * y_dist);
+      dist = sqrt (dist2);
+             
+      if (dist > 0.1) /* the balls are not overlapping */
+       {
+         float new_acc = ((balls[j].mass / dist2) *
+                          ((dist < threshold) ? -1.0 : 1.0));
+         float new_acc_dist = new_acc / dist;
+         *dx_ret += new_acc_dist * x_dist;
+         *dy_ret += new_acc_dist * y_dist;
+       }
+      else
+       {               /* the balls are overlapping; move randomly */
+         *dx_ret += (frand (10.0) - 5.0);
+         *dy_ret += (frand (10.0) - 5.0);
+       }
+    }
+}
+
+static void
+run_balls (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  int last_point_stack_fp = point_stack_fp;
+  static int tick = 500, xlim, ylim;
+  static Colormap cmap;
+  int i;
+
+  if (tick++ == 500)
+    {
+      XWindowAttributes xgwa;
+      XGetWindowAttributes (dpy, window, &xgwa);
+      tick = 0;
+      xlim = xgwa.width;
+      ylim = xgwa.height;
+      cmap = xgwa.colormap;
+    }
+
+  /* compute the force of attraction/repulsion among all balls */
+  for (i = 0; i < npoints; i++)
+    compute_force (i, &balls[i].dx, &balls[i].dy);
+
+  /* move the balls according to the forces now in effect */
+  for (i = 0; i < npoints; i++)
+    {
+      float old_x = balls[i].x;
+      float old_y = balls[i].y;
+      float new_x, new_y;
+      int size = balls[i].size;
+      balls[i].vx += balls[i].dx;
+      balls[i].vy += balls[i].dy;
+
+      /* don't let them get too fast: impose a terminal velocity
+         (actually, make the medium have friction) */
+      if (balls[i].vx > 10)
+       {
+         balls[i].vx *= 0.9;
+         balls[i].dx = 0;
+       }
+      if (balls[i].vy > 10)
+       {
+         balls[i].vy *= 0.9;
+         balls[i].dy = 0;
+       }
+
+      balls[i].x += balls[i].vx;
+      balls[i].y += balls[i].vy;
+
+      /* bounce off the walls */
+      if (balls[i].x >= (xlim - balls[i].size))
+       {
+         balls[i].x = (xlim - balls[i].size - 1);
+         if (balls[i].vx > 0)
+           balls[i].vx = -balls[i].vx;
+       }
+      if (balls[i].y >= (ylim - balls[i].size))
+       {
+         balls[i].y = (ylim - balls[i].size - 1);
+         if (balls[i].vy > 0)
+           balls[i].vy = -balls[i].vy;
+       }
+      if (balls[i].x <= 0)
+       {
+         balls[i].x = 0;
+         if (balls[i].vx < 0)
+           balls[i].vx = -balls[i].vx;
+       }
+      if (balls[i].y <= 0)
+       {
+         balls[i].y = 0;
+         if (balls[i].vy < 0)
+           balls[i].vy = -balls[i].vy;
+       }
+
+      new_x = balls[i].x;
+      new_y = balls[i].y;
+
+      /* make color saturation be related to particle acceleration. */
+      if (glow_p)
+       {
+         float limit = 0.5;
+         double s, v, fraction;
+         float vx = balls [i].dx;
+         float vy = balls [i].dy;
+         XColor new_color;
+         if (vx < 0) vx = -vx;
+         if (vy < 0) vy = -vy;
+         fraction = vx + vy;
+         if (fraction > limit) fraction = limit;
+
+         s = 1 - (fraction / limit);
+         v = 1.0;
+
+         s = (s * 0.75) + 0.25;
+
+         hsv_to_rgb (balls [i].hue, s, v, 
+                     &new_color.red, &new_color.green, &new_color.blue);
+         if (XAllocColor (dpy, cmap, &new_color))
+           {
+             XFreeColors (dpy, cmap, &balls [i].color.pixel, 1, 0);
+             balls [i].color = new_color;
+           }
+       }
+
+      if (mode == ball_mode)
+       {
+         if (!mono_p)
+           XSetForeground (dpy, draw_gc, balls [i].color.pixel);
+         XFillArc (dpy, window, erase_gc, (int) old_x, (int) old_y,
+                   size, size, 0, 360*64);
+         XFillArc (dpy, window, draw_gc,  (int) new_x, (int) new_y,
+                   size, size, 0, 360*64);
+       }
+      if (mode != ball_mode)
+       {
+         point_stack [point_stack_fp].x = new_x;
+         point_stack [point_stack_fp].y = new_y;
+         point_stack_fp++;
+       }
+    }
+
+  /* draw the lines or polygons after computing all points */
+  if (mode != ball_mode)
+    {
+      point_stack [point_stack_fp].x = balls [0].x; /* close the polygon */
+      point_stack [point_stack_fp].y = balls [0].y;
+      point_stack_fp++;
+      if (point_stack_fp == point_stack_size)
+       point_stack_fp = 0;
+      else if (point_stack_fp > point_stack_size) /* better be aligned */
+       abort ();
+      if (!mono_p)
+       {
+         XColor color2;
+         color2 = balls [0].color;
+         switch (cmode)
+           {
+           case cycle_mode:
+             cycle_hue (&color2, color_shift);
+             break;
+           case random_mode:
+             color2.red =   random () % 65535;
+             color2.green = random () % 65535;
+             color2.blue =  random () % 65535;
+             break;
+           default:
+             abort ();
+           }
+             
+         if (!XAllocColor (dpy, cmap, &color2))
+           {
+             color2 = balls [0].color;
+             if (!XAllocColor (dpy, cmap, &balls [0].color))
+               abort ();
+           }
+         pixel_stack [pixel_stack_fp++] = balls [0].color.pixel;
+         if (pixel_stack_fp >= pixel_stack_size)
+           pixel_stack_fp = 0;
+         XFreeColors (dpy, cmap, pixel_stack + pixel_stack_fp, 1, 0);
+         balls [0].color = color2;
+         XSetForeground (dpy, draw_gc, balls [0].color.pixel);
+       }
+    }
+
+  switch (mode)
+    {
+    case ball_mode:
+      break;
+    case line_mode:
+      if (segments > 0)
+       XDrawLines (dpy, window, erase_gc, point_stack + point_stack_fp,
+                   npoints + 1, CoordModeOrigin);
+      XDrawLines (dpy, window, draw_gc, point_stack + last_point_stack_fp,
+                 npoints + 1, CoordModeOrigin);
+      break;
+    case polygon_mode:
+      if (segments > 0)
+       XFillPolygon (dpy, window, erase_gc, point_stack + point_stack_fp,
+                     npoints + 1, (npoints == 3 ? Convex : Complex),
+                     CoordModeOrigin);
+      XFillPolygon (dpy, window, draw_gc, point_stack + last_point_stack_fp,
+                   npoints + 1, (npoints == 3 ? Convex : Complex),
+                   CoordModeOrigin);
+      break;
+    case tail_mode:
+      {
+       int i;
+       for (i = 0; i < npoints; i++)
+         {
+           int index = point_stack_fp + i;
+           int next_index = (index + (npoints + 1)) % point_stack_size;
+           XDrawLine (dpy, window, erase_gc,
+                      point_stack [index].x,
+                      point_stack [index].y,
+                      point_stack [next_index].x,
+                      point_stack [next_index].y);
+
+           index = last_point_stack_fp + i;
+           next_index = (index - (npoints + 1)) % point_stack_size;
+           if (next_index < 0) next_index += point_stack_size;
+           if (point_stack [next_index].x == 0 &&
+               point_stack [next_index].y == 0)
+             continue;
+           XDrawLine (dpy, window, draw_gc,
+                      point_stack [index].x,
+                      point_stack [index].y,
+                      point_stack [next_index].x,
+                      point_stack [next_index].y);
+         }
+      }
+      break;
+    case spline_mode:
+    case spline_filled_mode:
+      {
+       int i;
+       static spline *s = 0;
+       if (! s) s = make_spline (npoints);
+       if (segments > 0)
+         {
+           for (i = 0; i < npoints; i++)
+             {
+               s->control_x [i] = point_stack [point_stack_fp + i].x;
+               s->control_y [i] = point_stack [point_stack_fp + i].y;
+             }
+           compute_closed_spline (s);
+           if (mode == spline_filled_mode)
+             XFillPolygon (dpy, window, erase_gc, s->points, s->n_points,
+                           (s->n_points == 3 ? Convex : Complex),
+                           CoordModeOrigin);
+           else
+             XDrawLines (dpy, window, erase_gc, s->points, s->n_points,
+                         CoordModeOrigin);
+         }
+       for (i = 0; i < npoints; i++)
+         {
+           s->control_x [i] = point_stack [last_point_stack_fp + i].x;
+           s->control_y [i] = point_stack [last_point_stack_fp + i].y;
+         }
+       compute_closed_spline (s);
+       if (mode == spline_filled_mode)
+         XFillPolygon (dpy, window, draw_gc, s->points, s->n_points,
+                       (s->n_points == 3 ? Convex : Complex),
+                       CoordModeOrigin);
+       else
+         XDrawLines (dpy, window, draw_gc, s->points, s->n_points,
+                     CoordModeOrigin);
+      }
+      break;
+    default:
+      abort ();
+    }
+
+  XSync (dpy, True);
+}
+
+\f
+char *progclass = "Attraction";
+
+char *defaults [] = {
+  "*background:        black",
+  "*foreground:        white",
+  "*mode:      balls",
+  "*points:    0",
+  "*size:      0",
+  "*threshold: 100",
+  "*delay:     10000",
+  "*glow:      false",
+  "*orbit:     false",
+  "*colorShift:        3",
+  "*segments:  100",
+  0
+};
+
+XrmOptionDescRec options [] = {
+  { "-mode",           ".mode",        XrmoptionSepArg, 0 },
+  { "-points",         ".points",      XrmoptionSepArg, 0 },
+  { "-threshold",      ".threshold",   XrmoptionSepArg, 0 },
+  { "-segments",       ".segments",    XrmoptionSepArg, 0 },
+  { "-delay",          ".delay",       XrmoptionSepArg, 0 },
+  { "-size",           ".size",        XrmoptionSepArg, 0 },
+  { "-color-mode",     ".colorMode",   XrmoptionSepArg, 0 },
+  { "-color-shift",    ".colorShift",  XrmoptionSepArg, 0 },
+  { "-radius",         ".radius",      XrmoptionSepArg, 0 },
+  { "-vx",             ".vx",          XrmoptionSepArg, 0 },
+  { "-vy",             ".vy",          XrmoptionSepArg, 0 },
+  { "-vmult",          ".vMult",       XrmoptionSepArg, 0 },
+  { "-glow",           ".glow",        XrmoptionNoArg, "true" },
+  { "-noglow",         ".glow",        XrmoptionNoArg, "false" },
+  { "-orbit",          ".orbit",       XrmoptionNoArg, "true" }
+};
+int options_size = (sizeof (options) / sizeof (options[0]));
+
+void
+screenhack (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  init_balls (dpy, window);
+  while (1)
+    {
+      run_balls (dpy, window);
+      if (delay) usleep (delay);
+    }
+}
diff --git a/hacks/attraction.man b/hacks/attraction.man
new file mode 100644 (file)
index 0000000..daa6939
--- /dev/null
@@ -0,0 +1,132 @@
+.TH XScreenSaver 1 "22-mar-93" "X Version 11"
+.SH NAME
+attraction - interactions of opposing forces
+.SH SYNOPSIS
+.B attraction
+[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-points \fIint\fP] [\-threshold \fIint\fP] [\-mode balls | lines | polygons | splines | filled-splines | tails ] [\-color-mode cycle | random] [\-size \fIint\fP] [\-segments \fIint\fP] [\-delay \fIusecs\fP] [\-color-shift \fIdegrees\fP] [\-radius \fIint\fP] [\-vx \fIint\fP] [\-vy \fIint\fP] [\-glow] [\-noglow] [\-orbit]
+.SH DESCRIPTION
+The \fIattraction\fP program has several visually different modes of 
+operation, all of which are based on the interactions of a set of control
+points which attract each other up to a certain distance, and then begin
+to repel each other.  The attraction/repulsion is proportional to the 
+distance between any two particles.
+.SH OPTIONS
+.I attraction
+accepts the following options:
+.TP 8
+.B \-window
+Draw on a newly-created window.  This is the default.
+.TP 8
+.B \-root
+Draw on the root window.
+.TP 8
+.B \-mono 
+If on a color display, pretend we're on a monochrome display.
+.TP 8
+.B \-points integer
+How many control points should be used, or 0 to select the number randomly.
+Default 0.  Between 3 and 15 works best.
+.TP 8
+.B \-threshold integer
+The distance (in pixels) from each particle at which the attractive force
+becomes repulsive.  Default 100.
+.TP 8
+.B \-mode "balls | lines | polygons | tails | splines | filled-splines"
+In \fIballs\fP mode (the default) the control points are drawn as filled
+circles.  The larger the circle, the more massive the particle.
+
+In \fIlines\fP mode, the control points are connected by straight lines;
+the effect is something like \fIqix\fP.
+
+In \fIpolygons\fP mode, the control points are connected by straight
+lines, and filled in.  This is most interesting in color.
+
+In \fIsplines\fP mode, a closed spline is interpolated from the control 
+points.
+
+In \fIfilled-splines\fP mode, the splines are filled in instead of being
+outlines.  This is most interesting in color.
+
+In \fItails\fP mode, the path which each particle follows is indicated
+by a worm-like trail, whose length is controlled by the \fIsegments\fP
+parameter.
+.TP 8
+.B \-color-mode cycle | random
+Whether colors should cycle through the spectrum, or be picked randomly.
+.TP 8
+.B \-size integer
+The size of the balls in pixels, or 0, meaning to select the sizes 
+randomly (the default.)  If this is specified, then all balls will be 
+the same size.  This option has an effect in all modes, since the ``size''
+of the balls controls their mass.
+.TP 8
+.B \-segments integer
+If in \fIlines\fP or \fIpolygons\fP mode, how many sets of line segments
+or polygons should be drawn. Default 100.  This has no effect in \fIballs\fP
+mode.  If \fIsegments\fP is 0, then no segments will ever be erased (this
+is only useful in color.)
+.TP 8
+.B \-delay microseconds
+How much of a delay should be introduced between steps of the animation.
+Default 10000, or about 0.01 seconds.
+.TP 8
+.B \-color-shift degrees
+If on a color display, the color of the line segments or polygons will 
+cycle through the spectrum.  This specifies how far the hue of each segment
+should be from the next, in degrees on the HSV wheel.  Default 3.
+This has no effect in \fIballs\fP mode.
+.TP 8
+.B \-radius
+The size in pixels of the circle on which the points are initially positioned.
+The default is slightly smaller than the size of the window.
+.TP 8
+.B \-glow
+This is consulted only in \fIballs\fP mode.  If this is specified, then 
+the saturation of the colors of the points will vary according to their
+current acceleration.  This has the effect that the balls flare brighter
+when they are reacting to each other most strongly.
+
+In \fIglow\fP mode, all of the balls will be drawn the same (random)
+color, modulo the saturation shifts.  In non-glow mode, the balls will
+each be drawn in a random color that doesn't change.
+.TP 8
+.B \-noglow
+Don't do ``glowing.''  This is the default.
+.TP 8
+.B \-vx pixels
+.TP 8
+.B \-vy pixels
+Initial velocity of the balls.  This has no effect in \fB\-orbit\fP mode.
+.TP 8
+.B \-orbit
+Make the initial force on each ball be tangential to the circle on which
+they are initially placed, with the right velocity to hold them in orbit
+about each other.  After a while, roundoff errors will cause the orbit
+to decay.
+.TP 8
+.B \-vmult float
+In orbit mode, the initial velocity of the balls is multiplied by this;
+a number less than 1 will make the balls pull closer together, and a larger
+number will make them move apart.  The default is 1, meaning stability.
+.SH ENVIRONMENT
+.PP
+.TP 8
+.B DISPLAY
+to get the default host and display number.
+.TP 8
+.B XENVIRONMENT
+to get the name of a resource file that overrides the global resources
+stored in the RESOURCE_MANAGER property.
+.SH SEE ALSO
+.BR X (1),
+.BR xscreensaver (1)
+.SH COPYRIGHT
+Copyright \(co 1992, 1993 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
+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.
+.SH AUTHOR
+Jamie Zawinski <jwz@lucid.com>, 13-aug-92.
diff --git a/hacks/blitspin.c b/hacks/blitspin.c
new file mode 100644 (file)
index 0000000..a532e29
--- /dev/null
@@ -0,0 +1,191 @@
+/* xscreensaver, Copyright (c) 1992 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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.
+ */
+
+/* Rotate a bitmap using using bitblts.
+   The bitmap must be square, and must be a power of 2 in size.
+   This was translated from SmallTalk code which appeared in the
+   August 1981 issue of Byte magazine.
+
+   The input bitmap may be non-square, it is padded and centered
+   with the background color.  Another way would be to subdivide
+   the bitmap into square components and rotate them independently,
+   but I don't think that would be as interesting looking.
+
+   It's too bad almost nothing uses blitter hardware these days,
+   or this might actually win.
+ */
+
+#include "screenhack.h"
+#include <X11/Xmu/Drawing.h>
+#include <stdio.h>
+
+static Display *dpy;
+static Window window;
+static unsigned int size;
+static Pixmap self, temp, mask;
+static GC SET, CLR, CPY, IOR, AND, XOR;
+static GC gc;
+static int delay, delay2;
+static Pixmap bitmap;
+
+static void rotate(), init (), display ();
+
+#define copy_all_to(from, xoff, yoff, to, gc)          \
+  XCopyArea (dpy, (from), (to), (gc), 0, 0,            \
+            size-(xoff), size-(yoff), (xoff), (yoff))
+
+#define copy_all_from(to, xoff, yoff, from, gc)                \
+  XCopyArea (dpy, (from), (to), (gc), (xoff), (yoff),  \
+            size-(xoff), size-(yoff), 0, 0)
+
+static void
+rotate ()
+{
+  int qwad; /* fuckin' C, man... who needs namespaces? */
+  XFillRectangle (dpy, mask, CLR, 0, 0, size, size);
+  XFillRectangle (dpy, mask, SET, 0, 0, size>>1, size>>1);
+  for (qwad = size>>1; qwad > 0; qwad>>=1)
+    {
+      if (delay) usleep (delay);
+      copy_all_to   (mask,       0,       0, temp, CPY);  /* 1 */
+      copy_all_to   (mask,       0,    qwad, temp, IOR);  /* 2 */
+      copy_all_to   (self,       0,       0, temp, AND);  /* 3 */
+      copy_all_to   (temp,       0,       0, self, XOR);  /* 4 */
+      copy_all_from (temp,    qwad,       0, self, XOR);  /* 5 */
+      copy_all_from (self,    qwad,       0, self, IOR);  /* 6 */
+      copy_all_to   (temp,    qwad,       0, self, XOR);  /* 7 */
+      copy_all_to   (self,       0,       0, temp, CPY);  /* 8 */
+      copy_all_from (temp,    qwad,    qwad, self, XOR);  /* 9 */
+      copy_all_to   (mask,       0,       0, temp, AND);  /* A */
+      copy_all_to   (temp,       0,       0, self, XOR);  /* B */
+      copy_all_to   (temp,    qwad,    qwad, self, XOR);  /* C */
+      copy_all_from (mask, qwad>>1, qwad>>1, mask, AND);  /* D */
+      copy_all_to   (mask,    qwad,       0, mask, IOR);  /* E */
+      copy_all_to   (mask,       0,    qwad, mask, IOR);  /* F */
+      display (self);
+    }
+}
+
+static void
+init ()
+{
+  XWindowAttributes xgwa;
+  Colormap cmap;
+  XGCValues gcv;
+  int width, height, xh, yh;
+  unsigned int real_size;
+  char *bitmap_name;
+  int i;
+  XGetWindowAttributes (dpy, window, &xgwa);
+  cmap = xgwa.colormap;
+
+  delay = get_integer_resource ("delay", "Integer");
+  delay2 = get_integer_resource ("delay2", "Integer");
+  if (delay < 0) delay = 0;
+  if (delay2 < 0) delay2 = 0;
+  bitmap_name = get_string_resource ("bitmap", "Bitmap");
+  if (! bitmap_name)
+    {
+      fprintf (stderr, "%s: no bitmap specified\n", progname);
+      exit (1);
+    }
+  bitmap = XmuLocateBitmapFile (DefaultScreenOfDisplay (dpy), bitmap_name,
+                               0, 0, &width, &height, &xh, &yh);
+  if (! bitmap)
+    {
+      fprintf (stderr, "%s: couldn't find bitmap %s\n", progname, bitmap_name);
+      exit (1);
+    }
+
+  real_size = (width > height) ? width : height;
+
+  size = real_size;
+  /* semi-sleazy way of doing (setq size (expt 2 (ceiling (log size 2)))). */
+  for (i = 31; i > 0; i--)
+    if (size & (1<<i)) break;
+  if (size & (~(1<<i)))
+    size = (size>>i)<<(i+1);
+  self = XCreatePixmap (dpy, window, size, size, 1);
+  temp = XCreatePixmap (dpy, window, size, size, 1);
+  mask = XCreatePixmap (dpy, window, size, size, 1);
+  gcv.foreground = 1;
+  gcv.function=GXset;  SET = XCreateGC(dpy,self,GCFunction|GCForeground,&gcv);
+  gcv.function=GXclear;CLR = XCreateGC(dpy,self,GCFunction|GCForeground,&gcv);
+  gcv.function=GXcopy; CPY = XCreateGC(dpy,self,GCFunction|GCForeground,&gcv);
+  gcv.function=GXor;   IOR = XCreateGC(dpy,self,GCFunction|GCForeground,&gcv);
+  gcv.function=GXand;  AND = XCreateGC(dpy,self,GCFunction|GCForeground,&gcv);
+  gcv.function=GXxor;  XOR = XCreateGC(dpy,self,GCFunction|GCForeground,&gcv);
+
+  XFillRectangle (dpy, self, CLR, 0, 0, size, size);
+  XCopyArea (dpy, bitmap, self, CPY, 0, 0, width, height,
+            (size - width)>>1, (size - height)>>1);
+
+  gcv.foreground = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
+  gcv.background = get_pixel_resource ("background", "Background", dpy, cmap);
+  gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
+}
+
+static void
+display (pixmap)
+     Pixmap pixmap;
+{
+  XWindowAttributes xgwa;
+  static int last_w = 0, last_h = 0;
+  XGetWindowAttributes (dpy, window, &xgwa);
+  if (xgwa.width != last_w || xgwa.height != last_h)
+    {
+      XClearWindow (dpy, window);
+      last_w = xgwa.width;
+      last_h = xgwa.height;
+    }
+  XCopyPlane (dpy, pixmap, window, gc, 0, 0, size, size,
+             (xgwa.width-size)>>1, (xgwa.height-size)>>1, 1);
+/*
+  XDrawRectangle (dpy, window, gc,
+                 ((xgwa.width-size)>>1)-1, ((xgwa.height-size)>>1)-1,
+                 size+2, size+2);
+*/
+  XSync (dpy, True);
+}
+
+\f
+char *progclass = "BlitSpin";
+
+char *defaults [] = {
+  "*background:        black",
+  "*foreground:        white",
+  "*delay:     500000",
+  "*delay2:    500000",
+  "*bitmap:    xlogo64",       /* hey, pick something better! */
+  0
+};
+
+XrmOptionDescRec options [] = {
+  { "-delay",          ".delay",       XrmoptionSepArg, 0 },
+  { "-delay2",         ".delay2",      XrmoptionSepArg, 0 },
+  { "-bitmap",         ".bitmap",      XrmoptionSepArg, 0 }
+};
+int options_size = (sizeof (options) / sizeof (options[0]));
+
+void
+screenhack (d, w)
+     Display *d;
+     Window w;
+{
+  dpy = d;
+  window = w;
+  init ();
+  while (1)
+    {
+      rotate ();
+      if (delay2) usleep (delay2);
+    }
+}
diff --git a/hacks/blitspin.man b/hacks/blitspin.man
new file mode 100644 (file)
index 0000000..aac00a4
--- /dev/null
@@ -0,0 +1,68 @@
+.TH XScreenSaver 1 "17-aug-92" "X Version 11"
+.SH NAME
+blitspin - rotate a bitmap in an interesting way
+.SH SYNOPSIS
+.B blitspin
+[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-bitmap \fIfilename\fP] [\-delay \fIusecs\fP] [\-delay2 \fIusecs\fP]
+.SH DESCRIPTION
+The \fIblitspin\fP program repeatedly rotates a bitmap by 90 degrees by
+using logical operations: the bitmap is divided into quadrants, and the
+quadrants are shifted clockwise.  Then the same thing is done again with
+progressively smaller quadrants, except that all sub-quadrants of a 
+given size are rotated in parallel.  So this takes \fBO(16*log2(N))\fP 
+blits of size NxN, with the limitation that the image must be square,
+and the size must be a power of 2.
+.SH OPTIONS
+.I blitspin
+accepts the following options:
+.TP 8
+.B \-window
+Draw on a newly-created window.  This is the default.
+.TP 8
+.B \-root
+Draw on the root window.
+.TP 8
+.B \-mono 
+If on a color display, pretend we're on a monochrome display.
+.TP 8
+.B \-bitmap bitmap-name
+The bitmap to rotate.  It need not be square: it will be padded with
+the background color.  Default is \fIxlogo64\fP, but \fIescherknot\fP
+is also nice.  You really need to run this on a bigger bitmap than
+those shipped with the X distribution to do it justice.
+
+The \fB*bitmapFilePath\fP resource will be searched if the bitmap name
+is not a fully-qualified pathname.
+.SH ENVIRONMENT
+.PP
+.TP 8
+.B \-delay microseconds
+How long to delay between steps of the rotation process, in microseconds.
+Default is 500000, one-half second.
+.PP
+.TP 8
+.B \-delay2 microseconds
+How long to delay between each 90-degree rotation, in microseconds.
+Default is 500000, one-half second.
+.B DISPLAY
+to get the default host and display number.
+.TP 8
+.B XENVIRONMENT
+to get the name of a resource file that overrides the global resources
+stored in the RESOURCE_MANAGER property.
+.SH SEE ALSO
+.BR X (1),
+.BR xscreensaver (1)
+.SH COPYRIGHT
+Copyright \(co 1992 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
+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.
+.SH AUTHOR
+Jamie Zawinski <jwz@lucid.com>, 17-aug-92.
+
+Based on SmallTalk code which appeared in the August 1981 issue of Byte
+magazine.
diff --git a/hacks/greynetic.c b/hacks/greynetic.c
new file mode 100644 (file)
index 0000000..79e89c6
--- /dev/null
@@ -0,0 +1,166 @@
+/* xscreensaver, Copyright (c) 1992 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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"
+
+#define NBITS 12
+
+#include <X11/bitmaps/stipple>
+#include <X11/bitmaps/cross_weave>
+#include <X11/bitmaps/dimple1>
+#include <X11/bitmaps/dimple3>
+#include <X11/bitmaps/flipped_gray>
+#include <X11/bitmaps/gray1>
+#include <X11/bitmaps/gray3>
+#include <X11/bitmaps/hlines2>
+#include <X11/bitmaps/light_gray>
+#include <X11/bitmaps/root_weave>
+#include <X11/bitmaps/vlines2>
+#include <X11/bitmaps/vlines3>
+
+static Pixmap pixmaps [NBITS];
+static GC gc;
+static int delay;
+static unsigned long fg, bg, pixels [512];
+static int npixels;
+
+static void
+init_greynetic (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  int i;
+  XGCValues gcv;
+  XWindowAttributes xgwa;
+  Colormap cmap;
+  XGetWindowAttributes (dpy, window, &xgwa);
+  cmap = xgwa.colormap;
+  npixels = 0;
+  gcv.foreground= fg= get_pixel_resource("foreground","Foreground", dpy, cmap);
+  gcv.background= bg= get_pixel_resource("background","Background", dpy, cmap);
+  gcv.fill_style= FillOpaqueStippled;
+  gc = XCreateGC (dpy, window, GCForeground|GCBackground|GCFillStyle, &gcv);
+
+  delay = get_integer_resource ("delay", "Integer");
+  if (delay < 0) delay = 0;
+
+  i = 0;
+#define BITS(n,w,h) \
+  pixmaps [i++] = XCreatePixmapFromBitmapData (dpy, window, n, w, h, 1, 0, 1)
+
+  BITS (stipple_bits, stipple_width, stipple_height);
+  BITS (cross_weave_bits, cross_weave_width, cross_weave_height);
+  BITS (dimple1_bits, dimple1_width, dimple1_height);
+  BITS (dimple3_bits, dimple3_width, dimple3_height);
+  BITS (flipped_gray_bits, flipped_gray_width, flipped_gray_height);
+  BITS (gray1_bits, gray1_width, gray1_height);
+  BITS (gray3_bits, gray3_width, gray3_height);
+  BITS (hlines2_bits, hlines2_width, hlines2_height);
+  BITS (light_gray_bits, light_gray_width, light_gray_height);
+  BITS (root_weave_bits, root_weave_width, root_weave_height);
+  BITS (vlines2_bits, vlines2_width, vlines2_height);
+  BITS (vlines3_bits, vlines3_width, vlines3_height);
+}
+
+static void
+greynetic (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  static int tick = 500, xlim, ylim;
+  static Colormap cmap;
+  int x, y, w, h, i;
+  XGCValues gcv;
+  if (tick++ == 500)
+    {
+      XWindowAttributes xgwa;
+      XGetWindowAttributes (dpy, window, &xgwa);
+      tick = 0;
+      xlim = xgwa.width;
+      ylim = xgwa.height;
+      cmap = xgwa.colormap;
+    }
+  for (i = 0; i < 10; i++) /* minimize area, but don't try too hard */
+    {
+      w = 50 + random () % (xlim - 50);
+      h = 50 + random () % (ylim - 50);
+      if (w + h < xlim && w + h < ylim)
+       break;
+    }
+  x = random () % (xlim - w);
+  y = random () % (ylim - h);
+  gcv.stipple = pixmaps [random () % NBITS];
+  if (mono_p)
+    {
+      if (random () % 1)
+       gcv.foreground = fg, gcv.background = bg;
+      else
+       gcv.foreground = bg, gcv.background = fg;
+    }
+  else
+    {
+      XColor fgc, bgc;
+      if (npixels == sizeof (pixels) / sizeof (unsigned long))
+       goto REUSE;
+      fgc.flags = bgc.flags = DoRed|DoGreen|DoBlue;
+      fgc.red = random ();
+      fgc.green = random ();
+      fgc.blue = random ();
+      bgc.red = random ();
+      bgc.green = random ();
+      bgc.blue = random ();
+      if (! XAllocColor (dpy, cmap, &fgc))
+       goto REUSE;
+      pixels [npixels++] = fgc.pixel;
+      gcv.foreground = fgc.pixel;
+      if (! XAllocColor (dpy, cmap, &bgc))
+       goto REUSE;
+      pixels [npixels++] = bgc.pixel;
+      gcv.background = bgc.pixel;
+      goto DONE;
+    REUSE:
+      gcv.foreground = pixels [random () % npixels];
+      gcv.background = pixels [random () % npixels];
+    DONE:
+      ;
+    }
+  XChangeGC (dpy, gc, GCStipple|GCForeground|GCBackground, &gcv);
+  XFillRectangle (dpy, window, gc, x, y, w, h);
+  XSync (dpy, True);
+}
+
+\f
+char *progclass = "Greynetic";
+
+char *defaults [] = {
+  "*background:        black",
+  "*foreground:        white",
+  "*delay:     0",
+  0
+};
+
+XrmOptionDescRec options [] = {
+  { "-delay",          ".delay",       XrmoptionSepArg, 0 }
+};
+int options_size = (sizeof (options) / sizeof (options[0]));
+
+void
+screenhack (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  init_greynetic (dpy, window);
+  while (1)
+    {
+      greynetic (dpy, window);
+      if (delay) usleep (delay);
+    }
+}
diff --git a/hacks/greynetic.man b/hacks/greynetic.man
new file mode 100644 (file)
index 0000000..62bc532
--- /dev/null
@@ -0,0 +1,45 @@
+.TH XScreenSaver 1 "13-aug-92" "X Version 11"
+.SH NAME
+greynetic - draw random stippled/color rectangles
+.SH SYNOPSIS
+.B greynetic
+[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-delay \fIusecs\fP]
+.SH DESCRIPTION
+The \fIgreynetic\fP program draws random rectangles.
+.SH OPTIONS
+.I greynetic
+accepts the following options:
+.TP 8
+.B \-window
+Draw on a newly-created window.  This is the default.
+.TP 8
+.B \-root
+Draw on the root window.
+.TP 8
+.B \-mono 
+If on a color display, pretend we're on a monochrome display.
+.TP 8
+.B \-delay microseconds
+Slow it down.
+.SH ENVIRONMENT
+.PP
+.TP 8
+.B DISPLAY
+to get the default host and display number.
+.TP 8
+.B XENVIRONMENT
+to get the name of a resource file that overrides the global resources
+stored in the RESOURCE_MANAGER property.
+.SH SEE ALSO
+.BR X (1),
+.BR xscreensaver (1)
+.SH COPYRIGHT
+Copyright \(co 1992 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
+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.
+.SH AUTHOR
+Jamie Zawinski <jwz@lucid.com>, 13-aug-92.
diff --git a/hacks/halo.c b/hacks/halo.c
new file mode 100644 (file)
index 0000000..08db789
--- /dev/null
@@ -0,0 +1,342 @@
+/* xscreensaver, Copyright (c) 1993 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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.
+ */
+
+/* I wanted to lay down new circles with TV:ALU-ADD instead of TV:ALU-XOR,
+   but X doesn't support arithmetic combinations of pixmaps!!  What losers.
+   I suppose I could crank out the 2's compliment math by hand, but that's
+   a real drag...
+ */
+
+#include "screenhack.h"
+
+struct circle {
+  int x, y, radius;
+  int increment;
+  int dx, dy;
+};
+
+static struct circle *circles;
+static int count, global_count;
+static Pixmap pixmap, buffer;
+static int width, height, global_inc;
+static int delay;
+static unsigned long fg_pixel, bg_pixel;
+static XColor fgc, bgc;
+static Bool xor_p;
+static GC draw_gc, erase_gc, copy_gc, merge_gc;
+static Bool anim_p;
+static Colormap cmap;
+
+#define min(x,y) ((x)<(y)?(x):(y))
+#define max(x,y) ((x)>(y)?(x):(y))
+
+static void
+init_circles_1 (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  int i;
+  count = (global_count ? global_count
+          : (3 + (random () % max (1, (min (width, height) / 50)))
+               + (random () % max (1, (min (width, height) / 50)))));
+  circles = (struct circle *) malloc (count * sizeof (struct circle));
+  for (i = 0; i < count; i++)
+    {
+      circles [i].x = 10 + random () % (width - 20);
+      circles [i].y = 10 + random () % (height - 20);
+      if (global_inc)
+      circles [i].increment = global_inc;
+      else
+       { /* prefer smaller increments to larger ones */
+         int j = 8;
+         int inc = ((random()%j) + (random()%j) + (random()%j)) - ((j*3)/2);
+         if (inc < 0) inc = -inc + 3;
+         circles [i].increment = inc + 3;
+       }
+      circles [i].radius = random () % circles [i].increment;
+      circles [i].dx = ((random () % 3) - 1) * (1 + random () % 5);
+      circles [i].dy = ((random () % 3) - 1) * (1 + random () % 5);
+    }
+}
+
+static void
+init_circles (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  XGCValues gcv;
+  XWindowAttributes xgwa;
+  XGetWindowAttributes (dpy, window, &xgwa);
+  cmap = xgwa.colormap;
+  global_count = get_integer_resource ("count", "Integer");
+  if (global_count < 0) global_count = 0;
+  global_inc = get_integer_resource ("increment", "Integer");
+  if (global_inc < 0) global_inc = 0;
+  xor_p = get_boolean_resource ("xor", "Boolean");
+/*  if (mono_p) */ xor_p = True;
+  anim_p = get_boolean_resource ("animate", "Boolean");
+  delay = get_integer_resource ("delay", "Integer");
+  if (mono_p)
+    {
+      fg_pixel = get_pixel_resource ("foreground","Foreground", dpy, cmap);
+      bg_pixel = get_pixel_resource ("background","Background", dpy, cmap);
+    }
+  else
+    {
+      hsv_to_rgb (0,   0.5, 1.0, &fgc.red, &fgc.green, &fgc.blue);
+      hsv_to_rgb (180, 1.0, 0.7, &bgc.red, &bgc.green, &bgc.blue);
+      XAllocColor (dpy, cmap, &fgc);
+      XAllocColor (dpy, cmap, &bgc);
+      fg_pixel = fgc.pixel;
+      bg_pixel = bgc.pixel;
+    }
+
+  width = max (50, xgwa.width);
+  height = max (50, xgwa.height);
+
+#ifdef DEBUG
+  width/=2; height/=2;
+#endif
+
+  pixmap = XCreatePixmap (dpy, window, width, height, 1);
+  if (xor_p)
+    buffer = XCreatePixmap (dpy, window, width, height, 1);
+  else
+    buffer = 0;
+
+  gcv.foreground = 1;
+  gcv.background = 0;
+  draw_gc = XCreateGC (dpy, pixmap, GCForeground | GCBackground, &gcv);
+  gcv.foreground = 0;
+  erase_gc = XCreateGC (dpy, pixmap, GCForeground, &gcv);
+  gcv.foreground = fg_pixel;
+  gcv.background = bg_pixel;
+  copy_gc = XCreateGC (dpy, window, GCForeground | GCBackground, &gcv);
+
+  if (xor_p)
+    {
+      gcv.foreground = 1;
+      gcv.background = 0;
+      gcv.function = GXxor;
+      merge_gc = XCreateGC (dpy, pixmap,
+                           GCForeground | GCBackground | GCFunction, &gcv);
+    }
+  else
+    {
+      gcv.foreground = fg_pixel;
+      gcv.background = bg_pixel;
+      gcv.function = GXcopy;
+      merge_gc = XCreateGC (dpy, window,
+                           GCForeground | GCBackground | GCFunction, &gcv);
+    }
+
+  init_circles_1 (dpy, window);
+  XClearWindow (dpy, window);
+  if (buffer) XFillRectangle (dpy, buffer, erase_gc, 0, 0, width, height);
+}
+
+static void
+run_circles (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  int i;
+  static int iterations = 0;
+  static int oiterations = 0;
+  static Bool first_time_p = True;
+  Bool done = False;
+  Bool inhibit_sleep = False;
+  XFillRectangle (dpy, pixmap, erase_gc, 0, 0, width, height);
+  for (i = 0; i < count; i++)
+    {
+      int radius = circles [i].radius;
+      int inc = circles [i].increment;
+      if (! (iterations & 1))
+       ;
+      else if (radius == 0)
+       ;
+      else if (radius < 0)
+       done = True;
+      else
+       {
+         /* Probably there's a simpler way to ask the musical question,
+            "is this square completely enclosed by this circle," but I've
+            forgotten too much trig to know it...  (That's not really the
+            right question anyway, but the right question is too hard.) */
+         double x1 = ((double) (-circles [i].x)) / ((double) radius);
+         double y1 = ((double) (-circles [i].y)) / ((double) radius);
+         double x2 = ((double) (width - circles [i].x)) / ((double) radius);
+         double y2 = ((double) (height - circles [i].y)) / ((double) radius);
+         x1 *= x1; x2 *= x2; y1 *= y1; y2 *= y2;
+         if ((x1 + y1) < 1 && (x2 + y2) < 1 && (x1 + y2) < 1 && (x2 + y1) < 1)
+           done = True;
+       }
+      if (radius > 0 &&
+         (xor_p || circles [0].increment < 0))
+       XFillArc (dpy,
+                 (xor_p ? pixmap : window),
+                 (xor_p ? draw_gc : merge_gc),
+                 circles [i].x - radius, circles [i].y - radius,
+                 radius * 2, radius * 2, 0, 360*64);
+      circles [i].radius += inc;
+    }
+
+  if (anim_p && !first_time_p)
+    inhibit_sleep = !done;
+
+  if (done)
+    {
+      if (anim_p)
+       {
+         first_time_p = False;
+         for (i = 0; i < count; i++)
+           {
+             circles [i].x += circles [i].dx;
+             circles [i].y += circles [i].dy;
+             circles [i].radius %= circles [i].increment;
+             if (circles [i].x < 0 || circles [i].x >= width)
+               {
+                 circles [i].dx = -circles [i].dx;
+                 circles [i].x += (2 * circles [i].dx);
+               }
+             if (circles [i].y < 0 || circles [i].y >= height)
+               {
+                 circles [i].dy = -circles [i].dy;
+                 circles [i].y += (2 * circles [i].dy);
+               }
+           }
+       }
+      else if (circles [0].increment < 0)
+       {
+         free (circles);
+         init_circles_1 (dpy, window);
+         if (! mono_p)
+           {
+             cycle_hue (&fgc, 10);
+             cycle_hue (&bgc, 10);
+             XFreeColors (dpy, cmap, &fgc.pixel, 1, 0);
+             XFreeColors (dpy, cmap, &bgc.pixel, 1, 0);
+             XAllocColor (dpy, cmap, &fgc);
+             XAllocColor (dpy, cmap, &bgc);
+             XSetForeground (dpy, copy_gc, fgc.pixel);
+             XSetBackground (dpy, copy_gc, bgc.pixel);
+           }
+       }
+#if 0
+      else if ((random () % 2) == 0)
+       {
+         iterations = 0; /* ick */
+         for (i = 0; i < count; i++)
+           circles [i].radius %= circles [i].increment;
+       }
+#endif
+      else
+       {
+         oiterations = iterations;
+         for (i = 0; i < count; i++)
+           {
+             circles [i].increment = -circles [i].increment;
+             circles [i].radius += (2 * circles [i].increment);
+           }
+       }
+    }
+
+  if (buffer)
+    XCopyPlane (dpy, pixmap, buffer, merge_gc, 0, 0, width, height, 0, 0, 1);
+  else if (!xor_p)
+    {
+      static int ncolors = 0;
+      static XColor *colors = 0;
+      if (circles [0].increment >= 0)
+       inhibit_sleep = True;
+      else if (done)
+       {
+         int fgh, bgh;
+         double fgs, fgv, bgs, bgv;
+         if (colors)
+           for (i = 0; i < ncolors; i++)
+             XFreeColors (dpy, cmap, &colors [i].pixel, 1, 0);
+
+         rgb_to_hsv (fgc.red, fgc.green, fgc.blue, &fgh, &fgs, &fgv);
+         rgb_to_hsv (bgc.red, bgc.green, bgc.blue, &bgh, &bgs, &bgv);
+         ncolors = oiterations;
+         colors = ((XColor *)
+                   (colors
+                    ? realloc (colors, sizeof (XColor) * ncolors)
+                    : malloc (sizeof (XColor) * ncolors)));
+         
+         make_color_ramp (bgh, bgs, bgv, fgh, fgs, fgv, colors, ncolors);
+         for (i = 0; i < ncolors; i++)
+           XAllocColor (dpy, cmap, &colors [i]);
+         XSetForeground (dpy, merge_gc, colors [0].pixel);
+       }
+      else
+       {
+         XSetForeground (dpy, merge_gc, colors [iterations].pixel);
+       }
+    }
+  else
+    XCopyPlane (dpy, pixmap, window, merge_gc, 0, 0, width, height, 0, 0, 1);
+
+  if (buffer && (anim_p
+                ? (done || (first_time_p && (iterations & 1)))
+                : (iterations & 1)))
+    {
+      XCopyPlane (dpy, buffer, window, copy_gc, 0, 0, width, height, 0, 0, 1);
+      XSync (dpy, True);
+      if (anim_p && done)
+       XFillRectangle (dpy, buffer, erase_gc, 0, 0, width, height);
+    }
+#ifdef DEBUG
+  XCopyPlane (dpy, pixmap, window, copy_gc, 0,0,width,height,width,height, 1);
+  if (buffer)
+    XCopyPlane (dpy, buffer, window, copy_gc, 0,0,width,height,0,height, 1);
+  XSync (dpy, True);
+#endif
+
+  if (done)
+    iterations = 0;
+  else
+    iterations++;
+
+  if (delay && !inhibit_sleep) usleep (delay);
+}
+
+\f
+char *progclass = "Halo";
+
+char *defaults [] = {
+  "*background:        black",
+  "*foreground:        white",
+/*  "*xor:     false", */
+  "*count:     0",
+  "*delay:     100000",
+  0
+};
+
+XrmOptionDescRec options [] = {
+  { "-count",          ".count",       XrmoptionSepArg, 0 },
+  { "-delay",          ".delay",       XrmoptionSepArg, 0 },
+  { "-animate",                ".animate",     XrmoptionNoArg, "True" } /* ,
+  { "-xor",            ".xor",         XrmoptionNoArg, "True" },
+  { "-no-xor",         ".xor",         XrmoptionNoArg, "False" } */
+};
+int options_size = (sizeof (options) / sizeof (options[0]));
+
+void
+screenhack (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  init_circles (dpy, window);
+  while (1)
+    run_circles (dpy, window);
+}
diff --git a/hacks/halo.man b/hacks/halo.man
new file mode 100644 (file)
index 0000000..b0f8f6c
--- /dev/null
@@ -0,0 +1,54 @@
+.TH XScreenSaver 1 "7-jul-93" "X Version 11"
+.SH NAME
+halo - draw circular patterns
+.SH SYNOPSIS
+.B halo
+[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-count \fIint\fP] [\-delay \fIusecs\fP] [\-animate]
+.SH DESCRIPTION
+The \fIhalo\fP program draws cool patterns based on circles.
+.SH OPTIONS
+.I halo
+accepts the following options:
+.TP 8
+.B \-window
+Draw on a newly-created window.  This is the default.
+.TP 8
+.B \-root
+Draw on the root window.
+.TP 8
+.B \-mono 
+If on a color display, pretend we're on a monochrome display.
+.TP 8
+.B \-count integer
+How many circles to draw.  Default 0, meaning random.
+.TP 8
+.B \-delay microseconds
+How much of a delay should be introduced between steps of the animation.
+Default 100000, or about 0.1 second.
+.TP 8
+.B \-animate
+If specified, then the centerpoints of the circles will bounce around.
+Otherwise, the circles will be drawn once, erased, and a new set of
+circles will be drawn.
+.SH ENVIRONMENT
+.PP
+.TP 8
+.B DISPLAY
+to get the default host and display number.
+.TP 8
+.B XENVIRONMENT
+to get the name of a resource file that overrides the global resources
+stored in the RESOURCE_MANAGER property.
+.SH SEE ALSO
+.BR X (1),
+.BR xscreensaver (1)
+.SH COPYRIGHT
+Copyright \(co 1993 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
+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.
+.SH AUTHOR
+Jamie Zawinski <jwz@lucid.com>, 6-jul-93.
diff --git a/hacks/helix.c b/hacks/helix.c
new file mode 100644 (file)
index 0000000..9e6d905
--- /dev/null
@@ -0,0 +1,211 @@
+/* xscreensaver, Copyright (c) 1992 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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 <math.h>
+#if __STDC__
+#include <values.h>
+#endif
+
+static double sins [360];
+static double coss [360];
+
+static GC draw_gc, erase_gc;
+static unsigned int default_fg_pixel;
+
+static void
+init_helix (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  int i;
+  XGCValues gcv;
+  XWindowAttributes xgwa;
+  Colormap cmap;
+  XGetWindowAttributes (dpy, window, &xgwa);
+  cmap = xgwa.colormap;
+  gcv.foreground = default_fg_pixel =
+    get_pixel_resource ("foreground", "Foreground", dpy, cmap);
+  draw_gc = XCreateGC (dpy, window, GCForeground, &gcv);
+  gcv.foreground = get_pixel_resource ("background", "Background", dpy, cmap);
+  erase_gc = XCreateGC (dpy, window, GCForeground, &gcv);
+
+  for (i = 0; i < 360; i++)
+    {
+      sins [i] = sin ((((double) i) / 180.0) * M_PI);
+      coss [i] = cos ((((double) i) / 180.0) * M_PI);
+    }
+}
+
+static int
+gcd (a, b)
+     int a, b;
+{
+  while (b > 0)
+    {
+      int tmp;
+      tmp = a % b;
+      a = b;
+      b = tmp;
+    }
+  return (a < 0 ? -a : a);
+}
+
+static void
+helix (dpy, window,
+       radius1, radius2, d_angle,
+       factor1, factor2, factor3, factor4)
+     Display *dpy;
+     Window window;
+     int radius1, radius2, d_angle;
+     int factor1, factor2, factor3, factor4;
+{
+  XWindowAttributes xgwa;
+  int width, height;
+  int xmid, ymid;
+  int x1, y1, x2, y2, angle, limit;
+  int i;
+
+  XClearWindow (dpy, window);
+  XGetWindowAttributes (dpy, window, &xgwa);
+  width = xgwa.width;
+  height = xgwa.height;
+
+  xmid = width / 2;
+  ymid = height / 2;
+  x1 = xmid;
+  y1 = ymid + radius2;
+  x2 = xmid;
+  y2 = ymid + radius1;
+  angle = 0;
+  limit = 1 + (360 / gcd (360, d_angle));
+  
+  for (i = 0; i < limit; i++)
+    {
+      int tmp;
+#define pmod(x,y) (tmp = (x % y), (tmp >= 0 ? tmp : tmp + y))
+      x1 = xmid + (((double) radius1) * sins [pmod ((angle * factor1), 360)]);
+      y1 = ymid + (((double) radius2) * coss [pmod ((angle * factor2), 360)]);
+      XDrawLine (dpy, window, draw_gc, x1, y1, x2, y2);
+      x2 = xmid + (((double) radius2) * sins [pmod ((angle * factor3), 360)]);
+      y2 = ymid + (((double) radius1) * coss [pmod ((angle * factor4), 360)]);
+      XDrawLine (dpy, window, draw_gc, x1, y1, x2, y2);
+      angle += d_angle;
+      XFlush (dpy);
+    }
+}
+
+#define min(a,b) ((a)<(b)?(a):(b))
+
+static void
+random_helix (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  Colormap cmap;
+  int width, height;
+  int radius, radius1, radius2, d_angle, factor1, factor2, factor3, factor4;
+  double divisor;
+  XColor color;
+  int i, got_color = 0;
+  XWindowAttributes xgwa;
+  XGetWindowAttributes (dpy, window, &xgwa);
+  width = xgwa.width;
+  height = xgwa.height;
+  cmap = xgwa.colormap;
+
+  radius = min (width, height) / 2;
+
+  d_angle = 0;
+  factor1 = 2;
+  factor2 = 2;
+  factor3 = 2;
+  factor4 = 2;
+
+  divisor = ((frand (3.0) + 1) * (((random() % 1) * 2) - 1));
+
+  if ((random () & 1) == 0)
+    {
+      radius1 = radius;
+      radius2 = radius / divisor;
+    }
+  else
+    {
+      radius2 = radius;
+      radius1 = radius / divisor;
+    }
+
+  while (gcd (360, d_angle) >= 2)
+    d_angle = random () % 360;
+
+#define random_factor()                                \
+  (((random() % 7) ? ((random() % 1) + 1) : 3) \
+   * (((random() % 1) * 2) - 1))
+
+  while (gcd (gcd (gcd (factor1, factor2), factor3), factor4) != 1)
+    {
+      factor1 = random_factor ();
+      factor2 = random_factor ();
+      factor3 = random_factor ();
+      factor4 = random_factor ();
+    }
+
+  if (mono_p)
+    XSetForeground (dpy, draw_gc, default_fg_pixel);
+  else
+    {
+      hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5,
+                 &color.red, &color.green, &color.blue);
+      if (got_color = XAllocColor (dpy, cmap, &color))
+       XSetForeground (dpy, draw_gc, color.pixel);
+      else
+       XSetForeground (dpy, draw_gc, default_fg_pixel);
+    }
+  helix (dpy, window, radius1, radius2, d_angle,
+        factor1, factor2, factor3, factor4);
+
+  XSync (dpy, True);
+  sleep (5);
+
+  for (i = 0; i < height; i++)
+    {
+      int y = (random () % height);
+      XDrawLine (dpy, window, erase_gc, 0, y, width, y);
+      XFlush (dpy);
+      if ((i % 50) == 0)
+       usleep (10000);
+    }
+  XClearWindow (dpy, window);
+  if (got_color) XFreeColors (dpy, cmap, &color.pixel, 1, 0);
+  XSync (dpy, True);
+  sleep (1);
+}
+
+\f
+char *progclass = "Helix";
+
+char *defaults [] = {
+  "*background: black",
+  0
+};
+
+XrmOptionDescRec options [] = { 0 };
+int options_size = 0;
+
+void
+screenhack (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  init_helix (dpy, window);
+  while (1)
+    random_helix (dpy, window);
+}
diff --git a/hacks/helix.man b/hacks/helix.man
new file mode 100644 (file)
index 0000000..c262266
--- /dev/null
@@ -0,0 +1,43 @@
+.TH XScreenSaver 1 "13-aug-92" "X Version 11"
+.SH NAME
+helix - draw helical string-art patterns
+.SH SYNOPSIS
+.B helix
+[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root] [\-mono]
+.SH DESCRIPTION
+The \fIhelix\fP program draws interesting patterns composed of line segments
+in random colors.
+.SH OPTIONS
+.I helix
+accepts the following options:
+.TP 8
+.B \-window
+Draw on a newly-created window.  This is the default.
+.TP 8
+.B \-root
+Draw on the root window.
+.TP 8
+.B \-mono 
+If on a color display, pretend we're on a monochrome display.
+.SH ENVIRONMENT
+.PP
+.TP 8
+.B DISPLAY
+to get the default host and display number.
+.TP 8
+.B XENVIRONMENT
+to get the name of a resource file that overrides the global resources
+stored in the RESOURCE_MANAGER property.
+.SH SEE ALSO
+.BR X (1),
+.BR xscreensaver (1)
+.SH COPYRIGHT
+Copyright \(co 1992 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
+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.
+.SH AUTHOR
+Jamie Zawinski <jwz@lucid.com>, 13-aug-92.
diff --git a/hacks/hopalong.c b/hacks/hopalong.c
new file mode 100644 (file)
index 0000000..8a3943a
--- /dev/null
@@ -0,0 +1,236 @@
+/* xscreensaver, Copyright (c) 1992 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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.
+ */
+
+/* This file was ported from xlock for use in xscreensaver (and standalone)
+ * by jwz on 12-Aug-92.  Original copyright reads:
+ *
+ * hopalong.c - Real Plane Fractals for xlock, the X Window System lockscreen.
+ *
+ * Copyright (c) 1991 by Patrick J. Naughton.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * This file is provided AS IS with no warranties of any kind.  The author
+ * shall have no liability with respect to the infringement of copyrights,
+ * trade secrets or any patents by this file or any part thereof.  In no
+ * event will the author be liable for any lost revenue or profits or
+ * other special, indirect and consequential damages.
+ *
+ * Comments and additions should be sent to the author:
+ *
+ *                    naughton@eng.sun.com
+ *
+ *                    Patrick J. Naughton
+ *                    MS 21-14
+ *                    Sun Laboritories, Inc.
+ *                    2550 Garcia Ave
+ *                    Mountain View, CA  94043
+ *
+ * Revision History:
+ * 29-Oct-90: fix bad (int) cast.
+ * 29-Jul-90: support for multiple screens.
+ * 08-Jul-90: new timing and colors and new algorithm for fractals.
+ * 15-Dec-89: Fix for proper skipping of {White,Black}Pixel() in colors.
+ * 08-Oct-89: Fixed long standing typo bug in RandomInitHop();
+ *           Fixed bug in memory allocation in inithop();
+ *           Moved seconds() to an extern.
+ *           Got rid of the % mod since .mod is slow on a sparc.
+ * 20-Sep-89: Lint.
+ * 31-Aug-88: Forked from xlock.c for modularity.
+ * 23-Mar-88: Coded HOPALONG routines from Scientific American Sept. 86 p. 14.
+ */
+
+#include "screenhack.h"
+#include <math.h>
+
+static GC gc;
+static int batchcount = 1000;
+
+static unsigned int *pixels = 0, fg_pixel, bg_pixel;
+static int npixels;
+static unsigned int delay;
+static int timeout;
+
+typedef struct {
+    int         centerx;
+    int         centery;       /* center of the screen */
+    double      a;
+    double      b;
+    double      c;
+    double      i;
+    double      j;             /* hopalong parameters */
+    int         inc;
+    int         pix;
+    long        startTime;
+}           hopstruct;
+
+static hopstruct hop;
+static XPoint *pointBuffer = 0;        /* pointer for XDrawPoints */
+
+static void
+inithop(dsp,win)
+     Display *dsp;
+    Window      win;
+{
+    double      range;
+    XWindowAttributes xgwa;
+    hopstruct  *hp = &hop;
+    XGCValues gcv;
+    Colormap cmap;
+    XGetWindowAttributes (dsp, win, &xgwa);
+    cmap = xgwa.colormap;
+
+    if (! pixels)
+      {
+       XColor color;
+       int i = get_integer_resource ("ncolors", "Integer");
+       int shift;
+       if (i <= 2) i = 2, mono_p = True;
+       shift = 360 / i;
+       pixels = (unsigned int *) calloc (i, sizeof (unsigned int));
+       fg_pixel = get_pixel_resource ("foreground", "Foreground", dsp, cmap);
+       bg_pixel = get_pixel_resource ("background", "Background", dsp, cmap);
+       if (! mono_p)
+         {
+           hsv_to_rgb (random () % 360, 1.0, 1.0, 
+                       &color.red, &color.green, &color.blue);
+           for (npixels = 0; npixels < i; npixels++)
+             {
+               if (! XAllocColor (dsp, cmap, &color))
+                 break;
+               pixels[npixels] = color.pixel;
+               cycle_hue (&color, shift);
+             }
+         }
+       timeout = get_integer_resource ("timeout", "Seconds");
+       if (timeout <= 0) timeout = 30;
+       delay = get_integer_resource ("delay", "Usecs");
+
+       gcv.foreground = fg_pixel;
+       gc = XCreateGC (dsp, win, GCForeground, &gcv);
+      }
+
+    XClearWindow (dsp, win);
+
+    hp->centerx = xgwa.width / 2;
+    hp->centery = xgwa.height / 2;
+    range = sqrt((double) hp->centerx * hp->centerx +
+                (double) hp->centery * hp->centery) /
+       (10.0 + random() % 10);
+
+    hp->pix = 0;
+#define frand0() (((double) random()) / ((unsigned int) (~0)))
+    hp->inc = (int) (frand0() * 200) - 100;
+    hp->a = frand0() * range - range / 2.0;
+    hp->b = frand0() * range - range / 2.0;
+    hp->c = frand0() * range - range / 2.0;
+    if (!(random() % 2))
+       hp->c = 0.0;
+
+    hp->i = hp->j = 0.0;
+
+    if (!pointBuffer)
+       pointBuffer = (XPoint *) malloc(batchcount * sizeof(XPoint));
+
+    XSetForeground(dsp, gc, bg_pixel);
+    XFillRectangle(dsp, win, gc, 0, 0,
+                  hp->centerx * 2, hp->centery * 2);
+    XSetForeground(dsp, gc, fg_pixel);
+    hp->startTime = time ((time_t *) 0);
+}
+
+
+static void
+drawhop(dsp,win)
+     Display *dsp;
+    Window      win;
+{
+    double      oldj;
+    int         k = batchcount;
+    XPoint     *xp = pointBuffer;
+    hopstruct  *hp = &hop;
+
+    hp->inc++;
+    if (! mono_p) {
+       XSetForeground(dsp, gc, pixels[hp->pix]);
+       if (++hp->pix >= npixels)
+           hp->pix = 0;
+    }
+    while (k--) {
+       oldj = hp->j;
+       hp->j = hp->a - hp->i;
+       hp->i = oldj + (hp->i < 0
+                       ? sqrt(fabs(hp->b * (hp->i + hp->inc) - hp->c))
+                       : -sqrt(fabs(hp->b * (hp->i + hp->inc) - hp->c)));
+       xp->x = hp->centerx + (int) (hp->i + hp->j);
+       xp->y = hp->centery - (int) (hp->i - hp->j);
+       xp++;
+    }
+    XDrawPoints(dsp, win, gc,
+               pointBuffer, batchcount, CoordModeOrigin);
+    XSync (dsp, True);
+    if ((time ((time_t *) 0) - hp->startTime) > timeout)
+      {
+       int i;
+       XSetForeground(dsp, gc, bg_pixel);
+       for (i = 0; i < hp->centery; i++)
+         {
+           int y = (random () % (hp->centery << 1));
+           XDrawLine (dsp, win, gc, 0, y, hp->centerx << 1, y);
+           XFlush (dsp);
+           if ((i % 50) == 0)
+             usleep (10000);
+         }
+       XClearWindow (dsp, win);
+       XFlush (dsp);
+       sleep (1);
+       inithop(dsp,win);
+      }
+}
+
+\f
+char *progclass = "Hopalong";
+
+char *defaults [] = {
+  "*background:        black",
+  "*foreground:        white",
+  "*count:     1000",
+  "*ncolors:   100",
+  "*timeout:   20",
+  "*delay:     0",
+  0
+};
+
+XrmOptionDescRec options [] = {
+  { "-count",          ".count",       XrmoptionSepArg, 0 },
+  { "-ncolors",                ".ncolors",     XrmoptionSepArg, 0 },
+  { "-timeout",                ".timeout",     XrmoptionSepArg, 0 },
+  { "-delay",          ".delay",       XrmoptionSepArg, 0 },
+};
+int options_size = (sizeof (options) / sizeof (options[0]));
+
+void
+screenhack (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  inithop (dpy, window);
+  while (1)
+    {
+      drawhop (dpy, window);
+      XSync (dpy, True);
+      if (delay) usleep (delay);
+    }
+}
diff --git a/hacks/hopalong.man b/hacks/hopalong.man
new file mode 100644 (file)
index 0000000..0167356
--- /dev/null
@@ -0,0 +1,62 @@
+.TH XScreenSaver 1 "13-aug-92" "X Version 11"
+.SH NAME
+hopalong - draw real plane fractals
+.SH SYNOPSIS
+.B hopalong
+[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-count \fIinteger\fP] [\-ncolors \fIinteger\fP] [\-timeout \fIseconds\fP] [\-delay \fImicroseconds\fP]
+.SH DESCRIPTION
+The \fIhopalong\fP program generates real plane fractals as described in
+the September 1986 issue of Scientific American.
+.SH OPTIONS
+.I hopalong
+accepts the following options:
+.TP 8
+.B \-window
+Draw on a newly-created window.  This is the default.
+.TP 8
+.B \-root
+Draw on the root window.
+.TP 8
+.B \-mono 
+If on a color display, pretend we're on a monochrome display.
+.TP 8
+.B \-count integer
+How many pixels should be drawn before a color change.  Default 1000.
+.TP 8
+.B \-ncolors integer
+How many colors should be used (if possible).  Default 100.
+The colors used cycle through the hue, making N stops around 
+the color wheel.
+.TP 8
+.B \-timeout seconds
+How many seconds we should generate for before clearing the screen
+and starting over.  Default 20.
+.TP 8
+.B \-delay microseconds
+How long we should wait between drawing each pixel.  Default 0.
+.SH ENVIRONMENT
+.PP
+.TP 8
+.B DISPLAY
+to get the default host and display number.
+.TP 8
+.B XENVIRONMENT
+to get the name of a resource file that overrides the global resources
+stored in the RESOURCE_MANAGER property.
+.SH SEE ALSO
+.BR X (1),
+.BR xscreensaver (1),
+.BR xlock (1)
+.SH COPYRIGHT
+Copyright \(co 1988-91 by Patrick J. Naughton
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation. 
+.SH AUTHOR
+Patrick J. Naughton <naughton@eng.sun.com>, 23-mar-88.
+
+Ability to run standalone or with \fIxscreensaver\fP added by 
+Jamie Zawinski <jwz@lucid.com>, 13-aug-92.
diff --git a/hacks/hypercube.c b/hacks/hypercube.c
new file mode 100644 (file)
index 0000000..c58906e
--- /dev/null
@@ -0,0 +1,334 @@
+/* xscreensaver, Copyright (c) 1992 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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.
+ *
+ * This code derived from TI Explorer Lisp code by Joe Keane, Fritz Mueller,
+ * and Jamie Zawinski.
+ */
+
+#include "screenhack.h"
+#include <math.h>
+
+static Display *dpy;
+static Window window;
+static GC color0, color1, color2, color3, color4, color5, color6, color7;
+static GC black;
+
+static int delay;
+
+static int observer_z;
+static int x_offset, y_offset;
+static int unit_pixels;
+
+struct point_state {
+  int old_x, old_y;
+  int new_x, new_y;
+  Bool same_p;
+};
+
+static void
+move_line (state0, state1, gc)
+     struct point_state *state0, *state1;
+     GC gc;
+{
+  if (state0->same_p && state1->same_p)
+    return;
+  if (mono_p)
+    {
+      XDrawLine (dpy, window, black,
+                state0->old_x, state0->old_y, state1->old_x, state1->old_y);
+      XDrawLine (dpy, window, gc,
+                state0->new_x, state0->new_y, state1->new_x, state1->new_y);
+    }
+  else
+    {
+      XSegment segments [2];
+      segments [0].x1 = state0->old_x; segments [0].y1 = state0->old_y;
+      segments [0].x2 = state1->old_x; segments [0].y2 = state1->old_y;
+      segments [1].x1 = state0->new_x; segments [1].y1 = state0->new_y;
+      segments [1].x2 = state1->new_x; segments [1].y2 = state1->new_y;
+      XDrawSegments (dpy, window, gc, segments, 2);
+    }
+}
+
+static void
+hyper (xy, xz, yz, xw, yw, zw)
+     double xy, xz, yz, xw, yw, zw;
+{
+  double cos_xy = cos (xy), sin_xy = sin (xy);
+  double cos_xz = cos (xz), sin_xz = sin (xz);
+  double cos_yz = cos (yz), sin_yz = sin (yz);
+  double cos_xw = cos (xw), sin_xw = sin (xw);
+  double cos_yw = cos (yw), sin_yw = sin (yw);
+  double cos_zw = cos (zw), sin_zw = sin (zw);
+
+  double ax = 1.0, ay = 0.0, az = 0.0, aw = 0.0;
+  double bx = 0.0, by = 1.0, bz = 0.0, bw = 0.0;
+  double cx = 0.0, cy = 0.0, cz = 1.0, cw = 0.0;
+  double dx = 0.0, dy = 0.0, dz = 0.0, dw = 1.0;
+
+  double _tmp0_, _tmp1_;
+
+  struct point_state points [16];
+  bzero (points, sizeof (points));
+
+#define mmmm (&points[0])
+#define mmmp (&points[1])
+#define mmpm (&points[2])
+#define mmpp (&points[3])
+#define mpmm (&points[4])
+#define mpmp (&points[5])
+#define mppm (&points[6])
+#define mppp (&points[7])
+#define pmmm (&points[8])
+#define pmmp (&points[9])
+#define pmpm (&points[10])
+#define pmpp (&points[11])
+#define ppmm (&points[12])
+#define ppmp (&points[13])
+#define pppm (&points[14])
+#define pppp (&points[15])
+
+  while (1)
+    {
+      double temp_mult;
+
+#define compute(a,b,c,d,point_state) \
+      temp_mult = (unit_pixels / (((a*az) + (b*bz) + (c*cz) + (d*dz) +   \
+                                  (a*aw) + (b*bw) + (c*cw) + (d*dw))     \
+                                 - observer_z));                         \
+  point_state->old_x = point_state->new_x;                               \
+  point_state->old_y = point_state->new_y;                               \
+  point_state->new_x = ((((a*ax) + (b*bx) + (c*cx) + (d*dx)) * temp_mult) \
+                       + x_offset);                                      \
+  point_state->new_y = ((((a*ay) + (b*by) + (c*cy) + (d*dy)) * temp_mult) \
+                       + y_offset);                                      \
+  point_state->same_p = (point_state->old_x == point_state->new_x &&     \
+                        point_state->old_y == point_state->new_y);
+
+      compute (-1, -1, -1, -1, mmmm);
+      compute (-1, -1, -1,  1, mmmp);
+      compute (-1, -1,  1, -1, mmpm);
+      compute (-1, -1,  1,  1, mmpp);
+      compute (-1,  1, -1, -1, mpmm);
+      compute (-1,  1, -1,  1, mpmp);
+      compute (-1,  1,  1, -1, mppm);
+      compute (-1,  1,  1,  1, mppp);
+      compute ( 1, -1, -1, -1, pmmm);
+      compute ( 1, -1, -1,  1, pmmp);
+      compute ( 1, -1,  1, -1, pmpm);
+      compute ( 1, -1,  1,  1, pmpp);
+      compute ( 1,  1, -1, -1, ppmm);
+      compute ( 1,  1, -1,  1, ppmp);
+      compute ( 1,  1,  1, -1, pppm);
+      compute ( 1,  1,  1,  1, pppp);
+
+      move_line (mmmm, mmmp, color0);
+      move_line (mmmm, mmpm, color0);
+      move_line (mmpm, mmpp, color0);
+      move_line (mmmp, mmpp, color0);
+      
+      move_line (pmmm, pmmp, color1);
+      move_line (pmmm, pmpm, color1);
+      move_line (pmpm, pmpp, color1);
+      move_line (pmmp, pmpp, color1);
+      
+      move_line (mpmm, mpmp, color2);
+      move_line (mpmm, mppm, color2);
+      move_line (mppm, mppp, color2);
+      move_line (mpmp, mppp, color2);
+      
+      move_line (mmpp, mppp, color3);
+      move_line (mmpp, pmpp, color3);
+      move_line (pmpp, pppp, color3);
+      move_line (mppp, pppp, color3);
+      
+      move_line (mmmm, mpmm, color4);
+      move_line (mmmm, pmmm, color4);
+      move_line (mpmm, ppmm, color4);
+      move_line (pmmm, ppmm, color4);
+      
+      move_line (mmmp, mpmp, color5);
+      move_line (mmmp, pmmp, color5);
+      move_line (pmmp, ppmp, color5);
+      move_line (mpmp, ppmp, color5);
+      
+      move_line (mmpm, mppm, color6);
+      move_line (mmpm, pmpm, color6);
+      move_line (pmpm, pppm, color6);
+      move_line (mppm, pppm, color6);
+      
+      move_line (ppmm, ppmp, color7);
+      move_line (ppmm, pppm, color7);
+      move_line (pppm, pppp, color7);
+      move_line (ppmp, pppp, color7);
+
+ /* If you get error messages about the following forms, and you think you're
+    using an ANSI C conforming compiler, then you're mistaken.  Possibly you're
+    mixing an ANSI compiler with a non-ANSI preprocessor, or vice versa.
+    Regardless, your system is broken; it's not a bug in this program.
+  */
+#if __STDC__
+# define rotate(name,dim0,dim1,cos,sin) \
+      _tmp0_ = ((name##dim0 * cos) + (name##dim1 * sin)); \
+      _tmp1_ = ((name##dim1 * cos) - (name##dim0 * sin)); \
+      name##dim0 = _tmp0_; \
+      name##dim1 = _tmp1_;
+
+# define rotates(dim0,dim1) \
+      if (sin_##dim0##dim1 != 0) {                                \
+        rotate(a, dim0, dim1, cos_##dim0##dim1, sin_##dim0##dim1); \
+        rotate(b, dim0, dim1, cos_##dim0##dim1, sin_##dim0##dim1); \
+        rotate(c, dim0, dim1, cos_##dim0##dim1, sin_##dim0##dim1); \
+        rotate(d, dim0, dim1, cos_##dim0##dim1, sin_##dim0##dim1); \
+      }
+
+#else /* !__STDC__, courtesy of Andreas Luik <luik@isa.de> */
+# define rotate(name,dim0,dim1,cos,sin) \
+      _tmp0_ = ((name/**/dim0 * cos) + (name/**/dim1 * sin)); \
+      _tmp1_ = ((name/**/dim1 * cos) - (name/**/dim0 * sin)); \
+      name/**/dim0 = _tmp0_; \
+      name/**/dim1 = _tmp1_;
+
+# define rotates(dim0,dim1) \
+      if (sin_/**/dim0/**/dim1 != 0) {                                \
+        rotate(a,dim0,dim1,cos_/**/dim0/**/dim1,sin_/**/dim0/**/dim1); \
+        rotate(b,dim0,dim1,cos_/**/dim0/**/dim1,sin_/**/dim0/**/dim1); \
+        rotate(c,dim0,dim1,cos_/**/dim0/**/dim1,sin_/**/dim0/**/dim1); \
+        rotate(d,dim0,dim1,cos_/**/dim0/**/dim1,sin_/**/dim0/**/dim1); \
+      }
+#endif /* !__STDC__ */
+
+      rotates (x,y);
+      rotates (x,z);
+      rotates (y,z);
+      rotates (x,w);
+      rotates (y,w);
+      rotates (z,w);
+
+      XSync (dpy, True);
+      if (delay) usleep (delay);
+    }
+}
+
+\f
+char *progclass = "Hypercube";
+
+char *defaults [] = {
+  "*background:        black",
+  "*foreground:        white",
+  "*color0:    red",
+  "*color1:    orange",
+  "*color2:    yellow",
+  "*color3:    white",
+  "*color4:    green",
+  "*color5:    cyan",
+  "*color6:    dodgerblue",
+  "*color7:    magenta",
+
+  "*xw:                0.000",
+  "*xy:                0.010",
+  "*xz:                0.005",
+  "*yw:                0.010",
+  "*yz:                0.000",
+  "*zw:                0.000",
+
+  "*observer-z:        5",
+  "*delay:     100000",
+  0
+};
+
+XrmOptionDescRec options [] = {
+  { "-color0",         ".color0",      XrmoptionSepArg, 0 },
+  { "-color1",         ".color1",      XrmoptionSepArg, 0 },
+  { "-color2",         ".color2",      XrmoptionSepArg, 0 },
+  { "-color3",         ".color3",      XrmoptionSepArg, 0 },
+  { "-color4",         ".color4",      XrmoptionSepArg, 0 },
+  { "-color5",         ".color5",      XrmoptionSepArg, 0 },
+  { "-color6",         ".color6",      XrmoptionSepArg, 0 },
+  { "-color7",         ".color7",      XrmoptionSepArg, 0 },
+
+  { "-xw",             ".xw",          XrmoptionSepArg, 0 },
+  { "-xy",             ".xy",          XrmoptionSepArg, 0 },
+  { "-xz",             ".xz",          XrmoptionSepArg, 0 },
+  { "-yw",             ".yw",          XrmoptionSepArg, 0 },
+  { "-yz",             ".yz",          XrmoptionSepArg, 0 },
+  { "-zw",             ".zw",          XrmoptionSepArg, 0 },
+
+  { "-observer-z",     ".observer-z",  XrmoptionSepArg, 0 },
+  { "-delay",          ".delay",       XrmoptionSepArg, 0 }
+};
+
+int options_size = (sizeof (options) / sizeof (options[0]));
+
+
+void
+screenhack (d, w)
+     Display *d;
+     Window w;
+{
+  XGCValues gcv;
+  XWindowAttributes xgwa;
+  Colormap cmap;
+  double xy, xz, yz, xw, yw, zw;
+  unsigned long bg, pixel;
+
+  dpy = d;
+  window = w;
+  XGetWindowAttributes (dpy, window, &xgwa);
+  cmap = xgwa.colormap;
+
+  x_offset = xgwa.width / 2;
+  y_offset = xgwa.height / 2;
+  unit_pixels = xgwa.width < xgwa.height ? xgwa.width : xgwa.height;
+
+  xy = get_float_resource ("xy", "Float");
+  xz = get_float_resource ("xz", "Float");
+  yz = get_float_resource ("yz", "Float");
+  xw = get_float_resource ("xw", "Float");
+  yw = get_float_resource ("yw", "Float");
+  zw = get_float_resource ("zw", "Float");
+
+  observer_z = get_integer_resource ("observer-z", "Integer");
+
+  delay = get_integer_resource ("delay", "Integer");
+
+  bg = get_pixel_resource ("background", "Background", dpy, cmap);
+
+  if (mono_p)
+    {
+      gcv.function = GXcopy;
+      gcv.foreground = bg;
+      black = XCreateGC (dpy, window, GCForeground|GCFunction, &gcv);
+      gcv.foreground = get_pixel_resource ("foreground", "Foreground",
+                                          dpy, cmap);
+      color0 = color1 = color2 = color3 = color4 = color5 = color6 = color7 =
+       XCreateGC (dpy, window, GCForeground|GCFunction, &gcv);
+    }
+  else
+    {
+      black = 0;
+      gcv.function = GXxor;
+#define make_gc(color,name) \
+       gcv.foreground = bg ^ get_pixel_resource ((name), "Foreground", \
+                                                 dpy, cmap);           \
+       color = XCreateGC (dpy, window, GCForeground|GCFunction, &gcv)
+
+      make_gc (color0,"color0");
+      make_gc (color1,"color1");
+      make_gc (color2,"color2");
+      make_gc (color3,"color3");
+      make_gc (color4,"color4");
+      make_gc (color5,"color5");
+      make_gc (color6,"color6");
+      make_gc (color7,"color7");
+    }
+
+  hyper (xy, xz, yz, xw, yw, zw);
+}
diff --git a/hacks/hypercube.man b/hacks/hypercube.man
new file mode 100644 (file)
index 0000000..544ed97
--- /dev/null
@@ -0,0 +1,86 @@
+.TH XScreenSaver 1 "6-dec-92" "X Version 11"
+.SH NAME
+hypercube - 2d projection of a 4d object
+.SH SYNOPSIS
+.B hypercube
+[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-color[0-7] \fIcolor\fP] [\-xy \fIfloat\fP] [\-xz \fIfloat\fP] [\-yz \fIfloat\fP] [\-xw \fIfloat\fP] [\-yw \fIfloat\fP] [\-zw \fIfloat\fP] [\-observer-z \fIint\fP] [\-window] [\-root] [\-mono] [\-delay \fIusecs\fP]
+.SH DESCRIPTION
+The \fIhypercube\fP program displays a wireframe projection of a hypercube
+which is rotating at user-specified rates around any or all of its four axes.
+.SH OPTIONS
+.I hypercube
+accepts the following options:
+.TP 8
+.B \-window
+Draw on a newly-created window.  This is the default.
+.TP 8
+.B \-root
+Draw on the root window.
+.TP 8
+.B \-mono 
+If on a color display, pretend we're on a monochrome display.
+.TP 8
+.B \-delay microseconds
+How much of a delay should be introduced between steps of the animation.
+Default 100000, or about 1/10th second.
+.TP 8
+.B \-observer-z int
+How far away the observer is from the center of the cube (the cube is one
+unit per side.)  Default 5.
+.TP 8
+.B \-color0 color
+.TP 8
+.B \-color1 color
+.TP 8
+.B \-color2 color
+.TP 8
+.B \-color3 color
+.TP 8
+.B \-color4 color
+.TP 8
+.B \-color5 color
+.TP 8
+.B \-color6 color
+.TP 8
+.B \-color7 color
+The colors used to draw the line segments bordering the eight faces of
+the cube.  Some of the faces have only two of their border-lines drawn in
+the specified color, and some have all four.
+.TP 8
+.B \-xw float
+.TP 8
+.B \-xy float
+.TP 8
+.B \-xz float
+.TP 8
+.B \-yw float
+.TP 8
+.B \-yz float
+.TP 8
+.B \-zw float
+The amount that the cube should be rotated around the specified axis at
+each frame of the animation, expressed in radians.  These should be small
+floating-point values (less than 0.05 works best.)  Default: xy=0.01,
+xz=0.005, yw=0.01.
+.SH ENVIRONMENT
+.PP
+.TP 8
+.B DISPLAY
+to get the default host and display number.
+.TP 8
+.B XENVIRONMENT
+to get the name of a resource file that overrides the global resources
+stored in the RESOURCE_MANAGER property.
+.SH SEE ALSO
+.BR X (1),
+.BR xscreensaver (1)
+.SH COPYRIGHT
+Copyright \(co 1992 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
+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.
+.SH AUTHOR
+Jamie Zawinski <jwz@lucid.com>, 6-dec-92.
diff --git a/hacks/imsmap.c b/hacks/imsmap.c
new file mode 100644 (file)
index 0000000..8c36bcc
--- /dev/null
@@ -0,0 +1,439 @@
+/* imsmap, Copyright (c) 1992 Juergen Nickelsen <nickel@cs.tu-berlin.de>
+ * Derived from code by Markus Schirmer, TU Berlin.
+ *
+ * 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 <stdio.h>
+#include <X11/Xutil.h>
+
+#define NSTEPS 7
+#define COUNT (1 << NSTEPS)
+#define CELL(c, r) cell[((unsigned int)(c)) + ((unsigned int) (r)) * xmax]
+
+static enum mode_t { MODE_H, MODE_S, MODE_V, MODE_RANDOM } mode;
+
+static GC gc, gc2;
+static Display *disp;
+static Window wind;
+static XWindowAttributes wattrs;
+
+#if defined(sun) && !__STDC__  /* sun cc doesn't know "signed char" */
+#define signed /**/
+#endif
+
+static unsigned long *pixels = 0, fg_pixel, bg_pixel;
+static int npixels = 0;
+static Colormap cmap;
+static int timeout, cycle_delay;
+static int cycle_p;
+static signed char *cell = NULL;
+static int xmax, ymax;
+static int iterations;
+
+static void
+initwin (dsp, win)
+     Display *dsp;
+     Window win;
+{
+  int fg_h, bg_h;
+  double fg_s, fg_v, bg_s, bg_v;
+
+  enum mode_t this_mode;
+  static Bool rv_p;
+  static int ncolors = 0;
+  int shift;
+  double dshift;
+    
+  XGCValues gcv;
+
+  XGetWindowAttributes (dsp, win, &wattrs);
+  cmap = wattrs.colormap;
+
+  if (!ncolors)
+    {
+      char *mode_str = get_string_resource ("mode", "Mode");
+      rv_p = get_boolean_resource ("reverseVideo", "ReverseVideo");
+      cycle_p = get_boolean_resource ("cycle", "Cycle");
+      ncolors = get_integer_resource ("ncolors", "Integer");
+      timeout = get_integer_resource ("timeout", "Integer");
+      cycle_delay = get_integer_resource ("cycleDelay", "Integer");
+      iterations = get_integer_resource ("iterations", "Integer");
+      if (iterations < 0) iterations = 0;
+      else if (iterations > 7) iterations = 7;
+      pixels = (unsigned long *) calloc (ncolors, sizeof (unsigned int));
+      fg_pixel = get_pixel_resource ("background", "Background", dsp, cmap);
+      bg_pixel = get_pixel_resource ("foreground", "Foreground", dsp, cmap);
+
+      if (mono_p && fg_pixel == bg_pixel)
+       bg_pixel = !bg_pixel;
+
+      if (mono_p) cycle_p = False;
+
+      gcv.foreground = fg_pixel;
+      gcv.background = bg_pixel;
+      gc = XCreateGC (dsp, win, GCForeground|GCBackground, &gcv);
+      gcv.foreground = bg_pixel;
+      gc2 = XCreateGC (dsp, win, GCForeground, &gcv);
+
+      if (!mode_str || !strcmp (mode_str, "random"))
+       mode = MODE_RANDOM;
+      else if (!strcmp (mode_str, "h") || !strcmp (mode_str, "hue"))
+       mode = MODE_H;
+      else if (!strcmp (mode_str, "s") || !strcmp (mode_str, "saturation"))
+       mode = MODE_S;
+      else if (!strcmp (mode_str, "v") || !strcmp (mode_str, "value"))
+       mode = MODE_V;
+      else
+       {
+         fprintf (stderr,
+          "%s: mode must be hue, saturation, value, or random, not \"%s\"\n",
+                  progname, mode_str);
+         mode = MODE_RANDOM;
+       }
+    }
+    else if (! mono_p)
+      XFreeColors (dsp, cmap, pixels, npixels, 0);
+
+  this_mode = mode;
+  if (!mono_p && mode == MODE_RANDOM)
+    switch (random () % 3) {
+    case 0: this_mode = MODE_H; break;
+    case 1: this_mode = MODE_S; break;
+    case 2: this_mode = MODE_V; break;
+    }
+
+  if (mono_p)
+    {
+      npixels = ncolors;
+      pixels [0] = fg_pixel;
+      pixels [1] = bg_pixel;
+    }
+  else
+    {
+      XColor fg_color, bg_color;
+
+      if (fg_pixel == bg_pixel)
+       {
+       HSV_AGAIN:
+         fg_h = random () % 360;
+         bg_h = random () % 360;
+         fg_s = frand (1.0);
+         bg_s = frand (1.0);
+       V_AGAIN:
+         fg_v = frand (1.0);
+         bg_v = frand (1.0);
+         if ((fg_v - bg_v) > -0.4 && (fg_v - bg_v) < 0.4)
+           goto V_AGAIN;
+         hsv_to_rgb (fg_h, fg_s, fg_v, 
+                     &fg_color.red, &fg_color.green, &fg_color.blue);
+         hsv_to_rgb (bg_h, bg_s, bg_v, 
+                     &bg_color.red, &bg_color.green, &bg_color.blue);
+       }
+      else
+       {
+         fg_color.pixel = fg_pixel;
+         if (! XQueryColor (dsp, cmap, &fg_color))
+           abort ();
+         bg_color.pixel = bg_pixel;
+         if (! XQueryColor (dsp, cmap, &bg_color))
+           abort ();
+       }
+      fg_color.flags = DoRed|DoGreen|DoBlue;
+      bg_color.flags = DoRed|DoGreen|DoBlue;
+
+      rgb_to_hsv (fg_color.red, fg_color.green, fg_color.blue,
+                 &fg_h, &fg_s, &fg_v);
+      rgb_to_hsv (bg_color.red, bg_color.green, bg_color.blue,
+                 &bg_h, &bg_s, &bg_v);
+
+      if (/*mode == MODE_RANDOM &&*/
+         ((this_mode == MODE_S && (fg_s-bg_s) > -0.3 && (fg_s-bg_s) < 0.3) ||
+          (this_mode == MODE_V && (fg_v-bg_v) > -0.3 && (fg_v-bg_v) < 0.3) ||
+          (this_mode == MODE_H && (fg_h-bg_h) > -30 && (fg_h-bg_h) < 30)))
+       goto HSV_AGAIN;
+
+      switch (this_mode) {
+      case MODE_H:  shift = (bg_h - fg_h) / ncolors; break;
+      case MODE_S: dshift = (bg_s - fg_s) / ncolors; break;
+      case MODE_V: dshift = (bg_v - fg_v) / ncolors; break;
+      default: abort ();
+      }
+      
+      if (mode == MODE_RANDOM &&
+         ((this_mode == MODE_H)
+          ? ((shift > -2 && shift < 2) || fg_s < 0.3 || fg_v < 0.3)
+          : (dshift > -0.005 && dshift < 0.005)))
+       goto HSV_AGAIN;
+
+      if (mode == MODE_RANDOM && this_mode == MODE_S && fg_v < 0.5)
+       goto V_AGAIN;
+
+      for (npixels = 0; npixels < ncolors; npixels++)
+       {
+         if (cycle_p)
+           {
+             unsigned long plane_masks;
+             /* allocate the writable color cells, one at a time. */
+             if (! XAllocColorCells (dsp, cmap, False, &plane_masks, 0,
+                                     &fg_color.pixel, 1))
+               {
+                 fprintf (stderr,
+   "%s: couldn't allocate %s writable color cells.  Turning off -cycle.\n",
+                          progname, (npixels ? "enough" : "any"));
+                 cycle_p = 0;
+                 goto NON_CYCLE;
+               }
+             XStoreColor (dsp, cmap, &fg_color);
+           }
+         else
+           {
+           NON_CYCLE:
+             if (!XAllocColor (dsp, cmap, &fg_color))
+               break;
+           }
+         pixels[npixels] = fg_color.pixel;
+       
+         switch (this_mode)
+           {
+           case MODE_H: fg_h = (fg_h + shift) % 360; break;
+           case MODE_S: fg_s += dshift; break;
+           case MODE_V: fg_v += dshift; break;
+           default: abort ();
+           }
+         hsv_to_rgb (fg_h, fg_s, fg_v,
+                     &fg_color.red, &fg_color.green, &fg_color.blue);
+       }
+    }
+  XSetForeground (dsp, gc, pixels [0]);
+  XFillRectangle (dsp, win, gc, 0, 0, wattrs.width, wattrs.height);
+}
+
+
+#define HEIGHT_TO_PIXEL(height) \
+       (((int) (height)) < 0 ? 0 : \
+        ((int) (height)) >= npixels ? npixels - 3 : ((int) (height)))
+
+static unsigned int
+set (l, c, size, height)
+     unsigned int l, c, size;
+     int height;
+{
+  int rang = 1 << (NSTEPS - size);
+  height = height + (random () % rang) - rang / 2;
+  CELL (l, c) = height;
+
+  return pixels [HEIGHT_TO_PIXEL (height)];
+}
+
+static void
+floyd_steinberg ()
+{
+  int x, y, err;
+
+  /* Instead of repeatedly calling XPutPixel(), we make an Image and then
+     send its bits over all at once.  This consumes much less network
+     bandwidth.  The image we create is Wx1 intead of WxH, so that we
+     don't use enormous amounts of memory.
+   */
+  XImage *image =
+    XCreateImage (disp, DefaultVisual(disp,DefaultScreen(disp)),
+                 1, XYBitmap, 0,               /* depth, format, offset */
+                 (char *) calloc ((xmax + 1) / 8, 1),  /* data */
+                 xmax, 1, 8, 0);               /* w, h, pad, bpl */
+
+  for (y = 0; y < ymax - 1; y++)
+    {
+      for (x = 0; x < xmax - 1; x++)
+       {
+         if (CELL(x, y) < 0)
+           {
+             err = CELL (x, y);
+             XPutPixel (image, x, 0, 1);
+           }
+         else
+           {
+             err = CELL (x, y) - 1;
+             XPutPixel (image, x, 0, 0);
+           }
+         /* distribute error */
+         CELL (x,   y+1) += (int) (((float) err) * 3.0/8.0);
+         CELL (x+1, y)   += (int) (((float) err) * 3.0/8.0);
+         CELL (x+1, y+1) += (int) (((float) err) * 1.0/4.0);
+       }
+      XPutImage (disp, wind, gc, image, 0, 0, 0, y, xmax, 1);
+    }
+  XDestroyImage (image);
+}
+
+static void
+draw (x, y, pixel, grid_size)  /* not called in mono mode */
+     int x, y, grid_size;
+     unsigned long pixel;
+{
+  static unsigned int last_pixel, last_valid = 0;
+  if (! (last_valid && pixel == last_pixel))
+    XSetForeground (disp, gc, pixel);
+  last_valid = 1, last_pixel = pixel;
+  if (grid_size == 1)
+    XDrawPoint (disp, wind, gc, x, y);
+  else
+    XFillRectangle (disp, wind, gc, x, y, grid_size, grid_size);
+}
+
+
+static void 
+drawmap ()
+{
+  unsigned int x, y, i, step, nextStep, x1, x2, y1, y2;
+  unsigned int pixel, qpixels [4];
+
+  xmax = wattrs.width;
+  ymax = wattrs.height;
+
+  cell = (signed char *) calloc (xmax * ymax, 1);
+  if (cell == NULL)
+    exit (1);
+
+  CELL (0, 0) = 0;
+  step = COUNT;
+  for (i = 0; i < iterations; i++)
+    {
+      nextStep = step / 2;
+      for (x = 0; x < xmax; x += step)
+       {
+         x1 = x + nextStep;
+         if (x1 >= xmax)
+           x1 = 0;
+         x2 = x + step;
+         if (x2 >= xmax)
+           x2 = 0;
+         for (y = 0; y < ymax; y += step)
+           {
+             y1 = y + nextStep;
+             if (y1 >= ymax)
+               y1 = 0;
+             y2 = y + step;
+             if (y2 >= ymax)
+               y2 = 0;
+
+             qpixels [0] = pixels [HEIGHT_TO_PIXEL (CELL (x, y))];
+             qpixels [1] = pixels [HEIGHT_TO_PIXEL (CELL (x, y2))];
+             qpixels [2] = pixels [HEIGHT_TO_PIXEL (CELL (x2, y))];
+             qpixels [3] = pixels [HEIGHT_TO_PIXEL (CELL (x2, y2))];
+
+             pixel = set (x, y1, i,
+                          ((int) CELL (x, y) + (int) CELL (x, y2) + 1) / 2);
+             if (! mono_p &&
+                 (pixel != qpixels[0] || pixel != qpixels[1] || 
+                  pixel != qpixels[2] || pixel != qpixels[3]))
+               draw (x, y1, pixel, nextStep);
+
+             pixel = set (x1, y, i,
+                          ((int) CELL (x, y) + (int) CELL (x2, y) + 1) / 2);
+             if (! mono_p &&
+                 (pixel != qpixels[0] || pixel != qpixels[1] || 
+                  pixel != qpixels[2] || pixel != qpixels[3]))
+               draw (x1, y, pixel, nextStep);
+
+             pixel = set (x1, y1, i,
+                          ((int) CELL (x, y) + (int) CELL (x, y2) +
+                           (int) CELL (x2, y) + (int) CELL (x2, y2) + 2)
+                          / 4);
+             if (! mono_p &&
+                 (pixel != qpixels[0] || pixel != qpixels[1] || 
+                  pixel != qpixels[2] || pixel != qpixels[3]))
+               draw (x1, y1, pixel, nextStep);
+           }
+       }
+      step = nextStep;
+      if (!mono_p)
+       XSync (disp, True);
+    }
+  if (mono_p)
+    /* in mono-mode, we do all the drawing at the end */
+    floyd_steinberg ();
+  
+  free (cell);
+  XSync (disp, True);
+}
+
+static void
+cycle (dpy)
+     Display *dpy;
+{
+  XColor *colors = malloc (npixels * sizeof (XColor));
+  time_t stop;
+  int i;
+  for (i = 0; i < npixels; i++)
+    colors [i].pixel = pixels [i];
+  XQueryColors (dpy, cmap, colors, npixels);
+  stop = (time_t) ((time ((time_t) 0)) + timeout);
+  while (stop >= (time_t) time ((time_t) 0))
+    {
+      unsigned long scratch = colors [npixels-1].pixel;
+      for (i = npixels-1; i > 0; i--)
+       colors [i].pixel = colors [i-1].pixel;
+      colors [0].pixel = scratch;
+      XStoreColors (dpy, cmap, colors, npixels);
+      XSync (dpy, True);
+      if (cycle_delay) usleep (cycle_delay);
+    }
+  XSync (dpy, True);
+  free (colors);
+}
+
+
+char *progclass = "Imsmap";
+
+char *defaults [] = {
+  "*background:        black",
+  "*foreground:        black",
+  "*mode:      random",
+  "*ncolors:   50",
+  "*iterations:        7",
+  "*timeout:   10",
+  "*cycleDelay:        100000",
+  "*cycle:     true",
+  0
+};
+
+XrmOptionDescRec options [] = {
+  { "-ncolors",                ".ncolors",     XrmoptionSepArg, 0 },
+  { "-timeout",                ".timeout",     XrmoptionSepArg, 0 },
+  { "-cycle-delay",    ".cycleDelay",  XrmoptionSepArg, 0 },
+  { "-mode",           ".mode",        XrmoptionSepArg, 0 },
+  { "-iterations",     ".iterations",  XrmoptionSepArg, 0 },
+  { "-cycle",          ".cycle",       XrmoptionNoArg, "True"  },
+  { "-no-cycle",       ".cycle",       XrmoptionNoArg, "False" }
+};
+int options_size = (sizeof (options) / sizeof (options[0]));
+
+
+void
+screenhack (dpy, window)
+     Display *dpy;
+     Window window;
+{
+    disp = dpy;
+    wind = window;
+    while (1)
+      {
+       initwin (dpy, window);
+       drawmap ();
+       if (timeout)
+         {
+           if (cycle_p)
+             cycle (dpy);
+           else
+             sleep (timeout);
+         }
+      }
+}
diff --git a/hacks/imsmap.man b/hacks/imsmap.man
new file mode 100644 (file)
index 0000000..164faff
--- /dev/null
@@ -0,0 +1,56 @@
+.TH XScreenSaver 1 "26-apr-93" "X Version 11"
+.SH NAME
+imsmap - generate fractal maps
+.SH SYNOPSIS
+.B imsmap
+[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-ncolors \fIint\fP] [\-timeout \fIseconds\fP] [\-iterations \fIint\fP] [\-mode h|s|v|random] [\-cycle] [\-no\-cycle]
+.SH DESCRIPTION
+The \fIimsmap\fP program generates map or cloud-like patterns.  It looks
+quite different in monochrome and color.
+.SH OPTIONS
+.I imsmap
+accepts the following options:
+.TP 8
+.B \-window
+Draw on a newly-created window.  This is the default.
+.TP 8
+.B \-root
+Draw on the root window.
+.TP 8
+.B \-mono 
+If on a color display, pretend we're on a monochrome display.
+.TP 8
+.B \-ncolors integer
+How many colors to use.  Default 50.
+.TP 8
+.B \-timeout integer
+How long to delay between images.  Default 10 seconds.
+.TP 8
+.B \-iterations integer
+A measure of the resolution of the resultant image, from 0 to 7.  Default 7.
+.TP 8
+.B \-mode hue|saturation|value|random
+The axis upon which colors should be interpolated between the foreground
+and background color.  Default random.  
+.TP 8
+.B \-cycle
+Whether to do colormap cycling.  This is the default.
+.TP 8
+.B \-no\-cycle
+Turns \fI\-cycle\fP off.
+.SH ENVIRONMENT
+.PP
+.TP 8
+.B DISPLAY
+to get the default host and display number.
+.TP 8
+.B XENVIRONMENT
+to get the name of a resource file that overrides the global resources
+stored in the RESOURCE_MANAGER property.
+.SH SEE ALSO
+.BR X (1),
+.BR xscreensaver (1)
+.SH AUTHOR
+Juergen Nickelsen <nickel@cs.tu-berlin.de>, 23-aug-92.
+
+Hacked on by Jamie Zawinski <jwz@lucid.com>, 24-aug-92.
diff --git a/hacks/maze.c b/hacks/maze.c
new file mode 100644 (file)
index 0000000..abaf4e9
--- /dev/null
@@ -0,0 +1,781 @@
+/******************************************************************************
+ * [ maze ] ...
+ *
+ * modified:  [ 3-7-93 ]  Jamie Zawinski <jwz@lucid.com>
+ *             added the XRoger logo, cleaned up resources, made
+ *             grid size a parameter.
+ * modified:  [ 3-3-93 ]  Jim Randell <jmr@mddjmr.fc.hp.com>
+ *             Added the colour stuff and integrated it with jwz's
+ *             screenhack stuff.  There's still some work that could
+ *             be done on this, particularly allowing a resource to
+ *             specify how big the squares are.
+ * modified:  [ 10-4-88 ]  Richard Hess    ...!uunet!cimshop!rhess  
+ *              [ Revised primary execution loop within main()...
+ *              [ Extended X event handler, check_events()...
+ * modified:  [ 1-29-88 ]  Dave Lemke      lemke@sun.com  
+ *              [ Hacked for X11...
+ *              [  Note the word "hacked" -- this is extremely ugly, but at 
+ *              [   least it does the job.  NOT a good programming example 
+ *              [   for X.
+ * original:  [ 6/21/85 ]  Martin Weiss    Sun Microsystems  [ SunView ]
+ *
+ ******************************************************************************
+ Copyright 1988 by Sun Microsystems, Inc. Mountain View, CA.
+  
+ All Rights Reserved
+  
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee is hereby granted, 
+ provided that the above copyright notice appear in all copies and that
+ both that copyright notice and this permission notice appear in 
+ supporting documentation, and that the names of Sun or MIT not be
+ used in advertising or publicity pertaining to distribution of the
+ software without specific prior written permission. Sun and M.I.T. 
+ make no representations about the suitability of this software for 
+ any purpose. It is provided "as is" without any express or implied warranty.
+ SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE. IN NO EVENT SHALL SUN BE LIABLE FOR ANY SPECIAL, INDIRECT
+ OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 
+ OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
+ OR PERFORMANCE OF THIS SOFTWARE.
+ *****************************************************************************/
+
+#include "screenhack.h"
+
+#define XROGER
+
+static int solve_delay, pre_solve_delay, post_solve_delay;
+
+#include  <stdio.h>
+#include  <X11/Xlib.h>
+#include  <X11/Xutil.h>
+#include  <X11/bitmaps/gray1>
+
+#define MAX_MAZE_SIZE_X        500
+#define MAX_MAZE_SIZE_Y        500
+
+#define MOVE_LIST_SIZE  (MAX_MAZE_SIZE_X * MAX_MAZE_SIZE_Y)
+
+#define WALL_TOP       0x8000
+#define WALL_RIGHT     0x4000
+#define WALL_BOTTOM    0x2000
+#define WALL_LEFT      0x1000
+
+#define DOOR_IN_TOP    0x800
+#define DOOR_IN_RIGHT  0x400
+#define DOOR_IN_BOTTOM 0x200
+#define DOOR_IN_LEFT   0x100
+#define DOOR_IN_ANY    0xF00
+
+#define DOOR_OUT_TOP   0x80
+#define DOOR_OUT_RIGHT 0x40
+#define DOOR_OUT_BOTTOM        0x20
+#define DOOR_OUT_LEFT  0x10
+
+#define START_SQUARE   0x2
+#define END_SQUARE     0x1
+
+#define        border_x        (0)
+#define        border_y        (0)
+
+#define        get_random(x)   (random() % (x))
+  
+static int logo_x, logo_y;
+
+#ifdef XROGER
+# define logo_width  128
+# define logo_height 128
+#else
+# include  <X11/bitmaps/xlogo64>
+# define logo_width xlogo64_width
+# define logo_height xlogo64_height
+# define logo_bits xlogo64_bits
+#endif
+
+static unsigned short maze[MAX_MAZE_SIZE_X][MAX_MAZE_SIZE_Y];
+
+static struct {
+  unsigned char x;
+  unsigned char y;
+  unsigned char dir;
+} move_list[MOVE_LIST_SIZE], save_path[MOVE_LIST_SIZE], path[MOVE_LIST_SIZE];
+
+static int maze_size_x, maze_size_y;
+static int sqnum, cur_sq_x, cur_sq_y, path_length;
+static int start_x, start_y, start_dir, end_x, end_y, end_dir;
+static int maze_restart_flag, random_index;
+static int grid_width, grid_height;
+
+static Display *dpy;
+static Window  win;
+static GC      gc, cgc, tgc, logo_gc;
+static Pixmap  logo_map;
+
+static int     x = 0, y = 0, restart = 0, stop = 1, state = 1;
+
+check_events()                                  /* X event handler [ rhess ] */
+{
+  XEvent       e;
+
+  if (XPending(dpy)) {
+    XNextEvent(dpy, &e);
+    switch (e.type) {
+
+    case ButtonPress:
+      switch (e.xbutton.button) {
+      case 3:
+       exit (0);
+       break;
+      case 2:
+       stop = !stop ;
+       if (state == 5) state = 4 ;
+       else {
+         restart = 1;
+         stop = 0;
+       }
+       break;
+      default:
+       restart = 1 ;
+       stop = 0 ;
+       break;
+      }
+      break;
+
+    case ConfigureNotify:
+      restart = 1;
+      break;
+    case UnmapNotify:
+      stop = 1;
+      XClearWindow (dpy, win);
+      XSync (dpy, False);
+      break;
+    case Expose:
+      restart = 1;
+      break;
+    }
+    return(1);
+  }
+  return(0);
+}
+
+
+set_maze_sizes (width, height)
+     int width, height;
+{
+  maze_size_x = width / grid_width;
+  maze_size_y = height / grid_height;
+}
+
+
+initialize_maze()         /* draw the surrounding wall and start/end squares */
+{
+  register int i, j, wall;
+  
+  /* initialize all squares */
+  for ( i=0; i<maze_size_x; i++) {
+    for ( j=0; j<maze_size_y; j++) {
+      maze[i][j] = 0;
+    }
+  }
+  
+  /* top wall */
+  for ( i=0; i<maze_size_x; i++ ) {
+    maze[i][0] |= WALL_TOP;
+  }
+  
+  /* right wall */
+  for ( j=0; j<maze_size_y; j++ ) {
+    maze[maze_size_x-1][j] |= WALL_RIGHT;
+  }
+  
+  /* bottom wall */
+  for ( i=0; i<maze_size_x; i++ ) {
+    maze[i][maze_size_y-1] |= WALL_BOTTOM;
+  }
+  
+  /* left wall */
+  for ( j=0; j<maze_size_y; j++ ) {
+    maze[0][j] |= WALL_LEFT;
+  }
+  
+  /* set start square */
+  wall = get_random(4);
+  switch (wall) {
+  case 0:      
+    i = get_random(maze_size_x);
+    j = 0;
+    break;
+  case 1:      
+    i = maze_size_x - 1;
+    j = get_random(maze_size_y);
+    break;
+  case 2:      
+    i = get_random(maze_size_x);
+    j = maze_size_y - 1;
+    break;
+  case 3:      
+    i = 0;
+    j = get_random(maze_size_y);
+    break;
+  }
+  maze[i][j] |= START_SQUARE;
+  maze[i][j] |= ( DOOR_IN_TOP >> wall );
+  maze[i][j] &= ~( WALL_TOP >> wall );
+  cur_sq_x = i;
+  cur_sq_y = j;
+  start_x = i;
+  start_y = j;
+  start_dir = wall;
+  sqnum = 0;
+  
+  /* set end square */
+  wall = (wall + 2)%4;
+  switch (wall) {
+  case 0:
+    i = get_random(maze_size_x);
+    j = 0;
+    break;
+  case 1:
+    i = maze_size_x - 1;
+    j = get_random(maze_size_y);
+    break;
+  case 2:
+    i = get_random(maze_size_x);
+    j = maze_size_y - 1;
+    break;
+  case 3:
+    i = 0;
+    j = get_random(maze_size_y);
+    break;
+  }
+  maze[i][j] |= END_SQUARE;
+  maze[i][j] |= ( DOOR_OUT_TOP >> wall );
+  maze[i][j] &= ~( WALL_TOP >> wall );
+  end_x = i;
+  end_y = j;
+  end_dir = wall;
+  
+  /* set logo */
+  if ((maze_size_x > 15) && (maze_size_y > 15))
+    {
+      int logow = 1 + logo_width / grid_width;
+      int logoh = 1 + logo_height / grid_height;
+      /* not closer than 3 grid units from a wall */
+      logo_x = get_random (maze_size_x - logow - 6) + 3;
+      logo_y = get_random (maze_size_y - logoh - 6) + 3;
+      for (i=0; i<logow; i++)
+       for (j=0; j<logoh; j++)
+         maze[logo_x + i][logo_y + j] |= DOOR_IN_TOP;
+    }
+  else
+    logo_y = logo_x = -1;
+}
+
+static int choose_door ();
+static int backup ();
+static void draw_wall ();
+static void draw_solid_square ();
+static void enter_square ();
+
+create_maze()             /* create a maze layout given the intiialized maze */
+{
+  register int i, newdoor;
+  
+  do {
+    move_list[sqnum].x = cur_sq_x;
+    move_list[sqnum].y = cur_sq_y;
+    move_list[sqnum].dir = newdoor;
+    while ( ( newdoor = choose_door() ) == -1 ) { /* pick a door */
+      if ( backup() == -1 ) { /* no more doors ... backup */
+       return; /* done ... return */
+      }
+    }
+    
+    /* mark the out door */
+    maze[cur_sq_x][cur_sq_y] |= ( DOOR_OUT_TOP >> newdoor );
+    
+    switch (newdoor) {
+    case 0: cur_sq_y--;
+      break;
+    case 1: cur_sq_x++;
+      break;
+    case 2: cur_sq_y++;
+      break;
+    case 3: cur_sq_x--;
+      break;
+    }
+    sqnum++;
+    
+    /* mark the in door */
+    maze[cur_sq_x][cur_sq_y] |= ( DOOR_IN_TOP >> ((newdoor+2)%4) );
+    
+    /* if end square set path length and save path */
+    if ( maze[cur_sq_x][cur_sq_y] & END_SQUARE ) {
+      path_length = sqnum;
+      for ( i=0; i<path_length; i++) {
+       save_path[i].x = move_list[i].x;
+       save_path[i].y = move_list[i].y;
+       save_path[i].dir = move_list[i].dir;
+      }
+    }
+    
+  } while (1);
+  
+}
+
+
+static int
+choose_door()                                            /* pick a new path */
+{
+  int candidates[3];
+  register int num_candidates;
+  
+  num_candidates = 0;
+  
+ topwall:
+  /* top wall */
+  if ( maze[cur_sq_x][cur_sq_y] & DOOR_IN_TOP )
+    goto rightwall;
+  if ( maze[cur_sq_x][cur_sq_y] & DOOR_OUT_TOP )
+    goto rightwall;
+  if ( maze[cur_sq_x][cur_sq_y] & WALL_TOP )
+    goto rightwall;
+  if ( maze[cur_sq_x][cur_sq_y - 1] & DOOR_IN_ANY ) {
+    maze[cur_sq_x][cur_sq_y] |= WALL_TOP;
+    maze[cur_sq_x][cur_sq_y - 1] |= WALL_BOTTOM;
+    draw_wall(cur_sq_x, cur_sq_y, 0);
+    goto rightwall;
+  }
+  candidates[num_candidates++] = 0;
+  
+ rightwall:
+  /* right wall */
+  if ( maze[cur_sq_x][cur_sq_y] & DOOR_IN_RIGHT )
+    goto bottomwall;
+  if ( maze[cur_sq_x][cur_sq_y] & DOOR_OUT_RIGHT )
+    goto bottomwall;
+  if ( maze[cur_sq_x][cur_sq_y] & WALL_RIGHT )
+    goto bottomwall;
+  if ( maze[cur_sq_x + 1][cur_sq_y] & DOOR_IN_ANY ) {
+    maze[cur_sq_x][cur_sq_y] |= WALL_RIGHT;
+    maze[cur_sq_x + 1][cur_sq_y] |= WALL_LEFT;
+    draw_wall(cur_sq_x, cur_sq_y, 1);
+    goto bottomwall;
+  }
+  candidates[num_candidates++] = 1;
+  
+ bottomwall:
+  /* bottom wall */
+  if ( maze[cur_sq_x][cur_sq_y] & DOOR_IN_BOTTOM )
+    goto leftwall;
+  if ( maze[cur_sq_x][cur_sq_y] & DOOR_OUT_BOTTOM )
+    goto leftwall;
+  if ( maze[cur_sq_x][cur_sq_y] & WALL_BOTTOM )
+    goto leftwall;
+  if ( maze[cur_sq_x][cur_sq_y + 1] & DOOR_IN_ANY ) {
+    maze[cur_sq_x][cur_sq_y] |= WALL_BOTTOM;
+    maze[cur_sq_x][cur_sq_y + 1] |= WALL_TOP;
+    draw_wall(cur_sq_x, cur_sq_y, 2);
+    goto leftwall;
+  }
+  candidates[num_candidates++] = 2;
+  
+ leftwall:
+  /* left wall */
+  if ( maze[cur_sq_x][cur_sq_y] & DOOR_IN_LEFT )
+    goto donewall;
+  if ( maze[cur_sq_x][cur_sq_y] & DOOR_OUT_LEFT )
+    goto donewall;
+  if ( maze[cur_sq_x][cur_sq_y] & WALL_LEFT )
+    goto donewall;
+  if ( maze[cur_sq_x - 1][cur_sq_y] & DOOR_IN_ANY ) {
+    maze[cur_sq_x][cur_sq_y] |= WALL_LEFT;
+    maze[cur_sq_x - 1][cur_sq_y] |= WALL_RIGHT;
+    draw_wall(cur_sq_x, cur_sq_y, 3);
+    goto donewall;
+  }
+  candidates[num_candidates++] = 3;
+  
+ donewall:
+  if (num_candidates == 0)
+    return ( -1 );
+  if (num_candidates == 1)
+    return ( candidates[0] );
+  return ( candidates[ get_random(num_candidates) ] );
+  
+}
+
+
+static int
+backup()                                                  /* back up a move */
+{
+  sqnum--;
+  cur_sq_x = move_list[sqnum].x;
+  cur_sq_y = move_list[sqnum].y;
+  return ( sqnum );
+}
+
+
+draw_maze_border()                                  /* draw the maze outline */
+{
+  register int i, j;
+  
+  
+  for ( i=0; i<maze_size_x; i++) {
+    if ( maze[i][0] & WALL_TOP ) {
+      XDrawLine(dpy, win, gc,
+               border_x + grid_width * i,
+               border_y,
+               border_x + grid_width * (i+1) - 1,
+               border_y);
+    }
+    if ((maze[i][maze_size_y - 1] & WALL_BOTTOM)) {
+      XDrawLine(dpy, win, gc,
+               border_x + grid_width * i,
+               border_y + grid_height * (maze_size_y) - 1,
+               border_x + grid_width * (i+1) - 1,
+               border_y + grid_height * (maze_size_y) - 1);
+    }
+  }
+  for ( j=0; j<maze_size_y; j++) {
+    if ( maze[maze_size_x - 1][j] & WALL_RIGHT ) {
+      XDrawLine(dpy, win, gc,
+               border_x + grid_width * maze_size_x - 1,
+               border_y + grid_height * j,
+               border_x + grid_width * maze_size_x - 1,
+               border_y + grid_height * (j+1) - 1);
+    }
+    if ( maze[0][j] & WALL_LEFT ) {
+      XDrawLine(dpy, win, gc,
+               border_x,
+               border_y + grid_height * j,
+               border_x,
+               border_y + grid_height * (j+1) - 1);
+    }
+  }
+  
+  if (logo_x != -1)
+    {
+      Window r;
+      int x, y;
+      unsigned int w, h, bw, d;
+      XGetGeometry (dpy, logo_map, &r, &x, &y, &w, &h, &bw, &d);
+      XCopyPlane (dpy, logo_map, win, logo_gc,
+                 0, 0, w, h,
+                 border_x + 3 + grid_width * logo_x,
+                 border_y + 3 + grid_height * logo_y, 1);
+    }
+  draw_solid_square (start_x, start_y, start_dir, tgc);
+  draw_solid_square (end_x, end_y, end_dir, tgc);
+}
+
+
+static void
+draw_wall(i, j, dir)                                   /* draw a single wall */
+     int i, j, dir;
+{
+  switch (dir) {
+  case 0:
+    XDrawLine(dpy, win, gc,
+             border_x + grid_width * i, 
+             border_y + grid_height * j,
+             border_x + grid_width * (i+1), 
+             border_y + grid_height * j);
+    break;
+  case 1:
+    XDrawLine(dpy, win, gc,
+             border_x + grid_width * (i+1), 
+             border_y + grid_height * j,
+             border_x + grid_width * (i+1), 
+             border_y + grid_height * (j+1));
+    break;
+  case 2:
+    XDrawLine(dpy, win, gc,
+             border_x + grid_width * i, 
+             border_y + grid_height * (j+1),
+             border_x + grid_width * (i+1), 
+             border_y + grid_height * (j+1));
+    break;
+  case 3:
+    XDrawLine(dpy, win, gc,
+             border_x + grid_width * i, 
+             border_y + grid_height * j,
+             border_x + grid_width * i, 
+             border_y + grid_height * (j+1));
+    break;
+  }
+}
+
+int bw;
+
+static void
+draw_solid_square(i, j, dir, gc)          /* draw a solid square in a square */
+     register int i, j, dir;
+     GC        gc;
+{
+  switch (dir) {
+  case 0: XFillRectangle(dpy, win, gc,
+                        border_x + bw + grid_width * i, 
+                        border_y - bw + grid_height * j, 
+                        grid_width - (bw+bw), grid_height);
+    break;
+  case 1: XFillRectangle(dpy, win, gc,
+                        border_x + bw + grid_width * i, 
+                        border_y + bw + grid_height * j, 
+                        grid_width, grid_height - (bw+bw));
+    break;
+  case 2: XFillRectangle(dpy, win, gc,
+                        border_x + bw + grid_width * i, 
+                        border_y + bw + grid_height * j, 
+                        grid_width - (bw+bw), grid_height);
+    break;
+  case 3: XFillRectangle(dpy, win, gc,
+                        border_x - bw + grid_width * i, 
+                        border_y + bw + grid_height * j, 
+                        grid_width, grid_height - (bw+bw));
+    break;
+  }
+  XSync (dpy, False);
+}
+
+
+solve_maze()                             /* solve it with graphical feedback */
+{
+  int i;
+  
+  
+  /* plug up the surrounding wall */
+  maze[start_x][start_y] |= (WALL_TOP >> start_dir);
+  maze[end_x][end_y] |= (WALL_TOP >> end_dir);
+  
+  /* initialize search path */
+  i = 0;
+  path[i].x = end_x;
+  path[i].y = end_y;
+  path[i].dir = -1;
+  
+  /* do it */
+  while (1) {
+    if ( ++path[i].dir >= 4 ) {
+      i--;
+      draw_solid_square( (int)(path[i].x), (int)(path[i].y), 
+                       (int)(path[i].dir), cgc);
+    }
+    else if ( ! (maze[path[i].x][path[i].y] & 
+                (WALL_TOP >> path[i].dir))  && 
+            ( (i == 0) || ( (path[i].dir != 
+                             (int)(path[i-1].dir+2)%4) ) ) ) {
+      enter_square(i);
+      i++;
+      if ( maze[path[i].x][path[i].y] & START_SQUARE ) {
+       return;
+      }
+    } 
+    if (check_events()) return;
+    /* Abort solve on expose - cheapo repaint strategy */
+    if (solve_delay) usleep (solve_delay);
+  }
+} 
+
+
+static void
+enter_square(n)                            /* move into a neighboring square */
+     int n;
+{
+  draw_solid_square( (int)path[n].x, (int)path[n].y, 
+                   (int)path[n].dir, tgc);
+  
+  path[n+1].dir = -1;
+  switch (path[n].dir) {
+  case 0: path[n+1].x = path[n].x;
+    path[n+1].y = path[n].y - 1;
+    break;
+  case 1: path[n+1].x = path[n].x + 1;
+    path[n+1].y = path[n].y;
+    break;
+  case 2: path[n+1].x = path[n].x;
+    path[n+1].y = path[n].y + 1;
+    break;
+  case 3: path[n+1].x = path[n].x - 1;
+    path[n+1].y = path[n].y;
+    break;
+  }
+}
+
+/* ----<eof> */
+
+
+/*
+ *  jmr additions for Jamie Zawinski's <jwz@lucid.com> screensaver stuff,
+ *  note that the code above this has probably been hacked about in some
+ *  arbitrary way.
+ */
+
+char *progclass = "Maze";
+
+char *defaults[] = {
+  "*gridSize:  0",
+  "*background:        black",
+  "*solveDelay:        5000",
+  "*preDelay:  2000000",
+  "*postDelay: 4000000",
+  "*liveColor: green",
+  "*deadColor: red",
+#ifdef XROGER
+  "*logoColor: red3",
+#endif
+  0
+};
+
+XrmOptionDescRec options[] = {
+  { "-grid-size",      ".gridSize",    XrmoptionSepArg, 0 },
+  { "-solve-delay",    ".solveDelay",  XrmoptionSepArg, 0 },
+  { "-pre-delay",      ".preDelay",    XrmoptionSepArg, 0 },
+  { "-post-delay",     ".postDelay",   XrmoptionSepArg, 0 },
+  { "-live-color",     ".liveColor",   XrmoptionSepArg, 0 },
+  { "-dead-color",     ".deadColor",   XrmoptionSepArg, 0 }
+};
+
+int options_size = (sizeof(options)/sizeof(options[0]));
+
+void screenhack(display,window)
+     Display *display;
+     Window window;
+{
+  Pixmap gray;
+  int size, root;
+  XWindowAttributes xgwa;
+  unsigned long bg, fg, pfg, pbg, lfg;
+
+  size = get_integer_resource ("gridSize", "Dimension");
+  root = get_boolean_resource("root", "Boolean");
+  solve_delay = get_integer_resource ("solveDelay", "Integer");
+  pre_solve_delay = get_integer_resource ("preDelay", "Integer");
+  post_solve_delay = get_integer_resource ("postDelay", "Integer");
+
+  if (size < 2) size = 7 + (random () % 30);
+  grid_width = grid_height = size;
+  bw = (size > 6 ? 3 : (size-1)/2);
+
+  dpy = display; win = window; /* the maze stuff uses global variables */
+
+  XGetWindowAttributes (dpy, win, &xgwa);
+
+  x = 0;
+  y = 0;
+
+  set_maze_sizes (xgwa.width, xgwa.height);
+
+  if (! root)
+    XSelectInput (dpy, win, ExposureMask|ButtonPressMask|StructureNotifyMask);
+  
+  gc = XCreateGC(dpy, win, 0, 0);
+  cgc = XCreateGC(dpy, win, 0, 0);
+  tgc = XCreateGC(dpy,win,0,0);
+  logo_gc = XCreateGC(dpy, win, 0, 0);
+  
+  gray = XCreateBitmapFromData (dpy,win,gray1_bits,gray1_width,gray1_height);
+
+  bg  = get_pixel_resource ("background","Background", dpy, xgwa.colormap);
+  fg  = get_pixel_resource ("foreground","Foreground", dpy, xgwa.colormap);
+  lfg = get_pixel_resource ("logoColor", "Foreground", dpy, xgwa.colormap);
+  pfg = get_pixel_resource ("liveColor", "Foreground", dpy, xgwa.colormap);
+  pbg = get_pixel_resource ("deadColor", "Foreground", dpy, xgwa.colormap);
+  if (mono_p) lfg = pfg = fg;
+
+  if (lfg == bg)
+    lfg = ((bg == WhitePixel (dpy, DefaultScreen (dpy)))
+          ? BlackPixel (dpy, DefaultScreen (dpy))
+          : WhitePixel (dpy, DefaultScreen (dpy)));
+
+  XSetForeground (dpy, gc, fg);
+  XSetBackground (dpy, gc, bg);
+  XSetForeground (dpy, cgc, pbg);
+  XSetBackground (dpy, cgc, bg);
+  XSetForeground (dpy, tgc, pfg);
+  XSetBackground (dpy, tgc, bg);
+  XSetForeground (dpy, logo_gc, lfg);
+  XSetBackground (dpy, logo_gc, bg);
+
+  XSetStipple (dpy, cgc, gray);
+  XSetFillStyle (dpy, cgc, FillOpaqueStippled);
+  
+#ifdef XROGER
+  {
+    int w, h;
+    XGCValues gcv;
+    GC draw_gc, erase_gc;
+    extern void skull ();
+    /* round up to grid size */
+    w = ((logo_width  / grid_width) + 1)  * grid_width;
+    h = ((logo_height / grid_height) + 1) * grid_height;
+    logo_map = XCreatePixmap (dpy, win, w, h, 1);
+    gcv.foreground = 1L;
+    draw_gc = XCreateGC (dpy, logo_map, GCForeground, &gcv);
+    gcv.foreground = 0L;
+    erase_gc= XCreateGC (dpy, logo_map, GCForeground, &gcv);
+    XFillRectangle (dpy, logo_map, erase_gc, 0, 0, w, h);
+    skull (dpy, logo_map, draw_gc, erase_gc, 5, 0, w-10, h-10);
+    XFreeGC (dpy, draw_gc);
+    XFreeGC (dpy, erase_gc);
+  }
+#else
+  if  (!(logo_map = XCreateBitmapFromData (dpy, win, logo_bits,
+                                          logo_width, logo_height)))
+    {
+      fprintf (stderr, "Can't create logo pixmap\n");
+      exit (1);
+    }
+#endif
+  XMapRaised(dpy, win);
+  srandom(getpid());
+
+  restart = root;
+
+  while (1) {                            /* primary execution loop [ rhess ] */
+    if (check_events()) continue ;
+    if (restart || stop) goto pop;
+    switch (state) {
+    case 1:
+      initialize_maze();
+      break;
+    case 2:
+      XClearWindow(dpy, win);
+      draw_maze_border();
+      break;
+    case 3:
+      create_maze();
+      break;
+    case 4:
+      XSync (dpy, False);
+      usleep (pre_solve_delay);
+      break;
+    case 5:
+      solve_maze();
+      break;
+    case 6:
+      XSync (dpy, False);
+      usleep (post_solve_delay);
+      state = 0 ;
+      break;
+    default:
+      abort ();
+    }
+    ++state;
+  pop:
+    if (restart)
+      {
+       static XWindowAttributes wattr;
+       restart = 0;
+       stop = 0;
+       state = 1;
+       XGetWindowAttributes (dpy, win, &wattr);
+       set_maze_sizes (wattr.width, wattr.height);
+       XClearWindow (dpy, win);
+       XSync (dpy, False);
+      }
+  }
+}
diff --git a/hacks/maze.man b/hacks/maze.man
new file mode 100644 (file)
index 0000000..10d0cea
--- /dev/null
@@ -0,0 +1,97 @@
+.TH XScreenSaver 1 "7-mar-93" "X Version 11"
+.SH NAME
+maze \- an automated X11 demo repeatedly creating and solving a random maze
+.SH SYNOPSIS
+.B maze 
+[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root] [\-grid\-size \fIpixels\fP] [\-live\-color \fIcolor\fP] [\-dead\-color \fIcolor\fP] [\-solve\-delay \fIusecs\fP] [\-pre\-delay \fIusecs\fP] [\-post\-delay \fIusecs\fP]
+.SH DESCRIPTION
+The \fImaze\fP program creates a "random" maze and then solves it with 
+graphical feedback. 
+.SH OPTIONS
+.I maze
+accepts the following options:
+.TP 8
+.B \-window
+Draw on a newly-created window.  This is the default.
+.TP 8
+.B \-root
+Draw on the root window.
+.TP 8
+.B \-grid\-size pixels
+The size of each block of the maze, in pixels; default is 0, meaning
+pick a random grid size.
+.TP 8
+.B \-live\-color color
+The color of the path.
+.TP 8
+.B \-dead\-color color
+The color of the failed path (it is also stippled with a 50% pattern.)
+.TP 8
+.B \-solve\-delay integer
+Delay (in microseconds) between each step of the solution path.
+Default 5000, or about 1/200th second.
+.TP 8
+.B \-pre\-delay integer
+Delay (in microseconds) between generating a maze and starting to solve it.
+Default 2000000 (2 seconds.)
+.TP 8
+.B \-post\-delay integer
+Delay (in microseconds) after solving a maze and before generating a new one.
+Default 4000000 (4 seconds.)
+.PP
+Clicking the mouse in the maze window controls it.
+.IP "\fBLeftButton\fP"
+Clears the window and restarts maze.
+.IP "\fBMiddleButton\fP"
+Pause or unpause the program.
+.IP "\fBRightButton\fP"
+Exit.
+.SH BUGS
+Expose events force a restart of maze.
+
+Mouse actions are based on "raw" values (Button1, Button2 and Button3)
+instead of using the pointer map.
+.SH ENVIRONMENT
+.PP
+.TP 8
+.B DISPLAY
+to get the default host and display number.
+.TP 8
+.B XENVIRONMENT
+to get the name of a resource file that overrides the global resources
+stored in the RESOURCE_MANAGER property.
+.SH SEE ALSO
+.BR X (1),
+.BR xscreensaver (1)
+.SH COPYRIGHT
+.PP
+Copyright \(co 1988 by Sun Microsystems, Inc. Mountain View, CA.
+.PP  
+All Rights Reserved
+.PP
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided that
+the above copyright notice appear in all copies and that both that copyright
+notice and this permission notice appear in supporting documentation, and that
+the names of Sun or MIT not be used in advertising or publicity pertaining to
+distribution of the software without specific prior written permission. Sun
+and M.I.T.  make no representations about the suitability of this software for
+any purpose. It is provided "as is" without any express or implied warranty.
+.PP
+SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN
+NO EVENT SHALL SUN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.SH AUTHOR(s)
+.nf
+Jim Randell    [ XScreenSaver version ] jmr@mddjmr.fc.hp.com
+  HPLabs, Bristol
+Richard Hess   [ X11 extensions ]      {...}!uunet!cimshop!rhess
+  Consilium, Mountain View, CA
+Dave Lemke     [ X11 version ]         lemke@sun.COM
+  Sun MicroSystems, Mountain View, CA
+Martin Weiss   [ SunView version ]
+  Sun MicroSystems, Mountain View, CA
+.fi
diff --git a/hacks/noseguy.c b/hacks/noseguy.c
new file mode 100644 (file)
index 0000000..4707d42
--- /dev/null
@@ -0,0 +1,630 @@
+/* xscreensaver, Copyright (c) 1992 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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.
+ */
+
+/* Make a little guy with a big nose and a hat wanter around the screen,
+   spewing out messages.  Derived from xnlock by Dan Heller <argv@sun.com>.
+ */
+
+#include "screenhack.h"
+#include <stdio.h>
+
+#if __STDC__
+extern FILE *popen (const char *, const char *);
+extern int pclose (FILE *);
+#endif
+
+#define Pixel unsigned long
+
+#define font_height(font)              (font->ascent + font->descent)
+#define FONT_NAME                      "-*-times-*-*-*-*-18-*-*-*-*-*-*-*"
+
+static Display *dpy;
+static Window window;
+static int Width, Height;
+static GC fg_gc, bg_gc, text_fg_gc, text_bg_gc;
+static char *words, *get_words();
+static int x, y;
+static XFontStruct *font;
+static char *def_words = "I'm out running around.";
+static void init_images(), walk(), talk();
+static int think();
+static unsigned long interval, look(); 
+static Pixmap left0, left1, right0, right1;
+static Pixmap left_front, right_front, front, down;
+
+static char *program, *orig_program, *filename, *text;
+
+#define FROM_ARGV    1
+#define FROM_PROGRAM 2
+#define FROM_FILE    3
+#define FROM_RESRC   4
+static int getwordsfrom;
+
+#define IS_MOVING  1
+#define GET_PASSWD 2
+static int state;      /* indicates states: walking or getting passwd */
+
+static void (*next_fn) ();
+
+#include "noses/nose.0.left"
+#include "noses/nose.1.left"
+#include "noses/nose.0.right"
+#include "noses/nose.1.right"
+#include "noses/nose.left.front"
+#include "noses/nose.right.front"
+#include "noses/nose.front"
+#include "noses/nose.down"
+
+static void
+init_images ()
+{
+  static Pixmap *images[] = {
+    &left0, &left1, &right0, &right1,
+    &left_front, &right_front, &front, &down
+  };
+  static unsigned char *bits[] = {
+    nose_0_left_bits, nose_1_left_bits, nose_0_right_bits,
+    nose_1_right_bits, nose_left_front_bits, nose_right_front_bits,
+    nose_front_bits, nose_down_bits
+  };
+  int i;
+
+  for (i = 0; i < sizeof (images) / sizeof (images[0]); i++)
+    if (!(*images[i] =
+         XCreatePixmapFromBitmapData(dpy, window,
+                                     (char *) bits[i], 64, 64, 1, 0, 1)))
+      {
+       fprintf (stderr, "%s: Can't load nose images", progname);
+       exit (1);
+      }
+}
+
+#define LEFT   001
+#define RIGHT  002
+#define DOWN   004
+#define UP     010
+#define FRONT  020
+#define X_INCR 3
+#define Y_INCR 2
+
+static void
+move()
+{
+    static int      length,
+                    dir;
+
+    if (!length)
+    {
+       register int    tries = 0;
+       dir = 0;
+       if ((random() & 1) && think())
+       {
+           talk(0);            /* sets timeout to itself */
+           return;
+       }
+       if (!(random() % 3) && (interval = look()))
+       {
+           next_fn = move;
+           return;
+       }
+       interval = 20 + random() % 100;
+       do
+       {
+           if (!tries)
+               length = Width / 100 + random() % 90, tries = 8;
+           else
+               tries--;
+           switch (random() % 8)
+           {
+           case 0:
+               if (x - X_INCR * length >= 5)
+                   dir = LEFT;
+               break;
+           case 1:
+               if (x + X_INCR * length <= Width - 70)
+                   dir = RIGHT;
+               break;
+           case 2:
+               if (y - (Y_INCR * length) >= 5)
+                   dir = UP, interval = 40;
+               break;
+           case 3:
+               if (y + Y_INCR * length <= Height - 70)
+                   dir = DOWN, interval = 20;
+               break;
+           case 4:
+               if (x - X_INCR * length >= 5 && y - (Y_INCR * length) >= 5)
+                   dir = (LEFT | UP);
+               break;
+           case 5:
+               if (x + X_INCR * length <= Width - 70 &&
+                   y - Y_INCR * length >= 5)
+                   dir = (RIGHT | UP);
+               break;
+           case 6:
+               if (x - X_INCR * length >= 5 &&
+                   y + Y_INCR * length <= Height - 70)
+                   dir = (LEFT | DOWN);
+               break;
+           case 7:
+               if (x + X_INCR * length <= Width - 70 &&
+                   y + Y_INCR * length <= Height - 70)
+                   dir = (RIGHT | DOWN);
+               break;
+           default:
+               /* No Defaults */
+               break;
+           }
+       } while (!dir);
+    }
+    walk(dir);
+    --length;
+    next_fn = move;
+}
+
+static void
+walk(dir)
+    register int    dir;
+{
+    register int    incr = 0;
+    static int      lastdir;
+    static int      up = 1;
+    static Pixmap   frame;
+
+    if (dir & (LEFT | RIGHT))
+    {                          /* left/right movement (mabye up/down too) */
+       up = -up;               /* bouncing effect (even if hit a wall) */
+       if (dir & LEFT)
+       {
+           incr = X_INCR;
+           frame = (up < 0) ? left0 : left1;
+       }
+       else
+       {
+           incr = -X_INCR;
+           frame = (up < 0) ? right0 : right1;
+       }
+       if ((lastdir == FRONT || lastdir == DOWN) && dir & UP)
+       {
+
+           /*
+            * workaround silly bug that leaves screen dust when guy is
+            * facing forward or down and moves up-left/right.
+            */
+           XCopyPlane(dpy, frame, window, fg_gc, 0, 0, 64, 64, x, y, 1L);
+           XFlush(dpy);
+       }
+       /* note that maybe neither UP nor DOWN is set! */
+       if (dir & UP && y > Y_INCR)
+           y -= Y_INCR;
+       else if (dir & DOWN && y < Height - 64)
+           y += Y_INCR;
+    }
+    /* Explicit up/down movement only (no left/right) */
+    else if (dir == UP)
+       XCopyPlane(dpy, front, window, fg_gc,
+                  0, 0, 64, 64, x, y -= Y_INCR, 1L);
+    else if (dir == DOWN)
+       XCopyPlane(dpy, down, window, fg_gc,
+                  0, 0, 64, 64, x, y += Y_INCR, 1L);
+    else if (dir == FRONT && frame != front)
+    {
+       if (up > 0)
+           up = -up;
+       if (lastdir & LEFT)
+           frame = left_front;
+       else if (lastdir & RIGHT)
+           frame = right_front;
+       else
+           frame = front;
+       XCopyPlane(dpy, frame, window, fg_gc, 0, 0, 64, 64, x, y, 1L);
+    }
+    if (dir & LEFT)
+       while (--incr >= 0)
+       {
+           XCopyPlane(dpy, frame, window, fg_gc,
+                      0, 0, 64, 64, --x, y + up, 1L);
+           XFlush(dpy);
+       }
+    else if (dir & RIGHT)
+       while (++incr <= 0)
+       {
+           XCopyPlane(dpy, frame, window, fg_gc,
+                      0, 0, 64, 64, ++x, y + up, 1L);
+           XFlush(dpy);
+       }
+    lastdir = dir;
+}
+
+static int
+think()
+{
+    if (random() & 1)
+       walk(FRONT);
+    if (random() & 1)
+    {
+       if (getwordsfrom == FROM_PROGRAM)
+           words = get_words(0, (char **) 0);
+       return 1;
+    }
+    return 0;
+}
+
+#define MAXLINES 40
+
+static void
+talk(force_erase)
+    int             force_erase;
+{
+    int             width = 0,
+                    height,
+                    Z,
+                    total = 0;
+    static int      X,
+                    Y,
+                    talking;
+    static struct
+    {
+       int             x,
+                       y,
+                       width,
+                       height;
+    }               s_rect;
+    register char  *p,
+                   *p2;
+    char            buf[BUFSIZ],
+                    args[MAXLINES][256];
+
+    /* clear what we've written */
+    if (talking || force_erase)
+    {
+       if (!talking)
+           return;
+       XFillRectangle(dpy, window, bg_gc, s_rect.x - 5, s_rect.y - 5,
+                      s_rect.width + 10, s_rect.height + 10);
+       talking = 0;
+       if (!force_erase)
+         next_fn = move;
+       interval = 0;
+       {
+         /* might as well check the window for size changes now... */
+         XWindowAttributes xgwa;
+         XGetWindowAttributes (dpy, window, &xgwa);
+         Width = xgwa.width + 2;
+         Height = xgwa.height + 2;
+       }
+       return;
+    }
+    talking = 1;
+    walk(FRONT);
+    p = strcpy(buf, words);
+
+    if (!(p2 = index(p, '\n')) || !p2[1])
+      {
+       total = strlen (words);
+       strcpy (args[0], words);
+       width = XTextWidth(font, words, total);
+       height = 0;
+      }
+    else
+      /* p2 now points to the first '\n' */
+      for (height = 0; p; height++)
+       {
+         int             w;
+         *p2 = 0;
+         if ((w = XTextWidth(font, p, p2 - p)) > width)
+           width = w;
+         total += p2 - p;      /* total chars; count to determine reading
+                                * time */
+         (void) strcpy(args[height], p);
+         if (height == MAXLINES - 1)
+           {
+             puts("Message too long!");
+             break;
+           }
+         p = p2 + 1;
+         if (!(p2 = index(p, '\n')))
+           break;
+       }
+    height++;
+
+    /*
+     * Figure out the height and width in pixels (height, width) extend the
+     * new box by 15 pixels on the sides (30 total) top and bottom.
+     */
+    s_rect.width = width + 30;
+    s_rect.height = height * font_height(font) + 30;
+    if (x - s_rect.width - 10 < 5)
+       s_rect.x = 5;
+    else if ((s_rect.x = x + 32 - (s_rect.width + 15) / 2)
+            + s_rect.width + 15 > Width - 5)
+       s_rect.x = Width - 15 - s_rect.width;
+    if (y - s_rect.height - 10 < 5)
+       s_rect.y = y + 64 + 5;
+    else
+       s_rect.y = y - 5 - s_rect.height;
+
+    XFillRectangle(dpy, window, text_bg_gc,
+        s_rect.x, s_rect.y, s_rect.width, s_rect.height);
+
+    /* make a box that's 5 pixels thick. Then add a thin box inside it */
+    XSetLineAttributes(dpy, text_fg_gc, 5, 0, 0, 0);
+    XDrawRectangle(dpy, window, text_fg_gc,
+                  s_rect.x, s_rect.y, s_rect.width - 1, s_rect.height - 1);
+    XSetLineAttributes(dpy, text_fg_gc, 0, 0, 0, 0);
+    XDrawRectangle(dpy, window, text_fg_gc,
+        s_rect.x + 7, s_rect.y + 7, s_rect.width - 15, s_rect.height - 15);
+
+    X = 15;
+    Y = 15 + font_height(font);
+
+    /* now print each string in reverse order (start at bottom of box) */
+    for (Z = 0; Z < height; Z++)
+    {
+       XDrawString(dpy, window, text_fg_gc, s_rect.x + X, s_rect.y + Y,
+                   args[Z], strlen(args[Z]));
+       Y += font_height(font);
+    }
+    interval = (total / 15) * 1000;
+    if (interval < 2000) interval = 2000;
+    next_fn = talk;
+}
+
+static unsigned long
+look()
+{
+    if (random() % 3)
+    {
+       XCopyPlane(dpy, (random() & 1) ? down : front, window, fg_gc,
+                  0, 0, 64, 64, x, y, 1L);
+       return 1000L;
+    }
+    if (!(random() % 5))
+       return 0;
+    if (random() % 3)
+    {
+       XCopyPlane(dpy, (random() & 1) ? left_front : right_front,
+                  window, fg_gc, 0, 0, 64, 64, x, y, 1L);
+       return 1000L;
+    }
+    if (!(random() % 5))
+       return 0;
+    XCopyPlane(dpy, (random() & 1) ? left0 : right0, window, fg_gc,
+              0, 0, 64, 64, x, y, 1L);
+    return 1000L;
+}
+
+
+static void
+init_words()
+{
+  char *mode = get_string_resource ("mode", "Mode");
+
+  program = get_string_resource ("program", "Program");
+  filename = get_string_resource ("filename", "Filename");
+  text = get_string_resource ("text", "Text");
+
+  if (program) /* get stderr on stdout, so it shows up on the window */
+    {
+      orig_program = program;
+      program = (char *) malloc (strlen (program) + 10);
+      strcpy (program, "( ");
+      strcat (program, orig_program);
+      strcat (program, " ) 2>&1");
+    }
+
+  if (!mode || !strcmp (mode, "program"))
+    getwordsfrom = FROM_PROGRAM;
+  else if (!strcmp (mode, "file"))
+    getwordsfrom = FROM_FILE;
+  else if (!strcmp (mode, "string"))
+    getwordsfrom = FROM_RESRC;
+  else
+    {
+      fprintf (stderr,
+              "%s: mode must be program, file, or string, not %s\n",
+              progname, mode);
+      exit (1);
+    }
+
+  if (getwordsfrom == FROM_PROGRAM && !program)
+    {
+      fprintf (stderr, "%s: no program specified.\n", progname);
+      exit (1);
+    }
+  if (getwordsfrom == FROM_FILE && !filename)
+    {
+      fprintf (stderr, "%s: no file specified.\n", progname);
+      exit (1);
+    }
+
+  words = get_words(); 
+}
+
+static char *
+get_words()
+{
+    FILE           *pp;
+    static char     buf[BUFSIZ];
+    register char  *p = buf;
+
+    buf[0] = '\0';
+
+    switch (getwordsfrom)
+    {
+    case FROM_PROGRAM:
+       if (pp = popen(program, "r"))
+       {
+           while (fgets(p, sizeof(buf) - strlen(buf), pp))
+           {
+               if (strlen(buf) + 1 < sizeof(buf))
+                   p = buf + strlen(buf);
+               else
+                   break;
+           }
+           (void) pclose(pp);
+           if (! buf[0])
+             sprintf (buf, "\"%s\" produced no output!", orig_program);
+           p = buf;
+       }
+       else
+       {
+           perror(program);
+           p = def_words;
+       }
+       break;
+    case FROM_FILE:
+       if (pp = fopen(filename, "r"))
+       {
+           while (fgets(p, sizeof(buf) - strlen(buf), pp))
+           {
+               if (strlen(buf) + 1 < sizeof(buf))
+                   p = buf + strlen(buf);
+               else
+                   break;
+           }
+           (void) fclose(pp);
+           if (! buf[0])
+             sprintf (buf, "file \"%s\" is empty!", filename);
+           p = buf;
+       }
+       else
+       {
+         sprintf (buf, "couldn't read file \"%s\"!", filename);
+         p = buf;
+       }
+       break;
+    case FROM_RESRC:
+       p = text;
+       break;
+    default:
+       p = def_words;
+       break;
+    }
+
+    if (!p || *p == '\0')
+       p = def_words;
+    return p;
+}
+
+
+\f
+char *progclass = "Noseguy";
+
+char *defaults [] = {
+  "*background:                black",
+  "*foreground:                white",
+  "*mode:              program",
+  "*program:           fortune -s",
+  "noseguy.font:       -*-new century schoolbook-*-r-*-*-*-180-*-*-*-*-*-*",
+  0
+};
+
+XrmOptionDescRec options [] = {
+  { "-mode",           ".mode",                XrmoptionSepArg, 0 },
+  { "-program",                ".program",             XrmoptionSepArg, 0 },
+  { "-text",           ".text",                XrmoptionSepArg, 0 },
+  { "-filename",       ".filename",            XrmoptionSepArg, 0 },
+  { "-font",           ".font",                XrmoptionSepArg, 0 },
+  { "-text-foreground",        ".textForeground",      XrmoptionSepArg, 0 },
+  { "-text-background",        ".textBackground",      XrmoptionSepArg, 0 }
+};
+int options_size = (sizeof (options) / sizeof (options[0]));
+
+
+static void
+noseguy_init (d, w)
+     Display *d;
+     Window w;
+{
+  Pixel fg, bg, text_fg, text_bg;
+  XWindowAttributes xgwa;
+  Colormap cmap;
+  char *fontname = get_string_resource ("font", "Font");
+  char **list;
+  int foo, i;
+  XGCValues gcvalues;
+  dpy = d;
+  window = w;
+  XGetWindowAttributes (dpy, window, &xgwa);
+  Width = xgwa.width + 2;
+  Height = xgwa.height + 2;
+  cmap = xgwa.colormap;
+
+  init_words();
+  init_images();
+
+  if (!fontname || !(font = XLoadQueryFont(dpy, fontname)))
+    {
+       list = XListFonts(dpy, FONT_NAME, 32767, &foo);
+       for (i = 0; i < foo; i++)
+           if (font = XLoadQueryFont(dpy, list[i]))
+               break;
+       if (!font)
+         {
+           fprintf (stderr, "%s: Can't find a large font.", progname);
+           exit (1);
+         }
+       XFreeFontNames(list);
+    }
+
+  fg = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
+  bg = get_pixel_resource ("background", "Background", dpy, cmap);
+  text_fg = get_pixel_resource ("textForeground", "Foreground", dpy, cmap);
+  text_bg = get_pixel_resource ("textBackground", "Background", dpy, cmap);
+  /* notice when unspecified */
+  if (! get_string_resource ("textForeground", "Foreground"))
+    text_fg = bg;
+  if (! get_string_resource ("textBackground", "Background"))
+    text_bg = fg;
+
+  gcvalues.font = font->fid;
+  gcvalues.graphics_exposures = False;
+  gcvalues.foreground = fg;
+  gcvalues.background = bg;
+  fg_gc = XCreateGC (dpy, window,
+                    GCForeground|GCBackground|GCGraphicsExposures|GCFont,
+                    &gcvalues);
+  gcvalues.foreground = bg;
+  gcvalues.background = fg;
+  bg_gc = XCreateGC (dpy, window,
+                    GCForeground|GCBackground|GCGraphicsExposures|GCFont,
+                    &gcvalues);
+  gcvalues.foreground = text_fg;
+  gcvalues.background = text_bg;
+  text_fg_gc = XCreateGC (dpy, window,
+                         GCForeground|GCBackground|GCGraphicsExposures|GCFont,
+                         &gcvalues);
+  gcvalues.foreground = text_bg;
+  gcvalues.background = text_fg;
+  text_bg_gc = XCreateGC (dpy, window,
+                         GCForeground|GCBackground|GCGraphicsExposures|GCFont,
+                         &gcvalues);
+  x = Width / 2;
+  y = Height / 2;
+  state = IS_MOVING;
+}
+     
+void
+screenhack (d, w)
+     Display *d;
+     Window w;
+{
+  noseguy_init (d, w);
+  next_fn = move;
+  while (1)
+    {
+      next_fn (0);
+      XSync (dpy, True);
+      usleep (interval * 1000);
+    }
+}
+
diff --git a/hacks/noseguy.man b/hacks/noseguy.man
new file mode 100644 (file)
index 0000000..bd731a7
--- /dev/null
@@ -0,0 +1,67 @@
+.TH XScreenSaver 1 "13-aug-92" "X Version 11"
+.SH NAME
+noseguy - a little guy with a big nose wanders around being witty
+.SH SYNOPSIS
+.B noseguy
+[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-text-foreground \fIcolor\fP] [\-text-background \fIcolor\fP] [\-font \fIfont\fP] [\-window] [\-root] [\-mode \fImode\fP] [\-program \fIprogram\fP] [\-filename \file\fP] [\-text \fItext\fP]
+.SH DESCRIPTION
+A little man with a big nose and a hat runs around spewing out messages to
+the screen.  This code (and its bitmaps) were extracted from the \fIxnlock\fP
+program.
+.SH OPTIONS
+.I noseguy
+accepts the following options:
+.TP 8
+.B \-window
+Draw on a newly-created window.  This is the default.
+.TP 8
+.B \-root
+Draw on the root window.
+.TP 8
+.B \-font font
+The font used for the messages.
+.TP 8
+.B \-mode program | file | string
+In \fIprogram\fP mode, the messages are gotten by running a program.
+The program used is controlled by the \fI\-program\fP option, and 
+the \fI.program\fP resource.
+
+In \fIfilename\fP mode, the message used is the contents of a file.
+The file used is controlled by the \fI\-file\fP option, and 
+the \fI.filename\fP resource.
+
+In \fIstring\fP mode, the message is whatever was specified on the 
+command line as the \fI\-text\fP option, or in the resource database
+as the \fI.text\fP resource.
+.TP 8
+.B \-program " program"
+If \fImode\fP is \fIprogram\fP (the default), then this program will be
+run periodically, and its output will be the text of the messages.  The
+default program is \fI"fortune -s"\fP, but \fIyow\fP is also a good choice.
+.TP 8
+.B \-filename file
+If \fImode\fP is \fIfile\fP, then the contents of this file will be used
+for all messages.
+.TP 8
+.B \-text string
+If \fImode\fP is \fIstring\fP, then this text will be used for all messages.
+.SH ENVIRONMENT
+.PP
+.TP 8
+.B DISPLAY
+to get the default host and display number.
+.TP 8
+.B XENVIRONMENT
+to get the name of a resource file that overrides the global resources
+stored in the RESOURCE_MANAGER property.
+.SH SEE ALSO
+.BR X (1),
+.BR xscreensaver (1),
+.BR xnlock (1)
+.SH COPYRIGHT
+Copyright 1985, 1990 by Dan Heller <argv@sun.com>.
+.SH AUTHOR
+Dan Heller <argv@sun.com>, 1985.
+
+Ability to run standalone or with \fIxscreensaver\fP added by 
+Jamie Zawinski <jwz@lucid.com>, 13-aug-92.
diff --git a/hacks/noses/nose.0.left b/hacks/noses/nose.0.left
new file mode 100644 (file)
index 0000000..cb3d152
--- /dev/null
@@ -0,0 +1,38 @@
+#define nose_0_left_width 64
+#define nose_0_left_height 64
+static unsigned char nose_0_left_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x40,0x00,
+ 0x00,0x04,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x40,
+ 0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x04,0x00,0x00,0x00,0x00,
+ 0x40,0x00,0x00,0x04,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,
+ 0x08,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x20,0x00,
+ 0x00,0xf8,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0xf0,0x03,0x00,0x00,0x80,0x00,
+ 0x00,0x00,0x0e,0x0c,0x00,0x00,0x80,0x01,0x00,0x00,0x03,0x30,0x00,0x00,0x00,
+ 0x01,0x00,0x80,0x00,0x40,0x00,0x00,0x00,0x02,0x00,0x40,0x00,0xc0,0x00,0x00,
+ 0x00,0x02,0x00,0x20,0x00,0x80,0x00,0x00,0x00,0x04,0x00,0x10,0x00,0x00,0x00,
+ 0x00,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x08,0x00,0x00,
+ 0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x00,
+ 0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,
+ 0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,
+ 0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,
+ 0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x01,0x00,0x00,
+ 0x18,0x00,0x20,0x00,0x00,0x01,0x00,0x00,0x08,0x00,0x40,0x00,0x80,0x00,0x00,
+ 0x00,0x08,0x00,0x80,0x00,0x40,0x00,0x00,0x00,0x0c,0x00,0x00,0x01,0x20,0x00,
+ 0x00,0x00,0x04,0x00,0x00,0x06,0x18,0x00,0x00,0x00,0x06,0x00,0x00,0xf8,0x07,
+ 0x00,0x00,0x00,0x02,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0x01,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x0f,0x00,0x00,0x00,
+ 0x00,0xff,0x00,0x04,0x10,0x00,0x00,0x00,0xc0,0x00,0x03,0x03,0x10,0x00,0x00,
+ 0x00,0x30,0x00,0x0c,0x01,0x20,0x00,0x00,0x00,0x08,0x00,0x98,0x00,0x20,0x00,
+ 0x00,0x00,0x0c,0x03,0x60,0x00,0x20,0x00,0x00,0x00,0xc2,0x00,0xc0,0x00,0x20,
+ 0x00,0x00,0x00,0x42,0x00,0x80,0x00,0x20,0x00,0x00,0x00,0x21,0x00,0x00,0x01,
+ 0x20,0x00,0x00,0x00,0x21,0x00,0x00,0x01,0x20,0x00,0x00,0x00,0x21,0x00,0x00,
+ 0x00,0x20,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x01,0x00,
+ 0x00,0x00,0x40,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x02,
+ 0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x20,0x00,0x00,0x00,
+ 0x18,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x10,0x00,0x00,
+ 0x00,0xc0,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00};
diff --git a/hacks/noses/nose.0.right b/hacks/noses/nose.0.right
new file mode 100644 (file)
index 0000000..f387baa
--- /dev/null
@@ -0,0 +1,38 @@
+#define nose_0_right_width 64
+#define nose_0_right_height 64
+static unsigned char nose_0_right_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x20,0x00,
+ 0x00,0x02,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x20,
+ 0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x00,
+ 0x20,0x00,0x00,0x02,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,
+ 0x04,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x10,0x00,
+ 0x00,0xfc,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x01,0x00,0x00,0xc0,0x0f,
+ 0x00,0x00,0x80,0x01,0x00,0x00,0x30,0x70,0x00,0x00,0x80,0x00,0x00,0x00,0x0c,
+ 0xc0,0x00,0x00,0x40,0x00,0x00,0x00,0x02,0x00,0x01,0x00,0x40,0x00,0x00,0x00,
+ 0x03,0x00,0x02,0x00,0x20,0x00,0x00,0x00,0x01,0x00,0x04,0x00,0x20,0x00,0x00,
+ 0x00,0x00,0x00,0x08,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x10,0x00,
+ 0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,
+ 0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,
+ 0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,
+ 0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,
+ 0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x18,0x00,0x00,0x80,0x00,
+ 0x00,0x08,0x00,0x10,0x00,0x00,0x80,0x00,0x00,0x04,0x00,0x10,0x00,0x00,0x00,
+ 0x01,0x00,0x02,0x00,0x30,0x00,0x00,0x00,0x02,0x00,0x01,0x00,0x20,0x00,0x00,
+ 0x00,0x04,0x80,0x00,0x00,0x60,0x00,0x00,0x00,0x18,0x60,0x00,0x00,0x40,0x00,
+ 0x00,0x00,0xe0,0x1f,0x00,0x00,0x80,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x1f,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x08,0x20,0x00,0xff,0x00,0x00,0x00,0x00,0x08,0xc0,0xc0,0x00,0x03,0x00,
+ 0x00,0x00,0x04,0x80,0x30,0x00,0x0c,0x00,0x00,0x00,0x04,0x00,0x19,0x00,0x10,
+ 0x00,0x00,0x00,0x04,0x00,0x06,0xc0,0x30,0x00,0x00,0x00,0x04,0x00,0x03,0x00,
+ 0x43,0x00,0x00,0x00,0x04,0x00,0x01,0x00,0x42,0x00,0x00,0x00,0x04,0x80,0x00,
+ 0x00,0x84,0x00,0x00,0x00,0x04,0x80,0x00,0x00,0x84,0x00,0x00,0x00,0x04,0x00,
+ 0x00,0x00,0x84,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x02,
+ 0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x40,0x00,0x00,0x00,
+ 0x02,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x20,0x00,0x00,
+ 0x00,0x04,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x0e,0x00,
+ 0x00,0x00,0xf0,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00};
diff --git a/hacks/noses/nose.1.left b/hacks/noses/nose.1.left
new file mode 100644 (file)
index 0000000..8a6b829
--- /dev/null
@@ -0,0 +1,38 @@
+#define nose_1_left_width 64
+#define nose_1_left_height 64
+static unsigned char nose_1_left_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x40,0x00,
+ 0x00,0x04,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x40,
+ 0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x04,0x00,0x00,0x00,0x00,
+ 0x40,0x00,0x00,0x04,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,
+ 0x08,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x20,0x00,
+ 0x00,0xf8,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0xf0,0x03,0x00,0x00,0x80,0x00,
+ 0x00,0x00,0x0e,0x0c,0x00,0x00,0x80,0x01,0x00,0x00,0x03,0x30,0x00,0x00,0x00,
+ 0x01,0x00,0x80,0x00,0x40,0x00,0x00,0x00,0x02,0x00,0x40,0x00,0xc0,0x00,0x00,
+ 0x00,0x02,0x00,0x20,0x00,0x80,0x00,0x00,0x00,0x04,0x00,0x10,0x00,0x00,0x00,
+ 0x00,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x08,0x00,0x00,
+ 0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x00,
+ 0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,
+ 0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,
+ 0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,
+ 0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x01,0x00,0x00,
+ 0x18,0x00,0x10,0x00,0x00,0x01,0x00,0x00,0x08,0x00,0x20,0x00,0x80,0x00,0x00,
+ 0x00,0x08,0x00,0x40,0x00,0x40,0x00,0x00,0x00,0x0c,0x00,0x80,0x00,0x20,0x00,
+ 0x00,0x00,0xe4,0x00,0x00,0x03,0x18,0x00,0x00,0x00,0x26,0x03,0x00,0xfc,0x07,
+ 0x00,0x00,0x00,0x12,0x0c,0x00,0x00,0xf8,0xff,0xff,0xff,0x11,0x10,0x80,0x1f,
+ 0x00,0x00,0x00,0x00,0x08,0x20,0x60,0x60,0xc0,0x07,0x00,0x00,0x04,0x40,0x10,
+ 0xc0,0x20,0x08,0x00,0x1f,0x02,0x40,0x08,0x00,0x21,0x10,0xc0,0x60,0x02,0x40,
+ 0x04,0x00,0x12,0x20,0x20,0x80,0x02,0x20,0xc2,0x00,0x14,0x40,0x18,0x00,0x03,
+ 0x20,0x22,0x00,0x0c,0x80,0x04,0x03,0x02,0x10,0x12,0x00,0x08,0x80,0x86,0x00,
+ 0x04,0x10,0x12,0x00,0x10,0x80,0x42,0x00,0x18,0x08,0x12,0x00,0x10,0x40,0x42,
+ 0x00,0x00,0x04,0x02,0x00,0x20,0x40,0x42,0x00,0x00,0x04,0x02,0x00,0x00,0x20,
+ 0x42,0x00,0x00,0x02,0x04,0x00,0x00,0x20,0x02,0x00,0x00,0x01,0x04,0x00,0x00,
+ 0x20,0x02,0x00,0x00,0x01,0x08,0x00,0x00,0x20,0x04,0x00,0x80,0x00,0x10,0x00,
+ 0x00,0x20,0x0c,0x00,0x80,0x00,0x60,0x00,0x00,0x10,0x08,0x00,0x40,0x00,0x80,
+ 0xff,0xff,0x0f,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0x0f,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00};
diff --git a/hacks/noses/nose.1.right b/hacks/noses/nose.1.right
new file mode 100644 (file)
index 0000000..f7c8962
--- /dev/null
@@ -0,0 +1,38 @@
+#define nose_1_right_width 64
+#define nose_1_right_height 64
+static unsigned char nose_1_right_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x20,0x00,
+ 0x00,0x02,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x20,
+ 0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x00,
+ 0x20,0x00,0x00,0x02,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,
+ 0x04,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x10,0x00,
+ 0x00,0xfc,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0x00,0x01,0x00,0x00,0xc0,0x0f,
+ 0x00,0x00,0x80,0x01,0x00,0x00,0x30,0x70,0x00,0x00,0x80,0x00,0x00,0x00,0x0c,
+ 0xc0,0x00,0x00,0x40,0x00,0x00,0x00,0x02,0x00,0x01,0x00,0x40,0x00,0x00,0x00,
+ 0x03,0x00,0x02,0x00,0x20,0x00,0x00,0x00,0x01,0x00,0x04,0x00,0x20,0x00,0x00,
+ 0x00,0x00,0x00,0x08,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x10,0x00,
+ 0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,
+ 0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,
+ 0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,
+ 0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,
+ 0x10,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x18,0x00,0x00,0x80,0x00,
+ 0x00,0x08,0x00,0x10,0x00,0x00,0x80,0x00,0x00,0x08,0x00,0x10,0x00,0x00,0x00,
+ 0x01,0x00,0x04,0x00,0x30,0x00,0x00,0x00,0x02,0x00,0x02,0x00,0x27,0x00,0x00,
+ 0x00,0x04,0x00,0x01,0xc0,0x64,0x00,0x00,0x00,0x18,0xc0,0x00,0x30,0x48,0x00,
+ 0x00,0x00,0xe0,0x3f,0x00,0x08,0x88,0xff,0xff,0xff,0x1f,0x00,0x00,0x04,0x10,
+ 0x00,0x00,0x00,0x00,0xf8,0x01,0x02,0x20,0x00,0x00,0xe0,0x03,0x06,0x06,0x02,
+ 0x40,0xf8,0x00,0x10,0x04,0x03,0x08,0x02,0x40,0x06,0x03,0x08,0x84,0x00,0x10,
+ 0x04,0x40,0x01,0x04,0x04,0x48,0x00,0x20,0x04,0xc0,0x00,0x18,0x02,0x28,0x00,
+ 0x43,0x08,0x40,0xc0,0x20,0x01,0x30,0x00,0x44,0x08,0x20,0x00,0x61,0x01,0x10,
+ 0x00,0x48,0x10,0x18,0x00,0x42,0x01,0x08,0x00,0x48,0x20,0x00,0x00,0x42,0x02,
+ 0x08,0x00,0x48,0x20,0x00,0x00,0x42,0x02,0x04,0x00,0x40,0x40,0x00,0x00,0x42,
+ 0x04,0x00,0x00,0x40,0x80,0x00,0x00,0x40,0x04,0x00,0x00,0x20,0x80,0x00,0x00,
+ 0x40,0x04,0x00,0x00,0x20,0x00,0x01,0x00,0x20,0x04,0x00,0x00,0x10,0x00,0x01,
+ 0x00,0x30,0x04,0x00,0x00,0x08,0x00,0x02,0x00,0x10,0x08,0x00,0x00,0x06,0x00,
+ 0x0c,0x00,0x0c,0xf0,0xff,0xff,0x01,0x00,0xf0,0xff,0x03,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00};
diff --git a/hacks/noses/nose.down b/hacks/noses/nose.down
new file mode 100644 (file)
index 0000000..e8bdba4
--- /dev/null
@@ -0,0 +1,38 @@
+#define nose_down_width 64
+#define nose_down_height 64
+static unsigned char nose_down_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0xfc,0xff,0x01,0x00,0x00,0x00,0x00,0xc0,0x03,0x00,0x1e,0x00,
+ 0x00,0x00,0x00,0x38,0x00,0x00,0xe0,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,
+ 0x03,0x00,0x00,0x80,0x01,0x00,0x00,0x00,0x04,0x00,0x00,0x40,0x00,0x00,0x00,
+ 0x00,0x08,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x10,0x00,0x80,
+ 0x1f,0x00,0x40,0x00,0x00,0x08,0x00,0x60,0x60,0x00,0x80,0x00,0x00,0x08,0x00,
+ 0x10,0x80,0x00,0x80,0x00,0x00,0x04,0x00,0x08,0x00,0x01,0x00,0x01,0x00,0x04,
+ 0x00,0x08,0x00,0x01,0x00,0x01,0x00,0x02,0x00,0x18,0x80,0x01,0x00,0x02,0x00,
+ 0x02,0x00,0x68,0x60,0x01,0x00,0x02,0x00,0x02,0x00,0x88,0x1f,0x01,0x00,0x02,
+ 0x00,0x02,0x00,0x08,0x00,0x01,0x00,0x02,0x00,0x02,0x00,0x10,0x80,0x00,0x00,
+ 0x03,0x00,0x06,0x00,0x60,0x60,0x00,0x80,0x02,0x00,0x0c,0x00,0x80,0x1f,0x00,
+ 0x40,0x01,0x00,0x14,0x00,0x00,0x00,0x00,0x20,0x01,0x00,0x28,0x00,0x00,0x00,
+ 0x00,0x90,0x00,0x00,0x50,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0xa0,0x01,0x00,
+ 0x00,0x00,0x26,0x00,0x00,0x40,0x1e,0x00,0x00,0xc0,0x11,0x00,0x00,0x80,0xe1,
+ 0x03,0x00,0x3c,0x0c,0x00,0x00,0x00,0x0e,0xfc,0xff,0x83,0x03,0x00,0x00,0x00,
+ 0xf0,0x01,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0xfe,0xff,0x0f,0x00,0x00,0x00,
+ 0x00,0x80,0x03,0x00,0x0c,0x00,0x00,0x00,0x00,0x80,0x02,0x00,0x14,0x00,0x00,
+ 0x00,0x00,0x60,0x04,0x00,0x12,0x00,0x00,0xc0,0x7f,0x10,0x04,0x00,0x22,0xe0,
+ 0x01,0x70,0xc0,0x18,0x08,0x00,0x61,0x1c,0x06,0x10,0x00,0x0f,0x30,0xc0,0x80,
+ 0x07,0x08,0x08,0x00,0x06,0xc0,0x3f,0x80,0x01,0x08,0x08,0x00,0x18,0x00,0x02,
+ 0xc0,0x00,0x10,0x04,0x00,0x30,0x00,0x05,0x30,0x00,0x10,0x04,0x00,0x00,0x80,
+ 0x08,0x18,0x00,0x20,0x04,0x00,0x00,0x80,0x08,0x00,0x00,0x20,0x04,0x00,0x00,
+ 0x40,0x10,0x00,0x00,0x20,0x24,0x00,0x00,0x40,0x10,0x00,0x00,0x22,0x24,0x00,
+ 0x00,0x40,0x10,0x00,0x00,0x22,0x44,0x00,0x00,0x40,0x10,0x00,0x00,0x11,0x84,
+ 0x01,0x00,0xc0,0x18,0x00,0xc0,0x10,0x08,0x00,0x00,0x80,0x08,0x00,0x00,0x08,
+ 0x30,0x00,0x00,0x80,0x08,0x00,0x00,0x04,0xe0,0xff,0xff,0xff,0xf8,0xff,0xff,
+ 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00};
diff --git a/hacks/noses/nose.front b/hacks/noses/nose.front
new file mode 100644 (file)
index 0000000..64b8201
--- /dev/null
@@ -0,0 +1,38 @@
+#define nose_front_width 64
+#define nose_front_height 64
+static unsigned char nose_front_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x40,0x00,
+ 0x00,0x04,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x40,
+ 0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x04,0x00,0x00,0x00,0x00,
+ 0x40,0x00,0x00,0x04,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,
+ 0x08,0x00,0xc0,0x1f,0x00,0x20,0x00,0x00,0x08,0x00,0x30,0x60,0x00,0x20,0x00,
+ 0x00,0xf8,0xff,0x0f,0x80,0xff,0x3f,0x00,0x00,0x00,0x02,0x02,0x00,0x82,0x00,
+ 0x00,0x00,0x00,0x03,0x01,0x00,0x84,0x01,0x00,0x00,0x00,0x81,0x00,0x00,0x08,
+ 0x01,0x00,0x00,0x80,0x80,0x00,0x00,0x08,0x02,0x00,0x00,0x80,0x40,0x00,0x00,
+ 0x10,0x02,0x00,0x00,0x40,0x40,0x00,0x00,0x10,0x04,0x00,0x00,0x40,0x20,0x00,
+ 0x00,0x20,0x04,0x00,0x00,0x60,0x20,0x00,0x00,0x20,0x0c,0x00,0x00,0x20,0x20,
+ 0x00,0x00,0x20,0x08,0x00,0x00,0x20,0x20,0x00,0x00,0x20,0x08,0x00,0x00,0x10,
+ 0x20,0x00,0x00,0x20,0x10,0x00,0x00,0x10,0x20,0x00,0x00,0x20,0x10,0x00,0x00,
+ 0x10,0x20,0x00,0x00,0x20,0x10,0x00,0x00,0x10,0x40,0x00,0x00,0x10,0x10,0x00,
+ 0x00,0x10,0x40,0x00,0x00,0x10,0x10,0x00,0x00,0x10,0x80,0x00,0x00,0x08,0x10,
+ 0x00,0x00,0x10,0x80,0x00,0x00,0x08,0x10,0x00,0x00,0x30,0x00,0x01,0x00,0x04,
+ 0x18,0x00,0x00,0x20,0x00,0x02,0x00,0x02,0x08,0x00,0x00,0x20,0x00,0x0c,0x80,
+ 0x01,0x08,0x00,0x00,0x60,0x00,0x30,0x60,0x00,0x0c,0x00,0x00,0x40,0x00,0xc0,
+ 0x1f,0x00,0x04,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x01,
+ 0x00,0x00,0x00,0x02,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0x01,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x0f,0xc0,0x0f,0x00,0x00,0x00,
+ 0x00,0x40,0x10,0x20,0x10,0x00,0x00,0x00,0x00,0x20,0x60,0x30,0x20,0x00,0x00,
+ 0x00,0x00,0x20,0xc0,0x18,0x20,0x00,0x00,0xc0,0x7f,0x10,0x80,0x0d,0x40,0xe0,
+ 0x01,0x70,0xc0,0x18,0x00,0x05,0x40,0x1c,0x06,0x10,0x00,0x0f,0x00,0x05,0x80,
+ 0x07,0x08,0x08,0x00,0x06,0x00,0x05,0x80,0x01,0x08,0x08,0x00,0x18,0x00,0x05,
+ 0xc0,0x00,0x10,0x04,0x00,0x30,0x00,0x05,0x30,0x00,0x10,0x04,0x00,0x00,0x80,
+ 0x08,0x18,0x00,0x20,0x04,0x00,0x00,0x80,0x08,0x00,0x00,0x20,0x04,0x00,0x00,
+ 0x40,0x10,0x00,0x00,0x20,0x24,0x00,0x00,0x40,0x10,0x00,0x00,0x22,0x24,0x00,
+ 0x00,0x40,0x10,0x00,0x00,0x22,0x44,0x00,0x00,0x40,0x10,0x00,0x00,0x11,0x84,
+ 0x01,0x00,0xc0,0x18,0x00,0xc0,0x10,0x08,0x00,0x00,0x80,0x08,0x00,0x00,0x08,
+ 0x30,0x00,0x00,0x80,0x08,0x00,0x00,0x04,0xe0,0xff,0xff,0xff,0xf8,0xff,0xff,
+ 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00};
diff --git a/hacks/noses/nose.left.front b/hacks/noses/nose.left.front
new file mode 100644 (file)
index 0000000..3a871ea
--- /dev/null
@@ -0,0 +1,38 @@
+#define nose_left_front_width 64
+#define nose_left_front_height 64
+static unsigned char nose_left_front_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0x40,0x00,
+ 0x00,0x04,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x40,
+ 0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x04,0x00,0x00,0x00,0x00,
+ 0x40,0x00,0x00,0x04,0x00,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,
+ 0x08,0x00,0xe0,0x0f,0x00,0x20,0x00,0x00,0x08,0x00,0x18,0x30,0x00,0x20,0x00,
+ 0x00,0xf8,0xff,0x07,0xc0,0xff,0x3f,0x00,0x00,0x00,0x02,0x01,0x00,0x81,0x00,
+ 0x00,0x00,0x00,0x83,0x00,0x00,0x82,0x01,0x00,0x00,0x00,0x41,0x00,0x00,0x04,
+ 0x01,0x00,0x00,0x80,0x40,0x00,0x00,0x04,0x02,0x00,0x00,0x80,0x20,0x00,0x00,
+ 0x08,0x02,0x00,0x00,0x40,0x20,0x00,0x00,0x08,0x04,0x00,0x00,0x40,0x10,0x00,
+ 0x00,0x10,0x04,0x00,0x00,0x60,0x10,0x00,0x00,0x10,0x0c,0x00,0x00,0x20,0x10,
+ 0x00,0x00,0x10,0x08,0x00,0x00,0x30,0x10,0x00,0x00,0x10,0x08,0x00,0x00,0x10,
+ 0x10,0x00,0x00,0x10,0x10,0x00,0x00,0x10,0x10,0x00,0x00,0x10,0x10,0x00,0x00,
+ 0x10,0x10,0x00,0x00,0x10,0x10,0x00,0x00,0x10,0x20,0x00,0x00,0x08,0x10,0x00,
+ 0x00,0x10,0x20,0x00,0x00,0x08,0x10,0x00,0x00,0x10,0x40,0x00,0x00,0x04,0x10,
+ 0x00,0x00,0x30,0x40,0x00,0x00,0x04,0x10,0x00,0x00,0x20,0x80,0x00,0x00,0x02,
+ 0x18,0x00,0x00,0x20,0x00,0x01,0x00,0x01,0x08,0x00,0x00,0x60,0x00,0x06,0xc0,
+ 0x00,0x08,0x00,0x00,0x80,0x00,0x18,0x30,0x00,0x0c,0x00,0x00,0x80,0x00,0xe0,
+ 0x0f,0x00,0x04,0x00,0x00,0x80,0x01,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x01,
+ 0x00,0x00,0x00,0x02,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0x01,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x0f,0x00,0x00,0x00,
+ 0x00,0xff,0x00,0x04,0x10,0x00,0x00,0x00,0xe0,0x00,0x07,0x02,0x10,0x00,0x00,
+ 0x00,0x30,0x00,0x8c,0x01,0x20,0x00,0x00,0x00,0x0c,0x00,0x90,0x00,0x20,0x00,
+ 0x00,0x00,0x04,0x03,0x60,0x00,0x20,0x00,0x00,0x00,0xc2,0x00,0xc0,0x00,0x20,
+ 0x00,0x00,0x00,0x42,0x00,0x00,0x01,0x20,0x00,0x00,0x00,0x21,0x00,0x00,0x02,
+ 0x20,0x00,0x00,0x00,0x21,0x00,0x00,0x06,0x20,0x00,0x00,0x00,0x21,0x00,0x00,
+ 0x00,0x20,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x03,0x00,
+ 0x00,0x00,0x40,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x02,
+ 0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x20,0x00,0x00,0x00,
+ 0x18,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x10,0x00,0x00,
+ 0x00,0xc0,0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00};
diff --git a/hacks/noses/nose.right.front b/hacks/noses/nose.right.front
new file mode 100644 (file)
index 0000000..f821417
--- /dev/null
@@ -0,0 +1,38 @@
+#define nose_right_front_width 64
+#define nose_right_front_height 64
+static unsigned char nose_right_front_bits[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x20,0x00,
+ 0x00,0x02,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x20,
+ 0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x00,
+ 0x20,0x00,0x00,0x02,0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,
+ 0x04,0x00,0xf0,0x07,0x00,0x10,0x00,0x00,0x04,0x00,0x0c,0x18,0x00,0x10,0x00,
+ 0x00,0xfc,0xff,0x03,0xe0,0xff,0x1f,0x00,0x00,0x00,0x81,0x00,0x80,0x40,0x00,
+ 0x00,0x00,0x80,0x41,0x00,0x00,0xc1,0x00,0x00,0x00,0x80,0x20,0x00,0x00,0x82,
+ 0x00,0x00,0x00,0x40,0x20,0x00,0x00,0x02,0x01,0x00,0x00,0x40,0x10,0x00,0x00,
+ 0x04,0x01,0x00,0x00,0x20,0x10,0x00,0x00,0x04,0x02,0x00,0x00,0x20,0x08,0x00,
+ 0x00,0x08,0x02,0x00,0x00,0x30,0x08,0x00,0x00,0x08,0x06,0x00,0x00,0x10,0x08,
+ 0x00,0x00,0x08,0x04,0x00,0x00,0x10,0x08,0x00,0x00,0x08,0x0c,0x00,0x00,0x08,
+ 0x08,0x00,0x00,0x08,0x08,0x00,0x00,0x08,0x08,0x00,0x00,0x08,0x08,0x00,0x00,
+ 0x08,0x08,0x00,0x00,0x08,0x08,0x00,0x00,0x08,0x10,0x00,0x00,0x04,0x08,0x00,
+ 0x00,0x08,0x10,0x00,0x00,0x04,0x08,0x00,0x00,0x08,0x20,0x00,0x00,0x02,0x08,
+ 0x00,0x00,0x08,0x20,0x00,0x00,0x02,0x0c,0x00,0x00,0x18,0x40,0x00,0x00,0x01,
+ 0x04,0x00,0x00,0x10,0x80,0x00,0x80,0x00,0x04,0x00,0x00,0x10,0x00,0x03,0x60,
+ 0x00,0x06,0x00,0x00,0x30,0x00,0x0c,0x18,0x00,0x01,0x00,0x00,0x20,0x00,0xf0,
+ 0x07,0x00,0x01,0x00,0x00,0x60,0x00,0x00,0x00,0x80,0x01,0x00,0x00,0x40,0x00,
+ 0x00,0x00,0x80,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x1f,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x08,0x20,0x00,0xff,0x00,0x00,0x00,0x00,0x08,0x40,0xe0,0x00,0x07,0x00,
+ 0x00,0x00,0x04,0x80,0x31,0x00,0x0c,0x00,0x00,0x00,0x04,0x00,0x09,0x00,0x30,
+ 0x00,0x00,0x00,0x04,0x00,0x06,0xc0,0x20,0x00,0x00,0x00,0x04,0x00,0x03,0x00,
+ 0x43,0x00,0x00,0x00,0x04,0x80,0x00,0x00,0x42,0x00,0x00,0x00,0x04,0x40,0x00,
+ 0x00,0x84,0x00,0x00,0x00,0x04,0x60,0x00,0x00,0x84,0x00,0x00,0x00,0x04,0x00,
+ 0x00,0x00,0x84,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x02,
+ 0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x40,0x00,0x00,0x00,
+ 0x02,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x20,0x00,0x00,
+ 0x00,0x04,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x0e,0x00,
+ 0x00,0x00,0xf0,0xff,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00};
diff --git a/hacks/pyro.c b/hacks/pyro.c
new file mode 100644 (file)
index 0000000..69b0e06
--- /dev/null
@@ -0,0 +1,258 @@
+/* xscreensaver, Copyright (c) 1992 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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.
+ */
+
+/* Draw some fireworks.  Inspired from TI Explorer Lisp code by 
+   John S. Pezaris <pz@hx.lcs.mit.edu>
+ */
+
+#include "screenhack.h"
+
+struct projectile {
+  int x, y;    /* position */
+  int dx, dy;  /* velocity */
+  int decay;
+  int size;
+  int fuse;
+  Bool primary;
+  Bool dead;
+  XColor color;
+  struct projectile *next_free;
+};
+
+static struct projectile *projectiles, *free_projectiles;
+
+static struct projectile *
+get_projectile ()
+{
+  struct projectile *p;
+  if (free_projectiles)
+    {
+      p = free_projectiles;
+      free_projectiles = p->next_free;
+      p->next_free = 0;
+      p->dead = False;
+      return p;
+    }
+  else
+    return 0;
+}
+
+static void
+free_projectile (p)
+     struct projectile *p;
+{
+  p->next_free = free_projectiles;
+  free_projectiles = p;
+  p->dead = True;
+}
+
+static void
+launch (xlim, ylim, g, dpy, cmap)
+     int xlim, ylim, g;
+     Display *dpy;
+     Colormap cmap;
+{
+  struct projectile *p = get_projectile ();
+  int x, dx, xxx;
+  if (! p) return;
+
+  do {
+    x = (random () % xlim);
+    dx = 30000 - (random () % 60000);
+    xxx = x + (dx * 200);
+  } while (xxx <= 0 || xxx >= xlim);
+
+  p->x = x;
+  p->y = ylim;
+  p->dx = dx;
+  p->size = 8000;
+  p->decay = 0;
+  p->dy = (random () % 4000) - 13000;
+  p->fuse = ((((random () % 500) + 500) * abs (p->dy / g)) / 1000);
+  p->primary = True;
+
+  if (! mono_p)
+    {
+      hsv_to_rgb (random () % 360, 1.0, 1.0,
+                 &p->color.red, &p->color.green, &p->color.blue);
+      p->color.flags = DoRed | DoGreen | DoBlue;
+      if (!XAllocColor (dpy, cmap, &p->color))
+       {
+         p->color.pixel = WhitePixel (dpy, DefaultScreen (dpy));
+         p->color.red = p->color.green = p->color.blue = 0;
+       }
+    }
+}
+
+static struct projectile *
+shrapnel (parent, dpy, cmap)
+     struct projectile *parent;
+     Display *dpy;
+     Colormap cmap;
+{
+  struct projectile *p = get_projectile ();
+  if (! p) return 0;
+  p->x = parent->x;
+  p->y = parent->y;
+  p->dx = (random () % 5000) - 2500 + parent->dx;
+  p->dy = (random () % 5000) - 2500 + parent->dy;
+  p->decay = (random () % 50) - 60;
+  p->size = 6000;
+  p->fuse = 0;
+  p->primary = False;
+
+  p->color = parent->color;
+  if (! mono_p)
+    XAllocColor (dpy, cmap, &p->color); /* dup the lock */
+  
+  return p;
+}
+
+static GC draw_gc, erase_gc;
+static unsigned int default_fg_pixel;
+
+static int how_many, frequency, scatter;
+
+static Colormap
+init_pyro (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  int i;
+  Colormap cmap;
+  XGCValues gcv;
+  XWindowAttributes xgwa;
+  XGetWindowAttributes (dpy, window, &xgwa);
+  cmap = xgwa.colormap;
+  how_many = get_integer_resource ("count", "Integer");
+  frequency = get_integer_resource ("frequency", "Integer");
+  scatter = get_integer_resource ("scatter", "Integer");
+  if (how_many <= 0) how_many = 100;
+  if (frequency <= 0) frequency = 30;
+  if (scatter <= 0) scatter = 20;
+  projectiles = 0;
+  free_projectiles = 0;
+  projectiles = (struct projectile *)
+    calloc (how_many, sizeof (struct projectile));
+  for (i = 0; i < how_many; i++)
+    free_projectile (&projectiles [i]);
+  gcv.foreground = default_fg_pixel =
+    get_pixel_resource ("foreground", "Foreground", dpy, cmap);
+  draw_gc = XCreateGC (dpy, window, GCForeground, &gcv);
+  gcv.foreground = get_pixel_resource ("background", "Background", dpy, cmap);
+  erase_gc = XCreateGC (dpy, window, GCForeground, &gcv);
+  XClearWindow (dpy, window);
+  return cmap;
+}
+
+static void
+pyro (dpy, window, cmap)
+     Display *dpy;
+     Window window;
+     Colormap cmap;
+{
+  XWindowAttributes xgwa;
+  static int xlim, ylim, real_xlim, real_ylim;
+  int g = 100;
+  int i;
+
+  if ((random () % frequency) == 0)
+    {
+      XGetWindowAttributes (dpy, window, &xgwa);
+      real_xlim = xgwa.width;
+      real_ylim = xgwa.height;
+      xlim = real_xlim * 1000;
+      ylim = real_ylim * 1000;
+      launch (xlim, ylim, g, dpy, cmap);
+    }
+
+  XSync (dpy, True);
+  usleep (10000);
+
+  for (i = 0; i < how_many; i++)
+    {
+      struct projectile *p = &projectiles [i];
+      int old_x, old_y, old_size;
+      int size, x, y;
+      if (p->dead) continue;
+      old_x = p->x >> 10;
+      old_y = p->y >> 10;
+      old_size = p->size >> 10;
+      size = (p->size += p->decay) >> 10;
+      x = (p->x += p->dx) >> 10;
+      y = (p->y += p->dy) >> 10;
+      p->dy += (p->size >> 6);
+      if (p->primary) p->fuse--;
+
+      /* erase old one */
+      XFillRectangle (dpy, window, erase_gc, old_x, old_y,
+                     old_size, old_size);
+
+      if ((p->primary ? (p->fuse > 0) : (p->size > 0)) &&
+         x < real_xlim &&
+         y < real_ylim &&
+         x > 0 &&
+         y > 0)
+       {
+         if (mono_p || p->primary)
+           XSetForeground (dpy, draw_gc, default_fg_pixel);
+         else
+           XSetForeground (dpy, draw_gc, p->color.pixel);
+
+         if (p->primary)
+           XFillArc (dpy, window, draw_gc, x, y, size, size, 0, 360*64);
+         else
+           XFillRectangle (dpy, window, draw_gc, x, y, size, size);
+       }
+      else
+       {
+         free_projectile (p);
+         if (! mono_p) XFreeColors (dpy, cmap, &p->color.pixel, 1, 0);
+       }
+
+      if (p->primary && p->fuse <= 0)
+       {
+         int i = (random () % scatter) + (scatter/2);
+         while (i--)
+           shrapnel (p, dpy, cmap);
+       }
+    }
+}
+
+\f
+char *progclass = "Pyro";
+
+char *defaults [] = {
+  "*background:        black",
+  "*foreground:        white",
+  "*count:     100",
+  "*frequency: 30",
+  "*scatter:   20",
+  "*geometry:  800x500",
+  0
+};
+
+XrmOptionDescRec options [] = {
+  { "-count",          ".count",       XrmoptionSepArg, 0 },
+  { "-frequency",      ".frequency",   XrmoptionSepArg, 0 },
+  { "-scatter",                ".scatter",     XrmoptionSepArg, 0 }
+};
+int options_size = (sizeof (options) / sizeof (options[0]));
+
+void
+screenhack (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  Colormap cmap = init_pyro (dpy, window);
+  while (1)
+    pyro (dpy, window, cmap);
+}
diff --git a/hacks/pyro.man b/hacks/pyro.man
new file mode 100644 (file)
index 0000000..e92adb3
--- /dev/null
@@ -0,0 +1,53 @@
+.TH XScreenSaver 1 "13-aug-92" "X Version 11"
+.SH NAME
+pyro - simulate fireworks
+.SH SYNOPSIS
+.B pyro
+[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-count \fIinteger\fP] [\-frequency \fIinteger\fP] [\-scatter \fIinteger\fP]
+.SH DESCRIPTION
+The \fIpyro\fP program simulates fireworks, in a way similar to a Macintosh
+program of the same name.
+.SH OPTIONS
+.I pyro
+accepts the following options:
+.TP 8
+.B \-window
+Draw on a newly-created window.  This is the default.
+.TP 8
+.B \-root
+Draw on the root window.
+.TP 8
+.B \-mono 
+If on a color display, pretend we're on a monochrome display.
+.TP 8
+.B \-count integer
+How many particles should be allowed on the screen at once.  Default 100.
+.TP 8
+.B \-frequency integer
+How often new missiles should launch.  Default 30.
+.TP 8
+.B \-scatter integer
+How many particles should appear when a missile explodes.  Default 20.
+The actual number used is between \fIN\fP and \fIN+(N/2)\fP.
+.SH ENVIRONMENT
+.PP
+.TP 8
+.B DISPLAY
+to get the default host and display number.
+.TP 8
+.B XENVIRONMENT
+to get the name of a resource file that overrides the global resources
+stored in the RESOURCE_MANAGER property.
+.SH SEE ALSO
+.BR X (1),
+.BR xscreensaver (1)
+.SH COPYRIGHT
+Copyright \(co 1992 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
+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.
+.SH AUTHOR
+Jamie Zawinski <jwz@lucid.com>, 13-aug-92.
diff --git a/hacks/qix.c b/hacks/qix.c
new file mode 100644 (file)
index 0000000..7c70574
--- /dev/null
@@ -0,0 +1,503 @@
+/* xscreensaver, Copyright (c) 1992 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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 <stdio.h>
+
+struct qpoint {
+  int x, y;
+  int dx, dy;
+};
+
+struct qline {
+  struct qpoint p1, p2;
+  XColor color;
+  Bool dead;
+};
+
+struct qix {
+  int id;
+  int fp;
+  int nlines;
+  struct qline *lines;
+};
+
+static GC draw_gc, erase_gc;
+static unsigned int default_fg_pixel;
+static int maxx, maxy, max_spread, max_size, color_shift;
+static Bool random_p, solid_p, xor_p, transparent_p;
+static int delay;
+static int count;
+static Colormap cmap;
+static unsigned long base_pixel;
+
+static GC *gcs[2];
+
+static void
+get_geom (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  XWindowAttributes xgwa;
+  XGetWindowAttributes (dpy, window, &xgwa);
+  maxx = xgwa.width;
+  maxy = xgwa.height;
+}
+
+static struct qix *
+init_one_qix (dpy, window, nlines)
+     Display *dpy;
+     Window window;
+     int nlines;
+{
+  int i;
+  struct qix *qix = (struct qix *) calloc (1, sizeof (struct qix));
+  qix->nlines = nlines;
+  qix->lines = (struct qline *) calloc (qix->nlines, sizeof (struct qline));
+  
+  if (!mono_p && !transparent_p)
+    {
+      hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5,
+                 &qix->lines[0].color.red, &qix->lines[0].color.green,
+                 &qix->lines[0].color.blue);
+      if (!XAllocColor (dpy, cmap, &qix->lines[0].color))
+       {
+         qix->lines[0].color.pixel = default_fg_pixel;
+         if (!XQueryColor (dpy, cmap, &qix->lines[0].color))
+           abort ();
+         if (!XAllocColor (dpy, cmap, &qix->lines[0].color))
+           abort ();
+       }
+    }
+  qix->lines[0].p1.x = random () % maxx;
+  qix->lines[0].p1.y = random () % maxy;
+  if (max_size == 0)
+    {
+      qix->lines[0].p2.x = random () % maxx;
+      qix->lines[0].p2.y = random () % maxy;
+    }
+  else
+    {
+      qix->lines[0].p2.x = qix->lines[0].p1.x + (random () % (max_size/2));
+      qix->lines[0].p2.y = qix->lines[0].p1.y + (random () % (max_size/2));
+      if (qix->lines[0].p2.x > maxx) qix->lines[0].p2.x = maxx;
+      if (qix->lines[0].p2.y > maxy) qix->lines[0].p2.y = maxy;
+    }
+  qix->lines[0].p1.dx = (random () % (max_spread + 1)) - (max_spread / 2);
+  qix->lines[0].p1.dy = (random () % (max_spread + 1)) - (max_spread / 2);
+  qix->lines[0].p2.dx = (random () % (max_spread + 1)) - (max_spread / 2);
+  qix->lines[0].p2.dy = (random () % (max_spread + 1)) - (max_spread / 2);
+  qix->lines[0].dead = True;
+  for (i = 1; i < qix->nlines; i++)
+    {
+      qix->lines[i] = qix->lines[0];
+      if (!mono_p && !transparent_p)
+       if (!XAllocColor (dpy, cmap, &qix->lines[i].color))
+         abort ();
+    }
+  return qix;
+}
+
+/* I don't believe this fucking language doesn't have builtin exponentiation.
+   I further can't believe that the fucking ^ character means fucking XOR!! */
+static int i_exp(i,j)
+     int i, j;
+{
+  int k = 1;
+  while (j--) k *= i;
+  return k;
+}
+
+
+static void
+merge_colors (argc, argv, into_color, mask, increment_p)
+     int argc;
+     XColor **argv;
+     XColor *into_color;
+     int mask;
+     Bool increment_p;
+{
+  int j;
+  *into_color = *argv [0];
+  into_color->pixel |= mask;
+#define SHORT_INC(x,y) (x = ((((x)+(y)) > 0xFFFF) ? 0xFFFF : ((x)+(y))))
+#define SHORT_DEC(x,y) (x = ((((x)-(y)) < 0)      ? 0      : ((x)-(y))))
+  for (j = 1; j < argc; j++)
+    if (increment_p)
+      {
+       SHORT_INC (into_color->red,   argv[j]->red);
+       SHORT_INC (into_color->green, argv[j]->green);
+       SHORT_INC (into_color->blue,  argv[j]->blue);
+      }
+    else
+      {
+       SHORT_DEC (into_color->red,   argv[j]->red);
+       SHORT_DEC (into_color->green, argv[j]->green);
+       SHORT_DEC (into_color->blue,  argv[j]->blue);
+      }
+#undef SHORT_INC
+#undef SHORT_DEC
+}
+
+/* fill in all the permutations of colors that XAllocColorCells() has 
+   allocated for us.  Thanks Ron, you're an additive kind of guy. */
+static void
+permute_colors (pcolors, colors, count, plane_masks, increment_p)
+     XColor *pcolors, *colors;
+     int count;
+     unsigned long *plane_masks;
+     Bool increment_p;
+{
+  int out = 0;
+  int max = i_exp (2, count);
+  if (count > 31) abort ();
+  for (out = 1; out < max; out++)
+    {
+      XColor *argv [32];
+      int this_mask = 0;
+      int argc = 0;
+      int bit;
+      for (bit = 0; bit < 32; bit++)
+       if (out & (1<<bit))
+         {
+           argv [argc++] = &pcolors [bit];
+           this_mask |= plane_masks [bit];
+         }
+      merge_colors (argc, argv, &colors [out-1], this_mask, increment_p);
+    }
+}
+
+
+static struct qix **
+init_qix (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  int nlines;
+  struct qix **qixes;
+  XGCValues gcv;
+  XWindowAttributes xgwa;
+  XGetWindowAttributes (dpy, window, &xgwa);
+  cmap = xgwa.colormap;
+  count = get_integer_resource ("count", "Integer");
+  if (count <= 0) count = 1;
+  nlines = get_integer_resource ("segments", "Integer");
+  if (nlines <= 0) nlines = 20;
+  get_geom (dpy, window);
+  max_spread = get_integer_resource ("spread", "Integer");
+  if (max_spread <= 0) max_spread = 10;
+  max_size = get_integer_resource ("size", "Integer");
+  if (max_size < 0) max_size = 0;
+  random_p = get_boolean_resource ("random", "Boolean");
+  solid_p = get_boolean_resource ("solid", "Boolean");
+  xor_p = get_boolean_resource ("xor", "Boolean");
+  transparent_p = get_boolean_resource ("transparent", "Boolean");
+  delay = get_integer_resource ("delay", "Integer");
+  color_shift = get_integer_resource ("colorShift", "Integer");
+  if (color_shift < 0 || color_shift >= 360) color_shift = 5;
+  if (delay < 0) delay = 0;
+
+  if (count == 1 && transparent_p)
+    transparent_p = False; /* it's a no-op */
+
+  if (transparent_p && CellsOfScreen (DefaultScreenOfDisplay (dpy)) <= 2)
+    {
+      fprintf (stderr, "%s: -transparent only works on color displays.\n",
+              progname);
+      transparent_p = False;
+    }
+
+  if (xor_p && !transparent_p)
+    mono_p = True;
+
+  gcs[0] = gcs[1] = 0;
+  gcv.foreground = default_fg_pixel =
+    get_pixel_resource ("foreground", "Foreground", dpy, cmap);
+
+  if (transparent_p)
+    {
+      Bool increment_p = get_boolean_resource ("additive", "Boolean");
+      unsigned long plane_masks [32];
+      XColor *pcolors, *colors;
+      int nplanes = count;
+      int i, total_colors;
+
+      /* permutations would be harder if the number of planes didn't fit
+        in an int.  Who has >32-bit displays anyway... */
+      if (nplanes > 31) nplanes = 31;
+
+      while (nplanes > 1 &&
+            !XAllocColorCells (dpy, cmap, False, plane_masks, nplanes,
+                               &base_pixel, 1))
+       nplanes--;
+
+      if (nplanes <= 1)
+       {
+         fprintf (stderr,
+         "%s: couldn't allocate any color planes; turning -transparent off.\n",
+                  progname);
+         transparent_p = False;
+         if (xor_p)
+           goto NON_TRANSPARENT_XOR;
+         else
+           goto NON_TRANSPARENT;
+       }
+      else if (nplanes != count)
+       {
+         fprintf (stderr,
+                  "%s: only allocated %d color planes (instead of %d).\n",
+                  progname, nplanes, count);
+         count = nplanes;
+       }
+
+      gcs[0] = (GC *) malloc (count * sizeof (GC));
+      gcs[1] = xor_p ? gcs[0] : (GC *) malloc (count * sizeof (GC));
+      total_colors = i_exp (2, count);
+      pcolors = (XColor *) calloc (count, sizeof (XColor));
+      colors = (XColor *) calloc (total_colors, sizeof (XColor));
+      for (i = 0; i < count; i++)
+       {
+         gcv.plane_mask = plane_masks [i];
+         gcv.foreground = ~0;
+         if (xor_p)
+           {
+             gcv.function = GXxor;
+             gcs [0][i] = XCreateGC (dpy, window,
+                                     GCForeground|GCFunction|GCPlaneMask,
+                                     &gcv);
+           }
+         else
+           {
+             gcs [0][i] = XCreateGC (dpy, window, GCForeground|GCPlaneMask,
+                                     &gcv);
+             gcv.foreground = 0;
+             gcs [1][i] = XCreateGC (dpy, window, GCForeground|GCPlaneMask,
+                                     &gcv);
+           }
+
+         /* pick the "primary" (not in that sense) colors.
+            If we are in subtractive mode, pick higher intensities. */
+         hsv_to_rgb (random () % 360, frand (1.0),
+                     frand (0.5) + (increment_p ? 0.2 : 0.5),
+                     &pcolors[i].red, &pcolors[i].green, &pcolors[i].blue);
+
+         pcolors [i].flags = DoRed | DoGreen | DoBlue;
+         pcolors [i].pixel = base_pixel | plane_masks [i];
+       }
+      permute_colors (pcolors, colors, count, plane_masks, increment_p);
+      /* clone the default background of the window into our "base" pixel */
+      colors [total_colors - 1].pixel =
+       get_pixel_resource ("background", "Background", dpy, cmap);
+      XQueryColor (dpy, cmap, &colors [total_colors - 1]);
+      colors [total_colors - 1].pixel = base_pixel;
+      XStoreColors (dpy, cmap, colors, total_colors);
+      XSetWindowBackground (dpy, window, base_pixel);
+      XClearWindow (dpy, window);
+    }
+  else if (xor_p)
+    {
+    NON_TRANSPARENT_XOR:
+      gcv.function = GXxor;
+      gcv.foreground =
+       (default_fg_pixel ^ get_pixel_resource ("background", "Background",
+                                               dpy, cmap));
+      draw_gc = erase_gc = XCreateGC(dpy,window,GCForeground|GCFunction,&gcv);
+    }
+  else
+    {
+    NON_TRANSPARENT:
+      draw_gc = XCreateGC (dpy, window, GCForeground, &gcv);
+      gcv.foreground = get_pixel_resource ("background", "Background",
+                                          dpy, cmap);
+      erase_gc = XCreateGC (dpy, window, GCForeground, &gcv);
+    }
+
+  qixes = (struct qix **) malloc ((count + 1) * sizeof (struct qix *));
+  qixes [count] = 0;
+  while (count--)
+    {
+      qixes [count] = init_one_qix (dpy, window, nlines);
+      qixes [count]->id = count;
+    }
+  return qixes;
+}
+
+static void
+free_qline (dpy, window, cmap, qline, prev, qix)
+     Display *dpy;
+     Window window;
+     Colormap cmap;
+     struct qline *qline, *prev;
+     struct qix *qix;
+{
+  if (qline->dead || !prev)
+    ;
+  else if (solid_p)
+    {
+      XPoint points [4];
+      points [0].x = qline->p1.x; points [0].y = qline->p1.y;
+      points [1].x = qline->p2.x; points [1].y = qline->p2.y;
+      points [2].x = prev->p2.x; points [2].y = prev->p2.y;
+      points [3].x = prev->p1.x; points [3].y = prev->p1.y;
+      XFillPolygon (dpy, window, (transparent_p ? gcs[1][qix->id] : erase_gc),
+                   points, 4, Complex, CoordModeOrigin);
+    }
+  else
+    XDrawLine (dpy, window, (transparent_p ? gcs[1][qix->id] : erase_gc),
+              qline->p1.x, qline->p1.y, qline->p2.x, qline->p2.y);
+
+  if (!mono_p && !transparent_p)
+    XFreeColors (dpy, cmap, &qline->color.pixel, 1, 0);
+
+  qline->dead = True;
+}
+
+static void
+add_qline (dpy, window, cmap, qline, prev_qline, qix)
+     Display *dpy;
+     Window window;
+     Colormap cmap;
+     struct qline *qline, *prev_qline;
+     struct qix *qix;
+{
+  *qline = *prev_qline;
+
+#define wiggle(point,delta,max)                                                \
+  if (random_p) delta += (random () % 3) - 1;                          \
+  if (delta > max_spread) delta = max_spread;                          \
+  else if (delta < -max_spread) delta = -max_spread;                   \
+  point += delta;                                                      \
+  if (point < 0) point = 0, delta = -delta, point += delta<<1;         \
+  else if (point > max) point = max, delta = -delta, point += delta<<1;
+  
+  wiggle (qline->p1.x, qline->p1.dx, maxx);
+  wiggle (qline->p1.y, qline->p1.dy, maxy);
+  wiggle (qline->p2.x, qline->p2.dx, maxx);
+  wiggle (qline->p2.y, qline->p2.dy, maxy);
+
+  if (max_size)
+    {
+      if (qline->p1.x - qline->p2.x > max_size)
+       qline->p1.x = qline->p2.x + max_size
+         - (random_p ? random() % max_spread : 0);
+      else if (qline->p2.x - qline->p1.x > max_size)
+       qline->p2.x = qline->p1.x + max_size
+         - (random_p ? random() % max_spread : 0);
+      if (qline->p1.y - qline->p2.y > max_size)
+       qline->p1.y = qline->p2.y + max_size
+         - (random_p ? random() % max_spread : 0);
+      else if (qline->p2.y - qline->p1.y > max_size)
+       qline->p2.y = qline->p1.y + max_size
+         - (random_p ? random() % max_spread : 0);
+    }
+
+  if (!mono_p && !transparent_p)
+    {
+      cycle_hue (&qline->color, color_shift);
+      qline->color.flags = DoRed | DoGreen | DoBlue;
+      if (!XAllocColor (dpy, cmap, &qline->color))
+       {
+         qline->color = prev_qline->color;
+         if (!XAllocColor (dpy, cmap, &qline->color))
+           abort (); /* same color should work */
+       }
+      XSetForeground (dpy, draw_gc, qline->color.pixel);
+    }
+  if (! solid_p)
+    XDrawLine (dpy, window, (transparent_p ? gcs[0][qix->id] : draw_gc),
+              qline->p1.x, qline->p1.y, qline->p2.x, qline->p2.y);
+  else if (!prev_qline->dead)
+    {
+      XPoint points [4];
+      points [0].x = qline->p1.x; points [0].y = qline->p1.y;
+      points [1].x = qline->p2.x; points [1].y = qline->p2.y;
+      points [2].x = prev_qline->p2.x; points [2].y = prev_qline->p2.y;
+      points [3].x = prev_qline->p1.x; points [3].y = prev_qline->p1.y;
+      XFillPolygon (dpy, window, (transparent_p ? gcs[0][qix->id] : draw_gc),
+                   points, 4, Complex, CoordModeOrigin);
+    }
+
+  qline->dead = False;
+}
+
+static void
+qix1 (dpy, window, qix)
+     Display *dpy;
+     Window window;
+     struct qix *qix;
+{
+  int ofp = qix->fp - 1;
+  static int gtick = 0;
+  if (gtick++ == 500)
+    get_geom (dpy, window), gtick = 0;
+  if (ofp < 0) ofp = qix->nlines - 1;
+  free_qline (dpy, window, cmap, &qix->lines [qix->fp],
+             &qix->lines[(qix->fp + 1) % qix->nlines], qix);
+  add_qline (dpy, window, cmap, &qix->lines[qix->fp], &qix->lines[ofp], qix);
+  if ((++qix->fp) >= qix->nlines)
+    qix->fp = 0;
+}
+
+\f
+char *progclass = "Qix";
+
+char *defaults [] = {
+  "*background:        black",
+  "*foreground:        white",
+  "*count:     1",
+  "*segments:  50",
+  "*spread:    8",
+  "*size:      0",
+  "*colorShift:        3",
+  "*solid:     false",
+  "*delay:     10000",
+  "*random:    true",
+  "*xor:       false",
+  "*transparent:false",
+  "*additive:  true",
+  0
+};
+
+XrmOptionDescRec options [] = {
+  { "-count",          ".count",       XrmoptionSepArg, 0 },
+  { "-segments",       ".segments",    XrmoptionSepArg, 0 },
+  { "-spread",         ".spread",      XrmoptionSepArg, 0 },
+  { "-size",           ".size",        XrmoptionSepArg, 0 },
+  { "-delay",          ".delay",       XrmoptionSepArg, 0 },
+  { "-color-shift",    ".colorShift",  XrmoptionSepArg, 0 },
+  { "-random",         ".random",      XrmoptionNoArg, "true" },
+  { "-linear",         ".random",      XrmoptionNoArg, "false" },
+  { "-solid",          ".solid",       XrmoptionNoArg, "true" },
+  { "-hollow",         ".solid",       XrmoptionNoArg, "false" },
+  { "-xor",            ".xor",         XrmoptionNoArg, "true" },
+  { "-no-xor",         ".xor",         XrmoptionNoArg, "false" },
+  { "-transparent",    ".transparent", XrmoptionNoArg, "true" },
+  { "-non-transparent",        ".transparent", XrmoptionNoArg, "false" },
+  { "-additive",       ".additive",    XrmoptionNoArg, "true" },
+  { "-subtractive",    ".additive",    XrmoptionNoArg, "false" },
+};
+int options_size = (sizeof (options) / sizeof (options[0]));
+
+void
+screenhack (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  struct qix **q1 = init_qix (dpy, window);
+  struct qix **qn;
+  while (1)
+    for (qn = q1; *qn; qn++)
+      {
+       qix1 (dpy, window, *qn);
+       XSync (dpy, True);
+       if (delay) usleep (delay);
+      }
+}
diff --git a/hacks/qix.man b/hacks/qix.man
new file mode 100644 (file)
index 0000000..54f9f43
--- /dev/null
@@ -0,0 +1,107 @@
+.TH XScreenSaver 1 "9-dec-92" "X Version 11"
+.SH NAME
+qix - bounce colored lines around a window
+.SH SYNOPSIS
+.B qix
+[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-segments \fIint\fP] [\-spread \fIpixels\fP] [\-size \fIpixels\fP] [\-count \fIint\fP] [\-color-shift \fIdegrees\fP] [\-delay \fIusecs\fP] [\-random] [\-linear] [\-solid] [\-hollow] [\-xor] [\-no\-xor] [\-transparent] [\-non\-transparent] [\-additive] [\-subtractive]
+.SH DESCRIPTION
+The \fIqix\fP program bounces a series of line segments around its window.
+This is truly the swiss army chainsaw of qix programs.  If you know of one
+with more display modes, I want to know about it.
+.SH OPTIONS
+.I qix
+accepts the following options:
+.TP 8
+.B \-window
+Draw on a newly-created window.  This is the default.
+.TP 8
+.B \-root
+Draw on the root window.
+.TP 8
+.B \-mono 
+If on a color display, pretend we're on a monochrome display.
+.TP 8
+.B \-segments integer
+How many line segments should be drawn.  Default 50.
+.TP 8
+.B \-spread integer
+How far apart the endpoints of one segment should be from the next.
+Default 8.
+.TP 8
+.B \-size integer
+The maximum distance one endpoint of a segment is allowed to be from
+the opposite end of that segment.  Default 0, meaning unlimited.
+.TP 8
+.B \-count integer
+How many qixes to draw.  Default 1.
+.TP 8
+.B \-color\-shift degrees
+If on a color display, the color of the line segments will cycle through
+the spectrum.  This specifies how far the hue of each segment should be
+from the next, in degrees on the HSV wheel.  Default 3.
+.TP 8
+.B \-delay microseconds
+How much of a delay should be introduced between steps of the animation.
+Default 25000, or about 0.025 seconds.
+.TP 8
+.B \-random
+The \fIqix\fP will wander around the screen semi-randomly.  This is the
+default.
+.TP 8
+.B \-linear
+The opposite of \fI\-random\fP: the \fIqix\fP will travel in straight lines
+until it reaches a wall, and then it will bounce.
+.TP 8
+.B \-solid
+If this is specified, then the area between the line segments will be filled
+in with the appropriate color, instead of the \fIqix\fP simply being composed
+of one-pixel-wide line segments.  This option looks really good in color.
+.TP 8
+.B \-hollow
+The opposite of \fI\-solid\fP; this is the default.
+.TP 8
+.B \-xor
+If this is specified, then qix segments will be drawn and erased with xor,
+instead of being drawn in some color and erased in the background color.
+This implies \fI\-mono\fP, in that only two colors can be used.
+.TP 8
+.B \-transparent
+If this is specified, and \fI\-count\fP is greater than 1, then each qix
+will be drawn in one color, and when they overlap, the colors will be mixed.
+This only works on \fBPseudoColor\fP displays.  This looks best in
+conjuction with \fI\-solid\fP.
+.TP 8
+.B \-non\-transparent
+Turns off \fI\-transparent\fP.
+.TP 8
+.B \-additive
+If \fI\-transparent\fP is specified, then this option means that the colors
+will be mixed using an additive color model, as if the qixes were projected
+light.  This is the default.
+.TP 8
+.B \-subtractive
+If \fI\-transparent\fP is specified, then this option means that the
+colors will be mixed using a subtractive color model, as if the qixes were
+translucent filters.
+.SH ENVIRONMENT
+.PP
+.TP 8
+.B DISPLAY
+to get the default host and display number.
+.TP 8
+.B XENVIRONMENT
+to get the name of a resource file that overrides the global resources
+stored in the RESOURCE_MANAGER property.
+.SH SEE ALSO
+.BR X (1),
+.BR xscreensaver (1)
+.SH COPYRIGHT
+Copyright \(co 1992 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
+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.
+.SH AUTHOR
+Jamie Zawinski <jwz@lucid.com>, 13-aug-92.
diff --git a/hacks/rocks.c b/hacks/rocks.c
new file mode 100644 (file)
index 0000000..e97e6df
--- /dev/null
@@ -0,0 +1,313 @@
+/* xscreensaver, Copyright (c) 1992 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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.
+ */
+
+/* Flying through an asteroid field.  Based on TI Explorer Lisp code by 
+   John Nguyen <johnn@hx.lcs.mit.edu>
+ */
+
+#include "screenhack.h"
+#include <stdio.h>
+#include <math.h>
+#if __STDC__
+#include <values.h>
+#endif
+
+#define MIN_DEPTH 2            /* rocks disappar when they get this close */
+#define MAX_DEPTH 60           /* this is where rocks appear */
+#define MAX_WIDTH 100          /* how big (in pixels) rocks are at depth 1 */
+#define DEPTH_SCALE 100                /* how many ticks there are between depths */
+#define SIN_RESOLUTION 1000
+
+/* there's not much point in the above being user-customizable, but those
+   numbers might want to be tweaked for displays with an order of magnitude
+   higher resolution or compute power.
+ */
+
+static double sins [SIN_RESOLUTION];
+static double coss [SIN_RESOLUTION];
+static double depths [(MAX_DEPTH + 1) * DEPTH_SCALE];
+
+static Display *dpy;
+static Window window;
+static int width, height, midx, midy;
+static GC draw_gc, erase_gc;
+static Bool rotate_p ;
+
+static int speed;
+
+struct rock {
+  int real_size;
+  int r;
+  int theta;
+  int depth;
+  int size, x, y;
+};
+
+static struct rock *rocks;
+static int nrocks;
+static Pixmap pixmaps [MAX_WIDTH];
+static int delay;
+
+static void rock_reset(), rock_tick(), rock_compute(), rock_draw();
+static void init_pixmaps(), init_rocks(), tick_rocks(), rocks_once();
+
+
+static void
+rock_reset (rock)
+     struct rock *rock;
+{
+  rock->real_size = MAX_WIDTH;
+  rock->r = (SIN_RESOLUTION * 0.7) + (random () % (30 * SIN_RESOLUTION));
+  rock->theta = random () % SIN_RESOLUTION;
+  rock->depth = MAX_DEPTH * DEPTH_SCALE;
+  rock_compute (rock);
+  rock_draw (rock, True);
+}
+
+static void
+rock_tick (rock, d)
+     struct rock *rock;
+     int d;
+{
+  if (rock->depth > 0)
+    {
+      rock_draw (rock, False);
+      rock->depth -= speed;
+      if (rotate_p)
+        {
+         rock->theta = (rock->theta + d) % SIN_RESOLUTION;
+        }
+      while (rock->theta < 0)
+       rock->theta += SIN_RESOLUTION;
+      if (rock->depth < (MIN_DEPTH * DEPTH_SCALE))
+       rock->depth = 0;
+      else
+       {
+         rock_compute (rock);
+         rock_draw (rock, True);
+       }
+    }
+  else if ((random () % 40) == 0)
+    rock_reset (rock);
+}
+
+static void
+rock_compute (rock)
+     struct rock *rock;
+{
+  double factor = depths [rock->depth];
+  rock->size = (int) ((rock->real_size * factor) + 0.5);
+  rock->x = midx + (coss [rock->theta] * rock->r * factor);
+  rock->y = midy + (sins [rock->theta] * rock->r * factor);
+}
+
+static void
+rock_draw (rock, draw_p)
+     struct rock *rock;
+     Bool draw_p;
+{
+  GC gc = draw_p ? draw_gc : erase_gc;
+  if (rock->x <= 0 || rock->y <= 0 || rock->x >= width || rock->y >= height)
+    {
+      /* this means that if a rock were to go off the screen at 12:00, but
+        would have been visible at 3:00, it won't come back once the observer
+        rotates around so that the rock would have been visible again.
+        Oh well.
+       */
+      rock->depth = 0;
+      return;
+    }
+  if (rock->size <= 1)
+    XDrawPoint (dpy, window, gc, rock->x, rock->y);
+  else if (rock->size <= 3 || !draw_p)
+    XFillRectangle (dpy, window, gc,
+                   rock->x - rock->size/2, rock->y - rock->size/2,
+                   rock->size, rock->size);
+  else if (rock->size < MAX_WIDTH)
+    XCopyPlane (dpy, pixmaps [rock->size], window, gc,
+               0, 0, rock->size, rock->size,
+               rock->x - rock->size/2, rock->y - rock->size/2,
+               1);
+  else
+    abort ();
+}
+
+
+static void
+init_pixmaps (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  int i;
+  XGCValues gcv;
+  GC fg_gc = 0, bg_gc;
+  pixmaps [0] = pixmaps [1] = 0;
+  for (i = MIN_DEPTH; i < MAX_WIDTH; i++)
+    {
+      int w = (1+(i/32))<<5; /* server might be faster if word-aligned */
+      int h = i;
+      Pixmap p = XCreatePixmap (dpy, window, w, h, 1);
+      XPoint points [7];
+      pixmaps [i] = p;
+      if (! p)
+       {
+         fprintf (stderr, "%s: couldn't allocate pixmaps", progname);
+         exit (1);
+       }
+      if (! fg_gc)
+       {       /* must use drawable of pixmap, not window (fmh) */
+         gcv.foreground = 1;
+         fg_gc = XCreateGC (dpy, p, GCForeground, &gcv);
+         gcv.foreground = 0;
+         bg_gc = XCreateGC (dpy, p, GCForeground, &gcv);
+       }
+      XFillRectangle (dpy, p, bg_gc, 0, 0, w, h);
+      points [0].x = i * 0.15; points [0].y = i * 0.85;
+      points [1].x = i * 0.00; points [1].y = i * 0.20;
+      points [2].x = i * 0.30; points [2].y = i * 0.00;
+      points [3].x = i * 0.40; points [3].y = i * 0.10;
+      points [4].x = i * 0.90; points [4].y = i * 0.10;
+      points [5].x = i * 1.00; points [5].y = i * 0.55;
+      points [6].x = i * 0.45; points [6].y = i * 1.00;
+      XFillPolygon (dpy, p, fg_gc, points, 7, Nonconvex, CoordModeOrigin);
+    }
+  XFreeGC (dpy, fg_gc);
+  XFreeGC (dpy, bg_gc);
+}
+
+
+static void
+init_rocks (d, w)
+     Display *d;
+     Window w;
+{
+  int i;
+  XGCValues gcv;
+  Colormap cmap;
+  XWindowAttributes xgwa;
+  unsigned int fg, bg;
+  dpy = d;
+  window = w;
+  XGetWindowAttributes (dpy, window, &xgwa);
+  cmap = xgwa.colormap;
+  delay = get_integer_resource ("delay", "Integer");
+  if (delay < 0) delay = 0;
+  speed = get_integer_resource ("speed", "Integer");
+  if (speed < 1) speed = 1;
+  if (speed > 100) speed = 100;
+  rotate_p = get_boolean_resource ("rotate", "Boolean");
+  fg = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
+  bg = get_pixel_resource ("background", "Background", dpy, cmap);
+  gcv.foreground = fg;
+  gcv.background = bg;
+  draw_gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
+  gcv.foreground = bg;
+  gcv.background = fg;
+  erase_gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
+
+  for (i = 0; i < SIN_RESOLUTION; i++)
+    {
+      sins [i] = sin ((((double) i) / (SIN_RESOLUTION / 2)) * M_PI);
+      coss [i] = cos ((((double) i) / (SIN_RESOLUTION / 2)) * M_PI);
+    }
+  /* we actually only need i/speed of these, but wtf */
+  for (i = 1; i < (sizeof (depths) / sizeof (depths[0])); i++)
+    depths [i] = atan (((double) 0.5) / (((double) i) / DEPTH_SCALE));
+  depths [0] = M_PI/2; /* avoid division by 0 */
+
+  nrocks = get_integer_resource ("count", "Count");
+  if (nrocks < 1) nrocks = 1;
+  rocks = (struct rock *) calloc (nrocks, sizeof (struct rock));
+  init_pixmaps (dpy, window);
+  XClearWindow (dpy, window);
+}
+
+
+static void
+tick_rocks (d)
+     int d;
+{
+  int i;
+  for (i = 0; i < nrocks; i++)
+    rock_tick (&rocks [i], d);
+}
+
+static void
+rocks_once ()
+{
+  static int current_delta = 0;        /* observer Z rotation */
+  static int window_tick = 50;
+
+  if (window_tick++ == 50)
+    {
+      XWindowAttributes xgwa;
+      XGetWindowAttributes (dpy, window, &xgwa);
+      window_tick = 0;
+      width = xgwa.width;
+      height = xgwa.height;
+      midx = width/2;
+      midy = height/2;
+    }
+
+  if ((random () % 50) == 0)
+    {
+      int d = current_delta;
+      int new_delta = ((random () % 11) - 5);
+      if ((random () % 10) == 0)
+       new_delta *= 5;
+
+      while (d == current_delta)
+       {
+         int i;
+         for (i = 0; i < 3; i++)
+           tick_rocks (d);
+         if (current_delta < new_delta) d++;
+         else d--;
+       }
+      current_delta = new_delta;
+    }
+  tick_rocks (current_delta);
+}
+
+\f
+char *progclass = "Rocks";
+
+char *defaults [] = {
+  "*background:        black",
+  "*foreground:        white",
+  "*count:     100",
+  "*delay:     50000",
+  "*speed:     100",
+  "*rotate:     true",
+  0
+};
+
+XrmOptionDescRec options [] = {
+  { "-count",          ".count",       XrmoptionSepArg, 0 },
+  { "-norotate",        ".rotate",      XrmoptionNoArg,  "false" },
+  { "-delay",          ".delay",       XrmoptionSepArg, 0 },
+  { "-speed",          ".speed",       XrmoptionSepArg, 0 }
+};
+int options_size = (sizeof (options) / sizeof (options[0]));
+
+void
+screenhack (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  init_rocks (dpy, window);
+  while (1)
+    {
+      rocks_once ();
+      XSync (dpy, True);
+      if (delay) usleep (delay);
+    }
+}
diff --git a/hacks/rocks.man b/hacks/rocks.man
new file mode 100644 (file)
index 0000000..5eb4b03
--- /dev/null
@@ -0,0 +1,64 @@
+.TH XScreenSaver 1 "13-aug-92" "X Version 11"
+.SH NAME
+rocks - animation of flying through an asteroid field
+.SH SYNOPSIS
+.B rocks
+[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root] [\-count \fIinteger\fP] [\-delay \fIusecs\fP] [\-speed \fIinteger\fP] [\-norotate]
+.SH DESCRIPTION
+The \fIrocks\fP program draws an animation of an asteroid field moving past
+the observer (or vice versa).  Sometimes the observer picks up spin on Z axis.
+.SH OPTIONS
+.I rocks
+accepts the following options:
+.TP 8
+.B \-window
+Draw on a newly-created window.  This is the default.
+.TP 8
+.B \-root
+Draw on the root window.
+.TP 8
+.B \-count integer
+Maximum number of rocks to draw on the screen at once.  Default 100.
+.TP 8
+.B \-speed integer
+A measure of the speed with which the observer and the rocks pass each other,
+from 1 to 100.  Default 100, meaning ``very fast.''  If you're on a slow 
+display connection (the animation looks jerky) then try making this number 
+smaller, and/or decreasing the number of rocks.
+.TP 8
+.B \-delay microseconds
+Number of microseconds to delay between each frame.  Default 50000, meaning
+about 1/20th second.  Compare and contrast with \fI\-speed\fP, above.
+.TP 8
+.B \-norotate
+Don't rotate the observer; just fly straight through the field.
+.SH ENVIRONMENT
+.PP
+.TP 8
+.B DISPLAY
+to get the default host and display number.
+.TP 8
+.B XENVIRONMENT
+to get the name of a resource file that overrides the global resources
+stored in the RESOURCE_MANAGER property.
+.SH SEE ALSO
+.BR X (1),
+.BR xscreensaver (1)
+.SH BUGS
+There should be an option to display doppler shift (a gravity rainbow.)
+
+Speed of rotation should be settable.
+
+Default speed of rotation should be relative to forward velocity.
+.SH COPYRIGHT
+Copyright \(co 1992 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
+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.
+.SH AUTHOR
+Based on Lisp Machine code copyright 1988 John Nguyen <johnn@hx.lcs.mit.edu>.
+
+Ported to C and X by Jamie Zawinski <jwz@lucid.com>, 13-aug-92.
diff --git a/hacks/rorschach.c b/hacks/rorschach.c
new file mode 100644 (file)
index 0000000..5c55615
--- /dev/null
@@ -0,0 +1,140 @@
+/* xscreensaver, Copyright (c) 1992 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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"
+
+static GC draw_gc, erase_gc;
+static unsigned int default_fg_pixel;
+static int iterations, offset;
+static Bool xsym, ysym;
+
+static void
+init_rorschach (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  XGCValues gcv;
+  Colormap cmap;
+  XWindowAttributes xgwa;
+  XGetWindowAttributes (dpy, window, &xgwa);
+  cmap = xgwa.colormap;
+  gcv.foreground = default_fg_pixel =
+    get_pixel_resource ("foreground", "Foreground", dpy, cmap);
+  draw_gc = XCreateGC (dpy, window, GCForeground, &gcv);
+  gcv.foreground = get_pixel_resource ("background", "Background", dpy, cmap);
+  erase_gc = XCreateGC (dpy, window, GCForeground, &gcv);
+  iterations = get_integer_resource ("iterations", "Integer");
+  offset = get_integer_resource ("offset", "Integer");
+  if (offset <= 0) offset = 3;
+  if (iterations < 10) iterations = 10;
+  xsym = get_boolean_resource ("xsymmetry", "Symmetry");
+  ysym = get_boolean_resource ("ysymmetry", "Symmetry");
+}
+
+static void
+hurm (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  Colormap cmap;
+  XWindowAttributes xgwa;
+  int xlim, ylim, x, y, i, got_color = 0;
+  XPoint points [4];
+  XColor color;
+  XClearWindow (dpy, window);
+  XGetWindowAttributes (dpy, window, &xgwa);
+  xlim = xgwa.width;
+  ylim = xgwa.height;
+  cmap = xgwa.colormap;
+
+  if (! mono_p)
+    hsv_to_rgb (random()%360, 1.0, 1.0, &color.red, &color.green, &color.blue);
+  if ((!mono_p) && (got_color = XAllocColor (dpy, cmap, &color)))
+    XSetForeground (dpy, draw_gc, color.pixel);
+  else
+    XSetForeground (dpy, draw_gc, default_fg_pixel);
+
+  x = xlim/2;
+  y = ylim/2;
+  for (i = 0; i < iterations; i++)
+    {
+      int j = 0;
+      x += ((random () % (1 + (offset << 1))) - offset);
+      y += ((random () % (1 + (offset << 1))) - offset);
+      points [j].x = x;
+      points [j].y = y;
+      j++;
+      if (xsym)
+       {
+         points [j].x = xlim - x;
+         points [j].y = y;
+         j++;
+       }
+      if (ysym)
+       {
+         points [j].x = x;
+         points [j].y = ylim - y;
+         j++;
+       }
+      if (xsym && ysym)
+       {
+         points [j].x = xlim - x;
+         points [j].y = ylim - y;
+         j++;
+       }
+      XDrawPoints (dpy, window, draw_gc, points, j, CoordModeOrigin);
+      XSync (dpy, True);
+    }
+  sleep (5);
+  for (i = 0; i < (ylim >> 1); i++)
+    {
+      int y = (random () % ylim);
+      XDrawLine (dpy, window, erase_gc, 0, y, xlim, y);
+      XFlush (dpy);
+      if ((i % 50) == 0)
+       usleep (10000);
+    }
+  XClearWindow (dpy, window);
+  if (got_color) XFreeColors (dpy, cmap, &color.pixel, 1, 0);
+  XSync (dpy, True);
+  sleep (1);
+}
+
+\f
+char *progclass = "Rorschach";
+
+char *defaults [] = {
+  "*background:        black",
+  "*foreground:        white",
+  "*xsymmetry: true",
+  "*ysymmetry: false",
+  "*iterations:        4000",
+  "*offset:    4",
+  0
+};
+
+XrmOptionDescRec options [] = {
+  { "-iterations",     ".iterations",  XrmoptionSepArg, 0 },
+  { "-offset",         ".offset",      XrmoptionSepArg, 0 },
+  { "-xsymmetry",      ".xsymmetry",   XrmoptionNoArg, "true" },
+  { "-ysymmetry",      ".ysymmetry",   XrmoptionNoArg, "true" }
+};
+int options_size = (sizeof (options) / sizeof (options[0]));
+
+void
+screenhack (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  init_rorschach (dpy, window);
+  while (1)
+    hurm (dpy, window);
+}
diff --git a/hacks/rorschach.man b/hacks/rorschach.man
new file mode 100644 (file)
index 0000000..fd63db9
--- /dev/null
@@ -0,0 +1,57 @@
+.TH XScreenSaver 1 "13-aug-92" "X Version 11"
+.SH NAME
+rorschach - simulate ink-blot patterns
+.SH SYNOPSIS
+.B rorschach
+[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-iterations \fIinteger\fP] [\-offset \fIinteger\fP] [\-xsymmetry] [\-ysymmetry]
+.SH DESCRIPTION
+The \fIrorschach\fP program draws random patterns reminiscent of the
+psychological test of same name.
+.SH OPTIONS
+.I rorschach
+accepts the following options:
+.TP 8
+.B \-window
+Draw on a newly-created window.  This is the default.
+.TP 8
+.B \-root
+Draw on the root window.
+.TP 8
+.B \-mono 
+If on a color display, pretend we're on a monochrome display.
+.TP 8
+.B \-iterations integer
+How many dots should be drawn each time.  Default 4000.
+.TP 8
+.B \-offset integer
+How far apart the dots should be.  Default 4 pixels.
+.TP 8
+.B \-xsymmetry
+Whether the images should be horizontally symmetrical.  Default true.
+.TP 8
+.B \-ysymmetry
+Whether the images should be vertically symmetrical.  Default false.
+.SH ENVIRONMENT
+.PP
+.TP 8
+.B DISPLAY
+to get the default host and display number.
+.TP 8
+.B XENVIRONMENT
+to get the name of a resource file that overrides the global resources
+stored in the RESOURCE_MANAGER property.
+.SH BUGS
+May call your sanity into question.
+.SH SEE ALSO
+.BR X (1),
+.BR xscreensaver (1)
+.SH COPYRIGHT
+Copyright \(co 1992 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
+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.
+.SH AUTHOR
+Jamie Zawinski <jwz@lucid.com>, 13-aug-92.
diff --git a/hacks/screenhack.c b/hacks/screenhack.c
new file mode 100644 (file)
index 0000000..0bbd4be
--- /dev/null
@@ -0,0 +1,204 @@
+/* xscreensaver, Copyright (c) 1992 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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.
+ *
+ * And remember: X Windows is to graphics hacking as roman numerals are to
+ * the square root of pi.
+ */
+
+/* This file contains simple code to open a window or draw on the root.
+   The idea being that, when writing a graphics hack, you can just link
+   with this .o to get all of the uninteresting junk out of the way.
+
+   -  create a procedure `screenhack(dpy, window)'
+
+   -  create a variable `char *progclass' which names this program's
+      resource class.
+
+   -  create a variable `char defaults []' for the default resources.
+
+   -  create a variable `XrmOptionDescRec options []' for the command-line,
+      and `int options_size' which is `XtNumber (options)'.
+
+   And that's it...
+ */
+
+#include "version.h"
+
+#include <stdio.h>
+#include <X11/Intrinsic.h>
+#include <X11/IntrinsicP.h>
+#include <X11/CoreP.h>
+#include <X11/Xmu/Error.h>
+#include "screenhack.h"
+
+char *progname;
+XrmDatabase db;
+Bool mono_p;
+
+
+static XrmOptionDescRec default_options [] = {
+  { "-root",   ".root",                XrmoptionNoArg, "True" },
+  { "-window", ".root",                XrmoptionNoArg, "False" },
+  { "-mono",   ".mono",                XrmoptionNoArg, "True" },
+  { "-install",        ".installColormap",     XrmoptionNoArg, "True" }
+};
+
+static char *default_defaults[] = {
+  "*root:              false",
+  "*geometry:          500x500", /* this should be .geometry, but nooooo... */
+  "*mono:              false",
+  "*installColormap:   false",
+  0
+};
+
+static XrmOptionDescRec *merged_options;
+static int merged_options_size;
+static char **merged_defaults;
+
+static void
+merge_options ()
+{
+  int options_sizeof = options_size * sizeof (options[0]);
+  int defaults_size;
+  merged_options_size = XtNumber (default_options) + options_size;
+  merged_options = (XrmOptionDescRec *)
+    malloc (sizeof (default_options) + options_sizeof);
+  bcopy (options, merged_options, options_sizeof);
+  bcopy (default_options, merged_options + options_size,
+        sizeof (default_options));
+
+  for (defaults_size = 0; defaults [defaults_size]; defaults_size++);
+  merged_defaults = (char **)
+    malloc (sizeof (default_defaults) + (defaults_size * sizeof (char *)));
+  bcopy (default_defaults, merged_defaults, sizeof (default_defaults));
+  bcopy (defaults, merged_defaults - 1 +
+        (sizeof (default_defaults) / sizeof (default_defaults[0])),
+        ((defaults_size + 1) * sizeof (defaults[0])));
+}
+
+\f
+/* Make the X errors print out the name of this program, so we have some
+   clue which one has a bug when they die under the screensaver.
+ */
+
+static int
+screenhack_ehandler (dpy, error)
+     Display *dpy;
+     XErrorEvent *error;
+{
+  fprintf (stderr, "\nX error in %s:\n", progname);
+  if (XmuPrintDefaultErrorMessage (dpy, error, stderr))
+    exit (-1);
+  else
+    fprintf (stderr, " (nonfatal.)\n");
+  return 0;
+}
+
+static Bool
+MapNotify_event_p (dpy, event, window)
+     Display *dpy;
+     XEvent *event;
+     XPointer window;
+{
+  return (event->xany.type == MapNotify &&
+         event->xvisibility.window == (Window) window);
+}
+
+
+void
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  XtAppContext app;
+  Widget toplevel;
+  Display *dpy;
+  Window window;
+  Colormap cmap;
+  Bool root_p;
+  XEvent event;
+
+  merge_options ();
+  toplevel = XtAppInitialize (&app, progclass, merged_options,
+                             merged_options_size, &argc, argv,
+                             merged_defaults, 0, 0);
+  dpy = XtDisplay (toplevel);
+  db = XtDatabase (dpy);
+  XtGetApplicationNameAndClass (dpy, &progname, &progclass);
+  XSetErrorHandler (screenhack_ehandler);
+  if (argc > 1)
+    {
+      int i;
+      int x = 18;
+      int end = 78;
+      fprintf (stderr, "%s: unrecognised option \"%s\"\n", progname, argv[1]);
+      fprintf (stderr, "Options include: ");
+      for (i = 0; i < merged_options_size; i++)
+       {
+         char *sw = merged_options [i].option;
+         Bool argp = (merged_options [i].argKind == XrmoptionSepArg);
+         int size = strlen (sw) + (argp ? 6 : 0) + 2;
+         if (x + size >= end)
+           {
+             fprintf (stderr, "\n\t\t ");
+             x = 18;
+           }
+         x += size;
+         fprintf (stderr, "%s", sw);
+         if (argp) fprintf (stderr, " <arg>");
+         if (i != merged_options_size - 1) fprintf (stderr, ", ");
+       }
+      fprintf (stderr, ".\n");
+      exit (1);
+    }
+
+  mono_p = get_boolean_resource ("mono", "Boolean");
+  if (CellsOfScreen (DefaultScreenOfDisplay (dpy)) <= 2)
+    mono_p = True;
+
+  root_p = get_boolean_resource ("root", "Boolean");
+  if (root_p)
+    {
+      XWindowAttributes xgwa;
+      window = RootWindowOfScreen (XtScreen (toplevel));
+      XtDestroyWidget (toplevel);
+      XGetWindowAttributes (dpy, window, &xgwa);
+      cmap = xgwa.colormap;
+    }
+  else
+    {
+      XtRealizeWidget (toplevel);
+      window = XtWindow (toplevel);
+      if (get_boolean_resource ("installColormap", "InstallColormap"))
+       {
+         cmap = XCreateColormap (dpy, window,
+                                 DefaultVisualOfScreen (XtScreen (toplevel)),
+                                 AllocNone);
+         XSetWindowColormap (dpy, window, cmap);
+       }
+      else
+       cmap = DefaultColormap (dpy, DefaultScreen (dpy));
+    }
+  if (!get_boolean_resource ("dontClearWindow", "Boolean")) /* kludge-o-rama */
+    {
+      XSetWindowBackground (dpy, window,
+                           get_pixel_resource ("background", "Background",
+                                               dpy, cmap));
+      XClearWindow (dpy, window);
+    }
+
+  if (!root_p && toplevel->core.mapped_when_managed)
+    /* wait for it to be mapped */
+    XIfEvent (dpy, &event, MapNotify_event_p, (XPointer) window);
+
+  XSync (dpy, False);
+  srandom ((int) time ((time_t *) 0));
+  screenhack (dpy, window);
+}
diff --git a/hacks/screenhack.h b/hacks/screenhack.h
new file mode 100644 (file)
index 0000000..4cfc8f0
--- /dev/null
@@ -0,0 +1,120 @@
+
+#if 0
+ * Found in Don Hopkin`s .plan file:
+ *
+ *   The color situation is a total flying circus.  The X approach to
+ *   device independence is to treat everything like a MicroVax framebuffer
+ *   on acid.  A truely portable X application is required to act like the
+ *   persistent customer in the Monty Python ``Cheese Shop'' sketch.  Even
+ *   the simplest applications must answer many difficult questions, like:
+ *
+ *   WHAT IS YOUR DISPLAY?
+ *       display = XOpenDisplay("unix:0");
+ *   WHAT IS YOUR ROOT?
+ *       root = RootWindow(display, DefaultScreen(display));
+ *   AND WHAT IS YOUR WINDOW?
+ *       win = XCreateSimpleWindow(display, root, 0, 0, 256, 256, 1,
+ *                                 BlackPixel(display, DefaultScreen(display)),
+ *                                 WhitePixel(display, DefaultScreen(display)))
+ *   OH ALL RIGHT, YOU CAN GO ON.
+ *
+ *   WHAT IS YOUR DISPLAY?
+ *         display = XOpenDisplay("unix:0");
+ *   WHAT IS YOUR COLORMAP?
+ *         cmap = DefaultColormap(display, DefaultScreen(display));
+ *   AND WHAT IS YOUR FAVORITE COLOR?
+ *         favorite_color = 0; /* Black. */
+ *         /* Whoops! No, I mean: */
+ *         favorite_color = BlackPixel(display, DefaultScreen(display));
+ *         /* AAAYYYYEEEEE!! (client dumps core & falls into the chasm) */
+ *
+ *   WHAT IS YOUR DISPLAY?
+ *         display = XOpenDisplay("unix:0");
+ *   WHAT IS YOUR VISUAL?
+ *         struct XVisualInfo vinfo;
+ *         if (XMatchVisualInfo(display, DefaultScreen(display),
+ *                              8, PseudoColor, &vinfo) != 0)
+ *            visual = vinfo.visual;
+ *   AND WHAT IS THE NET SPEED VELOCITY OF AN XConfigureWindow REQUEST?
+ *         /* Is that a SubStructureRedirectMask or a ResizeRedirectMask? */
+ *   WHAT??! HOW AM I SUPPOSED TO KNOW THAT?
+ *   AAAAUUUGGGHHH!!!! (server dumps core & falls into the chasm)
+ *
+#endif /* 0 */
+
+#ifndef _SCREENHACK_H_
+#define _SCREENHACK_H_
+
+#if __STDC__
+#include <stdlib.h>
+#endif
+
+#include <X11/Xlib.h>
+#include <X11/Xresource.h>
+#include <X11/Xos.h>
+#include "vroot.h"
+
+extern Bool mono_p;
+extern char *progname;
+extern char *progclass;
+extern XrmDatabase db;
+extern XrmOptionDescRec options [];
+extern int options_size;
+extern char *defaults [];
+
+#if __STDC__
+
+# define bcopy(from,to,size) memcpy((to),(from),(size))
+# define bzero(addr,size) memset((addr),0,(size))
+
+# if defined(SVR4) || defined(SYSV)
+extern int rand (void);
+extern void srand (unsigned int);
+#  define random() rand()
+#  define srandom(i) srand((unsigned int)(i))
+# else /* !totally-losing-SYSV */
+extern long random (void);
+extern void srandom (int);
+# endif /* !totally-losing-SYSV */
+#endif /* __STDC__ */
+
+#if __STDC__
+# define P(x)x
+#else
+# define P(x)()
+#endif
+
+extern void screenhack P((Display*,Window));
+
+#define usleep screenhack_usleep
+
+extern void screenhack_usleep P((unsigned long));
+extern char *get_string_resource P((char*,char*));
+extern Bool get_boolean_resource P((char*,char*));
+extern int get_integer_resource P((char*,char*));
+extern double get_float_resource P((char*,char*));
+extern unsigned int get_pixel_resource P((char*,char*,Display*,Colormap));
+extern unsigned int get_minutes_resource P((char*,char*));
+extern unsigned int get_seconds_resource P((char*,char*));
+
+extern Visual *get_visual_resource P((Display *, char *, char *));
+extern int get_visual_depth P((Display *, Visual *));
+
+void hsv_to_rgb P((int,double,double,unsigned short*,
+                  unsigned short*,unsigned short*));
+void rgb_to_hsv P((unsigned short,unsigned short,unsigned short,
+                  int*,double*,double*));
+void cycle_hue P((XColor*,int));
+
+void make_color_ramp P((int h1, double s1, double v1,
+                       int h2, double s2, double v2,
+                       XColor *pixels, int npixels));
+
+static double _frand_tmp_;
+#define frand(f)                                                       \
+ (_frand_tmp_ = (((double) random()) /                                         \
+                (((double) ((unsigned int)~0)) / ((double) (f+f)))),   \
+  _frand_tmp_ < 0 ? -_frand_tmp_ : _frand_tmp_)
+
+#undef P
+#endif /* _SCREENHACK_H_ */
diff --git a/hacks/slidescreen.c b/hacks/slidescreen.c
new file mode 100644 (file)
index 0000000..37ca4d1
--- /dev/null
@@ -0,0 +1,317 @@
+/* xscreensaver, Copyright (c) 1992, 1993 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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"
+
+static int grid_size;
+static int pix_inc;
+static int hole_x, hole_y;
+static int bitmap_w, bitmap_h;
+static int xoff, yoff;
+static int grid_w, grid_h;
+static int delay, delay2;
+static GC gc;
+
+static Bool
+MapNotify_event_p (dpy, event, window)
+     Display *dpy;
+     XEvent *event;
+     XPointer window;
+{
+  return (event->xany.type == MapNotify &&
+         event->xvisibility.window == (Window) window);
+}
+
+
+static Bool
+screensaver_window_p (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  Atom type;
+  int format;
+  unsigned long nitems, bytesafter;
+  char *version;
+  Pixmap pixmap;
+  if (XGetWindowProperty (dpy, window,
+                         XInternAtom (dpy, "_SCREENSAVER_VERSION", False),
+                         0, 1, False, XA_STRING,
+                         &type, &format, &nitems, &bytesafter,
+                         (unsigned char **) &version)
+      == Success
+      && type != None)
+    return True;
+  return False;
+}
+
+static void
+init_slide (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  int i;
+  XEvent event;
+  XGCValues gcv;
+  XWindowAttributes xgwa;
+  int border;
+  int root_p;
+  unsigned long fg;
+  Pixmap pixmap = 0;
+  Drawable d;
+  Colormap cmap;
+
+  XGetWindowAttributes (dpy, window, &xgwa);
+  cmap = xgwa.colormap;
+
+  delay = get_integer_resource ("delay", "Integer");
+  delay2 = get_integer_resource ("delay2", "Integer");
+  grid_size = get_integer_resource ("gridSize", "Integer");
+  pix_inc = get_integer_resource ("pixelIncrement", "Integer");
+  border = get_integer_resource ("internalBorderWidth", "InternalBorderWidth");
+  fg = get_pixel_resource ("background", "Background", dpy, cmap);
+  root_p = get_boolean_resource ("root", "Boolean");
+
+  if (delay < 0) delay = 0;
+  if (delay2 < 0) delay2 = 0;
+  if (pix_inc < 1) pix_inc = 1;
+  if (grid_size < 1) grid_size = 1;
+
+  gcv.foreground = fg;
+  gcv.function = GXcopy;
+  gcv.subwindow_mode = IncludeInferiors;
+  gc = XCreateGC (dpy, window, GCForeground |GCFunction | GCSubwindowMode,
+                 &gcv);
+
+  if (screensaver_window_p (dpy, window))
+    {
+      /* note: this assumes vroot.h didn't encapsulate the XRootWindowOfScreen
+        function, only the RootWindowOfScreen macro... */
+      Window real_root = XRootWindowOfScreen (DefaultScreenOfDisplay (dpy));
+
+      XSetWindowBackgroundPixmap (dpy, window, None);
+
+      /* prevent random viewer of the screen saver (locker) from messing
+        with windows.   We don't check whether it succeeded, because what
+        are our options, really... */
+      XGrabPointer (dpy, real_root, True, ButtonPressMask|ButtonReleaseMask,
+                   GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
+      XGrabKeyboard (dpy, real_root, True, GrabModeSync, GrabModeAsync,
+                    CurrentTime);
+
+      XUnmapWindow (dpy, window);
+      XSync (dpy, True);
+      sleep (5);     /* wait for everyone to swap in and handle exposes... */
+      XMapWindow (dpy, window);
+
+      XUngrabPointer (dpy, CurrentTime);
+      XUngrabKeyboard (dpy, CurrentTime);
+
+      XSync (dpy, True);
+    }
+  else if (root_p)
+    {
+      pixmap = XCreatePixmap(dpy, window, xgwa.width, xgwa.height, xgwa.depth);
+      XCopyArea (dpy, RootWindowOfScreen (xgwa.screen), pixmap, gc,
+                xgwa.x, xgwa.y, xgwa.width, xgwa.height, 0, 0);
+      XSetWindowBackgroundPixmap (dpy, window, pixmap);
+    }
+  else
+    {
+      XSetWindowBackgroundPixmap (dpy, window, None);
+      XMapWindow (dpy, window);
+      XFlush (dpy);
+      XIfEvent (dpy, &event, MapNotify_event_p, (XPointer) window);
+      XSync (dpy, True);
+    }
+
+  XGetWindowAttributes (dpy, window, &xgwa);
+  bitmap_w = xgwa.width;
+  bitmap_h = xgwa.height;
+
+  grid_w = bitmap_w / grid_size;
+  grid_h = bitmap_h / grid_size;
+  hole_x = random () % grid_w;
+  hole_y = random () % grid_h;
+  xoff = (bitmap_w - (grid_w * grid_size)) / 2;
+  yoff = (bitmap_h - (grid_h * grid_size)) / 2;
+
+  d = (pixmap ? pixmap : window);
+
+  if (border)
+    {
+      int i;
+      for (i = 0; i <= bitmap_w; i += grid_size)
+       XFillRectangle (dpy, d, gc, xoff+i-border/2, yoff, border, bitmap_h);
+      for (i = 0; i <= bitmap_h; i += grid_size)
+       XFillRectangle (dpy, d, gc, xoff, yoff+i-border/2, bitmap_w, border);
+    }
+
+  if (xoff)
+    {
+      XFillRectangle (dpy, d, gc, 0, 0, xoff, bitmap_h);
+      XFillRectangle (dpy, d, gc, bitmap_w - xoff, 0, xoff, bitmap_h);
+    }
+  if (yoff)
+    {
+      XFillRectangle (dpy, d, gc, 0, 0, bitmap_w, yoff);
+      XFillRectangle (dpy, d, gc, 0, bitmap_h - yoff, bitmap_w, yoff);
+    }
+
+  if (pixmap) XClearWindow (dpy, window);
+  XSync (dpy, True);
+  if (delay2) usleep (delay2 * 2);
+ for (i = 0; i < grid_size; i += pix_inc)
+   {
+     XPoint points [3];
+     points[0].x = xoff + grid_size * hole_x;
+     points[0].y = yoff + grid_size * hole_y;
+     points[1].x = points[0].x + grid_size;
+     points[1].y = points[0].y;
+     points[2].x = points[0].x;
+     points[2].y = points[0].y + i;
+     XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
+
+     points[1].x = points[0].x;
+     points[1].y = points[0].y + grid_size;
+     points[2].x = points[0].x + i;
+     points[2].y = points[0].y + grid_size;
+     XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
+
+     points[0].x = points[1].x + grid_size;
+     points[0].y = points[1].y;
+     points[2].x = points[0].x;
+     points[2].y = points[0].y - i;
+     XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
+
+     points[1].x = points[0].x;
+     points[1].y = points[0].y - grid_size;
+     points[2].x = points[1].x - i;
+     points[2].y = points[1].y;
+     XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
+
+     XSync (dpy, True);
+     if (delay) usleep (delay);
+   }
+
+  XFillRectangle (dpy, window, gc,
+                 xoff + grid_size * hole_x,
+                 yoff + grid_size * hole_y,
+                 grid_size, grid_size);
+}
+
+static void
+slide1 (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  /* this code is a total kludge, but who cares, it works... */
+ int i, x, y, ix, iy, dx, dy, dir, w, h, size, inc;
+ static int last = -1;
+ do {
+   dir = random () % 4;
+   switch (dir)
+     {
+     case 0: dx = 0,  dy = 1;  break;
+     case 1: dx = -1, dy = 0;  break;
+     case 2: dx = 0,  dy = -1; break;
+     case 3: dx = 1,  dy = 0;  break;
+     }
+ } while (dir == last ||
+         hole_x + dx < 0 || hole_x + dx >= grid_w ||
+         hole_y + dy < 0 || hole_y + dy >= grid_h);
+ if (grid_w > 1 && grid_h > 1)
+   last = (dir == 0 ? 2 : dir == 2 ? 0 : dir == 1 ? 3 : 1);
+
+ switch (dir)
+   {
+   case 0: size = 1 + (random()%(grid_h - hole_y - 1)); h = size; w = 1; break;
+   case 1: size = 1 + (random()%hole_x);               w = size; h = 1; break;
+   case 2: size = 1 + (random()%hole_y);               h = size; w = 1; break;
+   case 3: size = 1 + (random()%(grid_w - hole_x - 1)); w = size; h = 1; break;
+   }
+
+ if (dx == -1) hole_x -= (size - 1);
+ else if (dy == -1) hole_y -= (size - 1);
+
+ ix = x = xoff + (hole_x + dx) * grid_size;
+ iy = y = yoff + (hole_y + dy) * grid_size;
+ inc = pix_inc;
+ for (i = 0; i < grid_size; i += inc)
+   {
+     if (inc + i > grid_size)
+       inc = grid_size - i;
+     XCopyArea (dpy, window, window, gc, x, y, grid_size * w, grid_size * h,
+               x - dx * inc, y - dy * inc);
+     x -= dx * inc;
+     y -= dy * inc;
+     switch (dir)
+       {
+       case 0: XFillRectangle (dpy, window, gc,
+                              ix, y + grid_size * h, grid_size * w, iy - y);
+        break;
+       case 1: XFillRectangle (dpy, window, gc, ix, iy, x - ix, grid_size * h);
+        break;
+       case 2: XFillRectangle (dpy, window, gc, ix, iy, grid_size * w, y - iy);
+        break;
+       case 3: XFillRectangle (dpy, window, gc,
+                              x + grid_size * w, iy, ix - x, grid_size * h);
+        break;
+       }
+
+     XSync (dpy, True);
+     if (delay) usleep (delay);
+   }
+ switch (dir)
+   {
+   case 0: hole_y += size; break;
+   case 1: hole_x--; break;
+   case 2: hole_y--; break;
+   case 3: hole_x += size; break;
+   }
+}
+
+\f
+char *progclass = "SlidePuzzle";
+
+char *defaults [] = {
+  "SlidePuzzle.mappedWhenManaged:false",
+  "SlidePuzzle.dontClearWindow:         true",
+  "*background:                        black",
+  "*gridSize:                  70",
+  "*pixelIncrement:            10",
+  "*internalBorderWidth:       1",
+  "*delay:                     50000",
+  "*delay2:                    1000000",
+  0
+};
+
+XrmOptionDescRec options [] = {
+  { "-grid-size",      ".gridSize",            XrmoptionSepArg, 0 },
+  { "-ibw",            ".internalBorderWidth", XrmoptionSepArg, 0 },
+  { "-increment",      ".pixelIncrement",      XrmoptionSepArg, 0 },
+  { "-delay",          ".delay",               XrmoptionSepArg, 0 },
+  { "-delay2",         ".delay2",              XrmoptionSepArg, 0 },
+};
+
+int options_size = (sizeof (options) / sizeof (options[0]));
+
+void
+screenhack (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  init_slide (dpy, window);
+  while (1)
+    {
+      slide1 (dpy, window);
+      if (delay2) usleep (delay2);
+    }
+}
diff --git a/hacks/slidescreen.man b/hacks/slidescreen.man
new file mode 100644 (file)
index 0000000..1573c86
--- /dev/null
@@ -0,0 +1,61 @@
+.TH XScreenSaver 1 "3-dec-92" "X Version 11"
+.SH NAME
+slidescreen - permute the screen image like an 8-puzzle
+.SH SYNOPSIS
+.B slidescreen
+[\-display \fIhost:display.screen\fP] [\-background \fIcolor\fP] [\-grid-size \fIpixels\fP] [\-ibw \fIpixels\fP] [\-increment \fIpixels\fP] [\-delay \fIusecs\fP] [\-delay2 \fIusecs\fP] [\-window] [\-root]
+.SH DESCRIPTION
+The \fIslidescreen\fP program takes an image of the screen, divides it into
+a grid, deletes a random square of that grid, and then randomly slides 
+one of the neighbors of this "hole" into the hole (and repeat.)
+.SH OPTIONS
+.I slidescreen
+accepts the following options:
+.TP 8
+.B \-window
+Draw on a newly-created window.  This is the default.
+.TP 8
+.B \-root
+Draw on the root window.
+.TP 8
+.B \-grid-size pixels
+The size of the grid cells.  Default 70 pixels.
+.TP 8
+.B \-ibw pixels
+The size of the "gutter" between grid cells.  Default 1 pixel.
+.TP 8
+.B \-increment pixels
+How many pixels by which a piece should be moved when sliding to a new 
+location.  Default 10 pixels.
+.TP 8
+.B \-delay microseconds
+How much of a delay should be introduced between steps of the animation of
+the motion of each segment.  Default 50000, which is 0.05 seconds.  This
+is closely related to the \fI\-increment\fP parameter.
+.TP 8
+.B \-delay microseconds
+How much of a delay should be introduced between the end of the motion of
+one segment and the beginning of the motion of another.  Default 1000000,
+which isone second.
+.SH ENVIRONMENT
+.PP
+.TP 8
+.B DISPLAY
+to get the default host and display number.
+.TP 8
+.B XENVIRONMENT
+to get the name of a resource file that overrides the global resources
+stored in the RESOURCE_MANAGER property.
+.SH SEE ALSO
+.BR X (1),
+.BR xscreensaver (1)
+.SH COPYRIGHT
+Copyright \(co 1992 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
+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.
+.SH AUTHOR
+Jamie Zawinski <jwz@lucid.com>, 3-dec-92.
diff --git a/hacks/vroot.h b/hacks/vroot.h
new file mode 100644 (file)
index 0000000..a00e706
--- /dev/null
@@ -0,0 +1,123 @@
+/*****************************************************************************/
+/**                   Copyright 1991 by Andreas Stolcke                     **/
+/**               Copyright 1990 by Solbourne Computer Inc.                 **/
+/**                          Longmont, Colorado                             **/
+/**                                                                         **/
+/**                           All Rights Reserved                           **/
+/**                                                                         **/
+/**    Permission to use, copy, modify, and distribute this software and    **/
+/**    its documentation  for  any  purpose  and  without  fee is hereby    **/
+/**    granted, provided that the above copyright notice appear  in  all    **/
+/**    copies and that both  that  copyright  notice  and  this  permis-    **/
+/**    sion  notice appear in supporting  documentation,  and  that  the    **/
+/**    name of Solbourne not be used in advertising                         **/
+/**    in publicity pertaining to distribution of the  software  without    **/
+/**    specific, written prior permission.                                  **/
+/**                                                                         **/
+/**    ANDREAS STOLCKE AND SOLBOURNE COMPUTER INC. DISCLAIMS ALL WARRANTIES **/
+/**    WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF    **/
+/**    MERCHANTABILITY  AND  FITNESS,  IN  NO  EVENT SHALL ANDREAS STOLCKE  **/
+/**    OR SOLBOURNE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL    **/
+/**    DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA   **/
+/**    OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER    **/
+/**    TORTIOUS ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE    **/
+/**    OR PERFORMANCE OF THIS SOFTWARE.                                     **/
+/*****************************************************************************/
+/*
+ * vroot.h -- Virtual Root Window handling header file
+ *
+ * This header file redefines the X11 macros RootWindow and DefaultRootWindow,
+ * making them look for a virtual root window as provided by certain `virtual'
+ * window managers like swm and tvtwm. If none is found, the ordinary root
+ * window is returned, thus retaining backward compatibility with standard
+ * window managers.
+ * The function implementing the virtual root lookup remembers the result of
+ * its last invocation to avoid overhead in the case of repeated calls
+ * on the same display and screen arguments. 
+ * The lookup code itself is taken from Tom LaStrange's ssetroot program.
+ *
+ * Most simple root window changing X programs can be converted to using
+ * virtual roots by just including
+ *
+ * #include <X11/vroot.h>
+ *
+ * after all the X11 header files.  It has been tested on such popular
+ * X clients as xphoon, xfroot, xloadimage, and xaqua.
+ * It also works with the core clients xprop, xwininfo, xwd, and editres
+ * (and is necessary to get those clients working under tvtwm).
+ * It does NOT work with xsetroot; get the xsetroot replacement included in
+ * the tvtwm distribution instead.
+ *
+ * Andreas Stolcke <stolcke@ICSI.Berkeley.EDU>, 9/7/90
+ * - replaced all NULL's with properly cast 0's, 5/6/91
+ * - free children list (suggested by Mark Martin <mmm@cetia.fr>), 5/16/91
+ * - include X11/Xlib.h and support RootWindowOfScreen, too 9/17/91
+ */
+
+#ifndef _VROOT_H_
+#define _VROOT_H_
+
+#if !defined(lint) && !defined(SABER)
+static char vroot_rcsid[] = "$Id: vroot.h,v 1.4 1991/09/30 19:23:16 stolcke Exp stolcke $";
+#endif
+
+#include <X11/X.h>
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+
+static Window
+VirtualRootWindowOfScreen(screen)
+       Screen *screen;
+{
+       static Screen *save_screen = (Screen *)0;
+       static Window root = (Window)0;
+
+       if (screen != save_screen) {
+               Display *dpy = DisplayOfScreen(screen);
+               Atom __SWM_VROOT = None;
+               int i;
+               Window rootReturn, parentReturn, *children;
+               unsigned int numChildren;
+
+               root = RootWindowOfScreen(screen);
+
+               /* go look for a virtual root */
+               __SWM_VROOT = XInternAtom(dpy, "__SWM_VROOT", False);
+               if (XQueryTree(dpy, root, &rootReturn, &parentReturn,
+                                &children, &numChildren)) {
+                       for (i = 0; i < numChildren; i++) {
+                               Atom actual_type;
+                               int actual_format;
+                               unsigned long nitems, bytesafter;
+                               Window *newRoot = (Window *)0;
+
+                               if (XGetWindowProperty(dpy, children[i],
+                                       __SWM_VROOT, 0, 1, False, XA_WINDOW,
+                                       &actual_type, &actual_format,
+                                       &nitems, &bytesafter,
+                                       (unsigned char **) &newRoot) == Success
+                                   && newRoot) {
+                                   root = *newRoot;
+                                   break;
+                               }
+                       }
+                       if (children)
+                               XFree((char *)children);
+               }
+
+               save_screen = screen;
+       }
+
+       return root;
+}
+
+#undef RootWindowOfScreen
+#define RootWindowOfScreen(s) VirtualRootWindowOfScreen(s)
+
+#undef RootWindow
+#define RootWindow(dpy,screen) VirtualRootWindowOfScreen(ScreenOfDisplay(dpy,screen))
+
+#undef DefaultRootWindow
+#define DefaultRootWindow(dpy) VirtualRootWindowOfScreen(DefaultScreenOfDisplay(dpy))
+
+#endif /* _VROOT_H_ */
diff --git a/hacks/xlock.h b/hacks/xlock.h
new file mode 100644 (file)
index 0000000..a53a99a
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+**  Helpful definitions for porting xlock modes to xscreensaver.
+**  by Charles Hannum, mycroft@ai.mit.edu
+**
+**  for xlock 2.3 and xscreensaver 1.2, 28AUG92
+**
+**
+**  To use, just copy the appropriate file from xlock, add a target
+**  for it in the Imakefile, and do the following:
+**
+**  1) If you include math.h, make sure it is before xlock.h.
+**  2) Make sure the first thing you do in initfoo() is to call
+**     XGetWindowAttributes.  This is what actually sets up the
+**     colormap and whatnot.
+**  3) Add an appropriate PROGRAM() line at the end of the .c file.
+**     The information you need for this comes from xlock's file
+**     resource.c.
+**
+**  That's about all there is to it.
+**
+**  As an added bonus, if you put an empty definition of PROGRAM() in
+**  xlock's xlock.h, you can now use the code with either xlock or
+**  xscreensaver.
+**
+**
+**  If you make any improvements to this code, please send them to me!
+**  It could certainly use some more work.
+*/
+
+#include "screenhack.h"
+
+#define MAXSCREENS 1
+
+static GC gc;
+static unsigned long *pixels = 0, fg_pixel, bg_pixel;
+static int npixels;
+static Colormap cmap;
+
+static int batchcount;
+static unsigned int delay;
+static double saturation;
+
+typedef struct {
+  GC gc;
+  int npixels;
+  u_long *pixels;
+} perscreen;
+
+static perscreen Scr[MAXSCREENS];
+static Display *dsp;
+
+static int screen = 0;
+
+static void
+My_XGetWindowAttributes (dpy, win, xgwa)
+  Display *dpy;
+  Window win;
+  XWindowAttributes *xgwa;
+{
+  XGetWindowAttributes (dpy, win, xgwa);
+
+  if (! pixels) {
+    XGCValues gcv;
+    XColor color;
+    int n;
+    int i, shift;
+
+    cmap = xgwa->colormap;
+
+    i = get_integer_resource ("ncolors", "Integer");
+    if (i <= 2) i = 2, mono_p = True;
+    shift = 360 / i;
+    pixels = (unsigned long *) calloc (i, sizeof (unsigned long));
+    fg_pixel = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
+    bg_pixel = get_pixel_resource ("background", "Background", dpy, cmap);
+    if (! mono_p) {
+      for (npixels = 0; npixels < i; npixels++) {
+        hsv_to_rgb ((360*npixels)/i, saturation, 1.0, &color.red, &color.green, &color.blue);
+        if (! XAllocColor (dpy, cmap, &color))
+          break;
+        pixels[npixels] = color.pixel;
+      }
+    }
+    n = get_integer_resource ("delay", "Usecs");
+    if (n >= 0) delay = n;
+    n = get_integer_resource ("count", "Integer");
+    if (n > 0) batchcount = n;
+
+    gcv.foreground = fg_pixel;
+    gcv.background = bg_pixel;
+    gc = XCreateGC (dpy, win, GCForeground|GCBackground, &gcv);
+
+    XClearWindow (dpy, win);
+
+    Scr[screen].gc = gc;
+    Scr[screen].npixels = npixels;
+    Scr[screen].pixels = pixels;
+  }
+}
+
+#define XGetWindowAttributes(a,b,c) My_XGetWindowAttributes(a,b,c)
+
+#undef BlackPixel
+#define BlackPixel(a,b) bg_pixel
+#undef WhitePixel
+#define WhitePixel(a,b) fg_pixel
+#define mono mono_p
+
+#define seconds() time((time_t*)0)
+
+char *defaults[] = {
+  "*background:        black",
+  "*foreground:        white",
+  "*ncolors:   64",
+  "*delay:     -1",
+  0
+};
+
+XrmOptionDescRec options[] = {
+  {"-count",   ".count",       XrmoptionSepArg, 0},
+  {"-ncolors", ".ncolors",     XrmoptionSepArg, 0},
+  {"-delay",   ".delay",       XrmoptionSepArg, 0},
+};
+int options_size = (sizeof (options) / sizeof (options[0]));
+
+#define PROGRAM(Y,Z,D,B,S) \
+char *progclass = Y;                   \
+                                       \
+void screenhack (dpy, window)          \
+  Display *dpy;                                \
+  Window window;                       \
+{                                      \
+  batchcount = B;                      \
+  delay = D;                           \
+  saturation = S;                      \
+  dsp = dpy;                           \
+                                       \
+  while (1) {                          \
+    init##Z (window);                  \
+    for (;;) {                         \
+      draw##Z (window);                        \
+      XSync (dpy, True);               \
+      if (delay) usleep (delay);       \
+    }                                  \
+  }                                    \
+}
diff --git a/hacks/xroger-hack.c b/hacks/xroger-hack.c
new file mode 100644 (file)
index 0000000..d2bc031
--- /dev/null
@@ -0,0 +1,101 @@
+/* xscreensaver, Copyright (c) 1991-1993 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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"
+
+char *progclass = "XRoger";
+
+char *defaults [] = {
+  "*background: black",
+  "*foreground: red",
+  "*delay:     5",
+  0
+};
+
+XrmOptionDescRec options [] = {
+  { "-delay",          ".delay",       XrmoptionSepArg, 0 }
+};
+int options_size = (sizeof (options) / sizeof (options[0]));
+
+#if __STDC__
+extern void skull (Display *, Window, GC, GC, int, int, int, int);
+#endif
+
+void
+screenhack (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  double delta = 0.005;
+  XGCValues gcv;
+  Colormap cmap;
+  GC draw_gc, erase_gc;
+  unsigned int fg;
+  XColor color, color2;
+  int delay = get_integer_resource ("delay", "Integer");
+  XWindowAttributes xgwa;
+  XGetWindowAttributes (dpy, window, &xgwa);
+  cmap = xgwa.colormap;
+  gcv.foreground = get_pixel_resource ("background", "Background", dpy, cmap);
+  erase_gc = XCreateGC (dpy, window, GCForeground, &gcv);
+  fg = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
+  if (fg == gcv.foreground)
+    fg = ((gcv.foreground == WhitePixel (dpy, DefaultScreen (dpy)))
+         ? BlackPixel (dpy, DefaultScreen (dpy))
+         : WhitePixel (dpy, DefaultScreen (dpy)));
+  gcv.foreground = fg;
+  draw_gc = XCreateGC (dpy, window, GCForeground, &gcv);
+  color.pixel = gcv.foreground;
+  XQueryColor (dpy, cmap, &color);
+  while (1)
+    {
+      int w, h, ww, hh, x, y;
+      time_t start_time;
+      XWindowAttributes xgwa;
+      XGetWindowAttributes (dpy, window, &xgwa);
+      w = xgwa.width;
+      h = xgwa.height;
+
+      ww = 100 + random () % (w - 100);
+      hh = 100 + random () % (h - 100);
+      if (ww < 10) ww = 50;
+      if (hh < 10) hh = 50;
+      if (ww < hh) hh = ww;
+      else ww = hh;
+      x = random () % (w - ww);
+      y = random () % (h - hh);
+      XClearWindow (dpy, window);
+      skull (dpy, window, draw_gc, erase_gc, x, y, ww, hh);
+      XSync (dpy, True);
+      start_time = time ((time_t *) 0);
+      if (mono_p)
+       sleep (delay);
+      else
+       while (start_time + delay > time ((time_t *) 0))
+         {
+           int h;
+           double s, v;
+           color2 = color;
+           rgb_to_hsv (color2.red, color2.green, color2.blue, &h, &s, &v);
+           v += delta;
+           if (v >= 1.0) v = 1.0, delta = -delta;
+           if (v <= 0.7) v = 0.7, delta = -delta;
+           hsv_to_rgb (h, s, v, &color2.red, &color2.green, &color2.blue);
+           if (XAllocColor (dpy, cmap, &color2))
+             {
+               XSetForeground (dpy, draw_gc, color.pixel);
+               XFreeColors (dpy, cmap, &color.pixel, 1, 0);
+             }
+           color = color2;
+           usleep (20000);
+         }
+    }
+}
diff --git a/hacks/xroger.man b/hacks/xroger.man
new file mode 100644 (file)
index 0000000..7661ec4
--- /dev/null
@@ -0,0 +1,43 @@
+.TH XScreenSaver 1 "22-mar-93" "X Version 11"
+.SH NAME
+xroger - throbbing X logo, of a sort
+.SH SYNOPSIS
+.B xroger
+[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root] [\-mono]
+.SH DESCRIPTION
+The \fIxroger\fP program displays a replacement for the X logo with a more
+accurate Look and Feel.
+.SH OPTIONS
+.I xroger
+accepts the following options:
+.TP 8
+.B \-window
+Draw on a newly-created window.  This is the default.
+.TP 8
+.B \-root
+Draw on the root window.
+.TP 8
+.B \-mono 
+If on a color display, pretend we're on a monochrome display.
+.SH ENVIRONMENT
+.PP
+.TP 8
+.B DISPLAY
+to get the default host and display number.
+.TP 8
+.B XENVIRONMENT
+to get the name of a resource file that overrides the global resources
+stored in the RESOURCE_MANAGER property.
+.SH SEE ALSO
+.BR X (1),
+.BR xscreensaver (1)
+.SH COPYRIGHT
+Copyright \(co 1992, 1993 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 fnord 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 fnord this software for any purpose.  It is provided "as
+is" without express or fnord implied warranty.
+.SH AUTHOR
+Jamie Zawinski <jwz@lucid.com>, 13-aug-92.
diff --git a/screenblank.txt b/screenblank.txt
new file mode 100644 (file)
index 0000000..1762158
--- /dev/null
@@ -0,0 +1,46 @@
+From mrapple@quack.kfu.com Mon Apr 26 18:31:07 1993
+Newsgroups: alt.hackers
+From: mrapple@quack.kfu.com (Nick Sayer)
+Subject: screenblank and xautolock living in harmony
+Organization: The Duck Pond public unix: +1 408 249 9630, log in as 'guest'.
+Date: 23 Apr 1993 19:26:57 UTC
+
+
+I have a Sun and use xinit to start X. This presented a problem.
+If I use xautolock or xscreensaver to save the screen, then after
+a period of inactivity screenblank would turn the video off despite
+'xset s off'. If I didn't run screenblank, then who would take care of
+the display when X wasn't running?
+
+The hack that saved the day was to include this in .xinitrc:
+
+(
+
+while true ; do
+sleep 360
+touch /dev/console
+done
+
+) &
+killblank=$!
+
+[start up all the clients, etc, etc. Wait for the window manager
+to die, then ]
+
+kill $killblank
+
+The result is that screenblank is kept safely out of the way when X
+is running and left to do its job otherwise.
+
+Yes, I know using XDM would solve this problem.
+
+No, I'm probably not the first to think of this.
+
+You're welcome.
+
+-- 
+Nick Sayer <mrapple@quack.kfu.com>   | "Dear Sexy Nickers. I don't half fancy
+N6QQQ @ N0ARY.#NOCAL.CA.USA.NOAM     | you. Meet me at the lift at 5:30 and
++1 408 249 9630, log in as 'guest'   | we'll get it together."
+PGP 2.2 public key via finger        |               -- Mr. Lucas
+
diff --git a/utils/Imakefile b/utils/Imakefile
new file mode 100644 (file)
index 0000000..87c1ca3
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Imakefile file for xscreensaver, Copyright (c) 1993 Jamie Zawinski.
+ *
+ * You should not need to edit this file; edit ../config.h instead.
+ *
+ */
+
+#include "../config.h"
+
+#ifdef NO_SELECT
+        DEFINES = -DNO_SELECT
+#endif
+           SRCS = fade.c hsv.c resources.c spline.c usleep.c xroger.c
+           OBJS = fade.o hsv.o resources.o spline.o usleep.o xroger.o
+       TARFILES = README Imakefile ad2c $(SRCS) spline.h version.h
+
+all:: $(OBJS)
+
+echo_tarfiles:
+       @echo $(TARFILES)
diff --git a/utils/README b/utils/README
new file mode 100644 (file)
index 0000000..2f5bc11
--- /dev/null
@@ -0,0 +1,6 @@
+
+This directory contains various utilities that are used both by the 
+screensaver driver and by the demo programs; for example, a portable
+implementation of usleep(), and code for manipulating color maps.
+
+If you have compilation problems, check the parameters in ../config.h.
diff --git a/utils/ad2c b/utils/ad2c
new file mode 100755 (executable)
index 0000000..1435e55
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/sh
+#
+#      ad2c : Convert app-defaults file to C strings decls.
+#
+#      George Ferguson, ferguson@cs.rcohester.edu, 12 Nov 1990.
+#      19 Mar 1991 : gf
+#              Made it self-contained.
+#      6 Jan 1992 : mycroft@gnu.ai.mit.edu (Charles Hannum)
+#              Removed use of "-n" and ":read" label since Gnu and
+#              IBM sed print pattern space on "n" command. Still works
+#              with Sun sed, of course.
+#      7 Jan 1992: matthew@sunpix.East.Sun.COM (Matthew Stier)
+#              Escape quotes after escaping backslashes.
+#
+
+sed '
+/^!/d
+/^$/d
+s/\\/\\\\/g
+s/\\$//g
+s/"/\\"/g
+s/^/"/
+: test
+/\\$/b slash
+s/$/",/
+p
+d
+: slash
+n
+/^!/d
+/^$/d
+s/"/\\"/g
+s/\\\\/\\/g
+s/\\n/\\\\n/g
+s/\\t/\\\\t/g
+s/\\f/\\\\f/g
+s/\\b/\\\\b/g
+b test' "$@"
diff --git a/utils/fade.c b/utils/fade.c
new file mode 100644 (file)
index 0000000..2fbb2e9
--- /dev/null
@@ -0,0 +1,166 @@
+/* xscreensaver, Copyright (c) 1992 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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.
+ */
+
+#if __STDC__
+# include <stdlib.h>
+#endif
+
+#include <stdio.h>
+#include <X11/Xlib.h>
+#include <X11/Xos.h>
+
+#if __STDC__
+# define bcopy(from,to,size) memcpy((to),(from),(size))
+# define bzero(addr,size) memset((addr),0,(size))
+extern void screenhack_usleep (unsigned long);
+#else
+extern void screenhack_usleep ();
+#endif
+
+#define usleep screenhack_usleep
+
+#define MAX_COLORS 4096
+static XColor orig_colors [MAX_COLORS];
+static XColor current_colors [MAX_COLORS];
+static int ncolors;
+
+Colormap
+copy_colormap (dpy, cmap, into_cmap)
+     Display *dpy;
+     Colormap cmap, into_cmap;
+{
+  int i;
+  ncolors = CellsOfScreen (DefaultScreenOfDisplay (dpy));
+  if (ncolors <= 2 || ncolors > MAX_COLORS)
+    return 0;
+  if (! into_cmap)
+    into_cmap = XCreateColormap (dpy, RootWindow (dpy, DefaultScreen (dpy)),
+                                DefaultVisual (dpy, DefaultScreen (dpy)),
+                                AllocAll);
+  if (! cmap)
+    cmap = DefaultColormap (dpy, DefaultScreen (dpy));
+  for (i = 0; i < ncolors; i++)
+    orig_colors [i].pixel = i;
+  XQueryColors (dpy, cmap, orig_colors, ncolors);
+  XStoreColors (dpy, into_cmap, orig_colors, ncolors);
+  return into_cmap;
+}
+
+void
+blacken_colormap (dpy, cmap)
+     Display *dpy;
+     Colormap cmap;
+{
+  int i;
+  for (i = 0; i < ncolors; i++)
+    {
+      current_colors [i].pixel = i;
+      current_colors [i].red = current_colors [i].green =
+       current_colors [i].blue = 0;
+    }
+  XStoreColors (dpy, cmap, current_colors, ncolors);
+}
+
+
+void
+fade_colormap (dpy, cmap, cmap2, seconds, ticks, out_p)
+     Display *dpy;
+     Colormap cmap, cmap2;
+     int seconds, ticks;
+     Bool out_p;
+{
+  int i;
+  int steps = seconds * ticks;
+  XEvent dummy_event;
+
+  if (! cmap2)
+    return;
+
+  for (i = 0; i < ncolors; i++)
+    orig_colors [i].pixel = i;
+  XQueryColors (dpy, cmap, orig_colors, ncolors);
+  bcopy (orig_colors, current_colors, ncolors * sizeof (XColor));
+
+  for (i = (out_p ? steps : 0);
+       (out_p ? i > 0 : i < steps);
+       (out_p ? i-- : i++))
+    {
+      int j;
+      for (j = 0; j < ncolors; j++)
+       {
+         current_colors[j].red   = orig_colors[j].red   * i / steps;
+         current_colors[j].green = orig_colors[j].green * i / steps;
+         current_colors[j].blue  = orig_colors[j].blue  * i / steps;
+       }
+      XStoreColors (dpy, cmap2, current_colors, ncolors);
+      XSync (dpy, False);
+
+      /* If there is user activity, bug out.
+        We put the event back so that the calling code can notice it too.
+        It would be better to not remove it at all, but that's harder
+        because Xlib has such a non-design for this kind of crap, and
+        in this application it doesn't matter if the events end up out
+        of order, so in the grand unix tradition we say "fuck it" and
+        do something that mostly works for the time being.
+       */
+      if (XCheckMaskEvent (dpy, (KeyPressMask | KeyReleaseMask |
+                                ButtonPressMask | ButtonReleaseMask |
+                                PointerMotionMask),
+                          &dummy_event))
+       {
+         XPutBackEvent (dpy, &dummy_event);
+         return;
+       }
+
+      usleep (1000000 / (ticks * 2)); /* the 2 is a hack... */
+    }
+}
+
+#if 0
+
+\f
+char *progclass = "foo";
+
+char *defaults [] = {
+  0
+};
+
+XrmOptionDescRec options [] = {0};
+int options_size = 0;
+
+void
+screenhack (dpy, w)
+     Display *dpy;
+     Window w;
+{
+  Colormap cmap = DefaultColormap (dpy, DefaultScreen (dpy));
+  Colormap cmap2 = copy_colormap (dpy, cmap, 0);
+
+  int seconds = 1;
+  int ticks = 30 * seconds;
+  int delay = 1;
+
+  while (1)
+    {
+      XSync (dpy, False);
+      XGrabServer (dpy);
+      XInstallColormap (dpy, cmap2);
+      fade_colormap (dpy, cmap, cmap2, seconds, ticks, True);
+      if (delay) sleep (delay);
+      fade_colormap (dpy, cmap, cmap2, seconds, ticks, False);
+      XInstallColormap (dpy, cmap);
+      XUngrabServer (dpy);
+      XSync (dpy, False);
+      if (delay) sleep (delay);
+    }
+}
+
+#endif
diff --git a/utils/hsv.c b/utils/hsv.c
new file mode 100644 (file)
index 0000000..bf508f3
--- /dev/null
@@ -0,0 +1,110 @@
+/* xscreensaver, Copyright (c) 1992 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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.
+ */
+
+/* This file contains some utility routines for randomly picking the colors
+   to hack the screen with.
+ */
+
+#include <X11/Xlib.h>
+
+void
+hsv_to_rgb (h,s,v, r,g,b)
+     int h;                    /* 0 - 360   */
+     double s, v;              /* 0.0 - 1.0 */
+     unsigned short *r, *g, *b;        /* 0 - 65535 */
+{
+  double H, S, V, R, G, B;
+  double p1, p2, p3;
+  double f;
+  int i;
+  S = s; V = v;
+  H = (h % 360) / 60.0;
+  i = H;
+  f = H - i;
+  p1 = V * (1 - S);
+  p2 = V * (1 - (S * f));
+  p3 = V * (1 - (S * (1 - f)));
+  if     (i == 0) { R = V;  G = p3; B = p1; }
+  else if (i == 1) { R = p2; G = V;  B = p1; }
+  else if (i == 2) { R = p1; G = V;  B = p3; }
+  else if (i == 3) { R = p1; G = p2; B = V;  }
+  else if (i == 4) { R = p3; G = p1; B = V;  }
+  else            { R = V;  G = p1; B = p2; }
+  *r = R * 65535;
+  *g = G * 65535;
+  *b = B * 65535;
+}
+
+void
+rgb_to_hsv (r,g,b, h,s,v)
+     unsigned short r, g, b;   /* 0 - 65535 */
+     int *h;                   /* 0 - 360   */
+     double *s, *v;            /* 0.0 - 1.0 */
+{
+  double R, G, B, H, S, V;
+  double cmax, cmin;
+  double cmm;
+  int imax;
+  R = ((double) r) / 65535.0;
+  G = ((double) g) / 65535.0;
+  B = ((double) b) / 65535.0;
+  cmax = R; cmin = G; imax = 1;
+  if  ( cmax < G ) { cmax = G; cmin = R; imax = 2; }
+  if  ( cmax < B ) { cmax = B; imax = 3; }
+  if  ( cmin > B ) { cmin = B; }
+  cmm = cmax - cmin;
+  V = cmax;
+  if (cmm == 0)
+    S = H = 0;
+  else
+    {
+      S = cmm / cmax;
+      if      (imax == 1) H =       (G - B) / cmm;
+      else if (imax == 2) H = 2.0 + (B - R) / cmm;
+      else if (imax == 3) H = 4.0 + (R - G) / cmm;
+      if (H < 0) H += 6.0;
+    }
+  *h = (H * 60.0);
+  *s = S;
+  *v = V;
+}
+
+
+void
+make_color_ramp (h1, s1, v1, h2, s2, v2,
+                pixels, npixels)
+     int h1, h2;                       /* 0 - 360   */
+     double s1, s2, v1, v2;            /* 0.0 - 1.0 */
+     XColor *pixels;
+     int npixels;
+{
+  int dh = (h2 - h1) / npixels;
+  double ds = (s2 - s1) / npixels;
+  double dv = (v2 - v1) / npixels;
+  int i;
+  for (i = 0; i < npixels; i++)
+    hsv_to_rgb ((h1 += dh), (s1 += ds), (v1 += dv),
+               &pixels [i].red, &pixels [i].green, &pixels [i].blue);
+}
+
+
+void
+cycle_hue (color, degrees)
+     XColor *color;
+     int degrees;
+{
+  int h;
+  double s, v;
+  rgb_to_hsv (color->red, color->green, color->blue,
+             &h, &s, &v);
+  h = (h + degrees) % 360;
+  hsv_to_rgb (h, s, v, &color->red, &color->green, &color->blue);
+}
diff --git a/utils/resources.c b/utils/resources.c
new file mode 100644 (file)
index 0000000..771e20f
--- /dev/null
@@ -0,0 +1,214 @@
+/* xscreensaver, Copyright (c) 1992 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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.
+ */
+
+#if __STDC__
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+#include <stdio.h>
+#include <X11/Xlib.h>
+#include <X11/Xresource.h>
+
+/* Resource functions.  Assumes: */
+
+extern char *progname;
+extern char *progclass;
+extern XrmDatabase db;
+
+#ifndef isupper
+# define isupper(c)  ((c) >= 'A' && (c) <= 'Z')
+#endif
+#ifndef _tolower
+# define _tolower(c)  ((c) - 'A' + 'a')
+#endif
+
+char *
+get_string_resource (res_name, res_class)
+     char *res_name, *res_class;
+{
+  XrmValue value;
+  char *type;
+  char full_name [1024], full_class [1024];
+  strcpy (full_name, progname);
+  strcat (full_name, ".");
+  strcat (full_name, res_name);
+  strcpy (full_class, progclass);
+  strcat (full_class, ".");
+  strcat (full_class, res_class);
+  if (XrmGetResource (db, full_name, full_class, &type, &value))
+    {
+      char *str = (char *) malloc (value.size + 1);
+      strncpy (str, (char *) value.addr, value.size);
+      str [value.size] = 0;
+      return str;
+    }
+  return 0;
+}
+
+Bool 
+get_boolean_resource (res_name, res_class)
+     char *res_name, *res_class;
+{
+  char *tmp, buf [100];
+  char *s = get_string_resource (res_name, res_class);
+  char *os = s;
+  if (! s) return 0;
+  for (tmp = buf; *s; s++)
+    *tmp++ = isupper (*s) ? _tolower (*s) : *s;
+  *tmp = 0;
+  free (os);
+
+  if (!strcmp (buf, "on") || !strcmp (buf, "true") || !strcmp (buf, "yes"))
+    return 1;
+  if (!strcmp (buf,"off") || !strcmp (buf, "false") || !strcmp (buf,"no"))
+    return 0;
+  fprintf (stderr, "%s: %s must be boolean, not %s.\n",
+          progname, res_class, buf);
+  return 0;
+}
+
+int 
+get_integer_resource (res_name, res_class)
+     char *res_name, *res_class;
+{
+  int val;
+  char c, *s = get_string_resource (res_name, res_class);
+  if (!s) return 0;
+  if (1 == sscanf (s, " %d %c", &val, &c))
+    {
+      free (s);
+      return val;
+    }
+  fprintf (stderr, "%s: %s must be an integer, not %s.\n",
+          progname, res_name, s);
+  free (s);
+  return 0;
+}
+
+double
+get_float_resource (res_name, res_class)
+     char *res_name, *res_class;
+{
+  double val;
+  char c, *s = get_string_resource (res_name, res_class);
+  if (! s) return 0.0;
+  if (1 == sscanf (s, " %lf %c", &val, &c))
+    {
+      free (s);
+      return val;
+    }
+  fprintf (stderr, "%s: %s must be a float, not %s.\n",
+          progname, res_name, s);
+  free (s);
+  return 0.0;
+}
+
+
+unsigned int
+get_pixel_resource (res_name, res_class, dpy, cmap)
+     char *res_name, *res_class;
+     Display *dpy;
+     Colormap cmap;
+{
+  XColor color;
+  char *s = get_string_resource (res_name, res_class);
+  if (!s) goto DEFAULT;
+
+  if (! XParseColor (dpy, cmap, s, &color))
+    {
+      fprintf (stderr, "%s: can't parse color %s\n", progname, s);
+      goto DEFAULT;
+    }
+  if (! XAllocColor (dpy, cmap, &color))
+    {
+      fprintf (stderr, "%s: couldn't allocate color %s\n", progname, s);
+      goto DEFAULT;
+    }
+  free (s);
+  return color.pixel;
+ DEFAULT:
+  if (s) free (s);
+  return (strcmp (res_class, "Background")
+         ? WhitePixel (dpy, DefaultScreen (dpy))
+         : BlackPixel (dpy, DefaultScreen (dpy)));
+}
+
+
+int
+parse_time (string, seconds_default_p, silent_p)
+     char *string;
+     Bool seconds_default_p, silent_p;
+{
+  unsigned int h, m, s;
+  char c;
+  if (3 == sscanf (string,   " %u : %2u : %2u %c", &h, &m, &s, &c))
+    ;
+  else if (2 == sscanf (string, " : %2u : %2u %c", &m, &s, &c) ||
+          2 == sscanf (string,    " %u : %2u %c", &m, &s, &c))
+    h = 0;
+  else if (1 == sscanf (string,       " : %2u %c", &s, &c))
+    h = m = 0;
+  else if (1 == sscanf (string,          " %u %c",
+                       (seconds_default_p ? &s : &m), &c))
+    {
+      h = 0;
+      if (seconds_default_p) m = 0;
+      else s = 0;
+    }
+  else
+    {
+      if (! silent_p)
+       fprintf (stderr, "%s: invalid time interval specification \"%s\".\n",
+                progname, string);
+      return -1;
+    }
+  if (s >= 60 && (h != 0 || m != 0))
+    {
+      if (! silent_p)
+       fprintf (stderr, "%s: seconds > 59 in \"%s\".\n", progname, string);
+      return -1;
+    }
+  if (m >= 60 && h > 0)
+    {
+      if (! silent_p)
+       fprintf (stderr, "%s: minutes > 59 in \"%s\".\n", progname, string);
+      return -1;
+    }
+  return ((h * 60 * 60) + (m * 60) + s);
+}
+
+static unsigned int 
+get_time_resource (res_name, res_class, sec_p)
+     char *res_name, *res_class;
+     Bool sec_p;
+{
+  int val;
+  char *s = get_string_resource (res_name, res_class);
+  if (!s) return 0;
+  val = parse_time (s, sec_p, False);
+  free (s);
+  return (val < 0 ? 0 : val);
+}
+
+unsigned int 
+get_seconds_resource (res_name, res_class)
+     char *res_name, *res_class;
+{
+  return get_time_resource (res_name, res_class, True);
+}
+
+unsigned int 
+get_minutes_resource (res_name, res_class)
+     char *res_name, *res_class;
+{
+  return get_time_resource (res_name, res_class, False);
+}
diff --git a/utils/spline.c b/utils/spline.c
new file mode 100644 (file)
index 0000000..ed5a224
--- /dev/null
@@ -0,0 +1,286 @@
+#include <stdio.h>
+#include "spline.h"
+#if __STDC__
+#include <stdlib.h>
+#endif
+#include <math.h>
+
+/* Lifted from InterViews */
+#define SMOOTHNESS 1.0
+
+static void
+no_more_memory ()
+{
+  fprintf (stderr, "No more memory\n");
+  exit (1);
+}
+
+spline*
+make_spline (size)
+     u_int size;
+{
+  spline* s = (spline*)calloc (1, sizeof (spline));
+  if (!s)
+    no_more_memory ();
+  s->n_controls = size;
+  s->control_x = (double*)calloc (s->n_controls, sizeof (double));
+  s->control_y = (double*)calloc (s->n_controls, sizeof (double));
+
+  s->n_points = 0;
+  s->allocated_points = s->n_controls;
+  s->points = (XPoint*)calloc (s->allocated_points, sizeof (XPoint));
+
+  if (!s->control_x || !s->control_y || !s->points)
+    no_more_memory ();
+
+  return s;
+}
+
+static void
+grow_spline_points (s)
+     spline* s;
+{
+  s->allocated_points *= 2;
+  s->points =
+    (XPoint*)realloc (s->points, s->allocated_points * sizeof (XPoint));
+
+  if (!s->points)
+    no_more_memory ();
+}
+
+static void 
+mid_point (x0, y0, x1, y1, mx, my)
+     double x0, y0, x1, y1, *mx, *my;
+{
+  *mx = (x0 + x1) / 2.0;
+  *my = (y0 + y1) / 2.0;
+}
+
+static void 
+third_point (x0, y0, x1, y1, tx, ty)
+     double x0, y0, x1, y1, *tx, *ty;
+{
+  *tx = (2 * x0 + x1) / 3.0;
+  *ty = (2 * y0 + y1) / 3.0;
+}
+
+static int
+can_approx_with_line (x0, y0, x2, y2, x3, y3)
+     double x0, y0, x2, y2, x3, y3;
+{
+  double triangle_area, side_squared, dx, dy;
+  
+  triangle_area = x0 * y2 - x2 * y0 + x2 * y3 - x3 * y2 + x3 * y0 - x0 * y3;
+  /* actually 4 times the area. */
+  triangle_area *= triangle_area;
+  dx = x3 - x0;
+  dy = y3 - y0;
+  side_squared = dx * dx + dy * dy;
+  return triangle_area <= SMOOTHNESS * side_squared;
+}
+
+static void
+add_line (s, x0, y0, x1, y1)
+     spline* s;
+     double x0, y0, x1, y1;
+{
+  if (s->n_points >= s->allocated_points)
+    grow_spline_points (s);
+
+  if (s->n_points == 0)
+    {
+      s->points [s->n_points].x = x0;
+      s->points [s->n_points].y = y0;
+      s->n_points += 1;
+    }
+  s->points [s->n_points].x = x1;
+  s->points [s->n_points].y = y1;
+  s->n_points += 1;
+}
+
+static void 
+add_bezier_arc (s, x0, y0, x1, y1, x2, y2, x3, y3)
+     spline* s;
+     double x0, y0, x1, y1, x2, y2, x3, y3;
+{
+  double midx01, midx12, midx23, midlsegx, midrsegx, cx,
+  midy01, midy12, midy23, midlsegy, midrsegy, cy;
+    
+  mid_point (x0, y0, x1, y1, &midx01, &midy01);
+  mid_point (x1, y1, x2, y2, &midx12, &midy12);
+  mid_point (x2, y2, x3, y3, &midx23, &midy23);
+  mid_point (midx01, midy01, midx12, midy12, &midlsegx, &midlsegy);
+  mid_point (midx12, midy12, midx23, midy23, &midrsegx, &midrsegy);
+  mid_point (midlsegx, midlsegy, midrsegx, midrsegy, &cx, &cy);    
+
+  if (can_approx_with_line (x0, y0, midlsegx, midlsegy, cx, cy))
+    add_line (s, x0, y0, cx, cy);
+  else if ((midx01 != x1) || (midy01 != y1) || (midlsegx != x2)
+          || (midlsegy != y2) || (cx != x3) || (cy != y3))
+    add_bezier_arc (s, x0, y0, midx01, midy01, midlsegx, midlsegy, cx, cy);
+
+  if (can_approx_with_line (cx, cy, midx23, midy23, x3, y3))
+    add_line (s, cx, cy, x3, y3);
+  else if ((cx != x0) || (cy != y0) || (midrsegx != x1) || (midrsegy != y1)
+          || (midx23 != x2) || (midy23 != y2))  
+    add_bezier_arc (s, cx, cy, midrsegx, midrsegy, midx23, midy23, x3, y3);
+}
+
+static void
+calc_section (s, cminus1x, cminus1y, cx, cy, cplus1x, cplus1y,
+             cplus2x, cplus2y)
+     spline* s;
+     double cminus1x, cminus1y, cx, cy, cplus1x, cplus1y, cplus2x, cplus2y;
+{
+  double p0x, p1x, p2x, p3x, tempx,
+  p0y, p1y, p2y, p3y, tempy;
+  
+  third_point (cx, cy, cplus1x, cplus1y, &p1x, &p1y);
+  third_point (cplus1x, cplus1y, cx, cy, &p2x, &p2y);
+  third_point (cx, cy, cminus1x, cminus1y, &tempx, &tempy);
+  mid_point (tempx, tempy, p1x, p1y, &p0x, &p0y);
+  third_point (cplus1x, cplus1y, cplus2x, cplus2y, &tempx, &tempy);
+  mid_point (tempx, tempy, p2x, p2y, &p3x, &p3y);
+  add_bezier_arc (s, p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y);
+}
+
+void
+compute_spline (s)
+     spline* s;
+{
+  int i;
+  s->n_points = 0;
+  
+  if (s->n_controls < 3)
+    return;
+
+  calc_section (s, s->control_x [0], s->control_y [0], s->control_x [0],
+               s->control_y [0], s->control_x [0], s->control_y [0],
+               s->control_x [1], s->control_y [1]);
+  calc_section (s, s->control_x [0], s->control_y [0], s->control_x [0],
+               s->control_y [0], s->control_x [1], s->control_y [1],
+               s->control_x [2], s->control_y [2]);
+
+  for (i = 1; i < s->n_controls - 2; i++)
+    calc_section (s, s->control_x [i - 1], s->control_y [i - 1],
+                 s->control_x [i], s->control_y [i],
+                 s->control_x [i + 1], s->control_y [i + 1],
+                 s->control_x [i + 2], s->control_y [i + 2]);
+  
+  calc_section (s, s->control_x [i - 1], s->control_y [i - 1],
+               s->control_x [i], s->control_y [i],
+               s->control_x [i + 1], s->control_y [i + 1],
+               s->control_x [i + 1], s->control_y [i + 1]);
+  calc_section (s, s->control_x [i], s->control_y [i],
+               s->control_x [i + 1], s->control_y [i + 1],
+               s->control_x [i + 1], s->control_y [i + 1],
+               s->control_x [i + 1], s->control_y [i + 1]);
+}
+
+void 
+compute_closed_spline (s)
+     spline *s;
+{
+  int i;
+  s->n_points = 0;
+
+  if (s->n_controls < 3) 
+    return;
+
+  calc_section (s,
+               s->control_x [s->n_controls - 1],
+               s->control_y [s->n_controls - 1],
+               s->control_x [0], s->control_y [0],
+               s->control_x [1], s->control_y [1],
+               s->control_x [2], s->control_y [2]);
+
+  for (i = 1; i < s->n_controls - 2; i++)
+    calc_section (s, s->control_x [i - 1], s->control_y [i - 1],
+                 s->control_x [i], s->control_y [i],
+                 s->control_x [i + 1], s->control_y [i + 1],
+                 s->control_x [i + 2], s->control_y [i + 2]);
+      
+  calc_section (s, s->control_x [i - 1], s->control_y [i - 1],
+               s->control_x [i], s->control_y [i],
+               s->control_x [i + 1], s->control_y [i + 1],
+               s->control_x [0], s->control_y [0]);
+  calc_section (s, s->control_x [i], s->control_y [i],
+               s->control_x [i + 1], s->control_y [i + 1],
+               s->control_x [0], s->control_y [0],
+               s->control_x [1], s->control_y [1]);
+}
+
+void
+just_fill_spline (s)
+     spline *s;
+{
+  int i;
+
+  while (s->allocated_points < s->n_controls + 1)
+    grow_spline_points (s);
+    
+  for (i = 0; i < s->n_controls; i++)
+    {
+      s->points [i].x = s->control_x [i];
+      s->points [i].y = s->control_y [i];
+    }
+  s->points [s->n_controls].x = s->control_x [0];
+  s->points [s->n_controls].y = s->control_y [0];
+  s->n_points = s->n_controls + 1;
+}
+
+void
+append_spline_points (s1, s2)
+     spline *s1, *s2;
+{
+  int i;
+  while (s1->allocated_points < s1->n_points + s2->n_points)
+    grow_spline_points (s1);
+  for (i = s1->n_points; i < s1->n_points + s2->n_points; i++)
+    {
+      s1->points [i].x = s2->points [i - s1->n_points].x;
+      s1->points [i].y = s2->points [i - s1->n_points].y;
+    }
+  s1->n_points = s1->n_points + s2->n_points;
+}
+
+void
+spline_bounding_box (s, rectangle_out)
+     spline* s;
+     XRectangle* rectangle_out;
+{
+  int min_x;
+  int max_x;
+  int min_y;
+  int max_y;
+  int i;
+
+  if (s->n_points == 0)
+    {
+      rectangle_out->x = 0;
+      rectangle_out->y = 0;
+      rectangle_out->width = 0;
+      rectangle_out->height = 0;
+    }
+
+  min_x = s->points [0].x;
+  max_x = min_x;
+  min_y = s->points [0].y;
+  max_y = min_y;
+
+  for (i = 1; i < s->n_points; i++)
+    {
+      if (s->points [i].x < min_x)
+       min_x = s->points [i].x;
+      if (s->points [i].x > max_x)
+       max_x = s->points [i].x;
+      if (s->points [i].y < min_y)
+       min_y = s->points [i].y;
+      if (s->points [i].y > max_y)
+       max_y = s->points [i].y;
+    }
+  rectangle_out->x = min_x;
+  rectangle_out->y = min_y;
+  rectangle_out->width = max_x - min_x;
+  rectangle_out->height = max_y - min_y;
+}
diff --git a/utils/spline.h b/utils/spline.h
new file mode 100644 (file)
index 0000000..c0c4d7f
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef _SPLINE_H_
+#define _SPLINE_H_
+
+#include <X11/Xlib.h>
+
+#if __STDC__
+# define P(x)x
+#else
+# define P(x)()
+#endif
+
+typedef struct _spline
+{
+  /* input */
+  u_int                n_controls;
+  double*      control_x;
+  double*      control_y;
+
+  /* output */
+  u_int                n_points;
+  XPoint*      points;
+  u_int                allocated_points;
+} spline;
+
+spline* make_spline P((u_int size));
+void compute_spline P((spline* s));
+void compute_closed_spline P((spline* s));
+void just_fill_spline P((spline* s));
+void append_spline_points P((spline* s1, spline* s2));
+void spline_bounding_box P((spline* s, XRectangle* rectangle_out));
+
+#undef P
+#endif /* _SPLINE_H_ */
diff --git a/utils/usleep.c b/utils/usleep.c
new file mode 100644 (file)
index 0000000..2529d57
--- /dev/null
@@ -0,0 +1,97 @@
+/* xscreensaver, Copyright (c) 1992 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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.
+ */
+
+#if __STDC__
+#include <stdlib.h>
+#endif
+
+#include <X11/Xlib.h>
+#include <X11/Xos.h>   /* lazy way out */
+
+/* usleep() doesn't exist everywhere, and select() is faster anyway.
+ */
+
+#ifndef VMS
+
+#ifdef NO_SELECT
+  /* If you don't have select() or usleep(), I guess you lose...
+     Maybe you have napms() instead?  Let me know.
+   */
+void
+screenhack_usleep (usecs)
+     unsigned long usecs;
+{
+  usleep (usecs);
+}
+
+#else /* ! NO_SELECT */
+
+void
+screenhack_usleep (usecs)
+     unsigned long usecs;
+{
+  struct timeval tv;
+  tv.tv_sec  = usecs / 1000000L;
+  tv.tv_usec = usecs % 1000000L;
+  (void) select (0, 0, 0, 0, &tv);
+}
+
+#endif /* ! NO_SELECT */
+
+#else /* VMS */
+
+#define SEC_DELTA  "0000 00:00:01.00"
+#define TICK_DELTA "0000 00:00:00.08"
+static int bin_sec_delta[2], bin_tick_delta[2], deltas_set = 0;
+
+static void
+set_deltas ()
+{
+  int status;
+  extern int SYS$BINTIM ();
+  $DESCRIPTOR (str_sec_delta,  SEC_DELTA);
+  $DESCRIPTOR (str_tick_delta, TICK_DELTA);
+  if (!deltas_set)
+    {
+      status = SYS$BINTIM (&str_sec_delta, &bin_sec_delta);
+      if (!(status & 1))
+       {
+         fprintf (stderr, "%s: cannot convert delta time ", progname);
+         fprintf (stderr, SEC_DELTA);
+         fprintf (stderr, "; status code = %d\n", status);
+         exit (status);
+       }
+      status = SYS$BINTIM (&str_tick_delta, &bin_tick_delta);
+      if (!(status & 1))
+       {
+         fprintf (stderr, "%s: cannot convert delta time ", progname);
+         fprintf (stderr, TICK_DELTA);
+         fprintf (stderr, "; status code = %d\n", status);
+         exit (status);
+       }
+      deltas_set = 1;
+    }
+}
+
+void
+screenhack_usleep (usecs)
+     unsigned long usecs;
+{
+  int status, *bin_delta;
+  extern int SYS$SCHWDK (), SYS$HIBER (); 
+  
+  if (!deltas_set) set_deltas ();
+  bin_delta = (usecs == TICK_INTERVAL) ? &bin_tick_delta : &bin_sec_delta;
+  status = SYS$SCHDWK (0, 0, bin_delta, 0);
+  if ((status & 1)) (void) SYS$HIBER ();
+}
+
+#endif /*VMS */
diff --git a/utils/version.h b/utils/version.h
new file mode 100644 (file)
index 0000000..867367a
--- /dev/null
@@ -0,0 +1,2 @@
+static char *screensaver_id =
+       "@(#)xscreensaver 1.17, by Jamie Zawinski (jwz@lucid.com)";
diff --git a/utils/xroger.c b/utils/xroger.c
new file mode 100644 (file)
index 0000000..31b6cbf
--- /dev/null
@@ -0,0 +1,102 @@
+/* xscreensaver, Copyright (c) 1991-1993 Jamie Zawinski <jwz@lucid.com>
+ *
+ * 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 <X11/Xlib.h>
+
+static void
+crossbones (dpy, window, draw_gc, x, y, w, h)
+     Display *dpy;
+     Window window;
+     GC draw_gc;
+     int x, y, w, h;
+{
+  double xscale = w / 440.0;
+  double yscale = h / 216.0;
+  XPoint points [6];
+  points [0].x = x + xscale * 20;
+  points [0].y = y + yscale * 10;
+  points [1].x = x + xscale * 120;
+  points [1].y = y + yscale * 10;
+  points [2].x = x + xscale * 243;
+  points [2].y = y + yscale * 93;
+  points [3].x = x + xscale * 57;
+  points [3].y = y + yscale * 210;
+  points [4].x = x + xscale * 20;
+  points [4].y = y + yscale * 210;
+  points [5].x = x + xscale * 175;
+  points [5].y = y + yscale * 113;
+  XFillPolygon (dpy, window, draw_gc, points, 6, Complex, CoordModeOrigin);
+  points [0].x = x + xscale * 197;
+  points [0].y = y + yscale * 127;
+  points [1].x = x + xscale * 384;
+  points [1].y = y + yscale * 10;
+  points [2].x = x + xscale * 420;
+  points [2].y = y + yscale * 10;
+  points [3].x = x + xscale * 265;
+  points [3].y = y + yscale * 108;
+  points [4].x = x + xscale * 420;
+  points [4].y = y + yscale * 210;
+  points [5].x = x + xscale * 320;
+  points [5].y = y + yscale * 210;
+  XFillPolygon (dpy, window, draw_gc, points, 6, Complex, CoordModeOrigin);
+}
+
+
+void
+skull (dpy, window, draw_gc, erase_gc, x, y, w, h)
+     Display *dpy;
+     Window window;
+     GC draw_gc, erase_gc;
+     int x, y, w, h;
+{
+  XPoint points [3];
+  crossbones (dpy, window, draw_gc, x, y+h/2, w, h/2);
+  x += w/100;
+  y += h/15;
+  XFillArc (dpy, window, draw_gc, (int) (x + (w * 0.3)), y, w/2, h/2,
+           -40*64, 260*64);
+  XFillRectangle (dpy, window, draw_gc, (int) (x + (w * 0.35)), y + h/5,
+                 (int) (w * 0.4), h/5);
+  XFillRectangle (dpy, window, draw_gc, (int) (x + (w * 0.375)),
+                 (int) (y + (h * 0.425)), w / 20, h / 20);
+  XFillRectangle (dpy, window, draw_gc, (int) (x + (w * 0.495)),
+                 (int) (y + (h * 0.425)), w / 20, h / 20);
+  XFillRectangle (dpy, window, draw_gc, (int) (x + (w * 0.555)),
+                 (int) (y + (h * 0.425)), w / 20, h / 20);
+  XFillRectangle (dpy, window, draw_gc, (int) (x + (w * 0.675)),
+                 (int) (y + (h * 0.425)), w / 20, h / 20);
+  points [0].x = x + (w * 0.435);
+  points [0].y = y + (h * 0.425);
+  points [1].x = x + (w * 0.485);
+  points [1].y = points [0].y;
+  points [2].x = (points [0].x + points [1].x) / 2;
+  points [2].y = points [0].y + h/10;
+  XFillPolygon (dpy, window, draw_gc, points, 3, Complex, CoordModeOrigin);
+  points [0].x = x + (w * 0.615);
+  points [1].x = x + (w * 0.665);
+  points [2].x = (points [0].x + points [1].x) / 2;
+  XFillPolygon (dpy, window, draw_gc, points, 3, Complex, CoordModeOrigin);
+  points [0].x = x + (w * 0.52);
+  points [0].y = y + (h * 0.35);
+  points [1].x = points [0].x - (w * 0.05);
+  points [1].y = points [0].y;
+  points [2].x = points [0].x;
+  points [2].y = points [0].y - (w * 0.10);
+  XFillPolygon (dpy, window, erase_gc, points, 3, Complex, CoordModeOrigin);
+  points [0].x = x + (w * 0.57);
+  points [1].x = x + (w * 0.62);
+  points [2].x = points [0].x;
+  XFillPolygon (dpy, window, erase_gc, points, 3, Complex, CoordModeOrigin);
+  XFillArc (dpy, window, erase_gc, x + ((int) (w * 0.375)), y + h/7,
+           w/10, h/10, 0, 360*64);
+  XFillArc (dpy, window, erase_gc, x + ((int) (w * 0.615)), y + h/7,
+           w/10, h/10, 0, 360*64);
+}