http://www.ibiblio.org/pub/historic-linux/ftp-archives/sunsite.unc.edu/Sep-29-1996...
[xscreensaver] / driver / windows.c
index fb459ace60c7bca9fa375a2495d9745c18866e51..084bce737cf1f84535fc7f712d93123620296972 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1991-1993 Jamie Zawinski <jwz@lucid.com>
+/* xscreensaver, Copyright (c) 1991-1995 Jamie Zawinski <jwz@netscape.com>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
 
 #include "xscreensaver.h"
 
+#ifdef HAVE_SAVER_EXTENSION
+#include <X11/extensions/scrnsaver.h>
+extern Bool use_saver_extension;
+#endif /* HAVE_SAVER_EXTENSION */
+
 #if __STDC__
 extern int kill (pid_t, int);          /* signal() is in sys/signal.h... */
 #endif /* __STDC__ */
 
+extern Time timeout;
+
 extern Bool lock_p, demo_mode_p;
 
 Atom XA_VROOT, XA_XSETROOT_ID;
@@ -31,6 +38,7 @@ Atom XA_SCREENSAVER_VERSION, XA_SCREENSAVER_ID;
 
 #if __STDC__
 extern void describe_visual (FILE *, Display *, Visual *);
+extern void reset_stderr (void);
 #endif
 
 Window screensaver_window = 0;
@@ -43,6 +51,10 @@ int fade_seconds, fade_ticks;
 static unsigned long black_pixel;
 static Window real_vroot, real_vroot_value;
 
+#ifdef HAVE_SAVER_EXTENSION
+Window server_saver_window = 0;
+#endif /* HAVE_SAVER_EXTENSION */
+
 #define ALL_POINTER_EVENTS \
        (ButtonPressMask | ButtonReleaseMask | EnterWindowMask | \
         LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | \
@@ -57,7 +69,7 @@ static Window real_vroot, real_vroot_value;
                GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime)
 
 void
-grab_keyboard_and_mouse ()
+grab_keyboard_and_mouse P((void))
 {
   Status status;
   XSync (dpy, False);
@@ -85,7 +97,7 @@ grab_keyboard_and_mouse ()
 }
 
 void
-ungrab_keyboard_and_mouse ()
+ungrab_keyboard_and_mouse P((void))
 {
   XUngrabPointer (dpy, CurrentTime);
   XUngrabKeyboard (dpy, CurrentTime);
@@ -147,12 +159,34 @@ ensure_no_screensaver_running ()
 void
 disable_builtin_screensaver ()
 {
-  int timeout, interval, prefer_blank, allow_exp;
+  int server_timeout, server_interval, prefer_blank, allow_exp;
+  /* Turn off the server builtin saver if it is now running. */
   XForceScreenSaver (dpy, ScreenSaverReset);
-  XGetScreenSaver (dpy, &timeout, &interval, &prefer_blank, &allow_exp);
-  if (timeout != 0)
+  XGetScreenSaver (dpy, &server_timeout, &server_interval,
+                  &prefer_blank, &allow_exp);
+
+#ifdef HAVE_SAVER_EXTENSION
+  if (use_saver_extension)
+    {
+      /* Override the values specified with "xset" with our own parameters. */
+      prefer_blank = False;
+      allow_exp = True;
+      server_interval = 0;
+      server_timeout = (timeout / 1000);
+      if (verbose_p)
+       fprintf (stderr,
+                "%s: configuring server for saver timeout of %d seconds.\n",
+                progname, server_timeout);
+      XSetScreenSaver (dpy, server_timeout, server_interval,
+                      prefer_blank, allow_exp);
+    }
+  else
+#endif /* HAVE_SAVER_EXTENSION */
+  if (server_timeout != 0)
     {
-      XSetScreenSaver (dpy, 0, interval, prefer_blank, allow_exp);
+      server_timeout = 0;
+      XSetScreenSaver (dpy, server_timeout, server_interval,
+                      prefer_blank, allow_exp);
       printf ("%s%sisabling server builtin screensaver.\n\
        You can re-enable it with \"xset s on\".\n",
              (verbose_p ? "" : progname), (verbose_p ? "\n\tD" : ": d"));
@@ -167,8 +201,12 @@ ERROR!  You must not include vroot.h in this file.
 #endif
 
 static void
+#if __STDC__
+store_vroot_property (Window win, Window value)
+#else
 store_vroot_property (win, value)
      Window win, value;
+#endif
 {
 #if 0
   printf ("%s: storing XA_VROOT = 0x%x (%s) = 0x%x (%s)\n", progname, 
@@ -186,8 +224,12 @@ store_vroot_property (win, value)
 }
 
 static void
+#if __STDC__
+remove_vroot_property (Window win)
+#else
 remove_vroot_property (win)
      Window win;
+#endif
 {
 #if 0
   printf ("%s: removing XA_VROOT from 0x%x (%s)\n", progname, win, 
@@ -200,7 +242,7 @@ remove_vroot_property (win)
 
 
 static void
-kill_xsetroot_data ()
+kill_xsetroot_data P((void))
 {
   Atom type;
   int format;
@@ -229,15 +271,15 @@ kill_xsetroot_data ()
          nitems == 1 && bytesafter == 0)
        {
          if (verbose_p)
-           printf ("%s: destroying xsetroot data (0x%X).\n",
+           printf ("%s: destroying xsetroot data (0x%lX).\n",
                    progname, *dataP);
          XKillClient (dpy, *dataP);
        }
       else
        fprintf (stderr, "%s: %sdeleted unrecognised _XSETROOT_ID property: \n\
-       %d, %d; type: %d, format: %d, nitems: %d, bytesafter %d\n",
+       %lu, %lu; type: %lu, format: %d, nitems: %lu, bytesafter %ld\n",
                 progname, (verbose_p ? "## " : ""),
-                dataP, (dataP ? *dataP : 0), type,
+                (unsigned long) dataP, (dataP ? *dataP : 0), type,
                 format, nitems, bytesafter);
     }
 }
@@ -246,7 +288,7 @@ kill_xsetroot_data ()
 static void handle_signals P((Bool on_p));
 
 static void
-save_real_vroot ()
+save_real_vroot P((void))
 {
   int i;
   Window root = RootWindowOfScreen (screen);
@@ -299,11 +341,11 @@ save_real_vroot ()
 }
 
 static Bool
-restore_real_vroot_1 ()
+restore_real_vroot_1 P((void))
 {
   if (verbose_p && real_vroot)
-    printf ("%s: restoring __SWM_VROOT property on the real vroot (0x%x).\n",
-           progname, real_vroot);
+    printf ("%s: restoring __SWM_VROOT property on the real vroot (0x%lx).\n",
+           progname, (unsigned long) real_vroot);
   remove_vroot_property (screensaver_window);
   if (real_vroot)
     {
@@ -349,10 +391,14 @@ restore_real_vroot_handler (sig)
 
 
 static void
+#if __STDC__
+catch_signal (int sig, char *signame, Bool on_p)
+#else
 catch_signal (sig, signame, on_p)
      int sig;
      char *signame;
      Bool on_p;
+#endif
 {
   if (! on_p)
     signal (sig, SIG_DFL);
@@ -393,7 +439,9 @@ handle_signals (on_p)
   catch_signal (SIGFPE,  "SIGFPE",  on_p);
   catch_signal (SIGBUS,  "SIGBUS",  on_p);
   catch_signal (SIGSEGV, "SIGSEGV", on_p);
+#ifdef SIGSYS
   catch_signal (SIGSYS,  "SIGSYS",  on_p);
+#endif
   catch_signal (SIGTERM, "SIGTERM", on_p);
 #ifdef SIGXCPU
   catch_signal (SIGXCPU, "SIGXCPU", on_p);
@@ -409,8 +457,23 @@ handle_signals (on_p)
 \f
 /* Managing the actual screensaver window */
 
+Bool
+window_exists_p (dpy, window)
+     Display *dpy;
+     Window window;
+{
+  int (*old_handler) ();
+  XWindowAttributes xgwa;
+  xgwa.screen = 0;
+  old_handler = XSetErrorHandler (BadWindow_ehandler);
+  XGetWindowAttributes (dpy, window, &xgwa);
+  XSync (dpy, False);
+  XSetErrorHandler (old_handler);
+  return (xgwa.screen != 0);
+}
+
 void
-initialize_screensaver_window ()
+initialize_screensaver_window P((void))
 {
   /* This resets the screensaver window as fully as possible, since there's
      no way of knowing what some random client may have done to us in the
@@ -425,13 +488,14 @@ initialize_screensaver_window ()
   int height = HeightOfScreen (screen);
   char id [2048];
 
+  reset_stderr ();
+
   black.red = black.green = black.blue = 0;
 
   if (cmap == DefaultColormapOfScreen (screen))
     cmap = 0;
 
-  if ((install_cmap_p && !demo_mode_p) ||
-      (visual != DefaultVisualOfScreen (screen)))
+  if (install_cmap_p || visual != DefaultVisualOfScreen (screen))
     {
       if (! cmap)
        {
@@ -477,7 +541,74 @@ initialize_screensaver_window ()
   attrs.backing_pixel = black_pixel;
   attrs.border_pixel = black_pixel;
 
-/*  if (demo_mode_p || lock_p) width = width / 2;   #### */
+#if 0
+  if (demo_mode_p || lock_p) width = width / 2;  /* #### */
+#endif
+
+  if (screensaver_window || !verbose_p)
+    ;
+  else if (visual == DefaultVisualOfScreen (screen))
+    {
+      fprintf (stderr, "%s: using default visual ", progname);
+      describe_visual (stderr, dpy, visual);
+    }
+  else
+    {
+      fprintf (stderr, "%s: using visual:   ", progname);
+      describe_visual (stderr, dpy, visual);
+      fprintf (stderr, "%s: default visual: ", progname);
+      describe_visual (stderr, dpy, DefaultVisualOfScreen (screen));
+    }
+
+#ifdef HAVE_SAVER_EXTENSION
+  if (use_saver_extension)
+    {
+      XScreenSaverInfo *info;
+      Window root = RootWindowOfScreen (screen);
+
+      /* This call sets the server screensaver timeouts to what we think
+        they should be (based on the resources and args xscreensaver was
+        started with.)  It's important that we do this to sync back up
+        with the server - if we have turned on prematurely, as by an
+        ACTIVATE ClientMessage, then the server may decide to activate
+        the screensaver while it's already active.  That's ok for us,
+        since we would know to ignore that ScreenSaverActivate event,
+        but a side effect of this would be that the server would map its
+        saver window (which we then hide again right away) meaning that
+        the bits currently on the screen get blown away.  Ugly. */
+#if 0
+      /* #### Ok, that doesn't work - when we tell the server that the
+        screensaver is "off" it sends us a Deactivate event, which is
+        sensible... but causes the saver to never come on.  Hmm. */
+      disable_builtin_screensaver ();
+#endif /* 0 */
+
+#if 0
+      /* #### The MIT-SCREEN-SAVER extension gives us access to the
+        window that the server itself uses for saving the screen.
+        However, using this window in any way, in particular, calling
+        XScreenSaverSetAttributes() as below, tends to make the X server
+        crash.  So fuck it, let's try and get along without using it...
+
+        It's also inconvenient to use this window because it doesn't
+        always exist (though the ID is constant.)  So to use this
+        window, we'd have to reimplement the ACTIVATE ClientMessage to
+        tell the *server* to tell *us* to turn on, to cause the window
+        to get created at the right time.  Gag.  */
+      XScreenSaverSetAttributes (dpy, root,
+                                0, 0, width, height, 0,
+                                visual_depth, InputOutput, visual,
+                                attrmask, &attrs);
+      XSync (dpy, False);
+#endif /* 0 */
+
+      info = XScreenSaverAllocInfo ();
+      XScreenSaverQueryInfo (dpy, root, info);
+      server_saver_window = info->window;
+      if (! server_saver_window) abort ();
+      XFree (info);
+    }
+#endif /* HAVE_SAVER_EXTENSION */
 
   if (screensaver_window)
     {
@@ -494,57 +625,54 @@ initialize_screensaver_window ()
     }
   else
     {
-      if (! verbose_p)
-       ;
-      else if (visual == DefaultVisualOfScreen (screen))
-       {
-         fprintf (stderr, "%s: using default visual ", progname);
-         describe_visual (stderr, dpy, visual);
-       }
-      else
-       {
-         fprintf (stderr, "%s: using visual:   ", progname);
-         describe_visual (stderr, dpy, visual);
-         fprintf (stderr, "%s: default visual: ", progname);
-         describe_visual (stderr, dpy, DefaultVisualOfScreen (screen));
-       }
-
       screensaver_window =
        XCreateWindow (dpy, RootWindowOfScreen (screen), 0, 0, width, height,
                       0, visual_depth, InputOutput, visual, attrmask,
                       &attrs);
     }
 
-  class_hints.res_name = progname;
-  class_hints.res_class = progclass;
-  XSetClassHint (dpy, screensaver_window, &class_hints);
-  XStoreName (dpy, screensaver_window, "screensaver");
-  XChangeProperty (dpy, screensaver_window, XA_SCREENSAVER_VERSION,
-                  XA_STRING, 8, PropModeReplace,
-                  (unsigned char *) screensaver_version,
-                  strlen (screensaver_version));
-
-  sprintf (id, "%d on host ", getpid ());
-  if (! XmuGetHostname (id + strlen (id), sizeof (id) - strlen (id) - 1))
-    strcat (id, "???");
-  XChangeProperty (dpy, screensaver_window, XA_SCREENSAVER_ID, XA_STRING, 8,
-                  PropModeReplace, (unsigned char *) id, strlen (id));
-
-  if (!cursor)
+#ifdef HAVE_SAVER_EXTENSION
+  if (!use_saver_extension ||
+      window_exists_p (dpy, screensaver_window))
+    /* When using the MIT-SCREEN-SAVER extension, the window pointed to
+       by screensaver_window only exists while the saver is active.
+       So we must be careful to only try and manipulate it while it
+       exists...
+     */
+#endif /* HAVE_SAVER_EXTENSION */
     {
-      Pixmap bit;
-      bit = XCreatePixmapFromBitmapData (dpy, screensaver_window, "\000", 1, 1,
-                                        BlackPixelOfScreen (screen),
-                                        BlackPixelOfScreen (screen), 1);
-      cursor = XCreatePixmapCursor (dpy, bit, bit, &black, &black, 0, 0);
-      XFreePixmap (dpy, bit);
-    }
+      class_hints.res_name = progname;
+      class_hints.res_class = progclass;
+      XSetClassHint (dpy, screensaver_window, &class_hints);
+      XStoreName (dpy, screensaver_window, "screensaver");
+      XChangeProperty (dpy, screensaver_window, XA_SCREENSAVER_VERSION,
+                      XA_STRING, 8, PropModeReplace,
+                      (unsigned char *) screensaver_version,
+                      strlen (screensaver_version));
+
+      sprintf (id, "%d on host ", getpid ());
+      if (! XmuGetHostname (id + strlen (id), sizeof (id) - strlen (id) - 1))
+       strcat (id, "???");
+      XChangeProperty (dpy, screensaver_window, XA_SCREENSAVER_ID, XA_STRING,
+                      8, PropModeReplace, (unsigned char *) id, strlen (id));
+
+      if (!cursor)
+       {
+         Pixmap bit;
+         bit = XCreatePixmapFromBitmapData (dpy, screensaver_window, "\000",
+                                            1, 1,
+                                            BlackPixelOfScreen (screen),
+                                            BlackPixelOfScreen (screen), 1);
+         cursor = XCreatePixmapCursor (dpy, bit, bit, &black, &black, 0, 0);
+         XFreePixmap (dpy, bit);
+       }
 
-  XSetWindowBackground (dpy, screensaver_window, black_pixel);
-  if (! demo_mode_p)
-    XDefineCursor (dpy, screensaver_window, cursor);
-  else
-    XUndefineCursor (dpy, screensaver_window);
+      XSetWindowBackground (dpy, screensaver_window, black_pixel);
+      if (! demo_mode_p)
+       XDefineCursor (dpy, screensaver_window, cursor);
+      else
+       XUndefineCursor (dpy, screensaver_window);
+    }
 }
 
 
@@ -569,6 +697,12 @@ raise_window (inhibit_fade, between_hacks_p)
       fade_colormap (dpy, current_map, cmap2, fade_seconds, fade_ticks, True);
       XClearWindow (dpy, screensaver_window);
       XMapRaised (dpy, screensaver_window);
+
+#ifdef HAVE_SAVER_EXTENSION
+      if (server_saver_window && window_exists_p (dpy, server_saver_window))
+       XUnmapWindow (dpy, server_saver_window);
+#endif /* HAVE_SAVER_EXTENSION */
+
       /* Once the saver window is up, restore the colormap.
         (The "black" pixels of the two colormaps are compatible.) */
       XInstallColormap (dpy, cmap);
@@ -580,12 +714,22 @@ raise_window (inhibit_fade, between_hacks_p)
     {
       XClearWindow (dpy, screensaver_window);
       XMapRaised (dpy, screensaver_window);
+#ifdef HAVE_SAVER_EXTENSION
+      if (server_saver_window && window_exists_p (dpy, server_saver_window))
+       XUnmapWindow (dpy, server_saver_window);
+#endif /* HAVE_SAVER_EXTENSION */
     }
 
-  if (install_cmap_p && !demo_mode_p)
+  if (install_cmap_p)
     XInstallColormap (dpy, cmap);
 }
 
+#ifdef __hpux
+ /* Calls to XHPDisableReset and XHPEnableReset must be balanced,
+    or BadAccess errors occur. */
+static Bool hp_locked_p = False;
+#endif /* __hpux */
+
 void
 blank_screen ()
 {
@@ -594,8 +738,9 @@ blank_screen ()
   raise_window (False, False);
   grab_keyboard_and_mouse ();
 #ifdef __hpux
-  if (lock_p)
+  if (lock_p && !hp_locked_p)
     XHPDisableReset (dpy);     /* turn off C-Sh-Reset */
+  hp_locked_p = True;
 #endif
 }
 
@@ -620,7 +765,7 @@ unblank_screen ()
     }
   else
     {
-      if (install_cmap_p && !demo_mode_p)
+      if (install_cmap_p)
        {
          XClearWindow (dpy, screensaver_window); /* avoid technicolor */
          XInstallColormap (dpy, DefaultColormapOfScreen (screen));
@@ -631,7 +776,8 @@ unblank_screen ()
   ungrab_keyboard_and_mouse ();
   restore_real_vroot ();
 #ifdef __hpux
-  if (lock_p)
+  if (lock_p && hp_locked_p)
     XHPEnableReset (dpy);      /* turn C-Sh-Reset back on */
+  hp_locked_p = False;
 #endif
 }