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 #ifdef HAVE_XHPDISABLERESET
886 /* This function enables and disables the C-Sh-Reset hot-key, which
887 normally resets the X server (logging out the logged-in user.)
888 We don't want random people to be able to do that while the
892 hp_lock_reset (saver_info *si, Bool lock_p)
894 static Bool hp_locked_p = False;
896 /* Calls to XHPDisableReset and XHPEnableReset must be balanced,
897 or BadAccess errors occur. (It's ok for this to be global,
898 since it affects the whole machine, not just the current screen.)
900 if (hp_locked_p == lock_p)
904 XHPDisableReset (si->dpy);
906 XHPEnableReset (si->dpy);
907 hp_locked_p = lock_p;
909 #endif /* HAVE_XHPDISABLERESET */
912 #ifdef HAVE_XF86MISCSETGRABKEYSSTATE
914 /* This function enables and disables the Ctrl-Alt-KP_star and
915 Ctrl-Alt-KP_slash hot-keys, which (in XFree86 4.2) break any
916 grabs and/or kill the grabbing client. That would effectively
917 unlock the screen, so we don't like that.
919 The Ctrl-Alt-KP_star and Ctrl-Alt-KP_slash hot-keys only exist
920 if AllowDeactivateGrabs and/or AllowClosedownGrabs are turned on
921 in XF86Config. I believe they are disabled by default.
923 This does not affect any other keys (specifically Ctrl-Alt-BS or
924 Ctrl-Alt-F1) but I wish it did. Maybe it will someday.
927 xfree_lock_grab_smasher (saver_info *si, Bool lock_p)
929 saver_preferences *p = &si->prefs;
930 int status = XF86MiscSetGrabKeysState (si->dpy, !lock_p);
932 if (p->verbose_p && status != MiscExtGrabStateSuccess)
933 fprintf (stderr, "%s: error: XF86MiscSetGrabKeysState returned %s\n",
935 (status == MiscExtGrabStateSuccess ? "MiscExtGrabStateSuccess" :
936 status == MiscExtGrabStateLocked ? "MiscExtGrabStateLocked" :
937 status == MiscExtGrabStateAlready ? "MiscExtGrabStateAlready" :
940 #endif /* HAVE_XF86MISCSETGRABKEYSSTATE */
945 /* This function enables and disables the C-Sh-F1 ... F12 hot-keys,
946 which, on Linux systems, switches to another virtual console.
947 We'd like the whole screen/keyboard to be locked, not just one
948 virtual console, so this function disables that while the X
951 Unfortunately, this doesn't work -- this ioctl only works when
952 called by root, and we have disavowed our privileges long ago.
954 #ifdef HAVE_VT_LOCKSWITCH
956 linux_lock_vt_switch (saver_info *si, Bool lock_p)
958 saver_preferences *p = &si->prefs;
959 static Bool vt_locked_p = False;
960 const char *dev_console = "/dev/console";
963 if (lock_p == vt_locked_p)
966 if (lock_p && !p->lock_vt_p)
969 fd = open (dev_console, O_RDWR);
973 sprintf (buf, "%s: couldn't %s VTs: %s", blurb(),
974 (lock_p ? "lock" : "unlock"),
976 #if 1 /* #### doesn't work yet, so don't bother complaining */
982 if (ioctl (fd, (lock_p ? VT_LOCKSWITCH : VT_UNLOCKSWITCH)) == 0)
984 vt_locked_p = lock_p;
987 fprintf (stderr, "%s: %s VTs\n", blurb(),
988 (lock_p ? "locked" : "unlocked"));
993 sprintf (buf, "%s: couldn't %s VTs: ioctl", blurb(),
994 (lock_p ? "lock" : "unlock"));
995 #if 0 /* #### doesn't work yet, so don't bother complaining */
1002 #endif /* HAVE_VT_LOCKSWITCH */
1005 /* This function enables and disables the C-Alt-Plus and C-Alt-Minus
1006 hot-keys, which normally change the resolution of the X server.
1007 We don't want people to be able to switch the server resolution
1008 while the screen is locked, because if they switch to a higher
1009 resolution, it could cause part of the underlying desktop to become
1012 #ifdef HAVE_XF86VMODE
1014 static int ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error);
1015 static Bool vp_got_error = False;
1018 xfree_lock_mode_switch (saver_info *si, Bool lock_p)
1020 static Bool any_mode_locked_p = False;
1021 saver_preferences *p = &si->prefs;
1025 XErrorHandler old_handler;
1027 if (any_mode_locked_p == lock_p)
1029 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1032 for (screen = 0; screen < si->nscreens; screen++)
1034 XSync (si->dpy, False);
1035 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1036 status = XF86VidModeLockModeSwitch (si->dpy, screen, lock_p);
1037 XSync (si->dpy, False);
1038 XSetErrorHandler (old_handler);
1039 if (vp_got_error) status = False;
1042 any_mode_locked_p = lock_p;
1044 if (!status && (p->verbose_p || !lock_p))
1045 /* Only print this when verbose, or when we locked but can't unlock.
1046 I tried printing this message whenever it comes up, but
1047 mode-locking always fails if DontZoom is set in XF86Config. */
1048 fprintf (stderr, "%s: %d: unable to %s mode switching!\n",
1049 blurb(), screen, (lock_p ? "lock" : "unlock"));
1050 else if (p->verbose_p)
1051 fprintf (stderr, "%s: %d: %s mode switching.\n",
1052 blurb(), screen, (lock_p ? "locked" : "unlocked"));
1057 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1059 vp_got_error = True;
1063 #endif /* HAVE_XF86VMODE */
1066 /* If the viewport has been scrolled since the screen was blanked,
1067 then scroll it back to where it belongs. This function only exists
1068 to patch over a very brief race condition.
1071 undo_vp_motion (saver_info *si)
1073 #ifdef HAVE_XF86VMODE
1074 saver_preferences *p = &si->prefs;
1078 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1081 for (screen = 0; screen < si->nscreens; screen++)
1083 saver_screen_info *ssi = &si->screens[screen];
1087 if (ssi->blank_vp_x == -1 && ssi->blank_vp_y == -1)
1089 if (!XF86VidModeGetViewPort (si->dpy, screen, &x, &y))
1091 if (ssi->blank_vp_x == x && ssi->blank_vp_y == y)
1094 /* We're going to move the viewport. The mouse has just been grabbed on
1095 (and constrained to, thus warped to) the password window, so it is no
1096 longer near the edge of the screen. However, wait a bit anyway, just
1097 to make sure the server drains its last motion event, so that the
1098 screen doesn't continue to scroll after we've reset the viewport.
1100 XSync (si->dpy, False);
1101 usleep (250000); /* 1/4 second */
1102 XSync (si->dpy, False);
1104 status = XF86VidModeSetViewPort (si->dpy, screen,
1105 ssi->blank_vp_x, ssi->blank_vp_y);
1109 "%s: %d: unable to move vp from (%d,%d) back to (%d,%d)!\n",
1110 blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1111 else if (p->verbose_p)
1113 "%s: %d: vp moved to (%d,%d); moved it back to (%d,%d).\n",
1114 blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1116 #endif /* HAVE_XF86VMODE */
1125 passwd_animate_timer (XtPointer closure, XtIntervalId *id)
1127 saver_info *si = (saver_info *) closure;
1129 passwd_dialog_data *pw = si->pw_data;
1133 pw->ratio -= (1.0 / ((double) si->prefs.passwd_timeout / (double) tick));
1137 if (pw->state == pw_read)
1138 pw->state = pw_time;
1141 update_passwd_window (si, 0, pw->ratio);
1143 if (pw->state == pw_read)
1144 pw->timer = XtAppAddTimeOut (si->app, tick, passwd_animate_timer,
1149 idle_timer ((XtPointer) si, id);
1153 static XComposeStatus *compose_status;
1156 handle_passwd_key (saver_info *si, XKeyEvent *event)
1158 saver_preferences *p = &si->prefs;
1159 passwd_dialog_data *pw = si->pw_data;
1160 int pw_size = sizeof (pw->typed_passwd) - 1;
1161 char *typed_passwd = pw->typed_passwd;
1165 int size = XLookupString (event, s, 1, 0, compose_status);
1167 if (size != 1) return;
1173 case '\010': case '\177': /* Backspace */
1177 typed_passwd [strlen(typed_passwd)-1] = 0;
1180 case '\025': case '\030': /* Erase line */
1181 memset (typed_passwd, 0, pw_size);
1184 case '\012': case '\015': /* Enter */
1185 if (pw->state != pw_read)
1186 ; /* already done? */
1187 else if (typed_passwd[0] == 0)
1188 pw->state = pw_null;
1191 update_passwd_window (si, "Checking...", pw->ratio);
1192 XSync (si->dpy, False);
1193 if (passwd_valid_p (typed_passwd, p->verbose_p))
1196 pw->state = pw_fail;
1197 update_passwd_window (si, "", pw->ratio);
1202 i = strlen (typed_passwd);
1207 typed_passwd [i] = *s;
1208 typed_passwd [i+1] = 0;
1213 i = strlen(typed_passwd);
1214 stars = (char *) malloc(i+1);
1215 memset (stars, '*', i);
1217 update_passwd_window (si, stars, pw->ratio);
1223 passwd_event_loop (saver_info *si)
1225 saver_preferences *p = &si->prefs;
1228 passwd_animate_timer ((XtPointer) si, 0);
1230 while (si->pw_data && si->pw_data->state == pw_read)
1232 XtAppNextEvent (si->app, &event);
1233 if (event.xany.window == si->passwd_dialog && event.xany.type == Expose)
1234 draw_passwd_window (si);
1235 else if (event.xany.type == KeyPress)
1236 handle_passwd_key (si, &event.xkey);
1238 XtDispatchEvent (&event);
1241 switch (si->pw_data->state)
1243 case pw_ok: msg = 0; break;
1244 case pw_null: msg = ""; break;
1245 case pw_time: msg = "Timed out!"; break;
1246 default: msg = "Sorry!"; break;
1249 if (si->pw_data->state == pw_fail)
1250 si->unlock_failures++;
1253 switch (si->pw_data->state)
1256 fprintf (stderr, "%s: password correct.\n", blurb()); break;
1258 fprintf (stderr, "%s: password incorrect!\n", blurb()); break;
1261 fprintf (stderr, "%s: password entry cancelled.\n", blurb()); break;
1263 fprintf (stderr, "%s: password entry timed out.\n", blurb()); break;
1268 if (si->pw_data->state == pw_fail)
1270 /* If they typed a password (as opposed to just hitting return) and
1271 the password was invalid, log it.
1273 struct passwd *pw = getpwuid (getuid ());
1274 char *d = DisplayString (si->dpy);
1275 char *u = (pw->pw_name ? pw->pw_name : "???");
1283 # if defined(LOG_AUTHPRIV)
1285 # elif defined(LOG_AUTH)
1292 openlog (progname, opt, fac);
1293 syslog (LOG_NOTICE, "FAILED LOGIN %d ON DISPLAY \"%s\", FOR \"%s\"",
1294 si->unlock_failures, d, u);
1297 #endif /* HAVE_SYSLOG */
1299 if (si->pw_data->state == pw_fail)
1300 XBell (si->dpy, False);
1302 if (si->pw_data->state == pw_ok && si->unlock_failures != 0)
1304 if (si->unlock_failures == 1)
1305 fprintf (real_stderr,
1306 "%s: WARNING: 1 failed attempt to unlock the screen.\n",
1309 fprintf (real_stderr,
1310 "%s: WARNING: %d failed attempts to unlock the screen.\n",
1311 blurb(), si->unlock_failures);
1312 fflush (real_stderr);
1314 si->unlock_failures = 0;
1319 si->pw_data->i_beam = 0;
1320 update_passwd_window (si, msg, 0.0);
1321 XSync (si->dpy, False);
1324 /* Swallow all pending KeyPress/KeyRelease events. */
1327 while (XCheckMaskEvent (si->dpy, KeyPressMask|KeyReleaseMask, &e))
1335 handle_typeahead (saver_info *si)
1337 passwd_dialog_data *pw = si->pw_data;
1339 if (!si->unlock_typeahead)
1342 i = strlen (si->unlock_typeahead);
1343 if (i >= sizeof(pw->typed_passwd) - 1)
1344 i = sizeof(pw->typed_passwd) - 1;
1346 memcpy (pw->typed_passwd, si->unlock_typeahead, i);
1347 pw->typed_passwd [i] = 0;
1349 memset (si->unlock_typeahead, '*', strlen(si->unlock_typeahead));
1350 si->unlock_typeahead[i] = 0;
1351 update_passwd_window (si, si->unlock_typeahead, pw->ratio);
1353 free (si->unlock_typeahead);
1354 si->unlock_typeahead = 0;
1359 unlock_p (saver_info *si)
1361 saver_preferences *p = &si->prefs;
1364 raise_window (si, True, True, True);
1367 fprintf (stderr, "%s: prompting for password.\n", blurb());
1369 if (si->pw_data || si->passwd_dialog)
1370 destroy_passwd_window (si);
1372 make_passwd_window (si);
1374 compose_status = calloc (1, sizeof (*compose_status));
1376 handle_typeahead (si);
1377 passwd_event_loop (si);
1379 status = (si->pw_data->state == pw_ok);
1380 destroy_passwd_window (si);
1382 free (compose_status);
1390 set_locked_p (saver_info *si, Bool locked_p)
1392 si->locked_p = locked_p;
1394 #ifdef HAVE_XHPDISABLERESET
1395 hp_lock_reset (si, locked_p); /* turn off/on C-Sh-Reset */
1397 #ifdef HAVE_VT_LOCKSWITCH
1398 linux_lock_vt_switch (si, locked_p); /* turn off/on C-Alt-F1 */
1400 #ifdef HAVE_XF86VMODE
1401 xfree_lock_mode_switch (si, locked_p); /* turn off/on C-Alt-Plus */
1403 #ifdef HAVE_XF86MISCSETGRABKEYSSTATE
1404 xfree_lock_grab_smasher (si, locked_p); /* turn off/on C-Alt-KP-*,/ */
1407 store_saver_status (si); /* store locked-p */
1411 #else /* NO_LOCKING -- whole file */
1414 set_locked_p (saver_info *si, Bool locked_p)
1416 if (locked_p) abort();
1419 #endif /* !NO_LOCKING */