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 #ifndef NO_LOCKING /* whole file */
22 #include <X11/Intrinsic.h>
23 #include "xscreensaver.h"
24 #include "resources.h"
28 #endif /* HAVE_SYSLOG */
30 #ifdef HAVE_XHPDISABLERESET
31 # include <X11/XHPlib.h>
32 static void hp_lock_reset (saver_info *si, Bool lock_p);
33 #endif /* HAVE_XHPDISABLERESET */
35 #ifdef HAVE_VT_LOCKSWITCH
37 # include <sys/ioctl.h>
39 static void linux_lock_vt_switch (saver_info *si, Bool lock_p);
40 #endif /* HAVE_VT_LOCKSWITCH */
43 # include <X11/extensions/xf86vmode.h>
44 static void xfree_lock_mode_switch (saver_info *si, Bool lock_p);
45 #endif /* HAVE_XF86VMODE */
49 ERROR! You must not include vroot.h in this file.
56 extern char *getenv(const char *name);
57 extern int validate_user(char *name, char *password);
60 vms_passwd_valid_p(char *pw, Bool verbose_p)
62 return (validate_user (getenv("USER"), typed_passwd) == 1);
64 # undef passwd_valid_p
65 # define passwd_valid_p vms_passwd_valid_p
71 #define MAX(a,b) ((a)>(b)?(a):(b))
73 enum passwd_state { pw_read, pw_ok, pw_null, pw_fail, pw_cancel, pw_time };
75 struct passwd_dialog_data {
77 enum passwd_state state;
78 char typed_passwd [80];
86 Dimension border_width;
95 XFontStruct *heading_font;
96 XFontStruct *body_font;
97 XFontStruct *label_font;
98 XFontStruct *passwd_font;
102 Pixel passwd_foreground;
103 Pixel passwd_background;
104 Pixel logo_foreground;
105 Pixel logo_background;
109 Dimension logo_width;
110 Dimension logo_height;
111 Dimension thermo_width;
112 Dimension internal_border;
113 Dimension shadow_width;
115 Dimension passwd_field_x, passwd_field_y;
116 Dimension passwd_field_width, passwd_field_height;
118 Dimension thermo_field_x, thermo_field_y;
119 Dimension thermo_field_height;
124 static void draw_passwd_window (saver_info *si);
125 static void update_passwd_window (saver_info *si, const char *printed_passwd,
127 static void destroy_passwd_window (saver_info *si);
128 static void undo_vp_motion (saver_info *si);
132 make_passwd_window (saver_info *si)
134 struct passwd *p = getpwuid (getuid ());
135 XSetWindowAttributes attrs;
136 unsigned long attrmask = 0;
137 Screen *screen = si->default_screen->screen;
138 passwd_dialog_data *pw = (passwd_dialog_data *) calloc (1, sizeof(*pw));
139 Colormap cmap = DefaultColormapOfScreen (screen);
144 pw->heading_label = get_string_resource ("passwd.heading.label",
145 "Dialog.Label.Label");
146 pw->body_label = get_string_resource ("passwd.body.label",
147 "Dialog.Label.Label");
148 pw->user_label = get_string_resource ("passwd.user.label",
149 "Dialog.Label.Label");
150 pw->passwd_label = get_string_resource ("passwd.passwd.label",
151 "Dialog.Label.Label");
153 if (!pw->heading_label)
154 pw->heading_label = strdup("ERROR: REESOURCES NOT INSTALLED CORRECTLY");
156 pw->body_label = strdup("ERROR: REESOURCES NOT INSTALLED CORRECTLY");
157 if (!pw->user_label) pw->user_label = strdup("ERROR");
158 if (!pw->passwd_label) pw->passwd_label = strdup("ERROR");
160 /* Put the version number in the label. */
162 char *s = (char *) malloc (strlen(pw->heading_label) + 20);
163 sprintf(s, pw->heading_label, si->version);
164 free (pw->heading_label);
165 pw->heading_label = s;
168 pw->user_string = (p->pw_name ? p->pw_name : "???");
169 pw->passwd_string = strdup("");
171 f = get_string_resource ("passwd.headingFont", "Dialog.Font");
172 pw->heading_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
173 if (!pw->heading_font) pw->heading_font = XLoadQueryFont (si->dpy, "fixed");
176 f = get_string_resource("passwd.bodyFont", "Dialog.Font");
177 pw->body_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
178 if (!pw->body_font) pw->body_font = XLoadQueryFont (si->dpy, "fixed");
181 f = get_string_resource("passwd.labelFont", "Dialog.Font");
182 pw->label_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
183 if (!pw->label_font) pw->label_font = XLoadQueryFont (si->dpy, "fixed");
186 f = get_string_resource("passwd.passwdFont", "Dialog.Font");
187 pw->passwd_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
188 if (!pw->passwd_font) pw->passwd_font = XLoadQueryFont (si->dpy, "fixed");
191 pw->foreground = get_pixel_resource ("passwd.foreground",
194 pw->background = get_pixel_resource ("passwd.background",
198 if (pw->foreground == pw->background)
200 /* Make sure the error messages show up. */
201 pw->foreground = BlackPixelOfScreen (screen);
202 pw->background = WhitePixelOfScreen (screen);
205 pw->passwd_foreground = get_pixel_resource ("passwd.text.foreground",
206 "Dialog.Text.Foreground",
208 pw->passwd_background = get_pixel_resource ("passwd.text.background",
209 "Dialog.Text.Background",
211 pw->logo_foreground = get_pixel_resource ("passwd.logo.foreground",
212 "Dialog.Logo.Foreground",
214 pw->logo_background = get_pixel_resource ("passwd.logo.background",
215 "Dialog.Logo.Background",
217 pw->shadow_top = get_pixel_resource ("passwd.topShadowColor",
220 pw->shadow_bottom = get_pixel_resource ("passwd.bottomShadowColor",
224 pw->logo_width = get_integer_resource ("passwd.logo.width",
225 "Dialog.Logo.Width");
226 pw->logo_height = get_integer_resource ("passwd.logo.height",
227 "Dialog.Logo.Height");
228 pw->thermo_width = get_integer_resource ("passwd.thermometer.width",
229 "Dialog.Thermometer.Width");
230 pw->internal_border = get_integer_resource ("passwd.internalBorderWidth",
231 "Dialog.InternalBorderWidth");
232 pw->shadow_width = get_integer_resource ("passwd.shadowThickness",
233 "Dialog.ShadowThickness");
235 if (pw->logo_width == 0) pw->logo_width = 150;
236 if (pw->logo_height == 0) pw->logo_height = 150;
237 if (pw->internal_border == 0) pw->internal_border = 15;
238 if (pw->shadow_width == 0) pw->shadow_width = 4;
239 if (pw->thermo_width == 0) pw->thermo_width = pw->shadow_width;
242 int direction, ascent, descent;
248 /* Measure the heading_label. */
249 XTextExtents (pw->heading_font,
250 pw->heading_label, strlen(pw->heading_label),
251 &direction, &ascent, &descent, &overall);
252 if (overall.width > pw->width) pw->width = overall.width;
253 pw->height += ascent + descent;
255 /* Measure the body_label. */
256 XTextExtents (pw->body_font,
257 pw->body_label, strlen(pw->body_label),
258 &direction, &ascent, &descent, &overall);
259 if (overall.width > pw->width) pw->width = overall.width;
260 pw->height += ascent + descent;
263 Dimension w2 = 0, w3 = 0;
264 Dimension h2 = 0, h3 = 0;
265 const char *passwd_string = "MMMMMMMMMMMM";
267 /* Measure the user_label. */
268 XTextExtents (pw->label_font,
269 pw->user_label, strlen(pw->user_label),
270 &direction, &ascent, &descent, &overall);
271 if (overall.width > w2) w2 = overall.width;
272 h2 += ascent + descent;
274 /* Measure the passwd_label. */
275 XTextExtents (pw->label_font,
276 pw->passwd_label, strlen(pw->passwd_label),
277 &direction, &ascent, &descent, &overall);
278 if (overall.width > w2) w2 = overall.width;
279 h2 += ascent + descent;
281 /* Measure the user_string. */
282 XTextExtents (pw->passwd_font,
283 pw->user_string, strlen(pw->user_string),
284 &direction, &ascent, &descent, &overall);
285 overall.width += (pw->shadow_width * 4);
286 ascent += (pw->shadow_width * 4);
287 if (overall.width > w3) w3 = overall.width;
288 h3 += ascent + descent;
290 /* Measure the (maximally-sized, dummy) passwd_string. */
291 XTextExtents (pw->passwd_font,
292 passwd_string, strlen(passwd_string),
293 &direction, &ascent, &descent, &overall);
294 overall.width += (pw->shadow_width * 4);
295 ascent += (pw->shadow_width * 4);
296 if (overall.width > w3) w3 = overall.width;
297 h3 += ascent + descent;
299 w2 = w2 + w3 + (pw->shadow_width * 2);
302 if (w2 > pw->width) pw->width = w2;
306 pw->width += (pw->internal_border * 2);
307 pw->height += (pw->internal_border * 4);
309 pw->width += pw->thermo_width + (pw->shadow_width * 3);
311 if (pw->logo_height > pw->height)
312 pw->height = pw->logo_height;
313 else if (pw->height > pw->logo_height)
314 pw->logo_height = pw->height;
316 pw->logo_width = pw->logo_height;
318 pw->width += pw->logo_width;
321 attrmask |= CWOverrideRedirect; attrs.override_redirect = True;
322 attrmask |= CWEventMask; attrs.event_mask = ExposureMask|KeyPressMask;
326 get_screen_viewport (si->default_screen, &x, &y, &w, &h, False);
327 if (si->prefs.debug_p) w /= 2;
328 pw->x = x + ((w + pw->width) / 2) - pw->width;
329 pw->y = y + ((h + pw->height) / 2) - pw->height;
330 if (pw->x < x) pw->x = x;
331 if (pw->y < y) pw->y = y;
334 pw->border_width = get_integer_resource ("passwd.borderWidth",
335 "Dialog.BorderWidth");
338 XCreateWindow (si->dpy,
339 RootWindowOfScreen(screen),
340 pw->x, pw->y, pw->width, pw->height, pw->border_width,
341 DefaultDepthOfScreen (screen), InputOutput,
342 DefaultVisualOfScreen(screen),
344 XSetWindowBackground (si->dpy, si->passwd_dialog, pw->background);
347 /* Before mapping the window, save the bits that are underneath the
348 rectangle the window will occlude. When we lower the window, we
349 restore these bits. This works, because the running screenhack
350 has already been sent SIGSTOP, so we know nothing else is drawing
355 pw->save_under = XCreatePixmap (si->dpy,
356 si->default_screen->screensaver_window,
357 pw->width + (pw->border_width*2) + 1,
358 pw->height + (pw->border_width*2) + 1,
359 si->default_screen->current_depth);
360 gcv.function = GXcopy;
361 gc = XCreateGC (si->dpy, pw->save_under, GCFunction, &gcv);
362 XCopyArea (si->dpy, si->default_screen->screensaver_window,
364 pw->x - pw->border_width, pw->y - pw->border_width,
365 pw->width + (pw->border_width*2) + 1,
366 pw->height + (pw->border_width*2) + 1,
368 XFreeGC (si->dpy, gc);
371 XMapRaised (si->dpy, si->passwd_dialog);
372 XSync (si->dpy, False);
374 move_mouse_grab (si, si->passwd_dialog, si->screens[0].cursor);
379 draw_passwd_window (si);
380 XSync (si->dpy, False);
385 draw_passwd_window (saver_info *si)
387 passwd_dialog_data *pw = si->pw_data;
391 int x1, x2, x3, y1, y2;
395 height = (pw->heading_font->ascent + pw->heading_font->descent +
396 pw->body_font->ascent + pw->body_font->descent +
397 (2 * MAX ((pw->label_font->ascent + pw->label_font->descent),
398 (pw->passwd_font->ascent + pw->passwd_font->descent +
399 (pw->shadow_width * 4)))));
400 spacing = ((pw->height - (2 * pw->shadow_width) -
401 pw->internal_border - height)) / 8;
402 if (spacing < 0) spacing = 0;
404 gcv.foreground = pw->foreground;
405 gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
406 gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
407 x1 = pw->logo_width + pw->thermo_width + (pw->shadow_width * 3);
408 x3 = pw->width - (pw->shadow_width * 2);
409 y1 = (pw->shadow_width * 2) + spacing + spacing;
413 XSetFont (si->dpy, gc1, pw->heading_font->fid);
414 sw = string_width (pw->heading_font, pw->heading_label);
415 x2 = (x1 + ((x3 - x1 - sw) / 2));
416 y1 += spacing + pw->heading_font->ascent + pw->heading_font->descent;
417 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
418 pw->heading_label, strlen(pw->heading_label));
420 /* text below top heading
422 XSetFont (si->dpy, gc1, pw->body_font->fid);
423 y1 += spacing + pw->body_font->ascent + pw->body_font->descent;
424 sw = string_width (pw->body_font, pw->body_label);
425 x2 = (x1 + ((x3 - x1 - sw) / 2));
426 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
427 pw->body_label, strlen(pw->body_label));
430 tb_height = (pw->passwd_font->ascent + pw->passwd_font->descent +
431 (pw->shadow_width * 4));
433 /* the "User:" prompt
437 XSetForeground (si->dpy, gc1, pw->foreground);
438 XSetFont (si->dpy, gc1, pw->label_font->fid);
439 y1 += (spacing + tb_height);
440 x2 = (x1 + pw->internal_border +
441 MAX(string_width (pw->label_font, pw->user_label),
442 string_width (pw->label_font, pw->passwd_label)));
443 XDrawString (si->dpy, si->passwd_dialog, gc1,
444 x2 - string_width (pw->label_font, pw->user_label),
446 pw->user_label, strlen(pw->user_label));
448 /* the "Password:" prompt
450 y1 += (spacing + tb_height);
451 XDrawString (si->dpy, si->passwd_dialog, gc1,
452 x2 - string_width (pw->label_font, pw->passwd_label),
454 pw->passwd_label, strlen(pw->passwd_label));
457 XSetForeground (si->dpy, gc2, pw->passwd_background);
459 /* the "user name" text field
462 XSetForeground (si->dpy, gc1, pw->passwd_foreground);
463 XSetFont (si->dpy, gc1, pw->passwd_font->fid);
464 y1 += (spacing + tb_height);
465 x2 += (pw->shadow_width * 4);
467 pw->passwd_field_width = x3 - x2 - pw->internal_border;
468 pw->passwd_field_height = (pw->passwd_font->ascent +
469 pw->passwd_font->descent +
472 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
473 x2 - pw->shadow_width,
474 y1 - (pw->passwd_font->ascent + pw->passwd_font->descent),
475 pw->passwd_field_width, pw->passwd_field_height);
476 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
477 pw->user_string, strlen(pw->user_string));
479 /* the "password" text field
481 y1 += (spacing + tb_height);
483 pw->passwd_field_x = x2 - pw->shadow_width;
484 pw->passwd_field_y = y1 - (pw->passwd_font->ascent +
485 pw->passwd_font->descent);
487 /* The shadow around the text fields
490 y1 += (spacing + (pw->shadow_width * 3));
491 x1 = x2 - (pw->shadow_width * 2);
492 x2 = pw->passwd_field_width + (pw->shadow_width * 2);
493 y2 = pw->passwd_field_height + (pw->shadow_width * 2);
495 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
498 pw->shadow_bottom, pw->shadow_top);
500 y1 += (spacing + pw->passwd_font->ascent + pw->passwd_font->descent +
501 (pw->shadow_width * 4));
502 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
505 pw->shadow_bottom, pw->shadow_top);
509 XSetForeground (si->dpy, gc1, pw->logo_foreground);
510 XSetForeground (si->dpy, gc2, pw->logo_background);
512 x1 = pw->shadow_width * 3;
513 y1 = pw->shadow_width * 3;
514 x2 = pw->logo_width - (pw->shadow_width * 6);
515 y2 = pw->logo_height - (pw->shadow_width * 6);
517 XFillRectangle (si->dpy, si->passwd_dialog, gc2, x1, y1, x2, y2);
518 skull (si->dpy, si->passwd_dialog, gc1, gc2,
519 x1 + pw->shadow_width, y1 + pw->shadow_width,
520 x2 - (pw->shadow_width * 2), y2 - (pw->shadow_width * 2));
524 pw->thermo_field_x = pw->logo_width + pw->shadow_width;
525 pw->thermo_field_y = pw->shadow_width * 3;
526 pw->thermo_field_height = pw->height - (pw->shadow_width * 6);
528 /* Solid border inside the logo box. */
529 XSetForeground (si->dpy, gc1, pw->foreground);
530 XDrawRectangle (si->dpy, si->passwd_dialog, gc1, x1, y1, x2-1, y2-1);
532 /* The shadow around the logo
534 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
535 pw->shadow_width * 2,
536 pw->shadow_width * 2,
537 pw->logo_width - (pw->shadow_width * 4),
538 pw->logo_height - (pw->shadow_width * 4),
540 pw->shadow_bottom, pw->shadow_top);
542 /* The shadow around the thermometer
544 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
546 pw->shadow_width * 2,
547 pw->thermo_width + (pw->shadow_width * 2),
548 pw->height - (pw->shadow_width * 4),
550 pw->shadow_bottom, pw->shadow_top);
552 /* Solid border inside the thermometer. */
553 XSetForeground (si->dpy, gc1, pw->foreground);
554 XDrawRectangle (si->dpy, si->passwd_dialog, gc1,
555 pw->logo_width + pw->shadow_width,
556 pw->shadow_width * 3,
557 pw->thermo_width - 1,
558 pw->height - (pw->shadow_width * 6) - 1);
560 /* The shadow around the whole window
562 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
563 0, 0, pw->width, pw->height, pw->shadow_width,
564 pw->shadow_top, pw->shadow_bottom);
566 XFreeGC (si->dpy, gc1);
567 XFreeGC (si->dpy, gc2);
569 update_passwd_window (si, pw->passwd_string, pw->ratio);
574 update_passwd_window (saver_info *si, const char *printed_passwd, float ratio)
576 passwd_dialog_data *pw = si->pw_data;
583 gcv.foreground = pw->passwd_foreground;
584 gcv.font = pw->passwd_font->fid;
585 gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground|GCFont, &gcv);
586 gcv.foreground = pw->passwd_background;
587 gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
591 char *s = strdup (printed_passwd);
592 if (pw->passwd_string) free (pw->passwd_string);
593 pw->passwd_string = s;
596 /* the "password" text field
598 rects[0].x = pw->passwd_field_x;
599 rects[0].y = pw->passwd_field_y;
600 rects[0].width = pw->passwd_field_width;
601 rects[0].height = pw->passwd_field_height;
603 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
604 rects[0].x, rects[0].y, rects[0].width, rects[0].height);
606 XSetClipRectangles (si->dpy, gc1, 0, 0, rects, 1, Unsorted);
608 XDrawString (si->dpy, si->passwd_dialog, gc1,
609 rects[0].x + pw->shadow_width,
610 rects[0].y + (pw->passwd_font->ascent +
611 pw->passwd_font->descent),
612 pw->passwd_string, strlen(pw->passwd_string));
614 XSetClipMask (si->dpy, gc1, None);
620 x = (rects[0].x + pw->shadow_width +
621 string_width (pw->passwd_font, pw->passwd_string));
622 y = rects[0].y + pw->shadow_width;
624 if (x > rects[0].x + rects[0].width - 1)
625 x = rects[0].x + rects[0].width - 1;
626 XDrawLine (si->dpy, si->passwd_dialog, gc1,
627 x, y, x, y + pw->passwd_font->ascent);
630 pw->i_beam = (pw->i_beam + 1) % 4;
635 y = pw->thermo_field_height * (1.0 - pw->ratio);
638 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
639 pw->thermo_field_x + 1,
640 pw->thermo_field_y + 1,
643 XSetForeground (si->dpy, gc1, pw->logo_foreground);
644 XFillRectangle (si->dpy, si->passwd_dialog, gc1,
645 pw->thermo_field_x + 1,
646 pw->thermo_field_y + 1 + y,
648 MAX (0, pw->thermo_field_height - y - 2));
651 XFreeGC (si->dpy, gc1);
652 XFreeGC (si->dpy, gc2);
653 XSync (si->dpy, False);
658 destroy_passwd_window (saver_info *si)
660 passwd_dialog_data *pw = si->pw_data;
661 Screen *screen = si->default_screen->screen;
662 Colormap cmap = DefaultColormapOfScreen (screen);
663 Pixel black = BlackPixelOfScreen (screen);
664 Pixel white = WhitePixelOfScreen (screen);
667 XtRemoveTimeOut (pw->timer);
669 move_mouse_grab (si, RootWindowOfScreen(si->screens[0].screen),
670 si->screens[0].cursor);
672 if (si->passwd_dialog)
674 XDestroyWindow (si->dpy, si->passwd_dialog);
675 si->passwd_dialog = 0;
682 gcv.function = GXcopy;
683 gc = XCreateGC (si->dpy, si->default_screen->screensaver_window,
685 XCopyArea (si->dpy, pw->save_under,
686 si->default_screen->screensaver_window, gc,
688 pw->width + (pw->border_width*2) + 1,
689 pw->height + (pw->border_width*2) + 1,
690 pw->x - pw->border_width, pw->y - pw->border_width);
691 XFreePixmap (si->dpy, pw->save_under);
693 XFreeGC (si->dpy, gc);
696 if (pw->heading_label) free (pw->heading_label);
697 if (pw->body_label) free (pw->body_label);
698 if (pw->user_label) free (pw->user_label);
699 if (pw->passwd_label) free (pw->passwd_label);
701 if (pw->heading_font) XFreeFont (si->dpy, pw->heading_font);
702 if (pw->body_font) XFreeFont (si->dpy, pw->body_font);
703 if (pw->label_font) XFreeFont (si->dpy, pw->label_font);
704 if (pw->passwd_font) XFreeFont (si->dpy, pw->passwd_font);
706 if (pw->foreground != black && pw->foreground != white)
707 XFreeColors (si->dpy, cmap, &pw->foreground, 1, 0L);
708 if (pw->background != black && pw->background != white)
709 XFreeColors (si->dpy, cmap, &pw->background, 1, 0L);
710 if (pw->passwd_foreground != black && pw->passwd_foreground != white)
711 XFreeColors (si->dpy, cmap, &pw->passwd_foreground, 1, 0L);
712 if (pw->passwd_background != black && pw->passwd_background != white)
713 XFreeColors (si->dpy, cmap, &pw->passwd_background, 1, 0L);
714 if (pw->logo_foreground != black && pw->logo_foreground != white)
715 XFreeColors (si->dpy, cmap, &pw->logo_foreground, 1, 0L);
716 if (pw->logo_background != black && pw->logo_background != white)
717 XFreeColors (si->dpy, cmap, &pw->logo_background, 1, 0L);
718 if (pw->shadow_top != black && pw->shadow_top != white)
719 XFreeColors (si->dpy, cmap, &pw->shadow_top, 1, 0L);
720 if (pw->shadow_bottom != black && pw->shadow_bottom != white)
721 XFreeColors (si->dpy, cmap, &pw->shadow_bottom, 1, 0L);
723 memset (pw, 0, sizeof(*pw));
730 #ifdef HAVE_XHPDISABLERESET
731 /* This function enables and disables the C-Sh-Reset hot-key, which
732 normally resets the X server (logging out the logged-in user.)
733 We don't want random people to be able to do that while the
737 hp_lock_reset (saver_info *si, Bool lock_p)
739 static Bool hp_locked_p = False;
741 /* Calls to XHPDisableReset and XHPEnableReset must be balanced,
742 or BadAccess errors occur. (It's ok for this to be global,
743 since it affects the whole machine, not just the current screen.)
745 if (hp_locked_p == lock_p)
749 XHPDisableReset (si->dpy);
751 XHPEnableReset (si->dpy);
752 hp_locked_p = lock_p;
754 #endif /* HAVE_XHPDISABLERESET */
758 /* This function enables and disables the C-Sh-F1 ... F12 hot-keys,
759 which, on Linux systems, switches to another virtual console.
760 We'd like the whole screen/keyboard to be locked, not just one
761 virtual console, so this function disables that while the X
764 Unfortunately, this doesn't work -- this ioctl only works when
765 called by root, and we have disavowed our privileges long ago.
767 #ifdef HAVE_VT_LOCKSWITCH
769 linux_lock_vt_switch (saver_info *si, Bool lock_p)
771 saver_preferences *p = &si->prefs;
772 static Bool vt_locked_p = False;
773 const char *dev_console = "/dev/console";
776 if (lock_p == vt_locked_p)
779 if (lock_p && !p->lock_vt_p)
782 fd = open (dev_console, O_RDWR);
786 sprintf (buf, "%s: couldn't %s VTs: %s", blurb(),
787 (lock_p ? "lock" : "unlock"),
789 #if 1 /* #### doesn't work yet, so don't bother complaining */
795 if (ioctl (fd, (lock_p ? VT_LOCKSWITCH : VT_UNLOCKSWITCH)) == 0)
797 vt_locked_p = lock_p;
800 fprintf (stderr, "%s: %s VTs\n", blurb(),
801 (lock_p ? "locked" : "unlocked"));
806 sprintf (buf, "%s: couldn't %s VTs: ioctl", blurb(),
807 (lock_p ? "lock" : "unlock"));
808 #if 0 /* #### doesn't work yet, so don't bother complaining */
815 #endif /* HAVE_VT_LOCKSWITCH */
818 /* This function enables and disables the C-Alt-Plus and C-Alt-Minus
819 hot-keys, which normally change the resolution of the X server.
820 We don't want people to be able to switch the server resolution
821 while the screen is locked, because if they switch to a higher
822 resolution, it could cause part of the underlying desktop to become
825 #ifdef HAVE_XF86VMODE
827 static int ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error);
828 static Bool vp_got_error = False;
831 xfree_lock_mode_switch (saver_info *si, Bool lock_p)
833 static Bool mode_locked_p = False;
834 saver_preferences *p = &si->prefs;
835 int screen = 0; /* always screen 0 */
838 XErrorHandler old_handler;
840 if (mode_locked_p == lock_p)
842 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
845 XSync (si->dpy, False);
846 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
847 status = XF86VidModeLockModeSwitch (si->dpy, screen, lock_p);
848 XSync (si->dpy, False);
849 XSetErrorHandler (old_handler);
850 if (vp_got_error) status = False;
853 mode_locked_p = lock_p;
855 if (!status && (p->verbose_p || !lock_p))
856 /* Only print this when verbose, or when we locked but can't unlock.
857 I tried printing this message whenever it comes up, but
858 mode-locking always fails if DontZoom is set in XF86Config. */
859 fprintf (stderr, "%s: unable to %s mode switching!\n",
860 blurb(), (lock_p ? "lock" : "unlock"));
861 else if (p->verbose_p)
862 fprintf (stderr, "%s: %s mode switching.\n",
863 blurb(), (lock_p ? "locked" : "unlocked"));
867 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
873 #endif /* HAVE_XF86VMODE */
876 /* If the viewport has been scrolled since the screen was blanked,
877 then scroll it back to where it belongs. This function only exists
878 to patch over a very brief race condition.
881 undo_vp_motion (saver_info *si)
883 #ifdef HAVE_XF86VMODE
884 saver_preferences *p = &si->prefs;
885 int screen = 0; /* always screen 0 */
886 saver_screen_info *ssi = &si->screens[screen];
887 int event, error, x, y;
890 if (ssi->blank_vp_x == -1 && ssi->blank_vp_y == -1)
892 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
894 if (!XF86VidModeGetViewPort (si->dpy, 0, &x, &y))
896 if (ssi->blank_vp_x == x && ssi->blank_vp_y == y)
899 /* We're going to move the viewport. The mouse has just been grabbed on
900 (and constrained to, thus warped to) the password window, so it is no
901 longer near the edge of the screen. However, wait a bit anyway, just
902 to make sure the server drains its last motion event, so that the
903 screen doesn't continue to scroll after we've reset the viewport.
905 XSync (si->dpy, False);
906 usleep (250000); /* 1/4 second */
907 XSync (si->dpy, False);
909 status = XF86VidModeSetViewPort (si->dpy, screen,
910 ssi->blank_vp_x, ssi->blank_vp_y);
913 fprintf (stderr, "%s: unable to move vp from (%d,%d) back to (%d,%d)!\n",
914 blurb(), x, y, ssi->blank_vp_x, ssi->blank_vp_y);
915 else if (p->verbose_p)
916 fprintf (stderr, "%s: vp moved to (%d,%d); moved it back to (%d,%d).\n",
917 blurb(), x, y, ssi->blank_vp_x, ssi->blank_vp_y);
919 #endif /* HAVE_XF86VMODE */
928 passwd_animate_timer (XtPointer closure, XtIntervalId *id)
930 saver_info *si = (saver_info *) closure;
932 passwd_dialog_data *pw = si->pw_data;
936 pw->ratio -= (1.0 / ((double) si->prefs.passwd_timeout / (double) tick));
940 if (pw->state == pw_read)
944 update_passwd_window (si, 0, pw->ratio);
946 if (pw->state == pw_read)
947 pw->timer = XtAppAddTimeOut (si->app, tick, passwd_animate_timer,
952 idle_timer ((XtPointer) si, id);
957 handle_passwd_key (saver_info *si, XKeyEvent *event)
959 saver_preferences *p = &si->prefs;
960 passwd_dialog_data *pw = si->pw_data;
961 int pw_size = sizeof (pw->typed_passwd) - 1;
962 char *typed_passwd = pw->typed_passwd;
966 int size = XLookupString (event, s, 1, 0, 0);
968 if (size != 1) return;
974 case '\010': case '\177': /* Backspace */
978 typed_passwd [strlen(typed_passwd)-1] = 0;
981 case '\025': case '\030': /* Erase line */
982 memset (typed_passwd, 0, pw_size);
985 case '\012': case '\015': /* Enter */
986 if (pw->state != pw_read)
987 ; /* already done? */
988 else if (typed_passwd[0] == 0)
992 update_passwd_window (si, "Checking...", pw->ratio);
993 XSync (si->dpy, False);
994 if (passwd_valid_p (typed_passwd, p->verbose_p))
998 update_passwd_window (si, "", pw->ratio);
1003 i = strlen (typed_passwd);
1008 typed_passwd [i] = *s;
1009 typed_passwd [i+1] = 0;
1014 i = strlen(typed_passwd);
1015 stars = (char *) malloc(i+1);
1016 memset (stars, '*', i);
1018 update_passwd_window (si, stars, pw->ratio);
1024 passwd_event_loop (saver_info *si)
1026 saver_preferences *p = &si->prefs;
1029 passwd_animate_timer ((XtPointer) si, 0);
1031 while (si->pw_data && si->pw_data->state == pw_read)
1033 XtAppNextEvent (si->app, &event);
1034 if (event.xany.window == si->passwd_dialog && event.xany.type == Expose)
1035 draw_passwd_window (si);
1036 else if (event.xany.type == KeyPress)
1037 handle_passwd_key (si, &event.xkey);
1039 XtDispatchEvent (&event);
1042 switch (si->pw_data->state)
1044 case pw_ok: msg = 0; break;
1045 case pw_null: msg = ""; break;
1046 case pw_time: msg = "Timed out!"; break;
1047 default: msg = "Sorry!"; break;
1050 if (si->pw_data->state == pw_fail)
1051 si->unlock_failures++;
1054 switch (si->pw_data->state)
1057 fprintf (stderr, "%s: password correct.\n", blurb()); break;
1059 fprintf (stderr, "%s: password incorrect!\n", blurb()); break;
1062 fprintf (stderr, "%s: password entry cancelled.\n", blurb()); break;
1064 fprintf (stderr, "%s: password entry timed out.\n", blurb()); break;
1069 if (si->pw_data->state == pw_fail)
1071 /* If they typed a password (as opposed to just hitting return) and
1072 the password was invalid, log it.
1074 struct passwd *pw = getpwuid (getuid ());
1075 char *d = DisplayString (si->dpy);
1076 char *u = (pw->pw_name ? pw->pw_name : "???");
1084 # if defined(LOG_AUTHPRIV)
1086 # elif defined(LOG_AUTH)
1093 openlog (progname, opt, fac);
1094 syslog (LOG_NOTICE, "FAILED LOGIN %d ON DISPLAY \"%s\", FOR \"%s\"",
1095 si->unlock_failures, d, u);
1098 #endif /* HAVE_SYSLOG */
1100 if (si->pw_data->state == pw_fail)
1101 XBell (si->dpy, False);
1103 if (si->pw_data->state == pw_ok && si->unlock_failures != 0)
1105 if (si->unlock_failures == 1)
1106 fprintf (real_stderr,
1107 "%s: WARNING: 1 failed attempt to unlock the screen.\n",
1110 fprintf (real_stderr,
1111 "%s: WARNING: %d failed attempts to unlock the screen.\n",
1112 blurb(), si->unlock_failures);
1113 fflush (real_stderr);
1115 si->unlock_failures = 0;
1120 si->pw_data->i_beam = 0;
1121 update_passwd_window (si, msg, 0.0);
1122 XSync (si->dpy, False);
1125 /* Swallow all pending KeyPress/KeyRelease events. */
1128 while (XCheckMaskEvent (si->dpy, KeyPressMask|KeyReleaseMask, &e))
1136 unlock_p (saver_info *si)
1138 saver_preferences *p = &si->prefs;
1139 Screen *screen = si->default_screen->screen;
1140 Colormap cmap = DefaultColormapOfScreen (screen);
1143 raise_window (si, True, True, True);
1146 fprintf (stderr, "%s: prompting for password.\n", blurb());
1148 if (si->pw_data || si->passwd_dialog)
1149 destroy_passwd_window (si);
1151 make_passwd_window (si);
1152 if (cmap) XInstallColormap (si->dpy, cmap);
1154 passwd_event_loop (si);
1156 status = (si->pw_data->state == pw_ok);
1157 destroy_passwd_window (si);
1159 cmap = si->default_screen->cmap;
1160 if (cmap) XInstallColormap (si->dpy, cmap);
1167 set_locked_p (saver_info *si, Bool locked_p)
1169 si->locked_p = locked_p;
1171 #ifdef HAVE_XHPDISABLERESET
1172 hp_lock_reset (si, locked_p); /* turn off/on C-Sh-Reset */
1174 #ifdef HAVE_VT_LOCKSWITCH
1175 linux_lock_vt_switch (si, locked_p); /* turn off/on C-Alt-F1 */
1177 #ifdef HAVE_XF86VMODE
1178 xfree_lock_mode_switch (si, locked_p); /* turn off/on C-Alt-Plus */
1183 #else /* NO_LOCKING -- whole file */
1186 set_locked_p (saver_info *si, Bool locked_p)
1188 if (locked_p) abort();
1191 #endif /* !NO_LOCKING */