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() */
22 #include "xscreensaver.h"
23 #include "resources.h"
25 #ifndef NO_LOCKING /* (mostly) whole file */
29 #endif /* HAVE_SYSLOG */
31 #ifdef HAVE_XHPDISABLERESET
32 # include <X11/XHPlib.h>
33 static void hp_lock_reset (saver_info *si, Bool lock_p);
34 #endif /* HAVE_XHPDISABLERESET */
36 #ifdef HAVE_VT_LOCKSWITCH
38 # include <sys/ioctl.h>
40 static void linux_lock_vt_switch (saver_info *si, Bool lock_p);
41 #endif /* HAVE_VT_LOCKSWITCH */
44 # include <X11/extensions/xf86vmode.h>
45 static void xfree_lock_mode_switch (saver_info *si, Bool lock_p);
46 #endif /* HAVE_XF86VMODE */
50 ERROR! You must not include vroot.h in this file.
57 extern char *getenv(const char *name);
58 extern int validate_user(char *name, char *password);
61 vms_passwd_valid_p(char *pw, Bool verbose_p)
63 return (validate_user (getenv("USER"), typed_passwd) == 1);
65 # undef passwd_valid_p
66 # define passwd_valid_p vms_passwd_valid_p
72 #define MAX(a,b) ((a)>(b)?(a):(b))
74 enum passwd_state { pw_read, pw_ok, pw_null, pw_fail, pw_cancel, pw_time };
76 struct passwd_dialog_data {
78 enum passwd_state state;
79 char typed_passwd [80];
87 Dimension border_width;
97 XFontStruct *heading_font;
98 XFontStruct *body_font;
99 XFontStruct *label_font;
100 XFontStruct *passwd_font;
101 XFontStruct *date_font;
105 Pixel passwd_foreground;
106 Pixel passwd_background;
107 Pixel thermo_foreground;
108 Pixel thermo_background;
112 Dimension logo_width;
113 Dimension logo_height;
114 Dimension thermo_width;
115 Dimension internal_border;
116 Dimension shadow_width;
118 Dimension passwd_field_x, passwd_field_y;
119 Dimension passwd_field_width, passwd_field_height;
121 Dimension thermo_field_x, thermo_field_y;
122 Dimension thermo_field_height;
126 unsigned long *logo_pixels;
131 static void draw_passwd_window (saver_info *si);
132 static void update_passwd_window (saver_info *si, const char *printed_passwd,
134 static void destroy_passwd_window (saver_info *si);
135 static void undo_vp_motion (saver_info *si);
139 make_passwd_window (saver_info *si)
141 struct passwd *p = getpwuid (getuid ());
142 XSetWindowAttributes attrs;
143 unsigned long attrmask = 0;
144 Screen *screen = si->default_screen->screen;
145 passwd_dialog_data *pw = (passwd_dialog_data *) calloc (1, sizeof(*pw));
146 Colormap cmap = DefaultColormapOfScreen (screen);
151 pw->heading_label = get_string_resource ("passwd.heading.label",
152 "Dialog.Label.Label");
153 pw->body_label = get_string_resource ("passwd.body.label",
154 "Dialog.Label.Label");
155 pw->user_label = get_string_resource ("passwd.user.label",
156 "Dialog.Label.Label");
157 pw->passwd_label = get_string_resource ("passwd.passwd.label",
158 "Dialog.Label.Label");
159 pw->date_label = get_string_resource ("dateFormat", "DateFormat");
161 if (!pw->heading_label)
162 pw->heading_label = strdup("ERROR: REESOURCES NOT INSTALLED CORRECTLY");
164 pw->body_label = strdup("ERROR: REESOURCES NOT INSTALLED CORRECTLY");
165 if (!pw->user_label) pw->user_label = strdup("ERROR");
166 if (!pw->passwd_label) pw->passwd_label = strdup("ERROR");
167 if (!pw->date_label) pw->date_label = strdup("ERROR");
169 /* Put the version number in the label. */
171 char *s = (char *) malloc (strlen(pw->heading_label) + 20);
172 sprintf(s, pw->heading_label, si->version);
173 free (pw->heading_label);
174 pw->heading_label = s;
177 pw->user_string = (p && p->pw_name ? p->pw_name : "???");
178 pw->passwd_string = strdup("");
180 f = get_string_resource ("passwd.headingFont", "Dialog.Font");
181 pw->heading_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
182 if (!pw->heading_font) pw->heading_font = XLoadQueryFont (si->dpy, "fixed");
185 f = get_string_resource("passwd.bodyFont", "Dialog.Font");
186 pw->body_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
187 if (!pw->body_font) pw->body_font = XLoadQueryFont (si->dpy, "fixed");
190 f = get_string_resource("passwd.labelFont", "Dialog.Font");
191 pw->label_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
192 if (!pw->label_font) pw->label_font = XLoadQueryFont (si->dpy, "fixed");
195 f = get_string_resource("passwd.passwdFont", "Dialog.Font");
196 pw->passwd_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
197 if (!pw->passwd_font) pw->passwd_font = XLoadQueryFont (si->dpy, "fixed");
200 f = get_string_resource("passwd.dateFont", "Dialog.Font");
201 pw->date_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
202 if (!pw->date_font) pw->date_font = XLoadQueryFont (si->dpy, "fixed");
205 pw->foreground = get_pixel_resource ("passwd.foreground",
208 pw->background = get_pixel_resource ("passwd.background",
212 if (pw->foreground == pw->background)
214 /* Make sure the error messages show up. */
215 pw->foreground = BlackPixelOfScreen (screen);
216 pw->background = WhitePixelOfScreen (screen);
219 pw->passwd_foreground = get_pixel_resource ("passwd.text.foreground",
220 "Dialog.Text.Foreground",
222 pw->passwd_background = get_pixel_resource ("passwd.text.background",
223 "Dialog.Text.Background",
225 pw->thermo_foreground = get_pixel_resource ("passwd.thermometer.foreground",
226 "Dialog.Thermometer.Foreground",
228 pw->thermo_background = get_pixel_resource ("passwd.thermometer.background",
229 "Dialog.Thermometer.Background",
231 pw->shadow_top = get_pixel_resource ("passwd.topShadowColor",
234 pw->shadow_bottom = get_pixel_resource ("passwd.bottomShadowColor",
238 pw->logo_width = get_integer_resource ("passwd.logo.width",
239 "Dialog.Logo.Width");
240 pw->logo_height = get_integer_resource ("passwd.logo.height",
241 "Dialog.Logo.Height");
242 pw->thermo_width = get_integer_resource ("passwd.thermometer.width",
243 "Dialog.Thermometer.Width");
244 pw->internal_border = get_integer_resource ("passwd.internalBorderWidth",
245 "Dialog.InternalBorderWidth");
246 pw->shadow_width = get_integer_resource ("passwd.shadowThickness",
247 "Dialog.ShadowThickness");
249 if (pw->logo_width == 0) pw->logo_width = 150;
250 if (pw->logo_height == 0) pw->logo_height = 150;
251 if (pw->internal_border == 0) pw->internal_border = 15;
252 if (pw->shadow_width == 0) pw->shadow_width = 4;
253 if (pw->thermo_width == 0) pw->thermo_width = pw->shadow_width;
256 int direction, ascent, descent;
262 /* Measure the heading_label. */
263 XTextExtents (pw->heading_font,
264 pw->heading_label, strlen(pw->heading_label),
265 &direction, &ascent, &descent, &overall);
266 if (overall.width > pw->width) pw->width = overall.width;
267 pw->height += ascent + descent;
269 /* Measure the body_label. */
270 XTextExtents (pw->body_font,
271 pw->body_label, strlen(pw->body_label),
272 &direction, &ascent, &descent, &overall);
273 if (overall.width > pw->width) pw->width = overall.width;
274 pw->height += ascent + descent;
277 Dimension w2 = 0, w3 = 0;
278 Dimension h2 = 0, h3 = 0;
279 const char *passwd_string = "MMMMMMMMMMMM";
281 /* Measure the user_label. */
282 XTextExtents (pw->label_font,
283 pw->user_label, strlen(pw->user_label),
284 &direction, &ascent, &descent, &overall);
285 if (overall.width > w2) w2 = overall.width;
286 h2 += ascent + descent;
288 /* Measure the passwd_label. */
289 XTextExtents (pw->label_font,
290 pw->passwd_label, strlen(pw->passwd_label),
291 &direction, &ascent, &descent, &overall);
292 if (overall.width > w2) w2 = overall.width;
293 h2 += ascent + descent;
295 /* Measure the user_string. */
296 XTextExtents (pw->passwd_font,
297 pw->user_string, strlen(pw->user_string),
298 &direction, &ascent, &descent, &overall);
299 overall.width += (pw->shadow_width * 4);
300 ascent += (pw->shadow_width * 4);
301 if (overall.width > w3) w3 = overall.width;
302 h3 += ascent + descent;
304 /* Measure the (maximally-sized, dummy) passwd_string. */
305 XTextExtents (pw->passwd_font,
306 passwd_string, strlen(passwd_string),
307 &direction, &ascent, &descent, &overall);
308 overall.width += (pw->shadow_width * 4);
309 ascent += (pw->shadow_width * 4);
310 if (overall.width > w3) w3 = overall.width;
311 h3 += ascent + descent;
313 w2 = w2 + w3 + (pw->shadow_width * 2);
316 if (w2 > pw->width) pw->width = w2;
320 pw->width += (pw->internal_border * 2);
321 pw->height += (pw->internal_border * 4);
323 pw->width += pw->thermo_width + (pw->shadow_width * 3);
325 if (pw->logo_height > pw->height)
326 pw->height = pw->logo_height;
327 else if (pw->height > pw->logo_height)
328 pw->logo_height = pw->height;
330 pw->logo_width = pw->logo_height;
332 pw->width += pw->logo_width;
335 attrmask |= CWOverrideRedirect; attrs.override_redirect = True;
336 attrmask |= CWEventMask; attrs.event_mask = ExposureMask|KeyPressMask;
340 get_screen_viewport (si->default_screen, &x, &y, &w, &h, False);
341 if (si->prefs.debug_p) w /= 2;
342 pw->x = x + ((w + pw->width) / 2) - pw->width;
343 pw->y = y + ((h + pw->height) / 2) - pw->height;
344 if (pw->x < x) pw->x = x;
345 if (pw->y < y) pw->y = y;
348 pw->border_width = get_integer_resource ("passwd.borderWidth",
349 "Dialog.BorderWidth");
352 XCreateWindow (si->dpy,
353 RootWindowOfScreen(screen),
354 pw->x, pw->y, pw->width, pw->height, pw->border_width,
355 DefaultDepthOfScreen (screen), InputOutput,
356 DefaultVisualOfScreen(screen),
358 XSetWindowBackground (si->dpy, si->passwd_dialog, pw->background);
360 pw->logo_pixmap = xscreensaver_logo (si->dpy, si->passwd_dialog, cmap,
362 &pw->logo_pixels, &pw->logo_npixels,
365 /* Before mapping the window, save the bits that are underneath the
366 rectangle the window will occlude. When we lower the window, we
367 restore these bits. This works, because the running screenhack
368 has already been sent SIGSTOP, so we know nothing else is drawing
373 pw->save_under = XCreatePixmap (si->dpy,
374 si->default_screen->screensaver_window,
375 pw->width + (pw->border_width*2) + 1,
376 pw->height + (pw->border_width*2) + 1,
377 si->default_screen->current_depth);
378 gcv.function = GXcopy;
379 gc = XCreateGC (si->dpy, pw->save_under, GCFunction, &gcv);
380 XCopyArea (si->dpy, si->default_screen->screensaver_window,
382 pw->x - pw->border_width, pw->y - pw->border_width,
383 pw->width + (pw->border_width*2) + 1,
384 pw->height + (pw->border_width*2) + 1,
386 XFreeGC (si->dpy, gc);
389 XMapRaised (si->dpy, si->passwd_dialog);
390 XSync (si->dpy, False);
392 move_mouse_grab (si, si->passwd_dialog, si->screens[0].cursor);
397 draw_passwd_window (si);
398 XSync (si->dpy, False);
403 draw_passwd_window (saver_info *si)
405 passwd_dialog_data *pw = si->pw_data;
409 int x1, x2, x3, y1, y2;
413 height = (pw->heading_font->ascent + pw->heading_font->descent +
414 pw->body_font->ascent + pw->body_font->descent +
415 (2 * MAX ((pw->label_font->ascent + pw->label_font->descent),
416 (pw->passwd_font->ascent + pw->passwd_font->descent +
417 (pw->shadow_width * 4)))) +
418 pw->date_font->ascent + pw->date_font->descent
420 spacing = ((pw->height - (2 * pw->shadow_width) -
421 pw->internal_border - height)) / 8;
422 if (spacing < 0) spacing = 0;
424 gcv.foreground = pw->foreground;
425 gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
426 gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
427 x1 = pw->logo_width + pw->thermo_width + (pw->shadow_width * 3);
428 x3 = pw->width - (pw->shadow_width * 2);
429 y1 = (pw->shadow_width * 2) + spacing + spacing;
433 XSetFont (si->dpy, gc1, pw->heading_font->fid);
434 sw = string_width (pw->heading_font, pw->heading_label);
435 x2 = (x1 + ((x3 - x1 - sw) / 2));
436 y1 += spacing + pw->heading_font->ascent + pw->heading_font->descent;
437 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
438 pw->heading_label, strlen(pw->heading_label));
440 /* text below top heading
442 XSetFont (si->dpy, gc1, pw->body_font->fid);
443 y1 += spacing + pw->body_font->ascent + pw->body_font->descent;
444 sw = string_width (pw->body_font, pw->body_label);
445 x2 = (x1 + ((x3 - x1 - sw) / 2));
446 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
447 pw->body_label, strlen(pw->body_label));
450 tb_height = (pw->passwd_font->ascent + pw->passwd_font->descent +
451 (pw->shadow_width * 4));
453 /* the "User:" prompt
457 XSetForeground (si->dpy, gc1, pw->foreground);
458 XSetFont (si->dpy, gc1, pw->label_font->fid);
459 y1 += (spacing + tb_height);
460 x2 = (x1 + pw->internal_border +
461 MAX(string_width (pw->label_font, pw->user_label),
462 string_width (pw->label_font, pw->passwd_label)));
463 XDrawString (si->dpy, si->passwd_dialog, gc1,
464 x2 - string_width (pw->label_font, pw->user_label),
466 pw->user_label, strlen(pw->user_label));
468 /* the "Password:" prompt
470 y1 += (spacing + tb_height);
471 XDrawString (si->dpy, si->passwd_dialog, gc1,
472 x2 - string_width (pw->label_font, pw->passwd_label),
474 pw->passwd_label, strlen(pw->passwd_label));
477 XSetForeground (si->dpy, gc2, pw->passwd_background);
479 /* the "user name" text field
482 XSetForeground (si->dpy, gc1, pw->passwd_foreground);
483 XSetFont (si->dpy, gc1, pw->passwd_font->fid);
484 y1 += (spacing + tb_height);
485 x2 += (pw->shadow_width * 4);
487 pw->passwd_field_width = x3 - x2 - pw->internal_border;
488 pw->passwd_field_height = (pw->passwd_font->ascent +
489 pw->passwd_font->descent +
492 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
493 x2 - pw->shadow_width,
494 y1 - (pw->passwd_font->ascent + pw->passwd_font->descent),
495 pw->passwd_field_width, pw->passwd_field_height);
496 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
497 pw->user_string, strlen(pw->user_string));
499 /* the "password" text field
501 y1 += (spacing + tb_height);
503 pw->passwd_field_x = x2 - pw->shadow_width;
504 pw->passwd_field_y = y1 - (pw->passwd_font->ascent +
505 pw->passwd_font->descent);
507 /* The shadow around the text fields
510 y1 += (spacing + (pw->shadow_width * 3));
511 x1 = x2 - (pw->shadow_width * 2);
512 x2 = pw->passwd_field_width + (pw->shadow_width * 2);
513 y2 = pw->passwd_field_height + (pw->shadow_width * 2);
515 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
518 pw->shadow_bottom, pw->shadow_top);
520 y1 += (spacing + pw->passwd_font->ascent + pw->passwd_font->descent +
521 (pw->shadow_width * 4));
522 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
525 pw->shadow_bottom, pw->shadow_top);
528 /* The date, below the text fields
532 time_t now = time ((time_t *) 0);
533 struct tm *tm = localtime (&now);
534 memset (buf, 0, sizeof(buf));
535 strftime (buf, sizeof(buf)-1, pw->date_label, tm);
537 XSetFont (si->dpy, gc1, pw->date_font->fid);
538 y1 += pw->shadow_width;
539 y1 += (spacing + tb_height);
541 sw = string_width (pw->date_font, buf);
543 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1, buf, strlen(buf));
549 x1 = pw->shadow_width * 3;
550 y1 = pw->shadow_width * 3;
551 x2 = pw->logo_width - (pw->shadow_width * 6);
552 y2 = pw->logo_height - (pw->shadow_width * 6);
558 unsigned int w, h, bw, d;
559 XGetGeometry (si->dpy, pw->logo_pixmap, &root, &x, &y, &w, &h, &bw, &d);
560 XSetForeground (si->dpy, gc1, pw->foreground);
561 XSetBackground (si->dpy, gc1, pw->background);
563 XCopyPlane (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1,
565 x1 + ((x2 - (int)w) / 2),
566 y1 + ((y2 - (int)h) / 2),
569 XCopyArea (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1,
571 x1 + ((x2 - (int)w) / 2),
572 y1 + ((y2 - (int)h) / 2));
577 XSetForeground (si->dpy, gc1, pw->thermo_foreground);
578 XSetForeground (si->dpy, gc2, pw->thermo_background);
580 pw->thermo_field_x = pw->logo_width + pw->shadow_width;
581 pw->thermo_field_y = pw->shadow_width * 3;
582 pw->thermo_field_height = pw->height - (pw->shadow_width * 6);
584 /* Solid border inside the logo box. */
585 XSetForeground (si->dpy, gc1, pw->foreground);
586 XDrawRectangle (si->dpy, si->passwd_dialog, gc1, x1, y1, x2-1, y2-1);
588 /* The shadow around the logo
590 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
591 pw->shadow_width * 2,
592 pw->shadow_width * 2,
593 pw->logo_width - (pw->shadow_width * 4),
594 pw->logo_height - (pw->shadow_width * 4),
596 pw->shadow_bottom, pw->shadow_top);
598 /* The shadow around the thermometer
600 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
602 pw->shadow_width * 2,
603 pw->thermo_width + (pw->shadow_width * 2),
604 pw->height - (pw->shadow_width * 4),
606 pw->shadow_bottom, pw->shadow_top);
608 /* Solid border inside the thermometer. */
609 XSetForeground (si->dpy, gc1, pw->foreground);
610 XDrawRectangle (si->dpy, si->passwd_dialog, gc1,
611 pw->logo_width + pw->shadow_width,
612 pw->shadow_width * 3,
613 pw->thermo_width - 1,
614 pw->height - (pw->shadow_width * 6) - 1);
616 /* The shadow around the whole window
618 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
619 0, 0, pw->width, pw->height, pw->shadow_width,
620 pw->shadow_top, pw->shadow_bottom);
622 XFreeGC (si->dpy, gc1);
623 XFreeGC (si->dpy, gc2);
625 update_passwd_window (si, pw->passwd_string, pw->ratio);
630 update_passwd_window (saver_info *si, const char *printed_passwd, float ratio)
632 passwd_dialog_data *pw = si->pw_data;
639 gcv.foreground = pw->passwd_foreground;
640 gcv.font = pw->passwd_font->fid;
641 gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground|GCFont, &gcv);
642 gcv.foreground = pw->passwd_background;
643 gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
647 char *s = strdup (printed_passwd);
648 if (pw->passwd_string) free (pw->passwd_string);
649 pw->passwd_string = s;
652 /* the "password" text field
654 rects[0].x = pw->passwd_field_x;
655 rects[0].y = pw->passwd_field_y;
656 rects[0].width = pw->passwd_field_width;
657 rects[0].height = pw->passwd_field_height;
659 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
660 rects[0].x, rects[0].y, rects[0].width, rects[0].height);
662 XSetClipRectangles (si->dpy, gc1, 0, 0, rects, 1, Unsorted);
664 XDrawString (si->dpy, si->passwd_dialog, gc1,
665 rects[0].x + pw->shadow_width,
666 rects[0].y + (pw->passwd_font->ascent +
667 pw->passwd_font->descent),
668 pw->passwd_string, strlen(pw->passwd_string));
670 XSetClipMask (si->dpy, gc1, None);
676 x = (rects[0].x + pw->shadow_width +
677 string_width (pw->passwd_font, pw->passwd_string));
678 y = rects[0].y + pw->shadow_width;
680 if (x > rects[0].x + rects[0].width - 1)
681 x = rects[0].x + rects[0].width - 1;
682 XDrawLine (si->dpy, si->passwd_dialog, gc1,
683 x, y, x, y + pw->passwd_font->ascent);
686 pw->i_beam = (pw->i_beam + 1) % 4;
691 y = pw->thermo_field_height * (1.0 - pw->ratio);
694 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
695 pw->thermo_field_x + 1,
696 pw->thermo_field_y + 1,
699 XSetForeground (si->dpy, gc1, pw->thermo_foreground);
700 XFillRectangle (si->dpy, si->passwd_dialog, gc1,
701 pw->thermo_field_x + 1,
702 pw->thermo_field_y + 1 + y,
704 MAX (0, pw->thermo_field_height - y - 2));
707 XFreeGC (si->dpy, gc1);
708 XFreeGC (si->dpy, gc2);
709 XSync (si->dpy, False);
714 destroy_passwd_window (saver_info *si)
716 passwd_dialog_data *pw = si->pw_data;
717 Screen *screen = si->default_screen->screen;
718 Colormap cmap = DefaultColormapOfScreen (screen);
719 Pixel black = BlackPixelOfScreen (screen);
720 Pixel white = WhitePixelOfScreen (screen);
723 XtRemoveTimeOut (pw->timer);
725 move_mouse_grab (si, RootWindowOfScreen(si->screens[0].screen),
726 si->screens[0].cursor);
728 if (si->passwd_dialog)
730 XDestroyWindow (si->dpy, si->passwd_dialog);
731 si->passwd_dialog = 0;
738 gcv.function = GXcopy;
739 gc = XCreateGC (si->dpy, si->default_screen->screensaver_window,
741 XCopyArea (si->dpy, pw->save_under,
742 si->default_screen->screensaver_window, gc,
744 pw->width + (pw->border_width*2) + 1,
745 pw->height + (pw->border_width*2) + 1,
746 pw->x - pw->border_width, pw->y - pw->border_width);
747 XFreePixmap (si->dpy, pw->save_under);
749 XFreeGC (si->dpy, gc);
752 if (pw->heading_label) free (pw->heading_label);
753 if (pw->body_label) free (pw->body_label);
754 if (pw->user_label) free (pw->user_label);
755 if (pw->passwd_label) free (pw->passwd_label);
757 if (pw->heading_font) XFreeFont (si->dpy, pw->heading_font);
758 if (pw->body_font) XFreeFont (si->dpy, pw->body_font);
759 if (pw->label_font) XFreeFont (si->dpy, pw->label_font);
760 if (pw->passwd_font) XFreeFont (si->dpy, pw->passwd_font);
762 if (pw->foreground != black && pw->foreground != white)
763 XFreeColors (si->dpy, cmap, &pw->foreground, 1, 0L);
764 if (pw->background != black && pw->background != white)
765 XFreeColors (si->dpy, cmap, &pw->background, 1, 0L);
766 if (pw->passwd_foreground != black && pw->passwd_foreground != white)
767 XFreeColors (si->dpy, cmap, &pw->passwd_foreground, 1, 0L);
768 if (pw->passwd_background != black && pw->passwd_background != white)
769 XFreeColors (si->dpy, cmap, &pw->passwd_background, 1, 0L);
770 if (pw->thermo_foreground != black && pw->thermo_foreground != white)
771 XFreeColors (si->dpy, cmap, &pw->thermo_foreground, 1, 0L);
772 if (pw->thermo_background != black && pw->thermo_background != white)
773 XFreeColors (si->dpy, cmap, &pw->thermo_background, 1, 0L);
774 if (pw->shadow_top != black && pw->shadow_top != white)
775 XFreeColors (si->dpy, cmap, &pw->shadow_top, 1, 0L);
776 if (pw->shadow_bottom != black && pw->shadow_bottom != white)
777 XFreeColors (si->dpy, cmap, &pw->shadow_bottom, 1, 0L);
780 XFreePixmap (si->dpy, pw->logo_pixmap);
781 if (pw->logo_npixels && pw->logo_pixels)
782 XFreeColors (si->dpy, cmap, pw->logo_pixels, pw->logo_npixels, 0L);
784 free (pw->logo_pixels);
786 memset (pw, 0, sizeof(*pw));
793 #ifdef HAVE_XHPDISABLERESET
794 /* This function enables and disables the C-Sh-Reset hot-key, which
795 normally resets the X server (logging out the logged-in user.)
796 We don't want random people to be able to do that while the
800 hp_lock_reset (saver_info *si, Bool lock_p)
802 static Bool hp_locked_p = False;
804 /* Calls to XHPDisableReset and XHPEnableReset must be balanced,
805 or BadAccess errors occur. (It's ok for this to be global,
806 since it affects the whole machine, not just the current screen.)
808 if (hp_locked_p == lock_p)
812 XHPDisableReset (si->dpy);
814 XHPEnableReset (si->dpy);
815 hp_locked_p = lock_p;
817 #endif /* HAVE_XHPDISABLERESET */
821 /* This function enables and disables the C-Sh-F1 ... F12 hot-keys,
822 which, on Linux systems, switches to another virtual console.
823 We'd like the whole screen/keyboard to be locked, not just one
824 virtual console, so this function disables that while the X
827 Unfortunately, this doesn't work -- this ioctl only works when
828 called by root, and we have disavowed our privileges long ago.
830 #ifdef HAVE_VT_LOCKSWITCH
832 linux_lock_vt_switch (saver_info *si, Bool lock_p)
834 saver_preferences *p = &si->prefs;
835 static Bool vt_locked_p = False;
836 const char *dev_console = "/dev/console";
839 if (lock_p == vt_locked_p)
842 if (lock_p && !p->lock_vt_p)
845 fd = open (dev_console, O_RDWR);
849 sprintf (buf, "%s: couldn't %s VTs: %s", blurb(),
850 (lock_p ? "lock" : "unlock"),
852 #if 1 /* #### doesn't work yet, so don't bother complaining */
858 if (ioctl (fd, (lock_p ? VT_LOCKSWITCH : VT_UNLOCKSWITCH)) == 0)
860 vt_locked_p = lock_p;
863 fprintf (stderr, "%s: %s VTs\n", blurb(),
864 (lock_p ? "locked" : "unlocked"));
869 sprintf (buf, "%s: couldn't %s VTs: ioctl", blurb(),
870 (lock_p ? "lock" : "unlock"));
871 #if 0 /* #### doesn't work yet, so don't bother complaining */
878 #endif /* HAVE_VT_LOCKSWITCH */
881 /* This function enables and disables the C-Alt-Plus and C-Alt-Minus
882 hot-keys, which normally change the resolution of the X server.
883 We don't want people to be able to switch the server resolution
884 while the screen is locked, because if they switch to a higher
885 resolution, it could cause part of the underlying desktop to become
888 #ifdef HAVE_XF86VMODE
890 static int ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error);
891 static Bool vp_got_error = False;
894 xfree_lock_mode_switch (saver_info *si, Bool lock_p)
896 static Bool mode_locked_p = False;
897 saver_preferences *p = &si->prefs;
898 int screen = 0; /* always screen 0 */
901 XErrorHandler old_handler;
903 if (mode_locked_p == lock_p)
905 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
908 XSync (si->dpy, False);
909 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
910 status = XF86VidModeLockModeSwitch (si->dpy, screen, lock_p);
911 XSync (si->dpy, False);
912 XSetErrorHandler (old_handler);
913 if (vp_got_error) status = False;
916 mode_locked_p = lock_p;
918 if (!status && (p->verbose_p || !lock_p))
919 /* Only print this when verbose, or when we locked but can't unlock.
920 I tried printing this message whenever it comes up, but
921 mode-locking always fails if DontZoom is set in XF86Config. */
922 fprintf (stderr, "%s: unable to %s mode switching!\n",
923 blurb(), (lock_p ? "lock" : "unlock"));
924 else if (p->verbose_p)
925 fprintf (stderr, "%s: %s mode switching.\n",
926 blurb(), (lock_p ? "locked" : "unlocked"));
930 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
936 #endif /* HAVE_XF86VMODE */
939 /* If the viewport has been scrolled since the screen was blanked,
940 then scroll it back to where it belongs. This function only exists
941 to patch over a very brief race condition.
944 undo_vp_motion (saver_info *si)
946 #ifdef HAVE_XF86VMODE
947 saver_preferences *p = &si->prefs;
948 int screen = 0; /* always screen 0 */
949 saver_screen_info *ssi = &si->screens[screen];
950 int event, error, x, y;
953 if (ssi->blank_vp_x == -1 && ssi->blank_vp_y == -1)
955 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
957 if (!XF86VidModeGetViewPort (si->dpy, 0, &x, &y))
959 if (ssi->blank_vp_x == x && ssi->blank_vp_y == y)
962 /* We're going to move the viewport. The mouse has just been grabbed on
963 (and constrained to, thus warped to) the password window, so it is no
964 longer near the edge of the screen. However, wait a bit anyway, just
965 to make sure the server drains its last motion event, so that the
966 screen doesn't continue to scroll after we've reset the viewport.
968 XSync (si->dpy, False);
969 usleep (250000); /* 1/4 second */
970 XSync (si->dpy, False);
972 status = XF86VidModeSetViewPort (si->dpy, screen,
973 ssi->blank_vp_x, ssi->blank_vp_y);
976 fprintf (stderr, "%s: unable to move vp from (%d,%d) back to (%d,%d)!\n",
977 blurb(), x, y, ssi->blank_vp_x, ssi->blank_vp_y);
978 else if (p->verbose_p)
979 fprintf (stderr, "%s: vp moved to (%d,%d); moved it back to (%d,%d).\n",
980 blurb(), x, y, ssi->blank_vp_x, ssi->blank_vp_y);
982 #endif /* HAVE_XF86VMODE */
991 passwd_animate_timer (XtPointer closure, XtIntervalId *id)
993 saver_info *si = (saver_info *) closure;
995 passwd_dialog_data *pw = si->pw_data;
999 pw->ratio -= (1.0 / ((double) si->prefs.passwd_timeout / (double) tick));
1003 if (pw->state == pw_read)
1004 pw->state = pw_time;
1007 update_passwd_window (si, 0, pw->ratio);
1009 if (pw->state == pw_read)
1010 pw->timer = XtAppAddTimeOut (si->app, tick, passwd_animate_timer,
1015 idle_timer ((XtPointer) si, id);
1019 static XComposeStatus *compose_status;
1022 handle_passwd_key (saver_info *si, XKeyEvent *event)
1024 saver_preferences *p = &si->prefs;
1025 passwd_dialog_data *pw = si->pw_data;
1026 int pw_size = sizeof (pw->typed_passwd) - 1;
1027 char *typed_passwd = pw->typed_passwd;
1031 int size = XLookupString (event, s, 1, 0, compose_status);
1033 if (size != 1) return;
1039 case '\010': case '\177': /* Backspace */
1043 typed_passwd [strlen(typed_passwd)-1] = 0;
1046 case '\025': case '\030': /* Erase line */
1047 memset (typed_passwd, 0, pw_size);
1050 case '\012': case '\015': /* Enter */
1051 if (pw->state != pw_read)
1052 ; /* already done? */
1053 else if (typed_passwd[0] == 0)
1054 pw->state = pw_null;
1057 update_passwd_window (si, "Checking...", pw->ratio);
1058 XSync (si->dpy, False);
1059 if (passwd_valid_p (typed_passwd, p->verbose_p))
1062 pw->state = pw_fail;
1063 update_passwd_window (si, "", pw->ratio);
1068 i = strlen (typed_passwd);
1073 typed_passwd [i] = *s;
1074 typed_passwd [i+1] = 0;
1079 i = strlen(typed_passwd);
1080 stars = (char *) malloc(i+1);
1081 memset (stars, '*', i);
1083 update_passwd_window (si, stars, pw->ratio);
1089 passwd_event_loop (saver_info *si)
1091 saver_preferences *p = &si->prefs;
1094 passwd_animate_timer ((XtPointer) si, 0);
1096 while (si->pw_data && si->pw_data->state == pw_read)
1098 XtAppNextEvent (si->app, &event);
1099 if (event.xany.window == si->passwd_dialog && event.xany.type == Expose)
1100 draw_passwd_window (si);
1101 else if (event.xany.type == KeyPress)
1102 handle_passwd_key (si, &event.xkey);
1104 XtDispatchEvent (&event);
1107 switch (si->pw_data->state)
1109 case pw_ok: msg = 0; break;
1110 case pw_null: msg = ""; break;
1111 case pw_time: msg = "Timed out!"; break;
1112 default: msg = "Sorry!"; break;
1115 if (si->pw_data->state == pw_fail)
1116 si->unlock_failures++;
1119 switch (si->pw_data->state)
1122 fprintf (stderr, "%s: password correct.\n", blurb()); break;
1124 fprintf (stderr, "%s: password incorrect!\n", blurb()); break;
1127 fprintf (stderr, "%s: password entry cancelled.\n", blurb()); break;
1129 fprintf (stderr, "%s: password entry timed out.\n", blurb()); break;
1134 if (si->pw_data->state == pw_fail)
1136 /* If they typed a password (as opposed to just hitting return) and
1137 the password was invalid, log it.
1139 struct passwd *pw = getpwuid (getuid ());
1140 char *d = DisplayString (si->dpy);
1141 char *u = (pw->pw_name ? pw->pw_name : "???");
1149 # if defined(LOG_AUTHPRIV)
1151 # elif defined(LOG_AUTH)
1158 openlog (progname, opt, fac);
1159 syslog (LOG_NOTICE, "FAILED LOGIN %d ON DISPLAY \"%s\", FOR \"%s\"",
1160 si->unlock_failures, d, u);
1163 #endif /* HAVE_SYSLOG */
1165 if (si->pw_data->state == pw_fail)
1166 XBell (si->dpy, False);
1168 if (si->pw_data->state == pw_ok && si->unlock_failures != 0)
1170 if (si->unlock_failures == 1)
1171 fprintf (real_stderr,
1172 "%s: WARNING: 1 failed attempt to unlock the screen.\n",
1175 fprintf (real_stderr,
1176 "%s: WARNING: %d failed attempts to unlock the screen.\n",
1177 blurb(), si->unlock_failures);
1178 fflush (real_stderr);
1180 si->unlock_failures = 0;
1185 si->pw_data->i_beam = 0;
1186 update_passwd_window (si, msg, 0.0);
1187 XSync (si->dpy, False);
1190 /* Swallow all pending KeyPress/KeyRelease events. */
1193 while (XCheckMaskEvent (si->dpy, KeyPressMask|KeyReleaseMask, &e))
1201 handle_typeahead (saver_info *si)
1203 passwd_dialog_data *pw = si->pw_data;
1205 if (!si->unlock_typeahead)
1208 i = strlen (si->unlock_typeahead);
1209 if (i >= sizeof(pw->typed_passwd) - 1)
1210 i = sizeof(pw->typed_passwd) - 1;
1212 memcpy (pw->typed_passwd, si->unlock_typeahead, i);
1213 pw->typed_passwd [i] = 0;
1215 memset (si->unlock_typeahead, '*', strlen(si->unlock_typeahead));
1216 si->unlock_typeahead[i] = 0;
1217 update_passwd_window (si, si->unlock_typeahead, pw->ratio);
1219 free (si->unlock_typeahead);
1220 si->unlock_typeahead = 0;
1225 unlock_p (saver_info *si)
1227 saver_preferences *p = &si->prefs;
1228 Screen *screen = si->default_screen->screen;
1229 Colormap cmap = DefaultColormapOfScreen (screen);
1232 raise_window (si, True, True, True);
1235 fprintf (stderr, "%s: prompting for password.\n", blurb());
1237 if (si->pw_data || si->passwd_dialog)
1238 destroy_passwd_window (si);
1240 make_passwd_window (si);
1241 if (cmap) XInstallColormap (si->dpy, cmap);
1243 compose_status = calloc (1, sizeof (*compose_status));
1245 handle_typeahead (si);
1246 passwd_event_loop (si);
1248 status = (si->pw_data->state == pw_ok);
1249 destroy_passwd_window (si);
1251 free (compose_status);
1254 cmap = si->default_screen->cmap;
1255 if (cmap) XInstallColormap (si->dpy, cmap);
1262 set_locked_p (saver_info *si, Bool locked_p)
1264 si->locked_p = locked_p;
1266 #ifdef HAVE_XHPDISABLERESET
1267 hp_lock_reset (si, locked_p); /* turn off/on C-Sh-Reset */
1269 #ifdef HAVE_VT_LOCKSWITCH
1270 linux_lock_vt_switch (si, locked_p); /* turn off/on C-Alt-F1 */
1272 #ifdef HAVE_XF86VMODE
1273 xfree_lock_mode_switch (si, locked_p); /* turn off/on C-Alt-Plus */
1276 store_saver_status (si); /* store locked-p */
1280 #else /* NO_LOCKING -- whole file */
1283 set_locked_p (saver_info *si, Bool locked_p)
1285 if (locked_p) abort();
1288 #endif /* !NO_LOCKING */