http://www.tienza.es/crux/src/www.jwz.org/xscreensaver/xscreensaver-5.06.tar.gz
authorZygo Blaxell <zblaxell@hungrycats.org>
Mon, 2 Mar 2009 05:43:52 +0000 (00:43 -0500)
committerZygo Blaxell <zblaxell@faye.furryterror.org>
Fri, 8 Feb 2013 17:54:48 +0000 (12:54 -0500)
-rw-r--r-- 1 zblaxell zblaxell 5486779 Jul 16  2008 xscreensaver-5.06.tar.gz
3310789ecf1ed8ff790d94512fe536857e793e4c  xscreensaver-5.06.tar.gz

111 files changed:
Makefile.in
OSX/._XScreenSaver.icns [new file with mode: 0644]
OSX/Makefile
OSX/SaverTester.plist
OSX/XScreenSaver.plist
OSX/XScreenSaverView.m
OSX/bindist.rtf
README
README.hacking
config.h.in
configure
configure.in
driver/.gdbinit
driver/Makefile.in
driver/XScreenSaver.ad.in
driver/XScreenSaver_ad.h
driver/demo-Gtk.c
driver/exec.c
driver/lock.c
driver/passwd-kerberos.c
driver/passwd-pam.c
driver/pdf2jpeg.m
driver/prefs.c
driver/screens.c [new file with mode: 0644]
driver/splash.c
driver/stderr.c
driver/subprocs.c
driver/test-passwd.c
driver/test-randr.c
driver/test-screens.c [new file with mode: 0644]
driver/timers.c
driver/types.h
driver/windows.c
driver/xscreensaver-command.c
driver/xscreensaver-command.man
driver/xscreensaver.c
driver/xscreensaver.h
driver/xscreensaver.man
hacks/Makefile.in
hacks/blitspin.c
hacks/blitspin.man
hacks/bsod.c
hacks/bsod.man
hacks/bumps.c
hacks/bumps.h
hacks/bumps.man
hacks/config/README
hacks/config/attraction.xml
hacks/config/blitspin.xml
hacks/config/bsod.xml
hacks/config/bumps.xml
hacks/config/carousel.xml
hacks/config/decayscreen.xml
hacks/config/distort.xml
hacks/config/glschool.xml
hacks/config/jigglypuff.xml
hacks/config/juggle.xml
hacks/config/lament.xml
hacks/config/mirrorblob.xml
hacks/config/popsquares.xml
hacks/config/ripples.xml
hacks/config/rotzoomer.xml
hacks/config/skytentacles.xml [new file with mode: 0644]
hacks/config/slidescreen.xml
hacks/config/spheremonics.xml
hacks/config/spotlight.xml
hacks/config/starwars.xml
hacks/config/substrate.xml
hacks/config/topblock.xml
hacks/config/twang.xml
hacks/config/voronoi.xml
hacks/config/xmatrix.xml
hacks/config/zoom.xml
hacks/decayscreen.c
hacks/decayscreen.man
hacks/distort.c
hacks/distort.man
hacks/galaxy.c
hacks/glx/Makefile.in
hacks/glx/circuit.c
hacks/glx/dnalogo.c
hacks/glx/gleidescope.c
hacks/glx/skytentacles.c [new file with mode: 0644]
hacks/glx/skytentacles.man [new file with mode: 0644]
hacks/glx/sphere.c
hacks/glx/sphere.h
hacks/images/atm.xbm [new file with mode: 0644]
hacks/lcdscrub [deleted file]
hacks/lcdscrub.man [new file with mode: 0644]
hacks/memscroller.man
hacks/penetrate.c
hacks/ripples.c
hacks/ripples.man
hacks/rotzoomer.c
hacks/rotzoomer.man
hacks/screenhack.c
hacks/slidescreen.c
hacks/slidescreen.man
hacks/spotlight.c
hacks/spotlight.man
hacks/twang.c
hacks/twang.man
hacks/webcollage
hacks/xlockmore.c
hacks/zoom.c
hacks/zoom.man
po/POTFILES.in
utils/version.h
utils/yarandom.c
xscreensaver.spec
xscreensaver.xcodeproj/project.pbxproj

index 99b6f4a257bb5abef0f2deb39794dd6ab717bc7c..c8e034f336457fe6f1dfa76a0aa278f995d63c24 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in --- xscreensaver, Copyright (c) 1999-2005 Jamie Zawinski.
+# Makefile.in --- xscreensaver, Copyright (c) 1999-2008 Jamie Zawinski.
 # the `../configure' script generates `Makefile' from this file.
 
 @SET_MAKE@
@@ -44,7 +44,7 @@ depend::
 distdepend::
        @$(MAKE) update_spec_version
        @$(MAKE_SUBDIR2)
-       @cd po ; $(MAKE) generate_potfiles_in
+       @cd po ; $(MAKE) update-po
 
 TAGS:: tags
 tags::
@@ -326,16 +326,18 @@ www::
   diff -U0 download.html $$TMP ;                                           \
   echo '' ;                                                                \
                                                                            \
-  OLDEST=`ls xscreensaver*.tar.gz | head -1` ;                             \
-  /bin/echo -n "Delete $$DEST/$$OLDEST? ";                                 \
-  read line;                                                               \
-  if [ "x$$line" = "xyes" -o "x$$line" = "xy" ]; then                      \
-    set -x ;                                                               \
-    rm $$OLDEST ;                                                          \
-    cvs remove $$OLDEST ;                                                  \
-  else                                                                     \
-    set -x ;                                                               \
-  fi ;                                                                     \
+  for EXT in tar.gz dmg ; do                                               \
+    OLDEST=`ls xscreensaver*.$$EXT | head -n 1` ;                          \
+    /bin/echo -n "Delete $$DEST/$$OLDEST? ";                               \
+    read line;                                                             \
+    if [ "x$$line" = "xyes" -o "x$$line" = "xy" ]; then                            \
+      set -x ;                                                             \
+      rm $$OLDEST ;                                                        \
+      cvs remove $$OLDEST ;                                                \
+    else                                                                   \
+      set -x ;                                                             \
+    fi ;                                                                   \
+  done ;                                                                   \
   cvs add -kb $$BNAME $$BNAME2 ;                                           \
   cat $$TMP > download.html ;                                              \
   rm -f $$TMP ;                                                                    \
@@ -353,22 +355,6 @@ www::
                                                                            \
   cvs commit -m "$$VERS"
 
-check_years::
-       @for file in `find . -name '*.*' \
-               \! -name '*~' \! -name '*.o' \! -name '*.gz' \! -name '*.Z' \
-               \! -name '*.po' \! -name 'config.*'  \! -name '*.glade*' \
-               \! -name '*.m4' \! -name '*.pdb' \! -name '*.xpm' \
-               \! -name '*.jpg' \! -name '*.gif' \! -name '*.eps' \
-               \! -name '*.png' \! -name '*.tif' \! -name '*.bak' \
-               | sort` \
-       ; do \
-         y=`date -r "$$file" '+%Y'` ; \
-         if ! ( grep "\b$$y\b" $$file >/dev/null ); then \
-           if ( grep "opyright\|(c)\|\.BR" $$file >/dev/null ); then \
-             echo "$$file              does not mention $$y" ; \
-           fi ; \
-         fi ; \
-       done
 
 count::
        @ \
diff --git a/OSX/._XScreenSaver.icns b/OSX/._XScreenSaver.icns
new file mode 100644 (file)
index 0000000..4ec02b2
Binary files /dev/null and b/OSX/._XScreenSaver.icns differ
index 1a222c711ecfa58772a7a91c055b51fe040aa1a8..2ff5fe1bcbac8538301ff029a0bd9a5bd39e6ebc 100644 (file)
@@ -28,7 +28,9 @@ release:: check_versions
 release:: sign
 
 sign:
-       codesign -vfs 'Jamie Zawinski' build/Release/*.saver
+       @for f in build/Release/*.saver ; do \
+         codesign -vfs 'Jamie Zawinski' $$f ; \
+        done
 
 check_versions:
        @\
index e5d26f4923b4f653d8e2736b803eff41e88876ab..3a29f28bc40673a6f6f924c8561557bf32b60102 100644 (file)
        <key>CFBundlePackageType</key>
        <string>APPL</string>
        <key>CFBundleShortVersionString</key>
-       <string>5.05</string>
+       <string>5.06</string>
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
-       <string>5.05</string>
+       <string>5.06</string>
        <key>LSMinimumSystemVersion</key>
        <string>10.4.0</string>
        <key>NSMainNibFile</key>
index 7e319f208f8361cea8460feb12cd1274c37ff2d7..cf398f13b17c0bb943c826c57ce3a5887a02da46 100644 (file)
        <key>CFBundlePackageType</key>
        <string>BNDL</string>
        <key>CFBundleShortVersionString</key>
-       <string>5.05</string>
+       <string>5.06</string>
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
-       <string>5.05</string>
+       <string>5.06</string>
        <key>LSMinimumSystemVersion</key>
        <string>10.4.0</string>
        <key>NSMainNibFile</key>
index a122f7f2b50466695cc2053b005bea0ba9141419..2baf2c69f9e3575cc026671e2d44f2b5e8e5147d 100644 (file)
@@ -384,10 +384,11 @@ add_default_options (const XrmOptionDescRec *opts,
 
   // And finally:
   //
+  NSDisableScreenUpdates();
   unsigned long delay = xsft->draw_cb (xdpy, xwindow, xdata);
-  
   XSync (xdpy, 0);
-  
+  NSEnableScreenUpdates();
+
   gettimeofday (&tv, 0);
   now = tv.tv_sec + (tv.tv_usec / 1000000.0);
   next_frame_time = now + (delay / 1000000.0);
index d6e13459c426f47014acc6a628a3f5477ed9e71a..dc18b3eab02b44062e6a979ba915a283d5d4de08 100644 (file)
@@ -15,7 +15,7 @@ XScreenSaver
 \f1\b0 \
 by Jamie Zawinski \uc0\u8232 and many others\
 \
-version 5.05 \uc0\u8232 01-Mar-2008\
+version 5.06 \uc0\u8232 16-Jul-2008\
 \
 {\field{\*\fldinst{HYPERLINK "http://www.jwz.org/xscreensaver/"}}{\fldrslt \cf2 \ul \ulc2 http://www.jwz.org/xscreensaver/}}\
 \pard\pardeftab720\li720
diff --git a/README b/README
index fe349aa757f71b8ab1d61c5fa2b16d2aca77ab85..5a0169241c96b7606315e65eff3b008ba4684ef5 100644 (file)
--- a/README
+++ b/README
@@ -38,6 +38,17 @@ XScreenSaver has an extensive manual -- please read it!
 
 ===============================================================================
 
+Changes since 5.05:   * Xinerama/RANDR fixes: this time for sure.  It should
+                        now work to add/remove monitors or resize screens at
+                        any time.
+                      * New hack, `skytentacles'.
+                      * New version of `gleidescope'.
+                      * Added the `-log' option to the xscreensaver daemon,
+                        since a truly shocking number of Linux users seem to
+                        have no idea how to redirect output to a file.
+                      * Added `-duration' arg to most image-loading hacks,
+                        so that they pick a new image every few minutes.
+                      * Added an ATM crash to BSOD.
 Changes since 5.04:   * New hacks, `cubicgrid', `hypnowheel', and
                         `lcdscrub' (which isn't really a screen saver).
                       * Updates to `m6502' and `gears'.
index 28767a5fb7ebe30936a756769f168c73484c01bd..4e5170e450dc45a3552dd41d3bdbc6b81bfbb4c6 100644 (file)
@@ -56,9 +56,13 @@ The XScreenSaver API
       yoursavername_free     -- Free everything you've allocated.
       yoursavername_reshape  -- Called when the window is resized.
       yoursavername_event    -- Called when a keyboard or mouse event happens.
-                                The "reshape" and "event" functions are only
-                                called when running in a window (not as a
-                                screen saver). It's ok for them to do nothing.
+
+      The "event" function will only be called when running in a window
+      (not as a screen saver).  The "reshape" event will be called when the
+      window size changes, or (as a screen saver) when the display size
+      changes as a result of a RANDR event (e.g., plugging in a new monitor).
+
+      It's ok for both the "event" and "resize" functions to do nothing.
 
   - All other functions should be static.
 
index c56839125f33374b19fe7188aa9afa0bf14b2e54..21b68cd4af79d65f263b18adb2daa8ff66f89bf5 100644 (file)
    available if the file /usr/include/X11/extensions/Xrandr.h exists.) */
 #undef HAVE_RANDR
 
+/* Define this if the RANDR library is version 1.2 or newer. */
+#undef HAVE_RANDR_12
+
 /* Define this if you have the XReadDisplay extension (I think this is an
    SGI-only thing; it's in <X11/extensions/readdisplay.h>.) A few of the
    screenhacks will take advantage of this if it's available. */
index 9af03d484dffff05a24c26917ce3b00fcd44551a..a6e9a4c3a9bf06a2561c4b59d15b0f7cb3b5816c 100755 (executable)
--- a/configure
+++ b/configure
@@ -2056,6 +2056,9 @@ echo "command line was: $0 $@"
 
 
 
+
+
+
 
 
 
@@ -2096,6 +2099,10 @@ done
 
 
 
+# Need to disable Objective C extensions in ANSI C on MacOS X to work
+# around an Apple-specific gcc bug.
+#
+
 
 ###############################################################################
 #
@@ -2122,18 +2129,6 @@ done
 
 
 
-###############################################################################
-#
-#       Function to figure out how to turn off Objective C on MacOS X.
-#       (We have to do this to work around an Apple-specific gcc bug.)
-#
-###############################################################################
-
-
-
-
-
-
 ###############################################################################
 #
 #       Function to figure out how to create directory trees.
@@ -3455,6 +3450,7 @@ else
        ac_cv_gcc_accepts_no_overlength=no
      else
        ac_cv_gcc_accepts_no_overlength=yes
+       CC="$CC -Wno-overlength-strings"
      fi
 fi
 { echo "$as_me:$LINENO: result: $ac_cv_gcc_accepts_no_overlength" >&5
@@ -3475,6 +3471,7 @@ else
        ac_cv_gcc_accepts_no_decl_after=no
      else
        ac_cv_gcc_accepts_no_decl_after=yes
+       CC="$CC -Wdeclaration-after-statement"
      fi
 fi
 { echo "$as_me:$LINENO: result: $ac_cv_gcc_accepts_no_decl_after" >&5
@@ -3483,7 +3480,6 @@ echo "${ECHO_T}$ac_cv_gcc_accepts_no_decl_after" >&6; }
   fi
 
 if test -n "$GCC"; then
-   if test -n "$GCC"; then
    { echo "$as_me:$LINENO: checking whether gcc accepts -no-cpp-precomp" >&5
 echo $ECHO_N "checking whether gcc accepts -no-cpp-precomp... $ECHO_C" >&6; }
 if test "${ac_cv_gcc_accepts_no_cpp_precomp+set}" = set; then
@@ -3496,6 +3492,7 @@ else
        ac_cv_gcc_accepts_no_cpp_precomp=no
      else
        ac_cv_gcc_accepts_no_cpp_precomp=yes
+       CC="$CC -no-cpp-precomp"
      fi
 fi
 { echo "$as_me:$LINENO: result: $ac_cv_gcc_accepts_no_cpp_precomp" >&5
@@ -3503,13 +3500,6 @@ echo "${ECHO_T}$ac_cv_gcc_accepts_no_cpp_precomp" >&6; }
    ac_gcc_accepts_no_cpp_precomp="$ac_cv_gcc_accepts_no_cpp_precomp"
   fi
 
-   if test "$ac_gcc_accepts_no_cpp_precomp" = yes ; then
-     { echo "$as_me:$LINENO: result: Disabling Objective C extensions in ANSI C code." >&5
-echo "${ECHO_T}Disabling Objective C extensions in ANSI C code." >&6; }
-     CC="$CC -no-cpp-precomp"
-   fi
-  fi
-
 if test -n "$GCC"; then
    if test -n "$GCC"; then
    { echo "$as_me:$LINENO: checking whether gcc accepts -std=c89" >&5
@@ -3524,6 +3514,7 @@ else
        ac_cv_gcc_accepts_std=no
      else
        ac_cv_gcc_accepts_std=yes
+       CC="$CC -std=c89"
      fi
 fi
 { echo "$as_me:$LINENO: result: $ac_cv_gcc_accepts_std" >&5
@@ -3552,7 +3543,8 @@ echo "${ECHO_T}Disabling C++ comments in ANSI C code." >&6; }
      # before they were in the ANSI C 99 spec...  (gcc 2.96 permits //
      # with -std=gnu89 but not with -std=c89.)
      #
-     CC="$CC -std=c89 -U__STRICT_ANSI__"
+     # $CC already contains "-std=c89" via AC_GCC_ACCEPTS_STD
+     CC="$CC -U__STRICT_ANSI__"
    else
      # The old way:
      CC="$CC -Wp,-lang-c89"
@@ -12140,7 +12132,7 @@ echo "${ECHO_T}not found ($d: no such directory)" >&6; }
 
 if test "$with_randr" = yes; then
 
-  # first check for Randr.h
+  # first check for Xrandr.h
 
   ac_save_CPPFLAGS="$CPPFLAGS"
   if test \! -z "$includedir" ; then
 #define HAVE_RANDR 1
 _ACEOF
 
+
+    # Now check for version 1.2 in the same libs.
+
+  ac_save_CPPFLAGS="$CPPFLAGS"
+  ac_save_LDFLAGS="$LDFLAGS"
+#  ac_save_LIBS="$LIBS"
+
+  if test \! -z "$includedir" ; then
+    CPPFLAGS="$CPPFLAGS -I$includedir"
+  fi
+  # note: $X_CFLAGS includes $x_includes
+  CPPFLAGS="$CPPFLAGS $X_CFLAGS"
+
+  if test \! -z "$libdir" ; then
+    LDFLAGS="$LDFLAGS -L$libdir"
   fi
+  # note: $X_LIBS includes $x_libraries
+  LDFLAGS="$LDFLAGS $X_LIBS $X_EXTRA_LIBS"
+
+  CPPFLAGS=`eval eval eval eval eval eval eval eval eval echo $CPPFLAGS`
+  LDFLAGS=`eval eval eval eval eval eval eval eval eval echo $LDFLAGS`
+  { echo "$as_me:$LINENO: checking for XRRGetOutputInfo in -lc" >&5
+echo $ECHO_N "checking for XRRGetOutputInfo in -lc... $ECHO_C" >&6; }
+if test "${ac_cv_lib_c_XRRGetOutputInfo+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lc $SAVER_LIBS $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char XRRGetOutputInfo ();
+int
+main ()
+{
+return XRRGetOutputInfo ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -rf conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -rf conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_c_XRRGetOutputInfo=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_c_XRRGetOutputInfo=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_c_XRRGetOutputInfo" >&5
+echo "${ECHO_T}$ac_cv_lib_c_XRRGetOutputInfo" >&6; }
+if test $ac_cv_lib_c_XRRGetOutputInfo = yes; then
+  cat >>confdefs.h <<\_ACEOF
+#define HAVE_RANDR_12 1
+_ACEOF
+
+else
+  true
+fi
+
+  CPPFLAGS="$ac_save_CPPFLAGS"
+  LDFLAGS="$ac_save_LDFLAGS"
+#  LIBS="$ac_save_LIBS"
+
+  fi
+
 
 elif test "$with_randr" != no; then
   echo "error: must be yes or no: --with-randr-ext=$with_randr"
@@ -16673,7 +16761,7 @@ if test "${ac_cv_mesagl_version_string+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 16680 "configure"
+#line 16768 "configure"
 #include "confdefs.h"
 #include <GL/gl.h>
 #ifndef MESA_MAJOR_VERSION
@@ -19890,9 +19978,11 @@ echo "${ECHO_T}no" >&6; }
 
     #### Could use some more defaults here...
     for f in \
-      "/usr/X11R6/lib/X11/doc/README"          \
-      "/usr/share/doc/xserver-common/copyright"        \
-      "/usr/X11R6/README"                      \
+      "/usr/X11R6/lib/X11/doc/README"             \
+      "/usr/share/doc/xserver-common/copyright"           \
+      "/usr/share/doc/xserver-xorg-core/copyright" \
+      "/usr/X11R6/README"                         \
+      "/usr/share/doc/debian/debian-manifesto"     \
     ; do
       if test -z "$with_textfile"; then
         { echo "$as_me:$LINENO: checking for text file $f" >&5
@@ -21883,8 +21973,9 @@ if test "$have_gl" = yes -a "$ac_have_mesa_gl" = yes ; then
   pgl="$preferred_mesagl"
 
   if test "$ac_mesagl_version" = unknown; then
-    warnL "Unable to determine the MesaGL version number!"
-    warn2 "Make sure you are using version $preferred_mesagl or newer."
+    true
+    # warnL "Unable to determine the MesaGL version number!"
+    # warn2 "Make sure you are using version $preferred_mesagl or newer."
 
   elif test \! "$ac_mesagl_version" -gt 2006; then
     warnL "MesaGL version number is $mgv --"
@@ -22035,7 +22126,7 @@ if test -z "$RPM_PACKAGE_VERSION" ; then
 
   if test \! -z "$rpmv" ; then
     rpmbdir=`rpm -ql $rpmnames | sed -n 's@^\(.*\)/xscreensaver-demo$@\1@p'`
-    rpmhdir=`rpm -ql $rpmnames | sed -n 's@^\(.*\)/attraction$@\1@p'`
+    rpmhdir=`rpm -ql $rpmnames | sed -n 's@^\(.*\)/popsquares$@\1@p'`
 
     warning=no
     warnL "There is already an installed RPM of xscreensaver $rpmv"
@@ -22058,6 +22149,33 @@ if test -z "$RPM_PACKAGE_VERSION" ; then
   fi
 fi
 
+# Also warn if there's a Debian package installed.
+#
+debnames="xscreensaver xscreensaver-data xscreensaver-data-extra"
+debv=''
+for dpkg in $debnames ; do
+  if test -z "$debv"; then
+    debv=`dpkg -s $dpkg 2>/dev/null | sed -n 's/^Version: \(.*\)$/\1/p'`
+  fi
+done
+
+if test \! -z "$debv" ; then
+  debbdir=`dpkg -L $debnames 2>/dev/null | \
+            sed -n 's@^\(.*/bin/\)xscreensaver$@\1@p'`
+  debhdir=`dpkg -L $debnames 2>/dev/null | \
+            sed -n 's@^\(.*/\)popsquares$@\1@p'`
+  if test -z "$debbdir" ; then debbdir='???'; fi
+  if test -z "$debhdir" ; then debhdir='???'; fi
+
+  warning=no
+  warnL "There is already an installed dpkg of xscreensaver"
+  warn2 "version \"$debv\" on this system."
+  echo ""
+  warn2 "The dpkg was installed in $debbdir,"
+  warn2 "with demos in $debhdir."
+fi
+
+
 if test "${bindir}" = "${HACKDIR}" ; then
   do_dir_warning=yes
 fi
index 9a049b55a7c474936da4ddd23428cce04fa3a616..ee131debdd500d1b85a4ba310424e984657139e5 100644 (file)
@@ -106,6 +106,9 @@ AH_TEMPLATE([HAVE_RANDR],
            possibly elsewhere.  (It's available if the file
            /usr/include/X11/extensions/Xrandr.h exists.)])
 
+AH_TEMPLATE([HAVE_RANDR_12],
+           [Define this if the RANDR library is version 1.2 or newer.])
+
 AH_TEMPLATE([HAVE_PROC_INTERRUPTS],
            [Define this if you have a Linux-like /proc/interrupts file which
            can be examined to determine when keyboard activity has
@@ -389,6 +392,7 @@ AC_DEFUN(AC_CHECK_GCC_ARG,
        ac_cv_gcc_accepts_[$1]=no
      else
        ac_cv_gcc_accepts_[$1]=yes
+       CC="$CC [$2]"
      fi])
    ac_gcc_accepts_[$1]="$ac_cv_gcc_accepts_[$1]"
   fi
@@ -400,6 +404,11 @@ AC_DEFUN(AC_NO_LONG_STRING_WARNINGS,
 AC_DEFUN(AC_NO_MISPLACED_DECLARATIONS,
          [AC_CHECK_GCC_ARG(no_decl_after, -Wdeclaration-after-statement)])
 
+# Need to disable Objective C extensions in ANSI C on MacOS X to work
+# around an Apple-specific gcc bug.
+#
+AC_DEFUN(AC_NO_OBJECTIVE_C,
+         [AC_CHECK_GCC_ARG(no_cpp_precomp, -no-cpp-precomp)])
 
 ###############################################################################
 #
@@ -447,7 +456,8 @@ AC_DEFUN(AC_NO_CPLUSPLUS_COMMENTS_IN_C_CODE,
      # before they were in the ANSI C 99 spec...  (gcc 2.96 permits //
      # with -std=gnu89 but not with -std=c89.)
      #
-     CC="$CC -std=c89 -U__STRICT_ANSI__"
+     # $CC already contains "-std=c89" via AC_GCC_ACCEPTS_STD
+     CC="$CC -U__STRICT_ANSI__"
    else
      # The old way:
      CC="$CC -Wp,-lang-c89"
@@ -456,27 +466,6 @@ AC_DEFUN(AC_NO_CPLUSPLUS_COMMENTS_IN_C_CODE,
 ])
 
 
-###############################################################################
-#
-#       Function to figure out how to turn off Objective C on MacOS X.
-#       (We have to do this to work around an Apple-specific gcc bug.)
-#
-###############################################################################
-
-AC_DEFUN(AC_GCC_ACCEPTS_NO_CPP_PRECOMP,
-         [AC_CHECK_GCC_ARG(no_cpp_precomp, -no-cpp-precomp)])
-
-AC_DEFUN(AC_NO_OBJECTIVE_C,
- [if test -n "$GCC"; then
-   AC_GCC_ACCEPTS_NO_CPP_PRECOMP
-   if test "$ac_gcc_accepts_no_cpp_precomp" = yes ; then
-     AC_MSG_RESULT(Disabling Objective C extensions in ANSI C code.)
-     CC="$CC -no-cpp-precomp"
-   fi
-  fi
-])
-
-
 ###############################################################################
 #
 #       Function to figure out how to create directory trees.
@@ -1667,7 +1656,7 @@ HANDLE_X_PATH_ARG(with_randr, --with-randr-ext, RANDR)
 
 if test "$with_randr" = yes; then
 
-  # first check for Randr.h
+  # first check for Xrandr.h
   AC_CHECK_X_HEADER(X11/extensions/Xrandr.h, [have_randr=yes],,
                     [#include <X11/Xlib.h>])
 
@@ -1696,8 +1685,13 @@ if test "$with_randr" = yes; then
   # if that succeeded, then we've really got it.
   if test "$have_randr" = yes; then
     AC_DEFINE(HAVE_RANDR)
+
+    # Now check for version 1.2 in the same libs.
+    AC_CHECK_X_LIB(c, XRRGetOutputInfo, [AC_DEFINE(HAVE_RANDR_12)],
+                   [true], $SAVER_LIBS)
   fi
 
+
 elif test "$with_randr" != no; then
   echo "error: must be yes or no: --with-randr-ext=$with_randr"
   exit 1
@@ -3414,9 +3408,11 @@ case "$with_textfile" in
 
     #### Could use some more defaults here...
     for f in \
-      "/usr/X11R6/lib/X11/doc/README"          \
-      "/usr/share/doc/xserver-common/copyright"        \
-      "/usr/X11R6/README"                      \
+      "/usr/X11R6/lib/X11/doc/README"             \
+      "/usr/share/doc/xserver-common/copyright"           \
+      "/usr/share/doc/xserver-xorg-core/copyright" \
+      "/usr/X11R6/README"                         \
+      "/usr/share/doc/debian/debian-manifesto"     \
     ; do
       if test -z "$with_textfile"; then
         AC_MSG_CHECKING([for text file $f])
@@ -4035,8 +4031,9 @@ if test "$have_gl" = yes -a "$ac_have_mesa_gl" = yes ; then
   pgl="$preferred_mesagl"
 
   if test "$ac_mesagl_version" = unknown; then
-    warnL "Unable to determine the MesaGL version number!"
-    warn2 "Make sure you are using version $preferred_mesagl or newer."
+    true
+    # warnL "Unable to determine the MesaGL version number!"
+    # warn2 "Make sure you are using version $preferred_mesagl or newer."
 
   elif test \! "$ac_mesagl_version" -gt 2006; then
     warnL "MesaGL version number is $mgv --"
@@ -4182,7 +4179,7 @@ if test -z "$RPM_PACKAGE_VERSION" ; then
 
   if test \! -z "$rpmv" ; then
     rpmbdir=`rpm -ql $rpmnames | sed -n 's@^\(.*\)/xscreensaver-demo$@\1@p'`
-    rpmhdir=`rpm -ql $rpmnames | sed -n 's@^\(.*\)/attraction$@\1@p'`
+    rpmhdir=`rpm -ql $rpmnames | sed -n 's@^\(.*\)/popsquares$@\1@p'`
 
     warning=no
     warnL "There is already an installed RPM of xscreensaver $rpmv"
@@ -4205,6 +4202,33 @@ if test -z "$RPM_PACKAGE_VERSION" ; then
   fi
 fi
 
+# Also warn if there's a Debian package installed.
+#
+debnames="xscreensaver xscreensaver-data xscreensaver-data-extra"
+debv=''
+for dpkg in $debnames ; do
+  if test -z "$debv"; then
+    debv=`dpkg -s $dpkg 2>/dev/null | sed -n 's/^Version: \(.*\)$/\1/p'`
+  fi
+done
+
+if test \! -z "$debv" ; then
+  debbdir=`dpkg -L $debnames 2>/dev/null | \
+            sed -n 's@^\(.*/bin/\)xscreensaver$@\1@p'`
+  debhdir=`dpkg -L $debnames 2>/dev/null | \
+            sed -n 's@^\(.*/\)popsquares$@\1@p'`
+  if test -z "$debbdir" ; then debbdir='???'; fi
+  if test -z "$debhdir" ; then debhdir='???'; fi
+
+  warning=no
+  warnL "There is already an installed dpkg of xscreensaver"
+  warn2 "version \"$debv\" on this system."
+  echo ""
+  warn2 "The dpkg was installed in $debbdir,"
+  warn2 "with demos in $debhdir."
+fi
+
+
 if test "${bindir}" = "${HACKDIR}" ; then
   do_dir_warning=yes
 fi
index cb7d98abf3b368c262b0796ca1c87ab81bdfde4e..a585259f29257dbf6295e9233c269229158adeb4 100644 (file)
@@ -20,6 +20,8 @@
 #handle 13 pass nostop
 #handle 15 pass nostop
 #handle 19 pass nostop
+set env MallocGuardEdges 1
+set env MallocPreScribble 1
+set env MallocScribble 1
 b exit
 set args -debug
-#b purify_stop_here
index d9e4d755d1c065abe6f2bc4fb095c73e303a9c18..13504008e72025063df16ba8490c93f028d31ac8 100644 (file)
@@ -116,10 +116,10 @@ NOLOCK_OBJS_1     = lock.o
 
 TEST_SRCS      = test-passwd.c test-uid.c  test-xdpms.c    test-grab.c \
                  test-apm.c    test-fade.c test-xinerama.c test-vp.c   \
-                 test-randr.c  xdpyinfo.c  test-mlstring.c
+                 test-randr.c  xdpyinfo.c  test-mlstring.c test-screens.c
 TEST_EXES      = test-passwd   test-uid    test-xdpms      test-grab   \
                  test-apm      test-fade   test-xinerama   test-vp     \
-                 test-randr    xdpyinfo    test-mlstring
+                 test-randr    xdpyinfo    test-mlstring   test-screens
 
 MOTIF_LIBS     = @MOTIF_LIBS@ @XPM_LIBS@ $(XMU_LIBS)
 GTK_LIBS       = @GTK_LIBS@ $(XMU_LIBS)
@@ -147,9 +147,9 @@ LOGO                = $(ICON_SRC)/logo-50.xpm
 GTK_ICONS      = $(ICON_SRC)/screensaver-*.png
 
 DEMO_UTIL_SRCS = $(UTILS_SRC)/resources.c $(UTILS_SRC)/usleep.c \
-                 $(UTILS_SRC)/visual.c
+                 $(UTILS_SRC)/visual.c $(XMU_SRCS)
 DEMO_UTIL_OBJS = $(UTILS_BIN)/resources.o $(UTILS_BIN)/usleep.o \
-                 $(UTILS_BIN)/visual.o
+                 $(UTILS_BIN)/visual.o $(XMU_OBJS)
 
 SAVER_UTIL_SRCS        = $(UTILS_SRC)/fade.c $(UTILS_SRC)/overlay.c \
                  $(UTILS_SRC)/logo.c $(UTILS_SRC)/yarandom.c \
@@ -179,24 +179,24 @@ GETIMG_OBJS       = $(GETIMG_OBJS_1) \
                  $(UTILS_BIN)/logo.o $(UTILS_BIN)/minixpm.o prefs.o \
                  $(XMU_OBJS)
 
-SAVER_SRCS_1   = xscreensaver.c windows.c timers.c subprocs.c exec.c \
-                 xset.c splash.c setuid.c stderr.c mlstring.c
-SAVER_OBJS_1   = xscreensaver.o windows.o timers.o subprocs.o exec.o \
-                 xset.o splash.o setuid.o stderr.o mlstring.o
+SAVER_SRCS_1   = xscreensaver.c windows.c screens.c timers.c subprocs.c \
+                 exec.c xset.c splash.c setuid.c stderr.c mlstring.c
+SAVER_OBJS_1   = xscreensaver.o windows.o screens.o timers.o subprocs.o \
+                 exec.o xset.o splash.o setuid.o stderr.o mlstring.o
 
 SAVER_SRCS     = $(SAVER_SRCS_1) prefs.c dpms.c $(LOCK_SRCS) \
-                 $(SAVER_UTIL_SRCS) $(GL_SRCS) $(XMU_SRCS)
+                 $(SAVER_UTIL_SRCS) $(GL_SRCS)
 SAVER_OBJS     = $(SAVER_OBJS_1) prefs.o dpms.o $(LOCK_OBJS) \
-                 $(SAVER_UTIL_OBJS) $(GL_OBJS) $(XMU_OBJS)
+                 $(SAVER_UTIL_OBJS) $(GL_OBJS)
 
 CMD_SRCS       = remote.c xscreensaver-command.c
 CMD_OBJS       = remote.o xscreensaver-command.o
 
-DEMO_SRCS_1    = prefs.c dpms.c $(XMU_SRCS)
-DEMO_OBJS_1    = prefs.o dpms.o $(XMU_OBJS)
+DEMO_SRCS_1    = prefs.c dpms.c
+DEMO_OBJS_1    = prefs.o dpms.o
 
-DEMO_SRCS      = prefs.c dpms.c remote.c exec.c $(DEMO_UTIL_SRCS)
-DEMO_OBJS      = prefs.o dpms.o remote.o exec.o $(DEMO_UTIL_OBJS)
+DEMO_SRCS      = $(DEMO_SRCS_1) remote.c exec.c $(DEMO_UTIL_SRCS)
+DEMO_OBJS      = $(DEMO_OBJS_1) remote.o exec.o $(DEMO_UTIL_OBJS)
 
 PDF2JPEG_SRCS  = pdf2jpeg.m
 PDF2JPEG_OBJS  = pdf2jpeg.o
@@ -453,7 +453,7 @@ install-pam:
  $$e "  ####################################################################";\
  $$e ""                                                                             ;\
          fi ;                                                          \
-       elif [ -f $$conf ]; then                                        \
+       elif [ -f $$conf -a "x$$dest" != "x" ]; then                    \
          if ( grep $$dest $$conf >/dev/null ); then                    \
           echo "$$conf unchanged: already has an entry for $$dest" ;   \
          else                                                          \
@@ -498,7 +498,7 @@ install-gnome:: screensaver-properties.desktop
             echo $(INSTALL_DIRS) "$(install_prefix)$(GTK_APPDIR)"           ;\
                  $(INSTALL_DIRS) "$(install_prefix)$(GTK_APPDIR)"           ;\
           fi                                                                ;\
-          name2=gnome-screensaver-properties.desktop                        ;\
+          name2=xscreensaver-properties.desktop                             ;\
           echo $(INSTALL_DATA) screensaver-properties.desktop                \
                  $(install_prefix)$(GTK_APPDIR)/$$name2                     ;\
                $(INSTALL_DATA) screensaver-properties.desktop                \
@@ -571,7 +571,7 @@ install-gnome:: xscreensaver-demo.glade2
 # into /usr/share/applications/
 uninstall-gnome::
        @if [ "$(GTK_DATADIR)" != "" ]; then                                  \
-          f=gnome-screensaver-properties.desktop                             ;\
+          f=xscreensaver-properties.desktop                                  ;\
           echo rm -f $(install_prefix)$(GTK_APPDIR)/$$f                      ;\
                rm -f $(install_prefix)$(GTK_APPDIR)/$$f                      ;\
         fi
@@ -846,6 +846,11 @@ TEST_FADE_OBJS = test-fade.o $(UTILS_SRC)/fade.o $(DEMO_UTIL_OBJS)
 test-fade: test-fade.o $(UTILS_BIN)/fade.o
        $(CC) $(LDFLAGS) -o $@ $(TEST_FADE_OBJS) $(SAVER_LIBS)
 
+TEST_SCREENS_OBJS = test-screens.o $(DEMO_UTIL_OBJS)
+test-screens.o: screens.c
+test-screens: test-screens.o
+       $(CC) $(LDFLAGS) -o $@ $(TEST_SCREENS_OBJS) $(SAVER_LIBS)
+
 
 xdpyinfo.o: xdpyinfo.c
        $(CC) -c $(INCLUDES) -DHAVE_GLX $(CFLAGS) $(X_CFLAGS) \
@@ -913,6 +918,11 @@ prefs.o: $(srcdir)/types.h
 prefs.o: $(UTILS_SRC)/resources.h
 remote.o: ../config.h
 remote.o: $(srcdir)/remote.h
+screens.o: ../config.h
+screens.o: $(srcdir)/prefs.h
+screens.o: $(srcdir)/types.h
+screens.o: $(UTILS_SRC)/visual.h
+screens.o: $(srcdir)/xscreensaver.h
 setuid.o: ../config.h
 setuid.o: $(srcdir)/prefs.h
 setuid.o: $(srcdir)/types.h
@@ -954,6 +964,12 @@ test-passwd.o: $(UTILS_SRC)/version.h
 test-passwd.o: $(UTILS_SRC)/visual.h
 test-passwd.o: $(srcdir)/xscreensaver.h
 test-randr.o: ../config.h
+test-screens.o: ../config.h
+test-screens.o: $(srcdir)/prefs.h
+test-screens.o: $(srcdir)/screens.c
+test-screens.o: $(srcdir)/types.h
+test-screens.o: $(UTILS_SRC)/visual.h
+test-screens.o: $(srcdir)/xscreensaver.h
 test-uid.o: ../config.h
 test-vp.o: ../config.h
 test-xdpms.o: ../config.h
index 3798dbeb946bd30e6d8b96022caa2efcc6a078b5..a6d595450ae6dc3794f406ae50372b64ea827a25 100644 (file)
@@ -4,8 +4,8 @@
 !            a screen saver and locker for the X window system
 !                            by Jamie Zawinski
 !
-!                              version 5.05
-!                              01-Mar-2008
+!                              version 5.06
+!                              16-Jul-2008
 !
 ! See "man xscreensaver" for more info.  The latest version is always
 ! available at http://www.jwz.org/xscreensaver/
@@ -125,7 +125,8 @@ GetViewPortIsFullOfLies: False
 
 
 ! This command is executed by the "New Login" button on the lock dialog.
-! (That button does not appear if this program does not exist.)
+! (That button does not appear on the dialog if this program does not exist.)
+! For Gnome: probably "gdmflexiserver -ls".  KDE, probably "kdmctl reserve".
 !
 @NEW_LOGIN_COMMAND_P@*newLoginCommand: @NEW_LOGIN_COMMAND@
 
@@ -400,6 +401,7 @@ GetViewPortIsFullOfLies: False
 @GL_KLUDGE@ GL:                        hypnowheel -root                            \n\
 @GL_KLUDGE@ GL:        "Hypnowheel (dense)"    hypnowheel -root -count 3 -layers 50 \n\
 @GL_KLUDGE@ GL:        "Hypnowheel (trifoil)"  hypnowheel -root -count 3 -layers 2 -speed 9 -twist 9 -wander \n\
+@GL_KLUDGE@ GL:                        skytentacles -root                          \n\
                                                                              \
 -                              xdaliclock -root -font BUILTIN3             \n\
 -                              xplanet -vroot -wait 1 -timewarp 90000        \
@@ -546,6 +548,8 @@ XScreenSaver.bourneShell:           /bin/sh
 *hacks.moebiusgears.name:   MoebiusGears
 *hacks.cubicgrid.name:      CubicGrid
 *hacks.lcdscrub.name:       LCDscrub
+*hacks.hypnowheel.name:     HypnoWheel
+*hacks.skytentacles.name:   SkyTentacles
 
 ! obsolete, but still used by xscreensaver-demo-Xm.
 *hacks.documentation.isInstalled: True
index e556203d6b73e660d3f473e439d6ba0195dec70d..26632eca59a864e4467c32d4f1b8817535757812 100644 (file)
           GL:                  hypnowheel -root                            \\n\
           GL:  \"Hypnowheel (dense)\"  hypnowheel -root -count 3 -layers 50 \\n\
           GL:  \"Hypnowheel (trifoil)\"        hypnowheel -root -count 3 -layers 2 -speed 9 -twist 9 -wander \\n\
+          GL:                  skytentacles -root                          \\n\
                                                                              \
 -                              xdaliclock -root -font BUILTIN3             \\n\
 -                              xplanet -vroot -wait 1 -timewarp 90000        \
 "*hacks.moebiusgears.name:   MoebiusGears",
 "*hacks.cubicgrid.name:      CubicGrid",
 "*hacks.lcdscrub.name:       LCDscrub",
+"*hacks.hypnowheel.name:     HypnoWheel",
+"*hacks.skytentacles.name:   SkyTentacles",
 "*hacks.documentation.isInstalled: True",
index d1eb3c85089901c9bc840c201580c7dbc711fb85..9ab83cbc94f025ba1453f9b05b75faf2fafdd124 100644 (file)
@@ -272,6 +272,9 @@ void settings_switch_page_cb (GtkNotebook *, GtkNotebookPage *,
 void settings_cancel_cb (GtkButton *, gpointer user_data);
 void settings_ok_cb (GtkButton *, gpointer user_data);
 
+static void kill_gnome_screensaver (void);
+static void kill_kde_screensaver (void);
+
 \f
 /* Some random utility functions
  */
@@ -482,9 +485,23 @@ static void warning_dialog_restart_cb (GtkWidget *widget, gpointer user_data)
   warning_dialog_dismiss_cb (widget, user_data);
 }
 
+static void warning_dialog_killg_cb (GtkWidget *widget, gpointer user_data)
+{
+  kill_gnome_screensaver ();
+  warning_dialog_dismiss_cb (widget, user_data);
+}
+
+static void warning_dialog_killk_cb (GtkWidget *widget, gpointer user_data)
+{
+  kill_kde_screensaver ();
+  warning_dialog_dismiss_cb (widget, user_data);
+}
+
+typedef enum { D_NONE, D_LAUNCH, D_GNOME, D_KDE } dialog_button;
+
 static void
 warning_dialog (GtkWidget *parent, const char *message,
-                Boolean restart_button_p, int center)
+                dialog_button button_type, int center)
 {
   char *msg = strdup (message);
   char *head;
@@ -557,7 +574,7 @@ warning_dialog (GtkWidget *parent, const char *message,
                       label, TRUE, TRUE, 0);
 
 #ifdef HAVE_GTK2
-  if (restart_button_p)
+  if (button_type != D_NONE)
     {
       cancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
       gtk_container_add (GTK_CONTAINER (label), cancel);
@@ -571,7 +588,7 @@ warning_dialog (GtkWidget *parent, const char *message,
   ok = gtk_button_new_with_label ("OK");
   gtk_container_add (GTK_CONTAINER (label), ok);
 
-  if (restart_button_p)
+  if (button_type != D_NONE)
     {
       cancel = gtk_button_new_with_label ("Cancel");
       gtk_container_add (GTK_CONTAINER (label), cancel);
@@ -582,22 +599,28 @@ warning_dialog (GtkWidget *parent, const char *message,
   gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
   gtk_container_set_border_width (GTK_CONTAINER (dialog), 10);
   gtk_window_set_title (GTK_WINDOW (dialog), progclass);
-  STFU GTK_WIDGET_SET_FLAGS (ok, GTK_CAN_DEFAULT);
+  GTK_WIDGET_SET_FLAGS (ok, GTK_CAN_DEFAULT);
   gtk_widget_show (ok);
   gtk_widget_grab_focus (ok);
 
   if (cancel)
     {
-      STFU GTK_WIDGET_SET_FLAGS (cancel, GTK_CAN_DEFAULT); 
+      GTK_WIDGET_SET_FLAGS (cancel, GTK_CAN_DEFAULT); 
       gtk_widget_show (cancel);
     }
   gtk_widget_show (label);
   gtk_widget_show (dialog);
 
-  if (restart_button_p)
+  if (button_type != D_NONE)
     {
-      gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
-                                 GTK_SIGNAL_FUNC (warning_dialog_restart_cb),
+      GtkSignalFunc fn;
+      switch (button_type) {
+      case D_LAUNCH: fn = GTK_SIGNAL_FUNC (warning_dialog_restart_cb); break;
+      case D_GNOME:  fn = GTK_SIGNAL_FUNC (warning_dialog_killg_cb);   break;
+      case D_KDE:    fn = GTK_SIGNAL_FUNC (warning_dialog_killk_cb);   break;
+      default: abort(); break;
+      }
+      gtk_signal_connect_object (GTK_OBJECT (ok), "clicked", fn, 
                                  (gpointer) dialog);
       gtk_signal_connect_object (GTK_OBJECT (cancel), "clicked",
                                  GTK_SIGNAL_FUNC (warning_dialog_dismiss_cb),
@@ -644,7 +667,7 @@ run_cmd (state *s, Atom command, int arg)
         sprintf (buf, "Error:\n\n%s", err);
       else
         strcpy (buf, "Unknown error!");
-      warning_dialog (s->toplevel_widget, buf, False, 100);
+      warning_dialog (s->toplevel_widget, buf, D_NONE, 100);
     }
   if (err) free (err);
 
@@ -685,7 +708,7 @@ run_hack (state *s, int list_elt, Bool report_errors_p)
                 sprintf (buf, "Error:\n\n%s", err);
               else
                 strcpy (buf, "Unknown error!");
-              warning_dialog (s->toplevel_widget, buf, False, 100);
+              warning_dialog (s->toplevel_widget, buf, D_NONE, 100);
             }
         }
       else
@@ -700,7 +723,7 @@ run_hack (state *s, int list_elt, Bool report_errors_p)
                      "The XScreenSaver daemon doesn't seem to be running\n"
                      "on display \"%s\".  Launch it now?"),
                    d);
-          warning_dialog (s->toplevel_widget, msg, True, 1);
+          warning_dialog (s->toplevel_widget, msg, D_LAUNCH, 1);
         }
     }
 
@@ -875,7 +898,7 @@ doc_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
     {
       warning_dialog (s->toplevel_widget,
                       _("Error:\n\n"
-                       "No Help URL has been specified.\n"), False, 100);
+                       "No Help URL has been specified.\n"), D_NONE, 100);
       return;
     }
 
@@ -1001,7 +1024,7 @@ await_xscreensaver (state *s)
       else
         strcat (buf, _("Please check your $PATH and permissions."));
 
-      warning_dialog (s->toplevel_widget, buf, False, 1);
+      warning_dialog (s->toplevel_widget, buf, D_NONE, 1);
     }
 
   force_dialog_repaint (s);
@@ -1038,12 +1061,12 @@ demo_write_init_file (state *s, saver_preferences *p)
       if (!f || !*f)
         warning_dialog (s->toplevel_widget,
                         _("Error:\n\nCouldn't determine init file name!\n"),
-                        False, 100);
+                        D_NONE, 100);
       else
         {
           char *b = (char *) malloc (strlen(f) + 1024);
           sprintf (b, _("Error:\n\nCouldn't write %s\n"), f);
-          warning_dialog (s->toplevel_widget, b, False, 100);
+          warning_dialog (s->toplevel_widget, b, D_NONE, 100);
           free (b);
         }
       return -1;
@@ -1106,7 +1129,7 @@ manual_cb (GtkButton *button, gpointer user_data)
     {
       warning_dialog (GTK_WIDGET (button),
                       _("Error:\n\nno `manualCommand' resource set."),
-                      False, 100);
+                      D_NONE, 100);
     }
 
   free (oname);
@@ -1291,7 +1314,7 @@ hack_time_text (state *s, const char *line, Time *store, Bool sec_p)
                   _("Error:\n\n"
                     "Unparsable time format: \"%s\"\n"),
                   line);
-         warning_dialog (s->toplevel_widget, b, False, 100);
+         warning_dialog (s->toplevel_widget, b, D_NONE, 100);
        }
       else
        *store = value;
@@ -1537,7 +1560,7 @@ flush_dialog_changes_and_save (state *s)
       char b[255];
       sprintf (b, "Error:\n\n" "Directory does not exist: \"%s\"\n",
                p2->image_directory);
-      warning_dialog (s->toplevel_widget, b, False, 100);
+      warning_dialog (s->toplevel_widget, b, D_NONE, 100);
     }
 
 
@@ -1808,7 +1831,7 @@ list_activated_cb (GtkTreeView       *list,
   char *str;
   int list_elt;
 
-  STFU g_return_if_fail (!gdk_pointer_is_grabbed ());
+  g_return_if_fail (!gdk_pointer_is_grabbed ());
 
   str = gtk_tree_path_to_string (path);
   list_elt = strtol (str, NULL, 10);
@@ -1996,7 +2019,7 @@ store_image_directory (GtkWidget *button, gpointer user_data)
     {
       char b[255];
       sprintf (b, _("Error:\n\n" "Directory does not exist: \"%s\"\n"), path);
-      warning_dialog (GTK_WIDGET (top), b, False, 100);
+      warning_dialog (GTK_WIDGET (top), b, D_NONE, 100);
       return;
     }
 
@@ -2026,7 +2049,7 @@ store_text_file (GtkWidget *button, gpointer user_data)
     {
       char b[255];
       sprintf (b, _("Error:\n\n" "File does not exist: \"%s\"\n"), path);
-      warning_dialog (GTK_WIDGET (top), b, False, 100);
+      warning_dialog (GTK_WIDGET (top), b, D_NONE, 100);
       return;
     }
 
@@ -2057,7 +2080,7 @@ store_text_program (GtkWidget *button, gpointer user_data)
     {
       char b[255];
       sprintf (b, _("Error:\n\n" "File does not exist: \"%s\"\n"), path);
-      warning_dialog (GTK_WIDGET (top), b, False, 100);
+      warning_dialog (GTK_WIDGET (top), b, D_NONE, 100);
       return;
     }
 # endif
@@ -3414,7 +3437,7 @@ maybe_reload_init_file (state *s)
                _("Warning:\n\n"
                 "file \"%s\" has changed, reloading.\n"),
                f);
-      warning_dialog (s->toplevel_widget, b, False, 100);
+      warning_dialog (s->toplevel_widget, b, D_NONE, 100);
       free (b);
 
       load_init_file (dpy, p);
@@ -4247,6 +4270,77 @@ mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
 #endif
 
 
+static Window
+gnome_screensaver_window (Screen *screen)
+{
+  Display *dpy = DisplayOfScreen (screen);
+  Window root = RootWindowOfScreen (screen);
+  Window parent, *kids;
+  unsigned int nkids;
+  Window gnome_window = 0;
+  int i;
+
+  if (! XQueryTree (dpy, root, &root, &parent, &kids, &nkids))
+    abort ();
+  for (i = 0; i < nkids; i++)
+    {
+      Atom type;
+      int format;
+      unsigned long nitems, bytesafter;
+      unsigned char *name;
+      if (XGetWindowProperty (dpy, kids[i], XA_WM_COMMAND, 0, 128,
+                              False, XA_STRING, &type, &format, &nitems,
+                              &bytesafter, &name)
+          == Success
+          && type != None
+          && !strcmp ((char *) name, "gnome-screensaver"))
+       {
+         gnome_window = kids[i];
+          break;
+       }
+    }
+
+  if (kids) XFree ((char *) kids);
+  return gnome_window;
+}
+
+static Bool
+gnome_screensaver_active_p (void)
+{
+  Display *dpy = GDK_DISPLAY();
+  Window w = gnome_screensaver_window (DefaultScreenOfDisplay (dpy));
+  return (w ? True : False);
+}
+
+static void
+kill_gnome_screensaver (void)
+{
+  Display *dpy = GDK_DISPLAY();
+  Window w = gnome_screensaver_window (DefaultScreenOfDisplay (dpy));
+  if (w) XKillClient (dpy, (XID) w);
+}
+
+static Bool
+kde_screensaver_active_p (void)
+{
+  FILE *p = popen ("dcop kdesktop KScreensaverIface isEnabled 2>/dev/null",
+                   "r");
+  char buf[255];
+  fgets (buf, sizeof(buf)-1, p);
+  pclose (p);
+  if (!strcmp (buf, "true\n"))
+    return True;
+  else
+    return False;
+}
+
+static void
+kill_kde_screensaver (void)
+{
+  system ("dcop kdesktop KScreensaverIface enable false");
+}
+
+
 static void
 the_network_is_not_the_computer (state *s)
 {
@@ -4360,12 +4454,36 @@ the_network_is_not_the_computer (state *s)
 
 
   if (*msg)
-    warning_dialog (s->toplevel_widget, msg, True, 1);
+    warning_dialog (s->toplevel_widget, msg, D_LAUNCH, 1);
 
   if (rversion) free (rversion);
   if (ruser) free (ruser);
   if (rhost) free (rhost);
   free (msg);
+  msg = 0;
+
+  /* Note: since these dialogs are not modal, they will stack up.
+     So we do this check *after* popping up the "xscreensaver is not
+     running" dialog so that these are on top.  Good enough.
+   */
+
+  if (gnome_screensaver_active_p ())
+    warning_dialog (s->toplevel_widget,
+                    _("Warning:\n\n"
+                      "The GNOME screensaver daemon appears to be running.\n"
+                      "It must be stopped for XScreenSaver to work properly.\n"
+                      "\n"
+                      "Stop the GNOME screen saver daemon now?\n"),
+                    D_GNOME, 1);
+
+  if (kde_screensaver_active_p ())
+    warning_dialog (s->toplevel_widget,
+                    _("Warning:\n\n"
+                      "The KDE screen saver daemon appears to be running.\n"
+                      "It must be stopped for XScreenSaver to work properly.\n"
+                      "\n"
+                      "Stop the KDE screen saver daemon now?\n"),
+                    D_KDE, 1);
 }
 
 
index 0f2aaa21dbef584321858c9747c4c377bc44750c..5da53a01831a406d07f947edd08a6399c4ce06fc 100644 (file)
@@ -1,5 +1,5 @@
 /* exec.c --- executes a program in *this* pid, without an intervening process.
- * xscreensaver, Copyright (c) 1991-2006 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1991-2008 Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -181,8 +181,7 @@ exec_command (const char *shell, const char *command, int nice_level)
   int hairy_p;
 
 #ifndef VMS
-  if (nice != 0)
-    nice_process (nice_level);
+  nice_process (nice_level);
 
   hairy_p = !!strpbrk (command, "*?$&!<>[];`'\\\"=");
   /* note: = is in the above because of the sh syntax "FOO=bar cmd". */
index e1d29dc92a958b31d8cbf3b6489e5997df8d012b..159c6a0f2517d548e7a1036d938466b303b89344 100644 (file)
@@ -1,5 +1,5 @@
 /* lock.c --- handling the password dialog for locking-mode.
- * xscreensaver, Copyright (c) 1993-2007 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1993-2008 Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -179,7 +179,7 @@ static void restore_background (saver_info *si);
 
 extern void xss_authenticate(saver_info *si, Bool verbose_p);
 
-static void
+static int
 new_passwd_window (saver_info *si)
 {
   passwd_dialog_data *pw;
@@ -190,7 +190,7 @@ new_passwd_window (saver_info *si)
 
   pw = (passwd_dialog_data *) calloc (1, sizeof(*pw));
   if (!pw)
-    return;
+    return -1;
 
   /* Display the button only if the "newLoginCommand" pref is non-null.
    */
@@ -406,13 +406,14 @@ new_passwd_window (saver_info *si)
   }
 
   si->pw_data = pw;
+  return 0;
 }
 
 
 /**
  * info_msg and prompt may be NULL.
  */
-static void
+static int
 make_passwd_window (saver_info *si,
                    const char *info_msg,
                    const char *prompt,
@@ -428,11 +429,15 @@ make_passwd_window (saver_info *si,
 
   cleanup_passwd_window (si);
 
+  if (! ssi)   /* WTF?  Trying to prompt while no screens connected? */
+    return -1;
+
   if (!si->pw_data)
-    new_passwd_window (si);
+    if (new_passwd_window (si) < 0)
+      return -1;
 
   if (!(pw = si->pw_data))
-    return;
+    return -1;
 
   pw->ratio = 1.0;
 
@@ -614,10 +619,11 @@ make_passwd_window (saver_info *si,
      actually be visible; this takes into account virtual viewports as
      well as Xinerama. */
   {
-    int x, y, w, h;
-    get_screen_viewport (pw->prompt_screen, &x, &y, &w, &h,
-                         pw->previous_mouse_x, pw->previous_mouse_y,
-                         si->prefs.verbose_p);
+    saver_screen_info *ssi = &si->screens [mouse_screen (si)];
+    int x = ssi->x;
+    int y = ssi->y;
+    int w = ssi->width;
+    int h = ssi->height;
     if (si->prefs.debug_p) w /= 2;
     pw->x = x + ((w + pw->width) / 2) - pw->width;
     pw->y = y + ((h + pw->height) / 2) - pw->height;
@@ -678,6 +684,8 @@ make_passwd_window (saver_info *si,
   if (cmap)
     XInstallColormap (si->dpy, cmap);
   draw_passwd_window (si);
+
+  return 0;
 }
 
 
@@ -1418,8 +1426,12 @@ xfree_lock_grab_smasher (saver_info *si, Bool lock_p)
 {
   saver_preferences *p = &si->prefs;
   int status;
-
+  int event, error;
   XErrorHandler old_handler;
+
+  if (!XF86MiscQueryExtension(si->dpy, &event, &error))
+    return;
+
   XSync (si->dpy, False);
   error_handler_hit_p = False;
   old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
@@ -1463,6 +1475,7 @@ xfree_lock_mode_switch (saver_info *si, Bool lock_p)
   static Bool any_mode_locked_p = False;
   saver_preferences *p = &si->prefs;
   int screen;
+  int real_nscreens = ScreenCount (si->dpy);
   int event, error;
   Bool status;
   XErrorHandler old_handler;
@@ -1472,7 +1485,7 @@ xfree_lock_mode_switch (saver_info *si, Bool lock_p)
   if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
     return;
 
-  for (screen = 0; screen < (si->xinerama_p ? 1 : si->nscreens); screen++)
+  for (screen = 0; screen < real_nscreens; screen++)
     {
       XSync (si->dpy, False);
       old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
@@ -1509,12 +1522,13 @@ undo_vp_motion (saver_info *si)
 #ifdef HAVE_XF86VMODE
   saver_preferences *p = &si->prefs;
   int screen;
+  int real_nscreens = ScreenCount (si->dpy);
   int event, error;
 
   if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
     return;
 
-  for (screen = 0; screen < si->nscreens; screen++)
+  for (screen = 0; screen < real_nscreens; screen++)
     {
       saver_screen_info *ssi = &si->screens[screen];
       int x, y;
@@ -1932,9 +1946,11 @@ gui_auth_conv(int num_msg,
        info_msg_trimmed = remove_trailing_whitespace(info_msg);
        prompt_trimmed = remove_trailing_whitespace(prompt);
 
-       make_passwd_window(si, info_msg_trimmed, prompt_trimmed,
-                          auth_msgs[i].type == AUTH_MSGTYPE_PROMPT_ECHO
-                          ? True : False);
+       if (make_passwd_window(si, info_msg_trimmed, prompt_trimmed,
+                               auth_msgs[i].type == AUTH_MSGTYPE_PROMPT_ECHO
+                               ? True : False)
+            < 0)
+          goto fail;
 
        if (info_msg_trimmed)
          free(info_msg_trimmed);
index bb8d99265eb6379debf527f852cd73ba4067eb10..202e0eb10982395a2f1c1186545c55e7ec4da38e 100644 (file)
  static const char *tk_file;
 #endif /* !HAVE_DARWIN */
 
+/* warning suppression: duplicated in passwd.c */
+extern Bool kerberos_lock_init (int argc, char **argv, Bool verbose_p);
+extern Bool kerberos_passwd_valid_p (const char *typed_passwd, Bool verbose_p);
+
 
 /* Called at startup to grab user, instance, and realm information
    from the user's ticketfile (remember, name.inst@realm). Since we're
index 334d12b913c83d8d42d7822099d47b727853a86c..3b4c64f91bfb584e2c739012c00c72f763275496 100644 (file)
@@ -452,6 +452,14 @@ pam_conversation (int nmsgs,
 
   ret = si->unlock_cb(nmsgs, messages, &authresp, si);
 
+  /* #### If the user times out, or hits ESC or Cancel, we return PAM_CONV_ERR,
+          and PAM logs this as an authentication failure.  It would be nice if
+          there was some way to indicate that this was a "cancel" rather than
+          a "fail", so that it wouldn't show up in syslog, but I think the
+          only options are PAM_SUCCESS and PAM_CONV_ERR.  (I think that
+          PAM_ABORT means "internal error", not "cancel".)  Bleh.
+   */
+
   if (ret == 0)
     {
       for (i = 0; i < nmsgs; ++i)
index 60778fe10c472169a07c062314ef2dbbcd9eb594..166826e8122298a29dc4ca319ffdd4ba85df3ff6 100644 (file)
@@ -1,6 +1,6 @@
 /* pdf2jpeg -- converts a PDF file to a JPEG file, using Cocoa
  *
- * Copyright (c) 2003 by Jamie Zawinski <jwz@jwz.org>
+ * Copyright (c) 2003, 2008 by Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -23,6 +23,7 @@ main (int argc, char** argv)
   const char *progname = argv[0];
   const char *infile = 0, *outfile = 0;
   double compression = 0.85;
+  double scale = 1.0;
   int verbose = 0;
   int i;
 
@@ -45,6 +46,18 @@ main (int argc, char** argv)
             }
           compression = q / 100.0;
         }
+      else if (!strcmp (argv[i], "-scale"))
+        {
+          float s;
+          if (1 != sscanf (argv[++i], " %f %c", &s, &c) ||
+              s <= 0 || s > 50)
+            {
+              fprintf (stderr, "%s: scale must be 0.0 - 50.0 (%f)\n",
+                       progname, s);
+              goto USAGE;
+            }
+          scale = s;
+        }
       else if (!strcmp (argv[i], "-verbose"))
         verbose++;
       else if (!strcmp (argv[i], "-v") ||
@@ -64,7 +77,7 @@ main (int argc, char** argv)
         {
         USAGE:
           fprintf (stderr,
-                   "usage: %s [-verbose] [-quality NN] "
+                   "usage: %s [-verbose] [-scale N] [-quality NN] "
                    "infile.pdf outfile.jpg\n",
                    progname);
           exit (1);
@@ -93,11 +106,16 @@ main (int argc, char** argv)
   NSPDFImageRep *pdf_rep = [NSPDFImageRep imageRepWithData:pdf_data];
 
   // Create an NSImage instance
-  NSImage *image = [[NSImage alloc] initWithSize:[pdf_rep size]];
+  NSRect rect;
+  rect.size = [pdf_rep size];
+  rect.size.width  *= scale;
+  rect.size.height *= scale;
+  rect.origin.x = rect.origin.y = 0;
+  NSImage *image = [[NSImage alloc] initWithSize:rect.size];
 
   // Draw the PDFImageRep in the NSImage
   [image lockFocus];
-  [pdf_rep drawAtPoint:NSMakePoint(0.0,0.0)];
+  [pdf_rep drawInRect:rect];
   [image unlockFocus];
 
   // Load the NSImage's contents into an NSBitmapImageRep:
index c8e4ae14868c671fb66371901667dade718413e2..1b093148098516b01378ccc57aa8e8f3434122d2 100644 (file)
@@ -1,5 +1,5 @@
 /* dotfile.c --- management of the ~/.xscreensaver file.
- * xscreensaver, Copyright (c) 1998-2006 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1998-2008 Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -272,6 +272,7 @@ static const char * const prefs[] = {
   "fadeTicks",
   "captureStderr",
   "captureStdout",             /* not saved -- obsolete */
+  "logFile",                   /* not saved */
   "ignoreUninstalledPrograms",
   "font",
   "dpmsEnabled",
@@ -808,6 +809,7 @@ write_init_file (Display *dpy,
       CHECK("fadeTicks")       type = pref_int,  i = p->fade_ticks;
       CHECK("captureStderr")   type = pref_bool, b = p->capture_stderr_p;
       CHECK("captureStdout")   continue;  /* don't save */
+      CHECK("logFile")         continue;  /* don't save */
       CHECK("ignoreUninstalledPrograms")
                                 type = pref_bool, b = p->ignore_uninstalled_p;
 
diff --git a/driver/screens.c b/driver/screens.c
new file mode 100644 (file)
index 0000000..cef66b7
--- /dev/null
@@ -0,0 +1,894 @@
+/* screens.c --- dealing with RANDR, Xinerama, and VidMode Viewports.
+ * xscreensaver, Copyright (c) 1991-2008 Jamie Zawinski <jwz@jwz.org>
+ *
+ * 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.
+ */
+
+/*   There are a bunch of different mechanisms for multiple monitors
+ *   available in X.  XScreenSaver needs to care about this for two
+ *   reasons: first, to ensure that all visible areas go black; and
+ *   second, so that the windows of screen savers exactly fill the
+ *   glass of each monitor (instead of one saver spanning multiple
+ *   monitors, or a monitor displaying only a sub-rectangle of the
+ *   screen saver.)
+ *
+ *   1) Multi-screen:
+ *
+ *      This is the original way.  Each monitor gets its own display
+ *      number.  :0.0 is the first one, :0.1 is the next, etc.  The
+ *      value of $DISPLAY determines which screen windows open on by
+ *      default.  A single app can open windows on multiple screens
+ *      with the same display connection, but windows cannot be moved
+ *      from one screen to another.  The mouse can be moved from one
+ *      screen to another, though.  Screens may be different depths
+ *      (e.g., one can be TrueColor and one can be PseudoColor.)
+ *      Screens cannot be resized or moved without restarting X.
+ *
+ *      Everyone hates this way of doing things because of the
+ *      inability to move a window from one screen to another without
+ *      restarting the application.
+ *
+ *   2) Xinerama:
+ *
+ *      There is a single giant root window that spans all the
+ *      monitors.  All monitors are the same depth, and windows can be
+ *      moved around.  Applications can learn which rectangles are
+ *      actually visible on monitors by querying the Xinerama server
+ *      extension.  (If you don't do that, you end up with dialog
+ *      boxes that try to appear in the middle of the screen actually
+ *      spanning the gap between two monitors.)
+ *
+ *      Xinerama doesn't work with DRI, which means that if you use
+ *      it, you lose hardware acceleration on OpenGL programs.  Also,
+ *      screens can't be resized or moved without restarting X.
+ *
+ *   3) Vidmode Viewports:
+ *
+ *      With this extension, the root window can be bigger than the
+ *      monitor.  Moving the mouse near the edges of the screen
+ *      scrolls around, like a pan-and-scan movie.  There can also be
+ *      a hot key for changing the monitor's resolution (zooming
+ *      in/out).
+ *
+ *      Trying to combine this with Xinerama crashes the server, so
+ *      you can only use this if you have only a single screen, or are
+ *      in old-multi-screen mode.
+ *
+ *      Also, half the time it doesn't work at all: it tends to lie
+ *      about the size of the rectangle in use.
+ *
+ *   4) RANDR 1.0:
+ *
+ *      The first version of the "Resize and Rotate" extension let you
+ *      change the resolution of a screen on the fly.  The root window
+ *      would actually resize.  However, it was also incompatible with
+ *      Xinerama (did it crash, or just do nothing? I can't remember)
+ *      so you needed to be in single-screen or old multi-screen mode.
+ *      I believe RANDR could co-exist with Vidmode Viewports, but I'm
+ *      not sure.
+ *
+ *   5) RANDR 1.2:
+ *
+ *      Finally, RANDR added the functionality of Xinerama, plus some.
+ *      Each X screen (in the sense of #1, "multi-screen") can have a
+ *      number of sub-rectangles that are displayed on monitors, and
+ *      each of those sub-rectangles can be displayed on more than one
+ *      monitor.  So it's possible (I think) to have a hybrid of
+ *      multi-screen and Xinerama (e.g., to have two monitors running
+ *      in one depth, and three monitors running in another?)
+ *      Typically though, there will be a single X screen, with
+ *      Xinerama-like division of that large root window onto multiple
+ *      monitors.  Also everything's dynamic: monitors can be added,
+ *      removed, and resized at runtime.
+ *
+ *      I believe that as of RANDR 1.2, the Xinerama extension still
+ *      exists but only as a compatiblity layer: it's actually
+ *      returning data from the RANDR extension.
+ *
+ *      Though RANDR 1.2 allows the same image to be cloned onto more
+ *      than one monitor, and also allows one monitor to show a
+ *      subsection of something on another monitor (e.g., the
+ *      rectangles can be enclosed or overlap).  Since there's no way
+ *      to put seperate savers on those duplicated-or-overlapping
+ *      monitors, xscreensaver just ignores them (which allows them to
+ *      display duplicates or overlaps).
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <X11/Xlib.h>
+
+#ifdef HAVE_RANDR
+# include <X11/extensions/Xrandr.h>
+#endif /* HAVE_RANDR */
+
+#ifdef HAVE_XINERAMA
+# include <X11/extensions/Xinerama.h>
+#endif /* HAVE_XINERAMA */
+
+#ifdef HAVE_XF86VMODE
+# include <X11/extensions/xf86vmode.h>
+#endif /* HAVE_XF86VMODE */
+
+/* This file doesn't need the Xt headers, so stub these types out... */
+#undef XtPointer
+#define XtAppContext void*
+#define XrmDatabase  void*
+#define XtIntervalId void*
+#define XtPointer    void*
+#define Widget       void*
+
+#include "xscreensaver.h"
+#include "visual.h"
+
+
+typedef enum { S_SANE, S_ENCLOSED, S_DUPLICATE, S_OVERLAP, 
+               S_OFFSCREEN, S_DISABLED } monitor_sanity;
+
+/* 'typedef monitor' is in types.h */
+struct _monitor {
+  int id;
+  char *desc;
+  Screen *screen;
+  int x, y, width, height;
+  monitor_sanity sanity;       /* I'm not crazy you're the one who's crazy */
+  int enemy;                   /* which monitor it overlaps or duplicates */
+};
+
+static void
+free_monitors (monitor **monitors)
+{
+  monitor **m2 = monitors;
+  if (! monitors) return;
+  while (*m2) 
+    {
+      if ((*m2)->desc) free ((*m2)->desc);
+      free (*m2);
+      m2++;
+    }
+  free (monitors);
+}
+
+
+#ifdef HAVE_XINERAMA
+
+static monitor **
+xinerama_scan_monitors (Display *dpy)
+{
+  Screen *screen = DefaultScreenOfDisplay (dpy);
+  int event, error, nscreens, i;
+  XineramaScreenInfo *xsi;
+  monitor **monitors;
+
+  if (! XineramaQueryExtension (dpy, &event, &error))
+    return 0;
+
+  if (! XineramaIsActive (dpy)) 
+    return 0;
+
+  xsi = XineramaQueryScreens (dpy, &nscreens);
+  if (!xsi) return 0;
+
+  monitors = (monitor **) calloc (nscreens + 1, sizeof(*monitors));
+  if (!monitors) return 0;
+
+  for (i = 0; i < nscreens; i++)
+    {
+      monitor *m = (monitor *) calloc (1, sizeof (monitor));
+      monitors[i] = m;
+      m->id       = i;
+      m->screen   = screen;
+      m->x        = xsi[i].x_org;
+      m->y        = xsi[i].y_org;
+      m->width    = xsi[i].width;
+      m->height   = xsi[i].height;
+    }
+  return monitors;
+}
+
+#endif /* HAVE_XINERAMA */
+
+
+#ifdef HAVE_XF86VMODE
+
+static monitor **
+vidmode_scan_monitors (Display *dpy)
+{
+  int event, error, nscreens, i;
+  monitor **monitors;
+
+  /* Note that XF86VidModeGetViewPort() tends to be full of lies on laptops
+     that have a docking station or external monitor that runs in a different
+     resolution than the laptop's screen:
+
+         http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=81593
+         http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=208417
+         http://bugs.xfree86.org/show_bug.cgi?id=421
+
+     Presumably this is fixed by using RANDR instead of VidMode.
+   */
+
+# ifdef HAVE_XINERAMA
+  /* Attempts to use the VidMode extension when the Xinerama extension is
+     active can result in a server crash! Yay! */
+  if (XQueryExtension (dpy, "XINERAMA", &error, &event, &error))
+    return 0;
+#  endif /* !HAVE_XINERAMA */
+
+  if (! XF86VidModeQueryExtension (dpy, &event, &error))
+    return 0;
+
+  nscreens = ScreenCount (dpy);
+  monitors = (monitor **) calloc (nscreens + 1, sizeof(*monitors));
+  if (!monitors) return 0;
+
+  for (i = 0; i < nscreens; i++)
+    {
+      monitor *m = (monitor *) calloc (1, sizeof (monitor));
+      XF86VidModeModeLine ml;
+      int dot;
+      Screen *screen = ScreenOfDisplay (dpy, i);
+
+      monitors[i] = m;
+      m->id       = i;
+      m->screen   = screen;
+
+      if (! safe_XF86VidModeGetViewPort (dpy, i, &m->x, &m->y))
+        m->x = m->y = -1;
+
+      if (XF86VidModeGetModeLine (dpy, i, &dot, &ml))
+        {
+          m->width  = ml.hdisplay;
+          m->height = ml.vdisplay;
+        }
+
+      /* Apparently, though the server stores the X position in increments of
+         1 pixel, it will only make changes to the *display* in some other
+         increment.  With XF86_SVGA on a Thinkpad, the display only updates
+         in multiples of 8 pixels when in 8-bit mode, and in multiples of 4
+         pixels in 16-bit mode.  I don't know what it does in 24- and 32-bit
+         mode, because I don't have enough video memory to find out.
+
+         I consider it a bug that XF86VidModeGetViewPort() is telling me the
+         server's *target* scroll position rather than the server's *actual*
+         scroll position.  David Dawes agrees, and says they may fix this in
+         XFree86 4.0, but it's notrivial.
+
+         He also confirms that this behavior is server-dependent, so the
+         actual scroll position cannot be reliably determined by the client.
+         So... that means the only solution is to provide a ``sandbox''
+         around the blackout window -- we make the window be up to N pixels
+         larger than the viewport on both the left and right sides.  That
+         means some part of the outer edges of each hack might not be
+         visible, but screw it.
+
+         I'm going to guess that 16 pixels is enough, and that the Y dimension
+         doesn't have this problem.
+
+         The drawback of doing this, of course, is that some of the screenhacks
+         will still look pretty stupid -- for example, "slidescreen" will cut
+         off the left and right edges of the grid, etc.
+      */
+#  define FUDGE 16
+      if (m->x > 0 && m->x < m->width - ml.hdisplay)
+        {
+          /* Not at left edge or right edge:
+             Round X position down to next lower multiple of FUDGE.
+             Increase width by 2*FUDGE in case some server rounds up.
+           */
+          m->x = ((m->x - 1) / FUDGE) * FUDGE;
+          m->width += (FUDGE * 2);
+        }
+#  undef FUDGE
+    }
+
+  return monitors;
+}
+
+#endif /* HAVE_XF86VMODE */
+
+
+#ifdef HAVE_RANDR
+
+static monitor **
+randr_scan_monitors (Display *dpy)
+{
+  int event, error, major, minor, nscreens, i, j;
+  monitor **monitors;
+  Bool new_randr_p = False;
+
+  if (! XRRQueryExtension (dpy, &event, &error))
+    return 0;
+
+  if (! XRRQueryVersion (dpy, &major, &minor))
+    return 0;
+
+  if (major <= 0)    /* Protocol was still in flux back then -- fuck it. */
+    return 0;
+
+# ifdef HAVE_RANDR_12
+  new_randr_p = (major > 1 || (major == 1 && minor >= 2));
+# endif
+
+  if (! new_randr_p)
+    /* RANDR 1.0 -- no Xinerama-like virtual screens. */
+    nscreens = ScreenCount (dpy);
+  else  /* RANDR 1.2 or newer -- built-in Xinerama */
+    {
+# ifdef HAVE_RANDR_12
+      int xsc = ScreenCount (dpy);
+      nscreens = 0;
+      /* Add up the virtual screens on each X screen. */
+      for (i = 0; i < xsc; i++)
+        {
+          XRRScreenResources *res = 
+            XRRGetScreenResources (dpy, RootWindow (dpy, i));
+          nscreens += res->noutput;
+          XRRFreeScreenResources (res);
+        }
+# endif /* HAVE_RANDR_12 */
+    }
+
+  monitors = (monitor **) calloc (nscreens + 1, sizeof(*monitors));
+  if (!monitors) return 0;
+
+  for (i = 0, j = 0; i < ScreenCount (dpy); i++)
+    {
+      Screen *screen = ScreenOfDisplay (dpy, j);
+
+      if (! new_randr_p)  /* RANDR 1.0 */
+        {
+          XRRScreenConfiguration *rrc;
+          monitor *m = (monitor *) calloc (1, sizeof (monitor));
+          monitors[i] = m;
+          m->screen   = screen;
+          m->id       = i;
+
+          rrc = XRRGetScreenInfo (dpy, RootWindowOfScreen (screen));
+          if (rrc)
+            {
+              SizeID size = -1;
+              Rotation rot = ~0;
+              XRRScreenSize *rrsizes;
+              int nsizes;
+
+              size = XRRConfigCurrentConfiguration (rrc, &rot);
+              rrsizes = XRRConfigSizes (rrc, &nsizes);
+
+              if (rot & (RR_Rotate_90|RR_Rotate_270))
+                {
+                  m->width  = rrsizes[size].height;
+                  m->height = rrsizes[size].width;
+                }
+              else
+                {
+                  m->width  = rrsizes[size].width;
+                  m->height = rrsizes[size].height;
+                }
+
+              /* don't free 'rrsizes' */
+              XRRFreeScreenConfigInfo (rrc);
+            }
+        }
+      else   /* RANDR 1.2 or newer */
+        {
+# ifdef HAVE_RANDR_12
+          int k;
+          XRRScreenResources *res = 
+            XRRGetScreenResources (dpy, RootWindowOfScreen (screen));
+          for (k = 0; k < res->noutput; k++)
+            {
+              monitor *m = (monitor *) calloc (1, sizeof (monitor));
+              XRROutputInfo *rroi = XRRGetOutputInfo (dpy, res, 
+                                                      res->outputs[k]);
+              RRCrtc crtc = (rroi->crtc ? rroi->crtc : rroi->crtcs[0]);
+              XRRCrtcInfo *crtci = XRRGetCrtcInfo (dpy, res, crtc);
+
+              monitors[j] = m;
+              m->screen   = screen;
+              m->id       = (i * 1000) + j;
+              m->desc     = (rroi->name ? strdup (rroi->name) : 0);
+              m->x        = crtci->x;
+              m->y        = crtci->y;
+
+              if (crtci->rotation & (RR_Rotate_90|RR_Rotate_270))
+                {
+                  m->width  = crtci->height;
+                  m->height = crtci->width;
+                }
+              else
+                {
+                  m->width  = crtci->width;
+                  m->height = crtci->height;
+                }
+
+              j++;
+
+              if (rroi->connection == RR_Disconnected)
+                m->sanity = S_DISABLED;
+              /* #### do the same for RR_UnknownConnection? */
+
+              XRRFreeCrtcInfo (crtci);
+              XRRFreeOutputInfo (rroi);
+            }
+          XRRFreeScreenResources (res);
+# endif /* HAVE_RANDR_12 */
+        }
+    }
+
+  return monitors;
+}
+
+#endif /* HAVE_RANDR */
+
+
+static monitor **
+basic_scan_monitors (Display *dpy)
+{
+  int nscreens = ScreenCount (dpy);
+  int i;
+  monitor **monitors = (monitor **) calloc (nscreens + 1, sizeof(*monitors));
+  if (!monitors) return 0;
+
+  for (i = 0; i < nscreens; i++)
+    {
+      Screen *screen = ScreenOfDisplay (dpy, i);
+      monitor *m = (monitor *) calloc (1, sizeof (monitor));
+      monitors[i] = m;
+      m->id       = i;
+      m->screen   = screen;
+      m->x        = 0;
+      m->y        = 0;
+      m->width    = WidthOfScreen (screen);
+      m->height   = HeightOfScreen (screen);
+    }
+  return monitors;
+}
+
+
+#ifdef DEBUG_MULTISCREEN
+
+/* If DEBUG_MULTISCREEN is defined, then in "-debug" mode, xscreensaver
+   will pretend that it is changing the number of connected monitors
+   every few seconds, using the geometries in the following list,
+   for stress-testing purposes.
+ */
+static monitor **
+debug_scan_monitors (Display *dpy)
+{
+  static const char * const geoms[] = {
+    "1600x1028+0+22",
+    "1024x768+0+22",
+    "800x600+0+22",
+    "800x600+0+22,800x600+800+22",
+    "800x600+0+22,800x600+800+22,800x600+300+622",
+    "800x600+0+22,800x600+800+22,800x600+0+622,800x600+800+622",
+    "640x480+0+22,640x480+640+22,640x480+0+502,640x480+640+502",
+    "640x480+240+22,640x480+0+502,640x480+640+502",
+    "640x480+0+200,640x480+640+200",
+    "800x600+400+22",
+    "320x200+0+22,320x200+320+22,320x200+640+22,320x200+960+22,320x200+0+222,320x200+320+222,320x200+640+222,320x200+960+222,320x200+0+422,320x200+320+422,320x200+640+422,320x200+960+422,320x200+0+622,320x200+320+622,320x200+640+622,320x200+960+622,320x200+0+822,320x200+320+822,320x200+640+822,320x200+960+822"
+  };
+  static int index = 0;
+  monitor **monitors = (monitor **) calloc (100, sizeof(*monitors));
+  int nscreens = 0;
+  Screen *screen = DefaultScreenOfDisplay (dpy);
+
+  char *s = strdup (geoms[index]);
+  char *token = strtok (s, ",");
+  while (token)
+    {
+      monitor *m = calloc (1, sizeof (monitor));
+      char c;
+      m->id = nscreens;
+      m->screen = screen;
+      if (4 != sscanf (token, "%dx%d+%d+%d%c", 
+                       &m->width, &m->height, &m->x, &m->y, &c))
+        abort();
+      m->width -= 2;
+      m->height -= 2;
+      monitors[nscreens++] = m;
+      token = strtok (0, ",");
+    }
+  free (s);
+  
+  index = (index+1) % countof(geoms);
+  return monitors;
+}
+
+#endif /* DEBUG_MULTISCREEN */
+
+
+#ifdef QUAD_MODE
+static monitor **
+quadruple (monitor **monitors, Bool debug_p)
+{
+  int i, j, count = 0;
+  monitor **monitors2;
+  while (monitors[count])
+    count++;
+  monitors2 = (monitor **) calloc (count * 4 + 1, sizeof(*monitors));
+  if (!monitors2) abort();
+
+  for (i = 0, j = 0; i < count; i++)
+    {
+      int k;
+      for (k = 0; k < 4; k++)
+        {
+          monitors2[j+k] = (monitor *) calloc (1, sizeof (monitor));
+          *monitors2[j+k] = *monitors[i];
+          monitors2[j+k]->width  /= (debug_p ? 4 : 2);
+          monitors2[j+k]->height /= 2;
+          monitors2[j+k]->id = (monitors[i]->id * 4) + k;
+          monitors2[j+k]->name = (monitors[i]->name
+                                  ? strdup (monitors[i]->name) : 0);
+        }
+      monitors2[j+1]->x += monitors2[j]->width;
+      monitors2[j+2]->y += monitors2[j]->height;
+      monitors2[j+3]->x += monitors2[j]->width;
+      monitors2[j+3]->y += monitors2[j]->height;
+      j += 4;
+    }
+
+  free_monitors (monitors);
+  return monitors2;
+}
+#endif /* QUAD_MODE */
+
+
+static monitor **
+scan_monitors (saver_info *si)
+{
+  saver_preferences *p = &si->prefs;
+  monitor **monitors = 0;
+
+# ifdef DEBUG_MULTISCREEN
+    if (! monitors) monitors = debug_scan_monitors (si->dpy);
+# endif
+
+# ifdef HAVE_RANDR
+  if (! p->getviewport_full_of_lies_p)
+    if (! monitors) monitors = randr_scan_monitors (si->dpy);
+# endif
+
+# ifdef HAVE_XF86VMODE
+  if (! monitors) monitors = vidmode_scan_monitors (si->dpy);
+# endif
+
+# ifdef HAVE_XF86VMODE
+  if (! monitors) monitors = xinerama_scan_monitors (si->dpy);
+# endif
+
+  if (! monitors) monitors = basic_scan_monitors (si->dpy);
+
+# ifdef QUAD_MODE
+  if (p->quad_p)
+    monitors = quadruple (monitors, p->debug_p);
+# endif
+
+  return monitors;
+}
+
+
+static Bool
+monitors_overlap_p (monitor *a, monitor *b)
+{
+  /* Two rectangles overlap if the max of the tops is less than the
+     min of the bottoms and the max of the lefts is less than the min
+     of the rights.
+   */
+# undef MAX
+# undef MIN
+# define MAX(A,B) ((A)>(B)?(A):(B))
+# define MIN(A,B) ((A)<(B)?(A):(B))
+
+  int maxleft  = MAX(a->x, b->x);
+  int maxtop   = MAX(a->y, b->y);
+  int minright = MIN(a->x + a->width  - 1, b->x + b->width);
+  int minbot   = MIN(a->y + a->height - 1, b->y + b->height);
+  return (maxtop < minbot && maxleft < minright);
+}
+
+
+/* Mark the ones that overlap, etc.
+ */
+static void
+check_monitor_sanity (monitor **monitors)
+{
+  int i, j, count = 0;
+
+  while (monitors[count])
+    count++;
+
+#  define X1 monitors[i]->x
+#  define X2 monitors[j]->x
+#  define Y1 monitors[i]->y
+#  define Y2 monitors[j]->y
+#  define W1 monitors[i]->width
+#  define W2 monitors[j]->width
+#  define H1 monitors[i]->height
+#  define H2 monitors[j]->height
+
+  /* If a monitor is enclosed by any other monitor, that's insane.
+   */
+  for (i = 0; i < count; i++)
+    for (j = 0; j < count; j++)
+      if (i != j &&
+          monitors[i]->sanity == S_SANE &&
+          monitors[j]->sanity == S_SANE &&
+          X2 >= X1 &&
+          Y2 >= Y1 &&
+          (X2+W2) <= (X1+W1) &&
+          (Y2+H2) <= (Y1+H1))
+        {
+          if (X1 == X2 &&
+              Y1 == Y2 &&
+              W1 == W2 &&
+              H1 == H2)
+            monitors[j]->sanity = S_DUPLICATE;
+          else 
+            monitors[j]->sanity = S_ENCLOSED;
+          monitors[j]->enemy = i;
+        }
+
+  /* After checking for enclosure, check for other lossage against earlier
+     monitors.  We do enclosure first so that we make sure to pick the
+     larger one.
+   */
+  for (i = 0; i < count; i++)
+    for (j = 0; j < i; j++)
+      {
+        if (monitors[i]->sanity != S_SANE) continue; /* already marked */
+        if (monitors[j]->sanity != S_SANE) continue;
+
+        if (monitors_overlap_p (monitors[i], monitors[j]))
+          {
+            monitors[i]->sanity = S_OVERLAP;
+            monitors[i]->enemy = j;
+          }
+      }
+
+  /* Finally, make sure all monitors are enclosed by their X screen.
+     Xinerama sometimes reports 1024x768 VPs at -1936862040, -1953705044.
+   */
+  for (i = 0; i < count; i++)
+    {
+      int sw = WidthOfScreen (monitors[i]->screen)  * 2;
+      int sh = HeightOfScreen (monitors[i]->screen) * 2;
+      if (monitors[i]->sanity != S_SANE) continue; /* already marked */
+      if (X1    <  0 || Y1    <  0 || 
+          W1    <= 0 || H1    <= 0 || 
+          X1+W1 > sw || Y1+H1 > sh)
+        {
+          monitors[i]->sanity = S_OFFSCREEN;
+          monitors[i]->enemy = 0;
+        }
+    }
+
+#  undef X1
+#  undef X2
+#  undef Y1
+#  undef Y2
+#  undef W1
+#  undef W2
+#  undef H1
+#  undef H2
+}
+
+
+static Bool
+layouts_differ_p (monitor **a, monitor **b)
+{
+  if (!a || !b) return True;
+  while (1)
+    {
+      if (!*a) break;
+      if (!*b) break;
+      if ((*a)->screen != (*b)->screen ||
+          (*a)->x      != (*b)->x      ||
+          (*a)->y      != (*b)->y      ||
+          (*a)->width  != (*b)->width  ||
+          (*a)->height != (*b)->height)
+        return True;
+      a++;
+      b++;
+    }
+  if (*a) return True;
+  if (*b) return True;
+
+  return False;
+}
+
+
+void
+describe_monitor_layout (saver_info *si)
+{
+  monitor **monitors = si->monitor_layout;
+  int count = 0;
+  int good_count = 0;
+  int bad_count = 0;
+  while (monitors[count])
+    {
+      if (monitors[count]->sanity == S_SANE)
+        good_count++;
+      else
+        bad_count++;
+      count++;
+    }
+
+  if (count == 0)
+    fprintf (stderr, "%s: no screens!\n", blurb());
+  else
+    {
+      int i;
+      fprintf (stderr, "%s: screens in use: %d\n", blurb(), good_count);
+      for (i = 0; i < count; i++)
+        {
+          monitor *m = monitors[i];
+          if (m->sanity != S_SANE) continue;
+          fprintf (stderr, "%s:  %3d/%d: %dx%d+%d+%d",
+                   blurb(), m->id, screen_number (m->screen),
+                   m->width, m->height, m->x, m->y);
+          if (m->desc && *m->desc) fprintf (stderr, " (%s)", m->desc);
+          fprintf (stderr, "\n");
+        }
+      if (bad_count > 0)
+        {
+          fprintf (stderr, "%s: rejected screens: %d\n", blurb(), bad_count);
+          for (i = 0; i < count; i++)
+            {
+              monitor *m = monitors[i];
+              monitor *e = monitors[m->enemy];
+              if (m->sanity == S_SANE) continue;
+              fprintf (stderr, "%s:  %3d/%d: %dx%d+%d+%d",
+                       blurb(), m->id, screen_number (m->screen),
+                       m->width, m->height, m->x, m->y);
+              if (m->desc && *m->desc) fprintf (stderr, " (%s)", m->desc);
+              fprintf (stderr, " -- ");
+              switch (m->sanity)
+                {
+                case S_SANE: abort(); break;
+                case S_ENCLOSED:
+                  fprintf (stderr, "enclosed by %d (%dx%d+%d+%d)\n",
+                           e->id, e->width, e->height, e->x, e->y);
+                  break;
+                case S_DUPLICATE:
+                  fprintf (stderr, "duplicate of %d\n", e->id);
+                  break;
+                case S_OVERLAP:
+                  fprintf (stderr, "overlaps %d (%dx%d+%d+%d)\n",
+                           e->id, e->width, e->height, e->x, e->y);
+                  break;
+                case S_OFFSCREEN:
+                  fprintf (stderr, "off screen (%dx%d)\n",
+                           WidthOfScreen (e->screen), 
+                           HeightOfScreen (e->screen));
+                  break;
+                case S_DISABLED:
+                  fprintf (stderr, "output disabled\n");
+                  break;
+                }
+            }
+        }
+    }
+}
+
+
+/* Synchronize the contents of si->ssi to the current state of the monitors.
+   Doesn't change anything if nothing has changed; otherwise, alters and
+   reuses existing saver_screen_info structs as much as possible.
+   Returns True if anything changed.
+ */
+Bool
+update_screen_layout (saver_info *si)
+{
+  monitor **monitors = scan_monitors (si);
+  int count = 0;
+  int good_count = 0;
+  int i, j;
+  int seen_screens[100] = { 0, };
+
+  if (! layouts_differ_p (monitors, si->monitor_layout))
+    {
+      free_monitors (monitors);
+      return False;
+    }
+
+  free_monitors (si->monitor_layout);
+  si->monitor_layout = monitors;
+  check_monitor_sanity (si->monitor_layout);
+
+  while (monitors[count])
+    {
+      if (monitors[count]->sanity == S_SANE)
+        good_count++;
+      count++;
+    }
+
+  if (si->ssi_count == 0)
+    {
+      si->ssi_count = 10;
+      si->screens = (saver_screen_info *)
+        calloc (sizeof(*si->screens), si->ssi_count);
+    }
+
+  if (si->ssi_count <= good_count)
+    {
+      si->ssi_count = good_count + 10;
+      si->screens = (saver_screen_info *)
+        realloc (si->screens, sizeof(*si->screens) * si->ssi_count);
+      memset (si->screens + si->nscreens, 0, 
+              sizeof(*si->screens) * (si->ssi_count - si->nscreens));
+    }
+
+  if (! si->screens) abort();
+
+  si->nscreens = good_count;
+
+  /* Regenerate the list of GL visuals as needed. */
+  if (si->best_gl_visuals)
+    free (si->best_gl_visuals);
+  si->best_gl_visuals = 0;
+
+  for (i = 0, j = 0; i < count; i++)
+    {
+      monitor *m = monitors[i];
+      saver_screen_info *ssi = &si->screens[j];
+      Screen *old_screen = ssi->screen;
+      int sn;
+      if (monitors[i]->sanity != S_SANE) continue;
+
+      ssi->global = si;
+      ssi->number = j;
+
+      sn = screen_number (m->screen);
+      ssi->screen = m->screen;
+      ssi->real_screen_number = sn;
+      ssi->real_screen_p = (seen_screens[sn] == 0);
+      seen_screens[sn]++;
+
+      ssi->default_visual =
+       get_visual_resource (ssi->screen, "visualID", "VisualID", False);
+      ssi->current_visual = ssi->default_visual;
+      ssi->current_depth = visual_depth (ssi->screen, ssi->current_visual);
+
+      /* If the screen changed (or if this is the first time) we need
+         a new toplevel shell for this screen's depth.
+       */
+      if (ssi->screen != old_screen)
+        initialize_screen_root_widget (ssi);
+
+      ssi->poll_mouse_last_root_x = -1;
+      ssi->poll_mouse_last_root_y = -1;
+
+      ssi->x      = m->x;
+      ssi->y      = m->y;
+      ssi->width  = m->width;
+      ssi->height = m->height;
+
+# ifndef DEBUG_MULTISCREEN
+      {
+        saver_preferences *p = &si->prefs;
+        if (p->debug_p
+#  ifdef QUAD_MODE
+            && !p->quad_p
+#  endif
+            )
+          ssi->width /= 2;
+      }
+# endif
+
+      j++;
+    }
+
+  si->default_screen = &si->screens[0];
+  return True;
+}
index 56f66daf5c69f38c62203aab1f4657b299f29153..491ebe80c2f1b355e2f83407750225953087c2ef 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1991-2006 Jamie Zawinski <jwz@netscape.com>
+/* xscreensaver, Copyright (c) 1991-2008 Jamie Zawinski <jwz@netscape.com>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -170,6 +170,10 @@ make_splash_dialog (saver_info *si)
     return;
 
   ssi = &si->screens[mouse_screen (si)];
+
+  if (!ssi || !ssi->screen)
+    return;    /* WTF?  Trying to splash while no screens connected? */
+
   cmap = DefaultColormapOfScreen (ssi->screen);
 
   sp = (splash_dialog_data *) calloc (1, sizeof(*sp));
@@ -376,7 +380,7 @@ make_splash_dialog (saver_info *si)
   attrs.event_mask = (ExposureMask | ButtonPressMask | ButtonReleaseMask);
 
   {
-    int sx, sy, w, h;
+    int sx = 0, sy = 0, w, h;
     int mouse_x = 0, mouse_y = 0;
 
     {
@@ -393,7 +397,10 @@ make_splash_dialog (saver_info *si)
         }
     }
 
-    get_screen_viewport (ssi, &sx, &sy, &w, &h, mouse_x, mouse_y, False);
+    x = ssi->x;
+    y = ssi->y;
+    w = ssi->width;
+    h = ssi->height;
     if (si->prefs.debug_p) w /= 2;
     x = sx + (((w + sp->width)  / 2) - sp->width);
     y = sy + (((h + sp->height) / 2) - sp->height);
index 6246dd3a8e554fd8caa0e8486599283a571473a0..68e752132e15c201d691e2180002cbe71bdc3b55 100644 (file)
@@ -1,5 +1,5 @@
 /* stderr.c --- capturing stdout/stderr output onto the screensaver window.
- * xscreensaver, Copyright (c) 1991-2006 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1991-2008 Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -472,6 +472,47 @@ initialize_stderr (saver_info *si)
 }
 
 
+/* If the "-log file" command-line option has been specified,
+   open the file for append, and redirect stdout/stderr there.
+   This is called very early, before initialize_stderr().
+ */
+void
+stderr_log_file (saver_info *si)
+{
+  int stdout_fd = 1;
+  int stderr_fd = 2;
+  const char *filename = get_string_resource (si->dpy, "logFile", "LogFile");
+  int fd;
+
+  if (!filename || !*filename) return;
+
+  fd = open (filename, O_WRONLY | O_APPEND | O_CREAT, 0666);
+
+  if (fd < 0)
+    {
+      char buf[255];
+    FAIL:
+      sprintf (buf, "%.100s: %.100s", blurb(), filename);
+      perror (buf);
+      fflush (stderr);
+      fflush (stdout);
+      exit (1);
+    }
+
+  fprintf (stderr, "%s: logging to file %s\n", blurb(), filename);
+
+  if (dup2 (fd, stdout_fd) < 0) goto FAIL;
+  if (dup2 (fd, stderr_fd) < 0) goto FAIL;
+
+  fprintf (stderr, "\n\n"
+ "##########################################################################\n"
+           "%s: logging to \"%s\" at %s\n"
+ "##########################################################################\n"
+           "\n",
+           blurb(), filename, timestring());
+}
+
+
 /* If there is anything in the stderr buffer, flush it to the real stderr.
    This does no X operations.  Call this when exiting to make sure any
    last words actually show up.
@@ -487,8 +528,7 @@ shutdown_stderr (saver_info *si)
 
   stderr_callback ((XtPointer) si, &stderr_stdout_read_fd, 0);
 
-  if (stderr_buffer &&
-      stderr_tail &&
+  if (stderr_tail &&
       stderr_buffer < stderr_tail)
     {
       *stderr_tail = 0;
index 88270d6ca0ad448ba55f374d1110faa3fb02ed5c..405a382b8bb6e70c94bd0de2aaee76e009bc1033 100644 (file)
@@ -851,7 +851,7 @@ fork_and_exec (saver_screen_info *ssi, const char *command)
     case 0:
       close (ConnectionNumber (si->dpy));      /* close display fd */
       limit_subproc_memory (p->inferior_memory_limit, p->verbose_p);
-      hack_subproc_environment (ssi);          /* set $DISPLAY */
+      hack_subproc_environment (ssi->screen, ssi->screensaver_window);
 
       if (p->verbose_p)
         fprintf (stderr, "%s: %d: spawning \"%s\" in pid %lu.\n",
@@ -878,14 +878,22 @@ fork_and_exec (saver_screen_info *ssi, const char *command)
 }
 
 
-static void
-spawn_screenhack_1 (saver_screen_info *ssi, Bool first_time_p)
+void
+spawn_screenhack (saver_screen_info *ssi)
 {
   saver_info *si = ssi->global;
   saver_preferences *p = &si->prefs;
-  raise_window (si, first_time_p, True, False);
   XFlush (si->dpy);
 
+  if (!monitor_powered_on_p (si))
+    {
+      if (si->prefs.verbose_p)
+        fprintf (stderr,
+                 "%s: %d: X says monitor has powered down; "
+                 "not launching a hack.\n", blurb(), ssi->number);
+      return;
+    }
+
   if (p->screenhacks_count)
     {
       screenhack *hack;
@@ -1017,55 +1025,28 @@ spawn_screenhack_1 (saver_screen_info *ssi, Bool first_time_p)
          break;
        }
     }
-}
-
-
-void
-spawn_screenhack (saver_info *si, Bool first_time_p)
-{
-  if (monitor_powered_on_p (si))
-    {
-      int i;
-      for (i = 0; i < si->nscreens; i++)
-        {
-          saver_screen_info *ssi = &si->screens[i];
-          spawn_screenhack_1 (ssi, first_time_p);
-        }
-    }
-  else if (si->prefs.verbose_p)
-    fprintf (stderr,
-             "%s: X says monitor has powered down; "
-             "not launching a hack.\n", blurb());
 
-  store_saver_status (si);  /* store current hack numbers */
+  store_saver_status (si);  /* store current hack number */
 }
 
 
 void
-kill_screenhack (saver_info *si)
+kill_screenhack (saver_screen_info *ssi)
 {
-  int i;
-  for (i = 0; i < si->nscreens; i++)
-    {
-      saver_screen_info *ssi = &si->screens[i];
-      if (ssi->pid)
-       kill_job (si, ssi->pid, SIGTERM);
-      ssi->pid = 0;
-    }
+  saver_info *si = ssi->global;
+  if (ssi->pid)
+    kill_job (si, ssi->pid, SIGTERM);
+  ssi->pid = 0;
 }
 
 
 void
-suspend_screenhack (saver_info *si, Bool suspend_p)
+suspend_screenhack (saver_screen_info *ssi, Bool suspend_p)
 {
 #ifdef SIGSTOP /* older VMS doesn't have it... */
-  int i;
-  for (i = 0; i < si->nscreens; i++)
-    {
-      saver_screen_info *ssi = &si->screens[i];
-      if (ssi->pid)
-       kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
-    }
+  saver_info *si = ssi->global;
+  if (ssi->pid)
+    kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
 #endif /* SIGSTOP */
 }
 
@@ -1137,7 +1118,7 @@ hack_environment (saver_info *si)
 
 
 void
-hack_subproc_environment (saver_screen_info *ssi)
+hack_subproc_environment (Screen *screen, Window saver_window)
 {
   /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
      the spawned processes inherit is correct.  First, it must be on the same
@@ -1152,8 +1133,8 @@ hack_subproc_environment (saver_screen_info *ssi)
      us to (eventually) run multiple hacks in Xinerama mode, where each hack
      has the same $DISPLAY but a different piece of glass.
    */
-  saver_info *si = ssi->global;
-  const char *odpy = DisplayString (si->dpy);
+  Display *dpy = DisplayOfScreen (screen);
+  const char *odpy = DisplayString (dpy);
   char *ndpy = (char *) malloc (strlen(odpy) + 20);
   char *nssw = (char *) malloc (40);
   char *s, *c;
@@ -1170,10 +1151,9 @@ hack_subproc_environment (saver_screen_info *ssi)
   while (isdigit(*s)) s++;                     /* skip over dpy number */
   while (*s == '.') s++;                       /* skip over dot */
   if (s[-1] != '.') *s++ = '.';                        /* put on a dot */
-  sprintf(s, "%d", ssi->real_screen_number);   /* put on screen number */
+  sprintf(s, "%d", screen_number (screen));    /* put on screen number */
 
-  sprintf (nssw, "XSCREENSAVER_WINDOW=0x%lX",
-           (unsigned long) ssi->screensaver_window);
+  sprintf (nssw, "XSCREENSAVER_WINDOW=0x%lX", (unsigned long) saver_window);
 
   /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
      any more, right?  It's not Posix, but everyone seems to have it. */
@@ -1194,9 +1174,8 @@ hack_subproc_environment (saver_screen_info *ssi)
 /* GL crap */
 
 Visual *
-get_best_gl_visual (saver_screen_info *ssi)
+get_best_gl_visual (saver_info *si, Screen *screen)
 {
-  saver_info *si = ssi->global;
   pid_t forked;
   int fds [2];
   int in, out;
@@ -1217,6 +1196,11 @@ get_best_gl_visual (saver_screen_info *ssi)
   in = fds [0];
   out = fds [1];
 
+  block_sigchld();   /* This blocks it in the parent and child, to avoid
+                        racing.  It is never unblocked in the child before
+                        the child exits, but that doesn't matter.
+                      */
+
   switch ((int) (forked = fork ()))
     {
     case -1:
@@ -1237,7 +1221,7 @@ get_best_gl_visual (saver_screen_info *ssi)
             perror ("could not dup() a new stdout:");
             return 0;
           }
-        hack_subproc_environment (ssi);                /* set $DISPLAY */
+        hack_subproc_environment (screen, 0);  /* set $DISPLAY */
 
         execvp (av[0], av);                    /* shouldn't return. */
 
@@ -1270,6 +1254,8 @@ get_best_gl_visual (saver_screen_info *ssi)
         /* Wait for the child to die. */
         waitpid (-1, &wait_status, 0);
 
+        unblock_sigchld();   /* child is dead and waited, unblock now. */
+
         if (1 == sscanf (buf, "0x%lx %c", &v, &c))
           result = (int) v;
 
@@ -1291,12 +1277,13 @@ get_best_gl_visual (saver_screen_info *ssi)
           }
         else
           {
-            Visual *v = id_to_visual (ssi->screen, result);
+            Visual *v = id_to_visual (screen, result);
             if (si->prefs.verbose_p)
               fprintf (stderr, "%s: %d: %s: GL visual is 0x%X%s.\n",
-                       blurb(), ssi->number,
+                       blurb(), screen_number (screen),
                        av[0], result,
-                       (v == ssi->default_visual ? " (default)" : ""));
+                       (v == DefaultVisualOfScreen (screen)
+                        ? " (default)" : ""));
             return v;
           }
       }
index ac5bf99213873d24138e800e23a45283b9695aad..42e2e280fb83e9a43c5541cc0dac225def5f6ced 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1998-2007 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1998-2008 Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -64,21 +64,6 @@ void shutdown_stderr (saver_info *si) { }
 const char *blurb(void) { return progname; }
 Atom XA_SCREENSAVER, XA_DEMO, XA_PREFS;
 
-void
-get_screen_viewport (saver_screen_info *ssi,
-                     int *x_ret, int *y_ret,
-                     int *w_ret, int *h_ret,
-                     int tx, int ty,
-                     Bool verbose_p)
-{
-  *x_ret = 0;
-  *y_ret = 0;
-  *w_ret = WidthOfScreen (ssi->screen);
-  *h_ret = HeightOfScreen (ssi->screen);
-
-  if (*w_ret > *h_ret * 2) *w_ret /= 2;  /* xinerama kludge */
-}
-
 void
 idle_timer (XtPointer closure, XtIntervalId *id)
 {
@@ -230,8 +215,6 @@ main (int argc, char **argv)
         visual_depth(si->default_screen->screen,
                      si->default_screen->current_visual);
 
-      /* I could call get_screen_viewport(), but it is not worthwhile.
-       * These are used by the save_under pixmap. */
       ssip.width = WidthOfScreen(ssip.screen);
       ssip.height = HeightOfScreen(ssip.screen);
 
@@ -246,6 +229,9 @@ main (int argc, char **argv)
   pw = getpwuid (getuid ());
   si->user = strdup (pw->pw_name);
 
+/*  si->nscreens = 0;
+  si->screens = si->default_screen = 0; */
+
   while (1)
     {
 #ifndef NO_LOCKING
index da86e04d79d78779064c1102ceb9d079496141a2..0d57895ab6a2fece2ff9c75be30fd7fff22a8151 100644 (file)
@@ -1,5 +1,5 @@
 /* test-randr.c --- playing with the Resize And Rotate extension.
- * xscreensaver, Copyright (c) 2004, 2005 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 2004-2008 Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -233,6 +233,43 @@ main (int argc, char **argv)
           fprintf(stderr, "%s:   XRRGetScreenInfo(dpy, %d) ==> NULL\n",
                   blurb(), i);
         }
+
+
+# ifdef HAVE_RANDR_12
+      if (major > 1 || (major == 1 && minor >= 2))
+        {
+          int j;
+          XRRScreenResources *res = 
+            XRRGetScreenResources (dpy, RootWindow (dpy, i));
+          fprintf (stderr, "\n");
+          for (j = 0; j < res->noutput; j++)
+            {
+              int k;
+              XRROutputInfo *rroi = 
+                XRRGetOutputInfo (dpy, res, res->outputs[j]);
+              fprintf (stderr, "%s:   Output %d: %s: %s (%d)\n", blurb(), j,
+                       rroi->name,
+                       (rroi->connection == RR_Disconnected ? "disconnected" :
+                        rroi->connection == RR_UnknownConnection ? "unknown" :
+                        "connected"),
+                       (int) rroi->crtc);
+              for (k = 0; k < rroi->ncrtc; k++)
+                {
+                  XRRCrtcInfo *crtci = XRRGetCrtcInfo (dpy, res, 
+                                                       rroi->crtcs[k]);
+                  fprintf(stderr, "%s:   %c CRTC %d (%d): %dx%d+%d+%d\n", 
+                          blurb(),
+                          (rroi->crtc == rroi->crtcs[k] ? '+' : ' '),
+                          k, (int) rroi->crtcs[k],
+                          crtci->width, crtci->height, crtci->x, crtci->y);
+                  XRRFreeCrtcInfo (crtci);
+                }
+              XRRFreeOutputInfo (rroi);
+              fprintf (stderr, "\n");
+            }
+          XRRFreeScreenResources (res);
+        }
+# endif /* HAVE_RANDR_12 */
     }
 
   if (major > 0)
diff --git a/driver/test-screens.c b/driver/test-screens.c
new file mode 100644 (file)
index 0000000..60bd569
--- /dev/null
@@ -0,0 +1,196 @@
+/* test-screens.c --- some test cases for the "monitor sanity" checks.
+ * xscreensaver, Copyright (c) 2008 Jamie Zawinski <jwz@jwz.org>
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <X11/Xlib.h>
+
+/* This file doesn't need the Xt headers, so stub these types out... */
+#undef XtPointer
+#define XtAppContext void*
+#define XrmDatabase  void*
+#define XtIntervalId void*
+#define XtPointer    void*
+#define Widget       void*
+
+#include "xscreensaver.h"
+#include "visual.h"
+
+#undef WidthOfScreen
+#undef HeightOfScreen
+#define WidthOfScreen(s) 10240
+#define HeightOfScreen(s) 10240
+
+#undef screen_number
+#define screen_number(s) (0)
+
+#include "screens.c"   /* to get at static void check_monitor_sanity() */
+
+char *progname = 0;
+char *progclass = "XScreenSaver";
+
+const char *blurb(void) { return progname; }
+
+Bool safe_XF86VidModeGetViewPort(Display *d, int i, int *x, int *y) { abort(); }
+void initialize_screen_root_widget(saver_screen_info *ssi) { abort(); }
+Visual *get_best_gl_visual (saver_info *si, Screen *sc) { abort(); }
+
+
+static const char *
+failstr (monitor_sanity san)
+{
+  switch (san) {
+  case S_SANE:      return "OK";
+  case S_ENCLOSED:  return "ENC";
+  case S_DUPLICATE: return "DUP";
+  case S_OVERLAP:   return "OVR";
+  case S_OFFSCREEN: return "OFF";
+  case S_DISABLED:  return "DIS";
+  }
+}
+
+
+static void
+test (int testnum, const char *screens, const char *desired)
+{
+  monitor *monitors[100];
+  char result[2048];
+  char *out = result;
+  int i, nscreens = 0;
+  char *token = strtok (strdup(screens), ",");
+  while (token)
+    {
+      monitor *m = calloc (1, sizeof (monitor));
+      char c;
+      m->id = (testnum * 1000) + nscreens;
+      if (4 != sscanf (token, "%dx%d+%d+%d%c", 
+                      &m->width, &m->height, &m->x, &m->y, &c))
+        {
+          fprintf (stderr, "%s: unparsable geometry: %s\n", blurb(), token);
+          exit (1);
+        }
+      monitors[nscreens] = m;
+      nscreens++;
+      token = strtok (0, ",");
+    }
+  monitors[nscreens] = 0;
+
+  check_monitor_sanity (monitors);
+
+  *out = 0;
+  for (i = 0; i < nscreens; i++)
+    {
+      monitor *m = monitors[i];
+      if (out != result) *out++ = ',';
+      if (m->sanity == S_SANE)
+        sprintf (out, "%dx%d+%d+%d", m->width, m->height, m->x, m->y);
+      else
+        strcpy (out, failstr (m->sanity));
+      out += strlen(out);
+    }
+  *out = 0;
+
+  if (!strcmp (result, desired))
+    fprintf (stderr, "%s: test %2d OK\n", blurb(), testnum);
+  else
+    fprintf (stderr, "%s: test %2d FAILED:\n"
+             "%s:   given: %s\n"
+             "%s:  wanted: %s\n"
+             "%s:     got: %s\n",
+             blurb(), testnum,
+             blurb(), screens, 
+             blurb(), desired, 
+             blurb(), result);
+
+# if 0
+  {
+    saver_info SI;
+    SI.monitor_layout = monitors;
+    describe_monitor_layout (&SI);
+  }
+# endif
+
+}
+
+static void
+run_tests(void)
+{
+  int i = 1;
+# define A(a)   test (i++, a, a);
+# define B(a,b) test (i++, a, b)
+
+  A("");
+  A("1024x768+0+0");
+  A("1024x768+0+0,1024x768+1024+0");
+  A("1024x768+0+0,1024x768+0+768");
+  A("1024x768+0+0,1024x768+0+768,1024x768+1024+0");
+
+  B("1024x768+999999+0",
+    "OFF");
+  B("1024x768+-999999+-999999",
+    "OFF");
+  B("1024x768+0+0,1024x768+0+0",
+    "1024x768+0+0,DUP");
+  B("1024x768+0+0,1024x768+0+0,1024x768+0+0",
+    "1024x768+0+0,DUP,DUP");
+  B("1024x768+0+0,1024x768+1024+0,1024x768+0+0",
+    "1024x768+0+0,1024x768+1024+0,DUP");
+  B("1280x1024+0+0,1024x768+0+64,800x600+0+0,640x480+0+0,720x400+0+0",
+    "1280x1024+0+0,ENC,ENC,ENC,ENC");
+  B("1024x768+0+64,1280x1024+0+0,800x600+0+0,640x480+0+0,800x600+0+0,720x400+0+0",
+    "ENC,1280x1024+0+0,ENC,ENC,ENC,ENC");
+  B("1024x768+0+64,1280x1024+0+0,800x600+0+0,640x480+0+0,1280x1024+0+0,720x400+0+0",
+    "ENC,1280x1024+0+0,ENC,ENC,DUP,ENC");
+  B("720x400+0+0,640x480+0+0,800x600+0+0,1024x768+0+64,1280x1024+0+0",
+    "ENC,ENC,ENC,ENC,1280x1024+0+0");
+  B("1280x1024+0+0,800x600+1280+0,800x600+1300+0",
+    "1280x1024+0+0,800x600+1280+0,OVR");
+  B("1280x1024+0+0,800x600+1280+0,800x600+1300+0,1280x1024+0+0,800x600+1280+0",
+    "1280x1024+0+0,800x600+1280+0,OVR,DUP,DUP");
+
+  /*  +-------------+----+  +------+---+   1: 1440x900,  widescreen display
+      |             :    |  | 3+4  :   |   2: 1280x1024, conventional display
+      |     1+2     : 1  |  +......+   |   3: 1024x768,  laptop
+      |             :    |  |  3       |   4: 800x600,   external projector
+      +.............+----+  +----------+
+      |      2      |
+      |             |
+      +-------------+
+   */
+  B("1440x900+0+0,1280x1024+0+0,1024x768+1440+0,800x600+1440+0",
+    "1440x900+0+0,OVR,1024x768+1440+0,ENC");
+  B("800x600+0+0,800x600+0+0,800x600+800+0",
+    "800x600+0+0,DUP,800x600+800+0");
+  B("1600x1200+0+0,1360x768+0+0",
+    "1600x1200+0+0,ENC");
+}
+
+
+int
+main (int argc, char **argv)
+{
+  char *s;
+  progname = argv[0];
+  s = strrchr(progname, '/');
+  if (s) progname = s+1;
+  if (argc != 1)
+    {
+      fprintf (stderr, "usage: %s\n", argv[0]);
+      exit (1);
+    }
+
+  run_tests();
+
+  exit (0);
+}
index c7434925286b02e2d13c8ba04e0cb689457af9c2..584a6d0d49f8f621df814661a9ad8fe571b1e15b 100644 (file)
@@ -264,14 +264,18 @@ cycle_timer (XtPointer closure, XtIntervalId *id)
     }
   else
     {
+      int i;
       maybe_reload_init_file (si);
-      kill_screenhack (si);
+      for (i = 0; i < si->nscreens; i++)
+        kill_screenhack (&si->screens[i]);
+
+      raise_window (si, True, True, False);
 
       if (!si->throttled_p)
-        spawn_screenhack (si, False);
+        for (i = 0; i < si->nscreens; i++)
+          spawn_screenhack (&si->screens[i]);
       else
         {
-          raise_window (si, True, True, False);
           if (p->verbose_p)
             fprintf (stderr, "%s: not launching new hack (throttled.)\n",
                      blurb());
@@ -1010,28 +1014,17 @@ sleep_until_idle (saver_info *si, Bool until_idle_p)
         if (event.type == (si->randr_event_number + RRScreenChangeNotify))
           {
             /* The Resize and Rotate extension sends an event when the
-               size, rotation, or refresh rate of the screen has changed. */
-
+               size, rotation, or refresh rate of any screen has changed.
+             */
             XRRScreenChangeNotifyEvent *xrr_event =
               (XRRScreenChangeNotifyEvent *) &event;
-            /* XRRRootToScreen is in Xrandr.h 1.4, 2001/06/07 */
-            int screen = XRRRootToScreen (si->dpy, xrr_event->window);
 
             if (p->verbose_p)
               {
-                if (si->screens[screen].width  == xrr_event->width &&
-                    si->screens[screen].height == xrr_event->height)
-                  fprintf (stderr,
-                          "%s: %d: no-op screen size change event (%dx%d)\n",
-                           blurb(), screen,
-                           xrr_event->width, xrr_event->height);
-                else
-                  fprintf (stderr,
-                       "%s: %d: screen size changed from %dx%d to %dx%d\n",
-                           blurb(), screen,
-                           si->screens[screen].width,
-                           si->screens[screen].height,
-                           xrr_event->width, xrr_event->height);
+                /* XRRRootToScreen is in Xrandr.h 1.4, 2001/06/07 */
+                int screen = XRRRootToScreen (si->dpy, xrr_event->window);
+                fprintf (stderr, "%s: %d: screen change event received\n",
+                         blurb(), screen);
               }
 
 # ifdef RRScreenChangeNotifyMask
@@ -1040,7 +1033,15 @@ sleep_until_idle (saver_info *si, Bool until_idle_p)
 # endif /* RRScreenChangeNotifyMask */
 
             /* Resize the existing xscreensaver windows and cached ssi data. */
-            resize_screensaver_window (si);
+            if (update_screen_layout (si))
+              {
+                if (p->verbose_p)
+                  {
+                    fprintf (stderr, "%s: new layout:\n", blurb());
+                    describe_monitor_layout (si);
+                  }
+                resize_screensaver_window (si);
+              }
           }
         else
 #endif /* HAVE_RANDR */
@@ -1401,11 +1402,13 @@ watchdog_timer (XtPointer closure, XtIntervalId *id)
       if (screenhack_running_p (si) &&
           !monitor_powered_on_p (si))
        {
+          int i;
          if (si->prefs.verbose_p)
            fprintf (stderr,
                     "%s: X says monitor has powered down; "
                     "killing running hacks.\n", blurb());
-         kill_screenhack (si);
+          for (i = 0; i < si->nscreens; i++)
+            kill_screenhack (&si->screens[i]);
        }
 
       /* Re-schedule this timer.  The watchdog timer defaults to a bit less
index 48321877254bbb6d8a79f3cae6710e1f69fe54f7..63ac39ec89148552bb4304c7f0981b12072a6a49 100644 (file)
@@ -1,7 +1,4 @@
-/* types.h
- *
- * This file is part of XScreenSaver,
- * Copyright (c) 1993-2004 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1993-2008 Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
  * implied warranty.
  */
 
-#ifndef TYPES_H
-#define TYPES_H
+#ifndef __XSCREENSAVER_TYPES_H__
+#define __XSCREENSAVER_TYPES_H__
 
 typedef struct saver_info saver_info;
 
-/* Unlock states. Old pw_* equivalents in square brackets:
- * ul_read - reading input (or ready to do so) [pw_read]
- * ul_success - auth success, unlock the screen [pw_ok]
- * ul_fail - authentication failed [pw_fail]
- * ul_cancel - user cancelled auth [pw_cancel or pw_null]
- * ul_time - timed out, user took too long [pw_time]
- * ul_finished - user pressed enter on the current prompt, process input
- */
-enum unlock_state { ul_read, ul_success, ul_fail, ul_cancel, ul_time, ul_finished };
+typedef enum {
+  ul_read,             /* reading input or ready to do so */
+  ul_success,          /* auth success, unlock */
+  ul_fail,             /* auth fail */
+  ul_cancel,           /* user cancelled auth (pw_cancel or pw_null) */
+  ul_time,             /* timed out */
+  ul_finished          /* user pressed enter */
+} unlock_state;
 
 typedef struct screenhack screenhack;
 struct screenhack {
@@ -56,6 +52,7 @@ typedef struct saver_preferences saver_preferences;
 typedef struct saver_screen_info saver_screen_info;
 typedef struct passwd_dialog_data passwd_dialog_data;
 typedef struct splash_dialog_data splash_dialog_data;
+typedef struct _monitor monitor;
 
 
 /* This structure holds all the user-specified parameters, read from the
@@ -158,9 +155,11 @@ struct saver_info {
   saver_preferences prefs;
 
   int nscreens;
+  int ssi_count;
   saver_screen_info *screens;
   saver_screen_info *default_screen;   /* ...on which dialogs will appear. */
-
+  monitor **monitor_layout;            /* private to screens.c */
+  Visual **best_gl_visuals;            /* visuals for GL hacks on screen N */
 
   /* =======================================================================
      global connection info
@@ -173,7 +172,6 @@ struct saver_info {
      server extension info
      ======================================================================= */
 
-  Bool xinerama_p;                /* Whether Xinerama is in use.            */
   Bool using_xidle_extension;     /* which extension is being used.         */
   Bool using_mit_saver_extension;  /* Note that `p->use_*' is the *request*, */
   Bool using_sgi_saver_extension;  /* and `si->using_*' is the *reality*.    */
@@ -247,7 +245,7 @@ struct saver_info {
   char *user;                  /* The user whose session is locked. */
   char *cached_passwd;         /* Cached password, used to avoid multiple
                                   prompts for password-only auth mechanisms.*/
-  enum unlock_state unlock_state;
+  unlock_state unlock_state;
 
   auth_conv_cb_t unlock_cb;    /* The function used to prompt for creds. */
   void (*auth_finished_cb) (saver_info *si);
@@ -349,7 +347,6 @@ struct saver_screen_info {
   int current_depth;           /* How deep the visual (and the window) are. */
 
   Visual *default_visual;      /* visual to use when none other specified */
-  Visual *best_gl_visual;      /* visual to use for GL hacks */
 
   Window real_vroot;           /* The original virtual-root window. */
   Window real_vroot_value;     /* What was in the __SWM_VROOT property. */
@@ -407,4 +404,4 @@ struct saver_screen_info {
 };
 
 
-#endif
+#endif /* __XSCREENSAVER_TYPES_H__ */
index 9dbb5004cfbe5428dabe4486803e038d64c49629..44cce89faca0141b68fabdfd3b6bf2a754cf2210 100644 (file)
@@ -226,6 +226,14 @@ nuke_focus (saver_info *si, int screen_no)
 }
 
 
+static void
+ungrab_keyboard_and_mouse (saver_info *si)
+{
+  ungrab_mouse (si);
+  ungrab_kbd (si);
+}
+
+
 static Bool
 grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor,
                          int screen_no)
@@ -291,18 +299,15 @@ grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor,
    */
 
   if (kstatus != GrabSuccess)  /* Do not blank without a kbd grab.   */
-    return False;
+    {
+      /* If we didn't get both grabs, release the one we did get. */
+      ungrab_keyboard_and_mouse (si);
+      return False;
+    }
 
   return True;                 /* Grab is good, go ahead and blank.  */
 }
 
-static void
-ungrab_keyboard_and_mouse (saver_info *si)
-{
-  ungrab_mouse (si);
-  ungrab_kbd (si);
-}
-
 
 int
 move_mouse_grab (saver_info *si, Window to, Cursor cursor, int to_screen_no)
@@ -393,6 +398,21 @@ ensure_no_screensaver_running (Display *dpy, Screen *screen)
                    (char *) id);
          status = True;
        }
+
+      else if (XGetWindowProperty (dpy, kids[i], XA_WM_COMMAND, 0, 128,
+                                   False, XA_STRING, &type, &format, &nitems,
+                                   &bytesafter, &version)
+               == Success
+               && type != None
+               && !strcmp ((char *) version, "gnome-screensaver"))
+       {
+         fprintf (stderr,
+                 "%s: \"%s\" is already running on display %s (window 0x%x)\n",
+                  blurb(), (char *) version,
+                   DisplayString (dpy), (int) kids [i]);
+         status = True;
+          break;
+       }
     }
 
   if (kids) XFree ((char *) kids);
@@ -445,11 +465,6 @@ remove_vroot_property (Display *dpy, Window win)
 
 static Bool safe_XKillClient (Display *dpy, XID id);
 
-#ifdef HAVE_XF86VMODE
-static Bool safe_XF86VidModeGetViewPort (Display *, int, int *, int *);
-#endif /* HAVE_XF86VMODE */
-
-
 static void
 kill_xsetroot_data_1 (Display *dpy, Window window,
                       Atom prop, const char *atom_name,
@@ -607,7 +622,8 @@ restore_real_vroot_1 (saver_screen_info *ssi)
     fprintf (stderr,
             "%s: restoring __SWM_VROOT property on the real vroot (0x%lx).\n",
             blurb(), (unsigned long) ssi->real_vroot);
-  remove_vroot_property (si->dpy, ssi->screensaver_window);
+  if (ssi->screensaver_window)
+    remove_vroot_property (si->dpy, ssi->screensaver_window);
   if (ssi->real_vroot)
     {
       store_vroot_property (si->dpy, ssi->real_vroot, ssi->real_vroot_value);
@@ -812,8 +828,10 @@ saver_sighup_handler (int sig)
 
   if (si->screen_blanked_p)
     {
+      int i;
+      for (i = 0; i < si->nscreens; i++)
+        kill_screenhack (&si->screens[i]);
       unblank_screen (si);
-      kill_screenhack (si);
       XSync (si->dpy, False);
     }
 
@@ -999,232 +1017,6 @@ store_saver_status (saver_info *si)
 }
 
 
-
-/* Returns the area of the screen which the xscreensaver window should cover.
-   Normally this is the whole screen, but if the X server's root window is
-   actually larger than the monitor's displayable area, then we want to
-   operate in the currently-visible portion of the desktop instead.
- */
-void
-get_screen_viewport (saver_screen_info *ssi,
-                     int *x_ret, int *y_ret,
-                     int *w_ret, int *h_ret,
-                     int target_x, int target_y,
-                     Bool verbose_p)
-{
-  int w = WidthOfScreen (ssi->screen);
-  int h = HeightOfScreen (ssi->screen);
-
-# ifdef HAVE_XF86VMODE
-  saver_info *si = ssi->global;
-  saver_preferences *p = &si->prefs;
-  int event, error;
-  int dot;
-  XF86VidModeModeLine ml;
-  int x, y;
-  Bool xinerama_p = si->xinerama_p;
-
-#  ifndef HAVE_XINERAMA
-  /* Even if we don't have the client-side Xinerama lib, check to see if
-     the server supports Xinerama, so that we know to ignore the VidMode
-     extension -- otherwise a server crash could result.  Yay. */
-  xinerama_p = XQueryExtension (si->dpy, "XINERAMA", &error, &event, &error);
-#  endif /* !HAVE_XINERAMA */
-
-#  ifdef HAVE_XINERAMA
-  if (xinerama_p)
-    {
-      int mouse_p = (target_x != -1 && target_y != -1);
-      int which = -1;
-      int i;
-
-      /* If a mouse position wasn't passed in, assume we're talking about
-         this screen. */
-      if (!mouse_p)
-        {
-          target_x = ssi->x;
-          target_y = ssi->y;
-          which = ssi->number;
-        }
-
-      /* Find the Xinerama rectangle that contains the mouse position. */
-      for (i = 0; i < si->nscreens; i++)
-        {
-          if (which == -1 &&
-              target_x >= si->screens[i].x &&
-              target_y >= si->screens[i].y &&
-              target_x <  si->screens[i].x + si->screens[i].width &&
-              target_y <  si->screens[i].y + si->screens[i].height)
-            which = i;
-        }
-      if (which == -1) which = 0;  /* didn't find it?  Use the first. */
-      *x_ret = si->screens[which].x;
-      *y_ret = si->screens[which].y;
-      *w_ret = si->screens[which].width;
-      *h_ret = si->screens[which].height;
-
-      if (verbose_p)
-        {
-          fprintf (stderr, "%s: %d: xinerama vp: %dx%d+%d+%d",
-                   blurb(), which,
-                   si->screens[which].width, si->screens[which].height,
-                   si->screens[which].x, si->screens[which].y);
-          if (mouse_p)
-            fprintf (stderr, "; mouse at %d,%d", target_x, target_y);
-          fprintf (stderr, ".\n");
-        }
-
-      return;
-    }
-#  endif /* HAVE_XINERAMA */
-
-  if (!xinerama_p &&  /* Xinerama + VidMode = broken. */
-      XF86VidModeQueryExtension (si->dpy, &event, &error) &&
-      safe_XF86VidModeGetViewPort (si->dpy, ssi->number, &x, &y) &&
-      XF86VidModeGetModeLine (si->dpy, ssi->number, &dot, &ml))
-    {
-      char msg[512];
-      *x_ret = x;
-      *y_ret = y;
-      *w_ret = ml.hdisplay;
-      *h_ret = ml.vdisplay;
-
-      if (*x_ret == 0 && *y_ret == 0 && *w_ret == w && *h_ret == h)
-        /* There is no viewport -- the screen does not scroll. */
-        return;
-
-
-      /* Apparently some versions of XFree86 return nonsense here!
-         I've had reports of 1024x768 viewports at -1936862040, -1953705044.
-         So, sanity-check the values and give up if they are out of range.
-       */
-      if (*x_ret <  0 || *x_ret >= w ||
-          *y_ret <  0 || *y_ret >= h ||
-          *w_ret <= 0 || *w_ret >  w ||
-          *h_ret <= 0 || *h_ret >  h)
-        {
-          static int warned_once = 0;
-          if (!warned_once)
-            {
-              fprintf (stderr, "\n"
-                  "%s: X SERVER BUG: %dx%d viewport at %d,%d is impossible.\n"
-                  "%s: The XVidMode server extension is returning nonsense.\n"
-                  "%s: Please report this bug to your X server vendor.\n\n",
-                       blurb(), *w_ret, *h_ret, *x_ret, *y_ret,
-                       blurb(), blurb());
-              warned_once = 1;
-            }
-          *x_ret = 0;
-          *y_ret = 0;
-          *w_ret = w;
-          *h_ret = h;
-          return;
-        }
-
-      sprintf (msg, "%s: %d: vp is %dx%d+%d+%d",
-               blurb(), ssi->number,
-               *w_ret, *h_ret, *x_ret, *y_ret);
-
-
-      if (p->getviewport_full_of_lies_p)
-        {
-          /* XF86VidModeGetViewPort() tends to be full of lies on laptops
-             that have a docking station or external monitor that runs in
-             a different resolution than the laptop's screen:
-
-                 http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=81593
-                 http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=208417
-                 http://bugs.xfree86.org/show_bug.cgi?id=421
-
-             The XFree86 developers have closed the bug. As far as I can
-             tell, their reason for this was, "this is an X server bug,
-             but it's pretty hard to fix. Therefore, we are closing it."
-
-             So, now there's a preference item for those unfortunate users to
-             tell us not to trust a word that XF86VidModeGetViewPort() says.
-           */
-          static int warned_once = 0;
-          if (!warned_once && verbose_p)
-            {
-              warned_once = 1;
-              fprintf (stderr,
-                  "%s: %d: XF86VidModeGetViewPort() says vp is %dx%d+%d+%d;\n"
-                  "%s: %d:     assuming that is a pack of lies;\n"
-                  "%s: %d:     using %dx%d+0+0 instead.\n",
-                       blurb(), ssi->number,
-                       *w_ret, *h_ret, *x_ret, *y_ret,
-                       blurb(), ssi->number,
-                       blurb(), ssi->number, w, h);
-            }
-
-          *x_ret = 0;
-          *y_ret = 0;
-          *w_ret = w;
-          *h_ret = h;
-          return;
-        }
-
-
-      /* Apparently, though the server stores the X position in increments of
-         1 pixel, it will only make changes to the *display* in some other
-         increment.  With XF86_SVGA on a Thinkpad, the display only updates
-         in multiples of 8 pixels when in 8-bit mode, and in multiples of 4
-         pixels in 16-bit mode.  I don't know what it does in 24- and 32-bit
-         mode, because I don't have enough video memory to find out.
-
-         I consider it a bug that XF86VidModeGetViewPort() is telling me the
-         server's *target* scroll position rather than the server's *actual*
-         scroll position.  David Dawes agrees, and says they may fix this in
-         XFree86 4.0, but it's notrivial.
-
-         He also confirms that this behavior is server-dependent, so the
-         actual scroll position cannot be reliably determined by the client.
-         So... that means the only solution is to provide a ``sandbox''
-         around the blackout window -- we make the window be up to N pixels
-         larger than the viewport on both the left and right sides.  That
-         means some part of the outer edges of each hack might not be
-         visible, but screw it.
-
-         I'm going to guess that 16 pixels is enough, and that the Y dimension
-         doesn't have this problem.
-
-         The drawback of doing this, of course, is that some of the screenhacks
-         will still look pretty stupid -- for example, "slidescreen" will cut
-         off the left and right edges of the grid, etc.
-      */
-#  define FUDGE 16
-      if (x > 0 && x < w - ml.hdisplay)  /* not at left edge or right edge */
-        {
-          /* Round X position down to next lower multiple of FUDGE.
-             Increase width by 2*FUDGE in case some server rounds up.
-           */
-          *x_ret = ((x - 1) / FUDGE) * FUDGE;
-          *w_ret += (FUDGE * 2);
-        }
-#  undef FUDGE
-
-      if (*x_ret != x ||
-          *y_ret != y ||
-          *w_ret != ml.hdisplay ||
-          *h_ret != ml.vdisplay)
-        sprintf (msg + strlen(msg), "; fudged to %dx%d+%d+%d",
-                 *w_ret, *h_ret, *x_ret, *y_ret);
-
-      if (verbose_p)
-        fprintf (stderr, "%s.\n", msg);
-
-      return;
-    }
-
-# endif /* HAVE_XF86VMODE */
-
-  *x_ret = 0;
-  *y_ret = 0;
-  *w_ret = w;
-  *h_ret = h;
-}
-
-
 static Bool error_handler_hit_p = False;
 
 static int
@@ -1318,7 +1110,7 @@ safe_XKillClient (Display *dpy, XID id)
 
 
 #ifdef HAVE_XF86VMODE
-static Bool
+Bool
 safe_XF86VidModeGetViewPort (Display *dpy, int screen, int *xP, int *yP)
 {
   Bool result;
@@ -1362,13 +1154,9 @@ initialize_screensaver_window_1 (saver_screen_info *ssi)
   XColor black;
   XSetWindowAttributes attrs;
   unsigned long attrmask;
-  int x, y, width, height;
   static Bool printed_visual_info = False;  /* only print the message once. */
   Window horked_window = 0;
 
-  get_screen_viewport (ssi, &x, &y, &width, &height, -1, -1,
-                       (p->verbose_p && !si->screen_blanked_p));
-
   black.red = black.green = black.blue = 0;
 
   if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
@@ -1421,13 +1209,6 @@ initialize_screensaver_window_1 (saver_screen_info *ssi)
   attrs.backing_pixel = ssi->black_pixel;
   attrs.border_pixel = ssi->black_pixel;
 
-  if (p->debug_p
-# ifdef QUAD_MODE
-      && !p->quad_p
-# endif
-      )
-    width = width / 2;
-
   if (!p->verbose_p || printed_visual_info)
     ;
   else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
@@ -1503,10 +1284,10 @@ initialize_screensaver_window_1 (saver_screen_info *ssi)
     {
       XWindowChanges changes;
       unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
-      changes.x = x;
-      changes.y = y;
-      changes.width = width;
-      changes.height = height;
+      changes.x = ssi->x;
+      changes.y = ssi->y;
+      changes.width = ssi->width;
+      changes.height = ssi->height;
       changes.border_width = 0;
 
       if (! (safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
@@ -1523,10 +1304,9 @@ initialize_screensaver_window_1 (saver_screen_info *ssi)
     {
       ssi->screensaver_window =
        XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen),
-                       x, y, width, height,
+                       ssi->x, ssi->y, ssi->width, ssi->height,
                        0, ssi->current_depth, InputOutput,
                       ssi->current_visual, attrmask, &attrs);
-
       reset_stderr (ssi);
 
       if (horked_window)
@@ -1578,10 +1358,10 @@ initialize_screensaver_window (saver_info *si)
 }
 
 
-/* Called when the RANDR (Resize and Rotate) extension tells us that the
-   size of the screen has changed while the screen was blanked.  If we
-   don't do this, then the screen saver will no longer fully fill the
-   screen, and some of the underlying desktop may be visible.
+/* Called when the RANDR (Resize and Rotate) extension tells us that
+   the size of the screen has changed while the screen was blanked.
+   Call update_screen_layout() first, then call this to synchronize
+   the size of the saver windows to the new sizes of the screens.
  */
 void
 resize_screensaver_window (saver_info *si)
@@ -1589,132 +1369,97 @@ resize_screensaver_window (saver_info *si)
   saver_preferences *p = &si->prefs;
   int i;
 
-  /* First update the size info in the saver_screen_info structs.
-   */
-
-# ifdef HAVE_XINERAMA
-  if (si->xinerama_p)
+  for (i = 0; i < si->nscreens; i++)
     {
-      /* As of XFree86 4.3.0, the RANDR and XINERAMA extensions cannot coexist.
-         However, maybe they will someday, so I'm guessing that the right thing
-         to do in that case will be to re-query the Xinerama rectangles after
-         a RANDR size change is received: presumably, if the resolution of one
-         or more of the monitors has changed, then the Xinerama rectangle
-         corresponding to that monitor will also have been updated.
-       */
-      int nscreens;
-      XineramaScreenInfo *xsi = XineramaQueryScreens (si->dpy, &nscreens);
-
-      if (nscreens != si->nscreens) {
-        /* Apparently some Xinerama implementations let you use a hot-key
-           to change the number of screens in use!  This is, of course,
-           documented nowhere.  Let's try to do something marginally less
-           bad than crashing.
-         */
-        fprintf (stderr, "%s: bad craziness: xinerama screen count changed "
-                 "from %d to %d!\n", blurb(), si->nscreens, nscreens);
-        if (nscreens > si->nscreens)
-          nscreens = si->nscreens;
-      }
+      saver_screen_info *ssi = &si->screens[i];
+      XWindowAttributes xgwa;
 
-      if (!xsi) abort();
-      for (i = 0; i < nscreens; i++)
+      /* Make sure a window exists -- it might not if a monitor was just
+         added for the first time.
+       */
+      if (! ssi->screensaver_window)
         {
-          saver_screen_info *ssi = &si->screens[i];
-          if (p->verbose_p &&
-              (ssi->x      != xsi[i].x_org ||
-               ssi->y      != xsi[i].y_org ||
-               ssi->width  != xsi[i].width ||
-               ssi->height != xsi[i].height))
+          initialize_screensaver_window_1 (ssi);
+          if (p->verbose_p)
             fprintf (stderr,
-                   "%s: %d: resize xinerama from %dx%d+%d+%d to %dx%d+%d+%d\n",
-                     blurb(), i,
-                     ssi->width,   ssi->height,   ssi->x,       ssi->y,
-                     xsi[i].width, xsi[i].height, xsi[i].x_org, xsi[i].y_org);
-
-          ssi->x      = xsi[i].x_org;
-          ssi->y      = xsi[i].y_org;
-          ssi->width  = xsi[i].width;
-          ssi->height = xsi[i].height;
+                     "%s: %d: newly added window 0x%lx %dx%d+%d+%d\n",
+                     blurb(), i, (unsigned long) ssi->screensaver_window,
+                     ssi->width, ssi->height, ssi->x, ssi->y);
         }
-      XFree (xsi);
-    }
-  else
-# endif /* HAVE_XINERAMA */
-    {
-      /* Not Xinerama -- get the real sizes of the root windows. */
-      for (i = 0; i < si->nscreens; i++)
+
+      /* Make sure the window is the right size -- it might not be if
+         the monitor changed resolution, or if a badly-behaved hack
+         screwed with it.
+       */
+      XGetWindowAttributes (si->dpy, ssi->screensaver_window, &xgwa);
+      if (xgwa.x      != ssi->x ||
+          xgwa.y      != ssi->y ||
+          xgwa.width  != ssi->width ||
+          xgwa.height != ssi->height)
         {
-          saver_screen_info *ssi = &si->screens[i];
-          XWindowAttributes xgwa;
-          XGetWindowAttributes (si->dpy, RootWindowOfScreen (ssi->screen),
-                                &xgwa);
-
-          if (p->verbose_p &&
-              (ssi->x      != xgwa.x ||
-               ssi->y      != xgwa.y ||
-               ssi->width  != xgwa.width ||
-               ssi->height != xgwa.height))
+          XWindowChanges changes;
+          unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
+          changes.x      = ssi->x;
+          changes.y      = ssi->y;
+          changes.width  = ssi->width;
+          changes.height = ssi->height;
+          changes.border_width = 0;
+
+          if (p->verbose_p)
             fprintf (stderr,
-                     "%s: %d: resize screen from %dx%d+%d+%d to %dx%d+%d+%d\n",
-                     blurb(), i,
-                     ssi->width, ssi->height, ssi->x, ssi->y,
-                     xgwa.width, xgwa.height, xgwa.x, xgwa.y);
-
-          ssi->x      = xgwa.x;
-          ssi->y      = xgwa.y;
-          ssi->width  = xgwa.width;
-          ssi->height = xgwa.height;
+                     "%s: %d: resize 0x%lx from %dx%d+%d+%d to %dx%d+%d+%d\n",
+                     blurb(), i, (unsigned long) ssi->screensaver_window,
+                     xgwa.width, xgwa.height, xgwa.x, xgwa.y,
+                     ssi->width, ssi->height, ssi->x, ssi->y);
+
+          if (! safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
+                                       changesmask, &changes))
+            fprintf (stderr, "%s: %d: someone horked our saver window"
+                     " (0x%lx)!  Unable to resize it!\n",
+                     blurb(), i, (unsigned long) ssi->screensaver_window);
+        }
+
+      /* Now (if blanked) make sure that it's mapped and running a hack --
+         it might not be if we just added it.  (We also might be re-using
+         an old window that existed for a previous monitor that was
+         removed and re-added.)
+
+         Note that spawn_screenhack() calls select_visual() which may destroy
+         and re-create the window via initialize_screensaver_window_1().
+       */
+      if (si->screen_blanked_p)
+        {
+          if (ssi->cmap)
+            XInstallColormap (si->dpy, ssi->cmap);
+          XMapRaised (si->dpy, ssi->screensaver_window);
+          if (! ssi->pid)
+            spawn_screenhack (ssi);
+
+          /* Make sure the act of adding a screen doesn't present as 
+             pointer motion (and thus cause an unblank). */
+          {
+            Window root, child;
+            int x, y;
+            unsigned int mask;
+            XQueryPointer (si->dpy, ssi->screensaver_window, &root, &child,
+                           &ssi->poll_mouse_last_root_x,
+                           &ssi->poll_mouse_last_root_y,
+                           &x, &y, &mask);
+          }
         }
     }
 
-  /* Next, ensure that the screensaver windows are the right size, taking
-     into account both the new size of the screen in question's root window,
-     and any viewport within that.
+  /* Kill off any savers running on no-longer-extant monitors.
    */
-
-  for (i = 0; i < si->nscreens; i++)
+  for (; i < si->ssi_count; i++)
     {
       saver_screen_info *ssi = &si->screens[i];
-      XWindowAttributes xgwa;
-      XWindowChanges changes;
-      int x, y, width, height;
-      unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
-
-      XGetWindowAttributes (si->dpy, ssi->screensaver_window, &xgwa);
-      get_screen_viewport (ssi, &x, &y, &width, &height, -1, -1,
-                           (p->verbose_p && !si->screen_blanked_p));
-      if (xgwa.x == x &&
-          xgwa.y == y &&
-          xgwa.width  == width &&
-          xgwa.height == height)
-        continue;  /* no change! */
-
-      changes.x = x;
-      changes.y = y;
-      changes.width  = width;
-      changes.height = height;
-      changes.border_width = 0;
-
-      if (p->debug_p
-# ifdef QUAD_MODE
-          && !p->quad_p
-# endif
-          ) 
-        changes.width = changes.width / 2;
-
-      if (p->verbose_p)
-        fprintf (stderr,
-                 "%s: %d: resize 0x%lx from %dx%d+%d+%d to %dx%d+%d+%d\n",
-                 blurb(), i, (unsigned long) ssi->screensaver_window,
-                 xgwa.width, xgwa.height, xgwa.x, xgwa.y,
-                 width, height, x, y);
-      if (! safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
-                                   changesmask, &changes))
+      if (ssi->pid)
+        kill_screenhack (ssi);
+      if (ssi->screensaver_window)
         {
-          fprintf (stderr,
-    "%s: %d: someone horked our saver window (0x%lx)!  Unable to resize it!\n",
-                   blurb(), i, (unsigned long) ssi->screensaver_window);
+          XUnmapWindow (si->dpy, ssi->screensaver_window);
+          restore_real_vroot_1 (ssi);
         }
     }
 }
@@ -2094,10 +1839,30 @@ maybe_transfer_grabs (saver_screen_info *ssi,
 }
 
 
+static Visual *
+get_screen_gl_visual (saver_info *si, int real_screen_number)
+{
+  int i;
+  int nscreens = ScreenCount (si->dpy);
+
+  if (! si->best_gl_visuals)
+    si->best_gl_visuals = (Visual **) 
+      calloc (nscreens + 1, sizeof (*si->best_gl_visuals));
+
+  for (i = 0; i < nscreens; i++)
+    if (! si->best_gl_visuals[i])
+      si->best_gl_visuals[i] = 
+        get_best_gl_visual (si, ScreenOfDisplay (si->dpy, i));
+
+  if (real_screen_number < 0 || real_screen_number >= nscreens) abort();
+  return si->best_gl_visuals[real_screen_number];
+}
+
 
 Bool
 select_visual (saver_screen_info *ssi, const char *visual_name)
 {
+  XWindowAttributes xgwa;
   saver_info *si = ssi->global;
   saver_preferences *p = &si->prefs;
   Bool install_cmap_p = p->install_cmap_p;
@@ -2112,6 +1877,17 @@ select_visual (saver_screen_info *ssi, const char *visual_name)
    */
   Bool always_recreate_window_p = True;
 
+  get_screen_gl_visual (si, 0);   /* let's probe all the GL visuals early */
+
+  /* We make sure the existing window is actually on ssi->screen before
+     trying to use it, in case things moved around radically when monitors
+     were added or deleted.  If we don't do this we could get a BadMatch
+     even though the depths match.  I think.
+   */
+  memset (&xgwa, 0, sizeof(xgwa));
+  if (ssi->screensaver_window)
+    XGetWindowAttributes (si->dpy, ssi->screensaver_window, &xgwa);
+
   if (visual_name && *visual_name)
     {
       if (!strcmp(visual_name, "default-i") ||
@@ -2133,7 +1909,7 @@ select_visual (saver_screen_info *ssi, const char *visual_name)
                !strcmp(visual_name, "Gl") ||
                !strcmp(visual_name, "GL"))
         {
-          new_v = ssi->best_gl_visual;
+          new_v = get_screen_gl_visual (si, ssi->real_screen_number);
           if (!new_v && p->verbose_p)
             fprintf (stderr, "%s: no GL visuals.\n", progname);
         }
@@ -2154,13 +1930,16 @@ select_visual (saver_screen_info *ssi, const char *visual_name)
 
   ssi->install_cmap_p = install_cmap_p;
 
-  if (new_v &&
-      (always_recreate_window_p ||
-       (ssi->current_visual != new_v) ||
-       (install_cmap_p != was_installed_p)))
+  if ((ssi->screen != xgwa.screen) ||
+      (new_v &&
+       (always_recreate_window_p ||
+        (ssi->current_visual != new_v) ||
+        (install_cmap_p != was_installed_p))))
     {
       Colormap old_c = ssi->cmap;
       Window old_w = ssi->screensaver_window;
+      if (! new_v) 
+        new_v = ssi->current_visual;
 
       if (p->verbose_p)
        {
index de507a0a57fcb4683c04ce336df652e47b25f90e..5ec74417b4dee28b1432f2755cdb23bad11a378e 100644 (file)
@@ -108,9 +108,9 @@ usage: %s -<option>\n\
                 (Note that one must *never* kill xscreensaver with -9!)\n\
 \n\
   -restart      Causes the screensaver process to exit and then restart with\n\
-                the same command line arguments as last time.  Do this after\n\
-                you've changed your X resource settings, to cause\n\
-                xscreensaver to notice the changes.\n\
+                the same command line arguments as last time.  You shouldn't\n\
+                really need to do this, since xscreensaver notices when the\n\
+                .xscreensaver file has changed and re-reads it as needed.\n\
 \n\
   -lock         Tells the running xscreensaver process to lock the screen\n\
                 immediately.  This is like -activate, but forces locking as\n\
index 1d0c24128d99fca1508753749fa5aba0bbc35cb2..ff5d0bd7887bf5a150ee4944dd04d99c15420736 100644 (file)
@@ -152,18 +152,9 @@ un-blanked.)
 .TP 8
 .B \-restart
 Causes the screensaver process to exit and then restart with the same command
-line arguments as last time.  Do this after you've changed the resource
-database, to cause xscreensaver to notice the changes.
-
-.B Warning:
-if you have a \fI.xscreensaver\fP file, this might not do what you 
-expect.  You're probably better off killing the existing 
-xscreensaver (with \fIxscreensaver\-command -exit\fP) and then
-launching it again.
-
-The important point is, you need to make sure that the xscreensaver 
-process is running as you.  If it's not, it won't be reading the 
-right \fI.xscreensaver\fP file.
+line arguments as last time.  You shouldn't really need to do this,
+since xscreensaver notices when the \fI.xscreensaver\fP file has
+changed and re-reads it as needed.
 .TP 8
 .B \-watch
 Prints a line each time the screensaver changes state: when the screen
index 92b28625c1a6337be6cdfbc178832116194e5861..2fb1ecd31727f6d4e2f191f0917c54770d9a17c6 100644 (file)
@@ -46,6 +46,8 @@
  *   via the $XSCREENSAVER_WINDOW environment variable -- this trick requires
  *   a recent (Aug 2003) revision of vroot.h.
  *
+ *   (See comments in screens.c for more details about Xinerama/RANDR stuff.)
+ *
  *   While we are waiting for user activity, 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
@@ -205,6 +207,7 @@ static XrmOptionDescRec options [] = {
 
   /* useful for debugging */
   { "-no-capture-stderr",  ".captureStderr",   XrmoptionNoArg, "off" },
+  { "-log",               ".logFile",          XrmoptionSepArg, 0 },
 };
 
 #ifdef __GNUC__
@@ -263,7 +266,7 @@ timestring (void)
   return str;
 }
 
-static Bool blurb_timestamp_p = False;   /* kludge */
+static Bool blurb_timestamp_p = True;   /* kludge */
 
 const char *
 blurb (void)
@@ -334,27 +337,30 @@ saver_ehandler (Display *dpy, XErrorEvent *error)
        }
       else
        {
+#ifdef __GNUC__
+  __extension__   /* don't warn about "string length is greater than the
+                     length ISO C89 compilers are required to support". */
+#endif
           fprintf (real_stderr,
-                   "#######################################"
-                   "#######################################\n\n");
-          fprintf (real_stderr,
+   "#######################################################################\n"
+   "\n"
    "    If at all possible, please re-run xscreensaver with the command\n"
-   "    line arguments `-sync -verbose -no-capture', and reproduce this\n"
+   "    line arguments `-sync -verbose -log log.txt', and reproduce this\n"
    "    bug.  That will cause xscreensaver to dump a `core' file to the\n"
    "    current directory.  Please include the stack trace from that core\n"
-   "    file in your bug report.  *DO NOT* mail the core file itself!\n"
-   "    That won't work.\n");
-          fprintf (real_stderr,
+   "    file in your bug report.  *DO NOT* mail the core file itself!  That\n"
+   "    won't work.  A \"log.txt\" file will also be written.  Please *do*\n"
+   "    include the complete \"log.txt\" file with your bug report.\n"
    "\n"
    "    http://www.jwz.org/xscreensaver/bugs.html explains how to create\n"
    "    the most useful bug reports, and how to examine core files.\n"
    "\n"
    "    The more information you can provide, the better.  But please\n"
    "    report this bug, regardless!\n"
+   "\n"
+   "#######################################################################\n"
+   "\n"
    "\n");
-          fprintf (real_stderr,
-                   "#######################################"
-                   "#######################################\n\n");
 
          saver_exit (si, -1, 0);
        }
@@ -658,13 +664,6 @@ process_command_line (saver_info *si, int *argc, char **argv)
     with `xscreensaver-demo' or `xscreensaver-command'.\n\
 .   See the man pages for details, or check the web page:\n\
     http://www.jwz.org/xscreensaver/\n\n");
-
-             /* Since version 1.21 renamed the "-lock" option to "-lock-mode",
-                suggest that explicitly. */
-             if (!strcmp (s, "-lock"))
-               fprintf (stderr, "\
-    Or perhaps you meant either the \"-lock-mode\" or the\n\
-    \"-lock-timeout <minutes>\" options to xscreensaver?\n\n");
            }
 
          exit (1);
@@ -755,110 +754,24 @@ print_lock_failure_banner (saver_info *si)
 }
 
 
-#ifdef HAVE_XINERAMA
-
-static Bool
-screens_overlap_p (XineramaScreenInfo *a, XineramaScreenInfo *b)
-{
-  /* Two rectangles overlap if the max of the tops is less than the
-     min of the bottoms and the max of the lefts is less than the min
-     of the rights.
-   */
-# undef MAX
-# undef MIN
-# define MAX(A,B) ((A)>(B)?(A):(B))
-# define MIN(A,B) ((A)<(B)?(A):(B))
-
-  int maxleft  = MAX(a->x_org, b->x_org);
-  int maxtop   = MAX(a->y_org, b->y_org);
-  int minright = MIN(a->x_org + a->width  - 1, b->x_org + b->width);
-  int minbot   = MIN(a->y_org + a->height - 1, b->y_org + b->height);
-  return (maxtop < minbot && maxleft < minright);
-}
-
-
-/* Go through the list of Xinerama screen descriptions, and mark the
-   ones that appear to be insane, so that we don't use them.
- */
-static void
-check_xinerama_sanity (int count, Bool verbose_p, XineramaScreenInfo *xsi)
+/* called from screens.c so that all the Xt crud is here. */
+void
+initialize_screen_root_widget (saver_screen_info *ssi)
 {
-  static Bool printed_p = False;
-  int i, j;
-  char err[1024];
-  *err = 0;
-
-# define X1 xsi[i].x_org
-# define X2 xsi[j].x_org
-# define Y1 xsi[i].y_org
-# define Y2 xsi[j].y_org
-# define W1 xsi[i].width
-# define W2 xsi[j].width
-# define H1 xsi[i].height
-# define H2 xsi[j].height
-
-# define WHINE() do {                                                        \
-    if (verbose_p) {                                                         \
-      if (! printed_p) {                                                     \
-        fprintf (stderr, "%s: compensating for Xinerama braindamage:\n",     \
-                 blurb());                                                   \
-        printed_p = True;                                                    \
-      }                                                                      \
-      fprintf (stderr, "%s:   %d: %s\n", blurb(), xsi[i].screen_number,err); \
-    }                                                                        \
-    xsi[i].screen_number = -1;                                               \
-  } while(0)
-
-  /* If a screen is enclosed by any other screen, that's insane.
-   */
-  for (i = 0; i < count; i++)
-    for (j = 0; j < count; j++)
-      if (i != j &&
-          xsi[i].screen_number >= 0 &&
-          xsi[j].screen_number >= 0 &&
-          X1 >= X2 && Y1 >= Y2 && (X1+W1) <= (X2+W2) && (X1+H1) <= (X2+H2))
-        {
-          sprintf (err, "%dx%d+%d+%d enclosed by %dx%d+%d+%d",
-                   W1, H1, X1, Y1,
-                   W2, H2, X2, Y2);
-          WHINE();
-          continue;
-        }
-
-  /* After checking for enclosure, check for other lossage against earlier
-     screens.  We do enclosure first so that we make sure to pick the
-     larger one.
-   */
-  for (i = 0; i < count; i++)
-    for (j = 0; j < i; j++)
-      {
-        if (xsi[i].screen_number < 0) continue; /* already marked */
-
-        *err = 0;
-        if (X1 == X2 && Y1 == Y2 && W1 == W2 && H1 == H2)
-          sprintf (err, "%dx%d+%d+%d duplicated", W1, H1, X1, Y1);
-
-        else if (screens_overlap_p (&xsi[i], &xsi[j]))
-          sprintf (err, "%dx%d+%d+%d overlaps %dx%d+%d+%d",
-                   W1, H1, X1, Y1,
-                   W2, H2, X2, Y2);
-
-        if (*err) WHINE();
-      }
-
-# undef X1
-# undef X2
-# undef Y1
-# undef Y2
-# undef W1
-# undef W2
-# undef H1
-# undef H2
+  saver_info *si = ssi->global;
+  if (ssi->toplevel_shell)
+    XtDestroyWidget (ssi->toplevel_shell);
+  ssi->toplevel_shell =
+    XtVaAppCreateShell (progname, progclass, 
+                        applicationShellWidgetClass,
+                        si->dpy,
+                        XtNscreen, ssi->screen,
+                        XtNvisual, ssi->current_visual,
+                        XtNdepth,  visual_depth (ssi->screen,
+                                                 ssi->current_visual),
+                        NULL);
 }
 
-#endif /* HAVE_XINERAMA */
-
-
 
 /* Examine all of the display's screens, and populate the `saver_screen_info'
    structures.  Make sure this is called after hack_environment() sets $PATH.
@@ -866,182 +779,28 @@ check_xinerama_sanity (int count, Bool verbose_p, XineramaScreenInfo *xsi)
 static void
 initialize_per_screen_info (saver_info *si, Widget toplevel_shell)
 {
-  Bool found_any_writable_cells = False;
   int i;
 
-# ifdef HAVE_XINERAMA
-  {
-    int event, error;
-    si->xinerama_p = (XineramaQueryExtension (si->dpy, &event, &error) &&
-                      XineramaIsActive (si->dpy));
-  }
-
-  if (si->xinerama_p && ScreenCount (si->dpy) != 1)
-    {
-      si->xinerama_p = False;
-      if (si->prefs.verbose_p)
-       fprintf (stderr,
-                 "%s: Xinerama AND %d screens?  Disabling Xinerama support!\n",
-                 blurb(), ScreenCount(si->dpy));
-    }
-
-  if (si->xinerama_p)
-    {
-      int nscreens = 0;
-      XineramaScreenInfo *xsi = XineramaQueryScreens (si->dpy, &nscreens);
-      if (!xsi)
-        si->xinerama_p = False;
-      else
-        {
-          int j = 0;
-          si->screens = (saver_screen_info *)
-            calloc(sizeof(saver_screen_info), nscreens);
-          check_xinerama_sanity (nscreens, si->prefs.verbose_p, xsi);
-          for (i = 0; i < nscreens; i++)
-            {
-              if (xsi[i].screen_number < 0)  /* deemed insane */
-                continue;
-              si->screens[j].x      = xsi[i].x_org;
-              si->screens[j].y      = xsi[i].y_org;
-              si->screens[j].width  = xsi[i].width;
-              si->screens[j].height = xsi[i].height;
-              j++;
-            }
-          si->nscreens = j;
-          XFree (xsi);
-        }
-      si->default_screen = &si->screens[0];
-      si->default_screen->real_screen_p = True;
-    }
-# endif /* !HAVE_XINERAMA */
-
-  if (!si->xinerama_p)
-    {
-      si->nscreens = ScreenCount(si->dpy);
-      si->screens = (saver_screen_info *)
-        calloc(sizeof(saver_screen_info), si->nscreens);
-      si->default_screen = &si->screens[DefaultScreen(si->dpy)];
-
-      for (i = 0; i < si->nscreens; i++)
-        {
-          saver_screen_info *ssi = &si->screens[i];
-          ssi->width  = DisplayWidth  (si->dpy, i);
-          ssi->height = DisplayHeight (si->dpy, i);
-          ssi->real_screen_p = True;
-          ssi->real_screen_number = i;
-        }
-    }
+  update_screen_layout (si);
 
-
-# ifdef QUAD_MODE
-  /* In "quad mode", we use the Xinerama code to pretend that there are 4
-     screens for every physical screen, and run four times as many hacks...
-   */
-  if (si->prefs.quad_p)
-    {
-      int ns2 = si->nscreens * 4;
-      saver_screen_info *ssi2 = (saver_screen_info *)
-        calloc(sizeof(saver_screen_info), ns2);
-
-      for (i = 0; i < si->nscreens; i++)
-        {
-          saver_screen_info *old = &si->screens[i];
-
-          if (si->prefs.debug_p) old->width = old->width / 2;
-
-          ssi2[i*4  ] = *old;
-          ssi2[i*4+1] = *old;
-          ssi2[i*4+2] = *old;
-          ssi2[i*4+3] = *old;
-
-          ssi2[i*4  ].width  /= 2;
-          ssi2[i*4  ].height /= 2;
-
-          ssi2[i*4+1].x      += ssi2[i*4  ].width;
-          ssi2[i*4+1].width  -= ssi2[i*4  ].width;
-          ssi2[i*4+1].height /= 2;
-
-          ssi2[i*4+2].y      += ssi2[i*4  ].height;
-          ssi2[i*4+2].width  /= 2;
-          ssi2[i*4+2].height -= ssi2[i*4  ].height;
-
-          ssi2[i*4+3].x      += ssi2[i*4+2].width;
-          ssi2[i*4+3].y      += ssi2[i*4+2].height;
-          ssi2[i*4+3].width  -= ssi2[i*4+2].width;
-          ssi2[i*4+3].height -= ssi2[i*4+2].height;
-
-          ssi2[i*4+1].real_screen_p = False;
-          ssi2[i*4+2].real_screen_p = False;
-          ssi2[i*4+3].real_screen_p = False;
-        }
-
-      si->nscreens = ns2;
-      free (si->screens);
-      si->screens = ssi2;
-      si->default_screen = &si->screens[DefaultScreen(si->dpy) * 4];
-      si->xinerama_p = True;
-    }
-# endif /* QUAD_MODE */
-
-  /* finish initializing the screens.
+  /* Check to see whether fading is ever possible -- if any of the
+     screens on the display has a PseudoColor visual, then fading can
+     work (on at least some screens.)  If no screen has a PseudoColor
+     visual, then don't bother ever trying to fade, because it will
+     just cause a delay without causing any visible effect.
    */
   for (i = 0; i < si->nscreens; i++)
     {
       saver_screen_info *ssi = &si->screens[i];
-      ssi->global = si;
-
-      ssi->number = i;
-      ssi->screen = ScreenOfDisplay (si->dpy, ssi->real_screen_number);
-      ssi->poll_mouse_last_root_x = -1;
-      ssi->poll_mouse_last_root_y = -1;
-
-      if (!si->xinerama_p)
+      if (has_writable_cells (ssi->screen, ssi->current_visual) ||
+          get_visual (ssi->screen, "PseudoColor", True, False) ||
+          get_visual (ssi->screen, "GrayScale", True, False))
         {
-          ssi->width  = WidthOfScreen  (ssi->screen);
-          ssi->height = HeightOfScreen (ssi->screen);
+          si->fading_possible_p = True;
+          break;
         }
-
-      /* Note: we can't use the resource ".visual" because Xt is SO FUCKED. */
-      ssi->default_visual =
-       get_visual_resource (ssi->screen, "visualID", "VisualID", False);
-
-      ssi->current_visual = ssi->default_visual;
-      ssi->current_depth = visual_depth (ssi->screen, ssi->current_visual);
-
-      /* Execute a subprocess to find the GL visual. */
-      ssi->best_gl_visual = get_best_gl_visual (ssi);
-
-      if (ssi == si->default_screen)
-       /* Since this is the default screen, use the one already created. */
-       ssi->toplevel_shell = toplevel_shell;
-      else
-       /* Otherwise, each screen must have its own unmapped root widget. */
-       ssi->toplevel_shell =
-         XtVaAppCreateShell (progname, progclass, applicationShellWidgetClass,
-                             si->dpy,
-                             XtNscreen, ssi->screen,
-                             XtNvisual, ssi->current_visual,
-                             XtNdepth,  visual_depth (ssi->screen,
-                                                      ssi->current_visual),
-                             NULL);
-
-      if (! found_any_writable_cells)
-       {
-         /* Check to see whether fading is ever possible -- if any of the
-            screens on the display has a PseudoColor visual, then fading can
-            work (on at least some screens.)  If no screen has a PseudoColor
-            visual, then don't bother ever trying to fade, because it will
-            just cause a delay without causing any visible effect.
-         */
-         if (has_writable_cells (ssi->screen, ssi->current_visual) ||
-             get_visual (ssi->screen, "PseudoColor", True, False) ||
-             get_visual (ssi->screen, "GrayScale", True, False))
-           found_any_writable_cells = True;
-       }
     }
 
-  si->fading_possible_p = found_any_writable_cells;
-
 #ifdef HAVE_XF86VMODE_GAMMA
   si->fading_possible_p = True;  /* if we can gamma fade, go for it */
 #endif
@@ -1115,15 +874,6 @@ initialize_server_extensions (saver_info *si)
                 blurb());
     }
 
-  /* These are incompatible (or at least, our support for them is...) */
-  if (si->xinerama_p && si->using_mit_saver_extension)
-    {
-      si->using_mit_saver_extension = False;
-      if (p->verbose_p)
-        fprintf (stderr, "%s: Xinerama in use: disabling MIT-SCREEN-SAVER.\n",
-                 blurb());
-    }
-
 #ifdef HAVE_RANDR
   query_randr_extension (si);
 #endif
@@ -1149,6 +899,26 @@ initialize_server_extensions (saver_info *si)
 }
 
 
+#ifdef DEBUG_MULTISCREEN
+static void
+debug_multiscreen_timer (XtPointer closure, XtIntervalId *id)
+{
+  saver_info *si = (saver_info *) closure;
+  saver_preferences *p = &si->prefs;
+  if (update_screen_layout (si))
+    {
+      if (p->verbose_p)
+        {
+          fprintf (stderr, "%s: new layout:\n", blurb());
+          describe_monitor_layout (si);
+        }
+      resize_screensaver_window (si);
+    }
+  XtAppAddTimeOut (si->app, 1000*4, debug_multiscreen_timer, (XtPointer) si);
+}
+#endif /* DEBUG_MULTISCREEN */
+
+
 /* For the case where we aren't using an server extensions, select user events
    on all the existing windows, and launch timers to select events on
    newly-created windows as well.
@@ -1201,6 +971,10 @@ select_events (saver_info *si)
 
   if (p->verbose_p)
     fprintf (stderr, " done.\n");
+
+# ifdef DEBUG_MULTISCREEN
+  if (p->debug_p) debug_multiscreen_timer ((XtPointer) si, 0);
+# endif
 }
 
 
@@ -1247,6 +1021,7 @@ main_loop (saver_info *si)
 {
   saver_preferences *p = &si->prefs;
   Bool ok_to_unblank;
+  int i;
 
   while (1)
     {
@@ -1342,12 +1117,15 @@ main_loop (saver_info *si)
             }
         }
 
-      kill_screenhack (si);
+      for (i = 0; i < si->nscreens; i++)
+        kill_screenhack (&si->screens[i]);
 
-      if (!si->throttled_p)
-        spawn_screenhack (si, True);
-      else if (p->verbose_p)
+      raise_window (si, True, True, False);
+      if (si->throttled_p)
         fprintf (stderr, "%s: not launching hack (throttled.)\n", blurb());
+      else
+        for (i = 0; i < si->nscreens; i++)
+          spawn_screenhack (&si->screens[i]);
 
       /* Don't start the cycle timer in demo mode. */
       if (!si->demoing_p && p->cycle)
@@ -1418,14 +1196,16 @@ main_loop (saver_info *si)
 
             was_locked = True;
            si->dbox_up_p = True;
-           suspend_screenhack (si, True);
+            for (i = 0; i < si->nscreens; i++)
+              suspend_screenhack (&si->screens[i], True);        /* suspend */
            XUndefineCursor (si->dpy, ssi->screensaver_window);
 
            ok_to_unblank = unlock_p (si);
 
            si->dbox_up_p = False;
            XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
-           suspend_screenhack (si, False);     /* resume */
+            for (i = 0; i < si->nscreens; i++)
+              suspend_screenhack (&si->screens[i], False);        /* resume */
 
             if (!ok_to_unblank &&
                 !screenhack_running_p (si))
@@ -1451,7 +1231,8 @@ main_loop (saver_info *si)
                 blurb(), timestring ());
 
       /* Kill before unblanking, to stop drawing as soon as possible. */
-      kill_screenhack (si);
+      for (i = 0; i < si->nscreens; i++)
+        kill_screenhack (&si->screens[i]);
       unblank_screen (si);
 
       set_locked_p (si, False);
@@ -1530,6 +1311,7 @@ main (int argc, char **argv)
 
   shell = connect_to_server (si, &argc, argv);
   process_command_line (si, &argc, argv);
+  stderr_log_file (si);
   print_banner (si);
 
   load_init_file(si->dpy, p); /* must be before initialize_per_screen_info() */
@@ -1951,8 +1733,10 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p)
                                  "exiting.");
          if (! until_idle_p)
            {
+              int i;
+              for (i = 0; i < si->nscreens; i++)
+                kill_screenhack (&si->screens[i]);
              unblank_screen (si);
-             kill_screenhack (si);
              XSync (si->dpy, False);
            }
          saver_exit (si, 0, 0);
@@ -1974,8 +1758,10 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p)
                                  "restarting.");
          if (! until_idle_p)
            {
+              int i;
+              for (i = 0; i < si->nscreens; i++)
+                kill_screenhack (&si->screens[i]);
              unblank_screen (si);
-             kill_screenhack (si);
              XSync (si->dpy, False);
            }
 
@@ -2254,17 +2040,15 @@ analyze_display (saver_info *si)
 #     else
         False
 #     endif
+   }, { "DRI",                                 "DRI",
+        True
    }, { "Apple-DRI",                            "Apple-DRI (XDarwin)",
         True
    },
   };
 
-  fprintf (stderr, "%s: running on display \"%s\" (%d %sscreen%s).\n",
-           blurb(),
-          DisplayString(si->dpy),
-           si->nscreens,
-           (si->xinerama_p ? "Xinerama " : ""),
-           (si->nscreens == 1 ? "" : "s"));
+  fprintf (stderr, "%s: running on display \"%s\"\n", blurb(), 
+           DisplayString(si->dpy));
   fprintf (stderr, "%s: vendor is %s, %d.\n", blurb(),
           ServerVendor(si->dpy), VendorRelease(si->dpy));
 
@@ -2324,21 +2108,10 @@ analyze_display (saver_info *si)
        }
     }
 
-  if (si->xinerama_p)
-    {
-      fprintf (stderr, "%s: Xinerama layout:\n", blurb());
-      for (i = 0; i < si->nscreens; i++)
-        {
-          saver_screen_info *ssi = &si->screens[i];
-          fprintf (stderr, "%s:   %c %d/%d: %dx%d+%d+%d\n",
-                   blurb(),
-                   (ssi->real_screen_p ? '+' : ' '),
-                   ssi->number, ssi->real_screen_number,
-                   ssi->width, ssi->height, ssi->x, ssi->y);
-        }
-    }
+  describe_monitor_layout (si);
 }
 
+
 Bool
 display_is_on_console_p (saver_info *si)
 {
index 5490e8eaa0ce3aac38c2178a036c0e0f082e5978..6c7e31749d43516483f9637518874ac465b7abf4 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1993-2006 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1993-2008 Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -67,7 +67,10 @@ extern void monitor_power_on (saver_info *si);
    blanking
    ======================================================================= */
 
+extern Bool update_screen_layout (saver_info *si);
 extern void initialize_screensaver_window (saver_info *si);
+extern void initialize_screen_root_widget (saver_screen_info *ssi);
+
 extern void raise_window (saver_info *si,
                            Bool inhibit_fade, Bool between_hacks_p,
                            Bool dont_clear);
@@ -156,12 +159,12 @@ extern void handle_signals (saver_info *si);
 #endif /* !HAVE_SIGACTION */
 extern void unblock_sigchld (void);
 extern void hack_environment (saver_info *si);
-extern void hack_subproc_environment (saver_screen_info *ssi);
+extern void hack_subproc_environment (Screen *, Window saver_window);
 extern void init_sigchld (void);
-extern void spawn_screenhack (saver_info *si, Bool first_time_p);
+extern void spawn_screenhack (saver_screen_info *ssi);
 extern pid_t fork_and_exec (saver_screen_info *ssi, const char *command);
-extern void kill_screenhack (saver_info *si);
-extern void suspend_screenhack (saver_info *si, Bool suspend_p);
+extern void kill_screenhack (saver_screen_info *ssi);
+extern void suspend_screenhack (saver_screen_info *ssi, Bool suspend_p);
 extern Bool screenhack_running_p (saver_info *si);
 extern void emergency_kill_subproc (saver_info *si);
 extern Bool select_visual (saver_screen_info *ssi, const char *visual_name);
@@ -174,6 +177,7 @@ extern const char *signal_name (int signal);
 
 extern FILE *real_stderr;
 extern FILE *real_stdout;
+extern void stderr_log_file (saver_info *si);
 extern void initialize_stderr (saver_info *si);
 extern void reset_stderr (saver_screen_info *ssi);
 extern void clear_stderr (saver_screen_info *ssi);
@@ -194,8 +198,13 @@ extern int BadWindow_ehandler (Display *dpy, XErrorEvent *error);
 extern Bool window_exists_p (Display *dpy, Window window);
 extern char *timestring (void);
 extern Bool display_is_on_console_p (saver_info *si);
-extern Visual *get_best_gl_visual (saver_screen_info *ssi);
+extern Visual *get_best_gl_visual (saver_info *si, Screen *screen);
 extern void check_for_leaks (const char *where);
+extern void describe_monitor_layout (saver_info *si);
+
+#ifdef HAVE_XF86VMODE
+Bool safe_XF86VidModeGetViewPort (Display *, int, int *, int *);
+#endif /* HAVE_XF86VMODE */
 
 extern Atom XA_VROOT, XA_XSETROOT_ID, XA_ESETROOT_PMAP_ID, XA_XROOTPMAP_ID;
 extern Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_ID;
index 0d2f65fc14f856211ee52aaef769c5080d8be192..d285f7990875f3eb712ffef1e6b35a647975ec10 100644 (file)
@@ -18,8 +18,9 @@ xscreensaver - extensible screen saver framework, plus locking
 .B xscreensaver
 [\-display \fIhost:display.screen\fP] \
 [\-verbose] \
+[\-no\-splash] \
 [\-no\-capture\-stderr] \
-[\-no\-splash]
+[\-log \fIfilename\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 
@@ -42,11 +43,9 @@ The
 program pops up a dialog box that lets you configure the screen saver,
 and experiment with the various display modes.
 
-.B Note:
-unlike
-.BR xlock (1),
-xscreensaver has a client-server model: the \fIxscreensaver\fP program is a
-daemon that runs in the background; it is controlled by the foreground
+.B Note that xscreensaver has a client-server model:
+the \fIxscreensaver\fP program is a daemon that runs in the background;
+it is controlled by the foreground
 .BR xscreensaver-demo (1)
 and
 .BR xscreensaver-command (1)
@@ -106,225 +105,559 @@ When settings are changed in the Preferences dialog box (see above)
 the current settings will be written to the \fI.xscreensaver\fP file.
 (The \fI.Xdefaults\fP file and the app-defaults file will never be
 written by xscreensaver itself.)
-.PP
-.TP 8
-.B timeout\fP (class \fBTime\fP)
-The screensaver will activate (blank the screen) after the keyboard and
-mouse have been idle for this many minutes.  Default 10 minutes.
-.TP 8
-.B cycle\fP (class \fBTime\fP)
-After the screensaver has been running for this many minutes, the currently
-running graphics-hack sub-process will be killed (with \fBSIGTERM\fP), and a
-new one started.  If this is 0, then the graphics hack will never be changed:
-only one demo will run until the screensaver is deactivated by user activity.
-Default 10 minutes.
-.TP 8
-.B lock\fP (class \fBBoolean\fP)
-Enable locking: before the screensaver will turn off, it will require you 
-to type the password of the logged-in user (really, the person who ran
-xscreensaver), or the root password.  (\fBNote:\fP 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.  See 
-the ``\fIUsing XDM(1)\fP'' section, below.
-.TP 8
-.B lockTimeout\fP (class \fBTime\fP)
-If locking is enabled, this controls the length of the ``grace period''
-between when the screensaver activates, and when the screen becomes locked.
-For example, if this is 5, and \fI\-timeout\fP is 10, then after 10 minutes,
-the screen would blank.  If there was user activity at 12 minutes, no password
-would be required to un-blank the screen.  But, if there was user activity
-at 15 minutes or later (that is, \fI\-lock\-timeout\fP minutes after 
-activation) then a password would be required.  The default is 0, meaning
-that if locking is enabled, then a password will be required as soon as the 
-screen blanks.
-.TP 8
-.B passwdTimeout\fP (class \fBTime\fP)
-If the screen is locked, then this is how many seconds the password dialog box
-should be left on the screen before giving up (default 30 seconds.)  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 dpmsEnabled\fP (class \fBBoolean\fP)
-Whether power management is enabled.
+.SH COMMAND-LINE OPTIONS
+.I xscreensaver
+also accepts a few command-line options, mostly for use when debugging:
+for normal operation, you should configure things via the \fI~/.xscreensaver\fP
+file.
 .TP 8
-.B dpmsStandby\fP (class \fBTime\fP)
-If power management is enabled, how long until the monitor goes solid black.
+.B \-display \fIhost:display.screen\fP
+The X display to use.  For displays with multiple screens, XScreenSaver
+will manage all screens on the display simultaniously.
 .TP 8
-.B dpmsSuspend\fP (class \fBTime\fP)
-If power management is enabled, how long until the monitor goes into
-power-saving mode.
+.B \-verbose
+Same as setting the \fIverbose\fP resource to \fItrue\fP: print diagnostics
+on stderr and on the xscreensaver window.
 .TP 8
-.B dpmsOff\fP (class \fBTime\fP)
-If power management is enabled, how long until the monitor powers down
-completely.  Note that these settings will have no effect unless both
-the X server and the display hardware support power management; not 
-all do.  See the \fIPower Management\fP section, below, for more 
-information.
+.B \-no-capture-stderr
+Do not redirect the stdout and stderr streams to the xscreensaver window
+itself.  If xscreensaver is crashing, you might need to do this in order
+to see the error message.
 .TP 8
-.B visualID\fP (class \fBVisualID\fP)
-Specify which X visual to use by default.  (Note carefully that this resource
-is called \fBvisualID\fP, not merely \fBvisual\fP; if you set the \fBvisual\fP
-resource instead, things will malfunction in obscure ways for obscure reasons.)
+.B \-log \fIfilename\fP
+This is exactly the same as redirecting stdout and stderr to the given
+file (for append).  This is useful when reporting bugs.
+.SH HOW IT WORKS
+When it is time to activate the screensaver, a full-screen black window is
+created on each screen of the display.  Each window is created in such a way
+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.
+The various graphics demos are, in fact, just standalone programs that
+know how to draw on the provided window.
 
-Legal values for the \fBVisualID\fP resource are:
-.RS 8
-.TP 8
-.B default
-Use the screen's default visual (the visual of the root window.)  
-This is the default.
-.TP 8
-.B best
-Use the visual which supports the most colors.  Note, however, that the
-visual with the most colors might be a TrueColor visual, which does not
-support colormap animation.  Some programs have more interesting behavior
-when run on PseudoColor visuals than on TrueColor.
-.TP 8
-.B mono
-Use a monochrome visual, if there is one.
-.TP 8
-.B gray
-Use a grayscale or staticgray visual, if there is one and it has more than
-one plane (that is, it's not monochrome.)
-.TP 8
-.B color
-Use the best of the color visuals, if there are any.
-.TP 8
-.B GL
-Use the visual that is best for OpenGL programs.  (OpenGL programs have
-somewhat different requirements than other X programs.)
-.TP 8
-.I class
-where \fIclass\fP is one of \fBStaticGray\fP, \fBStaticColor\fP, 
-\fBTrueColor\fP, \fBGrayScale\fP, \fBPseudoColor\fP, or \fBDirectColor\fP.
-Selects the deepest visual of the given class.
-.TP 8
-.I number
-where \fInumber\fP (decimal or hex) is interpreted as a visual id number, 
-as reported by the
-.BR xdpyinfo (1)
-program; in this way you can have finer control over exactly which visual
-gets used, for example, to select a shallower one than would otherwise
-have been chosen.
+When the user becomes active again, the screensaver windows are unmapped, and
+the running subprocesses are killed by sending them \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.
 
+You can control a running screensaver process by using the
+.BR xscreensaver\-command (1)
+program (which see.)
+.SH POWER MANAGEMENT
+Modern X servers contain support to power down the monitor after an idle
+period.  If the monitor has powered down, then \fIxscreensaver\fP will
+notice this (after a few minutes), and will not waste CPU by drawing 
+graphics demos on a black screen.  An attempt will also be made to
+explicitly power the monitor back up as soon as user activity is detected.
+
+The \fI~/.xscreensaver\fP file controls the configuration of your
+display's power management settings: if you have used
+.BR xset (1)
+to change your power management settings, then xscreensaver will
+override those changes with the values specified 
+in \fI~/.xscreensaver\fP (or with its built-in defaults, if there
+is no \fI~/.xscreensaver\fP file yet.)
+
+To change your power management settings, run
+.BR xscreensaver\-demo (1)
+and change the various timeouts through the user interface.
+Alternately, you can edit the \fI~/.xscreensaver\fP file directly.
+
+If the power management section is grayed out in the
+.BR xscreensaver\-demo (1)
+window,  then that means that your X server does not support
+the XDPMS extension, and so control over the monitor's power state
+is not available.
+
+If you're using a laptop, don't be surprised if changing the DPMS
+settings has no effect: many laptops have monitor power-saving behavior
+built in at a very low level that is invisible to Unix and X.  On such
+systems, you can typically adjust the power-saving delays only by
+changing settings in the BIOS in some hardware-specific way.
+
+If DPMS seems not to be working with XFree86, make sure the "DPMS"
+option is set in your \fI/etc/X11/XF86Config\fP file.  See the
+.BR XF86Config (5)
+manual for details.
+.SH USING GNOME
+For many years, GNOME shipped \fIxscreensaver\fP as-is, and
+everything just worked out of the box.  Recently, however, they've
+been re-inventing the wheel again in the form of "gnome-screensaver".
+
+To replace gnome-screensaver with xscreensaver:
+.RS 4
+.TP 3
+\fB1: Turn off gnome-screensaver.\fP
+Open ``System / Preferences / Screensaver'' and uncheck both boxes.
+.TP 3
+\fB2: Stop gnome-screensaver from launching at login.\fP
+Run the command:
+.EX
+gconftool-2 --type boolean -s \\
+/apps/gnome_settings_daemon/screensaver/start_screensaver \\
+false
+.EE
+Or, just uninstall the "gnome-screensaver" package entirely.
+.TP 3
+\fB3: Launch xscreensaver at login.\fP
+Open ``System / Preferences / Sessions / Startup Programs''.
+Click ``Add'' and type ``xscreensaver''.
+.TP 3
+\fB4: Tell Preferences to use the xscreensaver configurator.\fP
+Edit \fI/usr/share/applications/gnome-screensaver-preferences.desktop\fP
+and change the \fIExec=\fP line to say
+    Exec=xscreensaver-demo
+.TP 3
+\fB5: Make ``System / Quit / Lock Screen'' use xscreensaver.\fP
+Run the command:
+.EX
+sudo ln -sf /usr/bin/xscreensaver-command \\
+            /usr/bin/gnome-screensaver-command
+.EE
+.SH USING KDE
+KDE also has invented their own screen saver framework instead of
+simply using xscreensaver.  To replace the KDE screen saver with
+xscreensaver, do the following:
+.RS 4
+.TP 3
+\fB1: Turn off KDE's screen saver.\fP
+Open the ``\fIControl Center\fP'' and
+select the ``\fIAppearance & Themes / Screensaver\fP'' page.
+Un-check ``\fIStart Automatically\fP''.
+.TP 3
+\fB2: Find your Autostart directory.\fP
+Open the ``\fISystem Administration -> Paths\fP'' page,
+and see what your ``Autostart path'' is set to: it will
+probably be \fI~/.kde/Autostart/\fP or something similar.
+.TP 3
+\fB3: Make xscreensaver be an Autostart program.\fP
+Create a .desktop file in your autostart directory 
+called \fIxscreensaver.desktop\fP that contains the following five lines:
+.EX
+[Desktop Entry]
+Exec=xscreensaver
+Name=XScreensaver
+Type=Application
+X-KDE-StartupNotify=false
+.EE
+.TP 3
+\fB4: Make the various "lock session" buttons call xscreensaver.\fP
+Replace the file \fI/usr/bin/kdesktop_lock\fP (or 
+possibly \fI/usr/kde/3.5/bin/kdesktop_lock\fP)
+with these two lines:
+.EX
+#!/bin/sh
+xscreensaver-command -lock
+.EE
+Make sure the file is executable (chmod a+x).
 .RE
-.RS 8
-Note that this option specifies only the \fIdefault\fP visual that will
-be used: the visual used may be overridden on a program-by-program basis.
-See the description of the \fBprograms\fP resource, below.
-.RE
-.TP 8
-.B installColormap\fP (class \fBBoolean\fP)
-On PseudoColor (8-bit) displays, install a private colormap while the
-screensaver is active, so that the graphics hacks can get as many
-colors as possible.  This is the default.  (This only applies when the
-screen's default visual is being used, since non-default visuals get
-their own colormaps automatically.)  This can also be overridden on a
-per-hack basis: see the discussion of the \fBdefault\-n\fP name in the
-section about the \fBprograms\fP resource.
+.PP
+Now use xscreensaver normally, controlling it via the usual
+.BR xscreensaver-demo (1)
+and
+.BR xscreensaver-command (1)
+mechanisms.
+.SH USING GDM
+You can run \fIxscreensaver\fP from your 
+.BR gdm (1)
+session, so that the screensaver will run even when nobody is logged 
+in on the console.  To do this, run
+.BR gdmconfig (1)
+and on the \fIBackground\fP page, type the 
+command \fB"xscreensaver -nosplash"\fP into the \fIBackground Program\fP
+field.  That will cause gdm to run xscreensaver while nobody is logged
+in, and kill it as soon as someone does log in.  (The user will then
+be responsible for starting xscreensaver on their own, if they want.)
 
-This does nothing if you have a TrueColor (16-bit or deeper) display.
-.TP 8
-.B verbose\fP (class \fBBoolean\fP)
-Whether to print diagnostics.  Default false.
+Another way to accomplish the same thing is to edit the
+file \fI/etc/X11/gdm/gdm.conf\fP to include:
+.EX
+BackgroundProgram=xscreensaver -nosplash
+RunBackgroundProgramAlways=true
+.EE
+In this situation, the \fIxscreensaver\fP process will probably be running
+as user \fIgdm\fP instead of \fIroot\fP.  You can configure the settings
+for this nobody-logged-in state (timeouts, DPMS, etc.) by editing
+the \fI~gdm/.xscreensaver\fP file.
+
+To get gdm to run the BackgroundProgram, you may need to switch it from
+the "Graphical Greeter" to the "Standard Greeter".
+
+It is safe to run \fIxscreensaver\fP 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.
+
+An unfortunate side effect of this (important) security precaution is that
+it may conflict with cookie-based authentication.
+
+If you get "connection refused" errors when running \fIxscreensaver\fP
+from \fIgdm\fP, then this probably means that you have
+.BR xauth (1)
+or some other security mechanism turned on.  For information on the
+X server's access control mechanisms, see the man pages for
+.BR X (1),
+.BR Xsecurity (1),
+.BR xauth (1),
+and
+.BR xhost (1).
+.SH BUGS
+Bugs?  There are no bugs.  Ok, well, maybe.  If you find one, please let
+me know.  http://www.jwz.org/xscreensaver/bugs.html explains how to
+construct the most useful bug reports.
 .TP 8
-.B timestamp\fP (class \fBBoolean\fP)
-Whether to print the time of day along with any other diagnostic messages.
-Default true.
-.TP 8
-.B splash\fP (class \fBBoolean\fP)
-Whether to display a splash screen at startup.  Default true.
-.TP 8
-.B splashDuration\fP (class \fBTime\fP)
-How long the splash screen should remain visible; default 5 seconds.
+.B Locking and XDM
+If xscreensaver has been launched from 
+.BR xdm (1)
+before anyone has logged in, you will need to kill and then restart the
+xscreensaver daemon after you have logged in, or you will be confused by
+the results.  (For example, locking won't work, and your \fI~/.xscreensaver\fP
+file will be ignored.)
+
+When you are logged in, you want the \fIxscreensaver\fP daemon to be 
+running under \fIyour\fP user id, not as root or some other user.
+
+If it has already been started by \fIxdm\fP, you can kill it by sending
+it the \fBexit\fP command, and then re-launching it as you, by putting
+something like the following in your personal X startup script:
+.EX
+xscreensaver-command -exit
+xscreensaver &
+.EE
+The ``\fIUsing XDM(1)\fP'' section, above, goes into more detail, and explains
+how to configure the system to do this for all users automatically.
 .TP 8
-.B quad\fP (class \fBBoolean\fP)
-If true, then \fIfour\fP screensavers will be run on each monitor.
-Use at your own risk!
+.B Locking and root logins
+In order for it to be safe for xscreensaver to be launched by \fIxdm\fP,
+certain precautions had to be taken, among them that xscreensaver never
+runs as \fIroot\fP.  In particular, if it is launched as root (as \fIxdm\fP
+is likely to do), xscreensaver will disavow its privileges, and switch 
+itself to a safe user id (such as \fInobody\fP.)
+
+An implication of this is that if you log in as \fIroot\fP on the console, 
+xscreensaver will refuse to lock the screen (because it can't tell
+the difference between \fIroot\fP being logged in on the console, and a
+normal user being logged in on the console but xscreensaver having been 
+launched by the
+.BR xdm (1)
+.I Xsetup
+file.)
+
+The solution to this is simple: you shouldn't be logging in on the console
+as \fIroot\fP in the first place!  (What, are you crazy or something?)  
+
+Proper Unix hygiene dictates that you should log in as yourself, and
+.BR su (1)
+to \fIroot\fP as necessary.  People who spend their day logged in
+as \fIroot\fP are just begging for disaster.
 .TP 8
-.B helpURL\fP (class \fBURL\fP)
-The splash screen has a \fIHelp\fP button on it.  When you press it, it will
-display the web page indicated here in your web browser.
+.B XAUTH and XDM
+For xscreensaver to work when launched by
+.BR xdm (1),
+programs running on the local machine as user \fI"nobody"\fP must be
+able to connect to the X server.  This means that if you want to run
+xscreensaver on the console while nobody is logged in, you may need
+to disable cookie-based access control (and allow all users who can log
+in to the local machine to connect to the display.)  
+
+You should be sure that this is an acceptable thing to do in your
+environment before doing it.  See the ``\fIUsing XDM(1)\fP'' section, 
+above, for more details.
 .TP 8
-.B loadURL\fP (class \fBLoadURL\fP)
-This is the shell command used to load a URL into your web browser.
-The default setting will load it into Mozilla/Netscape if it is already
-running, otherwise, will launch a new browser looking at the \fIhelpURL\fP.
+.B Passwords
+If you get an error message at startup like ``couldn't get password
+of \fIuser\fP'' 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 in order for
+locking to work.  Care has been taken to make this a safe thing to do.  
+
+It also may mean that your system uses shadow passwords instead of the standard
+.BR getpwent (3)
+interface; in that case, you may need to change some options 
+with \fIconfigure\fP and recompile.
+
+If you change your password after xscreensaver has been launched, it will
+continue using your old password to unlock the screen until xscreensaver
+is restarted.  On some systems, it may accept \fIboth\fP your old and new
+passwords.  So, after you change your password, you'll have to do
+.EX
+xscreensaver-command -restart
+.EE
+to make \fIxscreensaver\fP notice.
 .TP 8
-.B demoCommand\fP (class \fBDemoCommand\fP)
-This is the shell command run when the \fIDemo\fP button on the splash window
-is pressed.  It defaults to
-.BR xscreensaver\-demo (1).
+.B PAM Passwords
+If your system uses PAM (Pluggable Authentication Modules), then in order
+for xscreensaver to use PAM properly, PAM must be told about xscreensaver.
+The xscreensaver installation process should update the PAM data (on Linux,
+by creating the file \fI/etc/pam.d/xscreensaver\fP for you, and on Solaris, 
+by telling you what lines to add to the \fI/etc/pam.conf\fP file.)  
+
+If the PAM configuration files do not know about xscreensaver, then 
+you \fImight\fP be in a situation where xscreensaver will refuse to ever
+unlock the screen.
+
+This is a design flaw in PAM (there is no way for a client to tell the
+difference between PAM responding ``I have never heard of your module,''
+and responding, ``you typed the wrong password.'')  As far as I can tell,
+there is no way for xscreensaver to automatically work around this, or
+detect the problem in advance, so if you have PAM, make sure it is
+configured correctly!
 .TP 8
-.B prefsCommand\fP (class \fBPrefsCommand\fP)
-This is the shell command run when the \fIPrefs\fP button on the splash window
-is pressed.  It defaults to \fIxscreensaver\-demo\ \-prefs\fP.
+.B Machine Load
+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 consume many
+cycles.  Care has been taken in all the modules shipped with xscreensaver
+to sleep periodically, and not run full tilt, so as not to cause
+appreciable load.
+
+However, if you are running the OpenGL-based screen savers on a machine
+that does not have a video card with 3D acceleration, they \fIwill\fP
+make your machine slow, despite
+.BR nice (1).
+
+Your options are: don't use the OpenGL display modes; or, collect the
+spare change hidden under the cushions of your couch, and use it to
+buy a video card manufactured after 1998.  (It doesn't even need to be
+\fIfast\fP 3D hardware: the problem will be fixed if there is any
+3D hardware \fIat all.\fP)
 .TP 8
-.B nice\fP (class \fBNice\fP)
-The sub-processes created by \fIxscreensaver\fP will be ``niced'' to this
-level, so that they are given lower priority than other processes on the
-system, and don't increase the load unnecessarily.  The default is 10.  
+.B XFree86's Magic Keystrokes
+The XFree86 X server traps certain magic keystrokes before client programs ever
+see them.  Two that are of note are Ctrl+Alt+Backspace, which causes 
+the X server to exit; and Ctrl+Alt+F\fIn\fP, which switches virtual consoles.
+The X server will respond to these keystrokes even if xscreensaver has the
+screen locked.  Depending on your setup, you might consider this a problem.
 
-(Higher numbers mean lower priority; see 
-.BR nice (1)
-for details.)
+Unfortunately, there is no way for xscreensaver itself to override the
+interpretation of these keys.  If you want to disable Ctrl+Alt+Backspace
+globally, you need to set the \fIDontZap\fP flag in 
+your \fI/etc/X11/XF86Config\fP file.  To globally disable VT switching,
+you can set the \fIDontVTSwitch\fP flag.  See the
+.BR XF86Config (5)
+manual for details.
+.SH X RESOURCES
+These are the X resources use by the \fIxscreensaver\fP program.
+You probably won't need to change these manually (that's what the
+.BR xscreensaver\-demo (1)
+program is for).
 .TP 8
-.B fade\fP (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 certain systems.  A fade will also be done when switching graphics
-hacks (when the \fIcycle\fP timer expires.)  Default: true.  
+.B timeout\fP (class \fBTime\fP)
+The screensaver will activate (blank the screen) after the keyboard and
+mouse have been idle for this many minutes.  Default 10 minutes.
 .TP 8
-.B unfade\fP (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 certain systems, and if \fIfade\fP is true as well.
-Default false.
+.B cycle\fP (class \fBTime\fP)
+After the screensaver has been running for this many minutes, the currently
+running graphics-hack sub-process will be killed (with \fBSIGTERM\fP), and a
+new one started.  If this is 0, then the graphics hack will never be changed:
+only one demo will run until the screensaver is deactivated by user activity.
+Default 10 minutes.
 .TP 8
-.B fadeSeconds\fP (class \fBTime\fP)
-If \fIfade\fP is true, this is how long the fade will be in 
-seconds (default 3 seconds.)
+.B lock\fP (class \fBBoolean\fP)
+Enable locking: before the screensaver will turn off, it will require you 
+to type the password of the logged-in user (really, the person who ran
+xscreensaver), or the root password.  (\fBNote:\fP 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.  See 
+the ``\fIUsing XDM(1)\fP'' section, below.
 .TP 8
-.B fadeTicks\fP (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 than the specified \fIfadeSeconds\fP if
-your server isn't fast enough to keep up.  Default 20.
+.B lockTimeout\fP (class \fBTime\fP)
+If locking is enabled, this controls the length of the ``grace period''
+between when the screensaver activates, and when the screen becomes locked.
+For example, if this is 5, and \fI\-timeout\fP is 10, then after 10 minutes,
+the screen would blank.  If there was user activity at 12 minutes, no password
+would be required to un-blank the screen.  But, if there was user activity
+at 15 minutes or later (that is, \fI\-lock\-timeout\fP minutes after 
+activation) then a password would be required.  The default is 0, meaning
+that if locking is enabled, then a password will be required as soon as the 
+screen blanks.
 .TP 8
-.B captureStderr\fP (class \fBBoolean\fP)
-Whether \fIxscreensaver\fP should redirect its stdout and stderr streams to
-the window itself.  Since its nature is to take over the screen, you would not
-normally see error messages generated by xscreensaver or the sub-programs it
-runs; this resource will cause the output of all relevant programs to be
-drawn on the screensaver window itself, as well as being written to the
-controlling terminal of the screensaver driver process.  Default true.
+.B passwdTimeout\fP (class \fBTime\fP)
+If the screen is locked, then this is how many seconds the password dialog box
+should be left on the screen before giving up (default 30 seconds.)  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 ignoreUninstalledPrograms\fP (class \fBBoolean\fP)
-There may be programs in the list that are not installed on the system,
-yet are marked as "enabled."  If this preference is true, then such 
-programs will simply be ignored.  If false, then a warning will be printed
-if an attempt is made to run the nonexistent program.  Also, the
-.BR xscreensaver-demo (1)
-program will suppress the non-existent programs from the list if this
-is true.  Default: false.
+.B dpmsEnabled\fP (class \fBBoolean\fP)
+Whether power management is enabled.
 .TP 8
-.B GetViewPortIsFullOfLies\fP (class \fBBoolean\fP)
-Set this to true if the xscreensaver window doesn't cover the whole screen.
-This works around a longstanding XFree86 bug #421.  See the 
-xscreensaver FAQ for details.
+.B dpmsStandby\fP (class \fBTime\fP)
+If power management is enabled, how long until the monitor goes solid black.
 .TP 8
-.B font\fP (class \fBFont\fP)
-The font used for the stdout/stderr text, if \fBcaptureStderr\fP is true.
-Default \fB*\-medium\-r\-*\-140\-*\-m\-*\fP (a 14 point fixed-width font.)
+.B dpmsSuspend\fP (class \fBTime\fP)
+If power management is enabled, how long until the monitor goes into
+power-saving mode.
 .TP 8
-.B mode\fP (class \fBMode\fP)
-Controls the behavior of xscreensaver.  Legal values are:
+.B dpmsOff\fP (class \fBTime\fP)
+If power management is enabled, how long until the monitor powers down
+completely.  Note that these settings will have no effect unless both
+the X server and the display hardware support power management; not 
+all do.  See the \fIPower Management\fP section, below, for more 
+information.
+.TP 8
+.B visualID\fP (class \fBVisualID\fP)
+Specify which X visual to use by default.  (Note carefully that this resource
+is called \fBvisualID\fP, not merely \fBvisual\fP; if you set the \fBvisual\fP
+resource instead, things will malfunction in obscure ways for obscure reasons.)
+
+Legal values for the \fBVisualID\fP resource are:
 .RS 8
 .TP 8
-.B random
-When blanking the screen, select a random display mode from among those
-that are enabled and applicable.  This is the default.
+.B default
+Use the screen's default visual (the visual of the root window.)  
+This is the default.
+.TP 8
+.B best
+Use the visual which supports the most colors.  Note, however, that the
+visual with the most colors might be a TrueColor visual, which does not
+support colormap animation.  Some programs have more interesting behavior
+when run on PseudoColor visuals than on TrueColor.
+.TP 8
+.B mono
+Use a monochrome visual, if there is one.
+.TP 8
+.B gray
+Use a grayscale or staticgray visual, if there is one and it has more than
+one plane (that is, it's not monochrome.)
+.TP 8
+.B color
+Use the best of the color visuals, if there are any.
+.TP 8
+.B GL
+Use the visual that is best for OpenGL programs.  (OpenGL programs have
+somewhat different requirements than other X programs.)
+.TP 8
+.I class
+where \fIclass\fP is one of \fBStaticGray\fP, \fBStaticColor\fP, 
+\fBTrueColor\fP, \fBGrayScale\fP, \fBPseudoColor\fP, or \fBDirectColor\fP.
+Selects the deepest visual of the given class.
+.TP 8
+.I number
+where \fInumber\fP (decimal or hex) is interpreted as a visual id number, 
+as reported by the
+.BR xdpyinfo (1)
+program; in this way you can have finer control over exactly which visual
+gets used, for example, to select a shallower one than would otherwise
+have been chosen.
+
+.RE
+.RS 8
+Note that this option specifies only the \fIdefault\fP visual that will
+be used: the visual used may be overridden on a program-by-program basis.
+See the description of the \fBprograms\fP resource, below.
+.RE
+.TP 8
+.B installColormap\fP (class \fBBoolean\fP)
+On PseudoColor (8-bit) displays, install a private colormap while the
+screensaver is active, so that the graphics hacks can get as many
+colors as possible.  This is the default.  (This only applies when the
+screen's default visual is being used, since non-default visuals get
+their own colormaps automatically.)  This can also be overridden on a
+per-hack basis: see the discussion of the \fBdefault\-n\fP name in the
+section about the \fBprograms\fP resource.
+
+This does nothing if you have a TrueColor (16-bit or deeper) display.
+.TP 8
+.B verbose\fP (class \fBBoolean\fP)
+Whether to print diagnostics.  Default false.
+.TP 8
+.B timestamp\fP (class \fBBoolean\fP)
+Whether to print the time of day along with any other diagnostic messages.
+Default true.
+.TP 8
+.B splash\fP (class \fBBoolean\fP)
+Whether to display a splash screen at startup.  Default true.
+.TP 8
+.B splashDuration\fP (class \fBTime\fP)
+How long the splash screen should remain visible; default 5 seconds.
+.TP 8
+.B helpURL\fP (class \fBURL\fP)
+The splash screen has a \fIHelp\fP button on it.  When you press it, it will
+display the web page indicated here in your web browser.
+.TP 8
+.B loadURL\fP (class \fBLoadURL\fP)
+This is the shell command used to load a URL into your web browser.
+The default setting will load it into Mozilla/Netscape if it is already
+running, otherwise, will launch a new browser looking at the \fIhelpURL\fP.
+.TP 8
+.B demoCommand\fP (class \fBDemoCommand\fP)
+This is the shell command run when the \fIDemo\fP button on the splash window
+is pressed.  It defaults to
+.BR xscreensaver\-demo (1).
+.TP 8
+.B prefsCommand\fP (class \fBPrefsCommand\fP)
+This is the shell command run when the \fIPrefs\fP button on the splash window
+is pressed.  It defaults to \fIxscreensaver\-demo\ \-prefs\fP.
+.TP 8
+.B nice\fP (class \fBNice\fP)
+The sub-processes created by \fIxscreensaver\fP will be ``niced'' to this
+level, so that they are given lower priority than other processes on the
+system, and don't increase the load unnecessarily.  The default is 10.  
+
+(Higher numbers mean lower priority; see 
+.BR nice (1)
+for details.)
+.TP 8
+.B fade\fP (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 certain systems.  A fade will also be done when switching graphics
+hacks (when the \fIcycle\fP timer expires.)  Default: true.  
+.TP 8
+.B unfade\fP (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 certain systems, and if \fIfade\fP is true as well.
+Default false.
+.TP 8
+.B fadeSeconds\fP (class \fBTime\fP)
+If \fIfade\fP is true, this is how long the fade will be in 
+seconds (default 3 seconds.)
+.TP 8
+.B fadeTicks\fP (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 than the specified \fIfadeSeconds\fP if
+your server isn't fast enough to keep up.  Default 20.
+.TP 8
+.B captureStderr\fP (class \fBBoolean\fP)
+Whether \fIxscreensaver\fP should redirect its stdout and stderr streams to
+the window itself.  Since its nature is to take over the screen, you would not
+normally see error messages generated by xscreensaver or the sub-programs it
+runs; this resource will cause the output of all relevant programs to be
+drawn on the screensaver window itself, as well as being written to the
+controlling terminal of the screensaver driver process.  Default true.
+.TP 8
+.B ignoreUninstalledPrograms\fP (class \fBBoolean\fP)
+There may be programs in the list that are not installed on the system,
+yet are marked as "enabled."  If this preference is true, then such 
+programs will simply be ignored.  If false, then a warning will be printed
+if an attempt is made to run the nonexistent program.  Also, the
+.BR xscreensaver-demo (1)
+program will suppress the non-existent programs from the list if this
+is true.  Default: false.
+.TP 8
+.B GetViewPortIsFullOfLies\fP (class \fBBoolean\fP)
+Set this to true if the xscreensaver window doesn't cover the whole screen.
+This works around a longstanding XFree86 bug #421.  See the 
+xscreensaver FAQ for details.
+.TP 8
+.B font\fP (class \fBFont\fP)
+The font used for the stdout/stderr text, if \fBcaptureStderr\fP is true.
+Default \fB*\-medium\-r\-*\-140\-*\-m\-*\fP (a 14 point fixed-width font.)
+.TP 8
+.B mode\fP (class \fBMode\fP)
+Controls the behavior of xscreensaver.  Legal values are:
+.RS 8
+.TP 8
+.B random
+When blanking the screen, select a random display mode from among those
+that are enabled and applicable.  This is the default.
 .TP 8
 .B random-same
 Like \fIrandom\fP, but if there are multiple screens, each screen
@@ -360,796 +693,188 @@ When the screensaver starts up, one of these is selected (according to
 the \fBmode\fP setting), and run.  After the \fIcycle\fP period
 expires, it is killed, and another is selected and run.
 
-If a line begins with a dash (-) then that particular program is
-disabled: it won't be selected at random (though you can still select
-it explicitly using the
-.BR xscreensaver\-demo (1)
-program.)
-
-If all programs are disabled, then the screen will just be made blank,
-as when \fImode\fP is set to \fIblank\fP.
-
-To disable a program, you must mark it as disabled with a dash instead
-of removing it from the list.  This is because the system-wide (app-defaults)
-and per-user (.xscreensaver) settings are merged together, and if a user
-just \fIdeletes\fP an entry from their programs list, but that entry still
-exists in the system-wide list, then it will come back.  However, if the
-user \fIdisables\fP it, then their setting takes precedence.
-
-If the display has multiple screens, then a different program will be run
-for each screen.  (All screens are blanked and unblanked simultaneously.)
-
-Note that you must escape the newlines; here is an example of how you
-might set this in your \fI~/.xscreensaver\fP file:
-
-.RS 8
-.EX
-programs:  \\
-       qix -root                          \\n\\
-       ico -r -faces -sleep 1 -obj ico    \\n\\
-       xdaliclock -builtin2 -root         \\n\\
-       xv -root -rmode 5 image.gif -quit  \\n
-.EE
-.RE
-.RS 8
-Make sure your \fB$PATH\fP environment variable is set up correctly
-\fIbefore\fP xscreensaver is launched, or it won't be able to find the
-programs listed in the \fIprograms\fP resource.
-
-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
-.BR tvtwm (1).
-(Generally, this is accomplished by just including the \fI"vroot.h"\fP 
-header file in the program's source.)
-
-If there are some programs that you want to run only when using a color
-display, and others that you want to run only when using a monochrome
-display, you can specify that like this:
-.EX
-       mono:   mono-program  -root        \\n\\
-       color:  color-program -root        \\n\\
-.EE
-.RE
-.RS 8
-More generally, you can specify the kind of visual that should be used for
-the window on which the program will be drawing.  For example, if one 
-program works best if it has a colormap, but another works best if it has
-a 24-bit visual, both can be accommodated:
-.EX
-       PseudoColor: cmap-program  -root   \\n\\
-       TrueColor:   24bit-program -root   \\n\\
-.EE
-.RE
-.RS 8
-In addition to the symbolic visual names described above (in the discussion
-of the \fIvisualID\fP resource) one other visual name is supported in
-the \fIprograms\fP list:
-.RS 1
-.TP 4
-.B default-n
-This is like \fBdefault\fP, but also requests the use of the default colormap,
-instead of a private colormap.  (That is, it behaves as if 
-the \fI\-no\-install\fP command-line option was specified, but only for
-this particular hack.)  This is provided because some third-party programs
-that draw on the root window (notably: 
-.BR xv (1),
-and
-.BR xearth (1))
-make assumptions about the visual and colormap of the root window: 
-assumptions which xscreensaver can violate.
-
-.RE
-If you specify a particular visual for a program, and that visual does not
-exist on the screen, then that program will not be chosen to run.  This
-means that on displays with multiple screens of different depths, you can
-arrange for appropriate hacks to be run on each.  For example, if one screen
-is color and the other is monochrome, hacks that look good in mono can be 
-run on one, and hacks that only look good in color will show up on the other.
-.RE
-.PP
-.PP
-You shouldn't ever need to change the following resources:
-.PP
-.TP 8
-.B pointerPollTime\fP (class \fBTime\fP)
-When server extensions are 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 pointerHysteresis\fP (class \fBInteger\fP)
-If the mouse moves less than this-many pixels in a second, ignore it
-(do not consider that to be "activity.")  This is so that the screen
-doesn't un-blank (or fail to blank) just because you bumped the desk.
-Default: 10 pixels.
-.TP 8
-.B windowCreationTimeout\fP (class \fBTime\fP)
-When server extensions are 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 initialDelay\fP (class \fBTime\fP)
-When server extensions are 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 0.  (This used to default to 30, but that was
-back in the days when slow machines and X terminals were more common...)
-.RE
-.PP
-There are a number of different X server extensions which can make
-xscreensaver's job easier.  The next few resources specify whether these
-extensions should be utilized if they are available.
-.TP 8
-.B sgiSaverExtension\fP (class \fBBoolean\fP)
-This resource controls whether the SGI \fBSCREEN_SAVER\fP server extension
-will be used to decide whether the user is idle.  This is the default 
-if \fIxscreensaver\fP has been compiled with support for this 
-extension (which is the default on SGI systems.).  If it is available, 
-the \fBSCREEN_SAVER\fP method is faster and more reliable than what will
-be done otherwise, so use it if you can.  (This extension is only available
-on Silicon Graphics systems, unfortunately.)
-.TP 8
-.B mitSaverExtension\fP (class \fBBoolean\fP)
-This resource controls whether the \fBMIT\-SCREEN\-SAVER\fP server extension
-will be used to decide whether the user is idle.  However, the default for
-this resource is \fIfalse\fP, because even if this extension is available,
-it is flaky (and it also makes the \fBfade\fP option not work properly.)
-Use of this extension is strongly discouraged.  Support for it will
-probably be removed eventually.
-.TP 8
-.B xidleExtension\fP (class \fBBoolean\fP)
-This resource controls whether the \fBXIDLE\fP server extension will be
-used to decide whether the user is idle.  This is the default 
-if \fIxscreensaver\fP has been compiled with support for this extension.
-(This extension is only available for X11R4 and X11R5 systems, unfortunately.)
-.TP 8
-.B procInterrupts\fP (class \fBBoolean\fP)
-This resource controls whether the \fB/proc/interrupts\fP file should be
-consulted to decide whether the user is idle.  This is the default
-if \fIxscreensaver\fP has been compiled on a system which supports this
-mechanism (i.e., Linux systems.)  
-
-The benefit to doing this is that \fIxscreensaver\fP can note that the user
-is active even when the X console is not the active one: if the user is 
-typing in another virtual console, xscreensaver will notice that and will
-fail to activate.  For example, if you're playing Quake in VGA-mode, 
-xscreensaver won't wake up in the middle of your game and start competing 
-for CPU.
-
-The drawback to doing this is that perhaps you \fIreally do\fP want idleness
-on the X console to cause the X display to lock, even if there is activity
-on other virtual consoles.  If you want that, then set this option to False.
-(Or just lock the X console manually.)
-
-The default value for this resource is True, on systems where it works.
-.TP 8
-.B overlayStderr\fP (class \fBBoolean\fP)
-If \fBcaptureStderr\fP is True, and your server supports ``overlay'' visuals,
-then the text will be written into one of the higher layers instead of into
-the same layer as the running screenhack.  Set this to False to disable 
-that (though you shouldn't need to.)
-.TP 8
-.B overlayTextForeground\fP (class \fBForeground\fP)
-The foreground color used for the stdout/stderr text, if \fBcaptureStderr\fP
-is true.  Default: Yellow.
-.TP 8
-.B overlayTextBackground\fP (class \fBBackground\fP)
-The background color used for the stdout/stderr text, if \fBcaptureStderr\fP
-is true.  Default: Black.
-.TP 8
-.B bourneShell\fP (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.
-.SH COMMAND-LINE OPTIONS
-.I xscreensaver
-also accepts a few command-line options, mostly for use when debugging:
-for normal operation, you should configure things via the \fI~/.xscreensaver\fP
-file.
-.TP 8
-.B \-display \fIhost:display.screen\fP
-The X display to use.  For displays with multiple screens, XScreenSaver
-will manage all screens on the display simultaniously.
-.TP 8
-.B \-verbose
-Same as setting the \fIverbose\fP resource to \fItrue\fP: print diagnostics
-on stderr and on the xscreensaver window.
-.TP 8
-.B \-no-capture-stderr
-Same as setting the \fIcaptureStderr\fP resource to \fIfalse\fP: do not
-redirect the stdout and stderr streams to the xscreensaver window itself.
-If xscreensaver is crashing, you might need to do this in order to see
-the error message.
-.SH HOW IT WORKS
-When it is time to activate the screensaver, a full-screen black window is
-created on each screen of the display.  Each window is created in such a way
-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.
-
-When the user becomes active again, the screensaver windows are unmapped, and
-the running subprocesses are killed by sending them \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.
-
-Before launching a subprocess, \fIxscreensaver\fP stores an appropriate value
-for \fB$DISPLAY\fP in the environment that the child will receive.  (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;
-and so that the child will end up drawing on the appropriate screen of a
-multi-headed display.)
-
-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.
-
-For all the gory details, see the commentary at the top of xscreensaver.c.
-
-You can control a running screensaver process by using the
-.BR xscreensaver\-command (1)
-program (which see.)
-.SH POWER MANAGEMENT
-Modern X servers contain support to power down the monitor after an idle
-period.  If the monitor has powered down, then \fIxscreensaver\fP will
-notice this (after a few minutes), and will not waste CPU by drawing 
-graphics demos on a black screen.  An attempt will also be made to
-explicitly power the monitor back up as soon as user activity is detected.
-
-As of version 3.28 (Feb 2001), the \fI~/.xscreensaver\fP file controls the
-configuration of your display's power management settings: if you have
-used
-.BR xset (1)
-to change your power management settings, then xscreensaver will
-override those changes with the values specified 
-in \fI~/.xscreensaver\fP (or with its built-in defaults, if there
-is no \fI~/.xscreensaver\fP file yet.)
-
-To change your power management settings, run
-.BR xscreensaver\-demo (1)
-and change the various timeouts through the user interface.
-Alternately, you can edit the \fI~/.xscreensaver\fP file directly.
-
-If the power management section is grayed out in the
-.BR xscreensaver\-demo (1)
-window,  then that means that your X server does not support
-the XDPMS extension, and so control over the monitor's power state
-is not available.
-
-If you're using a laptop, don't be surprised if changing the DPMS
-settings has no effect: many laptops have monitor power-saving behavior
-built in at a very low level that is invisible to Unix and X.  On such
-systems, you can typically adjust the power-saving delays only by
-changing settings in the BIOS in some hardware-specific way.
-
-If DPMS seems not to be working with XFree86, make sure the "DPMS"
-option is set in your \fI/etc/X11/XF86Config\fP file.  See the
-.BR XF86Config (5)
-manual for details.
-.SH USING XDM(1)
-You can run \fIxscreensaver\fP from your 
-.BR xdm (1)
-session, so that the screensaver will run even when nobody is logged 
-in on the console.
-
-The trick to using xscreensaver with \fIxdm\fP is this: keep in mind the 
-two very different states in which xscreensaver will be running:
-.RS 4
-.TP 3
-.B 1: Nobody logged in.
-
-If you're thinking of running xscreensaver from XDM at all, then it's 
-probably because you want graphics demos to be running on the console
-when nobody is logged in there.  In this case, xscreensaver will function
-only as a screen saver, not a screen locker: it doesn't make sense
-for xscreensaver to lock the screen, since nobody is logged in yet!
-The only thing on the screen is the XDM login prompt.
-.TP 3
-.B 2: Somebody logged in.
-
-Once someone has logged in through the XDM login window, the situation is
-very different.  For example: now it makes sense to lock the screen (and
-prompt for the logged in user's password); and now xscreensaver should
-consult that user's \fI~/.xscreensaver\fP file; and so on.
-.RE
-
-The difference between these two states comes down to a question of,
-which user is the \fIxscreensaver\fP process running as?  For the first
-state, it doesn't matter.  If you start \fIxscreensaver\fP in the usual
-XDM way, then xscreensaver will probably end up running as root, which 
-is fine for the first case (the ``nobody logged in'' case.)
-
-However, once someone is logged in, running as root is no longer fine:
-because xscreensaver will be consulting root's \fI.xscreensaver\fP file
-instead of that of the logged in user, and won't be prompting for the
-logged in user's password, and so on.  (This is not a security problem,
-it's just not what you want.)
-
-So, once someone has logged in, you want xscreensaver to be running as that
-user.  The way to accomplish this is to kill the old xscreensaver process
-and start a new one (as the new user.)
-
-The simplest way to accomplish all of this is as follows:
-.RS 4
-.TP 3
-.B 1: Launch xscreensaver before anyone logs in.
-
-To the file \fI/usr/lib/X11/xdm/Xsetup\fP, add the lines
-.EX
-xhost +localhost
-xscreensaver-command -exit
-xscreensaver &
-.EE
-This will run xscreensaver as root, over the XDM login window.
-Moving the mouse will cause the screen to un-blank, and allow the user
-to type their password at XDM to log in.
-.TP 3
-.B 2: Restart xscreensaver when someone logs in.
-
-Near the top of the file \fI/usr/lib/X11/xdm/Xsession\fP, add those same lines:
-.EX
-xscreensaver-command -exit
-xscreensaver &
-.EE
-When someone logs in, this will kill off the existing (root) xscreensaver
-process, and start a new one, running as the user who has just logged in.
-If the user's .xscreensaver file requests locking, they'll get it.  They
-will also get their own choice of timeouts, and graphics demos, and so on.
-
-Alternately, each user could just put those lines in their 
-personal \fI~/.xsession\fP files.
-.RE
-
-Make sure you have \fB$PATH\fP set up correctly in the \fIXsetup\fP 
-and \fIXsession\fP scripts, or \fIxdm\fP won't be able to 
-find \fIxscreensaver\fP, and/or \fIxscreensaver\fP won't be able to 
-find its graphics demos.
-
-(If your system does not seem to be executing the \fIXsetup\fP file, you
-may need to configure it to do so: the traditional way to do this is
-to make that file the value of the \fIDisplayManager*setup\fP resource
-in the \fI/usr/lib/X11/xdm/xdm-config\fP file.  See the man page for
-.BR xdm (1)
-for more details.)
-
-It is safe to run \fIxscreensaver\fP 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.
-
-An unfortunate side effect of this (important) security precaution is that
-it may conflict with cookie-based authentication.
-
-If you get "connection refused" errors when running \fIxscreensaver\fP
-from \fIxdm\fP, then this probably means that you have
-.BR xauth (1)
-or some other security mechanism turned on.  One way around this is to
-add \fB"xhost\ +localhost"\fP to \fIXsetup\fP, just before \fIxscreensaver\fP
-is launched.  
-
-Note that this will give access to the X server to anyone capable of logging
-in to the local machine, so in some environments, this might not be 
-appropriate.  If turning off file-system-based access control is not
-acceptable, then running \fIxscreensaver\fP from the \fIXsetup\fP file
-might not be possible, and xscreensaver will only work when running as
-a normal, unprivileged user.
-
-For more information on the X server's access control mechanisms, see the
-man pages for
-.BR X (1),
-.BR Xsecurity (1),
-.BR xauth (1),
-and
-.BR xhost (1).
-.SH USING GDM(1)
-Using xscreensaver with
-.BR gdm (1)
-is easy, because gdm has a configuration tool.  Just fire up
-.BR gdmconfig (1)
-and on the \fIBackground\fP page, type \fB"xscreensaver -nosplash"\fP into
-the \fIBackground Program\fP field.  That will cause gdm to run xscreensaver
-while nobody is logged in, and kill it as soon as someone does log in.
-(The user will then be responsible for starting xscreensaver on their
-own, if they want.)
-
-Another way to accomplish the same thing is to edit the
-file \fI/etc/X11/gdm/gdm.conf\fP to include:
-.EX
-BackgroundProgram=xscreensaver -nosplash
-RunBackgroundProgramAlways=true
-.EE
-In this situation, the \fIxscreensaver\fP process will probably be running
-as user \fIgdm\fP instead of \fIroot\fP.  You can configure the settings
-for this nobody-logged-in state (timeouts, DPMS, etc.) by editing
-the \fI~gdm/.xscreensaver\fP file.
-
-To get gdm to run the BackgroundProgram, you may need to switch it from
-the "Graphical Greeter" to the "Standard Greeter".
-.SH USING KDE (K DESKTOP ENVIRONMENT)
-I understand that KDE has invented their own wrapper around xscreensaver,
-that is inferior to 
-.BR xscreensaver-demo (1)
-in any number of ways.  I've never actually seen it, but I'm told that
-this is the way you disable it:
-.RS 4
-.TP 3
-\fB1: Switch off KDE's screen saver.\fP
-Open the ``\fIControl Center\fP'' and
-select the ``\fIAppearance & Themes -> Screensaver\fP'' page.
-Turn off the ``\fIStart Automatically\fP'' checkbox.
-.TP 3
-\fB2: Find your Autostart directory.\fP
-Open the ``\fISystem Administration -> Paths\fP'' page,
-and see what your ``Autostart path'' is set to: it will
-probably be \fI~/.kde/Autostart/\fP or something similar.
-.TP 3
-\fB3: Make xscreensaver be an Autostart program.\fP
-Create a .desktop file in your autostart directory 
-called \fIxscreensaver.desktop\fP that contains the following five lines:
-.EX
-[Desktop Entry]
-Exec=xscreensaver
-Name=XScreensaver
-Type=Application
-X-KDE-StartupNotify=false
-.EE
-.TP 3
-\fB4: Make the various "lock session" buttons call xscreensaver.\fP
-Replace the file \fI/usr/bin/kdesktop_lock\fP (or 
-possibly \fI/usr/kde/3.5/bin/kdesktop_lock\fP)
-with these two lines:
-.EX
-#!/bin/sh
-xscreensaver-command -lock
-.EE
-Make sure the file is executable (chmod a+x).
-.RE
-.PP
-Now use xscreensaver normally, controlling it via the usual
-.BR xscreensaver-demo (1)
-and
-.BR xscreensaver-command (1)
-mechanisms.
-.SH USING CDE (COMMON DESKTOP ENVIRONMENT)
-The easiest way to use \fIxscreensaver\fP on a system with CDE is to simply
-switch off the built-in CDE screensaver, and use \fIxscreensaver\fP instead;
-and second, to tell the front panel to run 
-.BR xscreensaver\-command (1)
-with the \fI\-lock\fP option when the \fILock\fP icon is clicked.
-
-To accomplish this involves five steps:
-.RS 4
-.TP 3
-\fB1: Switch off CDE's locker\fP
-Do this by turning off ``\fIScreen Saver and Screen Lock\fP'' in the
-Screen section of the Style Manager.
-.TP 3
-\fB2: Edit sessionetc\fP
-Edit the file \fI~/.dt/sessions/sessionetc\fP and add to it the line
-.EX
-xscreensaver &
-.EE
-And make sure the sessionetc file is executable.
-This will cause \fIxscreensaver\fP to be launched when you log in.
-(As always, make sure that xscreensaver and the graphics demos are on
-your \fB$PATH\fP; the path needs to be set in \fI.cshrc\fP 
-and/or \fI.dtprofile\fP, not \fI.login\fP.)
-.TP 3
-\fB3: Create XScreenSaver.dt\fP
-Create a file called \fI~/.dt/types/XScreenSaver.dt\fP with the following
-contents:
-.EX
-ACTION XScreenSaver
-{
-  LABEL         XScreenSaver
-  TYPE          COMMAND
-  EXEC_STRING   xscreensaver-command -lock
-  ICON          Dtkey
-  WINDOW_TYPE   NO_STDIO
-}
-.EE
-This defines a ``lock'' command for the CDE front panel, that knows how
-to talk to \fIxscreensaver\fP.
-.TP 3
-\fB4: Create Lock.fp\fP
-Create a file called \fI~/.dt/types/Lock.fp\fP with the following
-contents:
-.EX
-CONTROL Lock
-{
-  TYPE             icon
-  CONTAINER_NAME   Switch
-  CONTAINER_TYPE   SWITCH
-  POSITION_HINTS   1
-  ICON             Fplock
-  LABEL            Lock
-  PUSH_ACTION      XScreenSaver
-  HELP_TOPIC       FPOnItemLock
-  HELP_VOLUME      FPanel
-}
-.EE
-This associates the CDE front panel ``Lock'' icon with the lock command
-we just defined in step 3.
-.TP 3
-\fB5: Restart\fP
-Select ``\fIRestart Workspace Manager\fP'' from the popup menu to make
-your changes take effect.  If things seem not to be working, check the
-file \fI~/.dt/errorlog\fP for error messages.
-.RE
-.SH USING HP VUE (VISUAL USER ENVIRONMENT)
-Since CDE is a descendant of VUE, the instructions for using xscreensaver
-under VUE are similar to the above:
-.RS 4
-.TP 3
-\fB1: Switch off VUE's locker\fP
-Open the ``\fIStyle Manager\fP'' and select ``\fIScreen\fP.''
-Turn off ``\fIScreen Saver and Screen Lock\fP'' option.
-.TP 3
-\fB2: Make sure you have a Session\fP
-Next, go to the Style Manager's, ``\fIStartup\fP'' page.
-Click on ``\fISet Home Session\fP'' to create a session, then 
-on ``\fIReturn to Home Session\fP'' to select this session each
-time you log in.
-.TP 3
-\fB3: Edit vue.session\fP
-Edit the file \fI~/.vue/sessions/home/vue.session\fP and add to it
-the line
-.EX
-vuesmcmd -screen 0 -cmd "xscreensaver"
-.EE
-This will cause \fIxscreensaver\fP to be launched when you log in.
-(As always, make sure that xscreensaver and the graphics demos are on
-your \fB$PATH\fP; the path needs to be set in \fI.cshrc\fP
-and/or \fI.profile\fP, not \fI.login\fP.)
-.TP 3
-\fB3: Edit vuewmrc\fP
-Edit the file \fI~/.vue/vuewmrc\fP and add (or change) the Lock control:
-.EX
-CONTROL Lock
-{
-  TYPE         button
-  IMAGE        lock
-  PUSH_ACTION  f.exec "xscreensaver-command -lock"
-  HELP_TOPIC   FPLock
-}
-.EE
-This associates the VUE front panel ``Lock'' icon with the xscreensaver 
-lock command.
-.RE
-.PP
-.SH BUGS
-Bugs?  There are no bugs.  Ok, well, maybe.  If you find one, please let
-me know.  http://www.jwz.org/xscreensaver/bugs.html explains how to
-construct the most useful bug reports.
-.TP 8
-.B Locking and XDM
-If xscreensaver has been launched from 
-.BR xdm (1)
-before anyone has logged in, you will need to kill and then restart the
-xscreensaver daemon after you have logged in, or you will be confused by
-the results.  (For example, locking won't work, and your \fI~/.xscreensaver\fP
-file will be ignored.)
-
-When you are logged in, you want the \fIxscreensaver\fP daemon to be 
-running under \fIyour\fP user id, not as root or some other user.
-
-If it has already been started by \fIxdm\fP, you can kill it by sending
-it the \fBexit\fP command, and then re-launching it as you, by putting
-something like the following in your personal X startup script:
-.EX
-xscreensaver-command -exit
-xscreensaver &
-.EE
-The ``\fIUsing XDM(1)\fP'' section, above, goes into more detail, and explains
-how to configure the system to do this for all users automatically.
-.TP 8
-.B Locking and root logins
-In order for it to be safe for xscreensaver to be launched by \fIxdm\fP,
-certain precautions had to be taken, among them that xscreensaver never
-runs as \fIroot\fP.  In particular, if it is launched as root (as \fIxdm\fP
-is likely to do), xscreensaver will disavow its privileges, and switch 
-itself to a safe user id (such as \fInobody\fP.)
-
-An implication of this is that if you log in as \fIroot\fP on the console, 
-xscreensaver will refuse to lock the screen (because it can't tell
-the difference between \fIroot\fP being logged in on the console, and a
-normal user being logged in on the console but xscreensaver having been 
-launched by the
-.BR xdm (1)
-.I Xsetup
-file.)
+If a line begins with a dash (-) then that particular program is
+disabled: it won't be selected at random (though you can still select
+it explicitly using the
+.BR xscreensaver\-demo (1)
+program.)
 
-The solution to this is simple: you shouldn't be logging in on the console
-as \fIroot\fP in the first place!  (What, are you crazy or something?)  
+If all programs are disabled, then the screen will just be made blank,
+as when \fImode\fP is set to \fIblank\fP.
 
-Proper Unix hygiene dictates that you should log in as yourself, and
-.BR su (1)
-to \fIroot\fP as necessary.  People who spend their day logged in
-as \fIroot\fP are just begging for disaster.
-.TP 8
-.B XAUTH and XDM
-For xscreensaver to work when launched by
-.BR xdm (1),
-programs running on the local machine as user \fI"nobody"\fP must be
-able to connect to the X server.  This means that if you want to run
-xscreensaver on the console while nobody is logged in, you may need
-to disable cookie-based access control (and allow all users who can log
-in to the local machine to connect to the display.)  
+To disable a program, you must mark it as disabled with a dash instead
+of removing it from the list.  This is because the system-wide (app-defaults)
+and per-user (.xscreensaver) settings are merged together, and if a user
+just \fIdeletes\fP an entry from their programs list, but that entry still
+exists in the system-wide list, then it will come back.  However, if the
+user \fIdisables\fP it, then their setting takes precedence.
 
-You should be sure that this is an acceptable thing to do in your
-environment before doing it.  See the ``\fIUsing XDM(1)\fP'' section, 
-above, for more details.
-.TP 8
-.B Passwords
-If you get an error message at startup like ``couldn't get password
-of \fIuser\fP'' 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 in order for
-locking to work.  Care has been taken to make this a safe thing to do.  
+If the display has multiple screens, then a different program will be run
+for each screen.  (All screens are blanked and unblanked simultaneously.)
 
-It also may mean that your system uses shadow passwords instead of the standard
-.BR getpwent (3)
-interface; in that case, you may need to change some options 
-with \fIconfigure\fP and recompile.
+Note that you must escape the newlines; here is an example of how you
+might set this in your \fI~/.xscreensaver\fP file:
 
-If you change your password after xscreensaver has been launched, it will
-continue using your old password to unlock the screen until xscreensaver
-is restarted.  On some systems, it may accept \fIboth\fP your old and new
-passwords.  So, after you change your password, you'll have to do
+.RS 8
 .EX
-xscreensaver-command -restart
+programs:  \\
+       qix -root                          \\n\\
+       ico -r -faces -sleep 1 -obj ico    \\n\\
+       xdaliclock -builtin2 -root         \\n\\
+       xv -root -rmode 5 image.gif -quit  \\n
 .EE
-to make \fIxscreensaver\fP notice.
-.TP 8
-.B PAM Passwords
-If your system uses PAM (Pluggable Authentication Modules), then in order
-for xscreensaver to use PAM properly, PAM must be told about xscreensaver.
-The xscreensaver installation process should update the PAM data (on Linux,
-by creating the file \fI/etc/pam.d/xscreensaver\fP for you, and on Solaris, 
-by telling you what lines to add to the \fI/etc/pam.conf\fP file.)  
-
-If the PAM configuration files do not know about xscreensaver, then 
-you \fImight\fP be in a situation where xscreensaver will refuse to ever
-unlock the screen.
-
-This is a design flaw in PAM (there is no way for a client to tell the
-difference between PAM responding ``I have never heard of your module,''
-and responding, ``you typed the wrong password.'')  As far as I can tell,
-there is no way for xscreensaver to automatically work around this, or
-detect the problem in advance, so if you have PAM, make sure it is
-configured correctly!
-.TP 8
-.B Colormap lossage: TWM
-The \fBinstallColormap\fP option doesn't work very well with the
-.BR twm (1)
-window manager and its descendants, on 8-bit screens.
+.RE
+.RS 8
+Make sure your \fB$PATH\fP environment variable is set up correctly
+\fIbefore\fP xscreensaver is launched, or it won't be able to find the
+programs listed in the \fIprograms\fP resource.
 
-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.  (If the screen goes white instead of black, this is probably why.)
+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
+.BR tvtwm (1).
+(Generally, this is accomplished by just including the \fI"vroot.h"\fP 
+header file in the program's source.)
 
-The
-.BR mwm (1)
-and
-.BR olwm (1)
-window managers don't have this problem.  The race condition exists
-because X (really, ICCCM) 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 xscreensaver installs its colormap, \fBtwm\fP 
-responds to the resultant \fBColormapNotify\fP event by re-installing 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.  
+If there are some programs that you want to run only when using a color
+display, and others that you want to run only when using a monochrome
+display, you can specify that like this:
+.EX
+       mono:   mono-program  -root        \\n\\
+       color:  color-program -root        \\n\\
+.EE
+.RE
+.RS 8
+More generally, you can specify the kind of visual that should be used for
+the window on which the program will be drawing.  For example, if one 
+program works best if it has a colormap, but another works best if it has
+a 24-bit visual, both can be accommodated:
+.EX
+       PseudoColor: cmap-program  -root   \\n\\
+       TrueColor:   24bit-program -root   \\n\\
+.EE
+.RE
 .RS 8
+In addition to the symbolic visual names described above (in the discussion
+of the \fIvisualID\fP resource) one other visual name is supported in
+the \fIprograms\fP list:
+.RS 1
 .TP 4
-.B Attention, window manager authors!
-You should only call
-.BR XInstallColormap (3)
-in response to user events.  That is, it is appropriate to install a colormap
-in response to \fBFocusIn\fP, \fBFocusOut\fP, \fBEnterNotify\fP, 
-and \fBLeaveNotify\fP events; but it is not appropriate to call it in
-response to \fBColormapNotify\fP events.  If you install colormaps in
-response to \fIapplication\fP actions as well as in response to \fIuser\fP
-actions, then you create the situation where it is impossible for 
-override-redirect applications (such as xscreensaver) to display their
-windows in the proper colors.
+.B default-n
+This is like \fBdefault\fP, but also requests the use of the default colormap,
+instead of a private colormap.  (That is, it behaves as if 
+the \fI\-no\-install\fP command-line option was specified, but only for
+this particular hack.)  This is provided because some third-party programs
+that draw on the root window (notably: 
+.BR xv (1),
+and
+.BR xearth (1))
+make assumptions about the visual and colormap of the root window: 
+assumptions which xscreensaver can violate.
+
+.RE
+If you specify a particular visual for a program, and that visual does not
+exist on the screen, then that program will not be chosen to run.  This
+means that on displays with multiple screens of different depths, you can
+arrange for appropriate hacks to be run on each.  For example, if one screen
+is color and the other is monochrome, hacks that look good in mono can be 
+run on one, and hacks that only look good in color will show up on the other.
 .RE
+.PP
+.PP
+You shouldn't ever need to change the following resources:
+.PP
 .TP 8
-.B Colormap lossage: XV, XAnim, XEarth
-Some programs don't operate properly on visuals other than the default one,
-or with colormaps other than the default one.  See the discussion of the
-magic "default-n" visual name in the description of the \fBprograms\fP 
-resource in the \fIConfiguration\fP section.  When programs only work with
-the default colormap, you need to use a syntax like this:
-.EX
-   default-n: xv -root image-1.gif -quit  \\n\\
-   default-n: xearth -nostars -wait 0     \\n\\
-.EE
-It would also work to turn off the \fBinstallColormap\fP option altogether,
-but that would deny extra colors to those programs that \fIcan\fP take
-advantage of them.
+.B pointerPollTime\fP (class \fBTime\fP)
+When server extensions are 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 Machine Load
-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 consume many
-cycles.  Care has been taken in all the modules shipped with xscreensaver
-to sleep periodically, and not run full tilt, so as not to cause
-appreciable load.
-
-However, if you are running the OpenGL-based screen savers on a machine
-that does not have a video card with 3D acceleration, they \fIwill\fP
-make your machine slow, despite
-.BR nice (1).
-
-Your options are: don't use the OpenGL display modes; or, collect the
-spare change hidden under the cushions of your couch, and use it to
-buy a video card manufactured after 1998.  (It doesn't even need to be
-\fIfast\fP 3D hardware: the problem will be fixed if there is any
-3D hardware \fIat all.\fP)
+.B pointerHysteresis\fP (class \fBInteger\fP)
+If the mouse moves less than this-many pixels in a second, ignore it
+(do not consider that to be "activity.")  This is so that the screen
+doesn't un-blank (or fail to blank) just because you bumped the desk.
+Default: 10 pixels.
 .TP 8
-.B XFree86's Magic Keystrokes
-The XFree86 X server traps certain magic keystrokes before client programs ever
-see them.  Two that are of note are Ctrl+Alt+Backspace, which causes 
-the X server to exit; and Ctrl+Alt+F\fIn\fP, which switches virtual consoles.
-The X server will respond to these keystrokes even if xscreensaver has the
-screen locked.  Depending on your setup, you might consider this a problem.
-
-Unfortunately, there is no way for xscreensaver itself to override the
-interpretation of these keys.  If you want to disable Ctrl+Alt+Backspace
-globally, you need to set the \fIDontZap\fP flag in 
-your \fI/etc/X11/XF86Config\fP file.  To globally disable VT switching,
-you can set the \fIDontVTSwitch\fP flag.  See the
-.BR XF86Config (5)
-manual for details.
+.B windowCreationTimeout\fP (class \fBTime\fP)
+When server extensions are 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 initialDelay\fP (class \fBTime\fP)
+When server extensions are 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 0.  (This used to default to 30, but that was
+back in the days when slow machines and X terminals were more common...)
+.RE
+.PP
+There are a number of different X server extensions which can make
+xscreensaver's job easier.  The next few resources specify whether these
+extensions should be utilized if they are available.
+.TP 8
+.B sgiSaverExtension\fP (class \fBBoolean\fP)
+This resource controls whether the SGI \fBSCREEN_SAVER\fP server extension
+will be used to decide whether the user is idle.  This is the default 
+if \fIxscreensaver\fP has been compiled with support for this 
+extension (which is the default on SGI systems.).  If it is available, 
+the \fBSCREEN_SAVER\fP method is faster and more reliable than what will
+be done otherwise, so use it if you can.  (This extension is only available
+on Silicon Graphics systems, unfortunately.)
+.TP 8
+.B mitSaverExtension\fP (class \fBBoolean\fP)
+This resource controls whether the \fBMIT\-SCREEN\-SAVER\fP server extension
+will be used to decide whether the user is idle.  However, the default for
+this resource is \fIfalse\fP, because even if this extension is available,
+it is flaky (and it also makes the \fBfade\fP option not work properly.)
+Use of this extension is strongly discouraged.  Support for it will
+probably be removed eventually.
+.TP 8
+.B xidleExtension\fP (class \fBBoolean\fP)
+This resource controls whether the \fBXIDLE\fP server extension will be
+used to decide whether the user is idle.  This is the default 
+if \fIxscreensaver\fP has been compiled with support for this extension.
+(This extension is only available for X11R4 and X11R5 systems, unfortunately.)
 .TP 8
-.B MIT Extension and Fading
-The \fBMIT-SCREEN-SAVER\fP extension is junk.  Don't use it.
+.B procInterrupts\fP (class \fBBoolean\fP)
+This resource controls whether the \fB/proc/interrupts\fP file should be
+consulted to decide whether the user is idle.  This is the default
+if \fIxscreensaver\fP has been compiled on a system which supports this
+mechanism (i.e., Linux systems.)  
 
-When using the \fBMIT-SCREEN-SAVER\fP extension in conjunction with 
-the \fBfade\fP option, you'll notice an unattractive flicker just before 
-the fade begins.  This is because the server maps a black window just before 
-it tells the \fIxscreensaver\fP process to activate.  The \fIxscreensaver\fP 
-process immediately unmaps that window, but this results in a flicker.  I 
-haven't figured a way  to get around this; it seems to be a fundamental
-property of the (mis-) design of this server extension.
+The benefit to doing this is that \fIxscreensaver\fP can note that the user
+is active even when the X console is not the active one: if the user is 
+typing in another virtual console, xscreensaver will notice that and will
+fail to activate.  For example, if you're playing Quake in VGA-mode, 
+xscreensaver won't wake up in the middle of your game and start competing 
+for CPU.
 
-It sure would be nice if someone would implement the \fBSGI SCREEN_SAVER\fP
-extension in XFree86; it's dead simple, and works far better than the
-over-engineered and broken \fBMIT-SCREEN-SAVER\fP extension.
-.TP 8
-.B Keyboard LEDs
-If \fIprocInterrupts\fP is on (which is the default on Linux systems) and
-you're using some program that toggles the state of your keyboard LEDs,
-xscreensaver won't work right: turning those LEDs on or off causes a 
-keyboard interrupt, which xscreensaver will interpret as user activity.
-So if you're using such a program, set the \fIprocInterrupts\fP resource
-to False.
-.TP 8
-.B Extensions
-If you are not making use of one of the server extensions (\fBXIDLE\fP,
-\fBSGI SCREEN_SAVER\fP, or \fBMIT-SCREEN-SAVER\fP), then it is possible, in 
-rare situations, for \fIxscreensaver\fP to interfere with event propagation 
-and make another X program malfunction.  For this to occur, that other
-application would need to \fInot\fP select \fBKeyPress\fP events on its 
-non-leaf windows within the first 30 seconds of their existence, but then 
-select for them later.  In this case, that client \fImight\fP fail to receive 
-those events.  This isn't very likely, since programs generally select a
-constant set of events immediately after creating their windows and then 
-don't change them, but this is the reason that it's a good idea to install 
-and use one of the server extensions instead, to work around this shortcoming
-in the X protocol.
+The drawback to doing this is that perhaps you \fIreally do\fP want idleness
+on the X console to cause the X display to lock, even if there is activity
+on other virtual consoles.  If you want that, then set this option to False.
+(Or just lock the X console manually.)
 
-In all these years, I've not heard of even a single case of this happening,
-but it is theoretically possible, so I'm mentioning it for completeness...
+The default value for this resource is True, on systems where it works.
+.TP 8
+.B overlayStderr\fP (class \fBBoolean\fP)
+If \fBcaptureStderr\fP is True, and your server supports ``overlay'' visuals,
+then the text will be written into one of the higher layers instead of into
+the same layer as the running screenhack.  Set this to False to disable 
+that (though you shouldn't need to.)
+.TP 8
+.B overlayTextForeground\fP (class \fBForeground\fP)
+The foreground color used for the stdout/stderr text, if \fBcaptureStderr\fP
+is true.  Default: Yellow.
+.TP 8
+.B overlayTextBackground\fP (class \fBBackground\fP)
+The background color used for the stdout/stderr text, if \fBcaptureStderr\fP
+is true.  Default: Black.
+.TP 8
+.B bourneShell\fP (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.
 .SH ENVIRONMENT
 .PP
 .TP 8
@@ -1157,6 +882,11 @@ but it is theoretically possible, so I'm mentioning it for completeness...
 to get the default host and display number, and to inform the sub-programs
 of the screen on which to draw.
 .TP 8
+.B XSCREENSAVER_WINDOW
+Passed to sub-programs to indicate the ID of the window on which they
+should draw on.  This is necessary on Xinerama/RANDR systems where
+multiple physical monitors share a single X11 "Screen".
+.TP 8
 .B PATH
 to find the sub-programs to run.
 .TP 8
@@ -1183,13 +913,14 @@ and a FAQ can always be found at http://www.jwz.org/xscreensaver/
 .BR xscreensaver\-text (1).
 .SH COPYRIGHT
 Copyright \(co 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-2000, 2001, 2002, 2003, 2004, 2005 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.
+2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 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@jwz.org>.  Written in late 1991; version 1.0 posted
 to comp.sources.x on 17-Aug-1992.
index 2e26478661b6efcd888b54e5e105a7d67d08d8fa..898853ca5d598fd96049d027cee70f546a8a336d 100644 (file)
@@ -152,7 +152,7 @@ OBJS                = attraction.o blitspin.o bouboule.o braid.o bubbles.o \
                  intermomentary.o fireworkx.o fiberlamp.o boxfit.o \
                  interaggregate.o celtic.o cwaves.o webcollage-cocoa.o \
                  webcollage-helper-cocoa.o m6502.0 asm6502.o abstractile.o \
-                 lcdscrub.
+                 lcdscrub.o
 
 NEXES          = attraction blitspin bouboule braid bubbles decayscreen deco \
                  drift flag flame forest vines galaxy grav greynetic halo \
@@ -222,7 +222,7 @@ MEN         = anemone.man apollonian.man attraction.man \
                  anemotaxis.man memscroller.man substrate.man \
                  intermomentary.man fireworkx.man fiberlamp.man boxfit.man \
                  interaggregate.man celtic.man cwaves.man abstractile.man \
-                 lcdscrub
+                 lcdscrub.man
 STAR           = *
 EXTRAS         = README Makefile.in xml2man.pl m6502.sh .gdbinit \
                  euler2d.tex \
@@ -1186,6 +1186,7 @@ bsod.o: $(srcdir)/apple2.h
 bsod.o: ../config.h
 bsod.o: $(srcdir)/images/amiga.xpm
 bsod.o: $(srcdir)/images/atari.xbm
+bsod.o: $(srcdir)/images/atm.xbm
 bsod.o: $(srcdir)/images/hmac.xpm
 bsod.o: $(srcdir)/images/macbomb.xbm
 bsod.o: $(srcdir)/images/mac.xbm
index 38d82285c710549017dc588521aa0f063a9efe74..0be3c96d2a5648d325391edb6789e4e797b02b61 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1992-2006 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1992-2008 Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -40,6 +40,7 @@ struct state {
   GC SET, CLR, CPY, IOR, AND, XOR;
   GC gc;
   int delay, delay2;
+  int duration;
   Pixmap bitmap;
   unsigned int fg, bg;
 
@@ -47,6 +48,7 @@ struct state {
   int first_time;
   int last_w, last_h;
 
+  time_t start_time;
   Bool loaded_p;
   async_load_state *img_loader;
 };
@@ -71,9 +73,24 @@ blitspin_draw (Display *dpy, Window window, void *closure)
   if (st->img_loader)   /* still loading */
     {
       st->img_loader = load_image_async_simple (st->img_loader, 0, 0, 0, 0, 0);
+
+      if (!st->img_loader) { /* just finished */
+        st->first_time = 0;
+        st->loaded_p = False;
+        st->qwad = -1;
+        st->start_time = time ((time_t) 0);
+      }
+
       return this_delay;
     }
 
+  if (!st->img_loader &&
+      st->start_time + st->duration < time ((time_t) 0)) {
+    /* Start it loading, but keep rotating the old image until it arrives. */
+    st->img_loader = load_image_async_simple (0, st->xgwa.screen, st->window,
+                                              st->bitmap, 0, 0);
+  }
+
   if (! st->loaded_p) {
     blitspin_init_2 (st);
     st->loaded_p = True;
@@ -95,21 +112,21 @@ blitspin_draw (Display *dpy, Window window, void *closure)
 
   /* for (st->qwad = st->size>>1; st->qwad > 0; st->qwad>>=1) */
 
-  copy_all_to   (st->mask,       0,       0, st->temp, st->CPY);  /* 1 */
-  copy_all_to   (st->mask,       0,    st->qwad, st->temp, st->IOR);  /* 2 */
-  copy_all_to   (st->self,       0,       0, st->temp, st->AND);  /* 3 */
-  copy_all_to   (st->temp,       0,       0, st->self, st->XOR);  /* 4 */
-  copy_all_from (st->temp,    st->qwad,       0, st->self, st->XOR);  /* 5 */
-  copy_all_from (st->self,    st->qwad,       0, st->self, st->IOR);  /* 6 */
-  copy_all_to   (st->temp,    st->qwad,       0, st->self, st->XOR);  /* 7 */
-  copy_all_to   (st->self,       0,       0, st->temp, st->CPY);  /* 8 */
-  copy_all_from (st->temp,    st->qwad,    st->qwad, st->self, st->XOR);  /* 9 */
-  copy_all_to   (st->mask,       0,       0, st->temp, st->AND);  /* A */
-  copy_all_to   (st->temp,       0,       0, st->self, st->XOR);  /* B */
-  copy_all_to   (st->temp,    st->qwad,    st->qwad, st->self, st->XOR);  /* C */
-  copy_all_from (st->mask, st->qwad>>1, st->qwad>>1, st->mask, st->AND);  /* D */
-  copy_all_to   (st->mask,    st->qwad,       0, st->mask, st->IOR);  /* E */
-  copy_all_to   (st->mask,       0,    st->qwad, st->mask, st->IOR);  /* F */
+  copy_all_to  (st->mask, 0,        0,        st->temp, st->CPY);  /* 1 */
+  copy_all_to  (st->mask, 0,        st->qwad, st->temp, st->IOR);  /* 2 */
+  copy_all_to  (st->self, 0,        0,        st->temp, st->AND);  /* 3 */
+  copy_all_to  (st->temp, 0,        0,        st->self, st->XOR);  /* 4 */
+  copy_all_from(st->temp, st->qwad, 0,        st->self, st->XOR);  /* 5 */
+  copy_all_from(st->self, st->qwad, 0,        st->self, st->IOR);  /* 6 */
+  copy_all_to  (st->temp, st->qwad, 0,        st->self, st->XOR);  /* 7 */
+  copy_all_to  (st->self, 0,        0,        st->temp, st->CPY);  /* 8 */
+  copy_all_from(st->temp, st->qwad,           st->qwad, st->self,st->XOR);/*9*/
+  copy_all_to  (st->mask, 0,        0,        st->temp, st->AND);  /* A */
+  copy_all_to  (st->temp, 0,        0,        st->self, st->XOR);  /* B */
+  copy_all_to  (st->temp, st->qwad, st->qwad, st->self, st->XOR);  /* C */
+  copy_all_from(st->mask, st->qwad>>1,st->qwad>>1,st->mask,st->AND); /* D */
+  copy_all_to  (st->mask, st->qwad, 0,        st->mask, st->IOR);  /* E */
+  copy_all_to  (st->mask, 0,        st->qwad, st->mask, st->IOR);  /* F */
   display (st, st->self);
 
   st->qwad >>= 1;
@@ -155,8 +172,13 @@ blitspin_init (Display *d_arg, Window w_arg)
                                "background", "Background");
   st->delay = get_integer_resource (st->dpy, "delay", "Integer");
   st->delay2 = get_integer_resource (st->dpy, "delay2", "Integer");
+  st->duration = get_integer_resource (st->dpy, "duration", "Seconds");
   if (st->delay < 0) st->delay = 0;
   if (st->delay2 < 0) st->delay2 = 0;
+  if (st->duration < 1) st->duration = 1;
+
+  st->start_time = time ((time_t) 0);
+
   bitmap_name = get_string_resource (st->dpy, "bitmap", "Bitmap");
   if (! bitmap_name || !*bitmap_name)
     bitmap_name = "(default)";
@@ -164,6 +186,9 @@ blitspin_init (Display *d_arg, Window w_arg)
   if (!strcasecmp (bitmap_name, "(default)") ||
       !strcasecmp (bitmap_name, "default"))
 # ifdef HAVE_COCOA
+    /* I don't understand why it doesn't work with color images on OSX.
+       I guess "kCGBlendModeDarken" is not close enough to being "GXand".
+     */
     bitmap_name = "(builtin)";
 # else
     bitmap_name = "(screen)";
@@ -237,11 +262,23 @@ blitspin_init_2 (struct state *st)
   XFillRectangle (st->dpy, st->self, st->gc, 0, 0, st->size, st->size);
   XSetForeground (st->dpy, st->gc, st->fg);
 
+#if 0
+#ifdef HAVE_COCOA
+  jwxyz_XSetAntiAliasing (st->dpy, st->gc,  False);
+  jwxyz_XSetAntiAliasing (st->dpy, st->SET, False);
+  jwxyz_XSetAntiAliasing (st->dpy, st->CLR, False);
+  jwxyz_XSetAntiAliasing (st->dpy, st->CPY, False);
+  jwxyz_XSetAntiAliasing (st->dpy, st->IOR, False);
+  jwxyz_XSetAntiAliasing (st->dpy, st->AND, False);
+  jwxyz_XSetAntiAliasing (st->dpy, st->XOR, False);
+#endif /* HAVE_COCOA */
+#endif
+
   XCopyArea (st->dpy, st->bitmap, st->self, st->CPY, 0, 0, 
              st->width, st->height,
             (st->size - st->width)  >> 1,
              (st->size - st->height) >> 1);
-  XFreePixmap(st->dpy, st->bitmap);
+/*  XFreePixmap(st->dpy, st->bitmap);*/
 
   st->qwad = -1;
   st->first_time = 1;
@@ -299,6 +336,7 @@ static const char *blitspin_defaults [] = {
   ".foreground:        white",
   "*delay:     500000",
   "*delay2:    500000",
+  "*duration:  120",
   "*bitmap:    (default)",
   "*geometry:  512x512",
   0
@@ -307,6 +345,7 @@ static const char *blitspin_defaults [] = {
 static XrmOptionDescRec blitspin_options [] = {
   { "-delay",          ".delay",       XrmoptionSepArg, 0 },
   { "-delay2",         ".delay2",      XrmoptionSepArg, 0 },
+  { "-duration",       ".duration",    XrmoptionSepArg, 0 },
   { "-bitmap",         ".bitmap",      XrmoptionSepArg, 0 },
   { 0, 0, 0, 0 }
 };
index 0d2b9fbbbee17538f036857d45b8422f18539d84..17d28a6f65bd39507ffcb27b04b23a80d62b0deb 100644 (file)
@@ -6,7 +6,7 @@ blitspin - rotate a bitmap in an interesting way
 [\-display \fIhost:display.screen\fP]
 [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root]
 [\-mono] [\-install] [\-visual \fIvisual\fP] [\-bitmap \fIfilename\fP]
-[\-delay \fIusecs\fP] [\-delay2 \fIusecs\fP]
+[\-delay \fIusecs\fP] [\-delay2 \fIusecs\fP] [\-duration \fIsecs\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
@@ -56,12 +56,13 @@ and \fIchooseRandomImages\fP options in the \fI~/.xscreensaver\fP file;
 see
 .BR xscreensaver-demo (1)
 for more details.
-.PP
 .TP 8
 .B \-delay \fImicroseconds\fP
 How long to delay between steps of the rotation process, in microseconds.
 Default is 500000, one-half second.
-.PP
+.TP 8
+.B \-duration \fIseconds\fP
+How long to run before loading a new image.  Default 120 seconds.
 .TP 8
 .B \-delay2 \fImicroseconds\fP
 How long to delay between each 90-degree rotation, in microseconds.
index a38f151fe54d986ce6f9c7c364daaa7b1d367e4b..e520433ad5cd4f4788d035d9078715dfec3ebfaa 100644 (file)
@@ -62,6 +62,7 @@
 #include "images/atari.xbm"
 #include "images/mac.xbm"
 #include "images/macbomb.xbm"
+#include "images/atm.xbm"
 
 #undef countof
 #define countof(x) (sizeof((x))/sizeof((*x)))
@@ -919,7 +920,7 @@ windows_xp (Display *dpy, Window window)
       "Physical memory dump complete.\n"
       "Contact your system administrator or technical support group for "
       "further\n"
-      "assitance.\n");
+      "assistance.\n");
 
   XClearWindow (dpy, window);
   return bst;
@@ -2361,7 +2362,7 @@ hppa_linux (Display *dpy, Window window)
      { -1, "Soft power switch enabled, polling @ 0xf0400804.\n" },
      { -1, "pty: 256 Unix98 ptys configured\n" },
      { -1, "Generic RTC Driver v1.07\n" },
-     { -1, "Serial: 8250/16550 driver $Revision: 1.88 $ 13 ports, "
+     { -1, "Serial: 8250/16550 driver $Revision: 1.90 $ 13 ports, "
            "IRQ sharing disabled\n" },
      { -1, "ttyS0 at I/O 0x3f8 (irq = 0) is a 16550A\n" },
      { -1, "ttyS1 at I/O 0x2f8 (irq = 0) is a 16550A\n" },
@@ -3517,6 +3518,58 @@ apple2crash (Display *dpy, Window window)
 }
 
 
+static struct bsod_state *
+atm (Display *dpy, Window window)
+{
+  struct bsod_state *bst = make_bsod_state (dpy, window, "atm", "ATM");
+
+  Pixmap pixmap = 0;
+  int pix_w = atm_width;
+  int pix_h = atm_height;
+  int x, y, i = 0;
+  float scale = 0.48;
+
+  XClearWindow (dpy, window);
+
+  pixmap = XCreatePixmapFromBitmapData (dpy, window, (char *) atm_bits,
+                                        atm_width, atm_height,
+                                        bst->fg, bst->bg, bst->xgwa.depth);
+
+  while (pix_w <= bst->xgwa.width  * scale && 
+         pix_h <= bst->xgwa.height * scale)
+    {
+      pixmap = double_pixmap (dpy, bst->gc, bst->xgwa.visual, bst->xgwa.depth,
+                              pixmap, pix_w, pix_h);
+      pix_w *= 2;
+      pix_h *= 2;
+      i++;
+    }
+
+  x = (bst->xgwa.width  - pix_w) / 2;
+  y = (bst->xgwa.height - pix_h) / 2;
+  if (y < 0) y = 0;
+
+  if (i > 0)
+    {
+      int j;
+      XSetForeground (dpy, bst->gc,
+                      get_pixel_resource (dpy, bst->xgwa.colormap,
+                                          "atm.background",
+                                          "ATM.Background"));
+      for (j = -1; j < pix_w; j += i+1)
+        XDrawLine (bst->dpy, pixmap, bst->gc, j, 0, j, pix_h);
+      for (j = -1; j < pix_h; j += i+1)
+        XDrawLine (bst->dpy, pixmap, bst->gc, 0, j, pix_w, j);
+    }
+
+  XCopyArea (dpy, pixmap, window, bst->gc, 0, 0, pix_w, pix_h, x, y);
+
+  XFreePixmap (dpy, pixmap);
+
+  return bst;
+}
+
+
 /*****************************************************************************
  *****************************************************************************/
 
@@ -3552,6 +3605,7 @@ static const struct {
   { "MSDOS",           msdos },
   { "Nvidia",          nvidia },
   { "Apple2",          apple2crash },
+  { "ATM",             atm },
 };
 
 
@@ -3840,6 +3894,7 @@ static const char *bsod_defaults [] = {
   "*doMSDOS:              True",
   "*doOS2:                True",
   "*doNvidia:             True",
+  "*doATM:                True",
 
   "*font:                 9x15bold",
   "*font2:                -*-courier-bold-r-*-*-*-120-*-*-m-*-*-*",
@@ -3932,6 +3987,9 @@ static const char *bsod_defaults [] = {
   ".os2.foreground:       White",
   ".os2.background:       Black",
 
+  ".atm.foreground:       Black",
+  ".atm.background:       #FF6600",
+
   "*dontClearRoot:         True",
 
   "*apple2TVColor:         50",
@@ -4002,6 +4060,8 @@ static const XrmOptionDescRec bsod_options [] = {
   { "-no-msdos",       ".doMSDOS",             XrmoptionNoArg,  "False" },
   { "-os2",            ".doOS2",               XrmoptionNoArg,  "True"  },
   { "-no-os2",         ".doOS2",               XrmoptionNoArg,  "False" },
+  { "-atm",            ".doATM",               XrmoptionNoArg,  "True"  },
+  { "-no-atm",         ".doATM",               XrmoptionNoArg,  "False" },
   ANALOGTV_OPTIONS
   { 0, 0, 0, 0 }
 };
index 49588088878f5910b9d641c4fdfbfe640ffa325c..7800861bc47cbef1a320d4417bfcaa964e736210 100644 (file)
@@ -92,8 +92,9 @@ hacks are displayed and which aren't.
 .BR doVMS ,
 .BR doMSDOS ,
 .BR doOS2 ,
+.BR doHVX ,
 and
-.BR doHVX .
+.BR doATM .
 Each of these is a Boolean resource, they all default to true, except
 for doAtari, doBSD, doSparcLinux, and doHPPALinux, which are turned off
 by default, because they're really not all that interesting looking
index 2f510f5a9b5a5b15487a21ddb4e457a5e953b223..094d31306c95485df70edd3e947ab0f35a72dcf2 100644 (file)
@@ -161,6 +161,7 @@ static void CreateBumps( SBumps *pBumps, Display *dpy, Window NewWin )
        pBumps->SpotLight.nAccelMax = pBumps->SpotLight.nVelocityMax / 10.0f;
        pBumps->dpy = dpy;
        pBumps->Win = NewWin;
+    pBumps->screen = XWinAttribs.screen;
        pBumps->pXImage = NULL;
        
        iDiameter = ( ( pBumps->iWinWidth < pBumps->iWinHeight ) ? pBumps->iWinWidth : pBumps->iWinHeight ) / 2;
@@ -330,11 +331,13 @@ static void InitBumpMap_2(Display *dpy, SBumps *pBumps)
     XWindowAttributes XWinAttribs;
     XGetWindowAttributes( pBumps->dpy, pBumps->Win, &XWinAttribs );
 
+    pBumps->start_time = time ((time_t) 0);
+
        pScreenImage = XGetImage( pBumps->dpy, pBumps->source, 0, 0, 
                               pBumps->iWinWidth, pBumps->iWinHeight,
                               ~0L, ZPixmap );
-    XFreePixmap (pBumps->dpy, pBumps->source);
-    pBumps->source = 0;
+/*    XFreePixmap (pBumps->dpy, pBumps->source);
+    pBumps->source = 0;*/
 
        XSetWindowBackground( pBumps->dpy, pBumps->Win, pBumps->aColors[ 0 ] );
        XClearWindow (pBumps->dpy, pBumps->Win);
@@ -389,8 +392,8 @@ static void InitBumpMap_2(Display *dpy, SBumps *pBumps)
        while( nSoften-- )
                SoftenBumpMap( pBumps );
 
-       free( pBumps->xColors );
-    pBumps->xColors = 0;
+/*     free( pBumps->xColors );
+    pBumps->xColors = 0;*/
 }
 
 /* Soften the bump map.  This is to avoid pixelated-looking ridges.
@@ -558,6 +561,10 @@ bumps_init (Display *dpy, Window Win)
        
        CreateBumps( Bumps, dpy, Win );
        Bumps->delay = get_integer_resource(dpy,  "delay", "Integer" );
+    Bumps->duration = get_integer_resource (dpy, "duration", "Seconds");
+    if (Bumps->delay < 0) Bumps->delay = 0;
+    if (Bumps->duration < 1) Bumps->duration = 1;
+    Bumps->start_time = time ((time_t) 0);
     return Bumps;
 }
 
@@ -574,7 +581,12 @@ bumps_draw (Display *dpy, Window window, void *closure)
       return Bumps->delay;
     }
 
-
+  if (!Bumps->img_loader &&
+      Bumps->start_time + Bumps->duration < time ((time_t) 0)) {
+    Bumps->img_loader = load_image_async_simple (0, Bumps->screen,
+                                                 Bumps->Win, Bumps->source, 
+                                                 0, 0);
+  }
 
   Execute( Bumps );
 
index ee61755db866e1e406ff4e46d5de84ea71cf53b3..afac1b1c4048539d9b947159e5f7e73545cf82eb 100644 (file)
@@ -57,6 +57,7 @@ static const char *bumps_defaults [] = {
   "*color:             random",
   "*colorcount:        64",
   "*delay:             30000",
+  "*duration:  120",
   "*soften:            1",
   "*invert:            FALSE",
 #ifdef __sgi    /* really, HAVE_READ_DISPLAY_EXTENSION */
@@ -71,6 +72,7 @@ static const char *bumps_defaults [] = {
 static XrmOptionDescRec bumps_options [] = {
   { "-color",          ".color",               XrmoptionSepArg, 0 },
   { "-colorcount",     ".colorcount",  XrmoptionSepArg, 0 },
+  { "-duration",       ".duration",    XrmoptionSepArg, 0 },
   { "-delay",          ".delay",               XrmoptionSepArg, 0 },
   { "-soften",         ".soften",              XrmoptionSepArg, 0 },
   { "-invert",         ".invert",              XrmoptionNoArg, "TRUE" },
@@ -106,6 +108,7 @@ typedef struct
        /* XWindows specific variables. */
        Display *dpy;
        Window Win;
+       Screen *screen;
         Pixmap source;
        GC GraphicsContext;
        XColor *xColors;
@@ -123,6 +126,8 @@ typedef struct
        SSpotLight SpotLight;
 
         int delay;
+        int duration;
+        time_t start_time;
 
         async_load_state *img_loader;
 } SBumps;
index fe551ca714833a0a2205f2de36ef16b20211a220..d6f80145b80863ca44b41fbadc4d612b8907eead 100644 (file)
@@ -12,6 +12,7 @@ bumps - move distorting spotlight around desktop
 [\-install]
 [\-visual \fIvisual\fP]
 [\-delay \fIusecs\fP]
+[\-duration \fIsecs\fP]
 .SH DESCRIPTION
 The \fIbumps\fP program takes an image and exposes small, distorted
 sections of it as if through an odd wandering spotlight beam.
@@ -46,6 +47,9 @@ or the id number (decimal or hex) of a specific visual.
 .TP 8
 .B \-delay \fImicroseconds\fP
 Slow it down.
+.TP 8
+.B \-duration \fIseconds\fP
+How long to run before loading a new image.  Default 120 seconds.
 .SH ENVIRONMENT
 .PP
 .TP 8
index d1462bc73ddfaf16eb1a131e82e8594f414560eb..df490d302dbb1173cc38bca528a4641c2f9d9c09 100644 (file)
@@ -4,8 +4,8 @@
             a screen saver and locker for the X window system
                             by Jamie Zawinski
 
-                              version 5.05
-                               01-Mar-2008
+                              version 5.06
+                               16-Jul-2008
 
                      http://www.jwz.org/xscreensaver/
 
index 39aa08ec1d61cf42420443bc883b9c047d401216..868f87aa94fb3f433fd30f6fb92e6772a4ea7602 100644 (file)
@@ -4,6 +4,7 @@
 
   <command arg="-root"/>
 
+  <hgroup>
   <select id="mode">
     <option id="balls"    _label="Balls"    arg-set="-mode balls"/>
     <option id="lines"    _label="Lines"    arg-set="-mode lines"/>
@@ -19,6 +20,8 @@
     <option id="nowalls" _label="Ignore Screen Edges" arg-set="-nowalls"/>
   </select>
 
+  </hgroup>
+
   <hgroup>
     <number id="points" type="spinbutton" arg="-points %"
               _label="Ball Count" low="0" high="200" default="0"/>
             _label="Number of Colors" _low-label="Two" _high-label="Many"
             low="1" high="255" default="200"/>
 
+<!--
   <number id="color_contrast" type="slider" arg="-color-shift %"
           _label="Color Contrast" _low-label="Low" _high-label="High"
            low="0" high="25" default="3"/>
+-->
 
-  <boolean id="orbit" _label="Orbital Mode" arg-set="-orbit"/>
   <hgroup>
+    <boolean id="orbit" _label="Orbital Mode" arg-set="-orbit"/>
     <number id="radius" type="spinbutton" arg="-radius %"
               _label="Radius" low="0" high="1000" default="0"/>
     <number id="vmult" type="slider" arg="-vmult %"
index 7aaf308e729957ae6bdc851b9c979cf6c1e4a2a8..0d838864f066ca717580f49c71749be0af82a3df 100644 (file)
           low="1" high="800000" default="500000"
           convert="invert"/>
 
+  <number id="duration" type="slider" arg="-duration %"
+          _label="Duration" _low-label="10 seconds" _high-label="10 minutes"
+          low="10" high="600" default="120"/>
+
 <!--  <file id="bitmap" _label="Bitmap to rotate" arg="-bitmap %"/> -->
 
   <xscreensaver-image />
index a5d58d6e0c275fc52b05fef28eb095bdb6873ac3..24d2317367b32e90cf0630e09216bcf1f5aa87b4 100644 (file)
@@ -2,53 +2,54 @@
 
 <screensaver name="bsod" _label="BSOD">
 
 <command arg="-root"/>
+ <command arg="-root"/>
 
 <number id="delay" type="slider" arg="-delay %"
-          _label="Duration" _low-label="5 seconds" _high-label="2 minutes"
-          low="5" high="120" default="30"/>
+ <number id="delay" type="slider" arg="-delay %"
+         _label="Duration" _low-label="5 seconds" _high-label="2 minutes"
+         low="5" high="120" default="30"/>
 
-  <hgroup>
-   <vgroup>
-     <boolean id="windows"    _label="Windows 3.1"  arg-unset="-no-windows"/>
-     <boolean id="nt"         _label="Windows NT"   arg-unset="-no-nt"/>
-     <boolean id="2k"         _label="Windows 2000  " arg-unset="-no-2k"/>
-     <boolean id="msdos"      _label="MS-DOS"       arg-unset="-no-msdos"/>
-     <boolean id="amiga"      _label="AmigaDOS"     arg-unset="-no-amiga"/>
-     <boolean id="atari"      _label="Atari"        arg-set="-atari"/>
-     <boolean id="apple2"     _label="Apple II"     arg-unset="-no-apple2"/>
-     <boolean id="nvidia"     _label="Nvidia"       arg-unset="-no-nvidia"/>
-     <boolean id="os2"      _label="OS/2"        arg-unset="-no-os2"/>
-   </vgroup>
-   <vgroup>
-     <boolean id="mac"        _label="Sad Mac"      arg-unset="-no-mac"/>
-     <boolean id="mac1"       _label="Mac Bomb"     arg-unset="-no-mac1"/>
-     <boolean id="macsbug"    _label="MacsBug"      arg-unset="-no-macsbug"/>
-     <boolean id="macx"       _label="MacOS X"      arg-unset="-no-macx"/>
-     <boolean id="os390"      _label="OS/390"       arg-unset="-no-os390"/>
-     <boolean id="vms"        _label="VMS"          arg-unset="-no-vms"/>
-     <boolean id="hvx"        _label="HVX/GCOS6"    arg-unset="-no-hvx"/>
-     <boolean id="blitdamage" _label="NCD X Terminal  " arg-unset="-no-blitdamage"/>
-   </vgroup>
-   <vgroup>
-     <boolean id="bsd"        _label="BSD"          arg-set="-bsd"/>
-     <boolean id="linux"      _label="Linux (fsck)" arg-unset="-no-linux"/>
-     <boolean id="sparclinux" _label="Linux (sparc)" arg-set="-sparclinux"/>
-     <boolean id="hppalinux"  _label="Linux (hppa)" arg-unset="-no-hppalinux"/>
-     <boolean id="solaris"    _label="Solaris"      arg-unset="-no-solaris"/>
-     <boolean id="sco"        _label="SCO"          arg-unset="-no-sco"/>
-     <boolean id="hpux"       _label="HPUX"         arg-unset="-no-hpux"/>
-     <boolean id="tru64"      _label="Tru64"        arg-unset="-no-tru64"/>
-   </vgroup>
-  </hgroup>
+ <hgroup>
+  <vgroup>
+   <boolean id="windows"    _label="Windows 3.1"    arg-unset="-no-windows"/>
+   <boolean id="nt"         _label="Windows NT"     arg-unset="-no-nt"/>
+   <boolean id="2k"         _label="Windows 2000  " arg-unset="-no-2k"/>
+   <boolean id="msdos"      _label="MS-DOS"         arg-unset="-no-msdos"/>
+   <boolean id="amiga"      _label="AmigaDOS"       arg-unset="-no-amiga"/>
+   <boolean id="atari"      _label="Atari"          arg-set="-atari"/>
+   <boolean id="apple2"     _label="Apple II"       arg-unset="-no-apple2"/>
+   <boolean id="nvidia"     _label="Nvidia"         arg-unset="-no-nvidia"/>
+   <boolean id="os2"        _label="OS/2"           arg-unset="-no-os2"/>
+  </vgroup>
+  <vgroup>
+   <boolean id="mac"        _label="Sad Mac"        arg-unset="-no-mac"/>
+   <boolean id="mac1"       _label="Mac Bomb"       arg-unset="-no-mac1"/>
+   <boolean id="macsbug"    _label="MacsBug"        arg-unset="-no-macsbug"/>
+   <boolean id="macx"       _label="MacOS X"        arg-unset="-no-macx"/>
+   <boolean id="os390"      _label="OS/390"         arg-unset="-no-os390"/>
+   <boolean id="vms"        _label="VMS"            arg-unset="-no-vms"/>
+   <boolean id="hvx"        _label="HVX/GCOS6"      arg-unset="-no-hvx"/>
+   <boolean id="blitdamage" _label="NCD X Terminal  " arg-unset="-no-blitdamage"/>
+   <boolean id="atm"        _label="ATM"            arg-unset="-no-atm"/>
+  </vgroup>
+  <vgroup>
+   <boolean id="bsd"        _label="BSD"            arg-set="-bsd"/>
+   <boolean id="linux"      _label="Linux (fsck)"   arg-unset="-no-linux"/>
+   <boolean id="sparclinux" _label="Linux (sparc)"  arg-set="-sparclinux"/>
+   <boolean id="hppalinux"  _label="Linux (hppa)"   arg-unset="-no-hppalinux"/>
+   <boolean id="solaris"    _label="Solaris"        arg-unset="-no-solaris"/>
+   <boolean id="sco"        _label="SCO"            arg-unset="-no-sco"/>
+   <boolean id="hpux"       _label="HPUX"           arg-unset="-no-hpux"/>
+   <boolean id="tru64"      _label="Tru64"          arg-unset="-no-tru64"/>
+  </vgroup>
+ </hgroup>
 
 <xscreensaver-image />
+ <xscreensaver-image />
 
 <_description>
+ <_description>
 BSOD stands for "Blue Screen of Death".  The finest in personal
 computer emulation, this program simulates popular screen savers from a
 number of less robust operating systems.
 
 Written by Jamie Zawinski; 1998.
 </_description>
+ </_description>
 </screensaver>
index 2afec2492e3e9dc9a4edc341d8af5245473e1aef..67713de2fd6160a7b66f9a686f328a3c24b408ba 100644 (file)
           low="0" high="100000" default="30000"
           convert="invert"/>
 
+  <number id="duration" type="slider" arg="-duration %"
+          _label="Duration" _low-label="10 seconds" _high-label="10 minutes"
+          low="10" high="600" default="120"/>
+
   <!-- #### -soften [1] -->
   <!-- #### -invert -->
 
index 2f56cfa74035ed26058963a0c312328b8ff64fce..113d48465d0331cbf934dc78709e62e1299f1d32 100644 (file)
@@ -7,6 +7,12 @@
   <hgroup>
     <number id="count" type="spinbutton" arg="-count %"
             _label="Number of Images:" low="1" high="20" default="7"/>
+    <select id="mode">
+      <option id="tiltxy"  _label="Tilt In/Out and Left/Right"/>
+      <option id="tiltx"   _label="Tilt In/Out Only"     arg-set="-tilt x"/>
+      <option id="tilty"   _label="Tilt Left/Right Only" arg-set="-tilt y"/>
+      <option id="notilt"  _label="No Tilting"           arg-set="-tilt 0"/>
+    </select>
   </hgroup>
 
   <number id="duration" type="slider" arg="-duration %"
           low="0" high="100000" default="20000"
           convert="invert"/>
 
-  <select id="mode">
-    <option id="tiltxy"  _label="Tilt In/Out and Left/Right"/>
-    <option id="tiltx"   _label="Tilt In/Out Only"     arg-set="-tilt x"/>
-    <option id="tilty"   _label="Tilt Left/Right Only" arg-set="-tilt y"/>
-    <option id="notilt"  _label="No Tilting"           arg-set="-tilt 0"/>
-  </select>
-
   <xscreensaver-image />
 
   <boolean id="zoom" _label="Zoom In/Out" arg-unset="-no-zoom"/>
index c9b3ec275b0dd0637bf0d31cd26335ea6d004a5c..557924fcd46437d2cb09e8c78ed9605d0d7054c2 100644 (file)
@@ -9,6 +9,10 @@
           low="0" high="20000" default="10000"
           convert="invert"/>
 
+  <number id="duration" type="slider" arg="-duration %"
+          _label="Duration" _low-label="10 seconds" _high-label="10 minutes"
+          low="10" high="600" default="120"/>
+
   <select id="mode">
     <option id="random" _label="Random Melt Style"/>
     <option id="random" _label="Shuffle Melt" arg-set="-mode shuffle"/>
index 14f02c9393e07e8127f65a74033c083f9604e660..c0af41d8b00c72c4d0d83e1f9745929cff5f16fe 100644 (file)
@@ -9,6 +9,10 @@
           low="0" high="200000" default="20000"
           convert="invert"/>
 
+  <number id="duration" type="slider" arg="-duration %"
+          _label="Duration" _low-label="10 seconds" _high-label="10 minutes"
+          low="10" high="600" default="120"/>
+
   <!-- #### -speed [0] -->
   <!-- #### -slow -->
 
index 37456cbfd0718fa67e0af66ff2c163a0dcd30bea..47dbecbbff7eada842eb011642eae5c265afc0ea 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="ISO-8859-1"?>
 
-<screensaver name="glschool" _label="glschool">
+<screensaver name="glschool" _label="GLSchool">
 
        <command arg="-root"/>
 
        <number id="CenterFact" type="slider" arg="-centerfact %" _label="Centering" _low-label="None" _high-label="High" low="0" high="1.0" default="0.1"/>
        <number id="TargetFact" type="slider" arg="-targetfact %" _label="Goal Following" _low-label="None" _high-label="High" low="0" high="400" default="80"/>
 
+        <hgroup>
        <boolean id="wire"   _label="Wireframe" arg-set="-wireframe"/>
        <boolean id="fog"    _label="Fog" arg-set="-fog"/>
        <boolean id="drawgoal" _label="Draw Goal" arg-set="-drawgoal"/>
        <boolean id="drawbbox" _label="Draw Bounding Box" arg-set="-drawbbox"/>
+        </hgroup>
        <boolean id="showfps" _label="Show Frames-per-Second" arg-set="-fps"/>
 
        <_description>
index 02a7e149eaf79a97d9ef263b097efb831a9434cc..d88b93ee93c2a0a46842e0c3568570873150c72f 100644 (file)
@@ -4,7 +4,7 @@
 
   <command arg="-root"/>
 
- <boolean id="random" _label="Randomize Almost Everything" arg-unset="-no-random"/>
+ <boolean id="random" _label="Randomize almost everything" arg-unset="-no-random"/>
 
   <hgroup>
    <vgroup>
               low="50" high="1000" default="250"/>
 
       <number id="spherism" type="slider" arg="-spherism %"
-               _label="Sphere strength" _low-label="none" _high-label="strong"
+               _label="Sphere strength" _low-label="None" _high-label="Strong"
                low="0" high="1000" default="200"/>
 
       <number id="hold" type="slider" arg="-hold %"
-               _label="Vertex-vertex force" _low-label="none" _high-label="strong"
+               _label="Vertex-vertex force" _low-label="None" _high-label="Strong"
                low="0" high="1000" default="700"/>
 
     </vgroup>
     <vgroup>
 
       <number id="distance" type="slider" arg="-distance %"
-               _label="Vertex-vertex behavior" _low-label="expand"
-               _high-label="collapse" low="0" high="1000" default="300"/>
+               _label="Vertex-vertex behavior" _low-label="Expand"
+               _high-label="Collapse" low="0" high="1000" default="300"/>
 
       <number id="damping" type="slider" arg="-damping %"
                _label="Inertial damping" _low-label="Low" _high-label="High"
                _label="Spookiness" _low-label="None" _high-label="Spoooooky"
                low="0" high="12" default="0"/>
 
-    <hgroup>
-     <select id="color">
-      <option id="cycle"     _label="Cycle" />
-      <option id="flowerbox" _label="Flower box" arg-set="-color flowerbox"/>
-      <option id="clownbarf" _label="Clown barf" arg-set="-color clownbarf"/>
-      <option id="chrome" _label="Chrome" arg-set="-color chrome"/>
-     </select>
+      <number id="delay" type="slider" arg="-delay %"
+              _label="Animation Speed" _low-label="Slow" _high-label="Fast"
+              low="0" high="20000" default="20000"
+              convert="invert"/>
+    </vgroup>
+  </hgroup>
+
+  <hgroup>
+   <select id="color">
+    <option id="cycle"     _label="Cycle" />
+    <option id="flowerbox" _label="Flower box" arg-set="-color flowerbox"/>
+    <option id="clownbarf" _label="Clown barf" arg-set="-color clownbarf"/>
+    <option id="chrome" _label="Chrome" arg-set="-color chrome"/>
+   </select>
 
-     <select id="start">
-      <option id="sphere" _label="Sphere" />
-      <option id="tetrahedron" _label="Tetrahedron" arg-set="-tetra"/>
-     </select>
-    </hgroup>
+   <select id="start">
+    <option id="sphere" _label="Sphere" />
+    <option id="tetrahedron" _label="Tetrahedron" arg-set="-tetra"/>
+   </select>
 
-    <boolean id="wireframe" _label="Wireframe" arg-set="-wireframe"/>
-    <boolean id="showfps" _label="Show Frames-per-Second" arg-set="-fps"/>
+   <boolean id="wireframe" _label="Wireframe" arg-set="-wireframe"/>
+   <boolean id="showfps" _label="Show Frames-per-Second" arg-set="-fps"/>
 
-    </vgroup>
   </hgroup>
 
-  <number id="delay" type="slider" arg="-delay %"
-          _label="Animation Speed" _low-label="Slow" _high-label="Fast"
-          low="0" high="20000" default="20000"
-          convert="invert"/>
-
   <_description>
 This does bad things with quasi-spherical objects.
 
index 0f545eb63e7bab09cfb7aa4d21cda9797cd53c5f..6be4319dae4a0da55283a6daf99e438e5cecee86 100644 (file)
@@ -34,7 +34,7 @@
   <string id="pattern" _label="Juggle This Pattern" arg="-pattern %" />
 
   <_description>
-Draws a juggling stick-man.  See also "Juggle3D".
+Draws a juggling stick-man.  See also "Juggler3D".
 
 Written by Tim Auckland; 2002.
   </_description>
index dc081fca3c6d988a53ba364bfc167910f9ca4465..2befffab78803620c1e9f8363c56d03ac66943ad 100644 (file)
@@ -15,7 +15,9 @@
 
   <_description>
 Animates a simulation of Lemarchand's Box, the Lament Configuration,
-repeatedly solving itself.  Warning: occasionally opens doors.
+repeatedly solving itself.  
+
+Warning: occasionally opens doors.
 
 Written by Jamie Zawinski; 1998.
   </_description>
index 96f4b9ae2c37f8b39536cf2fb31c67306ca16cfe..6ce60ddafe1eab5cbb1c6d33f31e331a8edee5c5 100644 (file)
@@ -4,42 +4,48 @@
 
   <command arg="-root"/>
 
-  <number id="delay" type="slider" arg="-delay %"
-          _label="Speed" _low-label="Slow" _high-label="Fast"
-          low="0" high="20000" default="10000"
-          convert="invert"/>
-
-  <number id="zoom" type="slider" arg="-zoom %"
-          _label="Zoom"
-          _low-label="0.1x" _high-label="3.0x"
-          low="0.1" high="3.0" default="1.0"/>
-
-  <number id="hold_time" type="slider" arg="-hold-time %"
-          _label="Time until loading a new image"
-          _low-label="5 Sec" _high-label="5 Min"
-          low="5.0" high="300.0" default="30.0"/>
-
-  <number id="fade_speed" type="slider" arg="-fade-time %"
-          _label="Transition Duration"
-          _low-label="None" _high-label="30 Sec"
-          low="0.0" high="30.0" default="5.0"/>
-
-  <number id="resolution" type="slider" arg="-resolution %"
-           _low-label="Low" _high-label="High"
-           _label="Resolution" low="4" high="50" default="16"/>
-
-  <number id="bumps" type="slider" arg="-bumps %"
-          _low-label="None" _high-label="50 bumps"
-          _label="Bumps" low="0" high="50" default="10"/>
-
-  <number id="blend" type="slider" arg="-blend %"
-          _low-label="Clear" _high-label="Opaque"
-          _label="Transparency" low="0.1" high="1.0" default="0.0"/>
-
-  <select id="render">
-      <option id="wire"  _label="Wireframe" arg-set="-wire"/>
-      <option id="solid" _label="Solid Surface"/>
-  </select>
+  <hgroup>
+   <vgroup>
+    <number id="delay" type="slider" arg="-delay %"
+            _label="Speed" _low-label="Slow" _high-label="Fast"
+            low="0" high="20000" default="10000"
+            convert="invert"/>
+
+    <number id="zoom" type="slider" arg="-zoom %"
+            _label="Zoom"
+            _low-label="0.1x" _high-label="3.0x"
+            low="0.1" high="3.0" default="1.0"/>
+
+    <number id="hold_time" type="slider" arg="-hold-time %"
+            _label="Time until loading a new image"
+            _low-label="5 Sec" _high-label="5 Min"
+            low="5.0" high="300.0" default="30.0"/>
+
+    <select id="render">
+        <option id="wire"  _label="Wireframe" arg-set="-wire"/>
+        <option id="solid" _label="Solid Surface"/>
+    </select>
+
+   </vgroup>
+   <vgroup>
+    <number id="fade_speed" type="slider" arg="-fade-time %"
+            _label="Transition Duration"
+            _low-label="None" _high-label="30 Sec"
+            low="0.0" high="30.0" default="5.0"/>
+
+    <number id="resolution" type="slider" arg="-resolution %"
+             _low-label="Low" _high-label="High"
+             _label="Resolution" low="4" high="50" default="16"/>
+
+    <number id="bumps" type="slider" arg="-bumps %"
+            _low-label="None" _high-label="50 bumps"
+            _label="Bumps" low="0" high="50" default="10"/>
+
+    <number id="blend" type="slider" arg="-blend %"
+            _low-label="Clear" _high-label="Opaque"
+            _label="Transparency" low="0.1" high="1.0" default="0.0"/>
+   </vgroup>
+  </hgroup>
 
    <hgroup>
    <vgroup>
index 17e66682ff130fea1fd1b29096e593532d923f79..cea3d7b9d8d0cb73eded135e95297ccf03ad6b46 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="ISO-8859-1"?>
 
-<screensaver name="popsquares" _label="popsquares">
+<screensaver name="popsquares" _label="PopSquares">
 
   <command arg="-root"/>
 
index f062b3929573036f2b05331c667496f82a4adc43..1f31af687111615c10f11ce3689d727f7b2c90e4 100644 (file)
           low="0" high="80000" default="50000"
           convert="invert"/>
 
+  <number id="duration" type="slider" arg="-duration %"
+          _label="Duration" _low-label="10 seconds" _high-label="10 minutes"
+          low="10" high="600" default="120"/>
+
   <number id="rate" type="slider" arg="-rate %"
           _low-label="Drizzle" _high-label="Storm"
           low="1" high="100" default="5"
   <number id="light" type="spinbutton" arg="-light %"
           _label="Lighting Effect" low="0" high="8" default="0"/>
 
-  <boolean id="grab" _label="Grab Screen Image" arg-set="-water"/>
-
-  <boolean id="stir" _label="Moving Splashes" arg-set="-stir"/>
-
-  <boolean id="oily" _label="Psychedelic Colors" arg-set="-oily"/>
-
-  <boolean id="gray" _label="Grayscale" arg-set="-grayscale"/>
+  <hgroup>
+   <vgroup>
+    <boolean id="grab" _label="Grab Screen Image" arg-set="-water"/>
+    <boolean id="stir" _label="Moving Splashes" arg-set="-stir"/>
+   </vgroup>
+   <vgroup>
+    <boolean id="oily" _label="Psychedelic Colors" arg-set="-oily"/>
+    <boolean id="gray" _label="Grayscale" arg-set="-grayscale"/>
+   </vgroup>
+  </hgroup>
 
   <number id="ncolors" type="slider" arg="-colors %"
             _low-label="Colors    Two" _high-label="Many"
index 44e97645d21f4229e8dcea670c66e463dfd441f2..eebb1bc1c693212900049e0e2090adc7f132d0af 100644 (file)
@@ -8,6 +8,10 @@
           _label="Duration" _low-label="0" _high-label="60"
           low="0" high="60" default="10"/>
 
+  <number id="duration" type="slider" arg="-duration %"
+          _label="Duration" _low-label="10 seconds" _high-label="10 minutes"
+          low="10" high="600" default="120"/>
+
   <number id="n" type="spinbutton" arg="-n %"
           _label="Rectangle Count" low="1" high="20" default="2"/>
 
diff --git a/hacks/config/skytentacles.xml b/hacks/config/skytentacles.xml
new file mode 100644 (file)
index 0000000..e6fd19f
--- /dev/null
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<screensaver name="skytentacles" _label="SkyTentacles">
+
+  <command arg="-root"/>
+
+  <number id="count" type="slider" arg="-count %"
+          _label="Tentacles" _low-label="1" _high-label="20"
+          low="1" high="20" default="9"/>
+
+ <hgroup>
+  <vgroup>
+   <number id="delay" type="slider" arg="-delay %"
+           _label="Frame Rate" _low-label="Slow" _high-label="Fast"
+           low="0" high="100000" default="30000"
+           convert="invert"/>
+
+   <number id="length" type="slider" arg="-length %"
+           _label="Length" _low-label="Short" _high-label="Long"
+           low="1.0" high="20.0" default="9.0"/>
+
+   <number id="wiggliness" type="slider" arg="-wiggliness %"
+           _label="Wiggliness" _low-label="Low" _high-label="High"
+           low="0.1" high="1.0" default="0.35"/>
+
+    <hgroup>
+     <number id="slices" type="spinbutton" arg="-slices %"
+             _label="Slices" low="1" high="50" default="32"/>
+     <number id="segments" type="spinbutton" arg="-segments %"
+             _label="Segments" low="1" high="50" default="32"/>
+    </hgroup>
+
+  </vgroup>
+
+  <vgroup>
+   <number id="speed" type="slider" arg="-speed %"
+           _label="Speed" _low-label="Slow" _high-label="Fast"
+           low="0.1" high="20.0" default="1.0"/>
+
+   <number id="thickness" type="slider" arg="-thickness %"
+           _label="Thickness" _low-label="Thin" _high-label="Thick"
+           low="0.1" high="5.0" default="1.0"/>
+
+   <number id="flexibility" type="slider" arg="-flexibility %"
+           _label="Flexibility" _low-label="Low" _high-label="High"
+           low="0.1" high="1.0" default="0.35"/>
+
+    <hgroup>
+     <boolean id="smooth" _label="Smooth" arg-unset="-no-smooth"/>
+     <boolean id="showfps" _label="Show Frames-per-Second" arg-set="-fps"/>
+    </hgroup>
+
+   </vgroup>
+  </hgroup>
+
+
+  <_description>
+There is a tentacled abomination in the sky.   From above you it devours.
+
+Written by Jamie Zawinski; 2008.
+  </_description>
+</screensaver>
index 19cc15ae135fc059f649387d702e8526ead4c558..6cd3ccfe17caa80fb33610f598281fed7a3f0a9e 100644 (file)
          _label="Pause" _low-label="Short" _high-label="Long"
          low="0" high="2000000" default="1000000"/>
 
+  <number id="duration" type="slider" arg="-duration %"
+          _label="Duration" _low-label="10 seconds" _high-label="10 minutes"
+          low="10" high="600" default="120"/>
+
   <number id="increment" type="slider" arg="-increment %"
           _label="Slide Speed" _low-label="Slow" _high-label="Fast"
           low="1" high="30" default="10"/>
index 26708ffee072aebe21657643bfa3924ff5fdc3d9..f51db09fd34c9c7a1ef5a5b8e1c470b611a4cb1a 100644 (file)
@@ -41,7 +41,7 @@
 These closed objects are commonly called spherical harmonics,
 although they are only remotely related to the mathematical
 definition found in the solution to certain wave functions, most
-notable the eigenfunctions of angular momentum operators.
+notably the eigenfunctions of angular momentum operators.
 
 Written by Paul Bourke and Jamie Zawinski; 2002.
   </_description>
index 34e5a8f439e89818486fee3b28d853a74fee78c8..349c01de96e2b449b4f511f406201c25fe1f333f 100644 (file)
@@ -9,6 +9,10 @@
           low="0" high="20000" default="10000"
           convert="invert"/>
 
+  <number id="duration" type="slider" arg="-duration %"
+          _label="Duration" _low-label="10 seconds" _high-label="10 minutes"
+          low="10" high="600" default="120"/>
+
   <number id="radius" type="slider" arg="-radius %"
           _label="Spotlight Size" _low-label="Small" _high-label="Large"
           low="5" high="350" default="125"/>
index 63c6f349acd79dfd147e36d11bb356645355b337..bd5407c907075bc8a36a14206341c786300e7d68 100644 (file)
@@ -4,17 +4,24 @@
 
   <command arg="-root"/>
 
-  <number id="delay" type="slider" arg="-delay %"
-          _label="Animation Speed" _low-label="Slow" _high-label="Fast"
-          low="0" high="80000" default="40000"
-          convert="invert"/>
-
-  <number id="steps" type="slider" arg="-steps %"
-          _label="Scroll Speed" _low-label="Slow" _high-label="Fast"
-          low="1" high="100" default="35"
-          convert="invert"/>
-
   <hgroup>
+   <vgroup>
+    <number id="delay" type="slider" arg="-delay %"
+            _label="Animation Speed" _low-label="Slow" _high-label="Fast"
+            low="0" high="80000" default="40000"
+            convert="invert"/>
+    <number id="steps" type="slider" arg="-steps %"
+            _label="Scroll Speed" _low-label="Slow" _high-label="Fast"
+            low="1" high="100" default="35"
+            convert="invert"/>
+    <number id="spin" type="slider" arg="-spin %"
+            _label="Star Rotation Speed" _low-label="Slow" _high-label="Fast"
+            low="0.0" high="0.2" default="0.03"/>
+    <number id="lines" type="spinbutton" arg="-lines %"
+             _label="Text Lines" low="4" high="1000" default="125"/>
+   </vgroup>
+
+   <vgroup>
     <select id="align">
       <option id="left"   _label="Flush Left Text"  arg-set="-alignment left"/>
       <option id="center" _label="Centered Text"/>
     </select>
 
     <boolean id="wrap"   _label="Wrap Long Lines" arg-unset="-no-wrap"/>
-  </hgroup>
+   <boolean id="texture" _label="Texture-Mapped Font" arg-unset="-no-textures"/>
+    <boolean id="smooth" _label="Anti-aliased Lines" arg-unset="-no-smooth"/>
+    <hgroup>
+     <boolean id="thick"  _label="Thick Lines"        arg-unset="-no-thick"/>
+     <boolean id="fade"   _label="Fade Out"           arg-unset="-no-fade"/>
+    </hgroup>
+    <boolean id="showfps" _label="Show Frames-per-Second" arg-set="-fps"/>
 
-<!--  <file id="program" _label="Text Program" arg="-program %"/> -->
+   </vgroup>
+  </hgroup>
 
   <hgroup>
     <number id="size" type="spinbutton" arg="-size %"
              _label="Font Point Size" low="-1" high="10" default="-1"/>
-
     <number id="columns" type="spinbutton" arg="-columns %"
              _label="or, Text Columns" low="-1" high="200" default="-1"/>
   </hgroup>
 
-  <number id="lines" type="spinbutton" arg="-lines %"
-           _label="Text Lines" low="4" high="1000" default="125"/>
-
-  <number id="spin" type="slider" arg="-spin %"
-          _label="Star Rotation Speed" _low-label="Slow" _high-label="Fast"
-          low="0.0" high="0.2" default="0.03"/>
-
-  <hgroup>
-    <boolean id="smooth" _label="Anti-aliased Lines" arg-unset="-no-smooth"/>
-    <boolean id="thick"  _label="Thick Lines"        arg-unset="-no-thick"/>
-    <boolean id="fade"   _label="Fade Out"           arg-unset="-no-fade"/>
-  </hgroup>
-
-  <hgroup>
-   <boolean id="texture" _label="Texture-Mapped Font" arg-unset="-no-textures"/>
-   <boolean id="showfps" _label="Show Frames-per-Second" arg-set="-fps"/>
-  </hgroup>
-
   <xscreensaver-text />
 
   <_description>
index 9a953b127dcbb3ab2b04b0f33102115d5abe9540..5c4b725665fe30b94faf6d8df2c9714159048b47 100644 (file)
@@ -5,7 +5,7 @@
   <command arg="-root"/>
 
   <number id="init" type="spinbutton" arg="-initial-cracks %"
-          _label="Initial Cracks" low="2" high="15" default="3"/>
+          _label="Initial Cracks" low="3" high="15" default="3"/>
 
   <number id="speed" type="slider" arg="-growth-delay %"
           _label="Speed" _low-label="Slow" _high-label="Fast"
index 35c667508faf24779931d67c2d68303ac50f3192..5579a168176e1413e0a5478cc9093436934d9303 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="ISO-8859-1"?>
 
-<screensaver name="topblock" _label="topBlock">
+<screensaver name="topblock" _label="TopBlock">
 
   <command arg="-root"/>
 
index 732a5a3921597f4bf763f731a35193a33bae5f5c..80a8cf57215ca2c3efd94cd3d73b53cd5fc18382 100644 (file)
@@ -9,6 +9,10 @@
           low="0" high="50000" default="10000"
           convert="invert"/>
 
+  <number id="duration" type="slider" arg="-duration %"
+          _label="Duration" _low-label="10 seconds" _high-label="10 minutes"
+          low="10" high="600" default="120"/>
+
   <number id="event-chance" type="slider" arg="-event-chance %"
           _label="Randomness" _low-label="Slow" _high-label="Jumpy"
           low="0.0" high="0.1" default="0.01"/>
index af3ccbf3e6cdcf1bd835b4fac23bbcc28970af06..f65f223a1af50131f6941a3d3d8f00ce83746c8f 100644 (file)
@@ -4,37 +4,43 @@
 
   <command arg="-root"/>
 
-  <number id="delay" type="slider" arg="-delay %"
-          _label="Frame Rate" _low-label="Slow" _high-label="Fast"
-          low="0" high="100000" default="20000"
-          convert="invert"/>
-
-  <number id="points" type="slider" arg="-points %"
-          _label="Points" _low-label="Few" _high-label="Many"
-          low="1" high="100" default="25"/>
-
-  <number id="pointSize" type="slider" arg="-point-size %"
-          _label="Point Size" _low-label="0" _high-label="50 pixels"
-          low="0" high="50" default="9"/>
-
-  <number id="pointSpeed" type="slider" arg="-point-speed %"
-          _label="Wander Speed" _low-label="Slow" _high-label="Fast"
-          low="0.0" high="10.0" default="1.0"/>
-
-  <number id="pointDelay" type="slider" arg="-point-delay %"
-          _label="Insertion Speed" _low-label="Slow" _high-label="Fast"
-          low="0.0" high="3.0" default="0.05"
-          convert="invert"/>
-
-  <number id="zoomSpeed" type="slider" arg="-zoom-speed %"
-          _label="Zoom Speed" _low-label="Slow" _high-label="Fast"
-          low="0.1" high="10.0" default="1.0"/>
-
-  <number id="zoomDelay" type="slider" arg="-zoom-delay %"
-          _label="Zoom Frequency" _low-label="0" _high-label="60 Seconds"
-          low="0" high="60" default="15"/>
-
-  <boolean id="showfps" _label="Show Frames-per-Second" arg-set="-fps"/>
+  <hgroup>
+   <vgroup>
+    <number id="delay" type="slider" arg="-delay %"
+            _label="Frame Rate" _low-label="Slow" _high-label="Fast"
+            low="0" high="100000" default="20000"
+            convert="invert"/>
+
+    <number id="points" type="slider" arg="-points %"
+            _label="Points" _low-label="Few" _high-label="Many"
+            low="1" high="100" default="25"/>
+
+    <number id="pointSize" type="slider" arg="-point-size %"
+            _label="Point Size" _low-label="0" _high-label="50 pixels"
+            low="0" high="50" default="9"/>
+
+    <boolean id="showfps" _label="Show Frames-per-Second" arg-set="-fps"/>
+   </vgroup>
+
+   <vgroup>
+    <number id="pointSpeed" type="slider" arg="-point-speed %"
+            _label="Wander Speed" _low-label="Slow" _high-label="Fast"
+            low="0.0" high="10.0" default="1.0"/>
+
+    <number id="pointDelay" type="slider" arg="-point-delay %"
+            _label="Insertion Speed" _low-label="Slow" _high-label="Fast"
+            low="0.0" high="3.0" default="0.05"
+            convert="invert"/>
+
+    <number id="zoomSpeed" type="slider" arg="-zoom-speed %"
+            _label="Zoom Speed" _low-label="Slow" _high-label="Fast"
+            low="0.1" high="10.0" default="1.0"/>
+
+    <number id="zoomDelay" type="slider" arg="-zoom-delay %"
+            _label="Zoom Frequency" _low-label="0" _high-label="60 Seconds"
+            low="0" high="60" default="15"/>
+   </vgroup>
+  </hgroup>
 
   <_description>
 Draws a randomly-colored Voronoi tessellation, and periodically zooms 
index bc213e83e8de0d766620c6ad9c97cb4aac00bbec..31be04eab191a18613e1475e1824ebabad68e1da 100644 (file)
@@ -4,40 +4,47 @@
 
   <command arg="-root"/>
 
-  <select id="size">
-    <option id="font1" _label="Small Font"  arg-set="-small"/>
-    <option id="font2" _label="Large Font"/>
-  </select>
-
-  <select id="mode">
-    <option id="matrix" _label="Matrix Encoding"/>
-    <option id="binary" _label="Binary Encoding"      arg-set="-mode binary"/>
-    <option id="hex"    _label="Hexadecimal Encoding" arg-set="-mode hex"/>
-    <option id="dna"    _label="Genetic Encoding"     arg-set="-mode dna"/>
-    <option id="pipe"   _label="Piped ASCII Text"     arg-set="-mode pipe"/>
-  </select>
-
-  <select id="fill">
-    <option id="both"   _label="Synergistic Algorithm"/>
-    <option id="top"    _label="Slider Algorithm"    arg-set="-insert top"/>
-    <option id="bottom" _label="Expansion Algorithm" arg-set="-insert bottom"/>
-  </select>
-
-  <number id="delay" type="slider" arg="-delay %"
-          _label="Speed" _low-label="Slow" _high-label="Fast"
-          low="0" high="20000" default="10000"
-          convert="invert"/>
-
-  <number id="density" type="slider" arg="-density %"
-          _label="Density" _low-label="Sparse" _high-label="Full"
-          low="1" high="100" default="75"/>
+  <hgroup>
+   <select id="size">
+     <option id="font1" _label="Small Font"  arg-set="-small"/>
+     <option id="font2" _label="Large Font"/>
+   </select>
+
+   <select id="mode">
+     <option id="matrix" _label="Matrix Encoding"/>
+     <option id="binary" _label="Binary Encoding"      arg-set="-mode binary"/>
+     <option id="hex"    _label="Hexadecimal Encoding" arg-set="-mode hex"/>
+     <option id="dna"    _label="Genetic Encoding"     arg-set="-mode dna"/>
+     <option id="pipe"   _label="Piped ASCII Text"     arg-set="-mode pipe"/>
+   </select>
+
+   <select id="fill">
+     <option id="both"   _label="Synergistic Algorithm"/>
+     <option id="top"    _label="Slider Algorithm"    arg-set="-insert top"/>
+     <option id="bottom" _label="Expansion Algorithm" arg-set="-insert bottom"/>
+   </select>
+  </hgroup>
 
   <hgroup>
    <boolean id="trace" _label="Run Trace Program" arg-unset="-no-trace"/>
    <boolean id="knock" _label="Knock Knock"       arg-unset="-no-knock-knock"/>
+   <string id="phone" _label="Phone Number" arg="-phone %"/>
   </hgroup>
 
-  <string id="phone" _label="Phone Number" arg="-phone %"/>
+  <hgroup>
+   <vgroup>
+    <number id="delay" type="slider" arg="-delay %"
+            _label="Speed" _low-label="Slow" _high-label="Fast"
+            low="0" high="20000" default="10000"
+            convert="invert"/>
+   </vgroup>
+
+   <vgroup>
+    <number id="density" type="slider" arg="-density %"
+            _label="Density" _low-label="Sparse" _high-label="Full"
+            low="1" high="100" default="75"/>
+   </vgroup>
+  </hgroup>
 
   <xscreensaver-text />
 
index 167e28c25589b7cc7595de9249c63840025a4fa0..c0f11fb1b6151a4c2608f8cda62f49c5f8c310ce 100644 (file)
@@ -9,6 +9,10 @@
           low="0" high="20000" default="10000"
           convert="invert"/>
 
+  <number id="duration" type="slider" arg="-duration %"
+          _label="Duration" _low-label="10 seconds" _high-label="10 minutes"
+          low="10" high="600" default="120"/>
+
   <boolean id="lenses" _label="Lenses" arg-set="-lenses"/>
 
   <hgroup>
index 775e629282f9620aa8442fd2fddb2954e46321f7..fc74672c7180c3a7cf5c0290e62a9f09269ecb57 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1992-2006 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1992-2008 Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -43,9 +43,11 @@ struct state {
 
   int sizex, sizey;
   int delay;
+  int duration;
   GC gc;
   int mode;
-  int iterations;
+  int random_p;
+  time_t start_time;
 
   int fuzz_toggle;
   const int *current_bias;
@@ -69,6 +71,18 @@ struct state {
 #define STRETCH                12
 #define FUZZ           13
 
+static void
+decayscreen_load_image (struct state *st)
+{
+  XWindowAttributes xgwa;
+  XGetWindowAttributes (st->dpy, st->window, &xgwa);
+  st->sizex = xgwa.width;
+  st->sizey = xgwa.height;
+  if (st->img_loader) abort();
+  st->img_loader = load_image_async_simple (0, xgwa.screen, st->window,
+                                            st->window, 0, 0);
+}
+
 static void *
 decayscreen_init (Display *dpy, Window window)
 {
@@ -81,6 +95,7 @@ decayscreen_init (Display *dpy, Window window)
 
   st->dpy = dpy;
   st->window = window;
+  st->random_p = 0;
 
   s = get_string_resource(st->dpy, "mode", "Mode");
   if      (s && !strcmp(s, "shuffle")) st->mode = SHUFFLE;
@@ -100,13 +115,16 @@ decayscreen_init (Display *dpy, Window window)
   else {
     if (s && *s && !!strcmp(s, "random"))
       fprintf(stderr, "%s: unknown mode %s\n", progname, s);
+    st->random_p = 1;
     st->mode = random() % (FUZZ+1);
   }
 
   st->delay = get_integer_resource (st->dpy, "delay", "Integer");
-
   if (st->delay < 0) st->delay = 0;
 
+  st->duration = get_integer_resource (st->dpy, "duration", "Seconds");
+  if (st->duration < 1) st->duration = 1;
+
   XGetWindowAttributes (st->dpy, st->window, &xgwa);
 
   gcv.function = GXcopy;
@@ -119,14 +137,8 @@ decayscreen_init (Display *dpy, Window window)
     gcflags |= GCSubwindowMode;
   st->gc = XCreateGC (st->dpy, st->window, gcflags, &gcv);
 
-  st->sizex = xgwa.width;
-  st->sizey = xgwa.height;
-
-  if (st->mode == MELT || st->mode == STRETCH)
-    st->iterations = 1;    /* slow down for smoother melting */
-
-  st->img_loader = load_image_async_simple (0, xgwa.screen, st->window,
-                                            st->window, 0, 0);
+  st->start_time = time ((time_t) 0);
+  decayscreen_load_image (st);
 
   return st;
 }
@@ -161,6 +173,11 @@ decayscreen_draw (Display *dpy, Window window, void *closure)
         st->img_loader = load_image_async_simple (st->img_loader, 
                                                   0, 0, 0, 0, 0);
         if (! st->img_loader) {  /* just finished */
+
+          st->start_time = time ((time_t) 0);
+          if (st->random_p)
+            st->mode = random() % (FUZZ+1);
+
           if (st->mode == MELT || st->mode == STRETCH)
             /* make sure screen eventually turns background color */
             XDrawLine (st->dpy, st->window, st->gc, 0, 0, st->sizex, 0); 
@@ -168,6 +185,11 @@ decayscreen_draw (Display *dpy, Window window, void *closure)
       return st->delay;
     }
 
+    if (!st->img_loader &&
+        st->start_time + st->duration < time ((time_t) 0)) {
+      decayscreen_load_image (st);
+    }
+
     switch (st->mode) {
       case SHUFFLE:    st->current_bias = no_bias; break;
       case UP:         st->current_bias = up_bias; break;
@@ -324,12 +346,14 @@ static const char *decayscreen_defaults [] = {
 
   "*delay:                     10000",
   "*mode:                      random",
+  "*duration:                  120",
   0
 };
 
 static XrmOptionDescRec decayscreen_options [] = {
   { "-delay",          ".delay",               XrmoptionSepArg, 0 },
   { "-mode",           ".mode",                XrmoptionSepArg, 0 },
+  { "-duration",       ".duration",            XrmoptionSepArg, 0 },
   { 0, 0, 0, 0 }
 };
 
index 17f43329df5af0767e3956a8d70b5c0352e57a9a..76823f3dd89b88a7e1e481a39f2979ab37452b68 100644 (file)
@@ -3,8 +3,15 @@
 decayscreen - make a screen meltdown.
 .SH SYNOPSIS
 .B decayscreen
-[\-display \fIhost:display.screen\fP] [\-window] [\-root] [\-mono] [\-install]
-[\-visual \fIvisual\fP] [\-delay \fIusecs\fP] [\-mode \fImode\fP]
+[\-display \fIhost:display.screen\fP]
+[\-window]
+[\-root]
+[\-mono]
+[\-install]
+[\-visual \fIvisual\fP]
+[\-delay \fIusecs\fP]
+[\-duration \fIsecs\fP]
+[\-mode \fImode\fP]
 .SH DESCRIPTION
 The \fIdecayscreen\fP program creates a melting effect by randomly
 shifting rectangles around the screen.
@@ -40,6 +47,9 @@ or the id number (decimal or hex) of a specific visual.
 .B \-delay \fImicroseconds\fP
 Slow it down.
 .TP 8
+.B \-duration \fIseconds\fP
+How long to run before loading a new image.  Default 120 seconds.
+.TP 8
 .B \-mode \fImode\fP
 The direction in which the image should tend to slide.  Legal values are
 \fIrandom\fP (meaning pick one), \fIup\fP, \fIleft\fP, \fIright\fP, 
index 7755f0283fda8c722c23ef29b1c2e28a06a4dd0c..1653f24d9807220bb8a4fc360bdd6da27cd49208 100644 (file)
@@ -61,6 +61,9 @@ struct state {
   struct coo xy_coo[10];
 
   int delay, radius, speed, number, blackhole, vortex, magnify, reflect, slow;
+  int duration;
+  time_t start_time;
+
   XWindowAttributes xgwa;
   GC gc;
   unsigned long black_pixel;
@@ -115,10 +118,14 @@ distort_init (Display *dpy, Window window)
     st->window = window;
 
        st->delay = get_integer_resource(st->dpy, "delay", "Integer");
+    st->duration = get_integer_resource (st->dpy, "duration", "Seconds");
        st->radius = get_integer_resource(st->dpy, "radius", "Integer");
        st->speed = get_integer_resource(st->dpy, "speed", "Integer");
        st->number = get_integer_resource(st->dpy, "number", "Integer");
 
+    if (st->delay < 0) st->delay = 0;
+    if (st->duration < 1) st->duration = 1;
+
 #ifdef HAVE_XSHM_EXTENSION
        st->use_shm = get_boolean_resource(st->dpy, "useSHM", "Boolean");
 #endif /* HAVE_XSHM_EXTENSION */
@@ -277,6 +284,7 @@ distort_init (Display *dpy, Window window)
 
     st->img_loader = load_image_async_simple (0, st->xgwa.screen, st->window,
                                               st->window, 0, 0);
+    st->start_time = time ((time_t) 0);
     return st;
 }
 
@@ -285,6 +293,8 @@ distort_finish_loading (struct state *st)
 {
     int i;
 
+    st->start_time = time ((time_t) 0);
+
        st->buffer_map = 0;
        st->orig_map = XGetImage(st->dpy, st->window, 0, 0, st->xgwa.width, st->xgwa.height,
                                                 ~0L, ZPixmap);
@@ -747,11 +757,19 @@ distort_draw (Display *dpy, Window window, void *closure)
   if (st->img_loader)   /* still loading */
     {
       st->img_loader = load_image_async_simple (st->img_loader, 0, 0, 0, 0, 0);
-      if (! st->img_loader)  /* just finished */
+      if (! st->img_loader)  /* just finished */
         distort_finish_loading (st);
+      }
       return st->delay;
     }
 
+  if (!st->img_loader &&
+      st->start_time + st->duration < time ((time_t) 0)) {
+    st->img_loader = load_image_async_simple (0, st->xgwa.screen, st->window,
+                                              st->window, 0, 0);
+    return st->delay;
+  }
+
   for (k = 0; k < st->number; k++) {
     st->effect(st,k);
     st->draw(st,k);
@@ -795,6 +813,7 @@ static const char *distort_defaults [] = {
 #endif
 
        "*delay:                        20000",
+    "*duration:                        120",
        "*radius:                       0",
        "*speed:                        0",
        "*number:                       0",
@@ -812,6 +831,7 @@ static const char *distort_defaults [] = {
 
 static XrmOptionDescRec distort_options [] = {
   { "-delay",     ".delay",       XrmoptionSepArg, 0 },
+  { "-duration",  ".duration",   XrmoptionSepArg, 0 },
   { "-radius",    ".radius",      XrmoptionSepArg, 0 },
   { "-speed",     ".speed",       XrmoptionSepArg, 0 },
   { "-number",    ".number",      XrmoptionSepArg, 0 },
index ccc1c5bb31eea4d3ca620cc1940731adc1cce874..ee97bca234cebe08727ffaa96be332211fab44f6 100644 (file)
@@ -4,9 +4,20 @@ distort \- distort the content of the screen in interesting ways
 .SH SYNOPSIS
 .B distort
 [\-root] [\-window] [\-mono] [\-install] [\-noinstall] [\-visual \fIvisual\fP]
-[\-window\-id \fIwindow\-id\fP] [\-delay \fIusecs\fP] [\-radius \fIpixels\fP]
-[\-speed \fIint\fP] [\-number \fIint\fP] [\-swamp] [\-bounce] [\-reflect]
-[\-vortex] [\-magnify] [\-blackhole] [\-slow] [\-shm] [\-no\-shm]
+[\-window\-id \fIwindow\-id\fP]
+[\-delay \fIusecs\fP]
+[\-duration \fIsecs\fP]
+[\-radius \fIpixels\fP]
+[\-speed \fIint\fP]
+[\-number \fIint\fP]
+[\-swamp]
+[\-bounce]
+[\-reflect]
+[\-vortex]
+[\-magnify]
+[\-blackhole]
+[\-slow]
+[\-shm] [\-no\-shm]
 .SH DESCRIPTION
 The \fIdistort\fP program takes an image and lets circular zones of
 distortion wander randomly around it, distorting what is under them.
@@ -50,6 +61,9 @@ Specify which window id to use.
 .B \-delay \fIusecs\fP
 Specify the delay between subsequent animation frames in microseconds.
 .TP 8
+.B \-duration \fIseconds\fP
+How long to run before loading a new image.  Default 120 seconds.
+.TP 8
 .B \-radius \fIpixels\fP
 Specify the radius of the distortion zone in pixels.
 .TP 8
index 06aa1c4d4da252d6dac8173dea7d2ebbd8ef8ffd..f060591c0eed2a8b6d930d9d21db7caf57e1f63d 100644 (file)
@@ -368,9 +368,9 @@ draw_galaxy(ModeInfo * mi)
 
         d = d0 * d0 + d1 * d1 + d2 * d2;
         if (d > EPSILON)
-          d = gt->mass / (d * sqrt(d)) * DELTAT * DELTAT * QCONS;
+          d = gtk->mass / (d * sqrt(d)) * DELTAT * DELTAT * QCONS;
         else
-          d = gt->mass * eps;
+          d = gtk->mass / (eps * sqrt(eps));
         v0 += d0 * d;
         v1 += d1 * d;
         v2 += d2 * d;
@@ -400,19 +400,19 @@ draw_galaxy(ModeInfo * mi)
 
       d = d0 * d0 + d1 * d1 + d2 * d2;
       if (d > EPSILON)
-        d = gt->mass * gt->mass / (d * sqrt(d)) * DELTAT * QCONS;
+        d = 1 / (d * sqrt(d)) * DELTAT * QCONS;
       else
-        d = gt->mass * gt->mass / (EPSILON * sqrt_EPSILON) * DELTAT * QCONS;
+        d = 1 / (EPSILON * sqrt_EPSILON) * DELTAT * QCONS;
 
       d0 *= d;
       d1 *= d;
       d2 *= d;
-      gt->vel[0] += d0 / gt->mass;
-      gt->vel[1] += d1 / gt->mass;
-      gt->vel[2] += d2 / gt->mass;
-      gtk->vel[0] -= d0 / gtk->mass;
-      gtk->vel[1] -= d1 / gtk->mass;
-      gtk->vel[2] -= d2 / gtk->mass;
+      gt->vel[0] += d0 * gtk->mass;
+      gt->vel[1] += d1 * gtk->mass;
+      gt->vel[2] += d2 * gtk->mass;
+      gtk->vel[0] -= d0 * gt->mass;
+      gtk->vel[1] -= d1 * gt->mass;
+      gtk->vel[2] -= d2 * gt->mass;
     }
 
     gt->pos[0] += gt->vel[0] * DELTAT;
index 5d73861ca31233709fb4a73587bddb32b3b62b24..9a9f4b68d76275f71763c7fdb7c553a16604b96a 100644 (file)
@@ -105,7 +105,8 @@ SRCS                = xscreensaver-gl-helper.c normals.c glxfonts.c \
                  tangram_shapes.c crackberg.c glhanoi.c cube21.c \
                  timetunnel.c juggler3d.c topblock.c glschool.c \
                  glschool_gl.c glschool_alg.c glcells.c voronoi.c \
-                 moebiusgears.c lockward.c cubicgrid.c hypnowheel.c
+                 moebiusgears.c lockward.c cubicgrid.c hypnowheel.c \
+                 skytentacles.c
 
 OBJS           = xscreensaver-gl-helper.o normals.o glxfonts.o \
                  atlantis.o b_draw.o b_lockglue.o b_sphere.o bubble3d.o \
@@ -139,7 +140,8 @@ OBJS                = xscreensaver-gl-helper.o normals.o glxfonts.o \
                  tangram_shapes.o crackberg.o glhanoi.o cube21.o \
                  timetunnel.o juggler3d.o topblock.o glschool.o \
                  glschool_gl.o glschool_alg.o glcells.o voronoi.o \
-                 moebiusgears.o lockward.o cubicgrid.o hypnowheel.o
+                 moebiusgears.o lockward.o cubicgrid.o hypnowheel.o \
+                 skytentacles.o
 
 GL_EXES                = cage gears moebius pipes sproingies stairs superquadrics \
                  morph3d rubik atlantis lament bubble3d glplanet pulsar \
@@ -153,7 +155,7 @@ GL_EXES             = cage gears moebius pipes sproingies stairs superquadrics \
                  antinspect providence pinion boing carousel fliptext \
                  antmaze tangram crackberg glhanoi cube21 timetunnel \
                  juggler3d topblock glschool glcells voronoi moebiusgears \
-                 lockward cubicgrid hypnowheel
+                 lockward cubicgrid hypnowheel skytentacles
 GLE_EXES       = extrusion
 GL_UTIL_EXES   = xscreensaver-gl-helper
 HACK_EXES      = @GL_EXES@ @GLE_EXES@
@@ -196,7 +198,7 @@ GL_MEN              = atlantis.man boxed.man bubble3d.man cage.man circuit.man \
                  crackberg.man glhanoi.man cube21.man timetunnel.man \
                  juggler3d.man topblock.man glschool.man glcells.man \
                  voronoi.man moebiusgears.man lockward.man cubicgrid.man \
-                 hypnowheel.man
+                 hypnowheel.man skytentacles.man
 MEN            = @GL_MEN@
 EXTRAS         = README Makefile.in dxf2gl.pl molecules.sh starwars.txt
 
@@ -729,6 +731,9 @@ cubicgrid:  cubicgrid.o     $(HACK_TRACK_OBJS)
 hypnowheel:    hypnowheel.o    $(HACK_TRACK_OBJS)
        $(CC_HACK) -o $@ $@.o   $(HACK_TRACK_OBJS) $(HACK_LIBS)
 
+skytentacles:  skytentacles.o normals.o $(HACK_TRACK_OBJS)
+       $(CC_HACK) -o $@ $@.o  normals.o $(HACK_TRACK_OBJS) $(HACK_LIBS)
+
 ##############################################################################
 #
 # DO NOT DELETE: updated by make distdepend
@@ -1876,6 +1881,21 @@ sierpinski3d.o: $(UTILS_SRC)/xshm.h
 sierpinski3d.o: $(UTILS_SRC)/yarandom.h
 sierpinski3d.o: $(HACK_SRC)/xlockmoreI.h
 sierpinski3d.o: $(HACK_SRC)/xlockmore.h
+skytentacles.o: ../../config.h
+skytentacles.o: $(srcdir)/gltrackball.h
+skytentacles.o: $(srcdir)/normals.h
+skytentacles.o: $(srcdir)/rotator.h
+skytentacles.o: $(HACK_SRC)/screenhackI.h
+skytentacles.o: $(UTILS_SRC)/colors.h
+skytentacles.o: $(UTILS_SRC)/grabscreen.h
+skytentacles.o: $(UTILS_SRC)/hsv.h
+skytentacles.o: $(UTILS_SRC)/resources.h
+skytentacles.o: $(UTILS_SRC)/usleep.h
+skytentacles.o: $(UTILS_SRC)/visual.h
+skytentacles.o: $(UTILS_SRC)/xshm.h
+skytentacles.o: $(UTILS_SRC)/yarandom.h
+skytentacles.o: $(HACK_SRC)/xlockmoreI.h
+skytentacles.o: $(HACK_SRC)/xlockmore.h
 spheremonics.o: ../../config.h
 spheremonics.o: $(srcdir)/gltrackball.h
 spheremonics.o: $(srcdir)/glxfonts.h
index 856045bd5d0ebede2ee2caeabcc75a5975a9d284..123bc7e63e00ef62a78af35ed539b3f545e7b1eb 100644 (file)
@@ -104,7 +104,7 @@ ModStruct   circuit_description =
 
 #endif
 
-#define MAX_COMPONENTS 31
+#define MAX_COMPONENTS 400
 #define MOVE_MULT 0.02
 
 static float f_rand(void)
index 8cdca30fc1ad43b52de48308074dcddbb6bf6662..b62b3e5efa2990d701d2fd643e06755e19c8d1a5 100644 (file)
                        "*doGasket:         True    \n" \
                        "*doHelix:          True    \n" \
                        "*doLadder:         True    \n" \
+                       "*doFrame:          True    \n" \
                        "*wallFacets:       360     \n" \
-                       "*tubeFacets:       90      \n" \
+                       "*barFacets:        90      \n" \
                        "*clockwise:        False   \n" \
-                       "*turns:            0.    \n" \
-                       "*turnSpacing:      2.40    \n" \
-                       "*barSpacing:       0.30    \n" \
-                       "*wallHeight:       0.4     \n" \
-                       "*wallThickness:    0.1     \n" \
-                       "*tubeThickness:    0.075   \n" \
-                       "*wallTaper:        1.047   \n" \
-                       "*gasketSize:       2.15    \n" \
+                       "*turns:            0.69    \n" \
+                       "*turnSpacing:      2.    \n" \
+                       "*barSpacing:       0.24    \n" \
+                       "*wallHeight:       0.45    \n" \
+                       "*wallThickness:    0.12    \n" \
+                       "*barThickness:     0.058   \n" \
+                       "*wallTaper:        0.95    \n" \
+                       "*gasketSize:       1.88    \n" \
                        "*gasketDepth:      0.15    \n" \
                        "*gasketThickness:  0.4     \n" \
+                       "*frameSize:        1.20    \n" \
+                       "*frameDepth:       0.01    \n" \
+                       "*frameThickness:   0.03    \n" \
+                       "*triangleSize:     0.045   \n" \
                        "*speed:            1.0     \n" \
                        ".foreground:       #00AA00 \n" \
+                       "*geometry:         =640x640\n" \
 
 # define refresh_logo 0
 # define release_logo 0
@@ -57,9 +63,10 @@ typedef struct {
 
   GLuint helix_list,  helix_list_wire,  helix_list_facetted;
   GLuint gasket_list, gasket_list_wire;
+  GLuint frame_list,  frame_list_wire;
 
   int wall_facets;
-  int tube_facets;
+  int bar_facets;
   Bool clockwise;
   GLfloat color[4];
 
@@ -68,18 +75,24 @@ typedef struct {
   GLfloat bar_spacing;
   GLfloat wall_height;
   GLfloat wall_thickness;
-  GLfloat tube_thickness;
+  GLfloat bar_thickness;
   GLfloat wall_taper;
 
   GLfloat gasket_size;
   GLfloat gasket_depth;
   GLfloat gasket_thickness;
 
+  GLfloat frame_size;
+  GLfloat frame_depth;
+  GLfloat frame_thickness;
+  GLfloat triangle_size;
+
   GLfloat speed;
 
   spinner gasket_spinnerx, gasket_spinnery, gasket_spinnerz;
   spinner scene_spinnerx,  scene_spinnery;
   spinner helix_spinnerz;
+  spinner frame_spinner;
 
   trackball_state *trackball;
   Bool button_down_p;
@@ -136,7 +149,7 @@ vector_angle (double ax, double ay, double az,
 static void
 make_helix (logo_configuration *dc, int facetted, int wire)
 {
-  int wall_facets = dc->wall_facets / (facetted ? 15 : 1);
+  int wall_facets = dc->wall_facets / (facetted ? 10 : 1);
   GLfloat th;
   GLfloat max_th = M_PI * 2 * dc->turns;
   GLfloat th_inc = M_PI * 2 / wall_facets;
@@ -156,8 +169,8 @@ make_helix (logo_configuration *dc, int facetted, int wire)
 
   z1 = -(dc->turn_spacing * dc->turns / 2);
 
-  h1 = (dc->wall_taper > 0 ? 0 : dc->wall_height / 2);
-  h1off = (dc->wall_taper > 0 ? -dc->wall_height / 2 : 0);
+  h1    = (dc->wall_taper > 0 ? 0 : dc->wall_height / 2);
+  h1off = (dc->wall_taper > 0 ?    -dc->wall_height / 2 : 0);
 
   if (!dc->clockwise)
     z1 = -z1, z_inc = -z_inc, h1off = -h1off;
@@ -315,9 +328,13 @@ make_ladder (logo_configuration *dc, int facetted, int wire)
   GLfloat usable_th = max_th - dc->wall_taper;
   GLfloat usable_z  = max_z / (max_th / usable_th);
   int nbars = usable_z / dc->bar_spacing;
-  GLfloat used_z = (nbars - 1) * dc->bar_spacing;
-  GLfloat pad_z = max_z - used_z;
-  GLfloat pad_ratio = pad_z / max_z;
+  GLfloat used_z, pad_z, pad_ratio;
+
+  if (! (nbars & 1)) nbars--;  /* always an odd number of bars */
+
+  used_z = (nbars - 1) * dc->bar_spacing;
+  pad_z = max_z - used_z;
+  pad_ratio = pad_z / max_z;
 
   th = (max_th * pad_ratio/2);
   z  = -(max_z / 2) + (max_z * pad_ratio/2);
@@ -327,13 +344,13 @@ make_ladder (logo_configuration *dc, int facetted, int wire)
 
   for (i = 0; i < nbars; i++)
     {
-      int facets = dc->tube_facets / (facetted ? 14 : 1);
+      int facets = dc->bar_facets / (facetted ? 14 : 1);
       if (facets <= 3) facets = 3;
       x = cos (th) * (1 - dc->wall_thickness);
       y = sin (th) * (1 - dc->wall_thickness);
       tube ( x,  y, z,
             -x, -y, z,
-             dc->tube_thickness, 0, facets,
+             dc->bar_thickness, 0, facets,
              True, True, wire);
       z  += z_inc;
       th += th_inc;
@@ -360,15 +377,15 @@ make_gasket (logo_configuration *dc, int wire)
 
   GLfloat *pointsx0, *pointsy0, *pointsx1, *pointsy1, *normals;
 
-  GLfloat r0  = 0.780;  /* 395 */
-  GLfloat r1a = 0.855;                /* top of wall below upper left hole */
-  GLfloat r1b = 0.890;                /* center of upper left hole */
-  GLfloat r1c = 0.922;                /* bottom of wall above hole */
-  GLfloat r1  = 0.928;  /* 471 */
-  GLfloat r2  = 0.966;  /* 490 */
-  GLfloat r3  = 0.984;  /* 499 */
+  GLfloat r0  = 0.750;  /* 395 */
+  GLfloat r1a = 0.825;                /* bottom of wall below upper left hole */
+  GLfloat r1b = 0.867;                /* center of upper left hole */
+  GLfloat r1c = 0.909;                /* top of wall above hole */
+  GLfloat r1  = 0.916;  /* 471 */
+  GLfloat r2  = 0.963;  /* 490 */
+  GLfloat r3  = 0.960;  /* 499 */
   GLfloat r4  = 1.000;  /* 507 */
-  GLfloat r5  = 1.090;  /* 553 */
+  GLfloat r5  = 1.080;  /* 553 */
 
   GLfloat ctrl_r[100], ctrl_th[100];
 
@@ -388,46 +405,46 @@ make_gasket (logo_configuration *dc, int wire)
   POINT (0.872, 3.95);
 
   POINT (r4,    4.0);   /* moving clockwise... */
-  POINT (r4,   48.2);
-  POINT (r1,   48.2);
-  POINT (r1,   54.2);
-  POINT (r2,   55.8);
-  POINT (r2,   73.2);
-  POINT (r1,   74.8);
-  POINT (r1,  101.2);
-  POINT (r3,  103.4);
+  POINT (r4,   47.0);
+  POINT (r1,   47.0);
+  POINT (r1,   53.0);
+  POINT (r2,   55.5);
+  POINT (r2,   72.3);
+  POINT (r1,   74.0);
+  POINT (r1,  100.0);
+  POINT (r3,  102.5);
   POINT (r3,  132.0);
-  POINT (r1,  133.4);
+  POINT (r1,  133.0);
 
   POINT (r1,  180.7);
   POINT (r2,  183.6);
-  POINT (r2,  209.8);
-  POINT (r1,  211.0);
-  POINT (r1,  221.8);
-  POINT (r5,  221.8);
+  POINT (r2,  210.0);
+  POINT (r1,  212.0);
+  POINT (r1,  223.2);
   POINT (r5,  223.2);
-  POINT (r4,  223.2);
-
-  POINT (r4,  316.8);      /* upper left indentation */
-  POINT (0.990, 326.87);
-  POINT (0.880, 327.21);
-  POINT (0.872, 327.45);
-  POINT (0.869, 327.80);
-  POINT (0.867, 328.10);
-
-  POINT (0.867, 328.85);
-  POINT (0.869, 329.15);
-  POINT (0.872, 329.50);
-  POINT (0.880, 329.74);
-  POINT (0.990, 330.08);
-
-  POINT (r4,  339.0);
+  POINT (r5,  225.0);
+  POINT (r4,  225.0);
+
+  POINT (r4,    316.8);      /* upper left indentation */
+  POINT (0.990, 316.87);
+  POINT (0.880, 317.21);
+  POINT (0.872, 317.45);
+  POINT (0.869, 317.80);
+  POINT (0.867, 318.10);
+
+  POINT (0.867, 318.85);
+  POINT (0.869, 319.15);
+  POINT (0.872, 319.50);
+  POINT (0.880, 319.74);
+  POINT (0.990, 320.08);
+
+  POINT (r4,  338.5);
   if (! wire)
     {
-      POINT (r1a, 339.0);      /* cut-out disc */
-      POINT (r1a, 343.0);
+      POINT (r1a, 338.5);      /* cut-out disc */
+      POINT (r1a, 343.5);
     }
-  POINT (r4,  343.0);
+  POINT (r4,  343.5);
   POINT (r4,  356.0);
 
   POINT (0.872, 356.05);   /* top indentation, left half */
@@ -634,7 +651,7 @@ make_gasket (logo_configuration *dc, int wire)
     GLfloat th;
     npoints = 0;
 
-    th = 339.0 * d2r;
+    th = 338.5 * d2r;
     pointsx0[npoints] = r1c * cos(th) * dc->gasket_size;
     pointsy0[npoints] = r1c * sin(th) * dc->gasket_size;
     npoints++;
@@ -642,7 +659,7 @@ make_gasket (logo_configuration *dc, int wire)
     pointsy0[npoints] = r4 * sin(th) * dc->gasket_size;
     npoints++;
 
-    th = 343.0 * d2r;
+    th = 343.5 * d2r;
     pointsx0[npoints] = r1c * cos(th) * dc->gasket_size;
     pointsy0[npoints] = r1c * sin(th) * dc->gasket_size;
     npoints++;
@@ -690,7 +707,7 @@ make_gasket (logo_configuration *dc, int wire)
      */
     {
       int nsteps = 12;
-      GLfloat r0 = 0.026;
+      GLfloat r0 = 0.04;
       GLfloat r1 = 0.060;
       GLfloat th, cth, sth;
 
@@ -786,11 +803,11 @@ make_gasket (logo_configuration *dc, int wire)
   /* Attach the bottom-right dingus...
    */
   {
-    GLfloat w = 0.04;
-    GLfloat h = 0.17;
+    GLfloat w = 0.05;
+    GLfloat h = 0.19;
     GLfloat th;
 
-    glRotatef (50, 0, 0, 1);
+    glRotatef (49.5, 0, 0, 1);
     glScalef (dc->gasket_size, dc->gasket_size, 1);
     glTranslatef (0, (r0+r1)/2, 0);
 
@@ -888,6 +905,114 @@ make_gasket (logo_configuration *dc, int wire)
   glPopMatrix();
 }
 
+static void
+make_frame (logo_configuration *dc, int wire)
+{
+  int i, j;
+  GLfloat x[20], y[20];
+  GLfloat corner_cut = 0.5;
+
+  glPushMatrix();
+  glRotatef (90, 0, 1, 0);
+  glScalef (4 * dc->frame_size,
+            4 * dc->frame_size,
+            4 * dc->frame_size);
+
+  x[0] = -dc->frame_thickness;
+  x[1] = -dc->frame_thickness * corner_cut;
+  x[2] = 0;
+  x[3] = 0.5 - dc->triangle_size;
+  x[4] = 0.5;
+  x[5] = 0.5 + dc->triangle_size;
+  x[6] = 1;
+  x[7] = 1 + dc->frame_thickness * corner_cut;
+  x[8] = 1 + dc->frame_thickness;
+
+  y[0] = -dc->frame_thickness;
+  y[1] = -dc->frame_thickness * corner_cut;
+  y[2] = 0;
+  y[3] = dc->triangle_size;
+
+  /* front and back
+   */
+  glTranslatef (-0.5, -0.5, dc->frame_depth / 4);
+  if (! wire)
+    for (j = 0; j <= 1; j++)
+      {
+        if (j) glTranslatef (0, 0, -dc->frame_depth / 2);
+        glFrontFace (j ? GL_CCW : GL_CW);
+        for (i = 0; i < 4; i++)
+          {
+            glNormal3f (0, 0, (j ? -1 : 1));
+            glBegin (wire ? GL_LINES : GL_QUAD_STRIP);
+            glVertex3f (x[0], y[1], 0); glVertex3f (x[0], y[2], 0);
+            glVertex3f (x[1], y[0], 0); glVertex3f (x[1], y[2], 0);
+            glVertex3f (x[3], y[0], 0); glVertex3f (x[3], y[2], 0);
+            glVertex3f (x[4], y[0], 0); glVertex3f (x[4], y[3], 0);
+            glVertex3f (x[5], y[0], 0); glVertex3f (x[5], y[2], 0); 
+            glVertex3f (x[7], y[0], 0); glVertex3f (x[7], y[2], 0);
+            glVertex3f (x[8], y[1], 0); glVertex3f (x[8], y[2], 0);
+            glEnd ();
+            glTranslatef (0.5, 0.5, 0);
+            glRotatef (90, 0, 0, 1);
+            glTranslatef (-0.5, -0.5, 0);
+          }
+      }
+
+  /* ledges
+   */
+  glFrontFace (GL_CCW);
+  for (i = 0; i < 4; i++)
+    {
+      glNormal3f (0, 1, 0);
+      glBegin (wire ? GL_LINES : GL_QUAD_STRIP);
+      glVertex3f (x[2], y[2], 0); glVertex3f (x[2], y[2], dc->frame_depth/2); 
+      glVertex3f (x[3], y[2], 0); glVertex3f (x[3], y[2], dc->frame_depth/2); 
+      glVertex3f (x[4], y[3], 0); glVertex3f (x[4], y[3], dc->frame_depth/2); 
+      glVertex3f (x[5], y[2], 0); glVertex3f (x[5], y[2], dc->frame_depth/2); 
+      glVertex3f (x[6], y[2], 0); glVertex3f (x[6], y[2], dc->frame_depth/2); 
+      glEnd ();
+
+      glNormal3f (0, -1, 0);
+      glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
+      glVertex3f (x[7], y[0], 0); 
+      glVertex3f (x[7], y[0], dc->frame_depth/2); 
+      glVertex3f (x[1], y[0], dc->frame_depth/2); 
+      glVertex3f (x[1], y[0], 0); 
+      glEnd ();
+
+      glNormal3f (1, -1, 0);
+      glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
+      glVertex3f (x[8], y[1], 0); 
+      glVertex3f (x[8], y[1], dc->frame_depth/2); 
+      glVertex3f (x[7], y[0], dc->frame_depth/2); 
+      glVertex3f (x[7], y[0], 0); 
+      glEnd ();
+
+      if (wire) 
+        {
+          glNormal3f (0, 1, 0);
+          for (j = 0; j <= 1; j++)
+            {
+              glBegin (GL_LINE_STRIP);
+              glVertex3f (x[2], y[2], j*dc->frame_depth/2);
+              glVertex3f (x[3], y[2], j*dc->frame_depth/2);
+              glVertex3f (x[4], y[3], j*dc->frame_depth/2);
+              glVertex3f (x[5], y[2], j*dc->frame_depth/2);
+              glVertex3f (x[6], y[2], j*dc->frame_depth/2);
+              glEnd ();
+            }
+        }
+
+      glTranslatef (0.5, 0.5, 0);
+      glRotatef (90, 0, 0, 1);
+      glTranslatef (-0.5, -0.5, 0);
+    }
+
+  glPopMatrix();
+}
+
+
 \f
 /* Window management, etc
  */
@@ -945,7 +1070,10 @@ init_logo (ModeInfo *mi)
   logo_configuration *dc;
   int do_gasket = get_boolean_resource(mi->dpy, "doGasket", "Boolean");
   int do_helix = get_boolean_resource(mi->dpy, "doHelix", "Boolean");
-  int do_ladder = do_helix && get_boolean_resource(mi->dpy, "doLadder", "Boolean");
+  int do_ladder = (do_helix && 
+                   get_boolean_resource(mi->dpy, "doLadder", "Boolean"));
+  int do_frame = get_boolean_resource(mi->dpy, "doFrame", "Boolean");
+  GLfloat helix_rot = 147.0;
 
   if (!do_gasket && !do_helix)
     {
@@ -970,19 +1098,24 @@ init_logo (ModeInfo *mi)
   }
 
   dc->wall_facets    = get_integer_resource(mi->dpy, "wallFacets",  "Integer");
-  dc->tube_facets    = get_integer_resource(mi->dpy, "tubeFacets",  "Integer");
+  dc->bar_facets     = get_integer_resource(mi->dpy, "barFacets",   "Integer");
   dc->clockwise      = get_boolean_resource(mi->dpy, "clockwise",   "Boolean");
   dc->turns          = get_float_resource(mi->dpy, "turns",         "Float");
   dc->turn_spacing   = get_float_resource(mi->dpy, "turnSpacing",   "Float");
   dc->bar_spacing    = get_float_resource(mi->dpy, "barSpacing",    "Float");
   dc->wall_height    = get_float_resource(mi->dpy, "wallHeight",    "Float");
   dc->wall_thickness = get_float_resource(mi->dpy, "wallThickness", "Float");
-  dc->tube_thickness = get_float_resource(mi->dpy, "tubeThickness", "Float");
+  dc->bar_thickness  = get_float_resource(mi->dpy, "barThickness",  "Float");
   dc->wall_taper     = get_float_resource(mi->dpy, "wallTaper",     "Float");
 
-  dc->gasket_size      = get_float_resource(mi->dpy, "gasketSize",      "Float");
-  dc->gasket_depth     = get_float_resource(mi->dpy, "gasketDepth",     "Float");
-  dc->gasket_thickness = get_float_resource(mi->dpy, "gasketThickness", "Float");
+  dc->gasket_size      = get_float_resource(mi->dpy,"gasketSize",     "Float");
+  dc->gasket_depth     = get_float_resource(mi->dpy,"gasketDepth",    "Float");
+  dc->gasket_thickness = get_float_resource(mi->dpy,"gasketThickness","Float");
+
+  dc->frame_size      = get_float_resource(mi->dpy, "frameSize",      "Float");
+  dc->frame_depth     = get_float_resource(mi->dpy, "frameDepth",     "Float");
+  dc->frame_thickness = get_float_resource(mi->dpy, "frameThickness", "Float");
+  dc->triangle_size   = get_float_resource(mi->dpy, "triangleSize",   "Float");
 
   dc->speed          = get_float_resource(mi->dpy, "speed",         "Float");
 
@@ -1017,6 +1150,12 @@ init_logo (ModeInfo *mi)
   dc->helix_spinnerz.probability  = 0.6;
   dc->scene_spinnerx.probability  = 0.1;
   dc->scene_spinnery.probability  = 0.0;
+  dc->frame_spinner.probability   = 5.0;
+
+  /* start the frame off-screen */
+  dc->frame_spinner.spinning_p = True;
+  dc->frame_spinner.position = 0.3;
+  dc->frame_spinner.speed = 0.001;
 
   if (dc->speed > 0)    /* start off with the gasket in motion */
     {
@@ -1029,7 +1168,7 @@ init_logo (ModeInfo *mi)
   glPushMatrix();
   dc->helix_list = glGenLists (1);
   glNewList (dc->helix_list, GL_COMPILE);
-  glRotatef(126, 0, 0, 1);
+  glRotatef(helix_rot, 0, 0, 1);
   if (do_ladder) make_ladder (dc, 0, 0);
   if (do_helix)  make_helix  (dc, 0, 0);
   glRotatef(180, 0, 0, 1);
@@ -1040,7 +1179,7 @@ init_logo (ModeInfo *mi)
   glPushMatrix();
   dc->helix_list_wire = glGenLists (1);
   glNewList (dc->helix_list_wire, GL_COMPILE);
-  /* glRotatef(126, 0, 0, 1); wtf? */
+/*  glRotatef(helix_rot, 0, 0, 1); wtf? */
   if (do_ladder) make_ladder (dc, 1, 1);
   if (do_helix)  make_helix  (dc, 1, 1);
   glRotatef(180, 0, 0, 1);
@@ -1051,7 +1190,7 @@ init_logo (ModeInfo *mi)
   glPushMatrix();
   dc->helix_list_facetted = glGenLists (1);
   glNewList (dc->helix_list_facetted, GL_COMPILE);
-  glRotatef(126, 0, 0, 1);
+  glRotatef(helix_rot, 0, 0, 1);
   if (do_ladder) make_ladder (dc, 1, 0);
   if (do_helix)  make_helix  (dc, 1, 0);
   glRotatef(180, 0, 0, 1);
@@ -1069,6 +1208,16 @@ init_logo (ModeInfo *mi)
   if (do_gasket) make_gasket (dc, 1);
   glEndList ();
 
+  dc->frame_list = glGenLists (1);
+  glNewList (dc->frame_list, GL_COMPILE);
+  if (do_frame) make_frame (dc, 0);
+  glEndList ();
+
+  dc->frame_list_wire = glGenLists (1);
+  glNewList (dc->frame_list_wire, GL_COMPILE);
+  if (do_frame) make_frame (dc, 1);
+  glEndList ();
+
   /* When drawing both solid and wireframe objects,
      make sure the wireframe actually shows up! */
   glEnable (GL_POLYGON_OFFSET_FILL);
@@ -1193,21 +1342,49 @@ draw_logo (ModeInfo *mi)
   tick_spinner (mi, &dc->helix_spinnerz);
   tick_spinner (mi, &dc->scene_spinnerx);
   tick_spinner (mi, &dc->scene_spinnery);
+  tick_spinner (mi, &dc->frame_spinner);
   link_spinners (mi, &dc->scene_spinnerx, &dc->scene_spinnery);
 
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
   glPushMatrix ();
   {
-    glScalef(3.3, 3.3, 3.3);
+    glScalef(3, 3, 3);
+
+    glColor3f(dc->color[0], dc->color[1], dc->color[2]);
+
+    /* Draw frame before trackball rotation */
+    {
+      GLfloat p = (dc->frame_spinner.position >= 0
+                   ? dc->frame_spinner.position
+                   : -dc->frame_spinner.position);
+      GLfloat size = (p > 0.5 ? 1-p : p);
+      GLfloat scale = 1 + (size * 10);
+      glPushMatrix();
+      /* gltrackball_rotate (dc->trackball); */
+      glRotatef(90, 1, 0, 0);
+      glRotatef(90, 0, 0, 1);
+
+      glScalef (1, scale, scale);
+      if (wire)
+        glCallList (dc->frame_list_wire);
+      else if (dc->wire_overlay != 0)
+        {
+          glCallList (dc->frame_list);
+          glDisable (GL_LIGHTING);
+          glCallList (dc->frame_list_wire);
+          if (!wire) glEnable (GL_LIGHTING);
+        }
+      else
+        glCallList (dc->frame_list);
+      glPopMatrix();
+    }
 
     gltrackball_rotate (dc->trackball);
 
     glRotatef(90, 1, 0, 0);
     glRotatef(90, 0, 0, 1);
 
-    glColor3f(dc->color[0], dc->color[1], dc->color[2]);
-
     glRotatef (360 * sin (M_PI/2 * dc->scene_spinnerx.position), 0, 1, 0);
     glRotatef (360 * sin (M_PI/2 * dc->scene_spinnery.position), 0, 0, 1);
 
index 60b2dfd929755bef40fc4f7ccc2a3cec1a05602e..766e2396d914dac381a147ff38f5285ad4deffa9 100644 (file)
@@ -1,11 +1,14 @@
 /* -*- Mode: C; tab-width: 4 -*- */
+/* vim: set ai ts=4 sw=4: */
 
 #if !defined( lint ) && !defined( SABER )
 /*static const char sccsid[] = "@(#)gleidescope.c      1.0 03/06/27 xlockmore";*/
 #endif
 
-/* enable -grab switch */
-/*#define      GRAB*/
+/* enable -grab switch for animations */
+#undef GRAB
+
+#undef DISPLAY_TEXTURE
 
 /*-
  * Permission to use, copy, modify, and distribute this software and its
  *                                                                     no preference is given.
  *                                                             Made grid slightly bigger so you can't see
  *                                                                     the edge when zooming and moving.
+ *     20061226        1.4             acd             Now uses GL Display Lists.
+ *     20070318        1.5             acd             Generates textures.
+ *                                                             Fixed texture size problem (and introduced another).
+ *     20070412        1.6             acd             Textures now have independant sizes.
+ *     20070413        1.7             acd             Added Lissajous movement pattern.
+ *     20070414        1.8             acd             Added corners movement pattern.
+ *     20080319        1.9             acd             Changes to arguments for saner gleidescope.xml.
+ *
+ * TODO
+ * generate textures myself - render random shapes to 256x256 texture. (done)
+ * lower res for checks and random - use 256 and 4x4 or 8x8 pixels. (disabled for now)
+ * gnome-saver doesn't let you specify source directory so add that to this.
+ * image loading routine is too slow - rotation grinds to a halt - stop using it. (better in version 5)
+ * image loading also looks bad for non-square images - edges are black. (fixed)
+ * possible to see edge of the world on widescreen terminals - use larger grid and hidden hex removal?
+ * fading textures may have different max_tx - use two sets. (done)
+ * choice of movement patterns. (3 implemented, chooseable at compile time)
+ * look into rangle and tangle.
  */
 
 /*
 #include "xpm-ximage.h"
 #include "grab-ximage.h"
 
+#ifdef GRAB
+void grab_frame(Display *display, Window window);
+#endif
+
 /* acd TODO should all these be in gleidestruct? */
 /* they can't be, because of the idiotic way the xlockmore "argtype vars"
    interface works. -jwz */
@@ -82,8 +107,15 @@ static Bool         nozoom;                 /* no zooming camera */
 static char            *image;                 /* name of texture to load */
 static int             duration;               /* length of time to display grabbed image */
 
-#define        MAX_TANGLE_VEL  2.0
-#define        MAX_RANGLE_VEL  1.5
+#define MAX_CAM_SPEED                  1.0
+#define MAX_ANGLE_VEL                  1.0
+#define INITIAL_ANGLE_VEL              0.2
+#define INITIAL_ANGLE_ACC              0.001
+#define        TWISTING_PROBABILITY    1000    /* 1 in ... of change of acceleration */
+
+#define RADIANS        (M_PI / 180)
+#define ANGLE_120      (M_PI * 2 / 3)
+#define ANGLE_240      (M_PI * 4 / 3)
 
 static XrmOptionDescRec opts[] =
 {
@@ -162,6 +194,25 @@ typedef struct {
        GLfloat z;
 } vectorf;
 
+typedef struct {
+       GLfloat x;
+       GLfloat y;
+} vector2f;
+
+typedef struct {
+       GLuint                  id;                             /* opengl texture id */
+       GLfloat                 width, height;  /* texture width and height */
+       GLfloat                 min_tx, min_ty; /* minimum texture sizes */
+       GLfloat                 max_tx, max_ty; /* maximum texture sizes */
+       time_t                  start_time;
+       Bool                    button_down_p;
+    Bool                       mipmap_p;
+    Bool                       waiting_for_image_p;
+       /* r_phase is for triangle rotation speed */
+       GLfloat                 x_period, y_period, r_period;
+       GLfloat                 x_phase, y_phase, r_phase;
+} texture;
+
 #define        MAX_FADE        500     /* number of fade cycles */
 
 typedef struct {
@@ -170,16 +221,16 @@ typedef struct {
        float                   tic;
        GLXContext              *glx_context;
        Window                  window;
-       GLfloat                 max_tx, max_ty; /* maximum texture sizes */
-       GLuint                  textures[2];    /* texture handles */
-       GLuint                  visible;                /* texture handle for new texture */
+       texture                 textures[2];    /* texture handles */
+       GLuint                  visible;                /* index for current texture */
        GLint                   fade;
        time_t                  start_time;
        Bool                    button_down_p;
 
     int                size;
+       int             list;
 
-    float      tangle;         /* texture angle */
+    float      tangle;         /* texture angle (degrees) */
     float      tangle_vel;     /* texture velocity */
     float      tangle_acc;     /* texture acceleration */
 
@@ -198,6 +249,8 @@ typedef struct {
 
 } gleidestruct;
 
+#define frandrange(x, y)       (x + frand(y - x))
+
 #define        XOFFSET (0.8660254f)    /* sin 60' */
 #define        YOFFSET (1.5000000f)    /* cos 60' + 1 */
 
@@ -231,6 +284,7 @@ generate_grid(int size)
 }
 #endif
 
+/* acd - this is terrible - 120+ hexes */
 static const hex_t hex[] = {
        /* edges of size 7 */
        /* number of hexagons required to cover screen depends on camera distance */
@@ -474,37 +528,347 @@ image_loaded_cb (const char *filename, XRectangle *geometry,
                  int texture_width, int texture_height,
                  void *closure)
 {
-  gleidestruct *gp = (gleidestruct *) closure;
+       texture *tp = (texture *) closure;
+
+#if 0
+       gp->max_tx = (GLfloat) image_width  / texture_width;
+       gp->max_ty = (GLfloat) image_height / texture_height;
+#endif
+
+       /* new - taken from flipscreen */
+       tp->width = texture_width;
+       tp->height = texture_height;
+       tp->min_tx = (GLfloat) geometry->x / tp->width;
+       tp->min_ty = (GLfloat) geometry->y / tp->height;
+       tp->max_tx = (GLfloat) (geometry->x + geometry->width)  / tp->width;
+       tp->max_ty = (GLfloat) (geometry->y + geometry->height) / tp->height;
 
-  gp->max_tx = (GLfloat) image_width  / texture_width;
-  gp->max_ty = (GLfloat) image_height / texture_height;
+#ifdef DEBUG
+       printf("Image w,h: (%d, %d)\n", image_width, image_height);
+       printf("Texture w,h: (%d, %d)\n", texture_width, texture_height);
+       printf("Geom x,y: (%d, %d)\n", geometry->x, geometry->y);
+       printf("Geom w,h: (%d, %d)\n", geometry->width, geometry->height);
+       printf("Max Tx,Ty: (%f, %f)\n", tp->max_tx, tp->max_ty);
+#endif
 
-  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
-                   (gp->mipmap_p ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR));
+       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+                       (tp->mipmap_p ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR));
 
-  gp->waiting_for_image_p = False;
-  gp->start_time = time ((time_t *) 0);
+       tp->waiting_for_image_p = False;
+       tp->start_time = time ((time_t *) 0);
 }
 
-
 static void
-getSnapshot(ModeInfo *mi, GLuint name)
+getSnapshot(ModeInfo *mi, texture *texture)
 {
        gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
 
+#ifdef DEBUG
+       printf("getSnapshot");
+#endif
+
        if (MI_IS_WIREFRAME(mi))
                return;
 
     gp->mipmap_p = True;
     load_texture_async (mi->xgwa.screen, mi->window,
                         *gp->glx_context, 0, 0, gp->mipmap_p, 
-                        name, image_loaded_cb, gp);
+                        texture->id, image_loaded_cb, texture);
+       texture->start_time = time((time_t *)0);
+}
+
+#define TEXTURE_SIZE   256
+
+static void
+plot(unsigned char *buffer, int x, int y, int r, int g, int b, int a) {
+       int c;
+       if (x < 0 || x >= TEXTURE_SIZE || y < 0 || y >= TEXTURE_SIZE) {
+               return;
+       }
+       c = ((x * TEXTURE_SIZE) + y) * 4;
+       /*printf("(%d,%d)[%d]\n", x, y, c);*/
+       buffer[c + 0] = r;
+       buffer[c + 1] = g;
+       buffer[c + 2] = b;
+       buffer[c + 3] = a;
+}
+
+#if 0
+static void
+plot2(unsigned char *buffer, int x, int y, int r, int g, int b, int a) {
+       int c;
+       if (x < 0 || x >= TEXTURE_SIZE || y < 0 || y >= TEXTURE_SIZE) {
+               return;
+       }
+       c = ((x * TEXTURE_SIZE) + y) * 4;
+       /*printf("(%d,%d)[%d]\n", x, y, c);*/
+       buffer[c + 0] = r;
+       buffer[c + 1] = g;
+       buffer[c + 2] = b;
+       buffer[c + 3] = a;
+       
+       if (y + 1 < TEXTURE_SIZE) {
+               buffer[c + 4] = r;
+               buffer[c + 5] = g;
+               buffer[c + 6] = b;
+               buffer[c + 7] = a;
+       }
+
+       if (x + 1 < TEXTURE_SIZE) {
+               c += (TEXTURE_SIZE * 4);
+               buffer[c + 0] = r;
+               buffer[c + 1] = g;
+               buffer[c + 2] = b;
+               buffer[c + 3] = a;
+               if (y + 1 < TEXTURE_SIZE) {
+                       buffer[c + 4] = r;
+                       buffer[c + 5] = g;
+                       buffer[c + 6] = b;
+                       buffer[c + 7] = a;
+               }
+       }
+}
+#endif
+
+/* draw geometric shapes to texture */
+/* modifies passed in buffer */
+static void
+draw_shapes (unsigned char *buffer) {
+       int a = 0xff;
+       int x, y, w, h;
+       int i, j;
+       int s;
+       float left, right;
+
+       for (i = 0 ; i < TEXTURE_SIZE * TEXTURE_SIZE * 4 ; i += 4) {
+               buffer[i + 0] = 0x00;
+               buffer[i + 1] = 0x00;
+               buffer[i + 2] = 0x00;
+               buffer[i + 3] = 0xff;
+       }
+
+       for (s = 0 ; s < 25 ; s++) {
+               int shape = random() % 3;
+
+               /* 8 bits */
+               int r = (random() & 0xff);
+               int g = (random() & 0xff);
+               int b = (random() & 0xff);
+
+               switch (shape) {
+                       case 0:
+                               /* rectangle */
+                               x = (random() % TEXTURE_SIZE) - (TEXTURE_SIZE / 4);     /* top left */
+                               y = (random() % TEXTURE_SIZE) - (TEXTURE_SIZE / 4);
+                               w = 10 + random() % (TEXTURE_SIZE / 4); /* size */
+                               h = 10 + random() % (TEXTURE_SIZE / 4);
+#ifdef DEBUG
+                               printf("Rectangle: (%d, %d)(%d, %d)\n", x, y, w, h);
+#endif
+                               if (x < 0) {
+                                       x = 0;
+                               }
+                               if (y < 0) {
+                                       y = 0;
+                               }
+                               for (i = x ; i < x + w && i < TEXTURE_SIZE; i++) {
+                                       for (j = y ; j < y + h && j < TEXTURE_SIZE; j++) {
+                                               plot(buffer, i, j, r, g, b, a);
+                                       }
+                               }
+                               break;
+
+                       case 1:
+                               /* circle */
+                               x = random() % TEXTURE_SIZE;    /* centre */
+                               y = random() % TEXTURE_SIZE;
+                               h = 10 + random() % (TEXTURE_SIZE / 8); /* radius */
+#ifdef DEBUG
+                               printf("Circle: %d, %d, %d\n", x, y, h);
+#endif
+                               for (i = 0 ; i < h ; i++) {
+                                       int xdist = i * i;
+                                       for (j = 0 ; j < h ; j++) {
+                                               int ydist = j * j;
+                                               /*
+                                               printf("xdist: %d\n", xdist);
+                                               printf("ydist: %d\n", ydist);
+                                               printf("radius: %d\n", h * h);
+                                               */
+                                               if ((xdist + ydist) < (h * h)) {
+                                                       plot(buffer, x + i, y + j, r, b, g, a);
+                                                       /* check we haven't already done these */
+                                                       if (j != 0) {
+                                                               plot(buffer, x + i, y - j, r, b, g, a);
+                                                       }
+                                                       if (i != 0) {
+                                                               plot(buffer, x - i, y + j, r, b, g, a);
+                                                               if (j != 0) {
+                                                               plot(buffer, x - i, y - j, r, b, g, a);
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                               break;
+
+                       case 2:
+                               /* triangle */
+                               x = random() % TEXTURE_SIZE;    /* top */
+                               y = random() % TEXTURE_SIZE;
+                               h = 10 + random() % (TEXTURE_SIZE / 4); /* height */
+#ifdef DEBUG
+                               printf("Triangle: %d, %d, %d\n", x, y, h);
+#endif
+                               left = x;
+                               right = x;
+                               for (i = 0 ; i < h ; i++) {
+                                       for (j = left ; j < right ; j++) {
+                                               plot(buffer, j, y + i, r, g, b, a);
+                                       }
+                                       left -= .5;
+                                       right += .5;
+                               }
+                               break;
+               }
+       }
 }
 
+static void
+setup_random_texture (ModeInfo *mi, texture *texture)
+{
+       int width = 0, height = 0;
+       char buf[1024];
+       unsigned char *my_data = NULL;
+#if 0
+       int i, j, c;
+       int style;
+       int r0, g0, b0, a0, r1, g1, b1, a1;
+#endif
+
+#ifdef DEBUG
+       printf("RandomTexture\n");
+#endif
+
+       /* use this texture */
+       glBindTexture(GL_TEXTURE_2D, texture->id);
+
+       clear_gl_error();
+
+       /*
+        * code for various generated patterns - noise, stripes, checks etc.
+        * random geometric shapes looked the best.
+        */
+
+#if 0
+       style = random() & 0x3;
+       r0 = random() & 0xff; 
+       g0 = random() & 0xff; 
+       b0 = random() & 0xff; 
+       a0 = 0xff;
+       r1 = random() & 0xff; 
+       g1 = random() & 0xff; 
+       b1 = random() & 0xff; 
+       a1 = 0xff;
+
+       switch (style) {
+               case 0: /* random */
+                       printf("Random0\n");
+                       height = width = TEXTURE_SIZE;
+                       my_data = (void *)malloc(width * height * 4);
+                       for (i = 0 ; i < width ; i += 2) {
+                               for (j = 0 ; j < height ; j += 2) {
+                                       r0 = random() & 0xff; 
+                                       g0 = random() & 0xff; 
+                                       b0 = random() & 0xff; 
+                                       a0 = 0xff;
+                                       plot2(my_data, i, j, r0, g0, b0, a0);
+                               }
+                       }
+                       break;
+
+               case 1: /* shapes */
+#endif
+#ifdef DEBUG
+                       printf("Shapes\n");
+#endif
+                       height = width = TEXTURE_SIZE;
+                       my_data = (void *)malloc(width * height * 4);
+                       draw_shapes(my_data);
+#if 0
+                       break;
+
+               case 2: /* check */
+                       printf("Check\n");
+                       height = width = TEXTURE_SIZE;
+                       my_data = (void *)malloc(width * height * 4);
+                       for (i = 0 ; i < height ; i += 2) {
+                               for (j = 0 ; j < width ; j += 2) {
+                                       if (((i + j) & 0x3) == 0) {
+                                               plot2(my_data, i, j, r0, g0, b0, a0);
+                                       } else {
+                                               plot2(my_data, i, j, r1, g1, b1, a1);
+                                       }
+                               }
+                       }
+                       break;
+
+               case 3: /* random stripes */
+                       printf("Stripes 2\n");
+                       height = width = TEXTURE_SIZE;
+                       my_data = (void *)malloc(width * height * 4);
+                       for (i = 0 ; i < height ; i += 2) {
+                               r0 = random() & 0xff; 
+                               g0 = random() & 0xff; 
+                               b0 = random() & 0xff; 
+                               a0 = 0xff;
+                               for (j = 0 ; j < width ; j += 2) {
+                                       plot2(my_data, i, j, r0, g0, b0, a0);
+                               }
+                       }
+                       break;
+       }
+#endif
+
+       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
+                       width, height, 0,
+                       GL_RGBA, GL_UNSIGNED_BYTE, my_data);
+       sprintf (buf, "random texture: (%dx%d)",
+                       width, height);
+       check_gl_error(buf);
+
+       /* setup parameters for texturing */
+       glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+       glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
+
+       glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+       if (random() & 0x1) {
+               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+       } else {
+               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+               glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+       }
+
+       if (my_data != NULL) {
+               free(my_data);
+               my_data = NULL;
+       }
+
+       /* use full texture */
+       /* acd - was 1.0 */
+       texture->min_tx = 0.0;
+       texture->max_tx = 2.0;
+       texture->min_ty = 0.0;
+       texture->max_ty = 2.0;
+       texture->start_time = time((time_t *)0);
+}
 
 static void
-setup_file_texture (ModeInfo *mi, char *filename, GLuint name)
+setup_file_texture (ModeInfo *mi, char *filename, texture *texture)
 {
        Display *dpy = mi->dpy;
        Visual *visual = mi->xgwa.visual;
@@ -513,8 +877,12 @@ setup_file_texture (ModeInfo *mi, char *filename, GLuint name)
        Colormap cmap = mi->xgwa.colormap;
        XImage *image = xpm_file_to_ximage (dpy, visual, cmap, filename);
 
+#ifdef DEBUG
+       printf("FileTexture\n");
+#endif
+
        /* use this texture */
-       glBindTexture(GL_TEXTURE_2D, name);
+       glBindTexture(GL_TEXTURE_2D, texture->id);
 
        clear_gl_error();
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
@@ -533,32 +901,62 @@ setup_file_texture (ModeInfo *mi, char *filename, GLuint name)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+       /* use full texture */
+       texture->min_tx = 0.0;
+       texture->max_tx = 1.0;
+       texture->min_ty = 0.0;
+       texture->max_ty = 1.0;
+       texture->start_time = time((time_t *)0);
 }
 
 static void
-setup_texture(ModeInfo * mi, GLuint id)
+setup_texture(ModeInfo * mi, texture *texture)
 {
        gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
 
        if (!image || !*image || !strcmp(image, "DEFAULT")) {
-               /* no image specified - grab screen */
-               getSnapshot(mi, id);
-               /* max_tx and max_ty set in getSnapshot() */
+               /* no image specified - use system settings */
+#ifdef DEBUG
+               printf("SetupTexture: get_snapshot\n");
+#endif
+               getSnapshot(mi, texture);
        } else {
-               /* use supplied image file */
-               setup_file_texture(mi, image, id);
-
-               /* set tx params to use whole image */
-               gp->max_tx = 1.0f;
-               gp->max_ty = 1.0f;
+               if (strcmp(image, "GENERATE") == 0) {
+#ifdef DEBUG
+                       printf("SetupTexture: random_texture\n");
+#endif
+                       setup_random_texture(mi, texture);
+               } else {
+                       /* use supplied image file */
+#ifdef DEBUG
+                       printf("SetupTexture: file_texture\n");
+#endif
+                       setup_file_texture(mi, image, texture);
+               }
        }
+       /* copy start time from texture */
+       gp->start_time = texture->start_time;
 
        check_gl_error("texture initialization");
 
-       /* Need to flip the texture top for bottom for some reason. */
-       glMatrixMode (GL_TEXTURE);
-       glScalef (1, -1, 1);
-       glMatrixMode (GL_MODELVIEW);
+       /* acd 
+        * resultant loaded image is upside down BUT
+        * it's a kaledescope and half of the hexagon is backwards anyway...
+        */
+
+       /* TODO: values for lissajous movement */
+       texture->x_period = frandrange(-2.0, 2.0);
+       texture->y_period = frandrange(-2.0, 2.0);
+       texture->r_period = frandrange(-2.0, 2.0);
+       texture->x_phase = frand(M_PI * 2);
+       texture->y_phase = frand(M_PI * 2);
+       texture->r_phase = frand(M_PI * 2);
+#ifdef DEBUG
+       printf("XPeriod %f XPhase %f\n", texture->x_period, texture->x_phase);
+       printf("YPeriod %f YPhase %f\n", texture->y_period, texture->y_phase);
+       printf("RPeriod %f RPhase %f\n", texture->r_period, texture->r_phase);
+#endif
 }
 
 #define        VERTEX0 glVertex3f( 0.0000f,  0.000f, 0.0f);
@@ -569,99 +967,230 @@ setup_texture(ModeInfo * mi, GLuint id)
 #define        VERTEX5 glVertex3f(-XOFFSET, -0.500f, 0.0f);
 #define        VERTEX6 glVertex3f(-XOFFSET,  0.500f, 0.0f);
 
+/*
+** Three different functions for calculating texture coordinates
+** which modify how the texture triangle moves over the source image.
+** Choose one.
+*/
+
+#if 0
+/* the classic equilateral triangle rotating around centre */
+static void
+calculate_texture_coords(ModeInfo *mi, texture *texture, vector2f t[3]) {
+
+       gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
+       GLfloat centre_x = 0.5;
+       GLfloat centre_y = 0.5;
+       GLfloat radius_x = (texture->max_tx - texture->min_tx) / 2;
+       GLfloat radius_y = (texture->max_ty - texture->min_ty) / 2;
+       GLfloat tangle2;
+       t[0].x = centre_x;
+       t[0].y = centre_y;
+
+       /* t[1] */
+       t[1].x = centre_x + .95 * radius_x * cos((gp->ymouse * 2 * M_PI) + (gp->tangle * RADIANS));
+       t[1].y = centre_y + .95 * radius_y * sin((gp->ymouse * 2 * M_PI) + (gp->tangle * RADIANS));
+
+       /* t[2] is always 60' further around than t2 */
+       tangle2 = (gp->ymouse * 2 * M_PI) + (gp->tangle * RADIANS) + (M_PI * 2 / 6);
+       t[2].x = centre_x + .95 * radius_x * cos(tangle2);
+       t[2].y = centre_y + .95 * radius_y * sin(tangle2);
+#if 0
+       printf("texcoords:[%f,%f]->[%f,%f](%f,%f)\n", t[0].x, t[0].y, t[1].x, t[1].y, texture->max_tx, texture->max_ty);
+#endif
+}
+#endif
+
+#if 1
+/* new lissajous movement pattern */
+static void
+calculate_texture_coords(ModeInfo *mi, texture *texture, vector2f t[3]) {
+
+       /* equilateral triangle rotating around centre */
+       gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
+       GLfloat width = texture->max_tx - texture->min_tx;
+       GLfloat height = texture->max_ty - texture->min_ty;
+       /* centre */
+       GLfloat centre_x = texture->min_tx + (width * .5);
+       GLfloat centre_y = texture->min_ty + (height * .5);
+       /* m radius and t radius should be = .5 */
+       /* triangle radius is 30% available space */
+       GLfloat t_radius_x = width * .3;
+       GLfloat t_radius_y = height * .3;
+       /* movement radius is 30% available space */
+       GLfloat m_radius_x = width * .2;
+       GLfloat m_radius_y = height * .2;
+       GLfloat angle2;
+
+       /* centre of triangle */
+       GLfloat angle = (gp->ymouse * 2 * M_PI) + (gp->tangle * RADIANS);       /* to radians */
+       GLfloat t_centre_x = centre_x + m_radius_x * cos(texture->x_period * angle + texture->x_phase);
+       GLfloat t_centre_y = centre_y + m_radius_y * sin(texture->y_period * angle + texture->y_phase);
+
+#if 0
+       printf("WH: %f, %f - tWH: %f, %f\n", width, height, texture->width, texture->height);
+       printf("size: (%f, %f)\n", width, height);
+       printf("centre: (%f, %f)\n", centre_x, centre_y);
+#endif
+
+       angle2 = texture->r_period * angle + texture->r_phase;
+       t[0].x = t_centre_x + t_radius_x * cos(angle2);
+       t[0].y = t_centre_y + t_radius_y * sin(angle2);
+       t[1].x = t_centre_x + t_radius_x * cos(angle2 + ANGLE_120);
+       t[1].y = t_centre_y + t_radius_y * sin(angle2 + ANGLE_120);
+       t[2].x = t_centre_x + t_radius_x * cos(angle2 + ANGLE_240);
+       t[2].y = t_centre_y + t_radius_y * sin(angle2 + ANGLE_240);
+
+#if 0
+       printf("texcoords:[%f,%f]->[%f,%f](%f,%f)\n", t[0].x, t[0].y, t[1].x, t[1].y, texture->max_tx, texture->max_ty);
+#endif
+}
+#endif
+#if 0
+/* corners into corners - meant to maximise coverage */
+static void
+calculate_texture_coords(ModeInfo *mi, texture *texture, vector2f t[3]) {
+
+       /* equilateral triangle rotating around centre */
+       gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
+       GLfloat width = texture->max_tx - texture->min_tx;
+       GLfloat height = texture->max_ty - texture->min_ty;
+       /* centre */
+       GLfloat centre_x = texture->min_tx + (width * .5);
+       GLfloat centre_y = texture->min_ty + (height * .5);
+       /* m radius and t radius should be = .5 */
+       /* triangle radius calculated using maths 8) */
+#define TRADIUS (M_SQRT2 - 1.0)
+#define MRADIUS (1.0 - (M_SQRT2 / 2.0))
+       GLfloat t_radius_x = width * TRADIUS * .95;
+       GLfloat t_radius_y = height * TRADIUS * .95;
+       /* movement radius also calculated using maths */
+       GLfloat m_radius_x = width * MRADIUS * .95;
+       GLfloat m_radius_y = height * MRADIUS * .95;
+       GLfloat angle, angle2;
+       GLfloat t_centre_x, t_centre_y;
+
+       /* centre of triangle */
+       angle = gp->tangle * RADIANS;   /* to radians */
+       t_centre_x = centre_x + m_radius_x * cos(angle);
+       t_centre_y = centre_y + m_radius_y * sin(angle);
+#if 0
+       printf("angle: %f, %f\n", angle, gp->tangle);
+       printf("tcentre: %f,%f\n", t_centre_x, t_centre_y);
+       printf("tradius: %f,%f\n", t_radius_x, t_radius_y);
+
+       printf("size: (%f, %f)\n", width, height);
+       printf("centre: (%f, %f)\n", centre_x, centre_y);
+       printf("centre: (%f, %f)\n", centre_x, centre_y);
+       printf("TRADIUS: %f\n", TRADIUS);
+       printf("MRADIUS: %f\n", MRADIUS);
+#endif
+
+       /* angle2 is tied to tangle */
+       angle2 = (180.0 - ((30.0 / 90.0) * gp->tangle)) * RADIANS; 
+#if 0
+       printf("Angle1: %f\tAngle2: %f\n", angle / RADIANS, angle2 / RADIANS);
+#endif
+       t[0].x = t_centre_x + t_radius_x * cos(angle2);
+       t[0].y = t_centre_y + t_radius_y * sin(angle2);
+       t[1].x = t_centre_x + t_radius_x * cos(angle2 + ANGLE_120);
+       t[1].y = t_centre_y + t_radius_y * sin(angle2 + ANGLE_120);
+       t[2].x = t_centre_x + t_radius_x * cos(angle2 + ANGLE_240);
+       t[2].y = t_centre_y + t_radius_y * sin(angle2 + ANGLE_240);
+
+#if 0
+       printf("texcoords:[%f,%f][%f,%f][%f,%f]\n", t[0].x, t[0].y, t[1].x, t[1].y, t[2].x, t[2].y);
+#endif
+}
+#endif
+
 static void
-draw_hexagons(ModeInfo *mi, int translucency, GLuint texture)
+draw_hexagons(ModeInfo *mi, int translucency, texture *texture)
 {
        int             i;
        GLfloat col[4];
-       GLfloat t1x, t1y, t2x, t2y, t3x, t3y;
+       vector2f t[3];
        gleidestruct *gp = &gleidescope[MI_SCREEN(mi)];
-       GLfloat tangle2;
 
        col[0] = 1.0;
        col[1] = 1.0;
        col[2] = 1.0;
        col[3] = (float)translucency / MAX_FADE;
 
-       /* calculate vertices of equilateral triangle within image. */
-       /* t1 is always in centre */
-       t1x = gp->max_tx / 2;
-       t1y = gp->max_ty / 2;
-       /* t2 rotates */
-       t2x = (gp->max_tx / 2) * (1 + cos((gp->ymouse * 2 * M_PI) + (gp->tangle * M_PI / 180)));
-       t2y = (gp->max_ty / 2) * (1 + sin((gp->ymouse * 2 * M_PI) + (gp->tangle * M_PI / 180)));
-       /* t3 is always 60' further around than t2 */
-       tangle2 = (gp->ymouse * 2 * M_PI) + (gp->tangle * M_PI / 180) + (M_PI * 2 / 6);
-       t3x = (gp->max_tx / 2) * (1 + (cos(tangle2)));
-       t3y = (gp->max_ty / 2) * (1 + (sin(tangle2)));
-       /* NB image is flipped vertically hence: */
-       t1y = 1 - t1y;
-       t2y = 1 - t2y;
-       t3y = 1 - t3y;
-       /*printf("texcoords:[%f,%f]->[%f,%f](%f,%f)\n", t1x, t1y, t2x, t2y, gp->max_tx, gp->max_ty);*/
+       calculate_texture_coords(mi, texture, t);
 
        glColor4f(1.0, 1.0, 1.0, (float)translucency / MAX_FADE);
        glEnable(GL_TEXTURE_2D);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glDepthMask(GL_FALSE);
-       glBindTexture(GL_TEXTURE_2D, gp->textures[texture]);
+       glBindTexture(GL_TEXTURE_2D, texture->id);
 
+       if (gp->list == -1) {
+               gp->list = glGenLists(1);
+       }
+
+       /* compile new list */
+       glNewList(gp->list, GL_COMPILE);
+       glBegin(GL_TRIANGLES);
+
+       /*
+       ** six triangles to each hexagon
+       */
+
+       glTexCoord2f(t[0].x, t[0].y);
+       VERTEX0;
+       glTexCoord2f(t[1].x, t[1].y);
+       VERTEX1;
+       glTexCoord2f(t[2].x, t[2].y);
+       VERTEX6;
+
+       glTexCoord2f(t[0].x, t[0].y);
+       VERTEX0;
+       glTexCoord2f(t[2].x, t[2].y);
+       VERTEX6;
+       glTexCoord2f(t[1].x, t[1].y);
+       VERTEX5;
+
+       glTexCoord2f(t[0].x, t[0].y);
+       VERTEX0;
+       glTexCoord2f(t[1].x, t[1].y);
+       VERTEX5;
+       glTexCoord2f(t[2].x, t[2].y);
+       VERTEX4;
+
+       glTexCoord2f(t[0].x, t[0].y);
+       VERTEX0;
+       glTexCoord2f(t[2].x, t[2].y);
+       VERTEX4;
+       glTexCoord2f(t[1].x, t[1].y);
+       VERTEX3;
+
+       glTexCoord2f(t[0].x, t[0].y);
+       VERTEX0;
+       glTexCoord2f(t[1].x, t[1].y);
+       VERTEX3;
+       glTexCoord2f(t[2].x, t[2].y);
+       VERTEX2;
+
+       glTexCoord2f(t[0].x, t[0].y);
+       VERTEX0;
+       glTexCoord2f(t[2].x, t[2].y);
+       VERTEX2;
+       glTexCoord2f(t[1].x, t[1].y);
+       VERTEX1;
+
+       glEnd();
+       glEndList();
+
+       /* call the list n times */
        for (i = 0 ; i < sizeof(hex) / sizeof(hex[0]) ; i++) {
 
                glPushMatrix();
 
                glTranslatef(hex[i].x, hex[i].y, 0.0);
-
-               glBegin(GL_TRIANGLES);
-
-               /*
-               ** six triangles to each hexagon
-               */
-
-               glTexCoord2f(t1x, t1y);
-               VERTEX0;
-               glTexCoord2f(t2x, t2y);
-               VERTEX1;
-               glTexCoord2f(t3x, t3y);
-               VERTEX6;
-
-               glTexCoord2f(t1x, t1y);
-               VERTEX0;
-               glTexCoord2f(t3x, t3y);
-               VERTEX6;
-               glTexCoord2f(t2x, t2y);
-               VERTEX5;
-
-               glTexCoord2f(t1x, t1y);
-               VERTEX0;
-               glTexCoord2f(t2x, t2y);
-               VERTEX5;
-               glTexCoord2f(t3x, t3y);
-               VERTEX4;
-
-               glTexCoord2f(t1x, t1y);
-               VERTEX0;
-               glTexCoord2f(t3x, t3y);
-               VERTEX4;
-               glTexCoord2f(t2x, t2y);
-               VERTEX3;
-
-               glTexCoord2f(t1x, t1y);
-               VERTEX0;
-               glTexCoord2f(t2x, t2y);
-               VERTEX3;
-               glTexCoord2f(t3x, t3y);
-               VERTEX2;
-
-               glTexCoord2f(t1x, t1y);
-               VERTEX0;
-               glTexCoord2f(t3x, t3y);
-               VERTEX2;
-               glTexCoord2f(t2x, t2y);
-               VERTEX1;
-
-               glEnd();
+               glCallList(gp->list);
 
                glPopMatrix();
        }
@@ -682,11 +1211,11 @@ draw_hexagons(ModeInfo *mi, int translucency, GLuint texture)
        glVertex3f(0.0, 1.0, -0.1);
        glEnd();
        /* acd debug - display texture triangle */
-       glColor4f(1.0, 1.0, 1.0, 1.0);
+       glColor4f(1.0, 0.5, 1.0, 1.0);
        glBegin(GL_LINE_LOOP);
-       glVertex3f(t1x, t1y, -0.11);
-       glVertex3f(t2x, t2y, -0.11);
-       glVertex3f(t3x, t3y, -0.11);
+       glVertex3f(t[0].x, t[0].y, -0.11);
+       glVertex3f(t[1].x, t[1].y, -0.11);
+       glVertex3f(t[2].x, t[2].y, -0.11);
        glEnd();
        glPopMatrix();
 #endif
@@ -718,8 +1247,8 @@ draw(ModeInfo * mi)
        z_angle = gp->cam_z_phase + gp->tic * gp->cam_z_speed;
 
        if (move) {
-               v1.x = 2 * sin(x_angle);
-               v1.y = 2 * sin(y_angle);
+               v1.x = 1 * sin(x_angle);
+               v1.y = 1 * sin(y_angle);
        } else {
                v1.x = 0;
                v1.y = 0;
@@ -738,7 +1267,7 @@ draw(ModeInfo * mi)
                v1.z = gp->size;
        } else if (zoom) {
                /* max distance given by adding the constant and the multiplier */
-               v1.z = 5.0 + 4.0 * sin(z_angle);
+               v1.z = 5.0 + 3.0 * sin(z_angle);
        } else {
                /* default */
                v1.z = 7.0;
@@ -752,18 +1281,24 @@ draw(ModeInfo * mi)
                /* update camera rotation angle and velocity */
                gp->rangle += gp->rangle_vel;
                new_rangle_vel = gp->rangle_vel + gp->rangle_acc;
-               if (new_rangle_vel > -MAX_RANGLE_VEL && new_rangle_vel < MAX_RANGLE_VEL)
+               if (new_rangle_vel > -MAX_ANGLE_VEL && new_rangle_vel < MAX_ANGLE_VEL)
                {
                        /* new velocity is within limits */
                        gp->rangle_vel = new_rangle_vel;
                }
 
-               /* randomly change twisting speed */
-               if ((random() % 1000) < 1)
-               {
-                       gp->rangle_acc = frand(0.002) - 0.001;
+               /* randomly change twisting speed - 3ff = 1024 */
+               if ((random() % TWISTING_PROBABILITY) < 1.0) {
+                       gp->rangle_acc = INITIAL_ANGLE_ACC * frand(1.0);
+                       if (gp->rangle_vel > 0.0) {
+                               gp->rangle_acc = -gp->rangle_acc;
+                       }
                }
        }
+#if 0
+       printf("Rangle: %f : %f : %f\n", gp->rangle, gp->rangle_vel, gp->rangle_acc);
+       printf("Tangle: %f : %f : %f\n", gp->tangle, gp->tangle_vel, gp->tangle_acc);
+#endif
 
 #ifdef WOBBLE
        /* this makes the image wobble - requires -move and a larger grid */
@@ -775,8 +1310,8 @@ draw(ModeInfo * mi)
        gluLookAt(
                        v1.x, v1.y, v1.z,
                        v1.x, v1.y, 0.0,
-                       sin((gp->xmouse * M_PI * 2) + gp->rangle * M_PI / 180),
-                       cos((gp->xmouse * M_PI * 2) + gp->rangle * M_PI / 180),
+                       sin((gp->xmouse * M_PI * 2) + gp->rangle * RADIANS),
+                       cos((gp->xmouse * M_PI * 2) + gp->rangle * RADIANS),
                        0.0);
 #endif
 
@@ -789,13 +1324,14 @@ draw(ModeInfo * mi)
        if (gp->fade == 0)
        {
                /* not fading */
-               draw_hexagons(mi, MAX_FADE, gp->visible);
+               draw_hexagons(mi, MAX_FADE, &gp->textures[gp->visible]);
        }
        else
        {
-               /* fading - show both textures with alpha */
-               draw_hexagons(mi, MAX_FADE - gp->fade, gp->visible);
-               draw_hexagons(mi, gp->fade, 1 - gp->visible);
+               /* fading - show both textures with alpha
+               NB first is always max alpha */
+               draw_hexagons(mi, MAX_FADE, &gp->textures[1 - gp->visible]);
+               draw_hexagons(mi, MAX_FADE - gp->fade, &gp->textures[gp->visible]);
 
                /* fade some more */
                gp->fade++;
@@ -819,16 +1355,18 @@ draw(ModeInfo * mi)
 
                /* work out new texture angle velocity */
                new_tangle_vel = gp->tangle_vel + gp->tangle_acc;
-               if (new_tangle_vel > -MAX_TANGLE_VEL && new_tangle_vel < MAX_TANGLE_VEL)
+               if (new_tangle_vel > -MAX_ANGLE_VEL && new_tangle_vel < MAX_ANGLE_VEL)
                {
                        /* new velocity is inside limits */
                        gp->tangle_vel = new_tangle_vel;
                }
 
-               /* randomly change texture angle acceleration */
-               if ((random() % 1000) < 1)
-               {
-                       gp->tangle_acc = frand(0.002) - 0.001;
+               /* randomly change twisting speed - 3ff = 1024 */
+               if ((random() % TWISTING_PROBABILITY) < 1.0) {
+                       gp->tangle_acc = INITIAL_ANGLE_ACC * frand(1.0);
+                       if (gp->tangle_vel > 0.0) {
+                               gp->tangle_acc = -gp->tangle_acc;
+                       }
                }
        }
 
@@ -861,8 +1399,10 @@ pinit(ModeInfo * mi)
        gp->start_time = (time_t)0;
 
        /* set the texture size to default */
+       /*
        gp->max_tx = 1.0;
        gp->max_ty = 1.0;
+       */
 
        /* no fading */
        gp->fade = 0;
@@ -874,11 +1414,11 @@ pinit(ModeInfo * mi)
        glDisable(GL_LIGHTING);
 
        /* space for textures */
-       glGenTextures(1, &gp->textures[0]);
-       glGenTextures(1, &gp->textures[1]);
+       glGenTextures(1, &gp->textures[0].id);
+       glGenTextures(1, &gp->textures[1].id);
        gp->visible = 0;
 
-       setup_texture(mi, gp->textures[gp->visible]);
+       setup_texture(mi, &gp->textures[gp->visible]);
 
        /*
        **      want to choose a value for arg randomly if neither -arg nor -no-arg
@@ -922,20 +1462,21 @@ pinit(ModeInfo * mi)
        }
 
        /* define cam variables */
-       gp->cam_x_speed = frand(3.0) - 1.5;
+       gp->cam_x_speed = MAX_CAM_SPEED * frandrange(-.5, 0.5);
        gp->cam_x_phase = random() % 360;
-       gp->cam_y_speed = frand(3.0) - 1.5;
+       gp->cam_y_speed = MAX_CAM_SPEED * frandrange(-.5, 0.5);
        gp->cam_y_phase = random() % 360;
-       gp->cam_z_speed = frand(3.0) - 1.5;
+       gp->cam_z_speed = MAX_CAM_SPEED * frandrange(-.5, 0.5);
        gp->cam_z_phase = random() % 360;
 
        /* initial angular speeds */
-       gp->rangle_vel = frand(0.2) - 0.1;
-       gp->tangle_vel = frand(0.2) - 0.1;
-       gp->rangle_acc = frand(0.002) - 0.001;
-       gp->tangle_acc = frand(0.002) - 0.001;
+       gp->rangle_vel = INITIAL_ANGLE_VEL * frandrange(-.5, 0.5);
+       gp->tangle_vel = INITIAL_ANGLE_VEL * frandrange(-.5, 0.5);
+       gp->rangle_acc = INITIAL_ANGLE_ACC * frandrange(-.5, 0.5);
+       gp->tangle_acc = INITIAL_ANGLE_ACC * frandrange(-.5, 0.5);
 
     /* jwz */
+#if 0
     {
       GLfloat speed = 15;
       gp->rangle_vel *= speed;
@@ -943,6 +1484,7 @@ pinit(ModeInfo * mi)
       gp->rangle_acc *= speed;
       gp->tangle_acc *= speed;
     }
+#endif
 
        /* distance is 11 - size */
        if (gp->size != -1) {
@@ -969,7 +1511,6 @@ init_gleidescope(ModeInfo * mi)
        gleidestruct *gp;
        int screen = MI_SCREEN(mi);
 
-
        if (gleidescope == NULL) {
                gleidescope = (gleidestruct *) calloc(MI_NUM_SCREENS(mi), sizeof (gleidestruct));
                if (gleidescope == NULL) {
@@ -979,6 +1520,7 @@ init_gleidescope(ModeInfo * mi)
        gp = &gleidescope[screen];
        gp->window = MI_WINDOW(mi);
     gp->size = -1;
+    gp->list = -1;
 
        if ((gp->glx_context = init_GL(mi)) != NULL) {
 
@@ -1022,15 +1564,20 @@ draw_gleidescope(ModeInfo * mi)
 
 #ifdef GRAB
        if (grab) {
-               grab_frame(mi);
+               grab_frame(display, window);
        }
 #endif
 
        /* need to change texture? */
        if ((gp->start_time != 0) && (duration != -1) && gp->fade == 0) {
                if (gp->start_time + duration <= time((time_t *)0)) {
+#ifdef DEBUG
+                       printf("Start Time: %lu - Current Time: %lu\n", (unsigned long)gp->start_time, (unsigned long)time((time_t *)0));
+                       printf("Changing Texture\n");
+#endif
                        /* get new snapshot (into back buffer) and start fade count */
-                       getSnapshot(mi, gp->textures[1 - gp->visible]);
+                       setup_texture(mi, &gp->textures[1 - gp->visible]);
+                       /* restart fading */
                        gp->fade = 1;
                }
        }
diff --git a/hacks/glx/skytentacles.c b/hacks/glx/skytentacles.c
new file mode 100644 (file)
index 0000000..c4edc37
--- /dev/null
@@ -0,0 +1,808 @@
+/* Sky Tentacles, Copyright (c) 2008 Jamie Zawinski <jwz@jwz.org>
+ *
+ * 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.
+ */
+
+#define DEFAULTS       "*delay:        30000       \n" \
+                       "*count:        8           \n" \
+                       "*showFPS:      False       \n" \
+                       "*wireframe:    False       \n" \
+
+# define refresh_tentacles 0
+# define release_tentacles 0
+#undef countof
+#define countof(x) (sizeof((x))/sizeof((*x)))
+
+#include "xlockmore.h"
+#include "colors.h"
+#include "normals.h"
+#include "rotator.h"
+#include "gltrackball.h"
+#include <ctype.h>
+
+#ifdef USE_GL /* whole file */
+
+#define DEF_SPEED       "1.0"
+#define DEF_SMOOTH      "True"
+#define DEF_SLICES      "32"
+#define DEF_SEGMENTS    "32"
+#define DEF_WIGGLINESS  "0.35"
+#define DEF_FLEXIBILITY "0.35"
+#define DEF_THICKNESS   "1.0"
+#define DEF_LENGTH      "9.0"
+#define DEF_COLOR       "#305A30"
+#define DEF_STRIPE      "#451A30"
+#define DEF_SUCKER      "#453E30"
+#define DEF_DEBUG       "False"
+
+#define BELLRAND(n) ((frand((n)) + frand((n)) + frand((n))) / 3)
+
+typedef struct {
+  GLfloat length;     /* length of the segment coming out of this segment */
+  GLfloat th;         /* vector tilt (on yz plane) from previous segment */
+  GLfloat phi;       /* vector rotation (on xy plane) from previous segment */
+  GLfloat thickness;  /* radius of tentacle at this segment */
+  rotator *rot;              /* motion modeller */
+} segment;
+
+typedef struct {
+  ModeInfo *mi;
+  GLfloat x, y, z;     /* position of the base */
+  int nsegments;
+  segment *segments;
+  GLfloat tentacle_color[4], stripe_color[4], sucker_color[4];
+} tentacle;
+
+typedef struct {
+  GLXContext *glx_context;
+  trackball_state *trackball;
+  Bool button_down_p;
+
+  int ntentacles;
+  int tentacles_size;
+  tentacle **tentacles;
+  GLfloat tentacle_color[4], stripe_color[4], sucker_color[4];
+
+  GLuint sucker_list;
+  int sucker_polys;
+
+  Bool left_p;
+  
+
+} tentacles_configuration;
+
+static tentacles_configuration *tcs = NULL;
+
+static int debug_p;
+static GLfloat arg_speed;
+static int smooth_p;
+static int arg_slices;
+static int arg_segments;
+static GLfloat arg_thickness;
+static GLfloat arg_length;
+static GLfloat arg_wiggliness;
+static GLfloat arg_flexibility;
+static char *arg_color, *arg_stripe, *arg_sucker;
+
+static XrmOptionDescRec opts[] = {
+  { "-speed",        ".speed",         XrmoptionSepArg, 0 },
+  { "-no-smooth",    ".smooth",        XrmoptionNoArg, "False" },
+  { "-slices",       ".slices",        XrmoptionSepArg, 0 },
+  { "-segments",     ".segments",      XrmoptionSepArg, 0 },
+  { "-thickness",    ".thickness",     XrmoptionSepArg, 0 },
+  { "-length",       ".length",        XrmoptionSepArg, 0 },
+  { "-wiggliness",   ".wiggliness",    XrmoptionSepArg, 0 },
+  { "-flexibility",  ".flexibility",   XrmoptionSepArg, 0 },
+  { "-color",        ".tentacleColor", XrmoptionSepArg, 0 },
+  { "-stripe-color", ".stripeColor",   XrmoptionSepArg, 0 },
+  { "-sucker-color", ".suckerColor",   XrmoptionSepArg, 0 },
+  { "-debug",        ".debug",         XrmoptionNoArg, "True" },
+};
+
+static argtype vars[] = {
+  {&arg_speed,       "speed",         "Speed",       DEF_SPEED,       t_Float},
+  {&smooth_p,        "smooth",        "Smooth",      DEF_SMOOTH,      t_Bool},
+  {&arg_slices,      "slices",        "Slices",      DEF_SLICES,      t_Int},
+  {&arg_segments,    "segments",      "Segments",    DEF_SEGMENTS,    t_Int},
+  {&arg_thickness,   "thickness",     "Thickness",   DEF_THICKNESS,   t_Float},
+  {&arg_length,      "length",        "Length",      DEF_LENGTH,      t_Float},
+  {&arg_wiggliness,  "wiggliness",    "Wiggliness",  DEF_WIGGLINESS,  t_Float},
+  {&arg_flexibility, "flexibility",   "Flexibility", DEF_FLEXIBILITY, t_Float},
+  {&arg_color,       "tentacleColor", "Color",       DEF_COLOR,       t_String},
+  {&arg_stripe,      "stripeColor",   "Color",       DEF_STRIPE,      t_String},
+  {&arg_sucker,      "suckerColor",   "Color",       DEF_SUCKER,      t_String},
+  {&debug_p,         "debug",         "Debug",       DEF_DEBUG,       t_Bool},
+};
+
+ENTRYPOINT ModeSpecOpt tentacles_opts = {countof(opts), opts, countof(vars), vars, NULL};
+
+
+/* Window management, etc
+ */
+ENTRYPOINT void
+reshape_tentacles (ModeInfo *mi, int width, int height)
+{
+  GLfloat h = (GLfloat) height / (GLfloat) width;
+
+  glViewport (0, 0, (GLint) width, (GLint) height);
+
+  glMatrixMode(GL_PROJECTION);
+  glLoadIdentity();
+  gluPerspective (30.0, 1/h, 1.0, 100.0);
+
+  glMatrixMode(GL_MODELVIEW);
+  glLoadIdentity();
+  gluLookAt( 0.0, 0.0, 30.0,
+             0.0, 0.0, 0.0,
+             0.0, 1.0, 0.0);
+
+  glClear(GL_COLOR_BUFFER_BIT);
+}
+
+
+
+static int
+unit_torus (double ratio, int slices1, int slices2, Bool wire)
+{
+  int i, j, k, polys = 0;
+
+  if (wire) slices1 /= 2;
+  if (wire) slices2 /= 4;
+  if (slices1 < 3) slices1 = 3;
+  if (slices2 < 3) slices2 = 3;
+
+  glFrontFace (GL_CW);
+  glBegin (wire ? GL_LINE_STRIP : GL_QUAD_STRIP);
+  for (i = 0; i < slices1; i++)
+    for (j = 0; j <= slices2; j++)
+      for (k = 0; k <= 1; k++)
+        {
+          double s = (i + k) % slices1 + 0.5;
+          double t = j % slices2;
+
+          double x = cos(t*M_PI*2/slices2) * cos(s*M_PI*2/slices1);
+          double y = sin(t*M_PI*2/slices2) * cos(s*M_PI*2/slices1);
+          double z = sin(s*M_PI*2/slices1);
+          glNormal3f(x, y, z);
+
+          x = (1 + ratio * cos(s*M_PI*2/slices1)) * cos(t*M_PI*2/slices2) / 2;
+          y = (1 + ratio * cos(s*M_PI*2/slices1)) * sin(t*M_PI*2/slices2) / 2;
+          z = ratio * sin(s*M_PI*2/slices1) / 2;
+          glVertex3f(x, y, z);
+          polys++;
+        }
+  glEnd();
+  return polys;
+}
+
+
+
+
+/* Initializes a new tentacle and stores it in the list.
+ */
+static tentacle *
+make_tentacle (ModeInfo *mi, int which, int total)
+{
+  tentacles_configuration *tc = &tcs[MI_SCREEN(mi)];
+  tentacle *t = (tentacle *) calloc (1, sizeof (*t));
+  double brightness;
+  int i;
+
+  t->mi = mi;
+
+  /* position tentacles on a grid */
+  {
+    int cols = (int) (sqrt(total) + 0.5);
+    int rows = (total+cols-1) / cols;
+    int xx = which % cols;
+    int yy = which / cols;
+    double spc = arg_thickness * 0.8;
+    t->x = (cols * spc / 2) - (spc * (xx + 0.5));
+    t->y = (rows * spc / 2) - (spc * (yy + 0.5));
+    t->z = 0;
+  }
+
+  /* Brighten or darken the colors of this tentacle from the default.
+   */
+  brightness = 0.6 + frand(3.0);
+  memcpy (t->tentacle_color, tc->tentacle_color, 4 * sizeof(*t->tentacle_color));
+  memcpy (t->stripe_color,   tc->stripe_color,   4 * sizeof(*t->stripe_color));
+  memcpy (t->sucker_color,   tc->sucker_color,   4 * sizeof(*t->sucker_color));
+# define FROB(X) \
+    t->X[0] *= brightness; if (t->X[0] > 1) t->X[0] = 1; \
+    t->X[1] *= brightness; if (t->X[1] > 1) t->X[1] = 1; \
+    t->X[2] *= brightness; if (t->X[2] > 1) t->X[2] = 1
+  FROB (tentacle_color);
+  FROB (stripe_color);
+  FROB (sucker_color);
+# undef FROB
+
+  t->nsegments = (arg_segments) + BELLRAND(arg_segments);
+
+  t->segments = (segment *) calloc (t->nsegments+1, sizeof(*t->segments));
+  for (i = 0; i < t->nsegments; i++)
+    {
+      double spin_speed   = 0;
+      double spin_accel   = 0;
+      double wander_speed = arg_speed * (0.02 + BELLRAND(0.1));
+      t->segments[i].rot = make_rotator (spin_speed, spin_speed, spin_speed,
+                                         spin_accel, wander_speed, True);
+    }
+
+  t->segments[0].thickness = (((arg_thickness * 0.5) + 
+                               BELLRAND(arg_thickness * 0.6))
+                            / 1.0);
+
+  if (tc->tentacles_size <= tc->ntentacles)
+    {
+      tc->tentacles_size = (tc->tentacles_size * 1.2) + tc->ntentacles;
+      tc->tentacles = (tentacle **)
+        realloc (tc->tentacles, tc->tentacles_size * sizeof(*tc->tentacles));
+      if (! tc->tentacles)
+        {
+          fprintf (stderr, "%s: out of memory (%d tentacles)\n",
+                   progname, tc->tentacles_size);
+          exit (1);
+        }
+    }
+
+  tc->tentacles[tc->ntentacles++] = t;
+  return t;
+}
+
+
+static void
+draw_tentacle (tentacle *t)
+{
+  tentacles_configuration *tc = &tcs[MI_SCREEN(t->mi)];
+  int i;
+  Bool wire = MI_IS_WIREFRAME (t->mi);
+  XYZ ctr = { 0,0,0 };     /* current position of base of segment */
+  double cth  = 0;         /* overall orientation of current segment */
+  double cphi = 0;
+  double cth_cos  = 1, cth_sin  = 0;
+  double cphi_cos = 1, cphi_sin = 0;
+
+  XYZ *ring, *oring;       /* points around the edge (this, and previous) */
+  XYZ *norm, *onorm;       /* their normals */
+
+  /* Which portion of the radius the colored stripe takes up */
+  int indented_points = arg_slices * 0.2;
+
+  /* We do rotation way to minimize number of calls to sin/cos. */
+# define ROT(P) do { \
+    XYZ _p = P; \
+    _p.y = ((P.y * cth_sin - P.x * cth_cos)); \
+    _p.x = ((P.y * cth_cos + P.x * cth_sin) * cphi_sin - (P.z * cphi_cos)); \
+    _p.z = ((P.y * cth_cos + P.x * cth_sin) * cphi_cos + (P.z * cphi_sin)); \
+    P = _p; \
+  } while(0)
+
+  ring  = (XYZ *) malloc (arg_slices * sizeof(*ring));
+  norm  = (XYZ *) malloc (arg_slices * sizeof(*norm));
+  oring = (XYZ *) malloc (arg_slices * sizeof(*oring));
+  onorm = (XYZ *) malloc (arg_slices * sizeof(*onorm));
+
+  if (wire)
+    glColor4fv (t->tentacle_color);
+  else
+    {
+      static const GLfloat bspec[4]  = {1.0, 1.0, 1.0, 1.0};
+      static const GLfloat bshiny    = 128.0;
+      glMaterialfv (GL_FRONT, GL_SPECULAR,            bspec);
+      glMateriali  (GL_FRONT, GL_SHININESS,           bshiny);
+    }
+
+  glPushMatrix();
+  glTranslatef (t->x, t->y, t->z);
+
+  if (debug_p)
+    {
+      if (!wire) glDisable(GL_LIGHTING);
+      glBegin(GL_LINE_LOOP);
+      for (i = 0; i < arg_slices; i++)
+        glVertex3f (arg_thickness / 2 * cos (M_PI * 2 * i / arg_slices),
+                    arg_thickness / 2 * sin (M_PI * 2 * i / arg_slices),
+                    0);
+      glEnd();
+      if (!wire) glEnable(GL_LIGHTING);
+    }
+
+  for (i = 0; i < t->nsegments; i++)
+    {
+      int j;
+      XYZ p;
+
+      for (j = 0; j < arg_slices; j++)
+        {
+          /* Construct a vertical disc at the origin, to use as the
+             base of this segment.
+           */
+          double r = t->segments[i].thickness / 2;
+          double a = M_PI * 2 * j / arg_slices;
+
+          if (j <= indented_points/2 || j >= arg_slices-indented_points/2)
+            r *= 0.75;
+
+          ring[j].x = r * cos (a);
+          ring[j].y = 0;
+          ring[j].z = r * sin (a);
+
+          /* Then rotate the points by the angle of the current segment. */
+          ROT(ring[j]);
+
+          /* Then move the ring to the base of this segment. */
+          ring[j].x += ctr.x;
+          ring[j].y += ctr.y;
+          ring[j].z += ctr.z;
+        }
+
+
+      /* Compute the normals of the faces on this segment.  We do this
+         first so that the normals of the vertexes can be the average
+         of the normals of the faces.
+         #### Uh, except I didn't actually implement that...
+              but it would be a good idea.
+       */
+      if (i > 0)
+        for (j = 0; j <= arg_slices; j++)
+          {
+            int j0 = j     % arg_slices;
+            int j1 = (j+1) % arg_slices;
+            norm[j0] = calc_normal (oring[j0], ring[j0], ring[j1]);
+          }
+
+      /* Draw!
+       */
+
+      if (i > 0)
+        {
+          int j;
+          glFrontFace (GL_CCW);
+          glBegin (wire ? GL_LINES : smooth_p ? GL_QUAD_STRIP : GL_QUADS);
+          for (j = 0; j <= arg_slices; j++)
+            {
+              int j0 = j     % arg_slices;
+              int j1 = (j+1) % arg_slices;
+
+              if (j <= indented_points/2 || j >= arg_slices-indented_points/2)
+                glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE,
+                              t->stripe_color);
+              else
+                glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE,
+                              t->tentacle_color);
+
+              glNormal3f (onorm[j0].x, onorm[j0].y, onorm[j0].z);
+              glVertex3f (oring[j0].x, oring[j0].y, oring[j0].z);
+              glNormal3f ( norm[j0].x,  norm[j0].y,  norm[j0].z);
+              glVertex3f ( ring[j0].x,  ring[j0].y,  ring[j0].z);
+              if (!smooth_p)
+                {
+                  glVertex3f ( ring[j1].x,  ring[j1].y,  ring[j1].z);
+                  glVertex3f (oring[j1].x, oring[j1].y, oring[j1].z);
+                }
+              t->mi->polygon_count++;
+            }
+          glEnd ();
+
+          if (wire)
+            {
+              glBegin (GL_LINE_LOOP);
+              for (j = 0; j < arg_slices; j++)
+                glVertex3f (ring[j].x, ring[j].y, ring[j].z);
+              glEnd();
+            }
+
+          /* Now draw the suckers!
+           */
+          {
+            double seg_length = arg_length / t->nsegments;
+            double sucker_size = arg_thickness / 8;
+            double sucker_spacing = sucker_size * 1.5;
+            int nsuckers = seg_length / sucker_spacing;
+            double oth  = cth  - t->segments[i-1].th;
+            double ophi = cphi - t->segments[i-1].phi;
+            int k;
+
+            if (nsuckers == 0)
+              {
+                int segs_per_sucker =
+                  (int) ((sucker_spacing / seg_length) + 0.5);
+                nsuckers = (i % segs_per_sucker) ? 0 : 1;
+              }
+
+            glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, t->sucker_color);
+
+            for (k = 0; k < nsuckers; k++)
+              {
+                double scale;
+                XYZ p0 = ring[0];
+                XYZ p1 = oring[0];
+                XYZ p;
+                p.x = p0.x + (p1.x - p0.x) * (k + 0.5) / nsuckers;
+                p.y = p0.y + (p1.y - p0.y) * (k + 0.5) / nsuckers;
+                p.z = p0.z + (p1.z - p0.z) * (k + 0.5) / nsuckers;
+
+                glPushMatrix();
+                glTranslatef (p.x, p.y, p.z);
+                glRotatef (ophi * 180 / M_PI, 0, 1, 0);
+                glRotatef (-oth * 180 / M_PI, 1, 0, 0);
+                glRotatef (90, 1, 0, 0);
+
+                { /* Not quite right: this is the slope of the outer edge
+                     if the next segment was not tilted at all...  If there
+                     is any tilt, then the angle of this wall and the 
+                     opposite wall are very different.
+                   */
+                  double slope = ((t->segments[i-1].thickness -
+                                   t->segments[i].thickness) /
+                                  t->segments[i].length);
+                  glRotatef (-45 * slope, 1, 0, 0);
+                }
+
+                scale = t->segments[i].thickness / arg_thickness;
+                scale *= 0.7;
+                glTranslatef (0, 0, -0.15 * sucker_size);
+                glScalef (scale, scale, scale*4);
+                {
+                  double off = sucker_size * 1.4;
+                  glPushMatrix();
+                  glTranslatef (off, 0, 0);
+                  glCallList (tc->sucker_list);
+                  t->mi->polygon_count += tc->sucker_polys;
+                  glPopMatrix();
+
+                  glPushMatrix();
+                  glTranslatef (-off, 0, 0);
+                  glCallList (tc->sucker_list);
+                  t->mi->polygon_count += tc->sucker_polys;
+                  glPopMatrix();
+                }
+
+                glPopMatrix();
+              }
+          }
+        }
+
+      /* Now draw the end caps.
+       */
+      if (i == 0 || i == t->nsegments-1)
+        {
+          int j;
+          GLfloat ctrz = ctr.z + ((i == 0 ? -1 : 1) *
+                                  t->segments[i].thickness / 4);
+          glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, t->tentacle_color);
+          glFrontFace (i == 0 ? GL_CCW : GL_CW);
+          glBegin (wire ? GL_LINES : GL_TRIANGLE_FAN);
+          glNormal3f (0, 0, (i == 0 ? -1 : 1));
+          glVertex3f (ctr.x, ctr.y, ctrz);
+          for (j = 0; j <= arg_slices; j++)
+            {
+              int jj = j % arg_slices;
+              glNormal3f (norm[jj].x, norm[jj].y, norm[jj].z);
+              glVertex3f (ring[jj].x, ring[jj].y, ring[jj].z);
+              if (wire) glVertex3f (ctr.x, ctr.y, ctrz);
+              t->mi->polygon_count++;
+            }
+          glEnd();
+        }
+
+      /* Now move to the end of this segment in preparation for the next.
+       */
+      if (i != t->nsegments-1)
+        {
+          p.x = 0;
+          p.y = t->segments[i].length;
+          p.z = 0;
+          ROT (p);
+          ctr.x += p.x;
+          ctr.y += p.y;
+          ctr.z += p.z;
+
+          /* Accumulate the current angle and rotation, to keep track of the
+             rotation of the upcoming segment.
+           */
+          cth  += t->segments[i].th;
+          cphi += t->segments[i].phi;
+
+          cth_sin  = sin (cth);
+          cth_cos  = cos (cth);
+          cphi_sin = sin (cphi);
+          cphi_cos = cos (cphi);
+
+          memcpy (oring, ring, arg_slices * sizeof(*ring));
+          memcpy (onorm, norm, arg_slices * sizeof(*norm));
+        }
+    }
+
+  glPopMatrix();
+
+  free (ring);
+  free (norm);
+  free (oring);
+  free (onorm);
+}
+
+
+static void
+move_tentacle (tentacle *t)
+{
+  /* tentacles_configuration *tc = &tcs[MI_SCREEN(t->mi)]; */
+  GLfloat len = 0;
+  double pos = 0;
+  int i, j;
+  int skip = t->nsegments * (1 - (arg_wiggliness + 0.5));
+  int tick = 0;
+  int last = 0;
+
+  for (i = 0; i < t->nsegments; i++)
+    {
+      if (++tick >= skip || i == t->nsegments-1)
+        {
+          /* randomize the motion of this segment... */
+          double x, y, z;
+          double phi_range = M_PI * 0.8 * arg_flexibility;
+          double th_range  = M_PI * 0.9 * arg_flexibility;
+          get_position (t->segments[i].rot, &x, &y, &z, True);
+          t->segments[i].phi = phi_range * (0.5 - y);
+          t->segments[i].th  = th_range  * (0.5 - z);
+          t->segments[i].length = ((0.8 + ((0.5 - x) * 0.4)) * 
+                                   (arg_length / t->nsegments));
+
+          /* ...and make the previous N segments be interpolated
+             between this one and the previous randomized one. */
+          for (j = last+1; j <= i; j++)
+            {
+              t->segments[j].phi    = (t->segments[i].phi / (i - last));
+              t->segments[j].th     = (t->segments[i].th  / (i - last));
+              t->segments[j].length = (t->segments[i].length);
+            }
+
+          tick = 0;
+          last = i;
+        }
+      len += t->segments[i].length;
+    }
+
+  /* thickness of segment is relative to current position on tentacle
+     (not just the index of the segment). */
+  for (i = 0; i < t->nsegments; i++)
+    {
+      if (i > 0)
+        {
+          double tt = (t->segments[0].thickness * (len - pos) / len);
+          if (tt < 0.001) tt = 0.001;
+          t->segments[i].thickness = tt;
+        }
+      pos += t->segments[i].length;
+    }
+}
+
+
+
+ENTRYPOINT Bool
+tentacles_handle_event (ModeInfo *mi, XEvent *event)
+{
+  tentacles_configuration *tc = &tcs[MI_SCREEN(mi)];
+
+  if (event->xany.type == ButtonPress &&
+      event->xbutton.button == Button1)
+    {
+      tc->button_down_p = True;
+      gltrackball_start (tc->trackball,
+                         event->xbutton.x, event->xbutton.y,
+                         MI_WIDTH (mi), MI_HEIGHT (mi));
+      return True;
+    }
+  else if (event->xany.type == ButtonRelease &&
+           event->xbutton.button == Button1)
+    {
+      tc->button_down_p = False;
+      return True;
+    }
+  else if (event->xany.type == ButtonPress &&
+           (event->xbutton.button == Button4 ||
+            event->xbutton.button == Button5 ||
+            event->xbutton.button == Button6 ||
+            event->xbutton.button == Button7))
+    {
+      gltrackball_mousewheel (tc->trackball, event->xbutton.button, 10,
+                              !!event->xbutton.state);
+      return True;
+    }
+  else if (event->xany.type == MotionNotify &&
+           tc->button_down_p)
+    {
+      gltrackball_track (tc->trackball,
+                         event->xmotion.x, event->xmotion.y,
+                         MI_WIDTH (mi), MI_HEIGHT (mi));
+      return True;
+    }
+
+  return False;
+}
+
+
+static void
+parse_color (ModeInfo *mi, const char *name, const char *s, GLfloat *a)
+{
+  XColor c;
+  a[3] = 1.0;  /* alpha */
+
+  if (! XParseColor (MI_DISPLAY(mi), MI_COLORMAP(mi), s, &c))
+    {
+      fprintf (stderr, "%s: can't parse %s color %s", progname, name, s);
+      exit (1);
+    }
+  a[0] = c.red   / 65536.0;
+  a[1] = c.green / 65536.0;
+  a[2] = c.blue  / 65536.0;
+}
+
+
+ENTRYPOINT void 
+init_tentacles (ModeInfo *mi)
+{
+  tentacles_configuration *tc;
+  int wire = MI_IS_WIREFRAME(mi);
+  int i;
+
+  if (!tcs) {
+    tcs = (tentacles_configuration *)
+      calloc (MI_NUM_SCREENS(mi), sizeof (tentacles_configuration));
+    if (!tcs) {
+      fprintf(stderr, "%s: out of memory\n", progname);
+      exit(1);
+    }
+
+    tc = &tcs[MI_SCREEN(mi)];
+  }
+
+  tc = &tcs[MI_SCREEN(mi)];
+
+  tc->glx_context = init_GL(mi);
+
+  reshape_tentacles (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
+
+  if (!wire)
+    {
+      GLfloat pos[4] = {1.0, 1.0, 1.0, 0.0};
+      GLfloat amb[4] = {0.0, 0.0, 0.0, 1.0};
+      GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
+      GLfloat spc[4] = {0.0, 1.0, 1.0, 1.0};
+
+      glEnable(GL_LIGHTING);
+      glEnable(GL_LIGHT0);
+      glEnable(GL_DEPTH_TEST);
+      glEnable(GL_CULL_FACE);
+
+      glLightfv(GL_LIGHT0, GL_POSITION, pos);
+      glLightfv(GL_LIGHT0, GL_AMBIENT,  amb);
+      glLightfv(GL_LIGHT0, GL_DIFFUSE,  dif);
+      glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
+    }
+
+  tc->trackball = gltrackball_init ();
+
+  tc->left_p = !(random() % 5);
+
+  if (arg_segments    < 2) arg_segments    = 2;
+  if (arg_slices      < 3) arg_slices      = 3;
+  if (arg_thickness < 0.1) arg_thickness   = 0.1;
+  if (arg_wiggliness  < 0) arg_wiggliness  = 0;
+  if (arg_wiggliness  > 1) arg_wiggliness  = 1;
+  if (arg_flexibility < 0) arg_flexibility = 0;
+  if (arg_flexibility > 1) arg_flexibility = 1;
+
+  parse_color (mi, "tentacleColor", arg_color,  tc->tentacle_color);
+  parse_color (mi, "stripeColor",   arg_stripe, tc->stripe_color);
+  parse_color (mi, "suckerColor",   arg_sucker, tc->sucker_color);
+
+  for (i = 0; i < MI_COUNT(mi); i++)
+    move_tentacle (make_tentacle (mi, i, MI_COUNT(mi)));
+
+  tc->sucker_list = glGenLists (1);
+  glNewList (tc->sucker_list, GL_COMPILE);
+  { GLfloat s = arg_thickness / 5; glScalef (s, s, s); }
+  tc->sucker_polys = unit_torus (0.5, 
+                                 MIN(8,  arg_slices/6),
+                                 MIN(12, arg_slices/3), 
+                                 MI_IS_WIREFRAME(mi));
+  glEndList();
+}
+
+
+ENTRYPOINT void
+draw_tentacles (ModeInfo *mi)
+{
+  tentacles_configuration *tc = &tcs[MI_SCREEN(mi)];
+  int wire = MI_IS_WIREFRAME(mi);
+  Display *dpy = MI_DISPLAY(mi);
+  Window window = MI_WINDOW(mi);
+  int i;
+
+  if (!tc->glx_context)
+    return;
+
+  glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(tc->glx_context));
+
+  glShadeModel(GL_SMOOTH);
+
+  glEnable(GL_DEPTH_TEST);
+  glEnable(GL_NORMALIZE);
+  glEnable(GL_CULL_FACE);
+
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  glPushMatrix ();
+
+
+# if 1
+  glScalef (3, 3, 3);
+# else
+  glPushMatrix();
+  { GLfloat s = 8.7/1600; glScalef(s,s,s); }
+  glTranslatef(-800,-514,0);
+  if (!wire) glDisable(GL_LIGHTING);
+  glBegin(GL_LINE_LOOP);
+  glVertex3f(0,0,0);
+  glVertex3f(0,1028,0);
+  glVertex3f(1600,1028,0);
+  glVertex3f(1600,0,0);
+  glEnd();
+  if (!wire) glEnable(GL_LIGHTING);
+  glPopMatrix();
+# endif
+
+  gltrackball_rotate (tc->trackball);
+
+  mi->polygon_count = 0;
+
+  if (debug_p)
+    {
+      if (!wire) glDisable(GL_LIGHTING);
+      glBegin(GL_LINES);
+      glVertex3f(-0.5, 0, 0); glVertex3f(0.5, 0, 0);
+      glVertex3f(0, -0.5, 0); glVertex3f(0, 0.5, 0);
+      glEnd();
+      if (!wire) glEnable(GL_LIGHTING);
+    }
+  else if (tc->left_p)
+    {
+      glRotatef ( 45, 0, 1, 0);                /* upper left */
+      glRotatef ( 45, 1, 0, 0);
+      glRotatef (-70, 0, 0, 1);
+      glTranslatef (0, -2, -4.5);
+    }
+  else
+    {
+      glRotatef (-45, 0, 1, 0);                /* upper right */
+      glRotatef ( 45, 1, 0, 0);
+      glRotatef ( 70, 0, 0, 1);
+      glTranslatef (0, -2, -4.5);
+    }
+
+  if (!tc->button_down_p)
+    for (i = 0; i < tc->ntentacles; i++)
+      move_tentacle (tc->tentacles[i]);
+
+  for (i = 0; i < tc->ntentacles; i++)
+    draw_tentacle (tc->tentacles[i]);
+
+  glPopMatrix ();
+
+  if (mi->fps_p) do_fps (mi);
+  glFinish();
+
+  glXSwapBuffers(dpy, window);
+}
+
+XSCREENSAVER_MODULE_2 ("SkyTentacles", skytentacles, tentacles)
+
+#endif /* USE_GL */
diff --git a/hacks/glx/skytentacles.man b/hacks/glx/skytentacles.man
new file mode 100644 (file)
index 0000000..0bcc586
--- /dev/null
@@ -0,0 +1,102 @@
+.TH XScreenSaver 1 "" "X Version 11"
+.SH NAME
+skytentacles - 3D tentacles from the sky!
+.SH SYNOPSIS
+.B skytentacles
+[\-display \fIhost:display.screen\fP]
+[\-visual \fIvisual\fP]
+[\-window]
+[\-root]
+[\-delay \fIint\fP]
+[\-speed \fIratio\fP]
+[\-count \fIint\fP]
+[\-slices \fIint\fP]
+[\-length \fIfloat\fP]
+[\-wiggliness \fIratio\fP]
+[\-flexibility \fIratio\fP]
+[\-color \fIcolor\fP]
+[\-stripe\-color \fIcolor\fP]
+[\-sucker\-color \fIcolor\fP]
+[\-segments \fIint\fP]
+[\-thickness \fIratio\fP]
+[\-no\-smooth]
+[\-fps]
+.SH DESCRIPTION
+There is a tentacled abomination in the sky.  From above you it devours.
+.SH OPTIONS
+.TP 8
+.B \-visual \fIvisual\fP
+Specify which visual to use.  Legal values are the name of a visual class,
+or the id number (decimal or hex) of a specific visual.
+.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 \-delay \fIint\fP
+Delay between frames, in microseconds.  Default 30000.
+.TP 8
+.B \-speed \fIratio\fP
+Less than 1 for slower, greater than 1 for faster.  Default 1.
+.TP 8
+.B \-count \fIint\fP
+How many tentacles.  Default 8.
+.TP 8
+.B \-thickness \fIratio\fP
+Less than 1 for thinner tentacles, greater than 1 for thicker.  Default 1.
+.TP 8
+.B \-length \fIratio\fP
+Length of the tentacles.  Default 9.
+.TP 8
+.B \-wiggliness \fIratio\fP
+A measure of how bendy the tentacles are.  Smaller numbers result in
+smoother flexing; larger numbers make it "crinkly".  Default 0.35.
+.TP 8
+.B \-flexibility \fIratio\fP
+Another measure of how bendy the tentacles are.  Smaller numbers
+result in straighter tentacles; larger numbers result in more extreme
+curves.  Default 0.35.
+.TP 8
+.B \-color \fIcolor\fP
+.TP 8
+.B \-stripe\-color \fIcolor\fP
+.TP 8
+.B \-sucker\-color \fIcolor\fP
+The colors of the various parts of the tentacle.  Default green
+with a redish stripe.
+.TP 8
+.B \-slices \fIint\fP
+.TP 8
+.B \-segments \fIint\fP
+Larger numbers increase number of polygons in the object mesh.
+Default 32.
+.TP 8
+.B \-no\-smooth
+Make the tentacles appear faceted instead of smooth.
+.TP 8
+.B \-fps | \-no-fps
+Whether to show a frames-per-second display at the bottom of the screen.
+.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 2008 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.
index 9288b2f92c4287628e18dbeaec8f9159a8e0cc2e..10e86d7698e1fd6b81229034067a9f5ae39deb73 100644 (file)
@@ -1,4 +1,4 @@
-/* sphere, Copyright (c) 2002 Paul Bourke <pbourke@swin.edu.au>
+/* sphere, Copyright (c) 2002, 2008 Paul Bourke <pbourke@swin.edu.au>
  * Utility function to create a unit sphere in GL.
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
 
 typedef struct { GLfloat x, y, z; } XYZ;
 
-void
+int
 unit_sphere (int stacks, int slices, int wire_p)
 {
+  int polys = 0;
   int i,j;
   double theta1, theta2, theta3;
   XYZ e, p;
@@ -53,7 +54,7 @@ unit_sphere (int stacks, int slices, int wire_p)
       glBegin (GL_POINTS);
       glVertex3f (c.x, c.y, c.z);
       glEnd();
-      return;
+      return 1;
     }
 
   glFrontFace(GL_CW);
@@ -99,7 +100,9 @@ unit_sphere (int stacks, int slices, int wire_p)
                         2*j / (double)stacks2);
           glVertex3f (p.x, p.y, p.z);
           if (wire_p) lb = p;
+          polys++;
         }
       glEnd();
     }
+  return polys;
 }
index 55fa7aa59735abf038ef2bab921a2113b557194b..96d951463d8f433382599a3211f02ce411256e08 100644 (file)
@@ -1,4 +1,4 @@
-/* tube, Copyright (c) 2001 Jamie Zawinski <jwz@jwz.org>
+/* sphere, Copyright (c) 2001-2008 Jamie Zawinski <jwz@jwz.org>
  * Utility function to create a unit sphere in GL.
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
 #ifndef __SPHERE_H__
 #define __SPHERE_H__
 
-/* Creates a diamteter 1 sphere at 0, 0, 0.
+/* Creates a diameter 1 sphere at 0, 0, 0.
    stacks = number of north/south divisions (latitude)
    slices = number of clockwise/counterclockwise divisions (longitude)
+   Returns number of polygons used.
  */
-extern void unit_sphere (int stacks, int slices, int wire_p);
+extern int unit_sphere (int stacks, int slices, int wire_p);
 
 #endif /* __SPHERE_H__ */
diff --git a/hacks/images/atm.xbm b/hacks/images/atm.xbm
new file mode 100644 (file)
index 0000000..ee5fcdf
--- /dev/null
@@ -0,0 +1,246 @@
+#define atm_width 223
+#define atm_height 130
+static unsigned char atm_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,0xff,0x3f,0xfc,0x0f,0xfc,0x0f,0xfc,0x0f,
+ 0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x3c,0x3c,0x0f,0x3c,0x0f,0x3c,0x0f,0x3c,0xfc,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x3c,0x30,0x0f,0x3f,0x0f,0x3f,0x0f,0x3f,0xff,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x3c,0x03,0xcf,0x3f,0xcf,0x3f,0xcf,0x3f,0xf0,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,
+ 0x03,0xff,0x3c,0xff,0x3c,0xff,0x3c,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x03,0x3f,
+ 0x3c,0x3f,0x3c,0x3f,0x3c,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x00,0x0f,0x3c,0x0f,
+ 0x3c,0x0f,0x3c,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x00,0x0f,0x3c,0x0f,0x3c,0x0f,
+ 0x3c,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xfc,0x0f,0xfc,0x0f,0xfc,0x0f,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,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,0x07,0x1e,0x78,0xfe,0x7f,0x00,0x00,0xe0,0x07,0xff,0x3f,0x00,0x00,0xfc,
+ 0x0f,0xff,0x3f,0xff,0x0f,0x0f,0x3c,0xfc,0x03,0xf0,0x0f,0xff,0x3f,0x78,0x1e,
+ 0x1e,0x78,0xe2,0x61,0x00,0x00,0x78,0x1e,0x3c,0x3c,0x00,0x00,0x0f,0x3c,0x7c,
+ 0x3c,0x3c,0x3c,0x0f,0x3c,0xf0,0x00,0x3c,0x3c,0x3c,0x3c,0x1e,0x78,0x1e,0x78,
+ 0xe0,0x01,0x00,0x00,0x1e,0x78,0x3c,0x30,0x00,0x00,0x0f,0x3c,0x3c,0x30,0x3c,
+ 0x3c,0x0f,0x3c,0xf0,0x00,0x0f,0x30,0x3c,0x30,0x1e,0x78,0x1e,0x78,0xe0,0x01,
+ 0x00,0x00,0x1e,0x78,0x3c,0x03,0x00,0x00,0x3c,0x00,0x3c,0x03,0x3c,0x3c,0x0f,
+ 0x3c,0xf0,0x00,0x0f,0x00,0x3c,0x03,0x1e,0x78,0x1e,0x78,0xe0,0x01,0x00,0x00,
+ 0x1e,0x78,0xfc,0x03,0x00,0x00,0xf0,0x03,0xfc,0x03,0xfc,0x0f,0x0f,0x3c,0xf0,
+ 0x00,0x0f,0x00,0xfc,0x03,0x1e,0x78,0x1e,0x78,0xe0,0x01,0x00,0x00,0x1e,0x78,
+ 0x3c,0x03,0x00,0x00,0x00,0x0f,0x3c,0x03,0x3c,0x0e,0x0f,0x3c,0xf0,0x00,0x0f,
+ 0x00,0x3c,0x03,0x1e,0x78,0x1e,0x78,0xe0,0x01,0x00,0x00,0x1e,0x78,0x3c,0x00,
+ 0x00,0x00,0x0f,0x3c,0x3c,0x30,0x3c,0x1c,0x1c,0x0e,0xf0,0x00,0x0f,0x30,0x3c,
+ 0x30,0x78,0x1e,0xfe,0x7f,0xe0,0x01,0x00,0x00,0x78,0x1e,0x3c,0x00,0x00,0x00,
+ 0x0f,0x3c,0x3c,0x3c,0x3c,0x3c,0xf0,0x07,0xf0,0x00,0x3c,0x3c,0x3c,0x3c,0xe0,
+ 0x07,0xf8,0x1f,0xf8,0x07,0x00,0x00,0xe0,0x07,0xff,0x00,0x00,0x00,0xfc,0x0f,
+ 0xff,0x3f,0x3f,0x3c,0xc0,0x00,0xfc,0x03,0xf0,0x0f,0xff,0x3f,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,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,0x1f,0xc0,0x00,0xff,0x00,0xff,0x00,0x00,0x00,0xc0,0x00,0xff,0x3f,0xff,
+ 0x3f,0xfe,0x3f,0x0f,0x3c,0xff,0x03,0xc0,0x00,0x0f,0x3c,0xff,0x3f,0x78,0x78,
+ 0xf0,0x03,0x3c,0x00,0x3c,0x00,0x00,0x00,0xf0,0x03,0xf1,0x30,0xf1,0x30,0x7c,
+ 0x3c,0x3f,0x3c,0x3c,0x0f,0xf0,0x03,0x3f,0x3c,0xf1,0x30,0x1e,0x60,0x3c,0x0f,
+ 0x3c,0x00,0x3c,0x00,0x00,0x00,0x3c,0x0f,0xf0,0x00,0xf0,0x00,0x3c,0x30,0xff,
+ 0x3c,0x3c,0x3c,0x3c,0x0f,0xff,0x3c,0xf0,0x00,0x1e,0x00,0x0f,0x3c,0x3c,0x00,
+ 0x3c,0x00,0x00,0x00,0x0f,0x3c,0xf0,0x00,0xf0,0x00,0x3c,0x03,0xff,0x3f,0x3c,
+ 0x3c,0x0f,0x3c,0xff,0x3f,0xf0,0x00,0x1e,0x00,0x0f,0x3c,0x3c,0x00,0x3c,0x00,
+ 0x00,0x00,0x0f,0x3c,0xf0,0x00,0xf0,0x00,0xfc,0x03,0xcf,0x3f,0x3c,0x3c,0x0f,
+ 0x3c,0xcf,0x3f,0xf0,0x00,0x1e,0x00,0xff,0x3f,0x3c,0x00,0x3c,0x00,0x00,0x00,
+ 0xff,0x3f,0xf0,0x00,0xf0,0x00,0x3c,0x03,0x0f,0x3f,0x3c,0x3c,0xff,0x3f,0x0f,
+ 0x3f,0xf0,0x00,0x1e,0x60,0x0f,0x3c,0x3c,0x30,0x3c,0x30,0x00,0x00,0x0f,0x3c,
+ 0xf0,0x00,0xf0,0x00,0x3c,0x30,0x0f,0x3c,0x3c,0x3c,0x0f,0x3c,0x0f,0x3c,0xf0,
+ 0x00,0x78,0x78,0x0f,0x3c,0x3c,0x3c,0x3c,0x3c,0x00,0x00,0x0f,0x3c,0xf0,0x00,
+ 0xf0,0x00,0x3c,0x3c,0x0f,0x3c,0x3c,0x0f,0x0f,0x3c,0x0f,0x3c,0xf0,0x00,0xe0,
+ 0x1f,0x0f,0x3c,0xff,0x3f,0xff,0x3f,0x00,0x00,0x0f,0x3c,0xfc,0x03,0xfc,0x03,
+ 0xfe,0x3f,0x0f,0x3c,0xff,0x03,0x0f,0x3c,0x0f,0x3c,0xfc,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};
diff --git a/hacks/lcdscrub b/hacks/lcdscrub
deleted file mode 100755 (executable)
index 889a37f..0000000
Binary files a/hacks/lcdscrub and /dev/null differ
diff --git a/hacks/lcdscrub.man b/hacks/lcdscrub.man
new file mode 100644 (file)
index 0000000..23215e5
--- /dev/null
@@ -0,0 +1,69 @@
+.TH XScreenSaver 1 "" "X Version 11"
+.SH NAME
+lcdscrub - attempt to repair burn-in on LCD screens
+.SH SYNOPSIS
+.B deluxe
+[\-display \fIhost:display.screen\fP]
+[\-visual \fIvisual\fP]
+[\-window]
+[\-root]
+[\-delay \fInumber\fP]
+[\-spread \fInumber\fP]
+[\-cycles \fInumber\fP]
+.SH DESCRIPTION
+This screen saver is not meant to look pretty, but rather, to
+repair burn-in on LCD monitors.
+
+Believe it or not, screen burn is not a thing of the past.
+It can happen to LCD screens pretty easily, even in this modern age.
+However, leaving the screen on and displaying high contrast images
+can often repair the damage.  That's what this screen saver does.
+
+See also:
+
+       http://docs.info.apple.com/article.html?artnum=88343
+       http://toastycode.com/blog/2008/02/05/lcd-scrub/
+.SH OPTIONS
+.TP 8
+.B \-visual \fIvisual\fP
+Specify which visual to use.  Legal values are the name of a visual class,
+or the id number (decimal or hex) of a specific visual.
+.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 \-delay \fInumber\fP
+Per-frame delay, in microseconds.  Default: 1000000 (1 second.).
+.TP 8
+.B \-spread \fInumber\fP
+Distance between lines.  Default 8.
+.TP 8
+.B \-cycles \fInumber\fP
+Steps before switching display mode.  Default 60.
+.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 2008 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
+Inspired by the like-named program by Daniel Sandler.
+
+Written by Jamie Zawinski.
index 0df38b8d718803bdd200930806aa4aa8eeff73c5..948c43d8252b93e3580e105f051d293dd56c694f 100644 (file)
@@ -49,7 +49,7 @@ without ever returning any data.)
 .TP 8
 .B \-delay \fImicroseconds\fP
 How much of a delay should be introduced between steps of the animation.
-Default 100000, or about 1/10th second.
+Default 10000.
 .SH ENVIRONMENT
 .PP
 .TP 8
index 89eb777d2bfbd6119ec97444fbaafd71f317b13f..2196035f3cee476cd84eb5187b279035621b0d3e 100644 (file)
@@ -365,8 +365,8 @@ penetrate_init (Display *dpy, Window window)
 {
   struct state *st = (struct state *) calloc (1, sizeof(*st));
   int i;
-  /*char *fontname =   "-*-new century schoolbook-*-r-*-*-*-380-*-*-*-*-*-*"; */
-  char *fontname =   "-*-courier-*-r-*-*-*-380-*-*-*-*-*-*";
+  const char *levelfont = "-*-courier-*-r-*-*-*-380-*-*-*-*-*-*";
+  const char *scorefont = "-*-times-*-r-*-*-*-180-*-*-*-*-*-*";
   XGCValues gcv;
   XWindowAttributes xgwa;
 
@@ -387,14 +387,23 @@ penetrate_init (Display *dpy, Window window)
   if (st->lrate < 0) st->lrate = 2;
   st->startlrate = st->lrate;
 
-  if (!fontname || !*fontname)
-    fprintf (stderr, "%s: no font specified.\n", progname);
-  st->font = XLoadQueryFont(st->dpy, fontname);
-  if (!st->font)
-    fprintf (stderr, "%s: could not load font %s.\n", progname, fontname);
+  st->font = XLoadQueryFont(st->dpy, levelfont);
+  if (!st->font) {
+    fprintf (stderr, "%s: could not load font %s.\n", progname, levelfont);
+    st->font = XLoadQueryFont(st->dpy, scorefont);
+    if (! st->font)
+      st->font = XLoadQueryFont(st->dpy, "fixed");
+    if (! st->font) abort();
+  }
 
-  if (!(st->scoreFont = XLoadQueryFont(st->dpy, "-*-times-*-r-*-*-*-180-*-*-*-*-*-*")))
-        fprintf(stderr, "%s: Can't load Times font.", progname);
+  st->scoreFont = XLoadQueryFont(st->dpy, scorefont);
+  if (!st->scoreFont) {
+    fprintf (stderr, "%s: could not load font %s.\n", progname, scorefont);
+    st->scoreFont = XLoadQueryFont(st->dpy, levelfont);
+    if (! st->scoreFont)
+      st->scoreFont = XLoadQueryFont(st->dpy, "fixed");
+    if (! st->scoreFont) abort();
+  }
 
   for (i = 0; i < kMaxMissiles; i++)
     st->missile[i].alive = 0;
index 153f620e09171c22ea3d89a0cbef34737378b76f..aa286426a960537ce62e6360e1d049bde3d50001 100644 (file)
@@ -90,6 +90,8 @@ struct state {
   int draw_count;
 
   int iterations, delay, rate, box, oily, stir, fluidity;
+  int duration;
+  time_t start_time;
 
   void (*draw_transparent) (struct state *st, short *src);
 
@@ -529,6 +531,7 @@ setup_X(struct state *st)
 
     st->img_loader = load_image_async_simple (0, xgwa.screen, st->window,
                                               st->window, 0, 0);
+    st->start_time = time ((time_t) 0);
   } else {
     XGCValues gcv;
 
@@ -951,6 +954,7 @@ ripples_init (Display *disp, Window win)
   st->window = win;
   st->iterations = 0;
   st->delay = get_integer_resource(disp, "delay", "Integer");
+  st->duration = get_integer_resource (st->dpy, "duration", "Seconds");
   st->rate = get_integer_resource(disp, "rate", "Integer");
   st->box = get_integer_resource(disp, "box", "Integer");
   st->oily = get_boolean_resource(disp, "oily", "Boolean");
@@ -963,6 +967,8 @@ ripples_init (Display *disp, Window win)
 #endif /* HAVE_XSHM_EXTENSION */
   st->light = get_integer_resource(disp, "light", "Integer");
 
+  if (st->delay < 0) st->delay = 0;
+  if (st->duration < 1) st->duration = 1;
   if (st->fluidity <= 1) st->fluidity = 1;
   if (st->fluidity > 16) st->fluidity = 16; /* 16 = sizeof(short) */
   if (st->light < 0) st->light = 0;
@@ -1021,6 +1027,7 @@ ripples_draw (Display *dpy, Window window, void *closure)
       if (! st->img_loader) {  /* just finished */
         XWindowAttributes xgwa;
         XGetWindowAttributes(st->dpy, st->window, &xgwa);
+        st->start_time = time ((time_t) 0);
         st->orig_map = XGetImage (st->dpy, st->window, 0, 0, 
                                   xgwa.width, xgwa.height,
                                   ~0L, ZPixmap);
@@ -1029,6 +1036,16 @@ ripples_draw (Display *dpy, Window window, void *closure)
       return st->delay;
     }
 
+    if (!st->img_loader &&
+        st->start_time + st->duration < time ((time_t) 0)) {
+      XWindowAttributes xgwa;
+      XGetWindowAttributes(st->dpy, st->window, &xgwa);
+      st->img_loader = load_image_async_simple (0, xgwa.screen, st->window,
+                                                st->window, 0, 0);
+      st->start_time = time ((time_t) 0);
+      return st->delay;
+    }
+
     if (st->rate > 0 && (st->iterations % st->rate) == 0)
       add_drop(st, ripple_blob, -SPLASH);
     if (st->stir)
@@ -1071,6 +1088,7 @@ static const char *ripples_defaults[] =
   "*colors:            200",
   "*dontClearRoot:     True",
   "*delay:             50000",
+  "*duration:          120",
   "*rate:              5",
   "*box:               0",
   "*water:             False",
@@ -1092,6 +1110,7 @@ static XrmOptionDescRec ripples_options[] =
   { "-colors", ".colors",      XrmoptionSepArg, 0},
   { "-colours",        ".colors",      XrmoptionSepArg, 0},
   {"-delay",   ".delay",       XrmoptionSepArg, 0},
+  {"-duration",        ".duration",    XrmoptionSepArg, 0 },
   {"-rate",    ".rate",        XrmoptionSepArg, 0},
   {"-box",     ".box",         XrmoptionSepArg, 0},
   {"-water",   ".water",       XrmoptionNoArg, "True"},
index 55160029b3dcccf54d83fa6d6d9ff0927c07497d..a53945275d0ec9e98f1bb2b1e910c90d787b1b94 100644 (file)
@@ -8,6 +8,7 @@ ripples - interference patterns.
 [\-window]
 [\-root]
 [\-delay \fInumber\fP]
+[\-duration \fIsecs\fP]
 [\-rate \fInumber\fP]
 [\-fluidity \fInumber\fP]
 [\-light \fInumber\fP]
@@ -36,6 +37,9 @@ Draw on the root window.
 .B \-delay \fInumber\fP
 Per-frame delay, in microseconds.  Default: 50000 (0.05 seconds.).
 .TP 8
+.B \-duration \fIseconds\fP
+How long to run before loading a new image.  Default 120 seconds.
+.TP 8
 .B \-rate \fInumber\fP
 Drizzle.  1 - 100.  Default: 5.
 .TP 8
index 29a566275445ae07a6e70bacd5698a057e9bae53..cacb7229355a45d26d6f9fbf8b7beca9e386c3b6 100644 (file)
@@ -59,6 +59,8 @@ struct state {
   int sweep;
   int delay;
   int anim;
+  int duration;
+  time_t start_time;
 
   async_load_state *img_loader;
 
@@ -264,6 +266,7 @@ init_hack (struct state *st)
 {
   int i;
 
+  st->start_time = time ((time_t) 0);
   st->zoom_box = calloc (st->num_zoom, sizeof (struct zoom_area *));
   for (i = 0; i < st->num_zoom; i++) {
     st->zoom_box[i] = create_zoom (st);
@@ -295,6 +298,16 @@ rotzoomer_draw (Display *disp, Window win, void *closure)
       return st->delay;
     }
 
+  if (!st->img_loader &&
+      st->start_time + st->duration < time ((time_t) 0)) {
+    XWindowAttributes xgwa;
+    XGetWindowAttributes(st->dpy, st->window, &xgwa);
+    st->img_loader = load_image_async_simple (0, xgwa.screen, st->window,
+                                              st->window, 0, 0);
+    st->start_time = time ((time_t) 0);
+    return st->delay;
+  }
+
   for (i = 0; i < st->num_zoom; i++) {
     if (st->move || st->sweep)
       update_position (st->zoom_box[i]);
@@ -395,6 +408,9 @@ rotzoomer_init (Display *dpy, Window window)
 
   st->anim = get_boolean_resource (st->dpy, "anim", "Boolean");
   st->delay = get_integer_resource (st->dpy, "delay", "Integer");
+  st->duration = get_integer_resource (st->dpy, "duration", "Seconds");
+  if (st->delay < 0) st->delay = 0;
+  if (st->duration < 1) st->duration = 1;
 
   /* In sweep or static mode, we want only one box */
   if (st->sweep || !st->anim)
@@ -404,6 +420,8 @@ rotzoomer_init (Display *dpy, Window window)
   if (!st->anim)
     st->sweep = 0;
 
+  st->start_time = time ((time_t) 0);
+
   setup_X (st);
 
   return st;
@@ -441,6 +459,7 @@ static const char *rotzoomer_defaults[] = {
   "*mode: stationary",
   "*numboxes: 2",
   "*delay: 10",
+  "*duration: 120",
   0
 };
 
@@ -454,6 +473,7 @@ static XrmOptionDescRec rotzoomer_options[] = {
   { "-anim",   ".anim",        XrmoptionNoArg, "True"  },
   { "-no-anim",        ".anim",        XrmoptionNoArg, "False" },
   { "-delay",  ".delay",       XrmoptionSepArg, 0      },
+  {"-duration",        ".duration",    XrmoptionSepArg, 0      },
   { "-n",      ".numboxes",    XrmoptionSepArg, 0      },
   { 0, 0, 0, 0 }
 };
index aa805543a979c32661a3b3068ec03002e89563ca..1e0be923c0c46a68c5dfc1461fa3ff7a4a68eba6 100644 (file)
@@ -6,6 +6,7 @@ rotzoomer - animated rotations and scalings of portions of the screen
 [\-display \fIhost:display.screen\fP]
 [\-move | \-no\-move]
 [\-delay \fImillisecs\fP]
+[\-duration \fIsecs\fP]
 [\-n \fIcount\fP]
 [\-shm | \-no\-shm]
 [\-window] [\-root] [\-install] [\-visual \fIvisual\fP]
@@ -43,6 +44,9 @@ or the id number (decimal or hex) of a specific visual.
 How much of a delay should be introduced between steps of the animation.
 Default 10, or about 1/100th second.
 .TP 8
+.B \-duration \fIseconds\fP
+How long to run before loading a new image.  Default 120 seconds.
+.TP 8
 .B \-move
 Make the rectangles should wander around the screen.
 .TP 8
index 5a377233fc586dea7585232c266de7868c9c31d1..443d3f423745562b89165e8df92fa620caad08ec 100644 (file)
@@ -882,6 +882,8 @@ main (int argc, char **argv)
       window = VirtualRootWindowOfScreen (XtScreen (toplevel));
       XtDestroyWidget (toplevel);
       XGetWindowAttributes (dpy, window, &xgwa);
+      /* With RANDR, the root window can resize! */
+      XSelectInput (dpy, window, xgwa.your_event_mask | StructureNotifyMask);
       visual_warning (xgwa.screen, window, xgwa.visual, xgwa.colormap, False);
     }
   else
index 42d3fefca029a6b10a03d81b640f7f334f942f90..a3859b573eded9084152b4093890463d29773d00 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1992-2006 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1992-2008 Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -25,6 +25,7 @@ struct state {
   int xoff, yoff;
   int grid_w, grid_h;
   int delay, delay2;
+  int duration;
   GC gc;
   unsigned long fg, bg;
   int max_width, max_height;
@@ -36,6 +37,7 @@ struct state {
   int draw_last;
   int draw_initted;
 
+  time_t start_time;
   async_load_state *img_loader;
 };
 
@@ -54,6 +56,7 @@ slidescreen_init (Display *dpy, Window window)
   XGetWindowAttributes (st->dpy, st->window, &xgwa);
   st->img_loader = load_image_async_simple (0, xgwa.screen, st->window,
                                             st->window, 0, 0);
+  st->start_time = time ((time_t) 0);
 
   visual = xgwa.visual;
   st->max_width = xgwa.width;
@@ -61,6 +64,7 @@ slidescreen_init (Display *dpy, Window window)
 
   st->delay = get_integer_resource (st->dpy, "delay", "Integer");
   st->delay2 = get_integer_resource (st->dpy, "delay2", "Integer");
+  st->duration = get_integer_resource (st->dpy, "duration", "Seconds");
   st->grid_size = get_integer_resource (st->dpy, "gridSize", "Integer");
   st->pix_inc = get_integer_resource (st->dpy, "pixelIncrement", "Integer");
 
@@ -72,6 +76,7 @@ slidescreen_init (Display *dpy, Window window)
 
   if (st->delay < 0) st->delay = 0;
   if (st->delay2 < 0) st->delay2 = 0;
+  if (st->duration < 1) st->duration = 1;
   if (st->pix_inc < 1) st->pix_inc = 1;
   if (st->grid_size < 1) st->grid_size = 1;
 
@@ -303,11 +308,24 @@ slidescreen_draw (Display *dpy, Window window, void *closure)
   if (st->img_loader)   /* still loading */
     {
       st->img_loader = load_image_async_simple (st->img_loader, 0, 0, 0, 0, 0);
-      if (! st->img_loader)  /* just finished */
+      if (! st->img_loader) {  /* just finished */
+        st->start_time = time ((time_t) 0);
         draw_grid (st);
+      }
       return st->delay;
     }
 
+  if (!st->img_loader &&
+      st->start_time + st->duration < time ((time_t) 0)) {
+    XWindowAttributes xgwa;
+    XGetWindowAttributes(st->dpy, st->window, &xgwa);
+    st->img_loader = load_image_async_simple (0, xgwa.screen, st->window,
+                                              st->window, 0, 0);
+    st->start_time = time ((time_t) 0);
+    st->draw_initted = 0;
+    return st->delay;
+  }
+
   if (! st->draw_initted)
     {
       if (!slidescreen_draw_early (st))
@@ -441,6 +459,7 @@ static const char *slidescreen_defaults [] = {
   "*internalBorderWidth:       4",
   "*delay:                     50000",
   "*delay2:                    1000000",
+  "*duration:                  120",
   0
 };
 
@@ -450,6 +469,7 @@ static XrmOptionDescRec slidescreen_options [] = {
   { "-increment",      ".pixelIncrement",      XrmoptionSepArg, 0 },
   { "-delay",          ".delay",               XrmoptionSepArg, 0 },
   { "-delay2",         ".delay2",              XrmoptionSepArg, 0 },
+  {"-duration",                ".duration",            XrmoptionSepArg, 0 },
   { 0, 0, 0, 0 }
 };
 
index 9dd726628c5186f767f9e529dae84d85825a3ec1..f9bbac450c0adaf83f368af59e8d135e42c0c65f 100644 (file)
@@ -10,6 +10,7 @@ slidescreen - permute the screen image like an 8-puzzle
 [\-increment \fIpixels\fP]
 [\-delay \fIusecs\fP]
 [\-delay2 \fIusecs\fP]
+[\-duration \fIsecs\fP]
 [\-window]
 [\-root]
 [\-install]
@@ -63,6 +64,9 @@ is closely related to the \fI\-increment\fP parameter.
 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 is one second.
+.TP 8
+.B \-duration \fIseconds\fP
+How long to run before loading a new image.  Default 120 seconds.
 .SH ENVIRONMENT
 .PP
 .TP 8
index fffa6a83bcbaa4f836328676409a6ef38036abba..57519e7f72105ba4178f175df1dd1822df0c9b47 100644 (file)
 struct state {
   Display *dpy;
   Window window;
+  Screen *screen;
 
   int sizex, sizey; /* screen size */
-  int delay;        /* in case it's too fast... */
+  int delay;
+  int duration;
+  time_t start_time;
+
   GC window_gc;
 #ifdef DEBUG
   GC white_gc;
@@ -96,6 +100,7 @@ spotlight_init (Display *dpy, Window window)
   st->first_p = True;
 
   XGetWindowAttributes (st->dpy, st->window, &xgwa);
+  st->screen = xgwa.screen;
   st->sizex = xgwa.width;
   st->sizey = xgwa.height;
   cmap = xgwa.colormap;
@@ -105,6 +110,8 @@ spotlight_init (Display *dpy, Window window)
   /* read parameters, keep em sane */
   st->delay = get_integer_resource (st->dpy, "delay", "Integer");
   if (st->delay < 1) st->delay = 1;
+  st->duration = get_integer_resource (st->dpy, "duration", "Seconds");
+  if (st->duration < 1) st->duration = 1;
   st->radius = get_integer_resource (st->dpy, "radius", "Integer");
   if (st->radius < 0) st->radius = 125;
 
@@ -129,7 +136,6 @@ spotlight_init (Display *dpy, Window window)
 #endif
   st->window_gc = XCreateGC(st->dpy, st->window, gcflags, &gcv);
 
-  /* grab screen to pixmap */
   st->pm = XCreatePixmap(st->dpy, st->window, st->sizex, st->sizey, xgwa.depth);
   XClearWindow(st->dpy, st->window);
 
@@ -152,6 +158,7 @@ spotlight_init (Display *dpy, Window window)
   clip_pm = XCreatePixmap(st->dpy, st->window, st->radius*4, st->radius*4, 1);
   st->img_loader = load_image_async_simple (0, xgwa.screen, st->window, st->pm,
                                             0, 0);
+  st->start_time = time ((time_t) 0);
 
   gcv.foreground = 0L;
   clip_gc = XCreateGC(st->dpy, clip_pm, gcflags, &gcv);
@@ -193,9 +200,19 @@ onestep (struct state *st, Bool first_p)
   if (st->img_loader)   /* still loading */
     {
       st->img_loader = load_image_async_simple (st->img_loader, 0, 0, 0, 0, 0);
+      if (! st->img_loader) {  /* just finished */
+        st->start_time = time ((time_t) 0);
+      }
       return;
     }
 
+  if (!st->img_loader &&
+      st->start_time + st->duration < time ((time_t) 0)) {
+    st->img_loader = load_image_async_simple (0, st->screen, st->window,
+                                              st->pm, 0, 0);
+    return;
+  }
+
 #define nrnd(x) (random() % (x))
 
   st->oldx = st->x;
@@ -293,12 +310,14 @@ static const char *spotlight_defaults [] = {
 #endif
 
   "*delay:                     10000",
+  "*duration:                  120",
   "*radius:                    125",
   0
 };
 
 static XrmOptionDescRec spotlight_options [] = {
   { "-delay",          ".delay",               XrmoptionSepArg, 0 },
+  { "-duration",       ".duration",            XrmoptionSepArg, 0 },
   { "-radius",         ".radius",              XrmoptionSepArg, 0 },
   { 0, 0, 0, 0 }
 };
index 0af60b7bee258214974a139f73e5bfd5b27f459b..7984ff6b544d65cd8866b2dfbb68d1ba6e804022 100644 (file)
@@ -5,7 +5,10 @@ spotlight - move spotlight around desktop
 .B spotlight
 [\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP]
 [\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-install]
-[\-visual \fIvisual\fP] [\-delay \fIusecs\fP] [\-radius \fIpixels\fP]
+[\-visual \fIvisual\fP]
+[\-delay \fIusecs\fP]
+[\-duration \fIsecs\fP]
+[\-radius \fIpixels\fP]
 .SH DESCRIPTION
 The \fIspotlight\fP program takes an image and exposes small sections
 of it as if through a wandering spotlight beam.
@@ -41,6 +44,9 @@ or the id number (decimal or hex) of a specific visual.
 .B \-delay \fImicroseconds\fP
 Slow it down.
 .TP 8
+.B \-duration \fIseconds\fP
+How long to run before loading a new image.  Default 120 seconds.
+.TP 8
 .B \-radius \fIpixels\fP
 Radius of the spotlight in pixels.
 .SH ENVIRONMENT
index 79bbd8f735b6b10cfef31bdc595e2e96a001c9a0..7a606b129399a1adc38d4248cee83836cd4acee8 100644 (file)
@@ -48,6 +48,7 @@ struct state {
   Window window;
 
   int delay;                   /* delay (usec) between iterations */
+  int duration;                        /* time (sec) before loading new image */
   int maxColumns;              /* the maximum number of columns of tiles */
   int maxRows;                 /* the maximum number of rows of tiles */
   int tileSize;                        /* the size (width and height) of a tile */
@@ -76,6 +77,7 @@ struct state {
   Tile **sortedTiles; /* array of tile pointers, sorted by zoom */
   int tileCount;     /* total number of tiles */
 
+  time_t start_time;
   async_load_state *img_loader;
 
   Bool useShm;         /* whether or not to use xshm */
@@ -102,7 +104,8 @@ struct state {
  */
 
 /* grab the source image */
-static void grabImage_start (struct state *st, XWindowAttributes *xwa)
+static void
+grabImage_start (struct state *st, XWindowAttributes *xwa)
 {
     XFillRectangle (st->dpy, st->window, st->backgroundGC, 0, 0, 
                    st->windowWidth, st->windowHeight);
@@ -110,20 +113,26 @@ static void grabImage_start (struct state *st, XWindowAttributes *xwa)
        XGetImage (st->dpy, st->window, 0, 0, st->windowWidth, st->windowHeight,
                   ~0L, ZPixmap);
 
+    st->start_time = time ((time_t) 0);
     st->img_loader = load_image_async_simple (0, xwa->screen, st->window,
                                               st->window, 0, 0);
 }
 
-static void grabImage_done (struct state *st)
+static void
+grabImage_done (struct state *st)
 {
-   XWindowAttributes xwa;
-   XGetWindowAttributes (st->dpy, st->window, &xwa);
+    XWindowAttributes xwa;
+    XGetWindowAttributes (st->dpy, st->window, &xwa);
 
+    st->start_time = time ((time_t) 0);
+    if (st->sourceImage) XDestroyImage (st->sourceImage);
     st->sourceImage = XGetImage (st->dpy, st->window, 0, 0, st->windowWidth, st->windowHeight,
                             ~0L, ZPixmap);
 
-#ifdef HAVE_XSHM_EXTENSION
+    if (st->workImage) XDestroyImage (st->workImage);
     st->workImage = NULL;
+
+#ifdef HAVE_XSHM_EXTENSION
     if (st->useShm) 
     {
        st->workImage = create_xshm_image (st->dpy, xwa.visual, xwa.depth,
@@ -605,6 +614,13 @@ twang_draw (Display *dpy, Window window, void *closure)
       return st->delay;
     }
 
+  if (!st->img_loader &&
+      st->start_time + st->duration < time ((time_t) 0)) {
+    XWindowAttributes xgwa;
+    XGetWindowAttributes (st->dpy, st->window, &xgwa);
+    grabImage_start (st, &xgwa);
+    return st->delay;
+  }
 
   modelEvents (st);
   updateModel (st);
@@ -655,6 +671,9 @@ static void initParams (struct state *st)
        problems = 1;
     }
 
+    st->duration = get_integer_resource (st->dpy, "duration", "Seconds");
+    if (st->duration < 1) st->duration = 1;
+
     st->eventChance = get_float_resource (st->dpy, "eventChance", "Double");
     if ((st->eventChance < 0.0) || (st->eventChance > 1.0))
     {
@@ -735,6 +754,7 @@ static const char *twang_defaults [] = {
     "*borderColor:      blue",
     "*borderWidth:     3",
     "*delay:           10000",
+    "*duration:                120",
     "*eventChance:      0.01",
     "*friction:                0.05",
     "*maxColumns:       0",
@@ -754,6 +774,7 @@ static XrmOptionDescRec twang_options [] = {
   { "-border-color",     ".borderColor",    XrmoptionSepArg, 0 },
   { "-border-width",     ".borderWidth",    XrmoptionSepArg, 0 },
   { "-delay",            ".delay",          XrmoptionSepArg, 0 },
+  { "-duration",        ".duration",       XrmoptionSepArg, 0 },
   { "-event-chance",     ".eventChance",    XrmoptionSepArg, 0 },
   { "-friction",         ".friction",       XrmoptionSepArg, 0 },
   { "-max-columns",      ".maxColumns",     XrmoptionSepArg, 0 },
index 27cdc2ee636dcffc98d57c0fec8f66628cf2ab4c..bdb572b2b33d5b0fef8fc91492d022311657c766 100644 (file)
@@ -3,7 +3,25 @@
 twang - pluck pieces of the screen
 .SH SYNOPSIS
 .B twang
-[\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP] [\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-install] [\-visual \fIvisual\fP] [\-shm] [\-no-shm] [\-delay \fImicroseconds\fP] [\-border-color \fIcolor\fP] [\-border-width \fIinteger\fP] [\-event-chance \fIfraction\fP] [\-friction \fIfraction\fP] [\-springiness \fIfraction\fP] [\-tile-size \fIinteger\fP] [\-transference \fIfraction\fP]
+[\-display \fIhost:display.screen\fP]
+[\-foreground \fIcolor\fP]
+[\-background \fIcolor\fP]
+[\-window]
+[\-root]
+[\-mono]
+[\-install]
+[\-visual \fIvisual\fP]
+[\-shm]
+[\-no-shm]
+[\-delay \fIusecs\fP]
+[\-duration \fIsecs\fP]
+[\-border-color \fIcolor\fP]
+[\-border-width \fIinteger\fP]
+[\-event-chance \fIfraction\fP]
+[\-friction \fIfraction\fP]
+[\-springiness \fIfraction\fP]
+[\-tile-size \fIinteger\fP]
+[\-transference \fIfraction\fP]
 .SH DESCRIPTION
 \fITwang\fP divides the screen into equal-sized tiles, and then plucks
 them in various ways. Tiles are affected by their neighbors, so waves
@@ -41,6 +59,9 @@ defaults to true, resource \fIuseSHM\fP.
 The interframe delay, in microseconds. Defaults to 10000, resource
 \fIdelay\fP.
 .TP 8
+.B \-duration \fIseconds\fP
+How long to run before loading a new image.  Default 120 seconds.
+.TP 8
 .B \-border-color \fIcolor\fP
 Color of the border surrounding each tile. Defaults to blue, resource
 \fIborderColor\fP.
index 2afbeb61d5160799743c5c8f873f825b0f986fb2..8e5b78f6795fcd38e3d5712e2899b21cd5e83f8c 100755 (executable)
@@ -60,7 +60,7 @@ use bytes;  # Larry can take Unicode and shove it up his ass sideways.
 
 
 my $progname = $0; $progname =~ s@.*/@@g;
-my $version = q{ $Revision: 1.140 $ }; $version =~ s/^[^0-9]+([0-9.]+).*$/$1/;
+my $version = q{ $Revision: 1.142 $ }; $version =~ s/^[^0-9]+([0-9.]+).*$/$1/;
 my $copyright = "WebCollage $version, Copyright (c) 1999-2005" .
     " Jamie Zawinski <jwz\@jwz.org>\n" .
     "            http://www.jwz.org/webcollage/\n";
@@ -188,6 +188,11 @@ my %poisoners = (
                                    # (I don't see how they did it, though!)
   "alwayshotels.com"        => 1,  # Poisoned Lycos pretty heavily.
   "nextag.com"              => 1,  # Poisoned Alta Vista real good.
+  "ghettodriveby.com"       => 1,  # Poisoned Google Images.
+  "crosswordsolver.org"     => 1,  # Poisoned Google Images.
+  "xona.com"                => 1,  # Poisoned Google Images.
+  "freepatentsonline.com"   => 1,  # Poisoned Google Images.
+  "herbdatanz.com"          => 1,  # Poisoned Google Images.
 );
 
 
@@ -206,6 +211,10 @@ my %warningless_sites = (
   "pics.livejournal.com"    => 1,
   "tinypic.com"             => 1,
   "flickr.com"              => 1,
+  "pbase.com"               => 1,
+  "blogger.com"             => 1,
+  "multiply.com"            => 1,
+  "wikimedia.org"           => 1,
 
   "yimg.com"                => 1,  # This is where dailynews.yahoo.com stores
   "eimg.com"                => 1,  # its images, so pick_from_yahoo_news_text()
@@ -862,7 +871,10 @@ sub pick_image_from_rss($$) {
 sub pick_dictionary() {
   my @dicts = ("/usr/dict/words",
                "/usr/share/dict/words",
-               "/usr/share/lib/dict/words");
+               "/usr/share/lib/dict/words",
+               "/usr/share/dict/cracklib-small",
+               "/usr/share/dict/cracklib-words"
+               );
   foreach my $f (@dicts) {
     if (-f $f) {
       $wordlist = $f;
index 6018469239a478a7c0cac736843603b1b00abb56..58d6acd9b3c2379ff338a431c8b5e743519e53e5 100644 (file)
@@ -1,6 +1,5 @@
 /* xlockmore.c --- xscreensaver compatibility layer for xlockmore modules.
- * xscreensaver, Copyright (c) 1997, 1998, 2001, 2002, 2004, 2006
- *  Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1997-2008 Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -521,7 +520,7 @@ xlockmore_reshape (Display *dpy, Window window, void *closure,
                  unsigned int w, unsigned int h)
 {
   ModeInfo *mi = (ModeInfo *) closure;
-  if (mi->xlmft->hack_reshape)
+  if (mi && mi->xlmft->hack_reshape)
     {
       XGetWindowAttributes (dpy, window, &mi->xgwa);
       mi->xlmft->hack_reshape (mi, mi->xgwa.width, mi->xgwa.height);
@@ -532,7 +531,7 @@ static Bool
 xlockmore_event (Display *dpy, Window window, void *closure, XEvent *event)
 {
   ModeInfo *mi = (ModeInfo *) closure;
-  if (mi->xlmft->hack_handle_events)
+  if (mi && mi->xlmft->hack_handle_events)
     {
       mi->xlmft->hack_handle_events (mi, event);
       /* Since xlockmore hacks don't tell us whether they handled the
index 2dd27538b56d19d5addb2716b2a57a3396aeadff..4b35797d300094a78693d0f23e4016e4d5b46773 100644 (file)
 struct state {
   Display *dpy;
   Window window;
+  Screen *screen;
 
   int sizex, sizey;
 
   int delay;
+  int duration;
   int pixwidth, pixheight, pixspacex, pixspacey, lensoffsetx, lensoffsety;
   Bool lenses;
 
@@ -46,6 +48,7 @@ struct state {
 
   int sinusoid_offset;
 
+  time_t start_time;
   async_load_state *img_loader;
 };
 
@@ -76,6 +79,7 @@ zoom_init (Display *dpy, Window window)
   st->dpy = dpy;
   st->window = window;
   XGetWindowAttributes(st->dpy, st->window, &xgwa);
+  st->screen = xgwa.screen;
   st->sizex = xgwa.width;
   st->sizey = xgwa.height;
   cmap = xgwa.colormap;
@@ -85,6 +89,9 @@ zoom_init (Display *dpy, Window window)
   st->delay = get_integer_resource(st->dpy, "delay", "Integer");
   if (st->delay < 1)
     st->delay = 1;
+  st->duration = get_integer_resource (st->dpy, "duration", "Seconds");
+  if (st->duration < 1)
+    st->duration = 1;
   st->pixwidth = get_integer_resource(st->dpy, "pixwidth", "Integer");
   if (st->pixwidth < 1)
     st->pixwidth = 1;
@@ -118,6 +125,7 @@ zoom_init (Display *dpy, Window window)
   XFillRectangle(st->dpy, st->window, st->window_gc, 0, 0, st->sizex, st->sizey);
   XSetWindowBackground(st->dpy, st->window, bg);
 
+  st->start_time = time ((time_t) 0);
   st->img_loader = load_image_async_simple (0, xgwa.screen, st->window,
                                             st->pm, 0, 0);
 
@@ -152,15 +160,23 @@ zoom_draw (Display *dpy, Window window, void *closure)
       st->img_loader = load_image_async_simple (st->img_loader, 0, 0, 0, 0, 0);
       if (! st->img_loader) {  /* just finished */
         XClearWindow (st->dpy, st->window);
+        st->start_time = time ((time_t) 0);
         if (!st->lenses) {
           st->orig_map = XGetImage(st->dpy, st->pm, 0, 0, st->sizex, st->sizey, ~0L, ZPixmap);
-          XFreePixmap(st->dpy, st->pm);
-          st->pm = 0;
+/*          XFreePixmap(st->dpy, st->pm);
+          st->pm = 0;*/
         }
       }
       return st->delay;
     }
 
+  if (!st->img_loader &&
+      st->start_time + st->duration < time ((time_t) 0)) {
+    st->img_loader = load_image_async_simple (0, st->screen, st->window,
+                                              st->pm, 0, 0);
+    return st->delay;
+  }
+
 #define nrnd(x) (random() % (x))
 
   now = currentTimeInMs(st);
@@ -220,12 +236,13 @@ zoom_free (Display *dpy, Window window, void *closure)
 static const char *zoom_defaults[] = {
   "*dontClearRoot: True",
   ".foreground: white",
-  ".background: black",
+  ".background: #111111",
 #ifdef __sgi /* really, HAVE_READ_DISPLAY_EXTENSION */
   "*visualID: Best",
 #endif
   "*lenses:      false",
   "*delay:       10000",
+  "*duration:    120",
   "*pixwidth:    10",
   "*pixheight:   10",
   "*pixspacex:   2",
@@ -238,6 +255,7 @@ static const char *zoom_defaults[] = {
 static XrmOptionDescRec zoom_options[] = {
   { "-lenses", ".lenses", XrmoptionNoArg, "true" },
   { "-delay", ".delay", XrmoptionSepArg, 0 },
+  { "-duration",  ".duration", XrmoptionSepArg, 0 },
   { "-pixwidth", ".pixwidth", XrmoptionSepArg, 0 },
   { "-pixheight", ".pixheight", XrmoptionSepArg, 0 },
   { "-pixspacex", ".pixspacex", XrmoptionSepArg, 0 },
index 08069ab2d4c761ecb1143f0cc1555e03492d67d3..85cac1b2038212388d45e5f3d255a51b2bdecac2 100644 (file)
@@ -5,7 +5,10 @@ zoom - wander around magnified desktop
 .B zoom
 [\-display \fIhost:display.screen\fP] [\-foreground \fIcolor\fP]
 [\-background \fIcolor\fP] [\-window] [\-root] [\-mono] [\-install]
-[\-visual \fIvisual\fP] [\-delay \fIusecs\fP] [\-lenses]
+[\-visual \fIvisual\fP]
+[\-delay \fIusecs\fP]
+[\-duration \fIsecs\fP]
+[\-lenses]
 [\-pixwidth \fIpixels\fP] [\-pixheight \fIpixels\fP]
 [\-pixspacex \fIpixels\fP] [\-pixspacey \fIpixels\fP]
 [\-lensoffsetx \fIpixels\fP] [\-lensoffsety \fIpixels\fP]
@@ -44,6 +47,9 @@ or the id number (decimal or hex) of a specific visual.
 .B \-delay \fImicroseconds\fP
 Slow it down.
 .TP 8
+.B \-duration \fIseconds\fP
+How long to run before loading a new image.  Default 120 seconds.
+.TP 8
 .B \-lenses
 Instead of doing magnification we just copy an offset region from the original
 image.  If lensoffsetx < pixwidth (and similarly for Y) then consecutive
index a46d390024b0de22de32b31a2b8304a785c15993..84e2cef7600ab96b1b952bf0f19994ad734964ad 100644 (file)
@@ -1,4 +1,4 @@
-# Auto-generated: Sat Mar  1 21:34:50 PST 2008
+# Auto-generated: Sat Jul  5 19:27:06 PDT 2008
 driver/demo-Gtk-conf.c
 driver/demo-Gtk-support.c
 driver/demo-Gtk-widgets.c
index 41918cbea398dc8e4ebeb346419eeaf068ecef16..e6b3c5153e81030f630ca6adb9213a2f9c3d9a57 100644 (file)
@@ -1,2 +1,2 @@
 static const char screensaver_id[] =
-       "@(#)xscreensaver 5.05 (01-Mar-2008), by Jamie Zawinski (jwz@jwz.org)";
+       "@(#)xscreensaver 5.06 (16-Jul-2008), by Jamie Zawinski (jwz@jwz.org)";
index f12ea952857d3a84cc5e939814b9ee11acb74337..cc38895e5130bc2a7a625def971bd6e98cd8c338 100644 (file)
@@ -17,7 +17,7 @@
 
    I don't understand how it works at all, but he says "look at Knuth,
    Vol. 2 (original edition), page 26, Algorithm A.  In this case n=55,
-   k=20 and m=2^32."
+   k=24 and m=2^32."
 
    So there you have it.
 
@@ -121,5 +121,5 @@ ya_rand_init(unsigned int seed)
     }
 
   i1 = a[0] % VectorSize;
-  i2 = (i1 + 024) % VectorSize;
+  i2 = (i1 + 24) % VectorSize;
 }
index 58b1588b6c05432c706878e3e612d53b0c1d2b7c..83a542515ad4a3f673483a3057b320dac5df1d06 100644 (file)
@@ -1,5 +1,5 @@
 %define        name xscreensaver
-%define        version 5.05
+%define        version 5.06
 
 Summary:       X screen saver and locker
 Name:          %{name}
index cfa10319c7230202b17438786c27760cd789cca8..71244f8825b51d7122c058813a47491d2583d1df 100644 (file)
                                AF7779F109B660B000EA3033 /* PBXTargetDependency */,
                                AF7779EF09B660B000EA3033 /* PBXTargetDependency */,
                                AF7779ED09B660B000EA3033 /* PBXTargetDependency */,
+                               AFE2A46F0E2E908E00ADB298 /* PBXTargetDependency */,
                                AF7779EB09B660B000EA3033 /* PBXTargetDependency */,
                                AF7779E909B660B000EA3033 /* PBXTargetDependency */,
                                AF7779E709B660B000EA3033 /* PBXTargetDependency */,
                AFD573680997411200BA26F7 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
                AFD573700997418D00BA26F7 /* strange.xml in Resources */ = {isa = PBXBuildFile; fileRef = AFC2591D0988A469000655EE /* strange.xml */; };
                AFD57372099741A200BA26F7 /* strange.c in Sources */ = {isa = PBXBuildFile; fileRef = AFD57371099741A200BA26F7 /* strange.c */; };
+               AFE2A45C0E2E904600ADB298 /* XScreenSaverSubclass.m in Sources */ = {isa = PBXBuildFile; fileRef = AF9CC7A0099580E70075E99B /* XScreenSaverSubclass.m */; };
+               AFE2A45F0E2E904600ADB298 /* libjwxyz.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AF4808C1098C3B6C00FB32B8 /* libjwxyz.a */; };
+               AFE2A4600E2E904600ADB298 /* ScreenSaver.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF976ED30989BF59001F8B92 /* ScreenSaver.framework */; };
+               AFE2A4610E2E904600ADB298 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
+               AFE2A4620E2E904600ADB298 /* AGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF480FE70990375900FB32B8 /* AGL.framework */; };
+               AFE2A4630E2E904600ADB298 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF480DF1098F528500FB32B8 /* OpenGL.framework */; };
+               AFE2A4640E2E904600ADB298 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF48112B0990A2C700FB32B8 /* Carbon.framework */; };
+               AFE2A4730E2E90E300ADB298 /* skytentacles.c in Sources */ = {isa = PBXBuildFile; fileRef = AFE2A4720E2E90E300ADB298 /* skytentacles.c */; };
+               AFE2A4750E2E911200ADB298 /* skytentacles.xml in Resources */ = {isa = PBXBuildFile; fileRef = AFE2A4740E2E911200ADB298 /* skytentacles.xml */; };
                AFE6A16C0CDD78EA002805BF /* involute.c in Sources */ = {isa = PBXBuildFile; fileRef = AFE6A16A0CDD78EA002805BF /* involute.c */; };
                AFE6A1890CDD7B2E002805BF /* XScreenSaverSubclass.m in Sources */ = {isa = PBXBuildFile; fileRef = AF9CC7A0099580E70075E99B /* XScreenSaverSubclass.m */; };
                AFE6A18A0CDD7B2E002805BF /* involute.c in Sources */ = {isa = PBXBuildFile; fileRef = AFE6A16A0CDD78EA002805BF /* involute.c */; };
                        remoteGlobalIDString = AF4808C0098C3B6C00FB32B8;
                        remoteInfo = jwxyz;
                };
+               AFE2A4580E2E904600ADB298 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = AF4808C0098C3B6C00FB32B8;
+                       remoteInfo = jwxyz;
+               };
+               AFE2A46E0E2E908E00ADB298 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = AFE2A4560E2E904600ADB298;
+                       remoteInfo = SkyTentacles;
+               };
                AFE6A1840CDD7B2E002805BF /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
                AFE1FD5B0981E3CB00F7970E /* yarandom.c */ = {isa = PBXFileReference; fileEncoding = 12; lastKnownFileType = sourcecode.c.c; name = yarandom.c; path = utils/yarandom.c; sourceTree = "<group>"; };
                AFE1FD5C0981E3CB00F7970E /* yarandom.h */ = {isa = PBXFileReference; fileEncoding = 12; lastKnownFileType = sourcecode.c.h; name = yarandom.h; path = utils/yarandom.h; sourceTree = "<group>"; };
                AFE1FD620981E40800F7970E /* rorschach.c */ = {isa = PBXFileReference; fileEncoding = 12; lastKnownFileType = sourcecode.c.c; name = rorschach.c; path = hacks/rorschach.c; sourceTree = "<group>"; };
+               AFE2A46A0E2E904600ADB298 /* SkyTentacles.saver */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SkyTentacles.saver; sourceTree = BUILT_PRODUCTS_DIR; };
+               AFE2A46D0E2E904600ADB298 /* XScreenSaver copy.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "XScreenSaver copy.plist"; path = "OSX/XScreenSaver copy.plist"; sourceTree = "<group>"; };
+               AFE2A4720E2E90E300ADB298 /* skytentacles.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = skytentacles.c; path = hacks/glx/skytentacles.c; sourceTree = "<group>"; };
+               AFE2A4740E2E911200ADB298 /* skytentacles.xml */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text.xml; path = skytentacles.xml; sourceTree = "<group>"; };
                AFE6A16A0CDD78EA002805BF /* involute.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = involute.c; path = hacks/glx/involute.c; sourceTree = "<group>"; };
                AFE6A16B0CDD78EA002805BF /* involute.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; name = involute.h; path = hacks/glx/involute.h; sourceTree = "<group>"; };
                AFE6A1970CDD7B2E002805BF /* MoebiusGears.saver */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MoebiusGears.saver; sourceTree = BUILT_PRODUCTS_DIR; };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               AFE2A45E0E2E904600ADB298 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               AFE2A45F0E2E904600ADB298 /* libjwxyz.a in Frameworks */,
+                               AFE2A4600E2E904600ADB298 /* ScreenSaver.framework in Frameworks */,
+                               AFE2A4610E2E904600ADB298 /* Cocoa.framework in Frameworks */,
+                               AFE2A4620E2E904600ADB298 /* AGL.framework in Frameworks */,
+                               AFE2A4630E2E904600ADB298 /* OpenGL.framework in Frameworks */,
+                               AFE2A4640E2E904600ADB298 /* Carbon.framework in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                AFE6A18B0CDD7B2E002805BF /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                                AF4FF4CE0D52CBDE00666F98 /* CubicGrid.saver */,
                                AF3C71590D624BF50030CC0D /* Hypnowheel.saver */,
                                AF1A17730D6D6EE3008AF328 /* LCDscrub.saver */,
+                               AFE2A46A0E2E904600ADB298 /* SkyTentacles.saver */,
                        );
                        name = Products;
                        sourceTree = "<group>";
                                8D1107310486CEB800E47090 /* XScreenSaver.plist */,
                                AF0FAF1209CA712600EE1051 /* xscreensaver-getimage-file */,
                                AF0FAF0B09CA6FF900EE1051 /* xscreensaver-text */,
+                               AFE2A46D0E2E904600ADB298 /* XScreenSaver copy.plist */,
                        );
                        name = Resources;
                        sourceTree = "<group>";
                                AF083A58099312B000277BE9 /* tunnel_draw.c */,
                                AF083A31099311CE00277BE9 /* atunnel.c */,
                                AF0839A909930C4900277BE9 /* atlantis.c */,
+                               AFE2A4720E2E90E300ADB298 /* skytentacles.c */,
                                AF0839AA09930C4900277BE9 /* dolphin.c */,
                                AF4812760990CF5D00FB32B8 /* buildlwo.c */,
                                AF4812770990CF5D00FB32B8 /* buildlwo.h */,
                                AFC258C10988A468000655EE /* greynetic.xml */,
                                AFC258C20988A468000655EE /* halftone.xml */,
                                AFC258C30988A468000655EE /* halo.xml */,
+                               AFE2A4740E2E911200ADB298 /* skytentacles.xml */,
                                AFC258C40988A468000655EE /* helix.xml */,
                                AFC258C50988A468000655EE /* hopalong.xml */,
                                AFC258C60988A468000655EE /* hyperball.xml */,
                        productReference = AFD5736D0997411200BA26F7 /* Strange.saver */;
                        productType = "com.apple.product-type.bundle";
                };
+               AFE2A4560E2E904600ADB298 /* SkyTentacles */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = AFE2A4670E2E904600ADB298 /* Build configuration list for PBXNativeTarget "SkyTentacles" */;
+                       buildPhases = (
+                               AFE2A4590E2E904600ADB298 /* Resources */,
+                               AFE2A45B0E2E904600ADB298 /* Sources */,
+                               AFE2A45E0E2E904600ADB298 /* Frameworks */,
+                               AFE2A4650E2E904600ADB298 /* Rez */,
+                               AFE2A4660E2E904600ADB298 /* ShellScript */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                               AFE2A4570E2E904600ADB298 /* PBXTargetDependency */,
+                       );
+                       name = SkyTentacles;
+                       productName = TopBlock;
+                       productReference = AFE2A46A0E2E904600ADB298 /* SkyTentacles.saver */;
+                       productType = "com.apple.product-type.bundle";
+               };
                AFE6A1820CDD7B2E002805BF /* MoebiusGears */ = {
                        isa = PBXNativeTarget;
                        buildConfigurationList = AFE6A1940CDD7B2E002805BF /* Build configuration list for PBXNativeTarget "MoebiusGears" */;
                                AFA559CF0993330600F3E977 /* Rubik */,
                                AFA55D3C0993565300F3E977 /* SBalls */,
                                AFA55B7909933F7200F3E977 /* Sierpinski3D */,
+                               AFE2A4560E2E904600ADB298 /* SkyTentacles */,
                                AFA55D7F099358C400F3E977 /* Spheremonics */,
                                AFA55A20099334A000F3E977 /* Sproingies */,
                                AFA55A030993340300F3E977 /* Stairs */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               AFE2A4590E2E904600ADB298 /* Resources */ = {
+                       isa = PBXResourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               AFE2A4750E2E911200ADB298 /* skytentacles.xml in Resources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                AFE6A1850CDD7B2E002805BF /* Resources */ = {
                        isa = PBXResourcesBuildPhase;
                        buildActionMask = 2147483647;
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               AFE2A4650E2E904600ADB298 /* Rez */ = {
+                       isa = PBXRezBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                AFE6A1920CDD7B2E002805BF /* Rez */ = {
                        isa = PBXRezBuildPhase;
                        buildActionMask = 2147483647;
                        shellScript = "$SOURCE_ROOT/OSX/update-info-plist.pl $BUILT_PRODUCTS_DIR/$PRODUCT_NAME$WRAPPER_SUFFIX";
                        showEnvVarsInLog = 0;
                };
+               AFE2A4660E2E904600ADB298 /* ShellScript */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       outputPaths = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "$SOURCE_ROOT/OSX/update-info-plist.pl $BUILT_PRODUCTS_DIR/$PRODUCT_NAME$WRAPPER_SUFFIX";
+                       showEnvVarsInLog = 0;
+               };
                AFE6A1930CDD7B2E002805BF /* ShellScript */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 2147483647;
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               AFE2A45B0E2E904600ADB298 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               AFE2A45C0E2E904600ADB298 /* XScreenSaverSubclass.m in Sources */,
+                               AFE2A4730E2E90E300ADB298 /* skytentacles.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                AFE6A1870CDD7B2E002805BF /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        target = AF4808C0098C3B6C00FB32B8 /* jwxyz */;
                        targetProxy = AFD5735F0997411200BA26F7 /* PBXContainerItemProxy */;
                };
+               AFE2A4570E2E904600ADB298 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = AF4808C0098C3B6C00FB32B8 /* jwxyz */;
+                       targetProxy = AFE2A4580E2E904600ADB298 /* PBXContainerItemProxy */;
+               };
+               AFE2A46F0E2E908E00ADB298 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = AFE2A4560E2E904600ADB298 /* SkyTentacles */;
+                       targetProxy = AFE2A46E0E2E908E00ADB298 /* PBXContainerItemProxy */;
+               };
                AFE6A1830CDD7B2E002805BF /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = AF4808C0098C3B6C00FB32B8 /* jwxyz */;
                        };
                        name = Release;
                };
+               AFE2A4680E2E904600ADB298 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS = (
+                                       "USE_GL=1",
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS)",
+                               );
+                       };
+                       name = Debug;
+               };
+               AFE2A4690E2E904600ADB298 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS = (
+                                       "USE_GL=1",
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS)",
+                               );
+                       };
+                       name = Release;
+               };
                AFE6A1950CDD7B2E002805BF /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
+               AFE2A4670E2E904600ADB298 /* Build configuration list for PBXNativeTarget "SkyTentacles" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               AFE2A4680E2E904600ADB298 /* Debug */,
+                               AFE2A4690E2E904600ADB298 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
                AFE6A1940CDD7B2E002805BF /* Build configuration list for PBXNativeTarget "MoebiusGears" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (