+#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, Bool verbose_p)
+{
+ return (validate_user (getenv("USER"), typed_passwd) == 1);
+}
+# undef passwd_valid_p
+# define passwd_valid_p vms_passwd_valid_p
+
+#endif /* VMS */
+
+
+#undef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
+
+enum passwd_state { pw_read, pw_ok, pw_null, pw_fail, pw_cancel, pw_time };
+
+struct passwd_dialog_data {
+
+ saver_screen_info *prompt_screen;
+ int previous_mouse_x, previous_mouse_y;
+
+ enum passwd_state state;
+ char typed_passwd [80];
+ XtIntervalId timer;
+ int i_beam;
+
+ float ratio;
+ Position x, y;
+ Dimension width;
+ Dimension height;
+ Dimension border_width;
+
+ char *heading_label;
+ char *body_label;
+ char *user_label;
+ char *passwd_label;
+ char *date_label;
+ char *user_string;
+ char *passwd_string;
+ char *login_label;
+
+ XFontStruct *heading_font;
+ XFontStruct *body_font;
+ XFontStruct *label_font;
+ XFontStruct *passwd_font;
+ XFontStruct *date_font;
+ XFontStruct *button_font;
+
+ Pixel foreground;
+ Pixel background;
+ Pixel passwd_foreground;
+ Pixel passwd_background;
+ Pixel thermo_foreground;
+ Pixel thermo_background;
+ Pixel shadow_top;
+ Pixel shadow_bottom;
+ Pixel button_foreground;
+ Pixel button_background;
+
+ 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;
+
+ Dimension login_button_x, login_button_y;
+ Dimension login_button_width, login_button_height;
+
+ Dimension thermo_field_x, thermo_field_y;
+ Dimension thermo_field_height;
+
+ Pixmap logo_pixmap;
+ int logo_npixels;
+ unsigned long *logo_pixels;
+
+ Cursor passwd_cursor;
+ Bool login_button_down_p;
+ Bool login_button_p;
+ Bool login_button_enabled_p;
+
+ Pixmap save_under;
+};
+
+static void draw_passwd_window (saver_info *si);
+static void update_passwd_window (saver_info *si, const char *printed_passwd,
+ float ratio);
+static void destroy_passwd_window (saver_info *si);
+static void undo_vp_motion (saver_info *si);
+static void handle_passwd_button (saver_info *si, XEvent *event);
+
+
+static void
+make_passwd_window (saver_info *si)
+{
+ struct passwd *p = getpwuid (getuid ());
+ XSetWindowAttributes attrs;
+ unsigned long attrmask = 0;
+ passwd_dialog_data *pw = (passwd_dialog_data *) calloc (1, sizeof(*pw));
+ Screen *screen;
+ Colormap cmap;
+ char *f;
+ saver_screen_info *ssi = &si->screens [mouse_screen (si)];
+
+ /* Display the button only if the "newLoginCommand" pref is non-null.
+ */
+ pw->login_button_p = (si->prefs.new_login_command &&
+ *si->prefs.new_login_command);
+
+ if (pw->login_button_p)
+ pw->passwd_cursor = XCreateFontCursor (si->dpy, XC_top_left_arrow);
+ else
+ pw->passwd_cursor = 0;
+
+ pw->prompt_screen = ssi;
+ if (si->prefs.verbose_p)
+ fprintf (stderr, "%s: %d: creating password dialog.\n",
+ blurb(), pw->prompt_screen->number);
+
+ screen = pw->prompt_screen->screen;
+ cmap = DefaultColormapOfScreen (screen);
+
+ 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");
+ pw->login_label = get_string_resource ("passwd.login.label",
+ "Dialog.Button.Label");
+
+ pw->date_label = get_string_resource ("dateFormat", "DateFormat");
+
+ if (!pw->heading_label)
+ pw->heading_label = strdup("ERROR: RESOURCES NOT INSTALLED CORRECTLY");
+ if (!pw->body_label)
+ pw->body_label = strdup("ERROR: RESOURCES NOT INSTALLED CORRECTLY");
+ if (!pw->user_label) pw->user_label = strdup("ERROR");
+ if (!pw->passwd_label) pw->passwd_label = strdup("ERROR");
+ if (!pw->date_label) pw->date_label = strdup("ERROR");
+ if (!pw->login_label) pw->login_label = strdup ("ERROR (LOGIN)") ;
+
+ /* 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 = strdup (p && 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.buttonFont", "Dialog.Font");
+ pw->button_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
+ if (!pw->button_font) pw->button_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);
+
+ f = get_string_resource("passwd.dateFont", "Dialog.Font");
+ pw->date_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
+ if (!pw->date_font) pw->date_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);
+ }
+
+ 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->button_foreground = get_pixel_resource ("splash.Button.foreground",
+ "Dialog.Button.Foreground",
+ si->dpy, cmap);
+ pw->button_background = get_pixel_resource ("splash.Button.background",
+ "Dialog.Button.Background",
+ si->dpy, cmap);
+ pw->thermo_foreground = get_pixel_resource ("passwd.thermometer.foreground",
+ "Dialog.Thermometer.Foreground",
+ si->dpy, cmap);
+ pw->thermo_background = get_pixel_resource ("passwd.thermometer.background",
+ "Dialog.Thermometer.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;
+
+ {
+ 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, button_w = 0;
+ Dimension h2 = 0, h3 = 0, button_h = 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);
+
+ pw->login_button_width = 0;
+ pw->login_button_height = 0;
+
+ if (pw->login_button_p)
+ {
+ pw->login_button_enabled_p = True;
+
+ /* Measure the "New Login" button */
+ XTextExtents (pw->button_font, pw->login_label,
+ strlen (pw->login_label),
+ &direction, &ascent, &descent, &overall);
+ button_w = overall.width;
+ button_h = ascent + descent;
+
+ /* Add some horizontal padding inside the buttons. */
+ button_w += ascent;
+
+ button_w += ((ascent + descent) / 2) + (pw->shadow_width * 2);
+ button_h += ((ascent + descent) / 2) + (pw->shadow_width * 2);
+
+ pw->login_button_width = button_w;
+ pw->login_button_height = button_h;
+
+ w2 = MAX (w2, button_w);
+ h2 += button_h * 1.5;
+ }
+
+ if (w2 > pw->width) pw->width = w2;
+ pw->height += h2;
+ }
+
+ pw->width += (pw->internal_border * 2);
+ pw->height += (pw->internal_border * 4);
+
+ 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;
+
+ pw->logo_width = pw->logo_height;
+
+ pw->width += pw->logo_width;
+ }
+
+ attrmask |= CWOverrideRedirect; attrs.override_redirect = True;
+
+ attrmask |= CWEventMask;
+ attrs.event_mask = (ExposureMask | KeyPressMask |
+ ButtonPressMask | ButtonReleaseMask);
+
+ /* We need to remember the mouse position and restore it afterward, or
+ sometimes (perhaps only with Xinerama?) the mouse gets warped to
+ inside the bounds of the lock dialog window.
+ */
+ {
+ Window pointer_root, pointer_child;
+ int root_x, root_y, win_x, win_y;
+ unsigned int mask;
+ pw->previous_mouse_x = 0;
+ pw->previous_mouse_y = 0;
+ if (XQueryPointer (si->dpy, RootWindowOfScreen (pw->prompt_screen->screen),
+ &pointer_root, &pointer_child,
+ &root_x, &root_y, &win_x, &win_y, &mask))
+ {
+ pw->previous_mouse_x = root_x;
+ pw->previous_mouse_y = root_y;
+ if (si->prefs.verbose_p)
+ fprintf (stderr, "%s: %d: mouse is at %d,%d.\n",
+ blurb(), pw->prompt_screen->number,
+ pw->previous_mouse_x, pw->previous_mouse_y);
+ }
+ else if (si->prefs.verbose_p)
+ fprintf (stderr, "%s: %d: unable to determine mouse position?\n",
+ blurb(), pw->prompt_screen->number);
+ }
+
+ /* Figure out where on the desktop to place the window so that it will
+ actually be visible; this takes into account virtual viewports as
+ well as Xinerama. */
+ {
+ int x, y, w, h;
+ get_screen_viewport (pw->prompt_screen, &x, &y, &w, &h,
+ pw->previous_mouse_x, pw->previous_mouse_y,
+ si->prefs.verbose_p);
+ if (si->prefs.debug_p) w /= 2;
+ pw->x = x + ((w + pw->width) / 2) - pw->width;
+ pw->y = y + ((h + pw->height) / 2) - pw->height;
+ if (pw->x < x) pw->x = x;
+ if (pw->y < y) pw->y = y;
+ }
+
+ pw->border_width = get_integer_resource ("passwd.borderWidth",
+ "Dialog.BorderWidth");
+
+ si->passwd_dialog =
+ XCreateWindow (si->dpy,
+ RootWindowOfScreen(screen),
+ pw->x, pw->y, pw->width, pw->height, pw->border_width,
+ DefaultDepthOfScreen (screen), InputOutput,
+ DefaultVisualOfScreen(screen),
+ attrmask, &attrs);
+ XSetWindowBackground (si->dpy, si->passwd_dialog, pw->background);
+
+ /* We use the default visual, not ssi->visual, so that the logo pixmap's
+ visual matches that of the si->passwd_dialog window. */
+ pw->logo_pixmap = xscreensaver_logo (ssi->screen,
+ /* ssi->current_visual, */
+ DefaultVisualOfScreen(screen),
+ si->passwd_dialog, cmap,
+ pw->background,
+ &pw->logo_pixels, &pw->logo_npixels,
+ 0, True);
+
+ /* Before mapping the window, save the bits that are underneath the
+ rectangle the window will occlude. When we lower the window, we
+ restore these bits. This works, because the running screenhack
+ has already been sent SIGSTOP, so we know nothing else is drawing
+ right now! */
+ {
+ XGCValues gcv;
+ GC gc;
+ pw->save_under = XCreatePixmap (si->dpy,
+ pw->prompt_screen->screensaver_window,
+ pw->width + (pw->border_width*2) + 1,
+ pw->height + (pw->border_width*2) + 1,
+ pw->prompt_screen->current_depth);
+ gcv.function = GXcopy;
+ gc = XCreateGC (si->dpy, pw->save_under, GCFunction, &gcv);
+ XCopyArea (si->dpy, pw->prompt_screen->screensaver_window,
+ pw->save_under, gc,
+ pw->x - pw->border_width, pw->y - pw->border_width,
+ pw->width + (pw->border_width*2) + 1,
+ pw->height + (pw->border_width*2) + 1,
+ 0, 0);
+ XFreeGC (si->dpy, gc);
+ }