began for maemo
[xscreensaver] / xscreensaver / debian / patches / 10_jwz-xscreensaver-randr-patch-3.patch
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
6
7 Please see http://jwz.livejournal.com/908354.html
8
9 Apply this patch with:
10
11     cd xscreensaver-5.05
12     patch -p1 < ../xscreensaver-randr-patch-3.txt
13
14 Thanks!
15
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
20 @@ -234,6 +234,9 @@
21     available if the file /usr/include/X11/extensions/Xrandr.h exists.) */
22  #undef HAVE_RANDR
23  
24 +/* Define this if the RANDR library is version 1.2 or newer. */
25 +#undef HAVE_RANDR_12
26 +
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
34 @@ -2060,6 +2060,9 @@
35  
36  
37  
38 +
39 +
40 +
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 @@
45  
46  
47  
48 +# Need to disable Objective C extensions in ANSI C on MacOS X to work
49 +# around an Apple-specific gcc bug.
50 +#
51 +
52  
53  ###############################################################################
54  #
55 @@ -2124,18 +2131,6 @@
56  
57  ###############################################################################
58  #
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.)
61 -#
62 -###############################################################################
63 -
64 -
65 -
66 -
67 -
68 -
69 -###############################################################################
70 -#
71  #       Function to figure out how to create directory trees.
72  #
73  ###############################################################################
74 @@ -3455,6 +3450,7 @@
75         ac_cv_gcc_accepts_no_overlength=no
76       else
77         ac_cv_gcc_accepts_no_overlength=yes
78 +       CC="$CC -Wno-overlength-strings"
79       fi
80  fi
81  { echo "$as_me:$LINENO: result: $ac_cv_gcc_accepts_no_overlength" >&5
82 @@ -3475,6 +3471,7 @@
83         ac_cv_gcc_accepts_no_decl_after=no
84       else
85         ac_cv_gcc_accepts_no_decl_after=yes
86 +       CC="$CC -Wdeclaration-after-statement"
87       fi
88  fi
89  { echo "$as_me:$LINENO: result: $ac_cv_gcc_accepts_no_decl_after" >&5
90 @@ -3483,7 +3480,6 @@
91    fi
92  
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
98 @@ -3496,6 +3492,7 @@
99         ac_cv_gcc_accepts_no_cpp_precomp=no
100       else
101         ac_cv_gcc_accepts_no_cpp_precomp=yes
102 +       CC="$CC -no-cpp-precomp"
103       fi
104  fi
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"
108    fi
109  
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"
114 -   fi
115 -  fi
116 -
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
122       else
123         ac_cv_gcc_accepts_std=yes
124 +       CC="$CC -std=c89"
125       fi
126  fi
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.)
131       #
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__"
135     else
136       # The old way:
137       CC="$CC -Wp,-lang-c89"
138 @@ -12140,7 +12132,7 @@
139  
140  if test "$with_randr" = yes; then
141  
142 -  # first check for Randr.h
143 +  # first check for Xrandr.h
144  
145    ac_save_CPPFLAGS="$CPPFLAGS"
146    if test \! -z "$includedir" ; then
147 @@ -12489,7 +12481,103 @@
148  #define HAVE_RANDR 1
149  _ACEOF
150  
151 +
152 +    # Now check for version 1.2 in the same libs.
153 +
154 +  ac_save_CPPFLAGS="$CPPFLAGS"
155 +  ac_save_LDFLAGS="$LDFLAGS"
156 +#  ac_save_LIBS="$LIBS"
157 +
158 +  if test \! -z "$includedir" ; then
159 +    CPPFLAGS="$CPPFLAGS -I$includedir"
160 +  fi
161 +  # note: $X_CFLAGS includes $x_includes
162 +  CPPFLAGS="$CPPFLAGS $X_CFLAGS"
163 +
164 +  if test \! -z "$libdir" ; then
165 +    LDFLAGS="$LDFLAGS -L$libdir"
166    fi
167 +  # note: $X_LIBS includes $x_libraries
168 +  LDFLAGS="$LDFLAGS $X_LIBS $X_EXTRA_LIBS"
169 +
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
176 +else
177 +  ac_check_lib_save_LIBS=$LIBS
178 +LIBS="-lc $SAVER_LIBS $LIBS"
179 +cat >conftest.$ac_ext <<_ACEOF
180 +/* confdefs.h.  */
181 +_ACEOF
182 +cat confdefs.h >>conftest.$ac_ext
183 +cat >>conftest.$ac_ext <<_ACEOF
184 +/* end confdefs.h.  */
185 +
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.  */
189 +#ifdef __cplusplus
190 +extern "C"
191 +#endif
192 +char XRRGetOutputInfo ();
193 +int
194 +main ()
195 +{
196 +return XRRGetOutputInfo ();
197 +  ;
198 +  return 0;
199 +}
200 +_ACEOF
201 +rm -rf conftest.$ac_objext conftest$ac_exeext
202 +if { (ac_try="$ac_link"
203 +case "(($ac_try" in
204 +  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
205 +  *) ac_try_echo=$ac_try;;
206 +esac
207 +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
208 +  (eval "$ac_link") 2>conftest.er1
209 +  ac_status=$?
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
220 +else
221 +  echo "$as_me: failed program was:" >&5
222 +sed 's/^/| /' conftest.$ac_ext >&5
223 +
224 +       ac_cv_lib_c_XRRGetOutputInfo=no
225 +fi
226 +
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
230 +fi
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
236 +_ACEOF
237 +
238 +else
239 +  true
240 +fi
241 +
242 +  CPPFLAGS="$ac_save_CPPFLAGS"
243 +  LDFLAGS="$ac_save_LDFLAGS"
244 +#  LIBS="$ac_save_LIBS"
245 +
246 +  fi
247 +
248  
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
253  else
254    cat > conftest.$ac_ext <<EOF
255 -#line 16680 "configure"
256 +#line 16768 "configure"
257  #include "confdefs.h"
258  #include <GL/gl.h>
259  #ifndef MESA_MAJOR_VERSION
260 @@ -19890,9 +19978,11 @@
261  
262      #### Could use some more defaults here...
263      for f in \
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"     \
272      ; do
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"
277  
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."
281 +    true
282 +    # warnL "Unable to determine the MesaGL version number!"
283 +    # warn2 "Make sure you are using version $preferred_mesagl or newer."
284  
285    elif test \! "$ac_mesagl_version" -gt 2006; then
286      warnL "MesaGL version number is $mgv --"
287 @@ -22035,7 +22126,7 @@
288  
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'`
293  
294      warning=no
295      warnL "There is already an installed RPM of xscreensaver $rpmv"
296 @@ -22058,6 +22149,31 @@
297    fi
298  fi
299  
300 +# Also warn if there's a Debian package installed.
301 +#
302 +debnames="xscreensaver xscreensaver-data xscreensaver-data-extra"
303 +debv=''
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'`
307 +  fi
308 +done
309 +
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'`
315 +
316 +  warning=no
317 +  warnL "There is already an installed dpkg of xscreensaver"
318 +  warn2 "version \"$debv\" on this system."
319 +  echo ""
320 +  warn2 "The dpkg was installed in $debbdir/,"
321 +  warn2 "with demos in $debhdir/."
322 +fi
323 +
324 +
325  if test "${bindir}" = "${HACKDIR}" ; then
326    do_dir_warning=yes
327  fi
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
332 @@ -106,6 +106,9 @@
333             possibly elsewhere.  (It's available if the file
334             /usr/include/X11/extensions/Xrandr.h exists.)])
335  
336 +AH_TEMPLATE([HAVE_RANDR_12],
337 +           [Define this if the RANDR library is version 1.2 or newer.])
338 +
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
342 @@ -389,6 +392,7 @@
343         ac_cv_gcc_accepts_[$1]=no
344       else
345         ac_cv_gcc_accepts_[$1]=yes
346 +       CC="$CC [$2]"
347       fi])
348     ac_gcc_accepts_[$1]="$ac_cv_gcc_accepts_[$1]"
349    fi
350 @@ -400,6 +404,11 @@
351  AC_DEFUN(AC_NO_MISPLACED_DECLARATIONS,
352           [AC_CHECK_GCC_ARG(no_decl_after, -Wdeclaration-after-statement)])
353  
354 +# Need to disable Objective C extensions in ANSI C on MacOS X to work
355 +# around an Apple-specific gcc bug.
356 +#
357 +AC_DEFUN(AC_NO_OBJECTIVE_C,
358 +         [AC_CHECK_GCC_ARG(no_cpp_precomp, -no-cpp-precomp)])
359  
360  ###############################################################################
361  #
362 @@ -447,7 +456,8 @@
363       # before they were in the ANSI C 99 spec...  (gcc 2.96 permits //
364       # with -std=gnu89 but not with -std=c89.)
365       #
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__"
369     else
370       # The old way:
371       CC="$CC -Wp,-lang-c89"
372 @@ -458,27 +468,6 @@
373  
374  ###############################################################################
375  #
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.)
378 -#
379 -###############################################################################
380 -
381 -AC_DEFUN(AC_GCC_ACCEPTS_NO_CPP_PRECOMP,
382 -         [AC_CHECK_GCC_ARG(no_cpp_precomp, -no-cpp-precomp)])
383 -
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"
390 -   fi
391 -  fi
392 -])
393 -
394 -
395 -###############################################################################
396 -#
397  #       Function to figure out how to create directory trees.
398  #
399  ###############################################################################
400 @@ -1667,7 +1656,7 @@
401  
402  if test "$with_randr" = yes; then
403  
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>])
408  
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)
413 +
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)
417    fi
418  
419 +
420  elif test "$with_randr" != no; then
421    echo "error: must be yes or no: --with-randr-ext=$with_randr"
422    exit 1
423 @@ -3414,9 +3408,11 @@
424  
425      #### Could use some more defaults here...
426      for f in \
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"     \
435      ; do
436        if test -z "$with_textfile"; then
437          AC_MSG_CHECKING([for text file $f])
438 @@ -4035,8 +4031,9 @@
439    pgl="$preferred_mesagl"
440  
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."
444 +    true
445 +    # warnL "Unable to determine the MesaGL version number!"
446 +    # warn2 "Make sure you are using version $preferred_mesagl or newer."
447  
448    elif test \! "$ac_mesagl_version" -gt 2006; then
449      warnL "MesaGL version number is $mgv --"
450 @@ -4182,7 +4179,7 @@
451  
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'`
456  
457      warning=no
458      warnL "There is already an installed RPM of xscreensaver $rpmv"
459 @@ -4205,6 +4202,31 @@
460    fi
461  fi
462  
463 +# Also warn if there's a Debian package installed.
464 +#
465 +debnames="xscreensaver xscreensaver-data xscreensaver-data-extra"
466 +debv=''
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'`
470 +  fi
471 +done
472 +
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'`
478 +
479 +  warning=no
480 +  warnL "There is already an installed dpkg of xscreensaver"
481 +  warn2 "version \"$debv\" on this system."
482 +  echo ""
483 +  warn2 "The dpkg was installed in $debbdir/,"
484 +  warn2 "with demos in $debhdir/."
485 +fi
486 +
487 +
488  if test "${bindir}" = "${HACKDIR}" ; then
489    do_dir_warning=yes
490  fi
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 @@
496  
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
505  
506  MOTIF_LIBS     = @MOTIF_LIBS@ @XPM_LIBS@ $(XMU_LIBS)
507  GTK_LIBS       = @GTK_LIBS@ $(XMU_LIBS)
508 @@ -147,9 +147,9 @@
509  GTK_ICONS      = $(ICON_SRC)/screensaver-*.png
510  
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)
517  
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 \
522                   $(XMU_OBJS)
523  
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
532  
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)
539  
540  CMD_SRCS       = remote.c xscreensaver-command.c
541  CMD_OBJS       = remote.o xscreensaver-command.o
542  
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
547  
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)
552  
553  PDF2JPEG_SRCS  = pdf2jpeg.m
554  PDF2JPEG_OBJS  = pdf2jpeg.o
555 @@ -453,7 +453,7 @@
556   $$e "  ####################################################################";\
557   $$e ""                                                                             ;\
558           fi ;                                                          \
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" ;   \
563           else                                                          \
564 @@ -498,7 +498,7 @@
565              echo $(INSTALL_DIRS) "$(install_prefix)$(GTK_APPDIR)"           ;\
566                   $(INSTALL_DIRS) "$(install_prefix)$(GTK_APPDIR)"           ;\
567            fi                                                                ;\
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                \
573 @@ -571,7 +571,7 @@
574  # into /usr/share/applications/
575  uninstall-gnome::
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                      ;\
581          fi
582 @@ -846,6 +846,11 @@
583  test-fade: test-fade.o $(UTILS_BIN)/fade.o
584         $(CC) $(LDFLAGS) -o $@ $(TEST_FADE_OBJS) $(SAVER_LIBS)
585  
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)
590 +
591  
592  xdpyinfo.o: xdpyinfo.c
593         $(CC) -c $(INCLUDES) -DHAVE_GLX $(CFLAGS) $(X_CFLAGS) \
594 @@ -913,6 +918,11 @@
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
606 @@ -954,6 +964,12 @@
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
623 @@ -4,8 +4,8 @@
624  !            a screen saver and locker for the X window system
625  !                            by Jamie Zawinski
626  !
627 -!                              version 5.05
628 -!                              01-Mar-2008
629 +!                              version 5.06
630 +!                              05-Jul-2008
631  !
632  ! See "man xscreensaver" for more info.  The latest version is always
633  ! available at http://www.jwz.org/xscreensaver/
634 @@ -125,7 +125,8 @@
635  
636  
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".
641  !
642  @NEW_LOGIN_COMMAND_P@*newLoginCommand: @NEW_LOGIN_COMMAND@
643  
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
648 @@ -272,6 +272,9 @@
649  void settings_cancel_cb (GtkButton *, gpointer user_data);
650  void settings_ok_cb (GtkButton *, gpointer user_data);
651  
652 +static void kill_gnome_screensaver (void);
653 +static void kill_kde_screensaver (void);
654 +
655  \f
656  /* Some random utility functions
657   */
658 @@ -482,9 +485,23 @@
659    warning_dialog_dismiss_cb (widget, user_data);
660  }
661  
662 +static void warning_dialog_killg_cb (GtkWidget *widget, gpointer user_data)
663 +{
664 +  kill_gnome_screensaver ();
665 +  warning_dialog_dismiss_cb (widget, user_data);
666 +}
667 +
668 +static void warning_dialog_killk_cb (GtkWidget *widget, gpointer user_data)
669 +{
670 +  kill_kde_screensaver ();
671 +  warning_dialog_dismiss_cb (widget, user_data);
672 +}
673 +
674 +typedef enum { D_NONE, D_LAUNCH, D_GNOME, D_KDE } dialog_button;
675 +
676  static void
677  warning_dialog (GtkWidget *parent, const char *message,
678 -                Boolean restart_button_p, int center)
679 +                dialog_button button_type, int center)
680  {
681    char *msg = strdup (message);
682    char *head;
683 @@ -557,7 +574,7 @@
684                        label, TRUE, TRUE, 0);
685  
686  #ifdef HAVE_GTK2
687 -  if (restart_button_p)
688 +  if (button_type != D_NONE)
689      {
690        cancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
691        gtk_container_add (GTK_CONTAINER (label), cancel);
692 @@ -571,7 +588,7 @@
693    ok = gtk_button_new_with_label ("OK");
694    gtk_container_add (GTK_CONTAINER (label), ok);
695  
696 -  if (restart_button_p)
697 +  if (button_type != D_NONE)
698      {
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);
709  
710    if (cancel)
711      {
712 -      STFU GTK_WIDGET_SET_FLAGS (cancel, GTK_CAN_DEFAULT); 
713 +      GTK_WIDGET_SET_FLAGS (cancel, GTK_CAN_DEFAULT); 
714        gtk_widget_show (cancel);
715      }
716    gtk_widget_show (label);
717    gtk_widget_show (dialog);
718  
719 -  if (restart_button_p)
720 +  if (button_type != D_NONE)
721      {
722 -      gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
723 -                                 GTK_SIGNAL_FUNC (warning_dialog_restart_cb),
724 +      GtkSignalFunc fn;
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;
730 +      }
731 +      gtk_signal_connect_object (GTK_OBJECT (ok), "clicked", fn, 
732                                   (gpointer) dialog);
733        gtk_signal_connect_object (GTK_OBJECT (cancel), "clicked",
734                                   GTK_SIGNAL_FUNC (warning_dialog_dismiss_cb),
735 @@ -644,7 +667,7 @@
736          sprintf (buf, "Error:\n\n%s", err);
737        else
738          strcpy (buf, "Unknown error!");
739 -      warning_dialog (s->toplevel_widget, buf, False, 100);
740 +      warning_dialog (s->toplevel_widget, buf, D_NONE, 100);
741      }
742    if (err) free (err);
743  
744 @@ -685,7 +708,7 @@
745                  sprintf (buf, "Error:\n\n%s", err);
746                else
747                  strcpy (buf, "Unknown error!");
748 -              warning_dialog (s->toplevel_widget, buf, False, 100);
749 +              warning_dialog (s->toplevel_widget, buf, D_NONE, 100);
750              }
751          }
752        else
753 @@ -700,7 +723,7 @@
754                       "The XScreenSaver daemon doesn't seem to be running\n"
755                       "on display \"%s\".  Launch it now?"),
756                     d);
757 -          warning_dialog (s->toplevel_widget, msg, True, 1);
758 +          warning_dialog (s->toplevel_widget, msg, D_LAUNCH, 1);
759          }
760      }
761  
762 @@ -875,7 +898,7 @@
763      {
764        warning_dialog (s->toplevel_widget,
765                        _("Error:\n\n"
766 -                       "No Help URL has been specified.\n"), False, 100);
767 +                       "No Help URL has been specified.\n"), D_NONE, 100);
768        return;
769      }
770  
771 @@ -1001,7 +1024,7 @@
772        else
773          strcat (buf, _("Please check your $PATH and permissions."));
774  
775 -      warning_dialog (s->toplevel_widget, buf, False, 1);
776 +      warning_dialog (s->toplevel_widget, buf, D_NONE, 1);
777      }
778  
779    force_dialog_repaint (s);
780 @@ -1038,12 +1061,12 @@
781        if (!f || !*f)
782          warning_dialog (s->toplevel_widget,
783                          _("Error:\n\nCouldn't determine init file name!\n"),
784 -                        False, 100);
785 +                        D_NONE, 100);
786        else
787          {
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);
792            free (b);
793          }
794        return -1;
795 @@ -1106,7 +1129,7 @@
796      {
797        warning_dialog (GTK_WIDGET (button),
798                        _("Error:\n\nno `manualCommand' resource set."),
799 -                      False, 100);
800 +                      D_NONE, 100);
801      }
802  
803    free (oname);
804 @@ -1291,7 +1314,7 @@
805                    _("Error:\n\n"
806                      "Unparsable time format: \"%s\"\n"),
807                    line);
808 -         warning_dialog (s->toplevel_widget, b, False, 100);
809 +         warning_dialog (s->toplevel_widget, b, D_NONE, 100);
810         }
811        else
812         *store = value;
813 @@ -1537,7 +1560,7 @@
814        char b[255];
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);
819      }
820  
821  
822 @@ -1808,7 +1831,7 @@
823    char *str;
824    int list_elt;
825  
826 -  STFU g_return_if_fail (!gdk_pointer_is_grabbed ());
827 +  g_return_if_fail (!gdk_pointer_is_grabbed ());
828  
829    str = gtk_tree_path_to_string (path);
830    list_elt = strtol (str, NULL, 10);
831 @@ -1996,7 +2019,7 @@
832      {
833        char b[255];
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);
837        return;
838      }
839  
840 @@ -2026,7 +2049,7 @@
841      {
842        char b[255];
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);
846        return;
847      }
848  
849 @@ -2057,7 +2080,7 @@
850      {
851        char b[255];
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);
855        return;
856      }
857  # endif
858 @@ -3414,7 +3437,7 @@
859                 _("Warning:\n\n"
860                  "file \"%s\" has changed, reloading.\n"),
861                 f);
862 -      warning_dialog (s->toplevel_widget, b, False, 100);
863 +      warning_dialog (s->toplevel_widget, b, D_NONE, 100);
864        free (b);
865  
866        load_init_file (dpy, p);
867 @@ -4247,6 +4270,77 @@
868  #endif
869  
870  
871 +static Window
872 +gnome_screensaver_window (Screen *screen)
873 +{
874 +  Display *dpy = DisplayOfScreen (screen);
875 +  Window root = RootWindowOfScreen (screen);
876 +  Window parent, *kids;
877 +  unsigned int nkids;
878 +  Window gnome_window = 0;
879 +  int i;
880 +
881 +  if (! XQueryTree (dpy, root, &root, &parent, &kids, &nkids))
882 +    abort ();
883 +  for (i = 0; i < nkids; i++)
884 +    {
885 +      Atom type;
886 +      int format;
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)
892 +          == Success
893 +          && type != None
894 +          && !strcmp ((char *) name, "gnome-screensaver"))
895 +       {
896 +         gnome_window = kids[i];
897 +          break;
898 +       }
899 +    }
900 +
901 +  if (kids) XFree ((char *) kids);
902 +  return gnome_window;
903 +}
904 +
905 +static Bool
906 +gnome_screensaver_active_p (void)
907 +{
908 +  Display *dpy = GDK_DISPLAY();
909 +  Window w = gnome_screensaver_window (DefaultScreenOfDisplay (dpy));
910 +  return (w ? True : False);
911 +}
912 +
913 +static void
914 +kill_gnome_screensaver (void)
915 +{
916 +  Display *dpy = GDK_DISPLAY();
917 +  Window w = gnome_screensaver_window (DefaultScreenOfDisplay (dpy));
918 +  if (w) XKillClient (dpy, (XID) w);
919 +}
920 +
921 +static Bool
922 +kde_screensaver_active_p (void)
923 +{
924 +  FILE *p = popen ("dcop kdesktop KScreensaverIface isEnabled 2>/dev/null",
925 +                   "r");
926 +  char buf[255];
927 +  fgets (buf, sizeof(buf)-1, p);
928 +  pclose (p);
929 +  if (!strcmp (buf, "true\n"))
930 +    return True;
931 +  else
932 +    return False;
933 +}
934 +
935 +static void
936 +kill_kde_screensaver (void)
937 +{
938 +  system ("dcop kdesktop KScreensaverIface enable false");
939 +}
940 +
941 +
942  static void
943  the_network_is_not_the_computer (state *s)
944  {
945 @@ -4360,12 +4454,36 @@
946  
947  
948    if (*msg)
949 -    warning_dialog (s->toplevel_widget, msg, True, 1);
950 +    warning_dialog (s->toplevel_widget, msg, D_LAUNCH, 1);
951  
952    if (rversion) free (rversion);
953    if (ruser) free (ruser);
954    if (rhost) free (rhost);
955    free (msg);
956 +  msg = 0;
957 +
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.
961 +   */
962 +
963 +  if (gnome_screensaver_active_p ())
964 +    warning_dialog (s->toplevel_widget,
965 +                    _("Warning:\n\n"
966 +                      "The GNOME screensaver daemon appears to be running.\n"
967 +                      "It must be stopped for XScreenSaver to work properly.\n"
968 +                      "\n"
969 +                      "Stop the GNOME screen saver daemon now?\n"),
970 +                    D_GNOME, 1);
971 +
972 +  if (kde_screensaver_active_p ())
973 +    warning_dialog (s->toplevel_widget,
974 +                    _("Warning:\n\n"
975 +                      "The KDE screen saver daemon appears to be running.\n"
976 +                      "It must be stopped for XScreenSaver to work properly.\n"
977 +                      "\n"
978 +                      "Stop the KDE screen saver daemon now?\n"),
979 +                    D_KDE, 1);
980  }
981  
982  
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
987 @@ -1,5 +1,5 @@
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>
991   *
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
994 @@ -181,8 +181,7 @@
995    int hairy_p;
996  
997  #ifndef VMS
998 -  if (nice != 0)
999 -    nice_process (nice_level);
1000 +  nice_process (nice_level);
1001  
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
1008 @@ -1,5 +1,5 @@
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>
1012   *
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
1015 @@ -179,7 +179,7 @@
1016  
1017  extern void xss_authenticate(saver_info *si, Bool verbose_p);
1018  
1019 -static void
1020 +static int
1021  new_passwd_window (saver_info *si)
1022  {
1023    passwd_dialog_data *pw;
1024 @@ -190,7 +190,7 @@
1025  
1026    pw = (passwd_dialog_data *) calloc (1, sizeof(*pw));
1027    if (!pw)
1028 -    return;
1029 +    return -1;
1030  
1031    /* Display the button only if the "newLoginCommand" pref is non-null.
1032     */
1033 @@ -406,13 +406,14 @@
1034    }
1035  
1036    si->pw_data = pw;
1037 +  return 0;
1038  }
1039  
1040  
1041  /**
1042   * info_msg and prompt may be NULL.
1043   */
1044 -static void
1045 +static int
1046  make_passwd_window (saver_info *si,
1047                     const char *info_msg,
1048                     const char *prompt,
1049 @@ -428,11 +429,15 @@
1050  
1051    cleanup_passwd_window (si);
1052  
1053 +  if (! ssi)   /* WTF?  Trying to prompt while no screens connected? */
1054 +    return -1;
1055 +
1056    if (!si->pw_data)
1057 -    new_passwd_window (si);
1058 +    if (new_passwd_window (si) < 0)
1059 +      return -1;
1060  
1061    if (!(pw = si->pw_data))
1062 -    return;
1063 +    return -1;
1064  
1065    pw->ratio = 1.0;
1066  
1067 @@ -614,10 +619,11 @@
1068       actually be visible; this takes into account virtual viewports as
1069       well as Xinerama. */
1070    {
1071 -    int x, y, w, h;
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)];
1076 +    int x = ssi->x;
1077 +    int y = ssi->y;
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;
1083 @@ -678,6 +684,8 @@
1084    if (cmap)
1085      XInstallColormap (si->dpy, cmap);
1086    draw_passwd_window (si);
1087 +
1088 +  return 0;
1089  }
1090  
1091  
1092 @@ -1463,6 +1471,7 @@
1093    static Bool any_mode_locked_p = False;
1094    saver_preferences *p = &si->prefs;
1095    int screen;
1096 +  int real_nscreens = ScreenCount (si->dpy);
1097    int event, error;
1098    Bool status;
1099    XErrorHandler old_handler;
1100 @@ -1472,7 +1481,7 @@
1101    if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1102      return;
1103  
1104 -  for (screen = 0; screen < (si->xinerama_p ? 1 : si->nscreens); screen++)
1105 +  for (screen = 0; screen < real_nscreens; screen++)
1106      {
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;
1112    int screen;
1113 +  int real_nscreens = ScreenCount (si->dpy);
1114    int event, error;
1115  
1116    if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1117      return;
1118  
1119 -  for (screen = 0; screen < si->nscreens; screen++)
1120 +  for (screen = 0; screen < real_nscreens; screen++)
1121      {
1122        saver_screen_info *ssi = &si->screens[screen];
1123        int x, y;
1124 @@ -1932,9 +1942,11 @@
1125         info_msg_trimmed = remove_trailing_whitespace(info_msg);
1126         prompt_trimmed = remove_trailing_whitespace(prompt);
1127  
1128 -       make_passwd_window(si, info_msg_trimmed, prompt_trimmed,
1129 -                          auth_msgs[i].type == AUTH_MSGTYPE_PROMPT_ECHO
1130 -                          ? True : False);
1131 +       if (make_passwd_window(si, info_msg_trimmed, prompt_trimmed,
1132 +                               auth_msgs[i].type == AUTH_MSGTYPE_PROMPT_ECHO
1133 +                               ? True : False)
1134 +            < 0)
1135 +          goto fail;
1136  
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
1143 @@ -78,6 +78,10 @@
1144   static const char *tk_file;
1145  #endif /* !HAVE_DARWIN */
1146  
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);
1150 +
1151  
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 @@
1159  
1160    ret = si->unlock_cb(nmsgs, messages, &authresp, si);
1161  
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.
1168 +   */
1169 +
1170    if (ret == 0)
1171      {
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
1177 @@ -1,6 +1,6 @@
1178  /* pdf2jpeg -- converts a PDF file to a JPEG file, using Cocoa
1179   *
1180 - * Copyright (c) 2003 by Jamie Zawinski <jwz@jwz.org>
1181 + * Copyright (c) 2003, 2008 by Jamie Zawinski <jwz@jwz.org>
1182   *
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
1185 @@ -23,6 +23,7 @@
1186    const char *progname = argv[0];
1187    const char *infile = 0, *outfile = 0;
1188    double compression = 0.85;
1189 +  double scale = 1.0;
1190    int verbose = 0;
1191    int i;
1192  
1193 @@ -45,6 +46,18 @@
1194              }
1195            compression = q / 100.0;
1196          }
1197 +      else if (!strcmp (argv[i], "-scale"))
1198 +        {
1199 +          float s;
1200 +          if (1 != sscanf (argv[++i], " %f %c", &s, &c) ||
1201 +              s <= 0 || s > 50)
1202 +            {
1203 +              fprintf (stderr, "%s: scale must be 0.0 - 50.0 (%f)\n",
1204 +                       progname, s);
1205 +              goto USAGE;
1206 +            }
1207 +          scale = s;
1208 +        }
1209        else if (!strcmp (argv[i], "-verbose"))
1210          verbose++;
1211        else if (!strcmp (argv[i], "-v") ||
1212 @@ -64,7 +77,7 @@
1213          {
1214          USAGE:
1215            fprintf (stderr,
1216 -                   "usage: %s [-verbose] [-quality NN] "
1217 +                   "usage: %s [-verbose] [-scale N] [-quality NN] "
1218                     "infile.pdf outfile.jpg\n",
1219                     progname);
1220            exit (1);
1221 @@ -93,11 +106,16 @@
1222    NSPDFImageRep *pdf_rep = [NSPDFImageRep imageRepWithData:pdf_data];
1223  
1224    // Create an NSImage instance
1225 -  NSImage *image = [[NSImage alloc] initWithSize:[pdf_rep size]];
1226 +  NSRect rect;
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];
1232  
1233    // Draw the PDFImageRep in the NSImage
1234    [image lockFocus];
1235 -  [pdf_rep drawAtPoint:NSMakePoint(0.0,0.0)];
1236 +  [pdf_rep drawInRect:rect];
1237    [image unlockFocus];
1238  
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
1244 @@ -1,5 +1,5 @@
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>
1248   *
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
1251 @@ -272,6 +272,7 @@
1252    "fadeTicks",
1253    "captureStderr",
1254    "captureStdout",             /* not saved -- obsolete */
1255 +  "logFile",                   /* not saved */
1256    "ignoreUninstalledPrograms",
1257    "font",
1258    "dpmsEnabled",
1259 @@ -808,6 +809,7 @@
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;
1266  
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
1271 @@ -0,0 +1,894 @@
1272 +/* screens.c --- dealing with RANDR, Xinerama, and VidMode Viewports.
1273 + * xscreensaver, Copyright (c) 1991-2008 Jamie Zawinski <jwz@jwz.org>
1274 + *
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.
1282 + */
1283 +
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
1290 + *   screen saver.)
1291 + *
1292 + *   1) Multi-screen:
1293 + *
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.
1303 + *
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.
1307 + *
1308 + *   2) Xinerama:
1309 + *
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.)
1317 + *
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.
1321 + *
1322 + *   3) Vidmode Viewports:
1323 + *
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
1328 + *      in/out).
1329 + *
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.
1333 + *
1334 + *      Also, half the time it doesn't work at all: it tends to lie
1335 + *      about the size of the rectangle in use.
1336 + *
1337 + *   4) RANDR 1.0:
1338 + *
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
1345 + *      not sure.
1346 + *
1347 + *   5) RANDR 1.2:
1348 + *
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.
1360 + *
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.
1364 + *
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).
1372 + */
1373 +
1374 +#ifdef HAVE_CONFIG_H
1375 +# include "config.h"
1376 +#endif
1377 +
1378 +#include <X11/Xlib.h>
1379 +
1380 +#ifdef HAVE_RANDR
1381 +# include <X11/extensions/Xrandr.h>
1382 +#endif /* HAVE_RANDR */
1383 +
1384 +#ifdef HAVE_XINERAMA
1385 +# include <X11/extensions/Xinerama.h>
1386 +#endif /* HAVE_XINERAMA */
1387 +
1388 +#ifdef HAVE_XF86VMODE
1389 +# include <X11/extensions/xf86vmode.h>
1390 +#endif /* HAVE_XF86VMODE */
1391 +
1392 +/* This file doesn't need the Xt headers, so stub these types out... */
1393 +#undef XtPointer
1394 +#define XtAppContext void*
1395 +#define XrmDatabase  void*
1396 +#define XtIntervalId void*
1397 +#define XtPointer    void*
1398 +#define Widget       void*
1399 +
1400 +#include "xscreensaver.h"
1401 +#include "visual.h"
1402 +
1403 +
1404 +typedef enum { S_SANE, S_ENCLOSED, S_DUPLICATE, S_OVERLAP, 
1405 +               S_OFFSCREEN, S_DISABLED } monitor_sanity;
1406 +
1407 +/* 'typedef monitor' is in types.h */
1408 +struct _monitor {
1409 +  int id;
1410 +  char *desc;
1411 +  Screen *screen;
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 */
1415 +};
1416 +
1417 +static void
1418 +free_monitors (monitor **monitors)
1419 +{
1420 +  monitor **m2 = monitors;
1421 +  if (! monitors) return;
1422 +  while (*m2) 
1423 +    {
1424 +      if ((*m2)->desc) free ((*m2)->desc);
1425 +      free (*m2);
1426 +      m2++;
1427 +    }
1428 +  free (monitors);
1429 +}
1430 +
1431 +
1432 +#ifdef HAVE_XINERAMA
1433 +
1434 +static monitor **
1435 +xinerama_scan_monitors (Display *dpy)
1436 +{
1437 +  Screen *screen = DefaultScreenOfDisplay (dpy);
1438 +  int event, error, nscreens, i;
1439 +  XineramaScreenInfo *xsi;
1440 +  monitor **monitors;
1441 +
1442 +  if (! XineramaQueryExtension (dpy, &event, &error))
1443 +    return 0;
1444 +
1445 +  if (! XineramaIsActive (dpy)) 
1446 +    return 0;
1447 +
1448 +  xsi = XineramaQueryScreens (dpy, &nscreens);
1449 +  if (!xsi) return 0;
1450 +
1451 +  monitors = (monitor **) calloc (nscreens + 1, sizeof(*monitors));
1452 +  if (!monitors) return 0;
1453 +
1454 +  for (i = 0; i < nscreens; i++)
1455 +    {
1456 +      monitor *m = (monitor *) calloc (1, sizeof (monitor));
1457 +      monitors[i] = m;
1458 +      m->id       = i;
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;
1464 +    }
1465 +  return monitors;
1466 +}
1467 +
1468 +#endif /* HAVE_XINERAMA */
1469 +
1470 +
1471 +#ifdef HAVE_XF86VMODE
1472 +
1473 +static monitor **
1474 +vidmode_scan_monitors (Display *dpy)
1475 +{
1476 +  int event, error, nscreens, i;
1477 +  monitor **monitors;
1478 +
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:
1482 +
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
1486 +
1487 +     Presumably this is fixed by using RANDR instead of VidMode.
1488 +   */
1489 +
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))
1494 +    return 0;
1495 +#  endif /* !HAVE_XINERAMA */
1496 +
1497 +  if (! XF86VidModeQueryExtension (dpy, &event, &error))
1498 +    return 0;
1499 +
1500 +  nscreens = ScreenCount (dpy);
1501 +  monitors = (monitor **) calloc (nscreens + 1, sizeof(*monitors));
1502 +  if (!monitors) return 0;
1503 +
1504 +  for (i = 0; i < nscreens; i++)
1505 +    {
1506 +      monitor *m = (monitor *) calloc (1, sizeof (monitor));
1507 +      XF86VidModeModeLine ml;
1508 +      int dot;
1509 +      Screen *screen = ScreenOfDisplay (dpy, i);
1510 +
1511 +      monitors[i] = m;
1512 +      m->id       = i;
1513 +      m->screen   = screen;
1514 +
1515 +      if (! safe_XF86VidModeGetViewPort (dpy, i, &m->x, &m->y))
1516 +        m->x = m->y = -1;
1517 +
1518 +      if (XF86VidModeGetModeLine (dpy, i, &dot, &ml))
1519 +        {
1520 +          m->width  = ml.hdisplay;
1521 +          m->height = ml.vdisplay;
1522 +        }
1523 +
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.
1530 +
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.
1535 +
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.
1543 +
1544 +         I'm going to guess that 16 pixels is enough, and that the Y dimension
1545 +         doesn't have this problem.
1546 +
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.
1550 +      */
1551 +#  define FUDGE 16
1552 +      if (m->x > 0 && m->x < m->width - ml.hdisplay)
1553 +        {
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.
1557 +           */
1558 +          m->x = ((m->x - 1) / FUDGE) * FUDGE;
1559 +          m->width += (FUDGE * 2);
1560 +        }
1561 +#  undef FUDGE
1562 +    }
1563 +
1564 +  return monitors;
1565 +}
1566 +
1567 +#endif /* HAVE_XF86VMODE */
1568 +
1569 +
1570 +#ifdef HAVE_RANDR
1571 +
1572 +static monitor **
1573 +randr_scan_monitors (Display *dpy)
1574 +{
1575 +  int event, error, major, minor, nscreens, i, j;
1576 +  monitor **monitors;
1577 +  Bool new_randr_p = False;
1578 +
1579 +  if (! XRRQueryExtension (dpy, &event, &error))
1580 +    return 0;
1581 +
1582 +  if (! XRRQueryVersion (dpy, &major, &minor))
1583 +    return 0;
1584 +
1585 +  if (major <= 0)    /* Protocol was still in flux back then -- fuck it. */
1586 +    return 0;
1587 +
1588 +# ifdef HAVE_RANDR_12
1589 +  new_randr_p = (major > 1 || (major == 1 && minor >= 2));
1590 +# endif
1591 +
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 */
1596 +    {
1597 +# ifdef HAVE_RANDR_12
1598 +      int xsc = ScreenCount (dpy);
1599 +      nscreens = 0;
1600 +      /* Add up the virtual screens on each X screen. */
1601 +      for (i = 0; i < xsc; i++)
1602 +        {
1603 +          XRRScreenResources *res = 
1604 +            XRRGetScreenResources (dpy, RootWindow (dpy, i));
1605 +          nscreens += res->noutput;
1606 +          XRRFreeScreenResources (res);
1607 +        }
1608 +# endif /* HAVE_RANDR_12 */
1609 +    }
1610 +
1611 +  monitors = (monitor **) calloc (nscreens + 1, sizeof(*monitors));
1612 +  if (!monitors) return 0;
1613 +
1614 +  for (i = 0, j = 0; i < ScreenCount (dpy); i++)
1615 +    {
1616 +      Screen *screen = ScreenOfDisplay (dpy, j);
1617 +
1618 +      if (! new_randr_p)  /* RANDR 1.0 */
1619 +        {
1620 +          XRRScreenConfiguration *rrc;
1621 +          monitor *m = (monitor *) calloc (1, sizeof (monitor));
1622 +          monitors[i] = m;
1623 +          m->screen   = screen;
1624 +          m->id       = i;
1625 +
1626 +          rrc = XRRGetScreenInfo (dpy, RootWindowOfScreen (screen));
1627 +          if (rrc)
1628 +            {
1629 +              SizeID size = -1;
1630 +              Rotation rot = ~0;
1631 +              XRRScreenSize *rrsizes;
1632 +              int nsizes;
1633 +
1634 +              size = XRRConfigCurrentConfiguration (rrc, &rot);
1635 +              rrsizes = XRRConfigSizes (rrc, &nsizes);
1636 +
1637 +              if (rot & (RR_Rotate_90|RR_Rotate_270))
1638 +                {
1639 +                  m->width  = rrsizes[size].height;
1640 +                  m->height = rrsizes[size].width;
1641 +                }
1642 +              else
1643 +                {
1644 +                  m->width  = rrsizes[size].width;
1645 +                  m->height = rrsizes[size].height;
1646 +                }
1647 +
1648 +              /* don't free 'rrsizes' */
1649 +              XRRFreeScreenConfigInfo (rrc);
1650 +            }
1651 +        }
1652 +      else   /* RANDR 1.2 or newer */
1653 +        {
1654 +# ifdef HAVE_RANDR_12
1655 +          int k;
1656 +          XRRScreenResources *res = 
1657 +            XRRGetScreenResources (dpy, RootWindowOfScreen (screen));
1658 +          for (k = 0; k < res->noutput; k++)
1659 +            {
1660 +              monitor *m = (monitor *) calloc (1, sizeof (monitor));
1661 +              XRROutputInfo *rroi = XRRGetOutputInfo (dpy, res, 
1662 +                                                      res->outputs[k]);
1663 +              RRCrtc crtc = (rroi->crtc ? rroi->crtc : rroi->crtcs[0]);
1664 +              XRRCrtcInfo *crtci = XRRGetCrtcInfo (dpy, res, crtc);
1665 +
1666 +              monitors[j] = m;
1667 +              m->screen   = screen;
1668 +              m->id       = (i * 1000) + j;
1669 +              m->desc     = (rroi->name ? strdup (rroi->name) : 0);
1670 +              m->x        = crtci->x;
1671 +              m->y        = crtci->y;
1672 +
1673 +              if (crtci->rotation & (RR_Rotate_90|RR_Rotate_270))
1674 +                {
1675 +                  m->width  = crtci->height;
1676 +                  m->height = crtci->width;
1677 +                }
1678 +              else
1679 +                {
1680 +                  m->width  = crtci->width;
1681 +                  m->height = crtci->height;
1682 +                }
1683 +
1684 +              j++;
1685 +
1686 +              if (rroi->connection == RR_Disconnected)
1687 +                m->sanity = S_DISABLED;
1688 +              /* #### do the same for RR_UnknownConnection? */
1689 +
1690 +              XRRFreeCrtcInfo (crtci);
1691 +              XRRFreeOutputInfo (rroi);
1692 +            }
1693 +          XRRFreeScreenResources (res);
1694 +# endif /* HAVE_RANDR_12 */
1695 +        }
1696 +    }
1697 +
1698 +  return monitors;
1699 +}
1700 +
1701 +#endif /* HAVE_RANDR */
1702 +
1703 +
1704 +static monitor **
1705 +basic_scan_monitors (Display *dpy)
1706 +{
1707 +  int nscreens = ScreenCount (dpy);
1708 +  int i;
1709 +  monitor **monitors = (monitor **) calloc (nscreens + 1, sizeof(*monitors));
1710 +  if (!monitors) return 0;
1711 +
1712 +  for (i = 0; i < nscreens; i++)
1713 +    {
1714 +      Screen *screen = ScreenOfDisplay (dpy, i);
1715 +      monitor *m = (monitor *) calloc (1, sizeof (monitor));
1716 +      monitors[i] = m;
1717 +      m->id       = i;
1718 +      m->screen   = screen;
1719 +      m->x        = 0;
1720 +      m->y        = 0;
1721 +      m->width    = WidthOfScreen (screen);
1722 +      m->height   = HeightOfScreen (screen);
1723 +    }
1724 +  return monitors;
1725 +}
1726 +
1727 +
1728 +#ifdef DEBUG_MULTISCREEN
1729 +
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.
1734 + */
1735 +static monitor **
1736 +debug_scan_monitors (Display *dpy)
1737 +{
1738 +  static const char * const geoms[] = {
1739 +    "1600x1028+0+22",
1740 +    "1024x768+0+22",
1741 +    "800x600+0+22",
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",
1748 +    "800x600+400+22",
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"
1750 +  };
1751 +  static int index = 0;
1752 +  monitor **monitors = (monitor **) calloc (100, sizeof(*monitors));
1753 +  int nscreens = 0;
1754 +  Screen *screen = DefaultScreenOfDisplay (dpy);
1755 +
1756 +  char *s = strdup (geoms[index]);
1757 +  char *token = strtok (s, ",");
1758 +  while (token)
1759 +    {
1760 +      monitor *m = calloc (1, sizeof (monitor));
1761 +      char c;
1762 +      m->id = nscreens;
1763 +      m->screen = screen;
1764 +      if (4 != sscanf (token, "%dx%d+%d+%d%c", 
1765 +                       &m->width, &m->height, &m->x, &m->y, &c))
1766 +        abort();
1767 +      m->width -= 2;
1768 +      m->height -= 2;
1769 +      monitors[nscreens++] = m;
1770 +      token = strtok (0, ",");
1771 +    }
1772 +  free (s);
1773 +  
1774 +  index = (index+1) % countof(geoms);
1775 +  return monitors;
1776 +}
1777 +
1778 +#endif /* DEBUG_MULTISCREEN */
1779 +
1780 +
1781 +#ifdef QUAD_MODE
1782 +static monitor **
1783 +quadruple (monitor **monitors, Bool debug_p)
1784 +{
1785 +  int i, j, count = 0;
1786 +  monitor **monitors2;
1787 +  while (monitors[count])
1788 +    count++;
1789 +  monitors2 = (monitor **) calloc (count * 4 + 1, sizeof(*monitors));
1790 +  if (!monitors2) abort();
1791 +
1792 +  for (i = 0, j = 0; i < count; i++)
1793 +    {
1794 +      int k;
1795 +      for (k = 0; k < 4; k++)
1796 +        {
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);
1804 +        }
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;
1809 +      j += 4;
1810 +    }
1811 +
1812 +  free_monitors (monitors);
1813 +  return monitors2;
1814 +}
1815 +#endif /* QUAD_MODE */
1816 +
1817 +
1818 +static monitor **
1819 +scan_monitors (saver_info *si)
1820 +{
1821 +  saver_preferences *p = &si->prefs;
1822 +  monitor **monitors = 0;
1823 +
1824 +# ifdef DEBUG_MULTISCREEN
1825 +    if (! monitors) monitors = debug_scan_monitors (si->dpy);
1826 +# endif
1827 +
1828 +# ifdef HAVE_RANDR
1829 +  if (! p->getviewport_full_of_lies_p)
1830 +    if (! monitors) monitors = randr_scan_monitors (si->dpy);
1831 +# endif
1832 +
1833 +# ifdef HAVE_XF86VMODE
1834 +  if (! monitors) monitors = vidmode_scan_monitors (si->dpy);
1835 +# endif
1836 +
1837 +# ifdef HAVE_XF86VMODE
1838 +  if (! monitors) monitors = xinerama_scan_monitors (si->dpy);
1839 +# endif
1840 +
1841 +  if (! monitors) monitors = basic_scan_monitors (si->dpy);
1842 +
1843 +# ifdef QUAD_MODE
1844 +  if (p->quad_p)
1845 +    monitors = quadruple (monitors, p->debug_p);
1846 +# endif
1847 +
1848 +  return monitors;
1849 +}
1850 +
1851 +
1852 +static Bool
1853 +monitors_overlap_p (monitor *a, monitor *b)
1854 +{
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
1857 +     of the rights.
1858 +   */
1859 +# undef MAX
1860 +# undef MIN
1861 +# define MAX(A,B) ((A)>(B)?(A):(B))
1862 +# define MIN(A,B) ((A)<(B)?(A):(B))
1863 +
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);
1869 +}
1870 +
1871 +
1872 +/* Mark the ones that overlap, etc.
1873 + */
1874 +static void
1875 +check_monitor_sanity (monitor **monitors)
1876 +{
1877 +  int i, j, count = 0;
1878 +
1879 +  while (monitors[count])
1880 +    count++;
1881 +
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
1890 +
1891 +  /* If a monitor is enclosed by any other monitor, that's insane.
1892 +   */
1893 +  for (i = 0; i < count; i++)
1894 +    for (j = 0; j < count; j++)
1895 +      if (i != j &&
1896 +          monitors[i]->sanity == S_SANE &&
1897 +          monitors[j]->sanity == S_SANE &&
1898 +          X2 >= X1 &&
1899 +          Y2 >= Y1 &&
1900 +          (X2+W2) <= (X1+W1) &&
1901 +          (Y2+H2) <= (Y1+H1))
1902 +        {
1903 +          if (X1 == X2 &&
1904 +              Y1 == Y2 &&
1905 +              W1 == W2 &&
1906 +              H1 == H2)
1907 +            monitors[j]->sanity = S_DUPLICATE;
1908 +          else 
1909 +            monitors[j]->sanity = S_ENCLOSED;
1910 +          monitors[j]->enemy = i;
1911 +        }
1912 +
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
1915 +     larger one.
1916 +   */
1917 +  for (i = 0; i < count; i++)
1918 +    for (j = 0; j < i; j++)
1919 +      {
1920 +        if (monitors[i]->sanity != S_SANE) continue; /* already marked */
1921 +        if (monitors[j]->sanity != S_SANE) continue;
1922 +
1923 +        if (monitors_overlap_p (monitors[i], monitors[j]))
1924 +          {
1925 +            monitors[i]->sanity = S_OVERLAP;
1926 +            monitors[i]->enemy = j;
1927 +          }
1928 +      }
1929 +
1930 +  /* Finally, make sure all monitors are enclosed by their X screen.
1931 +     Xinerama sometimes reports 1024x768 VPs at -1936862040, -1953705044.
1932 +   */
1933 +  for (i = 0; i < count; i++)
1934 +    {
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)
1941 +        {
1942 +          monitors[i]->sanity = S_OFFSCREEN;
1943 +          monitors[i]->enemy = 0;
1944 +        }
1945 +    }
1946 +
1947 +#  undef X1
1948 +#  undef X2
1949 +#  undef Y1
1950 +#  undef Y2
1951 +#  undef W1
1952 +#  undef W2
1953 +#  undef H1
1954 +#  undef H2
1955 +}
1956 +
1957 +
1958 +static Bool
1959 +layouts_differ_p (monitor **a, monitor **b)
1960 +{
1961 +  if (!a || !b) return True;
1962 +  while (1)
1963 +    {
1964 +      if (!*a) break;
1965 +      if (!*b) break;
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)
1971 +        return True;
1972 +      a++;
1973 +      b++;
1974 +    }
1975 +  if (*a) return True;
1976 +  if (*b) return True;
1977 +
1978 +  return False;
1979 +}
1980 +
1981 +
1982 +void
1983 +describe_monitor_layout (saver_info *si)
1984 +{
1985 +  monitor **monitors = si->monitor_layout;
1986 +  int count = 0;
1987 +  int good_count = 0;
1988 +  int bad_count = 0;
1989 +  while (monitors[count])
1990 +    {
1991 +      if (monitors[count]->sanity == S_SANE)
1992 +        good_count++;
1993 +      else
1994 +        bad_count++;
1995 +      count++;
1996 +    }
1997 +
1998 +  if (count == 0)
1999 +    fprintf (stderr, "%s: no screens!\n", blurb());
2000 +  else
2001 +    {
2002 +      int i;
2003 +      fprintf (stderr, "%s: screens in use: %d\n", blurb(), good_count);
2004 +      for (i = 0; i < count; i++)
2005 +        {
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");
2013 +        }
2014 +      if (bad_count > 0)
2015 +        {
2016 +          fprintf (stderr, "%s: rejected screens: %d\n", blurb(), bad_count);
2017 +          for (i = 0; i < count; i++)
2018 +            {
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)
2028 +                {
2029 +                case S_SANE: abort(); break;
2030 +                case S_ENCLOSED:
2031 +                  fprintf (stderr, "enclosed by %d (%dx%d+%d+%d)\n",
2032 +                           e->id, e->width, e->height, e->x, e->y);
2033 +                  break;
2034 +                case S_DUPLICATE:
2035 +                  fprintf (stderr, "duplicate of %d\n", e->id);
2036 +                  break;
2037 +                case S_OVERLAP:
2038 +                  fprintf (stderr, "overlaps %d (%dx%d+%d+%d)\n",
2039 +                           e->id, e->width, e->height, e->x, e->y);
2040 +                  break;
2041 +                case S_OFFSCREEN:
2042 +                  fprintf (stderr, "off screen (%dx%d)\n",
2043 +                           WidthOfScreen (e->screen), 
2044 +                           HeightOfScreen (e->screen));
2045 +                  break;
2046 +                case S_DISABLED:
2047 +                  fprintf (stderr, "output disabled\n");
2048 +                  break;
2049 +                }
2050 +            }
2051 +        }
2052 +    }
2053 +}
2054 +
2055 +
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.
2060 + */
2061 +Bool
2062 +update_screen_layout (saver_info *si)
2063 +{
2064 +  monitor **monitors = scan_monitors (si);
2065 +  int count = 0;
2066 +  int good_count = 0;
2067 +  int i, j;
2068 +  int seen_screens[100] = { 0, };
2069 +
2070 +  if (! layouts_differ_p (monitors, si->monitor_layout))
2071 +    {
2072 +      free_monitors (monitors);
2073 +      return False;
2074 +    }
2075 +
2076 +  free_monitors (si->monitor_layout);
2077 +  si->monitor_layout = monitors;
2078 +  check_monitor_sanity (si->monitor_layout);
2079 +
2080 +  while (monitors[count])
2081 +    {
2082 +      if (monitors[count]->sanity == S_SANE)
2083 +        good_count++;
2084 +      count++;
2085 +    }
2086 +
2087 +  if (si->ssi_count == 0)
2088 +    {
2089 +      si->ssi_count = 10;
2090 +      si->screens = (saver_screen_info *)
2091 +        calloc (sizeof(*si->screens), si->ssi_count);
2092 +    }
2093 +
2094 +  if (si->ssi_count <= good_count)
2095 +    {
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));
2101 +    }
2102 +
2103 +  if (! si->screens) abort();
2104 +
2105 +  si->nscreens = good_count;
2106 +
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;
2111 +
2112 +  for (i = 0, j = 0; i < count; i++)
2113 +    {
2114 +      monitor *m = monitors[i];
2115 +      saver_screen_info *ssi = &si->screens[j];
2116 +      Screen *old_screen = ssi->screen;
2117 +      int sn;
2118 +      if (monitors[i]->sanity != S_SANE) continue;
2119 +
2120 +      ssi->global = si;
2121 +      ssi->number = j;
2122 +
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]++;
2128 +
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);
2133 +
2134 +      /* If the screen changed (or if this is the first time) we need
2135 +         a new toplevel shell for this screen's depth.
2136 +       */
2137 +      if (ssi->screen != old_screen)
2138 +        initialize_screen_root_widget (ssi);
2139 +
2140 +      ssi->poll_mouse_last_root_x = -1;
2141 +      ssi->poll_mouse_last_root_y = -1;
2142 +
2143 +      ssi->x      = m->x;
2144 +      ssi->y      = m->y;
2145 +      ssi->width  = m->width;
2146 +      ssi->height = m->height;
2147 +
2148 +# ifndef DEBUG_MULTISCREEN
2149 +      {
2150 +        saver_preferences *p = &si->prefs;
2151 +        if (p->debug_p
2152 +#  ifdef QUAD_MODE
2153 +            && !p->quad_p
2154 +#  endif
2155 +            )
2156 +          ssi->width /= 2;
2157 +      }
2158 +# endif
2159 +
2160 +      j++;
2161 +    }
2162 +
2163 +  si->default_screen = &si->screens[0];
2164 +  return True;
2165 +}
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
2170 @@ -1,4 +1,4 @@
2171 -/* xscreensaver, Copyright (c) 1991-2006 Jamie Zawinski <jwz@netscape.com>
2172 +/* xscreensaver, Copyright (c) 1991-2008 Jamie Zawinski <jwz@netscape.com>
2173   *
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 @@
2177      return;
2178  
2179    ssi = &si->screens[mouse_screen (si)];
2180 +
2181 +  if (!ssi || !ssi->screen)
2182 +    return;    /* WTF?  Trying to splash while no screens connected? */
2183 +
2184    cmap = DefaultColormapOfScreen (ssi->screen);
2185  
2186    sp = (splash_dialog_data *) calloc (1, sizeof(*sp));
2187 @@ -376,7 +380,7 @@
2188    attrs.event_mask = (ExposureMask | ButtonPressMask | ButtonReleaseMask);
2189  
2190    {
2191 -    int sx, sy, w, h;
2192 +    int sx = 0, sy = 0, w, h;
2193      int mouse_x = 0, mouse_y = 0;
2194  
2195      {
2196 @@ -393,7 +397,10 @@
2197          }
2198      }
2199  
2200 -    get_screen_viewport (ssi, &sx, &sy, &w, &h, mouse_x, mouse_y, False);
2201 +    x = ssi->x;
2202 +    y = ssi->y;
2203 +    w = ssi->width;
2204 +    h = ssi->height;
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
2212 @@ -1,5 +1,5 @@
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>
2216   *
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 @@
2220  }
2221  
2222  
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().
2226 + */
2227 +void
2228 +stderr_log_file (saver_info *si)
2229 +{
2230 +  int stdout_fd = 1;
2231 +  int stderr_fd = 2;
2232 +  const char *filename = get_string_resource (si->dpy, "logFile", "LogFile");
2233 +  int fd;
2234 +
2235 +  if (!filename || !*filename) return;
2236 +
2237 +  fd = open (filename, O_WRONLY | O_APPEND | O_CREAT, 0666);
2238 +
2239 +  if (fd < 0)
2240 +    {
2241 +      char buf[255];
2242 +    FAIL:
2243 +      sprintf (buf, "%.100s: %.100s", blurb(), filename);
2244 +      perror (buf);
2245 +      fflush (stderr);
2246 +      fflush (stdout);
2247 +      exit (1);
2248 +    }
2249 +
2250 +  fprintf (stderr, "%s: logging to file %s\n", blurb(), filename);
2251 +
2252 +  if (dup2 (fd, stdout_fd) < 0) goto FAIL;
2253 +  if (dup2 (fd, stderr_fd) < 0) goto FAIL;
2254 +
2255 +  fprintf (stderr, "\n\n"
2256 + "##########################################################################\n"
2257 +           "%s: logging to \"%s\" at %s\n"
2258 + "##########################################################################\n"
2259 +           "\n",
2260 +           blurb(), filename, timestring());
2261 +}
2262 +
2263 +
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.
2267 @@ -487,8 +528,7 @@
2268  
2269    stderr_callback ((XtPointer) si, &stderr_stdout_read_fd, 0);
2270  
2271 -  if (stderr_buffer &&
2272 -      stderr_tail &&
2273 +  if (stderr_tail &&
2274        stderr_buffer < stderr_tail)
2275      {
2276        *stderr_tail = 0;
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
2281 @@ -851,7 +851,7 @@
2282      case 0:
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);
2287  
2288        if (p->verbose_p)
2289          fprintf (stderr, "%s: %d: spawning \"%s\" in pid %lu.\n",
2290 @@ -878,14 +878,22 @@
2291  }
2292  
2293  
2294 -static void
2295 -spawn_screenhack_1 (saver_screen_info *ssi, Bool first_time_p)
2296 +void
2297 +spawn_screenhack (saver_screen_info *ssi)
2298  {
2299    saver_info *si = ssi->global;
2300    saver_preferences *p = &si->prefs;
2301 -  raise_window (si, first_time_p, True, False);
2302    XFlush (si->dpy);
2303  
2304 +  if (!monitor_powered_on_p (si))
2305 +    {
2306 +      if (si->prefs.verbose_p)
2307 +        fprintf (stderr,
2308 +                 "%s: %d: X says monitor has powered down; "
2309 +                 "not launching a hack.\n", blurb(), ssi->number);
2310 +      return;
2311 +    }
2312 +
2313    if (p->screenhacks_count)
2314      {
2315        screenhack *hack;
2316 @@ -1017,55 +1025,28 @@
2317           break;
2318         }
2319      }
2320 -}
2321 -
2322 -
2323 -void
2324 -spawn_screenhack (saver_info *si, Bool first_time_p)
2325 -{
2326 -  if (monitor_powered_on_p (si))
2327 -    {
2328 -      int i;
2329 -      for (i = 0; i < si->nscreens; i++)
2330 -        {
2331 -          saver_screen_info *ssi = &si->screens[i];
2332 -          spawn_screenhack_1 (ssi, first_time_p);
2333 -        }
2334 -    }
2335 -  else if (si->prefs.verbose_p)
2336 -    fprintf (stderr,
2337 -             "%s: X says monitor has powered down; "
2338 -             "not launching a hack.\n", blurb());
2339  
2340 -  store_saver_status (si);  /* store current hack numbers */
2341 +  store_saver_status (si);  /* store current hack number */
2342  }
2343  
2344  
2345  void
2346 -kill_screenhack (saver_info *si)
2347 +kill_screenhack (saver_screen_info *ssi)
2348  {
2349 -  int i;
2350 -  for (i = 0; i < si->nscreens; i++)
2351 -    {
2352 -      saver_screen_info *ssi = &si->screens[i];
2353 -      if (ssi->pid)
2354 -       kill_job (si, ssi->pid, SIGTERM);
2355 -      ssi->pid = 0;
2356 -    }
2357 +  saver_info *si = ssi->global;
2358 +  if (ssi->pid)
2359 +    kill_job (si, ssi->pid, SIGTERM);
2360 +  ssi->pid = 0;
2361  }
2362  
2363  
2364  void
2365 -suspend_screenhack (saver_info *si, Bool suspend_p)
2366 +suspend_screenhack (saver_screen_info *ssi, Bool suspend_p)
2367  {
2368  #ifdef SIGSTOP /* older VMS doesn't have it... */
2369 -  int i;
2370 -  for (i = 0; i < si->nscreens; i++)
2371 -    {
2372 -      saver_screen_info *ssi = &si->screens[i];
2373 -      if (ssi->pid)
2374 -       kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
2375 -    }
2376 +  saver_info *si = ssi->global;
2377 +  if (ssi->pid)
2378 +    kill_job (si, ssi->pid, (suspend_p ? SIGSTOP : SIGCONT));
2379  #endif /* SIGSTOP */
2380  }
2381  
2382 @@ -1137,7 +1118,7 @@
2383  
2384  
2385  void
2386 -hack_subproc_environment (saver_screen_info *ssi)
2387 +hack_subproc_environment (Screen *screen, Window saver_window)
2388  {
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.
2394     */
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);
2401    char *s, *c;
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 */
2408  
2409 -  sprintf (nssw, "XSCREENSAVER_WINDOW=0x%lX",
2410 -           (unsigned long) ssi->screensaver_window);
2411 +  sprintf (nssw, "XSCREENSAVER_WINDOW=0x%lX", (unsigned long) saver_window);
2412  
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 @@
2416  /* GL crap */
2417  
2418  Visual *
2419 -get_best_gl_visual (saver_screen_info *ssi)
2420 +get_best_gl_visual (saver_info *si, Screen *screen)
2421  {
2422 -  saver_info *si = ssi->global;
2423    pid_t forked;
2424    int fds [2];
2425    int in, out;
2426 @@ -1217,6 +1196,11 @@
2427    in = fds [0];
2428    out = fds [1];
2429  
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.
2433 +                      */
2434 +
2435    switch ((int) (forked = fork ()))
2436      {
2437      case -1:
2438 @@ -1237,7 +1221,7 @@
2439              perror ("could not dup() a new stdout:");
2440              return 0;
2441            }
2442 -        hack_subproc_environment (ssi);                /* set $DISPLAY */
2443 +        hack_subproc_environment (screen, 0);  /* set $DISPLAY */
2444  
2445          execvp (av[0], av);                    /* shouldn't return. */
2446  
2447 @@ -1270,6 +1254,8 @@
2448          /* Wait for the child to die. */
2449          waitpid (-1, &wait_status, 0);
2450  
2451 +        unblock_sigchld();   /* child is dead and waited, unblock now. */
2452 +
2453          if (1 == sscanf (buf, "0x%lx %c", &v, &c))
2454            result = (int) v;
2455  
2456 @@ -1291,12 +1277,13 @@
2457            }
2458          else
2459            {
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),
2466                         av[0], result,
2467 -                       (v == ssi->default_visual ? " (default)" : ""));
2468 +                       (v == DefaultVisualOfScreen (screen)
2469 +                        ? " (default)" : ""));
2470              return v;
2471            }
2472        }
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
2477 @@ -1,4 +1,4 @@
2478 -/* xscreensaver, Copyright (c) 1998-2007 Jamie Zawinski <jwz@jwz.org>
2479 +/* xscreensaver, Copyright (c) 1998-2008 Jamie Zawinski <jwz@jwz.org>
2480   *
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
2483 @@ -65,21 +65,6 @@
2484  Atom XA_SCREENSAVER, XA_DEMO, XA_PREFS;
2485  
2486  void
2487 -get_screen_viewport (saver_screen_info *ssi,
2488 -                     int *x_ret, int *y_ret,
2489 -                     int *w_ret, int *h_ret,
2490 -                     int tx, int ty,
2491 -                     Bool verbose_p)
2492 -{
2493 -  *x_ret = 0;
2494 -  *y_ret = 0;
2495 -  *w_ret = WidthOfScreen (ssi->screen);
2496 -  *h_ret = HeightOfScreen (ssi->screen);
2497 -
2498 -  if (*w_ret > *h_ret * 2) *w_ret /= 2;  /* xinerama kludge */
2499 -}
2500 -
2501 -void
2502  idle_timer (XtPointer closure, XtIntervalId *id)
2503  {
2504    saver_info *si = (saver_info *) closure;
2505 @@ -230,8 +215,6 @@
2506          visual_depth(si->default_screen->screen,
2507                       si->default_screen->current_visual);
2508  
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);
2513  
2514 @@ -246,6 +229,9 @@
2515    pw = getpwuid (getuid ());
2516    si->user = strdup (pw->pw_name);
2517  
2518 +/*  si->nscreens = 0;
2519 +  si->screens = si->default_screen = 0; */
2520 +
2521    while (1)
2522      {
2523  #ifndef NO_LOCKING
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
2528 @@ -1,5 +1,5 @@
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>
2532   *
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",
2537                    blurb(), i);
2538          }
2539 +
2540 +
2541 +# ifdef HAVE_RANDR_12
2542 +      if (major > 1 || (major == 1 && minor >= 2))
2543 +        {
2544 +          int j;
2545 +          XRRScreenResources *res = 
2546 +            XRRGetScreenResources (dpy, RootWindow (dpy, i));
2547 +          fprintf (stderr, "\n");
2548 +          for (j = 0; j < res->noutput; j++)
2549 +            {
2550 +              int k;
2551 +              XRROutputInfo *rroi = 
2552 +                XRRGetOutputInfo (dpy, res, res->outputs[j]);
2553 +              fprintf (stderr, "%s:   Output %d: %s: %s (%d)\n", blurb(), j,
2554 +                       rroi->name,
2555 +                       (rroi->connection == RR_Disconnected ? "disconnected" :
2556 +                        rroi->connection == RR_UnknownConnection ? "unknown" :
2557 +                        "connected"),
2558 +                       (int) rroi->crtc);
2559 +              for (k = 0; k < rroi->ncrtc; k++)
2560 +                {
2561 +                  XRRCrtcInfo *crtci = XRRGetCrtcInfo (dpy, res, 
2562 +                                                       rroi->crtcs[k]);
2563 +                  fprintf(stderr, "%s:   %c CRTC %d (%d): %dx%d+%d+%d\n", 
2564 +                          blurb(),
2565 +                          (rroi->crtc == rroi->crtcs[k] ? '+' : ' '),
2566 +                          k, (int) rroi->crtcs[k],
2567 +                          crtci->width, crtci->height, crtci->x, crtci->y);
2568 +                  XRRFreeCrtcInfo (crtci);
2569 +                }
2570 +              XRRFreeOutputInfo (rroi);
2571 +              fprintf (stderr, "\n");
2572 +            }
2573 +          XRRFreeScreenResources (res);
2574 +        }
2575 +# endif /* HAVE_RANDR_12 */
2576      }
2577  
2578    if (major > 0)
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
2583 @@ -0,0 +1,196 @@
2584 +/* test-screens.c --- some test cases for the "monitor sanity" checks.
2585 + * xscreensaver, Copyright (c) 2008 Jamie Zawinski <jwz@jwz.org>
2586 + *
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.
2594 + */
2595 +
2596 +#ifdef HAVE_CONFIG_H
2597 +# include "config.h"
2598 +#endif
2599 +
2600 +#include <X11/Xlib.h>
2601 +
2602 +/* This file doesn't need the Xt headers, so stub these types out... */
2603 +#undef XtPointer
2604 +#define XtAppContext void*
2605 +#define XrmDatabase  void*
2606 +#define XtIntervalId void*
2607 +#define XtPointer    void*
2608 +#define Widget       void*
2609 +
2610 +#include "xscreensaver.h"
2611 +#include "visual.h"
2612 +
2613 +#undef WidthOfScreen
2614 +#undef HeightOfScreen
2615 +#define WidthOfScreen(s) 10240
2616 +#define HeightOfScreen(s) 10240
2617 +
2618 +#undef screen_number
2619 +#define screen_number(s) (0)
2620 +
2621 +#include "screens.c"   /* to get at static void check_monitor_sanity() */
2622 +
2623 +char *progname = 0;
2624 +char *progclass = "XScreenSaver";
2625 +
2626 +const char *blurb(void) { return progname; }
2627 +
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(); }
2631 +
2632 +
2633 +static const char *
2634 +failstr (monitor_sanity san)
2635 +{
2636 +  switch (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";
2643 +  }
2644 +}
2645 +
2646 +
2647 +static void
2648 +test (int testnum, const char *screens, const char *desired)
2649 +{
2650 +  monitor *monitors[100];
2651 +  char result[2048];
2652 +  char *out = result;
2653 +  int i, nscreens = 0;
2654 +  char *token = strtok (strdup(screens), ",");
2655 +  while (token)
2656 +    {
2657 +      monitor *m = calloc (1, sizeof (monitor));
2658 +      char c;
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))
2662 +        {
2663 +          fprintf (stderr, "%s: unparsable geometry: %s\n", blurb(), token);
2664 +          exit (1);
2665 +        }
2666 +      monitors[nscreens] = m;
2667 +      nscreens++;
2668 +      token = strtok (0, ",");
2669 +    }
2670 +  monitors[nscreens] = 0;
2671 +
2672 +  check_monitor_sanity (monitors);
2673 +
2674 +  *out = 0;
2675 +  for (i = 0; i < nscreens; i++)
2676 +    {
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);
2681 +      else
2682 +        strcpy (out, failstr (m->sanity));
2683 +      out += strlen(out);
2684 +    }
2685 +  *out = 0;
2686 +
2687 +  if (!strcmp (result, desired))
2688 +    fprintf (stderr, "%s: test %2d OK\n", blurb(), testnum);
2689 +  else
2690 +    fprintf (stderr, "%s: test %2d FAILED:\n"
2691 +             "%s:   given: %s\n"
2692 +             "%s:  wanted: %s\n"
2693 +             "%s:     got: %s\n",
2694 +             blurb(), testnum,
2695 +             blurb(), screens, 
2696 +             blurb(), desired, 
2697 +             blurb(), result);
2698 +
2699 +# if 0
2700 +  {
2701 +    saver_info SI;
2702 +    SI.monitor_layout = monitors;
2703 +    describe_monitor_layout (&SI);
2704 +  }
2705 +# endif
2706 +
2707 +}
2708 +
2709 +static void
2710 +run_tests(void)
2711 +{
2712 +  int i = 1;
2713 +# define A(a)   test (i++, a, a);
2714 +# define B(a,b) test (i++, a, b)
2715 +
2716 +  A("");
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");
2721 +
2722 +  B("1024x768+999999+0",
2723 +    "OFF");
2724 +  B("1024x768+-999999+-999999",
2725 +    "OFF");
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");
2744 +
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 +      +.............+----+  +----------+
2750 +      |      2      |
2751 +      |             |
2752 +      +-------------+
2753 +   */
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");
2760 +}
2761 +
2762 +
2763 +int
2764 +main (int argc, char **argv)
2765 +{
2766 +  char *s;
2767 +  progname = argv[0];
2768 +  s = strrchr(progname, '/');
2769 +  if (s) progname = s+1;
2770 +  if (argc != 1)
2771 +    {
2772 +      fprintf (stderr, "usage: %s\n", argv[0]);
2773 +      exit (1);
2774 +    }
2775 +
2776 +  run_tests();
2777 +
2778 +  exit (0);
2779 +}
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 @@
2785      }
2786    else
2787      {
2788 +      int i;
2789        maybe_reload_init_file (si);
2790 -      kill_screenhack (si);
2791 +      for (i = 0; i < si->nscreens; i++)
2792 +        kill_screenhack (&si->screens[i]);
2793 +
2794 +      raise_window (si, True, True, False);
2795  
2796        if (!si->throttled_p)
2797 -        spawn_screenhack (si, False);
2798 +        for (i = 0; i < si->nscreens; i++)
2799 +          spawn_screenhack (&si->screens[i]);
2800        else
2801          {
2802 -          raise_window (si, True, True, False);
2803            if (p->verbose_p)
2804              fprintf (stderr, "%s: not launching new hack (throttled.)\n",
2805                       blurb());
2806 @@ -1010,28 +1014,17 @@
2807          if (event.type == (si->randr_event_number + RRScreenChangeNotify))
2808            {
2809              /* The Resize and Rotate extension sends an event when the
2810 -               size, rotation, or refresh rate of the screen has changed. */
2811 -
2812 +               size, rotation, or refresh rate of any screen has changed.
2813 +             */
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);
2818  
2819              if (p->verbose_p)
2820                {
2821 -                if (si->screens[screen].width  == xrr_event->width &&
2822 -                    si->screens[screen].height == xrr_event->height)
2823 -                  fprintf (stderr,
2824 -                          "%s: %d: no-op screen size change event (%dx%d)\n",
2825 -                           blurb(), screen,
2826 -                           xrr_event->width, xrr_event->height);
2827 -                else
2828 -                  fprintf (stderr,
2829 -                       "%s: %d: screen size changed from %dx%d to %dx%d\n",
2830 -                           blurb(), screen,
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",
2837 +                         blurb(), screen);
2838                }
2839  
2840  # ifdef RRScreenChangeNotifyMask
2841 @@ -1040,7 +1033,15 @@
2842  # endif /* RRScreenChangeNotifyMask */
2843  
2844              /* Resize the existing xscreensaver windows and cached ssi data. */
2845 -            resize_screensaver_window (si);
2846 +            if (update_screen_layout (si))
2847 +              {
2848 +                if (p->verbose_p)
2849 +                  {
2850 +                    fprintf (stderr, "%s: new layout:\n", blurb());
2851 +                    describe_monitor_layout (si);
2852 +                  }
2853 +                resize_screensaver_window (si);
2854 +              }
2855            }
2856          else
2857  #endif /* HAVE_RANDR */
2858 @@ -1401,11 +1402,13 @@
2859        if (screenhack_running_p (si) &&
2860            !monitor_powered_on_p (si))
2861         {
2862 +          int i;
2863           if (si->prefs.verbose_p)
2864             fprintf (stderr,
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]);
2870         }
2871  
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
2877 @@ -1,7 +1,4 @@
2878 -/* types.h
2879 - *
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>
2883   *
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
2886 @@ -12,20 +9,19 @@
2887   * implied warranty.
2888   */
2889  
2890 -#ifndef TYPES_H
2891 -#define TYPES_H
2892 +#ifndef __XSCREENSAVER_TYPES_H__
2893 +#define __XSCREENSAVER_TYPES_H__
2894  
2895  typedef struct saver_info saver_info;
2896  
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
2904 - */
2905 -enum unlock_state { ul_read, ul_success, ul_fail, ul_cancel, ul_time, ul_finished };
2906 +typedef enum {
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 */
2913 +} unlock_state;
2914  
2915  typedef struct screenhack screenhack;
2916  struct screenhack {
2917 @@ -56,6 +52,7 @@
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;
2922  
2923  
2924  /* This structure holds all the user-specified parameters, read from the
2925 @@ -158,9 +155,11 @@
2926    saver_preferences prefs;
2927  
2928    int nscreens;
2929 +  int ssi_count;
2930    saver_screen_info *screens;
2931    saver_screen_info *default_screen;   /* ...on which dialogs will appear. */
2932 -
2933 +  monitor **monitor_layout;            /* private to screens.c */
2934 +  Visual **best_gl_visuals;            /* visuals for GL hacks on screen N */
2935  
2936    /* =======================================================================
2937       global connection info
2938 @@ -173,7 +172,6 @@
2939       server extension info
2940       ======================================================================= */
2941  
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*.    */
2946 @@ -247,7 +245,7 @@
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;
2952  
2953    auth_conv_cb_t unlock_cb;    /* The function used to prompt for creds. */
2954    void (*auth_finished_cb) (saver_info *si);
2955 @@ -349,7 +347,6 @@
2956    int current_depth;           /* How deep the visual (and the window) are. */
2957  
2958    Visual *default_visual;      /* visual to use when none other specified */
2959 -  Visual *best_gl_visual;      /* visual to use for GL hacks */
2960  
2961    Window real_vroot;           /* The original virtual-root window. */
2962    Window real_vroot_value;     /* What was in the __SWM_VROOT property. */
2963 @@ -407,4 +404,4 @@
2964  };
2965  
2966  
2967 -#endif
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 @@
2974  }
2975  
2976  
2977 +static void
2978 +ungrab_keyboard_and_mouse (saver_info *si)
2979 +{
2980 +  ungrab_mouse (si);
2981 +  ungrab_kbd (si);
2982 +}
2983 +
2984 +
2985  static Bool
2986  grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor,
2987                           int screen_no)
2988 @@ -291,18 +299,15 @@
2989     */
2990  
2991    if (kstatus != GrabSuccess)  /* Do not blank without a kbd grab.   */
2992 -    return False;
2993 +    {
2994 +      /* If we didn't get both grabs, release the one we did get. */
2995 +      ungrab_keyboard_and_mouse (si);
2996 +      return False;
2997 +    }
2998  
2999    return True;                 /* Grab is good, go ahead and blank.  */
3000  }
3001  
3002 -static void
3003 -ungrab_keyboard_and_mouse (saver_info *si)
3004 -{
3005 -  ungrab_mouse (si);
3006 -  ungrab_kbd (si);
3007 -}
3008 -
3009  
3010  int
3011  move_mouse_grab (saver_info *si, Window to, Cursor cursor, int to_screen_no)
3012 @@ -393,6 +398,21 @@
3013                     (char *) id);
3014           status = True;
3015         }
3016 +
3017 +      else if (XGetWindowProperty (dpy, kids[i], XA_WM_COMMAND, 0, 128,
3018 +                                   False, XA_STRING, &type, &format, &nitems,
3019 +                                   &bytesafter, &version)
3020 +               == Success
3021 +               && type != None
3022 +               && !strcmp ((char *) version, "gnome-screensaver"))
3023 +       {
3024 +         fprintf (stderr,
3025 +                 "%s: \"%s\" is already running on display %s (window 0x%x)\n",
3026 +                  blurb(), (char *) version,
3027 +                   DisplayString (dpy), (int) kids [i]);
3028 +         status = True;
3029 +          break;
3030 +       }
3031      }
3032  
3033    if (kids) XFree ((char *) kids);
3034 @@ -445,11 +465,6 @@
3035  
3036  static Bool safe_XKillClient (Display *dpy, XID id);
3037  
3038 -#ifdef HAVE_XF86VMODE
3039 -static Bool safe_XF86VidModeGetViewPort (Display *, int, int *, int *);
3040 -#endif /* HAVE_XF86VMODE */
3041 -
3042 -
3043  static void
3044  kill_xsetroot_data_1 (Display *dpy, Window window,
3045                        Atom prop, const char *atom_name,
3046 @@ -607,7 +622,8 @@
3047      fprintf (stderr,
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)
3054      {
3055        store_vroot_property (si->dpy, ssi->real_vroot, ssi->real_vroot_value);
3056 @@ -812,8 +828,10 @@
3057  
3058    if (si->screen_blanked_p)
3059      {
3060 +      int i;
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);
3066      }
3067  
3068 @@ -999,232 +1017,6 @@
3069  }
3070  
3071  
3072 -
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.
3077 - */
3078 -void
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,
3083 -                     Bool verbose_p)
3084 -{
3085 -  int w = WidthOfScreen (ssi->screen);
3086 -  int h = HeightOfScreen (ssi->screen);
3087 -
3088 -# ifdef HAVE_XF86VMODE
3089 -  saver_info *si = ssi->global;
3090 -  saver_preferences *p = &si->prefs;
3091 -  int event, error;
3092 -  int dot;
3093 -  XF86VidModeModeLine ml;
3094 -  int x, y;
3095 -  Bool xinerama_p = si->xinerama_p;
3096 -
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 */
3103 -
3104 -#  ifdef HAVE_XINERAMA
3105 -  if (xinerama_p)
3106 -    {
3107 -      int mouse_p = (target_x != -1 && target_y != -1);
3108 -      int which = -1;
3109 -      int i;
3110 -
3111 -      /* If a mouse position wasn't passed in, assume we're talking about
3112 -         this screen. */
3113 -      if (!mouse_p)
3114 -        {
3115 -          target_x = ssi->x;
3116 -          target_y = ssi->y;
3117 -          which = ssi->number;
3118 -        }
3119 -
3120 -      /* Find the Xinerama rectangle that contains the mouse position. */
3121 -      for (i = 0; i < si->nscreens; i++)
3122 -        {
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)
3128 -            which = i;
3129 -        }
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;
3135 -
3136 -      if (verbose_p)
3137 -        {
3138 -          fprintf (stderr, "%s: %d: xinerama vp: %dx%d+%d+%d",
3139 -                   blurb(), which,
3140 -                   si->screens[which].width, si->screens[which].height,
3141 -                   si->screens[which].x, si->screens[which].y);
3142 -          if (mouse_p)
3143 -            fprintf (stderr, "; mouse at %d,%d", target_x, target_y);
3144 -          fprintf (stderr, ".\n");
3145 -        }
3146 -
3147 -      return;
3148 -    }
3149 -#  endif /* HAVE_XINERAMA */
3150 -
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))
3155 -    {
3156 -      char msg[512];
3157 -      *x_ret = x;
3158 -      *y_ret = y;
3159 -      *w_ret = ml.hdisplay;
3160 -      *h_ret = ml.vdisplay;
3161 -
3162 -      if (*x_ret == 0 && *y_ret == 0 && *w_ret == w && *h_ret == h)
3163 -        /* There is no viewport -- the screen does not scroll. */
3164 -        return;
3165 -
3166 -
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.
3170 -       */
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)
3175 -        {
3176 -          static int warned_once = 0;
3177 -          if (!warned_once)
3178 -            {
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());
3185 -              warned_once = 1;
3186 -            }
3187 -          *x_ret = 0;
3188 -          *y_ret = 0;
3189 -          *w_ret = w;
3190 -          *h_ret = h;
3191 -          return;
3192 -        }
3193 -
3194 -      sprintf (msg, "%s: %d: vp is %dx%d+%d+%d",
3195 -               blurb(), ssi->number,
3196 -               *w_ret, *h_ret, *x_ret, *y_ret);
3197 -
3198 -
3199 -      if (p->getviewport_full_of_lies_p)
3200 -        {
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:
3204 -
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
3208 -
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."
3212 -
3213 -             So, now there's a preference item for those unfortunate users to
3214 -             tell us not to trust a word that XF86VidModeGetViewPort() says.
3215 -           */
3216 -          static int warned_once = 0;
3217 -          if (!warned_once && verbose_p)
3218 -            {
3219 -              warned_once = 1;
3220 -              fprintf (stderr,
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);
3228 -            }
3229 -
3230 -          *x_ret = 0;
3231 -          *y_ret = 0;
3232 -          *w_ret = w;
3233 -          *h_ret = h;
3234 -          return;
3235 -        }
3236 -
3237 -
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.
3244 -
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.
3249 -
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.
3257 -
3258 -         I'm going to guess that 16 pixels is enough, and that the Y dimension
3259 -         doesn't have this problem.
3260 -
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.
3264 -      */
3265 -#  define FUDGE 16
3266 -      if (x > 0 && x < w - ml.hdisplay)  /* not at left edge or right edge */
3267 -        {
3268 -          /* Round X position down to next lower multiple of FUDGE.
3269 -             Increase width by 2*FUDGE in case some server rounds up.
3270 -           */
3271 -          *x_ret = ((x - 1) / FUDGE) * FUDGE;
3272 -          *w_ret += (FUDGE * 2);
3273 -        }
3274 -#  undef FUDGE
3275 -
3276 -      if (*x_ret != x ||
3277 -          *y_ret != y ||
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);
3282 -
3283 -      if (verbose_p)
3284 -        fprintf (stderr, "%s.\n", msg);
3285 -
3286 -      return;
3287 -    }
3288 -
3289 -# endif /* HAVE_XF86VMODE */
3290 -
3291 -  *x_ret = 0;
3292 -  *y_ret = 0;
3293 -  *w_ret = w;
3294 -  *h_ret = h;
3295 -}
3296 -
3297 -
3298  static Bool error_handler_hit_p = False;
3299  
3300  static int
3301 @@ -1318,7 +1110,7 @@
3302  
3303  
3304  #ifdef HAVE_XF86VMODE
3305 -static Bool
3306 +Bool
3307  safe_XF86VidModeGetViewPort (Display *dpy, int screen, int *xP, int *yP)
3308  {
3309    Bool result;
3310 @@ -1362,13 +1154,9 @@
3311    XColor black;
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;
3317  
3318 -  get_screen_viewport (ssi, &x, &y, &width, &height, -1, -1,
3319 -                       (p->verbose_p && !si->screen_blanked_p));
3320 -
3321    black.red = black.green = black.blue = 0;
3322  
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;
3327  
3328 -  if (p->debug_p
3329 -# ifdef QUAD_MODE
3330 -      && !p->quad_p
3331 -# endif
3332 -      )
3333 -    width = width / 2;
3334 -
3335    if (!p->verbose_p || printed_visual_info)
3336      ;
3337    else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
3338 @@ -1503,10 +1284,10 @@
3339      {
3340        XWindowChanges changes;
3341        unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
3342 -      changes.x = x;
3343 -      changes.y = y;
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;
3351  
3352        if (! (safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
3353 @@ -1523,10 +1304,9 @@
3354      {
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);
3361 -
3362        reset_stderr (ssi);
3363  
3364        if (horked_window)
3365 @@ -1578,10 +1358,10 @@
3366  }
3367  
3368  
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.
3377   */
3378  void
3379  resize_screensaver_window (saver_info *si)
3380 @@ -1589,132 +1369,97 @@
3381    saver_preferences *p = &si->prefs;
3382    int i;
3383  
3384 -  /* First update the size info in the saver_screen_info structs.
3385 -   */
3386 -
3387 -# ifdef HAVE_XINERAMA
3388 -  if (si->xinerama_p)
3389 +  for (i = 0; i < si->nscreens; i++)
3390      {
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.
3397 -       */
3398 -      int nscreens;
3399 -      XineramaScreenInfo *xsi = XineramaQueryScreens (si->dpy, &nscreens);
3400 -
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.
3406 -         */
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;
3411 -      }
3412 +      saver_screen_info *ssi = &si->screens[i];
3413 +      XWindowAttributes xgwa;
3414  
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.
3419 +       */
3420 +      if (! ssi->screensaver_window)
3421          {
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);
3429 +          if (p->verbose_p)
3430              fprintf (stderr,
3431 -                   "%s: %d: resize xinerama from %dx%d+%d+%d to %dx%d+%d+%d\n",
3432 -                     blurb(), i,
3433 -                     ssi->width,   ssi->height,   ssi->x,       ssi->y,
3434 -                     xsi[i].width, xsi[i].height, xsi[i].x_org, xsi[i].y_org);
3435 -
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);
3443          }
3444 -      XFree (xsi);
3445 -    }
3446 -  else
3447 -# endif /* HAVE_XINERAMA */
3448 -    {
3449 -      /* Not Xinerama -- get the real sizes of the root windows. */
3450 -      for (i = 0; i < si->nscreens; i++)
3451 +
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
3454 +         screwed with it.
3455 +       */
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)
3461          {
3462 -          saver_screen_info *ssi = &si->screens[i];
3463 -          XWindowAttributes xgwa;
3464 -          XGetWindowAttributes (si->dpy, RootWindowOfScreen (ssi->screen),
3465 -                                &xgwa);
3466 -
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;
3479 +
3480 +          if (p->verbose_p)
3481              fprintf (stderr,
3482 -                     "%s: %d: resize screen from %dx%d+%d+%d to %dx%d+%d+%d\n",
3483 -                     blurb(), i,
3484 -                     ssi->width, ssi->height, ssi->x, ssi->y,
3485 -                     xgwa.width, xgwa.height, xgwa.x, xgwa.y);
3486 -
3487 -          ssi->x      = xgwa.x;
3488 -          ssi->y      = 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);
3495 +
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);
3501 +        }
3502 +
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.)
3507 +
3508 +         Note that spawn_screenhack() calls select_visual() which may destroy
3509 +         and re-create the window via initialize_screensaver_window_1().
3510 +       */
3511 +      if (si->screen_blanked_p)
3512 +        {
3513 +          if (ssi->cmap)
3514 +            XInstallColormap (si->dpy, ssi->cmap);
3515 +          XMapRaised (si->dpy, ssi->screensaver_window);
3516 +          if (! ssi->pid)
3517 +            spawn_screenhack (ssi);
3518 +
3519 +          /* Make sure the act of adding a screen doesn't present as 
3520 +             pointer motion (and thus cause an unblank). */
3521 +          {
3522 +            Window root, child;
3523 +            int x, y;
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,
3528 +                           &x, &y, &mask);
3529 +          }
3530          }
3531      }
3532  
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.
3537     */
3538 -
3539 -  for (i = 0; i < si->nscreens; i++)
3540 +  for (; i < si->ssi_count; i++)
3541      {
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;
3547 -
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 &&
3552 -          xgwa.y == y &&
3553 -          xgwa.width  == width &&
3554 -          xgwa.height == height)
3555 -        continue;  /* no change! */
3556 -
3557 -      changes.x = x;
3558 -      changes.y = y;
3559 -      changes.width  = width;
3560 -      changes.height = height;
3561 -      changes.border_width = 0;
3562 -
3563 -      if (p->debug_p
3564 -# ifdef QUAD_MODE
3565 -          && !p->quad_p
3566 -# endif
3567 -          ) 
3568 -        changes.width = changes.width / 2;
3569 -
3570 -      if (p->verbose_p)
3571 -        fprintf (stderr,
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))
3578 +      if (ssi->pid)
3579 +        kill_screenhack (ssi);
3580 +      if (ssi->screensaver_window)
3581          {
3582 -          fprintf (stderr,
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);
3587          }
3588      }
3589  }
3590 @@ -2094,10 +1839,30 @@
3591  }
3592  
3593  
3594 +static Visual *
3595 +get_screen_gl_visual (saver_info *si, int real_screen_number)
3596 +{
3597 +  int i;
3598 +  int nscreens = ScreenCount (si->dpy);
3599 +
3600 +  if (! si->best_gl_visuals)
3601 +    si->best_gl_visuals = (Visual **) 
3602 +      calloc (nscreens + 1, sizeof (*si->best_gl_visuals));
3603 +
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));
3608 +
3609 +  if (real_screen_number < 0 || real_screen_number >= nscreens) abort();
3610 +  return si->best_gl_visuals[real_screen_number];
3611 +}
3612 +
3613  
3614  Bool
3615  select_visual (saver_screen_info *ssi, const char *visual_name)
3616  {
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 @@
3622     */
3623    Bool always_recreate_window_p = True;
3624  
3625 +  get_screen_gl_visual (si, 0);   /* let's probe all the GL visuals early */
3626 +
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.
3631 +   */
3632 +  memset (&xgwa, 0, sizeof(xgwa));
3633 +  if (ssi->screensaver_window)
3634 +    XGetWindowAttributes (si->dpy, ssi->screensaver_window, &xgwa);
3635 +
3636    if (visual_name && *visual_name)
3637      {
3638        if (!strcmp(visual_name, "default-i") ||
3639 @@ -2133,7 +1909,7 @@
3640                 !strcmp(visual_name, "Gl") ||
3641                 !strcmp(visual_name, "GL"))
3642          {
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);
3647          }
3648 @@ -2154,13 +1930,16 @@
3649  
3650    ssi->install_cmap_p = install_cmap_p;
3651  
3652 -  if (new_v &&
3653 -      (always_recreate_window_p ||
3654 -       (ssi->current_visual != new_v) ||
3655 -       (install_cmap_p != was_installed_p)))
3656 +  if ((ssi->screen != xgwa.screen) ||
3657 +      (new_v &&
3658 +       (always_recreate_window_p ||
3659 +        (ssi->current_visual != new_v) ||
3660 +        (install_cmap_p != was_installed_p))))
3661      {
3662        Colormap old_c = ssi->cmap;
3663        Window old_w = ssi->screensaver_window;
3664 +      if (! new_v) 
3665 +        new_v = ssi->current_visual;
3666  
3667        if (p->verbose_p)
3668         {
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
3673 @@ -108,9 +108,9 @@
3674                  (Note that one must *never* kill xscreensaver with -9!)\n\
3675  \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\
3683  \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
3690 @@ -46,6 +46,8 @@
3691   *   via the $XSCREENSAVER_WINDOW environment variable -- this trick requires
3692   *   a recent (Aug 2003) revision of vroot.h.
3693   *
3694 + *   (See comments in screens.c for more details about Xinerama/RANDR stuff.)
3695 + *
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
3699 @@ -205,6 +207,7 @@
3700  
3701    /* useful for debugging */
3702    { "-no-capture-stderr",  ".captureStderr",   XrmoptionNoArg, "off" },
3703 +  { "-log",               ".logFile",          XrmoptionSepArg, 0 },
3704  };
3705  
3706  #ifdef __GNUC__
3707 @@ -263,7 +266,7 @@
3708    return str;
3709  }
3710  
3711 -static Bool blurb_timestamp_p = False;   /* kludge */
3712 +static Bool blurb_timestamp_p = True;   /* kludge */
3713  
3714  const char *
3715  blurb (void)
3716 @@ -334,27 +337,30 @@
3717         }
3718        else
3719         {
3720 +#ifdef __GNUC__
3721 +  __extension__   /* don't warn about "string length is greater than the
3722 +                     length ISO C89 compilers are required to support". */
3723 +#endif
3724            fprintf (real_stderr,
3725 -                   "#######################################"
3726 -                   "#######################################\n\n");
3727 -          fprintf (real_stderr,
3728 +   "#######################################################################\n"
3729 +   "\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"
3741     "\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"
3744     "\n"
3745     "    The more information you can provide, the better.  But please\n"
3746     "    report this bug, regardless!\n"
3747 +   "\n"
3748 +   "#######################################################################\n"
3749 +   "\n"
3750     "\n");
3751 -          fprintf (real_stderr,
3752 -                   "#######################################"
3753 -                   "#######################################\n\n");
3754  
3755           saver_exit (si, -1, 0);
3756         }
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");
3761 -
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");
3768             }
3769  
3770           exit (1);
3771 @@ -755,110 +754,24 @@
3772  }
3773  
3774  
3775 -#ifdef HAVE_XINERAMA
3776 -
3777 -static Bool
3778 -screens_overlap_p (XineramaScreenInfo *a, XineramaScreenInfo *b)
3779 -{
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
3782 -     of the rights.
3783 -   */
3784 -# undef MAX
3785 -# undef MIN
3786 -# define MAX(A,B) ((A)>(B)?(A):(B))
3787 -# define MIN(A,B) ((A)<(B)?(A):(B))
3788 -
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);
3794 -}
3795 -
3796 -
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.
3799 - */
3800 -static void
3801 -check_xinerama_sanity (int count, Bool verbose_p, XineramaScreenInfo *xsi)
3802 +/* called from screens.c so that all the Xt crud is here. */
3803 +void
3804 +initialize_screen_root_widget (saver_screen_info *ssi)
3805  {
3806 -  static Bool printed_p = False;
3807 -  int i, j;
3808 -  char err[1024];
3809 -  *err = 0;
3810 -
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
3819 -
3820 -# define WHINE() do {                                                        \
3821 -    if (verbose_p) {                                                         \
3822 -      if (! printed_p) {                                                     \
3823 -        fprintf (stderr, "%s: compensating for Xinerama braindamage:\n",     \
3824 -                 blurb());                                                   \
3825 -        printed_p = True;                                                    \
3826 -      }                                                                      \
3827 -      fprintf (stderr, "%s:   %d: %s\n", blurb(), xsi[i].screen_number,err); \
3828 -    }                                                                        \
3829 -    xsi[i].screen_number = -1;                                               \
3830 -  } while(0)
3831 -
3832 -  /* If a screen is enclosed by any other screen, that's insane.
3833 -   */
3834 -  for (i = 0; i < count; i++)
3835 -    for (j = 0; j < count; j++)
3836 -      if (i != 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))
3840 -        {
3841 -          sprintf (err, "%dx%d+%d+%d enclosed by %dx%d+%d+%d",
3842 -                   W1, H1, X1, Y1,
3843 -                   W2, H2, X2, Y2);
3844 -          WHINE();
3845 -          continue;
3846 -        }
3847 -
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
3850 -     larger one.
3851 -   */
3852 -  for (i = 0; i < count; i++)
3853 -    for (j = 0; j < i; j++)
3854 -      {
3855 -        if (xsi[i].screen_number < 0) continue; /* already marked */
3856 -
3857 -        *err = 0;
3858 -        if (X1 == X2 && Y1 == Y2 && W1 == W2 && H1 == H2)
3859 -          sprintf (err, "%dx%d+%d+%d duplicated", W1, H1, X1, Y1);
3860 -
3861 -        else if (screens_overlap_p (&xsi[i], &xsi[j]))
3862 -          sprintf (err, "%dx%d+%d+%d overlaps %dx%d+%d+%d",
3863 -                   W1, H1, X1, Y1,
3864 -                   W2, H2, X2, Y2);
3865 -
3866 -        if (*err) WHINE();
3867 -      }
3868 -
3869 -# undef X1
3870 -# undef X2
3871 -# undef Y1
3872 -# undef Y2
3873 -# undef W1
3874 -# undef W2
3875 -# undef H1
3876 -# undef H2
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,
3883 +                        si->dpy,
3884 +                        XtNscreen, ssi->screen,
3885 +                        XtNvisual, ssi->current_visual,
3886 +                        XtNdepth,  visual_depth (ssi->screen,
3887 +                                                 ssi->current_visual),
3888 +                        NULL);
3889  }
3890  
3891 -#endif /* HAVE_XINERAMA */
3892 -
3893 -
3894  
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 @@
3898  static void
3899  initialize_per_screen_info (saver_info *si, Widget toplevel_shell)
3900  {
3901 -  Bool found_any_writable_cells = False;
3902    int i;
3903  
3904 -# ifdef HAVE_XINERAMA
3905 -  {
3906 -    int event, error;
3907 -    si->xinerama_p = (XineramaQueryExtension (si->dpy, &event, &error) &&
3908 -                      XineramaIsActive (si->dpy));
3909 -  }
3910 -
3911 -  if (si->xinerama_p && ScreenCount (si->dpy) != 1)
3912 -    {
3913 -      si->xinerama_p = False;
3914 -      if (si->prefs.verbose_p)
3915 -       fprintf (stderr,
3916 -                 "%s: Xinerama AND %d screens?  Disabling Xinerama support!\n",
3917 -                 blurb(), ScreenCount(si->dpy));
3918 -    }
3919 -
3920 -  if (si->xinerama_p)
3921 -    {
3922 -      int nscreens = 0;
3923 -      XineramaScreenInfo *xsi = XineramaQueryScreens (si->dpy, &nscreens);
3924 -      if (!xsi)
3925 -        si->xinerama_p = False;
3926 -      else
3927 -        {
3928 -          int j = 0;
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++)
3933 -            {
3934 -              if (xsi[i].screen_number < 0)  /* deemed insane */
3935 -                continue;
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;
3940 -              j++;
3941 -            }
3942 -          si->nscreens = j;
3943 -          XFree (xsi);
3944 -        }
3945 -      si->default_screen = &si->screens[0];
3946 -      si->default_screen->real_screen_p = True;
3947 -    }
3948 -# endif /* !HAVE_XINERAMA */
3949 -
3950 -  if (!si->xinerama_p)
3951 -    {
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)];
3956 -
3957 -      for (i = 0; i < si->nscreens; i++)
3958 -        {
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;
3964 -        }
3965 -    }
3966 -
3967 -
3968 -# ifdef QUAD_MODE
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...
3971 -   */
3972 -  if (si->prefs.quad_p)
3973 -    {
3974 -      int ns2 = si->nscreens * 4;
3975 -      saver_screen_info *ssi2 = (saver_screen_info *)
3976 -        calloc(sizeof(saver_screen_info), ns2);
3977 -
3978 -      for (i = 0; i < si->nscreens; i++)
3979 -        {
3980 -          saver_screen_info *old = &si->screens[i];
3981 +  update_screen_layout (si);
3982  
3983 -          if (si->prefs.debug_p) old->width = old->width / 2;
3984 -
3985 -          ssi2[i*4  ] = *old;
3986 -          ssi2[i*4+1] = *old;
3987 -          ssi2[i*4+2] = *old;
3988 -          ssi2[i*4+3] = *old;
3989 -
3990 -          ssi2[i*4  ].width  /= 2;
3991 -          ssi2[i*4  ].height /= 2;
3992 -
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;
3996 -
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;
4000 -
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;
4005 -
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;
4009 -        }
4010 -
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;
4016 -    }
4017 -# endif /* QUAD_MODE */
4018 -
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.
4025     */
4026    for (i = 0; i < si->nscreens; i++)
4027      {
4028        saver_screen_info *ssi = &si->screens[i];
4029 -      ssi->global = si;
4030 -
4031 -      ssi->number = 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;
4035 -
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))
4040          {
4041 -          ssi->width  = WidthOfScreen  (ssi->screen);
4042 -          ssi->height = HeightOfScreen (ssi->screen);
4043 +          si->fading_possible_p = True;
4044 +          break;
4045          }
4046 -
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);
4050 -
4051 -      ssi->current_visual = ssi->default_visual;
4052 -      ssi->current_depth = visual_depth (ssi->screen, ssi->current_visual);
4053 -
4054 -      /* Execute a subprocess to find the GL visual. */
4055 -      ssi->best_gl_visual = get_best_gl_visual (ssi);
4056 -
4057 -      if (ssi == si->default_screen)
4058 -       /* Since this is the default screen, use the one already created. */
4059 -       ssi->toplevel_shell = toplevel_shell;
4060 -      else
4061 -       /* Otherwise, each screen must have its own unmapped root widget. */
4062 -       ssi->toplevel_shell =
4063 -         XtVaAppCreateShell (progname, progclass, applicationShellWidgetClass,
4064 -                             si->dpy,
4065 -                             XtNscreen, ssi->screen,
4066 -                             XtNvisual, ssi->current_visual,
4067 -                             XtNdepth,  visual_depth (ssi->screen,
4068 -                                                      ssi->current_visual),
4069 -                             NULL);
4070 -
4071 -      if (! found_any_writable_cells)
4072 -       {
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.
4078 -         */
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;
4083 -       }
4084      }
4085  
4086 -  si->fading_possible_p = found_any_writable_cells;
4087 -
4088  #ifdef HAVE_XF86VMODE_GAMMA
4089    si->fading_possible_p = True;  /* if we can gamma fade, go for it */
4090  #endif
4091 @@ -1115,15 +874,6 @@
4092                  blurb());
4093      }
4094  
4095 -  /* These are incompatible (or at least, our support for them is...) */
4096 -  if (si->xinerama_p && si->using_mit_saver_extension)
4097 -    {
4098 -      si->using_mit_saver_extension = False;
4099 -      if (p->verbose_p)
4100 -        fprintf (stderr, "%s: Xinerama in use: disabling MIT-SCREEN-SAVER.\n",
4101 -                 blurb());
4102 -    }
4103 -
4104  #ifdef HAVE_RANDR
4105    query_randr_extension (si);
4106  #endif
4107 @@ -1149,6 +899,26 @@
4108  }
4109  
4110  
4111 +#ifdef DEBUG_MULTISCREEN
4112 +static void
4113 +debug_multiscreen_timer (XtPointer closure, XtIntervalId *id)
4114 +{
4115 +  saver_info *si = (saver_info *) closure;
4116 +  saver_preferences *p = &si->prefs;
4117 +  if (update_screen_layout (si))
4118 +    {
4119 +      if (p->verbose_p)
4120 +        {
4121 +          fprintf (stderr, "%s: new layout:\n", blurb());
4122 +          describe_monitor_layout (si);
4123 +        }
4124 +      resize_screensaver_window (si);
4125 +    }
4126 +  XtAppAddTimeOut (si->app, 1000*4, debug_multiscreen_timer, (XtPointer) si);
4127 +}
4128 +#endif /* DEBUG_MULTISCREEN */
4129 +
4130 +
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 @@
4135  
4136    if (p->verbose_p)
4137      fprintf (stderr, " done.\n");
4138 +
4139 +# ifdef DEBUG_MULTISCREEN
4140 +  if (p->debug_p) debug_multiscreen_timer ((XtPointer) si, 0);
4141 +# endif
4142  }
4143  
4144  
4145 @@ -1247,6 +1021,7 @@
4146  {
4147    saver_preferences *p = &si->prefs;
4148    Bool ok_to_unblank;
4149 +  int i;
4150  
4151    while (1)
4152      {
4153 @@ -1342,12 +1117,15 @@
4154              }
4155          }
4156  
4157 -      kill_screenhack (si);
4158 +      for (i = 0; i < si->nscreens; i++)
4159 +        kill_screenhack (&si->screens[i]);
4160  
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());
4167 +      else
4168 +        for (i = 0; i < si->nscreens; i++)
4169 +          spawn_screenhack (&si->screens[i]);
4170  
4171        /* Don't start the cycle timer in demo mode. */
4172        if (!si->demoing_p && p->cycle)
4173 @@ -1418,14 +1196,16 @@
4174  
4175              was_locked = True;
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);
4181  
4182             ok_to_unblank = unlock_p (si);
4183  
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 */
4189  
4190              if (!ok_to_unblank &&
4191                  !screenhack_running_p (si))
4192 @@ -1451,7 +1231,8 @@
4193                  blurb(), timestring ());
4194  
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);
4200  
4201        set_locked_p (si, False);
4202 @@ -1530,6 +1311,7 @@
4203  
4204    shell = connect_to_server (si, &argc, argv);
4205    process_command_line (si, &argc, argv);
4206 +  stderr_log_file (si);
4207    print_banner (si);
4208  
4209    load_init_file(si->dpy, p); /* must be before initialize_per_screen_info() */
4210 @@ -1951,8 +1733,10 @@
4211                                   "exiting.");
4212           if (! until_idle_p)
4213             {
4214 +              int i;
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);
4220             }
4221           saver_exit (si, 0, 0);
4222 @@ -1974,8 +1758,10 @@
4223                                   "restarting.");
4224           if (! until_idle_p)
4225             {
4226 +              int i;
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);
4232             }
4233  
4234 @@ -2254,17 +2040,15 @@
4235  #     else
4236          False
4237  #     endif
4238 +   }, { "DRI",                                 "DRI",
4239 +        True
4240     }, { "Apple-DRI",                            "Apple-DRI (XDarwin)",
4241          True
4242     },
4243    };
4244  
4245 -  fprintf (stderr, "%s: running on display \"%s\" (%d %sscreen%s).\n",
4246 -           blurb(),
4247 -          DisplayString(si->dpy),
4248 -           si->nscreens,
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));
4255  
4256 @@ -2324,21 +2108,10 @@
4257         }
4258      }
4259  
4260 -  if (si->xinerama_p)
4261 -    {
4262 -      fprintf (stderr, "%s: Xinerama layout:\n", blurb());
4263 -      for (i = 0; i < si->nscreens; i++)
4264 -        {
4265 -          saver_screen_info *ssi = &si->screens[i];
4266 -          fprintf (stderr, "%s:   %c %d/%d: %dx%d+%d+%d\n",
4267 -                   blurb(),
4268 -                   (ssi->real_screen_p ? '+' : ' '),
4269 -                   ssi->number, ssi->real_screen_number,
4270 -                   ssi->width, ssi->height, ssi->x, ssi->y);
4271 -        }
4272 -    }
4273 +  describe_monitor_layout (si);
4274  }
4275  
4276 +
4277  Bool
4278  display_is_on_console_p (saver_info *si)
4279  {
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
4284 @@ -1,4 +1,4 @@
4285 -/* xscreensaver, Copyright (c) 1993-2006 Jamie Zawinski <jwz@jwz.org>
4286 +/* xscreensaver, Copyright (c) 1993-2008 Jamie Zawinski <jwz@jwz.org>
4287   *
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
4290 @@ -67,7 +67,10 @@
4291     blanking
4292     ======================================================================= */
4293  
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);
4297 +
4298  extern void raise_window (saver_info *si,
4299                             Bool inhibit_fade, Bool between_hacks_p,
4300                             Bool dont_clear);
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);
4318 @@ -174,6 +177,7 @@
4319  
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);
4334 +
4335 +#ifdef HAVE_XF86VMODE
4336 +Bool safe_XF86VidModeGetViewPort (Display *, int, int *, int *);
4337 +#endif /* HAVE_XF86VMODE */
4338  
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
4345 @@ -882,6 +882,8 @@
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);
4352      }
4353    else