http://www.mirrorservice.org/sites/master.us.finkmirrors.net/distfiles/md5/fa43fdd68d...
[xscreensaver] / driver / lock.c
1 /* lock.c --- handling the password dialog for locking-mode.
2  * xscreensaver, Copyright (c) 1993-2002 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 <time.h>
23 #include <sys/time.h>
24 #include "xscreensaver.h"
25 #include "resources.h"
26
27 #ifndef NO_LOCKING              /* (mostly) whole file */
28
29 #ifdef HAVE_SYSLOG
30 # include <syslog.h>
31 #endif /* HAVE_SYSLOG */
32
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 */
37
38 #ifdef HAVE_VT_LOCKSWITCH
39 # include <fcntl.h>
40 # include <sys/ioctl.h>
41 # include <sys/vt.h>
42   static void linux_lock_vt_switch (saver_info *si, Bool lock_p);
43 #endif /* HAVE_VT_LOCKSWITCH */
44
45 #ifdef HAVE_XF86VMODE
46 # include <X11/extensions/xf86vmode.h>
47   static void xfree_lock_mode_switch (saver_info *si, Bool lock_p);
48 #endif /* HAVE_XF86VMODE */
49
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 */
54
55
56 #ifdef _VROOT_H_
57 ERROR!  You must not include vroot.h in this file.
58 #endif
59
60 #ifndef VMS
61 # include <pwd.h>
62 #else /* VMS */
63
64 extern char *getenv(const char *name);
65 extern int validate_user(char *name, char *password);
66
67 static Bool
68 vms_passwd_valid_p(char *pw, Bool verbose_p)
69 {
70   return (validate_user (getenv("USER"), typed_passwd) == 1);
71 }
72 # undef passwd_valid_p
73 # define passwd_valid_p vms_passwd_valid_p
74
75 #endif /* VMS */
76
77
78 #undef MAX
79 #define MAX(a,b) ((a)>(b)?(a):(b))
80
81 enum passwd_state { pw_read, pw_ok, pw_null, pw_fail, pw_cancel, pw_time };
82
83 struct passwd_dialog_data {
84
85   saver_screen_info *prompt_screen;
86   int previous_mouse_x, previous_mouse_y;
87
88   enum passwd_state state;
89   char typed_passwd [80];
90   XtIntervalId timer;
91   int i_beam;
92
93   float ratio;
94   Position x, y;
95   Dimension width;
96   Dimension height;
97   Dimension border_width;
98
99   char *heading_label;
100   char *body_label;
101   char *user_label;
102   char *passwd_label;
103   char *date_label;
104   char *user_string;
105   char *passwd_string;
106
107   XFontStruct *heading_font;
108   XFontStruct *body_font;
109   XFontStruct *label_font;
110   XFontStruct *passwd_font;
111   XFontStruct *date_font;
112
113   Pixel foreground;
114   Pixel background;
115   Pixel passwd_foreground;
116   Pixel passwd_background;
117   Pixel thermo_foreground;
118   Pixel thermo_background;
119   Pixel shadow_top;
120   Pixel shadow_bottom;
121
122   Dimension logo_width;
123   Dimension logo_height;
124   Dimension thermo_width;
125   Dimension internal_border;
126   Dimension shadow_width;
127
128   Dimension passwd_field_x, passwd_field_y;
129   Dimension passwd_field_width, passwd_field_height;
130
131   Dimension thermo_field_x, thermo_field_y;
132   Dimension thermo_field_height;
133
134   Pixmap logo_pixmap;
135   int logo_npixels;
136   unsigned long *logo_pixels;
137
138   Pixmap save_under;
139 };
140
141 static void draw_passwd_window (saver_info *si);
142 static void update_passwd_window (saver_info *si, const char *printed_passwd,
143                                   float ratio);
144 static void destroy_passwd_window (saver_info *si);
145 static void undo_vp_motion (saver_info *si);
146
147
148 static void
149 make_passwd_window (saver_info *si)
150 {
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));
155   Screen *screen;
156   Colormap cmap;
157   char *f;
158   saver_screen_info *ssi = &si->screens [mouse_screen (si)];
159
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);
164
165   screen = pw->prompt_screen->screen;
166   cmap = DefaultColormapOfScreen (screen);
167
168   pw->ratio = 1.0;
169
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");
179
180   if (!pw->heading_label)
181     pw->heading_label = strdup("ERROR: REESOURCES NOT INSTALLED CORRECTLY");
182   if (!pw->body_label)
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");
187
188   /* Put the version number in the label. */
189   {
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;
194   }
195
196   pw->user_string = strdup (p && p->pw_name ? p->pw_name : "???");
197   pw->passwd_string = strdup("");
198
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");
202   if (f) free (f);
203
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");
207   if (f) free (f);
208
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");
212   if (f) free (f);
213
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");
217   if (f) free (f);
218
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");
222   if (f) free (f);
223
224   pw->foreground = get_pixel_resource ("passwd.foreground",
225                                        "Dialog.Foreground",
226                                        si->dpy, cmap);
227   pw->background = get_pixel_resource ("passwd.background",
228                                        "Dialog.Background",
229                                        si->dpy, cmap);
230
231   if (pw->foreground == pw->background)
232     {
233       /* Make sure the error messages show up. */
234       pw->foreground = BlackPixelOfScreen (screen);
235       pw->background = WhitePixelOfScreen (screen);
236     }
237
238   pw->passwd_foreground = get_pixel_resource ("passwd.text.foreground",
239                                               "Dialog.Text.Foreground",
240                                               si->dpy, cmap);
241   pw->passwd_background = get_pixel_resource ("passwd.text.background",
242                                               "Dialog.Text.Background",
243                                               si->dpy, cmap);
244   pw->thermo_foreground = get_pixel_resource ("passwd.thermometer.foreground",
245                                               "Dialog.Thermometer.Foreground",
246                                               si->dpy, cmap);
247   pw->thermo_background = get_pixel_resource ("passwd.thermometer.background",
248                                               "Dialog.Thermometer.Background",
249                                               si->dpy, cmap);
250   pw->shadow_top = get_pixel_resource ("passwd.topShadowColor",
251                                        "Dialog.Foreground",
252                                        si->dpy, cmap);
253   pw->shadow_bottom = get_pixel_resource ("passwd.bottomShadowColor",
254                                           "Dialog.Background",
255                                           si->dpy, cmap);
256
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");
267
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;
273
274   {
275     int direction, ascent, descent;
276     XCharStruct overall;
277
278     pw->width = 0;
279     pw->height = 0;
280
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;
287
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;
294
295     {
296       Dimension w2 = 0, w3 = 0;
297       Dimension h2 = 0, h3 = 0;
298       const char *passwd_string = "MMMMMMMMMMMM";
299
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;
306
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;
313
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;
322
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;
331
332       w2 = w2 + w3 + (pw->shadow_width * 2);
333       h2 = MAX (h2, h3);
334
335       if (w2 > pw->width)  pw->width  = w2;
336       pw->height += h2;
337     }
338
339     pw->width  += (pw->internal_border * 2);
340     pw->height += (pw->internal_border * 4);
341
342     pw->width += pw->thermo_width + (pw->shadow_width * 3);
343
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;
348
349     pw->logo_width = pw->logo_height;
350
351     pw->width += pw->logo_width;
352   }
353
354   attrmask |= CWOverrideRedirect; attrs.override_redirect = True;
355   attrmask |= CWEventMask; attrs.event_mask = ExposureMask|KeyPressMask;
356
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.
360    */
361   {
362     Window pointer_root, pointer_child;
363     int root_x, root_y, win_x, win_y;
364     unsigned int mask;
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))
370       {
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);
377       }
378     else if (si->prefs.verbose_p)
379       fprintf (stderr, "%s: %d: unable to determine mouse position?\n",
380                blurb(), pw->prompt_screen->number);
381   }
382
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
385      well as Xinerama. */
386   {
387     int x, y, w, h;
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;
396   }
397
398   pw->border_width = get_integer_resource ("passwd.borderWidth",
399                                            "Dialog.BorderWidth");
400
401   si->passwd_dialog =
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),
407                    attrmask, &attrs);
408   XSetWindowBackground (si->dpy, si->passwd_dialog, pw->background);
409
410   pw->logo_pixmap = xscreensaver_logo (ssi->screen, ssi->current_visual,
411                                        si->passwd_dialog, cmap,
412                                        pw->background, 
413                                        &pw->logo_pixels, &pw->logo_npixels,
414                                        0, True);
415
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
420      right now! */
421   {
422     XGCValues gcv;
423     GC gc;
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,
432                pw->save_under, gc,
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,
436                0, 0);
437     XFreeGC (si->dpy, gc);
438   }
439
440   XMapRaised (si->dpy, si->passwd_dialog);
441   XSync (si->dpy, False);
442
443   move_mouse_grab (si, si->passwd_dialog,
444                    pw->prompt_screen->cursor,
445                    pw->prompt_screen->number);
446   undo_vp_motion (si);
447
448   si->pw_data = pw;
449
450   if (cmap)
451     XInstallColormap (si->dpy, cmap);
452   draw_passwd_window (si);
453   XSync (si->dpy, False);
454 }
455
456
457 static void
458 draw_passwd_window (saver_info *si)
459 {
460   passwd_dialog_data *pw = si->pw_data;
461   XGCValues gcv;
462   GC gc1, gc2;
463   int spacing, height;
464   int x1, x2, x3, y1, y2;
465   int sw;
466   int tb_height;
467
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
474             );
475   spacing = ((pw->height - (2 * pw->shadow_width) -
476               pw->internal_border - height)) / 8;
477   if (spacing < 0) spacing = 0;
478
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;
485
486   /* top heading
487    */
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));
494
495   /* text below top heading
496    */
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));
503
504
505   tb_height = (pw->passwd_font->ascent + pw->passwd_font->descent +
506                (pw->shadow_width * 4));
507
508   /* the "User:" prompt
509    */
510   y1 += spacing;
511   y2 = y1;
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),
520                y1,
521                pw->user_label, strlen(pw->user_label));
522
523   /* the "Password:" prompt
524    */
525   y1 += (spacing + tb_height);
526   XDrawString (si->dpy, si->passwd_dialog, gc1,
527                x2 - string_width (pw->label_font, pw->passwd_label),
528                y1,
529                pw->passwd_label, strlen(pw->passwd_label));
530
531
532   XSetForeground (si->dpy, gc2, pw->passwd_background);
533
534   /* the "user name" text field
535    */
536   y1 = y2;
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);
541
542   pw->passwd_field_width = x3 - x2 - pw->internal_border;
543   pw->passwd_field_height = (pw->passwd_font->ascent +
544                              pw->passwd_font->descent +
545                              pw->shadow_width);
546
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));
553
554   /* the "password" text field
555    */
556   y1 += (spacing + tb_height);
557
558   pw->passwd_field_x = x2 - pw->shadow_width;
559   pw->passwd_field_y = y1 - (pw->passwd_font->ascent +
560                              pw->passwd_font->descent);
561
562   /* The shadow around the text fields
563    */
564   y1 = y2;
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);
569
570   draw_shaded_rectangle (si->dpy, si->passwd_dialog,
571                          x1, y1, x2, y2,
572                          pw->shadow_width,
573                          pw->shadow_bottom, pw->shadow_top);
574
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,
578                          x1, y1, x2, y2,
579                          pw->shadow_width,
580                          pw->shadow_bottom, pw->shadow_top);
581
582
583   /* The date, below the text fields
584    */
585   {
586     char buf[100];
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);
591
592     XSetFont (si->dpy, gc1, pw->date_font->fid);
593     y1 += pw->shadow_width;
594     y1 += (spacing + tb_height);
595     y1 += spacing/2;
596     sw = string_width (pw->date_font, buf);
597     x2 = x1 + x2 - sw;
598     XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1, buf, strlen(buf));
599   }
600
601
602   /* The logo
603    */
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);
608
609   if (pw->logo_pixmap)
610     {
611       Window root;
612       int x, y;
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);
617       if (d == 1)
618         XCopyPlane (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1,
619                     0, 0, w, h,
620                     x1 + ((x2 - (int)w) / 2),
621                     y1 + ((y2 - (int)h) / 2),
622                     1);
623       else
624         XCopyArea (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1,
625                    0, 0, w, h,
626                    x1 + ((x2 - (int)w) / 2),
627                    y1 + ((y2 - (int)h) / 2));
628     }
629
630   /* The thermometer
631    */
632   XSetForeground (si->dpy, gc1, pw->thermo_foreground);
633   XSetForeground (si->dpy, gc2, pw->thermo_background);
634
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);
638
639 #if 0
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);
643 #endif
644
645   /* The shadow around the logo
646    */
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),
652                          pw->shadow_width,
653                          pw->shadow_bottom, pw->shadow_top);
654
655   /* The shadow around the thermometer
656    */
657   draw_shaded_rectangle (si->dpy, si->passwd_dialog,
658                          pw->logo_width,
659                          pw->shadow_width * 4,
660                          pw->thermo_width + (pw->shadow_width * 2),
661                          pw->height - (pw->shadow_width * 8),
662                          pw->shadow_width,
663                          pw->shadow_bottom, pw->shadow_top);
664
665 #if 1
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);
671 #endif
672
673   /* The shadow around the whole window
674    */
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);
678
679   XFreeGC (si->dpy, gc1);
680   XFreeGC (si->dpy, gc2);
681
682   update_passwd_window (si, pw->passwd_string, pw->ratio);
683 }
684
685
686 static void
687 update_passwd_window (saver_info *si, const char *printed_passwd, float ratio)
688 {
689   passwd_dialog_data *pw = si->pw_data;
690   XGCValues gcv;
691   GC gc1, gc2;
692   int x, y;
693   XRectangle rects[1];
694
695   pw->ratio = ratio;
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);
701
702   if (printed_passwd)
703     {
704       char *s = strdup (printed_passwd);
705       if (pw->passwd_string) free (pw->passwd_string);
706       pw->passwd_string = s;
707     }
708
709   /* the "password" text field
710    */
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;
715
716   XFillRectangle (si->dpy, si->passwd_dialog, gc2,
717                   rects[0].x, rects[0].y, rects[0].width, rects[0].height);
718
719   XSetClipRectangles (si->dpy, gc1, 0, 0, rects, 1, Unsorted);
720
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));
726
727   XSetClipMask (si->dpy, gc1, None);
728
729   /* The I-beam
730    */
731   if (pw->i_beam != 0)
732     {
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;
736
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);
741     }
742
743   pw->i_beam = (pw->i_beam + 1) % 4;
744
745
746   /* the thermometer
747    */
748   y = (pw->thermo_field_height - 2) * (1.0 - pw->ratio);
749   if (y > 0)
750     {
751       XFillRectangle (si->dpy, si->passwd_dialog, gc2,
752                       pw->thermo_field_x + 1,
753                       pw->thermo_field_y + 1,
754                       pw->thermo_width-2,
755                       y);
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,
760                       pw->thermo_width-2,
761                       MAX (0, pw->thermo_field_height - y - 2));
762     }
763
764   XFreeGC (si->dpy, gc1);
765   XFreeGC (si->dpy, gc2);
766   XSync (si->dpy, False);
767 }
768
769
770 static void
771 destroy_passwd_window (saver_info *si)
772 {
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);
779   XEvent event;
780
781   memset (pw->typed_passwd, 0, sizeof(pw->typed_passwd));
782   memset (pw->passwd_string, 0, strlen(pw->passwd_string));
783
784   if (pw->timer)
785     XtRemoveTimeOut (pw->timer);
786
787   move_mouse_grab (si, RootWindowOfScreen (ssi->screen),
788                    ssi->cursor, ssi->number);
789
790   if (p->verbose_p)
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);
794
795   XWarpPointer (si->dpy, None, RootWindowOfScreen (ssi->screen),
796                 0, 0, 0, 0,
797                 pw->previous_mouse_x, pw->previous_mouse_y);
798
799   XSync (si->dpy, False);
800   while (XCheckMaskEvent (si->dpy, PointerMotionMask, &event))
801     if (p->verbose_p)
802       fprintf (stderr, "%s: discarding MotionNotify event.\n", blurb());
803
804   if (si->passwd_dialog)
805     {
806       XDestroyWindow (si->dpy, si->passwd_dialog);
807       si->passwd_dialog = 0;
808     }
809   
810   if (pw->save_under)
811     {
812       XGCValues gcv;
813       GC gc;
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,
818                  0, 0,
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);
823       pw->save_under = 0;
824       XFreeGC (si->dpy, gc);
825     }
826
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);
834
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);
840
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);
857
858   if (pw->logo_pixmap)
859     XFreePixmap (si->dpy, pw->logo_pixmap);
860   if (pw->logo_pixels)
861     {
862       if (pw->logo_npixels)
863         XFreeColors (si->dpy, cmap, pw->logo_pixels, pw->logo_npixels, 0L);
864       free (pw->logo_pixels);
865       pw->logo_pixels = 0;
866       pw->logo_npixels = 0;
867     }
868
869   if (pw->save_under)
870     XFreePixmap (si->dpy, pw->save_under);
871
872   if (cmap)
873     XInstallColormap (si->dpy, cmap);
874
875   memset (pw, 0, sizeof(*pw));
876   free (pw);
877   si->pw_data = 0;
878 }
879
880
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
885    screen is locked.
886  */
887 static void
888 hp_lock_reset (saver_info *si, Bool lock_p)
889 {
890   static Bool hp_locked_p = False;
891
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.)
895   */
896   if (hp_locked_p == lock_p)
897     return;
898
899   if (lock_p)
900     XHPDisableReset (si->dpy);
901   else
902     XHPEnableReset (si->dpy);
903   hp_locked_p = lock_p;
904 }
905 #endif /* HAVE_XHPDISABLERESET */
906
907 \f
908 #ifdef HAVE_XF86MISCSETGRABKEYSSTATE
909
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.
914
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.
918
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.
921  */
922 static void
923 xfree_lock_grab_smasher (saver_info *si, Bool lock_p)
924 {
925   saver_preferences *p = &si->prefs;
926   int status = XF86MiscSetGrabKeysState (si->dpy, !lock_p);
927
928   if (p->verbose_p && status != MiscExtGrabStateSuccess)
929     fprintf (stderr, "%s: error: XF86MiscSetGrabKeysState returned %s\n",
930              blurb(),
931              (status == MiscExtGrabStateSuccess ? "MiscExtGrabStateSuccess" :
932               status == MiscExtGrabStateLocked  ? "MiscExtGrabStateLocked"  :
933               status == MiscExtGrabStateAlready ? "MiscExtGrabStateAlready" :
934               "unknown value"));
935 }
936 #endif /* HAVE_XF86MISCSETGRABKEYSSTATE */
937
938
939
940 \f
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
945    screen is locked.
946
947    Unfortunately, this doesn't work -- this ioctl only works when
948    called by root, and we have disavowed our privileges long ago.
949  */
950 #ifdef HAVE_VT_LOCKSWITCH
951 static void
952 linux_lock_vt_switch (saver_info *si, Bool lock_p)
953 {
954   saver_preferences *p = &si->prefs;
955   static Bool vt_locked_p = False;
956   const char *dev_console = "/dev/console";
957   int fd;
958
959   if (lock_p == vt_locked_p)
960     return;
961
962   if (lock_p && !p->lock_vt_p)
963     return;
964
965   fd = open (dev_console, O_RDWR);
966   if (fd < 0)
967     {
968       char buf [255];
969       sprintf (buf, "%s: couldn't %s VTs: %s", blurb(),
970                (lock_p ? "lock" : "unlock"),
971                dev_console);
972 #if 1 /* #### doesn't work yet, so don't bother complaining */
973       perror (buf);
974 #endif
975       return;
976     }
977
978   if (ioctl (fd, (lock_p ? VT_LOCKSWITCH : VT_UNLOCKSWITCH)) == 0)
979     {
980       vt_locked_p = lock_p;
981
982       if (p->verbose_p)
983         fprintf (stderr, "%s: %s VTs\n", blurb(),
984                  (lock_p ? "locked" : "unlocked"));
985     }
986   else
987     {
988       char buf [255];
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 */
992       perror (buf);
993 #endif
994     }
995
996   close (fd);
997 }
998 #endif /* HAVE_VT_LOCKSWITCH */
999
1000 \f
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
1006    exposed.
1007  */
1008 #ifdef HAVE_XF86VMODE
1009
1010 static int ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error);
1011 static Bool vp_got_error = False;
1012
1013 static void
1014 xfree_lock_mode_switch (saver_info *si, Bool lock_p)
1015 {
1016   static Bool any_mode_locked_p = False;
1017   saver_preferences *p = &si->prefs;
1018   int screen;
1019   int event, error;
1020   Bool status;
1021   XErrorHandler old_handler;
1022
1023   if (any_mode_locked_p == lock_p)
1024     return;
1025   if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1026     return;
1027
1028   for (screen = 0; screen < si->nscreens; screen++)
1029     {
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;
1036
1037       if (status)
1038         any_mode_locked_p = lock_p;
1039
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"));
1049     }
1050 }
1051
1052 static int
1053 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1054 {
1055   vp_got_error = True;
1056   return 0;
1057 }
1058
1059 #endif /* HAVE_XF86VMODE */
1060
1061 \f
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.
1065  */
1066 static void
1067 undo_vp_motion (saver_info *si)
1068 {
1069 #ifdef HAVE_XF86VMODE
1070   saver_preferences *p = &si->prefs;
1071   int screen;
1072   int event, error;
1073
1074   if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1075     return;
1076
1077   for (screen = 0; screen < si->nscreens; screen++)
1078     {
1079       saver_screen_info *ssi = &si->screens[screen];
1080       int x, y;
1081       Bool status;
1082
1083       if (ssi->blank_vp_x == -1 && ssi->blank_vp_y == -1)
1084         break;
1085       if (!XF86VidModeGetViewPort (si->dpy, screen, &x, &y))
1086         return;
1087       if (ssi->blank_vp_x == x && ssi->blank_vp_y == y)
1088         return;
1089     
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.
1095        */
1096       XSync (si->dpy, False);
1097       usleep (250000);  /* 1/4 second */
1098       XSync (si->dpy, False);
1099
1100       status = XF86VidModeSetViewPort (si->dpy, screen,
1101                                        ssi->blank_vp_x, ssi->blank_vp_y);
1102
1103       if (!status)
1104         fprintf (stderr,
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)
1108         fprintf (stderr,
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);
1111     }
1112 #endif /* HAVE_XF86VMODE */
1113 }
1114
1115
1116 \f
1117 /* Interactions
1118  */
1119
1120 static void
1121 passwd_animate_timer (XtPointer closure, XtIntervalId *id)
1122 {
1123   saver_info *si = (saver_info *) closure;
1124   int tick = 166;
1125   passwd_dialog_data *pw = si->pw_data;
1126
1127   if (!pw) return;
1128
1129   pw->ratio -= (1.0 / ((double) si->prefs.passwd_timeout / (double) tick));
1130   if (pw->ratio < 0)
1131     {
1132       pw->ratio = 0;
1133       if (pw->state == pw_read)
1134         pw->state = pw_time;
1135     }
1136
1137   update_passwd_window (si, 0, pw->ratio);
1138
1139   if (pw->state == pw_read)
1140     pw->timer = XtAppAddTimeOut (si->app, tick, passwd_animate_timer,
1141                                  (XtPointer) si);
1142   else
1143     pw->timer = 0;
1144
1145   idle_timer ((XtPointer) si, id);
1146 }
1147
1148
1149 static XComposeStatus *compose_status;
1150
1151 static void
1152 handle_passwd_key (saver_info *si, XKeyEvent *event)
1153 {
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;
1158   char s[2];
1159   char *stars = 0;
1160   int i;
1161   int size = XLookupString (event, s, 1, 0, compose_status);
1162
1163   if (size != 1) return;
1164
1165   s[1] = 0;
1166
1167   switch (*s)
1168     {
1169     case '\010': case '\177':                           /* Backspace */
1170       if (!*typed_passwd)
1171         XBell (si->dpy, 0);
1172       else
1173         typed_passwd [strlen(typed_passwd)-1] = 0;
1174       break;
1175
1176     case '\025': case '\030':                           /* Erase line */
1177       memset (typed_passwd, 0, pw_size);
1178       break;
1179
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;
1185       else
1186         {
1187           update_passwd_window (si, "Checking...", pw->ratio);
1188           XSync (si->dpy, False);
1189           if (passwd_valid_p (typed_passwd, p->verbose_p))
1190             pw->state = pw_ok;
1191           else
1192             pw->state = pw_fail;
1193           update_passwd_window (si, "", pw->ratio);
1194         }
1195       break;
1196
1197     default:
1198       i = strlen (typed_passwd);
1199       if (i >= pw_size-1)
1200         XBell (si->dpy, 0);
1201       else
1202         {
1203           typed_passwd [i] = *s;
1204           typed_passwd [i+1] = 0;
1205         }
1206       break;
1207     }
1208
1209   i = strlen(typed_passwd);
1210   stars = (char *) malloc(i+1);
1211   memset (stars, '*', i);
1212   stars[i] = 0;
1213   update_passwd_window (si, stars, pw->ratio);
1214   free (stars);
1215 }
1216
1217
1218 static void
1219 passwd_event_loop (saver_info *si)
1220 {
1221   saver_preferences *p = &si->prefs;
1222   char *msg = 0;
1223   XEvent event;
1224   passwd_animate_timer ((XtPointer) si, 0);
1225
1226   while (si->pw_data && si->pw_data->state == pw_read)
1227     {
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);
1233       else
1234         XtDispatchEvent (&event);
1235     }
1236
1237   switch (si->pw_data->state)
1238     {
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;
1243     }
1244
1245   if (si->pw_data->state == pw_fail)
1246     si->unlock_failures++;
1247
1248   if (p->verbose_p)
1249     switch (si->pw_data->state)
1250       {
1251       case pw_ok:
1252         fprintf (stderr, "%s: password correct.\n", blurb()); break;
1253       case pw_fail:
1254         fprintf (stderr, "%s: password incorrect!\n", blurb()); break;
1255       case pw_null:
1256       case pw_cancel:
1257         fprintf (stderr, "%s: password entry cancelled.\n", blurb()); break;
1258       case pw_time:
1259         fprintf (stderr, "%s: password entry timed out.\n", blurb()); break;
1260       default: break;
1261       }
1262
1263 #ifdef HAVE_SYSLOG
1264   if (si->pw_data->state == pw_fail)
1265     {
1266       /* If they typed a password (as opposed to just hitting return) and
1267          the password was invalid, log it.
1268       */
1269       struct passwd *pw = getpwuid (getuid ());
1270       char *d = DisplayString (si->dpy);
1271       char *u = (pw->pw_name ? pw->pw_name : "???");
1272       int opt = 0;
1273       int fac = 0;
1274
1275 # ifdef LOG_PID
1276       opt = LOG_PID;
1277 # endif
1278
1279 # if defined(LOG_AUTHPRIV)
1280       fac = LOG_AUTHPRIV;
1281 # elif defined(LOG_AUTH)
1282       fac = LOG_AUTH;
1283 # else
1284       fac = LOG_DAEMON;
1285 # endif
1286
1287       if (!d) d = "";
1288       openlog (progname, opt, fac);
1289       syslog (LOG_NOTICE, "FAILED LOGIN %d ON DISPLAY \"%s\", FOR \"%s\"",
1290               si->unlock_failures, d, u);
1291       closelog ();
1292     }
1293 #endif /* HAVE_SYSLOG */
1294
1295   if (si->pw_data->state == pw_fail)
1296     XBell (si->dpy, False);
1297
1298   if (si->pw_data->state == pw_ok && si->unlock_failures != 0)
1299     {
1300       if (si->unlock_failures == 1)
1301         fprintf (real_stderr,
1302                  "%s: WARNING: 1 failed attempt to unlock the screen.\n",
1303                  blurb());
1304       else
1305         fprintf (real_stderr,
1306                  "%s: WARNING: %d failed attempts to unlock the screen.\n",
1307                  blurb(), si->unlock_failures);
1308       fflush (real_stderr);
1309
1310       si->unlock_failures = 0;
1311     }
1312
1313   if (msg)
1314     {
1315       si->pw_data->i_beam = 0;
1316       update_passwd_window (si, msg, 0.0);
1317       XSync (si->dpy, False);
1318       sleep (1);
1319
1320       /* Swallow all pending KeyPress/KeyRelease events. */
1321       {
1322         XEvent e;
1323         while (XCheckMaskEvent (si->dpy, KeyPressMask|KeyReleaseMask, &e))
1324           ;
1325       }
1326     }
1327 }
1328
1329
1330 static void
1331 handle_typeahead (saver_info *si)
1332 {
1333   passwd_dialog_data *pw = si->pw_data;
1334   int i;
1335   if (!si->unlock_typeahead)
1336     return;
1337
1338   i = strlen (si->unlock_typeahead);
1339   if (i >= sizeof(pw->typed_passwd) - 1)
1340     i = sizeof(pw->typed_passwd) - 1;
1341
1342   memcpy (pw->typed_passwd, si->unlock_typeahead, i);
1343   pw->typed_passwd [i] = 0;
1344
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);
1348
1349   free (si->unlock_typeahead);
1350   si->unlock_typeahead = 0;
1351 }
1352
1353
1354 Bool
1355 unlock_p (saver_info *si)
1356 {
1357   saver_preferences *p = &si->prefs;
1358   Bool status;
1359
1360   raise_window (si, True, True, True);
1361
1362   if (p->verbose_p)
1363     fprintf (stderr, "%s: prompting for password.\n", blurb());
1364
1365   if (si->pw_data || si->passwd_dialog)
1366     destroy_passwd_window (si);
1367
1368   make_passwd_window (si);
1369
1370   compose_status = calloc (1, sizeof (*compose_status));
1371
1372   handle_typeahead (si);
1373   passwd_event_loop (si);
1374
1375   status = (si->pw_data->state == pw_ok);
1376   destroy_passwd_window (si);
1377
1378   free (compose_status);
1379   compose_status = 0;
1380
1381   return status;
1382 }
1383
1384
1385 void
1386 set_locked_p (saver_info *si, Bool locked_p)
1387 {
1388   si->locked_p = locked_p;
1389
1390 #ifdef HAVE_XHPDISABLERESET
1391   hp_lock_reset (si, locked_p);                 /* turn off/on C-Sh-Reset */
1392 #endif
1393 #ifdef HAVE_VT_LOCKSWITCH
1394   linux_lock_vt_switch (si, locked_p);          /* turn off/on C-Alt-F1 */
1395 #endif
1396 #ifdef HAVE_XF86VMODE
1397   xfree_lock_mode_switch (si, locked_p);        /* turn off/on C-Alt-Plus */
1398 #endif
1399 #ifdef HAVE_XF86MISCSETGRABKEYSSTATE
1400   xfree_lock_grab_smasher (si, locked_p);       /* turn off/on C-Alt-KP-*,/ */
1401 #endif
1402
1403   store_saver_status (si);                      /* store locked-p */
1404 }
1405
1406
1407 #else  /*  NO_LOCKING -- whole file */
1408
1409 void
1410 set_locked_p (saver_info *si, Bool locked_p)
1411 {
1412   if (locked_p) abort();
1413 }
1414
1415 #endif /* !NO_LOCKING */