http://ftp.x.org/contrib/applications/xscreensaver-3.20.tar.gz
[xscreensaver] / driver / demo.c
index e92e9617a1da6c111758a8e2dd2a1fbdeeab86d3..bec72e0e8a4bf52185bc086063712cff504ae1e8 100644 (file)
 # include "config.h"
 #endif
 
-#ifdef HAVE_ATHENA_KLUDGE      /* don't ask */
+
+#ifdef FORCE_ATHENA
 # undef HAVE_MOTIF
 # define HAVE_ATHENA 1
 #endif
+#ifdef FORCE_MOTIF
+# undef HAVE_ATHENA
+# define HAVE_MOTIF 1
+#endif
+
+/* Only one, please. */
+#ifdef HAVE_MOTIF
+# undef HAVE_ATHENA
+#endif
+#ifdef HAVE_ATHENA
+# undef HAVE_MOTIF
+#endif
+
 
 #include <stdlib.h>
 
@@ -37,6 +51,8 @@
 
 #include <stdio.h>
 
+#include <X11/Xproto.h>                /* for CARD32 */
+#include <X11/Xatom.h>         /* for XA_INTEGER */
 #include <X11/Intrinsic.h>
 #include <X11/StringDefs.h>
 
 #include <X11/IntrinsicP.h>
 #include <X11/ShellP.h>
 
+#ifdef HAVE_XMU
+# ifndef VMS
+#  include <X11/Xmu/Error.h>
+# else /* VMS */
+#  include <Xmu/Error.h>
+# endif
+#else
+# include "xmu.h"
+#endif
+
+
 #ifdef HAVE_MOTIF
 # include <Xm/Xm.h>
 # include <Xm/Text.h>
@@ -54,7 +81,7 @@
 # include <Xm/LabelG.h>
 # include <Xm/RowColumn.h>
 
-#else  /* HAVE_ATHENA */
+#elif defined(HAVE_ATHENA)
   /* Athena demo code contributed by Jon A. Christopher <jac8782@tamu.edu> */
   /* Copyright 1997, with the same permissions as above. */
 # include <X11/Shell.h>
@@ -67,6 +94,7 @@
 # include <X11/Xaw/Dialog.h>
 # include <X11/Xaw/Scrollbar.h>
 # include <X11/Xaw/Text.h>
+
 #endif /* HAVE_ATHENA */
 
 #include "version.h"
 #include "resources.h"         /* for parse_time() */
 #include "visual.h"            /* for has_writable_cells() */
 #include "remote.h"            /* for xscreensaver_command() */
+#include "usleep.h"
 
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
 
+#define WIDGET Widget
+#define POINTER XtPointer
+
 
 char *progname = 0;
 char *progclass = "XScreenSaver";
@@ -101,25 +133,39 @@ static char *short_version = 0;
 
 Atom XA_VROOT;
 Atom XA_SCREENSAVER, XA_SCREENSAVER_RESPONSE, XA_SCREENSAVER_VERSION;
-Atom XA_SCREENSAVER_TIME, XA_SCREENSAVER_ID, XA_SELECT, XA_DEMO, XA_RESTART;
+Atom XA_SCREENSAVER_ID, XA_SCREENSAVER_STATUS, XA_SELECT, XA_DEMO;
+Atom XA_BLANK, XA_LOCK, XA_RESTART, XA_EXIT;
 
 extern void create_demo_dialog (Widget, Visual *, Colormap);
 extern void create_preferences_dialog (Widget, Visual *, Colormap);
 
-extern Widget demo_dialog;
-extern Widget label1;
-extern Widget text_line;
-extern Widget demo_form;
-extern Widget demo_list;
-extern Widget next, prev, done, restart, edit;
-
-extern Widget preferences_dialog;
-extern Widget preferences_form;
-extern Widget prefs_done, prefs_cancel;
-extern Widget timeout_text, cycle_text, fade_text, fade_ticks_text;
-extern Widget lock_timeout_text, passwd_timeout_text;
-extern Widget verbose_toggle, install_cmap_toggle, fade_toggle, unfade_toggle,
-  lock_toggle;
+extern WIDGET demo_dialog;
+extern WIDGET label1;
+extern WIDGET text_line;
+extern WIDGET text_activate;
+extern WIDGET demo_form;
+extern WIDGET demo_list;
+extern WIDGET next;
+extern WIDGET prev;
+extern WIDGET done;
+extern WIDGET restart;
+extern WIDGET edit;
+
+extern WIDGET preferences_dialog;
+extern WIDGET preferences_form;
+extern WIDGET prefs_done;
+extern WIDGET prefs_cancel;
+extern WIDGET timeout_text;
+extern WIDGET cycle_text;
+extern WIDGET fade_text;
+extern WIDGET fade_ticks_text;
+extern WIDGET lock_timeout_text;
+extern WIDGET passwd_timeout_text;
+extern WIDGET verbose_toggle;
+extern WIDGET install_cmap_toggle;
+extern WIDGET fade_toggle;
+extern WIDGET unfade_toggle;
+extern WIDGET lock_toggle;
 
 
 #ifdef HAVE_MOTIF
@@ -133,8 +179,14 @@ extern Widget verbose_toggle, install_cmap_toggle, fade_toggle, unfade_toggle,
 # define add_toggle_callback(button,cb,arg) \
   XtAddCallback ((button), XmNvalueChangedCallback, (cb), (arg))
 # define add_text_callback add_toggle_callback
+# define disable_widget(widget) \
+  XtVaSetValues((widget), XtNsensitive, False, 0)
+# define widget_name(widget) XtName(widget)
+# define widget_display(widget) XtDisplay(widget)
+# define widget_screen(widget) XtScreen(widget)
+# define CB_ARGS(a,b,c) (a,b,c)
 
-#else  /* HAVE_ATHENA */
+#elif defined(HAVE_ATHENA)
 
 # define set_toggle_button_state(toggle,state) \
   XtVaSetValues((toggle), XtNstate, (state),  0)
@@ -144,20 +196,24 @@ extern Widget verbose_toggle, install_cmap_toggle, fade_toggle, unfade_toggle,
   XtAddCallback ((button), XtNcallback, (cb), (arg))
 # define add_toggle_callback add_button_callback
 # define add_text_callback(b,c,a) ERROR!
+# define disable_widget(widget) \
+  XtVaSetValues((widget), XtNsensitive, False, 0)
+# define widget_name(widget) XtName(widget)
+# define widget_display(widget) XtDisplay(widget)
+# define widget_screen(widget) XtScreen(widget)
+# define CB_ARGS(a,b,c) (a,b,c)
 
 #endif /* HAVE_ATHENA */
 
 
-#define disable_widget(widget) \
-  XtVaSetValues((widget), XtNsensitive, False, 0)
 
 
 static char *
-get_text_string (Widget text_widget)
+get_text_string (WIDGET text_widget)
 {
 #ifdef HAVE_MOTIF
   return XmTextGetString (text_widget);
-#else  /* HAVE_ATHENA */
+#elif defined(HAVE_ATHENA)
   char *string = 0;
   if (XtIsSubclass(text_widget, textWidgetClass))
     XtVaGetValues (text_widget, XtNstring, &string, 0);
@@ -170,8 +226,9 @@ get_text_string (Widget text_widget)
 #endif /* HAVE_ATHENA */
 }
 
+
 static char *
-get_label_string (Widget label_widget)
+get_label_string (WIDGET label_widget)
 {
 #ifdef HAVE_MOTIF
   char *label = 0;
@@ -181,7 +238,7 @@ get_label_string (Widget label_widget)
     return 0;
   XmStringGetLtoR (xm_label, XmSTRING_DEFAULT_CHARSET, &label);
   return label;
-#else  /* HAVE_ATHENA */
+#elif defined(HAVE_ATHENA)
   char *label = 0;
   XtVaGetValues (label_widget, XtNlabel, &label, 0);
   return (label ? strdup(label) : 0);
@@ -190,25 +247,28 @@ get_label_string (Widget label_widget)
 
 
 static void
-set_label_string (Widget label_widget, char *string)
+set_label_string (WIDGET label_widget, char *string)
 {
 #ifdef HAVE_MOTIF
   XmString xm_string = XmStringCreate (string, XmSTRING_DEFAULT_CHARSET);
   XtVaSetValues (label_widget, XmNlabelString, xm_string, 0);
   XmStringFree (xm_string);
-#else  /* HAVE_ATHENA */
+#elif defined(HAVE_ATHENA)
   XtVaSetValues (label_widget, XtNlabel, string, 0);
 #endif /* HAVE_ATHENA */
 }
 
 
+/* Given a label widget that has a %s in it, do the printf thing.
+   If the label's string is obviously wrong, complain about resource lossage.
+ */
 static void
-format_into_label (Widget label, const char *arg)
+format_into_label (WIDGET label, const char *arg)
 {
   char *text = get_label_string (label);
   char *buf = (char *) malloc ((text ? strlen(text) : 0) + strlen(arg) + 100);
 
-  if (!text || !strcmp (text, XtName (label)))
+  if (!text || !*text || !strcmp (text, widget_name (label)))
       strcpy (buf, "ERROR: RESOURCES ARE NOT INSTALLED CORRECTLY");
     else
       sprintf (buf, text, arg);
@@ -222,7 +282,7 @@ format_into_label (Widget label, const char *arg)
 /* Why this behavior isn't automatic in *either* toolkit, I'll never know.
  */
 static void
-ensure_selected_item_visible (Widget list)
+ensure_selected_item_visible (WIDGET list)
 {
 #ifdef HAVE_MOTIF
   int *pos_list = 0;
@@ -249,7 +309,7 @@ ensure_selected_item_visible (Widget list)
   if (pos_list)
     XtFree ((char *) pos_list);
 
-#else  /* HAVE_ATHENA */
+#elif defined(HAVE_ATHENA)
 # ifdef HAVE_XawViewportSetCoordinates
 
   int margin = 16;     /* should be line height or something. */
@@ -302,6 +362,31 @@ ensure_selected_item_visible (Widget list)
 }
 
 
+#ifdef HAVE_ATHENA
+static void
+set_hack_list (Widget demo_list, saver_preferences *p)
+{
+  char **strings = (char **) calloc (sizeof (char *), p->screenhacks_count);
+  int i;
+  for (i = 0; i < p->screenhacks_count; i++)
+    strings[i] = format_hack (p->screenhacks[i], False);
+  XtVaSetValues (demo_list,
+                 XtNlist, strings,
+                 XtNnumberStrings, p->screenhacks_count,
+                 0);
+# if 0
+  for (i = 0; i < p->screenhacks_count; i++)
+    {
+      free (strings[i]);
+      strings[i] = (char *) 0xDEADBEEF;
+    }
+  free (strings);
+# endif
+}
+#endif /* HAVE_ATHENA */
+
+
+
 /* Callback for the text area:
    - note the text the user has entered;
    - change the corresponding element in `screenhacks';
@@ -309,41 +394,40 @@ ensure_selected_item_visible (Widget list)
    - tell the xscreensaver daemon to run that hack.
  */
 static void
-text_cb (Widget text_widget, XtPointer client_data, XtPointer call_data)
+text_cb (WIDGET text_widget, POINTER client_data, POINTER call_data)
 {
-  Display *dpy = XtDisplay (text_widget);
   saver_preferences *p = (saver_preferences *) client_data;
   char *new_text = get_text_string (text_widget);
+  Display *dpy = widget_display (text_widget);
+  Bool save = TRUE;
 
   int hack_number = -1;                /* 0-based */
 
 #ifdef HAVE_ATHENA
   XawListReturnStruct *current = XawListShowCurrent(demo_list);
   hack_number = current->list_index;
-#else  /* HAVE_MOTIF */
+#elif defined(HAVE_MOTIF)
   int *pos_list = 0;
   int pos_count = 0;
   if (XmListGetSelectedPos (demo_list, &pos_list, &pos_count))
     hack_number = pos_list[0] - 1;
   if (pos_list)
     XtFree ((char *) pos_list);
-#endif /* HAVE_MOTIF */
+#endif /* HAVE_ATHENA */
 
   ensure_selected_item_visible (demo_list);
 
   if (hack_number < 0 || hack_number >= p->screenhacks_count)
     {
       set_text_string (text_widget, "");
-      XBell (dpy, 0);
+      XBell (XtDisplay (text_widget), 0);
     }
   else
     {
-fprintf(stderr, "%d:\nold: %s\nnew: %s\n",
-       hack_number, p->screenhacks [hack_number], new_text);
-
+      screenhack *new_hack = parse_screenhack (new_text);
       if (p->screenhacks [hack_number])
-       free (p->screenhacks [hack_number]);
-      p->screenhacks [hack_number] = strdup (new_text);
+       free_screenhack (p->screenhacks [hack_number]);
+      p->screenhacks [hack_number] = new_hack;
 
 #ifdef HAVE_MOTIF
 
@@ -355,7 +439,7 @@ fprintf(stderr, "%d:\nold: %s\nnew: %s\n",
       }
       XmListSelectPos (demo_list, hack_number+1, True);
 
-#else  /* HAVE_ATHENA */
+#elif defined(HAVE_ATHENA)
 
       {
        Widget vp = XtParent(demo_list);
@@ -365,22 +449,20 @@ fprintf(stderr, "%d:\nold: %s\nnew: %s\n",
        float sb_top = 0;
 
        XawListUnhighlight (demo_list);
-
        XtVaGetValues (vp, XtNx, &vp_x, 0);
        XtVaGetValues (sb, XtNtopOfThumb, &sb_top, 0);
        XtVaGetValues (demo_list, XtNheight, &list_h, 0);
        vp_y = (sb_top * list_h);
-       XtVaSetValues (demo_list,
-                      XtNlist, p->screenhacks,
-                      XtNnumberStrings, p->screenhacks_count,
-                      0);
+        set_hack_list (demo_list, p);
        XawViewportSetCoordinates (vp, vp_x, vp_y);
        XawListHighlight (demo_list, hack_number);
       }
 
 #endif /* HAVE_ATHENA */
 
-      write_init_file (p, short_version);
+      if (save)
+        write_init_file (p, short_version);
+
       XSync (dpy, False);
       usleep (500000);         /* give the disk time to settle down */
 
@@ -410,7 +492,7 @@ static char translations[] = ("<Key>Return: done()\n"
 /* Callback for the Run Next button.
  */
 static void
-next_cb (Widget button, XtPointer client_data, XtPointer call_data)
+next_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored)
 {
 #ifdef HAVE_ATHENA
   XawListReturnStruct *current = XawListShowCurrent(demo_list);
@@ -429,7 +511,7 @@ next_cb (Widget button, XtPointer client_data, XtPointer call_data)
 
   run_hack (XtDisplay (button), current->list_index + 1);
 
-#else  /* HAVE_MOTIF */
+#elif defined(HAVE_MOTIF)
 
   saver_preferences *p = (saver_preferences *) client_data;
   int *pos_list = 0;
@@ -462,7 +544,7 @@ next_cb (Widget button, XtPointer client_data, XtPointer call_data)
 /* Callback for the Run Previous button.
  */
 static void
-prev_cb (Widget button, XtPointer client_data, XtPointer call_data)
+prev_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored)
 {
 #ifdef HAVE_ATHENA
   XawListReturnStruct *current = XawListShowCurrent(demo_list);
@@ -481,7 +563,7 @@ prev_cb (Widget button, XtPointer client_data, XtPointer call_data)
 
   run_hack (XtDisplay (button), current->list_index + 1);
 
-#else  /* HAVE_MOTIF */
+#elif defined(HAVE_MOTIF)
 
   saver_preferences *p = (saver_preferences *) client_data;
   int *pos_list = 0;
@@ -514,7 +596,7 @@ prev_cb (Widget button, XtPointer client_data, XtPointer call_data)
 /* Callback run when a list element is double-clicked.
  */
 static void
-select_cb (Widget button, XtPointer client_data, XtPointer call_data)
+select_cb (WIDGET button, POINTER client_data, POINTER call_data)
 {
 /*  saver_preferences *p = (saver_preferences *) client_data; */
 
@@ -523,7 +605,7 @@ select_cb (Widget button, XtPointer client_data, XtPointer call_data)
   XtVaSetValues(text_line, XtNstring, item->string, 0);
   run_hack (XtDisplay (button), item->list_index + 1);
 
-#else  /* HAVE_MOTIF */
+#elif defined(HAVE_MOTIF)
   XmListCallbackStruct *lcb = (XmListCallbackStruct *) call_data;
   char *string = 0;
   if (lcb->item)
@@ -535,18 +617,18 @@ select_cb (Widget button, XtPointer client_data, XtPointer call_data)
 
   if (string)
     XtFree (string);
+
 #endif /* HAVE_MOTIF */
 }
 
 
-
 static void pop_preferences_dialog (prefs_pair *pair);
 static void make_preferences_dialog (prefs_pair *pair, Widget parent);
 
 /* Callback for the Preferences button.
  */
 static void
-preferences_cb (Widget button, XtPointer client_data, XtPointer call_data)
+preferences_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored)
 {
   prefs_pair *pair = (prefs_pair *) client_data;
   Widget parent = button;
@@ -557,13 +639,15 @@ preferences_cb (Widget button, XtPointer client_data, XtPointer call_data)
 
   if (! preferences_dialog)
     make_preferences_dialog (pair, parent);
+  *pair->b = *pair->a;
   pop_preferences_dialog (pair);
 }
 
+
 /* Callback for the Quit button.
  */
 static void
-quit_cb (Widget button, XtPointer client_data, XtPointer call_data)
+quit_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored)
 {
   /* Save here?  Right now we don't need to, because we save every time
      the text field is edited, or the Preferences OK button is pressed.
@@ -575,22 +659,77 @@ quit_cb (Widget button, XtPointer client_data, XtPointer call_data)
 /* Callback for the (now unused) Restart button.
  */
 static void
-restart_cb (Widget button, XtPointer client_data, XtPointer call_data)
+restart_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored)
 {
-  xscreensaver_command (XtDisplay (button), XA_RESTART, 0, False);
+  xscreensaver_command (widget_display (button), XA_RESTART, 0, False);
 }
 
 
+/* Finds the number of the last hack to run, and makes that item be
+   selected by default.
+ */
 static void
-pop_up_dialog_box (Widget dialog, Widget form)
+scroll_to_current_hack (WIDGET dialog)
+{
+  Atom type;
+  int format;
+  unsigned long nitems, bytesafter;
+  CARD32 *data = 0;
+  Display *dpy = widget_display (dialog);
+  int hack = 0;
+
+  if (XGetWindowProperty (dpy, RootWindow (dpy, 0), /* always screen #0 */
+                          XA_SCREENSAVER_STATUS,
+                          0, 3, False, XA_INTEGER,
+                          &type, &format, &nitems, &bytesafter,
+                          (unsigned char **) &data)
+      == Success
+      && type == XA_INTEGER
+      && nitems >= 3
+      && data)
+    hack = (int) data[2];
+
+  if (data) free (data);
+
+  if (hack <= 0)
+    return;
+
+#ifdef HAVE_MOTIF
+  XmListDeselectAllItems (demo_list);  /* LessTif lossage */
+  XmListSelectPos (demo_list, hack, False);
+  ensure_selected_item_visible (demo_list);
+
+#elif defined(HAVE_ATHENA)
+  XawListUnhighlight (demo_list);
+  XawListHighlight (demo_list, hack - 1);
+
+#endif /* HAVE_ATHENA */
+}
+
+
+static void
+pop_up_dialog_box (WIDGET dialog, WIDGET form)
 {
 #ifdef HAVE_ATHENA
   XtRealizeWidget (dialog);
   XtPopup (dialog, XtGrabNone);
-#else  /* HAVE_MOTIF */
+#elif defined(HAVE_MOTIF)
   XtRealizeWidget (form);
   XtManageChild (form);
+
+  /* Motif likes to make the dialog wider than the screen; throttle it. */
+  {
+    Dimension w=0, h=0, bw=0;
+    Dimension max_w;
+    Screen *screen = 0;
+    XtVaGetValues (dialog, XtNscreen, &screen, 0);
+    max_w = WidthOfScreen (screen) * 0.8;
+    XtVaGetValues(dialog, XtNwidth, &w, XtNheight, &h, XtNborderWidth, &bw, 0);
+    if (w > max_w)
+      XtResizeWidget(dialog, max_w, h, bw);
+  }
 #endif /* HAVE_MOTIF */
+
   XMapRaised (XtDisplay (dialog), XtWindow (dialog));
 }
 
@@ -600,38 +739,41 @@ make_demo_dialog (Widget toplevel_shell, prefs_pair *pair)
 {
   saver_preferences *p =  pair->a;
   /* saver_preferences *p2 = pair->b; */
-
   Widget parent = toplevel_shell;
-  char **hacks = p->screenhacks;
+#ifdef HAVE_MOTIF
+  screenhack **hacks = p->screenhacks;
+#endif /* HAVE_MOTIF */
 
   create_demo_dialog (parent,
-                     DefaultVisualOfScreen (XtScreen (parent)),
-                     DefaultColormapOfScreen (XtScreen (parent)));
-  format_into_label (label1, short_version);
+                      DefaultVisualOfScreen (widget_screen (parent)),
+                     DefaultColormapOfScreen (widget_screen (parent)));
 
-  add_button_callback (next,    next_cb,        (XtPointer) p);
-  add_button_callback (prev,    prev_cb,        (XtPointer) p);
-  add_button_callback (done,    quit_cb,        (XtPointer) p);
+  format_into_label (label1, short_version);
+  add_button_callback (next,    next_cb,        (POINTER) p);
+  add_button_callback (prev,    prev_cb,        (POINTER) p);
+  add_button_callback (done,    quit_cb,        (POINTER) p);
   if (restart)
-    add_button_callback(restart,restart_cb,     (XtPointer) p);
-  add_button_callback (edit,    preferences_cb, (XtPointer) pair);
+    add_button_callback(restart,restart_cb,     (POINTER) p);
+  add_button_callback (edit,    preferences_cb, (POINTER) pair);
 
 #ifdef HAVE_MOTIF
   XtAddCallback (demo_list, XmNbrowseSelectionCallback,
-                select_cb, (XtPointer) p);
+                select_cb, (POINTER) p);
   XtAddCallback (demo_list, XmNdefaultActionCallback,
-                select_cb, (XtPointer) p);
-  XtAddCallback (text_line, XmNactivateCallback, text_cb, (XtPointer) p);
+                select_cb, (POINTER) p);
+  XtAddCallback (text_line, XmNactivateCallback, text_cb, (POINTER) p);
 
   if (hacks)
     for (; *hacks; hacks++)
       {
-       XmString xmstr = XmStringCreate (*hacks, XmSTRING_DEFAULT_CHARSET);
+        char *hs = format_hack (*hacks, False);
+       XmString xmstr = XmStringCreate (hs, XmSTRING_DEFAULT_CHARSET);
        XmListAddItem (demo_list, xmstr, 0);
        XmStringFree (xmstr);
+        free (hs);
       }
 
-#else  /* HAVE_ATHENA */
+#elif defined(HAVE_ATHENA)
 
   /* Hook up the text line. */
 
@@ -645,10 +787,7 @@ make_demo_dialog (Widget toplevel_shell, prefs_pair *pair)
   */
   XtRealizeWidget (demo_dialog);
 
-  XtVaSetValues (demo_list,
-                XtNlist, hacks,
-                XtNnumberStrings, p->screenhacks_count,
-                0);
+  set_hack_list (demo_list, p);
   XtAddCallback (demo_list, XtNcallback, select_cb, p);
 
   /* Now that we've populated the list, make sure that the list is as
@@ -694,10 +833,12 @@ make_demo_dialog (Widget toplevel_shell, prefs_pair *pair)
 
 #endif /* HAVE_ATHENA */
 
+  scroll_to_current_hack (demo_dialog);
+
   pop_up_dialog_box(demo_dialog, demo_form);
 
-#ifdef HAVE_ATHENA
-  /* For Athena, have to do this after the dialog is managed. */
+#if defined(HAVE_ATHENA)
+  /* For Athena and Gtk, have to do this after the dialog is managed. */
   ensure_selected_item_visible (demo_list);
 #endif /* HAVE_ATHENA */
 }
@@ -726,13 +867,13 @@ hack_time_text (Display *dpy, char *line, Time *store, Bool sec_p)
 
 
 /* Callback for text fields that hold a time that default to seconds,
-   when not fully spelled out.  client_data is an Time* where the value goes.
+   when not fully spelled out.  client_data is a Time* where the value goes.
  */
 static void
-prefs_sec_cb (Widget button, XtPointer client_data, XtPointer call_data)
+prefs_sec_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored)
 {
-  hack_time_text (XtDisplay (button), get_text_string (button),
-               (Time *) client_data, True);
+  hack_time_text (widget_display (button), get_text_string (button),
+                  (Time *) client_data, True);
 }
 
 
@@ -740,10 +881,10 @@ prefs_sec_cb (Widget button, XtPointer client_data, XtPointer call_data)
    when not fully spelled out.  client_data is an Time* where the value goes.
  */
 static void
-prefs_min_cb (Widget button, XtPointer client_data, XtPointer call_data)
+prefs_min_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored)
 {
-  hack_time_text (XtDisplay (button), get_text_string (button),
-               (Time *) client_data, False);
+  hack_time_text (widget_display (button), get_text_string (button),
+                  (Time *) client_data, False);
 }
 
 
@@ -751,7 +892,7 @@ prefs_min_cb (Widget button, XtPointer client_data, XtPointer call_data)
    client_data is an int* where the value goes.
  */
 static void
-prefs_int_cb (Widget button, XtPointer client_data, XtPointer call_data)
+prefs_int_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored)
 {
   char *line = get_text_string (button);
   int *store = (int *) client_data;
@@ -765,15 +906,16 @@ prefs_int_cb (Widget button, XtPointer client_data, XtPointer call_data)
     *store = value;
 }
 
-/* Callback for toggle buttons.  client_data is an Bool* where the value goes.
+
+/* Callback for toggle buttons.  client_data is a Bool* where the value goes.
  */
 static void
-prefs_bool_cb (Widget button, XtPointer client_data, XtPointer call_data)
+prefs_bool_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER call_data)
 {
   Bool *store = (Bool *) client_data;
 #ifdef HAVE_MOTIF
   *store = ((XmToggleButtonCallbackStruct *) call_data)->set;
-#else /* HAVE_ATHENA */
+#elif defined(HAVE_ATHENA)
   Boolean state = FALSE;
   XtVaGetValues (button, XtNstate, &state, 0);
   *store = state;
@@ -784,7 +926,7 @@ prefs_bool_cb (Widget button, XtPointer client_data, XtPointer call_data)
 /* Callback for the Cancel button on the Preferences dialog.
  */
 static void
-prefs_cancel_cb (Widget button, XtPointer client_data, XtPointer call_data)
+prefs_cancel_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored)
 {
   XtDestroyWidget (preferences_dialog);
   preferences_dialog = 0;
@@ -795,23 +937,23 @@ prefs_cancel_cb (Widget button, XtPointer client_data, XtPointer call_data)
 /* Callback for the OK button on the Preferences dialog.
  */
 static void
-prefs_ok_cb (Widget button, XtPointer client_data, XtPointer call_data)
+prefs_ok_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER call_data)
 {
   prefs_pair *pair = (prefs_pair *) client_data;
   saver_preferences *p =  pair->a;
   saver_preferences *p2 = pair->b;
 
-  prefs_cancel_cb (button, 0, call_data);
+  prefs_cancel_cb CB_ARGS(button, client_data, call_data);
 
 #ifdef HAVE_ATHENA
   /* Athena doesn't let us put callbacks on these widgets, so run
      all the callbacks by hand when OK is pressed. */
-  prefs_min_cb (timeout_text,        (XtPointer) &p2->timeout,        0);
-  prefs_min_cb (cycle_text,          (XtPointer) &p2->cycle,          0);
-  prefs_sec_cb (fade_text,           (XtPointer) &p2->fade_seconds,   0);
-  prefs_int_cb (fade_ticks_text,     (XtPointer) &p2->fade_ticks,     0);
-  prefs_min_cb (lock_timeout_text,   (XtPointer) &p2->lock_timeout,   0);
-  prefs_sec_cb (passwd_timeout_text, (XtPointer) &p2->passwd_timeout, 0);
+  prefs_min_cb (timeout_text,        (POINTER) &p2->timeout,        0);
+  prefs_min_cb (cycle_text,          (POINTER) &p2->cycle,          0);
+  prefs_sec_cb (fade_text,           (POINTER) &p2->fade_seconds,   0);
+  prefs_int_cb (fade_ticks_text,     (POINTER) &p2->fade_ticks,     0);
+  prefs_min_cb (lock_timeout_text,   (POINTER) &p2->lock_timeout,   0);
+  prefs_sec_cb (passwd_timeout_text, (POINTER) &p2->passwd_timeout, 0);
 #endif /* HAVE_ATHENA */
 
   p->timeout       = p2->timeout;
@@ -836,24 +978,24 @@ make_preferences_dialog (prefs_pair *pair, Widget parent)
   saver_preferences *p =  pair->a;
   saver_preferences *p2 = pair->b;
 
-  Screen *screen = XtScreen (parent);
-  Display *dpy = XtDisplay (parent);
+  Screen *screen = widget_screen (parent);
+  Display *dpy = widget_display (parent);
 
   *p2 = *p;    /* copy all slots of p into p2. */
 
   create_preferences_dialog (parent,
-                            DefaultVisualOfScreen (screen),
-                            DefaultColormapOfScreen (screen));
+                             DefaultVisualOfScreen (screen),
+                             DefaultColormapOfScreen (screen));
 
-  add_button_callback (prefs_done,   prefs_ok_cb,     (XtPointer) pair);
+  add_button_callback (prefs_done,   prefs_ok_cb,     (POINTER) pair);
   add_button_callback (prefs_cancel, prefs_cancel_cb, 0);
 
 #define CB(widget,type,slot) \
-       add_text_callback ((widget), (type), (XtPointer) (slot))
+       add_text_callback ((widget), (type), (POINTER) (slot))
 #define CBT(widget,type,slot) \
-       add_toggle_callback ((widget), (type), (XtPointer) (slot))
+       add_toggle_callback ((widget), (type), (POINTER) (slot))
 
-#ifdef HAVE_MOTIF
+#ifndef HAVE_ATHENA
   /* When using Athena widgets, we can't set callbacks for these,
      so in that case, we run them by hand when "OK" is pressed. */
   CB (timeout_text,            prefs_min_cb,  &p2->timeout);
@@ -862,7 +1004,8 @@ make_preferences_dialog (prefs_pair *pair, Widget parent)
   CB (fade_ticks_text,         prefs_int_cb,  &p2->fade_ticks);
   CB (lock_timeout_text,       prefs_min_cb,  &p2->lock_timeout);
   CB (passwd_timeout_text,     prefs_sec_cb,  &p2->passwd_timeout);
-#endif /* HAVE_MOTIF */
+
+#endif /* !HAVE_ATHENA */
 
   CBT (verbose_toggle,         prefs_bool_cb, &p2->verbose_p);
   CBT (install_cmap_toggle,    prefs_bool_cb, &p2->install_cmap_p);
@@ -952,22 +1095,23 @@ run_hack (Display *dpy, int n)
 
 
 static void
-warning_dialog_dismiss_cb (Widget button, XtPointer client_data,
-                          XtPointer call_data)
+warning_dialog_dismiss_cb CB_ARGS(WIDGET button, POINTER client_data,
+                                  POINTER ignored)
 {
-  Widget shell = (Widget) client_data;
+  WIDGET shell = (WIDGET) client_data;
   XtDestroyWidget (shell);
 }
 
+
 static void
-warning_dialog (Widget parent, const char *message)
+warning_dialog (WIDGET parent, const char *message)
 {
   char *msg = strdup (message);
   char *head;
 
-  Widget dialog = 0;
-  Widget label = 0;
-  Widget ok = 0;
+  WIDGET dialog = 0;
+  WIDGET label = 0;
+  WIDGET ok = 0;
   int i = 0;
 
 #ifdef HAVE_MOTIF
@@ -998,13 +1142,12 @@ warning_dialog (Widget parent, const char *message)
   XtSetArg (av[ac], XmNspacing, 0); ac++;
   container = XmCreateRowColumn (dialog, "container", av, ac);
 
-#else  /* HAVE_ATHENA */
+#elif defined(HAVE_ATHENA)
 
   Widget form;
   dialog = XtVaCreatePopupShell("warning_dialog", transientShellWidgetClass,
                                parent, 0);
   form = XtVaCreateManagedWidget("warning_form", formWidgetClass, dialog, 0);
-
 #endif /* HAVE_ATHENA */
 
   head = msg;
@@ -1023,7 +1166,7 @@ warning_dialog (Widget parent, const char *message)
       label = XmCreateLabelGadget (container, name, av, ac);
       XtManageChild (label);
       XmStringFree (xmstr);
-#else  /* HAVE_ATHENA */
+#elif defined(HAVE_ATHENA)
       
       label = XtVaCreateManagedWidget (name, labelWidgetClass,
                                       form,
@@ -1048,7 +1191,7 @@ warning_dialog (Widget parent, const char *message)
   XtRealizeWidget (dialog);
   XtManageChild (dialog);
 
-#else  /* HAVE_ATHENA */
+#elif defined(HAVE_ATHENA)
 
   ok = XtVaCreateManagedWidget ("ok", commandWidgetClass, form,
                                XtNleft, XtChainLeft,
@@ -1058,10 +1201,9 @@ warning_dialog (Widget parent, const char *message)
 
   XtRealizeWidget (dialog);
   XtPopup (dialog, XtGrabNone);
-
 #endif /* HAVE_ATHENA */
 
-  add_button_callback (ok, warning_dialog_dismiss_cb, dialog);
+  add_button_callback (ok, warning_dialog_dismiss_cb, (POINTER) dialog);
 
   free (msg);
 }
@@ -1094,10 +1236,11 @@ mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
 }
 #endif
 
+
 static void
-the_network_is_not_the_computer (Widget parent)
+the_network_is_not_the_computer (WIDGET parent)
 {
-  Display *dpy = XtDisplay (parent);
+  Display *dpy = widget_display (parent);
   char *rversion, *ruser, *rhost;
   char *luser, *lhost;
   char *msg = 0;
@@ -1205,6 +1348,21 @@ the_network_is_not_the_computer (Widget parent)
 }
 
 
+/* We use this error handler so that X errors are preceeded by the name
+   of the program that generated them.
+ */
+static int
+demo_ehandler (Display *dpy, XErrorEvent *error)
+{
+  fprintf (stderr, "\nX error in %s:\n", progname);
+  if (XmuPrintDefaultErrorMessage (dpy, error, stderr))
+    exit (-1);
+  else
+    fprintf (stderr, " (nonfatal.)\n");
+  return 0;
+}
+
+
 static char *defaults[] = {
 #include "XScreenSaver_ad.h"
  0
@@ -1234,19 +1392,27 @@ main (int argc, char **argv)
   memset (p,  0, sizeof (*p));
   memset (p2, 0, sizeof (*p2));
 
+  progname = real_progname;
+
   /* We must read exactly the same resources as xscreensaver.
      That means we must have both the same progclass *and* progname,
      at least as far as the resource database is concerned.  So,
      put "xscreensaver" in argv[0] while initializing Xt.
    */
   argv[0] = "xscreensaver";
+  progname = argv[0];
+
 
   toplevel_shell = XtAppInitialize (&app, progclass, 0, 0, &argc, argv,
                                    defaults, 0, 0);
+
   dpy = XtDisplay (toplevel_shell);
   db = XtDatabase (dpy);
   XtGetApplicationNameAndClass (dpy, &progname, &progclass);
+  XSetErrorHandler (demo_ehandler);
 
+  /* Complain about unrecognized command-line arguments.
+   */
   for (i = 1; i < argc; i++)
     {
       char *s = argv[i];
@@ -1266,18 +1432,22 @@ main (int argc, char **argv)
   memcpy (short_version, screensaver_id + 17, 4);
   short_version [4] = 0;
 
-
-  /* Now that Xt has been initialized, we can set our `progname' variable
-     to something that makes more sense (like our "real" argv[0].)
+  /* Load the init file, which may end up consulting the X resource database
+     and the site-wide app-defaults file.  Note that at this point, it's
+     important that `progname' be "xscreensaver", rather than whatever
+     was in argv[0].
    */
-  progname = real_progname;
-
-
   p->db = db;
-  p->fading_possible_p = True;
   load_init_file (p);
   *p2 = *p;
 
+  /* Now that Xt has been initialized, and the resources have been read,
+     we can set our `progname' variable to something more in line with
+     reality.
+   */
+  progname = real_progname;
+
+
 #ifdef HAVE_ATHENA
   global_prefs_kludge = p;     /* I hate C so much... */
 #endif /* HAVE_ATHENA */
@@ -1288,7 +1458,7 @@ main (int argc, char **argv)
     XrmClass class = { 0 };
     int count = 0;
     XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, mapper,
-                         (XtPointer) &count);
+                         (POINTER) &count);
   }
 #endif
 
@@ -1296,11 +1466,14 @@ main (int argc, char **argv)
   XA_VROOT = XInternAtom (dpy, "__SWM_VROOT", False);
   XA_SCREENSAVER = XInternAtom (dpy, "SCREENSAVER", False);
   XA_SCREENSAVER_VERSION = XInternAtom (dpy, "_SCREENSAVER_VERSION",False);
-  XA_SCREENSAVER_TIME = XInternAtom (dpy, "_SCREENSAVER_TIME", False);
+  XA_SCREENSAVER_STATUS = XInternAtom (dpy, "_SCREENSAVER_STATUS", False);
   XA_SCREENSAVER_ID = XInternAtom (dpy, "_SCREENSAVER_ID", False);
   XA_SCREENSAVER_RESPONSE = XInternAtom (dpy, "_SCREENSAVER_RESPONSE", False);
   XA_SELECT = XInternAtom (dpy, "SELECT", False);
   XA_DEMO = XInternAtom (dpy, "DEMO", False);
+  XA_BLANK = XInternAtom (dpy, "BLANK", False);
+  XA_LOCK = XInternAtom (dpy, "LOCK", False);
+  XA_EXIT = XInternAtom (dpy, "EXIT", False);
   XA_RESTART = XInternAtom (dpy, "RESTART", False);
 
   make_demo_dialog (toplevel_shell, pair);
@@ -1315,6 +1488,7 @@ main (int argc, char **argv)
                                   ? preferences_dialog
                                   : demo_dialog);
 
-  XtAppMainLoop(app);
+  XtAppMainLoop (app);
+
   exit (0);
 }