From http://www.jwz.org/xscreensaver/xscreensaver-5.35.tar.gz
[xscreensaver] / driver / demo-Gtk.c
index 61e9aa284c41a5e74bc84df4e466e147c819009e..f5c483965a3a8ead6947abc473d9ea4a823f1c29 100644 (file)
@@ -1,5 +1,5 @@
 /* demo-Gtk.c --- implements the interactive demo-mode and options dialogs.
- * xscreensaver, Copyright (c) 1993-2006 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1993-2016 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 "logo-50.xpm"
 #include "logo-180.xpm"
 
-#undef dgettext  /* else these are defined twice... */
-#undef dcgettext
-
-#include "demo-Gtk-widgets.h"
-#include "demo-Gtk-support.h"
 #include "demo-Gtk-conf.h"
 
 #include <stdio.h>
@@ -142,6 +137,41 @@ enum {
 };
 #endif /* HAVE_GTK2 */
 
+/* Deal with deprecation of direct access to struct fields on the way to GTK3
+   See http://live.gnome.org/GnomeGoals/UseGseal
+ */
+#if GTK_CHECK_VERSION(2,14,0)
+# define GET_PARENT(w)          gtk_widget_get_parent (w)
+# define GET_WINDOW(w)          gtk_widget_get_window (w)
+# define GET_ACTION_AREA(d)     gtk_dialog_get_action_area (d)
+# define GET_CONTENT_AREA(d)    gtk_dialog_get_content_area (d)
+# define GET_ADJ_VALUE(a)       gtk_adjustment_get_value (a)
+# define SET_ADJ_VALUE(a,v)     gtk_adjustment_set_value (a, v)
+# define SET_ADJ_UPPER(a,v)     gtk_adjustment_set_upper (a, v)
+#else
+# define GET_PARENT(w)          ((w)->parent)
+# define GET_WINDOW(w)          ((w)->window)
+# define GET_ACTION_AREA(d)     ((d)->action_area)
+# define GET_CONTENT_AREA(d)    ((d)->vbox)
+# define GET_ADJ_VALUE(a)       ((a)->value)
+# define SET_ADJ_VALUE(a,v)     (a)->value = v
+# define SET_ADJ_UPPER(a,v)     (a)->upper = v
+#endif
+
+#if GTK_CHECK_VERSION(2,18,0)
+# define SET_CAN_DEFAULT(w)     gtk_widget_set_can_default ((w), TRUE)
+# define GET_SENSITIVE(w)       gtk_widget_get_sensitive (w)
+#else
+# define SET_CAN_DEFAULT(w)     GTK_WIDGET_SET_FLAGS ((w), GTK_CAN_DEFAULT)
+# define GET_SENSITIVE(w)       GTK_WIDGET_IS_SENSITIVE (w)
+#endif
+
+#if GTK_CHECK_VERSION(2,20,0)
+# define GET_REALIZED(w)        gtk_widget_get_realized (w)
+#else
+# define GET_REALIZED(w)        GTK_WIDGET_REALIZED (w)
+#endif
+
 /* from exec.c */
 extern void exec_command (const char *shell, const char *command, int nice);
 extern int on_path_p (const char *program);
@@ -152,6 +182,13 @@ static void hack_subproc_environment (Window preview_window_id, Bool debug_p);
 #define countof(x) (sizeof((x))/sizeof((*x)))
 
 
+/* You might think that to read an array of 32-bit quantities out of a
+   server-side property, you would pass an array of 32-bit data quantities
+   into XGetWindowProperty().  You would be wrong.  You have to use an array
+   of longs, even if long is 64 bits (using 32 of each 64.)
+ */
+typedef long PROP32;
+
 char *progname = 0;
 char *progclass = "XScreenSaver";
 XrmDatabase db;
@@ -233,11 +270,48 @@ static void schedule_preview (state *, const char *cmd);
 static void kill_preview_subproc (state *, Bool reset_p);
 static void schedule_preview_check (state *);
 
+\f
+/* Prototypes of functions used by the Glade-generated code,
+   to avoid warnings.
+ */
+void exit_menu_cb (GtkMenuItem *, gpointer user_data);
+void about_menu_cb (GtkMenuItem *, gpointer user_data);
+void doc_menu_cb (GtkMenuItem *, gpointer user_data);
+void file_menu_cb (GtkMenuItem *, gpointer user_data);
+void activate_menu_cb (GtkMenuItem *, gpointer user_data);
+void lock_menu_cb (GtkMenuItem *, gpointer user_data);
+void kill_menu_cb (GtkMenuItem *, gpointer user_data);
+void restart_menu_cb (GtkWidget *, gpointer user_data);
+void run_this_cb (GtkButton *, gpointer user_data);
+void manual_cb (GtkButton *, gpointer user_data);
+void run_next_cb (GtkButton *, gpointer user_data);
+void run_prev_cb (GtkButton *, gpointer user_data);
+void pref_changed_cb (GtkWidget *, gpointer user_data);
+gboolean pref_changed_event_cb (GtkWidget *, GdkEvent *, gpointer user_data);
+void mode_menu_item_cb (GtkWidget *, gpointer user_data);
+void switch_page_cb (GtkNotebook *, GtkNotebookPage *, 
+                     gint page_num, gpointer user_data);
+void browse_image_dir_cb (GtkButton *, gpointer user_data);
+void browse_text_file_cb (GtkButton *, gpointer user_data);
+void browse_text_program_cb (GtkButton *, gpointer user_data);
+void settings_cb (GtkButton *, gpointer user_data);
+void settings_adv_cb (GtkButton *, gpointer user_data);
+void settings_std_cb (GtkButton *, gpointer user_data);
+void settings_reset_cb (GtkButton *, gpointer user_data);
+void settings_switch_page_cb (GtkNotebook *, GtkNotebookPage *,
+                              gint page_num, gpointer user_data);
+void settings_cancel_cb (GtkButton *, gpointer user_data);
+void settings_ok_cb (GtkButton *, gpointer user_data);
+
+static void kill_gnome_screensaver (void);
+static void kill_kde_screensaver (void);
 
 \f
 /* Some random utility functions
  */
 
+const char *blurb (void);
+
 const char *
 blurb (void)
 {
@@ -383,9 +457,9 @@ ensure_selected_item_visible (GtkWidget *widget)
 
   adj = gtk_scrolled_window_get_vadjustment (scroller);
 
-  gdk_window_get_geometry (GTK_WIDGET(vp)->window,
+  gdk_window_get_geometry (GET_WINDOW (GTK_WIDGET (vp)),
                            &ignore, &ignore, &ignore, &parent_h, &ignore);
-  gdk_window_get_geometry (GTK_WIDGET(selected)->window,
+  gdk_window_get_geometry (GET_WINDOW (GTK_WIDGET (selected)),
                            &ignore, &child_y, &ignore, &child_h, &ignore);
   children_h = nkids * child_h;
 
@@ -428,8 +502,8 @@ static void
 warning_dialog_dismiss_cb (GtkWidget *widget, gpointer user_data)
 {
   GtkWidget *shell = GTK_WIDGET (user_data);
-  while (shell->parent)
-    shell = shell->parent;
+  while (GET_PARENT (shell))
+    shell = GET_PARENT (shell);
   gtk_widget_destroy (GTK_WIDGET (shell));
 }
 
@@ -442,9 +516,23 @@ static void warning_dialog_restart_cb (GtkWidget *widget, gpointer user_data)
   warning_dialog_dismiss_cb (widget, user_data);
 }
 
-static void
+static void warning_dialog_killg_cb (GtkWidget *widget, gpointer user_data)
+{
+  kill_gnome_screensaver ();
+  warning_dialog_dismiss_cb (widget, user_data);
+}
+
+static void warning_dialog_killk_cb (GtkWidget *widget, gpointer user_data)
+{
+  kill_kde_screensaver ();
+  warning_dialog_dismiss_cb (widget, user_data);
+}
+
+typedef enum { D_NONE, D_LAUNCH, D_GNOME, D_KDE } dialog_button;
+
+static Bool
 warning_dialog (GtkWidget *parent, const char *message,
-                Boolean restart_button_p, int center)
+                dialog_button button_type, int center)
 {
   char *msg = strdup (message);
   char *head;
@@ -455,14 +543,15 @@ warning_dialog (GtkWidget *parent, const char *message,
   GtkWidget *cancel = 0;
   int i = 0;
 
-  while (parent && !parent->window)
-    parent = parent->parent;
+  while (parent && !GET_WINDOW (parent))
+    parent = GET_PARENT (parent);
 
   if (!parent ||
-      !GTK_WIDGET (parent)->window) /* too early to pop up transient dialogs */
+      !GET_WINDOW (parent)) /* too early to pop up transient dialogs */
     {
       fprintf (stderr, "%s: too early for dialog?\n", progname);
-      return;
+      free(msg);
+      return False;
     }
 
   head = msg;
@@ -494,7 +583,7 @@ warning_dialog (GtkWidget *parent, const char *message,
 #endif /* !HAVE_GTK2 */
         if (center <= 0)
           gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-        gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
+        gtk_box_pack_start (GTK_BOX (GET_CONTENT_AREA (GTK_DIALOG (dialog))),
                             label, TRUE, TRUE, 0);
         gtk_widget_show (label);
       }
@@ -508,16 +597,16 @@ warning_dialog (GtkWidget *parent, const char *message,
     }
 
   label = gtk_label_new ("");
-  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
+  gtk_box_pack_start (GTK_BOX (GET_CONTENT_AREA (GTK_DIALOG (dialog))),
                       label, TRUE, TRUE, 0);
   gtk_widget_show (label);
 
   label = gtk_hbutton_box_new ();
-  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
+  gtk_box_pack_start (GTK_BOX (GET_ACTION_AREA (GTK_DIALOG (dialog))),
                       label, TRUE, TRUE, 0);
 
 #ifdef HAVE_GTK2
-  if (restart_button_p)
+  if (button_type != D_NONE)
     {
       cancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
       gtk_container_add (GTK_CONTAINER (label), cancel);
@@ -531,7 +620,7 @@ warning_dialog (GtkWidget *parent, const char *message,
   ok = gtk_button_new_with_label ("OK");
   gtk_container_add (GTK_CONTAINER (label), ok);
 
-  if (restart_button_p)
+  if (button_type != D_NONE)
     {
       cancel = gtk_button_new_with_label ("Cancel");
       gtk_container_add (GTK_CONTAINER (label), cancel);
@@ -542,22 +631,28 @@ warning_dialog (GtkWidget *parent, const char *message,
   gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
   gtk_container_set_border_width (GTK_CONTAINER (dialog), 10);
   gtk_window_set_title (GTK_WINDOW (dialog), progclass);
-  STFU GTK_WIDGET_SET_FLAGS (ok, GTK_CAN_DEFAULT);
+  SET_CAN_DEFAULT (ok);
   gtk_widget_show (ok);
   gtk_widget_grab_focus (ok);
 
   if (cancel)
     {
-      STFU GTK_WIDGET_SET_FLAGS (cancel, GTK_CAN_DEFAULT); 
+      SET_CAN_DEFAULT (cancel);
       gtk_widget_show (cancel);
     }
   gtk_widget_show (label);
   gtk_widget_show (dialog);
 
-  if (restart_button_p)
+  if (button_type != D_NONE)
     {
-      gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
-                                 GTK_SIGNAL_FUNC (warning_dialog_restart_cb),
+      GtkSignalFunc fn;
+      switch (button_type) {
+      case D_LAUNCH: fn = GTK_SIGNAL_FUNC (warning_dialog_restart_cb); break;
+      case D_GNOME:  fn = GTK_SIGNAL_FUNC (warning_dialog_killg_cb);   break;
+      case D_KDE:    fn = GTK_SIGNAL_FUNC (warning_dialog_killk_cb);   break;
+      default: abort(); break;
+      }
+      gtk_signal_connect_object (GTK_OBJECT (ok), "clicked", fn, 
                                  (gpointer) dialog);
       gtk_signal_connect_object (GTK_OBJECT (cancel), "clicked",
                                  GTK_SIGNAL_FUNC (warning_dialog_dismiss_cb),
@@ -570,8 +665,8 @@ warning_dialog (GtkWidget *parent, const char *message,
                                  (gpointer) dialog);
     }
 
-  gdk_window_set_transient_for (GTK_WIDGET (dialog)->window,
-                                GTK_WIDGET (parent)->window);
+  gdk_window_set_transient_for (GET_WINDOW (GTK_WIDGET (dialog)),
+                                GET_WINDOW (GTK_WIDGET (parent)));
 
 #ifdef HAVE_GTK2
   gtk_window_present (GTK_WINDOW (dialog));
@@ -581,6 +676,7 @@ warning_dialog (GtkWidget *parent, const char *message,
 #endif /* !HAVE_GTK2 */
 
   free (msg);
+  return True;
 }
 
 
@@ -604,7 +700,7 @@ run_cmd (state *s, Atom command, int arg)
         sprintf (buf, "Error:\n\n%s", err);
       else
         strcpy (buf, "Unknown error!");
-      warning_dialog (s->toplevel_widget, buf, False, 100);
+      warning_dialog (s->toplevel_widget, buf, D_NONE, 100);
     }
   if (err) free (err);
 
@@ -645,7 +741,7 @@ run_hack (state *s, int list_elt, Bool report_errors_p)
                 sprintf (buf, "Error:\n\n%s", err);
               else
                 strcpy (buf, "Unknown error!");
-              warning_dialog (s->toplevel_widget, buf, False, 100);
+              warning_dialog (s->toplevel_widget, buf, D_NONE, 100);
             }
         }
       else
@@ -660,7 +756,7 @@ run_hack (state *s, int list_elt, Bool report_errors_p)
                      "The XScreenSaver daemon doesn't seem to be running\n"
                      "on display \"%s\".  Launch it now?"),
                    d);
-          warning_dialog (s->toplevel_widget, msg, True, 1);
+          warning_dialog (s->toplevel_widget, msg, D_LAUNCH, 1);
         }
     }
 
@@ -702,23 +798,30 @@ about_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
 {
   char msg [2048];
   char *vers = strdup (screensaver_id + 4);
-  char *s;
+  char *s, *s2;
   char copy[1024];
-  char *desc = _("For updates, check http://www.jwz.org/xscreensaver/");
+  char year[5];
+  char *desc = _("For updates, check https://www.jwz.org/xscreensaver/");
 
   s = strchr (vers, ',');
   *s = 0;
   s += 2;
 
+  s2 = vers;
+  s2 = strrchr (vers, '-');
+  s2++;
+  strncpy (year, s2, 4);
+  year[4] = 0;
+
   /* Ole Laursen <olau@hardworking.dk> says "don't use _() here because
      non-ASCII characters aren't allowed in localizable string keys."
      (I don't want to just use (c) instead of © because that doesn't
      look as good in the plain-old default Latin1 "C" locale.)
    */
 #ifdef HAVE_GTK2
-  sprintf(copy, ("Copyright \xC2\xA9 1991-2005 %s"), s);
+  sprintf(copy, ("Copyright \xC2\xA9 1991-%s %s"), year, s);
 #else  /* !HAVE_GTK2 */
-  sprintf(copy, ("Copyright \251 1991-2005 %s"), s);
+  sprintf(copy, ("Copyright \251 1991-%s %s"), year, s);
 #endif /* !HAVE_GTK2 */
 
   sprintf (msg, "%s\n\n%s", copy, desc);
@@ -745,11 +848,11 @@ about_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
     GtkWidget *dialog = gtk_dialog_new ();
     GtkWidget *hbox, *icon, *vbox, *label1, *label2, *hb, *ok;
     GtkWidget *parent = GTK_WIDGET (menuitem);
-    while (parent->parent)
-      parent = parent->parent;
+    while (GET_PARENT (parent))
+      parent = GET_PARENT (parent);
 
     hbox = gtk_hbox_new (FALSE, 20);
-    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
+    gtk_box_pack_start (GTK_BOX (GET_CONTENT_AREA (GTK_DIALOG (dialog))),
                         hbox, TRUE, TRUE, 0);
 
     colormap = gtk_widget_get_colormap (parent);
@@ -790,7 +893,7 @@ about_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
 
     hb = gtk_hbutton_box_new ();
 
-    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
+    gtk_box_pack_start (GTK_BOX (GET_ACTION_AREA (GTK_DIALOG (dialog))),
                         hb, TRUE, TRUE, 0);
 
 #ifdef HAVE_GTK2
@@ -816,10 +919,10 @@ about_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
     gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
                                GTK_SIGNAL_FUNC (warning_dialog_dismiss_cb),
                                (gpointer) dialog);
-    gdk_window_set_transient_for (GTK_WIDGET (dialog)->window,
-                                  GTK_WIDGET (parent)->window);
-    gdk_window_show (GTK_WIDGET (dialog)->window);
-    gdk_window_raise (GTK_WIDGET (dialog)->window);
+    gdk_window_set_transient_for (GET_WINDOW (GTK_WIDGET (dialog)),
+                                  GET_WINDOW (GTK_WIDGET (parent)));
+    gdk_window_show (GET_WINDOW (GTK_WIDGET (dialog)));
+    gdk_window_raise (GET_WINDOW (GTK_WIDGET (dialog)));
   }
 }
 
@@ -835,7 +938,7 @@ doc_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
     {
       warning_dialog (s->toplevel_widget,
                       _("Error:\n\n"
-                       "No Help URL has been specified.\n"), False, 100);
+                       "No Help URL has been specified.\n"), D_NONE, 100);
       return;
     }
 
@@ -942,7 +1045,7 @@ await_xscreensaver (state *s)
                              the length ISO C89 compilers are required to
                              support" in the following expression... */
 # endif
-        strcat (buf,
+        strcat (buf, STFU
          _("You are running as root.  This usually means that xscreensaver\n"
             "was unable to contact your X server because access control is\n"
             "turned on.  Try running this command:\n"
@@ -961,7 +1064,7 @@ await_xscreensaver (state *s)
       else
         strcat (buf, _("Please check your $PATH and permissions."));
 
-      warning_dialog (s->toplevel_widget, buf, False, 1);
+      warning_dialog (s->toplevel_widget, buf, D_NONE, 1);
     }
 
   force_dialog_repaint (s);
@@ -978,6 +1081,7 @@ selected_list_element (state *s)
 static int
 demo_write_init_file (state *s, saver_preferences *p)
 {
+  Display *dpy = GDK_DISPLAY();
 
 #if 0
   /* #### try to figure out why shit keeps getting reordered... */
@@ -985,7 +1089,7 @@ demo_write_init_file (state *s, saver_preferences *p)
     abort();
 #endif
 
-  if (!write_init_file (p, s->short_version, False))
+  if (!write_init_file (dpy, p, s->short_version, False))
     {
       if (s->debug_p)
         fprintf (stderr, "%s: wrote %s\n", blurb(), init_file_name());
@@ -997,12 +1101,12 @@ demo_write_init_file (state *s, saver_preferences *p)
       if (!f || !*f)
         warning_dialog (s->toplevel_widget,
                         _("Error:\n\nCouldn't determine init file name!\n"),
-                        False, 100);
+                        D_NONE, 100);
       else
         {
           char *b = (char *) malloc (strlen(f) + 1024);
           sprintf (b, _("Error:\n\nCouldn't write %s\n"), f);
-          warning_dialog (s->toplevel_widget, b, False, 100);
+          warning_dialog (s->toplevel_widget, b, D_NONE, 100);
           free (b);
         }
       return -1;
@@ -1024,6 +1128,7 @@ run_this_cb (GtkButton *button, gpointer user_data)
 G_MODULE_EXPORT void
 manual_cb (GtkButton *button, gpointer user_data)
 {
+  Display *dpy = GDK_DISPLAY();
   state *s = global_state_kludge;  /* I hate C so much... */
   saver_preferences *p = &s->prefs;
   GtkWidget *list_widget = name_to_widget (s, "list");
@@ -1045,9 +1150,9 @@ manual_cb (GtkButton *button, gpointer user_data)
   while (*str && !isspace (*str)) str++;
   *str = 0;
   str = strrchr (name2, '/');
-  if (str) name = str+1;
+  if (str) name2 = str+1;
 
-  cmd = get_string_resource ("manualCommand", "ManualCommand");
+  cmd = get_string_resource (dpy, "manualCommand", "ManualCommand");
   if (cmd)
     {
       char *cmd2 = (char *) malloc (strlen (cmd) + (strlen (name2) * 4) + 100);
@@ -1064,7 +1169,7 @@ manual_cb (GtkButton *button, gpointer user_data)
     {
       warning_dialog (GTK_WIDGET (button),
                       _("Error:\n\nno `manualCommand' resource set."),
-                      False, 100);
+                      D_NONE, 100);
     }
 
   free (oname);
@@ -1075,7 +1180,7 @@ static void
 force_list_select_item (state *s, GtkWidget *list, int list_elt, Bool scroll_p)
 {
   GtkWidget *parent = name_to_widget (s, "scroller");
-  Bool was = GTK_WIDGET_IS_SENSITIVE (parent);
+  gboolean was = GET_SENSITIVE (parent);
 #ifdef HAVE_GTK2
   GtkTreeIter iter;
   GtkTreeModel *model;
@@ -1085,7 +1190,7 @@ force_list_select_item (state *s, GtkWidget *list, int list_elt, Bool scroll_p)
   if (!was) gtk_widget_set_sensitive (parent, True);
 #ifdef HAVE_GTK2
   model = gtk_tree_view_get_model (GTK_TREE_VIEW (list));
-  STFU g_assert (model);
+  g_assert (model);
   if (gtk_tree_model_iter_nth_child (model, &iter, NULL, list_elt))
     {
       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list));
@@ -1249,7 +1354,7 @@ hack_time_text (state *s, const char *line, Time *store, Bool sec_p)
                   _("Error:\n\n"
                     "Unparsable time format: \"%s\"\n"),
                   line);
-         warning_dialog (s->toplevel_widget, b, False, 100);
+         warning_dialog (s->toplevel_widget, b, D_NONE, 100);
        }
       else
        *store = value;
@@ -1310,19 +1415,32 @@ normalize_directory (const char *path)
             {
               s0--;
               s += 3;
-              strcpy (s0, s);
+              /* strcpy (s0, s); */
+              memmove(s0, s, strlen(s) + 1);
               s = s0-1;
             }
         }
-      else if (*s == '/' && !strncmp (s, "/./", 3))    /* delete "/./" */
-        strcpy (s, s+2), s--;
+      else if (*s == '/' && !strncmp (s, "/./", 3)) {  /* delete "/./" */
+        /* strcpy (s, s+2), s--; */
+        memmove(s, s+2, strlen(s+2) + 1);
+        s--;
+       }
       else if (*s == '/' && !strncmp (s, "/.\000", 3)) /* delete "/.$" */
         *s = 0, s--;
     }
 
-  for (s = p2; s && *s; s++)           /* normalize consecutive slashes */
-    while (s[0] == '/' && s[1] == '/')
-      strcpy (s, s+1);
+  /*
+    Normalize consecutive slashes.
+    Ignore doubled slashes after ":" to avoid mangling URLs.
+  */
+
+  for (s = p2; s && *s; s++){
+    if (*s == ':') continue;
+    if (!s[1] || !s[2]) continue;
+    while (s[1] == '/' && s[2] == '/')
+      /* strcpy (s+1, s+2); */
+      memmove (s+1, s+2, strlen(s+2) + 1);
+  }
 
   /* and strip trailing whitespace for good measure. */
   L = strlen(p2);
@@ -1384,6 +1502,7 @@ flush_dialog_changes_and_save (state *s)
   GList *kids = gtk_container_children (GTK_CONTAINER (list_widget));
   int i;
 #endif /* !HAVE_GTK2 */
+  static Bool already_warned_about_missing_image_directory = False; /* very long name... */
 
   Bool changed = False;
   GtkWidget *w;
@@ -1438,14 +1557,15 @@ flush_dialog_changes_and_save (state *s)
 
 # define TEXT(FIELD,NAME) \
     w = name_to_widget (s, (NAME)); \
-    (FIELD) = (char *) gtk_entry_get_text (GTK_ENTRY (w))
+    (FIELD) = (char *) g_strdup(gtk_entry_get_text (GTK_ENTRY (w)))
 
   MINUTES  (&p2->timeout,         "timeout_spinbutton");
   MINUTES  (&p2->cycle,           "cycle_spinbutton");
   CHECKBOX (p2->lock_p,           "lock_button");
   MINUTES  (&p2->lock_timeout,    "lock_spinbutton");
 
-  CHECKBOX (p2->dpms_enabled_p,  "dpms_button");
+  CHECKBOX (p2->dpms_enabled_p,   "dpms_button");
+  CHECKBOX (p2->dpms_quickoff_p,  "dpms_quickoff_button");
   MINUTES  (&p2->dpms_standby,    "dpms_standby_spinbutton");
   MINUTES  (&p2->dpms_suspend,    "dpms_suspend_spinbutton");
   MINUTES  (&p2->dpms_off,        "dpms_off_spinbutton");
@@ -1486,16 +1606,28 @@ flush_dialog_changes_and_save (state *s)
 # undef PATHNAME
 # undef TEXT
 
-  /* Warn if the image directory doesn't exist.
+  /* Warn if the image directory doesn't exist, when:
+     - not being warned before
+     - image directory is changed and the directory doesn't exist
+     - image directory does not begin with http://
    */
   if (p2->image_directory &&
       *p2->image_directory &&
-      !directory_p (p2->image_directory))
+      !directory_p (p2->image_directory) &&
+       strncmp(p2->image_directory, "http://", 6) &&
+        ( !already_warned_about_missing_image_directory ||
+          ( p->image_directory &&
+            *p->image_directory &&
+            strcmp(p->image_directory, p2->image_directory)
+          )
+        )
+      )
     {
       char b[255];
-      sprintf (b, "Error:\n\n" "Directory does not exist: \"%s\"\n",
+      sprintf (b, "Warning:\n\n" "Directory does not exist: \"%s\"\n",
                p2->image_directory);
-      warning_dialog (s->toplevel_widget, b, False, 100);
+      if (warning_dialog (s->toplevel_widget, b, D_NONE, 100))
+        already_warned_about_missing_image_directory = True;
     }
 
 
@@ -1534,10 +1666,11 @@ flush_dialog_changes_and_save (state *s)
   COPY(lock_p,         "lock_p");
   COPY(lock_timeout,   "lock_timeout");
 
-  COPY(dpms_enabled_p, "dpms_enabled_p");
-  COPY(dpms_standby,   "dpms_standby");
-  COPY(dpms_suspend,   "dpms_suspend");
-  COPY(dpms_off,       "dpms_off");
+  COPY(dpms_enabled_p,  "dpms_enabled_p");
+  COPY(dpms_quickoff_p, "dpms_quickoff_enabled_p");
+  COPY(dpms_standby,    "dpms_standby");
+  COPY(dpms_suspend,    "dpms_suspend");
+  COPY(dpms_off,        "dpms_off");
 
 #if 0
   COPY(verbose_p,        "verbose_p");
@@ -1585,7 +1718,7 @@ flush_dialog_changes_and_save (state *s)
     {
       Display *dpy = GDK_DISPLAY();
       Bool enabled_p = (p->dpms_enabled_p && p->mode != DONT_BLANK);
-      sync_server_dpms_settings (dpy, enabled_p,
+      sync_server_dpms_settings (dpy, enabled_p, p->dpms_quickoff_p,
                                  p->dpms_standby / 1000,
                                  p->dpms_suspend / 1000,
                                  p->dpms_off / 1000,
@@ -1697,7 +1830,7 @@ pref_changed_event_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data)
 
 /* Callback on menu items in the "mode" options menu.
  */
-void
+G_MODULE_EXPORT void
 mode_menu_item_cb (GtkWidget *widget, gpointer user_data)
 {
   state *s = (state *) user_data;
@@ -1705,7 +1838,8 @@ mode_menu_item_cb (GtkWidget *widget, gpointer user_data)
   GtkWidget *list = name_to_widget (s, "list");
   int list_elt;
 
-  GList *menu_items = gtk_container_children (GTK_CONTAINER (widget->parent));
+  GList *menu_items =
+    gtk_container_children (GTK_CONTAINER (GET_PARENT (widget)));
   int menu_index = 0;
   saver_mode new_mode;
 
@@ -1766,7 +1900,7 @@ list_activated_cb (GtkTreeView       *list,
   char *str;
   int list_elt;
 
-  STFU g_return_if_fail (!gdk_pointer_is_grabbed ());
+  g_return_if_fail (!gdk_pointer_is_grabbed ());
 
   str = gtk_tree_path_to_string (path);
   list_elt = strtol (str, NULL, 10);
@@ -1918,7 +2052,7 @@ list_checkbox_cb (
 
   /* remember previous scroll position of the top of the list */
   adj = gtk_scrolled_window_get_vadjustment (scroller);
-  scroll_top = adj->value;
+  scroll_top = GET_ADJ_VALUE (adj);
 
   flush_dialog_changes_and_save (s);
   force_list_select_item (s, GTK_WIDGET (list), list_elt, False);
@@ -1950,11 +2084,12 @@ store_image_directory (GtkWidget *button, gpointer user_data)
   if (p->image_directory && !strcmp(p->image_directory, path))
     return;  /* no change */
 
-  if (!directory_p (path))
+  /* No warning for URLs. */
+  if ((!directory_p (path)) && strncmp(path, "http://", 6))
     {
       char b[255];
       sprintf (b, _("Error:\n\n" "Directory does not exist: \"%s\"\n"), path);
-      warning_dialog (GTK_WIDGET (top), b, False, 100);
+      warning_dialog (GTK_WIDGET (top), b, D_NONE, 100);
       return;
     }
 
@@ -1984,7 +2119,7 @@ store_text_file (GtkWidget *button, gpointer user_data)
     {
       char b[255];
       sprintf (b, _("Error:\n\n" "File does not exist: \"%s\"\n"), path);
-      warning_dialog (GTK_WIDGET (top), b, False, 100);
+      warning_dialog (GTK_WIDGET (top), b, D_NONE, 100);
       return;
     }
 
@@ -2015,7 +2150,7 @@ store_text_program (GtkWidget *button, gpointer user_data)
     {
       char b[255];
       sprintf (b, _("Error:\n\n" "File does not exist: \"%s\"\n"), path);
-      warning_dialog (GTK_WIDGET (top), b, False, 100);
+      warning_dialog (GTK_WIDGET (top), b, D_NONE, 100);
       return;
     }
 # endif
@@ -2172,7 +2307,7 @@ browse_text_program_cb (GtkButton *button, gpointer user_data)
 
 
 
-G_MODULE_EXPORT  void
+G_MODULE_EXPORT void
 settings_cb (GtkButton *button, gpointer user_data)
 {
   state *s = global_state_kludge;  /* I hate C so much... */
@@ -2188,7 +2323,7 @@ settings_sync_cmd_text (state *s)
 {
 # ifdef HAVE_XML
   GtkWidget *cmd = GTK_WIDGET (name_to_widget (s, "cmd_text"));
-  char *cmd_line = get_configurator_command_line (s->cdata);
+  char *cmd_line = get_configurator_command_line (s->cdata, False);
   gtk_entry_set_text (GTK_ENTRY (cmd), cmd_line);
   gtk_entry_set_position (GTK_ENTRY (cmd), strlen (cmd_line));
   free (cmd_line);
@@ -2219,6 +2354,20 @@ settings_std_cb (GtkButton *button, gpointer user_data)
   gtk_notebook_set_page (notebook, 0);
 }
 
+G_MODULE_EXPORT void
+settings_reset_cb (GtkButton *button, gpointer user_data)
+{
+# ifdef HAVE_XML
+  state *s = global_state_kludge;  /* I hate C so much... */
+  GtkWidget *cmd = GTK_WIDGET (name_to_widget (s, "cmd_text"));
+  char *cmd_line = get_configurator_command_line (s->cdata, True);
+  gtk_entry_set_text (GTK_ENTRY (cmd), cmd_line);
+  gtk_entry_set_position (GTK_ENTRY (cmd), strlen (cmd_line));
+  free (cmd_line);
+  populate_popup_window (s);
+# endif /* HAVE_XML */
+}
+
 G_MODULE_EXPORT void
 settings_switch_page_cb (GtkNotebook *notebook, GtkNotebookPage *page,
                          gint page_num, gpointer user_data)
@@ -2303,7 +2452,7 @@ server_current_hack (void)
       && nitems >= 3
       && dataP)
     {
-      CARD32 *data = (CARD32 *) dataP;
+      PROP32 *data = (PROP32 *) dataP;
       hack_number = (int) data[2] - 1;
     }
 
@@ -2360,6 +2509,7 @@ scroll_to_current_hack (state *s)
 static void
 populate_hack_list (state *s)
 {
+  Display *dpy = GDK_DISPLAY();
 #ifdef HAVE_GTK2
   saver_preferences *p = &s->prefs;
   GtkTreeView *list = GTK_TREE_VIEW (name_to_widget (s, "list"));
@@ -2420,7 +2570,7 @@ populate_hack_list (state *s)
 
       pretty_name = (hack->name
                      ? strdup (hack->name)
-                     : make_hack_name (hack->command));
+                     : make_hack_name (dpy, hack->command));
 
       if (!available_p)
         {
@@ -2428,7 +2578,7 @@ populate_hack_list (state *s)
              (but don't actually make it be insensitive, since we still
              want to be able to click on it.)
            */
-          GtkStyle *style = GTK_WIDGET (list)->style;
+          GtkStyle *style = gtk_widget_get_style (GTK_WIDGET (list));
           GdkColor *fg = &style->fg[GTK_STATE_INSENSITIVE];
        /* GdkColor *bg = &style->bg[GTK_STATE_INSENSITIVE]; */
           char *buf = (char *) malloc (strlen (pretty_name) + 100);
@@ -2666,6 +2816,7 @@ populate_prefs_page (state *s)
   TOGGLE_ACTIVE ("splash_button",     p->splash_p);
 #endif
   TOGGLE_ACTIVE ("dpms_button",       p->dpms_enabled_p);
+  TOGGLE_ACTIVE ("dpms_quickoff_button", p->dpms_quickoff_p);
   TOGGLE_ACTIVE ("grab_desk_button",  p->grab_desktop_p);
   TOGGLE_ACTIVE ("grab_video_button", p->grab_video_p);
   TOGGLE_ACTIVE ("grab_image_button", p->random_image_p);
@@ -2769,8 +2920,11 @@ populate_prefs_page (state *s)
 
     /* DPMS
      */
+dpms_supported=1;
     SENSITIZE ("dpms_frame",              dpms_supported);
     SENSITIZE ("dpms_button",             dpms_supported);
+    SENSITIZE ("dpms_quickoff_button",    dpms_supported);
+
     SENSITIZE ("dpms_standby_label",      dpms_supported && p->dpms_enabled_p);
     SENSITIZE ("dpms_standby_mlabel",     dpms_supported && p->dpms_enabled_p);
     SENSITIZE ("dpms_standby_spinbutton", dpms_supported && p->dpms_enabled_p);
@@ -2896,7 +3050,7 @@ force_dialog_repaint (state *s)
 #if 1
   /* Tell GDK to invalidate and repaint the whole window.
    */
-  GdkWindow *w = s->toplevel_widget->window;
+  GdkWindow *w = GET_WINDOW (s->toplevel_widget);
   GdkRegion *region = gdk_region_new ();
   GdkRectangle rect;
   rect.x = rect.y = 0;
@@ -2984,7 +3138,7 @@ fix_text_entry_sizes (state *s)
 #ifdef HAVE_GTK2
     PangoFontMetrics *pain =
       pango_context_get_metrics (gtk_widget_get_pango_context (w),
-                                 w->style->font_desc,
+                                 gtk_widget_get_style (w)->font_desc,
                                  gtk_get_default_language ());
     height = PANGO_PIXELS (pango_font_metrics_get_ascent (pain) +
                            pango_font_metrics_get_descent (pain));
@@ -3152,11 +3306,12 @@ eschew_gtk_lossage (GtkLabel *label)
 static void
 populate_demo_window (state *s, int list_elt)
 {
+  Display *dpy = GDK_DISPLAY();
   saver_preferences *p = &s->prefs;
   screenhack *hack;
   char *pretty_name;
   GtkFrame *frame1 = GTK_FRAME (name_to_widget (s, "preview_frame"));
-  GtkFrame *frame2 = GTK_FRAME (name_to_widget (s, "doc_frame"));
+  GtkFrame *frame2 = GTK_FRAME (name_to_widget (s, "opt_frame"));
   GtkEntry *cmd    = GTK_ENTRY (name_to_widget (s, "cmd_text"));
   GtkCombo *vis    = GTK_COMBO (name_to_widget (s, "visual_combo"));
   GtkWidget *list  = GTK_WIDGET (name_to_widget (s, "list"));
@@ -3183,7 +3338,7 @@ populate_demo_window (state *s, int list_elt)
       pretty_name = (hack
                      ? (hack->name
                         ? strdup (hack->name)
-                        : make_hack_name (hack->command))
+                        : make_hack_name (dpy, hack->command))
                      : 0);
 
       if (hack)
@@ -3264,6 +3419,7 @@ sort_hack_cmp (const void *a, const void *b)
 static void
 initialize_sort_map (state *s)
 {
+  Display *dpy = GDK_DISPLAY();
   saver_preferences *p = &s->prefs;
   int i, j;
 
@@ -3314,7 +3470,7 @@ initialize_sort_map (state *s)
       screenhack *hack = p->screenhacks[i];
       char *name = (hack->name && *hack->name
                     ? strdup (hack->name)
-                    : make_hack_name (hack->command));
+                    : make_hack_name (dpy, hack->command));
       char *str;
       for (str = name; *str; str++)
         *str = tolower(*str);
@@ -3348,6 +3504,7 @@ initialize_sort_map (state *s)
 static int
 maybe_reload_init_file (state *s)
 {
+  Display *dpy = GDK_DISPLAY();
   saver_preferences *p = &s->prefs;
   int status = 0;
 
@@ -3368,10 +3525,10 @@ maybe_reload_init_file (state *s)
                _("Warning:\n\n"
                 "file \"%s\" has changed, reloading.\n"),
                f);
-      warning_dialog (s->toplevel_widget, b, False, 100);
+      warning_dialog (s->toplevel_widget, b, D_NONE, 100);
       free (b);
 
-      load_init_file (p);
+      load_init_file (dpy, p);
       initialize_sort_map (s);
 
       list_elt = selected_list_element (s);
@@ -3418,16 +3575,18 @@ clear_preview_window (state *s)
 {
   GtkWidget *p;
   GdkWindow *window;
+  GtkStyle  *style;
 
   if (!s->toplevel_widget) return;  /* very early */
   p = name_to_widget (s, "preview");
-  window = p->window;
+  window = GET_WINDOW (p);
 
   if (!window) return;
 
   /* Flush the widget background down into the window, in case a subproc
      has changed it. */
-  gdk_window_set_background (window, &p->style->bg[GTK_STATE_NORMAL]);
+  style = gtk_widget_get_style (p);
+  gdk_window_set_background (window, &style->bg[GTK_STATE_NORMAL]);
   gdk_window_clear (window);
 
   {
@@ -3488,15 +3647,16 @@ reset_preview_window (state *s)
      when changing hacks, instead of always trying to reuse the same one?
    */
   GtkWidget *pr = name_to_widget (s, "preview");
-  if (GTK_WIDGET_REALIZED (pr))
+  if (GET_REALIZED (pr))
     {
-      Window oid = (pr->window ? GDK_WINDOW_XWINDOW (pr->window) : 0);
+      GdkWindow *window = GET_WINDOW (pr);
+      Window oid = (window ? GDK_WINDOW_XWINDOW (window) : 0);
       Window id;
       gtk_widget_hide (pr);
       gtk_widget_unrealize (pr);
       gtk_widget_realize (pr);
       gtk_widget_show (pr);
-      id = (pr->window ? GDK_WINDOW_XWINDOW (pr->window) : 0);
+      id = (window ? GDK_WINDOW_XWINDOW (window) : 0);
       if (s->debug_p)
         fprintf (stderr, "%s: window id 0x%X -> 0x%X\n", blurb(),
                  (unsigned int) oid,
@@ -3521,7 +3681,7 @@ fix_preview_visual (state *s)
              (visual == dvisual ? "default" : "non-default"),
              (xvisual ? (unsigned long) xvisual->visualid : 0L));
 
-  if (!GTK_WIDGET_REALIZED (widget) ||
+  if (!GET_REALIZED (widget) ||
       gtk_widget_get_visual (widget) != visual)
     {
       gtk_widget_unrealize (widget);
@@ -3532,8 +3692,8 @@ fix_preview_visual (state *s)
 
   /* Set the Widget colors to be white-on-black. */
   {
-    GdkWindow *window = widget->window;
-    GtkStyle *style = gtk_style_copy (widget->style);
+    GdkWindow *window = GET_WINDOW (widget);
+    GtkStyle *style = gtk_style_copy (gtk_widget_get_style (widget));
     GdkColormap *cmap = gtk_widget_get_colormap (widget);
     GdkColor *fg = &style->fg[GTK_STATE_NORMAL];
     GdkColor *bg = &style->bg[GTK_STATE_NORMAL];
@@ -3755,9 +3915,13 @@ kill_preview_subproc (state *s, Bool reset_p)
               perror (buf);
             }
         }
-      else if (s->debug_p)
-        fprintf (stderr, "%s: killed pid %lu (%s)\n", blurb(),
-                 (unsigned long) s->running_preview_pid, ss);
+      else {
+       int endstatus;
+       waitpid(s->running_preview_pid, &endstatus, 0);
+       if (s->debug_p)
+         fprintf (stderr, "%s: killed pid %lu (%s)\n", blurb(),
+                  (unsigned long) s->running_preview_pid, ss);
+      }
 
       free (ss);
       s->running_preview_pid = 0;
@@ -3792,7 +3956,7 @@ launch_preview_subproc (state *s)
 
   reset_preview_window (s);
 
-  window = pr->window;
+  window = GET_WINDOW (pr);
 
   s->running_preview_error_p = False;
 
@@ -3974,6 +4138,13 @@ update_subproc_timer (gpointer data)
   return FALSE;  /* do not re-execute timer */
 }
 
+static int
+settings_timer (gpointer data)
+{
+  settings_cb (0, 0);
+  return FALSE;
+}
+
 
 /* Call this when you think you might want a preview process running.
    It will set a timer that will actually launch that program a second
@@ -4161,9 +4332,8 @@ static void
 init_icon (GdkWindow *window)
 {
   GdkBitmap *mask = 0;
-  GdkColor transp;
   GdkPixmap *pixmap =
-    gdk_pixmap_create_from_xpm_d (window, &mask, &transp,
+    gdk_pixmap_create_from_xpm_d (window, &mask, 0,
                                   (gchar **) logo_50_xpm);
   if (pixmap)
     gdk_window_set_icon (window, 0, pixmap, mask);
@@ -4197,6 +4367,77 @@ mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
 #endif
 
 
+static Window
+gnome_screensaver_window (Screen *screen)
+{
+  Display *dpy = DisplayOfScreen (screen);
+  Window root = RootWindowOfScreen (screen);
+  Window parent, *kids;
+  unsigned int nkids;
+  Window gnome_window = 0;
+  int i;
+
+  if (! XQueryTree (dpy, root, &root, &parent, &kids, &nkids))
+    abort ();
+  for (i = 0; i < nkids; i++)
+    {
+      Atom type;
+      int format;
+      unsigned long nitems, bytesafter;
+      unsigned char *name;
+      if (XGetWindowProperty (dpy, kids[i], XA_WM_COMMAND, 0, 128,
+                              False, XA_STRING, &type, &format, &nitems,
+                              &bytesafter, &name)
+          == Success
+          && type != None
+          && !strcmp ((char *) name, "gnome-screensaver"))
+       {
+         gnome_window = kids[i];
+          break;
+       }
+    }
+
+  if (kids) XFree ((char *) kids);
+  return gnome_window;
+}
+
+static Bool
+gnome_screensaver_active_p (void)
+{
+  Display *dpy = GDK_DISPLAY();
+  Window w = gnome_screensaver_window (DefaultScreenOfDisplay (dpy));
+  return (w ? True : False);
+}
+
+static void
+kill_gnome_screensaver (void)
+{
+  Display *dpy = GDK_DISPLAY();
+  Window w = gnome_screensaver_window (DefaultScreenOfDisplay (dpy));
+  if (w) XKillClient (dpy, (XID) w);
+}
+
+static Bool
+kde_screensaver_active_p (void)
+{
+  FILE *p = popen ("dcop kdesktop KScreensaverIface isEnabled 2>/dev/null",
+                   "r");
+  char buf[255];
+  fgets (buf, sizeof(buf)-1, p);
+  pclose (p);
+  if (!strcmp (buf, "true\n"))
+    return True;
+  else
+    return False;
+}
+
+static void
+kill_kde_screensaver (void)
+{
+  system ("dcop kdesktop KScreensaverIface enable false");
+}
+
+
 static void
 the_network_is_not_the_computer (state *s)
 {
@@ -4310,12 +4551,36 @@ the_network_is_not_the_computer (state *s)
 
 
   if (*msg)
-    warning_dialog (s->toplevel_widget, msg, True, 1);
+    warning_dialog (s->toplevel_widget, msg, D_LAUNCH, 1);
 
   if (rversion) free (rversion);
   if (ruser) free (ruser);
   if (rhost) free (rhost);
   free (msg);
+  msg = 0;
+
+  /* Note: since these dialogs are not modal, they will stack up.
+     So we do this check *after* popping up the "xscreensaver is not
+     running" dialog so that these are on top.  Good enough.
+   */
+
+  if (gnome_screensaver_active_p ())
+    warning_dialog (s->toplevel_widget,
+                    _("Warning:\n\n"
+                      "The GNOME screensaver daemon appears to be running.\n"
+                      "It must be stopped for XScreenSaver to work properly.\n"
+                      "\n"
+                      "Stop the GNOME screen saver daemon now?\n"),
+                    D_GNOME, 1);
+
+  if (kde_screensaver_active_p ())
+    warning_dialog (s->toplevel_widget,
+                    _("Warning:\n\n"
+                      "The KDE screen saver daemon appears to be running.\n"
+                      "It must be stopped for XScreenSaver to work properly.\n"
+                      "\n"
+                      "Stop the KDE screen saver daemon now?\n"),
+                    D_KDE, 1);
 }
 
 
@@ -4371,6 +4636,7 @@ g_log_handler (const gchar *log_domain, GLogLevelFlags log_level,
                       the .ad file... */
 #endif
 
+STFU
 static char *defaults[] = {
 #include "XScreenSaver_ad.h"
  0
@@ -4384,7 +4650,7 @@ static struct poptOption crapplet_options[] = {
 #endif /* HAVE_CRAPPLET */
 #endif /* 0 */
 
-const char *usage = "[--display dpy] [--prefs]"
+const char *usage = "[--display dpy] [--prefs | --settings]"
 # ifdef HAVE_CRAPPLET
                     " [--crapplet]"
 # endif
@@ -4450,7 +4716,7 @@ delayed_scroll_kludge (gpointer data)
 
 #ifdef HAVE_GTK2
 
-GtkWidget *
+static GtkWidget *
 create_xscreensaver_demo (void)
 {
   GtkWidget *nb;
@@ -4461,7 +4727,7 @@ create_xscreensaver_demo (void)
   return name_to_widget (global_state_kludge, "xscreensaver_demo");
 }
 
-GtkWidget *
+static GtkWidget *
 create_xscreensaver_settings_dialog (void)
 {
   GtkWidget *w, *box;
@@ -4485,7 +4751,8 @@ main (int argc, char **argv)
   XtAppContext app;
   state S, *s;
   saver_preferences *p;
-  Bool prefs = False;
+  Bool prefs_p = False;
+  Bool settings_p = False;
   int i;
   Display *dpy;
   Widget toplevel_shell;
@@ -4751,7 +5018,9 @@ main (int argc, char **argv)
       if (str[0] == '-' && str[1] == '-')
        str++;
       if (!strcmp (str, "-prefs"))
-       prefs = True;
+       prefs_p = True;
+      else if (!strcmp (str, "-settings"))
+       settings_p = True;
       else if (crapplet_p)
         /* There are lots of random args that we don't care about when we're
            started as a crapplet, so just ignore unknown args in that case. */
@@ -4775,7 +5044,7 @@ main (int argc, char **argv)
 
   hack_environment (s);  /* must be before initialize_sort_map() */
 
-  load_init_file (p);
+  load_init_file (dpy, p);
   initialize_sort_map (s);
 
   /* Now that Xt has been initialized, and the resources have been read,
@@ -4857,6 +5126,8 @@ main (int argc, char **argv)
     gtk_widget_set_sensitive (std, False);
     std = GTK_WIDGET (name_to_widget (s, "adv_button"));
     gtk_widget_hide (std);
+    std = GTK_WIDGET (name_to_widget (s, "reset_button"));
+    gtk_widget_hide (std);
     page = 1;
 # endif /* !HAVE_XML */
 
@@ -4921,7 +5192,7 @@ main (int argc, char **argv)
 
 
   /* Handle the -prefs command-line argument. */
-  if (prefs)
+  if (prefs_p)
     {
       GtkNotebook *notebook =
         GTK_NOTEBOOK (name_to_widget (s, "notebook"));
@@ -4959,7 +5230,7 @@ main (int argc, char **argv)
       {
         GtkWidget *window = capplet;
         while (window && !GTK_IS_WINDOW (window))
-          window = window->parent;
+          window = GET_PARENT (window);
         if (window)
           {
             gtk_window_set_title (GTK_WINDOW (window), window_title);
@@ -4994,7 +5265,7 @@ main (int argc, char **argv)
 #endif
 
   gtk_widget_show (s->toplevel_widget);
-  init_icon (GTK_WIDGET (s->toplevel_widget)->window);  /* after `show' */
+  init_icon (GET_WINDOW (GTK_WIDGET (s->toplevel_widget)));  /* after `show' */
   fix_preview_visual (s);
 
   /* Realize page zero, so that we can diddle the scrollbar when the
@@ -5011,8 +5282,28 @@ main (int argc, char **argv)
   gtk_timeout_add (60 * 1000, check_blanked_timer, s);
 
 
+  /* Handle the --settings command-line argument. */
+  if (settings_p)
+    gtk_timeout_add (500, settings_timer, 0);
+
+
   /* Issue any warnings about the running xscreensaver daemon. */
-  the_network_is_not_the_computer (s);
+  if (! s->debug_p)
+    the_network_is_not_the_computer (s);
+
+
+  if (decrepit_p())
+    warning_dialog (s->toplevel_widget,
+      _("Warning:\n\n"
+        "This version of xscreensaver is VERY OLD!\n"
+        "Please upgrade!\n"
+        "\n"
+        "https://www.jwz.org/xscreensaver/\n"
+        "\n"
+        "(If this is the latest version that your distro ships, then\n"
+        "your distro is doing you a disservice. Build from source.)\n"
+        ),
+      D_NONE, 7);
 
 
   /* Run the Gtk event loop, and not the Xt event loop.  This means that
@@ -5030,17 +5321,18 @@ main (int argc, char **argv)
   gtk_timeout_add (500, delayed_scroll_kludge, s);
 
 
-#if 0
+#if 1
   /* Load every configurator in turn, to scan them for errors all at once. */
-  {
-    int i;
-    for (i = 0; i < p->screenhacks_count; i++)
-      {
-        screenhack *hack = p->screenhacks[i];
-        conf_data *d = load_configurator (hack->command, False);
-        if (d) free_conf_data (d);
-      }
-  }
+  if (s->debug_p)
+    {
+      int i;
+      for (i = 0; i < p->screenhacks_count; i++)
+        {
+          screenhack *hack = p->screenhacks[i];
+          conf_data *d = load_configurator (hack->command, s->debug_p);
+          if (d) free_conf_data (d);
+        }
+    }
 #endif