+ 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;
+
+ if (!info_msg && decrepit_p())
+ info_msg = ("\n"
+ "This version of XScreenSaver\n"
+ "is very old! Please upgrade!\n");
+
+ pw->info_label = mlstring_new(info_msg ? info_msg : pw->body_label,
+ pw->label_font, max_string_width_px);
+
+ {
+ 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 uname_label. */
+ if ((strlen(pw->uname_label)) && pw->show_uname_p)
+ {
+ XTextExtents (pw->uname_font,
+ pw->uname_label, strlen(pw->uname_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 = SAMPLE_INPUT;
+
+ /* 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 info_label. */
+ if (pw->info_label->overall_width > pw->width)
+ pw->width = pw->info_label->overall_width;
+ h2 += pw->info_label->overall_height;
+
+ /* Measure the user string. */
+ XTextExtents (pw->passwd_font,
+ si->user, strlen(si->user),
+ &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 (dummy) passwd_string. */
+ if (prompt)
+ {
+ 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;
+
+ /* Measure the prompt_label. */
+ max_string_width_px -= w3;
+ pw->prompt_label = mlstring_new (prompt, pw->label_font,
+ max_string_width_px);
+
+ if (pw->prompt_label->overall_width > w2)
+ w2 = pw->prompt_label->overall_width;
+
+ h2 += pw->prompt_label->overall_height;
+
+ w2 = w2 + w3 + (pw->shadow_width * 2);
+ h2 = MAX (h2, h3);
+ }
+
+ /* The "Unlock" button. */
+ XTextExtents (pw->label_font,
+ pw->unlock_label, strlen(pw->unlock_label),
+ &direction, &ascent, &descent, &overall);
+ button_w = overall.width;
+ button_h = ascent + descent;
+
+ /* Add some horizontal padding inside the button. */
+ button_w += ascent;
+
+ button_w += ((ascent + descent) / 2) + (pw->shadow_width * 2);
+ button_h += ((ascent + descent) / 2) + (pw->shadow_width * 2);
+
+ pw->unlock_button_width = button_w;
+ pw->unlock_button_height = button_h;
+
+ w2 = MAX (w2, button_w);
+ h2 += button_h * 1.5;
+
+ /* The "New Login" button */
+ 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;
+
+ if (button_h > pw->unlock_button_height)
+ h2 += (button_h * 1.5 - pw->unlock_button_height * 1.5);
+
+ /* Use (2 * shadow_width) spacing between the buttons. Another
+ (2 * shadow_width) is required to account for button shadows. */
+ w2 = MAX (w2,
+ button_w + pw->unlock_button_width +
+ (pw->shadow_width * 4));
+ }
+
+ 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->preferred_logo_height > pw->height)
+ pw->height = pw->logo_height = pw->preferred_logo_height;
+ else if (pw->height > pw->preferred_logo_height)
+ pw->logo_height = pw->height;
+
+ pw->logo_width = pw->logo_height;
+
+ pw->width += pw->logo_width;
+ }
+
+ attrmask |= CWOverrideRedirect; attrs.override_redirect = True;
+
+ if (debug_passwd_window_p)
+ attrs.override_redirect = False; /* kludge for test-passwd.c */
+
+ attrmask |= CWEventMask;
+ attrs.event_mask = (ExposureMask | KeyPressMask |
+ ButtonPressMask | ButtonReleaseMask);
+
+ /* 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. */
+ {
+ saver_screen_info *ssi = &si->screens [mouse_screen (si)];
+ int x = ssi->x;
+ int y = ssi->y;
+ int w = ssi->width;
+ int h = ssi->height;
+ 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 (si->dpy, "passwd.borderWidth",
+ "Dialog.BorderWidth");
+
+ /* Only create the window the first time around */
+ if (!si->passwd_dialog)
+ {
+ 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);
+ XSetWindowBorder (si->dpy, si->passwd_dialog, pw->border);
+
+ /* 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,
+ &pw->logo_clipmask, True);
+ }
+ else /* On successive prompts, just resize the window */
+ {
+ XWindowChanges wc;
+ unsigned int mask = CWX | CWY | CWWidth | CWHeight;
+
+ wc.x = pw->x;
+ wc.y = pw->y;
+ wc.width = pw->width;
+ wc.height = pw->height;
+
+ XConfigureWindow (si->dpy, si->passwd_dialog, mask, &wc);
+ }
+
+ restore_background(si);
+
+ XMapRaised (si->dpy, si->passwd_dialog);
+ XSync (si->dpy, False);
+
+ move_mouse_grab (si, si->passwd_dialog,
+ pw->passwd_cursor,
+ pw->prompt_screen->number);
+ undo_vp_motion (si);
+
+ si->pw_data = pw;
+
+ if (cmap)
+ XInstallColormap (si->dpy, cmap);
+ draw_passwd_window (si);
+
+ return 0;