ftp://ftp.swin.edu.au/slackware/slackware-9.1/source/xap/xscreensaver/xscreensaver...
[xscreensaver] / driver / windows.c
index 8598e7e0f1ab05cfe4aae2afe3b0cb59aa9d44ab..e06ab2e9640cd1f674b4b5da9c744b22fcd536f2 100644 (file)
@@ -1,5 +1,5 @@
 /* windows.c --- turning the screen black; dealing with visuals, virtual roots.
- * xscreensaver, Copyright (c) 1991-2001 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1991-2003 Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -36,6 +36,8 @@
 #include <X11/Xatom.h>
 #include <X11/Xos.h>           /* for time() */
 #include <signal.h>            /* for the signal names */
+#include <time.h>
+#include <sys/time.h>
 
 #ifdef HAVE_MIT_SAVER_EXTENSION
 # include <X11/extensions/scrnsaver.h>
 # include <X11/extensions/xf86vmode.h>
 #endif /* HAVE_XF86VMODE */
 
-#ifdef HAVE_XINERAMA
-# include <X11/extensions/Xinerama.h>
-#endif /* HAVE_XINERAMA */
-
-
 /* This file doesn't need the Xt headers, so stub these types out... */
 #undef XtPointer
 #define XtAppContext void*
@@ -65,7 +62,7 @@
 
 extern int kill (pid_t, int);          /* signal() is in sys/signal.h... */
 
-Atom XA_VROOT, XA_XSETROOT_ID;
+Atom XA_VROOT, XA_XSETROOT_ID, XA_ESETROOT_PMAP_ID, XA_XROOTPMAP_ID;
 Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_ID;
 Atom XA_SCREENSAVER_STATUS;
 
@@ -117,7 +114,7 @@ grab_kbd(saver_info *si, Window w, int screen_no)
     }
 
   if (p->verbose_p)
-    fprintf(stderr, "%s: %d: grabbing keyboard on 0x%x... %s.\n",
+    fprintf(stderr, "%s: %d: grabbing keyboard on 0x%lx... %s.\n",
            blurb(), screen_no, (unsigned long) w, grab_string(status));
   return status;
 }
@@ -137,7 +134,7 @@ grab_mouse (saver_info *si, Window w, Cursor cursor, int screen_no)
     }
 
   if (p->verbose_p)
-    fprintf(stderr, "%s: %d: grabbing mouse on 0x%x... %s.\n",
+    fprintf(stderr, "%s: %d: grabbing mouse on 0x%lx... %s.\n",
            blurb(), screen_no, (unsigned long) w, grab_string(status));
   return status;
 }
@@ -149,7 +146,7 @@ ungrab_kbd(saver_info *si)
   saver_preferences *p = &si->prefs;
   XUngrabKeyboard(si->dpy, CurrentTime);
   if (p->verbose_p)
-    fprintf(stderr, "%s: %d: ungrabbing keyboard (was 0x%x).\n",
+    fprintf(stderr, "%s: %d: ungrabbing keyboard (was 0x%lx).\n",
             blurb(), si->keyboard_grab_screen,
             (unsigned long) si->keyboard_grab_window);
   si->keyboard_grab_window = 0;
@@ -162,7 +159,7 @@ ungrab_mouse(saver_info *si)
   saver_preferences *p = &si->prefs;
   XUngrabPointer(si->dpy, CurrentTime);
   if (p->verbose_p)
-    fprintf(stderr, "%s: %d: ungrabbing mouse (was 0x%x).\n",
+    fprintf(stderr, "%s: %d: ungrabbing mouse (was 0x%lx).\n",
             blurb(), si->mouse_grab_screen,
             (unsigned long) si->mouse_grab_window);
   si->mouse_grab_window = 0;
@@ -173,7 +170,7 @@ static Bool
 grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor,
                          int screen_no)
 {
-  Status mstatus, kstatus;
+  Status mstatus = 0, kstatus = 0;
   int i;
   int retries = 4;
 
@@ -357,8 +354,17 @@ remove_vroot_property (Display *dpy, Window win)
 }
 
 
+static Bool safe_XKillClient (Display *dpy, XID id);
+
+#ifdef HAVE_XF86VMODE
+static Bool safe_XF86VidModeGetViewPort (Display *, int, int *, int *);
+#endif /* HAVE_XF86VMODE */
+
+
 static void
-kill_xsetroot_data (Display *dpy, Window window, Bool verbose_p)
+kill_xsetroot_data_1 (Display *dpy, Window window,
+                      Atom prop, const char *atom_name,
+                      Bool verbose_p)
 {
   Atom type;
   int format;
@@ -376,8 +382,12 @@ kill_xsetroot_data (Display *dpy, Window window, Bool verbose_p)
      delete of the _XSETROOT_ID property, and if it held a pixmap, then we
      cause the RetainPermanent resources of the client which created it
      (and which no longer exists) to be freed.
+
+     Update: it seems that Gnome and KDE do this same trick, but with the
+     properties "ESETROOT_PMAP_ID" and/or "_XROOTPMAP_ID" instead of
+     "_XSETROOT_ID".  So, we'll kill those too.
    */
-  if (XGetWindowProperty (dpy, window, XA_XSETROOT_ID, 0, 1,
+  if (XGetWindowProperty (dpy, window, prop, 0, 1,
                          True, AnyPropertyType, &type, &format, &nitems, 
                          &bytesafter, (unsigned char **) &dataP)
       == Success
@@ -387,20 +397,31 @@ kill_xsetroot_data (Display *dpy, Window window, Bool verbose_p)
          nitems == 1 && bytesafter == 0)
        {
          if (verbose_p)
-           fprintf (stderr, "%s: destroying xsetroot data (0x%lX).\n",
-                    blurb(), *dataP);
-         XKillClient (dpy, *dataP);
+           fprintf (stderr, "%s: destroying %s data (0x%lX).\n",
+                    blurb(), atom_name, *dataP);
+         safe_XKillClient (dpy, *dataP);
        }
       else
-       fprintf (stderr, "%s: deleted unrecognised _XSETROOT_ID property: \n\
-       %lu, %lu; type: %lu, format: %d, nitems: %lu, bytesafter %ld\n",
-                blurb(), (unsigned long) dataP, (dataP ? *dataP : 0), type,
+       fprintf (stderr,
+                 "%s: deleted unrecognised %s property: \n"
+                 "\t%lu, %lu; type: %lu, format: %d, "
+                 "nitems: %lu, bytesafter %ld\n",
+                blurb(), atom_name,
+                 (unsigned long) dataP, (dataP ? *dataP : 0), type,
                 format, nitems, bytesafter);
     }
 }
 
 
-static void handle_signals (saver_info *si, Bool on_p);
+static void
+kill_xsetroot_data (Display *dpy, Window w, Bool verbose_p)
+{
+  kill_xsetroot_data_1 (dpy, w, XA_XSETROOT_ID, "_XSETROOT_ID", verbose_p);
+  kill_xsetroot_data_1 (dpy, w, XA_ESETROOT_PMAP_ID, "ESETROOT_PMAP_ID",
+                        verbose_p);
+  kill_xsetroot_data_1 (dpy, w, XA_XROOTPMAP_ID, "_XROOTPMAP_ID", verbose_p);
+}
+
 
 static void
 save_real_vroot (saver_screen_info *ssi)
@@ -437,6 +458,17 @@ save_real_vroot (saver_screen_info *ssi)
       int format;
       unsigned long nitems, bytesafter;
       Window *vrootP = 0;
+      int j;
+
+      /* Skip this window if it is the xscreensaver window of any other
+         screen (this can happen in the Xinerama case.)
+       */
+      for (j = 0; j < si->nscreens; j++)
+        {
+          saver_screen_info *ssi2 = &si->screens[j];
+          if (kids[i] == ssi2->screensaver_window)
+            goto SKIP;
+        }
 
       if (XGetWindowProperty (dpy, kids[i], XA_VROOT, 0, 1, False, XA_WINDOW,
                              &type, &format, &nitems, &bytesafter,
@@ -455,6 +487,8 @@ save_real_vroot (saver_screen_info *ssi)
        }
       ssi->real_vroot = kids [i];
       ssi->real_vroot_value = *vrootP;
+    SKIP:
+      ;
     }
 
   XSync (dpy, False);
@@ -463,7 +497,6 @@ save_real_vroot (saver_screen_info *ssi)
 
   if (ssi->real_vroot)
     {
-      handle_signals (si, True);
       remove_vroot_property (si->dpy, ssi->real_vroot);
       XSync (dpy, False);
     }
@@ -473,7 +506,7 @@ save_real_vroot (saver_screen_info *ssi)
 
 
 static Bool
-restore_real_vroot_2 (saver_screen_info *ssi)
+restore_real_vroot_1 (saver_screen_info *ssi)
 {
   saver_info *si = ssi->global;
   saver_preferences *p = &si->prefs;
@@ -496,27 +529,20 @@ restore_real_vroot_2 (saver_screen_info *ssi)
   return False;
 }
 
-static Bool
-restore_real_vroot_1 (saver_info *si)
+Bool
+restore_real_vroot (saver_info *si)
 {
   int i;
   Bool did_any = False;
   for (i = 0; i < si->nscreens; i++)
     {
       saver_screen_info *ssi = &si->screens[i];
-      if (restore_real_vroot_2 (ssi))
+      if (restore_real_vroot_1 (ssi))
        did_any = True;
     }
   return did_any;
 }
 
-void
-restore_real_vroot (saver_info *si)
-{
-  if (restore_real_vroot_1 (si))
-    handle_signals (si, False);
-}
-
 \f
 /* Signal hackery to ensure that the vroot doesn't get left in an 
    inconsistent state
@@ -603,67 +629,102 @@ restore_real_vroot_handler (int sig)
   saver_info *si = global_si_kludge;   /* I hate C so much... */
 
   signal (sig, SIG_DFL);
-  if (restore_real_vroot_1 (si))
+  if (restore_real_vroot (si))
     fprintf (real_stderr, "\n%s: %s intercepted, vroot restored.\n",
             blurb(), signal_name(sig));
   kill (getpid (), sig);
 }
 
 static void
-catch_signal (saver_info *si, int sig, Bool on_p)
+catch_signal (saver_info *si, int sig, RETSIGTYPE (*handler) (int))
 {
-  if (! on_p)
-    signal (sig, SIG_DFL);
-  else
+# ifdef HAVE_SIGACTION
+
+  struct sigaction a;
+  a.sa_handler = handler;
+  sigemptyset (&a.sa_mask);
+  a.sa_flags = 0;
+
+  /* On Linux 2.4.9 (at least) we need to tell the kernel to not mask delivery
+     of this signal from inside its handler, or else when we execvp() the
+     process again, it starts up with SIGHUP blocked, meaning that killing
+     it with -HUP only works *once*.  You'd think that execvp() would reset
+     all the signal masks, but it doesn't.
+   */
+#  if defined(SA_NOMASK)
+  a.sa_flags |= SA_NOMASK;
+#  elif defined(SA_NODEFER)
+  a.sa_flags |= SA_NODEFER;
+#  endif
+
+  if (sigaction (sig, &a, 0) < 0)
+# else  /* !HAVE_SIGACTION */
+  if (((long) signal (sig, handler)) == -1L)
+# endif /* !HAVE_SIGACTION */
     {
-      if (((long) signal (sig, restore_real_vroot_handler)) == -1L)
-       {
-         char buf [255];
-         sprintf (buf, "%s: couldn't catch %s", blurb(), signal_name(sig));
-         perror (buf);
-         saver_exit (si, 1, 0);
-       }
+      char buf [255];
+      sprintf (buf, "%s: couldn't catch %s", blurb(), signal_name(sig));
+      perror (buf);
+      saver_exit (si, 1, 0);
     }
 }
 
-static void
-handle_signals (saver_info *si, Bool on_p)
+static RETSIGTYPE saver_sighup_handler (int sig);
+
+void
+handle_signals (saver_info *si)
 {
-#if 0
-  if (on_p) fprintf (stderr, "handling signals\n");
-  else fprintf (stderr, "unhandling signals\n");
-#endif
+  catch_signal (si, SIGHUP, saver_sighup_handler);
 
-  catch_signal (si, SIGHUP,  on_p);
-  catch_signal (si, SIGINT,  on_p);
-  catch_signal (si, SIGQUIT, on_p);
-  catch_signal (si, SIGILL,  on_p);
-  catch_signal (si, SIGTRAP, on_p);
+  catch_signal (si, SIGINT,  restore_real_vroot_handler);
+  catch_signal (si, SIGQUIT, restore_real_vroot_handler);
+  catch_signal (si, SIGILL,  restore_real_vroot_handler);
+  catch_signal (si, SIGTRAP, restore_real_vroot_handler);
 #ifdef SIGIOT
-  catch_signal (si, SIGIOT,  on_p);
+  catch_signal (si, SIGIOT,  restore_real_vroot_handler);
 #endif
-  catch_signal (si, SIGABRT, on_p);
+  catch_signal (si, SIGABRT, restore_real_vroot_handler);
 #ifdef SIGEMT
-  catch_signal (si, SIGEMT,  on_p);
+  catch_signal (si, SIGEMT,  restore_real_vroot_handler);
 #endif
-  catch_signal (si, SIGFPE,  on_p);
-  catch_signal (si, SIGBUS,  on_p);
-  catch_signal (si, SIGSEGV, on_p);
+  catch_signal (si, SIGFPE,  restore_real_vroot_handler);
+  catch_signal (si, SIGBUS,  restore_real_vroot_handler);
+  catch_signal (si, SIGSEGV, restore_real_vroot_handler);
 #ifdef SIGSYS
-  catch_signal (si, SIGSYS,  on_p);
+  catch_signal (si, SIGSYS,  restore_real_vroot_handler);
 #endif
-  catch_signal (si, SIGTERM, on_p);
+  catch_signal (si, SIGTERM, restore_real_vroot_handler);
 #ifdef SIGXCPU
-  catch_signal (si, SIGXCPU, on_p);
+  catch_signal (si, SIGXCPU, restore_real_vroot_handler);
 #endif
 #ifdef SIGXFSZ
-  catch_signal (si, SIGXFSZ, on_p);
+  catch_signal (si, SIGXFSZ, restore_real_vroot_handler);
 #endif
 #ifdef SIGDANGER
-  catch_signal (si, SIGDANGER, on_p);
+  catch_signal (si, SIGDANGER, restore_real_vroot_handler);
 #endif
 }
 
+
+static RETSIGTYPE
+saver_sighup_handler (int sig)
+{
+  saver_info *si = global_si_kludge;   /* I hate C so much... */
+
+  /* Re-establish SIGHUP handler */
+  catch_signal (si, SIGHUP, saver_sighup_handler);
+
+  fprintf (stderr, "%s: %s received: restarting...\n",
+           blurb(), signal_name(sig));
+  unblank_screen (si);
+  kill_screenhack (si);
+  XSync (si->dpy, False);
+  restart_process (si);   /* Does not return */
+  abort ();
+}
+
+
+
 void
 saver_exit (saver_info *si, int status, const char *dump_core_reason)
 {
@@ -677,7 +738,7 @@ saver_exit (saver_info *si, int status, const char *dump_core_reason)
 
   exiting = True;
   
-  vrs = restore_real_vroot_1 (si);
+  vrs = restore_real_vroot (si);
   emergency_kill_subproc (si);
   shutdown_stderr (si);
 
@@ -710,7 +771,7 @@ saver_exit (saver_info *si, int status, const char *dump_core_reason)
       if (bugp)
        fprintf(real_stderr,
                "%s: see http://www.jwz.org/xscreensaver/bugs.html\n"
-               "\t\tfor bug reporting information.\n\n",
+               "\t\t\tfor bug reporting information.\n\n",
                blurb());
 
 # if defined(HAVE_GETCWD)
@@ -836,6 +897,7 @@ store_saver_status (saver_info *si)
                    XA_SCREENSAVER_STATUS,
                    XA_INTEGER, 32, PropModeReplace,
                    (unsigned char *) status, size);
+  free (status);
 }
 
 
@@ -861,64 +923,64 @@ get_screen_viewport (saver_screen_info *ssi,
   int dot;
   XF86VidModeModeLine ml;
   int x, y;
-  Bool xinerama_p;
-  Bool placement_only_p = (target_x != -1 && target_y != -1);
+  Bool xinerama_p = si->xinerama_p;
 
-#ifdef HAVE_XINERAMA
-  xinerama_p = (XineramaQueryExtension (si->dpy, &event, &error) &&
-                XineramaIsActive (si->dpy));
-#else  /* !HAVE_XINERAMA */
+#ifndef HAVE_XINERAMA
   /* Even if we don't have the client-side Xinerama lib, check to see if
      the server supports Xinerama, so that we know to ignore the VidMode
      extension -- otherwise a server crash could result.  Yay. */
   xinerama_p = XQueryExtension (si->dpy, "XINERAMA", &error, &event, &error);
-  
 #endif /* !HAVE_XINERAMA */
 
 #ifdef HAVE_XINERAMA
-  if (xinerama_p && placement_only_p)
+  if (xinerama_p)
     {
-      int nscreens = 0;
-      XineramaScreenInfo *xsi = XineramaQueryScreens (si->dpy, &nscreens);
-      if (xsi)
+      int mouse_p = (target_x != -1 && target_y != -1);
+      int which = -1;
+      int i;
+
+      /* If a mouse position wasn't passed in, assume we're talking about
+         this screen. */
+      if (!mouse_p)
         {
-          /* Find the screen that contains the mouse. */
-          int which = -1;
-          int i;
-          for (i = 0; i < nscreens; i++)
-            {
-              if (target_x >= xsi[i].x_org &&
-                  target_y >= xsi[i].y_org &&
-                  target_x < xsi[i].x_org + xsi[i].width &&
-                  target_y < xsi[i].y_org + xsi[i].height)
-                which = i;
-              if (verbose_p)
-                {
-                  fprintf (stderr, "%s: %d: xinerama vp: %dx%d+%d+%d",
-                           blurb(), i,
-                           xsi[which].width, xsi[which].height,
-                           xsi[i].x_org, xsi[i].y_org);
-                  if (which == i)
-                    fprintf (stderr, "; mouse at %d,%d",
-                             target_x, target_y);
-                  fprintf (stderr, ".\n");
-                }
-            }
-          if (which == -1) which = 0;  /* didn't find it?  Use the first. */
-          *x_ret = xsi[which].x_org;
-          *y_ret = xsi[which].y_org;
-          *w_ret = xsi[which].width;
-          *h_ret = xsi[which].height;
-          XFree (xsi);
-          return;
+          target_x = ssi->x;
+          target_y = ssi->y;
+        }
+
+      /* Find the Xinerama rectangle that contains the mouse position. */
+      for (i = 0; i < si->nscreens; i++)
+        {
+          if (target_x >= si->screens[i].x &&
+              target_y >= si->screens[i].y &&
+              target_x <  si->screens[i].x + si->screens[i].width &&
+              target_y <  si->screens[i].y + si->screens[i].height)
+            which = i;
         }
+      if (which == -1) which = 0;  /* didn't find it?  Use the first. */
+      *x_ret = si->screens[which].x;
+      *y_ret = si->screens[which].y;
+      *w_ret = si->screens[which].width;
+      *h_ret = si->screens[which].height;
+
+      if (verbose_p)
+        {
+          fprintf (stderr, "%s: %d: xinerama vp: %dx%d+%d+%d",
+                   blurb(), which,
+                   si->screens[which].width, si->screens[which].height,
+                   si->screens[which].x, si->screens[which].y);
+          if (mouse_p)
+            fprintf (stderr, "; mouse at %d,%d", target_x, target_y);
+          fprintf (stderr, ".\n");
+        }
+
+      return;
     }
 #endif /* HAVE_XINERAMA */
 
   if (!xinerama_p &&  /* Xinerama + VidMode = broken. */
       XF86VidModeQueryExtension (si->dpy, &event, &error) &&
-      XF86VidModeGetModeLine (si->dpy, ssi->number, &dot, &ml) &&
-      XF86VidModeGetViewPort (si->dpy, ssi->number, &x, &y))
+      safe_XF86VidModeGetViewPort (si->dpy, ssi->number, &x, &y) &&
+      XF86VidModeGetModeLine (si->dpy, ssi->number, &dot, &ml))
     {
       char msg[512];
       *x_ret = x;
@@ -1097,6 +1159,54 @@ safe_XDestroyWindow (Display *dpy, Window window)
 }
 
 
+static Bool
+safe_XKillClient (Display *dpy, XID id)
+{
+  XErrorHandler old_handler;
+  XSync (dpy, False);
+  error_handler_hit_p = False;
+  old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
+
+  XKillClient (dpy, id);
+
+  XSync (dpy, False);
+  XSetErrorHandler (old_handler);
+  XSync (dpy, False);
+
+  return (!error_handler_hit_p);
+}
+
+
+#ifdef HAVE_XF86VMODE
+static Bool
+safe_XF86VidModeGetViewPort (Display *dpy, int screen, int *xP, int *yP)
+{
+  Bool result;
+  XErrorHandler old_handler;
+  XSync (dpy, False);
+  error_handler_hit_p = False;
+  old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
+
+  result = XF86VidModeGetViewPort (dpy, screen, xP, yP);
+
+  XSync (dpy, False);
+  XSetErrorHandler (old_handler);
+  XSync (dpy, False);
+
+  return (error_handler_hit_p
+          ? False
+          : result);
+}
+
+/* There is no "safe_XF86VidModeGetModeLine" because it fails with an
+   untrappable I/O error instead of an X error -- so one must call
+   safe_XF86VidModeGetViewPort first, and assume that both have the
+   same error condition.  Thank you XFree, may I have another.
+ */
+
+#endif /* HAVE_XF86VMODE */
+
+
 static void
 initialize_screensaver_window_1 (saver_screen_info *ssi)
 {
@@ -1171,7 +1281,7 @@ initialize_screensaver_window_1 (saver_screen_info *ssi)
   attrs.backing_pixel = ssi->black_pixel;
   attrs.border_pixel = ssi->black_pixel;
 
-  if (p->debug_p) width = width / 2;
+  if (p->debug_p && !p->quad_p) width = width / 2;
 
   if (!p->verbose_p || printed_visual_info)
     ;
@@ -1379,7 +1489,8 @@ raise_window (saver_info *si,
 
       /* Note!  The server is grabbed, and this will take several seconds
         to complete! */
-      fade_screens (si->dpy, current_maps, current_windows,
+      fade_screens (si->dpy, current_maps,
+                    current_windows, si->nscreens,
                    p->fade_seconds/1000, p->fade_ticks, True, !dont_clear);
 
       free(current_maps);
@@ -1433,33 +1544,34 @@ int
 mouse_screen (saver_info *si)
 {
   saver_preferences *p = &si->prefs;
+  Window pointer_root, pointer_child;
+  int root_x, root_y, win_x, win_y;
+  unsigned int mask;
+  int i;
 
   if (si->nscreens == 1)
     return 0;
-  else
+
+  for (i = 0; i < si->nscreens; i++)
     {
-      int i;
-      for (i = 0; i < si->nscreens; i++)
+      saver_screen_info *ssi = &si->screens[i];
+      if (XQueryPointer (si->dpy, RootWindowOfScreen (ssi->screen),
+                         &pointer_root, &pointer_child,
+                         &root_x, &root_y, &win_x, &win_y, &mask) &&
+          root_x >= ssi->x &&
+          root_y >= ssi->y &&
+          root_x <  ssi->x + ssi->width &&
+          root_y <  ssi->y + ssi->height)
         {
-          saver_screen_info *ssi = &si->screens[i];
-          Window pointer_root, pointer_child;
-          int root_x, root_y, win_x, win_y;
-          unsigned int mask;
-          if (XQueryPointer (si->dpy,
-                             RootWindowOfScreen (ssi->screen),
-                             &pointer_root, &pointer_child,
-                             &root_x, &root_y, &win_x, &win_y, &mask))
-            {
-              if (p->verbose_p)
-                fprintf (stderr, "%s: mouse is on screen %d\n",
-                         blurb(), i, si->nscreens);
-              return i;
-            }
+          if (p->verbose_p)
+            fprintf (stderr, "%s: mouse is on screen %d of %d\n",
+                     blurb(), i, si->nscreens);
+          return i;
         }
-
-      /* couldn't figure out where the mouse is?  Oh well. */
-      return 0;
     }
+
+  /* couldn't figure out where the mouse is?  Oh well. */
+  return 0;
 }
 
 
@@ -1500,8 +1612,8 @@ blank_screen (saver_info *si)
   for (i = 0; i < si->nscreens; i++)
     {
       saver_screen_info *ssi = &si->screens[i];
-
-      save_real_vroot (ssi);
+      if (ssi->real_screen_p)
+        save_real_vroot (ssi);
       store_vroot_property (si->dpy,
                            ssi->screensaver_window,
                            ssi->screensaver_window);
@@ -1510,9 +1622,9 @@ blank_screen (saver_info *si)
       {
         int ev, er;
         if (!XF86VidModeQueryExtension (si->dpy, &ev, &er) ||
-            !XF86VidModeGetViewPort (si->dpy, i,
-                                     &ssi->blank_vp_x,
-                                     &ssi->blank_vp_y))
+            !safe_XF86VidModeGetViewPort (si->dpy, i,
+                                          &ssi->blank_vp_x,
+                                          &ssi->blank_vp_y))
           ssi->blank_vp_x = ssi->blank_vp_y = -1;
       }
 #endif /* HAVE_XF86VMODE */
@@ -1576,8 +1688,8 @@ unblank_screen (saver_info *si)
       XUngrabServer (si->dpy);
       XSync (si->dpy, False);                  /* ###### (danger over) */
 
-
-      fade_screens (si->dpy, 0, current_windows,
+      fade_screens (si->dpy, 0,
+                    current_windows, si->nscreens,
                    p->fade_seconds/1000, p->fade_ticks,
                    False, False);