From http://www.jwz.org/xscreensaver/xscreensaver-5.35.tar.gz
[xscreensaver] / driver / demo-Gtk.c
index d1eb3c85089901c9bc840c201580c7dbc711fb85..f5c483965a3a8ead6947abc473d9ea4a823f1c29 100644 (file)
@@ -1,5 +1,5 @@
 /* demo-Gtk.c --- implements the interactive demo-mode and options dialogs.
- * xscreensaver, Copyright (c) 1993-2008 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);
@@ -267,11 +297,15 @@ 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
  */
@@ -423,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;
 
@@ -468,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));
 }
 
@@ -482,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;
@@ -495,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;
@@ -534,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);
       }
@@ -548,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);
@@ -571,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);
@@ -582,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),
@@ -610,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));
@@ -621,6 +676,7 @@ warning_dialog (GtkWidget *parent, const char *message,
 #endif /* !HAVE_GTK2 */
 
   free (msg);
+  return True;
 }
 
 
@@ -644,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);
 
@@ -685,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
@@ -700,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);
         }
     }
 
@@ -742,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-2008 %s"), s);
+  sprintf(copy, ("Copyright \xC2\xA9 1991-%s %s"), year, s);
 #else  /* !HAVE_GTK2 */
-  sprintf(copy, ("Copyright \251 1991-2008 %s"), s);
+  sprintf(copy, ("Copyright \251 1991-%s %s"), year, s);
 #endif /* !HAVE_GTK2 */
 
   sprintf (msg, "%s\n\n%s", copy, desc);
@@ -785,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);
@@ -830,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
@@ -856,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)));
   }
 }
 
@@ -875,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;
     }
 
@@ -1001,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);
@@ -1038,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;
@@ -1106,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);
@@ -1117,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;
@@ -1291,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;
@@ -1352,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);
@@ -1426,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;
@@ -1480,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");
@@ -1528,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;
     }
 
 
@@ -1576,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");
@@ -1627,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,
@@ -1747,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;
 
@@ -1808,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);
@@ -1960,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);
@@ -1992,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;
     }
 
@@ -2026,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;
     }
 
@@ -2057,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
@@ -2230,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);
@@ -2261,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)
@@ -2471,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);
@@ -2709,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);
@@ -2812,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);
@@ -2939,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;
@@ -3027,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));
@@ -3200,7 +3311,7 @@ populate_demo_window (state *s, int list_elt)
   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"));
@@ -3414,7 +3525,7 @@ 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 (dpy, p);
@@ -3464,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);
 
   {
@@ -3534,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,
@@ -3567,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);
@@ -3578,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];
@@ -3842,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;
 
@@ -4024,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
@@ -4211,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);
@@ -4247,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)
 {
@@ -4360,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);
 }
 
 
@@ -4435,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
@@ -4501,7 +4716,7 @@ delayed_scroll_kludge (gpointer data)
 
 #ifdef HAVE_GTK2
 
-GtkWidget *
+static GtkWidget *
 create_xscreensaver_demo (void)
 {
   GtkWidget *nb;
@@ -4512,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;
@@ -4536,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;
@@ -4802,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. */
@@ -4908,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 */
 
@@ -4972,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"));
@@ -5010,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);
@@ -5045,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
@@ -5062,11 +5282,30 @@ 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. */
   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
      if there were Xt timers or fds registered, they would never get serviced,
      and if there were any Xt widgets, they would never have events delivered.