aad2cc6f58530d849f3d0b35849005a197697558
[xscreensaver] / driver / lock.c
1 /* lock.c --- handling the password dialog for locking-mode.
2  * xscreensaver, Copyright (c) 1993-1998 Jamie Zawinski <jwz@jwz.org>
3  *
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 
10  * implied warranty.
11  */
12
13 /* Athena locking code contributed by Jon A. Christopher <jac8782@tamu.edu> */
14 /* Copyright 1997, with the same permissions as above. */
15
16 #ifdef HAVE_CONFIG_H
17 # include "config.h"
18 #endif
19
20 #include <X11/Intrinsic.h>
21 #include <X11/Xos.h>            /* for time() */
22 #include "xscreensaver.h"
23 #include "resources.h"
24
25 #ifndef NO_LOCKING              /* (mostly) whole file */
26
27 #ifdef HAVE_SYSLOG
28 # include <syslog.h>
29 #endif /* HAVE_SYSLOG */
30
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 */
35
36 #ifdef HAVE_VT_LOCKSWITCH
37 # include <fcntl.h>
38 # include <sys/ioctl.h>
39 # include <sys/vt.h>
40   static void linux_lock_vt_switch (saver_info *si, Bool lock_p);
41 #endif /* HAVE_VT_LOCKSWITCH */
42
43 #ifdef HAVE_XF86VMODE
44 # include <X11/extensions/xf86vmode.h>
45   static void xfree_lock_mode_switch (saver_info *si, Bool lock_p);
46 #endif /* HAVE_XF86VMODE */
47
48
49 #ifdef _VROOT_H_
50 ERROR!  You must not include vroot.h in this file.
51 #endif
52
53 #ifndef VMS
54 # include <pwd.h>
55 #else /* VMS */
56
57 extern char *getenv(const char *name);
58 extern int validate_user(char *name, char *password);
59
60 static Bool
61 vms_passwd_valid_p(char *pw, Bool verbose_p)
62 {
63   return (validate_user (getenv("USER"), typed_passwd) == 1);
64 }
65 # undef passwd_valid_p
66 # define passwd_valid_p vms_passwd_valid_p
67
68 #endif /* VMS */
69
70
71 #undef MAX
72 #define MAX(a,b) ((a)>(b)?(a):(b))
73
74 enum passwd_state { pw_read, pw_ok, pw_null, pw_fail, pw_cancel, pw_time };
75
76 struct passwd_dialog_data {
77
78   saver_screen_info *prompt_screen;
79   int previous_mouse_x, previous_mouse_y;
80
81   enum passwd_state state;
82   char typed_passwd [80];
83   XtIntervalId timer;
84   int i_beam;
85
86   float ratio;
87   Position x, y;
88   Dimension width;
89   Dimension height;
90   Dimension border_width;
91
92   char *heading_label;
93   char *body_label;
94   char *user_label;
95   char *passwd_label;
96   char *date_label;
97   char *user_string;
98   char *passwd_string;
99
100   XFontStruct *heading_font;
101   XFontStruct *body_font;
102   XFontStruct *label_font;
103   XFontStruct *passwd_font;
104   XFontStruct *date_font;
105
106   Pixel foreground;
107   Pixel background;
108   Pixel passwd_foreground;
109   Pixel passwd_background;
110   Pixel thermo_foreground;
111   Pixel thermo_background;
112   Pixel shadow_top;
113   Pixel shadow_bottom;
114
115   Dimension logo_width;
116   Dimension logo_height;
117   Dimension thermo_width;
118   Dimension internal_border;
119   Dimension shadow_width;
120
121   Dimension passwd_field_x, passwd_field_y;
122   Dimension passwd_field_width, passwd_field_height;
123
124   Dimension thermo_field_x, thermo_field_y;
125   Dimension thermo_field_height;
126
127   Pixmap logo_pixmap;
128   int logo_npixels;
129   unsigned long *logo_pixels;
130
131   Pixmap save_under;
132 };
133
134 static void draw_passwd_window (saver_info *si);
135 static void update_passwd_window (saver_info *si, const char *printed_passwd,
136                                   float ratio);
137 static void destroy_passwd_window (saver_info *si);
138 static void undo_vp_motion (saver_info *si);
139
140
141 static void
142 make_passwd_window (saver_info *si)
143 {
144   struct passwd *p = getpwuid (getuid ());
145   XSetWindowAttributes attrs;
146   unsigned long attrmask = 0;
147   passwd_dialog_data *pw = (passwd_dialog_data *) calloc (1, sizeof(*pw));
148   Screen *screen;
149   Colormap cmap;
150   char *f;
151
152   pw->prompt_screen = &si->screens [mouse_screen (si)];
153   if (si->prefs.verbose_p)
154     fprintf (stderr, "%s: %d: creating password dialog.\n",
155              blurb(), pw->prompt_screen->number);
156
157   screen = pw->prompt_screen->screen;
158   cmap = DefaultColormapOfScreen (screen);
159
160   pw->ratio = 1.0;
161
162   pw->heading_label = get_string_resource ("passwd.heading.label",
163                                            "Dialog.Label.Label");
164   pw->body_label = get_string_resource ("passwd.body.label",
165                                         "Dialog.Label.Label");
166   pw->user_label = get_string_resource ("passwd.user.label",
167                                         "Dialog.Label.Label");
168   pw->passwd_label = get_string_resource ("passwd.passwd.label",
169                                           "Dialog.Label.Label");
170   pw->date_label = get_string_resource ("dateFormat", "DateFormat");
171
172   if (!pw->heading_label)
173     pw->heading_label = strdup("ERROR: REESOURCES NOT INSTALLED CORRECTLY");
174   if (!pw->body_label)
175     pw->body_label = strdup("ERROR: REESOURCES NOT INSTALLED CORRECTLY");
176   if (!pw->user_label) pw->user_label = strdup("ERROR");
177   if (!pw->passwd_label) pw->passwd_label = strdup("ERROR");
178   if (!pw->date_label) pw->date_label = strdup("ERROR");
179
180   /* Put the version number in the label. */
181   {
182     char *s = (char *) malloc (strlen(pw->heading_label) + 20);
183     sprintf(s, pw->heading_label, si->version);
184     free (pw->heading_label);
185     pw->heading_label = s;
186   }
187
188   pw->user_string = (p && p->pw_name ? p->pw_name : "???");
189   pw->passwd_string = strdup("");
190
191   f = get_string_resource ("passwd.headingFont", "Dialog.Font");
192   pw->heading_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
193   if (!pw->heading_font) pw->heading_font = XLoadQueryFont (si->dpy, "fixed");
194   if (f) free (f);
195
196   f = get_string_resource("passwd.bodyFont", "Dialog.Font");
197   pw->body_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
198   if (!pw->body_font) pw->body_font = XLoadQueryFont (si->dpy, "fixed");
199   if (f) free (f);
200
201   f = get_string_resource("passwd.labelFont", "Dialog.Font");
202   pw->label_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
203   if (!pw->label_font) pw->label_font = XLoadQueryFont (si->dpy, "fixed");
204   if (f) free (f);
205
206   f = get_string_resource("passwd.passwdFont", "Dialog.Font");
207   pw->passwd_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
208   if (!pw->passwd_font) pw->passwd_font = XLoadQueryFont (si->dpy, "fixed");
209   if (f) free (f);
210
211   f = get_string_resource("passwd.dateFont", "Dialog.Font");
212   pw->date_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
213   if (!pw->date_font) pw->date_font = XLoadQueryFont (si->dpy, "fixed");
214   if (f) free (f);
215
216   pw->foreground = get_pixel_resource ("passwd.foreground",
217                                        "Dialog.Foreground",
218                                        si->dpy, cmap);
219   pw->background = get_pixel_resource ("passwd.background",
220                                        "Dialog.Background",
221                                        si->dpy, cmap);
222
223   if (pw->foreground == pw->background)
224     {
225       /* Make sure the error messages show up. */
226       pw->foreground = BlackPixelOfScreen (screen);
227       pw->background = WhitePixelOfScreen (screen);
228     }
229
230   pw->passwd_foreground = get_pixel_resource ("passwd.text.foreground",
231                                               "Dialog.Text.Foreground",
232                                               si->dpy, cmap);
233   pw->passwd_background = get_pixel_resource ("passwd.text.background",
234                                               "Dialog.Text.Background",
235                                               si->dpy, cmap);
236   pw->thermo_foreground = get_pixel_resource ("passwd.thermometer.foreground",
237                                               "Dialog.Thermometer.Foreground",
238                                               si->dpy, cmap);
239   pw->thermo_background = get_pixel_resource ("passwd.thermometer.background",
240                                               "Dialog.Thermometer.Background",
241                                               si->dpy, cmap);
242   pw->shadow_top = get_pixel_resource ("passwd.topShadowColor",
243                                        "Dialog.Foreground",
244                                        si->dpy, cmap);
245   pw->shadow_bottom = get_pixel_resource ("passwd.bottomShadowColor",
246                                           "Dialog.Background",
247                                           si->dpy, cmap);
248
249   pw->logo_width = get_integer_resource ("passwd.logo.width",
250                                          "Dialog.Logo.Width");
251   pw->logo_height = get_integer_resource ("passwd.logo.height",
252                                           "Dialog.Logo.Height");
253   pw->thermo_width = get_integer_resource ("passwd.thermometer.width",
254                                            "Dialog.Thermometer.Width");
255   pw->internal_border = get_integer_resource ("passwd.internalBorderWidth",
256                                               "Dialog.InternalBorderWidth");
257   pw->shadow_width = get_integer_resource ("passwd.shadowThickness",
258                                            "Dialog.ShadowThickness");
259
260   if (pw->logo_width == 0)  pw->logo_width = 150;
261   if (pw->logo_height == 0) pw->logo_height = 150;
262   if (pw->internal_border == 0) pw->internal_border = 15;
263   if (pw->shadow_width == 0) pw->shadow_width = 4;
264   if (pw->thermo_width == 0) pw->thermo_width = pw->shadow_width;
265
266   {
267     int direction, ascent, descent;
268     XCharStruct overall;
269
270     pw->width = 0;
271     pw->height = 0;
272
273     /* Measure the heading_label. */
274     XTextExtents (pw->heading_font,
275                   pw->heading_label, strlen(pw->heading_label),
276                   &direction, &ascent, &descent, &overall);
277     if (overall.width > pw->width) pw->width = overall.width;
278     pw->height += ascent + descent;
279
280     /* Measure the body_label. */
281     XTextExtents (pw->body_font,
282                   pw->body_label, strlen(pw->body_label),
283                   &direction, &ascent, &descent, &overall);
284     if (overall.width > pw->width) pw->width = overall.width;
285     pw->height += ascent + descent;
286
287     {
288       Dimension w2 = 0, w3 = 0;
289       Dimension h2 = 0, h3 = 0;
290       const char *passwd_string = "MMMMMMMMMMMM";
291
292       /* Measure the user_label. */
293       XTextExtents (pw->label_font,
294                     pw->user_label, strlen(pw->user_label),
295                     &direction, &ascent, &descent, &overall);
296       if (overall.width > w2)  w2 = overall.width;
297       h2 += ascent + descent;
298
299       /* Measure the passwd_label. */
300       XTextExtents (pw->label_font,
301                     pw->passwd_label, strlen(pw->passwd_label),
302                     &direction, &ascent, &descent, &overall);
303       if (overall.width > w2)  w2 = overall.width;
304       h2 += ascent + descent;
305
306       /* Measure the user_string. */
307       XTextExtents (pw->passwd_font,
308                     pw->user_string, strlen(pw->user_string),
309                     &direction, &ascent, &descent, &overall);
310       overall.width += (pw->shadow_width * 4);
311       ascent += (pw->shadow_width * 4);
312       if (overall.width > w3)  w3 = overall.width;
313       h3 += ascent + descent;
314
315       /* Measure the (maximally-sized, dummy) passwd_string. */
316       XTextExtents (pw->passwd_font,
317                     passwd_string, strlen(passwd_string),
318                     &direction, &ascent, &descent, &overall);
319       overall.width += (pw->shadow_width * 4);
320       ascent += (pw->shadow_width * 4);
321       if (overall.width > w3)  w3 = overall.width;
322       h3 += ascent + descent;
323
324       w2 = w2 + w3 + (pw->shadow_width * 2);
325       h2 = MAX (h2, h3);
326
327       if (w2 > pw->width)  pw->width  = w2;
328       pw->height += h2;
329     }
330
331     pw->width  += (pw->internal_border * 2);
332     pw->height += (pw->internal_border * 4);
333
334     pw->width += pw->thermo_width + (pw->shadow_width * 3);
335
336     if (pw->logo_height > pw->height)
337       pw->height = pw->logo_height;
338     else if (pw->height > pw->logo_height)
339       pw->logo_height = pw->height;
340
341     pw->logo_width = pw->logo_height;
342
343     pw->width += pw->logo_width;
344   }
345
346   attrmask |= CWOverrideRedirect; attrs.override_redirect = True;
347   attrmask |= CWEventMask; attrs.event_mask = ExposureMask|KeyPressMask;
348
349   /* We need to remember the mouse position and restore it afterward, or
350      sometimes (perhaps only with Xinerama?) the mouse gets warped to
351      inside the bounds of the lock dialog window.
352    */
353   {
354     Window pointer_root, pointer_child;
355     int root_x, root_y, win_x, win_y;
356     unsigned int mask;
357     pw->previous_mouse_x = 0;
358     pw->previous_mouse_y = 0;
359     if (XQueryPointer (si->dpy, RootWindowOfScreen (pw->prompt_screen->screen),
360                        &pointer_root, &pointer_child,
361                        &root_x, &root_y, &win_x, &win_y, &mask))
362       {
363         pw->previous_mouse_x = root_x;
364         pw->previous_mouse_y = root_y;
365         if (si->prefs.verbose_p)
366           fprintf (stderr, "%s: %d: mouse is at %d,%d.\n",
367                    blurb(), pw->prompt_screen->number,
368                    pw->previous_mouse_x, pw->previous_mouse_y);
369       }
370     else if (si->prefs.verbose_p)
371       fprintf (stderr, "%s: %d: unable to determine mouse position?\n",
372                blurb(), pw->prompt_screen->number);
373   }
374
375   /* Figure out where on the desktop to place the window so that it will
376      actually be visible; this takes into account virtual viewports as
377      well as Xinerama. */
378   {
379     int x, y, w, h;
380     get_screen_viewport (pw->prompt_screen, &x, &y, &w, &h,
381                          pw->previous_mouse_x, pw->previous_mouse_y,
382                          si->prefs.verbose_p);
383     if (si->prefs.debug_p) w /= 2;
384     pw->x = x + ((w + pw->width) / 2) - pw->width;
385     pw->y = y + ((h + pw->height) / 2) - pw->height;
386     if (pw->x < x) pw->x = x;
387     if (pw->y < y) pw->y = y;
388   }
389
390   pw->border_width = get_integer_resource ("passwd.borderWidth",
391                                            "Dialog.BorderWidth");
392
393   si->passwd_dialog =
394     XCreateWindow (si->dpy,
395                    RootWindowOfScreen(screen),
396                    pw->x, pw->y, pw->width, pw->height, pw->border_width,
397                    DefaultDepthOfScreen (screen), InputOutput,
398                    DefaultVisualOfScreen(screen),
399                    attrmask, &attrs);
400   XSetWindowBackground (si->dpy, si->passwd_dialog, pw->background);
401
402   pw->logo_pixmap = xscreensaver_logo (si->dpy, si->passwd_dialog, cmap,
403                                        pw->background, 
404                                        &pw->logo_pixels, &pw->logo_npixels,
405                                        0, True);
406
407   /* Before mapping the window, save the bits that are underneath the
408      rectangle the window will occlude.  When we lower the window, we
409      restore these bits.  This works, because the running screenhack
410      has already been sent SIGSTOP, so we know nothing else is drawing
411      right now! */
412   {
413     XGCValues gcv;
414     GC gc;
415     pw->save_under = XCreatePixmap (si->dpy,
416                                     pw->prompt_screen->screensaver_window,
417                                     pw->width + (pw->border_width*2) + 1,
418                                     pw->height + (pw->border_width*2) + 1,
419                                     pw->prompt_screen->current_depth);
420     gcv.function = GXcopy;
421     gc = XCreateGC (si->dpy, pw->save_under, GCFunction, &gcv);
422     XCopyArea (si->dpy, pw->prompt_screen->screensaver_window,
423                pw->save_under, gc,
424                pw->x - pw->border_width, pw->y - pw->border_width,
425                pw->width + (pw->border_width*2) + 1,
426                pw->height + (pw->border_width*2) + 1,
427                0, 0);
428     XFreeGC (si->dpy, gc);
429   }
430
431   XMapRaised (si->dpy, si->passwd_dialog);
432   XSync (si->dpy, False);
433
434   move_mouse_grab (si, si->passwd_dialog,
435                    pw->prompt_screen->cursor,
436                    pw->prompt_screen->number);
437   undo_vp_motion (si);
438
439   si->pw_data = pw;
440
441   if (cmap)
442     XInstallColormap (si->dpy, cmap);
443   draw_passwd_window (si);
444   XSync (si->dpy, False);
445 }
446
447
448 static void
449 draw_passwd_window (saver_info *si)
450 {
451   passwd_dialog_data *pw = si->pw_data;
452   XGCValues gcv;
453   GC gc1, gc2;
454   int spacing, height;
455   int x1, x2, x3, y1, y2;
456   int sw;
457   int tb_height;
458
459   height = (pw->heading_font->ascent + pw->heading_font->descent +
460             pw->body_font->ascent + pw->body_font->descent +
461             (2 * MAX ((pw->label_font->ascent + pw->label_font->descent),
462                       (pw->passwd_font->ascent + pw->passwd_font->descent +
463                        (pw->shadow_width * 4)))) +
464             pw->date_font->ascent + pw->date_font->descent
465             );
466   spacing = ((pw->height - (2 * pw->shadow_width) -
467               pw->internal_border - height)) / 8;
468   if (spacing < 0) spacing = 0;
469
470   gcv.foreground = pw->foreground;
471   gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
472   gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
473   x1 = pw->logo_width + pw->thermo_width + (pw->shadow_width * 3);
474   x3 = pw->width - (pw->shadow_width * 2);
475   y1 = (pw->shadow_width * 2) + spacing + spacing;
476
477   /* top heading
478    */
479   XSetFont (si->dpy, gc1, pw->heading_font->fid);
480   sw = string_width (pw->heading_font, pw->heading_label);
481   x2 = (x1 + ((x3 - x1 - sw) / 2));
482   y1 += spacing + pw->heading_font->ascent + pw->heading_font->descent;
483   XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
484                pw->heading_label, strlen(pw->heading_label));
485
486   /* text below top heading
487    */
488   XSetFont (si->dpy, gc1, pw->body_font->fid);
489   y1 += spacing + pw->body_font->ascent + pw->body_font->descent;
490   sw = string_width (pw->body_font, pw->body_label);
491   x2 = (x1 + ((x3 - x1 - sw) / 2));
492   XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
493                pw->body_label, strlen(pw->body_label));
494
495
496   tb_height = (pw->passwd_font->ascent + pw->passwd_font->descent +
497                (pw->shadow_width * 4));
498
499   /* the "User:" prompt
500    */
501   y1 += spacing;
502   y2 = y1;
503   XSetForeground (si->dpy, gc1, pw->foreground);
504   XSetFont (si->dpy, gc1, pw->label_font->fid);
505   y1 += (spacing + tb_height);
506   x2 = (x1 + pw->internal_border +
507         MAX(string_width (pw->label_font, pw->user_label),
508             string_width (pw->label_font, pw->passwd_label)));
509   XDrawString (si->dpy, si->passwd_dialog, gc1,
510                x2 - string_width (pw->label_font, pw->user_label),
511                y1,
512                pw->user_label, strlen(pw->user_label));
513
514   /* the "Password:" prompt
515    */
516   y1 += (spacing + tb_height);
517   XDrawString (si->dpy, si->passwd_dialog, gc1,
518                x2 - string_width (pw->label_font, pw->passwd_label),
519                y1,
520                pw->passwd_label, strlen(pw->passwd_label));
521
522
523   XSetForeground (si->dpy, gc2, pw->passwd_background);
524
525   /* the "user name" text field
526    */
527   y1 = y2;
528   XSetForeground (si->dpy, gc1, pw->passwd_foreground);
529   XSetFont (si->dpy, gc1, pw->passwd_font->fid);
530   y1 += (spacing + tb_height);
531   x2 += (pw->shadow_width * 4);
532
533   pw->passwd_field_width = x3 - x2 - pw->internal_border;
534   pw->passwd_field_height = (pw->passwd_font->ascent +
535                              pw->passwd_font->descent +
536                              pw->shadow_width);
537
538   XFillRectangle (si->dpy, si->passwd_dialog, gc2,
539                   x2 - pw->shadow_width,
540                   y1 - (pw->passwd_font->ascent + pw->passwd_font->descent),
541                   pw->passwd_field_width, pw->passwd_field_height);
542   XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
543                pw->user_string, strlen(pw->user_string));
544
545   /* the "password" text field
546    */
547   y1 += (spacing + tb_height);
548
549   pw->passwd_field_x = x2 - pw->shadow_width;
550   pw->passwd_field_y = y1 - (pw->passwd_font->ascent +
551                              pw->passwd_font->descent);
552
553   /* The shadow around the text fields
554    */
555   y1 = y2;
556   y1 += (spacing + (pw->shadow_width * 3));
557   x1 = x2 - (pw->shadow_width * 2);
558   x2 = pw->passwd_field_width + (pw->shadow_width * 2);
559   y2 = pw->passwd_field_height + (pw->shadow_width * 2);
560
561   draw_shaded_rectangle (si->dpy, si->passwd_dialog,
562                          x1, y1, x2, y2,
563                          pw->shadow_width,
564                          pw->shadow_bottom, pw->shadow_top);
565
566   y1 += (spacing + pw->passwd_font->ascent + pw->passwd_font->descent +
567          (pw->shadow_width * 4));
568   draw_shaded_rectangle (si->dpy, si->passwd_dialog,
569                          x1, y1, x2, y2,
570                          pw->shadow_width,
571                          pw->shadow_bottom, pw->shadow_top);
572
573
574   /* The date, below the text fields
575    */
576   {
577     char buf[100];
578     time_t now = time ((time_t *) 0);
579     struct tm *tm = localtime (&now);
580     memset (buf, 0, sizeof(buf));
581     strftime (buf, sizeof(buf)-1, pw->date_label, tm);
582
583     XSetFont (si->dpy, gc1, pw->date_font->fid);
584     y1 += pw->shadow_width;
585     y1 += (spacing + tb_height);
586     y1 += spacing/2;
587     sw = string_width (pw->date_font, buf);
588     x2 = x1 + x2 - sw;
589     XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1, buf, strlen(buf));
590   }
591
592
593   /* The logo
594    */
595   x1 = pw->shadow_width * 6;
596   y1 = pw->shadow_width * 6;
597   x2 = pw->logo_width - (pw->shadow_width * 12);
598   y2 = pw->logo_height - (pw->shadow_width * 12);
599
600   if (pw->logo_pixmap)
601     {
602       Window root;
603       int x, y;
604       unsigned int w, h, bw, d;
605       XGetGeometry (si->dpy, pw->logo_pixmap, &root, &x, &y, &w, &h, &bw, &d);
606       XSetForeground (si->dpy, gc1, pw->foreground);
607       XSetBackground (si->dpy, gc1, pw->background);
608       if (d == 1)
609         XCopyPlane (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1,
610                     0, 0, w, h,
611                     x1 + ((x2 - (int)w) / 2),
612                     y1 + ((y2 - (int)h) / 2),
613                     1);
614       else
615         XCopyArea (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1,
616                    0, 0, w, h,
617                    x1 + ((x2 - (int)w) / 2),
618                    y1 + ((y2 - (int)h) / 2));
619     }
620
621   /* The thermometer
622    */
623   XSetForeground (si->dpy, gc1, pw->thermo_foreground);
624   XSetForeground (si->dpy, gc2, pw->thermo_background);
625
626   pw->thermo_field_x = pw->logo_width + pw->shadow_width;
627   pw->thermo_field_y = pw->shadow_width * 5;
628   pw->thermo_field_height = pw->height - (pw->shadow_width * 10);
629
630 #if 0
631   /* Solid border inside the logo box. */
632   XSetForeground (si->dpy, gc1, pw->foreground);
633   XDrawRectangle (si->dpy, si->passwd_dialog, gc1, x1, y1, x2-1, y2-1);
634 #endif
635
636   /* The shadow around the logo
637    */
638   draw_shaded_rectangle (si->dpy, si->passwd_dialog,
639                          pw->shadow_width * 4,
640                          pw->shadow_width * 4,
641                          pw->logo_width - (pw->shadow_width * 8),
642                          pw->logo_height - (pw->shadow_width * 8),
643                          pw->shadow_width,
644                          pw->shadow_bottom, pw->shadow_top);
645
646   /* The shadow around the thermometer
647    */
648   draw_shaded_rectangle (si->dpy, si->passwd_dialog,
649                          pw->logo_width,
650                          pw->shadow_width * 4,
651                          pw->thermo_width + (pw->shadow_width * 2),
652                          pw->height - (pw->shadow_width * 8),
653                          pw->shadow_width,
654                          pw->shadow_bottom, pw->shadow_top);
655
656 #if 1
657   /* Solid border inside the thermometer. */
658   XSetForeground (si->dpy, gc1, pw->foreground);
659   XDrawRectangle (si->dpy, si->passwd_dialog, gc1, 
660                   pw->thermo_field_x, pw->thermo_field_y,
661                   pw->thermo_width - 1, pw->thermo_field_height - 1);
662 #endif
663
664   /* The shadow around the whole window
665    */
666   draw_shaded_rectangle (si->dpy, si->passwd_dialog,
667                          0, 0, pw->width, pw->height, pw->shadow_width,
668                          pw->shadow_top, pw->shadow_bottom);
669
670   XFreeGC (si->dpy, gc1);
671   XFreeGC (si->dpy, gc2);
672
673   update_passwd_window (si, pw->passwd_string, pw->ratio);
674 }
675
676
677 static void
678 update_passwd_window (saver_info *si, const char *printed_passwd, float ratio)
679 {
680   passwd_dialog_data *pw = si->pw_data;
681   XGCValues gcv;
682   GC gc1, gc2;
683   int x, y;
684   XRectangle rects[1];
685
686   pw->ratio = ratio;
687   gcv.foreground = pw->passwd_foreground;
688   gcv.font = pw->passwd_font->fid;
689   gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground|GCFont, &gcv);
690   gcv.foreground = pw->passwd_background;
691   gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
692
693   if (printed_passwd)
694     {
695       char *s = strdup (printed_passwd);
696       if (pw->passwd_string) free (pw->passwd_string);
697       pw->passwd_string = s;
698     }
699
700   /* the "password" text field
701    */
702   rects[0].x =  pw->passwd_field_x;
703   rects[0].y =  pw->passwd_field_y;
704   rects[0].width = pw->passwd_field_width;
705   rects[0].height = pw->passwd_field_height;
706
707   XFillRectangle (si->dpy, si->passwd_dialog, gc2,
708                   rects[0].x, rects[0].y, rects[0].width, rects[0].height);
709
710   XSetClipRectangles (si->dpy, gc1, 0, 0, rects, 1, Unsorted);
711
712   XDrawString (si->dpy, si->passwd_dialog, gc1,
713                rects[0].x + pw->shadow_width,
714                rects[0].y + (pw->passwd_font->ascent +
715                              pw->passwd_font->descent),
716                pw->passwd_string, strlen(pw->passwd_string));
717
718   XSetClipMask (si->dpy, gc1, None);
719
720   /* The I-beam
721    */
722   if (pw->i_beam != 0)
723     {
724       x = (rects[0].x + pw->shadow_width +
725            string_width (pw->passwd_font, pw->passwd_string));
726       y = rects[0].y + pw->shadow_width;
727
728       if (x > rects[0].x + rects[0].width - 1)
729         x = rects[0].x + rects[0].width - 1;
730       XDrawLine (si->dpy, si->passwd_dialog, gc1, 
731                  x, y, x, y + pw->passwd_font->ascent);
732     }
733
734   pw->i_beam = (pw->i_beam + 1) % 4;
735
736
737   /* the thermometer
738    */
739   y = (pw->thermo_field_height - 2) * (1.0 - pw->ratio);
740   if (y > 0)
741     {
742       XFillRectangle (si->dpy, si->passwd_dialog, gc2,
743                       pw->thermo_field_x + 1,
744                       pw->thermo_field_y + 1,
745                       pw->thermo_width-2,
746                       y);
747       XSetForeground (si->dpy, gc1, pw->thermo_foreground);
748       XFillRectangle (si->dpy, si->passwd_dialog, gc1,
749                       pw->thermo_field_x + 1,
750                       pw->thermo_field_y + 1 + y,
751                       pw->thermo_width-2,
752                       MAX (0, pw->thermo_field_height - y - 2));
753     }
754
755   XFreeGC (si->dpy, gc1);
756   XFreeGC (si->dpy, gc2);
757   XSync (si->dpy, False);
758 }
759
760
761 static void
762 destroy_passwd_window (saver_info *si)
763 {
764   saver_preferences *p = &si->prefs;
765   passwd_dialog_data *pw = si->pw_data;
766   saver_screen_info *ssi = pw->prompt_screen;
767   Colormap cmap = DefaultColormapOfScreen (ssi->screen);
768   Pixel black = BlackPixelOfScreen (ssi->screen);
769   Pixel white = WhitePixelOfScreen (ssi->screen);
770   XEvent event;
771
772   if (pw->timer)
773     XtRemoveTimeOut (pw->timer);
774
775   move_mouse_grab (si, RootWindowOfScreen (ssi->screen),
776                    ssi->cursor, ssi->number);
777
778   if (p->verbose_p)
779     fprintf (stderr, "%s: %d: moving mouse back to %d,%d.\n",
780              blurb(), ssi->number,
781              pw->previous_mouse_x, pw->previous_mouse_y);
782
783   XWarpPointer (si->dpy, None, RootWindowOfScreen (ssi->screen),
784                 0, 0, 0, 0,
785                 pw->previous_mouse_x, pw->previous_mouse_y);
786
787   XSync (si->dpy, False);
788   while (XCheckMaskEvent (si->dpy, PointerMotionMask, &event))
789     if (p->verbose_p)
790       fprintf (stderr, "%s: discarding MotionNotify event.\n", blurb());
791
792   if (si->passwd_dialog)
793     {
794       XDestroyWindow (si->dpy, si->passwd_dialog);
795       si->passwd_dialog = 0;
796     }
797   
798   if (pw->save_under)
799     {
800       XGCValues gcv;
801       GC gc;
802       gcv.function = GXcopy;
803       gc = XCreateGC (si->dpy, ssi->screensaver_window, GCFunction, &gcv);
804       XCopyArea (si->dpy, pw->save_under,
805                  ssi->screensaver_window, gc,
806                  0, 0,
807                  pw->width + (pw->border_width*2) + 1,
808                  pw->height + (pw->border_width*2) + 1,
809                  pw->x - pw->border_width, pw->y - pw->border_width);
810       XFreePixmap (si->dpy, pw->save_under);
811       pw->save_under = 0;
812       XFreeGC (si->dpy, gc);
813     }
814
815   if (pw->heading_label) free (pw->heading_label);
816   if (pw->body_label)    free (pw->body_label);
817   if (pw->user_label)    free (pw->user_label);
818   if (pw->passwd_label)  free (pw->passwd_label);
819
820   if (pw->heading_font) XFreeFont (si->dpy, pw->heading_font);
821   if (pw->body_font)    XFreeFont (si->dpy, pw->body_font);
822   if (pw->label_font)   XFreeFont (si->dpy, pw->label_font);
823   if (pw->passwd_font)  XFreeFont (si->dpy, pw->passwd_font);
824
825   if (pw->foreground != black && pw->foreground != white)
826     XFreeColors (si->dpy, cmap, &pw->foreground, 1, 0L);
827   if (pw->background != black && pw->background != white)
828     XFreeColors (si->dpy, cmap, &pw->background, 1, 0L);
829   if (pw->passwd_foreground != black && pw->passwd_foreground != white)
830     XFreeColors (si->dpy, cmap, &pw->passwd_foreground, 1, 0L);
831   if (pw->passwd_background != black && pw->passwd_background != white)
832     XFreeColors (si->dpy, cmap, &pw->passwd_background, 1, 0L);
833   if (pw->thermo_foreground != black && pw->thermo_foreground != white)
834     XFreeColors (si->dpy, cmap, &pw->thermo_foreground, 1, 0L);
835   if (pw->thermo_background != black && pw->thermo_background != white)
836     XFreeColors (si->dpy, cmap, &pw->thermo_background, 1, 0L);
837   if (pw->shadow_top != black && pw->shadow_top != white)
838     XFreeColors (si->dpy, cmap, &pw->shadow_top, 1, 0L);
839   if (pw->shadow_bottom != black && pw->shadow_bottom != white)
840     XFreeColors (si->dpy, cmap, &pw->shadow_bottom, 1, 0L);
841
842   if (pw->logo_pixmap)
843     XFreePixmap (si->dpy, pw->logo_pixmap);
844   if (pw->logo_npixels && pw->logo_pixels)
845     XFreeColors (si->dpy, cmap, pw->logo_pixels, pw->logo_npixels, 0L);
846   if (pw->logo_pixels)
847     free (pw->logo_pixels);
848
849   memset (pw, 0, sizeof(*pw));
850   free (pw);
851
852   if (cmap)
853     XInstallColormap (si->dpy, cmap);
854
855   si->pw_data = 0;
856 }
857
858
859 #ifdef HAVE_XHPDISABLERESET
860 /* This function enables and disables the C-Sh-Reset hot-key, which
861    normally resets the X server (logging out the logged-in user.)
862    We don't want random people to be able to do that while the
863    screen is locked.
864  */
865 static void
866 hp_lock_reset (saver_info *si, Bool lock_p)
867 {
868   static Bool hp_locked_p = False;
869
870   /* Calls to XHPDisableReset and XHPEnableReset must be balanced,
871      or BadAccess errors occur.  (It's ok for this to be global,
872      since it affects the whole machine, not just the current screen.)
873   */
874   if (hp_locked_p == lock_p)
875     return;
876
877   if (lock_p)
878     XHPDisableReset (si->dpy);
879   else
880     XHPEnableReset (si->dpy);
881   hp_locked_p = lock_p;
882 }
883 #endif /* HAVE_XHPDISABLERESET */
884
885
886 \f
887 /* This function enables and disables the C-Sh-F1 ... F12 hot-keys,
888    which, on Linux systems, switches to another virtual console.
889    We'd like the whole screen/keyboard to be locked, not just one
890    virtual console, so this function disables that while the X
891    screen is locked.
892
893    Unfortunately, this doesn't work -- this ioctl only works when
894    called by root, and we have disavowed our privileges long ago.
895  */
896 #ifdef HAVE_VT_LOCKSWITCH
897 static void
898 linux_lock_vt_switch (saver_info *si, Bool lock_p)
899 {
900   saver_preferences *p = &si->prefs;
901   static Bool vt_locked_p = False;
902   const char *dev_console = "/dev/console";
903   int fd;
904
905   if (lock_p == vt_locked_p)
906     return;
907
908   if (lock_p && !p->lock_vt_p)
909     return;
910
911   fd = open (dev_console, O_RDWR);
912   if (fd < 0)
913     {
914       char buf [255];
915       sprintf (buf, "%s: couldn't %s VTs: %s", blurb(),
916                (lock_p ? "lock" : "unlock"),
917                dev_console);
918 #if 1 /* #### doesn't work yet, so don't bother complaining */
919       perror (buf);
920 #endif
921       return;
922     }
923
924   if (ioctl (fd, (lock_p ? VT_LOCKSWITCH : VT_UNLOCKSWITCH)) == 0)
925     {
926       vt_locked_p = lock_p;
927
928       if (p->verbose_p)
929         fprintf (stderr, "%s: %s VTs\n", blurb(),
930                  (lock_p ? "locked" : "unlocked"));
931     }
932   else
933     {
934       char buf [255];
935       sprintf (buf, "%s: couldn't %s VTs: ioctl", blurb(),
936                (lock_p ? "lock" : "unlock"));
937 #if 0 /* #### doesn't work yet, so don't bother complaining */
938       perror (buf);
939 #endif
940     }
941
942   close (fd);
943 }
944 #endif /* HAVE_VT_LOCKSWITCH */
945
946 \f
947 /* This function enables and disables the C-Alt-Plus and C-Alt-Minus
948    hot-keys, which normally change the resolution of the X server.
949    We don't want people to be able to switch the server resolution
950    while the screen is locked, because if they switch to a higher
951    resolution, it could cause part of the underlying desktop to become
952    exposed.
953  */
954 #ifdef HAVE_XF86VMODE
955
956 static int ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error);
957 static Bool vp_got_error = False;
958
959 static void
960 xfree_lock_mode_switch (saver_info *si, Bool lock_p)
961 {
962   static Bool any_mode_locked_p = False;
963   saver_preferences *p = &si->prefs;
964   int screen;
965   int event, error;
966   Bool status;
967   XErrorHandler old_handler;
968
969   if (any_mode_locked_p == lock_p)
970     return;
971   if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
972     return;
973
974   for (screen = 0; screen < si->nscreens; screen++)
975     {
976       XSync (si->dpy, False);
977       old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
978       status = XF86VidModeLockModeSwitch (si->dpy, screen, lock_p);
979       XSync (si->dpy, False);
980       XSetErrorHandler (old_handler);
981       if (vp_got_error) status = False;
982
983       if (status)
984         any_mode_locked_p = lock_p;
985
986       if (!status && (p->verbose_p || !lock_p))
987         /* Only print this when verbose, or when we locked but can't unlock.
988            I tried printing this message whenever it comes up, but
989            mode-locking always fails if DontZoom is set in XF86Config. */
990         fprintf (stderr, "%s: %d: unable to %s mode switching!\n",
991                  blurb(), screen, (lock_p ? "lock" : "unlock"));
992       else if (p->verbose_p)
993         fprintf (stderr, "%s: %d: %s mode switching.\n",
994                  blurb(), screen, (lock_p ? "locked" : "unlocked"));
995     }
996 }
997
998 static int
999 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1000 {
1001   vp_got_error = True;
1002   return 0;
1003 }
1004
1005 #endif /* HAVE_XF86VMODE */
1006
1007 \f
1008 /* If the viewport has been scrolled since the screen was blanked,
1009    then scroll it back to where it belongs.  This function only exists
1010    to patch over a very brief race condition.
1011  */
1012 static void
1013 undo_vp_motion (saver_info *si)
1014 {
1015 #ifdef HAVE_XF86VMODE
1016   saver_preferences *p = &si->prefs;
1017   int screen;
1018   int event, error;
1019
1020   if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1021     return;
1022
1023   for (screen = 0; screen < si->nscreens; screen++)
1024     {
1025       saver_screen_info *ssi = &si->screens[screen];
1026       int x, y;
1027       Bool status;
1028
1029       if (ssi->blank_vp_x == -1 && ssi->blank_vp_y == -1)
1030         break;
1031       if (!XF86VidModeGetViewPort (si->dpy, screen, &x, &y))
1032         return;
1033       if (ssi->blank_vp_x == x && ssi->blank_vp_y == y)
1034         return;
1035     
1036       /* We're going to move the viewport.  The mouse has just been grabbed on
1037          (and constrained to, thus warped to) the password window, so it is no
1038          longer near the edge of the screen.  However, wait a bit anyway, just
1039          to make sure the server drains its last motion event, so that the
1040          screen doesn't continue to scroll after we've reset the viewport.
1041        */
1042       XSync (si->dpy, False);
1043       usleep (250000);  /* 1/4 second */
1044       XSync (si->dpy, False);
1045
1046       status = XF86VidModeSetViewPort (si->dpy, screen,
1047                                        ssi->blank_vp_x, ssi->blank_vp_y);
1048
1049       if (!status)
1050         fprintf (stderr,
1051                  "%s: %d: unable to move vp from (%d,%d) back to (%d,%d)!\n",
1052                  blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1053       else if (p->verbose_p)
1054         fprintf (stderr,
1055                  "%s: %d: vp moved to (%d,%d); moved it back to (%d,%d).\n",
1056                  blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1057     }
1058 #endif /* HAVE_XF86VMODE */
1059 }
1060
1061
1062 \f
1063 /* Interactions
1064  */
1065
1066 static void
1067 passwd_animate_timer (XtPointer closure, XtIntervalId *id)
1068 {
1069   saver_info *si = (saver_info *) closure;
1070   int tick = 166;
1071   passwd_dialog_data *pw = si->pw_data;
1072
1073   if (!pw) return;
1074
1075   pw->ratio -= (1.0 / ((double) si->prefs.passwd_timeout / (double) tick));
1076   if (pw->ratio < 0)
1077     {
1078       pw->ratio = 0;
1079       if (pw->state == pw_read)
1080         pw->state = pw_time;
1081     }
1082
1083   update_passwd_window (si, 0, pw->ratio);
1084
1085   if (pw->state == pw_read)
1086     pw->timer = XtAppAddTimeOut (si->app, tick, passwd_animate_timer,
1087                                  (XtPointer) si);
1088   else
1089     pw->timer = 0;
1090
1091   idle_timer ((XtPointer) si, id);
1092 }
1093
1094
1095 static XComposeStatus *compose_status;
1096
1097 static void
1098 handle_passwd_key (saver_info *si, XKeyEvent *event)
1099 {
1100   saver_preferences *p = &si->prefs;
1101   passwd_dialog_data *pw = si->pw_data;
1102   int pw_size = sizeof (pw->typed_passwd) - 1;
1103   char *typed_passwd = pw->typed_passwd;
1104   char s[2];
1105   char *stars = 0;
1106   int i;
1107   int size = XLookupString (event, s, 1, 0, compose_status);
1108
1109   if (size != 1) return;
1110
1111   s[1] = 0;
1112
1113   switch (*s)
1114     {
1115     case '\010': case '\177':                           /* Backspace */
1116       if (!*typed_passwd)
1117         XBell (si->dpy, 0);
1118       else
1119         typed_passwd [strlen(typed_passwd)-1] = 0;
1120       break;
1121
1122     case '\025': case '\030':                           /* Erase line */
1123       memset (typed_passwd, 0, pw_size);
1124       break;
1125
1126     case '\012': case '\015':                           /* Enter */
1127       if (pw->state != pw_read)
1128         ;  /* already done? */
1129       else if (typed_passwd[0] == 0)
1130         pw->state = pw_null;
1131       else
1132         {
1133           update_passwd_window (si, "Checking...", pw->ratio);
1134           XSync (si->dpy, False);
1135           if (passwd_valid_p (typed_passwd, p->verbose_p))
1136             pw->state = pw_ok;
1137           else
1138             pw->state = pw_fail;
1139           update_passwd_window (si, "", pw->ratio);
1140         }
1141       break;
1142
1143     default:
1144       i = strlen (typed_passwd);
1145       if (i >= pw_size-1)
1146         XBell (si->dpy, 0);
1147       else
1148         {
1149           typed_passwd [i] = *s;
1150           typed_passwd [i+1] = 0;
1151         }
1152       break;
1153     }
1154
1155   i = strlen(typed_passwd);
1156   stars = (char *) malloc(i+1);
1157   memset (stars, '*', i);
1158   stars[i] = 0;
1159   update_passwd_window (si, stars, pw->ratio);
1160   free (stars);
1161 }
1162
1163
1164 static void
1165 passwd_event_loop (saver_info *si)
1166 {
1167   saver_preferences *p = &si->prefs;
1168   char *msg = 0;
1169   XEvent event;
1170   passwd_animate_timer ((XtPointer) si, 0);
1171
1172   while (si->pw_data && si->pw_data->state == pw_read)
1173     {
1174       XtAppNextEvent (si->app, &event);
1175       if (event.xany.window == si->passwd_dialog && event.xany.type == Expose)
1176         draw_passwd_window (si);
1177       else if (event.xany.type == KeyPress)
1178         handle_passwd_key (si, &event.xkey);
1179       else
1180         XtDispatchEvent (&event);
1181     }
1182
1183   switch (si->pw_data->state)
1184     {
1185     case pw_ok:   msg = 0; break;
1186     case pw_null: msg = ""; break;
1187     case pw_time: msg = "Timed out!"; break;
1188     default:      msg = "Sorry!"; break;
1189     }
1190
1191   if (si->pw_data->state == pw_fail)
1192     si->unlock_failures++;
1193
1194   if (p->verbose_p)
1195     switch (si->pw_data->state)
1196       {
1197       case pw_ok:
1198         fprintf (stderr, "%s: password correct.\n", blurb()); break;
1199       case pw_fail:
1200         fprintf (stderr, "%s: password incorrect!\n", blurb()); break;
1201       case pw_null:
1202       case pw_cancel:
1203         fprintf (stderr, "%s: password entry cancelled.\n", blurb()); break;
1204       case pw_time:
1205         fprintf (stderr, "%s: password entry timed out.\n", blurb()); break;
1206       default: break;
1207       }
1208
1209 #ifdef HAVE_SYSLOG
1210   if (si->pw_data->state == pw_fail)
1211     {
1212       /* If they typed a password (as opposed to just hitting return) and
1213          the password was invalid, log it.
1214       */
1215       struct passwd *pw = getpwuid (getuid ());
1216       char *d = DisplayString (si->dpy);
1217       char *u = (pw->pw_name ? pw->pw_name : "???");
1218       int opt = 0;
1219       int fac = 0;
1220
1221 # ifdef LOG_PID
1222       opt = LOG_PID;
1223 # endif
1224
1225 # if defined(LOG_AUTHPRIV)
1226       fac = LOG_AUTHPRIV;
1227 # elif defined(LOG_AUTH)
1228       fac = LOG_AUTH;
1229 # else
1230       fac = LOG_DAEMON;
1231 # endif
1232
1233       if (!d) d = "";
1234       openlog (progname, opt, fac);
1235       syslog (LOG_NOTICE, "FAILED LOGIN %d ON DISPLAY \"%s\", FOR \"%s\"",
1236               si->unlock_failures, d, u);
1237       closelog ();
1238     }
1239 #endif /* HAVE_SYSLOG */
1240
1241   if (si->pw_data->state == pw_fail)
1242     XBell (si->dpy, False);
1243
1244   if (si->pw_data->state == pw_ok && si->unlock_failures != 0)
1245     {
1246       if (si->unlock_failures == 1)
1247         fprintf (real_stderr,
1248                  "%s: WARNING: 1 failed attempt to unlock the screen.\n",
1249                  blurb());
1250       else
1251         fprintf (real_stderr,
1252                  "%s: WARNING: %d failed attempts to unlock the screen.\n",
1253                  blurb(), si->unlock_failures);
1254       fflush (real_stderr);
1255
1256       si->unlock_failures = 0;
1257     }
1258
1259   if (msg)
1260     {
1261       si->pw_data->i_beam = 0;
1262       update_passwd_window (si, msg, 0.0);
1263       XSync (si->dpy, False);
1264       sleep (1);
1265
1266       /* Swallow all pending KeyPress/KeyRelease events. */
1267       {
1268         XEvent e;
1269         while (XCheckMaskEvent (si->dpy, KeyPressMask|KeyReleaseMask, &e))
1270           ;
1271       }
1272     }
1273 }
1274
1275
1276 static void
1277 handle_typeahead (saver_info *si)
1278 {
1279   passwd_dialog_data *pw = si->pw_data;
1280   int i;
1281   if (!si->unlock_typeahead)
1282     return;
1283
1284   i = strlen (si->unlock_typeahead);
1285   if (i >= sizeof(pw->typed_passwd) - 1)
1286     i = sizeof(pw->typed_passwd) - 1;
1287
1288   memcpy (pw->typed_passwd, si->unlock_typeahead, i);
1289   pw->typed_passwd [i] = 0;
1290
1291   memset (si->unlock_typeahead, '*', strlen(si->unlock_typeahead));
1292   si->unlock_typeahead[i] = 0;
1293   update_passwd_window (si, si->unlock_typeahead, pw->ratio);
1294
1295   free (si->unlock_typeahead);
1296   si->unlock_typeahead = 0;
1297 }
1298
1299
1300 Bool
1301 unlock_p (saver_info *si)
1302 {
1303   saver_preferences *p = &si->prefs;
1304   Bool status;
1305
1306   raise_window (si, True, True, True);
1307
1308   if (p->verbose_p)
1309     fprintf (stderr, "%s: prompting for password.\n", blurb());
1310
1311   if (si->pw_data || si->passwd_dialog)
1312     destroy_passwd_window (si);
1313
1314   make_passwd_window (si);
1315
1316   compose_status = calloc (1, sizeof (*compose_status));
1317
1318   handle_typeahead (si);
1319   passwd_event_loop (si);
1320
1321   status = (si->pw_data->state == pw_ok);
1322   destroy_passwd_window (si);
1323
1324   free (compose_status);
1325   compose_status = 0;
1326
1327   return status;
1328 }
1329
1330
1331 void
1332 set_locked_p (saver_info *si, Bool locked_p)
1333 {
1334   si->locked_p = locked_p;
1335
1336 #ifdef HAVE_XHPDISABLERESET
1337   hp_lock_reset (si, locked_p);                 /* turn off/on C-Sh-Reset */
1338 #endif
1339 #ifdef HAVE_VT_LOCKSWITCH
1340   linux_lock_vt_switch (si, locked_p);          /* turn off/on C-Alt-F1 */
1341 #endif
1342 #ifdef HAVE_XF86VMODE
1343   xfree_lock_mode_switch (si, locked_p);        /* turn off/on C-Alt-Plus */
1344 #endif
1345
1346   store_saver_status (si);                      /* store locked-p */
1347 }
1348
1349
1350 #else  /*  NO_LOCKING -- whole file */
1351
1352 void
1353 set_locked_p (saver_info *si, Bool locked_p)
1354 {
1355   if (locked_p) abort();
1356 }
1357
1358 #endif /* !NO_LOCKING */