1 /* lock.c --- handling the password dialog for locking-mode.
2 * xscreensaver, Copyright (c) 1993-2002 Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
13 /* Athena locking code contributed by Jon A. Christopher <jac8782@tamu.edu> */
14 /* Copyright 1997, with the same permissions as above. */
20 #include <X11/Intrinsic.h>
21 #include <X11/Xos.h> /* for time() */
24 #include "xscreensaver.h"
25 #include "resources.h"
27 #ifndef NO_LOCKING /* (mostly) whole file */
31 #endif /* HAVE_SYSLOG */
33 #ifdef HAVE_XHPDISABLERESET
34 # include <X11/XHPlib.h>
35 static void hp_lock_reset (saver_info *si, Bool lock_p);
36 #endif /* HAVE_XHPDISABLERESET */
38 #ifdef HAVE_VT_LOCKSWITCH
40 # include <sys/ioctl.h>
42 static void linux_lock_vt_switch (saver_info *si, Bool lock_p);
43 #endif /* HAVE_VT_LOCKSWITCH */
46 # include <X11/extensions/xf86vmode.h>
47 static void xfree_lock_mode_switch (saver_info *si, Bool lock_p);
48 #endif /* HAVE_XF86VMODE */
50 #ifdef HAVE_XF86MISCSETGRABKEYSSTATE
51 # include <X11/extensions/xf86misc.h>
52 static void xfree_lock_grab_smasher (saver_info *si, Bool lock_p);
53 #endif /* HAVE_XF86MISCSETGRABKEYSSTATE */
57 ERROR! You must not include vroot.h in this file.
64 extern char *getenv(const char *name);
65 extern int validate_user(char *name, char *password);
68 vms_passwd_valid_p(char *pw, Bool verbose_p)
70 return (validate_user (getenv("USER"), typed_passwd) == 1);
72 # undef passwd_valid_p
73 # define passwd_valid_p vms_passwd_valid_p
79 #define MAX(a,b) ((a)>(b)?(a):(b))
81 enum passwd_state { pw_read, pw_ok, pw_null, pw_fail, pw_cancel, pw_time };
83 struct passwd_dialog_data {
85 saver_screen_info *prompt_screen;
86 int previous_mouse_x, previous_mouse_y;
88 enum passwd_state state;
89 char typed_passwd [80];
97 Dimension border_width;
107 XFontStruct *heading_font;
108 XFontStruct *body_font;
109 XFontStruct *label_font;
110 XFontStruct *passwd_font;
111 XFontStruct *date_font;
115 Pixel passwd_foreground;
116 Pixel passwd_background;
117 Pixel thermo_foreground;
118 Pixel thermo_background;
122 Dimension logo_width;
123 Dimension logo_height;
124 Dimension thermo_width;
125 Dimension internal_border;
126 Dimension shadow_width;
128 Dimension passwd_field_x, passwd_field_y;
129 Dimension passwd_field_width, passwd_field_height;
131 Dimension thermo_field_x, thermo_field_y;
132 Dimension thermo_field_height;
136 unsigned long *logo_pixels;
141 static void draw_passwd_window (saver_info *si);
142 static void update_passwd_window (saver_info *si, const char *printed_passwd,
144 static void destroy_passwd_window (saver_info *si);
145 static void undo_vp_motion (saver_info *si);
149 make_passwd_window (saver_info *si)
151 struct passwd *p = getpwuid (getuid ());
152 XSetWindowAttributes attrs;
153 unsigned long attrmask = 0;
154 passwd_dialog_data *pw = (passwd_dialog_data *) calloc (1, sizeof(*pw));
158 saver_screen_info *ssi = &si->screens [mouse_screen (si)];
160 pw->prompt_screen = ssi;
161 if (si->prefs.verbose_p)
162 fprintf (stderr, "%s: %d: creating password dialog.\n",
163 blurb(), pw->prompt_screen->number);
165 screen = pw->prompt_screen->screen;
166 cmap = DefaultColormapOfScreen (screen);
170 pw->heading_label = get_string_resource ("passwd.heading.label",
171 "Dialog.Label.Label");
172 pw->body_label = get_string_resource ("passwd.body.label",
173 "Dialog.Label.Label");
174 pw->user_label = get_string_resource ("passwd.user.label",
175 "Dialog.Label.Label");
176 pw->passwd_label = get_string_resource ("passwd.passwd.label",
177 "Dialog.Label.Label");
178 pw->date_label = get_string_resource ("dateFormat", "DateFormat");
180 if (!pw->heading_label)
181 pw->heading_label = strdup("ERROR: REESOURCES NOT INSTALLED CORRECTLY");
183 pw->body_label = strdup("ERROR: REESOURCES NOT INSTALLED CORRECTLY");
184 if (!pw->user_label) pw->user_label = strdup("ERROR");
185 if (!pw->passwd_label) pw->passwd_label = strdup("ERROR");
186 if (!pw->date_label) pw->date_label = strdup("ERROR");
188 /* Put the version number in the label. */
190 char *s = (char *) malloc (strlen(pw->heading_label) + 20);
191 sprintf(s, pw->heading_label, si->version);
192 free (pw->heading_label);
193 pw->heading_label = s;
196 pw->user_string = strdup (p && p->pw_name ? p->pw_name : "???");
197 pw->passwd_string = strdup("");
199 f = get_string_resource ("passwd.headingFont", "Dialog.Font");
200 pw->heading_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
201 if (!pw->heading_font) pw->heading_font = XLoadQueryFont (si->dpy, "fixed");
204 f = get_string_resource("passwd.bodyFont", "Dialog.Font");
205 pw->body_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
206 if (!pw->body_font) pw->body_font = XLoadQueryFont (si->dpy, "fixed");
209 f = get_string_resource("passwd.labelFont", "Dialog.Font");
210 pw->label_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
211 if (!pw->label_font) pw->label_font = XLoadQueryFont (si->dpy, "fixed");
214 f = get_string_resource("passwd.passwdFont", "Dialog.Font");
215 pw->passwd_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
216 if (!pw->passwd_font) pw->passwd_font = XLoadQueryFont (si->dpy, "fixed");
219 f = get_string_resource("passwd.dateFont", "Dialog.Font");
220 pw->date_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
221 if (!pw->date_font) pw->date_font = XLoadQueryFont (si->dpy, "fixed");
224 pw->foreground = get_pixel_resource ("passwd.foreground",
227 pw->background = get_pixel_resource ("passwd.background",
231 if (pw->foreground == pw->background)
233 /* Make sure the error messages show up. */
234 pw->foreground = BlackPixelOfScreen (screen);
235 pw->background = WhitePixelOfScreen (screen);
238 pw->passwd_foreground = get_pixel_resource ("passwd.text.foreground",
239 "Dialog.Text.Foreground",
241 pw->passwd_background = get_pixel_resource ("passwd.text.background",
242 "Dialog.Text.Background",
244 pw->thermo_foreground = get_pixel_resource ("passwd.thermometer.foreground",
245 "Dialog.Thermometer.Foreground",
247 pw->thermo_background = get_pixel_resource ("passwd.thermometer.background",
248 "Dialog.Thermometer.Background",
250 pw->shadow_top = get_pixel_resource ("passwd.topShadowColor",
253 pw->shadow_bottom = get_pixel_resource ("passwd.bottomShadowColor",
257 pw->logo_width = get_integer_resource ("passwd.logo.width",
258 "Dialog.Logo.Width");
259 pw->logo_height = get_integer_resource ("passwd.logo.height",
260 "Dialog.Logo.Height");
261 pw->thermo_width = get_integer_resource ("passwd.thermometer.width",
262 "Dialog.Thermometer.Width");
263 pw->internal_border = get_integer_resource ("passwd.internalBorderWidth",
264 "Dialog.InternalBorderWidth");
265 pw->shadow_width = get_integer_resource ("passwd.shadowThickness",
266 "Dialog.ShadowThickness");
268 if (pw->logo_width == 0) pw->logo_width = 150;
269 if (pw->logo_height == 0) pw->logo_height = 150;
270 if (pw->internal_border == 0) pw->internal_border = 15;
271 if (pw->shadow_width == 0) pw->shadow_width = 4;
272 if (pw->thermo_width == 0) pw->thermo_width = pw->shadow_width;
275 int direction, ascent, descent;
281 /* Measure the heading_label. */
282 XTextExtents (pw->heading_font,
283 pw->heading_label, strlen(pw->heading_label),
284 &direction, &ascent, &descent, &overall);
285 if (overall.width > pw->width) pw->width = overall.width;
286 pw->height += ascent + descent;
288 /* Measure the body_label. */
289 XTextExtents (pw->body_font,
290 pw->body_label, strlen(pw->body_label),
291 &direction, &ascent, &descent, &overall);
292 if (overall.width > pw->width) pw->width = overall.width;
293 pw->height += ascent + descent;
296 Dimension w2 = 0, w3 = 0;
297 Dimension h2 = 0, h3 = 0;
298 const char *passwd_string = "MMMMMMMMMMMM";
300 /* Measure the user_label. */
301 XTextExtents (pw->label_font,
302 pw->user_label, strlen(pw->user_label),
303 &direction, &ascent, &descent, &overall);
304 if (overall.width > w2) w2 = overall.width;
305 h2 += ascent + descent;
307 /* Measure the passwd_label. */
308 XTextExtents (pw->label_font,
309 pw->passwd_label, strlen(pw->passwd_label),
310 &direction, &ascent, &descent, &overall);
311 if (overall.width > w2) w2 = overall.width;
312 h2 += ascent + descent;
314 /* Measure the user_string. */
315 XTextExtents (pw->passwd_font,
316 pw->user_string, strlen(pw->user_string),
317 &direction, &ascent, &descent, &overall);
318 overall.width += (pw->shadow_width * 4);
319 ascent += (pw->shadow_width * 4);
320 if (overall.width > w3) w3 = overall.width;
321 h3 += ascent + descent;
323 /* Measure the (maximally-sized, dummy) passwd_string. */
324 XTextExtents (pw->passwd_font,
325 passwd_string, strlen(passwd_string),
326 &direction, &ascent, &descent, &overall);
327 overall.width += (pw->shadow_width * 4);
328 ascent += (pw->shadow_width * 4);
329 if (overall.width > w3) w3 = overall.width;
330 h3 += ascent + descent;
332 w2 = w2 + w3 + (pw->shadow_width * 2);
335 if (w2 > pw->width) pw->width = w2;
339 pw->width += (pw->internal_border * 2);
340 pw->height += (pw->internal_border * 4);
342 pw->width += pw->thermo_width + (pw->shadow_width * 3);
344 if (pw->logo_height > pw->height)
345 pw->height = pw->logo_height;
346 else if (pw->height > pw->logo_height)
347 pw->logo_height = pw->height;
349 pw->logo_width = pw->logo_height;
351 pw->width += pw->logo_width;
354 attrmask |= CWOverrideRedirect; attrs.override_redirect = True;
355 attrmask |= CWEventMask; attrs.event_mask = ExposureMask|KeyPressMask;
357 /* We need to remember the mouse position and restore it afterward, or
358 sometimes (perhaps only with Xinerama?) the mouse gets warped to
359 inside the bounds of the lock dialog window.
362 Window pointer_root, pointer_child;
363 int root_x, root_y, win_x, win_y;
365 pw->previous_mouse_x = 0;
366 pw->previous_mouse_y = 0;
367 if (XQueryPointer (si->dpy, RootWindowOfScreen (pw->prompt_screen->screen),
368 &pointer_root, &pointer_child,
369 &root_x, &root_y, &win_x, &win_y, &mask))
371 pw->previous_mouse_x = root_x;
372 pw->previous_mouse_y = root_y;
373 if (si->prefs.verbose_p)
374 fprintf (stderr, "%s: %d: mouse is at %d,%d.\n",
375 blurb(), pw->prompt_screen->number,
376 pw->previous_mouse_x, pw->previous_mouse_y);
378 else if (si->prefs.verbose_p)
379 fprintf (stderr, "%s: %d: unable to determine mouse position?\n",
380 blurb(), pw->prompt_screen->number);
383 /* Figure out where on the desktop to place the window so that it will
384 actually be visible; this takes into account virtual viewports as
388 get_screen_viewport (pw->prompt_screen, &x, &y, &w, &h,
389 pw->previous_mouse_x, pw->previous_mouse_y,
390 si->prefs.verbose_p);
391 if (si->prefs.debug_p) w /= 2;
392 pw->x = x + ((w + pw->width) / 2) - pw->width;
393 pw->y = y + ((h + pw->height) / 2) - pw->height;
394 if (pw->x < x) pw->x = x;
395 if (pw->y < y) pw->y = y;
398 pw->border_width = get_integer_resource ("passwd.borderWidth",
399 "Dialog.BorderWidth");
402 XCreateWindow (si->dpy,
403 RootWindowOfScreen(screen),
404 pw->x, pw->y, pw->width, pw->height, pw->border_width,
405 DefaultDepthOfScreen (screen), InputOutput,
406 DefaultVisualOfScreen(screen),
408 XSetWindowBackground (si->dpy, si->passwd_dialog, pw->background);
410 pw->logo_pixmap = xscreensaver_logo (ssi->screen, ssi->current_visual,
411 si->passwd_dialog, cmap,
413 &pw->logo_pixels, &pw->logo_npixels,
416 /* Before mapping the window, save the bits that are underneath the
417 rectangle the window will occlude. When we lower the window, we
418 restore these bits. This works, because the running screenhack
419 has already been sent SIGSTOP, so we know nothing else is drawing
424 pw->save_under = XCreatePixmap (si->dpy,
425 pw->prompt_screen->screensaver_window,
426 pw->width + (pw->border_width*2) + 1,
427 pw->height + (pw->border_width*2) + 1,
428 pw->prompt_screen->current_depth);
429 gcv.function = GXcopy;
430 gc = XCreateGC (si->dpy, pw->save_under, GCFunction, &gcv);
431 XCopyArea (si->dpy, pw->prompt_screen->screensaver_window,
433 pw->x - pw->border_width, pw->y - pw->border_width,
434 pw->width + (pw->border_width*2) + 1,
435 pw->height + (pw->border_width*2) + 1,
437 XFreeGC (si->dpy, gc);
440 XMapRaised (si->dpy, si->passwd_dialog);
441 XSync (si->dpy, False);
443 move_mouse_grab (si, si->passwd_dialog,
444 pw->prompt_screen->cursor,
445 pw->prompt_screen->number);
451 XInstallColormap (si->dpy, cmap);
452 draw_passwd_window (si);
453 XSync (si->dpy, False);
458 draw_passwd_window (saver_info *si)
460 passwd_dialog_data *pw = si->pw_data;
464 int x1, x2, x3, y1, y2;
468 height = (pw->heading_font->ascent + pw->heading_font->descent +
469 pw->body_font->ascent + pw->body_font->descent +
470 (2 * MAX ((pw->label_font->ascent + pw->label_font->descent),
471 (pw->passwd_font->ascent + pw->passwd_font->descent +
472 (pw->shadow_width * 4)))) +
473 pw->date_font->ascent + pw->date_font->descent
475 spacing = ((pw->height - (2 * pw->shadow_width) -
476 pw->internal_border - height)) / 8;
477 if (spacing < 0) spacing = 0;
479 gcv.foreground = pw->foreground;
480 gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
481 gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
482 x1 = pw->logo_width + pw->thermo_width + (pw->shadow_width * 3);
483 x3 = pw->width - (pw->shadow_width * 2);
484 y1 = (pw->shadow_width * 2) + spacing + spacing;
488 XSetFont (si->dpy, gc1, pw->heading_font->fid);
489 sw = string_width (pw->heading_font, pw->heading_label);
490 x2 = (x1 + ((x3 - x1 - sw) / 2));
491 y1 += spacing + pw->heading_font->ascent + pw->heading_font->descent;
492 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
493 pw->heading_label, strlen(pw->heading_label));
495 /* text below top heading
497 XSetFont (si->dpy, gc1, pw->body_font->fid);
498 y1 += spacing + pw->body_font->ascent + pw->body_font->descent;
499 sw = string_width (pw->body_font, pw->body_label);
500 x2 = (x1 + ((x3 - x1 - sw) / 2));
501 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
502 pw->body_label, strlen(pw->body_label));
505 tb_height = (pw->passwd_font->ascent + pw->passwd_font->descent +
506 (pw->shadow_width * 4));
508 /* the "User:" prompt
512 XSetForeground (si->dpy, gc1, pw->foreground);
513 XSetFont (si->dpy, gc1, pw->label_font->fid);
514 y1 += (spacing + tb_height);
515 x2 = (x1 + pw->internal_border +
516 MAX(string_width (pw->label_font, pw->user_label),
517 string_width (pw->label_font, pw->passwd_label)));
518 XDrawString (si->dpy, si->passwd_dialog, gc1,
519 x2 - string_width (pw->label_font, pw->user_label),
521 pw->user_label, strlen(pw->user_label));
523 /* the "Password:" prompt
525 y1 += (spacing + tb_height);
526 XDrawString (si->dpy, si->passwd_dialog, gc1,
527 x2 - string_width (pw->label_font, pw->passwd_label),
529 pw->passwd_label, strlen(pw->passwd_label));
532 XSetForeground (si->dpy, gc2, pw->passwd_background);
534 /* the "user name" text field
537 XSetForeground (si->dpy, gc1, pw->passwd_foreground);
538 XSetFont (si->dpy, gc1, pw->passwd_font->fid);
539 y1 += (spacing + tb_height);
540 x2 += (pw->shadow_width * 4);
542 pw->passwd_field_width = x3 - x2 - pw->internal_border;
543 pw->passwd_field_height = (pw->passwd_font->ascent +
544 pw->passwd_font->descent +
547 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
548 x2 - pw->shadow_width,
549 y1 - (pw->passwd_font->ascent + pw->passwd_font->descent),
550 pw->passwd_field_width, pw->passwd_field_height);
551 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
552 pw->user_string, strlen(pw->user_string));
554 /* the "password" text field
556 y1 += (spacing + tb_height);
558 pw->passwd_field_x = x2 - pw->shadow_width;
559 pw->passwd_field_y = y1 - (pw->passwd_font->ascent +
560 pw->passwd_font->descent);
562 /* The shadow around the text fields
565 y1 += (spacing + (pw->shadow_width * 3));
566 x1 = x2 - (pw->shadow_width * 2);
567 x2 = pw->passwd_field_width + (pw->shadow_width * 2);
568 y2 = pw->passwd_field_height + (pw->shadow_width * 2);
570 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
573 pw->shadow_bottom, pw->shadow_top);
575 y1 += (spacing + pw->passwd_font->ascent + pw->passwd_font->descent +
576 (pw->shadow_width * 4));
577 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
580 pw->shadow_bottom, pw->shadow_top);
583 /* The date, below the text fields
587 time_t now = time ((time_t *) 0);
588 struct tm *tm = localtime (&now);
589 memset (buf, 0, sizeof(buf));
590 strftime (buf, sizeof(buf)-1, pw->date_label, tm);
592 XSetFont (si->dpy, gc1, pw->date_font->fid);
593 y1 += pw->shadow_width;
594 y1 += (spacing + tb_height);
596 sw = string_width (pw->date_font, buf);
598 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1, buf, strlen(buf));
604 x1 = pw->shadow_width * 6;
605 y1 = pw->shadow_width * 6;
606 x2 = pw->logo_width - (pw->shadow_width * 12);
607 y2 = pw->logo_height - (pw->shadow_width * 12);
613 unsigned int w, h, bw, d;
614 XGetGeometry (si->dpy, pw->logo_pixmap, &root, &x, &y, &w, &h, &bw, &d);
615 XSetForeground (si->dpy, gc1, pw->foreground);
616 XSetBackground (si->dpy, gc1, pw->background);
618 XCopyPlane (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1,
620 x1 + ((x2 - (int)w) / 2),
621 y1 + ((y2 - (int)h) / 2),
624 XCopyArea (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1,
626 x1 + ((x2 - (int)w) / 2),
627 y1 + ((y2 - (int)h) / 2));
632 XSetForeground (si->dpy, gc1, pw->thermo_foreground);
633 XSetForeground (si->dpy, gc2, pw->thermo_background);
635 pw->thermo_field_x = pw->logo_width + pw->shadow_width;
636 pw->thermo_field_y = pw->shadow_width * 5;
637 pw->thermo_field_height = pw->height - (pw->shadow_width * 10);
640 /* Solid border inside the logo box. */
641 XSetForeground (si->dpy, gc1, pw->foreground);
642 XDrawRectangle (si->dpy, si->passwd_dialog, gc1, x1, y1, x2-1, y2-1);
645 /* The shadow around the logo
647 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
648 pw->shadow_width * 4,
649 pw->shadow_width * 4,
650 pw->logo_width - (pw->shadow_width * 8),
651 pw->logo_height - (pw->shadow_width * 8),
653 pw->shadow_bottom, pw->shadow_top);
655 /* The shadow around the thermometer
657 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
659 pw->shadow_width * 4,
660 pw->thermo_width + (pw->shadow_width * 2),
661 pw->height - (pw->shadow_width * 8),
663 pw->shadow_bottom, pw->shadow_top);
666 /* Solid border inside the thermometer. */
667 XSetForeground (si->dpy, gc1, pw->foreground);
668 XDrawRectangle (si->dpy, si->passwd_dialog, gc1,
669 pw->thermo_field_x, pw->thermo_field_y,
670 pw->thermo_width - 1, pw->thermo_field_height - 1);
673 /* The shadow around the whole window
675 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
676 0, 0, pw->width, pw->height, pw->shadow_width,
677 pw->shadow_top, pw->shadow_bottom);
679 XFreeGC (si->dpy, gc1);
680 XFreeGC (si->dpy, gc2);
682 update_passwd_window (si, pw->passwd_string, pw->ratio);
687 update_passwd_window (saver_info *si, const char *printed_passwd, float ratio)
689 passwd_dialog_data *pw = si->pw_data;
696 gcv.foreground = pw->passwd_foreground;
697 gcv.font = pw->passwd_font->fid;
698 gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground|GCFont, &gcv);
699 gcv.foreground = pw->passwd_background;
700 gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
704 char *s = strdup (printed_passwd);
705 if (pw->passwd_string) free (pw->passwd_string);
706 pw->passwd_string = s;
709 /* the "password" text field
711 rects[0].x = pw->passwd_field_x;
712 rects[0].y = pw->passwd_field_y;
713 rects[0].width = pw->passwd_field_width;
714 rects[0].height = pw->passwd_field_height;
716 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
717 rects[0].x, rects[0].y, rects[0].width, rects[0].height);
719 XSetClipRectangles (si->dpy, gc1, 0, 0, rects, 1, Unsorted);
721 XDrawString (si->dpy, si->passwd_dialog, gc1,
722 rects[0].x + pw->shadow_width,
723 rects[0].y + (pw->passwd_font->ascent +
724 pw->passwd_font->descent),
725 pw->passwd_string, strlen(pw->passwd_string));
727 XSetClipMask (si->dpy, gc1, None);
733 x = (rects[0].x + pw->shadow_width +
734 string_width (pw->passwd_font, pw->passwd_string));
735 y = rects[0].y + pw->shadow_width;
737 if (x > rects[0].x + rects[0].width - 1)
738 x = rects[0].x + rects[0].width - 1;
739 XDrawLine (si->dpy, si->passwd_dialog, gc1,
740 x, y, x, y + pw->passwd_font->ascent);
743 pw->i_beam = (pw->i_beam + 1) % 4;
748 y = (pw->thermo_field_height - 2) * (1.0 - pw->ratio);
751 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
752 pw->thermo_field_x + 1,
753 pw->thermo_field_y + 1,
756 XSetForeground (si->dpy, gc1, pw->thermo_foreground);
757 XFillRectangle (si->dpy, si->passwd_dialog, gc1,
758 pw->thermo_field_x + 1,
759 pw->thermo_field_y + 1 + y,
761 MAX (0, pw->thermo_field_height - y - 2));
764 XFreeGC (si->dpy, gc1);
765 XFreeGC (si->dpy, gc2);
766 XSync (si->dpy, False);
771 destroy_passwd_window (saver_info *si)
773 saver_preferences *p = &si->prefs;
774 passwd_dialog_data *pw = si->pw_data;
775 saver_screen_info *ssi = pw->prompt_screen;
776 Colormap cmap = DefaultColormapOfScreen (ssi->screen);
777 Pixel black = BlackPixelOfScreen (ssi->screen);
778 Pixel white = WhitePixelOfScreen (ssi->screen);
781 memset (pw->typed_passwd, 0, sizeof(pw->typed_passwd));
782 memset (pw->passwd_string, 0, strlen(pw->passwd_string));
785 XtRemoveTimeOut (pw->timer);
787 move_mouse_grab (si, RootWindowOfScreen (ssi->screen),
788 ssi->cursor, ssi->number);
791 fprintf (stderr, "%s: %d: moving mouse back to %d,%d.\n",
792 blurb(), ssi->number,
793 pw->previous_mouse_x, pw->previous_mouse_y);
795 XWarpPointer (si->dpy, None, RootWindowOfScreen (ssi->screen),
797 pw->previous_mouse_x, pw->previous_mouse_y);
799 XSync (si->dpy, False);
800 while (XCheckMaskEvent (si->dpy, PointerMotionMask, &event))
802 fprintf (stderr, "%s: discarding MotionNotify event.\n", blurb());
804 if (si->passwd_dialog)
806 XDestroyWindow (si->dpy, si->passwd_dialog);
807 si->passwd_dialog = 0;
814 gcv.function = GXcopy;
815 gc = XCreateGC (si->dpy, ssi->screensaver_window, GCFunction, &gcv);
816 XCopyArea (si->dpy, pw->save_under,
817 ssi->screensaver_window, gc,
819 pw->width + (pw->border_width*2) + 1,
820 pw->height + (pw->border_width*2) + 1,
821 pw->x - pw->border_width, pw->y - pw->border_width);
822 XFreePixmap (si->dpy, pw->save_under);
824 XFreeGC (si->dpy, gc);
827 if (pw->heading_label) free (pw->heading_label);
828 if (pw->body_label) free (pw->body_label);
829 if (pw->user_label) free (pw->user_label);
830 if (pw->passwd_label) free (pw->passwd_label);
831 if (pw->date_label) free (pw->date_label);
832 if (pw->user_string) free (pw->user_string);
833 if (pw->passwd_string) free (pw->passwd_string);
835 if (pw->heading_font) XFreeFont (si->dpy, pw->heading_font);
836 if (pw->body_font) XFreeFont (si->dpy, pw->body_font);
837 if (pw->label_font) XFreeFont (si->dpy, pw->label_font);
838 if (pw->passwd_font) XFreeFont (si->dpy, pw->passwd_font);
839 if (pw->date_font) XFreeFont (si->dpy, pw->date_font);
841 if (pw->foreground != black && pw->foreground != white)
842 XFreeColors (si->dpy, cmap, &pw->foreground, 1, 0L);
843 if (pw->background != black && pw->background != white)
844 XFreeColors (si->dpy, cmap, &pw->background, 1, 0L);
845 if (pw->passwd_foreground != black && pw->passwd_foreground != white)
846 XFreeColors (si->dpy, cmap, &pw->passwd_foreground, 1, 0L);
847 if (pw->passwd_background != black && pw->passwd_background != white)
848 XFreeColors (si->dpy, cmap, &pw->passwd_background, 1, 0L);
849 if (pw->thermo_foreground != black && pw->thermo_foreground != white)
850 XFreeColors (si->dpy, cmap, &pw->thermo_foreground, 1, 0L);
851 if (pw->thermo_background != black && pw->thermo_background != white)
852 XFreeColors (si->dpy, cmap, &pw->thermo_background, 1, 0L);
853 if (pw->shadow_top != black && pw->shadow_top != white)
854 XFreeColors (si->dpy, cmap, &pw->shadow_top, 1, 0L);
855 if (pw->shadow_bottom != black && pw->shadow_bottom != white)
856 XFreeColors (si->dpy, cmap, &pw->shadow_bottom, 1, 0L);
859 XFreePixmap (si->dpy, pw->logo_pixmap);
862 if (pw->logo_npixels)
863 XFreeColors (si->dpy, cmap, pw->logo_pixels, pw->logo_npixels, 0L);
864 free (pw->logo_pixels);
866 pw->logo_npixels = 0;
870 XFreePixmap (si->dpy, pw->save_under);
873 XInstallColormap (si->dpy, cmap);
875 memset (pw, 0, sizeof(*pw));
881 #ifdef HAVE_XHPDISABLERESET
882 /* This function enables and disables the C-Sh-Reset hot-key, which
883 normally resets the X server (logging out the logged-in user.)
884 We don't want random people to be able to do that while the
888 hp_lock_reset (saver_info *si, Bool lock_p)
890 static Bool hp_locked_p = False;
892 /* Calls to XHPDisableReset and XHPEnableReset must be balanced,
893 or BadAccess errors occur. (It's ok for this to be global,
894 since it affects the whole machine, not just the current screen.)
896 if (hp_locked_p == lock_p)
900 XHPDisableReset (si->dpy);
902 XHPEnableReset (si->dpy);
903 hp_locked_p = lock_p;
905 #endif /* HAVE_XHPDISABLERESET */
908 #ifdef HAVE_XF86MISCSETGRABKEYSSTATE
910 /* This function enables and disables the Ctrl-Alt-KP_star and
911 Ctrl-Alt-KP_slash hot-keys, which (in XFree86 4.2) break any
912 grabs and/or kill the grabbing client. That would effectively
913 unlock the screen, so we don't like that.
915 The Ctrl-Alt-KP_star and Ctrl-Alt-KP_slash hot-keys only exist
916 if AllowDeactivateGrabs and/or AllowClosedownGrabs are turned on
917 in XF86Config. I believe they are disabled by default.
919 This does not affect any other keys (specifically Ctrl-Alt-BS or
920 Ctrl-Alt-F1) but I wish it did. Maybe it will someday.
923 xfree_lock_grab_smasher (saver_info *si, Bool lock_p)
925 saver_preferences *p = &si->prefs;
926 int status = XF86MiscSetGrabKeysState (si->dpy, !lock_p);
928 if (p->verbose_p && status != MiscExtGrabStateSuccess)
929 fprintf (stderr, "%s: error: XF86MiscSetGrabKeysState returned %s\n",
931 (status == MiscExtGrabStateSuccess ? "MiscExtGrabStateSuccess" :
932 status == MiscExtGrabStateLocked ? "MiscExtGrabStateLocked" :
933 status == MiscExtGrabStateAlready ? "MiscExtGrabStateAlready" :
936 #endif /* HAVE_XF86MISCSETGRABKEYSSTATE */
941 /* This function enables and disables the C-Sh-F1 ... F12 hot-keys,
942 which, on Linux systems, switches to another virtual console.
943 We'd like the whole screen/keyboard to be locked, not just one
944 virtual console, so this function disables that while the X
947 Unfortunately, this doesn't work -- this ioctl only works when
948 called by root, and we have disavowed our privileges long ago.
950 #ifdef HAVE_VT_LOCKSWITCH
952 linux_lock_vt_switch (saver_info *si, Bool lock_p)
954 saver_preferences *p = &si->prefs;
955 static Bool vt_locked_p = False;
956 const char *dev_console = "/dev/console";
959 if (lock_p == vt_locked_p)
962 if (lock_p && !p->lock_vt_p)
965 fd = open (dev_console, O_RDWR);
969 sprintf (buf, "%s: couldn't %s VTs: %s", blurb(),
970 (lock_p ? "lock" : "unlock"),
972 #if 1 /* #### doesn't work yet, so don't bother complaining */
978 if (ioctl (fd, (lock_p ? VT_LOCKSWITCH : VT_UNLOCKSWITCH)) == 0)
980 vt_locked_p = lock_p;
983 fprintf (stderr, "%s: %s VTs\n", blurb(),
984 (lock_p ? "locked" : "unlocked"));
989 sprintf (buf, "%s: couldn't %s VTs: ioctl", blurb(),
990 (lock_p ? "lock" : "unlock"));
991 #if 0 /* #### doesn't work yet, so don't bother complaining */
998 #endif /* HAVE_VT_LOCKSWITCH */
1001 /* This function enables and disables the C-Alt-Plus and C-Alt-Minus
1002 hot-keys, which normally change the resolution of the X server.
1003 We don't want people to be able to switch the server resolution
1004 while the screen is locked, because if they switch to a higher
1005 resolution, it could cause part of the underlying desktop to become
1008 #ifdef HAVE_XF86VMODE
1010 static int ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error);
1011 static Bool vp_got_error = False;
1014 xfree_lock_mode_switch (saver_info *si, Bool lock_p)
1016 static Bool any_mode_locked_p = False;
1017 saver_preferences *p = &si->prefs;
1021 XErrorHandler old_handler;
1023 if (any_mode_locked_p == lock_p)
1025 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1028 for (screen = 0; screen < si->nscreens; screen++)
1030 XSync (si->dpy, False);
1031 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1032 status = XF86VidModeLockModeSwitch (si->dpy, screen, lock_p);
1033 XSync (si->dpy, False);
1034 XSetErrorHandler (old_handler);
1035 if (vp_got_error) status = False;
1038 any_mode_locked_p = lock_p;
1040 if (!status && (p->verbose_p || !lock_p))
1041 /* Only print this when verbose, or when we locked but can't unlock.
1042 I tried printing this message whenever it comes up, but
1043 mode-locking always fails if DontZoom is set in XF86Config. */
1044 fprintf (stderr, "%s: %d: unable to %s mode switching!\n",
1045 blurb(), screen, (lock_p ? "lock" : "unlock"));
1046 else if (p->verbose_p)
1047 fprintf (stderr, "%s: %d: %s mode switching.\n",
1048 blurb(), screen, (lock_p ? "locked" : "unlocked"));
1053 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1055 vp_got_error = True;
1059 #endif /* HAVE_XF86VMODE */
1062 /* If the viewport has been scrolled since the screen was blanked,
1063 then scroll it back to where it belongs. This function only exists
1064 to patch over a very brief race condition.
1067 undo_vp_motion (saver_info *si)
1069 #ifdef HAVE_XF86VMODE
1070 saver_preferences *p = &si->prefs;
1074 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1077 for (screen = 0; screen < si->nscreens; screen++)
1079 saver_screen_info *ssi = &si->screens[screen];
1083 if (ssi->blank_vp_x == -1 && ssi->blank_vp_y == -1)
1085 if (!XF86VidModeGetViewPort (si->dpy, screen, &x, &y))
1087 if (ssi->blank_vp_x == x && ssi->blank_vp_y == y)
1090 /* We're going to move the viewport. The mouse has just been grabbed on
1091 (and constrained to, thus warped to) the password window, so it is no
1092 longer near the edge of the screen. However, wait a bit anyway, just
1093 to make sure the server drains its last motion event, so that the
1094 screen doesn't continue to scroll after we've reset the viewport.
1096 XSync (si->dpy, False);
1097 usleep (250000); /* 1/4 second */
1098 XSync (si->dpy, False);
1100 status = XF86VidModeSetViewPort (si->dpy, screen,
1101 ssi->blank_vp_x, ssi->blank_vp_y);
1105 "%s: %d: unable to move vp from (%d,%d) back to (%d,%d)!\n",
1106 blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1107 else if (p->verbose_p)
1109 "%s: %d: vp moved to (%d,%d); moved it back to (%d,%d).\n",
1110 blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1112 #endif /* HAVE_XF86VMODE */
1121 passwd_animate_timer (XtPointer closure, XtIntervalId *id)
1123 saver_info *si = (saver_info *) closure;
1125 passwd_dialog_data *pw = si->pw_data;
1129 pw->ratio -= (1.0 / ((double) si->prefs.passwd_timeout / (double) tick));
1133 if (pw->state == pw_read)
1134 pw->state = pw_time;
1137 update_passwd_window (si, 0, pw->ratio);
1139 if (pw->state == pw_read)
1140 pw->timer = XtAppAddTimeOut (si->app, tick, passwd_animate_timer,
1145 idle_timer ((XtPointer) si, id);
1149 static XComposeStatus *compose_status;
1152 handle_passwd_key (saver_info *si, XKeyEvent *event)
1154 saver_preferences *p = &si->prefs;
1155 passwd_dialog_data *pw = si->pw_data;
1156 int pw_size = sizeof (pw->typed_passwd) - 1;
1157 char *typed_passwd = pw->typed_passwd;
1161 int size = XLookupString (event, s, 1, 0, compose_status);
1163 if (size != 1) return;
1169 case '\010': case '\177': /* Backspace */
1173 typed_passwd [strlen(typed_passwd)-1] = 0;
1176 case '\025': case '\030': /* Erase line */
1177 memset (typed_passwd, 0, pw_size);
1180 case '\012': case '\015': /* Enter */
1181 if (pw->state != pw_read)
1182 ; /* already done? */
1183 else if (typed_passwd[0] == 0)
1184 pw->state = pw_null;
1187 update_passwd_window (si, "Checking...", pw->ratio);
1188 XSync (si->dpy, False);
1189 if (passwd_valid_p (typed_passwd, p->verbose_p))
1192 pw->state = pw_fail;
1193 update_passwd_window (si, "", pw->ratio);
1198 i = strlen (typed_passwd);
1203 typed_passwd [i] = *s;
1204 typed_passwd [i+1] = 0;
1209 i = strlen(typed_passwd);
1210 stars = (char *) malloc(i+1);
1211 memset (stars, '*', i);
1213 update_passwd_window (si, stars, pw->ratio);
1219 passwd_event_loop (saver_info *si)
1221 saver_preferences *p = &si->prefs;
1224 passwd_animate_timer ((XtPointer) si, 0);
1226 while (si->pw_data && si->pw_data->state == pw_read)
1228 XtAppNextEvent (si->app, &event);
1229 if (event.xany.window == si->passwd_dialog && event.xany.type == Expose)
1230 draw_passwd_window (si);
1231 else if (event.xany.type == KeyPress)
1232 handle_passwd_key (si, &event.xkey);
1234 XtDispatchEvent (&event);
1237 switch (si->pw_data->state)
1239 case pw_ok: msg = 0; break;
1240 case pw_null: msg = ""; break;
1241 case pw_time: msg = "Timed out!"; break;
1242 default: msg = "Sorry!"; break;
1245 if (si->pw_data->state == pw_fail)
1246 si->unlock_failures++;
1249 switch (si->pw_data->state)
1252 fprintf (stderr, "%s: password correct.\n", blurb()); break;
1254 fprintf (stderr, "%s: password incorrect!\n", blurb()); break;
1257 fprintf (stderr, "%s: password entry cancelled.\n", blurb()); break;
1259 fprintf (stderr, "%s: password entry timed out.\n", blurb()); break;
1264 if (si->pw_data->state == pw_fail)
1266 /* If they typed a password (as opposed to just hitting return) and
1267 the password was invalid, log it.
1269 struct passwd *pw = getpwuid (getuid ());
1270 char *d = DisplayString (si->dpy);
1271 char *u = (pw->pw_name ? pw->pw_name : "???");
1279 # if defined(LOG_AUTHPRIV)
1281 # elif defined(LOG_AUTH)
1288 openlog (progname, opt, fac);
1289 syslog (LOG_NOTICE, "FAILED LOGIN %d ON DISPLAY \"%s\", FOR \"%s\"",
1290 si->unlock_failures, d, u);
1293 #endif /* HAVE_SYSLOG */
1295 if (si->pw_data->state == pw_fail)
1296 XBell (si->dpy, False);
1298 if (si->pw_data->state == pw_ok && si->unlock_failures != 0)
1300 if (si->unlock_failures == 1)
1301 fprintf (real_stderr,
1302 "%s: WARNING: 1 failed attempt to unlock the screen.\n",
1305 fprintf (real_stderr,
1306 "%s: WARNING: %d failed attempts to unlock the screen.\n",
1307 blurb(), si->unlock_failures);
1308 fflush (real_stderr);
1310 si->unlock_failures = 0;
1315 si->pw_data->i_beam = 0;
1316 update_passwd_window (si, msg, 0.0);
1317 XSync (si->dpy, False);
1320 /* Swallow all pending KeyPress/KeyRelease events. */
1323 while (XCheckMaskEvent (si->dpy, KeyPressMask|KeyReleaseMask, &e))
1331 handle_typeahead (saver_info *si)
1333 passwd_dialog_data *pw = si->pw_data;
1335 if (!si->unlock_typeahead)
1338 i = strlen (si->unlock_typeahead);
1339 if (i >= sizeof(pw->typed_passwd) - 1)
1340 i = sizeof(pw->typed_passwd) - 1;
1342 memcpy (pw->typed_passwd, si->unlock_typeahead, i);
1343 pw->typed_passwd [i] = 0;
1345 memset (si->unlock_typeahead, '*', strlen(si->unlock_typeahead));
1346 si->unlock_typeahead[i] = 0;
1347 update_passwd_window (si, si->unlock_typeahead, pw->ratio);
1349 free (si->unlock_typeahead);
1350 si->unlock_typeahead = 0;
1355 unlock_p (saver_info *si)
1357 saver_preferences *p = &si->prefs;
1360 raise_window (si, True, True, True);
1363 fprintf (stderr, "%s: prompting for password.\n", blurb());
1365 if (si->pw_data || si->passwd_dialog)
1366 destroy_passwd_window (si);
1368 make_passwd_window (si);
1370 compose_status = calloc (1, sizeof (*compose_status));
1372 handle_typeahead (si);
1373 passwd_event_loop (si);
1375 status = (si->pw_data->state == pw_ok);
1376 destroy_passwd_window (si);
1378 free (compose_status);
1386 set_locked_p (saver_info *si, Bool locked_p)
1388 si->locked_p = locked_p;
1390 #ifdef HAVE_XHPDISABLERESET
1391 hp_lock_reset (si, locked_p); /* turn off/on C-Sh-Reset */
1393 #ifdef HAVE_VT_LOCKSWITCH
1394 linux_lock_vt_switch (si, locked_p); /* turn off/on C-Alt-F1 */
1396 #ifdef HAVE_XF86VMODE
1397 xfree_lock_mode_switch (si, locked_p); /* turn off/on C-Alt-Plus */
1399 #ifdef HAVE_XF86MISCSETGRABKEYSSTATE
1400 xfree_lock_grab_smasher (si, locked_p); /* turn off/on C-Alt-KP-*,/ */
1403 store_saver_status (si); /* store locked-p */
1407 #else /* NO_LOCKING -- whole file */
1410 set_locked_p (saver_info *si, Bool locked_p)
1412 if (locked_p) abort();
1415 #endif /* !NO_LOCKING */