http://ftp.x.org/contrib/applications/xscreensaver-2.34.tar.gz
[xscreensaver] / driver / demo.c
index ec957243e0e30aea47c7332e44b91ddd10e7f3fa..c7a12ba3eb4b4c5e458440768e9672a8ff6f287a 100644 (file)
@@ -1,4 +1,5 @@
-/* xscreensaver, Copyright (c) 1993 Jamie Zawinski <jwz@lucid.com>
+/* demo.c --- implements the interactive demo-mode and options dialogs.
+ * xscreensaver, Copyright (c) 1993-1998 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
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
  * implied warranty.
  */
 
  * implied warranty.
  */
 
-#include <X11/Intrinsic.h>
-
-#if !__STDC__
-# define _NO_PROTO
+#ifdef HAVE_CONFIG_H
+# include "config.h"
 #endif
 
 #endif
 
-#include <Xm/Xm.h>
-#include <Xm/Text.h>
-#include <Xm/List.h>
-#include <Xm/ToggleB.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+
+/* We don't actually use any widget internals, but these are included
+   so that gdb will have debug info for the widgets... */
+#include <X11/IntrinsicP.h>
+#include <X11/ShellP.h>
+
+#ifdef HAVE_MOTIF
+# include <Xm/Xm.h>
+# include <Xm/Text.h>
+# include <Xm/List.h>
+# include <Xm/ToggleB.h>
+
+#else  /* 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>
+# include <X11/Xaw/Form.h>
+# include <X11/Xaw/Box.h>
+# include <X11/Xaw/List.h>
+# include <X11/Xaw/Command.h>
+# include <X11/Xaw/Toggle.h>
+# include <X11/Xaw/Viewport.h>
+# include <X11/Xaw/Dialog.h>
+# include <X11/Xaw/Scrollbar.h>
+# include <X11/Xaw/Text.h>
+#endif /* HAVE_ATHENA */
 
 #include "xscreensaver.h"
 
 #include "xscreensaver.h"
+#include "resources.h"         /* for parse_time() */
 #include <stdio.h>
 #include <stdio.h>
+#include <string.h>
+#include <ctype.h>
 
 
-extern Time timeout, cycle, lock_timeout, passwd_timeout;
-extern int fade_seconds, fade_ticks;
-extern Bool verbose_p, install_cmap_p, fade_p, unfade_p;
-extern Bool lock_p, locking_disabled_p;
-
-static void demo_mode_hack P((char *));
-static void demo_mode_done P((void));
+#ifdef _VROOT_H_
+ERROR!  You must not include vroot.h in this file.
+#endif
 
 
-extern void demo_mode_restart_process ();
+static void demo_mode_hack (saver_info *si, char *);
+static void demo_mode_done (saver_info *si);
 
 extern Widget demo_dialog;
 extern Widget label1;
 
 extern Widget demo_dialog;
 extern Widget label1;
@@ -48,133 +71,449 @@ extern Widget lock_time_text, passwd_time_text;
 extern Widget verbose_toggle, cmap_toggle, fade_toggle, unfade_toggle,
   lock_toggle;
 
 extern Widget verbose_toggle, cmap_toggle, fade_toggle, unfade_toggle,
   lock_toggle;
 
-extern create_demo_dialog ();
-extern create_resources_dialog ();
+
+#ifdef HAVE_MOTIF
+
+# define set_toggle_button_state(toggle,state) \
+  XmToggleButtonSetState ((toggle), (state), True)
+# define set_text_string(text_widget,string) \
+  XmTextSetString ((text_widget), (string))
+# define add_button_callback(button,cb,arg) \
+  XtAddCallback ((button), XmNactivateCallback, (cb), (arg))
+# define add_toggle_callback(button,cb,arg) \
+  XtAddCallback ((button), XmNvalueChangedCallback, (cb), (arg))
+# define add_text_callback add_toggle_callback
+
+#else  /* HAVE_ATHENA */
+
+# define set_toggle_button_state(toggle,state) \
+  XtVaSetValues((toggle), XtNstate, (state),  0)
+# define set_text_string(text_widget,string) \
+  XtVaSetValues ((text_widget), XtNvalue, (string), 0)
+# define add_button_callback(button,cb,arg) \
+  XtAddCallback ((button), XtNcallback, (cb), (arg))
+# define add_toggle_callback add_button_callback
+# define add_text_callback(b,c,a) ERROR!
+
+#endif /* HAVE_ATHENA */
+
+
+#define disable_widget(widget) \
+  XtVaSetValues((widget), XtNsensitive, False, 0)
+
+
+static char *
+get_text_string (Widget text_widget)
+{
+#ifdef HAVE_MOTIF
+  return XmTextGetString (text_widget);
+#else  /* HAVE_ATHENA */
+  char *string = 0;
+  if (XtIsSubclass(text_widget, textWidgetClass))
+    XtVaGetValues (text_widget, XtNstring, &string, 0);
+  else if (XtIsSubclass(text_widget, dialogWidgetClass))
+    XtVaGetValues (text_widget, XtNvalue, &string, 0);
+  else
+    string = 0;
+
+  return string;
+#endif /* HAVE_ATHENA */
+}
+
+static char *
+get_label_string (Widget label_widget)
+{
+#ifdef HAVE_MOTIF
+  char *label = 0;
+  XmString xm_label = 0;
+  XtVaGetValues (label_widget, XmNlabelString, &xm_label, 0);
+  if (!xm_label)
+    return 0;
+  XmStringGetLtoR (xm_label, XmSTRING_DEFAULT_CHARSET, &label);
+  return label;
+#else  /* HAVE_ATHENA */
+  char *label = 0;
+  XtVaGetValues (label_widget, XtNlabel, &label, 0);
+  return (label ? strdup(label) : 0);
+#endif /* HAVE_ATHENA */
+}
+
 
 static void
 
 static void
-focus_fuckus (dialog)
-     Widget dialog;
+set_label_string (Widget label_widget, char *string)
 {
 {
-  XSetInputFocus (XtDisplay (dialog), XtWindow (dialog),
-                 RevertToParent, CurrentTime);
+#ifdef HAVE_MOTIF
+  XmString xm_string = XmStringCreate (string, XmSTRING_DEFAULT_CHARSET);
+  XtVaSetValues (label_widget, XmNlabelString, xm_string, 0);
+  XmStringFree (xm_string);
+#else  /* HAVE_ATHENA */
+  XtVaSetValues (label_widget, XtNlabel, string, 0);
+#endif /* HAVE_ATHENA */
+}
+
+
+void
+format_into_label (Widget label, const char *arg)
+{
+  char *text = get_label_string (label);
+  char *buf = (char *) malloc ((text ? strlen(text) : 100) + strlen(arg) + 10);
+
+  if (!text || !strcmp (text, XtName (label)))
+      strcpy (buf, "ERROR: RESOURCES ARE NOT INSTALLED CORRECTLY");
+    else
+      sprintf (buf, text, arg);
+
+    set_label_string (label, buf);
+    free (buf);
+    XtFree (text);
+}
+
+
+void
+steal_focus_and_colormap (Widget dialog)
+{
+  Display *dpy = XtDisplay (dialog);
+  Window window = XtWindow (dialog);
+  Colormap cmap = 0;
+  XSetInputFocus (dpy, window, RevertToParent, CurrentTime);
+
+  XtVaGetValues (dialog, XtNcolormap, &cmap, 0);
+  if (cmap)
+    XInstallColormap (dpy, cmap);
 }
 
 static void
 }
 
 static void
-raise_screenhack_dialog ()
+raise_screenhack_dialog (void)
 {
   XMapRaised (XtDisplay (demo_dialog), XtWindow (demo_dialog));
   if (resources_dialog)
     XMapRaised (XtDisplay (resources_dialog), XtWindow (resources_dialog));
 {
   XMapRaised (XtDisplay (demo_dialog), XtWindow (demo_dialog));
   if (resources_dialog)
     XMapRaised (XtDisplay (resources_dialog), XtWindow (resources_dialog));
-  focus_fuckus (resources_dialog ? resources_dialog : demo_dialog);
+  steal_focus_and_colormap (resources_dialog ? resources_dialog : demo_dialog);
 }
 
 static void
 }
 
 static void
-destroy_screenhack_dialogs ()
+destroy_screenhack_dialogs (saver_info *si)
 {
 {
+  saver_screen_info *ssi = si->default_screen;
+
   if (demo_dialog) XtDestroyWidget (demo_dialog);
   if (resources_dialog) XtDestroyWidget (resources_dialog);
   demo_dialog = resources_dialog = 0;
   if (demo_dialog) XtDestroyWidget (demo_dialog);
   if (resources_dialog) XtDestroyWidget (resources_dialog);
   demo_dialog = resources_dialog = 0;
+
+  if (ssi->demo_cmap &&
+      ssi->demo_cmap != ssi->cmap &&
+      ssi->demo_cmap != DefaultColormapOfScreen (ssi->screen))
+    {
+      XFreeColormap (si->dpy, ssi->demo_cmap);
+      ssi->demo_cmap = 0;
+    }
+
+  /* Since we installed our colormap to display the dialogs properly, put
+     the old one back, so that the screensaver_window is now displayed
+     properly. */
+  if (ssi->cmap)
+    XInstallColormap (si->dpy, ssi->cmap);
 }
 
 }
 
+
 static void
 static void
-text_cb (button, client_data, call_data)
-     Widget button;
-     XtPointer client_data, call_data;
+text_cb (Widget text_widget, XtPointer client_data, XtPointer call_data)
 {
 {
-  char *line = XmTextGetString (button);
-  demo_mode_hack (line);
+  saver_info *si = (saver_info *) client_data;
+  saver_preferences *p = &si->prefs;
+  char *line;
+  line = get_text_string (text_widget);
+
+  if (p->verbose_p)
+    fprintf (stderr, "%s: processing text \"%s\".\n", blurb(), line);
+
+  demo_mode_hack (si, line);
 }
 
 
 }
 
 
+#ifdef HAVE_ATHENA
+/* Bend over backwards to make hitting Return in the text field do the
+   right thing. 
+   */
+extern saver_info *global_si_kludge;
+static void text_enter (Widget w, XEvent *event, String *av, Cardinal *ac)
+{
+  text_cb (w, global_si_kludge, 0);
+}
+
+static XtActionsRec actions[] = {{"done",      text_enter}
+                               };
+static char translations[] = ("<Key>Return:    done()\n"
+                             "<Key>Linefeed:   done()\n"
+                             "Ctrl<Key>M:      done()\n"
+                             "Ctrl<Key>J:      done()\n");
+#endif /* HAVE_ATHENA */
+
+
 static void
 static void
-select_cb (button, client_data, call_data)
-     Widget button;
-     XtPointer client_data, call_data;
+select_cb (Widget button, XtPointer client_data, XtPointer call_data)
 {
 {
-  char **hacks = (char **) client_data;
+  saver_info *si = (saver_info *) client_data;
+
+#ifdef HAVE_ATHENA
+  XawListReturnStruct *item = (XawListReturnStruct*)call_data;
+  XtVaSetValues(text_line, XtNstring, item->string, 0);
+
+  demo_mode_hack (si, item->string);
+  if (item->list_index >= 0)
+    si->default_screen->current_hack = item->list_index;
+
+#else  /* HAVE_MOTIF */
   XmListCallbackStruct *lcb = (XmListCallbackStruct *) call_data;
   XmListCallbackStruct *lcb = (XmListCallbackStruct *) call_data;
-  XmTextSetString (text_line, hacks [lcb->item_position - 1]);
-  if (lcb->reason == XmCR_DEFAULT_ACTION)
-    text_cb (text_line, 0, 0);
-  focus_fuckus (demo_dialog);
+  char *string = 0;
+  if (lcb->item)
+    XmStringGetLtoR (lcb->item, XmSTRING_DEFAULT_CHARSET, &string);
+  set_text_string (text_line, (string ? string : ""));
+  if (lcb->reason == XmCR_DEFAULT_ACTION && string)
+    {
+      demo_mode_hack (si, string);
+      if (lcb->item_position > 0)
+       si->default_screen->current_hack = lcb->item_position - 1;
+    }
+  if (string)
+    XtFree (string);
+#endif /* HAVE_MOTIF */
+  steal_focus_and_colormap (demo_dialog);
 }
 
 }
 
+
+/* Why this behavior isn't automatic in *either* toolkit, I'll never know.
+ */
 static void
 static void
-next_cb (button, client_data, call_data)
-     Widget button;
-     XtPointer client_data, call_data;
+ensure_selected_item_visible (Widget list)
 {
 {
+#ifdef HAVE_MOTIF
+  int *pos_list = 0;
+  int pos_count = 0;
+  if (XmListGetSelectedPos (list, &pos_list, &pos_count) && pos_count > 0)
+    {
+      int top = -2;
+      int visible = 0;
+      XtVaGetValues (list,
+                    XmNtopItemPosition, &top,
+                    XmNvisibleItemCount, &visible,
+                    0);
+      if (pos_list[0] >= top + visible)
+       {
+         int pos = pos_list[0] - visible + 1;
+         if (pos < 0) pos = 0;
+         XmListSetPos (list, pos);
+       }
+      else if (pos_list[0] < top)
+       {
+         XmListSetPos (list, pos_list[0]);
+       }
+    }
+  if (pos_list)
+    XtFree ((char *) pos_list);
+
+#else  /* HAVE_ATHENA */
+# ifdef HAVE_XawViewportSetCoordinates
+
+  int margin = 16;     /* should be line height or something. */
+  int count = 0;
+  int pos;
+  Dimension list_h = 0, vp_h = 0;
+  Dimension top_margin = 4;  /* I don't know where this value comes from */
+  Position vp_x = 0, vp_y = 0, current_y;
+  double cratio;
+  Widget viewport = XtParent(demo_list);
+  Widget sb = (viewport ? XtNameToWidget(viewport, "*vertical") : 0);
+  float sb_top = 0, sb_size = 0;
+  XawListReturnStruct *current = XawListShowCurrent(demo_list);
+  if (!current || !sb) return;
+
+  XtVaGetValues(demo_list,
+               XtNnumberStrings, &count,
+               XtNheight, &list_h,
+               0);
+  if (count < 2 || list_h < 10) return;
+
+  XtVaGetValues(viewport, XtNheight, &vp_h, XtNx, &vp_x, XtNy, &vp_y, 0);
+  if (vp_h < 10) return;
+
+  XtVaGetValues(sb, XtNtopOfThumb, &sb_top, XtNshown, &sb_size, 0);
+  if (sb_size <= 0) return;
+
+  pos = current->list_index;
+  cratio = ((double) pos)  / ((double) count);
+  current_y = (cratio * list_h);
+
+  if (cratio < sb_top ||
+      cratio > sb_top + sb_size)
+    {
+      if (cratio < sb_top)
+       current_y -= (vp_h - margin - margin);
+      else
+       current_y -= margin;
+
+      if ((long)current_y >= (long) list_h)
+       current_y = (Position) ((long)list_h - (long)vp_h);
+
+      if ((long)current_y < (long)top_margin)
+       current_y = (Position)top_margin;
+
+      XawViewportSetCoordinates (viewport, vp_x, current_y);
+    }
+# endif /* HAVE_XawViewportSetCoordinates */
+#endif /* HAVE_ATHENA */
+}
+
+
+static void
+next_cb (Widget button, XtPointer client_data, XtPointer call_data)
+{
+  saver_info *si = (saver_info *) client_data;
+  saver_preferences *p = &si->prefs;
+
+  if (p->verbose_p)
+    fprintf (stderr, "%s: Run Next\n", blurb());
+
+  {
+#ifdef HAVE_ATHENA
+  int cnt;
+  XawListReturnStruct *current = XawListShowCurrent(demo_list);
+  if (current->list_index == XAW_LIST_NONE)
+    XawListHighlight(demo_list, 0);
+  else
+    {
+      XtVaGetValues(demo_list,
+                   XtNnumberStrings, &cnt,
+                   NULL);
+      if (current->list_index + 1 < cnt)
+       {
+         current->list_index++;
+         XawListHighlight(demo_list, current->list_index);
+       }
+    }
+
+  ensure_selected_item_visible (demo_list);
+  current = XawListShowCurrent(demo_list);
+  XtVaSetValues(text_line, XtNstring, current->string, 0);
+  demo_mode_hack (si, current->string);
+
+#else  /* HAVE_MOTIF */
+
   int *pos_list;
   int pos_count;
   if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count))
   int *pos_list;
   int pos_count;
   if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count))
-    XmListSelectPos (demo_list, 1, True);
+    {
+      XmListDeselectAllItems(demo_list);       /* LessTif lossage */
+      XmListSelectPos (demo_list, 1, True);
+    }
   else
     {
   else
     {
-      int pos = pos_list [0];
-      XmListSelectPos (demo_list, pos + 1, True);
-      XtFree ((char *) pos_list);
-      if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count))
-       abort ();
-      if (pos_list [0] == pos)
-       XmListSelectPos (demo_list, 1, True);
-      XtFree ((char *) pos_list);
+      int pos = pos_list[0] + 1;
+      if (pos > si->prefs.screenhacks_count)
+       pos = 1;
+      XmListDeselectAllItems(demo_list);       /* LessTif lossage */
+      XmListSelectPos (demo_list, pos, True);
     }
     }
-  text_cb (text_line, 0, 0);
+  XtFree ((char *) pos_list);
+  ensure_selected_item_visible (demo_list);
+  demo_mode_hack (si, get_text_string (text_line));
+
+#endif /* HAVE_MOTIF */
+  }
 }
 
 }
 
+
 static void
 static void
-prev_cb (button, client_data, call_data)
-     Widget button;
-     XtPointer client_data, call_data;
+prev_cb (Widget button, XtPointer client_data, XtPointer call_data)
 {
 {
+  saver_info *si = (saver_info *) client_data;
+  saver_preferences *p = &si->prefs;
+
+  if (p->verbose_p)
+    fprintf (stderr, "%s: Run Previous\n", blurb());
+
+  {
+#ifdef HAVE_ATHENA
+  XawListReturnStruct *current=XawListShowCurrent(demo_list);
+  if (current->list_index == XAW_LIST_NONE)
+    XawListHighlight(demo_list, 0);
+  else
+    {
+      if (current->list_index >= 1)
+       {
+         current->list_index--;
+         XawListHighlight(demo_list, current->list_index);
+       }
+    }
+
+  ensure_selected_item_visible (demo_list);
+  current = XawListShowCurrent(demo_list);
+  XtVaSetValues(text_line, XtNstring, current->string, 0);
+  demo_mode_hack (si, current->string);
+
+#else  /* HAVE_MOTIF */
+
   int *pos_list;
   int pos_count;
   if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count))
   int *pos_list;
   int pos_count;
   if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count))
-    XmListSelectPos (demo_list, 0, True);
+    {
+      XmListDeselectAllItems(demo_list);       /* LessTif lossage */
+      XmListSelectPos (demo_list, 0, True);
+    }
   else
     {
   else
     {
+      XmListDeselectAllItems(demo_list);       /* LessTif lossage */
       XmListSelectPos (demo_list, pos_list [0] - 1, True);
       XtFree ((char *) pos_list);
     }
       XmListSelectPos (demo_list, pos_list [0] - 1, True);
       XtFree ((char *) pos_list);
     }
-  text_cb (text_line, 0, 0);
+  ensure_selected_item_visible (demo_list);
+  demo_mode_hack (si, get_text_string (text_line));
+
+#endif /* HAVE_MOTIF */
+  }
 }
 
 
 }
 
 
-static void pop_resources_dialog ();
-static void make_resources_dialog ();
+static void pop_resources_dialog (saver_info *si);
+static void make_resources_dialog (saver_info *si, Widget parent);
 
 static void
 
 static void
-edit_cb (button, client_data, call_data)
-     Widget button;
-     XtPointer client_data, call_data;
+edit_cb (Widget button, XtPointer client_data, XtPointer call_data)
 {
 {
-  Widget parent = (Widget) client_data;
+  saver_info *si = (saver_info *) client_data;
+  saver_screen_info *ssi = si->default_screen;
+  saver_preferences *p = &si->prefs;
+  Widget parent = ssi->toplevel_shell;
+
+  if (p->verbose_p)
+    fprintf (stderr, "%s: Preferences\n", blurb());
+
   if (! resources_dialog)
   if (! resources_dialog)
-    make_resources_dialog (parent);
-  pop_resources_dialog ();
+    make_resources_dialog (si, parent);
+  pop_resources_dialog (si);
 }
 
 static void
 }
 
 static void
-done_cb (button, client_data, call_data)
-     Widget button;
-     XtPointer client_data, call_data;
+done_cb (Widget button, XtPointer client_data, XtPointer call_data)
 {
 {
-  demo_mode_done ();
+  saver_info *si = (saver_info *) client_data;
+  demo_mode_done (si);
 }
 
 
 static void
 }
 
 
 static void
-restart_cb (button, client_data, call_data)
-     Widget button;
-     XtPointer client_data, call_data;
+restart_cb (Widget button, XtPointer client_data, XtPointer call_data)
 {
 {
-  demo_mode_restart_process ();
+  saver_info *si = (saver_info *) client_data;
+  saver_preferences *p = &si->prefs;
+  if (p->verbose_p)
+    fprintf (stderr, "%s: Restart\n", blurb());
+  demo_mode_restart_process (si);
 }
 
 }
 
+
 void
 void
-pop_up_dialog_box (dialog, form, where)
-     Widget dialog, form;
-     int where;
+pop_up_dialog_box (Widget dialog, Widget form, int where)
 {
   /* I'm sure this is the wrong way to pop up a dialog box, but I can't
      figure out how else to do it.
 {
   /* I'm sure this is the wrong way to pop up a dialog box, but I can't
      figure out how else to do it.
@@ -182,19 +521,34 @@ pop_up_dialog_box (dialog, form, where)
      It's important that the screensaver dialogs not get decorated or
      otherwise reparented by the window manager, because they need to be
      children of the *real* root window, not the WM's virtual root, in
      It's important that the screensaver dialogs not get decorated or
      otherwise reparented by the window manager, because they need to be
      children of the *real* root window, not the WM's virtual root, in
-     order for us to guarentee tha they are visible above the screensaver
+     order for us to guarentee that they are visible above the screensaver
      window itself.
    */
   Arg av [100];
   int ac = 0;
   Dimension sw, sh, x, y, w, h;
      window itself.
    */
   Arg av [100];
   int ac = 0;
   Dimension sw, sh, x, y, w, h;
+
+#ifdef HAVE_ATHENA
+  XtRealizeWidget (dialog);
+#else  /* HAVE_MOTIF */
+  /* Motif likes us to realize the *child* of the shell... */
   XtRealizeWidget (form);
   XtRealizeWidget (form);
+#endif /* HAVE_MOTIF */
+
   sw = WidthOfScreen (XtScreen (dialog));
   sh = HeightOfScreen (XtScreen (dialog));
   ac = 0;
   sw = WidthOfScreen (XtScreen (dialog));
   sh = HeightOfScreen (XtScreen (dialog));
   ac = 0;
-  XtSetArg (av [ac], XmNwidth, &w); ac++;
-  XtSetArg (av [ac], XmNheight, &h); ac++;
+  XtSetArg (av [ac], XtNwidth, &w); ac++;
+  XtSetArg (av [ac], XtNheight, &h); ac++;
   XtGetValues (form, av, ac);
   XtGetValues (form, av, ac);
+
+  /* for debugging -- don't ask */
+  if (where >= 69)
+    {
+      where -= 69;
+      sw = (sw * 7) / 12;
+    }
+
   switch (where)
     {
     case 0:    /* center it in the top-right quadrant */
   switch (where)
     {
     case 0:    /* center it in the top-right quadrant */
@@ -209,83 +563,185 @@ pop_up_dialog_box (dialog, form, where)
       x = (sw + w) / 2 - w;
       y = (sh + h) / 2 - h;
       break;
       x = (sw + w) / 2 - w;
       y = (sh + h) / 2 - h;
       break;
+    case 3:    /* center it in the top 2/3rds of the screen */
+      x = (sw + w) / 2 - w;
+      y = (sh*2/3 + h) / 2 - h;
+      break;
     default:
       abort ();
     }
   if (x + w > sw) x = sw - w;
   if (y + h > sh) y = sh - h;
   ac = 0;
     default:
       abort ();
     }
   if (x + w > sw) x = sw - w;
   if (y + h > sh) y = sh - h;
   ac = 0;
-  XtSetArg (av [ac], XmNx, x); ac++;
-  XtSetArg (av [ac], XmNy, y); ac++;
+  XtSetArg (av [ac], XtNx, x); ac++;
+  XtSetArg (av [ac], XtNy, y); ac++;
   XtSetArg (av [ac], XtNoverrideRedirect, True); ac++;
   XtSetArg (av [ac], XtNoverrideRedirect, True); ac++;
+
+#ifdef HAVE_MOTIF
   XtSetArg (av [ac], XmNdefaultPosition, False); ac++;
   XtSetArg (av [ac], XmNdefaultPosition, False); ac++;
-  /* I wonder whether this does anything useful? */
-/* XtSetArg (av [ac], XmNdialogStyle, XmDIALOG_SYSTEM_MODAL); ac++; */
+#endif /* HAVE_MOTIF */
+
   XtSetValues (dialog, av, ac);
   XtSetValues (form, av, ac);
   XtSetValues (dialog, av, ac);
   XtSetValues (form, av, ac);
+
+#ifdef HAVE_ATHENA
+  XtPopup (dialog, XtGrabNone);
+#else  /* HAVE_MOTIF */
   XtManageChild (form);
   XtManageChild (form);
+#endif /* HAVE_MOTIF */
 
 
-  focus_fuckus (dialog);
+  steal_focus_and_colormap (dialog);
 }
 
 
 }
 
 
-static void
-make_screenhack_dialog (parent, hacks)
-     Widget parent;
-     char **hacks;
+void
+make_screenhack_dialog (saver_info *si)
 {
 {
-  char buf [255];
-  Arg av[10];
-  int ac;
-  char *label;
-  Dimension max_w = 0;
-  XmString xm_label = 0;
-  XmString new_xm_label;
+  saver_screen_info *ssi = si->default_screen;
+  Widget parent = ssi->toplevel_shell;
+  char **hacks = si->prefs.screenhacks;
 
 
-  create_demo_dialog (parent);
-  ac = 0;
-  XtSetArg (av [ac], XmNlabelString, &xm_label); ac++;
-  XtGetValues (label1, av, ac);
-  XmStringGetLtoR (xm_label, XmSTRING_DEFAULT_CHARSET, &label);
-  if (!strcmp (label, XtName (label1)))
-    strcpy (buf, "ERROR: RESOURCES ARE NOT INSTALLED CORRECTLY");
-  else
-    sprintf (buf, label, screensaver_version);
-  new_xm_label = XmStringCreate (buf, XmSTRING_DEFAULT_CHARSET);
-  ac = 0;
-  XtSetArg (av [ac], XmNlabelString, new_xm_label); ac++;
-  XtSetValues (label1, av, ac);
-  XmStringFree (new_xm_label);
-  XtFree (label);
-
-  XtAddCallback (demo_list, XmNbrowseSelectionCallback, select_cb,
-                hacks);
-  XtAddCallback (demo_list, XmNdefaultActionCallback, select_cb,
-                hacks);
-
-  XtAddCallback (text_line, XmNactivateCallback, text_cb, 0);
-  XtAddCallback (next, XmNactivateCallback, next_cb, 0);
-  XtAddCallback (prev, XmNactivateCallback, prev_cb, 0);
-  XtAddCallback (done, XmNactivateCallback, done_cb, 0);
-  XtAddCallback (restart, XmNactivateCallback, restart_cb, 0);
-  XtAddCallback (edit, XmNactivateCallback, edit_cb, parent);
-
-  for (; *hacks; hacks++)
+  if (ssi->demo_cmap &&
+      ssi->demo_cmap != ssi->cmap &&
+      ssi->demo_cmap != DefaultColormapOfScreen (ssi->screen))
     {
     {
-      XmString xmstr = XmStringCreate (*hacks, XmSTRING_DEFAULT_CHARSET);
-      XmListAddItem (demo_list, xmstr, 0);
-      /* XmListSelectPos (widget, i, False); */
-      XmStringFree (xmstr);
+      XFreeColormap (si->dpy, ssi->demo_cmap);
+      ssi->demo_cmap = 0;
     }
 
     }
 
-#if 0
-  /* Dialogs that have scroll-lists don't obey maxWidth!  Fuck!!  Hack it. */
-  ac = 0;
-  XtSetArg (av [ac], XmNmaxWidth, &max_w); ac++;
-  XtGetValues (demo_dialog, av, ac); /* great, this SEGVs */
-#endif
+  if (ssi->default_visual == DefaultVisualOfScreen (ssi->screen))
+    ssi->demo_cmap = DefaultColormapOfScreen (ssi->screen);
+  else
+    ssi->demo_cmap = XCreateColormap (si->dpy,
+                                     RootWindowOfScreen (ssi->screen),
+                                     ssi->default_visual, AllocNone);
+
+  create_demo_dialog (parent, ssi->default_visual, ssi->demo_cmap);
+  format_into_label (label1, si->version);
+
+  add_button_callback (next,    next_cb,    (XtPointer) si);
+  add_button_callback (prev,    prev_cb,    (XtPointer) si);
+  add_button_callback (done,    done_cb,    (XtPointer) si);
+  add_button_callback (restart, restart_cb, (XtPointer) si);
+  add_button_callback (edit,    edit_cb,    (XtPointer) si);
+
+#ifdef HAVE_MOTIF
+  XtAddCallback (demo_list, XmNbrowseSelectionCallback,
+                select_cb, (XtPointer) si);
+  XtAddCallback (demo_list, XmNdefaultActionCallback,
+                select_cb, (XtPointer) si);
+  XtAddCallback (text_line, XmNactivateCallback, text_cb, (XtPointer) si);
+
+  if (hacks)
+    for (; *hacks; hacks++)
+      {
+       XmString xmstr = XmStringCreate (*hacks, XmSTRING_DEFAULT_CHARSET);
+       XmListAddItem (demo_list, xmstr, 0);
+       XmStringFree (xmstr);
+      }
+
+  /* Cause the most-recently-run hack to be selected in the list.
+     Do some voodoo to make it be roughly centered in the list (really,
+     just make it not be within +/- 5 of the top/bottom if possible.)
+   */
+  if (ssi->current_hack > 0)
+    {
+      int i = ssi->current_hack+1;
+      int top = i + 5;
+      int bot = i - 5;
+      if (bot < 1) bot = 1;
+      if (top > si->prefs.screenhacks_count)
+       top = si->prefs.screenhacks_count;
+
+      XmListDeselectAllItems(demo_list);       /* LessTif lossage */
+      XmListSelectPos (demo_list, bot, False);
+      ensure_selected_item_visible (demo_list);
+
+      XmListDeselectAllItems(demo_list);       /* LessTif lossage */
+      XmListSelectPos (demo_list, top, False);
+      ensure_selected_item_visible (demo_list);
+
+      XmListDeselectAllItems(demo_list);       /* LessTif lossage */
+      XmListSelectPos (demo_list, i, False);
+      ensure_selected_item_visible (demo_list);
+    }
 
 
-  pop_up_dialog_box (demo_dialog, demo_form, 0);
+#else  /* HAVE_ATHENA */
+
+  /* Hook up the text line. */
+
+  XtAppAddActions(XtWidgetToApplicationContext(text_line),
+                 actions, XtNumber(actions));
+  XtOverrideTranslations(text_line, XtParseTranslationTable(translations));
+
+
+  /* Must realize the widget before populating the list, or the dialog
+     will be as wide as the longest string.
+  */
+  XtRealizeWidget (demo_dialog);
+
+  XtVaSetValues (demo_list,
+                XtNlist, hacks,
+                XtNnumberStrings, si->prefs.screenhacks_count,
+                0);
+  XtAddCallback (demo_list, XtNcallback, select_cb, si);
+  if (ssi->current_hack > 0)
+  XawListHighlight(demo_list, ssi->current_hack);
+
+  /* Now that we've populated the list, make sure that the list is as
+     wide as the dialog itself.
+  */
+  {
+    Widget viewport = XtParent(demo_list);
+    Widget subform = XtParent(viewport);
+    Widget box = XtNameToWidget(demo_dialog, "*box");
+    Widget label1 = XtNameToWidget(demo_dialog, "*label1");
+    Widget label2 = XtNameToWidget(demo_dialog, "*label2");
+    Dimension x=0, y=0, w=0, h=0, bw=0, w2=0;
+    XtVaGetValues(subform,
+                 XtNwidth, &w, XtNheight, &h, XtNborderWidth, &bw, 0);
+    XtVaGetValues(box, XtNwidth, &w2, 0);
+    if (w2 != w)
+      XtResizeWidget(subform, w2, h, bw);
+
+    /* Why isn't the viewport getting centered? */
+    XtVaGetValues(viewport,
+                 XtNx, &x, XtNy, &y, XtNheight, &h, XtNborderWidth, &bw, 0);
+/*    printf("%d %d %d %d\n", x, y, w, h); */
+    XtConfigureWidget(viewport, x, y, w2-x-x, h, bw);
+
+    /* And the text line, too. */
+    XtVaGetValues(text_line,
+                 XtNwidth, &w, XtNheight, &h, XtNborderWidth, &bw, 0);
+    XtVaGetValues(viewport, XtNwidth, &w2, 0);
+    if (w2 != w)
+      XtResizeWidget(text_line, w2, h, bw);
+
+    /* And the labels too. */
+    XtVaGetValues(label1,
+                 XtNwidth, &w, XtNheight, &h, XtNborderWidth, &bw, 0);
+    if (w2 != w)
+      XtResizeWidget(label1, w2, h, bw);
+
+    XtVaGetValues(label2,
+                 XtNwidth, &w, XtNheight, &h, XtNborderWidth, &bw, 0);
+    if (w2 != w)
+      XtResizeWidget(label2, w2, h, bw);
+
+  }
+
+#endif /* HAVE_ATHENA */
+
+  monitor_power_on (si);
+  pop_up_dialog_box(demo_dialog, demo_form,
+                   /* for debugging -- don't ask */
+                   (si->prefs.debug_p ? 69 : 0) +
+                   0);
+
+#ifdef HAVE_ATHENA
+  /* For Athena, have to do this after the dialog is managed. */
+  ensure_selected_item_visible (demo_list);
+#endif /* HAVE_ATHENA */
 }
 
 \f
 }
 
 \f
@@ -297,14 +753,8 @@ static struct resources {
 } res;
 
 
 } res;
 
 
-extern int parse_time ();
-
 static void 
 static void 
-hack_time_cb (dpy, line, store, sec_p)
-     Display *dpy;
-     char *line;
-     int *store;
-     Bool sec_p;
+hack_time_cb (Display *dpy, char *line, int *store, Bool sec_p)
 {
   if (*line)
     {
 {
   if (*line)
     {
@@ -318,29 +768,23 @@ hack_time_cb (dpy, line, store, sec_p)
 }
 
 static void
 }
 
 static void
-res_sec_cb (button, client_data, call_data)
-     Widget button;
-     XtPointer client_data, call_data;
+res_sec_cb (Widget button, XtPointer client_data, XtPointer call_data)
 {
 {
-  hack_time_cb (XtDisplay (button), XmTextGetString (button),
+  hack_time_cb (XtDisplay (button), get_text_string (button),
                (int *) client_data, True);
 }
 
 static void
                (int *) client_data, True);
 }
 
 static void
-res_min_cb (button, client_data, call_data)
-     Widget button;
-     XtPointer client_data, call_data;
+res_min_cb (Widget button, XtPointer client_data, XtPointer call_data)
 {
 {
-  hack_time_cb (XtDisplay (button), XmTextGetString (button),
+  hack_time_cb (XtDisplay (button), get_text_string (button),
                (int *) client_data, False);
 }
 
 static void
                (int *) client_data, False);
 }
 
 static void
-res_int_cb (button, client_data, call_data)
-     Widget button;
-     XtPointer client_data, call_data;
+res_int_cb (Widget button, XtPointer client_data, XtPointer call_data)
 {
 {
-  char *line = XmTextGetString (button);
+  char *line = get_text_string (button);
   int *store = (int *) client_data;
   unsigned int value;
   char c;
   int *store = (int *) client_data;
   unsigned int value;
   char c;
@@ -353,101 +797,180 @@ res_int_cb (button, client_data, call_data)
 }
 
 static void
 }
 
 static void
-res_bool_cb (button, client_data, call_data)
-     Widget button;
-     XtPointer client_data, call_data;
+res_bool_cb (Widget button, XtPointer client_data, XtPointer call_data)
 {
   int *store = (int *) client_data;
 {
   int *store = (int *) client_data;
+#ifdef HAVE_MOTIF
   *store = ((XmToggleButtonCallbackStruct *) call_data)->set;
   *store = ((XmToggleButtonCallbackStruct *) call_data)->set;
+#else /* HAVE_ATHENA */
+  Boolean state = FALSE;
+  XtVaGetValues (button, XtNstate, &state, NULL);
+  *store = state;
+#endif /* HAVE_ATHENA */
 }
 
 static void
 }
 
 static void
-res_cancel_cb (button, client_data, call_data)
-     Widget button;
-     XtPointer client_data, call_data;
+res_cancel_cb (Widget button, XtPointer client_data, XtPointer call_data)
 {
 {
+  saver_info *si = (saver_info *) client_data;
+  saver_preferences *p = &si->prefs;
+
   XtDestroyWidget (resources_dialog);
   resources_dialog = 0;
   raise_screenhack_dialog ();
   XtDestroyWidget (resources_dialog);
   resources_dialog = 0;
   raise_screenhack_dialog ();
+
+  if (p->verbose_p)
+    fprintf (stderr, "%s: lowering preferences dialog.\n", blurb());
 }
 
 
 static void
 }
 
 
 static void
-res_done_cb (button, client_data, call_data)
-     Widget button;
-     XtPointer client_data, call_data;
+res_done_cb (Widget button, XtPointer client_data, XtPointer call_data)
 {
 {
+  saver_info *si = (saver_info *) client_data;
+  saver_preferences *p = &si->prefs;
+
   res_cancel_cb (button, client_data, call_data);
 
   res_cancel_cb (button, client_data, call_data);
 
-  if (res.timeout < 10) res.timeout = 10;
+#ifdef HAVE_ATHENA
+  /* Check all text widgets, since we don't have callbacks for these. */
+  res_min_cb (timeout_text,     (XtPointer) &res.timeout,     NULL);
+  res_min_cb (cycle_text,       (XtPointer) &res.cycle,       NULL);
+  res_sec_cb (fade_text,        (XtPointer) &res.secs,        NULL);
+  res_int_cb (ticks_text,       (XtPointer) &res.ticks,       NULL);
+  res_min_cb (lock_time_text,   (XtPointer) &res.lock_time,   NULL);
+  res_sec_cb (passwd_time_text, (XtPointer) &res.passwd_time, NULL);
+#endif /* HAVE_ATHENA */
+
+  /* Throttle the timeouts to minimum sane values. */
+  if (res.timeout < 5) res.timeout = 5;
   if (res.cycle < 2) res.cycle = 2;
   if (res.cycle < 2) res.cycle = 2;
-  if (res.passwd_time < 2) res.passwd_time = 30;
-
-  timeout = res.timeout * 1000;
-  cycle = res.cycle * 1000;
-  lock_timeout = res.lock_time * 1000;
-  passwd_timeout = res.passwd_time * 1000;
-  fade_seconds = res.secs;
-  fade_ticks = res.ticks;
-  verbose_p = res.verb;
-  install_cmap_p = res.cmap;
-  fade_p = res.fade;
-  unfade_p = res.unfade;
-  lock_p = res.lock_p;
+  if (res.passwd_time < 10) res.passwd_time = 10;
+
+  p->timeout = res.timeout * 1000;
+  p->cycle = res.cycle * 1000;
+  p->lock_timeout = res.lock_time * 1000;
+#ifndef NO_LOCKING
+  p->passwd_timeout = res.passwd_time * 1000;
+#endif
+  p->fade_seconds = res.secs;
+  p->fade_ticks = res.ticks;
+  p->verbose_p = res.verb;
+  p->install_cmap_p = res.cmap;
+  p->fade_p = res.fade;
+  p->unfade_p = res.unfade;
+  p->lock_p = res.lock_p;
+
+  if (p->debug_p && p->verbose_p)
+    fprintf (stderr, "%s: parameters changed:\n\
+       timeout: %d\n\tcycle:   %d\n\tlock:    %d\n\tpasswd:  %d\n\
+       fade:    %d\n\tfade:    %d\n\tverbose: %d\n\tinstall: %d\n\
+       fade:    %d\n\tunfade:  %d\n\tlock:    %d\n",
+            blurb(), p->timeout, p->cycle, p->lock_timeout,
+#ifdef NO_LOCKING
+            0,
+#else
+            p->passwd_timeout,
+#endif
+            p->fade_seconds, p->fade_ticks, p->verbose_p, p->install_cmap_p,
+            p->fade_p, p->unfade_p, p->lock_p);
+
+
+#if defined(HAVE_MIT_SAVER_EXTENSION) || defined(HAVE_SGI_SAVER_EXTENSION)
+  if (p->use_mit_saver_extension || p->use_sgi_saver_extension)
+    {
+      /* Need to set the server timeout to the new one the user has picked.
+       */
+      int server_timeout, server_interval, prefer_blank, allow_exp;
+      XGetScreenSaver (si->dpy, &server_timeout, &server_interval,
+                      &prefer_blank, &allow_exp);
+      if (server_timeout != (p->timeout / 1000))
+       {
+         server_timeout = (p->timeout / 1000);
+         if (p->verbose_p)
+           fprintf (stderr,
+                  "%s: configuring server for saver timeout of %d seconds.\n",
+                    blurb(), server_timeout);
+         /* Leave all other parameters the same. */
+         XSetScreenSaver (si->dpy, server_timeout, server_interval,
+                          prefer_blank, allow_exp);
+       }
+    }
+#endif /* HAVE_MIT_SAVER_EXTENSION || HAVE_SGI_SAVER_EXTENSION */
+
+  write_init_file (si);
 }
 
 
 static void
 }
 
 
 static void
-make_resources_dialog (parent)
-     Widget parent;
+make_resources_dialog (saver_info *si, Widget parent)
 {
 {
-  Arg av[10];
-  int ac;
+  saver_screen_info *ssi = si->default_screen;
 
 
-  create_resources_dialog (parent);
+  if (ssi->demo_cmap &&
+      ssi->demo_cmap != ssi->cmap &&
+      ssi->demo_cmap != DefaultColormapOfScreen (ssi->screen))
+    {
+      XFreeColormap (si->dpy, ssi->demo_cmap);
+      ssi->demo_cmap = 0;
+    }
 
 
-  XtAddCallback (res_done, XmNactivateCallback, res_done_cb, 0);
-  XtAddCallback (res_cancel, XmNactivateCallback, res_cancel_cb, 0);
+  if (ssi->default_visual == DefaultVisualOfScreen (ssi->screen))
+    ssi->demo_cmap = DefaultColormapOfScreen (ssi->screen);
+  else
+    ssi->demo_cmap = XCreateColormap (si->dpy,
+                                    RootWindowOfScreen (ssi->screen),
+                                    ssi->default_visual, AllocNone);
+
+  create_resources_dialog (parent, ssi->default_visual, ssi->demo_cmap);
+
+  add_button_callback (res_done,   res_done_cb,   (XtPointer) si);
+  add_button_callback (res_cancel, res_cancel_cb, (XtPointer) si);
 
 #define CB(widget,type,slot) \
 
 #define CB(widget,type,slot) \
-       XtAddCallback ((widget), XmNvalueChangedCallback, (type), (slot))
+       add_text_callback ((widget), (type), (XtPointer) (slot))
+#define CBT(widget,type,slot) \
+       add_toggle_callback ((widget), (type), (XtPointer) (slot))
+
+#ifdef HAVE_MOTIF
+  /* When using Athena widgets, we can't set callbacks for these,
+     so we'll check them all if "done" gets pressed.
+   */
   CB (timeout_text,    res_min_cb,  &res.timeout);
   CB (cycle_text,      res_min_cb,  &res.cycle);
   CB (fade_text,       res_sec_cb,  &res.secs);
   CB (ticks_text,      res_int_cb,  &res.ticks);
   CB (lock_time_text,  res_min_cb,  &res.lock_time);
   CB (passwd_time_text,        res_sec_cb,  &res.passwd_time);
   CB (timeout_text,    res_min_cb,  &res.timeout);
   CB (cycle_text,      res_min_cb,  &res.cycle);
   CB (fade_text,       res_sec_cb,  &res.secs);
   CB (ticks_text,      res_int_cb,  &res.ticks);
   CB (lock_time_text,  res_min_cb,  &res.lock_time);
   CB (passwd_time_text,        res_sec_cb,  &res.passwd_time);
-  CB (verbose_toggle,  res_bool_cb, &res.verb);
-  CB (cmap_toggle,     res_bool_cb, &res.cmap);
-  CB (fade_toggle,     res_bool_cb, &res.fade);
-  CB (unfade_toggle,   res_bool_cb, &res.unfade);
-  CB (lock_toggle,     res_bool_cb, &res.lock_p);
+#endif /* HAVE_MOTIF */
+
+  CBT (verbose_toggle, res_bool_cb, &res.verb);
+  CBT (cmap_toggle,    res_bool_cb, &res.cmap);
+  CBT (fade_toggle,    res_bool_cb, &res.fade);
+  CBT (unfade_toggle,  res_bool_cb, &res.unfade);
+  CBT (lock_toggle,    res_bool_cb, &res.lock_p);
 #undef CB
 #undef CB
-  ac = 0;
-  XtSetArg (av[ac], XmNsensitive, False); ac++;
+#undef CBT
 
 
-  if (locking_disabled_p)
+  if (si->locking_disabled_p)
     {
     {
-      XtSetValues (passwd_time_text, av, ac);
-      XtSetValues (lock_time_text, av, ac);
-      XtSetValues (lock_toggle, av, ac);
+      disable_widget (passwd_time_text);
+      disable_widget (lock_time_text);
+      disable_widget (lock_toggle);
     }
     }
-  if (CellsOfScreen (XtScreen (parent)) <= 2)
+  if (!si->fading_possible_p)
     {
     {
-      XtSetValues (fade_text, av, ac);
-      XtSetValues (ticks_text, av, ac);
-      XtSetValues (cmap_toggle, av, ac);
-      XtSetValues (fade_toggle, av, ac);
-      XtSetValues (unfade_toggle, av, ac);
+      disable_widget (fade_text);
+      disable_widget (ticks_text);
+      disable_widget (cmap_toggle);
+      disable_widget (fade_toggle);
+      disable_widget (unfade_toggle);
     }
 }
 
 
 static void
     }
 }
 
 
 static void
-fmt_time (buf, s, min_p)
-     char *buf;
-     unsigned int s;
-     int min_p;
+fmt_time (char *buf, unsigned int s, int min_p)
 {
   unsigned int h = 0, m = 0;
   if (s >= 60)
 {
   unsigned int h = 0, m = 0;
   if (s >= 60)
@@ -474,118 +997,159 @@ fmt_time (buf, s, min_p)
 }
 
 static void
 }
 
 static void
-pop_resources_dialog ()
+pop_resources_dialog (saver_info *si)
 {
 {
+  saver_preferences *p = &si->prefs;
   char buf [100];
 
   char buf [100];
 
-  res.timeout = timeout / 1000;
-  res.cycle = cycle / 1000;
-  res.lock_time = lock_timeout / 1000;
-  res.passwd_time = passwd_timeout / 1000;
-  res.secs = fade_seconds;
-  res.ticks = fade_ticks;
-  res.verb = verbose_p;
-  res.cmap = install_cmap_p;
-  res.fade = fade_p;
-  res.unfade = unfade_p;
-  res.lock_p = (lock_p && !locking_disabled_p);
-
-  fmt_time (buf, res.timeout, 1);     XmTextSetString (timeout_text, buf);
-  fmt_time (buf, res.cycle, 1);       XmTextSetString (cycle_text, buf);
-  fmt_time (buf, res.lock_time, 1);   XmTextSetString (lock_time_text, buf);
-  fmt_time (buf, res.passwd_time, 0); XmTextSetString (passwd_time_text, buf);
-  fmt_time (buf, res.secs, 0);        XmTextSetString (fade_text, buf);
-  sprintf (buf, "%u", res.ticks);     XmTextSetString (ticks_text, buf);
-
-  XmToggleButtonSetState (verbose_toggle, res.verb, True);
-  XmToggleButtonSetState (cmap_toggle, res.cmap, True);
-  XmToggleButtonSetState (fade_toggle, res.fade, True);
-  XmToggleButtonSetState (unfade_toggle, res.unfade, True);
-  XmToggleButtonSetState (lock_toggle, res.lock_p, True);
-
-  pop_up_dialog_box (resources_dialog, resources_form, 1);
+  if (p->verbose_p)
+    fprintf (stderr, "%s: raising preferences dialog.\n", blurb());
+
+  res.timeout = p->timeout / 1000;
+  res.cycle = p->cycle / 1000;
+  res.lock_time = p->lock_timeout / 1000;
+#ifndef NO_LOCKING
+  res.passwd_time = p->passwd_timeout / 1000;
+#endif
+  res.secs = p->fade_seconds;
+  res.ticks = p->fade_ticks;
+  res.verb = p->verbose_p;
+  res.cmap = p->install_cmap_p;
+  res.fade = p->fade_p;
+  res.unfade = p->unfade_p;
+  res.lock_p = (p->lock_p && !si->locking_disabled_p);
+
+  fmt_time (buf, res.timeout, 1);     set_text_string (timeout_text, buf);
+  fmt_time (buf, res.cycle, 1);       set_text_string (cycle_text, buf);
+  fmt_time (buf, res.lock_time, 1);   set_text_string (lock_time_text, buf);
+  fmt_time (buf, res.passwd_time, 0); set_text_string (passwd_time_text, buf);
+  fmt_time (buf, res.secs, 0);        set_text_string (fade_text, buf);
+  sprintf (buf, "%u", res.ticks);     set_text_string (ticks_text, buf);
+
+  set_toggle_button_state (verbose_toggle, res.verb);
+  set_toggle_button_state (cmap_toggle, res.cmap);
+  set_toggle_button_state (fade_toggle, res.fade);
+  set_toggle_button_state (unfade_toggle, res.unfade);
+  set_toggle_button_state (lock_toggle, res.lock_p);
+
+  monitor_power_on (si);
+  pop_up_dialog_box (resources_dialog, resources_form,
+                    /* for debugging -- don't ask */
+                    (si->prefs.debug_p ? 69 : 0) +
+                    1);
 }
 
 \f
 }
 
 \f
-/* The code on this page isn't actually Motif-specific */
+/* The main demo-mode command loop.
+ */
 
 
-Bool dbox_up_p = False;
-Bool demo_mode_p = False;
+void
+demo_mode (saver_info *si)
+{
+  saver_preferences *p = &si->prefs;
+  Bool prefs_p = (si->demo_mode_p == (Bool) 2);  /* kludge! */
 
 
-extern XtAppContext app;
-extern Widget toplevel_shell;
-extern Bool use_xidle;
-extern Time notice_events_timeout;
+  if (p->verbose_p)
+    fprintf (stderr, "%s: Demo Mode.\n", blurb());
 
 
-extern char **screenhacks;
-extern char *demo_hack;
+  si->selection_mode = 0;
+  si->dbox_up_p = True;
+  monitor_power_on (si);
+  raise_window (si, True, False, False);
+  make_screenhack_dialog (si);
 
 
-extern void notice_events_timer P((XtPointer closure, void *timer));
-extern Bool handle_clientmessage P((/*XEvent *, Bool*/));
+  if (prefs_p)
+    edit_cb (0, si, 0);                /* pop up preferences panel */
 
 
-void
-demo_mode ()
-{
-  dbox_up_p = True;
-  initialize_screensaver_window ();
-  raise_window (True, False);
-  make_screenhack_dialog (toplevel_shell, screenhacks);
-  while (demo_mode_p)
+  while (si->demo_mode_p)
     {
       XEvent event;
     {
       XEvent event;
-      XtAppNextEvent (app, &event);
+      XtAppNextEvent (si->app, &event);
       switch (event.xany.type)
        {
        case 0:         /* synthetic "timeout" event */
          break;
 
        case ClientMessage:
       switch (event.xany.type)
        {
        case 0:         /* synthetic "timeout" event */
          break;
 
        case ClientMessage:
-         handle_clientmessage (&event, False);
+         handle_clientmessage (si, &event, False);
          break;
 
        case CreateNotify:
          break;
 
        case CreateNotify:
-#ifdef HAVE_XIDLE
-         if (! use_xidle)
-#endif
-           XtAppAddTimeOut (app, notice_events_timeout, notice_events_timer,
-                            (XtPointer) event.xcreatewindow.window);
+         if (!p->use_xidle_extension &&
+             !p->use_mit_saver_extension &&
+             !p->use_sgi_saver_extension)
+           {
+             start_notice_events_timer (si, event.xcreatewindow.window);
+#ifdef DEBUG_TIMERS
+             if (p->verbose_p)
+               fprintf (stderr,
+                        "%s: starting notice_events_timer for 0x%X (%lu)\n",
+                        blurb(),
+                        (unsigned int) event.xcreatewindow.window,
+                        p->notice_events_timeout);
+#endif /* DEBUG_TIMERS */
+           }
          break;
 
        case ButtonPress:
        case ButtonRelease:
          break;
 
        case ButtonPress:
        case ButtonRelease:
-         if (!XtWindowToWidget (dpy, event.xbutton.window))
+         if (!XtWindowToWidget (si->dpy, event.xbutton.window))
            raise_screenhack_dialog ();
          /* fall through */
 
        default:
            raise_screenhack_dialog ();
          /* fall through */
 
        default:
+#ifdef HAVE_MIT_SAVER_EXTENSION
+         if (event.type == si->mit_saver_ext_event_number)
+           {
+             /* Get the "real" server window(s) out of the way as soon
+                as possible. */
+             int i = 0;
+             for (i = 0; i < si->nscreens; i++)
+               {
+                 saver_screen_info *ssi = &si->screens[i];
+                 if (ssi->server_mit_saver_window &&
+                     window_exists_p (si->dpy, ssi->server_mit_saver_window))
+                   XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
+               }
+           }
+         else
+#endif /* HAVE_MIT_SAVER_EXTENSION */
+
          XtDispatchEvent (&event);
          break;
        }
     }
          XtDispatchEvent (&event);
          break;
        }
     }
-  destroy_screenhack_dialogs ();
-  initialize_screensaver_window ();
-  unblank_screen ();
+
+  if (p->verbose_p)
+    fprintf (stderr, "%s: Demo Mode done.\n", blurb());
+
+  kill_screenhack (si);
+
+  destroy_screenhack_dialogs (si);
+  initialize_screensaver_window (si);
+
+  si->dbox_up_p = False;
+  si->demo_hack = 0;
+
+  si->demo_mode_p = True;  /* kludge to inhibit unfade... */
+  unblank_screen (si);
+  si->demo_mode_p = False;
 }
 
 static void
 }
 
 static void
-demo_mode_hack (hack)
-     char *hack;
+demo_mode_hack (saver_info *si, char *hack)
 {
 {
-  if (! demo_mode_p) abort ();
-  kill_screenhack ();
-  if (! demo_hack)
-    blank_screen ();
-  demo_hack = hack;
-  spawn_screenhack (False);
+  if (! si->demo_mode_p) abort ();
+  kill_screenhack (si);
+  if (! si->demo_hack)
+    blank_screen (si);
+  si->demo_hack = hack;
+  spawn_screenhack (si, False);
+  /* raise_screenhack_dialog(); */
 }
 
 static void
 }
 
 static void
-demo_mode_done ()
+demo_mode_done (saver_info *si)
 {
 {
-  kill_screenhack ();
-  if (demo_hack)
-    unblank_screen ();
-  demo_mode_p = False;
-  dbox_up_p = False;
-  demo_hack = 0;
+  si->demo_mode_p = False;
 }
 }