1 # Upstream patch, downloaded from
2 # http://www.jwz.org/xscreensaver/xscreensaver-randr-patch-3.txt
3 # + fixed typo "screen < real_nscreens" in driver/lock:1527
4 # Will probably go upstream with 5.06
5 # Fixes a bunch of xrandr/xinerama issues
7 Please see http://jwz.livejournal.com/908354.html
12 patch -p1 < ../xscreensaver-randr-patch-3.txt
16 Index: xscreensaver/config.h.in
17 ===================================================================
18 --- xscreensaver.orig/config.h.in 2008-07-16 23:47:00.000000000 +0200
19 +++ xscreensaver/config.h.in 2008-07-17 00:07:00.000000000 +0200
21 available if the file /usr/include/X11/extensions/Xrandr.h exists.) */
24 +/* Define this if the RANDR library is version 1.2 or newer. */
27 /* Define this if you have the XReadDisplay extension (I think this is an
28 SGI-only thing; it's in <X11/extensions/readdisplay.h>.) A few of the
29 screenhacks will take advantage of this if it's available. */
30 Index: xscreensaver/configure
31 ===================================================================
32 --- xscreensaver.orig/configure 2008-07-16 23:47:00.000000000 +0200
33 +++ xscreensaver/configure 2008-07-17 00:07:00.000000000 +0200
41 # After checking to see that --srcdir is correct (which AC_INIT does)
42 # check for some random other files that come later in the tar file,
43 # to make sure everything is here.
44 @@ -2096,6 +2099,10 @@
48 +# Need to disable Objective C extensions in ANSI C on MacOS X to work
49 +# around an Apple-specific gcc bug.
53 ###############################################################################
55 @@ -2124,18 +2131,6 @@
57 ###############################################################################
59 -# Function to figure out how to turn off Objective C on MacOS X.
60 -# (We have to do this to work around an Apple-specific gcc bug.)
62 -###############################################################################
69 -###############################################################################
71 # Function to figure out how to create directory trees.
73 ###############################################################################
75 ac_cv_gcc_accepts_no_overlength=no
77 ac_cv_gcc_accepts_no_overlength=yes
78 + CC="$CC -Wno-overlength-strings"
81 { echo "$as_me:$LINENO: result: $ac_cv_gcc_accepts_no_overlength" >&5
83 ac_cv_gcc_accepts_no_decl_after=no
85 ac_cv_gcc_accepts_no_decl_after=yes
86 + CC="$CC -Wdeclaration-after-statement"
89 { echo "$as_me:$LINENO: result: $ac_cv_gcc_accepts_no_decl_after" >&5
93 if test -n "$GCC"; then
94 - if test -n "$GCC"; then
95 { echo "$as_me:$LINENO: checking whether gcc accepts -no-cpp-precomp" >&5
96 echo $ECHO_N "checking whether gcc accepts -no-cpp-precomp... $ECHO_C" >&6; }
97 if test "${ac_cv_gcc_accepts_no_cpp_precomp+set}" = set; then
99 ac_cv_gcc_accepts_no_cpp_precomp=no
101 ac_cv_gcc_accepts_no_cpp_precomp=yes
102 + CC="$CC -no-cpp-precomp"
105 { echo "$as_me:$LINENO: result: $ac_cv_gcc_accepts_no_cpp_precomp" >&5
106 @@ -3503,13 +3500,6 @@
107 ac_gcc_accepts_no_cpp_precomp="$ac_cv_gcc_accepts_no_cpp_precomp"
110 - if test "$ac_gcc_accepts_no_cpp_precomp" = yes ; then
111 - { echo "$as_me:$LINENO: result: Disabling Objective C extensions in ANSI C code." >&5
112 -echo "${ECHO_T}Disabling Objective C extensions in ANSI C code." >&6; }
113 - CC="$CC -no-cpp-precomp"
117 if test -n "$GCC"; then
118 if test -n "$GCC"; then
119 { echo "$as_me:$LINENO: checking whether gcc accepts -std=c89" >&5
120 @@ -3524,6 +3514,7 @@
121 ac_cv_gcc_accepts_std=no
123 ac_cv_gcc_accepts_std=yes
127 { echo "$as_me:$LINENO: result: $ac_cv_gcc_accepts_std" >&5
128 @@ -3552,7 +3543,8 @@
129 # before they were in the ANSI C 99 spec... (gcc 2.96 permits //
130 # with -std=gnu89 but not with -std=c89.)
132 - CC="$CC -std=c89 -U__STRICT_ANSI__"
133 + # $CC already contains "-std=c89" via AC_GCC_ACCEPTS_STD
134 + CC="$CC -U__STRICT_ANSI__"
137 CC="$CC -Wp,-lang-c89"
138 @@ -12140,7 +12132,7 @@
140 if test "$with_randr" = yes; then
142 - # first check for Randr.h
143 + # first check for Xrandr.h
145 ac_save_CPPFLAGS="$CPPFLAGS"
146 if test \! -z "$includedir" ; then
147 @@ -12489,7 +12481,103 @@
152 + # Now check for version 1.2 in the same libs.
154 + ac_save_CPPFLAGS="$CPPFLAGS"
155 + ac_save_LDFLAGS="$LDFLAGS"
156 +# ac_save_LIBS="$LIBS"
158 + if test \! -z "$includedir" ; then
159 + CPPFLAGS="$CPPFLAGS -I$includedir"
161 + # note: $X_CFLAGS includes $x_includes
162 + CPPFLAGS="$CPPFLAGS $X_CFLAGS"
164 + if test \! -z "$libdir" ; then
165 + LDFLAGS="$LDFLAGS -L$libdir"
167 + # note: $X_LIBS includes $x_libraries
168 + LDFLAGS="$LDFLAGS $X_LIBS $X_EXTRA_LIBS"
170 + CPPFLAGS=`eval eval eval eval eval eval eval eval eval echo $CPPFLAGS`
171 + LDFLAGS=`eval eval eval eval eval eval eval eval eval echo $LDFLAGS`
172 + { echo "$as_me:$LINENO: checking for XRRGetOutputInfo in -lc" >&5
173 +echo $ECHO_N "checking for XRRGetOutputInfo in -lc... $ECHO_C" >&6; }
174 +if test "${ac_cv_lib_c_XRRGetOutputInfo+set}" = set; then
175 + echo $ECHO_N "(cached) $ECHO_C" >&6
177 + ac_check_lib_save_LIBS=$LIBS
178 +LIBS="-lc $SAVER_LIBS $LIBS"
179 +cat >conftest.$ac_ext <<_ACEOF
182 +cat confdefs.h >>conftest.$ac_ext
183 +cat >>conftest.$ac_ext <<_ACEOF
184 +/* end confdefs.h. */
186 +/* Override any GCC internal prototype to avoid an error.
187 + Use char because int might match the return type of a GCC
188 + builtin and then its argument prototype would still apply. */
192 +char XRRGetOutputInfo ();
196 +return XRRGetOutputInfo ();
201 +rm -rf conftest.$ac_objext conftest$ac_exeext
202 +if { (ac_try="$ac_link"
204 + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
205 + *) ac_try_echo=$ac_try;;
207 +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
208 + (eval "$ac_link") 2>conftest.er1
210 + grep -v '^ *+' conftest.er1 >conftest.err
211 + rm -rf conftest.er1
212 + cat conftest.err >&5
213 + echo "$as_me:$LINENO: \$? = $ac_status" >&5
214 + (exit $ac_status); } && {
215 + test -z "$ac_c_werror_flag" ||
216 + test ! -s conftest.err
217 + } && test -s conftest$ac_exeext &&
218 + $as_test_x conftest$ac_exeext; then
219 + ac_cv_lib_c_XRRGetOutputInfo=yes
221 + echo "$as_me: failed program was:" >&5
222 +sed 's/^/| /' conftest.$ac_ext >&5
224 + ac_cv_lib_c_XRRGetOutputInfo=no
227 +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
228 + conftest$ac_exeext conftest.$ac_ext
229 +LIBS=$ac_check_lib_save_LIBS
231 +{ echo "$as_me:$LINENO: result: $ac_cv_lib_c_XRRGetOutputInfo" >&5
232 +echo "${ECHO_T}$ac_cv_lib_c_XRRGetOutputInfo" >&6; }
233 +if test $ac_cv_lib_c_XRRGetOutputInfo = yes; then
234 + cat >>confdefs.h <<\_ACEOF
235 +#define HAVE_RANDR_12 1
242 + CPPFLAGS="$ac_save_CPPFLAGS"
243 + LDFLAGS="$ac_save_LDFLAGS"
244 +# LIBS="$ac_save_LIBS"
249 elif test "$with_randr" != no; then
250 echo "error: must be yes or no: --with-randr-ext=$with_randr"
251 @@ -16673,7 +16761,7 @@
252 echo $ECHO_N "(cached) $ECHO_C" >&6
254 cat > conftest.$ac_ext <<EOF
255 -#line 16680 "configure"
256 +#line 16768 "configure"
257 #include "confdefs.h"
259 #ifndef MESA_MAJOR_VERSION
260 @@ -19890,9 +19978,11 @@
262 #### Could use some more defaults here...
264 - "/usr/X11R6/lib/X11/doc/README" \
265 - "/usr/share/doc/xserver-common/copyright" \
266 - "/usr/X11R6/README" \
267 + "/usr/X11R6/lib/X11/doc/README" \
268 + "/usr/share/doc/xserver-common/copyright" \
269 + "/usr/share/doc/xserver-xorg-core/copyright" \
270 + "/usr/X11R6/README" \
271 + "/usr/share/doc/debian/debian-manifesto" \
273 if test -z "$with_textfile"; then
274 { echo "$as_me:$LINENO: checking for text file $f" >&5
275 @@ -21883,8 +21973,9 @@
276 pgl="$preferred_mesagl"
278 if test "$ac_mesagl_version" = unknown; then
279 - warnL "Unable to determine the MesaGL version number!"
280 - warn2 "Make sure you are using version $preferred_mesagl or newer."
282 + # warnL "Unable to determine the MesaGL version number!"
283 + # warn2 "Make sure you are using version $preferred_mesagl or newer."
285 elif test \! "$ac_mesagl_version" -gt 2006; then
286 warnL "MesaGL version number is $mgv --"
287 @@ -22035,7 +22126,7 @@
289 if test \! -z "$rpmv" ; then
290 rpmbdir=`rpm -ql $rpmnames | sed -n 's@^\(.*\)/xscreensaver-demo$@\1@p'`
291 - rpmhdir=`rpm -ql $rpmnames | sed -n 's@^\(.*\)/attraction$@\1@p'`
292 + rpmhdir=`rpm -ql $rpmnames | sed -n 's@^\(.*\)/popsquares$@\1@p'`
295 warnL "There is already an installed RPM of xscreensaver $rpmv"
296 @@ -22058,6 +22149,31 @@
300 +# Also warn if there's a Debian package installed.
302 +debnames="xscreensaver xscreensaver-data xscreensaver-data-extra"
304 +for dpkg in $debnames ; do
305 + if test -z "$debv"; then
306 + debv=`dpkg -s $dpkg 2>/dev/null | sed -n 's/^Version: \(.*\)$/\1/p'`
310 +if test \! -z "$debv" ; then
311 + debbdir=`dpkg -L $debnames 2>/dev/null | \
312 + sed -n 's@^\(.*/bin\)/xscreensaver$@\1@p'`
313 + debhdir=`dpkg -L $debnames 2>/dev/null | \
314 + sed -n 's@^\(.*\)/popsquares$@\1@p'`
317 + warnL "There is already an installed dpkg of xscreensaver"
318 + warn2 "version \"$debv\" on this system."
320 + warn2 "The dpkg was installed in $debbdir/,"
321 + warn2 "with demos in $debhdir/."
325 if test "${bindir}" = "${HACKDIR}" ; then
328 Index: xscreensaver/configure.in
329 ===================================================================
330 --- xscreensaver.orig/configure.in 2008-07-16 23:47:00.000000000 +0200
331 +++ xscreensaver/configure.in 2008-07-17 00:07:00.000000000 +0200
333 possibly elsewhere. (It's available if the file
334 /usr/include/X11/extensions/Xrandr.h exists.)])
336 +AH_TEMPLATE([HAVE_RANDR_12],
337 + [Define this if the RANDR library is version 1.2 or newer.])
339 AH_TEMPLATE([HAVE_PROC_INTERRUPTS],
340 [Define this if you have a Linux-like /proc/interrupts file which
341 can be examined to determine when keyboard activity has
343 ac_cv_gcc_accepts_[$1]=no
345 ac_cv_gcc_accepts_[$1]=yes
348 ac_gcc_accepts_[$1]="$ac_cv_gcc_accepts_[$1]"
351 AC_DEFUN(AC_NO_MISPLACED_DECLARATIONS,
352 [AC_CHECK_GCC_ARG(no_decl_after, -Wdeclaration-after-statement)])
354 +# Need to disable Objective C extensions in ANSI C on MacOS X to work
355 +# around an Apple-specific gcc bug.
357 +AC_DEFUN(AC_NO_OBJECTIVE_C,
358 + [AC_CHECK_GCC_ARG(no_cpp_precomp, -no-cpp-precomp)])
360 ###############################################################################
363 # before they were in the ANSI C 99 spec... (gcc 2.96 permits //
364 # with -std=gnu89 but not with -std=c89.)
366 - CC="$CC -std=c89 -U__STRICT_ANSI__"
367 + # $CC already contains "-std=c89" via AC_GCC_ACCEPTS_STD
368 + CC="$CC -U__STRICT_ANSI__"
371 CC="$CC -Wp,-lang-c89"
374 ###############################################################################
376 -# Function to figure out how to turn off Objective C on MacOS X.
377 -# (We have to do this to work around an Apple-specific gcc bug.)
379 -###############################################################################
381 -AC_DEFUN(AC_GCC_ACCEPTS_NO_CPP_PRECOMP,
382 - [AC_CHECK_GCC_ARG(no_cpp_precomp, -no-cpp-precomp)])
384 -AC_DEFUN(AC_NO_OBJECTIVE_C,
385 - [if test -n "$GCC"; then
386 - AC_GCC_ACCEPTS_NO_CPP_PRECOMP
387 - if test "$ac_gcc_accepts_no_cpp_precomp" = yes ; then
388 - AC_MSG_RESULT(Disabling Objective C extensions in ANSI C code.)
389 - CC="$CC -no-cpp-precomp"
395 -###############################################################################
397 # Function to figure out how to create directory trees.
399 ###############################################################################
400 @@ -1667,7 +1656,7 @@
402 if test "$with_randr" = yes; then
404 - # first check for Randr.h
405 + # first check for Xrandr.h
406 AC_CHECK_X_HEADER(X11/extensions/Xrandr.h, [have_randr=yes],,
407 [#include <X11/Xlib.h>])
409 @@ -1696,8 +1685,13 @@
410 # if that succeeded, then we've really got it.
411 if test "$have_randr" = yes; then
412 AC_DEFINE(HAVE_RANDR)
414 + # Now check for version 1.2 in the same libs.
415 + AC_CHECK_X_LIB(c, XRRGetOutputInfo, [AC_DEFINE(HAVE_RANDR_12)],
416 + [true], $SAVER_LIBS)
420 elif test "$with_randr" != no; then
421 echo "error: must be yes or no: --with-randr-ext=$with_randr"
423 @@ -3414,9 +3408,11 @@
425 #### Could use some more defaults here...
427 - "/usr/X11R6/lib/X11/doc/README" \
428 - "/usr/share/doc/xserver-common/copyright" \
429 - "/usr/X11R6/README" \
430 + "/usr/X11R6/lib/X11/doc/README" \
431 + "/usr/share/doc/xserver-common/copyright" \
432 + "/usr/share/doc/xserver-xorg-core/copyright" \
433 + "/usr/X11R6/README" \
434 + "/usr/share/doc/debian/debian-manifesto" \
436 if test -z "$with_textfile"; then
437 AC_MSG_CHECKING([for text file $f])
438 @@ -4035,8 +4031,9 @@
439 pgl="$preferred_mesagl"
441 if test "$ac_mesagl_version" = unknown; then
442 - warnL "Unable to determine the MesaGL version number!"
443 - warn2 "Make sure you are using version $preferred_mesagl or newer."
445 + # warnL "Unable to determine the MesaGL version number!"
446 + # warn2 "Make sure you are using version $preferred_mesagl or newer."
448 elif test \! "$ac_mesagl_version" -gt 2006; then
449 warnL "MesaGL version number is $mgv --"
450 @@ -4182,7 +4179,7 @@
452 if test \! -z "$rpmv" ; then
453 rpmbdir=`rpm -ql $rpmnames | sed -n 's@^\(.*\)/xscreensaver-demo$@\1@p'`
454 - rpmhdir=`rpm -ql $rpmnames | sed -n 's@^\(.*\)/attraction$@\1@p'`
455 + rpmhdir=`rpm -ql $rpmnames | sed -n 's@^\(.*\)/popsquares$@\1@p'`
458 warnL "There is already an installed RPM of xscreensaver $rpmv"
459 @@ -4205,6 +4202,31 @@
463 +# Also warn if there's a Debian package installed.
465 +debnames="xscreensaver xscreensaver-data xscreensaver-data-extra"
467 +for dpkg in $debnames ; do
468 + if test -z "$debv"; then
469 + debv=`dpkg -s $dpkg 2>/dev/null | sed -n 's/^Version: \(.*\)$/\1/p'`
473 +if test \! -z "$debv" ; then
474 + debbdir=`dpkg -L $debnames 2>/dev/null | \
475 + sed -n 's@^\(.*/bin\)/xscreensaver$@\1@p'`
476 + debhdir=`dpkg -L $debnames 2>/dev/null | \
477 + sed -n 's@^\(.*\)/popsquares$@\1@p'`
480 + warnL "There is already an installed dpkg of xscreensaver"
481 + warn2 "version \"$debv\" on this system."
483 + warn2 "The dpkg was installed in $debbdir/,"
484 + warn2 "with demos in $debhdir/."
488 if test "${bindir}" = "${HACKDIR}" ; then
491 Index: xscreensaver/driver/Makefile.in
492 ===================================================================
493 --- xscreensaver.orig/driver/Makefile.in 2008-07-16 23:47:00.000000000 +0200
494 +++ xscreensaver/driver/Makefile.in 2008-07-17 00:07:00.000000000 +0200
495 @@ -116,10 +116,10 @@
497 TEST_SRCS = test-passwd.c test-uid.c test-xdpms.c test-grab.c \
498 test-apm.c test-fade.c test-xinerama.c test-vp.c \
499 - test-randr.c xdpyinfo.c test-mlstring.c
500 + test-randr.c xdpyinfo.c test-mlstring.c test-screens.c
501 TEST_EXES = test-passwd test-uid test-xdpms test-grab \
502 test-apm test-fade test-xinerama test-vp \
503 - test-randr xdpyinfo test-mlstring
504 + test-randr xdpyinfo test-mlstring test-screens
506 MOTIF_LIBS = @MOTIF_LIBS@ @XPM_LIBS@ $(XMU_LIBS)
507 GTK_LIBS = @GTK_LIBS@ $(XMU_LIBS)
509 GTK_ICONS = $(ICON_SRC)/screensaver-*.png
511 DEMO_UTIL_SRCS = $(UTILS_SRC)/resources.c $(UTILS_SRC)/usleep.c \
512 - $(UTILS_SRC)/visual.c
513 + $(UTILS_SRC)/visual.c $(XMU_SRCS)
514 DEMO_UTIL_OBJS = $(UTILS_BIN)/resources.o $(UTILS_BIN)/usleep.o \
515 - $(UTILS_BIN)/visual.o
516 + $(UTILS_BIN)/visual.o $(XMU_OBJS)
518 SAVER_UTIL_SRCS = $(UTILS_SRC)/fade.c $(UTILS_SRC)/overlay.c \
519 $(UTILS_SRC)/logo.c $(UTILS_SRC)/yarandom.c \
520 @@ -179,24 +179,24 @@
521 $(UTILS_BIN)/logo.o $(UTILS_BIN)/minixpm.o prefs.o \
524 -SAVER_SRCS_1 = xscreensaver.c windows.c timers.c subprocs.c exec.c \
525 - xset.c splash.c setuid.c stderr.c mlstring.c
526 -SAVER_OBJS_1 = xscreensaver.o windows.o timers.o subprocs.o exec.o \
527 - xset.o splash.o setuid.o stderr.o mlstring.o
528 +SAVER_SRCS_1 = xscreensaver.c windows.c screens.c timers.c subprocs.c \
529 + exec.c xset.c splash.c setuid.c stderr.c mlstring.c
530 +SAVER_OBJS_1 = xscreensaver.o windows.o screens.o timers.o subprocs.o \
531 + exec.o xset.o splash.o setuid.o stderr.o mlstring.o
533 SAVER_SRCS = $(SAVER_SRCS_1) prefs.c dpms.c $(LOCK_SRCS) \
534 - $(SAVER_UTIL_SRCS) $(GL_SRCS) $(XMU_SRCS)
535 + $(SAVER_UTIL_SRCS) $(GL_SRCS)
536 SAVER_OBJS = $(SAVER_OBJS_1) prefs.o dpms.o $(LOCK_OBJS) \
537 - $(SAVER_UTIL_OBJS) $(GL_OBJS) $(XMU_OBJS)
538 + $(SAVER_UTIL_OBJS) $(GL_OBJS)
540 CMD_SRCS = remote.c xscreensaver-command.c
541 CMD_OBJS = remote.o xscreensaver-command.o
543 -DEMO_SRCS_1 = prefs.c dpms.c $(XMU_SRCS)
544 -DEMO_OBJS_1 = prefs.o dpms.o $(XMU_OBJS)
545 +DEMO_SRCS_1 = prefs.c dpms.c
546 +DEMO_OBJS_1 = prefs.o dpms.o
548 -DEMO_SRCS = prefs.c dpms.c remote.c exec.c $(DEMO_UTIL_SRCS)
549 -DEMO_OBJS = prefs.o dpms.o remote.o exec.o $(DEMO_UTIL_OBJS)
550 +DEMO_SRCS = $(DEMO_SRCS_1) remote.c exec.c $(DEMO_UTIL_SRCS)
551 +DEMO_OBJS = $(DEMO_OBJS_1) remote.o exec.o $(DEMO_UTIL_OBJS)
553 PDF2JPEG_SRCS = pdf2jpeg.m
554 PDF2JPEG_OBJS = pdf2jpeg.o
556 $$e " ####################################################################";\
559 - elif [ -f $$conf ]; then \
560 + elif [ -f $$conf -a "x$$dest" != "x" ]; then \
561 if ( grep $$dest $$conf >/dev/null ); then \
562 echo "$$conf unchanged: already has an entry for $$dest" ; \
565 echo $(INSTALL_DIRS) "$(install_prefix)$(GTK_APPDIR)" ;\
566 $(INSTALL_DIRS) "$(install_prefix)$(GTK_APPDIR)" ;\
568 - name2=gnome-screensaver-properties.desktop ;\
569 + name2=xscreensaver-properties.desktop ;\
570 echo $(INSTALL_DATA) screensaver-properties.desktop \
571 $(install_prefix)$(GTK_APPDIR)/$$name2 ;\
572 $(INSTALL_DATA) screensaver-properties.desktop \
574 # into /usr/share/applications/
576 @if [ "$(GTK_DATADIR)" != "" ]; then \
577 - f=gnome-screensaver-properties.desktop ;\
578 + f=xscreensaver-properties.desktop ;\
579 echo rm -f $(install_prefix)$(GTK_APPDIR)/$$f ;\
580 rm -f $(install_prefix)$(GTK_APPDIR)/$$f ;\
583 test-fade: test-fade.o $(UTILS_BIN)/fade.o
584 $(CC) $(LDFLAGS) -o $@ $(TEST_FADE_OBJS) $(SAVER_LIBS)
586 +TEST_SCREENS_OBJS = test-screens.o $(DEMO_UTIL_OBJS)
587 +test-screens.o: screens.c
588 +test-screens: test-screens.o
589 + $(CC) $(LDFLAGS) -o $@ $(TEST_SCREENS_OBJS) $(SAVER_LIBS)
592 xdpyinfo.o: xdpyinfo.c
593 $(CC) -c $(INCLUDES) -DHAVE_GLX $(CFLAGS) $(X_CFLAGS) \
595 prefs.o: $(UTILS_SRC)/resources.h
596 remote.o: ../config.h
597 remote.o: $(srcdir)/remote.h
598 +screens.o: ../config.h
599 +screens.o: $(srcdir)/prefs.h
600 +screens.o: $(srcdir)/types.h
601 +screens.o: $(UTILS_SRC)/visual.h
602 +screens.o: $(srcdir)/xscreensaver.h
603 setuid.o: ../config.h
604 setuid.o: $(srcdir)/prefs.h
605 setuid.o: $(srcdir)/types.h
607 test-passwd.o: $(UTILS_SRC)/visual.h
608 test-passwd.o: $(srcdir)/xscreensaver.h
609 test-randr.o: ../config.h
610 +test-screens.o: ../config.h
611 +test-screens.o: $(srcdir)/prefs.h
612 +test-screens.o: $(srcdir)/screens.c
613 +test-screens.o: $(srcdir)/types.h
614 +test-screens.o: $(UTILS_SRC)/visual.h
615 +test-screens.o: $(srcdir)/xscreensaver.h
616 test-uid.o: ../config.h
617 test-vp.o: ../config.h
618 test-xdpms.o: ../config.h
619 Index: xscreensaver/driver/XScreenSaver.ad.in
620 ===================================================================
621 --- xscreensaver.orig/driver/XScreenSaver.ad.in 2008-07-16 23:47:00.000000000 +0200
622 +++ xscreensaver/driver/XScreenSaver.ad.in 2008-07-17 00:07:00.000000000 +0200
624 ! a screen saver and locker for the X window system
632 ! See "man xscreensaver" for more info. The latest version is always
633 ! available at http://www.jwz.org/xscreensaver/
637 ! This command is executed by the "New Login" button on the lock dialog.
638 -! (That button does not appear if this program does not exist.)
639 +! (That button does not appear on the dialog if this program does not exist.)
640 +! For Gnome: probably "gdmflexiserver -ls". KDE, probably "kdmctl reserve".
642 @NEW_LOGIN_COMMAND_P@*newLoginCommand: @NEW_LOGIN_COMMAND@
644 Index: xscreensaver/driver/demo-Gtk.c
645 ===================================================================
646 --- xscreensaver.orig/driver/demo-Gtk.c 2008-07-16 23:47:00.000000000 +0200
647 +++ xscreensaver/driver/demo-Gtk.c 2008-07-17 00:07:00.000000000 +0200
649 void settings_cancel_cb (GtkButton *, gpointer user_data);
650 void settings_ok_cb (GtkButton *, gpointer user_data);
652 +static void kill_gnome_screensaver (void);
653 +static void kill_kde_screensaver (void);
656 /* Some random utility functions
659 warning_dialog_dismiss_cb (widget, user_data);
662 +static void warning_dialog_killg_cb (GtkWidget *widget, gpointer user_data)
664 + kill_gnome_screensaver ();
665 + warning_dialog_dismiss_cb (widget, user_data);
668 +static void warning_dialog_killk_cb (GtkWidget *widget, gpointer user_data)
670 + kill_kde_screensaver ();
671 + warning_dialog_dismiss_cb (widget, user_data);
674 +typedef enum { D_NONE, D_LAUNCH, D_GNOME, D_KDE } dialog_button;
677 warning_dialog (GtkWidget *parent, const char *message,
678 - Boolean restart_button_p, int center)
679 + dialog_button button_type, int center)
681 char *msg = strdup (message);
684 label, TRUE, TRUE, 0);
687 - if (restart_button_p)
688 + if (button_type != D_NONE)
690 cancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
691 gtk_container_add (GTK_CONTAINER (label), cancel);
693 ok = gtk_button_new_with_label ("OK");
694 gtk_container_add (GTK_CONTAINER (label), ok);
696 - if (restart_button_p)
697 + if (button_type != D_NONE)
699 cancel = gtk_button_new_with_label ("Cancel");
700 gtk_container_add (GTK_CONTAINER (label), cancel);
701 @@ -582,22 +599,28 @@
702 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
703 gtk_container_set_border_width (GTK_CONTAINER (dialog), 10);
704 gtk_window_set_title (GTK_WINDOW (dialog), progclass);
705 - STFU GTK_WIDGET_SET_FLAGS (ok, GTK_CAN_DEFAULT);
706 + GTK_WIDGET_SET_FLAGS (ok, GTK_CAN_DEFAULT);
707 gtk_widget_show (ok);
708 gtk_widget_grab_focus (ok);
712 - STFU GTK_WIDGET_SET_FLAGS (cancel, GTK_CAN_DEFAULT);
713 + GTK_WIDGET_SET_FLAGS (cancel, GTK_CAN_DEFAULT);
714 gtk_widget_show (cancel);
716 gtk_widget_show (label);
717 gtk_widget_show (dialog);
719 - if (restart_button_p)
720 + if (button_type != D_NONE)
722 - gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
723 - GTK_SIGNAL_FUNC (warning_dialog_restart_cb),
725 + switch (button_type) {
726 + case D_LAUNCH: fn = GTK_SIGNAL_FUNC (warning_dialog_restart_cb); break;
727 + case D_GNOME: fn = GTK_SIGNAL_FUNC (warning_dialog_killg_cb); break;
728 + case D_KDE: fn = GTK_SIGNAL_FUNC (warning_dialog_killk_cb); break;
729 + default: abort(); break;
731 + gtk_signal_connect_object (GTK_OBJECT (ok), "clicked", fn,
733 gtk_signal_connect_object (GTK_OBJECT (cancel), "clicked",
734 GTK_SIGNAL_FUNC (warning_dialog_dismiss_cb),
736 sprintf (buf, "Error:\n\n%s", err);
738 strcpy (buf, "Unknown error!");
739 - warning_dialog (s->toplevel_widget, buf, False, 100);
740 + warning_dialog (s->toplevel_widget, buf, D_NONE, 100);
745 sprintf (buf, "Error:\n\n%s", err);
747 strcpy (buf, "Unknown error!");
748 - warning_dialog (s->toplevel_widget, buf, False, 100);
749 + warning_dialog (s->toplevel_widget, buf, D_NONE, 100);
754 "The XScreenSaver daemon doesn't seem to be running\n"
755 "on display \"%s\". Launch it now?"),
757 - warning_dialog (s->toplevel_widget, msg, True, 1);
758 + warning_dialog (s->toplevel_widget, msg, D_LAUNCH, 1);
764 warning_dialog (s->toplevel_widget,
766 - "No Help URL has been specified.\n"), False, 100);
767 + "No Help URL has been specified.\n"), D_NONE, 100);
771 @@ -1001,7 +1024,7 @@
773 strcat (buf, _("Please check your $PATH and permissions."));
775 - warning_dialog (s->toplevel_widget, buf, False, 1);
776 + warning_dialog (s->toplevel_widget, buf, D_NONE, 1);
779 force_dialog_repaint (s);
780 @@ -1038,12 +1061,12 @@
782 warning_dialog (s->toplevel_widget,
783 _("Error:\n\nCouldn't determine init file name!\n"),
788 char *b = (char *) malloc (strlen(f) + 1024);
789 sprintf (b, _("Error:\n\nCouldn't write %s\n"), f);
790 - warning_dialog (s->toplevel_widget, b, False, 100);
791 + warning_dialog (s->toplevel_widget, b, D_NONE, 100);
795 @@ -1106,7 +1129,7 @@
797 warning_dialog (GTK_WIDGET (button),
798 _("Error:\n\nno `manualCommand' resource set."),
804 @@ -1291,7 +1314,7 @@
806 "Unparsable time format: \"%s\"\n"),
808 - warning_dialog (s->toplevel_widget, b, False, 100);
809 + warning_dialog (s->toplevel_widget, b, D_NONE, 100);
813 @@ -1537,7 +1560,7 @@
815 sprintf (b, "Error:\n\n" "Directory does not exist: \"%s\"\n",
816 p2->image_directory);
817 - warning_dialog (s->toplevel_widget, b, False, 100);
818 + warning_dialog (s->toplevel_widget, b, D_NONE, 100);
822 @@ -1808,7 +1831,7 @@
826 - STFU g_return_if_fail (!gdk_pointer_is_grabbed ());
827 + g_return_if_fail (!gdk_pointer_is_grabbed ());
829 str = gtk_tree_path_to_string (path);
830 list_elt = strtol (str, NULL, 10);
831 @@ -1996,7 +2019,7 @@
834 sprintf (b, _("Error:\n\n" "Directory does not exist: \"%s\"\n"), path);
835 - warning_dialog (GTK_WIDGET (top), b, False, 100);
836 + warning_dialog (GTK_WIDGET (top), b, D_NONE, 100);
840 @@ -2026,7 +2049,7 @@
843 sprintf (b, _("Error:\n\n" "File does not exist: \"%s\"\n"), path);
844 - warning_dialog (GTK_WIDGET (top), b, False, 100);
845 + warning_dialog (GTK_WIDGET (top), b, D_NONE, 100);
849 @@ -2057,7 +2080,7 @@
852 sprintf (b, _("Error:\n\n" "File does not exist: \"%s\"\n"), path);
853 - warning_dialog (GTK_WIDGET (top), b, False, 100);
854 + warning_dialog (GTK_WIDGET (top), b, D_NONE, 100);
858 @@ -3414,7 +3437,7 @@
860 "file \"%s\" has changed, reloading.\n"),
862 - warning_dialog (s->toplevel_widget, b, False, 100);
863 + warning_dialog (s->toplevel_widget, b, D_NONE, 100);
866 load_init_file (dpy, p);
867 @@ -4247,6 +4270,77 @@
872 +gnome_screensaver_window (Screen *screen)
874 + Display *dpy = DisplayOfScreen (screen);
875 + Window root = RootWindowOfScreen (screen);
876 + Window parent, *kids;
877 + unsigned int nkids;
878 + Window gnome_window = 0;
881 + if (! XQueryTree (dpy, root, &root, &parent, &kids, &nkids))
883 + for (i = 0; i < nkids; i++)
887 + unsigned long nitems, bytesafter;
888 + unsigned char *name;
889 + if (XGetWindowProperty (dpy, kids[i], XA_WM_COMMAND, 0, 128,
890 + False, XA_STRING, &type, &format, &nitems,
891 + &bytesafter, &name)
894 + && !strcmp ((char *) name, "gnome-screensaver"))
896 + gnome_window = kids[i];
901 + if (kids) XFree ((char *) kids);
902 + return gnome_window;
906 +gnome_screensaver_active_p (void)
908 + Display *dpy = GDK_DISPLAY();
909 + Window w = gnome_screensaver_window (DefaultScreenOfDisplay (dpy));
910 + return (w ? True : False);
914 +kill_gnome_screensaver (void)
916 + Display *dpy = GDK_DISPLAY();
917 + Window w = gnome_screensaver_window (DefaultScreenOfDisplay (dpy));
918 + if (w) XKillClient (dpy, (XID) w);
922 +kde_screensaver_active_p (void)
924 + FILE *p = popen ("dcop kdesktop KScreensaverIface isEnabled 2>/dev/null",
927 + fgets (buf, sizeof(buf)-1, p);
929 + if (!strcmp (buf, "true\n"))
936 +kill_kde_screensaver (void)
938 + system ("dcop kdesktop KScreensaverIface enable false");
943 the_network_is_not_the_computer (state *s)
945 @@ -4360,12 +4454,36 @@
949 - warning_dialog (s->toplevel_widget, msg, True, 1);
950 + warning_dialog (s->toplevel_widget, msg, D_LAUNCH, 1);
952 if (rversion) free (rversion);
953 if (ruser) free (ruser);
954 if (rhost) free (rhost);
958 + /* Note: since these dialogs are not modal, they will stack up.
959 + So we do this check *after* popping up the "xscreensaver is not
960 + running" dialog so that these are on top. Good enough.
963 + if (gnome_screensaver_active_p ())
964 + warning_dialog (s->toplevel_widget,
966 + "The GNOME screensaver daemon appears to be running.\n"
967 + "It must be stopped for XScreenSaver to work properly.\n"
969 + "Stop the GNOME screen saver daemon now?\n"),
972 + if (kde_screensaver_active_p ())
973 + warning_dialog (s->toplevel_widget,
975 + "The KDE screen saver daemon appears to be running.\n"
976 + "It must be stopped for XScreenSaver to work properly.\n"
978 + "Stop the KDE screen saver daemon now?\n"),
983 Index: xscreensaver/driver/exec.c
984 ===================================================================
985 --- xscreensaver.orig/driver/exec.c 2008-07-16 23:47:00.000000000 +0200
986 +++ xscreensaver/driver/exec.c 2008-07-17 00:07:00.000000000 +0200
988 /* exec.c --- executes a program in *this* pid, without an intervening process.
989 - * xscreensaver, Copyright (c) 1991-2006 Jamie Zawinski <jwz@jwz.org>
990 + * xscreensaver, Copyright (c) 1991-2008 Jamie Zawinski <jwz@jwz.org>
992 * Permission to use, copy, modify, distribute, and sell this software and its
993 * documentation for any purpose is hereby granted without fee, provided that
999 - nice_process (nice_level);
1000 + nice_process (nice_level);
1002 hairy_p = !!strpbrk (command, "*?$&!<>[];`'\\\"=");
1003 /* note: = is in the above because of the sh syntax "FOO=bar cmd". */
1004 Index: xscreensaver/driver/lock.c
1005 ===================================================================
1006 --- xscreensaver.orig/driver/lock.c 2008-07-16 23:47:00.000000000 +0200
1007 +++ xscreensaver/driver/lock.c 2008-07-17 00:08:10.000000000 +0200
1009 /* lock.c --- handling the password dialog for locking-mode.
1010 - * xscreensaver, Copyright (c) 1993-2007 Jamie Zawinski <jwz@jwz.org>
1011 + * xscreensaver, Copyright (c) 1993-2008 Jamie Zawinski <jwz@jwz.org>
1013 * Permission to use, copy, modify, distribute, and sell this software and its
1014 * documentation for any purpose is hereby granted without fee, provided that
1017 extern void xss_authenticate(saver_info *si, Bool verbose_p);
1021 new_passwd_window (saver_info *si)
1023 passwd_dialog_data *pw;
1026 pw = (passwd_dialog_data *) calloc (1, sizeof(*pw));
1031 /* Display the button only if the "newLoginCommand" pref is non-null.
1033 @@ -406,13 +406,14 @@
1042 * info_msg and prompt may be NULL.
1046 make_passwd_window (saver_info *si,
1047 const char *info_msg,
1049 @@ -428,11 +429,15 @@
1051 cleanup_passwd_window (si);
1053 + if (! ssi) /* WTF? Trying to prompt while no screens connected? */
1057 - new_passwd_window (si);
1058 + if (new_passwd_window (si) < 0)
1061 if (!(pw = si->pw_data))
1067 @@ -614,10 +619,11 @@
1068 actually be visible; this takes into account virtual viewports as
1069 well as Xinerama. */
1072 - get_screen_viewport (pw->prompt_screen, &x, &y, &w, &h,
1073 - pw->previous_mouse_x, pw->previous_mouse_y,
1074 - si->prefs.verbose_p);
1075 + saver_screen_info *ssi = &si->screens [mouse_screen (si)];
1078 + int w = ssi->width;
1079 + int h = ssi->height;
1080 if (si->prefs.debug_p) w /= 2;
1081 pw->x = x + ((w + pw->width) / 2) - pw->width;
1082 pw->y = y + ((h + pw->height) / 2) - pw->height;
1085 XInstallColormap (si->dpy, cmap);
1086 draw_passwd_window (si);
1092 @@ -1463,6 +1471,7 @@
1093 static Bool any_mode_locked_p = False;
1094 saver_preferences *p = &si->prefs;
1096 + int real_nscreens = ScreenCount (si->dpy);
1099 XErrorHandler old_handler;
1100 @@ -1472,7 +1481,7 @@
1101 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1104 - for (screen = 0; screen < (si->xinerama_p ? 1 : si->nscreens); screen++)
1105 + for (screen = 0; screen < real_nscreens; screen++)
1107 XSync (si->dpy, False);
1108 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1109 @@ -1509,12 +1518,13 @@
1110 #ifdef HAVE_XF86VMODE
1111 saver_preferences *p = &si->prefs;
1113 + int real_nscreens = ScreenCount (si->dpy);
1116 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1119 - for (screen = 0; screen < si->nscreens; screen++)
1120 + for (screen = 0; screen < real_nscreens; screen++)
1122 saver_screen_info *ssi = &si->screens[screen];
1124 @@ -1932,9 +1942,11 @@
1125 info_msg_trimmed = remove_trailing_whitespace(info_msg);
1126 prompt_trimmed = remove_trailing_whitespace(prompt);
1128 - make_passwd_window(si, info_msg_trimmed, prompt_trimmed,
1129 - auth_msgs[i].type == AUTH_MSGTYPE_PROMPT_ECHO
1131 + if (make_passwd_window(si, info_msg_trimmed, prompt_trimmed,
1132 + auth_msgs[i].type == AUTH_MSGTYPE_PROMPT_ECHO
1137 if (info_msg_trimmed)
1138 free(info_msg_trimmed);
1139 Index: xscreensaver/driver/passwd-kerberos.c
1140 ===================================================================
1141 --- xscreensaver.orig/driver/passwd-kerberos.c 2008-07-16 23:47:00.000000000 +0200
1142 +++ xscreensaver/driver/passwd-kerberos.c 2008-07-17 00:07:00.000000000 +0200
1144 static const char *tk_file;
1145 #endif /* !HAVE_DARWIN */
1147 +/* warning suppression: duplicated in passwd.c */
1148 +extern Bool kerberos_lock_init (int argc, char **argv, Bool verbose_p);
1149 +extern Bool kerberos_passwd_valid_p (const char *typed_passwd, Bool verbose_p);
1152 /* Called at startup to grab user, instance, and realm information
1153 from the user's ticketfile (remember, name.inst@realm). Since we're
1154 Index: xscreensaver/driver/passwd-pam.c
1155 ===================================================================
1156 --- xscreensaver.orig/driver/passwd-pam.c 2008-07-16 23:47:00.000000000 +0200
1157 +++ xscreensaver/driver/passwd-pam.c 2008-07-17 00:07:00.000000000 +0200
1158 @@ -452,6 +452,14 @@
1160 ret = si->unlock_cb(nmsgs, messages, &authresp, si);
1162 + /* #### If the user times out, or hits ESC or Cancel, we return PAM_CONV_ERR,
1163 + and PAM logs this as an authentication failure. It would be nice if
1164 + there was some way to indicate that this was a "cancel" rather than
1165 + a "fail", so that it wouldn't show up in syslog, but I think the
1166 + only options are PAM_SUCCESS and PAM_CONV_ERR. (I think that
1167 + PAM_ABORT means "internal error", not "cancel".) Bleh.
1172 for (i = 0; i < nmsgs; ++i)
1173 Index: xscreensaver/driver/pdf2jpeg.m
1174 ===================================================================
1175 --- xscreensaver.orig/driver/pdf2jpeg.m 2008-07-16 23:47:00.000000000 +0200
1176 +++ xscreensaver/driver/pdf2jpeg.m 2008-07-17 00:07:00.000000000 +0200
1178 /* pdf2jpeg -- converts a PDF file to a JPEG file, using Cocoa
1180 - * Copyright (c) 2003 by Jamie Zawinski <jwz@jwz.org>
1181 + * Copyright (c) 2003, 2008 by Jamie Zawinski <jwz@jwz.org>
1183 * Permission to use, copy, modify, distribute, and sell this software and its
1184 * documentation for any purpose is hereby granted without fee, provided that
1186 const char *progname = argv[0];
1187 const char *infile = 0, *outfile = 0;
1188 double compression = 0.85;
1189 + double scale = 1.0;
1195 compression = q / 100.0;
1197 + else if (!strcmp (argv[i], "-scale"))
1200 + if (1 != sscanf (argv[++i], " %f %c", &s, &c) ||
1203 + fprintf (stderr, "%s: scale must be 0.0 - 50.0 (%f)\n",
1209 else if (!strcmp (argv[i], "-verbose"))
1211 else if (!strcmp (argv[i], "-v") ||
1216 - "usage: %s [-verbose] [-quality NN] "
1217 + "usage: %s [-verbose] [-scale N] [-quality NN] "
1218 "infile.pdf outfile.jpg\n",
1221 @@ -93,11 +106,16 @@
1222 NSPDFImageRep *pdf_rep = [NSPDFImageRep imageRepWithData:pdf_data];
1224 // Create an NSImage instance
1225 - NSImage *image = [[NSImage alloc] initWithSize:[pdf_rep size]];
1227 + rect.size = [pdf_rep size];
1228 + rect.size.width *= scale;
1229 + rect.size.height *= scale;
1230 + rect.origin.x = rect.origin.y = 0;
1231 + NSImage *image = [[NSImage alloc] initWithSize:rect.size];
1233 // Draw the PDFImageRep in the NSImage
1235 - [pdf_rep drawAtPoint:NSMakePoint(0.0,0.0)];
1236 + [pdf_rep drawInRect:rect];
1237 [image unlockFocus];
1239 // Load the NSImage's contents into an NSBitmapImageRep:
1240 Index: xscreensaver/driver/prefs.c
1241 ===================================================================
1242 --- xscreensaver.orig/driver/prefs.c 2008-07-16 23:47:00.000000000 +0200
1243 +++ xscreensaver/driver/prefs.c 2008-07-17 00:07:00.000000000 +0200
1245 /* dotfile.c --- management of the ~/.xscreensaver file.
1246 - * xscreensaver, Copyright (c) 1998-2006 Jamie Zawinski <jwz@jwz.org>
1247 + * xscreensaver, Copyright (c) 1998-2008 Jamie Zawinski <jwz@jwz.org>
1249 * Permission to use, copy, modify, distribute, and sell this software and its
1250 * documentation for any purpose is hereby granted without fee, provided that
1254 "captureStdout", /* not saved -- obsolete */
1255 + "logFile", /* not saved */
1256 "ignoreUninstalledPrograms",
1260 CHECK("fadeTicks") type = pref_int, i = p->fade_ticks;
1261 CHECK("captureStderr") type = pref_bool, b = p->capture_stderr_p;
1262 CHECK("captureStdout") continue; /* don't save */
1263 + CHECK("logFile") continue; /* don't save */
1264 CHECK("ignoreUninstalledPrograms")
1265 type = pref_bool, b = p->ignore_uninstalled_p;
1267 Index: xscreensaver/driver/screens.c
1268 ===================================================================
1269 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
1270 +++ xscreensaver/driver/screens.c 2008-07-17 00:07:00.000000000 +0200
1272 +/* screens.c --- dealing with RANDR, Xinerama, and VidMode Viewports.
1273 + * xscreensaver, Copyright (c) 1991-2008 Jamie Zawinski <jwz@jwz.org>
1275 + * Permission to use, copy, modify, distribute, and sell this software and its
1276 + * documentation for any purpose is hereby granted without fee, provided that
1277 + * the above copyright notice appear in all copies and that both that
1278 + * copyright notice and this permission notice appear in supporting
1279 + * documentation. No representations are made about the suitability of this
1280 + * software for any purpose. It is provided "as is" without express or
1281 + * implied warranty.
1284 +/* There are a bunch of different mechanisms for multiple monitors
1285 + * available in X. XScreenSaver needs to care about this for two
1286 + * reasons: first, to ensure that all visible areas go black; and
1287 + * second, so that the windows of screen savers exactly fill the
1288 + * glass of each monitor (instead of one saver spanning multiple
1289 + * monitors, or a monitor displaying only a sub-rectangle of the
1292 + * 1) Multi-screen:
1294 + * This is the original way. Each monitor gets its own display
1295 + * number. :0.0 is the first one, :0.1 is the next, etc. The
1296 + * value of $DISPLAY determines which screen windows open on by
1297 + * default. A single app can open windows on multiple screens
1298 + * with the same display connection, but windows cannot be moved
1299 + * from one screen to another. The mouse can be moved from one
1300 + * screen to another, though. Screens may be different depths
1301 + * (e.g., one can be TrueColor and one can be PseudoColor.)
1302 + * Screens cannot be resized or moved without restarting X.
1304 + * Everyone hates this way of doing things because of the
1305 + * inability to move a window from one screen to another without
1306 + * restarting the application.
1310 + * There is a single giant root window that spans all the
1311 + * monitors. All monitors are the same depth, and windows can be
1312 + * moved around. Applications can learn which rectangles are
1313 + * actually visible on monitors by querying the Xinerama server
1314 + * extension. (If you don't do that, you end up with dialog
1315 + * boxes that try to appear in the middle of the screen actually
1316 + * spanning the gap between two monitors.)
1318 + * Xinerama doesn't work with DRI, which means that if you use
1319 + * it, you lose hardware acceleration on OpenGL programs. Also,
1320 + * screens can't be resized or moved without restarting X.
1322 + * 3) Vidmode Viewports:
1324 + * With this extension, the root window can be bigger than the
1325 + * monitor. Moving the mouse near the edges of the screen
1326 + * scrolls around, like a pan-and-scan movie. There can also be
1327 + * a hot key for changing the monitor's resolution (zooming
1330 + * Trying to combine this with Xinerama crashes the server, so
1331 + * you can only use this if you have only a single screen, or are
1332 + * in old-multi-screen mode.
1334 + * Also, half the time it doesn't work at all: it tends to lie
1335 + * about the size of the rectangle in use.
1339 + * The first version of the "Resize and Rotate" extension let you
1340 + * change the resolution of a screen on the fly. The root window
1341 + * would actually resize. However, it was also incompatible with
1342 + * Xinerama (did it crash, or just do nothing? I can't remember)
1343 + * so you needed to be in single-screen or old multi-screen mode.
1344 + * I believe RANDR could co-exist with Vidmode Viewports, but I'm
1349 + * Finally, RANDR added the functionality of Xinerama, plus some.
1350 + * Each X screen (in the sense of #1, "multi-screen") can have a
1351 + * number of sub-rectangles that are displayed on monitors, and
1352 + * each of those sub-rectangles can be displayed on more than one
1353 + * monitor. So it's possible (I think) to have a hybrid of
1354 + * multi-screen and Xinerama (e.g., to have two monitors running
1355 + * in one depth, and three monitors running in another?)
1356 + * Typically though, there will be a single X screen, with
1357 + * Xinerama-like division of that large root window onto multiple
1358 + * monitors. Also everything's dynamic: monitors can be added,
1359 + * removed, and resized at runtime.
1361 + * I believe that as of RANDR 1.2, the Xinerama extension still
1362 + * exists but only as a compatiblity layer: it's actually
1363 + * returning data from the RANDR extension.
1365 + * Though RANDR 1.2 allows the same image to be cloned onto more
1366 + * than one monitor, and also allows one monitor to show a
1367 + * subsection of something on another monitor (e.g., the
1368 + * rectangles can be enclosed or overlap). Since there's no way
1369 + * to put seperate savers on those duplicated-or-overlapping
1370 + * monitors, xscreensaver just ignores them (which allows them to
1371 + * display duplicates or overlaps).
1374 +#ifdef HAVE_CONFIG_H
1375 +# include "config.h"
1378 +#include <X11/Xlib.h>
1381 +# include <X11/extensions/Xrandr.h>
1382 +#endif /* HAVE_RANDR */
1384 +#ifdef HAVE_XINERAMA
1385 +# include <X11/extensions/Xinerama.h>
1386 +#endif /* HAVE_XINERAMA */
1388 +#ifdef HAVE_XF86VMODE
1389 +# include <X11/extensions/xf86vmode.h>
1390 +#endif /* HAVE_XF86VMODE */
1392 +/* This file doesn't need the Xt headers, so stub these types out... */
1394 +#define XtAppContext void*
1395 +#define XrmDatabase void*
1396 +#define XtIntervalId void*
1397 +#define XtPointer void*
1398 +#define Widget void*
1400 +#include "xscreensaver.h"
1401 +#include "visual.h"
1404 +typedef enum { S_SANE, S_ENCLOSED, S_DUPLICATE, S_OVERLAP,
1405 + S_OFFSCREEN, S_DISABLED } monitor_sanity;
1407 +/* 'typedef monitor' is in types.h */
1412 + int x, y, width, height;
1413 + monitor_sanity sanity; /* I'm not crazy you're the one who's crazy */
1414 + int enemy; /* which monitor it overlaps or duplicates */
1418 +free_monitors (monitor **monitors)
1420 + monitor **m2 = monitors;
1421 + if (! monitors) return;
1424 + if ((*m2)->desc) free ((*m2)->desc);
1432 +#ifdef HAVE_XINERAMA
1435 +xinerama_scan_monitors (Display *dpy)
1437 + Screen *screen = DefaultScreenOfDisplay (dpy);
1438 + int event, error, nscreens, i;
1439 + XineramaScreenInfo *xsi;
1440 + monitor **monitors;
1442 + if (! XineramaQueryExtension (dpy, &event, &error))
1445 + if (! XineramaIsActive (dpy))
1448 + xsi = XineramaQueryScreens (dpy, &nscreens);
1449 + if (!xsi) return 0;
1451 + monitors = (monitor **) calloc (nscreens + 1, sizeof(*monitors));
1452 + if (!monitors) return 0;
1454 + for (i = 0; i < nscreens; i++)
1456 + monitor *m = (monitor *) calloc (1, sizeof (monitor));
1459 + m->screen = screen;
1460 + m->x = xsi[i].x_org;
1461 + m->y = xsi[i].y_org;
1462 + m->width = xsi[i].width;
1463 + m->height = xsi[i].height;
1468 +#endif /* HAVE_XINERAMA */
1471 +#ifdef HAVE_XF86VMODE
1474 +vidmode_scan_monitors (Display *dpy)
1476 + int event, error, nscreens, i;
1477 + monitor **monitors;
1479 + /* Note that XF86VidModeGetViewPort() tends to be full of lies on laptops
1480 + that have a docking station or external monitor that runs in a different
1481 + resolution than the laptop's screen:
1483 + http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=81593
1484 + http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=208417
1485 + http://bugs.xfree86.org/show_bug.cgi?id=421
1487 + Presumably this is fixed by using RANDR instead of VidMode.
1490 +# ifdef HAVE_XINERAMA
1491 + /* Attempts to use the VidMode extension when the Xinerama extension is
1492 + active can result in a server crash! Yay! */
1493 + if (XQueryExtension (dpy, "XINERAMA", &error, &event, &error))
1495 +# endif /* !HAVE_XINERAMA */
1497 + if (! XF86VidModeQueryExtension (dpy, &event, &error))
1500 + nscreens = ScreenCount (dpy);
1501 + monitors = (monitor **) calloc (nscreens + 1, sizeof(*monitors));
1502 + if (!monitors) return 0;
1504 + for (i = 0; i < nscreens; i++)
1506 + monitor *m = (monitor *) calloc (1, sizeof (monitor));
1507 + XF86VidModeModeLine ml;
1509 + Screen *screen = ScreenOfDisplay (dpy, i);
1513 + m->screen = screen;
1515 + if (! safe_XF86VidModeGetViewPort (dpy, i, &m->x, &m->y))
1518 + if (XF86VidModeGetModeLine (dpy, i, &dot, &ml))
1520 + m->width = ml.hdisplay;
1521 + m->height = ml.vdisplay;
1524 + /* Apparently, though the server stores the X position in increments of
1525 + 1 pixel, it will only make changes to the *display* in some other
1526 + increment. With XF86_SVGA on a Thinkpad, the display only updates
1527 + in multiples of 8 pixels when in 8-bit mode, and in multiples of 4
1528 + pixels in 16-bit mode. I don't know what it does in 24- and 32-bit
1529 + mode, because I don't have enough video memory to find out.
1531 + I consider it a bug that XF86VidModeGetViewPort() is telling me the
1532 + server's *target* scroll position rather than the server's *actual*
1533 + scroll position. David Dawes agrees, and says they may fix this in
1534 + XFree86 4.0, but it's notrivial.
1536 + He also confirms that this behavior is server-dependent, so the
1537 + actual scroll position cannot be reliably determined by the client.
1538 + So... that means the only solution is to provide a ``sandbox''
1539 + around the blackout window -- we make the window be up to N pixels
1540 + larger than the viewport on both the left and right sides. That
1541 + means some part of the outer edges of each hack might not be
1542 + visible, but screw it.
1544 + I'm going to guess that 16 pixels is enough, and that the Y dimension
1545 + doesn't have this problem.
1547 + The drawback of doing this, of course, is that some of the screenhacks
1548 + will still look pretty stupid -- for example, "slidescreen" will cut
1549 + off the left and right edges of the grid, etc.
1552 + if (m->x > 0 && m->x < m->width - ml.hdisplay)
1554 + /* Not at left edge or right edge:
1555 + Round X position down to next lower multiple of FUDGE.
1556 + Increase width by 2*FUDGE in case some server rounds up.
1558 + m->x = ((m->x - 1) / FUDGE) * FUDGE;
1559 + m->width += (FUDGE * 2);
1567 +#endif /* HAVE_XF86VMODE */
1573 +randr_scan_monitors (Display *dpy)
1575 + int event, error, major, minor, nscreens, i, j;
1576 + monitor **monitors;
1577 + Bool new_randr_p = False;
1579 + if (! XRRQueryExtension (dpy, &event, &error))
1582 + if (! XRRQueryVersion (dpy, &major, &minor))
1585 + if (major <= 0) /* Protocol was still in flux back then -- fuck it. */
1588 +# ifdef HAVE_RANDR_12
1589 + new_randr_p = (major > 1 || (major == 1 && minor >= 2));
1592 + if (! new_randr_p)
1593 + /* RANDR 1.0 -- no Xinerama-like virtual screens. */
1594 + nscreens = ScreenCount (dpy);
1595 + else /* RANDR 1.2 or newer -- built-in Xinerama */
1597 +# ifdef HAVE_RANDR_12
1598 + int xsc = ScreenCount (dpy);
1600 + /* Add up the virtual screens on each X screen. */
1601 + for (i = 0; i < xsc; i++)
1603 + XRRScreenResources *res =
1604 + XRRGetScreenResources (dpy, RootWindow (dpy, i));
1605 + nscreens += res->noutput;
1606 + XRRFreeScreenResources (res);
1608 +# endif /* HAVE_RANDR_12 */
1611 + monitors = (monitor **) calloc (nscreens + 1, sizeof(*monitors));
1612 + if (!monitors) return 0;
1614 + for (i = 0, j = 0; i < ScreenCount (dpy); i++)
1616 + Screen *screen = ScreenOfDisplay (dpy, j);
1618 + if (! new_randr_p) /* RANDR 1.0 */
1620 + XRRScreenConfiguration *rrc;
1621 + monitor *m = (monitor *) calloc (1, sizeof (monitor));
1623 + m->screen = screen;
1626 + rrc = XRRGetScreenInfo (dpy, RootWindowOfScreen (screen));
1630 + Rotation rot = ~0;
1631 + XRRScreenSize *rrsizes;
1634 + size = XRRConfigCurrentConfiguration (rrc, &rot);
1635 + rrsizes = XRRConfigSizes (rrc, &nsizes);
1637 + if (rot & (RR_Rotate_90|RR_Rotate_270))
1639 + m->width = rrsizes[size].height;
1640 + m->height = rrsizes[size].width;
1644 + m->width = rrsizes[size].width;
1645 + m->height = rrsizes[size].height;
1648 + /* don't free 'rrsizes' */
1649 + XRRFreeScreenConfigInfo (rrc);
1652 + else /* RANDR 1.2 or newer */
1654 +# ifdef HAVE_RANDR_12
1656 + XRRScreenResources *res =
1657 + XRRGetScreenResources (dpy, RootWindowOfScreen (screen));
1658 + for (k = 0; k < res->noutput; k++)
1660 + monitor *m = (monitor *) calloc (1, sizeof (monitor));
1661 + XRROutputInfo *rroi = XRRGetOutputInfo (dpy, res,
1663 + RRCrtc crtc = (rroi->crtc ? rroi->crtc : rroi->crtcs[0]);
1664 + XRRCrtcInfo *crtci = XRRGetCrtcInfo (dpy, res, crtc);
1667 + m->screen = screen;
1668 + m->id = (i * 1000) + j;
1669 + m->desc = (rroi->name ? strdup (rroi->name) : 0);
1673 + if (crtci->rotation & (RR_Rotate_90|RR_Rotate_270))
1675 + m->width = crtci->height;
1676 + m->height = crtci->width;
1680 + m->width = crtci->width;
1681 + m->height = crtci->height;
1686 + if (rroi->connection == RR_Disconnected)
1687 + m->sanity = S_DISABLED;
1688 + /* #### do the same for RR_UnknownConnection? */
1690 + XRRFreeCrtcInfo (crtci);
1691 + XRRFreeOutputInfo (rroi);
1693 + XRRFreeScreenResources (res);
1694 +# endif /* HAVE_RANDR_12 */
1701 +#endif /* HAVE_RANDR */
1705 +basic_scan_monitors (Display *dpy)
1707 + int nscreens = ScreenCount (dpy);
1709 + monitor **monitors = (monitor **) calloc (nscreens + 1, sizeof(*monitors));
1710 + if (!monitors) return 0;
1712 + for (i = 0; i < nscreens; i++)
1714 + Screen *screen = ScreenOfDisplay (dpy, i);
1715 + monitor *m = (monitor *) calloc (1, sizeof (monitor));
1718 + m->screen = screen;
1721 + m->width = WidthOfScreen (screen);
1722 + m->height = HeightOfScreen (screen);
1728 +#ifdef DEBUG_MULTISCREEN
1730 +/* If DEBUG_MULTISCREEN is defined, then in "-debug" mode, xscreensaver
1731 + will pretend that it is changing the number of connected monitors
1732 + every few seconds, using the geometries in the following list,
1733 + for stress-testing purposes.
1736 +debug_scan_monitors (Display *dpy)
1738 + static const char * const geoms[] = {
1742 + "800x600+0+22,800x600+800+22",
1743 + "800x600+0+22,800x600+800+22,800x600+300+622",
1744 + "800x600+0+22,800x600+800+22,800x600+0+622,800x600+800+622",
1745 + "640x480+0+22,640x480+640+22,640x480+0+502,640x480+640+502",
1746 + "640x480+240+22,640x480+0+502,640x480+640+502",
1747 + "640x480+0+200,640x480+640+200",
1749 + "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"
1751 + static int index = 0;
1752 + monitor **monitors = (monitor **) calloc (100, sizeof(*monitors));
1754 + Screen *screen = DefaultScreenOfDisplay (dpy);
1756 + char *s = strdup (geoms[index]);
1757 + char *token = strtok (s, ",");
1760 + monitor *m = calloc (1, sizeof (monitor));
1763 + m->screen = screen;
1764 + if (4 != sscanf (token, "%dx%d+%d+%d%c",
1765 + &m->width, &m->height, &m->x, &m->y, &c))
1769 + monitors[nscreens++] = m;
1770 + token = strtok (0, ",");
1774 + index = (index+1) % countof(geoms);
1778 +#endif /* DEBUG_MULTISCREEN */
1783 +quadruple (monitor **monitors, Bool debug_p)
1785 + int i, j, count = 0;
1786 + monitor **monitors2;
1787 + while (monitors[count])
1789 + monitors2 = (monitor **) calloc (count * 4 + 1, sizeof(*monitors));
1790 + if (!monitors2) abort();
1792 + for (i = 0, j = 0; i < count; i++)
1795 + for (k = 0; k < 4; k++)
1797 + monitors2[j+k] = (monitor *) calloc (1, sizeof (monitor));
1798 + *monitors2[j+k] = *monitors[i];
1799 + monitors2[j+k]->width /= (debug_p ? 4 : 2);
1800 + monitors2[j+k]->height /= 2;
1801 + monitors2[j+k]->id = (monitors[i]->id * 4) + k;
1802 + monitors2[j+k]->name = (monitors[i]->name
1803 + ? strdup (monitors[i]->name) : 0);
1805 + monitors2[j+1]->x += monitors2[j]->width;
1806 + monitors2[j+2]->y += monitors2[j]->height;
1807 + monitors2[j+3]->x += monitors2[j]->width;
1808 + monitors2[j+3]->y += monitors2[j]->height;
1812 + free_monitors (monitors);
1815 +#endif /* QUAD_MODE */
1819 +scan_monitors (saver_info *si)
1821 + saver_preferences *p = &si->prefs;
1822 + monitor **monitors = 0;
1824 +# ifdef DEBUG_MULTISCREEN
1825 + if (! monitors) monitors = debug_scan_monitors (si->dpy);
1829 + if (! p->getviewport_full_of_lies_p)
1830 + if (! monitors) monitors = randr_scan_monitors (si->dpy);
1833 +# ifdef HAVE_XF86VMODE
1834 + if (! monitors) monitors = vidmode_scan_monitors (si->dpy);
1837 +# ifdef HAVE_XF86VMODE
1838 + if (! monitors) monitors = xinerama_scan_monitors (si->dpy);
1841 + if (! monitors) monitors = basic_scan_monitors (si->dpy);
1845 + monitors = quadruple (monitors, p->debug_p);
1853 +monitors_overlap_p (monitor *a, monitor *b)
1855 + /* Two rectangles overlap if the max of the tops is less than the
1856 + min of the bottoms and the max of the lefts is less than the min
1861 +# define MAX(A,B) ((A)>(B)?(A):(B))
1862 +# define MIN(A,B) ((A)<(B)?(A):(B))
1864 + int maxleft = MAX(a->x, b->x);
1865 + int maxtop = MAX(a->y, b->y);
1866 + int minright = MIN(a->x + a->width - 1, b->x + b->width);
1867 + int minbot = MIN(a->y + a->height - 1, b->y + b->height);
1868 + return (maxtop < minbot && maxleft < minright);
1872 +/* Mark the ones that overlap, etc.
1875 +check_monitor_sanity (monitor **monitors)
1877 + int i, j, count = 0;
1879 + while (monitors[count])
1882 +# define X1 monitors[i]->x
1883 +# define X2 monitors[j]->x
1884 +# define Y1 monitors[i]->y
1885 +# define Y2 monitors[j]->y
1886 +# define W1 monitors[i]->width
1887 +# define W2 monitors[j]->width
1888 +# define H1 monitors[i]->height
1889 +# define H2 monitors[j]->height
1891 + /* If a monitor is enclosed by any other monitor, that's insane.
1893 + for (i = 0; i < count; i++)
1894 + for (j = 0; j < count; j++)
1896 + monitors[i]->sanity == S_SANE &&
1897 + monitors[j]->sanity == S_SANE &&
1900 + (X2+W2) <= (X1+W1) &&
1901 + (Y2+H2) <= (Y1+H1))
1907 + monitors[j]->sanity = S_DUPLICATE;
1909 + monitors[j]->sanity = S_ENCLOSED;
1910 + monitors[j]->enemy = i;
1913 + /* After checking for enclosure, check for other lossage against earlier
1914 + monitors. We do enclosure first so that we make sure to pick the
1917 + for (i = 0; i < count; i++)
1918 + for (j = 0; j < i; j++)
1920 + if (monitors[i]->sanity != S_SANE) continue; /* already marked */
1921 + if (monitors[j]->sanity != S_SANE) continue;
1923 + if (monitors_overlap_p (monitors[i], monitors[j]))
1925 + monitors[i]->sanity = S_OVERLAP;
1926 + monitors[i]->enemy = j;
1930 + /* Finally, make sure all monitors are enclosed by their X screen.
1931 + Xinerama sometimes reports 1024x768 VPs at -1936862040, -1953705044.
1933 + for (i = 0; i < count; i++)
1935 + int sw = WidthOfScreen (monitors[i]->screen) * 2;
1936 + int sh = HeightOfScreen (monitors[i]->screen) * 2;
1937 + if (monitors[i]->sanity != S_SANE) continue; /* already marked */
1938 + if (X1 < 0 || Y1 < 0 ||
1939 + W1 <= 0 || H1 <= 0 ||
1940 + X1+W1 > sw || Y1+H1 > sh)
1942 + monitors[i]->sanity = S_OFFSCREEN;
1943 + monitors[i]->enemy = 0;
1959 +layouts_differ_p (monitor **a, monitor **b)
1961 + if (!a || !b) return True;
1966 + if ((*a)->screen != (*b)->screen ||
1967 + (*a)->x != (*b)->x ||
1968 + (*a)->y != (*b)->y ||
1969 + (*a)->width != (*b)->width ||
1970 + (*a)->height != (*b)->height)
1975 + if (*a) return True;
1976 + if (*b) return True;
1983 +describe_monitor_layout (saver_info *si)
1985 + monitor **monitors = si->monitor_layout;
1987 + int good_count = 0;
1988 + int bad_count = 0;
1989 + while (monitors[count])
1991 + if (monitors[count]->sanity == S_SANE)
1999 + fprintf (stderr, "%s: no screens!\n", blurb());
2003 + fprintf (stderr, "%s: screens in use: %d\n", blurb(), good_count);
2004 + for (i = 0; i < count; i++)
2006 + monitor *m = monitors[i];
2007 + if (m->sanity != S_SANE) continue;
2008 + fprintf (stderr, "%s: %3d/%d: %dx%d+%d+%d",
2009 + blurb(), m->id, screen_number (m->screen),
2010 + m->width, m->height, m->x, m->y);
2011 + if (m->desc && *m->desc) fprintf (stderr, " (%s)", m->desc);
2012 + fprintf (stderr, "\n");
2014 + if (bad_count > 0)
2016 + fprintf (stderr, "%s: rejected screens: %d\n", blurb(), bad_count);
2017 + for (i = 0; i < count; i++)
2019 + monitor *m = monitors[i];
2020 + monitor *e = monitors[m->enemy];
2021 + if (m->sanity == S_SANE) continue;
2022 + fprintf (stderr, "%s: %3d/%d: %dx%d+%d+%d",
2023 + blurb(), m->id, screen_number (m->screen),
2024 + m->width, m->height, m->x, m->y);
2025 + if (m->desc && *m->desc) fprintf (stderr, " (%s)", m->desc);
2026 + fprintf (stderr, " -- ");
2027 + switch (m->sanity)
2029 + case S_SANE: abort(); break;
2031 + fprintf (stderr, "enclosed by %d (%dx%d+%d+%d)\n",
2032 + e->id, e->width, e->height, e->x, e->y);
2035 + fprintf (stderr, "duplicate of %d\n", e->id);
2038 + fprintf (stderr, "overlaps %d (%dx%d+%d+%d)\n",
2039 + e->id, e->width, e->height, e->x, e->y);
2042 + fprintf (stderr, "off screen (%dx%d)\n",
2043 + WidthOfScreen (e->screen),
2044 + HeightOfScreen (e->screen));
2047 + fprintf (stderr, "output disabled\n");
2056 +/* Synchronize the contents of si->ssi to the current state of the monitors.
2057 + Doesn't change anything if nothing has changed; otherwise, alters and
2058 + reuses existing saver_screen_info structs as much as possible.
2059 + Returns True if anything changed.
2062 +update_screen_layout (saver_info *si)
2064 + monitor **monitors = scan_monitors (si);
2066 + int good_count = 0;
2068 + int seen_screens[100] = { 0, };
2070 + if (! layouts_differ_p (monitors, si->monitor_layout))
2072 + free_monitors (monitors);
2076 + free_monitors (si->monitor_layout);
2077 + si->monitor_layout = monitors;
2078 + check_monitor_sanity (si->monitor_layout);
2080 + while (monitors[count])
2082 + if (monitors[count]->sanity == S_SANE)
2087 + if (si->ssi_count == 0)
2089 + si->ssi_count = 10;
2090 + si->screens = (saver_screen_info *)
2091 + calloc (sizeof(*si->screens), si->ssi_count);
2094 + if (si->ssi_count <= good_count)
2096 + si->ssi_count = good_count + 10;
2097 + si->screens = (saver_screen_info *)
2098 + realloc (si->screens, sizeof(*si->screens) * si->ssi_count);
2099 + memset (si->screens + si->nscreens, 0,
2100 + sizeof(*si->screens) * (si->ssi_count - si->nscreens));
2103 + if (! si->screens) abort();
2105 + si->nscreens = good_count;
2107 + /* Regenerate the list of GL visuals as needed. */
2108 + if (si->best_gl_visuals)
2109 + free (si->best_gl_visuals);
2110 + si->best_gl_visuals = 0;
2112 + for (i = 0, j = 0; i < count; i++)
2114 + monitor *m = monitors[i];
2115 + saver_screen_info *ssi = &si->screens[j];
2116 + Screen *old_screen = ssi->screen;
2118 + if (monitors[i]->sanity != S_SANE) continue;
2123 + sn = screen_number (m->screen);
2124 + ssi->screen = m->screen;
2125 + ssi->real_screen_number = sn;
2126 + ssi->real_screen_p = (seen_screens[sn] == 0);
2127 + seen_screens[sn]++;
2129 + ssi->default_visual =
2130 + get_visual_resource (ssi->screen, "visualID", "VisualID", False);
2131 + ssi->current_visual = ssi->default_visual;
2132 + ssi->current_depth = visual_depth (ssi->screen, ssi->current_visual);
2134 + /* If the screen changed (or if this is the first time) we need
2135 + a new toplevel shell for this screen's depth.
2137 + if (ssi->screen != old_screen)
2138 + initialize_screen_root_widget (ssi);
2140 + ssi->poll_mouse_last_root_x = -1;
2141 + ssi->poll_mouse_last_root_y = -1;
2145 + ssi->width = m->width;
2146 + ssi->height = m->height;
2148 +# ifndef DEBUG_MULTISCREEN
2150 + saver_preferences *p = &si->prefs;
2163 + si->default_screen = &si->screens[0];
2166 Index: xscreensaver/driver/splash.c
2167 ===================================================================
2168 --- xscreensaver.orig/driver/splash.c 2008-07-16 23:47:00.000000000 +0200
2169 +++ xscreensaver/driver/splash.c 2008-07-17 00:07:00.000000000 +0200
2171 -/* xscreensaver, Copyright (c) 1991-2006 Jamie Zawinski <jwz@netscape.com>
2172 +/* xscreensaver, Copyright (c) 1991-2008 Jamie Zawinski <jwz@netscape.com>
2174 * Permission to use, copy, modify, distribute, and sell this software and its
2175 * documentation for any purpose is hereby granted without fee, provided that
2176 @@ -170,6 +170,10 @@
2179 ssi = &si->screens[mouse_screen (si)];
2181 + if (!ssi || !ssi->screen)
2182 + return; /* WTF? Trying to splash while no screens connected? */
2184 cmap = DefaultColormapOfScreen (ssi->screen);
2186 sp = (splash_dialog_data *) calloc (1, sizeof(*sp));
2188 attrs.event_mask = (ExposureMask | ButtonPressMask | ButtonReleaseMask);
2192 + int sx = 0, sy = 0, w, h;
2193 int mouse_x = 0, mouse_y = 0;
2196 @@ -393,7 +397,10 @@
2200 - get_screen_viewport (ssi, &sx, &sy, &w, &h, mouse_x, mouse_y, False);
2205 if (si->prefs.debug_p) w /= 2;
2206 x = sx + (((w + sp->width) / 2) - sp->width);
2207 y = sy + (((h + sp->height) / 2) - sp->height);
2208 Index: xscreensaver/driver/stderr.c
2209 ===================================================================
2210 --- xscreensaver.orig/driver/stderr.c 2008-07-16 23:47:00.000000000 +0200
2211 +++ xscreensaver/driver/stderr.c 2008-07-17 00:07:00.000000000 +0200
2213 /* stderr.c --- capturing stdout/stderr output onto the screensaver window.
2214 - * xscreensaver, Copyright (c) 1991-2006 Jamie Zawinski <jwz@jwz.org>
2215 + * xscreensaver, Copyright (c) 1991-2008 Jamie Zawinski <jwz@jwz.org>
2217 * Permission to use, copy, modify, distribute, and sell this software and its
2218 * documentation for any purpose is hereby granted without fee, provided that
2219 @@ -472,6 +472,47 @@
2223 +/* If the "-log file" command-line option has been specified,
2224 + open the file for append, and redirect stdout/stderr there.
2225 + This is called very early, before initialize_stderr().
2228 +stderr_log_file (saver_info *si)
2230 + int stdout_fd = 1;
2231 + int stderr_fd = 2;
2232 + const char *filename = get_string_resource (si->dpy, "logFile", "LogFile");
2235 + if (!filename || !*filename) return;
2237 + fd = open (filename, O_WRONLY | O_APPEND | O_CREAT, 0666);
2243 + sprintf (buf, "%.100s: %.100s", blurb(), filename);
2250 + fprintf (stderr, "%s: logging to file %s\n", blurb(), filename);
2252 + if (dup2 (fd, stdout_fd) < 0) goto FAIL;
2253 + if (dup2 (fd, stderr_fd) < 0) goto FAIL;
2255 + fprintf (stderr, "\n\n"
2256 + "##########################################################################\n"
2257 + "%s: logging to \"%s\" at %s\n"
2258 + "##########################################################################\n"
2260 + blurb(), filename, timestring());
2264 /* If there is anything in the stderr buffer, flush it to the real stderr.
2265 This does no X operations. Call this when exiting to make sure any
2266 last words actually show up.
2269 stderr_callback ((XtPointer) si, &stderr_stdout_read_fd, 0);
2271 - if (stderr_buffer &&
2273 + if (stderr_tail &&
2274 stderr_buffer < stderr_tail)
2277 Index: xscreensaver/driver/subprocs.c
2278 ===================================================================
2279 --- xscreensaver.orig/driver/subprocs.c 2008-07-16 23:47:00.000000000 +0200
2280 +++ xscreensaver/driver/subprocs.c 2008-07-17 00:07:00.000000000 +0200
2283 close (ConnectionNumber (si->dpy)); /* close display fd */
2284 limit_subproc_memory (p->inferior_memory_limit, p->verbose_p);
2285 - hack_subproc_environment (ssi); /* set $DISPLAY */
2286 + hack_subproc_environment (ssi->screen, ssi->screensaver_window);
2289 fprintf (stderr, "%s: %d: spawning \"%s\" in pid %lu.\n",
2290 @@ -878,14 +878,22 @@
2295 -spawn_screenhack_1 (saver_screen_info *ssi, Bool first_time_p)
2297 +spawn_screenhack (saver_screen_info *ssi)
2299 saver_info *si = ssi->global;
2300 saver_preferences *p = &si->prefs;
2301 - raise_window (si, first_time_p, True, False);
2304 + if (!monitor_powered_on_p (si))
2306 + if (si->prefs.verbose_p)
2308 + "%s: %d: X says monitor has powered down; "
2309 + "not launching a hack.\n", blurb(), ssi->number);
2313 if (p->screenhacks_count)
2316 @@ -1017,55 +1025,28 @@
2324 -spawn_screenhack (saver_info *si, Bool first_time_p)
2326 - if (monitor_powered_on_p (si))
2329 - for (i = 0; i < si->nscreens; i++)
2331 - saver_screen_info *ssi = &si->screens[i];
2332 - spawn_screenhack_1 (ssi, first_time_p);
2335 - else if (si->prefs.verbose_p)
2337 - "%s: X says monitor has powered down; "
2338 - "not launching a hack.\n", blurb());
2340 - store_saver_status (si); /* store current hack numbers */
2341 + store_saver_status (si); /* store current hack number */
2346 -kill_screenhack (saver_info *si)
2347 +kill_screenhack (saver_screen_info *ssi)
2350 - for (i = 0; i < si->nscreens; i++)
2352 - saver_screen_info *ssi = &si->screens[i];
2354 - kill_job (si, ssi->pid, SIGTERM);
2357 + saver_info *si = ssi->global;
2359 + kill_job (si, ssi->pid, SIGTERM);
2365 -suspend_screenhack (saver_info *si, Bool suspend_p)
2366 +suspend_screenhack (saver_screen_info *ssi, Bool suspend_p)
2368 #ifdef SIGSTOP /* older VMS doesn't have it... */
2370 - for (i = 0; i < si->nscreens; i++)
2372 - saver_screen_info *ssi = &si->screens[i];
2374 - kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
2376 + saver_info *si = ssi->global;
2378 + kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
2379 #endif /* SIGSTOP */
2382 @@ -1137,7 +1118,7 @@
2386 -hack_subproc_environment (saver_screen_info *ssi)
2387 +hack_subproc_environment (Screen *screen, Window saver_window)
2389 /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
2390 the spawned processes inherit is correct. First, it must be on the same
2391 @@ -1152,8 +1133,8 @@
2392 us to (eventually) run multiple hacks in Xinerama mode, where each hack
2393 has the same $DISPLAY but a different piece of glass.
2395 - saver_info *si = ssi->global;
2396 - const char *odpy = DisplayString (si->dpy);
2397 + Display *dpy = DisplayOfScreen (screen);
2398 + const char *odpy = DisplayString (dpy);
2399 char *ndpy = (char *) malloc (strlen(odpy) + 20);
2400 char *nssw = (char *) malloc (40);
2402 @@ -1170,10 +1151,9 @@
2403 while (isdigit(*s)) s++; /* skip over dpy number */
2404 while (*s == '.') s++; /* skip over dot */
2405 if (s[-1] != '.') *s++ = '.'; /* put on a dot */
2406 - sprintf(s, "%d", ssi->real_screen_number); /* put on screen number */
2407 + sprintf(s, "%d", screen_number (screen)); /* put on screen number */
2409 - sprintf (nssw, "XSCREENSAVER_WINDOW=0x%lX",
2410 - (unsigned long) ssi->screensaver_window);
2411 + sprintf (nssw, "XSCREENSAVER_WINDOW=0x%lX", (unsigned long) saver_window);
2413 /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
2414 any more, right? It's not Posix, but everyone seems to have it. */
2415 @@ -1194,9 +1174,8 @@
2419 -get_best_gl_visual (saver_screen_info *ssi)
2420 +get_best_gl_visual (saver_info *si, Screen *screen)
2422 - saver_info *si = ssi->global;
2426 @@ -1217,6 +1196,11 @@
2430 + block_sigchld(); /* This blocks it in the parent and child, to avoid
2431 + racing. It is never unblocked in the child before
2432 + the child exits, but that doesn't matter.
2435 switch ((int) (forked = fork ()))
2438 @@ -1237,7 +1221,7 @@
2439 perror ("could not dup() a new stdout:");
2442 - hack_subproc_environment (ssi); /* set $DISPLAY */
2443 + hack_subproc_environment (screen, 0); /* set $DISPLAY */
2445 execvp (av[0], av); /* shouldn't return. */
2447 @@ -1270,6 +1254,8 @@
2448 /* Wait for the child to die. */
2449 waitpid (-1, &wait_status, 0);
2451 + unblock_sigchld(); /* child is dead and waited, unblock now. */
2453 if (1 == sscanf (buf, "0x%lx %c", &v, &c))
2456 @@ -1291,12 +1277,13 @@
2460 - Visual *v = id_to_visual (ssi->screen, result);
2461 + Visual *v = id_to_visual (screen, result);
2462 if (si->prefs.verbose_p)
2463 fprintf (stderr, "%s: %d: %s: GL visual is 0x%X%s.\n",
2464 - blurb(), ssi->number,
2465 + blurb(), screen_number (screen),
2467 - (v == ssi->default_visual ? " (default)" : ""));
2468 + (v == DefaultVisualOfScreen (screen)
2469 + ? " (default)" : ""));
2473 Index: xscreensaver/driver/test-passwd.c
2474 ===================================================================
2475 --- xscreensaver.orig/driver/test-passwd.c 2008-07-16 23:47:00.000000000 +0200
2476 +++ xscreensaver/driver/test-passwd.c 2008-07-17 00:07:00.000000000 +0200
2478 -/* xscreensaver, Copyright (c) 1998-2007 Jamie Zawinski <jwz@jwz.org>
2479 +/* xscreensaver, Copyright (c) 1998-2008 Jamie Zawinski <jwz@jwz.org>
2481 * Permission to use, copy, modify, distribute, and sell this software and its
2482 * documentation for any purpose is hereby granted without fee, provided that
2484 Atom XA_SCREENSAVER, XA_DEMO, XA_PREFS;
2487 -get_screen_viewport (saver_screen_info *ssi,
2488 - int *x_ret, int *y_ret,
2489 - int *w_ret, int *h_ret,
2495 - *w_ret = WidthOfScreen (ssi->screen);
2496 - *h_ret = HeightOfScreen (ssi->screen);
2498 - if (*w_ret > *h_ret * 2) *w_ret /= 2; /* xinerama kludge */
2502 idle_timer (XtPointer closure, XtIntervalId *id)
2504 saver_info *si = (saver_info *) closure;
2506 visual_depth(si->default_screen->screen,
2507 si->default_screen->current_visual);
2509 - /* I could call get_screen_viewport(), but it is not worthwhile.
2510 - * These are used by the save_under pixmap. */
2511 ssip.width = WidthOfScreen(ssip.screen);
2512 ssip.height = HeightOfScreen(ssip.screen);
2515 pw = getpwuid (getuid ());
2516 si->user = strdup (pw->pw_name);
2518 +/* si->nscreens = 0;
2519 + si->screens = si->default_screen = 0; */
2524 Index: xscreensaver/driver/test-randr.c
2525 ===================================================================
2526 --- xscreensaver.orig/driver/test-randr.c 2008-07-16 23:47:00.000000000 +0200
2527 +++ xscreensaver/driver/test-randr.c 2008-07-17 00:07:00.000000000 +0200
2529 /* test-randr.c --- playing with the Resize And Rotate extension.
2530 - * xscreensaver, Copyright (c) 2004, 2005 Jamie Zawinski <jwz@jwz.org>
2531 + * xscreensaver, Copyright (c) 2004-2008 Jamie Zawinski <jwz@jwz.org>
2533 * Permission to use, copy, modify, distribute, and sell this software and its
2534 * documentation for any purpose is hereby granted without fee, provided that
2535 @@ -233,6 +233,43 @@
2536 fprintf(stderr, "%s: XRRGetScreenInfo(dpy, %d) ==> NULL\n",
2541 +# ifdef HAVE_RANDR_12
2542 + if (major > 1 || (major == 1 && minor >= 2))
2545 + XRRScreenResources *res =
2546 + XRRGetScreenResources (dpy, RootWindow (dpy, i));
2547 + fprintf (stderr, "\n");
2548 + for (j = 0; j < res->noutput; j++)
2551 + XRROutputInfo *rroi =
2552 + XRRGetOutputInfo (dpy, res, res->outputs[j]);
2553 + fprintf (stderr, "%s: Output %d: %s: %s (%d)\n", blurb(), j,
2555 + (rroi->connection == RR_Disconnected ? "disconnected" :
2556 + rroi->connection == RR_UnknownConnection ? "unknown" :
2558 + (int) rroi->crtc);
2559 + for (k = 0; k < rroi->ncrtc; k++)
2561 + XRRCrtcInfo *crtci = XRRGetCrtcInfo (dpy, res,
2563 + fprintf(stderr, "%s: %c CRTC %d (%d): %dx%d+%d+%d\n",
2565 + (rroi->crtc == rroi->crtcs[k] ? '+' : ' '),
2566 + k, (int) rroi->crtcs[k],
2567 + crtci->width, crtci->height, crtci->x, crtci->y);
2568 + XRRFreeCrtcInfo (crtci);
2570 + XRRFreeOutputInfo (rroi);
2571 + fprintf (stderr, "\n");
2573 + XRRFreeScreenResources (res);
2575 +# endif /* HAVE_RANDR_12 */
2579 Index: xscreensaver/driver/test-screens.c
2580 ===================================================================
2581 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
2582 +++ xscreensaver/driver/test-screens.c 2008-07-17 00:07:00.000000000 +0200
2584 +/* test-screens.c --- some test cases for the "monitor sanity" checks.
2585 + * xscreensaver, Copyright (c) 2008 Jamie Zawinski <jwz@jwz.org>
2587 + * Permission to use, copy, modify, distribute, and sell this software and its
2588 + * documentation for any purpose is hereby granted without fee, provided that
2589 + * the above copyright notice appear in all copies and that both that
2590 + * copyright notice and this permission notice appear in supporting
2591 + * documentation. No representations are made about the suitability of this
2592 + * software for any purpose. It is provided "as is" without express or
2593 + * implied warranty.
2596 +#ifdef HAVE_CONFIG_H
2597 +# include "config.h"
2600 +#include <X11/Xlib.h>
2602 +/* This file doesn't need the Xt headers, so stub these types out... */
2604 +#define XtAppContext void*
2605 +#define XrmDatabase void*
2606 +#define XtIntervalId void*
2607 +#define XtPointer void*
2608 +#define Widget void*
2610 +#include "xscreensaver.h"
2611 +#include "visual.h"
2613 +#undef WidthOfScreen
2614 +#undef HeightOfScreen
2615 +#define WidthOfScreen(s) 10240
2616 +#define HeightOfScreen(s) 10240
2618 +#undef screen_number
2619 +#define screen_number(s) (0)
2621 +#include "screens.c" /* to get at static void check_monitor_sanity() */
2623 +char *progname = 0;
2624 +char *progclass = "XScreenSaver";
2626 +const char *blurb(void) { return progname; }
2628 +Bool safe_XF86VidModeGetViewPort(Display *d, int i, int *x, int *y) { abort(); }
2629 +void initialize_screen_root_widget(saver_screen_info *ssi) { abort(); }
2630 +Visual *get_best_gl_visual (saver_info *si, Screen *sc) { abort(); }
2633 +static const char *
2634 +failstr (monitor_sanity san)
2637 + case S_SANE: return "OK";
2638 + case S_ENCLOSED: return "ENC";
2639 + case S_DUPLICATE: return "DUP";
2640 + case S_OVERLAP: return "OVR";
2641 + case S_OFFSCREEN: return "OFF";
2642 + case S_DISABLED: return "DIS";
2648 +test (int testnum, const char *screens, const char *desired)
2650 + monitor *monitors[100];
2651 + char result[2048];
2652 + char *out = result;
2653 + int i, nscreens = 0;
2654 + char *token = strtok (strdup(screens), ",");
2657 + monitor *m = calloc (1, sizeof (monitor));
2659 + m->id = (testnum * 1000) + nscreens;
2660 + if (4 != sscanf (token, "%dx%d+%d+%d%c",
2661 + &m->width, &m->height, &m->x, &m->y, &c))
2663 + fprintf (stderr, "%s: unparsable geometry: %s\n", blurb(), token);
2666 + monitors[nscreens] = m;
2668 + token = strtok (0, ",");
2670 + monitors[nscreens] = 0;
2672 + check_monitor_sanity (monitors);
2675 + for (i = 0; i < nscreens; i++)
2677 + monitor *m = monitors[i];
2678 + if (out != result) *out++ = ',';
2679 + if (m->sanity == S_SANE)
2680 + sprintf (out, "%dx%d+%d+%d", m->width, m->height, m->x, m->y);
2682 + strcpy (out, failstr (m->sanity));
2683 + out += strlen(out);
2687 + if (!strcmp (result, desired))
2688 + fprintf (stderr, "%s: test %2d OK\n", blurb(), testnum);
2690 + fprintf (stderr, "%s: test %2d FAILED:\n"
2692 + "%s: wanted: %s\n"
2702 + SI.monitor_layout = monitors;
2703 + describe_monitor_layout (&SI);
2713 +# define A(a) test (i++, a, a);
2714 +# define B(a,b) test (i++, a, b)
2717 + A("1024x768+0+0");
2718 + A("1024x768+0+0,1024x768+1024+0");
2719 + A("1024x768+0+0,1024x768+0+768");
2720 + A("1024x768+0+0,1024x768+0+768,1024x768+1024+0");
2722 + B("1024x768+999999+0",
2724 + B("1024x768+-999999+-999999",
2726 + B("1024x768+0+0,1024x768+0+0",
2727 + "1024x768+0+0,DUP");
2728 + B("1024x768+0+0,1024x768+0+0,1024x768+0+0",
2729 + "1024x768+0+0,DUP,DUP");
2730 + B("1024x768+0+0,1024x768+1024+0,1024x768+0+0",
2731 + "1024x768+0+0,1024x768+1024+0,DUP");
2732 + B("1280x1024+0+0,1024x768+0+64,800x600+0+0,640x480+0+0,720x400+0+0",
2733 + "1280x1024+0+0,ENC,ENC,ENC,ENC");
2734 + B("1024x768+0+64,1280x1024+0+0,800x600+0+0,640x480+0+0,800x600+0+0,720x400+0+0",
2735 + "ENC,1280x1024+0+0,ENC,ENC,ENC,ENC");
2736 + B("1024x768+0+64,1280x1024+0+0,800x600+0+0,640x480+0+0,1280x1024+0+0,720x400+0+0",
2737 + "ENC,1280x1024+0+0,ENC,ENC,DUP,ENC");
2738 + B("720x400+0+0,640x480+0+0,800x600+0+0,1024x768+0+64,1280x1024+0+0",
2739 + "ENC,ENC,ENC,ENC,1280x1024+0+0");
2740 + B("1280x1024+0+0,800x600+1280+0,800x600+1300+0",
2741 + "1280x1024+0+0,800x600+1280+0,OVR");
2742 + B("1280x1024+0+0,800x600+1280+0,800x600+1300+0,1280x1024+0+0,800x600+1280+0",
2743 + "1280x1024+0+0,800x600+1280+0,OVR,DUP,DUP");
2745 + /* +-------------+----+ +------+---+ 1: 1440x900, widescreen display
2746 + | : | | 3+4 : | 2: 1280x1024, conventional display
2747 + | 1+2 : 1 | +......+ | 3: 1024x768, laptop
2748 + | : | | 3 | 4: 800x600, external projector
2749 + +.............+----+ +----------+
2754 + B("1440x900+0+0,1280x1024+0+0,1024x768+1440+0,800x600+1440+0",
2755 + "1440x900+0+0,OVR,1024x768+1440+0,ENC");
2756 + B("800x600+0+0,800x600+0+0,800x600+800+0",
2757 + "800x600+0+0,DUP,800x600+800+0");
2758 + B("1600x1200+0+0,1360x768+0+0",
2759 + "1600x1200+0+0,ENC");
2764 +main (int argc, char **argv)
2767 + progname = argv[0];
2768 + s = strrchr(progname, '/');
2769 + if (s) progname = s+1;
2772 + fprintf (stderr, "usage: %s\n", argv[0]);
2780 Index: xscreensaver/driver/timers.c
2781 ===================================================================
2782 --- xscreensaver.orig/driver/timers.c 2008-07-16 23:47:00.000000000 +0200
2783 +++ xscreensaver/driver/timers.c 2008-07-17 00:07:00.000000000 +0200
2784 @@ -264,14 +264,18 @@
2789 maybe_reload_init_file (si);
2790 - kill_screenhack (si);
2791 + for (i = 0; i < si->nscreens; i++)
2792 + kill_screenhack (&si->screens[i]);
2794 + raise_window (si, True, True, False);
2796 if (!si->throttled_p)
2797 - spawn_screenhack (si, False);
2798 + for (i = 0; i < si->nscreens; i++)
2799 + spawn_screenhack (&si->screens[i]);
2802 - raise_window (si, True, True, False);
2804 fprintf (stderr, "%s: not launching new hack (throttled.)\n",
2806 @@ -1010,28 +1014,17 @@
2807 if (event.type == (si->randr_event_number + RRScreenChangeNotify))
2809 /* The Resize and Rotate extension sends an event when the
2810 - size, rotation, or refresh rate of the screen has changed. */
2812 + size, rotation, or refresh rate of any screen has changed.
2814 XRRScreenChangeNotifyEvent *xrr_event =
2815 (XRRScreenChangeNotifyEvent *) &event;
2816 - /* XRRRootToScreen is in Xrandr.h 1.4, 2001/06/07 */
2817 - int screen = XRRRootToScreen (si->dpy, xrr_event->window);
2821 - if (si->screens[screen].width == xrr_event->width &&
2822 - si->screens[screen].height == xrr_event->height)
2824 - "%s: %d: no-op screen size change event (%dx%d)\n",
2826 - xrr_event->width, xrr_event->height);
2829 - "%s: %d: screen size changed from %dx%d to %dx%d\n",
2831 - si->screens[screen].width,
2832 - si->screens[screen].height,
2833 - xrr_event->width, xrr_event->height);
2834 + /* XRRRootToScreen is in Xrandr.h 1.4, 2001/06/07 */
2835 + int screen = XRRRootToScreen (si->dpy, xrr_event->window);
2836 + fprintf (stderr, "%s: %d: screen change event received\n",
2840 # ifdef RRScreenChangeNotifyMask
2841 @@ -1040,7 +1033,15 @@
2842 # endif /* RRScreenChangeNotifyMask */
2844 /* Resize the existing xscreensaver windows and cached ssi data. */
2845 - resize_screensaver_window (si);
2846 + if (update_screen_layout (si))
2850 + fprintf (stderr, "%s: new layout:\n", blurb());
2851 + describe_monitor_layout (si);
2853 + resize_screensaver_window (si);
2857 #endif /* HAVE_RANDR */
2858 @@ -1401,11 +1402,13 @@
2859 if (screenhack_running_p (si) &&
2860 !monitor_powered_on_p (si))
2863 if (si->prefs.verbose_p)
2865 "%s: X says monitor has powered down; "
2866 "killing running hacks.\n", blurb());
2867 - kill_screenhack (si);
2868 + for (i = 0; i < si->nscreens; i++)
2869 + kill_screenhack (&si->screens[i]);
2872 /* Re-schedule this timer. The watchdog timer defaults to a bit less
2873 Index: xscreensaver/driver/types.h
2874 ===================================================================
2875 --- xscreensaver.orig/driver/types.h 2008-07-16 23:47:00.000000000 +0200
2876 +++ xscreensaver/driver/types.h 2008-07-17 00:07:00.000000000 +0200
2880 - * This file is part of XScreenSaver,
2881 - * Copyright (c) 1993-2004 Jamie Zawinski <jwz@jwz.org>
2882 +/* xscreensaver, Copyright (c) 1993-2008 Jamie Zawinski <jwz@jwz.org>
2884 * Permission to use, copy, modify, distribute, and sell this software and its
2885 * documentation for any purpose is hereby granted without fee, provided that
2892 +#ifndef __XSCREENSAVER_TYPES_H__
2893 +#define __XSCREENSAVER_TYPES_H__
2895 typedef struct saver_info saver_info;
2897 -/* Unlock states. Old pw_* equivalents in square brackets:
2898 - * ul_read - reading input (or ready to do so) [pw_read]
2899 - * ul_success - auth success, unlock the screen [pw_ok]
2900 - * ul_fail - authentication failed [pw_fail]
2901 - * ul_cancel - user cancelled auth [pw_cancel or pw_null]
2902 - * ul_time - timed out, user took too long [pw_time]
2903 - * ul_finished - user pressed enter on the current prompt, process input
2905 -enum unlock_state { ul_read, ul_success, ul_fail, ul_cancel, ul_time, ul_finished };
2907 + ul_read, /* reading input or ready to do so */
2908 + ul_success, /* auth success, unlock */
2909 + ul_fail, /* auth fail */
2910 + ul_cancel, /* user cancelled auth (pw_cancel or pw_null) */
2911 + ul_time, /* timed out */
2912 + ul_finished /* user pressed enter */
2915 typedef struct screenhack screenhack;
2918 typedef struct saver_screen_info saver_screen_info;
2919 typedef struct passwd_dialog_data passwd_dialog_data;
2920 typedef struct splash_dialog_data splash_dialog_data;
2921 +typedef struct _monitor monitor;
2924 /* This structure holds all the user-specified parameters, read from the
2925 @@ -158,9 +155,11 @@
2926 saver_preferences prefs;
2930 saver_screen_info *screens;
2931 saver_screen_info *default_screen; /* ...on which dialogs will appear. */
2933 + monitor **monitor_layout; /* private to screens.c */
2934 + Visual **best_gl_visuals; /* visuals for GL hacks on screen N */
2936 /* =======================================================================
2937 global connection info
2939 server extension info
2940 ======================================================================= */
2942 - Bool xinerama_p; /* Whether Xinerama is in use. */
2943 Bool using_xidle_extension; /* which extension is being used. */
2944 Bool using_mit_saver_extension; /* Note that `p->use_*' is the *request*, */
2945 Bool using_sgi_saver_extension; /* and `si->using_*' is the *reality*. */
2947 char *user; /* The user whose session is locked. */
2948 char *cached_passwd; /* Cached password, used to avoid multiple
2949 prompts for password-only auth mechanisms.*/
2950 - enum unlock_state unlock_state;
2951 + unlock_state unlock_state;
2953 auth_conv_cb_t unlock_cb; /* The function used to prompt for creds. */
2954 void (*auth_finished_cb) (saver_info *si);
2956 int current_depth; /* How deep the visual (and the window) are. */
2958 Visual *default_visual; /* visual to use when none other specified */
2959 - Visual *best_gl_visual; /* visual to use for GL hacks */
2961 Window real_vroot; /* The original virtual-root window. */
2962 Window real_vroot_value; /* What was in the __SWM_VROOT property. */
2968 +#endif /* __XSCREENSAVER_TYPES_H__ */
2969 Index: xscreensaver/driver/windows.c
2970 ===================================================================
2971 --- xscreensaver.orig/driver/windows.c 2008-07-16 23:47:00.000000000 +0200
2972 +++ xscreensaver/driver/windows.c 2008-07-17 00:07:00.000000000 +0200
2973 @@ -226,6 +226,14 @@
2978 +ungrab_keyboard_and_mouse (saver_info *si)
2980 + ungrab_mouse (si);
2986 grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor,
2988 @@ -291,18 +299,15 @@
2991 if (kstatus != GrabSuccess) /* Do not blank without a kbd grab. */
2994 + /* If we didn't get both grabs, release the one we did get. */
2995 + ungrab_keyboard_and_mouse (si);
2999 return True; /* Grab is good, go ahead and blank. */
3003 -ungrab_keyboard_and_mouse (saver_info *si)
3005 - ungrab_mouse (si);
3011 move_mouse_grab (saver_info *si, Window to, Cursor cursor, int to_screen_no)
3012 @@ -393,6 +398,21 @@
3017 + else if (XGetWindowProperty (dpy, kids[i], XA_WM_COMMAND, 0, 128,
3018 + False, XA_STRING, &type, &format, &nitems,
3019 + &bytesafter, &version)
3022 + && !strcmp ((char *) version, "gnome-screensaver"))
3025 + "%s: \"%s\" is already running on display %s (window 0x%x)\n",
3026 + blurb(), (char *) version,
3027 + DisplayString (dpy), (int) kids [i]);
3033 if (kids) XFree ((char *) kids);
3034 @@ -445,11 +465,6 @@
3036 static Bool safe_XKillClient (Display *dpy, XID id);
3038 -#ifdef HAVE_XF86VMODE
3039 -static Bool safe_XF86VidModeGetViewPort (Display *, int, int *, int *);
3040 -#endif /* HAVE_XF86VMODE */
3044 kill_xsetroot_data_1 (Display *dpy, Window window,
3045 Atom prop, const char *atom_name,
3048 "%s: restoring __SWM_VROOT property on the real vroot (0x%lx).\n",
3049 blurb(), (unsigned long) ssi->real_vroot);
3050 - remove_vroot_property (si->dpy, ssi->screensaver_window);
3051 + if (ssi->screensaver_window)
3052 + remove_vroot_property (si->dpy, ssi->screensaver_window);
3053 if (ssi->real_vroot)
3055 store_vroot_property (si->dpy, ssi->real_vroot, ssi->real_vroot_value);
3056 @@ -812,8 +828,10 @@
3058 if (si->screen_blanked_p)
3061 + for (i = 0; i < si->nscreens; i++)
3062 + kill_screenhack (&si->screens[i]);
3063 unblank_screen (si);
3064 - kill_screenhack (si);
3065 XSync (si->dpy, False);
3068 @@ -999,232 +1017,6 @@
3073 -/* Returns the area of the screen which the xscreensaver window should cover.
3074 - Normally this is the whole screen, but if the X server's root window is
3075 - actually larger than the monitor's displayable area, then we want to
3076 - operate in the currently-visible portion of the desktop instead.
3079 -get_screen_viewport (saver_screen_info *ssi,
3080 - int *x_ret, int *y_ret,
3081 - int *w_ret, int *h_ret,
3082 - int target_x, int target_y,
3085 - int w = WidthOfScreen (ssi->screen);
3086 - int h = HeightOfScreen (ssi->screen);
3088 -# ifdef HAVE_XF86VMODE
3089 - saver_info *si = ssi->global;
3090 - saver_preferences *p = &si->prefs;
3093 - XF86VidModeModeLine ml;
3095 - Bool xinerama_p = si->xinerama_p;
3097 -# ifndef HAVE_XINERAMA
3098 - /* Even if we don't have the client-side Xinerama lib, check to see if
3099 - the server supports Xinerama, so that we know to ignore the VidMode
3100 - extension -- otherwise a server crash could result. Yay. */
3101 - xinerama_p = XQueryExtension (si->dpy, "XINERAMA", &error, &event, &error);
3102 -# endif /* !HAVE_XINERAMA */
3104 -# ifdef HAVE_XINERAMA
3107 - int mouse_p = (target_x != -1 && target_y != -1);
3111 - /* If a mouse position wasn't passed in, assume we're talking about
3115 - target_x = ssi->x;
3116 - target_y = ssi->y;
3117 - which = ssi->number;
3120 - /* Find the Xinerama rectangle that contains the mouse position. */
3121 - for (i = 0; i < si->nscreens; i++)
3123 - if (which == -1 &&
3124 - target_x >= si->screens[i].x &&
3125 - target_y >= si->screens[i].y &&
3126 - target_x < si->screens[i].x + si->screens[i].width &&
3127 - target_y < si->screens[i].y + si->screens[i].height)
3130 - if (which == -1) which = 0; /* didn't find it? Use the first. */
3131 - *x_ret = si->screens[which].x;
3132 - *y_ret = si->screens[which].y;
3133 - *w_ret = si->screens[which].width;
3134 - *h_ret = si->screens[which].height;
3138 - fprintf (stderr, "%s: %d: xinerama vp: %dx%d+%d+%d",
3140 - si->screens[which].width, si->screens[which].height,
3141 - si->screens[which].x, si->screens[which].y);
3143 - fprintf (stderr, "; mouse at %d,%d", target_x, target_y);
3144 - fprintf (stderr, ".\n");
3149 -# endif /* HAVE_XINERAMA */
3151 - if (!xinerama_p && /* Xinerama + VidMode = broken. */
3152 - XF86VidModeQueryExtension (si->dpy, &event, &error) &&
3153 - safe_XF86VidModeGetViewPort (si->dpy, ssi->number, &x, &y) &&
3154 - XF86VidModeGetModeLine (si->dpy, ssi->number, &dot, &ml))
3159 - *w_ret = ml.hdisplay;
3160 - *h_ret = ml.vdisplay;
3162 - if (*x_ret == 0 && *y_ret == 0 && *w_ret == w && *h_ret == h)
3163 - /* There is no viewport -- the screen does not scroll. */
3167 - /* Apparently some versions of XFree86 return nonsense here!
3168 - I've had reports of 1024x768 viewports at -1936862040, -1953705044.
3169 - So, sanity-check the values and give up if they are out of range.
3171 - if (*x_ret < 0 || *x_ret >= w ||
3172 - *y_ret < 0 || *y_ret >= h ||
3173 - *w_ret <= 0 || *w_ret > w ||
3174 - *h_ret <= 0 || *h_ret > h)
3176 - static int warned_once = 0;
3179 - fprintf (stderr, "\n"
3180 - "%s: X SERVER BUG: %dx%d viewport at %d,%d is impossible.\n"
3181 - "%s: The XVidMode server extension is returning nonsense.\n"
3182 - "%s: Please report this bug to your X server vendor.\n\n",
3183 - blurb(), *w_ret, *h_ret, *x_ret, *y_ret,
3184 - blurb(), blurb());
3194 - sprintf (msg, "%s: %d: vp is %dx%d+%d+%d",
3195 - blurb(), ssi->number,
3196 - *w_ret, *h_ret, *x_ret, *y_ret);
3199 - if (p->getviewport_full_of_lies_p)
3201 - /* XF86VidModeGetViewPort() tends to be full of lies on laptops
3202 - that have a docking station or external monitor that runs in
3203 - a different resolution than the laptop's screen:
3205 - http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=81593
3206 - http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=208417
3207 - http://bugs.xfree86.org/show_bug.cgi?id=421
3209 - The XFree86 developers have closed the bug. As far as I can
3210 - tell, their reason for this was, "this is an X server bug,
3211 - but it's pretty hard to fix. Therefore, we are closing it."
3213 - So, now there's a preference item for those unfortunate users to
3214 - tell us not to trust a word that XF86VidModeGetViewPort() says.
3216 - static int warned_once = 0;
3217 - if (!warned_once && verbose_p)
3221 - "%s: %d: XF86VidModeGetViewPort() says vp is %dx%d+%d+%d;\n"
3222 - "%s: %d: assuming that is a pack of lies;\n"
3223 - "%s: %d: using %dx%d+0+0 instead.\n",
3224 - blurb(), ssi->number,
3225 - *w_ret, *h_ret, *x_ret, *y_ret,
3226 - blurb(), ssi->number,
3227 - blurb(), ssi->number, w, h);
3238 - /* Apparently, though the server stores the X position in increments of
3239 - 1 pixel, it will only make changes to the *display* in some other
3240 - increment. With XF86_SVGA on a Thinkpad, the display only updates
3241 - in multiples of 8 pixels when in 8-bit mode, and in multiples of 4
3242 - pixels in 16-bit mode. I don't know what it does in 24- and 32-bit
3243 - mode, because I don't have enough video memory to find out.
3245 - I consider it a bug that XF86VidModeGetViewPort() is telling me the
3246 - server's *target* scroll position rather than the server's *actual*
3247 - scroll position. David Dawes agrees, and says they may fix this in
3248 - XFree86 4.0, but it's notrivial.
3250 - He also confirms that this behavior is server-dependent, so the
3251 - actual scroll position cannot be reliably determined by the client.
3252 - So... that means the only solution is to provide a ``sandbox''
3253 - around the blackout window -- we make the window be up to N pixels
3254 - larger than the viewport on both the left and right sides. That
3255 - means some part of the outer edges of each hack might not be
3256 - visible, but screw it.
3258 - I'm going to guess that 16 pixels is enough, and that the Y dimension
3259 - doesn't have this problem.
3261 - The drawback of doing this, of course, is that some of the screenhacks
3262 - will still look pretty stupid -- for example, "slidescreen" will cut
3263 - off the left and right edges of the grid, etc.
3266 - if (x > 0 && x < w - ml.hdisplay) /* not at left edge or right edge */
3268 - /* Round X position down to next lower multiple of FUDGE.
3269 - Increase width by 2*FUDGE in case some server rounds up.
3271 - *x_ret = ((x - 1) / FUDGE) * FUDGE;
3272 - *w_ret += (FUDGE * 2);
3276 - if (*x_ret != x ||
3278 - *w_ret != ml.hdisplay ||
3279 - *h_ret != ml.vdisplay)
3280 - sprintf (msg + strlen(msg), "; fudged to %dx%d+%d+%d",
3281 - *w_ret, *h_ret, *x_ret, *y_ret);
3284 - fprintf (stderr, "%s.\n", msg);
3289 -# endif /* HAVE_XF86VMODE */
3298 static Bool error_handler_hit_p = False;
3301 @@ -1318,7 +1110,7 @@
3304 #ifdef HAVE_XF86VMODE
3307 safe_XF86VidModeGetViewPort (Display *dpy, int screen, int *xP, int *yP)
3310 @@ -1362,13 +1154,9 @@
3312 XSetWindowAttributes attrs;
3313 unsigned long attrmask;
3314 - int x, y, width, height;
3315 static Bool printed_visual_info = False; /* only print the message once. */
3316 Window horked_window = 0;
3318 - get_screen_viewport (ssi, &x, &y, &width, &height, -1, -1,
3319 - (p->verbose_p && !si->screen_blanked_p));
3321 black.red = black.green = black.blue = 0;
3323 if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
3324 @@ -1421,13 +1209,6 @@
3325 attrs.backing_pixel = ssi->black_pixel;
3326 attrs.border_pixel = ssi->black_pixel;
3333 - width = width / 2;
3335 if (!p->verbose_p || printed_visual_info)
3337 else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
3338 @@ -1503,10 +1284,10 @@
3340 XWindowChanges changes;
3341 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
3344 - changes.width = width;
3345 - changes.height = height;
3346 + changes.x = ssi->x;
3347 + changes.y = ssi->y;
3348 + changes.width = ssi->width;
3349 + changes.height = ssi->height;
3350 changes.border_width = 0;
3352 if (! (safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
3353 @@ -1523,10 +1304,9 @@
3355 ssi->screensaver_window =
3356 XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen),
3357 - x, y, width, height,
3358 + ssi->x, ssi->y, ssi->width, ssi->height,
3359 0, ssi->current_depth, InputOutput,
3360 ssi->current_visual, attrmask, &attrs);
3365 @@ -1578,10 +1358,10 @@
3369 -/* Called when the RANDR (Resize and Rotate) extension tells us that the
3370 - size of the screen has changed while the screen was blanked. If we
3371 - don't do this, then the screen saver will no longer fully fill the
3372 - screen, and some of the underlying desktop may be visible.
3373 +/* Called when the RANDR (Resize and Rotate) extension tells us that
3374 + the size of the screen has changed while the screen was blanked.
3375 + Call update_screen_layout() first, then call this to synchronize
3376 + the size of the saver windows to the new sizes of the screens.
3379 resize_screensaver_window (saver_info *si)
3380 @@ -1589,132 +1369,97 @@
3381 saver_preferences *p = &si->prefs;
3384 - /* First update the size info in the saver_screen_info structs.
3387 -# ifdef HAVE_XINERAMA
3388 - if (si->xinerama_p)
3389 + for (i = 0; i < si->nscreens; i++)
3391 - /* As of XFree86 4.3.0, the RANDR and XINERAMA extensions cannot coexist.
3392 - However, maybe they will someday, so I'm guessing that the right thing
3393 - to do in that case will be to re-query the Xinerama rectangles after
3394 - a RANDR size change is received: presumably, if the resolution of one
3395 - or more of the monitors has changed, then the Xinerama rectangle
3396 - corresponding to that monitor will also have been updated.
3399 - XineramaScreenInfo *xsi = XineramaQueryScreens (si->dpy, &nscreens);
3401 - if (nscreens != si->nscreens) {
3402 - /* Apparently some Xinerama implementations let you use a hot-key
3403 - to change the number of screens in use! This is, of course,
3404 - documented nowhere. Let's try to do something marginally less
3405 - bad than crashing.
3407 - fprintf (stderr, "%s: bad craziness: xinerama screen count changed "
3408 - "from %d to %d!\n", blurb(), si->nscreens, nscreens);
3409 - if (nscreens > si->nscreens)
3410 - nscreens = si->nscreens;
3412 + saver_screen_info *ssi = &si->screens[i];
3413 + XWindowAttributes xgwa;
3415 - if (!xsi) abort();
3416 - for (i = 0; i < nscreens; i++)
3417 + /* Make sure a window exists -- it might not if a monitor was just
3418 + added for the first time.
3420 + if (! ssi->screensaver_window)
3422 - saver_screen_info *ssi = &si->screens[i];
3423 - if (p->verbose_p &&
3424 - (ssi->x != xsi[i].x_org ||
3425 - ssi->y != xsi[i].y_org ||
3426 - ssi->width != xsi[i].width ||
3427 - ssi->height != xsi[i].height))
3428 + initialize_screensaver_window_1 (ssi);
3431 - "%s: %d: resize xinerama from %dx%d+%d+%d to %dx%d+%d+%d\n",
3433 - ssi->width, ssi->height, ssi->x, ssi->y,
3434 - xsi[i].width, xsi[i].height, xsi[i].x_org, xsi[i].y_org);
3436 - ssi->x = xsi[i].x_org;
3437 - ssi->y = xsi[i].y_org;
3438 - ssi->width = xsi[i].width;
3439 - ssi->height = xsi[i].height;
3440 + "%s: %d: newly added window 0x%lx %dx%d+%d+%d\n",
3441 + blurb(), i, (unsigned long) ssi->screensaver_window,
3442 + ssi->width, ssi->height, ssi->x, ssi->y);
3447 -# endif /* HAVE_XINERAMA */
3449 - /* Not Xinerama -- get the real sizes of the root windows. */
3450 - for (i = 0; i < si->nscreens; i++)
3452 + /* Make sure the window is the right size -- it might not be if
3453 + the monitor changed resolution, or if a badly-behaved hack
3456 + XGetWindowAttributes (si->dpy, ssi->screensaver_window, &xgwa);
3457 + if (xgwa.x != ssi->x ||
3458 + xgwa.y != ssi->y ||
3459 + xgwa.width != ssi->width ||
3460 + xgwa.height != ssi->height)
3462 - saver_screen_info *ssi = &si->screens[i];
3463 - XWindowAttributes xgwa;
3464 - XGetWindowAttributes (si->dpy, RootWindowOfScreen (ssi->screen),
3467 - if (p->verbose_p &&
3468 - (ssi->x != xgwa.x ||
3469 - ssi->y != xgwa.y ||
3470 - ssi->width != xgwa.width ||
3471 - ssi->height != xgwa.height))
3472 + XWindowChanges changes;
3473 + unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
3474 + changes.x = ssi->x;
3475 + changes.y = ssi->y;
3476 + changes.width = ssi->width;
3477 + changes.height = ssi->height;
3478 + changes.border_width = 0;
3482 - "%s: %d: resize screen from %dx%d+%d+%d to %dx%d+%d+%d\n",
3484 - ssi->width, ssi->height, ssi->x, ssi->y,
3485 - xgwa.width, xgwa.height, xgwa.x, xgwa.y);
3489 - ssi->width = xgwa.width;
3490 - ssi->height = xgwa.height;
3491 + "%s: %d: resize 0x%lx from %dx%d+%d+%d to %dx%d+%d+%d\n",
3492 + blurb(), i, (unsigned long) ssi->screensaver_window,
3493 + xgwa.width, xgwa.height, xgwa.x, xgwa.y,
3494 + ssi->width, ssi->height, ssi->x, ssi->y);
3496 + if (! safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
3497 + changesmask, &changes))
3498 + fprintf (stderr, "%s: %d: someone horked our saver window"
3499 + " (0x%lx)! Unable to resize it!\n",
3500 + blurb(), i, (unsigned long) ssi->screensaver_window);
3503 + /* Now (if blanked) make sure that it's mapped and running a hack --
3504 + it might not be if we just added it. (We also might be re-using
3505 + an old window that existed for a previous monitor that was
3506 + removed and re-added.)
3508 + Note that spawn_screenhack() calls select_visual() which may destroy
3509 + and re-create the window via initialize_screensaver_window_1().
3511 + if (si->screen_blanked_p)
3514 + XInstallColormap (si->dpy, ssi->cmap);
3515 + XMapRaised (si->dpy, ssi->screensaver_window);
3517 + spawn_screenhack (ssi);
3519 + /* Make sure the act of adding a screen doesn't present as
3520 + pointer motion (and thus cause an unblank). */
3522 + Window root, child;
3524 + unsigned int mask;
3525 + XQueryPointer (si->dpy, ssi->screensaver_window, &root, &child,
3526 + &ssi->poll_mouse_last_root_x,
3527 + &ssi->poll_mouse_last_root_y,
3533 - /* Next, ensure that the screensaver windows are the right size, taking
3534 - into account both the new size of the screen in question's root window,
3535 - and any viewport within that.
3536 + /* Kill off any savers running on no-longer-extant monitors.
3539 - for (i = 0; i < si->nscreens; i++)
3540 + for (; i < si->ssi_count; i++)
3542 saver_screen_info *ssi = &si->screens[i];
3543 - XWindowAttributes xgwa;
3544 - XWindowChanges changes;
3545 - int x, y, width, height;
3546 - unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
3548 - XGetWindowAttributes (si->dpy, ssi->screensaver_window, &xgwa);
3549 - get_screen_viewport (ssi, &x, &y, &width, &height, -1, -1,
3550 - (p->verbose_p && !si->screen_blanked_p));
3551 - if (xgwa.x == x &&
3553 - xgwa.width == width &&
3554 - xgwa.height == height)
3555 - continue; /* no change! */
3559 - changes.width = width;
3560 - changes.height = height;
3561 - changes.border_width = 0;
3568 - changes.width = changes.width / 2;
3572 - "%s: %d: resize 0x%lx from %dx%d+%d+%d to %dx%d+%d+%d\n",
3573 - blurb(), i, (unsigned long) ssi->screensaver_window,
3574 - xgwa.width, xgwa.height, xgwa.x, xgwa.y,
3575 - width, height, x, y);
3576 - if (! safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
3577 - changesmask, &changes))
3579 + kill_screenhack (ssi);
3580 + if (ssi->screensaver_window)
3583 - "%s: %d: someone horked our saver window (0x%lx)! Unable to resize it!\n",
3584 - blurb(), i, (unsigned long) ssi->screensaver_window);
3585 + XUnmapWindow (si->dpy, ssi->screensaver_window);
3586 + restore_real_vroot_1 (ssi);
3590 @@ -2094,10 +1839,30 @@
3595 +get_screen_gl_visual (saver_info *si, int real_screen_number)
3598 + int nscreens = ScreenCount (si->dpy);
3600 + if (! si->best_gl_visuals)
3601 + si->best_gl_visuals = (Visual **)
3602 + calloc (nscreens + 1, sizeof (*si->best_gl_visuals));
3604 + for (i = 0; i < nscreens; i++)
3605 + if (! si->best_gl_visuals[i])
3606 + si->best_gl_visuals[i] =
3607 + get_best_gl_visual (si, ScreenOfDisplay (si->dpy, i));
3609 + if (real_screen_number < 0 || real_screen_number >= nscreens) abort();
3610 + return si->best_gl_visuals[real_screen_number];
3615 select_visual (saver_screen_info *ssi, const char *visual_name)
3617 + XWindowAttributes xgwa;
3618 saver_info *si = ssi->global;
3619 saver_preferences *p = &si->prefs;
3620 Bool install_cmap_p = p->install_cmap_p;
3621 @@ -2112,6 +1877,17 @@
3623 Bool always_recreate_window_p = True;
3625 + get_screen_gl_visual (si, 0); /* let's probe all the GL visuals early */
3627 + /* We make sure the existing window is actually on ssi->screen before
3628 + trying to use it, in case things moved around radically when monitors
3629 + were added or deleted. If we don't do this we could get a BadMatch
3630 + even though the depths match. I think.
3632 + memset (&xgwa, 0, sizeof(xgwa));
3633 + if (ssi->screensaver_window)
3634 + XGetWindowAttributes (si->dpy, ssi->screensaver_window, &xgwa);
3636 if (visual_name && *visual_name)
3638 if (!strcmp(visual_name, "default-i") ||
3639 @@ -2133,7 +1909,7 @@
3640 !strcmp(visual_name, "Gl") ||
3641 !strcmp(visual_name, "GL"))
3643 - new_v = ssi->best_gl_visual;
3644 + new_v = get_screen_gl_visual (si, ssi->real_screen_number);
3645 if (!new_v && p->verbose_p)
3646 fprintf (stderr, "%s: no GL visuals.\n", progname);
3648 @@ -2154,13 +1930,16 @@
3650 ssi->install_cmap_p = install_cmap_p;
3653 - (always_recreate_window_p ||
3654 - (ssi->current_visual != new_v) ||
3655 - (install_cmap_p != was_installed_p)))
3656 + if ((ssi->screen != xgwa.screen) ||
3658 + (always_recreate_window_p ||
3659 + (ssi->current_visual != new_v) ||
3660 + (install_cmap_p != was_installed_p))))
3662 Colormap old_c = ssi->cmap;
3663 Window old_w = ssi->screensaver_window;
3665 + new_v = ssi->current_visual;
3669 Index: xscreensaver/driver/xscreensaver-command.c
3670 ===================================================================
3671 --- xscreensaver.orig/driver/xscreensaver-command.c 2008-07-16 23:47:00.000000000 +0200
3672 +++ xscreensaver/driver/xscreensaver-command.c 2008-07-17 00:07:00.000000000 +0200
3674 (Note that one must *never* kill xscreensaver with -9!)\n\
3676 -restart Causes the screensaver process to exit and then restart with\n\
3677 - the same command line arguments as last time. Do this after\n\
3678 - you've changed your X resource settings, to cause\n\
3679 - xscreensaver to notice the changes.\n\
3680 + the same command line arguments as last time. You shouldn't\n\
3681 + really need to do this, since xscreensaver notices when the\n\
3682 + .xscreensaver file has changed and re-reads it as needed.\n\
3684 -lock Tells the running xscreensaver process to lock the screen\n\
3685 immediately. This is like -activate, but forces locking as\n\
3686 Index: xscreensaver/driver/xscreensaver.c
3687 ===================================================================
3688 --- xscreensaver.orig/driver/xscreensaver.c 2008-07-16 23:47:00.000000000 +0200
3689 +++ xscreensaver/driver/xscreensaver.c 2008-07-17 00:07:00.000000000 +0200
3691 * via the $XSCREENSAVER_WINDOW environment variable -- this trick requires
3692 * a recent (Aug 2003) revision of vroot.h.
3694 + * (See comments in screens.c for more details about Xinerama/RANDR stuff.)
3696 * While we are waiting for user activity, we also set up timers so that,
3697 * after a certain amount of time has passed, we can start a different
3698 * screenhack. We do this by killing the running child process with
3701 /* useful for debugging */
3702 { "-no-capture-stderr", ".captureStderr", XrmoptionNoArg, "off" },
3703 + { "-log", ".logFile", XrmoptionSepArg, 0 },
3711 -static Bool blurb_timestamp_p = False; /* kludge */
3712 +static Bool blurb_timestamp_p = True; /* kludge */
3716 @@ -334,27 +337,30 @@
3721 + __extension__ /* don't warn about "string length is greater than the
3722 + length ISO C89 compilers are required to support". */
3724 fprintf (real_stderr,
3725 - "#######################################"
3726 - "#######################################\n\n");
3727 - fprintf (real_stderr,
3728 + "#######################################################################\n"
3730 " If at all possible, please re-run xscreensaver with the command\n"
3731 - " line arguments `-sync -verbose -no-capture', and reproduce this\n"
3732 + " line arguments `-sync -verbose -log log.txt', and reproduce this\n"
3733 " bug. That will cause xscreensaver to dump a `core' file to the\n"
3734 " current directory. Please include the stack trace from that core\n"
3735 - " file in your bug report. *DO NOT* mail the core file itself!\n"
3736 - " That won't work.\n");
3737 - fprintf (real_stderr,
3738 + " file in your bug report. *DO NOT* mail the core file itself! That\n"
3739 + " won't work. A \"log.txt\" file will also be written. Please *do*\n"
3740 + " include the complete \"log.txt\" file with your bug report.\n"
3742 " http://www.jwz.org/xscreensaver/bugs.html explains how to create\n"
3743 " the most useful bug reports, and how to examine core files.\n"
3745 " The more information you can provide, the better. But please\n"
3746 " report this bug, regardless!\n"
3748 + "#######################################################################\n"
3751 - fprintf (real_stderr,
3752 - "#######################################"
3753 - "#######################################\n\n");
3755 saver_exit (si, -1, 0);
3757 @@ -658,13 +664,6 @@
3758 with `xscreensaver-demo' or `xscreensaver-command'.\n\
3759 . See the man pages for details, or check the web page:\n\
3760 http://www.jwz.org/xscreensaver/\n\n");
3762 - /* Since version 1.21 renamed the "-lock" option to "-lock-mode",
3763 - suggest that explicitly. */
3764 - if (!strcmp (s, "-lock"))
3765 - fprintf (stderr, "\
3766 - Or perhaps you meant either the \"-lock-mode\" or the\n\
3767 - \"-lock-timeout <minutes>\" options to xscreensaver?\n\n");
3771 @@ -755,110 +754,24 @@
3775 -#ifdef HAVE_XINERAMA
3778 -screens_overlap_p (XineramaScreenInfo *a, XineramaScreenInfo *b)
3780 - /* Two rectangles overlap if the max of the tops is less than the
3781 - min of the bottoms and the max of the lefts is less than the min
3786 -# define MAX(A,B) ((A)>(B)?(A):(B))
3787 -# define MIN(A,B) ((A)<(B)?(A):(B))
3789 - int maxleft = MAX(a->x_org, b->x_org);
3790 - int maxtop = MAX(a->y_org, b->y_org);
3791 - int minright = MIN(a->x_org + a->width - 1, b->x_org + b->width);
3792 - int minbot = MIN(a->y_org + a->height - 1, b->y_org + b->height);
3793 - return (maxtop < minbot && maxleft < minright);
3797 -/* Go through the list of Xinerama screen descriptions, and mark the
3798 - ones that appear to be insane, so that we don't use them.
3801 -check_xinerama_sanity (int count, Bool verbose_p, XineramaScreenInfo *xsi)
3802 +/* called from screens.c so that all the Xt crud is here. */
3804 +initialize_screen_root_widget (saver_screen_info *ssi)
3806 - static Bool printed_p = False;
3811 -# define X1 xsi[i].x_org
3812 -# define X2 xsi[j].x_org
3813 -# define Y1 xsi[i].y_org
3814 -# define Y2 xsi[j].y_org
3815 -# define W1 xsi[i].width
3816 -# define W2 xsi[j].width
3817 -# define H1 xsi[i].height
3818 -# define H2 xsi[j].height
3820 -# define WHINE() do { \
3821 - if (verbose_p) { \
3822 - if (! printed_p) { \
3823 - fprintf (stderr, "%s: compensating for Xinerama braindamage:\n", \
3825 - printed_p = True; \
3827 - fprintf (stderr, "%s: %d: %s\n", blurb(), xsi[i].screen_number,err); \
3829 - xsi[i].screen_number = -1; \
3832 - /* If a screen is enclosed by any other screen, that's insane.
3834 - for (i = 0; i < count; i++)
3835 - for (j = 0; j < count; j++)
3837 - xsi[i].screen_number >= 0 &&
3838 - xsi[j].screen_number >= 0 &&
3839 - X1 >= X2 && Y1 >= Y2 && (X1+W1) <= (X2+W2) && (X1+H1) <= (X2+H2))
3841 - sprintf (err, "%dx%d+%d+%d enclosed by %dx%d+%d+%d",
3848 - /* After checking for enclosure, check for other lossage against earlier
3849 - screens. We do enclosure first so that we make sure to pick the
3852 - for (i = 0; i < count; i++)
3853 - for (j = 0; j < i; j++)
3855 - if (xsi[i].screen_number < 0) continue; /* already marked */
3858 - if (X1 == X2 && Y1 == Y2 && W1 == W2 && H1 == H2)
3859 - sprintf (err, "%dx%d+%d+%d duplicated", W1, H1, X1, Y1);
3861 - else if (screens_overlap_p (&xsi[i], &xsi[j]))
3862 - sprintf (err, "%dx%d+%d+%d overlaps %dx%d+%d+%d",
3866 - if (*err) WHINE();
3877 + saver_info *si = ssi->global;
3878 + if (ssi->toplevel_shell)
3879 + XtDestroyWidget (ssi->toplevel_shell);
3880 + ssi->toplevel_shell =
3881 + XtVaAppCreateShell (progname, progclass,
3882 + applicationShellWidgetClass,
3884 + XtNscreen, ssi->screen,
3885 + XtNvisual, ssi->current_visual,
3886 + XtNdepth, visual_depth (ssi->screen,
3887 + ssi->current_visual),
3891 -#endif /* HAVE_XINERAMA */
3895 /* Examine all of the display's screens, and populate the `saver_screen_info'
3896 structures. Make sure this is called after hack_environment() sets $PATH.
3897 @@ -866,182 +779,28 @@
3899 initialize_per_screen_info (saver_info *si, Widget toplevel_shell)
3901 - Bool found_any_writable_cells = False;
3904 -# ifdef HAVE_XINERAMA
3907 - si->xinerama_p = (XineramaQueryExtension (si->dpy, &event, &error) &&
3908 - XineramaIsActive (si->dpy));
3911 - if (si->xinerama_p && ScreenCount (si->dpy) != 1)
3913 - si->xinerama_p = False;
3914 - if (si->prefs.verbose_p)
3916 - "%s: Xinerama AND %d screens? Disabling Xinerama support!\n",
3917 - blurb(), ScreenCount(si->dpy));
3920 - if (si->xinerama_p)
3923 - XineramaScreenInfo *xsi = XineramaQueryScreens (si->dpy, &nscreens);
3925 - si->xinerama_p = False;
3929 - si->screens = (saver_screen_info *)
3930 - calloc(sizeof(saver_screen_info), nscreens);
3931 - check_xinerama_sanity (nscreens, si->prefs.verbose_p, xsi);
3932 - for (i = 0; i < nscreens; i++)
3934 - if (xsi[i].screen_number < 0) /* deemed insane */
3936 - si->screens[j].x = xsi[i].x_org;
3937 - si->screens[j].y = xsi[i].y_org;
3938 - si->screens[j].width = xsi[i].width;
3939 - si->screens[j].height = xsi[i].height;
3945 - si->default_screen = &si->screens[0];
3946 - si->default_screen->real_screen_p = True;
3948 -# endif /* !HAVE_XINERAMA */
3950 - if (!si->xinerama_p)
3952 - si->nscreens = ScreenCount(si->dpy);
3953 - si->screens = (saver_screen_info *)
3954 - calloc(sizeof(saver_screen_info), si->nscreens);
3955 - si->default_screen = &si->screens[DefaultScreen(si->dpy)];
3957 - for (i = 0; i < si->nscreens; i++)
3959 - saver_screen_info *ssi = &si->screens[i];
3960 - ssi->width = DisplayWidth (si->dpy, i);
3961 - ssi->height = DisplayHeight (si->dpy, i);
3962 - ssi->real_screen_p = True;
3963 - ssi->real_screen_number = i;
3969 - /* In "quad mode", we use the Xinerama code to pretend that there are 4
3970 - screens for every physical screen, and run four times as many hacks...
3972 - if (si->prefs.quad_p)
3974 - int ns2 = si->nscreens * 4;
3975 - saver_screen_info *ssi2 = (saver_screen_info *)
3976 - calloc(sizeof(saver_screen_info), ns2);
3978 - for (i = 0; i < si->nscreens; i++)
3980 - saver_screen_info *old = &si->screens[i];
3981 + update_screen_layout (si);
3983 - if (si->prefs.debug_p) old->width = old->width / 2;
3985 - ssi2[i*4 ] = *old;
3986 - ssi2[i*4+1] = *old;
3987 - ssi2[i*4+2] = *old;
3988 - ssi2[i*4+3] = *old;
3990 - ssi2[i*4 ].width /= 2;
3991 - ssi2[i*4 ].height /= 2;
3993 - ssi2[i*4+1].x += ssi2[i*4 ].width;
3994 - ssi2[i*4+1].width -= ssi2[i*4 ].width;
3995 - ssi2[i*4+1].height /= 2;
3997 - ssi2[i*4+2].y += ssi2[i*4 ].height;
3998 - ssi2[i*4+2].width /= 2;
3999 - ssi2[i*4+2].height -= ssi2[i*4 ].height;
4001 - ssi2[i*4+3].x += ssi2[i*4+2].width;
4002 - ssi2[i*4+3].y += ssi2[i*4+2].height;
4003 - ssi2[i*4+3].width -= ssi2[i*4+2].width;
4004 - ssi2[i*4+3].height -= ssi2[i*4+2].height;
4006 - ssi2[i*4+1].real_screen_p = False;
4007 - ssi2[i*4+2].real_screen_p = False;
4008 - ssi2[i*4+3].real_screen_p = False;
4011 - si->nscreens = ns2;
4012 - free (si->screens);
4013 - si->screens = ssi2;
4014 - si->default_screen = &si->screens[DefaultScreen(si->dpy) * 4];
4015 - si->xinerama_p = True;
4017 -# endif /* QUAD_MODE */
4019 - /* finish initializing the screens.
4020 + /* Check to see whether fading is ever possible -- if any of the
4021 + screens on the display has a PseudoColor visual, then fading can
4022 + work (on at least some screens.) If no screen has a PseudoColor
4023 + visual, then don't bother ever trying to fade, because it will
4024 + just cause a delay without causing any visible effect.
4026 for (i = 0; i < si->nscreens; i++)
4028 saver_screen_info *ssi = &si->screens[i];
4032 - ssi->screen = ScreenOfDisplay (si->dpy, ssi->real_screen_number);
4033 - ssi->poll_mouse_last_root_x = -1;
4034 - ssi->poll_mouse_last_root_y = -1;
4036 - if (!si->xinerama_p)
4037 + if (has_writable_cells (ssi->screen, ssi->current_visual) ||
4038 + get_visual (ssi->screen, "PseudoColor", True, False) ||
4039 + get_visual (ssi->screen, "GrayScale", True, False))
4041 - ssi->width = WidthOfScreen (ssi->screen);
4042 - ssi->height = HeightOfScreen (ssi->screen);
4043 + si->fading_possible_p = True;
4047 - /* Note: we can't use the resource ".visual" because Xt is SO FUCKED. */
4048 - ssi->default_visual =
4049 - get_visual_resource (ssi->screen, "visualID", "VisualID", False);
4051 - ssi->current_visual = ssi->default_visual;
4052 - ssi->current_depth = visual_depth (ssi->screen, ssi->current_visual);
4054 - /* Execute a subprocess to find the GL visual. */
4055 - ssi->best_gl_visual = get_best_gl_visual (ssi);
4057 - if (ssi == si->default_screen)
4058 - /* Since this is the default screen, use the one already created. */
4059 - ssi->toplevel_shell = toplevel_shell;
4061 - /* Otherwise, each screen must have its own unmapped root widget. */
4062 - ssi->toplevel_shell =
4063 - XtVaAppCreateShell (progname, progclass, applicationShellWidgetClass,
4065 - XtNscreen, ssi->screen,
4066 - XtNvisual, ssi->current_visual,
4067 - XtNdepth, visual_depth (ssi->screen,
4068 - ssi->current_visual),
4071 - if (! found_any_writable_cells)
4073 - /* Check to see whether fading is ever possible -- if any of the
4074 - screens on the display has a PseudoColor visual, then fading can
4075 - work (on at least some screens.) If no screen has a PseudoColor
4076 - visual, then don't bother ever trying to fade, because it will
4077 - just cause a delay without causing any visible effect.
4079 - if (has_writable_cells (ssi->screen, ssi->current_visual) ||
4080 - get_visual (ssi->screen, "PseudoColor", True, False) ||
4081 - get_visual (ssi->screen, "GrayScale", True, False))
4082 - found_any_writable_cells = True;
4086 - si->fading_possible_p = found_any_writable_cells;
4088 #ifdef HAVE_XF86VMODE_GAMMA
4089 si->fading_possible_p = True; /* if we can gamma fade, go for it */
4091 @@ -1115,15 +874,6 @@
4095 - /* These are incompatible (or at least, our support for them is...) */
4096 - if (si->xinerama_p && si->using_mit_saver_extension)
4098 - si->using_mit_saver_extension = False;
4100 - fprintf (stderr, "%s: Xinerama in use: disabling MIT-SCREEN-SAVER.\n",
4105 query_randr_extension (si);
4107 @@ -1149,6 +899,26 @@
4111 +#ifdef DEBUG_MULTISCREEN
4113 +debug_multiscreen_timer (XtPointer closure, XtIntervalId *id)
4115 + saver_info *si = (saver_info *) closure;
4116 + saver_preferences *p = &si->prefs;
4117 + if (update_screen_layout (si))
4121 + fprintf (stderr, "%s: new layout:\n", blurb());
4122 + describe_monitor_layout (si);
4124 + resize_screensaver_window (si);
4126 + XtAppAddTimeOut (si->app, 1000*4, debug_multiscreen_timer, (XtPointer) si);
4128 +#endif /* DEBUG_MULTISCREEN */
4131 /* For the case where we aren't using an server extensions, select user events
4132 on all the existing windows, and launch timers to select events on
4133 newly-created windows as well.
4134 @@ -1201,6 +971,10 @@
4137 fprintf (stderr, " done.\n");
4139 +# ifdef DEBUG_MULTISCREEN
4140 + if (p->debug_p) debug_multiscreen_timer ((XtPointer) si, 0);
4145 @@ -1247,6 +1021,7 @@
4147 saver_preferences *p = &si->prefs;
4153 @@ -1342,12 +1117,15 @@
4157 - kill_screenhack (si);
4158 + for (i = 0; i < si->nscreens; i++)
4159 + kill_screenhack (&si->screens[i]);
4161 - if (!si->throttled_p)
4162 - spawn_screenhack (si, True);
4163 - else if (p->verbose_p)
4164 + raise_window (si, True, True, False);
4165 + if (si->throttled_p)
4166 fprintf (stderr, "%s: not launching hack (throttled.)\n", blurb());
4168 + for (i = 0; i < si->nscreens; i++)
4169 + spawn_screenhack (&si->screens[i]);
4171 /* Don't start the cycle timer in demo mode. */
4172 if (!si->demoing_p && p->cycle)
4173 @@ -1418,14 +1196,16 @@
4176 si->dbox_up_p = True;
4177 - suspend_screenhack (si, True);
4178 + for (i = 0; i < si->nscreens; i++)
4179 + suspend_screenhack (&si->screens[i], True); /* suspend */
4180 XUndefineCursor (si->dpy, ssi->screensaver_window);
4182 ok_to_unblank = unlock_p (si);
4184 si->dbox_up_p = False;
4185 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
4186 - suspend_screenhack (si, False); /* resume */
4187 + for (i = 0; i < si->nscreens; i++)
4188 + suspend_screenhack (&si->screens[i], False); /* resume */
4190 if (!ok_to_unblank &&
4191 !screenhack_running_p (si))
4192 @@ -1451,7 +1231,8 @@
4193 blurb(), timestring ());
4195 /* Kill before unblanking, to stop drawing as soon as possible. */
4196 - kill_screenhack (si);
4197 + for (i = 0; i < si->nscreens; i++)
4198 + kill_screenhack (&si->screens[i]);
4199 unblank_screen (si);
4201 set_locked_p (si, False);
4202 @@ -1530,6 +1311,7 @@
4204 shell = connect_to_server (si, &argc, argv);
4205 process_command_line (si, &argc, argv);
4206 + stderr_log_file (si);
4209 load_init_file(si->dpy, p); /* must be before initialize_per_screen_info() */
4210 @@ -1951,8 +1733,10 @@
4215 + for (i = 0; i < si->nscreens; i++)
4216 + kill_screenhack (&si->screens[i]);
4217 unblank_screen (si);
4218 - kill_screenhack (si);
4219 XSync (si->dpy, False);
4221 saver_exit (si, 0, 0);
4222 @@ -1974,8 +1758,10 @@
4227 + for (i = 0; i < si->nscreens; i++)
4228 + kill_screenhack (&si->screens[i]);
4229 unblank_screen (si);
4230 - kill_screenhack (si);
4231 XSync (si->dpy, False);
4234 @@ -2254,17 +2040,15 @@
4238 + }, { "DRI", "DRI",
4240 }, { "Apple-DRI", "Apple-DRI (XDarwin)",
4245 - fprintf (stderr, "%s: running on display \"%s\" (%d %sscreen%s).\n",
4247 - DisplayString(si->dpy),
4249 - (si->xinerama_p ? "Xinerama " : ""),
4250 - (si->nscreens == 1 ? "" : "s"));
4251 + fprintf (stderr, "%s: running on display \"%s\"\n", blurb(),
4252 + DisplayString(si->dpy));
4253 fprintf (stderr, "%s: vendor is %s, %d.\n", blurb(),
4254 ServerVendor(si->dpy), VendorRelease(si->dpy));
4256 @@ -2324,21 +2108,10 @@
4260 - if (si->xinerama_p)
4262 - fprintf (stderr, "%s: Xinerama layout:\n", blurb());
4263 - for (i = 0; i < si->nscreens; i++)
4265 - saver_screen_info *ssi = &si->screens[i];
4266 - fprintf (stderr, "%s: %c %d/%d: %dx%d+%d+%d\n",
4268 - (ssi->real_screen_p ? '+' : ' '),
4269 - ssi->number, ssi->real_screen_number,
4270 - ssi->width, ssi->height, ssi->x, ssi->y);
4273 + describe_monitor_layout (si);
4278 display_is_on_console_p (saver_info *si)
4280 Index: xscreensaver/driver/xscreensaver.h
4281 ===================================================================
4282 --- xscreensaver.orig/driver/xscreensaver.h 2008-07-16 23:47:00.000000000 +0200
4283 +++ xscreensaver/driver/xscreensaver.h 2008-07-17 00:07:00.000000000 +0200
4285 -/* xscreensaver, Copyright (c) 1993-2006 Jamie Zawinski <jwz@jwz.org>
4286 +/* xscreensaver, Copyright (c) 1993-2008 Jamie Zawinski <jwz@jwz.org>
4288 * Permission to use, copy, modify, distribute, and sell this software and its
4289 * documentation for any purpose is hereby granted without fee, provided that
4292 ======================================================================= */
4294 +extern Bool update_screen_layout (saver_info *si);
4295 extern void initialize_screensaver_window (saver_info *si);
4296 +extern void initialize_screen_root_widget (saver_screen_info *ssi);
4298 extern void raise_window (saver_info *si,
4299 Bool inhibit_fade, Bool between_hacks_p,
4301 @@ -156,12 +159,12 @@
4302 #endif /* !HAVE_SIGACTION */
4303 extern void unblock_sigchld (void);
4304 extern void hack_environment (saver_info *si);
4305 -extern void hack_subproc_environment (saver_screen_info *ssi);
4306 +extern void hack_subproc_environment (Screen *, Window saver_window);
4307 extern void init_sigchld (void);
4308 -extern void spawn_screenhack (saver_info *si, Bool first_time_p);
4309 +extern void spawn_screenhack (saver_screen_info *ssi);
4310 extern pid_t fork_and_exec (saver_screen_info *ssi, const char *command);
4311 -extern void kill_screenhack (saver_info *si);
4312 -extern void suspend_screenhack (saver_info *si, Bool suspend_p);
4313 +extern void kill_screenhack (saver_screen_info *ssi);
4314 +extern void suspend_screenhack (saver_screen_info *ssi, Bool suspend_p);
4315 extern Bool screenhack_running_p (saver_info *si);
4316 extern void emergency_kill_subproc (saver_info *si);
4317 extern Bool select_visual (saver_screen_info *ssi, const char *visual_name);
4320 extern FILE *real_stderr;
4321 extern FILE *real_stdout;
4322 +extern void stderr_log_file (saver_info *si);
4323 extern void initialize_stderr (saver_info *si);
4324 extern void reset_stderr (saver_screen_info *ssi);
4325 extern void clear_stderr (saver_screen_info *ssi);
4326 @@ -194,8 +198,13 @@
4327 extern Bool window_exists_p (Display *dpy, Window window);
4328 extern char *timestring (void);
4329 extern Bool display_is_on_console_p (saver_info *si);
4330 -extern Visual *get_best_gl_visual (saver_screen_info *ssi);
4331 +extern Visual *get_best_gl_visual (saver_info *si, Screen *screen);
4332 extern void check_for_leaks (const char *where);
4333 +extern void describe_monitor_layout (saver_info *si);
4335 +#ifdef HAVE_XF86VMODE
4336 +Bool safe_XF86VidModeGetViewPort (Display *, int, int *, int *);
4337 +#endif /* HAVE_XF86VMODE */
4339 extern Atom XA_VROOT, XA_XSETROOT_ID, XA_ESETROOT_PMAP_ID, XA_XROOTPMAP_ID;
4340 extern Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_ID;
4341 Index: xscreensaver/hacks/screenhack.c
4342 ===================================================================
4343 --- xscreensaver.orig/hacks/screenhack.c 2008-07-16 23:47:00.000000000 +0200
4344 +++ xscreensaver/hacks/screenhack.c 2008-07-17 00:07:00.000000000 +0200
4346 window = VirtualRootWindowOfScreen (XtScreen (toplevel));
4347 XtDestroyWidget (toplevel);
4348 XGetWindowAttributes (dpy, window, &xgwa);
4349 + /* With RANDR, the root window can resize! */
4350 + XSelectInput (dpy, window, xgwa.your_event_mask | StructureNotifyMask);
4351 visual_warning (xgwa.screen, window, xgwa.visual, xgwa.colormap, False);