+ passwd_dialog_data *pw;
+
+ if (!(pw = si->pw_data))
+ return;
+
+ if (pw->info_label)
+ {
+ mlstring_free(pw->info_label);
+ pw->info_label = 0;
+ }
+
+ if (pw->prompt_label)
+ {
+ mlstring_free(pw->prompt_label);
+ pw->prompt_label = 0;
+ }
+
+ memset (pw->typed_passwd, 0, sizeof(pw->typed_passwd));
+ memset (pw->typed_passwd_char_size, 0, sizeof(pw->typed_passwd_char_size));
+ memset (pw->passwd_string, 0, strlen(pw->passwd_string));
+
+ if (pw->timer)
+ {
+ XtRemoveTimeOut (pw->timer);
+ pw->timer = 0;
+ }
+
+ if (pw->user_entry_pixmap)
+ {
+ XFreePixmap(si->dpy, pw->user_entry_pixmap);
+ pw->user_entry_pixmap = 0;
+ }
+}
+
+
+static void
+destroy_passwd_window (saver_info *si)
+{
+ saver_preferences *p = &si->prefs;
+ passwd_dialog_data *pw = si->pw_data;
+ saver_screen_info *ssi = pw->prompt_screen;
+ Colormap cmap = DefaultColormapOfScreen (ssi->screen);
+ Pixel black = BlackPixelOfScreen (ssi->screen);
+ Pixel white = WhitePixelOfScreen (ssi->screen);
+ XEvent event;
+
+ cleanup_passwd_window (si);
+
+ if (si->cached_passwd)
+ {
+ char *wipe = si->cached_passwd;
+
+ while (*wipe)
+ *wipe++ = '\0';
+
+ free(si->cached_passwd);
+ si->cached_passwd = NULL;
+ }
+
+ move_mouse_grab (si, RootWindowOfScreen (ssi->screen),
+ ssi->cursor, ssi->number);
+
+ if (pw->passwd_cursor)
+ XFreeCursor (si->dpy, pw->passwd_cursor);
+
+ if (p->verbose_p)
+ fprintf (stderr, "%s: %d: moving mouse back to %d,%d.\n",
+ blurb(), ssi->number,
+ pw->previous_mouse_x, pw->previous_mouse_y);
+
+ XWarpPointer (si->dpy, None, RootWindowOfScreen (ssi->screen),
+ 0, 0, 0, 0,
+ pw->previous_mouse_x, pw->previous_mouse_y);
+ XSync (si->dpy, False);
+
+ while (XCheckMaskEvent (si->dpy, PointerMotionMask, &event))
+ if (p->verbose_p)
+ fprintf (stderr, "%s: discarding MotionNotify event.\n", blurb());
+
+#ifdef HAVE_XINPUT
+ if (si->using_xinput_extension && si->xinput_DeviceMotionNotify)
+ while (XCheckTypedEvent (si->dpy, si->xinput_DeviceMotionNotify, &event))
+ if (p->verbose_p)
+ fprintf (stderr, "%s: discarding DeviceMotionNotify event.\n",
+ blurb());
+#endif
+
+ if (si->passwd_dialog)
+ {
+ if (si->prefs.verbose_p)
+ fprintf (stderr, "%s: %d: destroying password dialog.\n",
+ blurb(), pw->prompt_screen->number);
+
+ XDestroyWindow (si->dpy, si->passwd_dialog);
+ si->passwd_dialog = 0;
+ }
+
+ if (pw->save_under)
+ {
+ restore_background(si);
+ XFreePixmap (si->dpy, pw->save_under);
+ pw->save_under = 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->date_label) free (pw->date_label);
+ if (pw->login_label) free (pw->login_label);
+ if (pw->unlock_label) free (pw->unlock_label);
+ if (pw->passwd_string) free (pw->passwd_string);
+ if (pw->uname_label) free (pw->uname_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->date_font) XFreeFont (si->dpy, pw->date_font);
+ if (pw->button_font) XFreeFont (si->dpy, pw->button_font);
+ if (pw->uname_font) XFreeFont (si->dpy, pw->uname_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->button_foreground == black || pw->button_foreground == white))
+ XFreeColors (si->dpy, cmap, &pw->button_foreground, 1, 0L);
+ if (!(pw->button_background == black || pw->button_background == white))
+ XFreeColors (si->dpy, cmap, &pw->button_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->thermo_foreground != black && pw->thermo_foreground != white)
+ XFreeColors (si->dpy, cmap, &pw->thermo_foreground, 1, 0L);
+ if (pw->thermo_background != black && pw->thermo_background != white)
+ XFreeColors (si->dpy, cmap, &pw->thermo_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);
+
+ if (pw->logo_pixmap)
+ XFreePixmap (si->dpy, pw->logo_pixmap);
+ if (pw-> logo_clipmask)
+ XFreePixmap (si->dpy, pw->logo_clipmask);
+ if (pw->logo_pixels)
+ {
+ if (pw->logo_npixels)
+ XFreeColors (si->dpy, cmap, pw->logo_pixels, pw->logo_npixels, 0L);
+ free (pw->logo_pixels);
+ pw->logo_pixels = 0;
+ pw->logo_npixels = 0;
+ }
+
+ if (pw->save_under)
+ XFreePixmap (si->dpy, pw->save_under);
+
+ if (cmap)
+ XInstallColormap (si->dpy, cmap);
+
+ memset (pw, 0, sizeof(*pw));
+ free (pw);
+ si->pw_data = 0;
+}
+
+
+#if defined(HAVE_XF86MISCSETGRABKEYSSTATE) || defined(HAVE_XF86VMODE)
+
+static Bool error_handler_hit_p = False;
+
+static int
+ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
+{
+ error_handler_hit_p = True;
+ return 0;
+}
+
+#endif /* HAVE_XF86MISCSETGRABKEYSSTATE || HAVE_XF86VMODE */
+
+
+#ifdef HAVE_XHPDISABLERESET
+/* This function enables and disables the C-Sh-Reset hot-key, which
+ normally resets the X server (logging out the logged-in user.)
+ We don't want random people to be able to do that while the
+ screen is locked.
+ */
+static void
+hp_lock_reset (saver_info *si, Bool lock_p)
+{
+ static Bool hp_locked_p = False;
+
+ /* Calls to XHPDisableReset and XHPEnableReset must be balanced,
+ or BadAccess errors occur. (It's ok for this to be global,
+ since it affects the whole machine, not just the current screen.)
+ */
+ if (hp_locked_p == lock_p)
+ return;
+
+ if (lock_p)
+ XHPDisableReset (si->dpy);
+ else
+ XHPEnableReset (si->dpy);
+ hp_locked_p = lock_p;
+}
+#endif /* HAVE_XHPDISABLERESET */
+
+\f
+#ifdef HAVE_XF86MISCSETGRABKEYSSTATE
+
+/* This function enables and disables the Ctrl-Alt-KP_star and
+ Ctrl-Alt-KP_slash hot-keys, which (in XFree86 4.2) break any
+ grabs and/or kill the grabbing client. That would effectively
+ unlock the screen, so we don't like that.
+
+ The Ctrl-Alt-KP_star and Ctrl-Alt-KP_slash hot-keys only exist
+ if AllowDeactivateGrabs and/or AllowClosedownGrabs are turned on
+ in XF86Config. I believe they are disabled by default.
+
+ This does not affect any other keys (specifically Ctrl-Alt-BS or
+ Ctrl-Alt-F1) but I wish it did. Maybe it will someday.
+ */
+static void
+xfree_lock_grab_smasher (saver_info *si, Bool lock_p)
+{
+ saver_preferences *p = &si->prefs;
+ int status;
+ int event, error;
+ XErrorHandler old_handler;
+
+ if (!XF86MiscQueryExtension(si->dpy, &event, &error))
+ return;
+
+ XSync (si->dpy, False);
+ error_handler_hit_p = False;
+ old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
+ XSync (si->dpy, False);
+ status = XF86MiscSetGrabKeysState (si->dpy, !lock_p);
+ XSync (si->dpy, False);
+ if (error_handler_hit_p) status = 666;
+
+ if (!lock_p && status == MiscExtGrabStateAlready)
+ status = MiscExtGrabStateSuccess; /* shut up, consider this success */
+
+ if (p->verbose_p && status != MiscExtGrabStateSuccess)
+ fprintf (stderr, "%s: error: XF86MiscSetGrabKeysState(%d) returned %s\n",
+ blurb(), !lock_p,
+ (status == MiscExtGrabStateSuccess ? "MiscExtGrabStateSuccess" :
+ status == MiscExtGrabStateLocked ? "MiscExtGrabStateLocked" :
+ status == MiscExtGrabStateAlready ? "MiscExtGrabStateAlready" :
+ status == 666 ? "an X error" :
+ "unknown value"));
+
+ XSync (si->dpy, False);
+ XSetErrorHandler (old_handler);
+ XSync (si->dpy, False);
+}
+#endif /* HAVE_XF86MISCSETGRABKEYSSTATE */
+
+
+\f
+/* This function enables and disables the C-Alt-Plus and C-Alt-Minus
+ hot-keys, which normally change the resolution of the X server.
+ We don't want people to be able to switch the server resolution
+ while the screen is locked, because if they switch to a higher
+ resolution, it could cause part of the underlying desktop to become
+ exposed.
+ */
+#ifdef HAVE_XF86VMODE
+
+static void
+xfree_lock_mode_switch (saver_info *si, Bool lock_p)
+{
+ static Bool any_mode_locked_p = False;
+ saver_preferences *p = &si->prefs;
+ int screen;
+ int real_nscreens = ScreenCount (si->dpy);
+ int event, error;
+ Bool status;
+ XErrorHandler old_handler;
+
+ if (any_mode_locked_p == lock_p)
+ return;
+ if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
+ return;
+
+ for (screen = 0; screen < real_nscreens; screen++)
+ {
+ XSync (si->dpy, False);
+ old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
+ error_handler_hit_p = False;
+ status = XF86VidModeLockModeSwitch (si->dpy, screen, lock_p);
+ XSync (si->dpy, False);
+ XSetErrorHandler (old_handler);
+ if (error_handler_hit_p) status = False;
+
+ if (status)
+ any_mode_locked_p = lock_p;
+
+ if (!status && (p->verbose_p || !lock_p))
+ /* Only print this when verbose, or when we locked but can't unlock.
+ I tried printing this message whenever it comes up, but
+ mode-locking always fails if DontZoom is set in XF86Config. */
+ fprintf (stderr, "%s: %d: unable to %s mode switching!\n",
+ blurb(), screen, (lock_p ? "lock" : "unlock"));
+ else if (p->verbose_p)
+ fprintf (stderr, "%s: %d: %s mode switching.\n",
+ blurb(), screen, (lock_p ? "locked" : "unlocked"));
+ }
+}
+#endif /* HAVE_XF86VMODE */
+
+\f
+/* If the viewport has been scrolled since the screen was blanked,
+ then scroll it back to where it belongs. This function only exists
+ to patch over a very brief race condition.
+ */
+static void
+undo_vp_motion (saver_info *si)
+{
+#ifdef HAVE_XF86VMODE
+ saver_preferences *p = &si->prefs;
+ int screen;
+ int real_nscreens = ScreenCount (si->dpy);
+ int event, error;
+
+ if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
+ return;
+
+ for (screen = 0; screen < real_nscreens; screen++)
+ {
+ saver_screen_info *ssi = &si->screens[screen];
+ int x, y;
+ Bool status;
+
+ if (ssi->blank_vp_x == -1 && ssi->blank_vp_y == -1)
+ break;
+ if (!XF86VidModeGetViewPort (si->dpy, screen, &x, &y))
+ return;
+ if (ssi->blank_vp_x == x && ssi->blank_vp_y == y)
+ return;
+
+ /* We're going to move the viewport. The mouse has just been grabbed on
+ (and constrained to, thus warped to) the password window, so it is no
+ longer near the edge of the screen. However, wait a bit anyway, just
+ to make sure the server drains its last motion event, so that the
+ screen doesn't continue to scroll after we've reset the viewport.
+ */
+ XSync (si->dpy, False);
+ usleep (250000); /* 1/4 second */
+ XSync (si->dpy, False);
+
+ status = XF86VidModeSetViewPort (si->dpy, screen,
+ ssi->blank_vp_x, ssi->blank_vp_y);
+
+ if (!status)
+ fprintf (stderr,
+ "%s: %d: unable to move vp from (%d,%d) back to (%d,%d)!\n",
+ blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
+ else if (p->verbose_p)
+ fprintf (stderr,
+ "%s: %d: vp moved to (%d,%d); moved it back to (%d,%d).\n",
+ blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
+ }
+#endif /* HAVE_XF86VMODE */
+}
+
+
+\f
+/* Interactions
+ */
+
+static void
+passwd_animate_timer (XtPointer closure, XtIntervalId *id)
+{
+ saver_info *si = (saver_info *) closure;