http://ftp.x.org/contrib/applications/xscreensaver-2.34.tar.gz
[xscreensaver] / driver / lock.c
index f388c0d61deeceffdc560032f7ed85a88e854280..7a3ed6a259ffbf3ca1a6a5a6da6fdae625f8c64f 100644 (file)
 
 #ifndef NO_LOCKING   /* whole file */
 
-#include <X11/StringDefs.h>
 #include <X11/Intrinsic.h>
-#include <X11/IntrinsicP.h>    /* for XtResizeWidget */
 #include "xscreensaver.h"
 #include "resources.h"
 
+#ifdef _VROOT_H_
+ERROR!  You must not include vroot.h in this file.
+#endif
+
 #ifndef VMS
 # include <pwd.h>
 #else /* VMS */
+
 extern char *getenv(const char *name);
 extern int validate_user(char *name, char *password);
+
+static Bool
+vms_passwd_valid_p(char *pw)
+{
+  return (validate_user (getenv("USER"), typed_passwd) == 1);
+}
+# undef passwd_valid_p
+# define passwd_valid_p vms_passwd_valid_p
+
 #endif /* VMS */
 
 
-#ifdef HAVE_ATHENA
+#undef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
 
-# include <X11/Shell.h>
-# include <X11/StringDefs.h>
-# include <X11/Xaw/Text.h>
-# include <X11/Xaw/Label.h>
-# include <X11/Xaw/Dialog.h>
+enum passwd_state { pw_read, pw_ok, pw_fail, pw_cancel, pw_time };
 
-#else  /* HAVE_MOTIF */
+struct passwd_dialog_data {
 
-# include <Xm/Xm.h>
-# include <Xm/List.h>
-# include <Xm/TextF.h>
+  enum passwd_state state;
+  char typed_passwd [80];
+  XtIntervalId timer;
+  int i_beam;
 
-#endif /* HAVE_MOTIF */
+  float ratio;
+  Dimension width;
+  Dimension height;
 
-#ifdef _VROOT_H_
-ERROR!  You must not include vroot.h in this file.
-#endif
+  char *heading_label;
+  char *body_label;
+  char *user_label;
+  char *passwd_label;
+  char *user_string;
+  char *passwd_string;
 
-extern Widget passwd_dialog;
-extern Widget passwd_form;
-extern Widget roger_label;
-extern Widget passwd_label1;
-extern Widget passwd_label3;
-extern Widget passwd_cancel;
+  XFontStruct *heading_font;
+  XFontStruct *body_font;
+  XFontStruct *label_font;
+  XFontStruct *passwd_font;
 
-#ifdef HAVE_MOTIF
-extern Widget passwd_text;
-extern Widget passwd_done;
-#else  /* HAVE_ATHENA */
-static Widget passwd_text = 0; /* gag... */
-static Widget passwd_done = 0;
-#endif /* HAVE_ATHENA */
+  Pixel foreground;
+  Pixel background;
+  Pixel passwd_foreground;
+  Pixel passwd_background;
+  Pixel logo_foreground;
+  Pixel logo_background;
+  Pixel shadow_top;
+  Pixel shadow_bottom;
 
+  Dimension logo_width;
+  Dimension logo_height;
+  Dimension thermo_width;
+  Dimension internal_border;
+  Dimension shadow_width;
 
+  Dimension passwd_field_x, passwd_field_y;
+  Dimension passwd_field_width, passwd_field_height;
 
-static enum { pw_read, pw_ok, pw_fail, pw_cancel, pw_time } passwd_state;
-static char typed_passwd [80];
+  Dimension thermo_field_x, thermo_field_y;
+  Dimension thermo_field_height;
+};
 
-\f
-#if defined(HAVE_ATHENA) || (XmVersion >= 1002)
-   /* The `destroy' bug apears to be fixed as of Motif 1.2.1, but
-      the `verify-callback' bug is still present. */
-# define DESTROY_WORKS
-#endif
 
-static void
-passwd_cancel_cb (Widget button, XtPointer client_data, XtPointer call_data)
+void
+make_passwd_window (saver_info *si)
 {
-  passwd_state = pw_cancel;
-}
+  struct passwd *p = getpwuid (getuid ());
+  int x, y, bw;
+  XSetWindowAttributes attrs;
+  unsigned long attrmask = 0;
+  Screen *screen = si->default_screen->screen;
+  passwd_dialog_data *pw = (passwd_dialog_data *) calloc (1, sizeof(*pw));
+  Colormap cmap = DefaultColormapOfScreen (screen);
+  char *f;
+
+  pw->ratio = 1.0;
+
+  pw->heading_label = get_string_resource ("passwd.heading.label",
+                                          "Dialog.Label.Label");
+  pw->body_label = get_string_resource ("passwd.body.label",
+                                       "Dialog.Label.Label");
+  pw->user_label = get_string_resource ("passwd.user.label",
+                                       "Dialog.Label.Label");
+  pw->passwd_label = get_string_resource ("passwd.passwd.label",
+                                         "Dialog.Label.Label");
+
+  if (!pw->heading_label)
+    pw->heading_label = strdup("ERROR: REESOURCES NOT INSTALLED CORRECTLY");
+  if (!pw->body_label)
+    pw->body_label = strdup("ERROR: REESOURCES NOT INSTALLED CORRECTLY");
+  if (!pw->user_label) pw->user_label = strdup("ERROR");
+  if (!pw->passwd_label) pw->passwd_label = strdup("ERROR");
+
+  /* Put the version number in the label. */
+  {
+    char *s = (char *) malloc (strlen(pw->heading_label) + 20);
+    sprintf(s, pw->heading_label, si->version);
+    free (pw->heading_label);
+    pw->heading_label = s;
+  }
 
+  pw->user_string = (p->pw_name ? p->pw_name : "???");
+  pw->passwd_string = strdup("");
+
+  f = get_string_resource ("passwd.headingFont", "Dialog.Font");
+  pw->heading_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
+  if (!pw->heading_font) pw->heading_font = XLoadQueryFont (si->dpy, "fixed");
+  if (f) free (f);
+
+  f = get_string_resource("passwd.bodyFont", "Dialog.Font");
+  pw->body_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
+  if (!pw->body_font) pw->body_font = XLoadQueryFont (si->dpy, "fixed");
+  if (f) free (f);
+
+  f = get_string_resource("passwd.labelFont", "Dialog.Font");
+  pw->label_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
+  if (!pw->label_font) pw->label_font = XLoadQueryFont (si->dpy, "fixed");
+  if (f) free (f);
+
+  f = get_string_resource("passwd.passwdFont", "Dialog.Font");
+  pw->passwd_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
+  if (!pw->passwd_font) pw->passwd_font = XLoadQueryFont (si->dpy, "fixed");
+  if (f) free (f);
+
+  pw->foreground = get_pixel_resource ("passwd.foreground",
+                                      "Dialog.Foreground",
+                                      si->dpy, cmap);
+  pw->background = get_pixel_resource ("passwd.background",
+                                      "Dialog.Background",
+                                      si->dpy, cmap);
+
+  if (pw->foreground == pw->background)
+    {
+      /* Make sure the error messages show up. */
+      pw->foreground = BlackPixelOfScreen (screen);
+      pw->background = WhitePixelOfScreen (screen);
+    }
 
-#ifdef VMS
-static Bool
-vms_passwd_valid_p(char *pw)
-{
-  char *u = getenv("USER");
-  return (validate_user (i, typed_passwd) == 1);
-}
-# undef passwd_valid_p
-# define passwd_valid_p vms_passwd_valid_p
+  pw->passwd_foreground = get_pixel_resource ("passwd.text.foreground",
+                                             "Dialog.Text.Foreground",
+                                             si->dpy, cmap);
+  pw->passwd_background = get_pixel_resource ("passwd.text.background",
+                                             "Dialog.Text.Background",
+                                             si->dpy, cmap);
+  pw->logo_foreground = get_pixel_resource ("passwd.logo.foreground",
+                                           "Dialog.Logo.Foreground",
+                                           si->dpy, cmap);
+  pw->logo_background = get_pixel_resource ("passwd.logo.background",
+                                           "Dialog.Logo.Background",
+                                           si->dpy, cmap);
+  pw->shadow_top = get_pixel_resource ("passwd.topShadowColor",
+                                      "Dialog.Foreground",
+                                      si->dpy, cmap);
+  pw->shadow_bottom = get_pixel_resource ("passwd.bottomShadowColor",
+                                         "Dialog.Background",
+                                         si->dpy, cmap);
+
+  pw->logo_width = get_integer_resource ("passwd.logo.width",
+                                        "Dialog.Logo.Width");
+  pw->logo_height = get_integer_resource ("passwd.logo.height",
+                                         "Dialog.Logo.Height");
+  pw->thermo_width = get_integer_resource ("passwd.thermometer.width",
+                                          "Dialog.Thermometer.Width");
+  pw->internal_border = get_integer_resource ("passwd.internalBorderWidth",
+                                             "Dialog.InternalBorderWidth");
+  pw->shadow_width = get_integer_resource ("passwd.shadowThickness",
+                                          "Dialog.ShadowThickness");
+
+  if (pw->logo_width == 0)  pw->logo_width = 150;
+  if (pw->logo_height == 0) pw->logo_height = 150;
+  if (pw->internal_border == 0) pw->internal_border = 15;
+  if (pw->shadow_width == 0) pw->shadow_width = 4;
+  if (pw->thermo_width == 0) pw->thermo_width = pw->shadow_width;
 
-#endif /* VMS */
+  {
+    int direction, ascent, descent;
+    XCharStruct overall;
+
+    pw->width = 0;
+    pw->height = 0;
+
+    /* Measure the heading_label. */
+    XTextExtents (pw->heading_font,
+                 pw->heading_label, strlen(pw->heading_label),
+                 &direction, &ascent, &descent, &overall);
+    if (overall.width > pw->width) pw->width = overall.width;
+    pw->height += ascent + descent;
+
+    /* Measure the body_label. */
+    XTextExtents (pw->body_font,
+                 pw->body_label, strlen(pw->body_label),
+                 &direction, &ascent, &descent, &overall);
+    if (overall.width > pw->width) pw->width = overall.width;
+    pw->height += ascent + descent;
 
+    {
+      Dimension w2 = 0, w3 = 0;
+      Dimension h2 = 0, h3 = 0;
+      const char *passwd_string = "MMMMMMMMMMMM";
+
+      /* Measure the user_label. */
+      XTextExtents (pw->label_font,
+                   pw->user_label, strlen(pw->user_label),
+                   &direction, &ascent, &descent, &overall);
+      if (overall.width > w2)  w2 = overall.width;
+      h2 += ascent + descent;
+
+      /* Measure the passwd_label. */
+      XTextExtents (pw->label_font,
+                   pw->passwd_label, strlen(pw->passwd_label),
+                   &direction, &ascent, &descent, &overall);
+      if (overall.width > w2)  w2 = overall.width;
+      h2 += ascent + descent;
+
+      /* Measure the user_string. */
+      XTextExtents (pw->passwd_font,
+                   pw->user_string, strlen(pw->user_string),
+                   &direction, &ascent, &descent, &overall);
+      overall.width += (pw->shadow_width * 4);
+      ascent += (pw->shadow_width * 4);
+      if (overall.width > w3)  w3 = overall.width;
+      h3 += ascent + descent;
+
+      /* Measure the (maximally-sized, dummy) passwd_string. */
+      XTextExtents (pw->passwd_font,
+                   passwd_string, strlen(passwd_string),
+                   &direction, &ascent, &descent, &overall);
+      overall.width += (pw->shadow_width * 4);
+      ascent += (pw->shadow_width * 4);
+      if (overall.width > w3)  w3 = overall.width;
+      h3 += ascent + descent;
+
+      w2 = w2 + w3 + (pw->shadow_width * 2);
+      h2 = MAX (h2, h3);
+
+      if (w2 > pw->width)  pw->width  = w2;
+      pw->height += h2;
+    }
 
-static void
-passwd_done_cb (Widget button, XtPointer client_data, XtPointer call_data)
-{
-  if (passwd_state != pw_read) return; /* already done */
+    pw->width  += (pw->internal_border * 2);
+    pw->height += (pw->internal_border * 4);
 
-  if (passwd_valid_p (typed_passwd))
-    passwd_state = pw_ok;
-  else
-    passwd_state = pw_fail;
-}
+    pw->width += pw->thermo_width + (pw->shadow_width * 3);
 
+    if (pw->logo_height > pw->height)
+      pw->height = pw->logo_height;
+    else if (pw->height > pw->logo_height)
+      pw->logo_height = pw->height;
 
-#if defined(HAVE_MOTIF) && defined(VERIFY_CALLBACK_WORKS)
+    pw->logo_width = pw->logo_height;
 
-  /* It looks to me like adding any modifyVerify callback causes
-     Motif 1.1.4 to free the the TextF_Value() twice.  I can't see
-     the bug in the Motif source, but Purify complains, even if
-     check_passwd_cb() is a no-op.
+    pw->width += pw->logo_width;
+  }
 
-     Update: Motif 1.2.1 also loses, but in a different way: it
-     writes beyond the end of a malloc'ed block in ModifyVerify().
-     Probably this block is the text field's text.
-   */
+  attrmask |= CWOverrideRedirect; attrs.override_redirect = True;
+  attrmask |= CWEventMask; attrs.event_mask = ExposureMask|KeyPressMask;
 
-static void 
-check_passwd_cb (Widget button, XtPointer client_data, XtPointer call_data)
-{
-  XmTextVerifyCallbackStruct *vcb = (XmTextVerifyCallbackStruct *) call_data;
+  {
+    Dimension w = WidthOfScreen(screen);
+    Dimension h = HeightOfScreen(screen);
+    if (si->prefs.debug_p) w /= 2;
+    x = ((w + pw->width) / 2) - pw->width;
+    y = ((h + pw->height) / 2) - pw->height;
+    if (x < 0) x = 0;
+    if (y < 0) y = 0;
+  }
 
-  if (passwd_state != pw_read)
-    return;
-  else if (vcb->reason == XmCR_ACTIVATE)
-    {
-      passwd_done_cb (0, 0, 0);
-    }
-  else if (vcb->text->length > 1)      /* don't allow "paste" operations */
-    {
-      vcb->doit = False;
-    }
-  else if (vcb->text->ptr != 0)
-    {
-      int i;
-      int L = vcb->text->length;
-      if (L >= sizeof(typed_passwd))
-       L = sizeof(typed_passwd)-1;
-      strncat (typed_passwd, vcb->text->ptr, L);
-      typed_passwd [vcb->endPos + L] = 0;
-      for (i = 0; i < vcb->text->length; i++)
-       vcb->text->ptr [i] = '*';
-    }
-}
+  bw = get_integer_resource ("passwd.borderWidth", "Dialog.BorderWidth");
 
-# else /* HAVE_ATHENA || !VERIFY_CALLBACK_WORKS */
-
-static void keypress (Widget w, XEvent *event, String *av, Cardinal *ac);
-static void backspace (Widget w, XEvent *event, String *av, Cardinal *ac);
-static void kill_line (Widget w, XEvent *event, String *av, Cardinal *ac);
-static void done (Widget w, XEvent *event, String *av, Cardinal *ac);
-
-static XtActionsRec actions[] = {{"keypress",  keypress},
-                                {"backspace", backspace},
-                                {"kill_line", kill_line},
-                                {"done",      done}
-                               };
-
-# if 0  /* This works for Athena, but not Motif: keypress() gets called
-          for all keys anyway.  So, the implementation of keypress()
-          has BackSpace, etc, hardcoded into it instead.  FMH!
-        */
-static char translations[] =  "<Key>BackSpace: backspace()\n"
-                             "<Key>Delete:     backspace()\n"
-                             "Ctrl<Key>H:      backspace()\n"
-                             "Ctrl<Key>U:      kill_line()\n"
-                             "Ctrl<Key>X:      kill_line()\n"
-                             "Ctrl<Key>J:      done()\n"
-                             "Ctrl<Key>M:      done()\n"
-                             "<Key>:           keypress()\n";
-# else  /* !0 */
-static char translations[] =  "<Key>:          keypress()\n";
-# endif /* !0 */
+  si->passwd_dialog =
+    XCreateWindow (si->dpy,
+                  RootWindowOfScreen(screen),
+                  x, y, pw->width, pw->height, bw,
+                  DefaultDepthOfScreen (screen), InputOutput,
+                  DefaultVisualOfScreen(screen),
+                  attrmask, &attrs);
+  XSetWindowBackground (si->dpy, si->passwd_dialog, pw->background);
 
+  XMapRaised (si->dpy, si->passwd_dialog);
+  XSync (si->dpy, False);
 
-static void
-text_field_set_string (Widget widget, char *text, int position)
-{
-#ifdef HAVE_MOTIF
-  XmTextFieldSetString (widget, text);
-  XmTextFieldSetInsertionPosition (widget, position);
-
-#else /* HAVE_ATHENA */
-  char *buf;
-  int end_pos;
-
-  XawTextBlock block;
-  block.firstPos = 0;
-  block.length = strlen (text);
-  block.ptr = text;
-  block.format = 0;
-  if (block.length == 0)
-    {
-      buf = XawDialogGetValueString(passwd_form);
-      if (buf)
-       end_pos = strlen(buf);
-      else
-       end_pos = -1;
-    }
-  XawTextReplace (widget, 0, end_pos, &block);
-  XawTextSetInsertionPoint (widget, position);
-#endif /* HAVE_ATHENA */
+  si->pw_data = pw;
+
+  draw_passwd_window (si);
+  XSync (si->dpy, False);
 }
 
 
-static void
-keypress (Widget w, XEvent *event, String *argv, Cardinal *argc)
+void
+draw_passwd_window (saver_info *si)
 {
-  int i, j;
-  char s [sizeof(typed_passwd)];
-  int size = XLookupString ((XKeyEvent *) event, s, sizeof(s)-1, 0, 0);
-  if (size != 1) return;
+  passwd_dialog_data *pw = si->pw_data;
+  XGCValues gcv;
+  GC gc1, gc2;
+  int spacing, height;
+  int x1, x2, x3, y1, y2;
+  int sw;
+  int tb_height;
+
+  height = (pw->heading_font->ascent + pw->heading_font->descent +
+           pw->body_font->ascent + pw->body_font->descent +
+           (2 * MAX ((pw->label_font->ascent + pw->label_font->descent),
+                     (pw->passwd_font->ascent + pw->passwd_font->descent +
+                      (pw->shadow_width * 4)))));
+  spacing = ((pw->height - (2 * pw->shadow_width) -
+             pw->internal_border - height)) / 8;
+  if (spacing < 0) spacing = 0;
+
+  gcv.foreground = pw->foreground;
+  gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
+  gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
+  x1 = pw->logo_width + pw->thermo_width + (pw->shadow_width * 3);
+  x3 = pw->width - (pw->shadow_width * 2);
+  y1 = (pw->shadow_width * 2) + spacing + spacing;
+
+  /* top heading
+   */
+  XSetFont (si->dpy, gc1, pw->heading_font->fid);
+  sw = string_width (pw->heading_font, pw->heading_label);
+  x2 = (x1 + ((x3 - x1 - sw) / 2));
+  y1 += spacing + pw->heading_font->ascent + pw->heading_font->descent;
+  XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
+              pw->heading_label, strlen(pw->heading_label));
+
+  /* text below top heading
+   */
+  XSetFont (si->dpy, gc1, pw->body_font->fid);
+  y1 += spacing + pw->body_font->ascent + pw->body_font->descent;
+  sw = string_width (pw->body_font, pw->body_label);
+  x2 = (x1 + ((x3 - x1 - sw) / 2));
+  XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
+              pw->body_label, strlen(pw->body_label));
 
-  /* hack because I can't get translations to dance to my tune... */
-  if (*s == '\010') { backspace (w, event, argv, argc); return; }
-  if (*s == '\177') { backspace (w, event, argv, argc); return; }
-  if (*s == '\025') { kill_line (w, event, argv, argc); return; }
-  if (*s == '\030') { kill_line (w, event, argv, argc); return; }
-  if (*s == '\012') { done (w, event, argv, argc); return; }
-  if (*s == '\015') { done (w, event, argv, argc); return; }
 
-  i = j = strlen (typed_passwd);
+  tb_height = (pw->passwd_font->ascent + pw->passwd_font->descent +
+              (pw->shadow_width * 4));
 
-  if (i >= (sizeof(typed_passwd)-1))
-    {
-      XBell(XtDisplay(w), 0);
-      return;
-    }
+  /* the "User:" prompt
+   */
+  y1 += spacing;
+  y2 = y1;
+  XSetForeground (si->dpy, gc1, pw->foreground);
+  XSetFont (si->dpy, gc1, pw->label_font->fid);
+  y1 += (spacing + tb_height);
+  x2 = (x1 + pw->internal_border +
+       MAX(string_width (pw->label_font, pw->user_label),
+           string_width (pw->label_font, pw->passwd_label)));
+  XDrawString (si->dpy, si->passwd_dialog, gc1,
+              x2 - string_width (pw->label_font, pw->user_label),
+              y1,
+              pw->user_label, strlen(pw->user_label));
+
+  /* the "Password:" prompt
+   */
+  y1 += (spacing + tb_height);
+  XDrawString (si->dpy, si->passwd_dialog, gc1,
+              x2 - string_width (pw->label_font, pw->passwd_label),
+              y1,
+              pw->passwd_label, strlen(pw->passwd_label));
 
-  typed_passwd [i] = *s;
-  s [++i] = 0;
-  while (i--)
-    s [i] = '*';
 
-  text_field_set_string (passwd_text, s, j + 1);
-}
+  XSetForeground (si->dpy, gc2, pw->passwd_background);
 
-static void
-backspace (Widget w, XEvent *event, String *argv, Cardinal *argc)
-{
-  char s [sizeof(typed_passwd)];
-  int i = strlen (typed_passwd);
-  int j = i;
-  if (i == 0)
-    return;
-  typed_passwd [--i] = 0;
-  s [i] = 0;
-  while (i--)
-    s [i] = '*';
-
-  text_field_set_string (passwd_text, s, j + 1);
-}
+  /* the "user name" text field
+   */
+  y1 = y2;
+  XSetForeground (si->dpy, gc1, pw->passwd_foreground);
+  XSetFont (si->dpy, gc1, pw->passwd_font->fid);
+  y1 += (spacing + tb_height);
+  x2 += (pw->shadow_width * 4);
+
+  pw->passwd_field_width = x3 - x2 - pw->internal_border;
+  pw->passwd_field_height = (pw->passwd_font->ascent +
+                            pw->passwd_font->descent +
+                            pw->shadow_width);
+
+  XFillRectangle (si->dpy, si->passwd_dialog, gc2,
+                 x2 - pw->shadow_width,
+                 y1 - (pw->passwd_font->ascent + pw->passwd_font->descent),
+                 pw->passwd_field_width, pw->passwd_field_height);
+  XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
+              pw->user_string, strlen(pw->user_string));
+
+  /* the "password" text field
+   */
+  y1 += (spacing + tb_height);
 
-static void
-kill_line (Widget w, XEvent *event, String *argv, Cardinal *argc)
-{
-  memset (typed_passwd, 0, sizeof(typed_passwd));
-  text_field_set_string (passwd_text, "", 0);
-}
+  pw->passwd_field_x = x2 - pw->shadow_width;
+  pw->passwd_field_y = y1 - (pw->passwd_font->ascent +
+                            pw->passwd_font->descent);
 
-static void
-done (Widget w, XEvent *event, String *argv, Cardinal *argc)
-{
-  passwd_done_cb (w, 0, 0);
-}
+  /* The shadow around the text fields
+   */
+  y1 = y2;
+  y1 += (spacing + (pw->shadow_width * 3));
+  x1 = x2 - (pw->shadow_width * 2);
+  x2 = pw->passwd_field_width + (pw->shadow_width * 2);
+  y2 = pw->passwd_field_height + (pw->shadow_width * 2);
+
+  draw_shaded_rectangle (si->dpy, si->passwd_dialog,
+                        x1, y1, x2, y2,
+                        pw->shadow_width,
+                        pw->shadow_bottom, pw->shadow_top);
+
+  y1 += (spacing + pw->passwd_font->ascent + pw->passwd_font->descent +
+        (pw->shadow_width * 4));
+  draw_shaded_rectangle (si->dpy, si->passwd_dialog,
+                        x1, y1, x2, y2,
+                        pw->shadow_width,
+                        pw->shadow_bottom, pw->shadow_top);
+
+  /* the logo
+   */
+  XSetForeground (si->dpy, gc1, pw->logo_foreground);
+  XSetForeground (si->dpy, gc2, pw->logo_background);
 
-#endif /* HAVE_ATHENA || !VERIFY_CALLBACK_WORKS */
+  x1 = pw->shadow_width * 3;
+  y1 = pw->shadow_width * 3;
+  x2 = pw->logo_width - (pw->shadow_width * 6);
+  y2 = pw->logo_height - (pw->shadow_width * 6);
 
+  XFillRectangle (si->dpy, si->passwd_dialog, gc2, x1, y1, x2, y2);
+  skull (si->dpy, si->passwd_dialog, gc1, gc2,
+        x1 + pw->shadow_width, y1 + pw->shadow_width,
+        x2 - (pw->shadow_width * 2), y2 - (pw->shadow_width * 2));
 
-static void
-make_passwd_dialog (saver_info *si)
-{
-  char *username = 0;
-  saver_screen_info *ssi = si->default_screen;
-  Widget parent = ssi->toplevel_shell;
+  /* The thermometer
+   */
+  pw->thermo_field_x = pw->logo_width + pw->shadow_width;
+  pw->thermo_field_y = pw->shadow_width * 3;
+  pw->thermo_field_height = pw->height - (pw->shadow_width * 6);
 
-  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;
-    }
+  /* Solid border inside the logo box. */
+  XSetForeground (si->dpy, gc1, pw->foreground);
+  XDrawRectangle (si->dpy, si->passwd_dialog, gc1, x1, y1, x2-1, y2-1);
 
-  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);
+  /* The shadow around the logo
+   */
+  draw_shaded_rectangle (si->dpy, si->passwd_dialog,
+                        pw->shadow_width * 2,
+                        pw->shadow_width * 2,
+                        pw->logo_width - (pw->shadow_width * 4),
+                        pw->logo_height - (pw->shadow_width * 4),
+                        pw->shadow_width,
+                        pw->shadow_bottom, pw->shadow_top);
+
+  /* The shadow around the thermometer
+   */
+  draw_shaded_rectangle (si->dpy, si->passwd_dialog,
+                        pw->logo_width,
+                        pw->shadow_width * 2,
+                        pw->thermo_width + (pw->shadow_width * 2),
+                        pw->height - (pw->shadow_width * 4),
+                        pw->shadow_width,
+                        pw->shadow_bottom, pw->shadow_top);
+
+  /* Solid border inside the thermometer. */
+  XSetForeground (si->dpy, gc1, pw->foreground);
+  XDrawRectangle (si->dpy, si->passwd_dialog, gc1, 
+                 pw->logo_width + pw->shadow_width,
+                 pw->shadow_width * 3,
+                 pw->thermo_width - 1,
+                 pw->height - (pw->shadow_width * 6) - 1);
+
+  /* The shadow around the whole window
+   */
+  draw_shaded_rectangle (si->dpy, si->passwd_dialog,
+                        0, 0, pw->width, pw->height, pw->shadow_width,
+                        pw->shadow_top, pw->shadow_bottom);
 
-  create_passwd_dialog (parent, ssi->default_visual, ssi->demo_cmap);
+  XFreeGC (si->dpy, gc1);
+  XFreeGC (si->dpy, gc2);
 
-#ifdef HAVE_ATHENA
-  XtVaSetValues(passwd_form, XtNvalue, typed_passwd, 0);
+  update_passwd_window (si, pw->passwd_string, pw->ratio);
+}
 
-  XawDialogAddButton(passwd_form,"ok", passwd_done_cb, 0);
-  XawDialogAddButton(passwd_form,"cancel", passwd_cancel_cb, 0);
-  passwd_done = XtNameToWidget(passwd_form,"ok");
-  passwd_text = XtNameToWidget(passwd_form,"value");
 
-  XtAppAddActions(XtWidgetToApplicationContext(passwd_text),
-                 actions, XtNumber(actions));
-  XtOverrideTranslations(passwd_text, XtParseTranslationTable(translations));
+void
+update_passwd_window (saver_info *si, const char *printed_passwd, float ratio)
+{
+  passwd_dialog_data *pw = si->pw_data;
+  XGCValues gcv;
+  GC gc1, gc2;
+  int x, y;
+
+  pw->ratio = ratio;
+  gcv.foreground = pw->passwd_foreground;
+  gcv.font = pw->passwd_font->fid;
+  gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground|GCFont, &gcv);
+  gcv.foreground = pw->passwd_background;
+  gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
+
+  if (printed_passwd)
+    {
+      char *s = strdup (printed_passwd);
+      if (pw->passwd_string) free (pw->passwd_string);
+      pw->passwd_string = s;
+    }
 
-  /* Lose the label on the inner dialog. */
-  {
-    Widget w = XtNameToWidget(passwd_form, "label");
-    if (w) XtUnmanageChild(w);
-  }
+  /* the "password" text field
+   */
+  XFillRectangle (si->dpy, si->passwd_dialog, gc2,
+                 pw->passwd_field_x, pw->passwd_field_y,
+                 pw->passwd_field_width, pw->passwd_field_height);
+  XDrawString (si->dpy, si->passwd_dialog, gc1,
+              pw->passwd_field_x + pw->shadow_width,
+              pw->passwd_field_y + (pw->passwd_font->ascent +
+                                    pw->passwd_font->descent),
+              pw->passwd_string, strlen(pw->passwd_string));
+
+  /* The I-beam
+   */
+  if (pw->i_beam != 0)
+    {
+      x = (pw->passwd_field_x + pw->shadow_width +
+          string_width (pw->passwd_font, pw->passwd_string));
+      y = pw->passwd_field_y + pw->shadow_width;
+      XDrawLine (si->dpy, si->passwd_dialog, gc1, 
+                x, y, x, y + pw->passwd_font->ascent);
+    }
 
-#else  /* HAVE_MOTIF */
+  pw->i_beam = (pw->i_beam + 1) % 4;
 
-  XtAddCallback (passwd_done, XmNactivateCallback, passwd_done_cb, 0);
-  XtAddCallback (passwd_cancel, XmNactivateCallback, passwd_cancel_cb, 0);
-  XtAddCallback (roger_label, XmNexposeCallback, roger, 0);
 
-# ifdef VERIFY_CALLBACK_WORKS
-  XtAddCallback (passwd_text, XmNmodifyVerifyCallback, check_passwd_cb, 0);
-  XtAddCallback (passwd_text, XmNactivateCallback, check_passwd_cb, 0);
-# else  /* !VERIFY_CALLBACK_WORKS */
-  XtAddCallback (passwd_text, XmNactivateCallback, passwd_done_cb, 0);
-  XtOverrideTranslations (passwd_text, XtParseTranslationTable (translations));
-# endif /* !VERIFY_CALLBACK_WORKS */
+  /* the thermometer
+   */
+  y = pw->thermo_field_height * (1.0 - pw->ratio);
+  if (y > 0)
+    {
+      XFillRectangle (si->dpy, si->passwd_dialog, gc2,
+                     pw->thermo_field_x + 1,
+                     pw->thermo_field_y + 1,
+                     pw->thermo_width-2,
+                     y);
+      XSetForeground (si->dpy, gc1, pw->logo_foreground);
+      XFillRectangle (si->dpy, si->passwd_dialog, gc1,
+                     pw->thermo_field_x + 1,
+                     pw->thermo_field_y + 1 + y,
+                     pw->thermo_width-2,
+                     MAX (0, pw->thermo_field_height - y - 2));
+    }
 
-# if defined(HAVE_MOTIF) && (XmVersion >= 1002)
-  /* The focus stuff changed around; this didn't exist in 1.1.5. */
-  XtVaSetValues (passwd_form, XmNinitialFocus, passwd_text, 0);
-# endif /* HAVE_MOTIF && XmVersion >= 1002 */
+  XFreeGC (si->dpy, gc1);
+  XFreeGC (si->dpy, gc2);
+  XSync (si->dpy, False);
+}
 
-  /* Another random thing necessary in 1.2.1 but not 1.1.5... */
-  XtVaSetValues (roger_label, XmNborderWidth, 2, 0);
 
-#endif /* HAVE_MOTIF */
+void
+destroy_passwd_window (saver_info *si)
+{
+  passwd_dialog_data *pw = si->pw_data;
+  Screen *screen = si->default_screen->screen;
+  Colormap cmap = DefaultColormapOfScreen (screen);
+  Pixel black = BlackPixelOfScreen (screen);
+  Pixel white = WhitePixelOfScreen (screen);
 
-#ifndef VMS
-  {
-    struct passwd *pw = getpwuid (getuid ());
-    username = pw->pw_name;
-  }
-#else  /* VMS -- from "R.S.Niranjan" <U00C782%BRKVC1@navistar.com> who says
-                that on OpenVMS 6.1, using `struct passwd' crashes... */
-  username = getenv("USER");
-#endif /* VMS */
+  if (pw->timer)
+    XtRemoveTimeOut (pw->timer);
 
-  format_into_label (passwd_label1, si->version);
-  format_into_label (passwd_label3, (username ? username : "???"));
+  if (si->passwd_dialog)
+    {
+      XDestroyWindow (si->dpy, si->passwd_dialog);
+      si->passwd_dialog = 0;
+    }
+  
+  if (pw->heading_label) free (pw->heading_label);
+  if (pw->body_label)    free (pw->body_label);
+  if (pw->user_label)    free (pw->user_label);
+  if (pw->passwd_label)  free (pw->passwd_label);
+
+  if (pw->heading_font) XFreeFont (si->dpy, pw->heading_font);
+  if (pw->body_font)    XFreeFont (si->dpy, pw->body_font);
+  if (pw->label_font)   XFreeFont (si->dpy, pw->label_font);
+  if (pw->passwd_font)  XFreeFont (si->dpy, pw->passwd_font);
+
+  if (pw->foreground != black && pw->foreground != white)
+    XFreeColors (si->dpy, cmap, &pw->foreground, 1, 0L);
+  if (pw->background != black && pw->background != white)
+    XFreeColors (si->dpy, cmap, &pw->background, 1, 0L);
+  if (pw->passwd_foreground != black && pw->passwd_foreground != white)
+    XFreeColors (si->dpy, cmap, &pw->passwd_foreground, 1, 0L);
+  if (pw->passwd_background != black && pw->passwd_background != white)
+    XFreeColors (si->dpy, cmap, &pw->passwd_background, 1, 0L);
+  if (pw->logo_foreground != black && pw->logo_foreground != white)
+    XFreeColors (si->dpy, cmap, &pw->logo_foreground, 1, 0L);
+  if (pw->logo_background != black && pw->logo_background != white)
+    XFreeColors (si->dpy, cmap, &pw->logo_background, 1, 0L);
+  if (pw->shadow_top != black && pw->shadow_top != white)
+    XFreeColors (si->dpy, cmap, &pw->shadow_top, 1, 0L);
+  if (pw->shadow_bottom != black && pw->shadow_bottom != white)
+    XFreeColors (si->dpy, cmap, &pw->shadow_bottom, 1, 0L);
+
+  memset (pw, 0, sizeof(*pw));
+  free (pw);
+
+  si->pw_data = 0;
 }
 
-static int passwd_idle_timer_tick = -1;
-static XtIntervalId passwd_idle_id;
+\f
+/* Interactions
+ */
 
 static void
-passwd_idle_timer (XtPointer closure, XtIntervalId *id)
+passwd_animate_timer (XtPointer closure, XtIntervalId *id)
 {
   saver_info *si = (saver_info *) closure;
-  saver_preferences *p = &si->prefs;
-
-  Display *dpy = XtDisplay (passwd_form);
-#ifdef HAVE_ATHENA
-  Window window = XtWindow (passwd_form);
-#else  /* MOTIF */
-  Window window = XtWindow (XtParent(passwd_done));
-#endif /* MOTIF */
-  static Dimension x, y, d, s, ss;
-  static GC gc = 0;
-  int max = p->passwd_timeout / 1000;
+  int tick = 166;
+  passwd_dialog_data *pw = si->pw_data;
 
-  idle_timer ((XtPointer) si, id);
+  if (!pw) return;
 
-  if (passwd_idle_timer_tick == max)  /* first time */
+  pw->ratio -= (1.0 / ((double) si->prefs.passwd_timeout / (double) tick));
+  if (pw->ratio < 0)
     {
-      XGCValues gcv;
-#ifdef HAVE_MOTIF
-      unsigned long fg = 0, bg = 0, ts = 0, bs = 0;
-      Dimension w = 0, h = 0;
-      XtVaGetValues(XtParent(passwd_done),
-                   XmNwidth, &w,
-                   0);
-      XtVaGetValues(passwd_done,
-                   XmNheight, &h,
-                   XmNy, &y,
-                   0);
-      XtVaGetValues(passwd_form,
-                   XtNforeground, &fg,
-                   XtNbackground, &bg,
-                   XmNtopShadowColor, &ts,
-                   XmNbottomShadowColor, &bs,
-                   0);
-
-      if (ts != bg && ts != fg)
-       fg = ts;
-      if (bs != bg && bs != fg)
-       fg = bs;
-
-      d = h / 2;
-      if (d & 1) d++;
-
-      x = (w / 2);
-
-# ifdef __sgi  /* Kludge -- SGI's Motif hacks place buttons differently. */
-      {
-       static int sgi_mode = -1;
-       if (sgi_mode == -1)
-         sgi_mode = get_boolean_resource("sgiMode", "sgiMode") ? 1 : 0;
-
-       if (sgi_mode)
-         x = d;
-      }
-# endif /* __sgi */
-
-      x -= d/2;
-      y += d/2;
-
-#else  /* HAVE_ATHENA */
-
-      Arg av [100];
-      int ac = 0;
-      unsigned long fg = 0, bg = 0;
-      XtSetArg (av [ac], XtNheight, &d); ac++;
-      XtGetValues (passwd_done, av, ac);
-      ac = 0;
-      XtSetArg (av [ac], XtNwidth, &x); ac++;
-      XtSetArg (av [ac], XtNheight, &y); ac++;
-      XtSetArg (av [ac], XtNforeground, &fg); ac++;
-      XtSetArg (av [ac], XtNbackground, &bg); ac++;
-      XtGetValues (passwd_form, av, ac);
-      x -= d;
-      y -= d;
-      d -= 4;
-
-#endif /* HAVE_ATHENA */
-
-      gcv.foreground = fg;
-      if (gc) XFreeGC (dpy, gc);
-      gc = XCreateGC (dpy, window, GCForeground, &gcv);
-      s = 360*64 / (passwd_idle_timer_tick - 1);
-      ss = 90*64;
-      XFillArc (dpy, window, gc, x, y, d, d, 0, 360*64);
-      XSetForeground (dpy, gc, bg);
-      x += 1;
-      y += 1;
-      d -= 2;
+      pw->ratio = 0;
+      if (pw->state == pw_read)
+       pw->state = pw_time;
     }
 
-  if (--passwd_idle_timer_tick)
-    {
-      passwd_idle_id = XtAppAddTimeOut (si->app, 1000, passwd_idle_timer,
-                                       (XtPointer) si);
-      XFillArc (dpy, window, gc, x, y, d, d, ss, s);
-      ss += s;
-    }
+  update_passwd_window (si, 0, pw->ratio);
+
+  if (pw->state == pw_read)
+    pw->timer = XtAppAddTimeOut (si->app, tick, passwd_animate_timer,
+                                (XtPointer) si);
+  else
+    pw->timer = 0;
+
+  idle_timer ((XtPointer) si, id);
 }
 
 
-static Bool
-pop_passwd_dialog (saver_info *si)
+static void
+handle_passwd_key (saver_info *si, XKeyEvent *event)
 {
-  saver_preferences *p = &si->prefs;
-  saver_screen_info *ssi = si->default_screen;
-  Widget parent = ssi->toplevel_shell;
-  Display *dpy = XtDisplay (passwd_dialog);
-  Window focus;
-  int revert_to;
+  passwd_dialog_data *pw = si->pw_data;
+  int pw_size = sizeof (pw->typed_passwd) - 1;
+  char *typed_passwd = pw->typed_passwd;
+  char s[2];
+  char *stars = 0;
   int i;
-  Window grab_window = RootWindowOfScreen(si->screens[0].screen);
-
-  typed_passwd [0] = 0;
-  passwd_state = pw_read;
-  text_field_set_string (passwd_text, "", 0);
-
-  /* In case one of the hacks has unmapped it temporarily...
-     Get that sucker on stage now! */
-  for (i = 0; i < si->nscreens; i++)
-    XMapRaised(si->dpy, si->screens[i].screensaver_window);
-
-  XGetInputFocus (dpy, &focus, &revert_to);
-#if defined(HAVE_MOTIF) && !defined(DESTROY_WORKS)
-  /* This fucker blows up if we destroy the widget.  I can't figure
-     out why.  The second destroy phase dereferences freed memory...
-     So we just keep it around; but unrealizing or unmanaging it
-     doesn't work right either, so we hack the window directly. FMH.
-   */
-  if (XtWindow (passwd_form))
-    XMapRaised (dpy, XtWindow (passwd_dialog));
-#endif /* HAVE_MOTIF && !DESTROY_WORKS */
-
-  monitor_power_on (si);
-  pop_up_dialog_box (passwd_dialog, passwd_form,
-                    /* for debugging -- don't ask */
-                    (si->prefs.debug_p ? 69 : 0) +
-                    2);
-  XtManageChild (passwd_form);
-
-#ifdef HAVE_ATHENA
-  steal_focus_and_colormap (passwd_text);
-
-  /* For some reason, the passwd_form box is not stretching all the way
-     to the right edge of the window, despite being XtChainRight.
-     So... resize it by hand.
-  */
-  {
-    Dimension x=0, w=0, h=0;
-    XtVaGetValues(passwd_form, XtNx, &x, XtNwidth, &w, XtNheight, &h, 0);
-    XtVaGetValues(XtParent(passwd_form), XtNwidth, &w, 0);
-    w -= x;
-    w -= 6;
-    if (w > 0) XtResizeWidget(passwd_form, w, h, 0);
-  }
+  int size = XLookupString (event, s, 1, 0, 0);
+
+  if (size != 1) return;
 
-#endif /* HAVE_ATHENA */
+  s[1] = 0;
 
+  switch (*s)
+    {
+    case '\010': case '\177':                          /* Backspace */
+      if (!*typed_passwd)
+       XBell (si->dpy, 0);
+      else
+       typed_passwd [strlen(typed_passwd)-1] = 0;
+      break;
+
+    case '\025': case '\030':                          /* Erase line */
+      memset (typed_passwd, 0, pw_size);
+      break;
+
+    case '\012': case '\015':                          /* Enter */
+      if (pw->state != pw_read)
+       ;  /* already done? */
+      else if (passwd_valid_p (typed_passwd))
+       pw->state = pw_ok;
+      else
+       pw->state = pw_fail;
+      break;
 
-#if defined(HAVE_MOTIF) && (XmVersion < 1002)
-  /* The focus stuff changed around; this causes problems in 1.2.1
-     but is necessary in 1.1.5. */
-  XmProcessTraversal (passwd_text, XmTRAVERSE_CURRENT);
-#endif /* HAVE_MOTIF && XmVersion < 1002 */
+    default:
+      i = strlen (typed_passwd);
+      if (i >= pw_size-1)
+       XBell (si->dpy, 0);
+      else
+       {
+         typed_passwd [i] = *s;
+         typed_passwd [i+1] = 0;
+       }
+      break;
+    }
 
-  passwd_idle_timer_tick = p->passwd_timeout / 1000;
-  passwd_idle_id = XtAppAddTimeOut (si->app, 1000,  passwd_idle_timer,
-                                   (XtPointer) si);
+  i = strlen(typed_passwd);
+  stars = (char *) malloc(i+1);
+  memset (stars, '*', i);
+  stars[i] = 0;
+  update_passwd_window (si, stars, pw->ratio);
+  free (stars);
+}
 
-#ifdef HAVE_ATHENA
-  if (roger_label)
-    roger(roger_label, 0, 0);
-#endif /* HAVE_ATHENA */
 
+static void
+passwd_event_loop (saver_info *si)
+{
+  char *msg = 0;
+  XEvent event;
+  passwd_animate_timer ((XtPointer) si, 0);
 
-  /* Make sure the mouse cursor is visible.
-     Since the screensaver was already active, we had already called
-     grab_keyboard_and_mouse() with our "invisible" Cursor object.
-     Now we need to change that.  (cursor == 0 means "server default
-     cursor.")
-   */
-  if (grab_window != si->mouse_grab_window ||
-      grab_window != si->keyboard_grab_window)
-    fprintf(stderr,
-           "%s: WARNING: expected mouse and keyboard grabs on 0x%x,\n"
-           "\tbut mouse-grab is 0x%x and keyboard-grab is 0x%x.\n",
-           blurb(),
-           (unsigned long) grab_window,
-           (unsigned long) si->mouse_grab_window,
-           (unsigned long) si->keyboard_grab_window);
-
-  if (p->verbose_p)
-    fprintf(stderr, "%s: re-grabbing keyboard and mouse to expose cursor.\n",
-           blurb());
-  grab_keyboard_and_mouse (si, grab_window, 0);
-
-
-  if (!si->prefs.debug_p)
-    XGrabServer (dpy);                         /* ############ DANGER! */
-
-  while (passwd_state == pw_read)
+  while (si->pw_data && si->pw_data->state == pw_read)
     {
-      XEvent event;
       XtAppNextEvent (si->app, &event);
-      /* wait for timer event */
-      if (event.xany.type == 0 && passwd_idle_timer_tick == 0)
-       passwd_state = pw_time;
-      XtDispatchEvent (&event);
+      if (event.xany.window == si->passwd_dialog && event.xany.type == Expose)
+       draw_passwd_window (si);
+      else if (event.xany.type == KeyPress)
+       handle_passwd_key (si, &event.xkey);
+      else
+       XtDispatchEvent (&event);
     }
-  XUngrabServer (dpy);
-  XSync (dpy, False);                          /* ###### (danger over) */
-
-
-  /* Now turn off the mouse cursor again.
-   */
-  if (p->verbose_p)
-    fprintf(stderr, "%s: re-grabbing keyboard and mouse to hide cursor.\n",
-           blurb());
-  grab_keyboard_and_mouse (si, grab_window, si->screens[0].cursor);
 
-
-  if (passwd_state != pw_time)
-    XtRemoveTimeOut (passwd_idle_id);
-
-  if (passwd_state != pw_ok)
+  switch (si->pw_data->state)
     {
-      char *lose;
-      switch (passwd_state)
-       {
-       case pw_time: lose = "Timed out!"; break;
-       case pw_fail: lose = "Sorry!"; break;
-       case pw_cancel: lose = 0; break;
-       default: abort ();
-       }
-
-#ifdef HAVE_MOTIF
-      XmProcessTraversal (passwd_cancel, 0); /* turn off I-beam */
-#else  /* HAVE_ATHENA */
-      steal_focus_and_colormap (passwd_done);
-#endif /* HAVE_ATHENA */
-
-      if (lose)
-       {
-         text_field_set_string (passwd_text, lose, strlen (lose) + 1);
-
-         passwd_idle_timer_tick = 1;
-         passwd_idle_id = XtAppAddTimeOut (si->app, 3000, passwd_idle_timer,
-                               (XtPointer) si);
-         while (1)
-           {
-             XEvent event;
-             XtAppNextEvent (si->app, &event);
-             if (event.xany.type == 0 &&       /* wait for timer event */
-                 passwd_idle_timer_tick == 0)
-               break;
-             XtDispatchEvent (&event);
-           }
-       }
+    case pw_ok:   msg = 0; break;
+    case pw_time: msg = "Timed out!"; break;
+    default:      msg = "Sorry!"; break;
     }
-  memset (typed_passwd, 0, sizeof(typed_passwd));
-  text_field_set_string (passwd_text, "", 0);
-  XtSetKeyboardFocus (parent, None);
-
-#ifdef DESTROY_WORKS
-  XtDestroyWidget (passwd_dialog);
-  passwd_dialog = 0;
-#else  /* !DESTROY_WORKS */
-  XUnmapWindow (XtDisplay (passwd_dialog), XtWindow (passwd_dialog));
-#endif /* !DESTROY_WORKS */
-  {
-    XErrorHandler old_handler = XSetErrorHandler (BadWindow_ehandler);
-    /* I don't understand why this doesn't refocus on the old selected
-       window when MWM is running in click-to-type mode.  The value of
-       `focus' seems to be correct. */
-    XSetInputFocus (dpy, focus, revert_to, CurrentTime);
-    XSync (dpy, False);
-    XSetErrorHandler (old_handler);
-  }
 
-  /* Since we installed our colormap to display the dialog properly, put
-     the old one back, so that the screensaver_window is now displayed
-     properly. */
-  for (i = 0; i < si->nscreens; i++)
+  if (msg)
     {
-      saver_screen_info *ssi = &si->screens[i];
-      if (ssi->cmap)
-       XInstallColormap (si->dpy, ssi->cmap);
-    }
+      si->pw_data->i_beam = 0;
+      update_passwd_window (si, msg, 0.0);
+      XBell (si->dpy, False);
+      XSync (si->dpy, False);
+      sleep (1);
 
-  return (passwd_state == pw_ok ? True : False);
+      /* Swallow all pending KeyPress/KeyRelease events. */
+      {
+       XEvent e;
+       while (XCheckMaskEvent (si->dpy, KeyPressMask|KeyReleaseMask, &e))
+         ;
+      }
+    }
 }
 
 Bool
 unlock_p (saver_info *si)
 {
-  static Bool initted = False;
-  if (! initted)
-    {
+  Screen *screen = si->default_screen->screen;
+  Colormap cmap = DefaultColormapOfScreen (screen);
+  Bool status;
 
-#ifndef VERIFY_CALLBACK_WORKS
-      XtAppAddActions (si->app, actions, XtNumber (actions));
-#endif /* !VERIFY_CALLBACK_WORKS */
+  if (si->pw_data || si->passwd_dialog)
+    destroy_passwd_window (si);
 
-      passwd_dialog = 0;
-      initted = True;
-    }
-  if (! passwd_dialog)
-    make_passwd_dialog (si);
-  return pop_passwd_dialog (si);
+  make_passwd_window (si);
+  if (cmap) XInstallColormap (si->dpy, cmap);
+
+  passwd_event_loop (si);
+
+  status = (si->pw_data->state == pw_ok);
+  destroy_passwd_window (si);
+
+  cmap = si->default_screen->cmap;
+  if (cmap) XInstallColormap (si->dpy, cmap);
+
+  return status;
 }
 
 #endif /* !NO_LOCKING -- whole file */