1 /* lock.c --- handling the password dialog for locking-mode.
2 * xscreensaver, Copyright (c) 1993-2005 Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
13 /* Athena locking code contributed by Jon A. Christopher <jac8782@tamu.edu> */
14 /* Copyright 1997, with the same permissions as above. */
21 #include <X11/Intrinsic.h>
22 #include <X11/cursorfont.h>
23 #include <X11/Xos.h> /* for time() */
26 #include "xscreensaver.h"
27 #include "resources.h"
29 #ifndef NO_LOCKING /* (mostly) whole file */
33 #endif /* HAVE_SYSLOG */
35 #ifdef HAVE_XHPDISABLERESET
36 # include <X11/XHPlib.h>
37 static void hp_lock_reset (saver_info *si, Bool lock_p);
38 #endif /* HAVE_XHPDISABLERESET */
40 #ifdef HAVE_VT_LOCKSWITCH
42 # include <sys/ioctl.h>
44 static void linux_lock_vt_switch (saver_info *si, Bool lock_p);
45 #endif /* HAVE_VT_LOCKSWITCH */
48 # include <X11/extensions/xf86vmode.h>
49 static void xfree_lock_mode_switch (saver_info *si, Bool lock_p);
50 #endif /* HAVE_XF86VMODE */
52 #ifdef HAVE_XF86MISCSETGRABKEYSSTATE
53 # include <X11/extensions/xf86misc.h>
54 static void xfree_lock_grab_smasher (saver_info *si, Bool lock_p);
55 #endif /* HAVE_XF86MISCSETGRABKEYSSTATE */
59 ERROR! You must not include vroot.h in this file.
66 extern char *getenv(const char *name);
67 extern int validate_user(char *name, char *password);
70 vms_passwd_valid_p(char *pw, Bool verbose_p)
72 return (validate_user (getenv("USER"), typed_passwd) == 1);
74 # undef passwd_valid_p
75 # define passwd_valid_p vms_passwd_valid_p
81 #define MAX(a,b) ((a)>(b)?(a):(b))
83 enum passwd_state { pw_read, pw_ok, pw_null, pw_fail, pw_cancel, pw_time };
85 struct passwd_dialog_data {
87 saver_screen_info *prompt_screen;
88 int previous_mouse_x, previous_mouse_y;
90 enum passwd_state state;
91 char typed_passwd [80];
99 Dimension border_width;
101 Bool show_stars_p; /* "I regret that I have but one asterisk for my country."
102 -- Nathan Hale, 1776. */
113 XFontStruct *heading_font;
114 XFontStruct *body_font;
115 XFontStruct *label_font;
116 XFontStruct *passwd_font;
117 XFontStruct *date_font;
118 XFontStruct *button_font;
122 Pixel passwd_foreground;
123 Pixel passwd_background;
124 Pixel thermo_foreground;
125 Pixel thermo_background;
128 Pixel button_foreground;
129 Pixel button_background;
131 Dimension logo_width;
132 Dimension logo_height;
133 Dimension thermo_width;
134 Dimension internal_border;
135 Dimension shadow_width;
137 Dimension passwd_field_x, passwd_field_y;
138 Dimension passwd_field_width, passwd_field_height;
140 Dimension login_button_x, login_button_y;
141 Dimension login_button_width, login_button_height;
143 Dimension thermo_field_x, thermo_field_y;
144 Dimension thermo_field_height;
148 unsigned long *logo_pixels;
150 Cursor passwd_cursor;
151 Bool login_button_down_p;
153 Bool login_button_enabled_p;
158 static void draw_passwd_window (saver_info *si);
159 static void update_passwd_window (saver_info *si, const char *printed_passwd,
161 static void destroy_passwd_window (saver_info *si);
162 static void undo_vp_motion (saver_info *si);
163 static void handle_passwd_button (saver_info *si, XEvent *event);
167 make_passwd_window (saver_info *si)
169 struct passwd *p = getpwuid (getuid ());
170 XSetWindowAttributes attrs;
171 unsigned long attrmask = 0;
172 passwd_dialog_data *pw = (passwd_dialog_data *) calloc (1, sizeof(*pw));
176 saver_screen_info *ssi = &si->screens [mouse_screen (si)];
178 /* Display the button only if the "newLoginCommand" pref is non-null.
180 pw->login_button_p = (si->prefs.new_login_command &&
181 *si->prefs.new_login_command);
183 if (pw->login_button_p)
184 pw->passwd_cursor = XCreateFontCursor (si->dpy, XC_top_left_arrow);
186 pw->passwd_cursor = 0;
188 pw->prompt_screen = ssi;
189 if (si->prefs.verbose_p)
190 fprintf (stderr, "%s: %d: creating password dialog.\n",
191 blurb(), pw->prompt_screen->number);
193 screen = pw->prompt_screen->screen;
194 cmap = DefaultColormapOfScreen (screen);
198 pw->show_stars_p = get_boolean_resource("passwd.asterisks", "Boolean");
200 pw->heading_label = get_string_resource ("passwd.heading.label",
201 "Dialog.Label.Label");
202 pw->body_label = get_string_resource ("passwd.body.label",
203 "Dialog.Label.Label");
204 pw->user_label = get_string_resource ("passwd.user.label",
205 "Dialog.Label.Label");
206 pw->passwd_label = get_string_resource ("passwd.passwd.label",
207 "Dialog.Label.Label");
208 pw->login_label = get_string_resource ("passwd.login.label",
209 "Dialog.Button.Label");
211 pw->date_label = get_string_resource ("dateFormat", "DateFormat");
213 if (!pw->heading_label)
214 pw->heading_label = strdup("ERROR: RESOURCES NOT INSTALLED CORRECTLY");
216 pw->body_label = strdup("ERROR: RESOURCES NOT INSTALLED CORRECTLY");
217 if (!pw->user_label) pw->user_label = strdup("ERROR");
218 if (!pw->passwd_label) pw->passwd_label = strdup("ERROR");
219 if (!pw->date_label) pw->date_label = strdup("ERROR");
220 if (!pw->login_label) pw->login_label = strdup ("ERROR (LOGIN)") ;
222 /* Put the version number in the label. */
224 char *s = (char *) malloc (strlen(pw->heading_label) + 20);
225 sprintf(s, pw->heading_label, si->version);
226 free (pw->heading_label);
227 pw->heading_label = s;
230 pw->user_string = strdup (p && p->pw_name ? p->pw_name : "???");
231 pw->passwd_string = strdup("");
233 f = get_string_resource ("passwd.headingFont", "Dialog.Font");
234 pw->heading_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
235 if (!pw->heading_font) pw->heading_font = XLoadQueryFont (si->dpy, "fixed");
238 f = get_string_resource ("passwd.buttonFont", "Dialog.Font");
239 pw->button_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
240 if (!pw->button_font) pw->button_font = XLoadQueryFont (si->dpy, "fixed");
243 f = get_string_resource("passwd.bodyFont", "Dialog.Font");
244 pw->body_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
245 if (!pw->body_font) pw->body_font = XLoadQueryFont (si->dpy, "fixed");
248 f = get_string_resource("passwd.labelFont", "Dialog.Font");
249 pw->label_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
250 if (!pw->label_font) pw->label_font = XLoadQueryFont (si->dpy, "fixed");
253 f = get_string_resource("passwd.passwdFont", "Dialog.Font");
254 pw->passwd_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
255 if (!pw->passwd_font) pw->passwd_font = XLoadQueryFont (si->dpy, "fixed");
258 f = get_string_resource("passwd.dateFont", "Dialog.Font");
259 pw->date_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
260 if (!pw->date_font) pw->date_font = XLoadQueryFont (si->dpy, "fixed");
263 pw->foreground = get_pixel_resource ("passwd.foreground",
266 pw->background = get_pixel_resource ("passwd.background",
270 if (pw->foreground == pw->background)
272 /* Make sure the error messages show up. */
273 pw->foreground = BlackPixelOfScreen (screen);
274 pw->background = WhitePixelOfScreen (screen);
277 pw->passwd_foreground = get_pixel_resource ("passwd.text.foreground",
278 "Dialog.Text.Foreground",
280 pw->passwd_background = get_pixel_resource ("passwd.text.background",
281 "Dialog.Text.Background",
283 pw->button_foreground = get_pixel_resource ("splash.Button.foreground",
284 "Dialog.Button.Foreground",
286 pw->button_background = get_pixel_resource ("splash.Button.background",
287 "Dialog.Button.Background",
289 pw->thermo_foreground = get_pixel_resource ("passwd.thermometer.foreground",
290 "Dialog.Thermometer.Foreground",
292 pw->thermo_background = get_pixel_resource ("passwd.thermometer.background",
293 "Dialog.Thermometer.Background",
295 pw->shadow_top = get_pixel_resource ("passwd.topShadowColor",
298 pw->shadow_bottom = get_pixel_resource ("passwd.bottomShadowColor",
302 pw->logo_width = get_integer_resource ("passwd.logo.width",
303 "Dialog.Logo.Width");
304 pw->logo_height = get_integer_resource ("passwd.logo.height",
305 "Dialog.Logo.Height");
306 pw->thermo_width = get_integer_resource ("passwd.thermometer.width",
307 "Dialog.Thermometer.Width");
308 pw->internal_border = get_integer_resource ("passwd.internalBorderWidth",
309 "Dialog.InternalBorderWidth");
310 pw->shadow_width = get_integer_resource ("passwd.shadowThickness",
311 "Dialog.ShadowThickness");
313 if (pw->logo_width == 0) pw->logo_width = 150;
314 if (pw->logo_height == 0) pw->logo_height = 150;
315 if (pw->internal_border == 0) pw->internal_border = 15;
316 if (pw->shadow_width == 0) pw->shadow_width = 4;
317 if (pw->thermo_width == 0) pw->thermo_width = pw->shadow_width;
320 int direction, ascent, descent;
326 /* Measure the heading_label. */
327 XTextExtents (pw->heading_font,
328 pw->heading_label, strlen(pw->heading_label),
329 &direction, &ascent, &descent, &overall);
330 if (overall.width > pw->width) pw->width = overall.width;
331 pw->height += ascent + descent;
333 /* Measure the body_label. */
334 XTextExtents (pw->body_font,
335 pw->body_label, strlen(pw->body_label),
336 &direction, &ascent, &descent, &overall);
337 if (overall.width > pw->width) pw->width = overall.width;
338 pw->height += ascent + descent;
341 Dimension w2 = 0, w3 = 0, button_w = 0;
342 Dimension h2 = 0, h3 = 0, button_h = 0;
343 const char *passwd_string = "MMMMMMMMMMMM";
345 /* Measure the user_label. */
346 XTextExtents (pw->label_font,
347 pw->user_label, strlen(pw->user_label),
348 &direction, &ascent, &descent, &overall);
349 if (overall.width > w2) w2 = overall.width;
350 h2 += ascent + descent;
352 /* Measure the passwd_label. */
353 XTextExtents (pw->label_font,
354 pw->passwd_label, strlen(pw->passwd_label),
355 &direction, &ascent, &descent, &overall);
356 if (overall.width > w2) w2 = overall.width;
357 h2 += ascent + descent;
359 /* Measure the user_string. */
360 XTextExtents (pw->passwd_font,
361 pw->user_string, strlen(pw->user_string),
362 &direction, &ascent, &descent, &overall);
363 overall.width += (pw->shadow_width * 4);
364 ascent += (pw->shadow_width * 4);
365 if (overall.width > w3) w3 = overall.width;
366 h3 += ascent + descent;
368 /* Measure the (maximally-sized, dummy) passwd_string. */
369 XTextExtents (pw->passwd_font,
370 passwd_string, strlen(passwd_string),
371 &direction, &ascent, &descent, &overall);
372 overall.width += (pw->shadow_width * 4);
373 ascent += (pw->shadow_width * 4);
374 if (overall.width > w3) w3 = overall.width;
375 h3 += ascent + descent;
377 w2 = w2 + w3 + (pw->shadow_width * 2);
380 pw->login_button_width = 0;
381 pw->login_button_height = 0;
383 if (pw->login_button_p)
385 pw->login_button_enabled_p = True;
387 /* Measure the "New Login" button */
388 XTextExtents (pw->button_font, pw->login_label,
389 strlen (pw->login_label),
390 &direction, &ascent, &descent, &overall);
391 button_w = overall.width;
392 button_h = ascent + descent;
394 /* Add some horizontal padding inside the buttons. */
397 button_w += ((ascent + descent) / 2) + (pw->shadow_width * 2);
398 button_h += ((ascent + descent) / 2) + (pw->shadow_width * 2);
400 pw->login_button_width = button_w;
401 pw->login_button_height = button_h;
403 w2 = MAX (w2, button_w);
404 h2 += button_h * 1.5;
407 if (w2 > pw->width) pw->width = w2;
411 pw->width += (pw->internal_border * 2);
412 pw->height += (pw->internal_border * 4);
414 pw->width += pw->thermo_width + (pw->shadow_width * 3);
416 if (pw->logo_height > pw->height)
417 pw->height = pw->logo_height;
418 else if (pw->height > pw->logo_height)
419 pw->logo_height = pw->height;
421 pw->logo_width = pw->logo_height;
423 pw->width += pw->logo_width;
426 attrmask |= CWOverrideRedirect; attrs.override_redirect = True;
428 attrmask |= CWEventMask;
429 attrs.event_mask = (ExposureMask | KeyPressMask |
430 ButtonPressMask | ButtonReleaseMask);
432 /* We need to remember the mouse position and restore it afterward, or
433 sometimes (perhaps only with Xinerama?) the mouse gets warped to
434 inside the bounds of the lock dialog window.
437 Window pointer_root, pointer_child;
438 int root_x, root_y, win_x, win_y;
440 pw->previous_mouse_x = 0;
441 pw->previous_mouse_y = 0;
442 if (XQueryPointer (si->dpy, RootWindowOfScreen (pw->prompt_screen->screen),
443 &pointer_root, &pointer_child,
444 &root_x, &root_y, &win_x, &win_y, &mask))
446 pw->previous_mouse_x = root_x;
447 pw->previous_mouse_y = root_y;
448 if (si->prefs.verbose_p)
449 fprintf (stderr, "%s: %d: mouse is at %d,%d.\n",
450 blurb(), pw->prompt_screen->number,
451 pw->previous_mouse_x, pw->previous_mouse_y);
453 else if (si->prefs.verbose_p)
454 fprintf (stderr, "%s: %d: unable to determine mouse position?\n",
455 blurb(), pw->prompt_screen->number);
458 /* Figure out where on the desktop to place the window so that it will
459 actually be visible; this takes into account virtual viewports as
463 get_screen_viewport (pw->prompt_screen, &x, &y, &w, &h,
464 pw->previous_mouse_x, pw->previous_mouse_y,
465 si->prefs.verbose_p);
466 if (si->prefs.debug_p) w /= 2;
467 pw->x = x + ((w + pw->width) / 2) - pw->width;
468 pw->y = y + ((h + pw->height) / 2) - pw->height;
469 if (pw->x < x) pw->x = x;
470 if (pw->y < y) pw->y = y;
473 pw->border_width = get_integer_resource ("passwd.borderWidth",
474 "Dialog.BorderWidth");
477 XCreateWindow (si->dpy,
478 RootWindowOfScreen(screen),
479 pw->x, pw->y, pw->width, pw->height, pw->border_width,
480 DefaultDepthOfScreen (screen), InputOutput,
481 DefaultVisualOfScreen(screen),
483 XSetWindowBackground (si->dpy, si->passwd_dialog, pw->background);
485 /* We use the default visual, not ssi->visual, so that the logo pixmap's
486 visual matches that of the si->passwd_dialog window. */
487 pw->logo_pixmap = xscreensaver_logo (ssi->screen,
488 /* ssi->current_visual, */
489 DefaultVisualOfScreen(screen),
490 si->passwd_dialog, cmap,
492 &pw->logo_pixels, &pw->logo_npixels,
495 /* Before mapping the window, save the bits that are underneath the
496 rectangle the window will occlude. When we lower the window, we
497 restore these bits. This works, because the running screenhack
498 has already been sent SIGSTOP, so we know nothing else is drawing
503 pw->save_under = XCreatePixmap (si->dpy,
504 pw->prompt_screen->screensaver_window,
505 pw->width + (pw->border_width*2) + 1,
506 pw->height + (pw->border_width*2) + 1,
507 pw->prompt_screen->current_depth);
508 gcv.function = GXcopy;
509 gc = XCreateGC (si->dpy, pw->save_under, GCFunction, &gcv);
510 XCopyArea (si->dpy, pw->prompt_screen->screensaver_window,
512 pw->x - pw->border_width, pw->y - pw->border_width,
513 pw->width + (pw->border_width*2) + 1,
514 pw->height + (pw->border_width*2) + 1,
516 XFreeGC (si->dpy, gc);
519 XMapRaised (si->dpy, si->passwd_dialog);
520 XSync (si->dpy, False);
522 move_mouse_grab (si, si->passwd_dialog,
525 : pw->prompt_screen->cursor),
526 pw->prompt_screen->number);
532 XInstallColormap (si->dpy, cmap);
533 draw_passwd_window (si);
534 XSync (si->dpy, False);
539 draw_passwd_window (saver_info *si)
541 passwd_dialog_data *pw = si->pw_data;
545 int x1, x2, x3, y1, y2;
549 height = (pw->heading_font->ascent + pw->heading_font->descent +
550 pw->body_font->ascent + pw->body_font->descent +
551 (2 * MAX ((pw->label_font->ascent + pw->label_font->descent),
552 (pw->passwd_font->ascent + pw->passwd_font->descent +
553 (pw->shadow_width * 4)))) +
554 pw->date_font->ascent + pw->date_font->descent);
556 if (pw->login_button_p)
557 height += ((pw->button_font->ascent + pw->button_font->descent) * 2 +
558 2 * pw->shadow_width);
560 spacing = (((pw->height
561 - ((pw->login_button_p ? 4 : 2) * pw->shadow_width)
562 - pw->internal_border - height))
565 if (spacing < 0) spacing = 0;
567 gcv.foreground = pw->foreground;
568 gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
569 gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
570 x1 = pw->logo_width + pw->thermo_width + (pw->shadow_width * 3);
571 x3 = pw->width - (pw->shadow_width * 2);
572 y1 = (pw->shadow_width * 2) + spacing + spacing;
576 XSetFont (si->dpy, gc1, pw->heading_font->fid);
577 sw = string_width (pw->heading_font, pw->heading_label);
578 x2 = (x1 + ((x3 - x1 - sw) / 2));
579 y1 += spacing + pw->heading_font->ascent + pw->heading_font->descent;
580 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
581 pw->heading_label, strlen(pw->heading_label));
583 /* text below top heading
585 XSetFont (si->dpy, gc1, pw->body_font->fid);
586 y1 += spacing + pw->body_font->ascent + pw->body_font->descent;
587 sw = string_width (pw->body_font, pw->body_label);
588 x2 = (x1 + ((x3 - x1 - sw) / 2));
589 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
590 pw->body_label, strlen(pw->body_label));
593 tb_height = (pw->passwd_font->ascent + pw->passwd_font->descent +
594 (pw->shadow_width * 4));
596 /* the "User:" prompt
600 XSetForeground (si->dpy, gc1, pw->foreground);
601 XSetFont (si->dpy, gc1, pw->label_font->fid);
602 y1 += (spacing + tb_height);
603 x2 = (x1 + pw->internal_border +
604 MAX(string_width (pw->label_font, pw->user_label),
605 string_width (pw->label_font, pw->passwd_label)));
606 XDrawString (si->dpy, si->passwd_dialog, gc1,
607 x2 - string_width (pw->label_font, pw->user_label),
608 y1 - pw->passwd_font->descent,
609 pw->user_label, strlen(pw->user_label));
611 /* the "Password:" prompt
613 y1 += (spacing + tb_height);
614 XDrawString (si->dpy, si->passwd_dialog, gc1,
615 x2 - string_width (pw->label_font, pw->passwd_label),
616 y1 - pw->passwd_font->descent,
617 pw->passwd_label, strlen(pw->passwd_label));
620 XSetForeground (si->dpy, gc2, pw->passwd_background);
622 /* the "user name" text field
625 XSetForeground (si->dpy, gc1, pw->passwd_foreground);
626 XSetFont (si->dpy, gc1, pw->passwd_font->fid);
627 y1 += (spacing + tb_height);
628 x2 += (pw->shadow_width * 4);
630 pw->passwd_field_width = x3 - x2 - pw->internal_border;
631 pw->passwd_field_height = (pw->passwd_font->ascent +
632 pw->passwd_font->descent +
635 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
636 x2 - pw->shadow_width,
637 y1 - (pw->passwd_font->ascent + pw->passwd_font->descent),
638 pw->passwd_field_width, pw->passwd_field_height);
639 XDrawString (si->dpy, si->passwd_dialog, gc1,
641 y1 - pw->passwd_font->descent,
642 pw->user_string, strlen(pw->user_string));
644 /* the "password" text field
646 y1 += (spacing + tb_height);
648 pw->passwd_field_x = x2 - pw->shadow_width;
649 pw->passwd_field_y = y1 - (pw->passwd_font->ascent +
650 pw->passwd_font->descent);
652 /* The shadow around the text fields
655 y1 += (spacing + (pw->shadow_width * 3));
656 x1 = x2 - (pw->shadow_width * 2);
657 x2 = pw->passwd_field_width + (pw->shadow_width * 2);
658 y2 = pw->passwd_field_height + (pw->shadow_width * 2);
660 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
663 pw->shadow_bottom, pw->shadow_top);
665 y1 += (spacing + pw->passwd_font->ascent + pw->passwd_font->descent +
666 (pw->shadow_width * 4));
667 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
670 pw->shadow_bottom, pw->shadow_top);
673 /* The date, below the text fields
677 time_t now = time ((time_t *) 0);
678 struct tm *tm = localtime (&now);
679 memset (buf, 0, sizeof(buf));
680 strftime (buf, sizeof(buf)-1, pw->date_label, tm);
682 XSetFont (si->dpy, gc1, pw->date_font->fid);
683 y1 += pw->shadow_width;
684 y1 += (spacing + tb_height);
686 sw = string_width (pw->date_font, buf);
688 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1, buf, strlen(buf));
691 /* The "New Login" button
693 if (pw->login_button_p)
695 XSetForeground (si->dpy, gc1, pw->button_foreground);
696 XSetForeground (si->dpy, gc2, pw->button_background);
697 XSetFont (si->dpy, gc1, pw->button_font->fid);
699 sw = string_width (pw->button_font, pw->login_label);
701 x2 = pw->width - pw->internal_border - (pw->shadow_width * 2);
703 /* right aligned button */
704 /* x1 = x2 - pw->login_button_width; */
706 /* centered button */
707 x1 = (pw->logo_width + pw->thermo_width + (pw->shadow_width * 3) +
708 pw->internal_border);
709 x1 = x1 + (x2 - x1 - pw->login_button_width) / 2;
711 y1 = (pw->height - pw->internal_border - pw->login_button_height +
714 ((pw->login_button_height -
715 (pw->button_font->ascent + pw->button_font->descent))
717 pw->button_font->ascent);
719 pw->login_button_x = x1;
720 pw->login_button_y = y1;
725 x1 = pw->shadow_width * 6;
726 y1 = pw->shadow_width * 6;
727 x2 = pw->logo_width - (pw->shadow_width * 12);
728 y2 = pw->logo_height - (pw->shadow_width * 12);
734 unsigned int w, h, bw, d;
735 XGetGeometry (si->dpy, pw->logo_pixmap, &root, &x, &y, &w, &h, &bw, &d);
736 XSetForeground (si->dpy, gc1, pw->foreground);
737 XSetBackground (si->dpy, gc1, pw->background);
739 XCopyPlane (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1,
741 x1 + ((x2 - (int)w) / 2),
742 y1 + ((y2 - (int)h) / 2),
745 XCopyArea (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1,
747 x1 + ((x2 - (int)w) / 2),
748 y1 + ((y2 - (int)h) / 2));
753 XSetForeground (si->dpy, gc1, pw->thermo_foreground);
754 XSetForeground (si->dpy, gc2, pw->thermo_background);
756 pw->thermo_field_x = pw->logo_width + pw->shadow_width;
757 pw->thermo_field_y = pw->shadow_width * 5;
758 pw->thermo_field_height = pw->height - (pw->shadow_width * 10);
761 /* Solid border inside the logo box. */
762 XSetForeground (si->dpy, gc1, pw->foreground);
763 XDrawRectangle (si->dpy, si->passwd_dialog, gc1, x1, y1, x2-1, y2-1);
766 /* The shadow around the logo
768 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
769 pw->shadow_width * 4,
770 pw->shadow_width * 4,
771 pw->logo_width - (pw->shadow_width * 8),
772 pw->logo_height - (pw->shadow_width * 8),
774 pw->shadow_bottom, pw->shadow_top);
776 /* The shadow around the thermometer
778 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
780 pw->shadow_width * 4,
781 pw->thermo_width + (pw->shadow_width * 2),
782 pw->height - (pw->shadow_width * 8),
784 pw->shadow_bottom, pw->shadow_top);
787 /* Solid border inside the thermometer. */
788 XSetForeground (si->dpy, gc1, pw->foreground);
789 XDrawRectangle (si->dpy, si->passwd_dialog, gc1,
790 pw->thermo_field_x, pw->thermo_field_y,
791 pw->thermo_width - 1, pw->thermo_field_height - 1);
794 /* The shadow around the whole window
796 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
797 0, 0, pw->width, pw->height, pw->shadow_width,
798 pw->shadow_top, pw->shadow_bottom);
800 XFreeGC (si->dpy, gc1);
801 XFreeGC (si->dpy, gc2);
803 update_passwd_window (si, pw->passwd_string, pw->ratio);
808 update_passwd_window (saver_info *si, const char *printed_passwd, float ratio)
810 passwd_dialog_data *pw = si->pw_data;
817 gcv.foreground = pw->passwd_foreground;
818 gcv.font = pw->passwd_font->fid;
819 gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground|GCFont, &gcv);
820 gcv.foreground = pw->passwd_background;
821 gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
825 char *s = strdup (printed_passwd);
826 if (pw->passwd_string) free (pw->passwd_string);
827 pw->passwd_string = s;
830 /* the "password" text field
832 rects[0].x = pw->passwd_field_x;
833 rects[0].y = pw->passwd_field_y;
834 rects[0].width = pw->passwd_field_width;
835 rects[0].height = pw->passwd_field_height;
837 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
838 rects[0].x, rects[0].y, rects[0].width, rects[0].height);
840 XSetClipRectangles (si->dpy, gc1, 0, 0, rects, 1, Unsorted);
842 XDrawString (si->dpy, si->passwd_dialog, gc1,
843 rects[0].x + pw->shadow_width,
844 rects[0].y + pw->passwd_font->ascent,
845 pw->passwd_string, strlen(pw->passwd_string));
847 XSetClipMask (si->dpy, gc1, None);
853 x = (rects[0].x + pw->shadow_width +
854 string_width (pw->passwd_font, pw->passwd_string));
855 y = rects[0].y + pw->shadow_width;
857 if (x > rects[0].x + rects[0].width - 1)
858 x = rects[0].x + rects[0].width - 1;
859 XDrawLine (si->dpy, si->passwd_dialog, gc1,
861 x, y + pw->passwd_font->ascent + pw->passwd_font->descent-1);
864 pw->i_beam = (pw->i_beam + 1) % 4;
869 y = (pw->thermo_field_height - 2) * (1.0 - pw->ratio);
872 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
873 pw->thermo_field_x + 1,
874 pw->thermo_field_y + 1,
877 XSetForeground (si->dpy, gc1, pw->thermo_foreground);
878 XFillRectangle (si->dpy, si->passwd_dialog, gc1,
879 pw->thermo_field_x + 1,
880 pw->thermo_field_y + 1 + y,
882 MAX (0, pw->thermo_field_height - y - 2));
885 /* The "New Login" button
887 if (pw->login_button_p)
890 XSetFont (si->dpy, gc1, pw->button_font->fid);
891 XSetForeground (si->dpy, gc1,
892 (pw->login_button_enabled_p
893 ? pw->passwd_foreground
894 : pw->shadow_bottom));
895 XSetForeground (si->dpy, gc2, pw->button_background);
897 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
898 pw->login_button_x, pw->login_button_y,
899 pw->login_button_width, pw->login_button_height);
901 sw = string_width (pw->button_font, pw->login_label);
902 x2 = pw->login_button_x + ((pw->login_button_width - sw) / 2);
903 y2 = (pw->login_button_y +
904 ((pw->login_button_height -
905 (pw->button_font->ascent + pw->button_font->descent))
907 pw->button_font->ascent);
909 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y2,
910 pw->login_label, strlen(pw->login_label));
912 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
913 pw->login_button_x, pw->login_button_y,
914 pw->login_button_width, pw->login_button_height,
916 (pw->login_button_down_p
919 (pw->login_button_down_p
921 : pw->shadow_bottom));
924 XFreeGC (si->dpy, gc1);
925 XFreeGC (si->dpy, gc2);
926 XSync (si->dpy, False);
931 destroy_passwd_window (saver_info *si)
933 saver_preferences *p = &si->prefs;
934 passwd_dialog_data *pw = si->pw_data;
935 saver_screen_info *ssi = pw->prompt_screen;
936 Colormap cmap = DefaultColormapOfScreen (ssi->screen);
937 Pixel black = BlackPixelOfScreen (ssi->screen);
938 Pixel white = WhitePixelOfScreen (ssi->screen);
941 memset (pw->typed_passwd, 0, sizeof(pw->typed_passwd));
942 memset (pw->passwd_string, 0, strlen(pw->passwd_string));
945 XtRemoveTimeOut (pw->timer);
947 move_mouse_grab (si, RootWindowOfScreen (ssi->screen),
948 ssi->cursor, ssi->number);
950 if (pw->passwd_cursor)
951 XFreeCursor (si->dpy, pw->passwd_cursor);
954 fprintf (stderr, "%s: %d: moving mouse back to %d,%d.\n",
955 blurb(), ssi->number,
956 pw->previous_mouse_x, pw->previous_mouse_y);
958 XWarpPointer (si->dpy, None, RootWindowOfScreen (ssi->screen),
960 pw->previous_mouse_x, pw->previous_mouse_y);
962 XSync (si->dpy, False);
963 while (XCheckMaskEvent (si->dpy, PointerMotionMask, &event))
965 fprintf (stderr, "%s: discarding MotionNotify event.\n", blurb());
967 if (si->passwd_dialog)
969 XDestroyWindow (si->dpy, si->passwd_dialog);
970 si->passwd_dialog = 0;
977 gcv.function = GXcopy;
978 gc = XCreateGC (si->dpy, ssi->screensaver_window, GCFunction, &gcv);
979 XCopyArea (si->dpy, pw->save_under,
980 ssi->screensaver_window, gc,
982 pw->width + (pw->border_width*2) + 1,
983 pw->height + (pw->border_width*2) + 1,
984 pw->x - pw->border_width, pw->y - pw->border_width);
985 XFreePixmap (si->dpy, pw->save_under);
987 XFreeGC (si->dpy, gc);
990 if (pw->heading_label) free (pw->heading_label);
991 if (pw->body_label) free (pw->body_label);
992 if (pw->user_label) free (pw->user_label);
993 if (pw->passwd_label) free (pw->passwd_label);
994 if (pw->date_label) free (pw->date_label);
995 if (pw->login_label) free (pw->login_label);
996 if (pw->user_string) free (pw->user_string);
997 if (pw->passwd_string) free (pw->passwd_string);
999 if (pw->heading_font) XFreeFont (si->dpy, pw->heading_font);
1000 if (pw->body_font) XFreeFont (si->dpy, pw->body_font);
1001 if (pw->label_font) XFreeFont (si->dpy, pw->label_font);
1002 if (pw->passwd_font) XFreeFont (si->dpy, pw->passwd_font);
1003 if (pw->date_font) XFreeFont (si->dpy, pw->date_font);
1004 if (pw->button_font) XFreeFont (si->dpy, pw->button_font);
1006 if (pw->foreground != black && pw->foreground != white)
1007 XFreeColors (si->dpy, cmap, &pw->foreground, 1, 0L);
1008 if (pw->background != black && pw->background != white)
1009 XFreeColors (si->dpy, cmap, &pw->background, 1, 0L);
1010 if (!(pw->button_foreground == black || pw->button_foreground == white))
1011 XFreeColors (si->dpy, cmap, &pw->button_foreground, 1, 0L);
1012 if (!(pw->button_background == black || pw->button_background == white))
1013 XFreeColors (si->dpy, cmap, &pw->button_background, 1, 0L);
1014 if (pw->passwd_foreground != black && pw->passwd_foreground != white)
1015 XFreeColors (si->dpy, cmap, &pw->passwd_foreground, 1, 0L);
1016 if (pw->passwd_background != black && pw->passwd_background != white)
1017 XFreeColors (si->dpy, cmap, &pw->passwd_background, 1, 0L);
1018 if (pw->thermo_foreground != black && pw->thermo_foreground != white)
1019 XFreeColors (si->dpy, cmap, &pw->thermo_foreground, 1, 0L);
1020 if (pw->thermo_background != black && pw->thermo_background != white)
1021 XFreeColors (si->dpy, cmap, &pw->thermo_background, 1, 0L);
1022 if (pw->shadow_top != black && pw->shadow_top != white)
1023 XFreeColors (si->dpy, cmap, &pw->shadow_top, 1, 0L);
1024 if (pw->shadow_bottom != black && pw->shadow_bottom != white)
1025 XFreeColors (si->dpy, cmap, &pw->shadow_bottom, 1, 0L);
1027 if (pw->logo_pixmap)
1028 XFreePixmap (si->dpy, pw->logo_pixmap);
1029 if (pw->logo_pixels)
1031 if (pw->logo_npixels)
1032 XFreeColors (si->dpy, cmap, pw->logo_pixels, pw->logo_npixels, 0L);
1033 free (pw->logo_pixels);
1034 pw->logo_pixels = 0;
1035 pw->logo_npixels = 0;
1039 XFreePixmap (si->dpy, pw->save_under);
1042 XInstallColormap (si->dpy, cmap);
1044 memset (pw, 0, sizeof(*pw));
1050 static Bool error_handler_hit_p = False;
1053 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1055 error_handler_hit_p = True;
1060 #ifdef HAVE_XHPDISABLERESET
1061 /* This function enables and disables the C-Sh-Reset hot-key, which
1062 normally resets the X server (logging out the logged-in user.)
1063 We don't want random people to be able to do that while the
1067 hp_lock_reset (saver_info *si, Bool lock_p)
1069 static Bool hp_locked_p = False;
1071 /* Calls to XHPDisableReset and XHPEnableReset must be balanced,
1072 or BadAccess errors occur. (It's ok for this to be global,
1073 since it affects the whole machine, not just the current screen.)
1075 if (hp_locked_p == lock_p)
1079 XHPDisableReset (si->dpy);
1081 XHPEnableReset (si->dpy);
1082 hp_locked_p = lock_p;
1084 #endif /* HAVE_XHPDISABLERESET */
1087 #ifdef HAVE_XF86MISCSETGRABKEYSSTATE
1089 /* This function enables and disables the Ctrl-Alt-KP_star and
1090 Ctrl-Alt-KP_slash hot-keys, which (in XFree86 4.2) break any
1091 grabs and/or kill the grabbing client. That would effectively
1092 unlock the screen, so we don't like that.
1094 The Ctrl-Alt-KP_star and Ctrl-Alt-KP_slash hot-keys only exist
1095 if AllowDeactivateGrabs and/or AllowClosedownGrabs are turned on
1096 in XF86Config. I believe they are disabled by default.
1098 This does not affect any other keys (specifically Ctrl-Alt-BS or
1099 Ctrl-Alt-F1) but I wish it did. Maybe it will someday.
1102 xfree_lock_grab_smasher (saver_info *si, Bool lock_p)
1104 saver_preferences *p = &si->prefs;
1107 XErrorHandler old_handler;
1108 XSync (si->dpy, False);
1109 error_handler_hit_p = False;
1110 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1111 XSync (si->dpy, False);
1112 status = XF86MiscSetGrabKeysState (si->dpy, !lock_p);
1113 XSync (si->dpy, False);
1114 if (error_handler_hit_p) status = 666;
1116 if (!lock_p && status == MiscExtGrabStateAlready)
1117 status = MiscExtGrabStateSuccess; /* shut up, consider this success */
1119 if (p->verbose_p && status != MiscExtGrabStateSuccess)
1120 fprintf (stderr, "%s: error: XF86MiscSetGrabKeysState(%d) returned %s\n",
1122 (status == MiscExtGrabStateSuccess ? "MiscExtGrabStateSuccess" :
1123 status == MiscExtGrabStateLocked ? "MiscExtGrabStateLocked" :
1124 status == MiscExtGrabStateAlready ? "MiscExtGrabStateAlready" :
1125 status == 666 ? "an X error" :
1128 XSync (si->dpy, False);
1129 XSetErrorHandler (old_handler);
1130 XSync (si->dpy, False);
1132 #endif /* HAVE_XF86MISCSETGRABKEYSSTATE */
1137 /* This function enables and disables the C-Sh-F1 ... F12 hot-keys,
1138 which, on Linux systems, switches to another virtual console.
1139 We'd like the whole screen/keyboard to be locked, not just one
1140 virtual console, so this function disables that while the X
1143 Unfortunately, this doesn't work -- this ioctl only works when
1144 called by root, and we have disavowed our privileges long ago.
1146 #ifdef HAVE_VT_LOCKSWITCH
1148 linux_lock_vt_switch (saver_info *si, Bool lock_p)
1150 saver_preferences *p = &si->prefs;
1151 static Bool vt_locked_p = False;
1152 const char *dev_console = "/dev/console";
1155 if (lock_p == vt_locked_p)
1158 if (lock_p && !p->lock_vt_p)
1161 fd = open (dev_console, O_RDWR);
1165 sprintf (buf, "%s: couldn't %s VTs: %s", blurb(),
1166 (lock_p ? "lock" : "unlock"),
1168 #if 1 /* #### doesn't work yet, so don't bother complaining */
1174 if (ioctl (fd, (lock_p ? VT_LOCKSWITCH : VT_UNLOCKSWITCH)) == 0)
1176 vt_locked_p = lock_p;
1179 fprintf (stderr, "%s: %s VTs\n", blurb(),
1180 (lock_p ? "locked" : "unlocked"));
1185 sprintf (buf, "%s: couldn't %s VTs: ioctl", blurb(),
1186 (lock_p ? "lock" : "unlock"));
1187 #if 0 /* #### doesn't work yet, so don't bother complaining */
1194 #endif /* HAVE_VT_LOCKSWITCH */
1197 /* This function enables and disables the C-Alt-Plus and C-Alt-Minus
1198 hot-keys, which normally change the resolution of the X server.
1199 We don't want people to be able to switch the server resolution
1200 while the screen is locked, because if they switch to a higher
1201 resolution, it could cause part of the underlying desktop to become
1204 #ifdef HAVE_XF86VMODE
1207 xfree_lock_mode_switch (saver_info *si, Bool lock_p)
1209 static Bool any_mode_locked_p = False;
1210 saver_preferences *p = &si->prefs;
1214 XErrorHandler old_handler;
1216 if (any_mode_locked_p == lock_p)
1218 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1221 for (screen = 0; screen < (si->xinerama_p ? 1 : si->nscreens); screen++)
1223 XSync (si->dpy, False);
1224 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1225 error_handler_hit_p = False;
1226 status = XF86VidModeLockModeSwitch (si->dpy, screen, lock_p);
1227 XSync (si->dpy, False);
1228 XSetErrorHandler (old_handler);
1229 if (error_handler_hit_p) status = False;
1232 any_mode_locked_p = lock_p;
1234 if (!status && (p->verbose_p || !lock_p))
1235 /* Only print this when verbose, or when we locked but can't unlock.
1236 I tried printing this message whenever it comes up, but
1237 mode-locking always fails if DontZoom is set in XF86Config. */
1238 fprintf (stderr, "%s: %d: unable to %s mode switching!\n",
1239 blurb(), screen, (lock_p ? "lock" : "unlock"));
1240 else if (p->verbose_p)
1241 fprintf (stderr, "%s: %d: %s mode switching.\n",
1242 blurb(), screen, (lock_p ? "locked" : "unlocked"));
1245 #endif /* HAVE_XF86VMODE */
1248 /* If the viewport has been scrolled since the screen was blanked,
1249 then scroll it back to where it belongs. This function only exists
1250 to patch over a very brief race condition.
1253 undo_vp_motion (saver_info *si)
1255 #ifdef HAVE_XF86VMODE
1256 saver_preferences *p = &si->prefs;
1260 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1263 for (screen = 0; screen < si->nscreens; screen++)
1265 saver_screen_info *ssi = &si->screens[screen];
1269 if (ssi->blank_vp_x == -1 && ssi->blank_vp_y == -1)
1271 if (!XF86VidModeGetViewPort (si->dpy, screen, &x, &y))
1273 if (ssi->blank_vp_x == x && ssi->blank_vp_y == y)
1276 /* We're going to move the viewport. The mouse has just been grabbed on
1277 (and constrained to, thus warped to) the password window, so it is no
1278 longer near the edge of the screen. However, wait a bit anyway, just
1279 to make sure the server drains its last motion event, so that the
1280 screen doesn't continue to scroll after we've reset the viewport.
1282 XSync (si->dpy, False);
1283 usleep (250000); /* 1/4 second */
1284 XSync (si->dpy, False);
1286 status = XF86VidModeSetViewPort (si->dpy, screen,
1287 ssi->blank_vp_x, ssi->blank_vp_y);
1291 "%s: %d: unable to move vp from (%d,%d) back to (%d,%d)!\n",
1292 blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1293 else if (p->verbose_p)
1295 "%s: %d: vp moved to (%d,%d); moved it back to (%d,%d).\n",
1296 blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1298 #endif /* HAVE_XF86VMODE */
1307 passwd_animate_timer (XtPointer closure, XtIntervalId *id)
1309 saver_info *si = (saver_info *) closure;
1311 passwd_dialog_data *pw = si->pw_data;
1315 pw->ratio -= (1.0 / ((double) si->prefs.passwd_timeout / (double) tick));
1319 if (pw->state == pw_read)
1320 pw->state = pw_time;
1323 update_passwd_window (si, 0, pw->ratio);
1325 if (pw->state == pw_read)
1326 pw->timer = XtAppAddTimeOut (si->app, tick, passwd_animate_timer,
1331 idle_timer ((XtPointer) si, 0);
1335 static XComposeStatus *compose_status;
1338 handle_passwd_button (saver_info *si, XEvent *event)
1340 saver_preferences *p = &si->prefs;
1341 Bool mouse_in_box = False;
1343 passwd_dialog_data *pw = si->pw_data;
1344 saver_screen_info *ssi = pw->prompt_screen;
1346 if (! pw->login_button_enabled_p)
1350 (event->xbutton.x >= pw->login_button_x &&
1351 event->xbutton.x <= pw->login_button_x + pw->login_button_width &&
1352 event->xbutton.y >= pw->login_button_y &&
1353 event->xbutton.y <= pw->login_button_y + pw->login_button_height);
1355 if (ButtonRelease == event->xany.type &&
1356 pw->login_button_down_p &&
1359 /* Only allow them to press the button once: don't want to
1360 accidentally launch a dozen gdm choosers if the machine
1364 pw->login_button_enabled_p = False;
1367 pw->login_button_down_p = (mouse_in_box &&
1368 ButtonRelease != event->xany.type);
1370 update_passwd_window (si, 0, pw->ratio);
1373 fork_and_exec (ssi, p->new_login_command);
1378 handle_passwd_key (saver_info *si, XKeyEvent *event)
1380 saver_preferences *p = &si->prefs;
1381 passwd_dialog_data *pw = si->pw_data;
1382 int pw_size = sizeof (pw->typed_passwd) - 1;
1383 char *typed_passwd = pw->typed_passwd;
1387 int size = XLookupString (event, s, 1, 0, compose_status);
1389 if (size != 1) return;
1393 /* Add 10% to the time remaining every time a key is pressed. */
1395 if (pw->ratio > 1) pw->ratio = 1;
1399 case '\010': case '\177': /* Backspace */
1403 typed_passwd [strlen(typed_passwd)-1] = 0;
1406 case '\025': case '\030': /* Erase line */
1407 memset (typed_passwd, 0, pw_size);
1410 case '\012': case '\015': /* Enter */
1411 if (pw->state != pw_read)
1412 ; /* already done? */
1413 else if (typed_passwd[0] == 0)
1414 pw->state = pw_null;
1417 update_passwd_window (si, "Checking...", pw->ratio);
1418 XSync (si->dpy, False);
1419 if (passwd_valid_p (typed_passwd, p->verbose_p))
1422 pw->state = pw_fail;
1423 update_passwd_window (si, "", pw->ratio);
1428 /* Though technically the only illegal characters in Unix passwords
1429 are LF and NUL, most GUI programs (e.g., GDM) use regular text-entry
1430 fields that only let you type printable characters. So, people
1431 who use funky characters in their passwords are already broken.
1432 We follow that precedent.
1434 if (isprint ((unsigned char) *s))
1436 i = strlen (typed_passwd);
1441 typed_passwd [i] = *s;
1442 typed_passwd [i+1] = 0;
1450 if (pw->show_stars_p)
1452 i = strlen(typed_passwd);
1453 stars = (char *) malloc(i+1);
1454 memset (stars, '*', i);
1456 update_passwd_window (si, stars, pw->ratio);
1461 update_passwd_window (si, "", pw->ratio);
1467 passwd_event_loop (saver_info *si)
1469 saver_preferences *p = &si->prefs;
1472 unsigned int caps_p = 0;
1474 passwd_animate_timer ((XtPointer) si, 0);
1476 while (si->pw_data && si->pw_data->state == pw_read)
1478 XtAppNextEvent (si->app, &event);
1479 if (event.xany.window == si->passwd_dialog && event.xany.type == Expose)
1480 draw_passwd_window (si);
1481 else if (event.xany.type == KeyPress)
1483 handle_passwd_key (si, &event.xkey);
1484 caps_p = (event.xkey.state & LockMask);
1486 else if ((event.xany.type == ButtonPress ||
1487 event.xany.type == ButtonRelease) &&
1488 si->pw_data->login_button_p)
1489 handle_passwd_button (si, &event);
1491 XtDispatchEvent (&event);
1494 switch (si->pw_data->state)
1496 case pw_ok: msg = 0; break;
1497 case pw_null: msg = ""; break;
1498 case pw_time: msg = "Timed out!"; break;
1499 default: msg = (caps_p ? "CapsLock?" : "Sorry!"); break;
1502 if (si->pw_data->state == pw_fail)
1503 si->unlock_failures++;
1506 switch (si->pw_data->state)
1509 fprintf (stderr, "%s: password correct.\n", blurb()); break;
1511 fprintf (stderr, "%s: password incorrect!%s\n", blurb(),
1512 (caps_p ? " (CapsLock)" : ""));
1516 fprintf (stderr, "%s: password entry cancelled.\n", blurb()); break;
1518 fprintf (stderr, "%s: password entry timed out.\n", blurb()); break;
1523 if (si->pw_data->state == pw_fail)
1525 /* If they typed a password (as opposed to just hitting return) and
1526 the password was invalid, log it.
1528 struct passwd *pw = getpwuid (getuid ());
1529 char *d = DisplayString (si->dpy);
1530 char *u = (pw->pw_name ? pw->pw_name : "???");
1538 # if defined(LOG_AUTHPRIV)
1540 # elif defined(LOG_AUTH)
1547 openlog (progname, opt, fac);
1548 syslog (LOG_NOTICE, "FAILED LOGIN %d ON DISPLAY \"%s\", FOR \"%s\"",
1549 si->unlock_failures, d, u);
1552 #endif /* HAVE_SYSLOG */
1554 if (si->pw_data->state == pw_fail)
1555 XBell (si->dpy, False);
1557 if (si->pw_data->state == pw_ok && si->unlock_failures != 0)
1559 if (si->unlock_failures == 1)
1560 fprintf (real_stderr,
1561 "%s: WARNING: 1 failed attempt to unlock the screen.\n",
1564 fprintf (real_stderr,
1565 "%s: WARNING: %d failed attempts to unlock the screen.\n",
1566 blurb(), si->unlock_failures);
1567 fflush (real_stderr);
1569 si->unlock_failures = 0;
1574 si->pw_data->i_beam = 0;
1575 update_passwd_window (si, msg, 0.0);
1576 XSync (si->dpy, False);
1579 /* Swallow all pending KeyPress/KeyRelease events. */
1582 while (XCheckMaskEvent (si->dpy, KeyPressMask|KeyReleaseMask, &e))
1590 handle_typeahead (saver_info *si)
1592 passwd_dialog_data *pw = si->pw_data;
1594 if (!si->unlock_typeahead)
1597 i = strlen (si->unlock_typeahead);
1598 if (i >= sizeof(pw->typed_passwd) - 1)
1599 i = sizeof(pw->typed_passwd) - 1;
1601 memcpy (pw->typed_passwd, si->unlock_typeahead, i);
1602 pw->typed_passwd [i] = 0;
1604 memset (si->unlock_typeahead, '*', strlen(si->unlock_typeahead));
1605 si->unlock_typeahead[i] = 0;
1606 update_passwd_window (si, si->unlock_typeahead, pw->ratio);
1608 free (si->unlock_typeahead);
1609 si->unlock_typeahead = 0;
1614 unlock_p (saver_info *si)
1616 saver_preferences *p = &si->prefs;
1619 raise_window (si, True, True, True);
1622 fprintf (stderr, "%s: prompting for password.\n", blurb());
1624 if (si->pw_data || si->passwd_dialog)
1625 destroy_passwd_window (si);
1627 make_passwd_window (si);
1629 compose_status = calloc (1, sizeof (*compose_status));
1631 handle_typeahead (si);
1632 passwd_event_loop (si);
1634 status = (si->pw_data->state == pw_ok);
1635 destroy_passwd_window (si);
1637 free (compose_status);
1645 set_locked_p (saver_info *si, Bool locked_p)
1647 si->locked_p = locked_p;
1649 #ifdef HAVE_XHPDISABLERESET
1650 hp_lock_reset (si, locked_p); /* turn off/on C-Sh-Reset */
1652 #ifdef HAVE_VT_LOCKSWITCH
1653 linux_lock_vt_switch (si, locked_p); /* turn off/on C-Alt-F1 */
1655 #ifdef HAVE_XF86VMODE
1656 xfree_lock_mode_switch (si, locked_p); /* turn off/on C-Alt-Plus */
1658 #ifdef HAVE_XF86MISCSETGRABKEYSSTATE
1659 xfree_lock_grab_smasher (si, locked_p); /* turn off/on C-Alt-KP-*,/ */
1662 store_saver_status (si); /* store locked-p */
1666 #else /* NO_LOCKING -- whole file */
1669 set_locked_p (saver_info *si, Bool locked_p)
1671 if (locked_p) abort();
1674 #endif /* !NO_LOCKING */