From: Zygo Blaxell Date: Sat, 12 Jun 2021 04:54:48 +0000 (-0400) Subject: From https://www.jwz.org/xscreensaver/xscreensaver-6.01.tar.gz X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=98e6bdf3259b58791b6e8f273621bb961a702aee;p=xscreensaver From https://www.jwz.org/xscreensaver/xscreensaver-6.01.tar.gz -rw-rw-r-- 1 zblaxell zblaxell 27820165 Jun 9 12:00 xscreensaver-6.01.tar.gz 5e6bf477d14b8a4a07e65ac2fd32b7b7f71e422b xscreensaver-6.01.tar.gz --- diff --git a/Makefile.in b/Makefile.in index 42742d3c..ce469fc3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -16,7 +16,9 @@ TARFILES = README README.hacking INSTALL \ intltool-merge.in intltool-extract.in intltool-update.in \ xscreensaver.spec -TAR = tar +TAR = gnutar +TAR_ARGS = --owner=0 --group=0 --posix --no-acls --no-xattrs --no-selinux + # Using $(MAKE) directly means the shell executes things even with "make -n" MAKE2 = $(MAKE) @@ -94,7 +96,7 @@ _tar: echo creating tar file $$ADIR$$NAME.tar.gz... ; \ export COPYFILE_DISABLE=true ; \ export GZIP="-9v" ; \ - $(TAR) -vczf $$ADIR$$NAME.tar.gz -T "$$LIST" ; \ + $(TAR) -vczf $$ADIR$$NAME.tar.gz -T "$$LIST" $(TAR_ARGS) ; \ rm "$$LIST" "$$NAME" @@ -361,7 +363,7 @@ www:: diff -U0 download.html $$TMP ; \ echo '' ; \ \ - for EXT in tar.gz dmg ; do \ + for EXT in tar.gz dmg apk ; do \ OLDEST=`ls xscreensaver*.$$EXT | \ fgrep -v 5.14 | \ fgrep -v 5.34 | \ @@ -413,7 +415,7 @@ count:: # rsync -vax . cerebrum:src/xscreensaver/ \ cerebrum:: - rsync -vax . pi@10.0.1.19:xscreensaver/ \ + rsync -vax . pi@10.0.1.10:xscreensaver/ \ --omit-dir-times \ --delete-during \ --exclude .git \ diff --git a/OSX/Randomizer.plist b/OSX/Randomizer.plist index e2d4c576..d2761b82 100644 --- a/OSX/Randomizer.plist +++ b/OSX/Randomizer.plist @@ -17,7 +17,7 @@ CFBundleSignature ???? CFBundleVersion - 6.00 + 6.01 LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET} NSPrincipalClass @@ -25,12 +25,12 @@ LSApplicationCategoryType public.app-category.entertainment CFBundleShortVersionString - 6.00 + 6.01 CFBundleLongVersionString - 6.00 + 6.01 CFBundleGetInfoString - 6.00 + 6.01 NSHumanReadableCopyright - 6.00 + 6.01 diff --git a/OSX/SaverRunner.plist b/OSX/SaverRunner.plist index ac6292aa..df4d5487 100644 --- a/OSX/SaverRunner.plist +++ b/OSX/SaverRunner.plist @@ -17,7 +17,7 @@ CFBundleSignature ???? CFBundleVersion - 6.00 + 6.01 LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET} NSPrincipalClass @@ -25,13 +25,13 @@ LSApplicationCategoryType public.app-category.entertainment CFBundleShortVersionString - 6.00 + 6.01 CFBundleLongVersionString - 6.00 + 6.01 CFBundleGetInfoString - 6.00 + 6.01 NSHumanReadableCopyright - 6.00 + 6.01 NSMainNibFile SaverRunner CFBundleIconFile diff --git a/OSX/Updater.plist b/OSX/Updater.plist index e399326f..9d799fa2 100644 --- a/OSX/Updater.plist +++ b/OSX/Updater.plist @@ -17,7 +17,7 @@ CFBundleSignature ???? CFBundleVersion - 6.00 + 6.01 LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET} NSPrincipalClass @@ -25,13 +25,13 @@ LSApplicationCategoryType public.app-category.entertainment CFBundleShortVersionString - 6.00 + 6.01 CFBundleLongVersionString - 6.00 + 6.01 CFBundleGetInfoString - 6.00 + 6.01 NSHumanReadableCopyright - 6.00 + 6.01 NSMainNibFile Updater CFBundleIconFile diff --git a/OSX/XScreenSaver.plist b/OSX/XScreenSaver.plist index b91d3c55..69c687b4 100644 --- a/OSX/XScreenSaver.plist +++ b/OSX/XScreenSaver.plist @@ -17,7 +17,7 @@ CFBundleSignature ???? CFBundleVersion - 6.00 + 6.01 LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET} NSPrincipalClass @@ -25,13 +25,13 @@ LSApplicationCategoryType public.app-category.entertainment CFBundleShortVersionString - 6.00 + 6.01 CFBundleLongVersionString - 6.00 + 6.01 CFBundleGetInfoString - 6.00 + 6.01 NSHumanReadableCopyright - 6.00 + 6.01 NSMainNibFile SaverRunner diff --git a/OSX/bindist.rtf b/OSX/bindist.rtf index f2909b90..469f51ff 100644 --- a/OSX/bindist.rtf +++ b/OSX/bindist.rtf @@ -16,8 +16,8 @@ \b0 by Jamie Zawinski\ and many others\ \ -version 6.00\ -01-Apr-2021\ +version 6.01\ +09-Jun-2021\ \ {\field{\*\fldinst{HYPERLINK "https://www.jwz.org/xscreensaver/"}}{\fldrslt \cf2 \ul \ulc2 https://www.jwz.org/xscreensaver/}}\ \pard\pardeftab720 diff --git a/OSX/iSaverRunner.plist b/OSX/iSaverRunner.plist index a65d7be1..835f8c43 100644 --- a/OSX/iSaverRunner.plist +++ b/OSX/iSaverRunner.plist @@ -17,17 +17,17 @@ CFBundleSignature ???? CFBundleVersion - 6.00 + 6.01 LSApplicationCategoryType public.app-category.entertainment CFBundleShortVersionString - 6.00 + 6.01 CFBundleLongVersionString - 6.00 + 6.01 CFBundleGetInfoString - 6.00 + 6.01 NSHumanReadableCopyright - 6.00 + 6.01 NSMainNibFile iSaverRunner CFBundleDisplayName diff --git a/README b/README index ddb97869..85295491 100644 --- a/README +++ b/README @@ -70,6 +70,17 @@ Interested in writing a new screen saver? Version History =============================================================================== +6.01 * X11: Properly disable the server's built-in screen saver. + * X11: The passwdTimeout option was being ignored. + * X11: The display of the unlock thermometer was weird. + * X11: Fixed password entry on old-school multi-screen setups (:0.1). + * X11: Worked around a KDE 5 compositor bug that caused the desktop + to momentarily become visible when cycling. + * X11: Fixed possible high CPU usage in `xscreensaver-systemd'. + * X11: Fixed some spurious warnings in `xscreensaver-text'. + * X11: Warn when Wayland is in use, since it makes both screen saving + and locking impossible. + 6.00 * X11: Major refactor of the `xscreensaver' daemon for improved security, dividing it into three programs: `xscreensaver', `xscreensaver-gfx' and `xscreensaver-auth'. diff --git a/config.h.in b/config.h.in index 11a0ab9e..d326fb86 100644 --- a/config.h.in +++ b/config.h.in @@ -154,6 +154,9 @@ /* Define this if your system has libcap. */ #undef HAVE_LIBCAP +/* Define this if you have libelogind. */ +#undef HAVE_LIBELOGIND + /* Define this if you have the Portable Network Graphics library. */ #undef HAVE_LIBPNG diff --git a/configure b/configure index 4a03e1e8..0bec009e 100755 --- a/configure +++ b/configure @@ -839,6 +839,7 @@ with_xkb_ext with_proc_interrupts with_proc_oom with_systemd +with_elogind enable_locking enable_root_passwd with_pam @@ -1496,6 +1497,7 @@ Server Extension Options: --with-proc-oom Include support to duck the out-of-memory killer. --with-systemd Support systemd requests to lock on suspend, and to allow video players to inhibit the screen saver. + --with-elogind Use elogind instead of systemd. Screen Locking Options: @@ -10500,6 +10502,219 @@ else SYSTEMD_LIBS='' fi +############################################################################### +# +# Check for -lelogind, a stripped down subset of systemd. +# +############################################################################### + +have_elogind=no +with_elogind_req=unspecified +elogind_halfassed=no +elogind_too_old=no + +# Check whether --with-elogind was given. +if test "${with_elogind+set}" = set; then : + withval=$with_elogind; with_elogind="$withval"; with_elogind_req="$withval" +else + with_elogind=yes +fi + + case "$with_elogind" in + yes) ;; + no) ;; + + /*) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for elogind headers" >&5 +$as_echo_n "checking for elogind headers... " >&6; } + d=$with_elogind/include + if test -d $d; then + X_CFLAGS="-I$d $X_CFLAGS" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $d" >&5 +$as_echo "$d" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found ($d: no such directory)" >&5 +$as_echo "not found ($d: no such directory)" >&6; } + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for elogind libs" >&5 +$as_echo_n "checking for elogind libs... " >&6; } + d=$with_elogind/lib + if test -d $d; then + X_LIBS="-L$d $X_LIBS" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $d" >&5 +$as_echo "$d" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found ($d: no such directory)" >&5 +$as_echo "not found ($d: no such directory)" >&6; } + fi + + # replace the directory string with "yes". + with_elogind_req="yes" + with_elogind=$with_elogind_req + ;; + + *) + echo "" + echo "error: argument to --with-elogind must be \"yes\", \"no\", or a directory." + echo " If it is a directory, then \`DIR/include' will be added to" + echo " the -I list, and \`DIR/lib' will be added to the -L list." + exit 1 + ;; + esac + +if test "$with_elogind" != yes -a "$with_elogind" != no ; then + echo "error: must be yes or no: --with-elogind=$with_elogind" + exit 1 +fi + +if test "$with_elogind" = yes; then + + pkgs='' + ok="yes" + pkg_check_version libelogind 221 + have_elogind="$ok" + + if test "$have_elogind" = no; then + if $pkg_config --exists libelogind ; then + elogind_too_old=yes + fi + fi + + if test "$have_elogind" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libelogind includes" >&5 +$as_echo_n "checking for libelogind includes... " >&6; } +if ${ac_cv_elogind_config_cflags+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_elogind_config_cflags=`$pkg_config --cflags $pkgs` +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_elogind_config_cflags" >&5 +$as_echo "$ac_cv_elogind_config_cflags" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libelogind libs" >&5 +$as_echo_n "checking for libelogind libs... " >&6; } +if ${ac_cv_elogind_config_libs+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_elogind_config_libs=`$pkg_config --libs $pkgs` +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_elogind_config_libs" >&5 +$as_echo "$ac_cv_elogind_config_libs" >&6; } + fi + + ac_elogind_config_cflags=$ac_cv_elogind_config_cflags + ac_elogind_config_libs=$ac_cv_elogind_config_libs + + if test "$have_elogind" = yes; then + # + # we appear to have libelogind; check for headers/libs to be sure. + # + ac_save_elogind_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $ac_elogind_config_cflags" + + have_elogind=no + + ac_save_CPPFLAGS="$CPPFLAGS" + if test \! -z "$includedir" ; then + CPPFLAGS="$CPPFLAGS -I$includedir" + fi + CPPFLAGS="$CPPFLAGS $X_CFLAGS" + CPPFLAGS=`eval eval eval eval eval eval eval eval eval echo $CPPFLAGS` + ac_fn_c_check_header_mongrel "$LINENO" "elogind/sd-bus.h" "ac_cv_header_elogind_sd_bus_h" "$ac_includes_default" +if test "x$ac_cv_header_elogind_sd_bus_h" = xyes; then : + have_elogind=yes +fi + + CPPFLAGS="$ac_save_CPPFLAGS" + + CPPFLAGS="$ac_save_elogind_CPPFLAGS" + fi + + if test "$have_elogind" = yes; then + # we have the headers, now check for the libraries + have_elogind=no + elogind_halfassed=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: result: checking for libelogind usability..." >&5 +$as_echo "checking for libelogind usability..." >&6; } + + 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` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sd_bus_open_system in -lc" >&5 +$as_echo_n "checking for sd_bus_open_system in -lc... " >&6; } +if ${ac_cv_lib_c_sd_bus_open_system+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lc $ac_elogind_config_libs -lX11 -lXext -lm $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* 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 sd_bus_open_system (); +int +main () +{ +return sd_bus_open_system (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_c_sd_bus_open_system=yes +else + ac_cv_lib_c_sd_bus_open_system=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_sd_bus_open_system" >&5 +$as_echo "$ac_cv_lib_c_sd_bus_open_system" >&6; } +if test "x$ac_cv_lib_c_sd_bus_open_system" = xyes; then : + have_elogind=yes; elogind_halfassed=no +fi + + CPPFLAGS="$ac_save_CPPFLAGS" + LDFLAGS="$ac_save_LDFLAGS" +# LIBS="$ac_save_LIBS" + + fi + + if test "$have_elogind" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: checking for libelogind usability... no" >&5 +$as_echo "checking for libelogind usability... no" >&6; } + fi +fi + +if test "$have_elogind" = yes; then + INCLUDES="$INCLUDES $ac_elogind_config_cflags" + EXES_SYSTEMD='$(EXES_SYSTEMD)' + SYSTEMD_LIBS="$ac_elogind_config_libs" + $as_echo "#define HAVE_LIBELOGIND 1" >>confdefs.h + +fi + ############################################################################### # # The --enable-locking option @@ -19080,7 +19295,7 @@ if test \! -z "$rpm_vers" ; then pkg_bindir2=`rpm -ql $rpmnames | sed -n 's@^\(.*/\)xscreensaver-demo$@\1@p'` pkg_hackdir=`rpm -ql $rpmnames | sed -n 's@^\(.*/\)popsquares$@\1@p'` pkg_confdir=`rpm -ql $rpmnames | sed -n 's@^\(.*/\)popsquares\.xml$@\1@p'` - pkg_fontdir=`rpm -ql $rpmnames | sed -n 's@^\(.*/\)\.ttf$@\1@p'` + pkg_fontdir=`rpm -ql $rpmnames | sed -n 's@^\(.*/\).*\.ttf$@\1@p' | head -1` pkg_addir=`rpm -ql $rpmnames | sed -n 's@^\(.*/\)XScreenSaver$@\1@p'` if test -z "$pkg_bindir" ; then pkg_bindir="$pkg_bindir2" ; fi @@ -19109,7 +19324,7 @@ if test \! -z "$deb_vers" ; then pkg_bindir2=`dpkg -L $debnames 2>&- | sed -n 's@^\(.*/\)xscreensaver-demo$@\1@p'` pkg_hackdir=`dpkg -L $debnames 2>&- | sed -n 's@^\(.*/\)popsquares$@\1@p'` pkg_confdir=`dpkg -L $debnames 2>&- | sed -n 's@^\(.*/\)popsquares\.xml$@\1@p'` - pkg_fontdir=`dpkg -L $debnames 2>&- | sed -n 's@^\(.*/\)\.ttf$@\1@p'` + pkg_fontdir=`dpkg -L $debnames 2>&- | sed -n 's@^\(.*/\).*\.ttf$@\1@p' | head -1` pkg_addir=`dpkg -L $debnames 2>&- | sed -n 's@^\(.*/\)XScreenSaver[^/]*$@\1@p'` if test -z "$pkg_bindir" ; then pkg_bindir="$pkg_bindir2" ; fi diff --git a/configure.ac b/configure.ac index c3f0b5b5..0b92abcf 100644 --- a/configure.ac +++ b/configure.ac @@ -126,6 +126,9 @@ AH_TEMPLATE([HAVE_XKB], AH_TEMPLATE([HAVE_LIBSYSTEMD], [Define this if you have libsystemd.]) +AH_TEMPLATE([HAVE_LIBELOGIND], + [Define this if you have libelogind.]) + 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 @@ -2138,6 +2141,87 @@ else fi +############################################################################### +# +# Check for -lelogind, a stripped down subset of systemd. +# +############################################################################### + +have_elogind=no +with_elogind_req=unspecified +elogind_halfassed=no +elogind_too_old=no +AC_ARG_WITH(elogind, +[ --with-elogind Use elogind instead of systemd.], + [with_elogind="$withval"; with_elogind_req="$withval"], + [with_elogind=yes]) + +HANDLE_X_PATH_ARG(with_elogind, --with-elogind, elogind) + +if test "$with_elogind" != yes -a "$with_elogind" != no ; then + echo "error: must be yes or no: --with-elogind=$with_elogind" + exit 1 +fi + +if test "$with_elogind" = yes; then + + pkgs='' + ok="yes" + pkg_check_version libelogind 221 + have_elogind="$ok" + + if test "$have_elogind" = no; then + if $pkg_config --exists libelogind ; then + elogind_too_old=yes + fi + fi + + if test "$have_elogind" = yes; then + AC_CACHE_CHECK([for libelogind includes], ac_cv_elogind_config_cflags, + [ac_cv_elogind_config_cflags=`$pkg_config --cflags $pkgs`]) + AC_CACHE_CHECK([for libelogind libs], ac_cv_elogind_config_libs, + [ac_cv_elogind_config_libs=`$pkg_config --libs $pkgs`]) + fi + + ac_elogind_config_cflags=$ac_cv_elogind_config_cflags + ac_elogind_config_libs=$ac_cv_elogind_config_libs + + if test "$have_elogind" = yes; then + # + # we appear to have libelogind; check for headers/libs to be sure. + # + ac_save_elogind_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $ac_elogind_config_cflags" + + have_elogind=no + AC_CHECK_X_HEADER(elogind/sd-bus.h, [have_elogind=yes]) + + CPPFLAGS="$ac_save_elogind_CPPFLAGS" + fi + + if test "$have_elogind" = yes; then + # we have the headers, now check for the libraries + have_elogind=no + elogind_halfassed=yes + AC_MSG_RESULT(checking for libelogind usability...) + AC_CHECK_X_LIB(c, sd_bus_open_system, + [have_elogind=yes; elogind_halfassed=no],, + $ac_elogind_config_libs -lX11 -lXext -lm) + fi + + if test "$have_elogind" = no; then + AC_MSG_RESULT(checking for libelogind usability... no) + fi +fi + +if test "$have_elogind" = yes; then + INCLUDES="$INCLUDES $ac_elogind_config_cflags" + EXES_SYSTEMD='$(EXES_SYSTEMD)' + SYSTEMD_LIBS="$ac_elogind_config_libs" + AC_DEFINE(HAVE_LIBELOGIND) +fi + + ############################################################################### # # The --enable-locking option @@ -4774,7 +4858,7 @@ if test \! -z "$rpm_vers" ; then pkg_bindir2=`rpm -ql $rpmnames | sed -n 's@^\(.*/\)xscreensaver-demo$@\1@p'` pkg_hackdir=`rpm -ql $rpmnames | sed -n 's@^\(.*/\)popsquares$@\1@p'` pkg_confdir=`rpm -ql $rpmnames | sed -n 's@^\(.*/\)popsquares\.xml$@\1@p'` - pkg_fontdir=`rpm -ql $rpmnames | sed -n 's@^\(.*/\)\.ttf$@\1@p'` + pkg_fontdir=`rpm -ql $rpmnames | sed -n 's@^\(.*/\).*\.ttf$@\1@p' | head -1` pkg_addir=`rpm -ql $rpmnames | sed -n 's@^\(.*/\)XScreenSaver$@\1@p'` if test -z "$pkg_bindir" ; then pkg_bindir="$pkg_bindir2" ; fi @@ -4804,7 +4888,7 @@ if test \! -z "$deb_vers" ; then pkg_bindir2=`dpkg -L $debnames 2>&- | sed -n 's@^\(.*/\)xscreensaver-demo$@\1@p'` pkg_hackdir=`dpkg -L $debnames 2>&- | sed -n 's@^\(.*/\)popsquares$@\1@p'` pkg_confdir=`dpkg -L $debnames 2>&- | sed -n 's@^\(.*/\)popsquares\.xml$@\1@p'` - pkg_fontdir=`dpkg -L $debnames 2>&- | sed -n 's@^\(.*/\)\.ttf$@\1@p'` + pkg_fontdir=`dpkg -L $debnames 2>&- | sed -n 's@^\(.*/\).*\.ttf$@\1@p' | head -1` pkg_addir=`dpkg -L $debnames 2>&- | sed -n 's@^\(.*/\)XScreenSaver[^/]*$@\1@p'` changequote([,]) diff --git a/driver/XScreenSaver.ad.in b/driver/XScreenSaver.ad.in index bfc64142..764ae34f 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 6.00 -! 01-Apr-2021 +! version 6.01 +! 09-Jun-2021 ! ! See "man xscreensaver" for more info. The latest version is always ! available at https://www.jwz.org/xscreensaver/ diff --git a/driver/atoms.c b/driver/atoms.c index e8b6addc..d8847e90 100644 --- a/driver/atoms.c +++ b/driver/atoms.c @@ -28,6 +28,7 @@ Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_RESPONSE, XA_DEACTIVATE, XA_CYCLE, XA_RESTART, XA_PREFS, XA_NET_WM_PID, XA_NET_WM_STATE, XA_NET_WM_STATE_ABOVE, XA_NET_WM_STATE_FULLSCREEN, XA_NET_WM_BYPASS_COMPOSITOR, + XA_NET_WM_STATE_STAYS_ON_TOP, XA_KDE_NET_WM_WINDOW_TYPE_OVERRIDE, XA_NET_WM_WINDOW_TYPE, XA_NET_WM_WINDOW_TYPE_SPLASH, XA_NET_WM_WINDOW_TYPE_DIALOG, XA_NET_WM_WINDOW_TYPE_NOTIFICATION, XA_NET_WM_WINDOW_TYPE_NORMAL; @@ -66,5 +67,8 @@ init_xscreensaver_atoms (Display *dpy) XA_NET_WM_WINDOW_TYPE_DIALOG = A("_NET_WM_WINDOW_TYPE_DIALOG"); XA_NET_WM_WINDOW_TYPE_NOTIFICATION = A("_NET_WM_WINDOW_TYPE_NOTIFICATION"); XA_NET_WM_WINDOW_TYPE_NORMAL = A("_NET_WM_WINDOW_TYPE_NORMAL"); + XA_NET_WM_STATE_STAYS_ON_TOP = A("_NET_WM_STATE_STAYS_ON_TOP"); + XA_KDE_NET_WM_WINDOW_TYPE_OVERRIDE = A("_KDE_NET_WM_WINDOW_TYPE_OVERRIDE"); + # undef A } diff --git a/driver/atoms.h b/driver/atoms.h index b5a7b7c3..9dcacce9 100644 --- a/driver/atoms.h +++ b/driver/atoms.h @@ -18,6 +18,7 @@ extern Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_RESPONSE, XA_DEACTIVATE, XA_CYCLE, XA_RESTART, XA_PREFS, XA_NET_WM_PID, XA_NET_WM_STATE, XA_NET_WM_STATE_ABOVE, XA_NET_WM_STATE_FULLSCREEN, XA_NET_WM_BYPASS_COMPOSITOR, + XA_NET_WM_STATE_STAYS_ON_TOP, XA_KDE_NET_WM_WINDOW_TYPE_OVERRIDE, XA_NET_WM_WINDOW_TYPE, XA_NET_WM_WINDOW_TYPE_SPLASH, XA_NET_WM_WINDOW_TYPE_DIALOG, XA_NET_WM_WINDOW_TYPE_NOTIFICATION, XA_NET_WM_WINDOW_TYPE_NORMAL; diff --git a/driver/atomswm.c b/driver/atomswm.c index 887dc2c3..1ddf47ad 100644 --- a/driver/atomswm.c +++ b/driver/atomswm.c @@ -43,6 +43,7 @@ xscreensaver_set_wm_atoms (Display *dpy, Window window, int width, int height, # endif Atom va[10]; long vl[10]; + int i; class_hints.res_name = "xscreensaver"; /* not progname */ class_hints.res_class = "XScreenSaver"; size_hints.flags = PMinSize | PMaxSize; @@ -73,22 +74,27 @@ xscreensaver_set_wm_atoms (Display *dpy, Window window, int width, int height, grubby paws off of our windows. */ - vl[0] = 1; /* _NET_WM_BYPASS_COMPOSITOR = 1 */ + i = 0; + vl[i++] = 1; /* _NET_WM_BYPASS_COMPOSITOR = 1 */ XChangeProperty (dpy, window, XA_NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32, - PropModeReplace, (unsigned char *) vl, 1); + PropModeReplace, (unsigned char *) vl, i); /* _NET_WM_STATE = [ _NET_WM_STATE_ABOVE, _NET_WM_STATE_FULLSCREEN ] */ - va[0] = XA_NET_WM_STATE_ABOVE; - va[1] = XA_NET_WM_STATE_FULLSCREEN; + i = 0; + va[i++] = XA_NET_WM_STATE_ABOVE; + va[i++] = XA_NET_WM_STATE_FULLSCREEN; + va[i++] = XA_NET_WM_STATE_STAYS_ON_TOP; /* Does this do anything? */ XChangeProperty (dpy, window, XA_NET_WM_STATE, XA_ATOM, 32, - PropModeReplace, (unsigned char *) va, 2); + PropModeReplace, (unsigned char *) va, i); /* As there is no _NET_WM_WINDOW_TYPE_SCREENSAVER, which property is most likely to effectively communicate "on top always" to the WM? _NET_WM_WINDOW_TYPE = NORMAL, SPLASH, DIALOG or NOTIFICATION? */ - va[0] = XA_NET_WM_WINDOW_TYPE_NOTIFICATION; + i = 0; + va[i++] = XA_NET_WM_WINDOW_TYPE_NOTIFICATION; + va[i++] = XA_KDE_NET_WM_WINDOW_TYPE_OVERRIDE; /* Does this do anything? */ XChangeProperty (dpy, window, XA_NET_WM_WINDOW_TYPE, XA_ATOM, 32, - PropModeReplace, (unsigned char *) va, 1); + PropModeReplace, (unsigned char *) va, i); if (for_window) /* This is the error dialog for a saver window */ { diff --git a/driver/demo-Gtk.c b/driver/demo-Gtk.c index b5e82e26..b94a8ce7 100644 --- a/driver/demo-Gtk.c +++ b/driver/demo-Gtk.c @@ -4407,7 +4407,7 @@ mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks, static Window -gnome_screensaver_window (Screen *screen) +gnome_screensaver_window (Screen *screen, char **name_ret) { Display *dpy = DisplayOfScreen (screen); Window root = RootWindowOfScreen (screen); @@ -4418,6 +4418,8 @@ gnome_screensaver_window (Screen *screen) if (! XQueryTree (dpy, root, &root, &parent, &kids, &nkids)) abort (); + if (name_ret) + *name_ret = 0; for (i = 0; i < nkids; i++) { Atom type; @@ -4434,6 +4436,8 @@ gnome_screensaver_window (Screen *screen) !strcmp ((char *) name, "cinnamon-screensaver"))) { gnome_window = kids[i]; + if (name_ret) + *name_ret = strdup ((char *) name); break; } } @@ -4443,10 +4447,10 @@ gnome_screensaver_window (Screen *screen) } static Bool -gnome_screensaver_active_p (void) +gnome_screensaver_active_p (char **name_ret) { Display *dpy = GDK_DISPLAY(); - Window w = gnome_screensaver_window (DefaultScreenOfDisplay (dpy)); + Window w = gnome_screensaver_window (DefaultScreenOfDisplay (dpy), name_ret); return (w ? True : False); } @@ -4454,13 +4458,18 @@ static void kill_gnome_screensaver (void) { Display *dpy = GDK_DISPLAY(); - Window w = gnome_screensaver_window (DefaultScreenOfDisplay (dpy)); + Window w = gnome_screensaver_window (DefaultScreenOfDisplay (dpy), NULL); if (w) XKillClient (dpy, (XID) w); } static Bool kde_screensaver_active_p (void) { + /* Apparently this worked in KDE 3, but not 4 or 5. + Maybe parsing the output of this would work in KDE 5: + kreadconfig5 --file kscreenlockerrc --group Daemon --key Autolock + but there's probably no way to kill the KDE saver. + Fuck it. */ FILE *p = popen ("dcop kdesktop KScreensaverIface isEnabled 2>/dev/null", "r"); char buf[255]; @@ -4491,6 +4500,7 @@ the_network_is_not_the_computer (state *s) char *rversion = 0, *ruser = 0, *rhost = 0; char *luser, *lhost; char *msg = 0; + char *oname = 0; struct passwd *p = getpwuid (getuid ()); const char *d = DisplayString (dpy); @@ -4608,14 +4618,18 @@ the_network_is_not_the_computer (state *s) 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 (gnome_screensaver_active_p (&oname)) + { + char msg [1024]; + sprintf (msg, + _("Warning:\n\n" + "The GNOME screen saver daemon (%s) appears to be running.\n" + "It must be stopped for XScreenSaver to work properly.\n" + "\n" + "Stop the \"%s\" daemon now?\n"), + oname, oname); + warning_dialog (s->toplevel_widget, msg, D_GNOME, 1); + } if (kde_screensaver_active_p ()) warning_dialog (s->toplevel_widget, @@ -4625,6 +4639,19 @@ the_network_is_not_the_computer (state *s) "\n" "Stop the KDE screen saver daemon now?\n"), D_KDE, 1); + + if (getenv ("WAYLAND_DISPLAY") || getenv ("WAYLAND_SOCKET")) + warning_dialog (s->toplevel_widget, + _("Warning:\n\n" + "You are running Wayland rather than the X Window System.\n" + "\n" + "Under Wayland, idle-detection fails when non-X11 programs\n" + "are selected, meaning the screen may blank prematurely.\n" + "Also, locking is impossible.\n" + "\n" + "See the XScreenSaver manual for instructions on\n" + "configuring your system to use X11 instead of Wayland.\n"), + D_NONE, 1); } diff --git a/driver/dialog.c b/driver/dialog.c index fce74c4d..e115cee0 100644 --- a/driver/dialog.c +++ b/driver/dialog.c @@ -180,6 +180,7 @@ struct window_state { int i_beam; double start_time, end_time; + int passwd_timeout; Bool show_stars_p; /* "I regret that I have but one asterisk for my country." -- Nathan Hale, 1776. */ @@ -733,43 +734,44 @@ splash_pick_window_position (Display *dpy, Position *xP, Position *yP) static void unlock_cb (window_state *ws); -/* This program only needs one option from the init file, so it - just reads the .ad file and the .xscreensaver file directly rather - than going through Xt and Xrm. +/* This program only needs a few options from .xscreensaver. + Read that file directly and store those into the Xrm database. */ -static void init_line_handler (int lineno, +static void init_line_handler (int lineno, const char *key, const char *val, void *closure) { window_state *ws = (window_state *) closure; - if (val && *val && !strcmp (key, "dialogTheme")) + if (!val || !*val) + ; + else if (!strcmp (key, "dialogTheme") || + !strcmp (key, "passwdTimeout")) { - if (ws->dialog_theme) free (ws->dialog_theme); - ws->dialog_theme = strdup (val); + XrmDatabase db = XtDatabase (ws->dpy); + char *key2 = (char *) malloc (strlen (progname) + strlen (val) + 10); + sprintf (key2, "%s.%s", progname, key); + XrmPutStringResource (&db, key2, val); + free (key2); } + /* We read additional resources, such as "PROGCLASS.THEME.Dialog.foreground", + but those are from the .ad file only, not from .xscreensaver, so they + don't need a clause here in the file parser. They have already been + read into the DB by Xt's Xrm initialization. */ } + static void read_init_file_simple (window_state *ws) { const char *home = getenv("HOME"); - const char *fn1 = AD_DIR "/XScreenSaver"; - char *fn2; + char *fn; if (!home || !*home) return; - fn2 = (char *) malloc (strlen(home) + 40); - sprintf (fn2, "%s/.xscreensaver", home); - - if (debug_p) - fprintf (stderr, "%s: reading %s\n", blurb(), fn1); - parse_init_file (fn1, init_line_handler, ws); - + fn = (char *) malloc (strlen(home) + 40); + sprintf (fn, "%s/.xscreensaver", home); if (debug_p) - fprintf (stderr, "%s: reading %s\n", blurb(), fn2); - parse_init_file (fn2, init_line_handler, ws); - - if (verbose_p) - fprintf (stderr, "%s: theme: %s\n", blurb(), - (ws->dialog_theme ? ws->dialog_theme : "none")); + fprintf (stderr, "%s: reading %s\n", blurb(), fn); + parse_init_file (fn, init_line_handler, ws); + free (fn); } @@ -921,15 +923,9 @@ window_init (Widget root_widget, Bool splash_p) ws->dpy = dpy; ws->screen = screen; ws->app = XtWidgetToApplicationContext (root_widget); - - /* Read default theme from resources before the init file. */ - ws->dialog_theme = - get_string_resource (ws->dpy, "dialogTheme", "DialogTheme"); - if (!ws->dialog_theme || !*ws->dialog_theme) - ws->dialog_theme = strdup ("default"); - - /* Read theme from init file before any other resources. */ - read_init_file_simple (ws); + ws->cmap = XCreateColormap (dpy, RootWindowOfScreen (screen), /* Old skool */ + DefaultVisualOfScreen (screen), + AllocNone); { struct passwd *p = getpwuid (getuid()); @@ -937,15 +933,25 @@ window_init (Widget root_widget, Bool splash_p) ws->user = p->pw_name; } - ws->cmap = XCreateColormap (dpy, RootWindowOfScreen (screen), /* Old skool */ - DefaultVisualOfScreen (screen), - AllocNone); + /* Read resources and .xscreensaver file settings. + */ + read_init_file_simple (ws); + + ws->dialog_theme = /* must be first */ + get_string_resource (ws->dpy, "dialogTheme", "DialogTheme"); + if (!ws->dialog_theme || !*ws->dialog_theme) + ws->dialog_theme = strdup ("default"); + if (verbose_p) + fprintf (stderr, "%s: theme: %s\n", blurb(), ws->dialog_theme); ws->newlogin_cmd = get_str (ws, "newLoginCommand", "NewLoginCommand"); ws->date_format = get_str (ws, "dateFormat", "DateFormat"); ws->show_stars_p = get_boolean_resource (ws->dpy, "passwd.asterisks", "Passwd.Boolean"); + ws->passwd_timeout = get_seconds_resource (ws->dpy, "passwdTimeout", "Time"); + if (ws->passwd_timeout <= 5) ws->passwd_timeout = 5; + /* Put the version number in the label. */ { char *version = strdup (screensaver_id + 17); @@ -1234,8 +1240,6 @@ window_draw (window_state *ws) char date_text[100]; time_t now = time ((time_t *) 0); struct tm *tm = localtime (&now); - double ratio = 1 - ((double_time() - ws->start_time) / - (ws->end_time - ws->start_time)); dialog_line *lines = (dialog_line *) calloc (ws->nmsgs + 40, sizeof(*lines)); Bool emitted_user_p = False; @@ -1536,10 +1540,12 @@ window_draw (window_state *ws) { if (ws->auth_state != AUTH_NOTIFY) { + double remain = ws->end_time - double_time(); + double ratio = remain / ws->passwd_timeout; int thermo_w = ws->thermo_width; int thermo_h = window_height - ext_border * 2; int thermo_h2 = thermo_h - ws->shadow_width * 2; - int thermo_h3 = thermo_h2 * (1.0 - ratio); + int thermo_h3 = thermo_h2 * (1.0 - (ratio > 1 ? 1 : ratio)); XSetForeground (dpy, gc, ws->thermo_foreground); XFillRectangle (dpy, dbuf, gc, @@ -1914,15 +1920,13 @@ handle_keypress (window_state *ws, XKeyEvent *event) /* Add 10% to the time remaining every time a key is pressed, but don't go past the max duration. */ { - time_t now = time ((time_t *) 0); - int max = get_seconds_resource (ws->dpy, "passwdTimeout", "Time"); - int remain = ws->end_time - now; + double now = double_time(); + double remain = ws->end_time - now; remain *= 1.1; - if (remain > max) remain = max; + if (remain > ws->passwd_timeout) remain = ws->passwd_timeout; if (remain < 3) remain = 3; ws->end_time = now + remain; } - if (decoded_size == 1) /* Handle single-char commands */ { @@ -2121,8 +2125,7 @@ gui_main_loop (window_state *ws, Bool splash_p, Bool notification_p) timeout = 5; else { - timeout = get_seconds_resource (ws->dpy, "passwdTimeout", "Time"); - if (timeout <= 5) timeout = 5; + timeout = ws->passwd_timeout; cursor_timer (ws, 0); } diff --git a/driver/dpms.c b/driver/dpms.c index 15721eae..18a59b62 100644 --- a/driver/dpms.c +++ b/driver/dpms.c @@ -20,17 +20,59 @@ #include "xscreensaver.h" +/* Disable the X11 built-in screen saver. This is not directly related + to DPMS, but it does need to be prevented from fighting with us. + */ +static void +disable_builtin_saver (Display *dpy) +{ + int otimeout = -1; + int ointerval = -1; + int oblanking = -1; + int oexposures = -1; + XGetScreenSaver (dpy, &otimeout, &ointerval, &oblanking, &oexposures); + if (otimeout == 0 && ointerval == 0 && oblanking == 0 && oexposures == 0) + { + if (verbose_p > 1) + fprintf (stderr, "%s: builtin saver already disabled\n", blurb()); + } + else + { + if (verbose_p) + fprintf (stderr, "%s: disabling server's builtin saver\n", blurb()); + XSetScreenSaver (dpy, 0, 0, 0, 0); + XForceScreenSaver (dpy, ScreenSaverReset); + } +} + + #ifndef HAVE_DPMS_EXTENSION /* almost the whole file */ void sync_server_dpms_settings (Display *dpy, struct saver_preferences *p) { + disable_builtin_saver (dpy); if (p->verbose_p) fprintf (stderr, "%s: DPMS not supported at compile time\n", blurb()); } -Bool monitor_powered_on_p (Display *dpy) { return True; } -void monitor_power_on (saver_info *si, Bool on_p) { return; } +Bool monitor_powered_on_p (Display *dpy) +{ + if (verbose_p > 1) + fprintf (stderr, + "%s: DPMS disabled at compile time, assuming monitor on\n", + blurb()); + return True; +} + +void monitor_power_on (saver_info *si, Bool on_p) +{ + if (verbose_p > 1) + fprintf (stderr, + "%s: DPMS disabled at compile time, not turning monitor %s\n", + blurb(), (on ? "on" : "off")); + return; +} #else /* HAVE_DPMS_EXTENSION -- whole file */ @@ -68,12 +110,13 @@ sync_server_dpms_settings (Display *dpy, struct saver_preferences *p) /* If the monitor is currently powered off, defer any changes until we are next called while it is powered on. */ if (! monitor_powered_on_p (dpy)) - return; + { + if (verbose_p > 1) + fprintf (stderr, "%s: DPMS: monitor off, skipping sync\n", blurb()); + return; + } - /* Why did I do this? It makes DPMS never happen. - XSetScreenSaver (dpy, 0, 0, 0, 0); - XForceScreenSaver (dpy, ScreenSaverReset); - */ + disable_builtin_saver (dpy); if (dpms_quickoff_p && !off_secs) { @@ -102,7 +145,7 @@ sync_server_dpms_settings (Display *dpy, struct saver_preferences *p) if (! DPMSQueryExtension (dpy, &event, &error)) { - if (verbose_p && !warned_p) + if (verbose_p > 1 || (verbose_p && !warned_p)) fprintf (stderr, "%s: XDPMS extension not supported\n", blurb()); warned_p = True; return; @@ -110,7 +153,7 @@ sync_server_dpms_settings (Display *dpy, struct saver_preferences *p) if (! DPMSCapable (dpy)) { - if (verbose_p && !warned_p) + if (verbose_p > 1 || (verbose_p && !warned_p)) fprintf (stderr, "%s: DPMS not supported\n", blurb()); warned_p = True; return; @@ -118,7 +161,7 @@ sync_server_dpms_settings (Display *dpy, struct saver_preferences *p) if (! DPMSInfo (dpy, &o_power, &o_enabled)) { - if (verbose_p && !warned_p) + if (verbose_p > 1 || (verbose_p && !warned_p)) fprintf (stderr, "%s: unable to get DPMS state\n", blurb()); warned_p = True; return; @@ -167,6 +210,9 @@ sync_server_dpms_settings (Display *dpy, struct saver_preferences *p) fprintf (stderr, "%s: set DPMS timeouts: %d %d %d\n", blurb(), standby_secs, suspend_secs, off_secs); } + else if (verbose_p > 1) + fprintf (stderr, "%s: DPMS timeouts already %d %d %d\n", blurb(), + o_standby, o_suspend, o_off); } Bool @@ -178,19 +224,34 @@ monitor_powered_on_p (Display *dpy) CARD16 state; if (!DPMSQueryExtension(dpy, &event_number, &error_number)) - /* Server doesn't know -- assume the monitor is on. */ - result = True; + { + /* Server doesn't know -- assume the monitor is on. */ + if (verbose_p > 1) + fprintf (stderr, "%s: DPMSQueryExtension failed, assuming monitor on\n", + blurb()); + result = True; + } else if (!DPMSCapable(dpy)) - /* Server says the monitor doesn't do power management -- so it's on. */ - result = True; + { + /* Server says the monitor doesn't do power management -- so it's on. */ + if (verbose_p > 1) + fprintf (stderr, "%s: DPMSCapable false; assuming monitor on\n", + blurb()); + result = True; + } else { DPMSInfo(dpy, &state, &onoff); if (!onoff) - /* Server says DPMS is disabled -- so the monitor is on. */ - result = True; + { + /* Server says DPMS is disabled -- so the monitor is on. */ + if (verbose_p > 1) + fprintf (stderr, "%s: DPMSInfo disabled; assuming monitor on\n", + blurb()); + result = True; + } else switch (state) { case DPMSModeOn: result = True; break; /* really on */ @@ -199,6 +260,13 @@ monitor_powered_on_p (Display *dpy) case DPMSModeOff: result = False; break; /* really off */ default: result = True; break; /* protocol error? */ } + if (verbose_p > 1) + fprintf (stderr, "%s: DPMSInfo = %s %s\n", blurb(), + (state == DPMSModeOn ? "DPMSModeOn" : + state == DPMSModeStandby ? "DPMSModeStandby" : + state == DPMSModeSuspend ? "DPMSModeSuspend" : + state == DPMSModeOff ? "DPMSModeOff" : "???"), + (result ? "True" : "False")); } return result; @@ -207,6 +275,7 @@ monitor_powered_on_p (Display *dpy) void monitor_power_on (saver_info *si, Bool on_p) { + Bool verbose_p = si->prefs.verbose_p; if ((!!on_p) != monitor_powered_on_p (si->dpy)) { XErrorHandler old_handler; @@ -215,7 +284,7 @@ monitor_power_on (saver_info *si, Bool on_p) if (!DPMSQueryExtension(si->dpy, &event_number, &error_number) || !DPMSCapable(si->dpy)) { - if (si->prefs.verbose_p && !warned_p) + if (verbose_p > 1 || (verbose_p && !warned_p)) fprintf (stderr, "%s: unable to power %s monitor: no DPMS extension\n", blurb(), (on_p ? "on" : "off")); @@ -243,12 +312,18 @@ monitor_power_on (saver_info *si, Bool on_p) XSetErrorHandler (old_handler); /* Ignore error_handler_hit_p, just probe monitor instead */ + if (verbose_p > 1 && error_handler_hit_p) + fprintf (stderr, "%s: DPMSForceLevel got an X11 error\n", blurb()); + if ((!!on_p) != monitor_powered_on_p (si->dpy)) /* double-check */ fprintf (stderr, "%s: DPMSForceLevel(dpy, %s) did not change monitor power state\n", blurb(), (on_p ? "DPMSModeOn" : "DPMSModeOff")); } + else if (verbose_p > 1) + fprintf (stderr, "%s: monitor is already %s\n", blurb(), + on_p ? "on" : "off"); } #endif /* HAVE_DPMS_EXTENSION -- whole file */ diff --git a/driver/exts.c b/driver/exts.c index 641325d3..ffc2d1a1 100644 --- a/driver/exts.c +++ b/driver/exts.c @@ -190,8 +190,13 @@ print_available_extensions (saver_info *si) # ifdef HAVE_LIBSYSTEMD fprintf (stderr, "%s: libsystemd\n", blurb()); -# else - fprintf (stderr, "%s: libsystemd (disabled at compile time)\n", blurb()); +# endif +# ifdef HAVE_LIBELOGIND + fprintf (stderr, "%s: libelogind\n", blurb()); +# endif +# if !defined(HAVE_LIBSYSTEMD) && !defined(HAVE_LIBELOGIND) + fprintf (stderr, "%s: libsystemd/libelogind (disabled at compile time)\n", + blurb()); # endif for (i = 0; i < si->nscreens; i++) diff --git a/driver/fade.c b/driver/fade.c index 94515827..4a2d3bc6 100644 --- a/driver/fade.c +++ b/driver/fade.c @@ -294,6 +294,46 @@ ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error) } +/* Like XDestroyWindow, but destroys the window later, on a timer. This is + necessary to work around a KDE 5 compositor bug. Without this, destroying + an old window causes the desktop to briefly become visible, even though a + new window has already been mapped that is obscuring both of them! + */ +typedef struct { + XtAppContext app; + Display *dpy; + Window window; +} defer_destroy_closure; + +static void +defer_destroy_handler (XtPointer closure, XtIntervalId *id) +{ + defer_destroy_closure *c = (defer_destroy_closure *) closure; + XErrorHandler old_handler; + XSync (c->dpy, False); + error_handler_hit_p = False; + old_handler = XSetErrorHandler (ignore_all_errors_ehandler); + XDestroyWindow (c->dpy, c->window); + XSync (c->dpy, False); + XSetErrorHandler (old_handler); + if (verbose_p > 1 && !error_handler_hit_p) + fprintf (stderr, "%s: destroyed old window 0x%lx\n", + blurb(), (unsigned long) c->window); + free (c); +} + +/* Used here and in windows.c */ +void +defer_XDestroyWindow (XtAppContext app, Display *dpy, Window w) +{ + defer_destroy_closure *c = (defer_destroy_closure *) malloc (sizeof (*c)); + c->app = app; + c->dpy = dpy; + c->window = w; + XtAppAddTimeOut (app, 5 * 1000, defer_destroy_handler, (XtPointer) c); +} + + /* Returns true if canceled by user activity. */ Bool fade_screens (XtAppContext app, Display *dpy, @@ -1659,8 +1699,10 @@ xshm_fade (XtAppContext app, Display *dpy, { XClearWindow (dpy, saver_windows[screen]); XMapRaised (dpy, saver_windows[screen]); - if (info[screen].window) - XUnmapWindow (dpy, info[screen].window); + /* Doing this here triggers the same KDE 5 compositor bug that + defer_XDestroyWindow is to work around. */ + /* if (info[screen].window) + XUnmapWindow (dpy, info[screen].window); */ } } @@ -1688,7 +1730,7 @@ xshm_fade (XtAppContext app, Display *dpy, if (info[screen].intermediate) destroy_xshm_image (dpy, info[screen].intermediate, &shm_info); if (info[screen].window) - XDestroyWindow (dpy, info[screen].window); + defer_XDestroyWindow (app, dpy, info[screen].window); if (info[screen].gc) XFreeGC (dpy, info[screen].gc); } diff --git a/driver/fade.h b/driver/fade.h index 56725b59..6c62d33e 100644 --- a/driver/fade.h +++ b/driver/fade.h @@ -17,4 +17,12 @@ extern Bool fade_screens (XtAppContext app, Display *dpy, Window *black_windows, int nwindows, double seconds, Bool out_p, Bool from_desktop_p, void **closureP); + +/* Like XDestroyWindow, but destroys the window later, on a timer. This is + necessary to work around a KDE 5 compositor bug. Without this, destroying + an old window causes the desktop to briefly become visible, even though a + new window has already been mapped that is obscuring both of them! + */ +extern void defer_XDestroyWindow (XtAppContext, Display *, Window); + #endif /* __FADE_H__ */ diff --git a/driver/screens.c b/driver/screens.c index dc87e51c..1e90b97e 100644 --- a/driver/screens.c +++ b/driver/screens.c @@ -27,7 +27,7 @@ * 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. + * restarting X. Sometimes this mode is referred to as "ZaphodHeads". * * Everyone hates this way of doing things because of the inability to * move a window from one screen to another without restarting the @@ -43,7 +43,7 @@ * middle of the screen actually spanning the gap between two * monitors.) * - * Xinerama didn't? work with DRI, which means that Xinerama precluded + * Xinerama didn't work with DRI, which means that Xinerama precluded * hardware acceleration in OpenGL programs. Also, screens couldn't * be resized or moved without restarting X. * @@ -51,14 +51,14 @@ * * No longer supported as of XScreenSaver 6. * - * 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 was also a hot-key for - * changing the monitor's resolution (zooming in/out). + * With this extension, the root window could be bigger than the + * monitor. Moving the mouse near the edges of the screen would + * scroll around, like a pan-and-scan movie. There was also a + * hot-key for changing the monitor's resolution (zooming in/out). * - * Trying to combine this with Xinerama crashes the server, so you - * could only use this if you had only a single screen, or were in old - * multi-screen mode. + * Trying to combine this with Xinerama crashed the server, so you + * could ONLY use this if you had only a single screen, or were in + * old multi-screen mode. * * Also, half the time it didn't work at all: it tended to lie about * the size of the rectangle in use. diff --git a/driver/test-xinput.c b/driver/test-xinput.c index e3a64874..eea707cf 100644 --- a/driver/test-xinput.c +++ b/driver/test-xinput.c @@ -73,8 +73,8 @@ main (int argc, char **argv) int xi_opcode; Bool grab_kbd_p = False; Bool grab_mouse_p = False; - Bool mouse_sync_p = True; - Bool kbd_sync_p = True; + Bool mouse_sync_p = False; + Bool kbd_sync_p = False; int i; progname = argv[0]; diff --git a/driver/windows.c b/driver/windows.c index c9cdf9d2..0152c96d 100644 --- a/driver/windows.c +++ b/driver/windows.c @@ -218,7 +218,7 @@ initialize_screensaver_window_1 (saver_screen_info *ssi) if (ssi->error_dialog) { - XDestroyWindow (si->dpy, ssi->error_dialog); + defer_XDestroyWindow (si->app, si->dpy, ssi->error_dialog); ssi->error_dialog = 0; } @@ -260,7 +260,7 @@ initialize_screensaver_window_1 (saver_screen_info *ssi) fprintf (stderr, "%s: someone horked our saver window (0x%lx)! Recreating it...\n", blurb(), (unsigned long) horked_window); - XDestroyWindow (si->dpy, horked_window); + defer_XDestroyWindow (si->app, si->dpy, horked_window); } if (p->verbose_p > 1) @@ -687,7 +687,7 @@ select_visual (saver_screen_info *ssi, const char *visual_name) raise_window (ssi); /* Now we can destroy the old window without horking our grabs. */ - XDestroyWindow (si->dpy, old_w); + defer_XDestroyWindow (si->app, si->dpy, old_w); if (p->verbose_p > 1) fprintf (stderr, "%s: %d: destroyed old saver window 0x%lx\n", @@ -814,7 +814,7 @@ cycle_timer (XtPointer closure, XtIntervalId *id) if (ssi->error_dialog) { - XDestroyWindow (si->dpy, ssi->error_dialog); + defer_XDestroyWindow (si->app, si->dpy, ssi->error_dialog); ssi->error_dialog = 0; } @@ -884,7 +884,7 @@ screenhack_obituary (saver_screen_info *ssi, */ cmap = ssi->cmap ? ssi->cmap : DefaultColormapOfScreen (ssi->screen); window = ssi->error_dialog; - if (window) XDestroyWindow (si->dpy, window); + if (window) defer_XDestroyWindow (si->app, si->dpy, window); attrs.override_redirect = True; attrs.background_pixel = ssi->black_pixel; attrs.border_pixel = ssi->black_pixel; diff --git a/driver/xinput.c b/driver/xinput.c index 3b21db02..c9e8b91e 100644 --- a/driver/xinput.c +++ b/driver/xinput.c @@ -117,11 +117,62 @@ init_xinput (Display *dpy, int *opcode_ret) } +/* If there is more than one Screen on the Display, XInput2 sends a duplicate + event for each Screen. You'd think that they would have the 'root' member + set to the root window of that screen, so that we could ignore events not + destined for our screen, but no, they all have the same root window. But + they also have the same 'serial' and 'time', so (in theory) we can ignore + the duplicates by noticing recently-duplicated event serial numbers, which + ought never happen. BUT...! + */ +static Bool +duplicate_xinput_event_p (int evtype, XIDeviceEvent *in) +{ + static unsigned long dups[50] = { 0, }; + int i; + + /* Great news, everybody: XEvent.xany.serial is apparently not unique. Wny? + Because fuck you that's why. XtAppNextEvent is returning a RawKeyRelease + followed by a RawKeyPress with the same serial. It doesn't happen every + time, but seems to happen most often if a second key goes down before the + first key is released, e.g., which often happens when typing fast. + + I have not seen it duplicating serials between two different KeyPress + events, but I have seen it being duplicated between a KeyPress and a + non-corresponding KeyRelease event; and between two different KeyRelease + events. It does this even when there is only one Screen. + + So we must compare both 'serial' and 'type' when looking for duplicates. + This should be ok if it really does not duplicate serials between + unrelated KeyPress events. And we ignore KeyRelease events, so what + happens with those doesn't matter. + + Between this shit and the random noise that shows up in XIDeviceEvent, + I'm starting to suspect that maybe, just maybe, the XInput2 library is + extremely careless about memory management! + */ + unsigned long key = (in->serial & 0xFFFF) | (evtype << 16); + + for (i = 0; i < countof(dups); i++) + if (dups[i] == key) + { + if (debug_p) + fprintf (stderr, "%s: discard duplicate XInput event %08lx\n", + blurb(), key); + return True; + } + for (i = 0; i < countof(dups)-1; i++) + dups[i] = dups[i+1]; + dups[i] = key; + return False; +} + + /* Convert an XInput2 event to corresponding old-school Xlib event. Returns true on success. */ -Bool -xinput_event_to_xlib (int evtype, XIDeviceEvent *in, XEvent *out) +static Bool +xinput_event_to_xlib_1 (int evtype, XIDeviceEvent *in, XEvent *out) { Display *dpy = in->display; Bool ok = False; @@ -228,6 +279,16 @@ xinput_event_to_xlib (int evtype, XIDeviceEvent *in, XEvent *out) return ok; } +Bool +xinput_event_to_xlib (int evtype, XIDeviceEvent *in, XEvent *out) +{ + Bool ok = xinput_event_to_xlib_1 (evtype, in, out); + if (ok && duplicate_xinput_event_p (evtype, in)) + ok = False; + return ok; +} + + static void print_kbd_event (XEvent *xev, XComposeStatus *compose, Bool x11_p) @@ -321,9 +382,9 @@ print_xinput_event (Display *dpy, XEvent *xev, const char *desc) { /* Fake up an XKeyEvent in order to call XKeysymToString(). */ XEvent ev2; - Bool ok = xinput_event_to_xlib (xev->xcookie.evtype, - (XIDeviceEvent *) re, - &ev2); + Bool ok = xinput_event_to_xlib_1 (re->evtype, + (XIDeviceEvent *) re, + &ev2); if (!ok) fprintf (stderr, "%s: unable to translate XInput2 event\n", blurb()); else diff --git a/driver/xscreensaver-settings.man b/driver/xscreensaver-settings.man index 6b9657d6..df2798d8 100644 --- a/driver/xscreensaver-settings.man +++ b/driver/xscreensaver-settings.man @@ -315,16 +315,13 @@ the screen will be powered off when black. .B Blanking These options control how the screen fades to or from black when -a screen saver begins or ends. Note: fading doesn't work with all -video drivers. -In particular, it does not work on the 2020-vintage Raspberry Pi. +a screen saver begins or ends. .RS 4 .TP 4 .B Fade To Black When Blanking If selected, then when the screensaver activates, the current contents -of the screen will fade to black instead of simply winking out. A fade -will also be done when switching from one display mode to another. +of the screen will fade to black instead of simply winking out. .TP 4 .B Unfade From Black When Unblanking diff --git a/driver/xscreensaver-systemd.c b/driver/xscreensaver-systemd.c index d06174a1..2a5a11ff 100644 --- a/driver/xscreensaver-systemd.c +++ b/driver/xscreensaver-systemd.c @@ -228,8 +228,19 @@ * I'm told that the proprietary Zoom executable for Linux sends "inhibit" * to "org.freedesktop.ScreenSaver", but I don't have any further details. * + * + ***************************************************************************** + * + * Steam: + * + * Inhibits as "My SDL application" (ooh, "Baby's First Hello World", + * nice! You get a gold star sticker) and then 30 seconds later, + * uninhibits and immediately re-inhibits, forever. This works, but + * is dumb. + * ***************************************************************************** * + * * TO DO: * * - What precisely does the standalone Zoom executable do on Linux? @@ -294,7 +305,13 @@ #include #include -#include +#if defined (HAVE_LIBSYSTEMD) +# include +#elif defined (HAVE_LIBELOGIND) +# include +#else +# error Neither HAVE_LIBSYSTEMD nor HAVE_LIBELOGIND is defined. +#endif #include "version.h" #include "blurb.h" @@ -797,7 +814,7 @@ xscreensaver_systemd_loop (void) */ while (1) { struct pollfd fds[3]; - uint64_t poll_timeout, system_timeout, user_timeout; + uint64_t poll_timeout_msec, system_timeout_usec, user_timeout_usec; struct inhibit_entry *entry; /* We MUST call sd_bus_process() on each bus at least once before calling @@ -821,32 +838,6 @@ xscreensaver_systemd_loop (void) } } while (rc > 0); - fds[0].fd = sd_bus_get_fd (system_bus); - fds[0].events = sd_bus_get_events (system_bus); - fds[0].revents = 0; - - fds[1].fd = sd_bus_get_fd (user_bus); - fds[1].events = sd_bus_get_events (user_bus); - fds[1].revents = 0; - - fds[2].fd = XConnectionNumber (dpy); - fds[2].events = POLLIN; - fds[2].revents = 0; - - - sd_bus_get_timeout (system_bus, &system_timeout); - sd_bus_get_timeout (user_bus, &user_timeout); - - if (system_timeout == 0 && user_timeout == 0) - poll_timeout = 0; - else if (system_timeout == UINT64_MAX && user_timeout == UINT64_MAX) - poll_timeout = -1; - else { - poll_timeout = (system_timeout < user_timeout - ? system_timeout : user_timeout); - poll_timeout /= 1000000; - } - /* Prune any entries whose original sender has gone away: this happens if a program inhibits, then exits without having called uninhibit. That would have left us inhibited forever, even if the inhibiting @@ -873,24 +864,8 @@ xscreensaver_systemd_loop (void) } } - - /* We want to wake up at least once every N seconds to de-activate - the screensaver if we have been inhibited. - */ - if (poll_timeout > HEARTBEAT_INTERVAL * 1000) - poll_timeout = HEARTBEAT_INTERVAL * 1000; - - rc = poll (fds, 3, poll_timeout); - if (rc < 0) { - fprintf (stderr, "%s: poll failed: %s\n", blurb(), strerror(-rc)); - exit (EXIT_FAILURE); - } - - if (fds[2].revents & (POLLERR | POLLHUP | POLLNVAL)) { - fprintf (stderr, "%s: X connection closed\n", blurb()); - goto FAIL; - } - + /* If we are inhibited and HEARTBEAT_INTERVAL has passed, de-activate the + screensaver. */ if (ctx->is_inhibited) { time_t now = time ((time_t *) 0); if (now - last_deactivate_time >= HEARTBEAT_INTERVAL) { @@ -906,11 +881,99 @@ xscreensaver_systemd_loop (void) last_deactivate_time = now; } } - } - FAIL: + /* The remainder of the code that follows is concerned solely with + determining how long we should wait until the next iteration of the + event loop. + */ + rc = sd_bus_get_fd (system_bus); + if (rc < 0) { + fprintf (stderr, "%s: sd_bus_get_fd failed for system bus: %s\n", + blurb(), strerror(-rc)); + goto FAIL; + } + fds[0].fd = rc; + rc = sd_bus_get_events (system_bus); + if (rc < 0) { + fprintf (stderr, "%s: sd_bus_get_events failed for system bus: %s\n", + blurb(), strerror(-rc)); + goto FAIL; + } + fds[0].events = rc; + fds[0].revents = 0; - XCloseDisplay(dpy); + rc = sd_bus_get_fd (user_bus); + if (rc < 0) { + fprintf (stderr, "%s: sd_bus_get_fd failed for user bus: %s\n", + blurb(), strerror(-rc)); + goto FAIL; + } + fds[1].fd = rc; + rc = sd_bus_get_events (user_bus); + if (rc < 0) { + fprintf (stderr, "%s: sd_bus_get_events failed for user bus: %s\n", + blurb(), strerror(-rc)); + goto FAIL; + } + fds[1].events = rc; + fds[1].revents = 0; + + /* Activity on the X server connection will wake us from the poll(). */ + fds[2].fd = XConnectionNumber (dpy); + fds[2].events = POLLIN; + fds[2].revents = 0; + + rc = sd_bus_get_timeout (system_bus, &system_timeout_usec); + if (rc < 0) { + fprintf (stderr, "%s: sd_bus_get_timeout failed for system bus: %s\n", + blurb(), strerror(-rc)); + goto FAIL; + } + sd_bus_get_timeout (user_bus, &user_timeout_usec); + if (rc < 0) { + fprintf (stderr, "%s: sd_bus_get_timeout failed for user bus: %s\n", + blurb(), strerror(-rc)); + goto FAIL; + } + + /* Pick the smaller of the two bus timeouts and convert from microseconds + to milliseconds expected by poll(). */ + poll_timeout_msec = ((system_timeout_usec < user_timeout_usec + ? system_timeout_usec : user_timeout_usec) + / 1000); + + /* If we have been inhibited, we want to wake up at least once every N + seconds to de-activate the screensaver. + */ + if (ctx->is_inhibited && + poll_timeout_msec > HEARTBEAT_INTERVAL * 1000) + poll_timeout_msec = HEARTBEAT_INTERVAL * 1000; + + if (poll_timeout_msec < 1000) + poll_timeout_msec = 1000; + + rc = poll (fds, 3, poll_timeout_msec); + if (rc < 0) { + fprintf (stderr, "%s: poll failed: %s\n", blurb(), strerror(errno)); + goto FAIL; + } + + if (fds[2].revents & (POLLERR | POLLHUP | POLLNVAL)) { + fprintf (stderr, "%s: X connection closed\n", blurb()); + dpy = 0; + goto FAIL; + } else if (fds[2].revents & POLLIN) { + /* Even though we have requested no events, there are some events that + the X server sends anyway, e.g. MappingNotify, and if we don't flush + the fd, it will constantly be ready for reading, and we busy-loop. */ + char buf[1024]; + while (read (fds[2].fd, buf, sizeof(buf)) > 0) + ; + } + + } /* Event loop end */ + + FAIL: if (system_bus) sd_bus_flush_close_unref (system_bus); @@ -923,6 +986,9 @@ xscreensaver_systemd_loop (void) sd_bus_error_free (&error); + if (dpy) + XCloseDisplay (dpy); + return EXIT_FAILURE; } diff --git a/driver/xscreensaver.c b/driver/xscreensaver.c index 5eb71674..bfce5f73 100644 --- a/driver/xscreensaver.c +++ b/driver/xscreensaver.c @@ -456,8 +456,10 @@ handle_sigchld (Display *dpy, Bool blanked_p) int ac = 0; av[ac++] = SAVER_GFX_PROGRAM; av[ac++] = "--emergency"; - if (verbose_p) av[ac++] = "--verbose"; - if (debug_p) av[ac++] = "--debug"; + if (verbose_p) av[ac++] = "--verbose"; + if (verbose_p > 1) av[ac++] = "--verbose"; + if (verbose_p > 2) av[ac++] = "--verbose"; + if (debug_p) av[ac++] = "--debug"; av[ac] = 0; fprintf (stderr, "%s: pid %lu: " SAVER_GFX_PROGRAM " exited unexpectedly %s: re-launching\n", @@ -1304,6 +1306,8 @@ static void maybe_disable_locking (Display *dpy) { const char *why = 0; + Bool wayland_p = (getenv ("WAYLAND_DISPLAY") || + getenv ("WAYLAND_SOCKET")); # ifdef NO_LOCKING why = "locking disabled at compile time"; @@ -1322,7 +1326,7 @@ maybe_disable_locking (Display *dpy) /* X11 grabs don't work under Wayland's embedded X11 server. The Wayland window manager lives at a higher level than the X11 emulation layer. */ - if (!why && getenv ("WAYLAND_DISPLAY")) + if (!why && wayland_p) why = "cannot lock securely under Wayland"; if (!why) @@ -1344,6 +1348,25 @@ maybe_disable_locking (Display *dpy) fprintf (stderr, "%s: DEBUG MODE: allowing locking anyway!\n", blurb()); } + else if (wayland_p) + { + const char *s = blurb(); + locking_disabled_p = True; + + /* Maybe we should just refuse to launch instead? We can operate + properly only if the user uses only X11 programs, and doesn't + want to lock the screen. + */ + fprintf (stderr, "\n" + "%s: WARNING: Wayland is not supported.\n" + "\n" + "%s: Under Wayland, idle-detection fails when non-X11\n" + "%s: programs are selected, meaning the screen may\n" + "%s: blank prematurely. Also, locking is impossible.\n" + "%s: See the manual for instructions on configuring\n" + "%s: your system to use X11 instead of Wayland.\n\n", + s, s, s, s, s, s); + } else { locking_disabled_p = True; @@ -1377,6 +1400,14 @@ main_loop (Display *dpy) if (! init_xinput (dpy, &xi_opcode)) saver_exit (1); + /* Disable server built-in screen saver. */ + XSetScreenSaver (dpy, 0, 0, 0, 0); + XForceScreenSaver (dpy, ScreenSaverReset); + + /* It would be nice to sync the server's DPMS settings here to what is + specified in the .xscreensaver file, but xscreensaver-gfx handles that, + so that won't happen until the first time the screen blanks. */ + create_daemon_window (dpy); handle_signals(); @@ -1402,7 +1433,7 @@ main_loop (Display *dpy) saver_auth_pid = fork_and_exec (dpy, ac, av); } -# ifdef HAVE_LIBSYSTEMD +# if defined(HAVE_LIBSYSTEMD) || defined(HAVE_LIBELOGIND) /* Launch xscreensaver-systemd at startup. */ { char *av[10]; @@ -1413,7 +1444,7 @@ main_loop (Display *dpy) av[ac] = 0; saver_systemd_pid = fork_and_exec (dpy, ac, av); } -# endif /* HAVE_LIBSYSTEMD */ +# endif /* HAVE_LIBSYSTEMD || HAVE_LIBELOGIND */ /* X11 errors during startup initialization were fatal. @@ -1930,9 +1961,11 @@ main_loop (Display *dpy) char *av[20]; int ac = 0; av[ac++] = SAVER_GFX_PROGRAM; - if (first_time_p) av[ac++] = "--init"; - if (verbose_p) av[ac++] = "--verbose"; - if (debug_p) av[ac++] = "--debug"; + if (first_time_p) av[ac++] = "--init"; + if (verbose_p) av[ac++] = "--verbose"; + if (verbose_p > 1) av[ac++] = "--verbose"; + if (verbose_p > 2) av[ac++] = "--verbose"; + if (debug_p) av[ac++] = "--debug"; if (blank_mode == XA_NEXT) av[ac++] = "--next"; diff --git a/driver/xscreensaver.man b/driver/xscreensaver.man index 9c3bdd0d..ff4a67b7 100644 --- a/driver/xscreensaver.man +++ b/driver/xscreensaver.man @@ -86,7 +86,7 @@ then closing the lid of your laptop will cause the screen to lock immediately. If not, then the screen might not lock until a few seconds \fIafter\fP you re-open the lid. Which is less than ideal. So if you don't use \fIsystemd\fP, you might want to get in the habit of -doing \fIxscreensaver-command --lock\fP before closing the lid. +doing \fIxscreensaver-command \-\-lock\fP before closing the lid. .SH PLAYING VIDEOS Likewise, if you have @@ -146,10 +146,7 @@ Be careful that it doesn't try to uninstall all of GNOME. Select "\fIStartup Applications\fP" from the menu (or manually launch "\fIgnome-session-properties\fP") and add "\fIxscreensaver\fP". - Do this as your normal user account, not as root. -(This should go without saying, because you should never, ever, ever -be logged in to the graphical desktop as user "root".) .TP 3 \fB3: Make GNOME's "Lock Screen" use XScreenSaver.\fP .nf @@ -158,12 +155,6 @@ be logged in to the graphical desktop as user "root".) /usr/bin/gnome-screensaver-command .sp .fi -That doesn't work under Unity, though. Apparently it has its own -built-in screen locker which is not gnome-screensaver, and cannot be -removed, and yet still manages to be bug-addled and insecure. -Keep reinventing that wheel, guys! (If you have figured out how to -replace Unity's locking "feature" with XScreenSaver, let me know.) - .TP 3 \fB4: Turn off Unity's built-in blanking.\fP @@ -173,6 +164,7 @@ Un-check "\fIStart Automatically\fP"; .br Set \fI"Turn screen off when inactive for"\fP to \fI"Never".\fP .br + Or possibly that has been randomly renamed again: .br Set "\fISettings / Power / Power Settings\fP" to \fI"Never".\fP @@ -181,13 +173,15 @@ Set "\fISettings / Power / Power Settings\fP" to \fI"Never".\fP .nf .sp sudo systemctl \-\-user mask gsd\-screensaver\-proxy.service + sudo systemctl \-\-user mask \\ + org.gnome.SettingsDaemon.ScreensaverProxy.service .sp .fi Without the above, video players will not be able to tell XScreenSaver not to blank the screen while videos are playing, and the screen will not auto-lock when you close your laptop's lid. -After running that command, reboot. Yes, you have to reboot; it won't let +After running those commands, reboot. Yes, you have to reboot; it won't let you simply stop the service. Logging out won't do it either. .SS INSTALLING XSCREENSAVER ON KDE @@ -217,7 +211,7 @@ If that doesn't work, then try this: Open "\fISystem Settings / Startup/Shutdown / Autostart\fP", and then add "\fI/usr/bin/xscreensaver\fP". -If you are lucky, that will create a \fI"xscreensaver.desktop"\fP file +If you are lucky, that will create an \fI"xscreensaver.desktop"\fP file for you in \fI~/.config/autostart/\fP or \fI~/.kde/Autostart/\fP. .TP 3 \fB3: Make XScreenSaver be an Autostart program.\fP @@ -250,16 +244,22 @@ of that file with these two lines: .sp .fi Make sure the file is executable (chmod a+x). + +This change will probably get blown away the next time your system +upgrades KDE. .TP 3 \fB5: Stop KDE from blocking XScreenSaver's "systemd" integration:\fP You must arrange for KDE's .BR ksmserver (1) -daemon to be launched with the command line switch \fI\-\-no\-lockscreen\fP. +daemon to be launched with the command line option \fI\-\-no\-lockscreen\fP. -One way to accomplish that is to edit the +Under KDE 5.00 through 5.16, you can accomplish that by editing the .BR startkde (1) -script in \fI/usr/bin/\fP by hand, then log out and log back in. Another -way would be to wrap the \fIksmserver\fP program: +script in \fI/usr/bin/\fP by hand, then logging out and back in again. + +Under KDE 5.17 through 5.20, you must wrap +.BR ksmserver (1) +instead: .nf .sp mv /usr/bin/ksmserver /usr/bin/ksmserver-orig @@ -276,17 +276,27 @@ Either change will, of course, get blown away the next time your system upgrades KDE. Instead of being in \fI/usr/bin/\fP, the \fIksmserver\fP program might be -in \fI/usr/lib/\fP or \fIusr/lib*/libexec/\fP or \fIusr/lib/*/libexec/\fP +in \fI/usr/lib/\fP or \fI/usr/lib*/libexec/\fP or \fIusr/lib/*/libexec/\fP or somewhere else, depending on your distro. -But without this, video players will not be able to tell XScreenSaver not to -blank the screen while videos are playing, and the screen will not auto-lock -when you close your laptop's lid. - -It seems that KDE 5.17 replaced \fIstartkde\fP with \fIstartplasma-x11\fP, -and I don't know how to change how \fIthat\fP launches \fIksmserver\fP. -Let me know if you figure it out. - +Under KDE 5.21+ this might work instead, and might persist through upgrades: +.nf +.sp + systemctl edit plasma-ksmserver.service +.sp +.fi +and then put this in the file you get to edit: +.nf +.sp + [Service] + ExecStart=/usr/bin/ksmserver \-\-no\-lockscreen +.sp +.fi +Regardless of which approach you need to use, if you do not force +.BR ksmserver (1) +to stop squatting on the DBus endpoint, video players will not be able to tell +XScreenSaver not to blank the screen while videos are playing, and the screen +will not auto-lock when you close your laptop's lid. .SS LAUNCHING XSCREENSAVER FROM SYSTEMD If the above didn't do it, and your system has .BR systemd (1), @@ -343,7 +353,7 @@ On the \fIGeneral\fP page set the \fILocal Greeter\fP to \fIStandard Greeter\fP. On the \fIBackground\fP page, type the -command \fB"xscreensaver \-\-nosplash"\fP into the \fIBackground Program\fP +command \fI"xscreensaver \-\-nosplash"\fP into the \fIBackground Program\fP field. That will cause gdm to run XScreenSaver while nobody is logged in, and kill it as soon as someone does log in. (The user will then be responsible for starting XScreenSaver on their own, if they want.) @@ -390,11 +400,58 @@ might have luck by adding \fIxscreensaver\-command \-\-suspend\fP to some appropriate spot in \fI/etc/acpi/events/anything\fP or in \fI/etc/acpi/handler.sh\fP, if those files exist. +.SH THE WAYLAND PROBLEM +Wayland is a completely different window system that is intended to replace +X11. After 13+ years of trying, some Linux distros have finally begun +enabling it by default. Most deployments of it also include XWayland, which +is a compatibility layer that allows \fIsome\fP X11 programs to continue to +work within a Wayland environment. + +Unfortunately, XScreenSaver is not one of those programs. + +If your system is running XWayland, XScreenSaver will malfunction in two +ways: +.RS 0 +.TP 3 +\fB1:\fP It will be unable to detect user activity in non-X11 programs. + +This means that while a native Wayland program is selected, XScreenSaver will +think that you are idle, and may blank the screen prematurely. +.TP 3 +\fB2:\fP It will be unable to lock the screen. + +This is because X11 grabs don't work properly under XWayland, so there is no +way for XScreenSaver to prevent the user from switching away from the screen +locker to another application. +.RE + +In short, for XScreenSaver to work properly, you will need to switch off +Wayland and use the X Window System like in the "good old days". +.SS TO DISABLE WAYLAND UNDER GNOME +The login screen should have a gear-icon menu that lets you change the session +type from "GNOME" (the Wayland session) to "GNOME on Xorg" (the X11 session). + +Alternately, edit \fI/etc/gdm/custom.conf\fP and make sure it includes this +line: +.nf +.sp + WaylandEnable=false +.fi +.SS TO DISABLE WAYLAND UNDER KDE +The login screen should have a menu that lets you change the session type to +"Plasma (X11)". + +Alternately, edit \fI/etc/sddm.conf\fP and change the \fISessionDir\fP line +under the \fI[Wayland]\fP section to say: +.nf +.sp + SessionDir=/dev/null +.fi + .SH SECURITY CONCERNS XScreenSaver has a decades-long track record of securely locking your screen. However, there are many things that can go wrong. X11 is a very old system, and has a number of design flaws that make it susceptible to foot-shooting. - .SS MAGIC BACKDOOR KEYSTROKES The XFree86 and Xorg X servers, as well as the Linux kernel, both trap certain magic keystrokes before X11 client programs ever see them. @@ -791,9 +848,9 @@ might set this in your \fI~/.xscreensaver\fP file: .sp .fi .RS 8 -Make sure your \fB$PATH\fP environment variable is set up correctly -\fIbefore\fP XScreenSaver is launched, or it won't be able to find the -programs listed in the \fIprograms\fP resource. +The default XScreenSaver hacks directory (typically +\fI/usr/libexec/xscreensaver/\fP) is prepended to \fB$PATH\fP +before searching for these programs. To use a program as a screensaver, it must be able to render onto the window provided to it in the \fB$XSCREENSAVER_WINDOW\fP environment @@ -921,6 +978,9 @@ If the mouse moves less than this-many pixels in a second, ignore it doesn't un-blank (or fail to blank) just because you bumped the desk. Default: 10 pixels. +A single pixel of motion will still cause the monitor to power back on, +but not un-blank. This is because the X11 server itself unfortunately handles +power-management-related activity detection rather than XScreenSaver. .SH BUGS https://www.jwz.org/xscreensaver/bugs.html explains how to write the most useful bug reports. If you find a bug, please let me know! diff --git a/hacks/Makefile.in b/hacks/Makefile.in index ef6ee5cd..d7cb4dd0 100644 --- a/hacks/Makefile.in +++ b/hacks/Makefile.in @@ -680,7 +680,8 @@ analogtv-cli.o: $(srcdir)/analogtv-cli.c $(CC) -o $@ -c $(ATVCLI_CFLAGS) $< ATVCLI = analogtv2.o $(UTILS_BIN)/yarandom.o \ - $(UTILS_BIN)/aligned_malloc.o $(THRO) $(PNG) @ANIM_OBJS@ + $(UTILS_BIN)/aligned_malloc.o $(THRO) $(PNG) \ + $(UTILS_BIN)/font-retry.o @ANIM_OBJS@ analogtv-cli: analogtv-cli.o $(ATVCLI) $(CC_HACK) -o $@ $@.o $(ATVCLI) $(THRL) $(PNG_LIBS) -lpng clean:: diff --git a/hacks/analogtv-cli.c b/hacks/analogtv-cli.c index 2c4a880b..975c79ad 100644 --- a/hacks/analogtv-cli.c +++ b/hacks/analogtv-cli.c @@ -1,4 +1,4 @@ -/* xanalogtv-cli, Copyright (c) 2018-2020 Jamie Zawinski +/* xanalogtv-cli, Copyright © 2018-2021 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 @@ -345,12 +345,6 @@ get_pixel_resource (Display *dpy, Colormap cmap, char *name, char *class) abort(); } -XFontStruct * -load_font_retry (Display *dpy, const char *xlfd) -{ - abort(); -} - Bool put_xshm_image (Display *dpy, Drawable d, GC gc, XImage *image, int src_x, int src_y, int dest_x, int dest_y, diff --git a/hacks/config/README b/hacks/config/README index b0313231..43a64908 100644 --- a/hacks/config/README +++ b/hacks/config/README @@ -4,8 +4,8 @@ a screen saver and locker for the X window system by Jamie Zawinski - version 6.00 - 01-Apr-2021 + version 6.01 + 09-Jun-2021 https://www.jwz.org/xscreensaver/ diff --git a/hacks/config/covid19.xml b/hacks/config/covid19.xml index 96f395b1..f5943f44 100644 --- a/hacks/config/covid19.xml +++ b/hacks/config/covid19.xml @@ -31,7 +31,7 @@ <_description> -SARS-CoV-2. Stay the fuck home. Wear a fucking mask. +SARS-CoV-2. Get vaccinated. Wear a mask. Written by Jamie Zawinski; 2020. diff --git a/hacks/xscreensaver-text b/hacks/xscreensaver-text index 421fae7d..641f9653 100755 --- a/hacks/xscreensaver-text +++ b/hacks/xscreensaver-text @@ -39,7 +39,7 @@ BEGIN { eval 'use Text::Wrap qw(wrap);' } my $progname = $0; $progname =~ s@.*/@@g; -my ($version) = ('$Revision: 1.60 $' =~ m/\s(\d[.\d]+)\s/s); +my ($version) = ('$Revision: 1.62 $' =~ m/\s(\d[.\d]+)\s/s); my $verbose = 0; my $http_proxy = undef; @@ -380,6 +380,8 @@ sub output() { # In a truly shocking turn of events, nearly every distro uses a different # file to identify itself. Are you shocked? I for one am shocked. + $ENV{LC_NUMERIC} = 'C'; # Decimals with periods, not commas, plz. + if (open (my $in, "<:utf8", "/etc/os-release")) { while (<$in>) { # PRETTY_NAME="CentOS Linux 7 (Core)" if (m/^PRETTY_NAME="(.*)"/si) { # PRETTY_NAME="Raspbian 10 (buster)" @@ -991,7 +993,7 @@ sub main() { # amount of time (e.g., url-mode.) # my $secs = 10; - $secs = 1 if ($truncate_lines < 10); # for 'gltext' + $secs = 1 if (($truncate_lines || 0) < 10); # for 'gltext' sleep ($secs); } } diff --git a/po/POTFILES.in b/po/POTFILES.in index c288450a..60aa6d28 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,4 +1,4 @@ -# Auto-generated: Thu Apr 1 03:16:58 PDT 2021 +# Auto-generated: Wed Jun 9 08:47:14 PDT 2021 driver/demo-Gtk-conf.c driver/demo-Gtk.c driver/dialog.c diff --git a/utils/version.h b/utils/version.h index 8e385851..579bcc6b 100644 --- a/utils/version.h +++ b/utils/version.h @@ -1,4 +1,4 @@ static const char screensaver_id[] = - "@(#)xscreensaver 6.00 (01-Apr-2021), by Jamie Zawinski (jwz@jwz.org)"; -#define XSCREENSAVER_VERSION "6.00" -#define XSCREENSAVER_RELEASED 1617303600 + "@(#)xscreensaver 6.01 (09-Jun-2021), by Jamie Zawinski (jwz@jwz.org)"; +#define XSCREENSAVER_VERSION "6.01" +#define XSCREENSAVER_RELEASED 1623265200 diff --git a/xscreensaver.spec b/xscreensaver.spec index d9d239b0..ac012f54 100644 --- a/xscreensaver.spec +++ b/xscreensaver.spec @@ -1,5 +1,5 @@ %define name xscreensaver -%define version 6.00 +%define version 6.01 Summary: X screen saver and locker Name: %{name}