1 /* lock.c --- handling the password dialog for locking-mode.
2 * xscreensaver, Copyright (c) 1993-2006 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 */
41 # include <X11/extensions/xf86vmode.h>
42 static void xfree_lock_mode_switch (saver_info *si, Bool lock_p);
43 #endif /* HAVE_XF86VMODE */
45 #ifdef HAVE_XF86MISCSETGRABKEYSSTATE
46 # include <X11/extensions/xf86misc.h>
47 static void xfree_lock_grab_smasher (saver_info *si, Bool lock_p);
48 #endif /* HAVE_XF86MISCSETGRABKEYSSTATE */
52 ERROR! You must not include vroot.h in this file.
56 # include <sys/utsname.h> /* for hostname info */
57 #endif /* HAVE_UNAME */
64 extern char *getenv(const char *name);
65 extern int validate_user(char *name, char *password);
68 vms_passwd_valid_p(char *pw, Bool verbose_p)
70 return (validate_user (getenv("USER"), typed_passwd) == 1);
72 # undef passwd_valid_p
73 # define passwd_valid_p vms_passwd_valid_p
79 #define MAX(a,b) ((a)>(b)?(a):(b))
81 enum passwd_state { pw_read, pw_ok, pw_null, pw_fail, pw_cancel, pw_time };
83 struct passwd_dialog_data {
85 saver_screen_info *prompt_screen;
86 int previous_mouse_x, previous_mouse_y;
88 enum passwd_state state;
89 char typed_passwd [80];
97 Dimension border_width;
99 Bool show_stars_p; /* "I regret that I have but one asterisk for my country."
100 -- Nathan Hale, 1776. */
114 XFontStruct *heading_font;
115 XFontStruct *body_font;
116 XFontStruct *label_font;
117 XFontStruct *passwd_font;
118 XFontStruct *date_font;
119 XFontStruct *button_font;
120 XFontStruct *uname_font;
124 Pixel passwd_foreground;
125 Pixel passwd_background;
126 Pixel thermo_foreground;
127 Pixel thermo_background;
130 Pixel button_foreground;
131 Pixel button_background;
133 Dimension logo_width;
134 Dimension logo_height;
135 Dimension thermo_width;
136 Dimension internal_border;
137 Dimension shadow_width;
139 Dimension passwd_field_x, passwd_field_y;
140 Dimension passwd_field_width, passwd_field_height;
142 Dimension login_button_x, login_button_y;
143 Dimension login_button_width, login_button_height;
145 Dimension thermo_field_x, thermo_field_y;
146 Dimension thermo_field_height;
149 Pixmap logo_clipmask;
151 unsigned long *logo_pixels;
153 Cursor passwd_cursor;
154 Bool login_button_down_p;
156 Bool login_button_enabled_p;
161 static void draw_passwd_window (saver_info *si);
162 static void update_passwd_window (saver_info *si, const char *printed_passwd,
164 static void destroy_passwd_window (saver_info *si);
165 static void undo_vp_motion (saver_info *si);
166 static void handle_passwd_button (saver_info *si, XEvent *event);
170 make_passwd_window (saver_info *si)
172 struct passwd *p = getpwuid (getuid ());
173 XSetWindowAttributes attrs;
174 unsigned long attrmask = 0;
175 passwd_dialog_data *pw = (passwd_dialog_data *) calloc (1, sizeof(*pw));
179 saver_screen_info *ssi = &si->screens [mouse_screen (si)];
181 /* Display the button only if the "newLoginCommand" pref is non-null.
183 pw->login_button_p = (si->prefs.new_login_command &&
184 *si->prefs.new_login_command);
186 if (pw->login_button_p)
187 pw->passwd_cursor = XCreateFontCursor (si->dpy, XC_top_left_arrow);
189 pw->passwd_cursor = 0;
191 pw->prompt_screen = ssi;
192 if (si->prefs.verbose_p)
193 fprintf (stderr, "%s: %d: creating password dialog.\n",
194 blurb(), pw->prompt_screen->number);
196 screen = pw->prompt_screen->screen;
197 cmap = DefaultColormapOfScreen (screen);
201 pw->show_stars_p = get_boolean_resource(si->dpy, "passwd.asterisks",
204 pw->heading_label = get_string_resource (si->dpy, "passwd.heading.label",
205 "Dialog.Label.Label");
206 pw->body_label = get_string_resource (si->dpy, "passwd.body.label",
207 "Dialog.Label.Label");
208 pw->user_label = get_string_resource (si->dpy, "passwd.user.label",
209 "Dialog.Label.Label");
210 pw->passwd_label = get_string_resource (si->dpy, "passwd.passwd.label",
211 "Dialog.Label.Label");
212 pw->login_label = get_string_resource (si->dpy, "passwd.login.label",
213 "Dialog.Button.Label");
215 pw->date_label = get_string_resource (si->dpy, "dateFormat", "DateFormat");
217 if (!pw->heading_label)
218 pw->heading_label = strdup("ERROR: RESOURCES NOT INSTALLED CORRECTLY");
220 pw->body_label = strdup("ERROR: RESOURCES NOT INSTALLED CORRECTLY");
221 if (!pw->user_label) pw->user_label = strdup("ERROR");
222 if (!pw->passwd_label) pw->passwd_label = strdup("ERROR");
223 if (!pw->date_label) pw->date_label = strdup("ERROR");
224 if (!pw->login_label) pw->login_label = strdup ("ERROR (LOGIN)") ;
226 /* Put the version number in the label. */
228 char *s = (char *) malloc (strlen(pw->heading_label) + 20);
229 sprintf(s, pw->heading_label, si->version);
230 free (pw->heading_label);
231 pw->heading_label = s;
234 /* Get hostname info */
235 pw->uname_label = strdup(""); /* Initialy, write nothing */
241 if (uname (&uts) == 0)
243 #if 0 /* Get the full hostname */
246 if ((s = strchr(uts.nodename, '.')))
250 char *s = strdup (uts.nodename);
251 free (pw->uname_label);
257 pw->user_string = strdup (p && p->pw_name ? p->pw_name : "???");
258 pw->passwd_string = strdup("");
260 f = get_string_resource (si->dpy, "passwd.headingFont", "Dialog.Font");
261 pw->heading_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
262 if (!pw->heading_font) pw->heading_font = XLoadQueryFont (si->dpy, "fixed");
265 f = get_string_resource (si->dpy, "passwd.buttonFont", "Dialog.Font");
266 pw->button_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
267 if (!pw->button_font) pw->button_font = XLoadQueryFont (si->dpy, "fixed");
270 f = get_string_resource(si->dpy, "passwd.bodyFont", "Dialog.Font");
271 pw->body_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
272 if (!pw->body_font) pw->body_font = XLoadQueryFont (si->dpy, "fixed");
275 f = get_string_resource(si->dpy, "passwd.labelFont", "Dialog.Font");
276 pw->label_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
277 if (!pw->label_font) pw->label_font = XLoadQueryFont (si->dpy, "fixed");
280 f = get_string_resource(si->dpy, "passwd.passwdFont", "Dialog.Font");
281 pw->passwd_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
282 if (!pw->passwd_font) pw->passwd_font = XLoadQueryFont (si->dpy, "fixed");
285 f = get_string_resource(si->dpy, "passwd.dateFont", "Dialog.Font");
286 pw->date_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
287 if (!pw->date_font) pw->date_font = XLoadQueryFont (si->dpy, "fixed");
290 f = get_string_resource(si->dpy, "passwd.unameFont", "Dialog.Font");
291 pw->uname_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
292 if (!pw->uname_font) pw->uname_font = XLoadQueryFont (si->dpy, "fixed");
295 pw->show_uname_p = get_boolean_resource(si->dpy, "passwd.uname", "Boolean");
297 pw->foreground = get_pixel_resource (si->dpy, cmap,
299 "Dialog.Foreground" );
300 pw->background = get_pixel_resource (si->dpy, cmap,
302 "Dialog.Background" );
304 if (pw->foreground == pw->background)
306 /* Make sure the error messages show up. */
307 pw->foreground = BlackPixelOfScreen (screen);
308 pw->background = WhitePixelOfScreen (screen);
311 pw->passwd_foreground = get_pixel_resource (si->dpy, cmap,
312 "passwd.text.foreground",
313 "Dialog.Text.Foreground" );
314 pw->passwd_background = get_pixel_resource (si->dpy, cmap,
315 "passwd.text.background",
316 "Dialog.Text.Background" );
317 pw->button_foreground = get_pixel_resource (si->dpy, cmap,
318 "splash.Button.foreground",
319 "Dialog.Button.Foreground" );
320 pw->button_background = get_pixel_resource (si->dpy, cmap,
321 "splash.Button.background",
322 "Dialog.Button.Background" );
323 pw->thermo_foreground = get_pixel_resource (si->dpy, cmap,
324 "passwd.thermometer.foreground",
325 "Dialog.Thermometer.Foreground" );
326 pw->thermo_background = get_pixel_resource ( si->dpy, cmap,
327 "passwd.thermometer.background",
328 "Dialog.Thermometer.Background" );
329 pw->shadow_top = get_pixel_resource ( si->dpy, cmap,
330 "passwd.topShadowColor",
331 "Dialog.Foreground" );
332 pw->shadow_bottom = get_pixel_resource (si->dpy, cmap,
333 "passwd.bottomShadowColor",
334 "Dialog.Background" );
336 pw->logo_width = get_integer_resource (si->dpy, "passwd.logo.width",
337 "Dialog.Logo.Width");
338 pw->logo_height = get_integer_resource (si->dpy, "passwd.logo.height",
339 "Dialog.Logo.Height");
340 pw->thermo_width = get_integer_resource (si->dpy, "passwd.thermometer.width",
341 "Dialog.Thermometer.Width");
342 pw->internal_border = get_integer_resource (si->dpy, "passwd.internalBorderWidth",
343 "Dialog.InternalBorderWidth");
344 pw->shadow_width = get_integer_resource (si->dpy, "passwd.shadowThickness",
345 "Dialog.ShadowThickness");
347 if (pw->logo_width == 0) pw->logo_width = 150;
348 if (pw->logo_height == 0) pw->logo_height = 150;
349 if (pw->internal_border == 0) pw->internal_border = 15;
350 if (pw->shadow_width == 0) pw->shadow_width = 4;
351 if (pw->thermo_width == 0) pw->thermo_width = pw->shadow_width;
354 int direction, ascent, descent;
360 /* Measure the heading_label. */
361 XTextExtents (pw->heading_font,
362 pw->heading_label, strlen(pw->heading_label),
363 &direction, &ascent, &descent, &overall);
364 if (overall.width > pw->width) pw->width = overall.width;
365 pw->height += ascent + descent;
367 /* Measure the uname_label. */
368 if ((strlen(pw->uname_label)) && pw->show_uname_p)
370 XTextExtents (pw->uname_font,
371 pw->uname_label, strlen(pw->uname_label),
372 &direction, &ascent, &descent, &overall);
373 if (overall.width > pw->width) pw->width = overall.width;
374 pw->height += ascent + descent;
377 /* Measure the body_label. */
378 XTextExtents (pw->body_font,
379 pw->body_label, strlen(pw->body_label),
380 &direction, &ascent, &descent, &overall);
381 if (overall.width > pw->width) pw->width = overall.width;
382 pw->height += ascent + descent;
385 Dimension w2 = 0, w3 = 0, button_w = 0;
386 Dimension h2 = 0, h3 = 0, button_h = 0;
387 const char *passwd_string = "MMMMMMMMMMMM";
389 /* Measure the user_label. */
390 XTextExtents (pw->label_font,
391 pw->user_label, strlen(pw->user_label),
392 &direction, &ascent, &descent, &overall);
393 if (overall.width > w2) w2 = overall.width;
394 h2 += ascent + descent;
396 /* Measure the passwd_label. */
397 XTextExtents (pw->label_font,
398 pw->passwd_label, strlen(pw->passwd_label),
399 &direction, &ascent, &descent, &overall);
400 if (overall.width > w2) w2 = overall.width;
401 h2 += ascent + descent;
403 /* Measure the user_string. */
404 XTextExtents (pw->passwd_font,
405 pw->user_string, strlen(pw->user_string),
406 &direction, &ascent, &descent, &overall);
407 overall.width += (pw->shadow_width * 4);
408 ascent += (pw->shadow_width * 4);
409 if (overall.width > w3) w3 = overall.width;
410 h3 += ascent + descent;
412 /* Measure the (maximally-sized, dummy) passwd_string. */
413 XTextExtents (pw->passwd_font,
414 passwd_string, strlen(passwd_string),
415 &direction, &ascent, &descent, &overall);
416 overall.width += (pw->shadow_width * 4);
417 ascent += (pw->shadow_width * 4);
418 if (overall.width > w3) w3 = overall.width;
419 h3 += ascent + descent;
421 w2 = w2 + w3 + (pw->shadow_width * 2);
424 pw->login_button_width = 0;
425 pw->login_button_height = 0;
427 if (pw->login_button_p)
429 pw->login_button_enabled_p = True;
431 /* Measure the "New Login" button */
432 XTextExtents (pw->button_font, pw->login_label,
433 strlen (pw->login_label),
434 &direction, &ascent, &descent, &overall);
435 button_w = overall.width;
436 button_h = ascent + descent;
438 /* Add some horizontal padding inside the buttons. */
441 button_w += ((ascent + descent) / 2) + (pw->shadow_width * 2);
442 button_h += ((ascent + descent) / 2) + (pw->shadow_width * 2);
444 pw->login_button_width = button_w;
445 pw->login_button_height = button_h;
447 w2 = MAX (w2, button_w);
448 h2 += button_h * 1.5;
451 if (w2 > pw->width) pw->width = w2;
455 pw->width += (pw->internal_border * 2);
456 pw->height += (pw->internal_border * 4);
458 pw->width += pw->thermo_width + (pw->shadow_width * 3);
460 if (pw->logo_height > pw->height)
461 pw->height = pw->logo_height;
462 else if (pw->height > pw->logo_height)
463 pw->logo_height = pw->height;
465 pw->logo_width = pw->logo_height;
467 pw->width += pw->logo_width;
470 attrmask |= CWOverrideRedirect; attrs.override_redirect = True;
472 attrmask |= CWEventMask;
473 attrs.event_mask = (ExposureMask | KeyPressMask |
474 ButtonPressMask | ButtonReleaseMask);
476 /* We need to remember the mouse position and restore it afterward, or
477 sometimes (perhaps only with Xinerama?) the mouse gets warped to
478 inside the bounds of the lock dialog window.
481 Window pointer_root, pointer_child;
482 int root_x, root_y, win_x, win_y;
484 pw->previous_mouse_x = 0;
485 pw->previous_mouse_y = 0;
486 if (XQueryPointer (si->dpy, RootWindowOfScreen (pw->prompt_screen->screen),
487 &pointer_root, &pointer_child,
488 &root_x, &root_y, &win_x, &win_y, &mask))
490 pw->previous_mouse_x = root_x;
491 pw->previous_mouse_y = root_y;
492 if (si->prefs.verbose_p)
493 fprintf (stderr, "%s: %d: mouse is at %d,%d.\n",
494 blurb(), pw->prompt_screen->number,
495 pw->previous_mouse_x, pw->previous_mouse_y);
497 else if (si->prefs.verbose_p)
498 fprintf (stderr, "%s: %d: unable to determine mouse position?\n",
499 blurb(), pw->prompt_screen->number);
502 /* Figure out where on the desktop to place the window so that it will
503 actually be visible; this takes into account virtual viewports as
507 get_screen_viewport (pw->prompt_screen, &x, &y, &w, &h,
508 pw->previous_mouse_x, pw->previous_mouse_y,
509 si->prefs.verbose_p);
510 if (si->prefs.debug_p) w /= 2;
511 pw->x = x + ((w + pw->width) / 2) - pw->width;
512 pw->y = y + ((h + pw->height) / 2) - pw->height;
513 if (pw->x < x) pw->x = x;
514 if (pw->y < y) pw->y = y;
517 pw->border_width = get_integer_resource (si->dpy, "passwd.borderWidth",
518 "Dialog.BorderWidth");
521 XCreateWindow (si->dpy,
522 RootWindowOfScreen(screen),
523 pw->x, pw->y, pw->width, pw->height, pw->border_width,
524 DefaultDepthOfScreen (screen), InputOutput,
525 DefaultVisualOfScreen(screen),
527 XSetWindowBackground (si->dpy, si->passwd_dialog, pw->background);
529 /* We use the default visual, not ssi->visual, so that the logo pixmap's
530 visual matches that of the si->passwd_dialog window. */
531 pw->logo_pixmap = xscreensaver_logo (ssi->screen,
532 /* ssi->current_visual, */
533 DefaultVisualOfScreen(screen),
534 si->passwd_dialog, cmap,
536 &pw->logo_pixels, &pw->logo_npixels,
537 &pw->logo_clipmask, True);
539 /* Before mapping the window, save the bits that are underneath the
540 rectangle the window will occlude. When we lower the window, we
541 restore these bits. This works, because the running screenhack
542 has already been sent SIGSTOP, so we know nothing else is drawing
547 pw->save_under = XCreatePixmap (si->dpy,
548 pw->prompt_screen->screensaver_window,
549 pw->width + (pw->border_width*2) + 1,
550 pw->height + (pw->border_width*2) + 1,
551 pw->prompt_screen->current_depth);
552 gcv.function = GXcopy;
553 gc = XCreateGC (si->dpy, pw->save_under, GCFunction, &gcv);
554 XCopyArea (si->dpy, pw->prompt_screen->screensaver_window,
556 pw->x - pw->border_width, pw->y - pw->border_width,
557 pw->width + (pw->border_width*2) + 1,
558 pw->height + (pw->border_width*2) + 1,
560 XFreeGC (si->dpy, gc);
563 XMapRaised (si->dpy, si->passwd_dialog);
564 XSync (si->dpy, False);
566 move_mouse_grab (si, si->passwd_dialog,
569 : pw->prompt_screen->cursor),
570 pw->prompt_screen->number);
576 XInstallColormap (si->dpy, cmap);
577 draw_passwd_window (si);
578 XSync (si->dpy, False);
583 draw_passwd_window (saver_info *si)
585 passwd_dialog_data *pw = si->pw_data;
589 int x1, x2, x3, y1, y2;
593 height = (pw->heading_font->ascent + pw->heading_font->descent +
594 pw->body_font->ascent + pw->body_font->descent +
595 (2 * MAX ((pw->label_font->ascent + pw->label_font->descent),
596 (pw->passwd_font->ascent + pw->passwd_font->descent +
597 (pw->shadow_width * 4)))) +
598 pw->date_font->ascent + pw->date_font->descent);
600 if ((strlen(pw->uname_label)) && pw->show_uname_p)
601 height += (pw->uname_font->ascent + pw->uname_font->descent); /* for uname */
603 if (pw->login_button_p)
604 height += ((pw->button_font->ascent + pw->button_font->descent) * 2 +
605 2 * pw->shadow_width);
607 spacing = (((pw->height
608 - ((pw->login_button_p ? 4 : 2) * pw->shadow_width)
609 - pw->internal_border - height))
612 if (spacing < 0) spacing = 0;
614 gcv.foreground = pw->foreground;
615 gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
616 gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
617 x1 = pw->logo_width + pw->thermo_width + (pw->shadow_width * 3);
618 x3 = pw->width - (pw->shadow_width * 2);
619 y1 = (pw->shadow_width * 2) + spacing + spacing;
623 XSetFont (si->dpy, gc1, pw->heading_font->fid);
624 sw = string_width (pw->heading_font, pw->heading_label);
625 x2 = (x1 + ((x3 - x1 - sw) / 2));
626 y1 += spacing + pw->heading_font->ascent + pw->heading_font->descent;
627 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
628 pw->heading_label, strlen(pw->heading_label));
630 /* uname below top heading
632 if ((strlen(pw->uname_label)) && pw->show_uname_p)
634 XSetFont (si->dpy, gc1, pw->uname_font->fid);
635 y1 += spacing + pw->uname_font->ascent + pw->uname_font->descent;
636 sw = string_width (pw->uname_font, pw->uname_label);
637 x2 = (x1 + ((x3 - x1 - sw) / 2));
638 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
639 pw->uname_label, strlen(pw->uname_label));
644 XSetFont (si->dpy, gc1, pw->body_font->fid);
645 y1 += spacing + pw->body_font->ascent + pw->body_font->descent;
646 sw = string_width (pw->body_font, pw->body_label);
647 x2 = (x1 + ((x3 - x1 - sw) / 2));
648 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
649 pw->body_label, strlen(pw->body_label));
652 tb_height = (pw->passwd_font->ascent + pw->passwd_font->descent +
653 (pw->shadow_width * 4));
655 /* the "User:" prompt
659 XSetForeground (si->dpy, gc1, pw->foreground);
660 XSetFont (si->dpy, gc1, pw->label_font->fid);
661 y1 += (spacing + tb_height);
662 x2 = (x1 + pw->internal_border +
663 MAX(string_width (pw->label_font, pw->user_label),
664 string_width (pw->label_font, pw->passwd_label)));
665 XDrawString (si->dpy, si->passwd_dialog, gc1,
666 x2 - string_width (pw->label_font, pw->user_label),
667 y1 - pw->passwd_font->descent,
668 pw->user_label, strlen(pw->user_label));
670 /* the "Password:" prompt
672 y1 += (spacing + tb_height);
673 XDrawString (si->dpy, si->passwd_dialog, gc1,
674 x2 - string_width (pw->label_font, pw->passwd_label),
675 y1 - pw->passwd_font->descent,
676 pw->passwd_label, strlen(pw->passwd_label));
679 XSetForeground (si->dpy, gc2, pw->passwd_background);
681 /* the "user name" text field
684 XSetForeground (si->dpy, gc1, pw->passwd_foreground);
685 XSetFont (si->dpy, gc1, pw->passwd_font->fid);
686 y1 += (spacing + tb_height);
687 x2 += (pw->shadow_width * 4);
689 pw->passwd_field_width = x3 - x2 - pw->internal_border;
690 pw->passwd_field_height = (pw->passwd_font->ascent +
691 pw->passwd_font->descent +
694 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
695 x2 - pw->shadow_width,
696 y1 - (pw->passwd_font->ascent + pw->passwd_font->descent),
697 pw->passwd_field_width, pw->passwd_field_height);
698 XDrawString (si->dpy, si->passwd_dialog, gc1,
700 y1 - pw->passwd_font->descent,
701 pw->user_string, strlen(pw->user_string));
703 /* the "password" text field
705 y1 += (spacing + tb_height);
707 pw->passwd_field_x = x2 - pw->shadow_width;
708 pw->passwd_field_y = y1 - (pw->passwd_font->ascent +
709 pw->passwd_font->descent);
711 /* The shadow around the text fields
714 y1 += (spacing + (pw->shadow_width * 3));
715 x1 = x2 - (pw->shadow_width * 2);
716 x2 = pw->passwd_field_width + (pw->shadow_width * 2);
717 y2 = pw->passwd_field_height + (pw->shadow_width * 2);
719 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
722 pw->shadow_bottom, pw->shadow_top);
724 y1 += (spacing + pw->passwd_font->ascent + pw->passwd_font->descent +
725 (pw->shadow_width * 4));
726 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
729 pw->shadow_bottom, pw->shadow_top);
732 /* The date, below the text fields
736 time_t now = time ((time_t *) 0);
737 struct tm *tm = localtime (&now);
738 memset (buf, 0, sizeof(buf));
739 strftime (buf, sizeof(buf)-1, pw->date_label, tm);
741 XSetFont (si->dpy, gc1, pw->date_font->fid);
742 y1 += pw->shadow_width;
743 y1 += (spacing + tb_height);
745 sw = string_width (pw->date_font, buf);
747 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1, buf, strlen(buf));
750 /* The "New Login" button
752 if (pw->login_button_p)
754 XSetForeground (si->dpy, gc1, pw->button_foreground);
755 XSetForeground (si->dpy, gc2, pw->button_background);
756 XSetFont (si->dpy, gc1, pw->button_font->fid);
758 sw = string_width (pw->button_font, pw->login_label);
760 x2 = pw->width - pw->internal_border - (pw->shadow_width * 2);
762 /* right aligned button */
763 /* x1 = x2 - pw->login_button_width; */
765 /* centered button */
766 x1 = (pw->logo_width + pw->thermo_width + (pw->shadow_width * 3) +
767 pw->internal_border);
768 x1 = x1 + (x2 - x1 - pw->login_button_width) / 2;
770 y1 = (pw->height - pw->internal_border - pw->login_button_height +
773 ((pw->login_button_height -
774 (pw->button_font->ascent + pw->button_font->descent))
776 pw->button_font->ascent);
778 pw->login_button_x = x1;
779 pw->login_button_y = y1;
784 x1 = pw->shadow_width * 6;
785 y1 = pw->shadow_width * 6;
786 x2 = pw->logo_width - (pw->shadow_width * 12);
787 y2 = pw->logo_height - (pw->shadow_width * 12);
793 unsigned int w, h, bw, d;
794 XGetGeometry (si->dpy, pw->logo_pixmap, &root, &x, &y, &w, &h, &bw, &d);
795 XSetForeground (si->dpy, gc1, pw->foreground);
796 XSetBackground (si->dpy, gc1, pw->background);
797 XSetClipMask (si->dpy, gc1, pw->logo_clipmask);
798 XSetClipOrigin (si->dpy, gc1, x1 + ((x2 - (int)w) / 2), y1 + ((y2 - (int)h) / 2));
800 XCopyPlane (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1,
802 x1 + ((x2 - (int)w) / 2),
803 y1 + ((y2 - (int)h) / 2),
806 XCopyArea (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1,
808 x1 + ((x2 - (int)w) / 2),
809 y1 + ((y2 - (int)h) / 2));
814 XSetForeground (si->dpy, gc1, pw->thermo_foreground);
815 XSetForeground (si->dpy, gc2, pw->thermo_background);
817 pw->thermo_field_x = pw->logo_width + pw->shadow_width;
818 pw->thermo_field_y = pw->shadow_width * 5;
819 pw->thermo_field_height = pw->height - (pw->shadow_width * 10);
822 /* Solid border inside the logo box. */
823 XSetForeground (si->dpy, gc1, pw->foreground);
824 XDrawRectangle (si->dpy, si->passwd_dialog, gc1, x1, y1, x2-1, y2-1);
827 /* The shadow around the logo
829 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
830 pw->shadow_width * 4,
831 pw->shadow_width * 4,
832 pw->logo_width - (pw->shadow_width * 8),
833 pw->logo_height - (pw->shadow_width * 8),
835 pw->shadow_bottom, pw->shadow_top);
837 /* The shadow around the thermometer
839 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
841 pw->shadow_width * 4,
842 pw->thermo_width + (pw->shadow_width * 2),
843 pw->height - (pw->shadow_width * 8),
845 pw->shadow_bottom, pw->shadow_top);
848 /* Solid border inside the thermometer. */
849 XSetForeground (si->dpy, gc1, pw->foreground);
850 XDrawRectangle (si->dpy, si->passwd_dialog, gc1,
851 pw->thermo_field_x, pw->thermo_field_y,
852 pw->thermo_width - 1, pw->thermo_field_height - 1);
855 /* The shadow around the whole window
857 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
858 0, 0, pw->width, pw->height, pw->shadow_width,
859 pw->shadow_top, pw->shadow_bottom);
861 XFreeGC (si->dpy, gc1);
862 XFreeGC (si->dpy, gc2);
864 update_passwd_window (si, pw->passwd_string, pw->ratio);
869 update_passwd_window (saver_info *si, const char *printed_passwd, float ratio)
871 passwd_dialog_data *pw = si->pw_data;
878 gcv.foreground = pw->passwd_foreground;
879 gcv.font = pw->passwd_font->fid;
880 gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground|GCFont, &gcv);
881 gcv.foreground = pw->passwd_background;
882 gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
886 char *s = strdup (printed_passwd);
887 if (pw->passwd_string) free (pw->passwd_string);
888 pw->passwd_string = s;
891 /* the "password" text field
893 rects[0].x = pw->passwd_field_x;
894 rects[0].y = pw->passwd_field_y;
895 rects[0].width = pw->passwd_field_width;
896 rects[0].height = pw->passwd_field_height;
898 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
899 rects[0].x, rects[0].y, rects[0].width, rects[0].height);
901 XSetClipRectangles (si->dpy, gc1, 0, 0, rects, 1, Unsorted);
903 XDrawString (si->dpy, si->passwd_dialog, gc1,
904 rects[0].x + pw->shadow_width,
905 rects[0].y + pw->passwd_font->ascent,
906 pw->passwd_string, strlen(pw->passwd_string));
908 XSetClipMask (si->dpy, gc1, None);
914 x = (rects[0].x + pw->shadow_width +
915 string_width (pw->passwd_font, pw->passwd_string));
916 y = rects[0].y + pw->shadow_width;
918 if (x > rects[0].x + rects[0].width - 1)
919 x = rects[0].x + rects[0].width - 1;
920 XDrawLine (si->dpy, si->passwd_dialog, gc1,
922 x, y + pw->passwd_font->ascent + pw->passwd_font->descent-1);
925 pw->i_beam = (pw->i_beam + 1) % 4;
930 y = (pw->thermo_field_height - 2) * (1.0 - pw->ratio);
933 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
934 pw->thermo_field_x + 1,
935 pw->thermo_field_y + 1,
938 XSetForeground (si->dpy, gc1, pw->thermo_foreground);
939 XFillRectangle (si->dpy, si->passwd_dialog, gc1,
940 pw->thermo_field_x + 1,
941 pw->thermo_field_y + 1 + y,
943 MAX (0, pw->thermo_field_height - y - 2));
946 /* The "New Login" button
948 if (pw->login_button_p)
951 XSetFont (si->dpy, gc1, pw->button_font->fid);
952 XSetForeground (si->dpy, gc1,
953 (pw->login_button_enabled_p
954 ? pw->passwd_foreground
955 : pw->shadow_bottom));
956 XSetForeground (si->dpy, gc2, pw->button_background);
958 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
959 pw->login_button_x, pw->login_button_y,
960 pw->login_button_width, pw->login_button_height);
962 sw = string_width (pw->button_font, pw->login_label);
963 x2 = pw->login_button_x + ((pw->login_button_width - sw) / 2);
964 y2 = (pw->login_button_y +
965 ((pw->login_button_height -
966 (pw->button_font->ascent + pw->button_font->descent))
968 pw->button_font->ascent);
970 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y2,
971 pw->login_label, strlen(pw->login_label));
973 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
974 pw->login_button_x, pw->login_button_y,
975 pw->login_button_width, pw->login_button_height,
977 (pw->login_button_down_p
980 (pw->login_button_down_p
982 : pw->shadow_bottom));
985 XFreeGC (si->dpy, gc1);
986 XFreeGC (si->dpy, gc2);
987 XSync (si->dpy, False);
992 destroy_passwd_window (saver_info *si)
994 saver_preferences *p = &si->prefs;
995 passwd_dialog_data *pw = si->pw_data;
996 saver_screen_info *ssi = pw->prompt_screen;
997 Colormap cmap = DefaultColormapOfScreen (ssi->screen);
998 Pixel black = BlackPixelOfScreen (ssi->screen);
999 Pixel white = WhitePixelOfScreen (ssi->screen);
1002 memset (pw->typed_passwd, 0, sizeof(pw->typed_passwd));
1003 memset (pw->passwd_string, 0, strlen(pw->passwd_string));
1006 XtRemoveTimeOut (pw->timer);
1008 move_mouse_grab (si, RootWindowOfScreen (ssi->screen),
1009 ssi->cursor, ssi->number);
1011 if (pw->passwd_cursor)
1012 XFreeCursor (si->dpy, pw->passwd_cursor);
1015 fprintf (stderr, "%s: %d: moving mouse back to %d,%d.\n",
1016 blurb(), ssi->number,
1017 pw->previous_mouse_x, pw->previous_mouse_y);
1019 XWarpPointer (si->dpy, None, RootWindowOfScreen (ssi->screen),
1021 pw->previous_mouse_x, pw->previous_mouse_y);
1023 XSync (si->dpy, False);
1024 while (XCheckMaskEvent (si->dpy, PointerMotionMask, &event))
1026 fprintf (stderr, "%s: discarding MotionNotify event.\n", blurb());
1028 if (si->passwd_dialog)
1030 XDestroyWindow (si->dpy, si->passwd_dialog);
1031 si->passwd_dialog = 0;
1038 gcv.function = GXcopy;
1039 gc = XCreateGC (si->dpy, ssi->screensaver_window, GCFunction, &gcv);
1040 XCopyArea (si->dpy, pw->save_under,
1041 ssi->screensaver_window, gc,
1043 pw->width + (pw->border_width*2) + 1,
1044 pw->height + (pw->border_width*2) + 1,
1045 pw->x - pw->border_width, pw->y - pw->border_width);
1046 XFreePixmap (si->dpy, pw->save_under);
1048 XFreeGC (si->dpy, gc);
1051 if (pw->heading_label) free (pw->heading_label);
1052 if (pw->body_label) free (pw->body_label);
1053 if (pw->user_label) free (pw->user_label);
1054 if (pw->passwd_label) free (pw->passwd_label);
1055 if (pw->date_label) free (pw->date_label);
1056 if (pw->login_label) free (pw->login_label);
1057 if (pw->user_string) free (pw->user_string);
1058 if (pw->passwd_string) free (pw->passwd_string);
1059 if (pw->uname_label) free (pw->uname_label);
1061 if (pw->heading_font) XFreeFont (si->dpy, pw->heading_font);
1062 if (pw->body_font) XFreeFont (si->dpy, pw->body_font);
1063 if (pw->label_font) XFreeFont (si->dpy, pw->label_font);
1064 if (pw->passwd_font) XFreeFont (si->dpy, pw->passwd_font);
1065 if (pw->date_font) XFreeFont (si->dpy, pw->date_font);
1066 if (pw->button_font) XFreeFont (si->dpy, pw->button_font);
1067 if (pw->uname_font) XFreeFont (si->dpy, pw->uname_font);
1069 if (pw->foreground != black && pw->foreground != white)
1070 XFreeColors (si->dpy, cmap, &pw->foreground, 1, 0L);
1071 if (pw->background != black && pw->background != white)
1072 XFreeColors (si->dpy, cmap, &pw->background, 1, 0L);
1073 if (!(pw->button_foreground == black || pw->button_foreground == white))
1074 XFreeColors (si->dpy, cmap, &pw->button_foreground, 1, 0L);
1075 if (!(pw->button_background == black || pw->button_background == white))
1076 XFreeColors (si->dpy, cmap, &pw->button_background, 1, 0L);
1077 if (pw->passwd_foreground != black && pw->passwd_foreground != white)
1078 XFreeColors (si->dpy, cmap, &pw->passwd_foreground, 1, 0L);
1079 if (pw->passwd_background != black && pw->passwd_background != white)
1080 XFreeColors (si->dpy, cmap, &pw->passwd_background, 1, 0L);
1081 if (pw->thermo_foreground != black && pw->thermo_foreground != white)
1082 XFreeColors (si->dpy, cmap, &pw->thermo_foreground, 1, 0L);
1083 if (pw->thermo_background != black && pw->thermo_background != white)
1084 XFreeColors (si->dpy, cmap, &pw->thermo_background, 1, 0L);
1085 if (pw->shadow_top != black && pw->shadow_top != white)
1086 XFreeColors (si->dpy, cmap, &pw->shadow_top, 1, 0L);
1087 if (pw->shadow_bottom != black && pw->shadow_bottom != white)
1088 XFreeColors (si->dpy, cmap, &pw->shadow_bottom, 1, 0L);
1090 if (pw->logo_pixmap)
1091 XFreePixmap (si->dpy, pw->logo_pixmap);
1092 if (pw-> logo_clipmask)
1093 XFreePixmap (si->dpy, pw->logo_clipmask);
1094 if (pw->logo_pixels)
1096 if (pw->logo_npixels)
1097 XFreeColors (si->dpy, cmap, pw->logo_pixels, pw->logo_npixels, 0L);
1098 free (pw->logo_pixels);
1099 pw->logo_pixels = 0;
1100 pw->logo_npixels = 0;
1104 XFreePixmap (si->dpy, pw->save_under);
1107 XInstallColormap (si->dpy, cmap);
1109 memset (pw, 0, sizeof(*pw));
1115 static Bool error_handler_hit_p = False;
1118 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1120 error_handler_hit_p = True;
1125 #ifdef HAVE_XHPDISABLERESET
1126 /* This function enables and disables the C-Sh-Reset hot-key, which
1127 normally resets the X server (logging out the logged-in user.)
1128 We don't want random people to be able to do that while the
1132 hp_lock_reset (saver_info *si, Bool lock_p)
1134 static Bool hp_locked_p = False;
1136 /* Calls to XHPDisableReset and XHPEnableReset must be balanced,
1137 or BadAccess errors occur. (It's ok for this to be global,
1138 since it affects the whole machine, not just the current screen.)
1140 if (hp_locked_p == lock_p)
1144 XHPDisableReset (si->dpy);
1146 XHPEnableReset (si->dpy);
1147 hp_locked_p = lock_p;
1149 #endif /* HAVE_XHPDISABLERESET */
1152 #ifdef HAVE_XF86MISCSETGRABKEYSSTATE
1154 /* This function enables and disables the Ctrl-Alt-KP_star and
1155 Ctrl-Alt-KP_slash hot-keys, which (in XFree86 4.2) break any
1156 grabs and/or kill the grabbing client. That would effectively
1157 unlock the screen, so we don't like that.
1159 The Ctrl-Alt-KP_star and Ctrl-Alt-KP_slash hot-keys only exist
1160 if AllowDeactivateGrabs and/or AllowClosedownGrabs are turned on
1161 in XF86Config. I believe they are disabled by default.
1163 This does not affect any other keys (specifically Ctrl-Alt-BS or
1164 Ctrl-Alt-F1) but I wish it did. Maybe it will someday.
1167 xfree_lock_grab_smasher (saver_info *si, Bool lock_p)
1169 saver_preferences *p = &si->prefs;
1172 XErrorHandler old_handler;
1173 XSync (si->dpy, False);
1174 error_handler_hit_p = False;
1175 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1176 XSync (si->dpy, False);
1177 status = XF86MiscSetGrabKeysState (si->dpy, !lock_p);
1178 XSync (si->dpy, False);
1179 if (error_handler_hit_p) status = 666;
1181 if (!lock_p && status == MiscExtGrabStateAlready)
1182 status = MiscExtGrabStateSuccess; /* shut up, consider this success */
1184 if (p->verbose_p && status != MiscExtGrabStateSuccess)
1185 fprintf (stderr, "%s: error: XF86MiscSetGrabKeysState(%d) returned %s\n",
1187 (status == MiscExtGrabStateSuccess ? "MiscExtGrabStateSuccess" :
1188 status == MiscExtGrabStateLocked ? "MiscExtGrabStateLocked" :
1189 status == MiscExtGrabStateAlready ? "MiscExtGrabStateAlready" :
1190 status == 666 ? "an X error" :
1193 XSync (si->dpy, False);
1194 XSetErrorHandler (old_handler);
1195 XSync (si->dpy, False);
1197 #endif /* HAVE_XF86MISCSETGRABKEYSSTATE */
1201 /* This function enables and disables the C-Alt-Plus and C-Alt-Minus
1202 hot-keys, which normally change the resolution of the X server.
1203 We don't want people to be able to switch the server resolution
1204 while the screen is locked, because if they switch to a higher
1205 resolution, it could cause part of the underlying desktop to become
1208 #ifdef HAVE_XF86VMODE
1211 xfree_lock_mode_switch (saver_info *si, Bool lock_p)
1213 static Bool any_mode_locked_p = False;
1214 saver_preferences *p = &si->prefs;
1218 XErrorHandler old_handler;
1220 if (any_mode_locked_p == lock_p)
1222 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1225 for (screen = 0; screen < (si->xinerama_p ? 1 : si->nscreens); screen++)
1227 XSync (si->dpy, False);
1228 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1229 error_handler_hit_p = False;
1230 status = XF86VidModeLockModeSwitch (si->dpy, screen, lock_p);
1231 XSync (si->dpy, False);
1232 XSetErrorHandler (old_handler);
1233 if (error_handler_hit_p) status = False;
1236 any_mode_locked_p = lock_p;
1238 if (!status && (p->verbose_p || !lock_p))
1239 /* Only print this when verbose, or when we locked but can't unlock.
1240 I tried printing this message whenever it comes up, but
1241 mode-locking always fails if DontZoom is set in XF86Config. */
1242 fprintf (stderr, "%s: %d: unable to %s mode switching!\n",
1243 blurb(), screen, (lock_p ? "lock" : "unlock"));
1244 else if (p->verbose_p)
1245 fprintf (stderr, "%s: %d: %s mode switching.\n",
1246 blurb(), screen, (lock_p ? "locked" : "unlocked"));
1249 #endif /* HAVE_XF86VMODE */
1252 /* If the viewport has been scrolled since the screen was blanked,
1253 then scroll it back to where it belongs. This function only exists
1254 to patch over a very brief race condition.
1257 undo_vp_motion (saver_info *si)
1259 #ifdef HAVE_XF86VMODE
1260 saver_preferences *p = &si->prefs;
1264 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1267 for (screen = 0; screen < si->nscreens; screen++)
1269 saver_screen_info *ssi = &si->screens[screen];
1273 if (ssi->blank_vp_x == -1 && ssi->blank_vp_y == -1)
1275 if (!XF86VidModeGetViewPort (si->dpy, screen, &x, &y))
1277 if (ssi->blank_vp_x == x && ssi->blank_vp_y == y)
1280 /* We're going to move the viewport. The mouse has just been grabbed on
1281 (and constrained to, thus warped to) the password window, so it is no
1282 longer near the edge of the screen. However, wait a bit anyway, just
1283 to make sure the server drains its last motion event, so that the
1284 screen doesn't continue to scroll after we've reset the viewport.
1286 XSync (si->dpy, False);
1287 usleep (250000); /* 1/4 second */
1288 XSync (si->dpy, False);
1290 status = XF86VidModeSetViewPort (si->dpy, screen,
1291 ssi->blank_vp_x, ssi->blank_vp_y);
1295 "%s: %d: unable to move vp from (%d,%d) back to (%d,%d)!\n",
1296 blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1297 else if (p->verbose_p)
1299 "%s: %d: vp moved to (%d,%d); moved it back to (%d,%d).\n",
1300 blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1302 #endif /* HAVE_XF86VMODE */
1311 passwd_animate_timer (XtPointer closure, XtIntervalId *id)
1313 saver_info *si = (saver_info *) closure;
1315 passwd_dialog_data *pw = si->pw_data;
1319 pw->ratio -= (1.0 / ((double) si->prefs.passwd_timeout / (double) tick));
1323 if (pw->state == pw_read)
1324 pw->state = pw_time;
1327 update_passwd_window (si, 0, pw->ratio);
1329 if (pw->state == pw_read)
1330 pw->timer = XtAppAddTimeOut (si->app, tick, passwd_animate_timer,
1335 idle_timer ((XtPointer) si, 0);
1339 static XComposeStatus *compose_status;
1342 handle_passwd_button (saver_info *si, XEvent *event)
1344 saver_preferences *p = &si->prefs;
1345 Bool mouse_in_box = False;
1347 passwd_dialog_data *pw = si->pw_data;
1348 saver_screen_info *ssi = pw->prompt_screen;
1350 if (! pw->login_button_enabled_p)
1354 (event->xbutton.x >= pw->login_button_x &&
1355 event->xbutton.x <= pw->login_button_x + pw->login_button_width &&
1356 event->xbutton.y >= pw->login_button_y &&
1357 event->xbutton.y <= pw->login_button_y + pw->login_button_height);
1359 if (ButtonRelease == event->xany.type &&
1360 pw->login_button_down_p &&
1363 /* Only allow them to press the button once: don't want to
1364 accidentally launch a dozen gdm choosers if the machine
1368 pw->login_button_enabled_p = False;
1371 pw->login_button_down_p = (mouse_in_box &&
1372 ButtonRelease != event->xany.type);
1374 update_passwd_window (si, 0, pw->ratio);
1377 fork_and_exec (ssi, p->new_login_command);
1382 handle_passwd_key (saver_info *si, XKeyEvent *event)
1384 saver_preferences *p = &si->prefs;
1385 passwd_dialog_data *pw = si->pw_data;
1386 int pw_size = sizeof (pw->typed_passwd) - 1;
1387 char *typed_passwd = pw->typed_passwd;
1391 int size = XLookupString (event, s, 1, 0, compose_status);
1393 if (size != 1) return;
1397 /* Add 10% to the time remaining every time a key is pressed. */
1399 if (pw->ratio > 1) pw->ratio = 1;
1403 case '\010': case '\177': /* Backspace */
1407 typed_passwd [strlen(typed_passwd)-1] = 0;
1410 case '\025': case '\030': /* Erase line */
1411 memset (typed_passwd, 0, pw_size);
1414 case '\012': case '\015': /* Enter */
1415 if (pw->state != pw_read)
1416 ; /* already done? */
1417 else if (typed_passwd[0] == 0)
1418 pw->state = pw_null;
1421 update_passwd_window (si, "Checking...", pw->ratio);
1422 XSync (si->dpy, False);
1423 if (passwd_valid_p (typed_passwd, p->verbose_p))
1426 pw->state = pw_fail;
1427 update_passwd_window (si, "", pw->ratio);
1432 /* Though technically the only illegal characters in Unix passwords
1433 are LF and NUL, most GUI programs (e.g., GDM) use regular text-entry
1434 fields that only let you type printable characters. So, people
1435 who use funky characters in their passwords are already broken.
1436 We follow that precedent.
1438 if (isprint ((unsigned char) *s))
1440 i = strlen (typed_passwd);
1445 typed_passwd [i] = *s;
1446 typed_passwd [i+1] = 0;
1454 if (pw->show_stars_p)
1456 i = strlen(typed_passwd);
1457 stars = (char *) malloc(i+1);
1458 memset (stars, '*', i);
1460 update_passwd_window (si, stars, pw->ratio);
1465 update_passwd_window (si, "", pw->ratio);
1471 passwd_event_loop (saver_info *si)
1473 saver_preferences *p = &si->prefs;
1476 unsigned int caps_p = 0;
1478 passwd_animate_timer ((XtPointer) si, 0);
1480 while (si->pw_data && si->pw_data->state == pw_read)
1482 XtAppNextEvent (si->app, &event);
1483 if (event.xany.window == si->passwd_dialog && event.xany.type == Expose)
1484 draw_passwd_window (si);
1485 else if (event.xany.type == KeyPress)
1487 handle_passwd_key (si, &event.xkey);
1488 caps_p = (event.xkey.state & LockMask);
1490 else if ((event.xany.type == ButtonPress ||
1491 event.xany.type == ButtonRelease) &&
1492 si->pw_data->login_button_p)
1493 handle_passwd_button (si, &event);
1495 XtDispatchEvent (&event);
1498 switch (si->pw_data->state)
1500 case pw_ok: msg = 0; break;
1501 case pw_null: msg = ""; break;
1502 case pw_time: msg = "Timed out!"; break;
1503 default: msg = (caps_p ? "CapsLock?" : "Sorry!"); break;
1506 if (si->pw_data->state == pw_fail)
1507 si->unlock_failures++;
1510 switch (si->pw_data->state)
1513 fprintf (stderr, "%s: password correct.\n", blurb()); break;
1515 fprintf (stderr, "%s: password incorrect!%s\n", blurb(),
1516 (caps_p ? " (CapsLock)" : ""));
1520 fprintf (stderr, "%s: password entry cancelled.\n", blurb()); break;
1522 fprintf (stderr, "%s: password entry timed out.\n", blurb()); break;
1527 if (si->pw_data->state == pw_fail)
1529 /* If they typed a password (as opposed to just hitting return) and
1530 the password was invalid, log it.
1532 struct passwd *pw = getpwuid (getuid ());
1533 char *d = DisplayString (si->dpy);
1534 char *u = (pw->pw_name ? pw->pw_name : "???");
1542 # if defined(LOG_AUTHPRIV)
1544 # elif defined(LOG_AUTH)
1551 openlog (progname, opt, fac);
1552 syslog (LOG_NOTICE, "FAILED LOGIN %d ON DISPLAY \"%s\", FOR \"%s\"",
1553 si->unlock_failures, d, u);
1556 #endif /* HAVE_SYSLOG */
1558 if (si->pw_data->state == pw_fail)
1559 XBell (si->dpy, False);
1561 if (si->pw_data->state == pw_ok && si->unlock_failures != 0)
1563 if (si->unlock_failures == 1)
1564 fprintf (real_stderr,
1565 "%s: WARNING: 1 failed attempt to unlock the screen.\n",
1568 fprintf (real_stderr,
1569 "%s: WARNING: %d failed attempts to unlock the screen.\n",
1570 blurb(), si->unlock_failures);
1571 fflush (real_stderr);
1573 si->unlock_failures = 0;
1578 si->pw_data->i_beam = 0;
1579 update_passwd_window (si, msg, 0.0);
1580 XSync (si->dpy, False);
1583 /* Swallow all pending KeyPress/KeyRelease events. */
1586 while (XCheckMaskEvent (si->dpy, KeyPressMask|KeyReleaseMask, &e))
1594 handle_typeahead (saver_info *si)
1596 passwd_dialog_data *pw = si->pw_data;
1598 if (!si->unlock_typeahead)
1601 i = strlen (si->unlock_typeahead);
1602 if (i >= sizeof(pw->typed_passwd) - 1)
1603 i = sizeof(pw->typed_passwd) - 1;
1605 memcpy (pw->typed_passwd, si->unlock_typeahead, i);
1606 pw->typed_passwd [i] = 0;
1608 memset (si->unlock_typeahead, '*', strlen(si->unlock_typeahead));
1609 si->unlock_typeahead[i] = 0;
1610 update_passwd_window (si, si->unlock_typeahead, pw->ratio);
1612 free (si->unlock_typeahead);
1613 si->unlock_typeahead = 0;
1618 unlock_p (saver_info *si)
1620 saver_preferences *p = &si->prefs;
1623 raise_window (si, True, True, True);
1626 fprintf (stderr, "%s: prompting for password.\n", blurb());
1628 if (si->pw_data || si->passwd_dialog)
1629 destroy_passwd_window (si);
1631 make_passwd_window (si);
1633 compose_status = calloc (1, sizeof (*compose_status));
1635 handle_typeahead (si);
1636 passwd_event_loop (si);
1638 status = (si->pw_data->state == pw_ok);
1639 destroy_passwd_window (si);
1641 free (compose_status);
1649 set_locked_p (saver_info *si, Bool locked_p)
1651 si->locked_p = locked_p;
1653 #ifdef HAVE_XHPDISABLERESET
1654 hp_lock_reset (si, locked_p); /* turn off/on C-Sh-Reset */
1656 #ifdef HAVE_XF86VMODE
1657 xfree_lock_mode_switch (si, locked_p); /* turn off/on C-Alt-Plus */
1659 #ifdef HAVE_XF86MISCSETGRABKEYSSTATE
1660 xfree_lock_grab_smasher (si, locked_p); /* turn off/on C-Alt-KP-*,/ */
1663 store_saver_status (si); /* store locked-p */
1667 #else /* NO_LOCKING -- whole file */
1670 set_locked_p (saver_info *si, Bool locked_p)
1672 if (locked_p) abort();
1675 #endif /* !NO_LOCKING */