1 /* lock.c --- handling the password dialog for locking-mode.
2 * xscreensaver, Copyright (c) 1993-2004 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. */
20 #include <X11/Intrinsic.h>
21 #include <X11/Xos.h> /* for time() */
24 #include "xscreensaver.h"
25 #include "resources.h"
27 #ifndef NO_LOCKING /* (mostly) whole file */
31 #endif /* HAVE_SYSLOG */
33 #ifdef HAVE_XHPDISABLERESET
34 # include <X11/XHPlib.h>
35 static void hp_lock_reset (saver_info *si, Bool lock_p);
36 #endif /* HAVE_XHPDISABLERESET */
38 #ifdef HAVE_VT_LOCKSWITCH
40 # include <sys/ioctl.h>
42 static void linux_lock_vt_switch (saver_info *si, Bool lock_p);
43 #endif /* HAVE_VT_LOCKSWITCH */
46 # include <X11/extensions/xf86vmode.h>
47 static void xfree_lock_mode_switch (saver_info *si, Bool lock_p);
48 #endif /* HAVE_XF86VMODE */
50 #ifdef HAVE_XF86MISCSETGRABKEYSSTATE
51 # include <X11/extensions/xf86misc.h>
52 static void xfree_lock_grab_smasher (saver_info *si, Bool lock_p);
53 #endif /* HAVE_XF86MISCSETGRABKEYSSTATE */
57 ERROR! You must not include vroot.h in this file.
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;
107 XFontStruct *heading_font;
108 XFontStruct *body_font;
109 XFontStruct *label_font;
110 XFontStruct *passwd_font;
111 XFontStruct *date_font;
115 Pixel passwd_foreground;
116 Pixel passwd_background;
117 Pixel thermo_foreground;
118 Pixel thermo_background;
122 Dimension logo_width;
123 Dimension logo_height;
124 Dimension thermo_width;
125 Dimension internal_border;
126 Dimension shadow_width;
128 Dimension passwd_field_x, passwd_field_y;
129 Dimension passwd_field_width, passwd_field_height;
131 Dimension thermo_field_x, thermo_field_y;
132 Dimension thermo_field_height;
136 unsigned long *logo_pixels;
141 static void draw_passwd_window (saver_info *si);
142 static void update_passwd_window (saver_info *si, const char *printed_passwd,
144 static void destroy_passwd_window (saver_info *si);
145 static void undo_vp_motion (saver_info *si);
149 make_passwd_window (saver_info *si)
151 struct passwd *p = getpwuid (getuid ());
152 XSetWindowAttributes attrs;
153 unsigned long attrmask = 0;
154 passwd_dialog_data *pw = (passwd_dialog_data *) calloc (1, sizeof(*pw));
158 saver_screen_info *ssi = &si->screens [mouse_screen (si)];
160 pw->prompt_screen = ssi;
161 if (si->prefs.verbose_p)
162 fprintf (stderr, "%s: %d: creating password dialog.\n",
163 blurb(), pw->prompt_screen->number);
165 screen = pw->prompt_screen->screen;
166 cmap = DefaultColormapOfScreen (screen);
170 pw->heading_label = get_string_resource ("passwd.heading.label",
171 "Dialog.Label.Label");
172 pw->body_label = get_string_resource ("passwd.body.label",
173 "Dialog.Label.Label");
174 pw->user_label = get_string_resource ("passwd.user.label",
175 "Dialog.Label.Label");
176 pw->passwd_label = get_string_resource ("passwd.passwd.label",
177 "Dialog.Label.Label");
178 pw->date_label = get_string_resource ("dateFormat", "DateFormat");
180 if (!pw->heading_label)
181 pw->heading_label = strdup("ERROR: REESOURCES NOT INSTALLED CORRECTLY");
183 pw->body_label = strdup("ERROR: REESOURCES NOT INSTALLED CORRECTLY");
184 if (!pw->user_label) pw->user_label = strdup("ERROR");
185 if (!pw->passwd_label) pw->passwd_label = strdup("ERROR");
186 if (!pw->date_label) pw->date_label = strdup("ERROR");
188 /* Put the version number in the label. */
190 char *s = (char *) malloc (strlen(pw->heading_label) + 20);
191 sprintf(s, pw->heading_label, si->version);
192 free (pw->heading_label);
193 pw->heading_label = s;
196 pw->user_string = strdup (p && p->pw_name ? p->pw_name : "???");
197 pw->passwd_string = strdup("");
199 f = get_string_resource ("passwd.headingFont", "Dialog.Font");
200 pw->heading_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
201 if (!pw->heading_font) pw->heading_font = XLoadQueryFont (si->dpy, "fixed");
204 f = get_string_resource("passwd.bodyFont", "Dialog.Font");
205 pw->body_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
206 if (!pw->body_font) pw->body_font = XLoadQueryFont (si->dpy, "fixed");
209 f = get_string_resource("passwd.labelFont", "Dialog.Font");
210 pw->label_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
211 if (!pw->label_font) pw->label_font = XLoadQueryFont (si->dpy, "fixed");
214 f = get_string_resource("passwd.passwdFont", "Dialog.Font");
215 pw->passwd_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
216 if (!pw->passwd_font) pw->passwd_font = XLoadQueryFont (si->dpy, "fixed");
219 f = get_string_resource("passwd.dateFont", "Dialog.Font");
220 pw->date_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
221 if (!pw->date_font) pw->date_font = XLoadQueryFont (si->dpy, "fixed");
224 pw->foreground = get_pixel_resource ("passwd.foreground",
227 pw->background = get_pixel_resource ("passwd.background",
231 if (pw->foreground == pw->background)
233 /* Make sure the error messages show up. */
234 pw->foreground = BlackPixelOfScreen (screen);
235 pw->background = WhitePixelOfScreen (screen);
238 pw->passwd_foreground = get_pixel_resource ("passwd.text.foreground",
239 "Dialog.Text.Foreground",
241 pw->passwd_background = get_pixel_resource ("passwd.text.background",
242 "Dialog.Text.Background",
244 pw->thermo_foreground = get_pixel_resource ("passwd.thermometer.foreground",
245 "Dialog.Thermometer.Foreground",
247 pw->thermo_background = get_pixel_resource ("passwd.thermometer.background",
248 "Dialog.Thermometer.Background",
250 pw->shadow_top = get_pixel_resource ("passwd.topShadowColor",
253 pw->shadow_bottom = get_pixel_resource ("passwd.bottomShadowColor",
257 pw->logo_width = get_integer_resource ("passwd.logo.width",
258 "Dialog.Logo.Width");
259 pw->logo_height = get_integer_resource ("passwd.logo.height",
260 "Dialog.Logo.Height");
261 pw->thermo_width = get_integer_resource ("passwd.thermometer.width",
262 "Dialog.Thermometer.Width");
263 pw->internal_border = get_integer_resource ("passwd.internalBorderWidth",
264 "Dialog.InternalBorderWidth");
265 pw->shadow_width = get_integer_resource ("passwd.shadowThickness",
266 "Dialog.ShadowThickness");
268 if (pw->logo_width == 0) pw->logo_width = 150;
269 if (pw->logo_height == 0) pw->logo_height = 150;
270 if (pw->internal_border == 0) pw->internal_border = 15;
271 if (pw->shadow_width == 0) pw->shadow_width = 4;
272 if (pw->thermo_width == 0) pw->thermo_width = pw->shadow_width;
275 int direction, ascent, descent;
281 /* Measure the heading_label. */
282 XTextExtents (pw->heading_font,
283 pw->heading_label, strlen(pw->heading_label),
284 &direction, &ascent, &descent, &overall);
285 if (overall.width > pw->width) pw->width = overall.width;
286 pw->height += ascent + descent;
288 /* Measure the body_label. */
289 XTextExtents (pw->body_font,
290 pw->body_label, strlen(pw->body_label),
291 &direction, &ascent, &descent, &overall);
292 if (overall.width > pw->width) pw->width = overall.width;
293 pw->height += ascent + descent;
296 Dimension w2 = 0, w3 = 0;
297 Dimension h2 = 0, h3 = 0;
298 const char *passwd_string = "MMMMMMMMMMMM";
300 /* Measure the user_label. */
301 XTextExtents (pw->label_font,
302 pw->user_label, strlen(pw->user_label),
303 &direction, &ascent, &descent, &overall);
304 if (overall.width > w2) w2 = overall.width;
305 h2 += ascent + descent;
307 /* Measure the passwd_label. */
308 XTextExtents (pw->label_font,
309 pw->passwd_label, strlen(pw->passwd_label),
310 &direction, &ascent, &descent, &overall);
311 if (overall.width > w2) w2 = overall.width;
312 h2 += ascent + descent;
314 /* Measure the user_string. */
315 XTextExtents (pw->passwd_font,
316 pw->user_string, strlen(pw->user_string),
317 &direction, &ascent, &descent, &overall);
318 overall.width += (pw->shadow_width * 4);
319 ascent += (pw->shadow_width * 4);
320 if (overall.width > w3) w3 = overall.width;
321 h3 += ascent + descent;
323 /* Measure the (maximally-sized, dummy) passwd_string. */
324 XTextExtents (pw->passwd_font,
325 passwd_string, strlen(passwd_string),
326 &direction, &ascent, &descent, &overall);
327 overall.width += (pw->shadow_width * 4);
328 ascent += (pw->shadow_width * 4);
329 if (overall.width > w3) w3 = overall.width;
330 h3 += ascent + descent;
332 w2 = w2 + w3 + (pw->shadow_width * 2);
335 if (w2 > pw->width) pw->width = w2;
339 pw->width += (pw->internal_border * 2);
340 pw->height += (pw->internal_border * 4);
342 pw->width += pw->thermo_width + (pw->shadow_width * 3);
344 if (pw->logo_height > pw->height)
345 pw->height = pw->logo_height;
346 else if (pw->height > pw->logo_height)
347 pw->logo_height = pw->height;
349 pw->logo_width = pw->logo_height;
351 pw->width += pw->logo_width;
354 attrmask |= CWOverrideRedirect; attrs.override_redirect = True;
355 attrmask |= CWEventMask; attrs.event_mask = ExposureMask|KeyPressMask;
357 /* We need to remember the mouse position and restore it afterward, or
358 sometimes (perhaps only with Xinerama?) the mouse gets warped to
359 inside the bounds of the lock dialog window.
362 Window pointer_root, pointer_child;
363 int root_x, root_y, win_x, win_y;
365 pw->previous_mouse_x = 0;
366 pw->previous_mouse_y = 0;
367 if (XQueryPointer (si->dpy, RootWindowOfScreen (pw->prompt_screen->screen),
368 &pointer_root, &pointer_child,
369 &root_x, &root_y, &win_x, &win_y, &mask))
371 pw->previous_mouse_x = root_x;
372 pw->previous_mouse_y = root_y;
373 if (si->prefs.verbose_p)
374 fprintf (stderr, "%s: %d: mouse is at %d,%d.\n",
375 blurb(), pw->prompt_screen->number,
376 pw->previous_mouse_x, pw->previous_mouse_y);
378 else if (si->prefs.verbose_p)
379 fprintf (stderr, "%s: %d: unable to determine mouse position?\n",
380 blurb(), pw->prompt_screen->number);
383 /* Figure out where on the desktop to place the window so that it will
384 actually be visible; this takes into account virtual viewports as
388 get_screen_viewport (pw->prompt_screen, &x, &y, &w, &h,
389 pw->previous_mouse_x, pw->previous_mouse_y,
390 si->prefs.verbose_p);
391 if (si->prefs.debug_p) w /= 2;
392 pw->x = x + ((w + pw->width) / 2) - pw->width;
393 pw->y = y + ((h + pw->height) / 2) - pw->height;
394 if (pw->x < x) pw->x = x;
395 if (pw->y < y) pw->y = y;
398 pw->border_width = get_integer_resource ("passwd.borderWidth",
399 "Dialog.BorderWidth");
402 XCreateWindow (si->dpy,
403 RootWindowOfScreen(screen),
404 pw->x, pw->y, pw->width, pw->height, pw->border_width,
405 DefaultDepthOfScreen (screen), InputOutput,
406 DefaultVisualOfScreen(screen),
408 XSetWindowBackground (si->dpy, si->passwd_dialog, pw->background);
410 /* We use the default visual, not ssi->visual, so that the logo pixmap's
411 visual matches that of the si->passwd_dialog window. */
412 pw->logo_pixmap = xscreensaver_logo (ssi->screen,
413 /* ssi->current_visual, */
414 DefaultVisualOfScreen(screen),
415 si->passwd_dialog, cmap,
417 &pw->logo_pixels, &pw->logo_npixels,
420 /* Before mapping the window, save the bits that are underneath the
421 rectangle the window will occlude. When we lower the window, we
422 restore these bits. This works, because the running screenhack
423 has already been sent SIGSTOP, so we know nothing else is drawing
428 pw->save_under = XCreatePixmap (si->dpy,
429 pw->prompt_screen->screensaver_window,
430 pw->width + (pw->border_width*2) + 1,
431 pw->height + (pw->border_width*2) + 1,
432 pw->prompt_screen->current_depth);
433 gcv.function = GXcopy;
434 gc = XCreateGC (si->dpy, pw->save_under, GCFunction, &gcv);
435 XCopyArea (si->dpy, pw->prompt_screen->screensaver_window,
437 pw->x - pw->border_width, pw->y - pw->border_width,
438 pw->width + (pw->border_width*2) + 1,
439 pw->height + (pw->border_width*2) + 1,
441 XFreeGC (si->dpy, gc);
444 XMapRaised (si->dpy, si->passwd_dialog);
445 XSync (si->dpy, False);
447 move_mouse_grab (si, si->passwd_dialog,
448 pw->prompt_screen->cursor,
449 pw->prompt_screen->number);
455 XInstallColormap (si->dpy, cmap);
456 draw_passwd_window (si);
457 XSync (si->dpy, False);
462 draw_passwd_window (saver_info *si)
464 passwd_dialog_data *pw = si->pw_data;
468 int x1, x2, x3, y1, y2;
472 height = (pw->heading_font->ascent + pw->heading_font->descent +
473 pw->body_font->ascent + pw->body_font->descent +
474 (2 * MAX ((pw->label_font->ascent + pw->label_font->descent),
475 (pw->passwd_font->ascent + pw->passwd_font->descent +
476 (pw->shadow_width * 4)))) +
477 pw->date_font->ascent + pw->date_font->descent
479 spacing = ((pw->height - (2 * pw->shadow_width) -
480 pw->internal_border - height)) / 8;
481 if (spacing < 0) spacing = 0;
483 gcv.foreground = pw->foreground;
484 gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
485 gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
486 x1 = pw->logo_width + pw->thermo_width + (pw->shadow_width * 3);
487 x3 = pw->width - (pw->shadow_width * 2);
488 y1 = (pw->shadow_width * 2) + spacing + spacing;
492 XSetFont (si->dpy, gc1, pw->heading_font->fid);
493 sw = string_width (pw->heading_font, pw->heading_label);
494 x2 = (x1 + ((x3 - x1 - sw) / 2));
495 y1 += spacing + pw->heading_font->ascent + pw->heading_font->descent;
496 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
497 pw->heading_label, strlen(pw->heading_label));
499 /* text below top heading
501 XSetFont (si->dpy, gc1, pw->body_font->fid);
502 y1 += spacing + pw->body_font->ascent + pw->body_font->descent;
503 sw = string_width (pw->body_font, pw->body_label);
504 x2 = (x1 + ((x3 - x1 - sw) / 2));
505 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
506 pw->body_label, strlen(pw->body_label));
509 tb_height = (pw->passwd_font->ascent + pw->passwd_font->descent +
510 (pw->shadow_width * 4));
512 /* the "User:" prompt
516 XSetForeground (si->dpy, gc1, pw->foreground);
517 XSetFont (si->dpy, gc1, pw->label_font->fid);
518 y1 += (spacing + tb_height);
519 x2 = (x1 + pw->internal_border +
520 MAX(string_width (pw->label_font, pw->user_label),
521 string_width (pw->label_font, pw->passwd_label)));
522 XDrawString (si->dpy, si->passwd_dialog, gc1,
523 x2 - string_width (pw->label_font, pw->user_label),
525 pw->user_label, strlen(pw->user_label));
527 /* the "Password:" prompt
529 y1 += (spacing + tb_height);
530 XDrawString (si->dpy, si->passwd_dialog, gc1,
531 x2 - string_width (pw->label_font, pw->passwd_label),
533 pw->passwd_label, strlen(pw->passwd_label));
536 XSetForeground (si->dpy, gc2, pw->passwd_background);
538 /* the "user name" text field
541 XSetForeground (si->dpy, gc1, pw->passwd_foreground);
542 XSetFont (si->dpy, gc1, pw->passwd_font->fid);
543 y1 += (spacing + tb_height);
544 x2 += (pw->shadow_width * 4);
546 pw->passwd_field_width = x3 - x2 - pw->internal_border;
547 pw->passwd_field_height = (pw->passwd_font->ascent +
548 pw->passwd_font->descent +
551 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
552 x2 - pw->shadow_width,
553 y1 - (pw->passwd_font->ascent + pw->passwd_font->descent),
554 pw->passwd_field_width, pw->passwd_field_height);
555 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
556 pw->user_string, strlen(pw->user_string));
558 /* the "password" text field
560 y1 += (spacing + tb_height);
562 pw->passwd_field_x = x2 - pw->shadow_width;
563 pw->passwd_field_y = y1 - (pw->passwd_font->ascent +
564 pw->passwd_font->descent);
566 /* The shadow around the text fields
569 y1 += (spacing + (pw->shadow_width * 3));
570 x1 = x2 - (pw->shadow_width * 2);
571 x2 = pw->passwd_field_width + (pw->shadow_width * 2);
572 y2 = pw->passwd_field_height + (pw->shadow_width * 2);
574 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
577 pw->shadow_bottom, pw->shadow_top);
579 y1 += (spacing + pw->passwd_font->ascent + pw->passwd_font->descent +
580 (pw->shadow_width * 4));
581 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
584 pw->shadow_bottom, pw->shadow_top);
587 /* The date, below the text fields
591 time_t now = time ((time_t *) 0);
592 struct tm *tm = localtime (&now);
593 memset (buf, 0, sizeof(buf));
594 strftime (buf, sizeof(buf)-1, pw->date_label, tm);
596 XSetFont (si->dpy, gc1, pw->date_font->fid);
597 y1 += pw->shadow_width;
598 y1 += (spacing + tb_height);
600 sw = string_width (pw->date_font, buf);
602 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1, buf, strlen(buf));
608 x1 = pw->shadow_width * 6;
609 y1 = pw->shadow_width * 6;
610 x2 = pw->logo_width - (pw->shadow_width * 12);
611 y2 = pw->logo_height - (pw->shadow_width * 12);
617 unsigned int w, h, bw, d;
618 XGetGeometry (si->dpy, pw->logo_pixmap, &root, &x, &y, &w, &h, &bw, &d);
619 XSetForeground (si->dpy, gc1, pw->foreground);
620 XSetBackground (si->dpy, gc1, pw->background);
622 XCopyPlane (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1,
624 x1 + ((x2 - (int)w) / 2),
625 y1 + ((y2 - (int)h) / 2),
628 XCopyArea (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1,
630 x1 + ((x2 - (int)w) / 2),
631 y1 + ((y2 - (int)h) / 2));
636 XSetForeground (si->dpy, gc1, pw->thermo_foreground);
637 XSetForeground (si->dpy, gc2, pw->thermo_background);
639 pw->thermo_field_x = pw->logo_width + pw->shadow_width;
640 pw->thermo_field_y = pw->shadow_width * 5;
641 pw->thermo_field_height = pw->height - (pw->shadow_width * 10);
644 /* Solid border inside the logo box. */
645 XSetForeground (si->dpy, gc1, pw->foreground);
646 XDrawRectangle (si->dpy, si->passwd_dialog, gc1, x1, y1, x2-1, y2-1);
649 /* The shadow around the logo
651 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
652 pw->shadow_width * 4,
653 pw->shadow_width * 4,
654 pw->logo_width - (pw->shadow_width * 8),
655 pw->logo_height - (pw->shadow_width * 8),
657 pw->shadow_bottom, pw->shadow_top);
659 /* The shadow around the thermometer
661 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
663 pw->shadow_width * 4,
664 pw->thermo_width + (pw->shadow_width * 2),
665 pw->height - (pw->shadow_width * 8),
667 pw->shadow_bottom, pw->shadow_top);
670 /* Solid border inside the thermometer. */
671 XSetForeground (si->dpy, gc1, pw->foreground);
672 XDrawRectangle (si->dpy, si->passwd_dialog, gc1,
673 pw->thermo_field_x, pw->thermo_field_y,
674 pw->thermo_width - 1, pw->thermo_field_height - 1);
677 /* The shadow around the whole window
679 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
680 0, 0, pw->width, pw->height, pw->shadow_width,
681 pw->shadow_top, pw->shadow_bottom);
683 XFreeGC (si->dpy, gc1);
684 XFreeGC (si->dpy, gc2);
686 update_passwd_window (si, pw->passwd_string, pw->ratio);
691 update_passwd_window (saver_info *si, const char *printed_passwd, float ratio)
693 passwd_dialog_data *pw = si->pw_data;
700 gcv.foreground = pw->passwd_foreground;
701 gcv.font = pw->passwd_font->fid;
702 gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground|GCFont, &gcv);
703 gcv.foreground = pw->passwd_background;
704 gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
708 char *s = strdup (printed_passwd);
709 if (pw->passwd_string) free (pw->passwd_string);
710 pw->passwd_string = s;
713 /* the "password" text field
715 rects[0].x = pw->passwd_field_x;
716 rects[0].y = pw->passwd_field_y;
717 rects[0].width = pw->passwd_field_width;
718 rects[0].height = pw->passwd_field_height;
720 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
721 rects[0].x, rects[0].y, rects[0].width, rects[0].height);
723 XSetClipRectangles (si->dpy, gc1, 0, 0, rects, 1, Unsorted);
725 XDrawString (si->dpy, si->passwd_dialog, gc1,
726 rects[0].x + pw->shadow_width,
727 rects[0].y + (pw->passwd_font->ascent +
728 pw->passwd_font->descent),
729 pw->passwd_string, strlen(pw->passwd_string));
731 XSetClipMask (si->dpy, gc1, None);
737 x = (rects[0].x + pw->shadow_width +
738 string_width (pw->passwd_font, pw->passwd_string));
739 y = rects[0].y + pw->shadow_width;
741 if (x > rects[0].x + rects[0].width - 1)
742 x = rects[0].x + rects[0].width - 1;
743 XDrawLine (si->dpy, si->passwd_dialog, gc1,
744 x, y, x, y + pw->passwd_font->ascent);
747 pw->i_beam = (pw->i_beam + 1) % 4;
752 y = (pw->thermo_field_height - 2) * (1.0 - pw->ratio);
755 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
756 pw->thermo_field_x + 1,
757 pw->thermo_field_y + 1,
760 XSetForeground (si->dpy, gc1, pw->thermo_foreground);
761 XFillRectangle (si->dpy, si->passwd_dialog, gc1,
762 pw->thermo_field_x + 1,
763 pw->thermo_field_y + 1 + y,
765 MAX (0, pw->thermo_field_height - y - 2));
768 XFreeGC (si->dpy, gc1);
769 XFreeGC (si->dpy, gc2);
770 XSync (si->dpy, False);
775 destroy_passwd_window (saver_info *si)
777 saver_preferences *p = &si->prefs;
778 passwd_dialog_data *pw = si->pw_data;
779 saver_screen_info *ssi = pw->prompt_screen;
780 Colormap cmap = DefaultColormapOfScreen (ssi->screen);
781 Pixel black = BlackPixelOfScreen (ssi->screen);
782 Pixel white = WhitePixelOfScreen (ssi->screen);
785 memset (pw->typed_passwd, 0, sizeof(pw->typed_passwd));
786 memset (pw->passwd_string, 0, strlen(pw->passwd_string));
789 XtRemoveTimeOut (pw->timer);
791 move_mouse_grab (si, RootWindowOfScreen (ssi->screen),
792 ssi->cursor, ssi->number);
795 fprintf (stderr, "%s: %d: moving mouse back to %d,%d.\n",
796 blurb(), ssi->number,
797 pw->previous_mouse_x, pw->previous_mouse_y);
799 XWarpPointer (si->dpy, None, RootWindowOfScreen (ssi->screen),
801 pw->previous_mouse_x, pw->previous_mouse_y);
803 XSync (si->dpy, False);
804 while (XCheckMaskEvent (si->dpy, PointerMotionMask, &event))
806 fprintf (stderr, "%s: discarding MotionNotify event.\n", blurb());
808 if (si->passwd_dialog)
810 XDestroyWindow (si->dpy, si->passwd_dialog);
811 si->passwd_dialog = 0;
818 gcv.function = GXcopy;
819 gc = XCreateGC (si->dpy, ssi->screensaver_window, GCFunction, &gcv);
820 XCopyArea (si->dpy, pw->save_under,
821 ssi->screensaver_window, gc,
823 pw->width + (pw->border_width*2) + 1,
824 pw->height + (pw->border_width*2) + 1,
825 pw->x - pw->border_width, pw->y - pw->border_width);
826 XFreePixmap (si->dpy, pw->save_under);
828 XFreeGC (si->dpy, gc);
831 if (pw->heading_label) free (pw->heading_label);
832 if (pw->body_label) free (pw->body_label);
833 if (pw->user_label) free (pw->user_label);
834 if (pw->passwd_label) free (pw->passwd_label);
835 if (pw->date_label) free (pw->date_label);
836 if (pw->user_string) free (pw->user_string);
837 if (pw->passwd_string) free (pw->passwd_string);
839 if (pw->heading_font) XFreeFont (si->dpy, pw->heading_font);
840 if (pw->body_font) XFreeFont (si->dpy, pw->body_font);
841 if (pw->label_font) XFreeFont (si->dpy, pw->label_font);
842 if (pw->passwd_font) XFreeFont (si->dpy, pw->passwd_font);
843 if (pw->date_font) XFreeFont (si->dpy, pw->date_font);
845 if (pw->foreground != black && pw->foreground != white)
846 XFreeColors (si->dpy, cmap, &pw->foreground, 1, 0L);
847 if (pw->background != black && pw->background != white)
848 XFreeColors (si->dpy, cmap, &pw->background, 1, 0L);
849 if (pw->passwd_foreground != black && pw->passwd_foreground != white)
850 XFreeColors (si->dpy, cmap, &pw->passwd_foreground, 1, 0L);
851 if (pw->passwd_background != black && pw->passwd_background != white)
852 XFreeColors (si->dpy, cmap, &pw->passwd_background, 1, 0L);
853 if (pw->thermo_foreground != black && pw->thermo_foreground != white)
854 XFreeColors (si->dpy, cmap, &pw->thermo_foreground, 1, 0L);
855 if (pw->thermo_background != black && pw->thermo_background != white)
856 XFreeColors (si->dpy, cmap, &pw->thermo_background, 1, 0L);
857 if (pw->shadow_top != black && pw->shadow_top != white)
858 XFreeColors (si->dpy, cmap, &pw->shadow_top, 1, 0L);
859 if (pw->shadow_bottom != black && pw->shadow_bottom != white)
860 XFreeColors (si->dpy, cmap, &pw->shadow_bottom, 1, 0L);
863 XFreePixmap (si->dpy, pw->logo_pixmap);
866 if (pw->logo_npixels)
867 XFreeColors (si->dpy, cmap, pw->logo_pixels, pw->logo_npixels, 0L);
868 free (pw->logo_pixels);
870 pw->logo_npixels = 0;
874 XFreePixmap (si->dpy, pw->save_under);
877 XInstallColormap (si->dpy, cmap);
879 memset (pw, 0, sizeof(*pw));
885 static Bool error_handler_hit_p = False;
888 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
890 error_handler_hit_p = True;
895 #ifdef HAVE_XHPDISABLERESET
896 /* This function enables and disables the C-Sh-Reset hot-key, which
897 normally resets the X server (logging out the logged-in user.)
898 We don't want random people to be able to do that while the
902 hp_lock_reset (saver_info *si, Bool lock_p)
904 static Bool hp_locked_p = False;
906 /* Calls to XHPDisableReset and XHPEnableReset must be balanced,
907 or BadAccess errors occur. (It's ok for this to be global,
908 since it affects the whole machine, not just the current screen.)
910 if (hp_locked_p == lock_p)
914 XHPDisableReset (si->dpy);
916 XHPEnableReset (si->dpy);
917 hp_locked_p = lock_p;
919 #endif /* HAVE_XHPDISABLERESET */
922 #ifdef HAVE_XF86MISCSETGRABKEYSSTATE
924 /* This function enables and disables the Ctrl-Alt-KP_star and
925 Ctrl-Alt-KP_slash hot-keys, which (in XFree86 4.2) break any
926 grabs and/or kill the grabbing client. That would effectively
927 unlock the screen, so we don't like that.
929 The Ctrl-Alt-KP_star and Ctrl-Alt-KP_slash hot-keys only exist
930 if AllowDeactivateGrabs and/or AllowClosedownGrabs are turned on
931 in XF86Config. I believe they are disabled by default.
933 This does not affect any other keys (specifically Ctrl-Alt-BS or
934 Ctrl-Alt-F1) but I wish it did. Maybe it will someday.
937 xfree_lock_grab_smasher (saver_info *si, Bool lock_p)
939 saver_preferences *p = &si->prefs;
942 XErrorHandler old_handler;
943 XSync (si->dpy, False);
944 error_handler_hit_p = False;
945 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
946 XSync (si->dpy, False);
947 status = XF86MiscSetGrabKeysState (si->dpy, !lock_p);
948 XSync (si->dpy, False);
949 if (error_handler_hit_p) status = 666;
951 if (!lock_p && status == MiscExtGrabStateAlready)
952 status = MiscExtGrabStateSuccess; /* shut up, consider this success */
954 if (p->verbose_p && status != MiscExtGrabStateSuccess)
955 fprintf (stderr, "%s: error: XF86MiscSetGrabKeysState(%d) returned %s\n",
957 (status == MiscExtGrabStateSuccess ? "MiscExtGrabStateSuccess" :
958 status == MiscExtGrabStateLocked ? "MiscExtGrabStateLocked" :
959 status == MiscExtGrabStateAlready ? "MiscExtGrabStateAlready" :
960 status == 666 ? "an X error" :
963 XSync (si->dpy, False);
964 XSetErrorHandler (old_handler);
965 XSync (si->dpy, False);
967 #endif /* HAVE_XF86MISCSETGRABKEYSSTATE */
972 /* This function enables and disables the C-Sh-F1 ... F12 hot-keys,
973 which, on Linux systems, switches to another virtual console.
974 We'd like the whole screen/keyboard to be locked, not just one
975 virtual console, so this function disables that while the X
978 Unfortunately, this doesn't work -- this ioctl only works when
979 called by root, and we have disavowed our privileges long ago.
981 #ifdef HAVE_VT_LOCKSWITCH
983 linux_lock_vt_switch (saver_info *si, Bool lock_p)
985 saver_preferences *p = &si->prefs;
986 static Bool vt_locked_p = False;
987 const char *dev_console = "/dev/console";
990 if (lock_p == vt_locked_p)
993 if (lock_p && !p->lock_vt_p)
996 fd = open (dev_console, O_RDWR);
1000 sprintf (buf, "%s: couldn't %s VTs: %s", blurb(),
1001 (lock_p ? "lock" : "unlock"),
1003 #if 1 /* #### doesn't work yet, so don't bother complaining */
1009 if (ioctl (fd, (lock_p ? VT_LOCKSWITCH : VT_UNLOCKSWITCH)) == 0)
1011 vt_locked_p = lock_p;
1014 fprintf (stderr, "%s: %s VTs\n", blurb(),
1015 (lock_p ? "locked" : "unlocked"));
1020 sprintf (buf, "%s: couldn't %s VTs: ioctl", blurb(),
1021 (lock_p ? "lock" : "unlock"));
1022 #if 0 /* #### doesn't work yet, so don't bother complaining */
1029 #endif /* HAVE_VT_LOCKSWITCH */
1032 /* This function enables and disables the C-Alt-Plus and C-Alt-Minus
1033 hot-keys, which normally change the resolution of the X server.
1034 We don't want people to be able to switch the server resolution
1035 while the screen is locked, because if they switch to a higher
1036 resolution, it could cause part of the underlying desktop to become
1039 #ifdef HAVE_XF86VMODE
1042 xfree_lock_mode_switch (saver_info *si, Bool lock_p)
1044 static Bool any_mode_locked_p = False;
1045 saver_preferences *p = &si->prefs;
1049 XErrorHandler old_handler;
1051 if (any_mode_locked_p == lock_p)
1053 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1056 for (screen = 0; screen < (si->xinerama_p ? 1 : si->nscreens); screen++)
1058 XSync (si->dpy, False);
1059 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1060 error_handler_hit_p = False;
1061 status = XF86VidModeLockModeSwitch (si->dpy, screen, lock_p);
1062 XSync (si->dpy, False);
1063 XSetErrorHandler (old_handler);
1064 if (error_handler_hit_p) status = False;
1067 any_mode_locked_p = lock_p;
1069 if (!status && (p->verbose_p || !lock_p))
1070 /* Only print this when verbose, or when we locked but can't unlock.
1071 I tried printing this message whenever it comes up, but
1072 mode-locking always fails if DontZoom is set in XF86Config. */
1073 fprintf (stderr, "%s: %d: unable to %s mode switching!\n",
1074 blurb(), screen, (lock_p ? "lock" : "unlock"));
1075 else if (p->verbose_p)
1076 fprintf (stderr, "%s: %d: %s mode switching.\n",
1077 blurb(), screen, (lock_p ? "locked" : "unlocked"));
1080 #endif /* HAVE_XF86VMODE */
1083 /* If the viewport has been scrolled since the screen was blanked,
1084 then scroll it back to where it belongs. This function only exists
1085 to patch over a very brief race condition.
1088 undo_vp_motion (saver_info *si)
1090 #ifdef HAVE_XF86VMODE
1091 saver_preferences *p = &si->prefs;
1095 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1098 for (screen = 0; screen < si->nscreens; screen++)
1100 saver_screen_info *ssi = &si->screens[screen];
1104 if (ssi->blank_vp_x == -1 && ssi->blank_vp_y == -1)
1106 if (!XF86VidModeGetViewPort (si->dpy, screen, &x, &y))
1108 if (ssi->blank_vp_x == x && ssi->blank_vp_y == y)
1111 /* We're going to move the viewport. The mouse has just been grabbed on
1112 (and constrained to, thus warped to) the password window, so it is no
1113 longer near the edge of the screen. However, wait a bit anyway, just
1114 to make sure the server drains its last motion event, so that the
1115 screen doesn't continue to scroll after we've reset the viewport.
1117 XSync (si->dpy, False);
1118 usleep (250000); /* 1/4 second */
1119 XSync (si->dpy, False);
1121 status = XF86VidModeSetViewPort (si->dpy, screen,
1122 ssi->blank_vp_x, ssi->blank_vp_y);
1126 "%s: %d: unable to move vp from (%d,%d) back to (%d,%d)!\n",
1127 blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1128 else if (p->verbose_p)
1130 "%s: %d: vp moved to (%d,%d); moved it back to (%d,%d).\n",
1131 blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1133 #endif /* HAVE_XF86VMODE */
1142 passwd_animate_timer (XtPointer closure, XtIntervalId *id)
1144 saver_info *si = (saver_info *) closure;
1146 passwd_dialog_data *pw = si->pw_data;
1150 pw->ratio -= (1.0 / ((double) si->prefs.passwd_timeout / (double) tick));
1154 if (pw->state == pw_read)
1155 pw->state = pw_time;
1158 update_passwd_window (si, 0, pw->ratio);
1160 if (pw->state == pw_read)
1161 pw->timer = XtAppAddTimeOut (si->app, tick, passwd_animate_timer,
1166 idle_timer ((XtPointer) si, 0);
1170 static XComposeStatus *compose_status;
1173 handle_passwd_key (saver_info *si, XKeyEvent *event)
1175 saver_preferences *p = &si->prefs;
1176 passwd_dialog_data *pw = si->pw_data;
1177 int pw_size = sizeof (pw->typed_passwd) - 1;
1178 char *typed_passwd = pw->typed_passwd;
1182 int size = XLookupString (event, s, 1, 0, compose_status);
1184 if (size != 1) return;
1190 case '\010': case '\177': /* Backspace */
1194 typed_passwd [strlen(typed_passwd)-1] = 0;
1197 case '\025': case '\030': /* Erase line */
1198 memset (typed_passwd, 0, pw_size);
1201 case '\012': case '\015': /* Enter */
1202 if (pw->state != pw_read)
1203 ; /* already done? */
1204 else if (typed_passwd[0] == 0)
1205 pw->state = pw_null;
1208 update_passwd_window (si, "Checking...", pw->ratio);
1209 XSync (si->dpy, False);
1210 if (passwd_valid_p (typed_passwd, p->verbose_p))
1213 pw->state = pw_fail;
1214 update_passwd_window (si, "", pw->ratio);
1219 i = strlen (typed_passwd);
1224 typed_passwd [i] = *s;
1225 typed_passwd [i+1] = 0;
1230 i = strlen(typed_passwd);
1231 stars = (char *) malloc(i+1);
1232 memset (stars, '*', i);
1234 update_passwd_window (si, stars, pw->ratio);
1240 passwd_event_loop (saver_info *si)
1242 saver_preferences *p = &si->prefs;
1245 passwd_animate_timer ((XtPointer) si, 0);
1247 while (si->pw_data && si->pw_data->state == pw_read)
1249 XtAppNextEvent (si->app, &event);
1250 if (event.xany.window == si->passwd_dialog && event.xany.type == Expose)
1251 draw_passwd_window (si);
1252 else if (event.xany.type == KeyPress)
1253 handle_passwd_key (si, &event.xkey);
1255 XtDispatchEvent (&event);
1258 switch (si->pw_data->state)
1260 case pw_ok: msg = 0; break;
1261 case pw_null: msg = ""; break;
1262 case pw_time: msg = "Timed out!"; break;
1263 default: msg = "Sorry!"; break;
1266 if (si->pw_data->state == pw_fail)
1267 si->unlock_failures++;
1270 switch (si->pw_data->state)
1273 fprintf (stderr, "%s: password correct.\n", blurb()); break;
1275 fprintf (stderr, "%s: password incorrect!\n", blurb()); break;
1278 fprintf (stderr, "%s: password entry cancelled.\n", blurb()); break;
1280 fprintf (stderr, "%s: password entry timed out.\n", blurb()); break;
1285 if (si->pw_data->state == pw_fail)
1287 /* If they typed a password (as opposed to just hitting return) and
1288 the password was invalid, log it.
1290 struct passwd *pw = getpwuid (getuid ());
1291 char *d = DisplayString (si->dpy);
1292 char *u = (pw->pw_name ? pw->pw_name : "???");
1300 # if defined(LOG_AUTHPRIV)
1302 # elif defined(LOG_AUTH)
1309 openlog (progname, opt, fac);
1310 syslog (LOG_NOTICE, "FAILED LOGIN %d ON DISPLAY \"%s\", FOR \"%s\"",
1311 si->unlock_failures, d, u);
1314 #endif /* HAVE_SYSLOG */
1316 if (si->pw_data->state == pw_fail)
1317 XBell (si->dpy, False);
1319 if (si->pw_data->state == pw_ok && si->unlock_failures != 0)
1321 if (si->unlock_failures == 1)
1322 fprintf (real_stderr,
1323 "%s: WARNING: 1 failed attempt to unlock the screen.\n",
1326 fprintf (real_stderr,
1327 "%s: WARNING: %d failed attempts to unlock the screen.\n",
1328 blurb(), si->unlock_failures);
1329 fflush (real_stderr);
1331 si->unlock_failures = 0;
1336 si->pw_data->i_beam = 0;
1337 update_passwd_window (si, msg, 0.0);
1338 XSync (si->dpy, False);
1341 /* Swallow all pending KeyPress/KeyRelease events. */
1344 while (XCheckMaskEvent (si->dpy, KeyPressMask|KeyReleaseMask, &e))
1352 handle_typeahead (saver_info *si)
1354 passwd_dialog_data *pw = si->pw_data;
1356 if (!si->unlock_typeahead)
1359 i = strlen (si->unlock_typeahead);
1360 if (i >= sizeof(pw->typed_passwd) - 1)
1361 i = sizeof(pw->typed_passwd) - 1;
1363 memcpy (pw->typed_passwd, si->unlock_typeahead, i);
1364 pw->typed_passwd [i] = 0;
1366 memset (si->unlock_typeahead, '*', strlen(si->unlock_typeahead));
1367 si->unlock_typeahead[i] = 0;
1368 update_passwd_window (si, si->unlock_typeahead, pw->ratio);
1370 free (si->unlock_typeahead);
1371 si->unlock_typeahead = 0;
1376 unlock_p (saver_info *si)
1378 saver_preferences *p = &si->prefs;
1381 raise_window (si, True, True, True);
1384 fprintf (stderr, "%s: prompting for password.\n", blurb());
1386 if (si->pw_data || si->passwd_dialog)
1387 destroy_passwd_window (si);
1389 make_passwd_window (si);
1391 compose_status = calloc (1, sizeof (*compose_status));
1393 handle_typeahead (si);
1394 passwd_event_loop (si);
1396 status = (si->pw_data->state == pw_ok);
1397 destroy_passwd_window (si);
1399 free (compose_status);
1407 set_locked_p (saver_info *si, Bool locked_p)
1409 si->locked_p = locked_p;
1411 #ifdef HAVE_XHPDISABLERESET
1412 hp_lock_reset (si, locked_p); /* turn off/on C-Sh-Reset */
1414 #ifdef HAVE_VT_LOCKSWITCH
1415 linux_lock_vt_switch (si, locked_p); /* turn off/on C-Alt-F1 */
1417 #ifdef HAVE_XF86VMODE
1418 xfree_lock_mode_switch (si, locked_p); /* turn off/on C-Alt-Plus */
1420 #ifdef HAVE_XF86MISCSETGRABKEYSSTATE
1421 xfree_lock_grab_smasher (si, locked_p); /* turn off/on C-Alt-KP-*,/ */
1424 store_saver_status (si); /* store locked-p */
1428 #else /* NO_LOCKING -- whole file */
1431 set_locked_p (saver_info *si, Bool locked_p)
1433 if (locked_p) abort();
1436 #endif /* !NO_LOCKING */