http://www.jwz.org/xscreensaver/xscreensaver-5.13.tar.gz
[xscreensaver] / driver / prefs.c
index 71ed252aa5741793d25d6a46126366f74429b6b2..857139350ae4e2687d87d7e4c27a479cb87f6db8 100644 (file)
@@ -1,5 +1,5 @@
 /* dotfile.c --- management of the ~/.xscreensaver file.
- * xscreensaver, Copyright (c) 1998 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1998-2011 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
 #include <stdio.h>
 #include <ctype.h>
 #include <string.h>
+#include <time.h>
 #include <sys/stat.h>
 #include <sys/time.h>
+#include <sys/param.h>   /* for PATH_MAX */
 
 #include <X11/Xlib.h>
 #include <X11/Xresource.h>
 #include "prefs.h"
 #include "resources.h"
 
+/* don't use realpath() on fedora system */
+#ifdef _FORTIFY_SOURCE
+#undef HAVE_REALPATH
+#endif
+
 
 extern char *progname;
 extern char *progclass;
@@ -72,10 +79,12 @@ extern const char *blurb (void);
 
 
 
-static void get_screenhacks (saver_preferences *p);
+static void get_screenhacks (Display *, saver_preferences *);
 static char *format_command (const char *cmd, Bool wrap_p);
-static void merge_system_screenhacks (saver_preferences *p,
+static void merge_system_screenhacks (Display *, saver_preferences *,
                                       screenhack **system_list, int count);
+static void stop_the_insanity (saver_preferences *p);
+
 
 static char *
 chase_symlinks (const char *file)
@@ -83,12 +92,19 @@ chase_symlinks (const char *file)
 # ifdef HAVE_REALPATH
   if (file)
     {
-      char buf [2048];
+# ifndef PATH_MAX
+#  ifdef MAXPATHLEN
+#   define PATH_MAX MAXPATHLEN
+#  else
+#   define PATH_MAX 2048
+#  endif
+# endif
+      char buf[PATH_MAX];
       if (realpath (file, buf))
         return strdup (buf);
 
-      sprintf (buf, "%s: realpath", blurb());
-      perror(buf);
+/*      sprintf (buf, "%.100s: realpath %.200s", blurb(), file);
+      perror(buf);*/
     }
 # endif /* HAVE_REALPATH */
   return 0;
@@ -192,12 +208,47 @@ init_file_tmp_name (void)
     return 0;
 }
 
+static int
+get_byte_resource (Display *dpy, char *name, char *class)
+{
+  char *s = get_string_resource (dpy, name, class);
+  char *s2 = s;
+  int n = 0;
+  if (!s) return 0;
+
+  while (isspace(*s2)) s2++;
+  while (*s2 >= '0' && *s2 <= '9')
+    {
+      n = (n * 10) + (*s2 - '0');
+      s2++;
+    }
+  while (isspace(*s2)) s2++;
+  if      (*s2 == 'k' || *s2 == 'K') n <<= 10;
+  else if (*s2 == 'm' || *s2 == 'M') n <<= 20;
+  else if (*s2 == 'g' || *s2 == 'G') n <<= 30;
+  else if (*s2)
+    {
+    LOSE:
+      fprintf (stderr, "%s: %s must be a number of bytes, not \"%s\".\n",
+               progname, name, s);
+      free (s);
+      return 0;
+    }
+  s2++;
+  if (*s2 == 'b' || *s2 == 'B') s2++;
+  while (isspace(*s2)) s2++;
+  if (*s2) goto LOSE;
+
+  free (s);
+  return n;
+}
+
 
 static const char * const prefs[] = {
   "timeout",
   "cycle",
   "lock",
-  "lockVTs",
+  "lockVTs",                   /* not saved */
   "lockTimeout",
   "passwdTimeout",
   "visualID",
@@ -206,32 +257,52 @@ static const char * const prefs[] = {
   "timestamp",
   "splash",
   "splashDuration",
+  "quad",
   "demoCommand",
   "prefsCommand",
-  "helpURL",
-  "loadURL",
+  "newLoginCommand",
+  "helpURL",                   /* not saved */
+  "loadURL",                   /* not saved */
+  "newLoginCommand",           /* not saved */
   "nice",
+  "memoryLimit",
   "fade",
   "unfade",
   "fadeSeconds",
   "fadeTicks",
   "captureStderr",
   "captureStdout",             /* not saved -- obsolete */
+  "logFile",                   /* not saved */
+  "ignoreUninstalledPrograms",
   "font",
   "dpmsEnabled",
   "dpmsStandby",
   "dpmsSuspend",
   "dpmsOff",
+  "grabDesktopImages",
+  "grabVideoFrames",
+  "chooseRandomImages",
+  "imageDirectory",
+  "mode",
+  "selected",
+  "textMode",
+  "textLiteral",
+  "textFile",
+  "textProgram",
+  "textURL",
   "",
   "programs",
   "",
   "pointerPollTime",
+  "pointerHysteresis",
   "windowCreationTimeout",
   "initialDelay",
-  "sgiSaverExtension",
-  "mitSaverExtension",
-  "xidleExtension",
+  "sgiSaverExtension",         /* not saved -- obsolete */
+  "mitSaverExtension",         /* not saved -- obsolete */
+  "xidleExtension",            /* not saved -- obsolete */
+  "GetViewPortIsFullOfLies",
   "procInterrupts",
+  "xinputExtensionDev",
   "overlayStderr",
   "overlayTextBackground",     /* not saved -- X resources only */
   "overlayTextForeground",     /* not saved -- X resources only */
@@ -495,6 +566,9 @@ write_entry (FILE *out, const char *key, const char *value)
   fprintf(out, "%s:", key);
   col = strlen(key) + 1;
 
+  if (strlen(key) > 14)
+    col = tab_to (out, col, 20);
+
   while (1)
     {
       if (!programs_p)
@@ -566,7 +640,8 @@ write_entry (FILE *out, const char *key, const char *value)
 }
 
 int
-write_init_file (saver_preferences *p, const char *version_string,
+write_init_file (Display *dpy,
+                 saver_preferences *p, const char *version_string,
                  Bool verbose_p)
 {
   int status = -1;
@@ -588,6 +663,11 @@ write_init_file (saver_preferences *p, const char *version_string,
 
   if (n2) name = n2;
 
+  /* Throttle the various timeouts to reasonable values before writing
+     the file to disk. */
+  stop_the_insanity (p);
+
+
   if (verbose_p)
     fprintf (stderr, "%s: writing \"%s\".\n", blurb(), name);
 
@@ -629,10 +709,10 @@ write_init_file (saver_preferences *p, const char *version_string,
     }
 
   /* Kludge, since these aren't in the saver_preferences struct... */
-  visual_name = get_string_resource ("visualID", "VisualID");
+  visual_name = get_string_resource (dpy, "visualID", "VisualID");
   programs = 0;
-  overlay_stderr_p = get_boolean_resource ("overlayStderr", "Boolean");
-  stderr_font = get_string_resource ("font", "Font");
+  overlay_stderr_p = get_boolean_resource (dpy, "overlayStderr", "Boolean");
+  stderr_font = get_string_resource (dpy, "font", "Font");
 
   i = 0;
   {
@@ -642,7 +722,7 @@ write_init_file (saver_preferences *p, const char *version_string,
 
     for (j = 0; j < p->screenhacks_count; j++)
       {
-        hack_strings[j] = format_hack (p->screenhacks[j], True);
+        hack_strings[j] = format_hack (dpy, p->screenhacks[j], True);
         i += strlen (hack_strings[j]);
         i += 2;
       }
@@ -657,6 +737,7 @@ write_init_file (saver_preferences *p, const char *version_string,
        *ss++ = '\n';
        *ss = 0;
       }
+    free (hack_strings);
   }
 
   {
@@ -680,7 +761,7 @@ write_init_file (saver_preferences *p, const char *version_string,
     {
       char buf[255];
       const char *pr = prefs[j];
-      enum pref_type { pref_str, pref_int, pref_bool, pref_time
+      enum pref_type { pref_str, pref_int, pref_bool, pref_byte, pref_time
       } type = pref_str;
       const char *s = 0;
       int i = 0;
@@ -699,11 +780,7 @@ write_init_file (saver_preferences *p, const char *version_string,
       CHECK("timeout")         type = pref_time, t = p->timeout;
       CHECK("cycle")           type = pref_time, t = p->cycle;
       CHECK("lock")            type = pref_bool, b = p->lock_p;
-# if 0 /* #### not ready yet */
-      CHECK("lockVTs")         type = pref_bool, b = p->lock_vt_p;
-# else
-      CHECK("lockVTs")         continue;  /* don't save */
-# endif
+      CHECK("lockVTs")         continue;  /* don't save, unused */
       CHECK("lockTimeout")     type = pref_time, t = p->lock_timeout;
       CHECK("passwdTimeout")   type = pref_time, t = p->passwd_timeout;
       CHECK("visualID")                type = pref_str,  s =    visual_name;
@@ -712,34 +789,79 @@ write_init_file (saver_preferences *p, const char *version_string,
       CHECK("timestamp")       type = pref_bool, b = p->timestamp_p;
       CHECK("splash")          type = pref_bool, b = p->splash_p;
       CHECK("splashDuration")  type = pref_time, t = p->splash_duration;
+# ifdef QUAD_MODE
+      CHECK("quad")            type = pref_bool, b = p->quad_p;
+# else  /* !QUAD_MODE */
+      CHECK("quad")            continue;  /* don't save */
+# endif /* !QUAD_MODE */
       CHECK("demoCommand")     type = pref_str,  s = p->demo_command;
       CHECK("prefsCommand")    type = pref_str,  s = p->prefs_command;
-      CHECK("helpURL")         type = pref_str,  s = p->help_url;
-      CHECK("loadURL")         type = pref_str,  s = p->load_url_command;
+/*    CHECK("helpURL")         type = pref_str,  s = p->help_url; */
+      CHECK("helpURL")         continue;  /* don't save */
+/*    CHECK("loadURL")         type = pref_str,  s = p->load_url_command; */
+      CHECK("loadURL")         continue;  /* don't save */
+/*    CHECK("newLoginCommand") type = pref_str,  s = p->new_login_command; */
+      CHECK("newLoginCommand") continue;  /* don't save */
       CHECK("nice")            type = pref_int,  i = p->nice_inferior;
+      CHECK("memoryLimit")     type = pref_byte, i = p->inferior_memory_limit;
       CHECK("fade")            type = pref_bool, b = p->fade_p;
       CHECK("unfade")          type = pref_bool, b = p->unfade_p;
       CHECK("fadeSeconds")     type = pref_time, t = p->fade_seconds;
       CHECK("fadeTicks")       type = pref_int,  i = p->fade_ticks;
       CHECK("captureStderr")   type = pref_bool, b = p->capture_stderr_p;
       CHECK("captureStdout")   continue;  /* don't save */
+      CHECK("logFile")         continue;  /* don't save */
+      CHECK("ignoreUninstalledPrograms")
+                                type = pref_bool, b = p->ignore_uninstalled_p;
+
       CHECK("font")            type = pref_str,  s =    stderr_font;
+
       CHECK("dpmsEnabled")     type = pref_bool, b = p->dpms_enabled_p;
       CHECK("dpmsStandby")     type = pref_time, t = p->dpms_standby;
       CHECK("dpmsSuspend")     type = pref_time, t = p->dpms_suspend;
       CHECK("dpmsOff")         type = pref_time, t = p->dpms_off;
+
+      CHECK("grabDesktopImages") type =pref_bool, b = p->grab_desktop_p;
+      CHECK("grabVideoFrames")   type =pref_bool, b = p->grab_video_p;
+      CHECK("chooseRandomImages")type =pref_bool, b = p->random_image_p;
+      CHECK("imageDirectory")    type =pref_str,  s = p->image_directory;
+
+      CHECK("mode")             type = pref_str,
+                                s = (p->mode == ONE_HACK ? "one" :
+                                     p->mode == BLANK_ONLY ? "blank" :
+                                     p->mode == DONT_BLANK ? "off" :
+                                     p->mode == RANDOM_HACKS_SAME
+                                     ? "random-same"
+                                     : "random");
+      CHECK("selected")         type = pref_int,  i = p->selected_hack;
+
+      CHECK("textMode")         type = pref_str,
+                                s = (p->tmode == TEXT_URL     ? "url" :
+                                     p->tmode == TEXT_LITERAL ? "literal" :
+                                     p->tmode == TEXT_FILE    ? "file" :
+                                     p->tmode == TEXT_PROGRAM ? "program" :
+                                     "date");
+      CHECK("textLiteral")      type = pref_str,  s = p->text_literal;
+      CHECK("textFile")         type = pref_str,  s = p->text_file;
+      CHECK("textProgram")      type = pref_str,  s = p->text_program;
+      CHECK("textURL")          type = pref_str,  s = p->text_url;
+
       CHECK("programs")                type = pref_str,  s =    programs;
       CHECK("pointerPollTime") type = pref_time, t = p->pointer_timeout;
+      CHECK("pointerHysteresis")type = pref_int,  i = p->pointer_hysteresis;
       CHECK("windowCreationTimeout")type=pref_time,t= p->notice_events_timeout;
       CHECK("initialDelay")    type = pref_time, t = p->initial_delay;
-      CHECK("sgiSaverExtension")type = pref_bool, b=p->use_sgi_saver_extension;
-      CHECK("mitSaverExtension")type = pref_bool, b=p->use_mit_saver_extension;
-      CHECK("xidleExtension")  type = pref_bool, b = p->use_xidle_extension;
+      CHECK("sgiSaverExtension") continue;  /* don't save */
+      CHECK("mitSaverExtension") continue;  /* don't save */
+      CHECK("xidleExtension")   continue;  /* don't save */
       CHECK("procInterrupts")  type = pref_bool, b = p->use_proc_interrupts;
+      CHECK("xinputExtensionDev") type = pref_bool, b = p->use_xinput_extension;
+      CHECK("GetViewPortIsFullOfLies")  type = pref_bool,
+                                       b = p->getviewport_full_of_lies_p;
       CHECK("overlayStderr")   type = pref_bool, b = overlay_stderr_p;
       CHECK("overlayTextBackground") continue;  /* don't save */
       CHECK("overlayTextForeground") continue;  /* don't save */
-      CHECK("bourneShell")     continue;
+      CHECK("bourneShell")          continue;  /* don't save */
       else                     abort();
 # undef CHECK
 
@@ -771,10 +893,27 @@ write_init_file (saver_preferences *p, const char *version_string,
            s = buf;
          }
          break;
+       case pref_byte:
+         {
+            if      (i >= (1<<30) && i == ((i >> 30) << 30))
+              sprintf(buf, "%dG", i >> 30);
+            else if (i >= (1<<20) && i == ((i >> 20) << 20))
+              sprintf(buf, "%dM", i >> 20);
+            else if (i >= (1<<10) && i == ((i >> 10) << 10))
+              sprintf(buf, "%dK", i >> 10);
+            else
+              sprintf(buf, "%d", i);
+            s = buf;
+          }
+         break;
        default:
          abort();
          break;
        }
+
+      if (pr && (!strcmp(pr, "mode") || !strcmp(pr, "textMode")))
+        fprintf(out, "\n");
+
       write_entry (out, pr, s);
     }
 
@@ -864,6 +1003,7 @@ free_screenhack_list (screenhack **list, int count)
 }
 
 
+
 /* 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.
@@ -872,7 +1012,7 @@ free_screenhack_list (screenhack **list, int count)
    and so on.
  */
 void
-load_init_file (saver_preferences *p)
+load_init_file (Display *dpy, saver_preferences *p)
 {
   static Bool first_time = True;
   
@@ -887,7 +1027,7 @@ load_init_file (saver_preferences *p)
          Then clear it out so that it will be parsed again later, after
          the init file has been read.
        */
-      get_screenhacks (p);
+      get_screenhacks (dpy, p);
       system_default_screenhacks = p->screenhacks;
       system_default_screenhack_count = p->screenhacks_count;
       p->screenhacks = 0;
@@ -899,87 +1039,142 @@ load_init_file (saver_preferences *p)
 
   first_time = False;
 
-  p->xsync_p       = get_boolean_resource ("synchronous", "Synchronous");
-  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->splash_p       = get_boolean_resource ("splash", "Boolean");
-  p->capture_stderr_p = get_boolean_resource ("captureStderr", "Boolean");
-
-  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",
+  p->xsync_p       = get_boolean_resource (dpy, "synchronous", "Synchronous");
+  p->verbose_p     = get_boolean_resource (dpy, "verbose", "Boolean");
+  p->timestamp_p    = get_boolean_resource (dpy, "timestamp", "Boolean");
+  p->lock_p        = get_boolean_resource (dpy, "lock", "Boolean");
+  p->fade_p        = get_boolean_resource (dpy, "fade", "Boolean");
+  p->unfade_p      = get_boolean_resource (dpy, "unfade", "Boolean");
+  p->fade_seconds   = 1000 * get_seconds_resource (dpy, "fadeSeconds", "Time");
+  p->fade_ticks            = get_integer_resource (dpy, "fadeTicks", "Integer");
+  p->install_cmap_p = get_boolean_resource (dpy, "installColormap", "Boolean");
+  p->nice_inferior  = get_integer_resource (dpy, "nice", "Nice");
+  p->inferior_memory_limit = get_byte_resource (dpy, "memoryLimit",
+                                                "MemoryLimit");
+  p->splash_p       = get_boolean_resource (dpy, "splash", "Boolean");
+# ifdef QUAD_MODE
+  p->quad_p         = get_boolean_resource (dpy, "quad", "Boolean");
+# endif
+  p->capture_stderr_p = get_boolean_resource (dpy, "captureStderr", "Boolean");
+  p->ignore_uninstalled_p = get_boolean_resource (dpy, 
+                                                  "ignoreUninstalledPrograms",
+                                                  "Boolean");
+
+  p->initial_delay   = 1000 * get_seconds_resource (dpy, "initialDelay", "Time");
+  p->splash_duration = 1000 * get_seconds_resource (dpy, "splashDuration", "Time");
+  p->timeout         = 1000 * get_minutes_resource (dpy, "timeout", "Time");
+  p->lock_timeout    = 1000 * get_minutes_resource (dpy, "lockTimeout", "Time");
+  p->cycle           = 1000 * get_minutes_resource (dpy, "cycle", "Time");
+  p->passwd_timeout  = 1000 * get_seconds_resource (dpy, "passwdTimeout", "Time");
+  p->pointer_timeout = 1000 * get_seconds_resource (dpy, "pointerPollTime", "Time");
+  p->pointer_hysteresis = get_integer_resource (dpy, "pointerHysteresis","Integer");
+  p->notice_events_timeout = 1000*get_seconds_resource(dpy,
+                                                       "windowCreationTimeout",
                                                       "Time");
 
-  p->dpms_enabled_p  = get_boolean_resource ("dpmsEnabled", "Boolean");
-  p->dpms_standby    = 1000 * get_seconds_resource ("dpmsStandby", "Time");
-  p->dpms_suspend    = 1000 * get_seconds_resource ("dpmsSuspend", "Time");
-  p->dpms_off        = 1000 * get_seconds_resource ("dpmsOff",     "Time");
-
-  p->shell = get_string_resource ("bourneShell", "BourneShell");
-
-  p->demo_command = get_string_resource("demoCommand", "URL");
-  p->prefs_command = get_string_resource("prefsCommand", "URL");
-  p->help_url = get_string_resource("helpURL", "URL");
-  p->load_url_command = get_string_resource("loadURL", "LoadURL");
-
+  p->dpms_enabled_p  = get_boolean_resource (dpy, "dpmsEnabled", "Boolean");
+  p->dpms_standby    = 1000 * get_minutes_resource (dpy, "dpmsStandby", "Time");
+  p->dpms_suspend    = 1000 * get_minutes_resource (dpy, "dpmsSuspend", "Time");
+  p->dpms_off        = 1000 * get_minutes_resource (dpy, "dpmsOff",     "Time");
+
+  p->grab_desktop_p  = get_boolean_resource (dpy, "grabDesktopImages",  "Boolean");
+  p->grab_video_p    = get_boolean_resource (dpy, "grabVideoFrames",    "Boolean");
+  p->random_image_p  = get_boolean_resource (dpy, "chooseRandomImages", "Boolean");
+  p->image_directory = get_string_resource  (dpy,
+                                             "imageDirectory",
+                                             "ImageDirectory");
+
+  p->text_literal = get_string_resource (dpy, "textLiteral", "TextLiteral");
+  p->text_file    = get_string_resource (dpy, "textFile",    "TextFile");
+  p->text_program = get_string_resource (dpy, "textProgram", "TextProgram");
+  p->text_url     = get_string_resource (dpy, "textURL",     "TextURL");
+
+  p->shell = get_string_resource (dpy, "bourneShell", "BourneShell");
+
+  p->demo_command = get_string_resource(dpy, "demoCommand", "URL");
+  p->prefs_command = get_string_resource(dpy, "prefsCommand", "URL");
+  p->help_url = get_string_resource(dpy, "helpURL", "URL");
+  p->load_url_command = get_string_resource(dpy, "loadURL", "LoadURL");
+  p->new_login_command = get_string_resource(dpy,
+                                             "newLoginCommand",
+                                             "NewLoginCommand");
 
   /* If "*splash" is unset, default to true. */
   {
-    char *s = get_string_resource ("splash", "Boolean");
+    char *s = get_string_resource (dpy, "splash", "Boolean");
     if (s)
       free (s);
     else
       p->splash_p = True;
   }
 
-  p->use_xidle_extension = get_boolean_resource ("xidleExtension","Boolean");
-  p->use_mit_saver_extension = get_boolean_resource ("mitSaverExtension",
+  /* If "*grabDesktopImages" is unset, default to true. */
+  {
+    char *s = get_string_resource (dpy, "grabDesktopImages", "Boolean");
+    if (s)
+      free (s);
+    else
+      p->grab_desktop_p = True;
+  }
+
+  p->use_xidle_extension = get_boolean_resource (dpy, "xidleExtension","Boolean");
+#if 0 /* obsolete. */
+  p->use_sgi_saver_extension = get_boolean_resource (dpy,
+                                                     "sgiSaverExtension",
                                                     "Boolean");
-  p->use_sgi_saver_extension = get_boolean_resource ("sgiSaverExtension",
+#endif
+#if 0 /* obsolete. */
+  p->use_xinput_extension = get_boolean_resource (dpy, "xinputExtensionDev",
+                                                  "Boolean");
+#endif
+#if 0 /* broken and evil. */
+  p->use_mit_saver_extension = get_boolean_resource (dpy, 
+                                                     "mitSaverExtension",
                                                     "Boolean");
-  p->use_proc_interrupts = get_boolean_resource ("procInterrupts", "Boolean");
+#endif
 
-  /* 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->use_proc_interrupts = get_boolean_resource (dpy,
+                                                 "procInterrupts", "Boolean");
 
-  if (p->dpms_standby <= 0 || p->dpms_suspend <= 0 || p->dpms_off <= 0)
-    p->dpms_enabled_p = False;
+  p->getviewport_full_of_lies_p =
+    get_boolean_resource (dpy, "GetViewPortIsFullOfLies", "Boolean");
 
-  if (p->dpms_standby <= 10000) p->dpms_standby = 10000;        /* 10 secs */
-  if (p->dpms_suspend <= 10000) p->dpms_suspend = 10000;        /* 10 secs */
-  if (p->dpms_off     <= 10000) p->dpms_off     = 10000;        /* 10 secs */
+  get_screenhacks (dpy, p);             /* Parse the "programs" resource. */
 
-  p->watchdog_timeout = p->cycle * 0.6;
-  if (p->watchdog_timeout < 30000) p->watchdog_timeout = 30000;          /* 30 secs */
-  if (p->watchdog_timeout > 3600000) p->watchdog_timeout = 3600000; /*  1 hr */
+  {
+    char *s = get_string_resource (dpy, "selected", "Integer");
+    if (!s || !*s)
+      p->selected_hack = -1;
+    else
+      p->selected_hack = get_integer_resource (dpy, "selected", "Integer");
+    if (s) free (s);
+    if (p->selected_hack < 0 || p->selected_hack >= p->screenhacks_count)
+      p->selected_hack = -1;
+  }
 
-  get_screenhacks (p);
+  {
+    char *s = get_string_resource (dpy, "mode", "Mode");
+    if      (s && !strcasecmp (s, "one"))         p->mode = ONE_HACK;
+    else if (s && !strcasecmp (s, "blank"))       p->mode = BLANK_ONLY;
+    else if (s && !strcasecmp (s, "off"))         p->mode = DONT_BLANK;
+    else if (s && !strcasecmp (s, "random-same")) p->mode = RANDOM_HACKS_SAME;
+    else                                          p->mode = RANDOM_HACKS;
+    if (s) free (s);
+  }
+
+  {
+    char *s = get_string_resource (dpy, "textMode", "TextMode");
+    if      (s && !strcasecmp (s, "url"))         p->tmode = TEXT_URL;
+    else if (s && !strcasecmp (s, "literal"))     p->tmode = TEXT_LITERAL;
+    else if (s && !strcasecmp (s, "file"))        p->tmode = TEXT_FILE;
+    else if (s && !strcasecmp (s, "program"))     p->tmode = TEXT_PROGRAM;
+    else                                          p->tmode = TEXT_DATE;
+    if (s) free (s);
+  }
 
   if (system_default_screenhack_count)  /* note: first_time is also true */
     {
-      merge_system_screenhacks (p, system_default_screenhacks,
+      merge_system_screenhacks (dpy, p, system_default_screenhacks,
                                 system_default_screenhack_count);
       free_screenhack_list (system_default_screenhacks,
                             system_default_screenhack_count);
@@ -994,6 +1189,10 @@ load_init_file (saver_preferences *p)
       p->timestamp_p = True;
       p->initial_delay = 0;
     }
+
+  /* Throttle the various timeouts to reasonable values after reading the
+     disk file. */
+  stop_the_insanity (p);
 }
 
 
@@ -1002,7 +1201,7 @@ load_init_file (saver_preferences *p)
    This does *not* actually save the file.
  */
 static void
-merge_system_screenhacks (saver_preferences *p,
+merge_system_screenhacks (Display *dpy, saver_preferences *p,
                           screenhack **system_list, int system_count)
 {
   /* Yeah yeah, this is an N^2 operation, but I don't have hashtables handy,
@@ -1019,11 +1218,12 @@ merge_system_screenhacks (saver_preferences *p,
         {
           char *name;
           if (!system_list[i]->name)
-            system_list[i]->name = make_hack_name (system_list[i]->command);
+            system_list[i]->name = make_hack_name (dpy, 
+                                                   system_list[i]->command);
 
           name = p->screenhacks[j]->name;
           if (!name)
-            name = make_hack_name (p->screenhacks[j]->command);
+            name = make_hack_name (dpy, p->screenhacks[j]->command);
 
           matched_p = !strcasecmp (name, system_list[i]->name);
 
@@ -1049,7 +1249,7 @@ merge_system_screenhacks (saver_preferences *p,
               made_space = 10;
               p->screenhacks = (screenhack **)
                 realloc (p->screenhacks,
-                         (p->screenhacks_count + made_space
+                         (p->screenhacks_count + made_space + 1)
                          * sizeof(screenhack));
               if (!p->screenhacks) abort();
             }
@@ -1060,11 +1260,12 @@ merge_system_screenhacks (saver_preferences *p,
           nh->command   = oh->command ? strdup(oh->command) : 0;
 
           p->screenhacks[p->screenhacks_count++] = nh;
+          p->screenhacks[p->screenhacks_count] = 0;
           made_space--;
 
 #if 0
           fprintf (stderr, "%s: noticed new hack: %s\n", blurb(),
-                   (nh->name ? nh->name : make_hack_name (nh->command)));
+                   (nh->name ? nh->name : make_hack_name (dpy, nh->command)));
 #endif
         }
     }
@@ -1175,7 +1376,7 @@ format_command (const char *cmd, Bool wrap_p)
    by looking for "hacks.XYZ.name", where XYZ is the program.)
  */
 char *
-make_hack_name (const char *shell_command)
+make_hack_name (Display *dpy, const char *shell_command)
 {
   char *s = strdup (shell_command);
   char *s2;
@@ -1200,9 +1401,12 @@ make_hack_name (const char *shell_command)
     s[50] = 0;
 
   sprintf (res_name, "hacks.%s.name", s);              /* resource? */
-  s2 = get_string_resource (res_name, res_name);
+  s2 = get_string_resource (dpy, res_name, res_name);
   if (s2)
-    return s2;
+    {
+      free (s);
+      return s2;
+    }
 
   for (s2 = s; *s2; s2++)      /* if it has any capitals, return it */
     if (*s2 >= 'A' && *s2 <= 'Z')
@@ -1212,23 +1416,40 @@ make_hack_name (const char *shell_command)
     s[0] -= 'a'-'A';
   if (s[0] == 'X' && s[1] >= 'a' && s[1] <= 'z')       /* (magic leading X) */
     s[1] -= 'a'-'A';
+  if (s[0] == 'G' && s[1] == 'l' && 
+      s[2] >= 'a' && s[2] <= 'z')                     /* (magic leading GL) */
+    s[1] -= 'a'-'A',
+    s[2] -= 'a'-'A';
   return s;
 }
 
 
 char *
-format_hack (screenhack *hack, Bool wrap_p)
+format_hack (Display *dpy, screenhack *hack, Bool wrap_p)
 {
   int tab = 32;
-  int size = (2 * (strlen(hack->command) +
-                   (hack->visual ? strlen(hack->visual) : 0) +
-                   (hack->name ? strlen(hack->name) : 0) +
-                   tab));
-  char *h2 = (char *) malloc (size);
-  char *out = h2;
-  char *s;
+  int size;
+  char *h2, *out, *s;
   int col = 0;
 
+  char *def_name = make_hack_name (dpy, hack->command);
+
+  /* Don't ever write out a name for a hack if it's the same as the default.
+   */
+  if (hack->name && !strcmp (hack->name, def_name))
+    {
+      free (hack->name);
+      hack->name = 0;
+    }
+  free (def_name);
+
+  size = (2 * (strlen(hack->command) +
+               (hack->visual ? strlen(hack->visual) : 0) +
+               (hack->name ? strlen(hack->name) : 0) +
+               tab));
+  h2 = (char *) malloc (size);
+  out = h2;
+
   if (!hack->enabled_p) *out++ = '-';          /* write disabled flag */
 
   if (hack->visual && *hack->visual)           /* write visual name */
@@ -1259,10 +1480,7 @@ format_hack (screenhack *hack, Bool wrap_p)
 
       col = string_columns (h2, strlen (h2), 0);
       if (wrap_p && col >= tab)
-        {
-          out = stab_to (out, col, 77);
-          *out += strlen(out);
-        }
+        out = stab_to (out, col, 77);
       else
         *out++ = ' ';
 
@@ -1285,18 +1503,18 @@ format_hack (screenhack *hack, Bool wrap_p)
 
 
 static void
-get_screenhacks (saver_preferences *p)
+get_screenhacks (Display *dpy, saver_preferences *p)
 {
-  int i = 0;
+  int i, j;
   int start = 0;
   int end = 0;
   int size;
   char *d;
 
-  d = get_string_resource ("monoPrograms", "MonoPrograms");
+  d = get_string_resource (dpy, "monoPrograms", "MonoPrograms");
   if (d && !*d) { free(d); d = 0; }
   if (!d)
-    d = get_string_resource ("colorPrograms", "ColorPrograms");
+    d = get_string_resource (dpy, "colorPrograms", "ColorPrograms");
   if (d && !*d) { free(d); d = 0; }
 
   if (d)
@@ -1307,7 +1525,7 @@ get_screenhacks (saver_preferences *p)
       free(d);
     }
 
-  d = get_string_resource ("programs", "Programs");
+  d = get_string_resource (dpy, "programs", "Programs");
 
   free_screenhack_list (p->screenhacks, p->screenhacks_count);
   p->screenhacks = 0;
@@ -1320,15 +1538,14 @@ get_screenhacks (saver_preferences *p)
 
 
   /* Count up the number of newlines (which will be equal to or larger than
-     the number of hacks.)
+     one less than the number of hacks.)
    */
-  i = 0;
-  for (i = 0; d[i]; i++)
+  for (i = j = 0; d[i]; i++)
     if (d[i] == '\n')
-      i++;
-  i++;
+      j++;
+  j++;
 
-  p->screenhacks = (screenhack **) calloc (sizeof (screenhack *), i+1);
+  p->screenhacks = (screenhack **) calloc (j + 1, sizeof (screenhack *));
 
   /* Iterate over the lines in `d' (the string with newlines)
      and make new strings to stuff into the `screenhacks' array.
@@ -1355,9 +1572,76 @@ get_screenhacks (saver_preferences *p)
       start = end+1;
     }
 
+  free (d);
+
   if (p->screenhacks_count == 0)
     {
       free (p->screenhacks);
       p->screenhacks = 0;
     }
 }
+
+
+/* Make sure all the values in the preferences struct are sane.
+ */
+static void
+stop_the_insanity (saver_preferences *p)
+{
+  if (p->passwd_timeout <= 0) p->passwd_timeout = 30000;        /* 30 secs */
+  if (p->timeout < 15000) p->timeout = 15000;                   /* 15 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;
+
+  /* The DPMS settings may have the value 0.
+     But if they are negative, or are a range less than 10 seconds,
+     reset them to sensible defaults.  (Since that must be a mistake.)
+   */
+  if (p->dpms_standby != 0 &&
+      p->dpms_standby < 10 * 1000)
+    p->dpms_standby =  2 * 60 * 60 * 1000;                      /* 2 hours */
+  if (p->dpms_suspend != 0 &&
+      p->dpms_suspend < 10 * 1000)
+    p->dpms_suspend =  2 * 60 * 60 * 1000;                      /* 2 hours */
+  if (p->dpms_off != 0 &&
+      p->dpms_off < 10 * 1000)
+    p->dpms_off      = 4 * 60 * 60 * 1000;                      /* 4 hours */
+
+  /* suspend may not be greater than off, unless off is 0.
+     standby may not be greater than suspend, unless suspend is 0.
+   */
+  if (p->dpms_off != 0 &&
+      p->dpms_suspend > p->dpms_off)
+    p->dpms_suspend = p->dpms_off;
+  if (p->dpms_suspend != 0 &&
+      p->dpms_standby > p->dpms_suspend)
+    p->dpms_standby = p->dpms_suspend;
+
+  /* These fixes above ignores the case
+     suspend = 0 and standby > off ...
+   */
+  if (p->dpms_off != 0 &&
+      p->dpms_standby > p->dpms_off)
+    p->dpms_standby = p->dpms_off;
+
+
+  if (p->dpms_standby == 0 &&     /* if *all* are 0, then DPMS is disabled */
+      p->dpms_suspend == 0 &&
+      p->dpms_off     == 0)
+    p->dpms_enabled_p = False;
+
+
+  /* Set watchdog timeout to about half of the cycle timeout, but
+     don't let it be faster than 1/2 minute or slower than 1 minute.
+   */
+  p->watchdog_timeout = p->cycle * 0.6;
+  if (p->watchdog_timeout < 27000) p->watchdog_timeout = 27000;          /* 27 secs */
+  if (p->watchdog_timeout > 57000) p->watchdog_timeout = 57000;   /* 57 secs */
+
+  if (p->pointer_hysteresis < 0)   p->pointer_hysteresis = 0;
+  if (p->pointer_hysteresis > 100) p->pointer_hysteresis = 100;
+}