http://ftp.nluug.nl/pub/os/Linux/distr/pardusrepo/sources/xscreensaver-5.02.tar.gz
[xscreensaver] / driver / xscreensaver.c
index 5327ccb0cf23470ed07b66f42ca18f2909109a91..3f0c7409edb20e9a5a062f2731cccb8819282e0d 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1991-2003 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1991-2006 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
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
 #include <time.h>
 #include <sys/time.h>
 #include <netdb.h>     /* for gethostbyname() */
 #include <time.h>
 #include <sys/time.h>
 #include <netdb.h>     /* for gethostbyname() */
+#include <sys/types.h>
+#include <pwd.h>
 #ifdef HAVE_XMU
 # ifndef VMS
 #  include <X11/Xmu/Error.h>
 #ifdef HAVE_XMU
 # ifndef VMS
 #  include <X11/Xmu/Error.h>
 #include "resources.h"
 #include "visual.h"
 #include "usleep.h"
 #include "resources.h"
 #include "visual.h"
 #include "usleep.h"
+#include "auth.h"
 
 saver_info *global_si_kludge = 0;      /* I hate C so much... */
 
 
 saver_info *global_si_kludge = 0;      /* I hate C so much... */
 
@@ -202,36 +205,6 @@ static XrmOptionDescRec options [] = {
 
   /* useful for debugging */
   { "-no-capture-stderr",  ".captureStderr",   XrmoptionNoArg, "off" },
 
   /* useful for debugging */
   { "-no-capture-stderr",  ".captureStderr",   XrmoptionNoArg, "off" },
-
-  /* There's really no reason to have these command-line args; they just
-     lead to confusion when the .xscreensaver file has conflicting values.
-   */
-#if 0
-  { "-splash",            ".splash",           XrmoptionNoArg, "on" },
-  { "-capture-stderr",    ".captureStderr",    XrmoptionNoArg, "on" },
-  { "-timeout",                   ".timeout",          XrmoptionSepArg, 0 },
-  { "-cycle",             ".cycle",            XrmoptionSepArg, 0 },
-  { "-lock-mode",         ".lock",             XrmoptionNoArg, "on" },
-  { "-no-lock-mode",      ".lock",             XrmoptionNoArg, "off" },
-  { "-no-lock",                   ".lock",             XrmoptionNoArg, "off" },
-  { "-lock-timeout",      ".lockTimeout",      XrmoptionSepArg, 0 },
-  { "-lock-vts",          ".lockVTs",          XrmoptionNoArg, "on" },
-  { "-no-lock-vts",       ".lockVTs",          XrmoptionNoArg, "off" },
-  { "-visual",            ".visualID",         XrmoptionSepArg, 0 },
-  { "-install",                   ".installColormap",  XrmoptionNoArg, "on" },
-  { "-no-install",        ".installColormap",  XrmoptionNoArg, "off" },
-  { "-timestamp",         ".timestamp",        XrmoptionNoArg, "on" },
-  { "-xidle-extension",           ".xidleExtension",   XrmoptionNoArg, "on" },
-  { "-no-xidle-extension", ".xidleExtension",  XrmoptionNoArg, "off" },
-  { "-mit-extension",     ".mitSaverExtension",XrmoptionNoArg, "on" },
-  { "-no-mit-extension",   ".mitSaverExtension",XrmoptionNoArg, "off" },
-  { "-sgi-extension",     ".sgiSaverExtension",XrmoptionNoArg, "on" },
-  { "-no-sgi-extension",   ".sgiSaverExtension",XrmoptionNoArg, "off" },
-  { "-proc-interrupts",           ".procInterrupts",   XrmoptionNoArg, "on" },
-  { "-no-proc-interrupts", ".procInterrupts",  XrmoptionNoArg, "off" },
-  { "-idelay",            ".initialDelay",     XrmoptionSepArg, 0 },
-  { "-nice",              ".nice",             XrmoptionSepArg, 0 },
-#endif /* 0 */
 };
 
 #ifdef __GNUC__
 };
 
 #ifdef __GNUC__
@@ -255,7 +228,7 @@ do_help (saver_info *si)
   fflush (stdout);
   fflush (stderr);
   fprintf (stdout, "\
   fflush (stdout);
   fflush (stderr);
   fprintf (stdout, "\
-xscreensaver %s, copyright (c) 1991-2004 by Jamie Zawinski <jwz@jwz.org>\n\
+xscreensaver %s, copyright (c) 1991-2006 by Jamie Zawinski <jwz@jwz.org>\n\
 \n\
   All xscreensaver configuration is via the `~/.xscreensaver' file.\n\
   Rather than editing that file by hand, just run `xscreensaver-demo':\n\
 \n\
   All xscreensaver configuration is via the `~/.xscreensaver' file.\n\
   Rather than editing that file by hand, just run `xscreensaver-demo':\n\
@@ -712,14 +685,15 @@ print_banner (saver_info *si)
      whether to print the banner (and so that the banner gets printed before
      any resource-database-related error messages.)
    */
      whether to print the banner (and so that the banner gets printed before
      any resource-database-related error messages.)
    */
-  p->verbose_p = (p->debug_p || get_boolean_resource ("verbose", "Boolean"));
+  p->verbose_p = (p->debug_p || 
+                  get_boolean_resource (si->dpy, "verbose", "Boolean"));
 
   /* Ditto, for the locking_disabled_p message. */
 
   /* Ditto, for the locking_disabled_p message. */
-  p->lock_p = get_boolean_resource ("lock", "Boolean");
+  p->lock_p = get_boolean_resource (si->dpy, "lock", "Boolean");
 
   if (p->verbose_p)
     fprintf (stderr,
 
   if (p->verbose_p)
     fprintf (stderr,
-            "%s %s, copyright (c) 1991-2004 "
+            "%s %s, copyright (c) 1991-2006 "
             "by Jamie Zawinski <jwz@jwz.org>.\n",
             progname, si->version);
 
             "by Jamie Zawinski <jwz@jwz.org>.\n",
             progname, si->version);
 
@@ -847,6 +821,7 @@ initialize_per_screen_info (saver_info *si, Widget toplevel_shell)
     }
 
 
     }
 
 
+# ifdef QUAD_MODE
   /* In "quad mode", we use the Xinerama code to pretend that there are 4
      screens for every physical screen, and run four times as many hacks...
    */
   /* In "quad mode", we use the Xinerama code to pretend that there are 4
      screens for every physical screen, and run four times as many hacks...
    */
@@ -894,6 +869,7 @@ initialize_per_screen_info (saver_info *si, Widget toplevel_shell)
       si->default_screen = &si->screens[DefaultScreen(si->dpy) * 4];
       si->xinerama_p = True;
     }
       si->default_screen = &si->screens[DefaultScreen(si->dpy) * 4];
       si->xinerama_p = True;
     }
+# endif /* QUAD_MODE */
 
   /* finish initializing the screens.
    */
 
   /* finish initializing the screens.
    */
@@ -904,6 +880,8 @@ initialize_per_screen_info (saver_info *si, Widget toplevel_shell)
 
       ssi->number = i;
       ssi->screen = ScreenOfDisplay (si->dpy, ssi->real_screen_number);
 
       ssi->number = i;
       ssi->screen = ScreenOfDisplay (si->dpy, ssi->real_screen_number);
+      ssi->poll_mouse_last_root_x = -1;
+      ssi->poll_mouse_last_root_y = -1;
 
       if (!si->xinerama_p)
         {
 
       if (!si->xinerama_p)
         {
@@ -1034,6 +1012,10 @@ initialize_server_extensions (saver_info *si)
                  blurb());
     }
 
                  blurb());
     }
 
+#ifdef HAVE_RANDR
+  query_randr_extension (si);
+#endif
+
   if (!system_has_proc_interrupts_p)
     {
       si->using_proc_interrupts = False;
   if (!system_has_proc_interrupts_p)
     {
       si->using_proc_interrupts = False;
@@ -1120,7 +1102,7 @@ maybe_reload_init_file (saver_info *si)
        fprintf (stderr, "%s: file \"%s\" has changed, reloading.\n",
                 blurb(), init_file_name());
 
        fprintf (stderr, "%s: file \"%s\" has changed, reloading.\n",
                 blurb(), init_file_name());
 
-      load_init_file (p);
+      load_init_file (si->dpy, p);
 
       /* If a server extension is in use, and p->timeout has changed,
         we need to inform the server of the new timeout. */
 
       /* If a server extension is in use, and p->timeout has changed,
         we need to inform the server of the new timeout. */
@@ -1186,10 +1168,33 @@ main_loop (saver_info *si)
           /* Go around the loop and wait for the next bout of idleness,
              or for the init file to change, or for a remote command to
              come in, or something.
           /* Go around the loop and wait for the next bout of idleness,
              or for the init file to change, or for a remote command to
              come in, or something.
+
+             But, if locked_p is true, go ahead.  This can only happen
+             if we're in "disabled" mode but a "lock" clientmessage came
+             in: in that case, we should go ahead and blank/lock the screen.
            */
            */
-          continue;
+          if (!si->locked_p)
+            continue;
+        }
+
+      /* Since we're about to blank the screen, kill the de-race timer,
+         if any.  It might still be running if we have unblanked and then
+         re-blanked in a short period (e.g., when using the "next" button
+         in xscreensaver-demo.)
+       */
+      if (si->de_race_id)
+        {
+          if (p->verbose_p)
+            fprintf (stderr, "%s: stopping de-race timer (%d remaining.)\n",
+                     blurb(), si->de_race_ticks);
+          XtRemoveTimeOut (si->de_race_id);
+          si->de_race_id = 0;
         }
 
         }
 
+
+      /* Now, try to blank.
+       */
+
       if (! blank_screen (si))
         {
           /* We were unable to grab either the keyboard or mouse.
       if (! blank_screen (si))
         {
           /* We were unable to grab either the keyboard or mouse.
@@ -1200,13 +1205,29 @@ main_loop (saver_info *si)
              see any events, and the display would be wedged.
 
              So, just go around the loop again and wait for the
              see any events, and the display would be wedged.
 
              So, just go around the loop again and wait for the
-             next bout of idleness.
+             next bout of idleness.  (If the user remains idle, we
+             will next try to blank the screen again in no more than
+             60 seconds.)
           */
           */
+          Time retry = 60 * 1000;
+          if (p->timeout < retry)
+            retry = p->timeout;
 
 
-          fprintf (stderr,
+          if (p->debug_p)
+            {
+              fprintf (stderr,
+                  "%s: DEBUG MODE: unable to grab -- BLANKING ANYWAY.\n",
+                       blurb());
+            }
+          else
+            {
+              fprintf (stderr,
                   "%s: unable to grab keyboard or mouse!  Blanking aborted.\n",
                   "%s: unable to grab keyboard or mouse!  Blanking aborted.\n",
-                   blurb());
-          continue;
+                       blurb());
+
+              schedule_wakeup_event (si, retry, p->debug_p);
+              continue;
+            }
         }
 
       kill_screenhack (si);
         }
 
       kill_screenhack (si);
@@ -1348,58 +1369,10 @@ main_loop (saver_info *si)
          si->lock_id = 0;
        }
 
          si->lock_id = 0;
        }
 
-      /* It's possible that a race condition could have led to the saver
-         window being unexpectedly still mapped.  This can happen like so:
-
-          - screen is blanked
-          - hack is launched
-          - that hack tries to grab a screen image (it does this by
-            first unmapping the saver window, then remapping it.)
-          - hack unmaps window
-          - hack waits
-          - user becomes active
-          - hack re-maps window (*)
-          - driver kills subprocess
-          - driver unmaps window (**)
-
-         The race is that (*) might have been sent to the server before
-         the client process was killed, but, due to scheduling randomness,
-         might not have been received by the server until after (**).
-         In other words, (*) and (**) might happen out of order, meaning
-         the driver will unmap the window, and then after that, the
-         recently-dead client will re-map it.  This leaves the user
-         locked out (it looks like a desktop, but it's not!)
-
-         To avoid this: after un-blanking the screen, sleep for a second,
-         and then really make sure the window is unmapped.
-
-         Update: actually, let's do that once a second for 8 seconds,
-         because sometimes the machine is slow, and we miss...
-       */
-      {
-        int i, j;
-        for (j = 0; j < 8; j++)
-          {
-            XSync (si->dpy, False);
-            sleep (1);
-            for (i = 0; i < si->nscreens; i++)
-              {
-                saver_screen_info *ssi = &si->screens[i];
-                Window w = ssi->screensaver_window;
-                XWindowAttributes xgwa;
-                XGetWindowAttributes (si->dpy, w, &xgwa);
-                if (xgwa.map_state != IsUnmapped)
-                  {
-                    if (p->verbose_p)
-                      fprintf (stderr,
-                               "%s: %d: client race! emergency unmap 0x%lx.\n",
-                               blurb(), i, (unsigned long) w);
-                    XUnmapWindow (si->dpy, w);
-                  }
-              }
-            XSync (si->dpy, False);
-          }
-      }
+      /* Since we're unblanked now, break race conditions and make
+         sure we stay that way (see comment in timers.c.) */
+      if (! si->de_race_id)
+        de_race_timer ((XtPointer) si, 0);
     }
 }
 
     }
 }
 
@@ -1413,6 +1386,7 @@ main (int argc, char **argv)
   saver_info the_si;
   saver_info *si = &the_si;
   saver_preferences *p = &si->prefs;
   saver_info the_si;
   saver_info *si = &the_si;
   saver_preferences *p = &si->prefs;
+  struct passwd *spasswd;
   int i;
 
   memset(si, 0, sizeof(*si));
   int i;
 
   memset(si, 0, sizeof(*si));
@@ -1428,11 +1402,26 @@ main (int argc, char **argv)
   privileged_initialization (si, &argc, argv);
   hack_environment (si);
 
   privileged_initialization (si, &argc, argv);
   hack_environment (si);
 
+  spasswd = getpwuid(getuid());
+  if (!spasswd)
+    {
+      fprintf(stderr, "Could not figure out who the current user is!\n");
+      fprintf(stderr, "spasswd is %x\n", (unsigned int) spasswd);
+      return 1;
+    }
+
+  si->user = strdup(spasswd->pw_name ? spasswd->pw_name : "(unknown)");
+
+# ifndef NO_LOCKING
+  si->unlock_cb = gui_auth_conv;
+  si->auth_finished_cb = auth_finished_cb;
+# endif /* !NO_LOCKING */
+
   shell = connect_to_server (si, &argc, argv);
   process_command_line (si, &argc, argv);
   print_banner (si);
 
   shell = connect_to_server (si, &argc, argv);
   process_command_line (si, &argc, argv);
   print_banner (si);
 
-  load_init_file (p);  /* must be before initialize_per_screen_info() */
+  load_init_file(si->dpy, p); /* must be before initialize_per_screen_info() */
   blurb_timestamp_p = p->timestamp_p;  /* kludge */
   initialize_per_screen_info (si, shell); /* also sets si->fading_possible_p */
 
   blurb_timestamp_p = p->timestamp_p;  /* kludge */
   initialize_per_screen_info (si, shell); /* also sets si->fading_possible_p */
 
@@ -1601,10 +1590,12 @@ clientmessage_response (saver_info *si, Window w, Bool error,
 static void
 bogus_clientmessage_warning (saver_info *si, XEvent *event)
 {
 static void
 bogus_clientmessage_warning (saver_info *si, XEvent *event)
 {
+  saver_preferences *p = &si->prefs;
   char *str = XGetAtomName_safe (si->dpy, event->xclient.message_type);
   Window w = event->xclient.window;
   char wdesc[255];
   int screen = 0;
   char *str = XGetAtomName_safe (si->dpy, event->xclient.message_type);
   Window w = event->xclient.window;
   char wdesc[255];
   int screen = 0;
+  Bool root_p = False;
 
   *wdesc = 0;
   for (screen = 0; screen < si->nscreens; screen++)
 
   *wdesc = 0;
   for (screen = 0; screen < si->nscreens; screen++)
@@ -1616,9 +1607,19 @@ bogus_clientmessage_warning (saver_info *si, XEvent *event)
     else if (w == RootWindow (si->dpy, screen))
       {
         strcpy (wdesc, "root");
     else if (w == RootWindow (si->dpy, screen))
       {
         strcpy (wdesc, "root");
+        root_p = True;
         break;
       }
 
         break;
       }
 
+  /* If this ClientMessage was sent to the real root window instead of to the
+     xscreensaver window, then it might be intended for someone else who is
+     listening on the root window (e.g., the window manager).  So only print
+     the warning if: we are in debug mode; or if the bogus message was
+     actually sent to one of the xscreensaver-created windows.
+   */
+  if (root_p && !p->debug_p)
+    return;
+
   if (!*wdesc)
     {
       XErrorHandler old_handler;
   if (!*wdesc)
     {
       XErrorHandler old_handler;
@@ -1864,7 +1865,7 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p)
   else if (type == XA_DEMO)
     {
       long arg = event->xclient.data.l[1];
   else if (type == XA_DEMO)
     {
       long arg = event->xclient.data.l[1];
-      Bool demo_one_hack_p = (arg == 300);
+      Bool demo_one_hack_p = (arg == 5000);
 
       if (demo_one_hack_p)
        {
 
       if (demo_one_hack_p)
        {
@@ -1912,11 +1913,7 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p)
                              "not compiled with support for locking.",
                              "locking not enabled.");
 #else /* !NO_LOCKING */
                              "not compiled with support for locking.",
                              "locking not enabled.");
 #else /* !NO_LOCKING */
-      if (p->mode == DONT_BLANK)
-        clientmessage_response(si, window, True,
-                             "LOCK ClientMessage received in DONT_BLANK mode.",
-                               "screen blanking is currently disabled.");
-      else if (si->locking_disabled_p)
+      if (si->locking_disabled_p)
        clientmessage_response (si, window, True,
                      "LOCK ClientMessage received, but locking is disabled.",
                              "locking not enabled.");
        clientmessage_response (si, window, True,
                      "LOCK ClientMessage received, but locking is disabled.",
                              "locking not enabled.");
@@ -1960,6 +1957,12 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p)
     }
   else if (type == XA_THROTTLE)
     {
     }
   else if (type == XA_THROTTLE)
     {
+      /* The THROTTLE command is deprecated -- it predates the XDPMS
+         extension.  Instead of using -throttle, users should instead
+         just power off the monitor (e.g., "xset dpms force off".)
+         In a few minutes, xscreensaver will notice that the monitor
+         is off, and cease running hacks.
+       */
       if (si->throttled_p)
        clientmessage_response (si, window, True,
                                 "THROTTLE ClientMessage received, but "
       if (si->throttled_p)
        clientmessage_response (si, window, True,
                                 "THROTTLE ClientMessage received, but "
@@ -2115,7 +2118,17 @@ analyze_display (saver_info *si)
         False
 #     endif
    }, { "XINERAMA",                             "Xinerama",
         False
 #     endif
    }, { "XINERAMA",                             "Xinerama",
+#     ifdef HAVE_XINERAMA
         True
         True
+#     else
+        False
+#     endif
+   }, { "RANDR",                                "Resize-and-Rotate",
+#     ifdef HAVE_RANDR
+        True
+#     else
+        False
+#     endif
    }, { "Apple-DRI",                            "Apple-DRI (XDarwin)",
         True
    },
    }, { "Apple-DRI",                            "Apple-DRI (XDarwin)",
         True
    },
@@ -2258,7 +2271,7 @@ display_is_on_console_p (saver_info *si)
 void
 check_for_leaks (const char *where)
 {
 void
 check_for_leaks (const char *where)
 {
-#ifdef HAVE_SBRK
+#if defined(HAVE_SBRK) && defined(LEAK_PARANOIA)
   static unsigned long last_brk = 0;
   int b = (unsigned long) sbrk(0);
   if (last_brk && last_brk < b)
   static unsigned long last_brk = 0;
   int b = (unsigned long) sbrk(0);
   if (last_brk && last_brk < b)