+
+ /* 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);
+ }
+
+ /* Before mapping the window, save a pixmap of the current screen.
+ 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->prompt_screen->width,
+ pw->prompt_screen->height,
+ 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,
+ 0, 0,
+ pw->prompt_screen->width, pw->prompt_screen->height,
+ 0, 0);
+ XFreeGC (si->dpy, gc);
+ }
+
+ si->pw_data = pw;
+ return 0;
+}
+
+
+Bool debug_passwd_window_p = False; /* used only by test-passwd.c */
+
+
+/**
+ * info_msg and prompt may be NULL.
+ */
+static int
+make_passwd_window (saver_info *si,
+ const char *info_msg,
+ const char *prompt,
+ Bool echo)
+{
+ XSetWindowAttributes attrs;
+ unsigned long attrmask = 0;
+ passwd_dialog_data *pw;
+ Screen *screen;
+ Colormap cmap;
+ Dimension max_string_width_px;
+ saver_screen_info *ssi = &si->screens [mouse_screen (si)];
+
+ cleanup_passwd_window (si);
+
+ if (! ssi) /* WTF? Trying to prompt while no screens connected? */
+ return -1;
+
+ if (!si->pw_data)
+ if (new_passwd_window (si) < 0)
+ return -1;
+
+ if (!(pw = si->pw_data))
+ return -1;
+
+ pw->ratio = 1.0;
+
+ pw->prompt_screen = ssi;
+ if (si->prefs.verbose_p)
+ fprintf (stderr, "%s: %d: creating password dialog (\"%s\")\n",
+ blurb(), pw->prompt_screen->number,
+ info_msg ? info_msg : "");
+
+ screen = pw->prompt_screen->screen;
+ cmap = DefaultColormapOfScreen (screen);
+
+ pw->echo_input = echo;
+
+ max_string_width_px = ssi->width
+ - pw->shadow_width * 4
+ - pw->border_width * 2
+ - pw->thermo_width
+ - pw->preferred_logo_width
+ - pw->internal_border * 2;
+ /* As the string wraps it makes the window taller which makes the logo wider
+ * which leaves less room for the text which makes the string wrap. Uh-oh, a
+ * loop. By wrapping at a bit less than the available width, there's some
+ * room for the dialog to grow without going off the edge of the screen. */
+ max_string_width_px *= 0.75;
+
+ pw->info_label = mlstring_new(info_msg ? info_msg : pw->body_label,
+ pw->label_font, max_string_width_px);
+