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 */
52 ERROR! You must not include vroot.h in this file.
59 extern char *getenv(const char *name);
60 extern int validate_user(char *name, char *password);
63 vms_passwd_valid_p(char *pw, Bool verbose_p)
65 return (validate_user (getenv("USER"), typed_passwd) == 1);
67 # undef passwd_valid_p
68 # define passwd_valid_p vms_passwd_valid_p
74 #define MAX(a,b) ((a)>(b)?(a):(b))
76 enum passwd_state { pw_read, pw_ok, pw_null, pw_fail, pw_cancel, pw_time };
78 struct passwd_dialog_data {
80 saver_screen_info *prompt_screen;
81 int previous_mouse_x, previous_mouse_y;
83 enum passwd_state state;
84 char typed_passwd [80];
92 Dimension border_width;
102 XFontStruct *heading_font;
103 XFontStruct *body_font;
104 XFontStruct *label_font;
105 XFontStruct *passwd_font;
106 XFontStruct *date_font;
110 Pixel passwd_foreground;
111 Pixel passwd_background;
112 Pixel thermo_foreground;
113 Pixel thermo_background;
117 Dimension logo_width;
118 Dimension logo_height;
119 Dimension thermo_width;
120 Dimension internal_border;
121 Dimension shadow_width;
123 Dimension passwd_field_x, passwd_field_y;
124 Dimension passwd_field_width, passwd_field_height;
126 Dimension thermo_field_x, thermo_field_y;
127 Dimension thermo_field_height;
131 unsigned long *logo_pixels;
136 static void draw_passwd_window (saver_info *si);
137 static void update_passwd_window (saver_info *si, const char *printed_passwd,
139 static void destroy_passwd_window (saver_info *si);
140 static void undo_vp_motion (saver_info *si);
144 make_passwd_window (saver_info *si)
146 struct passwd *p = getpwuid (getuid ());
147 XSetWindowAttributes attrs;
148 unsigned long attrmask = 0;
149 passwd_dialog_data *pw = (passwd_dialog_data *) calloc (1, sizeof(*pw));
154 pw->prompt_screen = &si->screens [mouse_screen (si)];
155 if (si->prefs.verbose_p)
156 fprintf (stderr, "%s: %d: creating password dialog.\n",
157 blurb(), pw->prompt_screen->number);
159 screen = pw->prompt_screen->screen;
160 cmap = DefaultColormapOfScreen (screen);
164 pw->heading_label = get_string_resource ("passwd.heading.label",
165 "Dialog.Label.Label");
166 pw->body_label = get_string_resource ("passwd.body.label",
167 "Dialog.Label.Label");
168 pw->user_label = get_string_resource ("passwd.user.label",
169 "Dialog.Label.Label");
170 pw->passwd_label = get_string_resource ("passwd.passwd.label",
171 "Dialog.Label.Label");
172 pw->date_label = get_string_resource ("dateFormat", "DateFormat");
174 if (!pw->heading_label)
175 pw->heading_label = strdup("ERROR: REESOURCES NOT INSTALLED CORRECTLY");
177 pw->body_label = strdup("ERROR: REESOURCES NOT INSTALLED CORRECTLY");
178 if (!pw->user_label) pw->user_label = strdup("ERROR");
179 if (!pw->passwd_label) pw->passwd_label = strdup("ERROR");
180 if (!pw->date_label) pw->date_label = strdup("ERROR");
182 /* Put the version number in the label. */
184 char *s = (char *) malloc (strlen(pw->heading_label) + 20);
185 sprintf(s, pw->heading_label, si->version);
186 free (pw->heading_label);
187 pw->heading_label = s;
190 pw->user_string = strdup (p && p->pw_name ? p->pw_name : "???");
191 pw->passwd_string = strdup("");
193 f = get_string_resource ("passwd.headingFont", "Dialog.Font");
194 pw->heading_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
195 if (!pw->heading_font) pw->heading_font = XLoadQueryFont (si->dpy, "fixed");
198 f = get_string_resource("passwd.bodyFont", "Dialog.Font");
199 pw->body_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
200 if (!pw->body_font) pw->body_font = XLoadQueryFont (si->dpy, "fixed");
203 f = get_string_resource("passwd.labelFont", "Dialog.Font");
204 pw->label_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
205 if (!pw->label_font) pw->label_font = XLoadQueryFont (si->dpy, "fixed");
208 f = get_string_resource("passwd.passwdFont", "Dialog.Font");
209 pw->passwd_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
210 if (!pw->passwd_font) pw->passwd_font = XLoadQueryFont (si->dpy, "fixed");
213 f = get_string_resource("passwd.dateFont", "Dialog.Font");
214 pw->date_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
215 if (!pw->date_font) pw->date_font = XLoadQueryFont (si->dpy, "fixed");
218 pw->foreground = get_pixel_resource ("passwd.foreground",
221 pw->background = get_pixel_resource ("passwd.background",
225 if (pw->foreground == pw->background)
227 /* Make sure the error messages show up. */
228 pw->foreground = BlackPixelOfScreen (screen);
229 pw->background = WhitePixelOfScreen (screen);
232 pw->passwd_foreground = get_pixel_resource ("passwd.text.foreground",
233 "Dialog.Text.Foreground",
235 pw->passwd_background = get_pixel_resource ("passwd.text.background",
236 "Dialog.Text.Background",
238 pw->thermo_foreground = get_pixel_resource ("passwd.thermometer.foreground",
239 "Dialog.Thermometer.Foreground",
241 pw->thermo_background = get_pixel_resource ("passwd.thermometer.background",
242 "Dialog.Thermometer.Background",
244 pw->shadow_top = get_pixel_resource ("passwd.topShadowColor",
247 pw->shadow_bottom = get_pixel_resource ("passwd.bottomShadowColor",
251 pw->logo_width = get_integer_resource ("passwd.logo.width",
252 "Dialog.Logo.Width");
253 pw->logo_height = get_integer_resource ("passwd.logo.height",
254 "Dialog.Logo.Height");
255 pw->thermo_width = get_integer_resource ("passwd.thermometer.width",
256 "Dialog.Thermometer.Width");
257 pw->internal_border = get_integer_resource ("passwd.internalBorderWidth",
258 "Dialog.InternalBorderWidth");
259 pw->shadow_width = get_integer_resource ("passwd.shadowThickness",
260 "Dialog.ShadowThickness");
262 if (pw->logo_width == 0) pw->logo_width = 150;
263 if (pw->logo_height == 0) pw->logo_height = 150;
264 if (pw->internal_border == 0) pw->internal_border = 15;
265 if (pw->shadow_width == 0) pw->shadow_width = 4;
266 if (pw->thermo_width == 0) pw->thermo_width = pw->shadow_width;
269 int direction, ascent, descent;
275 /* Measure the heading_label. */
276 XTextExtents (pw->heading_font,
277 pw->heading_label, strlen(pw->heading_label),
278 &direction, &ascent, &descent, &overall);
279 if (overall.width > pw->width) pw->width = overall.width;
280 pw->height += ascent + descent;
282 /* Measure the body_label. */
283 XTextExtents (pw->body_font,
284 pw->body_label, strlen(pw->body_label),
285 &direction, &ascent, &descent, &overall);
286 if (overall.width > pw->width) pw->width = overall.width;
287 pw->height += ascent + descent;
290 Dimension w2 = 0, w3 = 0;
291 Dimension h2 = 0, h3 = 0;
292 const char *passwd_string = "MMMMMMMMMMMM";
294 /* Measure the user_label. */
295 XTextExtents (pw->label_font,
296 pw->user_label, strlen(pw->user_label),
297 &direction, &ascent, &descent, &overall);
298 if (overall.width > w2) w2 = overall.width;
299 h2 += ascent + descent;
301 /* Measure the passwd_label. */
302 XTextExtents (pw->label_font,
303 pw->passwd_label, strlen(pw->passwd_label),
304 &direction, &ascent, &descent, &overall);
305 if (overall.width > w2) w2 = overall.width;
306 h2 += ascent + descent;
308 /* Measure the user_string. */
309 XTextExtents (pw->passwd_font,
310 pw->user_string, strlen(pw->user_string),
311 &direction, &ascent, &descent, &overall);
312 overall.width += (pw->shadow_width * 4);
313 ascent += (pw->shadow_width * 4);
314 if (overall.width > w3) w3 = overall.width;
315 h3 += ascent + descent;
317 /* Measure the (maximally-sized, dummy) passwd_string. */
318 XTextExtents (pw->passwd_font,
319 passwd_string, strlen(passwd_string),
320 &direction, &ascent, &descent, &overall);
321 overall.width += (pw->shadow_width * 4);
322 ascent += (pw->shadow_width * 4);
323 if (overall.width > w3) w3 = overall.width;
324 h3 += ascent + descent;
326 w2 = w2 + w3 + (pw->shadow_width * 2);
329 if (w2 > pw->width) pw->width = w2;
333 pw->width += (pw->internal_border * 2);
334 pw->height += (pw->internal_border * 4);
336 pw->width += pw->thermo_width + (pw->shadow_width * 3);
338 if (pw->logo_height > pw->height)
339 pw->height = pw->logo_height;
340 else if (pw->height > pw->logo_height)
341 pw->logo_height = pw->height;
343 pw->logo_width = pw->logo_height;
345 pw->width += pw->logo_width;
348 attrmask |= CWOverrideRedirect; attrs.override_redirect = True;
349 attrmask |= CWEventMask; attrs.event_mask = ExposureMask|KeyPressMask;
351 /* We need to remember the mouse position and restore it afterward, or
352 sometimes (perhaps only with Xinerama?) the mouse gets warped to
353 inside the bounds of the lock dialog window.
356 Window pointer_root, pointer_child;
357 int root_x, root_y, win_x, win_y;
359 pw->previous_mouse_x = 0;
360 pw->previous_mouse_y = 0;
361 if (XQueryPointer (si->dpy, RootWindowOfScreen (pw->prompt_screen->screen),
362 &pointer_root, &pointer_child,
363 &root_x, &root_y, &win_x, &win_y, &mask))
365 pw->previous_mouse_x = root_x;
366 pw->previous_mouse_y = root_y;
367 if (si->prefs.verbose_p)
368 fprintf (stderr, "%s: %d: mouse is at %d,%d.\n",
369 blurb(), pw->prompt_screen->number,
370 pw->previous_mouse_x, pw->previous_mouse_y);
372 else if (si->prefs.verbose_p)
373 fprintf (stderr, "%s: %d: unable to determine mouse position?\n",
374 blurb(), pw->prompt_screen->number);
377 /* Figure out where on the desktop to place the window so that it will
378 actually be visible; this takes into account virtual viewports as
382 get_screen_viewport (pw->prompt_screen, &x, &y, &w, &h,
383 pw->previous_mouse_x, pw->previous_mouse_y,
384 si->prefs.verbose_p);
385 if (si->prefs.debug_p) w /= 2;
386 pw->x = x + ((w + pw->width) / 2) - pw->width;
387 pw->y = y + ((h + pw->height) / 2) - pw->height;
388 if (pw->x < x) pw->x = x;
389 if (pw->y < y) pw->y = y;
392 pw->border_width = get_integer_resource ("passwd.borderWidth",
393 "Dialog.BorderWidth");
396 XCreateWindow (si->dpy,
397 RootWindowOfScreen(screen),
398 pw->x, pw->y, pw->width, pw->height, pw->border_width,
399 DefaultDepthOfScreen (screen), InputOutput,
400 DefaultVisualOfScreen(screen),
402 XSetWindowBackground (si->dpy, si->passwd_dialog, pw->background);
404 pw->logo_pixmap = xscreensaver_logo (si->dpy, si->passwd_dialog, cmap,
406 &pw->logo_pixels, &pw->logo_npixels,
409 /* Before mapping the window, save the bits that are underneath the
410 rectangle the window will occlude. When we lower the window, we
411 restore these bits. This works, because the running screenhack
412 has already been sent SIGSTOP, so we know nothing else is drawing
417 pw->save_under = XCreatePixmap (si->dpy,
418 pw->prompt_screen->screensaver_window,
419 pw->width + (pw->border_width*2) + 1,
420 pw->height + (pw->border_width*2) + 1,
421 pw->prompt_screen->current_depth);
422 gcv.function = GXcopy;
423 gc = XCreateGC (si->dpy, pw->save_under, GCFunction, &gcv);
424 XCopyArea (si->dpy, pw->prompt_screen->screensaver_window,
426 pw->x - pw->border_width, pw->y - pw->border_width,
427 pw->width + (pw->border_width*2) + 1,
428 pw->height + (pw->border_width*2) + 1,
430 XFreeGC (si->dpy, gc);
433 XMapRaised (si->dpy, si->passwd_dialog);
434 XSync (si->dpy, False);
436 move_mouse_grab (si, si->passwd_dialog,
437 pw->prompt_screen->cursor,
438 pw->prompt_screen->number);
444 XInstallColormap (si->dpy, cmap);
445 draw_passwd_window (si);
446 XSync (si->dpy, False);
451 draw_passwd_window (saver_info *si)
453 passwd_dialog_data *pw = si->pw_data;
457 int x1, x2, x3, y1, y2;
461 height = (pw->heading_font->ascent + pw->heading_font->descent +
462 pw->body_font->ascent + pw->body_font->descent +
463 (2 * MAX ((pw->label_font->ascent + pw->label_font->descent),
464 (pw->passwd_font->ascent + pw->passwd_font->descent +
465 (pw->shadow_width * 4)))) +
466 pw->date_font->ascent + pw->date_font->descent
468 spacing = ((pw->height - (2 * pw->shadow_width) -
469 pw->internal_border - height)) / 8;
470 if (spacing < 0) spacing = 0;
472 gcv.foreground = pw->foreground;
473 gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
474 gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
475 x1 = pw->logo_width + pw->thermo_width + (pw->shadow_width * 3);
476 x3 = pw->width - (pw->shadow_width * 2);
477 y1 = (pw->shadow_width * 2) + spacing + spacing;
481 XSetFont (si->dpy, gc1, pw->heading_font->fid);
482 sw = string_width (pw->heading_font, pw->heading_label);
483 x2 = (x1 + ((x3 - x1 - sw) / 2));
484 y1 += spacing + pw->heading_font->ascent + pw->heading_font->descent;
485 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
486 pw->heading_label, strlen(pw->heading_label));
488 /* text below top heading
490 XSetFont (si->dpy, gc1, pw->body_font->fid);
491 y1 += spacing + pw->body_font->ascent + pw->body_font->descent;
492 sw = string_width (pw->body_font, pw->body_label);
493 x2 = (x1 + ((x3 - x1 - sw) / 2));
494 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
495 pw->body_label, strlen(pw->body_label));
498 tb_height = (pw->passwd_font->ascent + pw->passwd_font->descent +
499 (pw->shadow_width * 4));
501 /* the "User:" prompt
505 XSetForeground (si->dpy, gc1, pw->foreground);
506 XSetFont (si->dpy, gc1, pw->label_font->fid);
507 y1 += (spacing + tb_height);
508 x2 = (x1 + pw->internal_border +
509 MAX(string_width (pw->label_font, pw->user_label),
510 string_width (pw->label_font, pw->passwd_label)));
511 XDrawString (si->dpy, si->passwd_dialog, gc1,
512 x2 - string_width (pw->label_font, pw->user_label),
514 pw->user_label, strlen(pw->user_label));
516 /* the "Password:" prompt
518 y1 += (spacing + tb_height);
519 XDrawString (si->dpy, si->passwd_dialog, gc1,
520 x2 - string_width (pw->label_font, pw->passwd_label),
522 pw->passwd_label, strlen(pw->passwd_label));
525 XSetForeground (si->dpy, gc2, pw->passwd_background);
527 /* the "user name" text field
530 XSetForeground (si->dpy, gc1, pw->passwd_foreground);
531 XSetFont (si->dpy, gc1, pw->passwd_font->fid);
532 y1 += (spacing + tb_height);
533 x2 += (pw->shadow_width * 4);
535 pw->passwd_field_width = x3 - x2 - pw->internal_border;
536 pw->passwd_field_height = (pw->passwd_font->ascent +
537 pw->passwd_font->descent +
540 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
541 x2 - pw->shadow_width,
542 y1 - (pw->passwd_font->ascent + pw->passwd_font->descent),
543 pw->passwd_field_width, pw->passwd_field_height);
544 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
545 pw->user_string, strlen(pw->user_string));
547 /* the "password" text field
549 y1 += (spacing + tb_height);
551 pw->passwd_field_x = x2 - pw->shadow_width;
552 pw->passwd_field_y = y1 - (pw->passwd_font->ascent +
553 pw->passwd_font->descent);
555 /* The shadow around the text fields
558 y1 += (spacing + (pw->shadow_width * 3));
559 x1 = x2 - (pw->shadow_width * 2);
560 x2 = pw->passwd_field_width + (pw->shadow_width * 2);
561 y2 = pw->passwd_field_height + (pw->shadow_width * 2);
563 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
566 pw->shadow_bottom, pw->shadow_top);
568 y1 += (spacing + pw->passwd_font->ascent + pw->passwd_font->descent +
569 (pw->shadow_width * 4));
570 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
573 pw->shadow_bottom, pw->shadow_top);
576 /* The date, below the text fields
580 time_t now = time ((time_t *) 0);
581 struct tm *tm = localtime (&now);
582 memset (buf, 0, sizeof(buf));
583 strftime (buf, sizeof(buf)-1, pw->date_label, tm);
585 XSetFont (si->dpy, gc1, pw->date_font->fid);
586 y1 += pw->shadow_width;
587 y1 += (spacing + tb_height);
589 sw = string_width (pw->date_font, buf);
591 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1, buf, strlen(buf));
597 x1 = pw->shadow_width * 6;
598 y1 = pw->shadow_width * 6;
599 x2 = pw->logo_width - (pw->shadow_width * 12);
600 y2 = pw->logo_height - (pw->shadow_width * 12);
606 unsigned int w, h, bw, d;
607 XGetGeometry (si->dpy, pw->logo_pixmap, &root, &x, &y, &w, &h, &bw, &d);
608 XSetForeground (si->dpy, gc1, pw->foreground);
609 XSetBackground (si->dpy, gc1, pw->background);
611 XCopyPlane (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1,
613 x1 + ((x2 - (int)w) / 2),
614 y1 + ((y2 - (int)h) / 2),
617 XCopyArea (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1,
619 x1 + ((x2 - (int)w) / 2),
620 y1 + ((y2 - (int)h) / 2));
625 XSetForeground (si->dpy, gc1, pw->thermo_foreground);
626 XSetForeground (si->dpy, gc2, pw->thermo_background);
628 pw->thermo_field_x = pw->logo_width + pw->shadow_width;
629 pw->thermo_field_y = pw->shadow_width * 5;
630 pw->thermo_field_height = pw->height - (pw->shadow_width * 10);
633 /* Solid border inside the logo box. */
634 XSetForeground (si->dpy, gc1, pw->foreground);
635 XDrawRectangle (si->dpy, si->passwd_dialog, gc1, x1, y1, x2-1, y2-1);
638 /* The shadow around the logo
640 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
641 pw->shadow_width * 4,
642 pw->shadow_width * 4,
643 pw->logo_width - (pw->shadow_width * 8),
644 pw->logo_height - (pw->shadow_width * 8),
646 pw->shadow_bottom, pw->shadow_top);
648 /* The shadow around the thermometer
650 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
652 pw->shadow_width * 4,
653 pw->thermo_width + (pw->shadow_width * 2),
654 pw->height - (pw->shadow_width * 8),
656 pw->shadow_bottom, pw->shadow_top);
659 /* Solid border inside the thermometer. */
660 XSetForeground (si->dpy, gc1, pw->foreground);
661 XDrawRectangle (si->dpy, si->passwd_dialog, gc1,
662 pw->thermo_field_x, pw->thermo_field_y,
663 pw->thermo_width - 1, pw->thermo_field_height - 1);
666 /* The shadow around the whole window
668 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
669 0, 0, pw->width, pw->height, pw->shadow_width,
670 pw->shadow_top, pw->shadow_bottom);
672 XFreeGC (si->dpy, gc1);
673 XFreeGC (si->dpy, gc2);
675 update_passwd_window (si, pw->passwd_string, pw->ratio);
680 update_passwd_window (saver_info *si, const char *printed_passwd, float ratio)
682 passwd_dialog_data *pw = si->pw_data;
689 gcv.foreground = pw->passwd_foreground;
690 gcv.font = pw->passwd_font->fid;
691 gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground|GCFont, &gcv);
692 gcv.foreground = pw->passwd_background;
693 gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
697 char *s = strdup (printed_passwd);
698 if (pw->passwd_string) free (pw->passwd_string);
699 pw->passwd_string = s;
702 /* the "password" text field
704 rects[0].x = pw->passwd_field_x;
705 rects[0].y = pw->passwd_field_y;
706 rects[0].width = pw->passwd_field_width;
707 rects[0].height = pw->passwd_field_height;
709 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
710 rects[0].x, rects[0].y, rects[0].width, rects[0].height);
712 XSetClipRectangles (si->dpy, gc1, 0, 0, rects, 1, Unsorted);
714 XDrawString (si->dpy, si->passwd_dialog, gc1,
715 rects[0].x + pw->shadow_width,
716 rects[0].y + (pw->passwd_font->ascent +
717 pw->passwd_font->descent),
718 pw->passwd_string, strlen(pw->passwd_string));
720 XSetClipMask (si->dpy, gc1, None);
726 x = (rects[0].x + pw->shadow_width +
727 string_width (pw->passwd_font, pw->passwd_string));
728 y = rects[0].y + pw->shadow_width;
730 if (x > rects[0].x + rects[0].width - 1)
731 x = rects[0].x + rects[0].width - 1;
732 XDrawLine (si->dpy, si->passwd_dialog, gc1,
733 x, y, x, y + pw->passwd_font->ascent);
736 pw->i_beam = (pw->i_beam + 1) % 4;
741 y = (pw->thermo_field_height - 2) * (1.0 - pw->ratio);
744 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
745 pw->thermo_field_x + 1,
746 pw->thermo_field_y + 1,
749 XSetForeground (si->dpy, gc1, pw->thermo_foreground);
750 XFillRectangle (si->dpy, si->passwd_dialog, gc1,
751 pw->thermo_field_x + 1,
752 pw->thermo_field_y + 1 + y,
754 MAX (0, pw->thermo_field_height - y - 2));
757 XFreeGC (si->dpy, gc1);
758 XFreeGC (si->dpy, gc2);
759 XSync (si->dpy, False);
764 destroy_passwd_window (saver_info *si)
766 saver_preferences *p = &si->prefs;
767 passwd_dialog_data *pw = si->pw_data;
768 saver_screen_info *ssi = pw->prompt_screen;
769 Colormap cmap = DefaultColormapOfScreen (ssi->screen);
770 Pixel black = BlackPixelOfScreen (ssi->screen);
771 Pixel white = WhitePixelOfScreen (ssi->screen);
774 memset (pw->typed_passwd, 0, sizeof(pw->typed_passwd));
775 memset (pw->passwd_string, 0, strlen(pw->passwd_string));
778 XtRemoveTimeOut (pw->timer);
780 move_mouse_grab (si, RootWindowOfScreen (ssi->screen),
781 ssi->cursor, ssi->number);
784 fprintf (stderr, "%s: %d: moving mouse back to %d,%d.\n",
785 blurb(), ssi->number,
786 pw->previous_mouse_x, pw->previous_mouse_y);
788 XWarpPointer (si->dpy, None, RootWindowOfScreen (ssi->screen),
790 pw->previous_mouse_x, pw->previous_mouse_y);
792 XSync (si->dpy, False);
793 while (XCheckMaskEvent (si->dpy, PointerMotionMask, &event))
795 fprintf (stderr, "%s: discarding MotionNotify event.\n", blurb());
797 if (si->passwd_dialog)
799 XDestroyWindow (si->dpy, si->passwd_dialog);
800 si->passwd_dialog = 0;
807 gcv.function = GXcopy;
808 gc = XCreateGC (si->dpy, ssi->screensaver_window, GCFunction, &gcv);
809 XCopyArea (si->dpy, pw->save_under,
810 ssi->screensaver_window, gc,
812 pw->width + (pw->border_width*2) + 1,
813 pw->height + (pw->border_width*2) + 1,
814 pw->x - pw->border_width, pw->y - pw->border_width);
815 XFreePixmap (si->dpy, pw->save_under);
817 XFreeGC (si->dpy, gc);
820 if (pw->heading_label) free (pw->heading_label);
821 if (pw->body_label) free (pw->body_label);
822 if (pw->user_label) free (pw->user_label);
823 if (pw->passwd_label) free (pw->passwd_label);
824 if (pw->date_label) free (pw->date_label);
825 if (pw->user_string) free (pw->user_string);
826 if (pw->passwd_string) free (pw->passwd_string);
828 if (pw->heading_font) XFreeFont (si->dpy, pw->heading_font);
829 if (pw->body_font) XFreeFont (si->dpy, pw->body_font);
830 if (pw->label_font) XFreeFont (si->dpy, pw->label_font);
831 if (pw->passwd_font) XFreeFont (si->dpy, pw->passwd_font);
832 if (pw->date_font) XFreeFont (si->dpy, pw->date_font);
834 if (pw->foreground != black && pw->foreground != white)
835 XFreeColors (si->dpy, cmap, &pw->foreground, 1, 0L);
836 if (pw->background != black && pw->background != white)
837 XFreeColors (si->dpy, cmap, &pw->background, 1, 0L);
838 if (pw->passwd_foreground != black && pw->passwd_foreground != white)
839 XFreeColors (si->dpy, cmap, &pw->passwd_foreground, 1, 0L);
840 if (pw->passwd_background != black && pw->passwd_background != white)
841 XFreeColors (si->dpy, cmap, &pw->passwd_background, 1, 0L);
842 if (pw->thermo_foreground != black && pw->thermo_foreground != white)
843 XFreeColors (si->dpy, cmap, &pw->thermo_foreground, 1, 0L);
844 if (pw->thermo_background != black && pw->thermo_background != white)
845 XFreeColors (si->dpy, cmap, &pw->thermo_background, 1, 0L);
846 if (pw->shadow_top != black && pw->shadow_top != white)
847 XFreeColors (si->dpy, cmap, &pw->shadow_top, 1, 0L);
848 if (pw->shadow_bottom != black && pw->shadow_bottom != white)
849 XFreeColors (si->dpy, cmap, &pw->shadow_bottom, 1, 0L);
852 XFreePixmap (si->dpy, pw->logo_pixmap);
855 if (pw->logo_npixels)
856 XFreeColors (si->dpy, cmap, pw->logo_pixels, pw->logo_npixels, 0L);
857 free (pw->logo_pixels);
859 pw->logo_npixels = 0;
863 XFreePixmap (si->dpy, pw->save_under);
866 XInstallColormap (si->dpy, cmap);
868 memset (pw, 0, sizeof(*pw));
874 #ifdef HAVE_XHPDISABLERESET
875 /* This function enables and disables the C-Sh-Reset hot-key, which
876 normally resets the X server (logging out the logged-in user.)
877 We don't want random people to be able to do that while the
881 hp_lock_reset (saver_info *si, Bool lock_p)
883 static Bool hp_locked_p = False;
885 /* Calls to XHPDisableReset and XHPEnableReset must be balanced,
886 or BadAccess errors occur. (It's ok for this to be global,
887 since it affects the whole machine, not just the current screen.)
889 if (hp_locked_p == lock_p)
893 XHPDisableReset (si->dpy);
895 XHPEnableReset (si->dpy);
896 hp_locked_p = lock_p;
898 #endif /* HAVE_XHPDISABLERESET */
902 /* This function enables and disables the C-Sh-F1 ... F12 hot-keys,
903 which, on Linux systems, switches to another virtual console.
904 We'd like the whole screen/keyboard to be locked, not just one
905 virtual console, so this function disables that while the X
908 Unfortunately, this doesn't work -- this ioctl only works when
909 called by root, and we have disavowed our privileges long ago.
911 #ifdef HAVE_VT_LOCKSWITCH
913 linux_lock_vt_switch (saver_info *si, Bool lock_p)
915 saver_preferences *p = &si->prefs;
916 static Bool vt_locked_p = False;
917 const char *dev_console = "/dev/console";
920 if (lock_p == vt_locked_p)
923 if (lock_p && !p->lock_vt_p)
926 fd = open (dev_console, O_RDWR);
930 sprintf (buf, "%s: couldn't %s VTs: %s", blurb(),
931 (lock_p ? "lock" : "unlock"),
933 #if 1 /* #### doesn't work yet, so don't bother complaining */
939 if (ioctl (fd, (lock_p ? VT_LOCKSWITCH : VT_UNLOCKSWITCH)) == 0)
941 vt_locked_p = lock_p;
944 fprintf (stderr, "%s: %s VTs\n", blurb(),
945 (lock_p ? "locked" : "unlocked"));
950 sprintf (buf, "%s: couldn't %s VTs: ioctl", blurb(),
951 (lock_p ? "lock" : "unlock"));
952 #if 0 /* #### doesn't work yet, so don't bother complaining */
959 #endif /* HAVE_VT_LOCKSWITCH */
962 /* This function enables and disables the C-Alt-Plus and C-Alt-Minus
963 hot-keys, which normally change the resolution of the X server.
964 We don't want people to be able to switch the server resolution
965 while the screen is locked, because if they switch to a higher
966 resolution, it could cause part of the underlying desktop to become
969 #ifdef HAVE_XF86VMODE
971 static int ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error);
972 static Bool vp_got_error = False;
975 xfree_lock_mode_switch (saver_info *si, Bool lock_p)
977 static Bool any_mode_locked_p = False;
978 saver_preferences *p = &si->prefs;
982 XErrorHandler old_handler;
984 if (any_mode_locked_p == lock_p)
986 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
989 for (screen = 0; screen < si->nscreens; screen++)
991 XSync (si->dpy, False);
992 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
993 status = XF86VidModeLockModeSwitch (si->dpy, screen, lock_p);
994 XSync (si->dpy, False);
995 XSetErrorHandler (old_handler);
996 if (vp_got_error) status = False;
999 any_mode_locked_p = lock_p;
1001 if (!status && (p->verbose_p || !lock_p))
1002 /* Only print this when verbose, or when we locked but can't unlock.
1003 I tried printing this message whenever it comes up, but
1004 mode-locking always fails if DontZoom is set in XF86Config. */
1005 fprintf (stderr, "%s: %d: unable to %s mode switching!\n",
1006 blurb(), screen, (lock_p ? "lock" : "unlock"));
1007 else if (p->verbose_p)
1008 fprintf (stderr, "%s: %d: %s mode switching.\n",
1009 blurb(), screen, (lock_p ? "locked" : "unlocked"));
1014 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1016 vp_got_error = True;
1020 #endif /* HAVE_XF86VMODE */
1023 /* If the viewport has been scrolled since the screen was blanked,
1024 then scroll it back to where it belongs. This function only exists
1025 to patch over a very brief race condition.
1028 undo_vp_motion (saver_info *si)
1030 #ifdef HAVE_XF86VMODE
1031 saver_preferences *p = &si->prefs;
1035 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1038 for (screen = 0; screen < si->nscreens; screen++)
1040 saver_screen_info *ssi = &si->screens[screen];
1044 if (ssi->blank_vp_x == -1 && ssi->blank_vp_y == -1)
1046 if (!XF86VidModeGetViewPort (si->dpy, screen, &x, &y))
1048 if (ssi->blank_vp_x == x && ssi->blank_vp_y == y)
1051 /* We're going to move the viewport. The mouse has just been grabbed on
1052 (and constrained to, thus warped to) the password window, so it is no
1053 longer near the edge of the screen. However, wait a bit anyway, just
1054 to make sure the server drains its last motion event, so that the
1055 screen doesn't continue to scroll after we've reset the viewport.
1057 XSync (si->dpy, False);
1058 usleep (250000); /* 1/4 second */
1059 XSync (si->dpy, False);
1061 status = XF86VidModeSetViewPort (si->dpy, screen,
1062 ssi->blank_vp_x, ssi->blank_vp_y);
1066 "%s: %d: unable to move vp from (%d,%d) back to (%d,%d)!\n",
1067 blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1068 else if (p->verbose_p)
1070 "%s: %d: vp moved to (%d,%d); moved it back to (%d,%d).\n",
1071 blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1073 #endif /* HAVE_XF86VMODE */
1082 passwd_animate_timer (XtPointer closure, XtIntervalId *id)
1084 saver_info *si = (saver_info *) closure;
1086 passwd_dialog_data *pw = si->pw_data;
1090 pw->ratio -= (1.0 / ((double) si->prefs.passwd_timeout / (double) tick));
1094 if (pw->state == pw_read)
1095 pw->state = pw_time;
1098 update_passwd_window (si, 0, pw->ratio);
1100 if (pw->state == pw_read)
1101 pw->timer = XtAppAddTimeOut (si->app, tick, passwd_animate_timer,
1106 idle_timer ((XtPointer) si, id);
1110 static XComposeStatus *compose_status;
1113 handle_passwd_key (saver_info *si, XKeyEvent *event)
1115 saver_preferences *p = &si->prefs;
1116 passwd_dialog_data *pw = si->pw_data;
1117 int pw_size = sizeof (pw->typed_passwd) - 1;
1118 char *typed_passwd = pw->typed_passwd;
1122 int size = XLookupString (event, s, 1, 0, compose_status);
1124 if (size != 1) return;
1130 case '\010': case '\177': /* Backspace */
1134 typed_passwd [strlen(typed_passwd)-1] = 0;
1137 case '\025': case '\030': /* Erase line */
1138 memset (typed_passwd, 0, pw_size);
1141 case '\012': case '\015': /* Enter */
1142 if (pw->state != pw_read)
1143 ; /* already done? */
1144 else if (typed_passwd[0] == 0)
1145 pw->state = pw_null;
1148 update_passwd_window (si, "Checking...", pw->ratio);
1149 XSync (si->dpy, False);
1150 if (passwd_valid_p (typed_passwd, p->verbose_p))
1153 pw->state = pw_fail;
1154 update_passwd_window (si, "", pw->ratio);
1159 i = strlen (typed_passwd);
1164 typed_passwd [i] = *s;
1165 typed_passwd [i+1] = 0;
1170 i = strlen(typed_passwd);
1171 stars = (char *) malloc(i+1);
1172 memset (stars, '*', i);
1174 update_passwd_window (si, stars, pw->ratio);
1180 passwd_event_loop (saver_info *si)
1182 saver_preferences *p = &si->prefs;
1185 passwd_animate_timer ((XtPointer) si, 0);
1187 while (si->pw_data && si->pw_data->state == pw_read)
1189 XtAppNextEvent (si->app, &event);
1190 if (event.xany.window == si->passwd_dialog && event.xany.type == Expose)
1191 draw_passwd_window (si);
1192 else if (event.xany.type == KeyPress)
1193 handle_passwd_key (si, &event.xkey);
1195 XtDispatchEvent (&event);
1198 switch (si->pw_data->state)
1200 case pw_ok: msg = 0; break;
1201 case pw_null: msg = ""; break;
1202 case pw_time: msg = "Timed out!"; break;
1203 default: msg = "Sorry!"; break;
1206 if (si->pw_data->state == pw_fail)
1207 si->unlock_failures++;
1210 switch (si->pw_data->state)
1213 fprintf (stderr, "%s: password correct.\n", blurb()); break;
1215 fprintf (stderr, "%s: password incorrect!\n", blurb()); break;
1218 fprintf (stderr, "%s: password entry cancelled.\n", blurb()); break;
1220 fprintf (stderr, "%s: password entry timed out.\n", blurb()); break;
1225 if (si->pw_data->state == pw_fail)
1227 /* If they typed a password (as opposed to just hitting return) and
1228 the password was invalid, log it.
1230 struct passwd *pw = getpwuid (getuid ());
1231 char *d = DisplayString (si->dpy);
1232 char *u = (pw->pw_name ? pw->pw_name : "???");
1240 # if defined(LOG_AUTHPRIV)
1242 # elif defined(LOG_AUTH)
1249 openlog (progname, opt, fac);
1250 syslog (LOG_NOTICE, "FAILED LOGIN %d ON DISPLAY \"%s\", FOR \"%s\"",
1251 si->unlock_failures, d, u);
1254 #endif /* HAVE_SYSLOG */
1256 if (si->pw_data->state == pw_fail)
1257 XBell (si->dpy, False);
1259 if (si->pw_data->state == pw_ok && si->unlock_failures != 0)
1261 if (si->unlock_failures == 1)
1262 fprintf (real_stderr,
1263 "%s: WARNING: 1 failed attempt to unlock the screen.\n",
1266 fprintf (real_stderr,
1267 "%s: WARNING: %d failed attempts to unlock the screen.\n",
1268 blurb(), si->unlock_failures);
1269 fflush (real_stderr);
1271 si->unlock_failures = 0;
1276 si->pw_data->i_beam = 0;
1277 update_passwd_window (si, msg, 0.0);
1278 XSync (si->dpy, False);
1281 /* Swallow all pending KeyPress/KeyRelease events. */
1284 while (XCheckMaskEvent (si->dpy, KeyPressMask|KeyReleaseMask, &e))
1292 handle_typeahead (saver_info *si)
1294 passwd_dialog_data *pw = si->pw_data;
1296 if (!si->unlock_typeahead)
1299 i = strlen (si->unlock_typeahead);
1300 if (i >= sizeof(pw->typed_passwd) - 1)
1301 i = sizeof(pw->typed_passwd) - 1;
1303 memcpy (pw->typed_passwd, si->unlock_typeahead, i);
1304 pw->typed_passwd [i] = 0;
1306 memset (si->unlock_typeahead, '*', strlen(si->unlock_typeahead));
1307 si->unlock_typeahead[i] = 0;
1308 update_passwd_window (si, si->unlock_typeahead, pw->ratio);
1310 free (si->unlock_typeahead);
1311 si->unlock_typeahead = 0;
1316 unlock_p (saver_info *si)
1318 saver_preferences *p = &si->prefs;
1321 raise_window (si, True, True, True);
1324 fprintf (stderr, "%s: prompting for password.\n", blurb());
1326 if (si->pw_data || si->passwd_dialog)
1327 destroy_passwd_window (si);
1329 make_passwd_window (si);
1331 compose_status = calloc (1, sizeof (*compose_status));
1333 handle_typeahead (si);
1334 passwd_event_loop (si);
1336 status = (si->pw_data->state == pw_ok);
1337 destroy_passwd_window (si);
1339 free (compose_status);
1347 set_locked_p (saver_info *si, Bool locked_p)
1349 si->locked_p = locked_p;
1351 #ifdef HAVE_XHPDISABLERESET
1352 hp_lock_reset (si, locked_p); /* turn off/on C-Sh-Reset */
1354 #ifdef HAVE_VT_LOCKSWITCH
1355 linux_lock_vt_switch (si, locked_p); /* turn off/on C-Alt-F1 */
1357 #ifdef HAVE_XF86VMODE
1358 xfree_lock_mode_switch (si, locked_p); /* turn off/on C-Alt-Plus */
1361 store_saver_status (si); /* store locked-p */
1365 #else /* NO_LOCKING -- whole file */
1368 set_locked_p (saver_info *si, Bool locked_p)
1370 if (locked_p) abort();
1373 #endif /* !NO_LOCKING */