http://ftp.x.org/contrib/applications/xscreensaver-3.01.tar.gz
[xscreensaver] / driver / xscreensaver.c
index 92b0f6f4a35a1e08419c6cee7497ce7f96d1ee57..d0efd9b0359f7942e5c2bef28f37c4e81c8c0ba8 100644 (file)
@@ -169,6 +169,7 @@ static XrmOptionDescRec options [] = {
   { "-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" },
@@ -228,7 +229,8 @@ The standard Xt command-line options are accepted; other options include:\n\
 See the manual for other options and X resources.\n\
 \n\
 The `xscreensaver' program should be left running in the background.\n\
-Use the `xscreensaver-command' program to manipulate a running xscreensaver.\n\
+Use the `xscreensaver-demo' and `xscreensaver-command' programs to\n\
+manipulate a running xscreensaver.\n\
 \n\
 The `*programs' resource controls which graphics demos will be launched by\n\
 the screensaver.  See `man xscreensaver' or the web page for more details.\n\
@@ -236,7 +238,7 @@ the screensaver.  See `man xscreensaver' or the web page for more details.\n\
 Just getting started?  Try this:\n\
 \n\
         xscreensaver &\n\
-        xscreensaver-command -demo\n\
+        xscreensaver-demo\n\
 \n\
 For updates, check http://www.jwz.org/xscreensaver/\n\
 \n",
@@ -318,10 +320,6 @@ saver_ehandler (Display *dpy, XErrorEvent *error)
 /* The zillions of initializations.
  */
 
-static void get_screenhacks (saver_info *si);
-
-
-
 /* Set progname, version, etc.  This is done very early.
  */
 static void
@@ -388,13 +386,13 @@ connect_to_server (saver_info *si, int *argc, char **argv)
                                    argc, argv, defaults, 0, 0);
 
   si->dpy = XtDisplay (toplevel_shell);
-  si->db = XtDatabase (si->dpy);
+  si->prefs.db = XtDatabase (si->dpy);
   XtGetApplicationNameAndClass (si->dpy, &progname, &progclass);
 
   if(strlen(progname) > 100)   /* keep it short. */
     progname [99] = 0;
 
-  db = si->db; /* resources.c needs this */
+  db = si->prefs.db;   /* resources.c needs this */
 
   XA_VROOT = XInternAtom (si->dpy, "__SWM_VROOT", False);
   XA_SCREENSAVER = XInternAtom (si->dpy, "SCREENSAVER", False);
@@ -433,11 +431,6 @@ process_command_line (saver_info *si, int *argc, char **argv)
        /* no resource for this one, out of paranoia. */
        si->prefs.debug_p = True;
 
-      else if (!strcmp (argv[i], "-initial-demo-mode"))
-       /* This isn't an advertized option; it is used internally to implement
-          the "Reinitialize" button on the Demo Mode window. */
-       si->demo_mode_p = True;
-
       else if (!strcmp (argv[i], "-h") ||
               !strcmp (argv[i], "-help") ||
               !strcmp (argv[i], "--help"))
@@ -464,13 +457,20 @@ process_command_line (saver_info *si, int *argc, char **argv)
              !strcmp (s, "-version") ||
              !strcmp (s, "-time"))
            {
-             fprintf (stderr, "\n\
-    However, %s is an option to the `xscreensaver-command' program.\n\
+
+             if (!strcmp (s, "-demo") || !strcmp (s, "-prefs"))
+               fprintf (stderr, "\n\
+    Perhaps you meant to run the `xscreensaver-demo' program instead?\n");
+             else
+               fprintf (stderr, "\n\
+    However, `%s' is an option to the `xscreensaver-command' program.\n", s);
+
+             fprintf (stderr, "\
     The `xscreensaver' program is a daemon that runs in the background.\n\
     You control a running xscreensaver process by sending it messages\n\
-    with `xscreensaver-command'.  See the man pages for details,\n\
-    or check the web page: http://www.jwz.org/xscreensaver/\n\n",
-                      s);
+    with `xscreensaver-demo' or `xscreensaver-command'.\n\
+.   See the man pages for details, or check the web page:\n\
+    http://www.jwz.org/xscreensaver/\n\n");
 
              /* Since version 1.21 renamed the "-lock" option to "-lock-mode",
                 suggest that explicitly. */
@@ -479,6 +479,7 @@ process_command_line (saver_info *si, int *argc, char **argv)
     Or perhaps you meant either the \"-lock-mode\" or the\n\
     \"-lock-timeout <minutes>\" options to xscreensaver?\n\n");
            }
+
          exit (1);
        }
     }
@@ -504,9 +505,9 @@ print_banner (saver_info *si)
 
   if (p->verbose_p)
     fprintf (stderr,
-            "%s %s, copyright (c) 1991-1998 by Jamie Zawinski <jwz@jwz.org>\n"
-            " pid = %d.\n",
-            blurb(), si->version, (int) getpid ());
+            "%s %s, copyright (c) 1991-1998 "
+            "by Jamie Zawinski <jwz@jwz.org>.\n",
+            progname, si->version);
 
   if (p->debug_p)
     fprintf (stderr, "\n"
@@ -533,6 +534,9 @@ print_banner (saver_info *si)
                     blurb(), si->orig_uid);
          fprintf (stderr, "%s: %s\n", blurb(), si->uid_message);
        }
+
+      fprintf (stderr, "%s: in process %lu.\n", blurb(),
+              (unsigned long) getpid());
     }
 
   /* If locking was not able to be initalized for some reason, explain why.
@@ -613,138 +617,7 @@ initialize_per_screen_info (saver_info *si, Widget toplevel_shell)
        }
     }
 
-  si->fading_possible_p = found_any_writable_cells;
-}
-
-
-/* Populate `saver_preferences' with the contents of the resource database.
-   Note that this may be called multiple times -- it is re-run each time
-   the ~/.xscreensaver file is reloaded.
-
-   This function can be very noisy, since it issues resource syntax errors
-   and so on.
- */
-void
-get_resources (saver_info *si)
-{
-  char *s;
-  saver_preferences *p = &si->prefs;
-
-  if (si->init_file_date == 0)
-    /* The date will be 0 the first time this is called; and when this is
-       called subsequent times, the file will have already been reloaded. */
-    read_init_file (si);
-
-  p->xsync_p       = get_boolean_resource ("synchronous", "Synchronous");
-  if (p->xsync_p)
-    XSynchronize(si->dpy, True);
-
-  p->verbose_p     = get_boolean_resource ("verbose", "Boolean");
-  p->timestamp_p    = get_boolean_resource ("timestamp", "Boolean");
-  p->lock_p        = get_boolean_resource ("lock", "Boolean");
-  p->lock_vt_p     = get_boolean_resource ("lockVTs", "Boolean");
-  p->fade_p        = get_boolean_resource ("fade", "Boolean");
-  p->unfade_p      = get_boolean_resource ("unfade", "Boolean");
-  p->fade_seconds   = 1000 * get_seconds_resource ("fadeSeconds", "Time");
-  p->fade_ticks            = get_integer_resource ("fadeTicks", "Integer");
-  p->install_cmap_p = get_boolean_resource ("installColormap", "Boolean");
-  p->nice_inferior  = get_integer_resource ("nice", "Nice");
-
-  p->initial_delay   = 1000 * get_seconds_resource ("initialDelay", "Time");
-  p->splash_duration = 1000 * get_seconds_resource ("splashDuration", "Time");
-  p->timeout         = 1000 * get_minutes_resource ("timeout", "Time");
-  p->lock_timeout    = 1000 * get_minutes_resource ("lockTimeout", "Time");
-  p->cycle           = 1000 * get_minutes_resource ("cycle", "Time");
-  p->passwd_timeout  = 1000 * get_seconds_resource ("passwdTimeout", "Time");
-  p->pointer_timeout = 1000 * get_seconds_resource ("pointerPollTime", "Time");
-  p->notice_events_timeout = 1000*get_seconds_resource("windowCreationTimeout",
-                                                      "Time");
-  p->shell = get_string_resource ("bourneShell", "BourneShell");
-
-  p->help_url = get_string_resource("helpURL", "URL");
-  p->load_url_command = get_string_resource("loadURL", "LoadURL");
-
-  if ((s = get_string_resource ("splash", "Boolean")))
-    if (!get_boolean_resource("splash", "Boolean"))
-      p->splash_duration = 0;
-  if (s) free (s);
-
-  if (p->verbose_p && !si->fading_possible_p && (p->fade_p || p->unfade_p))
-    {
-      fprintf (stderr,
-              (si->nscreens == 1
-               ? "%s: the screen has no PseudoColor or GrayScale visuals.\n"
-               : "%s: no screens have PseudoColor or GrayScale visuals.\n"),
-              blurb());
-      fprintf (stderr, "%s: ignoring the request for fading/unfading.\n",
-              blurb());
-    }
-
-  /* don't set use_xidle_extension unless it is explicitly specified */
-  if ((s = get_string_resource ("xidleExtension", "Boolean")))
-    p->use_xidle_extension = get_boolean_resource ("xidleExtension","Boolean");
-  else
-#ifdef HAVE_XIDLE_EXTENSION            /* pick a default */
-    p->use_xidle_extension = True;     /* if we have it, use it */
-#else  /* !HAVE_XIDLE_EXTENSION */
-    p->use_xidle_extension = False;
-#endif /* !HAVE_XIDLE_EXTENSION */
-  if (s) free (s);
-
-  /* don't set use_mit_extension unless it is explicitly specified */
-  if ((s = get_string_resource ("mitSaverExtension", "Boolean")))
-    p->use_mit_saver_extension = get_boolean_resource ("mitSaverExtension",
-                                                      "Boolean");
-  else
-#ifdef HAVE_MIT_SAVER_EXTENSION                /* pick a default */
-    p->use_mit_saver_extension = False;        /* Default false, because it sucks */
-#else  /* !HAVE_MIT_SAVER_EXTENSION */
-    p->use_mit_saver_extension = False;
-#endif /* !HAVE_MIT_SAVER_EXTENSION */
-  if (s) free (s);
-
-
-  /* don't set use_mit_extension unless it is explicitly specified */
-  if ((s = get_string_resource ("sgiSaverExtension", "Boolean")))
-    p->use_sgi_saver_extension = get_boolean_resource ("sgiSaverExtension",
-                                                      "Boolean");
-  else
-#ifdef HAVE_SGI_SAVER_EXTENSION                /* pick a default */
-    p->use_sgi_saver_extension = True; /* if we have it, use it */
-#else  /* !HAVE_SGI_SAVER_EXTENSION */
-    p->use_sgi_saver_extension = False;
-#endif /* !HAVE_SGI_SAVER_EXTENSION */
-  if (s) free (s);
-
-
-  /* Throttle the various timeouts to reasonable values.
-   */
-  if (p->passwd_timeout == 0) p->passwd_timeout = 30000;        /* 30 secs */
-  if (p->timeout < 10000) p->timeout = 10000;                   /* 10 secs */
-  if (p->cycle != 0 && p->cycle < 2000) p->cycle = 2000;        /*  2 secs */
-  if (p->pointer_timeout == 0) p->pointer_timeout = 5000;       /*  5 secs */
-  if (p->notice_events_timeout == 0)
-    p->notice_events_timeout = 10000;                           /* 10 secs */
-  if (p->fade_seconds == 0 || p->fade_ticks == 0)
-    p->fade_p = False;
-  if (! p->fade_p) p->unfade_p = False;
-
-  p->watchdog_timeout = p->cycle;
-  if (p->watchdog_timeout < 30000) p->watchdog_timeout = 30000;          /* 30 secs */
-  if (p->watchdog_timeout > 3600000) p->watchdog_timeout = 3600000; /*  1 hr */
-
-  get_screenhacks (si);
-
-  if (p->debug_p)
-    {
-      XSynchronize(si->dpy, True);
-      p->xsync_p = True;
-      p->verbose_p = True;
-      p->timestamp_p = True;
-      p->initial_delay = 0;
-    }
-
-  blurb_timestamp_p = p->timestamp_p;
+  si->prefs.fading_possible_p = found_any_writable_cells;
 }
 
 
@@ -756,94 +629,54 @@ initialize_server_extensions (saver_info *si)
 {
   saver_preferences *p = &si->prefs;
 
-  if (p->use_sgi_saver_extension)
-    {
+  Bool server_has_xidle_extension_p = False;
+  Bool server_has_sgi_saver_extension_p = False;
+  Bool server_has_mit_saver_extension_p = False;
+
+#ifdef HAVE_XIDLE_EXTENSION
+  server_has_xidle_extension_p = query_xidle_extension (si);
+#endif
 #ifdef HAVE_SGI_SAVER_EXTENSION
-      if (! query_sgi_saver_extension (si))
-       {
-         fprintf (stderr,
-        "%s: display %s does not support the SGI SCREEN_SAVER extension.\n",
-                  blurb(), DisplayString (si->dpy));
-         p->use_sgi_saver_extension = False;
-       }
-      else if (p->use_mit_saver_extension)
-       {
-         fprintf (stderr,
-                  "%s: SGI SCREEN_SAVER extension used instead"
-                  " of MIT-SCREEN-SAVER extension.\n",
-                  blurb());
-         p->use_mit_saver_extension = False;
-       }
-      else if (p->use_xidle_extension)
-       {
-         fprintf (stderr,
-        "%s: SGI SCREEN_SAVER extension used instead of XIDLE extension.\n",
-                  blurb());
-         p->use_xidle_extension = False;
-       }
-#else  /* !HAVE_MIT_SAVER_EXTENSION */
-      fprintf (stderr,
-              "%s: not compiled with support for the SGI SCREEN_SAVER"
-              " extension.\n",
-              blurb());
-      p->use_sgi_saver_extension = False;
-#endif /* !HAVE_SGI_SAVER_EXTENSION */
-    }
+  server_has_sgi_saver_extension_p = query_sgi_saver_extension (si);
+#endif
+#ifdef HAVE_MIT_SAVER_EXTENSION
+  server_has_mit_saver_extension_p = query_mit_saver_extension (si);
+#endif
 
-  if (p->use_mit_saver_extension)
+  if (!server_has_xidle_extension_p)
+    p->use_xidle_extension = False;
+  else if (p->verbose_p)
     {
-#ifdef HAVE_MIT_SAVER_EXTENSION
-      if (! query_mit_saver_extension (si))
-       {
-         fprintf (stderr,
-                  "%s: display %s does not support the MIT-SCREEN-SAVER"
-                  " extension.\n",
-                  blurb(), DisplayString (si->dpy));
-         p->use_mit_saver_extension = False;
-       }
-      else if (p->use_xidle_extension)
-       {
-         fprintf (stderr,
-                  "%s: MIT-SCREEN-SAVER extension used instead of XIDLE"
-                  " extension.\n",
-                  blurb());
-         p->use_xidle_extension = False;
-       }
-#else  /* !HAVE_MIT_SAVER_EXTENSION */
-      fprintf (stderr,
-              "%s: not compiled with support for the MIT-SCREEN-SAVER"
-              " extension.\n",
-              blurb());
-      p->use_mit_saver_extension = False;
-#endif /* !HAVE_MIT_SAVER_EXTENSION */
+      if (p->use_xidle_extension)
+       fprintf (stderr, "%s: using XIDLE extension.\n", blurb());
+      else
+       fprintf (stderr, "%s: not using server's XIDLE extension.\n", blurb());
     }
 
-  if (p->use_xidle_extension)
+  if (!server_has_sgi_saver_extension_p)
+    p->use_sgi_saver_extension = False;
+  else if (p->verbose_p)
     {
-#ifdef HAVE_XIDLE_EXTENSION
-      int first_event, first_error;
-      if (! XidleQueryExtension (si->dpy, &first_event, &first_error))
-       {
-         fprintf (stderr,
-                  "%s: display %s does not support the XIdle extension.\n",
-                  blurb(), DisplayString (si->dpy));
-         p->use_xidle_extension = False;
-       }
-#else  /* !HAVE_XIDLE_EXTENSION */
-      fprintf (stderr, "%s: not compiled with support for XIdle.\n", blurb());
-      p->use_xidle_extension = False;
-#endif /* !HAVE_XIDLE_EXTENSION */
+      if (p->use_sgi_saver_extension)
+       fprintf (stderr, "%s: using SGI SCREEN_SAVER extension.\n", blurb());
+      else
+       fprintf (stderr,
+                "%s: not using server's SGI SCREEN_SAVER extension.\n",
+                blurb());
     }
 
-  if (p->verbose_p && p->use_mit_saver_extension)
-    fprintf (stderr, "%s: using MIT-SCREEN-SAVER server extension.\n",
-            blurb());
-  if (p->verbose_p && p->use_sgi_saver_extension)
-    fprintf (stderr, "%s: using SGI SCREEN_SAVER server extension.\n",
-            blurb());
-  if (p->verbose_p && p->use_xidle_extension)
-    fprintf (stderr, "%s: using XIdle server extension.\n",
-            blurb());
+  if (!server_has_mit_saver_extension_p)
+    p->use_mit_saver_extension = False;
+  else if (p->verbose_p)
+    {
+      if (p->use_mit_saver_extension)
+       fprintf (stderr, "%s: using lame MIT-SCREEN-SAVER extension.\n",
+                blurb());
+      else
+       fprintf (stderr,
+                "%s: not using server's lame MIT-SCREEN-SAVER extension.\n",
+                blurb());
+    }
 }
 
 
@@ -864,7 +697,7 @@ select_events (saver_info *si)
       p->use_sgi_saver_extension)
     return;
 
-  if (p->initial_delay && !si->demo_mode_p)
+  if (p->initial_delay)
     {
       if (p->verbose_p)
        {
@@ -897,6 +730,25 @@ select_events (saver_info *si)
 }
 
 
+void
+maybe_reload_init_file (saver_info *si)
+{
+  saver_preferences *p = &si->prefs;
+  if (init_file_changed_p (p))
+    {
+      if (p->verbose_p)
+       fprintf (stderr, "%s: file \"%s\" has changed, reloading.\n",
+                blurb(), init_file_name());
+
+      load_init_file (p);
+
+      /* If a server extension is in use, and p->timeout has changed,
+        we need to inform the server of the new timeout. */
+      disable_builtin_screensaver (si, False);
+    }
+}
+
+
 /* Loop forever:
 
        - wait until the user is idle;
@@ -910,104 +762,112 @@ static void
 main_loop (saver_info *si)
 {
   saver_preferences *p = &si->prefs;
+  Bool ok_to_unblank;
+
   while (1)
     {
-      if (! si->demo_mode_p)
-       sleep_until_idle (si, True);
+      sleep_until_idle (si, True);
+
+      if (p->verbose_p)
+       {
+         if (si->demoing_p)
+           fprintf (stderr, "%s: demoing %d at %s.\n", blurb(),
+                    si->selection_mode, timestring());
+         else
+           if (p->verbose_p)
+             fprintf (stderr, "%s: blanking screen at %s.\n", blurb(),
+                      timestring());
+       }
 
       maybe_reload_init_file (si);
 
-#ifndef NO_DEMO_MODE
-      if (si->demo_mode_p)
-       demo_mode (si);
-      else
-#endif /* !NO_DEMO_MODE */
-       {
-         if (p->verbose_p)
-           fprintf (stderr, "%s: user is idle; waking up at %s.\n", blurb(),
-                    timestring());
-         maybe_reload_init_file (si);
-         blank_screen (si);
-         spawn_screenhack (si, True);
-         if (p->cycle)
-           si->cycle_id = XtAppAddTimeOut (si->app, p->cycle, cycle_timer,
-                                           (XtPointer) si);
+      blank_screen (si);
+      kill_screenhack (si);
+      spawn_screenhack (si, True);
+
+      /* Don't start the cycle timer in demo mode. */
+      if (!si->demoing_p && p->cycle)
+       si->cycle_id = XtAppAddTimeOut (si->app, p->cycle, cycle_timer,
+                                       (XtPointer) si);
+
 
 #ifndef NO_LOCKING
-         if (p->lock_p &&
-             !si->locking_disabled_p &&
-             p->lock_timeout == 0)
-           si->locked_p = True;
-
-         if (p->lock_p && !si->locked_p)
-           /* locked_p might be true already because of ClientMessage */
-           si->lock_id = XtAppAddTimeOut (si->app, p->lock_timeout,
-                                          activate_lock_timer,
-                                          (XtPointer) si);
+      if (!si->demoing_p &&            /* if not going into demo mode */
+         p->lock_p &&                  /* and locking is enabled */
+         !si->locking_disabled_p &&    /* and locking is possible */
+         p->lock_timeout == 0)         /* and locking is not timer-deferred */
+       si->locked_p = True;            /* then lock right now. */
+
+      /* locked_p might be true already because of the above, or because of
+        the LOCK ClientMessage.  But if not, and if we're supposed to lock
+        after some time, set up a timer to do so.
+       */
+      if (p->lock_p &&
+         !si->locked_p &&
+         p->lock_timeout > 0)
+       si->lock_id = XtAppAddTimeOut (si->app, p->lock_timeout,
+                                      activate_lock_timer,
+                                      (XtPointer) si);
 #endif /* !NO_LOCKING */
 
-       PASSWD_INVALID:
 
-         sleep_until_idle (si, False); /* until not idle */
-         maybe_reload_init_file (si);
+      ok_to_unblank = True;
+      do {
+
+       sleep_until_idle (si, False);           /* until not idle */
+       maybe_reload_init_file (si);
 
 #ifndef NO_LOCKING
-         if (si->locked_p)
-           {
-             Bool val;
-             if (si->locking_disabled_p) abort ();
-             si->dbox_up_p = True;
-
-             {
-               saver_screen_info *ssi = si->default_screen;
-               suspend_screenhack (si, True);
-               XUndefineCursor (si->dpy, ssi->screensaver_window);
-               if (p->verbose_p)
-                 fprintf (stderr, "%s: prompting for password.\n", blurb());
-               val = unlock_p (si);
-               if (p->verbose_p && val == False)
-                 fprintf (stderr, "%s: password incorrect!\n", blurb());
-               si->dbox_up_p = False;
-               XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
-               suspend_screenhack (si, False);
-             }
-
-             if (! val)
-               goto PASSWD_INVALID;
-             si->locked_p = False;
-           }
+       if (si->locked_p)
+         {
+           saver_screen_info *ssi = si->default_screen;
+           if (si->locking_disabled_p) abort ();
+
+           si->dbox_up_p = True;
+           suspend_screenhack (si, True);
+           XUndefineCursor (si->dpy, ssi->screensaver_window);
+
+           ok_to_unblank = unlock_p (si);
+
+           si->dbox_up_p = False;
+           XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
+           suspend_screenhack (si, False);     /* resume */
+         }
 #endif /* !NO_LOCKING */
 
-         if (p->verbose_p)
-           fprintf (stderr, "%s: user is active at %s.\n",
-                    blurb(), timestring ());
+       } while (!ok_to_unblank);
 
-         /* Let's kill it before unblanking, to get it to stop drawing as
-            soon as possible... */
-         kill_screenhack (si);
-         unblank_screen (si);
-         si->selection_mode = 0;
 
-         if (si->cycle_id)
-           {
-             XtRemoveTimeOut (si->cycle_id);
-             si->cycle_id = 0;
-           }
+      if (p->verbose_p)
+       fprintf (stderr, "%s: unblanking screen at %s.\n",
+                blurb(), timestring ());
 
-#ifndef NO_LOCKING
-         if (si->lock_id)
-           {
-             XtRemoveTimeOut (si->lock_id);
-             si->lock_id = 0;
-           }
-#endif /* !NO_LOCKING */
+      /* Kill before unblanking, to stop drawing as soon as possible. */
+      kill_screenhack (si);
+      unblank_screen (si);
+
+      si->locked_p = False;
+      si->demoing_p = 0;
+      si->selection_mode = 0;
+
+      if (si->cycle_id)
+       {
+         XtRemoveTimeOut (si->cycle_id);
+         si->cycle_id = 0;
+       }
 
-         if (p->verbose_p)
-           fprintf (stderr, "%s: going to sleep.\n", blurb());
+      if (si->lock_id)
+       {
+         XtRemoveTimeOut (si->lock_id);
+         si->lock_id = 0;
        }
+
+      if (p->verbose_p)
+       fprintf (stderr, "%s: awaiting idleness.\n", blurb());
     }
 }
 
+static void analyze_display (saver_info *si);
 
 int
 main (int argc, char **argv)
@@ -1015,6 +875,7 @@ main (int argc, char **argv)
   Widget shell;
   saver_info the_si;
   saver_info *si = &the_si;
+  saver_preferences *p = &si->prefs;
   int i;
 
   memset(si, 0, sizeof(*si));
@@ -1022,21 +883,27 @@ main (int argc, char **argv)
 
   srandom ((int) time ((time_t *) 0));
 
-  set_version_string (si, &argc, argv);
   save_argv (argc, argv);
+  set_version_string (si, &argc, argv);
   privileged_initialization (si, &argc, argv);
   hack_environment (si);
 
   shell = connect_to_server (si, &argc, argv);
   process_command_line (si, &argc, argv);
   print_banner (si);
-  initialize_per_screen_info (si, shell);
-  get_resources (si);
+
+  initialize_per_screen_info (si, shell);  /* also sets p->fading_possible_p */
 
   for (i = 0; i < si->nscreens; i++)
     if (ensure_no_screensaver_running (si->dpy, si->screens[i].screen))
       exit (1);
 
+  load_init_file (p);
+
+  if (p->xsync_p) XSynchronize (si->dpy, True);
+  blurb_timestamp_p = p->timestamp_p;  /* kludge */
+
+  if (p->verbose_p) analyze_display (si);
   initialize_server_extensions (si);
   initialize_screensaver_window (si);
   select_events (si);
@@ -1044,173 +911,12 @@ main (int argc, char **argv)
   disable_builtin_screensaver (si, True);
   initialize_stderr (si);
 
-  if (!si->demo_mode_p)
-    make_splash_dialog (si);
+  make_splash_dialog (si);
 
   main_loop (si);              /* doesn't return */
   return 0;
 }
 
-\f
-/* Parsing the programs resource.
- */
-
-static char *
-reformat_hack (const char *hack)
-{
-  int i;
-  const char *in = hack;
-  int indent = 13;
-  char *h2 = (char *) malloc(strlen(in) + indent + 2);
-  char *out = h2;
-
-  while (isspace(*in)) in++;           /* skip whitespace */
-  while (*in && !isspace(*in) && *in != ':')
-    *out++ = *in++;                    /* snarf first token */
-  while (isspace(*in)) in++;           /* skip whitespace */
-
-  if (*in == ':')
-    *out++ = *in++;                    /* copy colon */
-  else
-    {
-      in = hack;
-      out = h2;                                /* reset to beginning */
-    }
-
-  *out = 0;
-
-  while (isspace(*in)) in++;           /* skip whitespace */
-  for (i = strlen(h2); i < indent; i++)        /* indent */
-    *out++ = ' ';
-
-  /* copy the rest of the line. */
-  while (*in)
-    {
-      /* shrink all whitespace to one space, for the benefit of the "demo"
-        mode display.  We only do this when we can easily tell that the
-        whitespace is not significant (no shell metachars).
-       */
-      switch (*in)
-       {
-       case '\'': case '"': case '`': case '\\':
-         {
-           /* Metachars are scary.  Copy the rest of the line unchanged. */
-           while (*in)
-             *out++ = *in++;
-         }
-         break;
-       case ' ': case '\t':
-         {
-           while (*in == ' ' || *in == '\t')
-             in++;
-           *out++ = ' ';
-         }
-         break;
-       default:
-         *out++ = *in++;
-         break;
-       }
-    }
-  *out = 0;
-
-  /* strip trailing whitespace. */
-  out = out-1;
-  while (out > h2 && (*out == ' ' || *out == '\t' || *out == '\n'))
-    *out-- = 0;
-
-  return h2;
-}
-
-
-static void
-get_screenhacks (saver_info *si)
-{
-  saver_preferences *p = &si->prefs;
-  int i = 0;
-  int start = 0;
-  int end = 0;
-  int size;
-  char *d;
-
-  d = get_string_resource ("monoPrograms", "MonoPrograms");
-  if (d && !*d) { free(d); d = 0; }
-  if (!d)
-    d = get_string_resource ("colorPrograms", "ColorPrograms");
-  if (d && !*d) { free(d); d = 0; }
-
-  if (d)
-    {
-      fprintf (stderr,
-       "%s: the `monoPrograms' and `colorPrograms' resources are obsolete;\n\
-       see the manual for details.\n", blurb());
-      free(d);
-    }
-
-  d = get_string_resource ("programs", "Programs");
-
-  if (p->screenhacks)
-    {
-      for (i = 0; i < p->screenhacks_count; i++)
-       if (p->screenhacks[i])
-         free (p->screenhacks[i]);
-      free(p->screenhacks);
-      p->screenhacks = 0;
-    }
-
-  if (!d || !*d)
-    {
-      p->screenhacks_count = 0;
-      p->screenhacks = 0;
-      return;
-    }
-
-  size = strlen (d);
-
-
-  /* Count up the number of newlines (which will be equal to or larger than
-     the number of hacks.)
-   */
-  i = 0;
-  for (i = 0; d[i]; i++)
-    if (d[i] == '\n')
-      i++;
-  i++;
-
-  p->screenhacks = (char **) calloc (sizeof (char *), i+1);
-
-  /* Iterate over the lines in `d' (the string with newlines)
-     and make new strings to stuff into the `screenhacks' array.
-   */
-  p->screenhacks_count = 0;
-  while (start < size)
-    {
-      /* skip forward over whitespace. */
-      while (d[start] == ' ' || d[start] == '\t' || d[start] == '\n')
-       start++;
-
-      /* skip forward to newline or end of string. */
-      end = start;
-      while (d[end] != 0 && d[end] != '\n')
-       end++;
-
-      /* null terminate. */
-      d[end] = 0;
-
-      p->screenhacks[p->screenhacks_count++] = reformat_hack (d + start);
-      if (p->screenhacks_count >= i)
-       abort();
-
-      start = end+1;
-    }
-
-  if (p->screenhacks_count == 0)
-    {
-      free (p->screenhacks);
-      p->screenhacks = 0;
-    }
-}
-
-
 \f
 /* Processing ClientMessage events.
  */
@@ -1273,6 +979,7 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p)
                                 "ACTIVATE ClientMessage received.",
                                 "activating.");
          si->selection_mode = 0;
+         si->demoing_p = False;
          if (p->use_mit_saver_extension || p->use_sgi_saver_extension)
            {
              XForceScreenSaver (si->dpy, ScreenSaverActive);
@@ -1316,6 +1023,7 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p)
                                 "CYCLE ClientMessage received.",
                                 "cycling.");
          si->selection_mode = 0;       /* 0 means randomize when its time. */
+         si->demoing_p = False;
          if (si->cycle_id)
            XtRemoveTimeOut (si->cycle_id);
          si->cycle_id = 0;
@@ -1334,6 +1042,7 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p)
                              : "PREV ClientMessage received."),
                             "cycling.");
       si->selection_mode = (type == XA_NEXT ? -1 : -2);
+      si->demoing_p = False;
 
       if (! until_idle_p)
        {
@@ -1357,6 +1066,7 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p)
 
       if (which < 0) which = 0;                /* 0 == "random" */
       si->selection_mode = which;
+      si->demoing_p = False;
 
       if (! until_idle_p)
        {
@@ -1421,43 +1131,43 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p)
     }
   else if (type == XA_DEMO)
     {
-#ifdef NO_DEMO_MODE
-      clientmessage_response (si, window, True,
-                             "not compiled with support for DEMO mode.",
-                             "demo mode not enabled.");
-#else /* !NO_DEMO_MODE */
-      if (until_idle_p)
+      long arg = event->xclient.data.l[1];
+      Bool demo_one_hack_p = (arg == 300);
+
+      if (demo_one_hack_p)
        {
-         clientmessage_response (si, window, False,
-                                 "DEMO ClientMessage received.",
-                                 "Demo mode.");
-         si->demo_mode_p = True;
-         return True;
+         if (until_idle_p)
+           {
+             long which = event->xclient.data.l[2];
+             char buf [255];
+             char buf2 [255];
+             sprintf (buf, "DEMO %ld ClientMessage received.", which);
+             sprintf (buf2, "demoing (%ld).", which);
+             clientmessage_response (si, window, False, buf, buf2);
+
+             if (which < 0) which = 0;         /* 0 == "random" */
+             si->selection_mode = which;
+             si->demoing_p = True;
+
+             return True;
+           }
+
+         clientmessage_response (si, window, True,
+                                 "DEMO ClientMessage received while active.",
+                                 "already active.");
+       }
+      else
+       {
+         clientmessage_response (si, window, True,
+                                 "obsolete form of DEMO ClientMessage.",
+                                 "obsolete form of DEMO ClientMessage.");
        }
-      clientmessage_response (si, window, True,
-                             "DEMO ClientMessage received while active.",
-                             "already active.");
-#endif /* !NO_DEMO_MODE */
     }
   else if (type == XA_PREFS)
     {
-#ifdef NO_DEMO_MODE
-      clientmessage_response (si, window, True,
-                             "not compiled with support for DEMO mode.",
-                             "preferences mode not enabled.");
-#else /* !NO_DEMO_MODE */
-      if (until_idle_p)
-       {
-         clientmessage_response (si, window, False,
-                                 "PREFS ClientMessage received.",
-                                 "preferences mode.");
-         si->demo_mode_p = (Bool) 2;  /* kludge, so sue me. */
-         return True;
-       }
       clientmessage_response (si, window, True,
-                             "PREFS ClientMessage received while active.",
-                             "already active.");
-#endif /* !NO_DEMO_MODE */
+                             "the PREFS client-message is obsolete.",
+                             "the PREFS client-message is obsolete.");
     }
   else if (type == XA_LOCK)
     {
@@ -1482,6 +1192,7 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p)
                            : "locking.");
          si->locked_p = True;
          si->selection_mode = 0;
+         si->demoing_p = False;
          sprintf (buf, "LOCK ClientMessage received; %s", response);
          clientmessage_response (si, window, False, buf, response);
 
@@ -1531,3 +1242,72 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p)
     }
   return False;
 }
+
+\f
+/* Some random diagnostics printed in -verbose mode.
+ */
+
+static void
+analyze_display (saver_info *si)
+{
+  int i, j;
+  static const char *exts[][2] = {
+    { "SCREEN_SAVER",     "SGI Screen-Saver" },
+    { "SCREEN-SAVER",     "SGI Screen-Saver" },
+    { "MIT-SCREEN-SAVER",  "MIT Screen-Saver" },
+    { "XIDLE",            "XIdle" },
+    { "SGI-VIDEO-CONTROL", "SGI Video-Control" },
+    { "READDISPLAY",      "SGI Read-Display" },
+    { "MIT-SHM",          "Shared Memory" },
+    { "DOUBLE-BUFFER",    "Double-Buffering" },
+    { "DPMS",             "Power Management" },
+    { "GLX",              "GLX" }
+  };
+
+  fprintf (stderr, "%s: running on display \"%s\"\n", blurb(),
+          DisplayString(si->dpy));
+  fprintf (stderr, "%s: vendor is %s, %d\n", blurb(),
+          ServerVendor(si->dpy), VendorRelease(si->dpy));
+
+  fprintf (stderr, "%s: useful extensions:\n", blurb());
+  for (i = 0; i < countof(exts); i++)
+    {
+      int op = 0, event = 0, error = 0;
+      if (XQueryExtension (si->dpy, exts[i][0], &op, &event, &error))
+       fprintf (stderr, "%s:   %s\n", blurb(), exts[i][1]);
+    }
+
+  for (i = 0; i < si->nscreens; i++)
+    {
+      unsigned long colormapped_depths = 0;
+      unsigned long non_mapped_depths = 0;
+      XVisualInfo vi_in, *vi_out;
+      int out_count;
+      vi_in.screen = i;
+      vi_out = XGetVisualInfo (si->dpy, VisualScreenMask, &vi_in, &out_count);
+      if (!vi_out) continue;
+      for (j = 0; j < out_count; j++)
+       if (vi_out[j].class == PseudoColor)
+         colormapped_depths |= (1 << vi_out[j].depth);
+       else
+         non_mapped_depths  |= (1 << vi_out[j].depth);
+      XFree ((char *) vi_out);
+
+      if (colormapped_depths)
+       {
+         fprintf (stderr, "%s: screen %d colormapped depths:", blurb(), i);
+         for (j = 0; j < 32; j++)
+           if (colormapped_depths & (1 << j))
+             fprintf (stderr, " %d", j);
+         fprintf (stderr, "\n");
+       }
+      if (non_mapped_depths)
+       {
+         fprintf (stderr, "%s: screen %d non-mapped depths:", blurb(), i);
+         for (j = 0; j < 32; j++)
+           if (non_mapped_depths & (1 << j))
+             fprintf (stderr, " %d", j);
+         fprintf (stderr, "\n");
+       }
+    }
+}