1 /* lock.c --- handling the password dialog for locking-mode.
2 * xscreensaver, Copyright (c) 1993-2002 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 (p->verbose_p && status != MiscExtGrabStateSuccess)
952 fprintf (stderr, "%s: error: XF86MiscSetGrabKeysState(%d) returned %s\n",
954 (status == MiscExtGrabStateSuccess ? "MiscExtGrabStateSuccess" :
955 status == MiscExtGrabStateLocked ? "MiscExtGrabStateLocked" :
956 status == MiscExtGrabStateAlready ? "MiscExtGrabStateAlready" :
957 status == 666 ? "an X error" :
960 XSync (si->dpy, False);
961 XSetErrorHandler (old_handler);
962 XSync (si->dpy, False);
964 #endif /* HAVE_XF86MISCSETGRABKEYSSTATE */
969 /* This function enables and disables the C-Sh-F1 ... F12 hot-keys,
970 which, on Linux systems, switches to another virtual console.
971 We'd like the whole screen/keyboard to be locked, not just one
972 virtual console, so this function disables that while the X
975 Unfortunately, this doesn't work -- this ioctl only works when
976 called by root, and we have disavowed our privileges long ago.
978 #ifdef HAVE_VT_LOCKSWITCH
980 linux_lock_vt_switch (saver_info *si, Bool lock_p)
982 saver_preferences *p = &si->prefs;
983 static Bool vt_locked_p = False;
984 const char *dev_console = "/dev/console";
987 if (lock_p == vt_locked_p)
990 if (lock_p && !p->lock_vt_p)
993 fd = open (dev_console, O_RDWR);
997 sprintf (buf, "%s: couldn't %s VTs: %s", blurb(),
998 (lock_p ? "lock" : "unlock"),
1000 #if 1 /* #### doesn't work yet, so don't bother complaining */
1006 if (ioctl (fd, (lock_p ? VT_LOCKSWITCH : VT_UNLOCKSWITCH)) == 0)
1008 vt_locked_p = lock_p;
1011 fprintf (stderr, "%s: %s VTs\n", blurb(),
1012 (lock_p ? "locked" : "unlocked"));
1017 sprintf (buf, "%s: couldn't %s VTs: ioctl", blurb(),
1018 (lock_p ? "lock" : "unlock"));
1019 #if 0 /* #### doesn't work yet, so don't bother complaining */
1026 #endif /* HAVE_VT_LOCKSWITCH */
1029 /* This function enables and disables the C-Alt-Plus and C-Alt-Minus
1030 hot-keys, which normally change the resolution of the X server.
1031 We don't want people to be able to switch the server resolution
1032 while the screen is locked, because if they switch to a higher
1033 resolution, it could cause part of the underlying desktop to become
1036 #ifdef HAVE_XF86VMODE
1039 xfree_lock_mode_switch (saver_info *si, Bool lock_p)
1041 static Bool any_mode_locked_p = False;
1042 saver_preferences *p = &si->prefs;
1046 XErrorHandler old_handler;
1048 if (any_mode_locked_p == lock_p)
1050 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1053 for (screen = 0; screen < (si->xinerama_p ? 1 : si->nscreens); screen++)
1055 XSync (si->dpy, False);
1056 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1057 error_handler_hit_p = False;
1058 status = XF86VidModeLockModeSwitch (si->dpy, screen, lock_p);
1059 XSync (si->dpy, False);
1060 XSetErrorHandler (old_handler);
1061 if (error_handler_hit_p) status = False;
1064 any_mode_locked_p = lock_p;
1066 if (!status && (p->verbose_p || !lock_p))
1067 /* Only print this when verbose, or when we locked but can't unlock.
1068 I tried printing this message whenever it comes up, but
1069 mode-locking always fails if DontZoom is set in XF86Config. */
1070 fprintf (stderr, "%s: %d: unable to %s mode switching!\n",
1071 blurb(), screen, (lock_p ? "lock" : "unlock"));
1072 else if (p->verbose_p)
1073 fprintf (stderr, "%s: %d: %s mode switching.\n",
1074 blurb(), screen, (lock_p ? "locked" : "unlocked"));
1077 #endif /* HAVE_XF86VMODE */
1080 /* If the viewport has been scrolled since the screen was blanked,
1081 then scroll it back to where it belongs. This function only exists
1082 to patch over a very brief race condition.
1085 undo_vp_motion (saver_info *si)
1087 #ifdef HAVE_XF86VMODE
1088 saver_preferences *p = &si->prefs;
1092 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1095 for (screen = 0; screen < si->nscreens; screen++)
1097 saver_screen_info *ssi = &si->screens[screen];
1101 if (ssi->blank_vp_x == -1 && ssi->blank_vp_y == -1)
1103 if (!XF86VidModeGetViewPort (si->dpy, screen, &x, &y))
1105 if (ssi->blank_vp_x == x && ssi->blank_vp_y == y)
1108 /* We're going to move the viewport. The mouse has just been grabbed on
1109 (and constrained to, thus warped to) the password window, so it is no
1110 longer near the edge of the screen. However, wait a bit anyway, just
1111 to make sure the server drains its last motion event, so that the
1112 screen doesn't continue to scroll after we've reset the viewport.
1114 XSync (si->dpy, False);
1115 usleep (250000); /* 1/4 second */
1116 XSync (si->dpy, False);
1118 status = XF86VidModeSetViewPort (si->dpy, screen,
1119 ssi->blank_vp_x, ssi->blank_vp_y);
1123 "%s: %d: unable to move vp from (%d,%d) back to (%d,%d)!\n",
1124 blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1125 else if (p->verbose_p)
1127 "%s: %d: vp moved to (%d,%d); moved it back to (%d,%d).\n",
1128 blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1130 #endif /* HAVE_XF86VMODE */
1139 passwd_animate_timer (XtPointer closure, XtIntervalId *id)
1141 saver_info *si = (saver_info *) closure;
1143 passwd_dialog_data *pw = si->pw_data;
1147 pw->ratio -= (1.0 / ((double) si->prefs.passwd_timeout / (double) tick));
1151 if (pw->state == pw_read)
1152 pw->state = pw_time;
1155 update_passwd_window (si, 0, pw->ratio);
1157 if (pw->state == pw_read)
1158 pw->timer = XtAppAddTimeOut (si->app, tick, passwd_animate_timer,
1163 idle_timer ((XtPointer) si, id);
1167 static XComposeStatus *compose_status;
1170 handle_passwd_key (saver_info *si, XKeyEvent *event)
1172 saver_preferences *p = &si->prefs;
1173 passwd_dialog_data *pw = si->pw_data;
1174 int pw_size = sizeof (pw->typed_passwd) - 1;
1175 char *typed_passwd = pw->typed_passwd;
1179 int size = XLookupString (event, s, 1, 0, compose_status);
1181 if (size != 1) return;
1187 case '\010': case '\177': /* Backspace */
1191 typed_passwd [strlen(typed_passwd)-1] = 0;
1194 case '\025': case '\030': /* Erase line */
1195 memset (typed_passwd, 0, pw_size);
1198 case '\012': case '\015': /* Enter */
1199 if (pw->state != pw_read)
1200 ; /* already done? */
1201 else if (typed_passwd[0] == 0)
1202 pw->state = pw_null;
1205 update_passwd_window (si, "Checking...", pw->ratio);
1206 XSync (si->dpy, False);
1207 if (passwd_valid_p (typed_passwd, p->verbose_p))
1210 pw->state = pw_fail;
1211 update_passwd_window (si, "", pw->ratio);
1216 i = strlen (typed_passwd);
1221 typed_passwd [i] = *s;
1222 typed_passwd [i+1] = 0;
1227 i = strlen(typed_passwd);
1228 stars = (char *) malloc(i+1);
1229 memset (stars, '*', i);
1231 update_passwd_window (si, stars, pw->ratio);
1237 passwd_event_loop (saver_info *si)
1239 saver_preferences *p = &si->prefs;
1242 passwd_animate_timer ((XtPointer) si, 0);
1244 while (si->pw_data && si->pw_data->state == pw_read)
1246 XtAppNextEvent (si->app, &event);
1247 if (event.xany.window == si->passwd_dialog && event.xany.type == Expose)
1248 draw_passwd_window (si);
1249 else if (event.xany.type == KeyPress)
1250 handle_passwd_key (si, &event.xkey);
1252 XtDispatchEvent (&event);
1255 switch (si->pw_data->state)
1257 case pw_ok: msg = 0; break;
1258 case pw_null: msg = ""; break;
1259 case pw_time: msg = "Timed out!"; break;
1260 default: msg = "Sorry!"; break;
1263 if (si->pw_data->state == pw_fail)
1264 si->unlock_failures++;
1267 switch (si->pw_data->state)
1270 fprintf (stderr, "%s: password correct.\n", blurb()); break;
1272 fprintf (stderr, "%s: password incorrect!\n", blurb()); break;
1275 fprintf (stderr, "%s: password entry cancelled.\n", blurb()); break;
1277 fprintf (stderr, "%s: password entry timed out.\n", blurb()); break;
1282 if (si->pw_data->state == pw_fail)
1284 /* If they typed a password (as opposed to just hitting return) and
1285 the password was invalid, log it.
1287 struct passwd *pw = getpwuid (getuid ());
1288 char *d = DisplayString (si->dpy);
1289 char *u = (pw->pw_name ? pw->pw_name : "???");
1297 # if defined(LOG_AUTHPRIV)
1299 # elif defined(LOG_AUTH)
1306 openlog (progname, opt, fac);
1307 syslog (LOG_NOTICE, "FAILED LOGIN %d ON DISPLAY \"%s\", FOR \"%s\"",
1308 si->unlock_failures, d, u);
1311 #endif /* HAVE_SYSLOG */
1313 if (si->pw_data->state == pw_fail)
1314 XBell (si->dpy, False);
1316 if (si->pw_data->state == pw_ok && si->unlock_failures != 0)
1318 if (si->unlock_failures == 1)
1319 fprintf (real_stderr,
1320 "%s: WARNING: 1 failed attempt to unlock the screen.\n",
1323 fprintf (real_stderr,
1324 "%s: WARNING: %d failed attempts to unlock the screen.\n",
1325 blurb(), si->unlock_failures);
1326 fflush (real_stderr);
1328 si->unlock_failures = 0;
1333 si->pw_data->i_beam = 0;
1334 update_passwd_window (si, msg, 0.0);
1335 XSync (si->dpy, False);
1338 /* Swallow all pending KeyPress/KeyRelease events. */
1341 while (XCheckMaskEvent (si->dpy, KeyPressMask|KeyReleaseMask, &e))
1349 handle_typeahead (saver_info *si)
1351 passwd_dialog_data *pw = si->pw_data;
1353 if (!si->unlock_typeahead)
1356 i = strlen (si->unlock_typeahead);
1357 if (i >= sizeof(pw->typed_passwd) - 1)
1358 i = sizeof(pw->typed_passwd) - 1;
1360 memcpy (pw->typed_passwd, si->unlock_typeahead, i);
1361 pw->typed_passwd [i] = 0;
1363 memset (si->unlock_typeahead, '*', strlen(si->unlock_typeahead));
1364 si->unlock_typeahead[i] = 0;
1365 update_passwd_window (si, si->unlock_typeahead, pw->ratio);
1367 free (si->unlock_typeahead);
1368 si->unlock_typeahead = 0;
1373 unlock_p (saver_info *si)
1375 saver_preferences *p = &si->prefs;
1378 raise_window (si, True, True, True);
1381 fprintf (stderr, "%s: prompting for password.\n", blurb());
1383 if (si->pw_data || si->passwd_dialog)
1384 destroy_passwd_window (si);
1386 make_passwd_window (si);
1388 compose_status = calloc (1, sizeof (*compose_status));
1390 handle_typeahead (si);
1391 passwd_event_loop (si);
1393 status = (si->pw_data->state == pw_ok);
1394 destroy_passwd_window (si);
1396 free (compose_status);
1404 set_locked_p (saver_info *si, Bool locked_p)
1406 si->locked_p = locked_p;
1408 #ifdef HAVE_XHPDISABLERESET
1409 hp_lock_reset (si, locked_p); /* turn off/on C-Sh-Reset */
1411 #ifdef HAVE_VT_LOCKSWITCH
1412 linux_lock_vt_switch (si, locked_p); /* turn off/on C-Alt-F1 */
1414 #ifdef HAVE_XF86VMODE
1415 xfree_lock_mode_switch (si, locked_p); /* turn off/on C-Alt-Plus */
1417 #ifdef HAVE_XF86MISCSETGRABKEYSSTATE
1418 xfree_lock_grab_smasher (si, locked_p); /* turn off/on C-Alt-KP-*,/ */
1421 store_saver_status (si); /* store locked-p */
1425 #else /* NO_LOCKING -- whole file */
1428 set_locked_p (saver_info *si, Bool locked_p)
1430 if (locked_p) abort();
1433 #endif /* !NO_LOCKING */