From de460e831dc8578acfa8b72251ab9346c99c1f96 Mon Sep 17 00:00:00 2001 From: Zygo Blaxell Date: Mon, 2 Mar 2009 00:43:52 -0500 Subject: [PATCH] http://www.tienza.es/crux/src/www.jwz.org/xscreensaver/xscreensaver-5.06.tar.gz -rw-r--r-- 1 zblaxell zblaxell 5486779 Jul 16 2008 xscreensaver-5.06.tar.gz 3310789ecf1ed8ff790d94512fe536857e793e4c xscreensaver-5.06.tar.gz --- Makefile.in | 42 +- OSX/._XScreenSaver.icns | Bin 0 -> 39555 bytes OSX/Makefile | 4 +- OSX/SaverTester.plist | 4 +- OSX/XScreenSaver.plist | 4 +- OSX/XScreenSaverView.m | 5 +- OSX/bindist.rtf | 2 +- README | 11 + README.hacking | 10 +- config.h.in | 3 + configure | 176 ++- configure.in | 82 +- driver/.gdbinit | 4 +- driver/Makefile.in | 50 +- driver/XScreenSaver.ad.in | 10 +- driver/XScreenSaver_ad.h | 3 + driver/demo-Gtk.c | 166 ++- driver/exec.c | 5 +- driver/lock.c | 48 +- driver/passwd-kerberos.c | 4 + driver/passwd-pam.c | 8 + driver/pdf2jpeg.m | 26 +- driver/prefs.c | 4 +- driver/screens.c | 894 +++++++++++++ driver/splash.c | 13 +- driver/stderr.c | 46 +- driver/subprocs.c | 93 +- driver/test-passwd.c | 22 +- driver/test-randr.c | 39 +- driver/test-screens.c | 196 +++ driver/timers.c | 47 +- driver/types.h | 37 +- driver/windows.c | 539 +++----- driver/xscreensaver-command.c | 6 +- driver/xscreensaver-command.man | 15 +- driver/xscreensaver.c | 415 ++---- driver/xscreensaver.h | 21 +- driver/xscreensaver.man | 1683 ++++++++++-------------- hacks/Makefile.in | 5 +- hacks/blitspin.c | 73 +- hacks/blitspin.man | 7 +- hacks/bsod.c | 64 +- hacks/bsod.man | 3 +- hacks/bumps.c | 22 +- hacks/bumps.h | 5 + hacks/bumps.man | 4 + hacks/config/README | 4 +- hacks/config/attraction.xml | 7 +- hacks/config/blitspin.xml | 4 + hacks/config/bsod.xml | 81 +- hacks/config/bumps.xml | 4 + hacks/config/carousel.xml | 13 +- hacks/config/decayscreen.xml | 4 + hacks/config/distort.xml | 4 + hacks/config/glschool.xml | 4 +- hacks/config/jigglypuff.xml | 50 +- hacks/config/juggle.xml | 2 +- hacks/config/lament.xml | 4 +- hacks/config/mirrorblob.xml | 78 +- hacks/config/popsquares.xml | 2 +- hacks/config/ripples.xml | 21 +- hacks/config/rotzoomer.xml | 4 + hacks/config/skytentacles.xml | 62 + hacks/config/slidescreen.xml | 4 + hacks/config/spheremonics.xml | 2 +- hacks/config/spotlight.xml | 4 + hacks/config/starwars.xml | 57 +- hacks/config/substrate.xml | 2 +- hacks/config/topblock.xml | 2 +- hacks/config/twang.xml | 4 + hacks/config/voronoi.xml | 68 +- hacks/config/xmatrix.xml | 63 +- hacks/config/zoom.xml | 4 + hacks/decayscreen.c | 46 +- hacks/decayscreen.man | 14 +- hacks/distort.c | 22 +- hacks/distort.man | 20 +- hacks/galaxy.c | 20 +- hacks/glx/Makefile.in | 28 +- hacks/glx/circuit.c | 2 +- hacks/glx/dnalogo.c | 331 +++-- hacks/glx/gleidescope.c | 829 ++++++++++-- hacks/glx/skytentacles.c | 808 ++++++++++++ hacks/glx/skytentacles.man | 102 ++ hacks/glx/sphere.c | 9 +- hacks/glx/sphere.h | 7 +- hacks/images/atm.xbm | 246 ++++ hacks/lcdscrub | Bin 41648 -> 0 bytes hacks/lcdscrub.man | 69 + hacks/memscroller.man | 2 +- hacks/penetrate.c | 27 +- hacks/ripples.c | 19 + hacks/ripples.man | 4 + hacks/rotzoomer.c | 20 + hacks/rotzoomer.man | 4 + hacks/screenhack.c | 2 + hacks/slidescreen.c | 24 +- hacks/slidescreen.man | 4 + hacks/spotlight.c | 23 +- hacks/spotlight.man | 8 +- hacks/twang.c | 31 +- hacks/twang.man | 23 +- hacks/webcollage | 16 +- hacks/xlockmore.c | 7 +- hacks/zoom.c | 24 +- hacks/zoom.man | 8 +- po/POTFILES.in | 2 +- utils/version.h | 2 +- utils/yarandom.c | 4 +- xscreensaver.spec | 2 +- xscreensaver.xcodeproj/project.pbxproj | 143 ++ 111 files changed, 5909 insertions(+), 2521 deletions(-) create mode 100644 OSX/._XScreenSaver.icns create mode 100644 driver/screens.c create mode 100644 driver/test-screens.c create mode 100644 hacks/config/skytentacles.xml create mode 100644 hacks/glx/skytentacles.c create mode 100644 hacks/glx/skytentacles.man create mode 100644 hacks/images/atm.xbm delete mode 100755 hacks/lcdscrub create mode 100644 hacks/lcdscrub.man diff --git a/Makefile.in b/Makefile.in index 99b6f4a2..c8e034f3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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 index 0000000000000000000000000000000000000000..4ec02b270045e5c5d5031f8f1541f0ba26027fd1 GIT binary patch literal 39555 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 Dv{kzR literal 0 HcmV?d00001 diff --git a/OSX/Makefile b/OSX/Makefile index 1a222c71..2ff5fe1b 100644 --- a/OSX/Makefile +++ b/OSX/Makefile @@ -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: @\ diff --git a/OSX/SaverTester.plist b/OSX/SaverTester.plist index e5d26f49..3a29f28b 100644 --- a/OSX/SaverTester.plist +++ b/OSX/SaverTester.plist @@ -15,11 +15,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 5.05 + 5.06 CFBundleSignature ???? CFBundleVersion - 5.05 + 5.06 LSMinimumSystemVersion 10.4.0 NSMainNibFile diff --git a/OSX/XScreenSaver.plist b/OSX/XScreenSaver.plist index 7e319f20..cf398f13 100644 --- a/OSX/XScreenSaver.plist +++ b/OSX/XScreenSaver.plist @@ -15,11 +15,11 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 5.05 + 5.06 CFBundleSignature ???? CFBundleVersion - 5.05 + 5.06 LSMinimumSystemVersion 10.4.0 NSMainNibFile diff --git a/OSX/XScreenSaverView.m b/OSX/XScreenSaverView.m index a122f7f2..2baf2c69 100644 --- a/OSX/XScreenSaverView.m +++ b/OSX/XScreenSaverView.m @@ -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); diff --git a/OSX/bindist.rtf b/OSX/bindist.rtf index d6e13459..dc18b3ea 100644 --- a/OSX/bindist.rtf +++ b/OSX/bindist.rtf @@ -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 fe349aa7..5a016924 100644 --- 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'. diff --git a/README.hacking b/README.hacking index 28767a5f..4e5170e4 100644 --- a/README.hacking +++ b/README.hacking @@ -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. diff --git a/config.h.in b/config.h.in index c5683912..21b68cd4 100644 --- a/config.h.in +++ b/config.h.in @@ -234,6 +234,9 @@ 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 .) A few of the screenhacks will take advantage of this if it's available. */ diff --git a/configure b/configure index 9af03d48..a6e9a4c3 100755 --- 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 @@ -12489,7 +12481,103 @@ fi #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 < #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 diff --git a/configure.in b/configure.in index 9a049b55..ee131deb 100644 --- a/configure.in +++ b/configure.in @@ -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 ]) @@ -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 diff --git a/driver/.gdbinit b/driver/.gdbinit index cb7d98ab..a585259f 100644 --- a/driver/.gdbinit +++ b/driver/.gdbinit @@ -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 diff --git a/driver/Makefile.in b/driver/Makefile.in index d9e4d755..13504008 100644 --- a/driver/Makefile.in +++ b/driver/Makefile.in @@ -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 diff --git a/driver/XScreenSaver.ad.in b/driver/XScreenSaver.ad.in index 3798dbeb..a6d59545 100644 --- a/driver/XScreenSaver.ad.in +++ b/driver/XScreenSaver.ad.in @@ -4,8 +4,8 @@ ! a screen saver and locker for the X window system ! by Jamie Zawinski ! -! version 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 diff --git a/driver/XScreenSaver_ad.h b/driver/XScreenSaver_ad.h index e556203d..26632eca 100644 --- a/driver/XScreenSaver_ad.h +++ b/driver/XScreenSaver_ad.h @@ -301,6 +301,7 @@ 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 \ @@ -417,4 +418,6 @@ "*hacks.moebiusgears.name: MoebiusGears", "*hacks.cubicgrid.name: CubicGrid", "*hacks.lcdscrub.name: LCDscrub", +"*hacks.hypnowheel.name: HypnoWheel", +"*hacks.skytentacles.name: SkyTentacles", "*hacks.documentation.isInstalled: True", diff --git a/driver/demo-Gtk.c b/driver/demo-Gtk.c index d1eb3c85..9ab83cbc 100644 --- a/driver/demo-Gtk.c +++ b/driver/demo-Gtk.c @@ -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); + /* 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); } diff --git a/driver/exec.c b/driver/exec.c index 0f2aaa21..5da53a01 100644 --- a/driver/exec.c +++ b/driver/exec.c @@ -1,5 +1,5 @@ /* exec.c --- executes a program in *this* pid, without an intervening process. - * xscreensaver, Copyright (c) 1991-2006 Jamie Zawinski + * xscreensaver, Copyright (c) 1991-2008 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 @@ -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". */ diff --git a/driver/lock.c b/driver/lock.c index e1d29dc9..159c6a0f 100644 --- a/driver/lock.c +++ b/driver/lock.c @@ -1,5 +1,5 @@ /* lock.c --- handling the password dialog for locking-mode. - * xscreensaver, Copyright (c) 1993-2007 Jamie Zawinski + * xscreensaver, Copyright (c) 1993-2008 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 @@ -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); diff --git a/driver/passwd-kerberos.c b/driver/passwd-kerberos.c index bb8d9926..202e0eb1 100644 --- a/driver/passwd-kerberos.c +++ b/driver/passwd-kerberos.c @@ -78,6 +78,10 @@ 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 diff --git a/driver/passwd-pam.c b/driver/passwd-pam.c index 334d12b9..3b4c64f9 100644 --- a/driver/passwd-pam.c +++ b/driver/passwd-pam.c @@ -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) diff --git a/driver/pdf2jpeg.m b/driver/pdf2jpeg.m index 60778fe1..166826e8 100644 --- a/driver/pdf2jpeg.m +++ b/driver/pdf2jpeg.m @@ -1,6 +1,6 @@ /* pdf2jpeg -- converts a PDF file to a JPEG file, using Cocoa * - * Copyright (c) 2003 by Jamie Zawinski + * Copyright (c) 2003, 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 @@ -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: diff --git a/driver/prefs.c b/driver/prefs.c index c8e4ae14..1b093148 100644 --- a/driver/prefs.c +++ b/driver/prefs.c @@ -1,5 +1,5 @@ /* dotfile.c --- management of the ~/.xscreensaver file. - * xscreensaver, Copyright (c) 1998-2006 Jamie Zawinski + * xscreensaver, Copyright (c) 1998-2008 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 @@ -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 index 00000000..cef66b78 --- /dev/null +++ b/driver/screens.c @@ -0,0 +1,894 @@ +/* screens.c --- dealing with RANDR, Xinerama, and VidMode Viewports. + * xscreensaver, Copyright (c) 1991-2008 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. + */ + +/* 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 + +#ifdef HAVE_RANDR +# include +#endif /* HAVE_RANDR */ + +#ifdef HAVE_XINERAMA +# include +#endif /* HAVE_XINERAMA */ + +#ifdef HAVE_XF86VMODE +# include +#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; +} diff --git a/driver/splash.c b/driver/splash.c index 56f66daf..491ebe80 100644 --- a/driver/splash.c +++ b/driver/splash.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1991-2006 Jamie Zawinski +/* xscreensaver, Copyright (c) 1991-2008 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 @@ -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); diff --git a/driver/stderr.c b/driver/stderr.c index 6246dd3a..68e75213 100644 --- a/driver/stderr.c +++ b/driver/stderr.c @@ -1,5 +1,5 @@ /* stderr.c --- capturing stdout/stderr output onto the screensaver window. - * xscreensaver, Copyright (c) 1991-2006 Jamie Zawinski + * xscreensaver, Copyright (c) 1991-2008 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 @@ -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; diff --git a/driver/subprocs.c b/driver/subprocs.c index 88270d6c..405a382b 100644 --- a/driver/subprocs.c +++ b/driver/subprocs.c @@ -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; } } diff --git a/driver/test-passwd.c b/driver/test-passwd.c index ac5bf992..42e2e280 100644 --- a/driver/test-passwd.c +++ b/driver/test-passwd.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1998-2007 Jamie Zawinski +/* xscreensaver, Copyright (c) 1998-2008 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 @@ -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 diff --git a/driver/test-randr.c b/driver/test-randr.c index da86e04d..0d57895a 100644 --- a/driver/test-randr.c +++ b/driver/test-randr.c @@ -1,5 +1,5 @@ /* test-randr.c --- playing with the Resize And Rotate extension. - * xscreensaver, Copyright (c) 2004, 2005 Jamie Zawinski + * xscreensaver, Copyright (c) 2004-2008 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 @@ -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 index 00000000..60bd569d --- /dev/null +++ b/driver/test-screens.c @@ -0,0 +1,196 @@ +/* test-screens.c --- some test cases for the "monitor sanity" checks. + * xscreensaver, Copyright (c) 2008 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +/* 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); +} diff --git a/driver/timers.c b/driver/timers.c index c7434925..584a6d0d 100644 --- a/driver/timers.c +++ b/driver/timers.c @@ -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 diff --git a/driver/types.h b/driver/types.h index 48321877..63ac39ec 100644 --- a/driver/types.h +++ b/driver/types.h @@ -1,7 +1,4 @@ -/* types.h - * - * This file is part of XScreenSaver, - * Copyright (c) 1993-2004 Jamie Zawinski +/* xscreensaver, Copyright (c) 1993-2008 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 @@ -12,20 +9,19 @@ * 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__ */ diff --git a/driver/windows.c b/driver/windows.c index 9dbb5004..44cce89f 100644 --- a/driver/windows.c +++ b/driver/windows.c @@ -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) { diff --git a/driver/xscreensaver-command.c b/driver/xscreensaver-command.c index de507a0a..5ec74417 100644 --- a/driver/xscreensaver-command.c +++ b/driver/xscreensaver-command.c @@ -108,9 +108,9 @@ usage: %s -