+ char *s = strdup (uts.nodename);
+ free (pw->uname_label);
+ pw->uname_label = s;
+ }
+ }
+# endif
+
+ pw->passwd_string = strdup("");
+
+ f = get_string_resource (si->dpy, "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 (si->dpy, "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(si->dpy, "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(si->dpy, "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(si->dpy, "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(si->dpy, "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);
+
+ f = get_string_resource(si->dpy, "passwd.unameFont", "Dialog.Font");
+ pw->uname_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
+ if (!pw->uname_font) pw->uname_font = XLoadQueryFont (si->dpy, "fixed");
+ if (f) free (f);
+
+ pw->show_uname_p = get_boolean_resource(si->dpy, "passwd.uname", "Boolean");
+
+ pw->foreground = get_pixel_resource (si->dpy, cmap,
+ "passwd.foreground",
+ "Dialog.Foreground" );
+ pw->background = get_pixel_resource (si->dpy, cmap,
+ "passwd.background",
+ "Dialog.Background" );
+
+ 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 (si->dpy, cmap,
+ "passwd.text.foreground",
+ "Dialog.Text.Foreground" );
+ pw->passwd_background = get_pixel_resource (si->dpy, cmap,
+ "passwd.text.background",
+ "Dialog.Text.Background" );
+ pw->button_foreground = get_pixel_resource (si->dpy, cmap,
+ "splash.Button.foreground",
+ "Dialog.Button.Foreground" );
+ pw->button_background = get_pixel_resource (si->dpy, cmap,
+ "splash.Button.background",
+ "Dialog.Button.Background" );
+ pw->thermo_foreground = get_pixel_resource (si->dpy, cmap,
+ "passwd.thermometer.foreground",
+ "Dialog.Thermometer.Foreground" );
+ pw->thermo_background = get_pixel_resource ( si->dpy, cmap,
+ "passwd.thermometer.background",
+ "Dialog.Thermometer.Background" );
+ pw->shadow_top = get_pixel_resource ( si->dpy, cmap,
+ "passwd.topShadowColor",
+ "Dialog.Foreground" );
+ pw->shadow_bottom = get_pixel_resource (si->dpy, cmap,
+ "passwd.bottomShadowColor",
+ "Dialog.Background" );
+
+ pw->preferred_logo_width = get_integer_resource (si->dpy, "passwd.logo.width",
+ "Dialog.Logo.Width");
+ pw->preferred_logo_height = get_integer_resource (si->dpy, "passwd.logo.height",
+ "Dialog.Logo.Height");
+ pw->thermo_width = get_integer_resource (si->dpy, "passwd.thermometer.width",
+ "Dialog.Thermometer.Width");
+ pw->internal_border = get_integer_resource (si->dpy, "passwd.internalBorderWidth",
+ "Dialog.InternalBorderWidth");
+ pw->shadow_width = get_integer_resource (si->dpy, "passwd.shadowThickness",
+ "Dialog.ShadowThickness");
+
+ if (pw->preferred_logo_width == 0) pw->preferred_logo_width = 150;
+ if (pw->preferred_logo_height == 0) pw->preferred_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;
+
+
+ /* 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;
+}
+
+
+/**
+ * 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);
+
+ {
+ 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;
+
+ 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);
+
+ /* 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;
+}
+
+
+static void
+draw_passwd_window (saver_info *si)
+{
+ 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;
+
+ /* Force redraw */
+ pw->passwd_changed_p = True;
+ pw->button_state_changed_p = True;
+
+ /* This height is the height of all the elements, not to be confused with
+ * the overall window height which is pw->height. It is used to compute
+ * the amount of spacing (padding) between elements. */
+ height = (pw->heading_font->ascent + pw->heading_font->descent +
+ pw->info_label->overall_height +
+ MAX (((pw->label_font->ascent + pw->label_font->descent) +
+ (pw->prompt_label ? pw->prompt_label->overall_height : 0)),
+ ((pw->passwd_font->ascent + pw->passwd_font->descent) +
+ (pw->shadow_width * 2)) * (pw->prompt_label ? 2 : 1)) +
+ pw->date_font->ascent + pw->date_font->descent);
+
+ if ((strlen(pw->uname_label)) && pw->show_uname_p)
+ height += (pw->uname_font->ascent + pw->uname_font->descent); /* for uname */
+
+ height += ((pw->button_font->ascent + pw->button_font->descent) * 2 +
+ 2 * pw->shadow_width);
+
+ spacing = ((pw->height - 2 * pw->shadow_width
+ - pw->internal_border - height)
+ / 10);
+
+ 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));
+
+ /* uname below top heading
+ */
+ if ((strlen(pw->uname_label)) && pw->show_uname_p)
+ {
+ XSetFont (si->dpy, gc1, pw->uname_font->fid);
+ y1 += spacing + pw->uname_font->ascent + pw->uname_font->descent;
+ sw = string_width (pw->uname_font, pw->uname_label);
+ x2 = (x1 + ((x3 - x1 - sw) / 2));
+ XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
+ pw->uname_label, strlen(pw->uname_label));
+ }
+
+ /* the info_label (below uname)
+ */
+ x2 = (x1 + ((x3 - x1 - pw->info_label->overall_width) / 2));
+ y1 += spacing + pw->info_label->font_height / 2;
+ mlstring_draw(si->dpy, si->passwd_dialog, gc1, pw->info_label,
+ x2, y1);
+ y1 += pw->info_label->overall_height;
+
+
+ tb_height = (pw->passwd_font->ascent + pw->passwd_font->descent +
+ (pw->shadow_width * 4));
+
+ /* the "User:" prompt
+ */
+ y2 = y1;
+ XSetForeground (si->dpy, gc1, pw->foreground);
+ XSetFont (si->dpy, gc1, pw->label_font->fid);
+ y1 += (spacing + tb_height + pw->shadow_width);
+ x2 = (x1 + pw->internal_border +
+ MAX(string_width (pw->label_font, pw->user_label),
+ pw->prompt_label ? pw->prompt_label->overall_width : 0));
+ XDrawString (si->dpy, si->passwd_dialog, gc1,
+ x2 - string_width (pw->label_font, pw->user_label),
+ y1 - pw->passwd_font->descent,
+ pw->user_label, strlen(pw->user_label));
+
+ /* the prompt_label prompt
+ */
+ if (pw->prompt_label)
+ {
+ y1 += tb_height - pw->label_font->ascent + pw->shadow_width;
+ mlstring_draw(si->dpy, si->passwd_dialog, gc1, pw->prompt_label,
+ x2 - pw->prompt_label->overall_width, y1);
+ }
+
+ /* the "user name" text field
+ */
+ y1 = y2;
+ XSetForeground (si->dpy, gc1, pw->passwd_foreground);
+ XSetForeground (si->dpy, gc2, pw->passwd_background);
+ 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->passwd_font->descent,
+ si->user, strlen(si->user));
+
+ /* the password/prompt text field
+ */
+ if (pw->prompt_label)
+ {
+ y1 += (spacing + pw->prompt_label->overall_height + pw->shadow_width * 2);
+
+ pw->passwd_field_x = x2 - pw->shadow_width;
+ pw->passwd_field_y = y1 - (pw->passwd_font->ascent +
+ pw->passwd_font->descent);
+ }
+
+ /* 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);
+
+ if (pw->prompt_label)
+ {
+ y1 += (spacing + pw->prompt_label->overall_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);
+ }
+
+
+ /* The date, below the text fields
+ */
+ {
+ char buf[100];
+ time_t now = time ((time_t *) 0);
+ struct tm *tm = localtime (&now);
+ memset (buf, 0, sizeof(buf));
+ strftime (buf, sizeof(buf)-1, pw->date_label, tm);
+
+ XSetFont (si->dpy, gc1, pw->date_font->fid);
+ y1 += pw->shadow_width;
+ y1 += (spacing + tb_height);
+ y1 += spacing/2;
+ sw = string_width (pw->date_font, buf);
+ x2 = x1 + x2 - sw;
+ XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1, buf, strlen(buf));
+ }
+
+ /* Set up the GCs for the "New Login" and "Unlock" buttons.
+ */
+ XSetForeground(si->dpy, gc1, pw->button_foreground);
+ XSetForeground(si->dpy, gc2, pw->button_background);
+ XSetFont(si->dpy, gc1, pw->button_font->fid);
+
+ /* The "Unlock" button */
+ x2 = pw->width - pw->internal_border - (pw->shadow_width * 2);
+
+ /* right aligned button */
+ x1 = x2 - pw->unlock_button_width;
+
+ /* Add half the difference between y1 and the internal edge.
+ * It actually looks better if the internal border is ignored. */
+ y1 += ((pw->height - MAX (pw->unlock_button_height, pw->login_button_height)
+ - spacing - y1)
+ / 2);
+
+ pw->unlock_button_x = x1;
+ pw->unlock_button_y = y1;
+
+ /* The "New Login" button
+ */
+ if (pw->login_button_p)
+ {
+ /* Using the same GC as for the Unlock button */
+
+ sw = string_width (pw->button_font, pw->login_label);
+
+ /* left aligned button */
+ x1 = (pw->logo_width + pw->thermo_width + (pw->shadow_width * 3) +
+ pw->internal_border);
+
+ pw->login_button_x = x1;
+ pw->login_button_y = y1;
+ }
+
+ /* The logo
+ */
+ x1 = pw->shadow_width * 6;
+ y1 = pw->shadow_width * 6;
+ x2 = pw->logo_width - (pw->shadow_width * 12);
+ y2 = pw->logo_height - (pw->shadow_width * 12);
+
+ if (pw->logo_pixmap)
+ {
+ Window root;
+ int x, y;
+ unsigned int w, h, bw, d;
+ XGetGeometry (si->dpy, pw->logo_pixmap, &root, &x, &y, &w, &h, &bw, &d);
+ XSetForeground (si->dpy, gc1, pw->foreground);
+ XSetBackground (si->dpy, gc1, pw->background);
+ XSetClipMask (si->dpy, gc1, pw->logo_clipmask);
+ XSetClipOrigin (si->dpy, gc1, x1 + ((x2 - (int)w) / 2), y1 + ((y2 - (int)h) / 2));
+ if (d == 1)
+ XCopyPlane (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1,
+ 0, 0, w, h,
+ x1 + ((x2 - (int)w) / 2),
+ y1 + ((y2 - (int)h) / 2),
+ 1);
+ else
+ XCopyArea (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1,
+ 0, 0, w, h,
+ x1 + ((x2 - (int)w) / 2),
+ y1 + ((y2 - (int)h) / 2));
+ }
+
+ /* The thermometer
+ */
+ XSetForeground (si->dpy, gc1, pw->thermo_foreground);
+ XSetForeground (si->dpy, gc2, pw->thermo_background);
+
+ pw->thermo_field_x = pw->logo_width + pw->shadow_width;
+ pw->thermo_field_y = pw->shadow_width * 5;
+ pw->thermo_field_height = pw->height - (pw->shadow_width * 10);
+
+#if 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);
+#endif
+
+ /* The shadow around the logo
+ */
+ draw_shaded_rectangle (si->dpy, si->passwd_dialog,
+ pw->shadow_width * 4,
+ pw->shadow_width * 4,
+ pw->logo_width - (pw->shadow_width * 8),
+ pw->logo_height - (pw->shadow_width * 8),
+ 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 * 4,
+ pw->thermo_width + (pw->shadow_width * 2),
+ pw->height - (pw->shadow_width * 8),
+ pw->shadow_width,
+ pw->shadow_bottom, pw->shadow_top);
+
+#if 1
+ /* Solid border inside the thermometer. */
+ XSetForeground (si->dpy, gc1, pw->foreground);
+ XDrawRectangle (si->dpy, si->passwd_dialog, gc1,
+ pw->thermo_field_x, pw->thermo_field_y,
+ pw->thermo_width - 1, pw->thermo_field_height - 1);
+#endif
+
+ /* 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);
+
+ XFreeGC (si->dpy, gc1);
+ XFreeGC (si->dpy, gc2);
+
+ update_passwd_window (si, pw->passwd_string, pw->ratio);
+}
+
+static void
+draw_button(Display *dpy,
+ Drawable dialog,
+ XFontStruct *font,
+ unsigned long foreground, unsigned long background,
+ char *label,
+ int x, int y,
+ int width, int height,
+ int shadow_width,
+ Pixel shadow_light, Pixel shadow_dark,
+ Bool button_down)
+{
+ XGCValues gcv;
+ GC gc1, gc2;
+ int sw;
+ int label_x, label_y;
+
+ gcv.foreground = foreground;
+ gcv.font = font->fid;
+ gc1 = XCreateGC(dpy, dialog, GCForeground|GCFont, &gcv);
+ gcv.foreground = background;
+ gc2 = XCreateGC(dpy, dialog, GCForeground, &gcv);
+
+ XFillRectangle(dpy, dialog, gc2,
+ x, y, width, height);
+
+ sw = string_width(font, label);
+
+ label_x = x + ((width - sw) / 2);
+ label_y = (y + (height - (font->ascent + font->descent)) / 2 + font->ascent);
+
+ if (button_down)
+ {
+ label_x += 2;
+ label_y += 2;
+ }
+
+ XDrawString(dpy, dialog, gc1, label_x, label_y, label, strlen(label));
+
+ XFreeGC(dpy, gc1);
+ XFreeGC(dpy, gc2);
+
+ draw_shaded_rectangle(dpy, dialog, x, y, width, height,
+ shadow_width, shadow_light, shadow_dark);
+}
+
+static 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;
+ XRectangle rects[1];
+
+ 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;
+ }
+
+ if (pw->prompt_label)
+ {
+
+ /* the "password" text field
+ */
+ rects[0].x = pw->passwd_field_x;
+ rects[0].y = pw->passwd_field_y;
+ rects[0].width = pw->passwd_field_width;
+ rects[0].height = pw->passwd_field_height;
+
+ /* The user entry (password) field is double buffered.
+ * This avoids flickering, particularly in synchronous mode. */
+
+ if (pw->passwd_changed_p)
+ {
+ pw->passwd_changed_p = False;
+
+ if (pw->user_entry_pixmap)
+ {
+ XFreePixmap(si->dpy, pw->user_entry_pixmap);
+ pw->user_entry_pixmap = 0;
+ }
+
+ pw->user_entry_pixmap =
+ XCreatePixmap (si->dpy, si->passwd_dialog,
+ rects[0].width, rects[0].height,
+ DefaultDepthOfScreen (pw->prompt_screen->screen));
+
+ XFillRectangle (si->dpy, pw->user_entry_pixmap, gc2,
+ 0, 0, rects[0].width, rects[0].height);