1 /* lock.c --- handling the password dialog for locking-mode.
2 * xscreensaver, Copyright (c) 1993-1998 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 = (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);
775 XtRemoveTimeOut (pw->timer);
777 move_mouse_grab (si, RootWindowOfScreen (ssi->screen),
778 ssi->cursor, ssi->number);
781 fprintf (stderr, "%s: %d: moving mouse back to %d,%d.\n",
782 blurb(), ssi->number,
783 pw->previous_mouse_x, pw->previous_mouse_y);
785 XWarpPointer (si->dpy, None, RootWindowOfScreen (ssi->screen),
787 pw->previous_mouse_x, pw->previous_mouse_y);
789 XSync (si->dpy, False);
790 while (XCheckMaskEvent (si->dpy, PointerMotionMask, &event))
792 fprintf (stderr, "%s: discarding MotionNotify event.\n", blurb());
794 if (si->passwd_dialog)
796 XDestroyWindow (si->dpy, si->passwd_dialog);
797 si->passwd_dialog = 0;
804 gcv.function = GXcopy;
805 gc = XCreateGC (si->dpy, ssi->screensaver_window, GCFunction, &gcv);
806 XCopyArea (si->dpy, pw->save_under,
807 ssi->screensaver_window, gc,
809 pw->width + (pw->border_width*2) + 1,
810 pw->height + (pw->border_width*2) + 1,
811 pw->x - pw->border_width, pw->y - pw->border_width);
812 XFreePixmap (si->dpy, pw->save_under);
814 XFreeGC (si->dpy, gc);
817 if (pw->heading_label) free (pw->heading_label);
818 if (pw->body_label) free (pw->body_label);
819 if (pw->user_label) free (pw->user_label);
820 if (pw->passwd_label) free (pw->passwd_label);
822 if (pw->heading_font) XFreeFont (si->dpy, pw->heading_font);
823 if (pw->body_font) XFreeFont (si->dpy, pw->body_font);
824 if (pw->label_font) XFreeFont (si->dpy, pw->label_font);
825 if (pw->passwd_font) XFreeFont (si->dpy, pw->passwd_font);
827 if (pw->foreground != black && pw->foreground != white)
828 XFreeColors (si->dpy, cmap, &pw->foreground, 1, 0L);
829 if (pw->background != black && pw->background != white)
830 XFreeColors (si->dpy, cmap, &pw->background, 1, 0L);
831 if (pw->passwd_foreground != black && pw->passwd_foreground != white)
832 XFreeColors (si->dpy, cmap, &pw->passwd_foreground, 1, 0L);
833 if (pw->passwd_background != black && pw->passwd_background != white)
834 XFreeColors (si->dpy, cmap, &pw->passwd_background, 1, 0L);
835 if (pw->thermo_foreground != black && pw->thermo_foreground != white)
836 XFreeColors (si->dpy, cmap, &pw->thermo_foreground, 1, 0L);
837 if (pw->thermo_background != black && pw->thermo_background != white)
838 XFreeColors (si->dpy, cmap, &pw->thermo_background, 1, 0L);
839 if (pw->shadow_top != black && pw->shadow_top != white)
840 XFreeColors (si->dpy, cmap, &pw->shadow_top, 1, 0L);
841 if (pw->shadow_bottom != black && pw->shadow_bottom != white)
842 XFreeColors (si->dpy, cmap, &pw->shadow_bottom, 1, 0L);
845 XFreePixmap (si->dpy, pw->logo_pixmap);
846 if (pw->logo_npixels && pw->logo_pixels)
847 XFreeColors (si->dpy, cmap, pw->logo_pixels, pw->logo_npixels, 0L);
849 free (pw->logo_pixels);
851 memset (pw, 0, sizeof(*pw));
855 XInstallColormap (si->dpy, cmap);
861 #ifdef HAVE_XHPDISABLERESET
862 /* This function enables and disables the C-Sh-Reset hot-key, which
863 normally resets the X server (logging out the logged-in user.)
864 We don't want random people to be able to do that while the
868 hp_lock_reset (saver_info *si, Bool lock_p)
870 static Bool hp_locked_p = False;
872 /* Calls to XHPDisableReset and XHPEnableReset must be balanced,
873 or BadAccess errors occur. (It's ok for this to be global,
874 since it affects the whole machine, not just the current screen.)
876 if (hp_locked_p == lock_p)
880 XHPDisableReset (si->dpy);
882 XHPEnableReset (si->dpy);
883 hp_locked_p = lock_p;
885 #endif /* HAVE_XHPDISABLERESET */
889 /* This function enables and disables the C-Sh-F1 ... F12 hot-keys,
890 which, on Linux systems, switches to another virtual console.
891 We'd like the whole screen/keyboard to be locked, not just one
892 virtual console, so this function disables that while the X
895 Unfortunately, this doesn't work -- this ioctl only works when
896 called by root, and we have disavowed our privileges long ago.
898 #ifdef HAVE_VT_LOCKSWITCH
900 linux_lock_vt_switch (saver_info *si, Bool lock_p)
902 saver_preferences *p = &si->prefs;
903 static Bool vt_locked_p = False;
904 const char *dev_console = "/dev/console";
907 if (lock_p == vt_locked_p)
910 if (lock_p && !p->lock_vt_p)
913 fd = open (dev_console, O_RDWR);
917 sprintf (buf, "%s: couldn't %s VTs: %s", blurb(),
918 (lock_p ? "lock" : "unlock"),
920 #if 1 /* #### doesn't work yet, so don't bother complaining */
926 if (ioctl (fd, (lock_p ? VT_LOCKSWITCH : VT_UNLOCKSWITCH)) == 0)
928 vt_locked_p = lock_p;
931 fprintf (stderr, "%s: %s VTs\n", blurb(),
932 (lock_p ? "locked" : "unlocked"));
937 sprintf (buf, "%s: couldn't %s VTs: ioctl", blurb(),
938 (lock_p ? "lock" : "unlock"));
939 #if 0 /* #### doesn't work yet, so don't bother complaining */
946 #endif /* HAVE_VT_LOCKSWITCH */
949 /* This function enables and disables the C-Alt-Plus and C-Alt-Minus
950 hot-keys, which normally change the resolution of the X server.
951 We don't want people to be able to switch the server resolution
952 while the screen is locked, because if they switch to a higher
953 resolution, it could cause part of the underlying desktop to become
956 #ifdef HAVE_XF86VMODE
958 static int ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error);
959 static Bool vp_got_error = False;
962 xfree_lock_mode_switch (saver_info *si, Bool lock_p)
964 static Bool any_mode_locked_p = False;
965 saver_preferences *p = &si->prefs;
969 XErrorHandler old_handler;
971 if (any_mode_locked_p == lock_p)
973 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
976 for (screen = 0; screen < si->nscreens; screen++)
978 XSync (si->dpy, False);
979 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
980 status = XF86VidModeLockModeSwitch (si->dpy, screen, lock_p);
981 XSync (si->dpy, False);
982 XSetErrorHandler (old_handler);
983 if (vp_got_error) status = False;
986 any_mode_locked_p = lock_p;
988 if (!status && (p->verbose_p || !lock_p))
989 /* Only print this when verbose, or when we locked but can't unlock.
990 I tried printing this message whenever it comes up, but
991 mode-locking always fails if DontZoom is set in XF86Config. */
992 fprintf (stderr, "%s: %d: unable to %s mode switching!\n",
993 blurb(), screen, (lock_p ? "lock" : "unlock"));
994 else if (p->verbose_p)
995 fprintf (stderr, "%s: %d: %s mode switching.\n",
996 blurb(), screen, (lock_p ? "locked" : "unlocked"));
1001 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1003 vp_got_error = True;
1007 #endif /* HAVE_XF86VMODE */
1010 /* If the viewport has been scrolled since the screen was blanked,
1011 then scroll it back to where it belongs. This function only exists
1012 to patch over a very brief race condition.
1015 undo_vp_motion (saver_info *si)
1017 #ifdef HAVE_XF86VMODE
1018 saver_preferences *p = &si->prefs;
1022 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1025 for (screen = 0; screen < si->nscreens; screen++)
1027 saver_screen_info *ssi = &si->screens[screen];
1031 if (ssi->blank_vp_x == -1 && ssi->blank_vp_y == -1)
1033 if (!XF86VidModeGetViewPort (si->dpy, screen, &x, &y))
1035 if (ssi->blank_vp_x == x && ssi->blank_vp_y == y)
1038 /* We're going to move the viewport. The mouse has just been grabbed on
1039 (and constrained to, thus warped to) the password window, so it is no
1040 longer near the edge of the screen. However, wait a bit anyway, just
1041 to make sure the server drains its last motion event, so that the
1042 screen doesn't continue to scroll after we've reset the viewport.
1044 XSync (si->dpy, False);
1045 usleep (250000); /* 1/4 second */
1046 XSync (si->dpy, False);
1048 status = XF86VidModeSetViewPort (si->dpy, screen,
1049 ssi->blank_vp_x, ssi->blank_vp_y);
1053 "%s: %d: unable to move vp from (%d,%d) back to (%d,%d)!\n",
1054 blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1055 else if (p->verbose_p)
1057 "%s: %d: vp moved to (%d,%d); moved it back to (%d,%d).\n",
1058 blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1060 #endif /* HAVE_XF86VMODE */
1069 passwd_animate_timer (XtPointer closure, XtIntervalId *id)
1071 saver_info *si = (saver_info *) closure;
1073 passwd_dialog_data *pw = si->pw_data;
1077 pw->ratio -= (1.0 / ((double) si->prefs.passwd_timeout / (double) tick));
1081 if (pw->state == pw_read)
1082 pw->state = pw_time;
1085 update_passwd_window (si, 0, pw->ratio);
1087 if (pw->state == pw_read)
1088 pw->timer = XtAppAddTimeOut (si->app, tick, passwd_animate_timer,
1093 idle_timer ((XtPointer) si, id);
1097 static XComposeStatus *compose_status;
1100 handle_passwd_key (saver_info *si, XKeyEvent *event)
1102 saver_preferences *p = &si->prefs;
1103 passwd_dialog_data *pw = si->pw_data;
1104 int pw_size = sizeof (pw->typed_passwd) - 1;
1105 char *typed_passwd = pw->typed_passwd;
1109 int size = XLookupString (event, s, 1, 0, compose_status);
1111 if (size != 1) return;
1117 case '\010': case '\177': /* Backspace */
1121 typed_passwd [strlen(typed_passwd)-1] = 0;
1124 case '\025': case '\030': /* Erase line */
1125 memset (typed_passwd, 0, pw_size);
1128 case '\012': case '\015': /* Enter */
1129 if (pw->state != pw_read)
1130 ; /* already done? */
1131 else if (typed_passwd[0] == 0)
1132 pw->state = pw_null;
1135 update_passwd_window (si, "Checking...", pw->ratio);
1136 XSync (si->dpy, False);
1137 if (passwd_valid_p (typed_passwd, p->verbose_p))
1140 pw->state = pw_fail;
1141 update_passwd_window (si, "", pw->ratio);
1146 i = strlen (typed_passwd);
1151 typed_passwd [i] = *s;
1152 typed_passwd [i+1] = 0;
1157 i = strlen(typed_passwd);
1158 stars = (char *) malloc(i+1);
1159 memset (stars, '*', i);
1161 update_passwd_window (si, stars, pw->ratio);
1167 passwd_event_loop (saver_info *si)
1169 saver_preferences *p = &si->prefs;
1172 passwd_animate_timer ((XtPointer) si, 0);
1174 while (si->pw_data && si->pw_data->state == pw_read)
1176 XtAppNextEvent (si->app, &event);
1177 if (event.xany.window == si->passwd_dialog && event.xany.type == Expose)
1178 draw_passwd_window (si);
1179 else if (event.xany.type == KeyPress)
1180 handle_passwd_key (si, &event.xkey);
1182 XtDispatchEvent (&event);
1185 switch (si->pw_data->state)
1187 case pw_ok: msg = 0; break;
1188 case pw_null: msg = ""; break;
1189 case pw_time: msg = "Timed out!"; break;
1190 default: msg = "Sorry!"; break;
1193 if (si->pw_data->state == pw_fail)
1194 si->unlock_failures++;
1197 switch (si->pw_data->state)
1200 fprintf (stderr, "%s: password correct.\n", blurb()); break;
1202 fprintf (stderr, "%s: password incorrect!\n", blurb()); break;
1205 fprintf (stderr, "%s: password entry cancelled.\n", blurb()); break;
1207 fprintf (stderr, "%s: password entry timed out.\n", blurb()); break;
1212 if (si->pw_data->state == pw_fail)
1214 /* If they typed a password (as opposed to just hitting return) and
1215 the password was invalid, log it.
1217 struct passwd *pw = getpwuid (getuid ());
1218 char *d = DisplayString (si->dpy);
1219 char *u = (pw->pw_name ? pw->pw_name : "???");
1227 # if defined(LOG_AUTHPRIV)
1229 # elif defined(LOG_AUTH)
1236 openlog (progname, opt, fac);
1237 syslog (LOG_NOTICE, "FAILED LOGIN %d ON DISPLAY \"%s\", FOR \"%s\"",
1238 si->unlock_failures, d, u);
1241 #endif /* HAVE_SYSLOG */
1243 if (si->pw_data->state == pw_fail)
1244 XBell (si->dpy, False);
1246 if (si->pw_data->state == pw_ok && si->unlock_failures != 0)
1248 if (si->unlock_failures == 1)
1249 fprintf (real_stderr,
1250 "%s: WARNING: 1 failed attempt to unlock the screen.\n",
1253 fprintf (real_stderr,
1254 "%s: WARNING: %d failed attempts to unlock the screen.\n",
1255 blurb(), si->unlock_failures);
1256 fflush (real_stderr);
1258 si->unlock_failures = 0;
1263 si->pw_data->i_beam = 0;
1264 update_passwd_window (si, msg, 0.0);
1265 XSync (si->dpy, False);
1268 /* Swallow all pending KeyPress/KeyRelease events. */
1271 while (XCheckMaskEvent (si->dpy, KeyPressMask|KeyReleaseMask, &e))
1279 handle_typeahead (saver_info *si)
1281 passwd_dialog_data *pw = si->pw_data;
1283 if (!si->unlock_typeahead)
1286 i = strlen (si->unlock_typeahead);
1287 if (i >= sizeof(pw->typed_passwd) - 1)
1288 i = sizeof(pw->typed_passwd) - 1;
1290 memcpy (pw->typed_passwd, si->unlock_typeahead, i);
1291 pw->typed_passwd [i] = 0;
1293 memset (si->unlock_typeahead, '*', strlen(si->unlock_typeahead));
1294 si->unlock_typeahead[i] = 0;
1295 update_passwd_window (si, si->unlock_typeahead, pw->ratio);
1297 free (si->unlock_typeahead);
1298 si->unlock_typeahead = 0;
1303 unlock_p (saver_info *si)
1305 saver_preferences *p = &si->prefs;
1308 raise_window (si, True, True, True);
1311 fprintf (stderr, "%s: prompting for password.\n", blurb());
1313 if (si->pw_data || si->passwd_dialog)
1314 destroy_passwd_window (si);
1316 make_passwd_window (si);
1318 compose_status = calloc (1, sizeof (*compose_status));
1320 handle_typeahead (si);
1321 passwd_event_loop (si);
1323 status = (si->pw_data->state == pw_ok);
1324 destroy_passwd_window (si);
1326 free (compose_status);
1334 set_locked_p (saver_info *si, Bool locked_p)
1336 si->locked_p = locked_p;
1338 #ifdef HAVE_XHPDISABLERESET
1339 hp_lock_reset (si, locked_p); /* turn off/on C-Sh-Reset */
1341 #ifdef HAVE_VT_LOCKSWITCH
1342 linux_lock_vt_switch (si, locked_p); /* turn off/on C-Alt-F1 */
1344 #ifdef HAVE_XF86VMODE
1345 xfree_lock_mode_switch (si, locked_p); /* turn off/on C-Alt-Plus */
1348 store_saver_status (si); /* store locked-p */
1352 #else /* NO_LOCKING -- whole file */
1355 set_locked_p (saver_info *si, Bool locked_p)
1357 if (locked_p) abort();
1360 #endif /* !NO_LOCKING */