http://www.archive.org/download/tucows_10294_XScreenSaver/xscreensaver-4.10.tar.gz
[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   /* We use the default visual, not ssi->visual, so that the logo pixmap's
411      visual matches that of the si->passwd_dialog window. */
412   pw->logo_pixmap = xscreensaver_logo (ssi->screen,
413                                        /* ssi->current_visual, */
414                                        DefaultVisualOfScreen(screen),
415                                        si->passwd_dialog, cmap,
416                                        pw->background, 
417                                        &pw->logo_pixels, &pw->logo_npixels,
418                                        0, True);
419
420   /* Before mapping the window, save the bits that are underneath the
421      rectangle the window will occlude.  When we lower the window, we
422      restore these bits.  This works, because the running screenhack
423      has already been sent SIGSTOP, so we know nothing else is drawing
424      right now! */
425   {
426     XGCValues gcv;
427     GC gc;
428     pw->save_under = XCreatePixmap (si->dpy,
429                                     pw->prompt_screen->screensaver_window,
430                                     pw->width + (pw->border_width*2) + 1,
431                                     pw->height + (pw->border_width*2) + 1,
432                                     pw->prompt_screen->current_depth);
433     gcv.function = GXcopy;
434     gc = XCreateGC (si->dpy, pw->save_under, GCFunction, &gcv);
435     XCopyArea (si->dpy, pw->prompt_screen->screensaver_window,
436                pw->save_under, gc,
437                pw->x - pw->border_width, pw->y - pw->border_width,
438                pw->width + (pw->border_width*2) + 1,
439                pw->height + (pw->border_width*2) + 1,
440                0, 0);
441     XFreeGC (si->dpy, gc);
442   }
443
444   XMapRaised (si->dpy, si->passwd_dialog);
445   XSync (si->dpy, False);
446
447   move_mouse_grab (si, si->passwd_dialog,
448                    pw->prompt_screen->cursor,
449                    pw->prompt_screen->number);
450   undo_vp_motion (si);
451
452   si->pw_data = pw;
453
454   if (cmap)
455     XInstallColormap (si->dpy, cmap);
456   draw_passwd_window (si);
457   XSync (si->dpy, False);
458 }
459
460
461 static void
462 draw_passwd_window (saver_info *si)
463 {
464   passwd_dialog_data *pw = si->pw_data;
465   XGCValues gcv;
466   GC gc1, gc2;
467   int spacing, height;
468   int x1, x2, x3, y1, y2;
469   int sw;
470   int tb_height;
471
472   height = (pw->heading_font->ascent + pw->heading_font->descent +
473             pw->body_font->ascent + pw->body_font->descent +
474             (2 * MAX ((pw->label_font->ascent + pw->label_font->descent),
475                       (pw->passwd_font->ascent + pw->passwd_font->descent +
476                        (pw->shadow_width * 4)))) +
477             pw->date_font->ascent + pw->date_font->descent
478             );
479   spacing = ((pw->height - (2 * pw->shadow_width) -
480               pw->internal_border - height)) / 8;
481   if (spacing < 0) spacing = 0;
482
483   gcv.foreground = pw->foreground;
484   gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
485   gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
486   x1 = pw->logo_width + pw->thermo_width + (pw->shadow_width * 3);
487   x3 = pw->width - (pw->shadow_width * 2);
488   y1 = (pw->shadow_width * 2) + spacing + spacing;
489
490   /* top heading
491    */
492   XSetFont (si->dpy, gc1, pw->heading_font->fid);
493   sw = string_width (pw->heading_font, pw->heading_label);
494   x2 = (x1 + ((x3 - x1 - sw) / 2));
495   y1 += spacing + pw->heading_font->ascent + pw->heading_font->descent;
496   XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
497                pw->heading_label, strlen(pw->heading_label));
498
499   /* text below top heading
500    */
501   XSetFont (si->dpy, gc1, pw->body_font->fid);
502   y1 += spacing + pw->body_font->ascent + pw->body_font->descent;
503   sw = string_width (pw->body_font, pw->body_label);
504   x2 = (x1 + ((x3 - x1 - sw) / 2));
505   XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
506                pw->body_label, strlen(pw->body_label));
507
508
509   tb_height = (pw->passwd_font->ascent + pw->passwd_font->descent +
510                (pw->shadow_width * 4));
511
512   /* the "User:" prompt
513    */
514   y1 += spacing;
515   y2 = y1;
516   XSetForeground (si->dpy, gc1, pw->foreground);
517   XSetFont (si->dpy, gc1, pw->label_font->fid);
518   y1 += (spacing + tb_height);
519   x2 = (x1 + pw->internal_border +
520         MAX(string_width (pw->label_font, pw->user_label),
521             string_width (pw->label_font, pw->passwd_label)));
522   XDrawString (si->dpy, si->passwd_dialog, gc1,
523                x2 - string_width (pw->label_font, pw->user_label),
524                y1,
525                pw->user_label, strlen(pw->user_label));
526
527   /* the "Password:" prompt
528    */
529   y1 += (spacing + tb_height);
530   XDrawString (si->dpy, si->passwd_dialog, gc1,
531                x2 - string_width (pw->label_font, pw->passwd_label),
532                y1,
533                pw->passwd_label, strlen(pw->passwd_label));
534
535
536   XSetForeground (si->dpy, gc2, pw->passwd_background);
537
538   /* the "user name" text field
539    */
540   y1 = y2;
541   XSetForeground (si->dpy, gc1, pw->passwd_foreground);
542   XSetFont (si->dpy, gc1, pw->passwd_font->fid);
543   y1 += (spacing + tb_height);
544   x2 += (pw->shadow_width * 4);
545
546   pw->passwd_field_width = x3 - x2 - pw->internal_border;
547   pw->passwd_field_height = (pw->passwd_font->ascent +
548                              pw->passwd_font->descent +
549                              pw->shadow_width);
550
551   XFillRectangle (si->dpy, si->passwd_dialog, gc2,
552                   x2 - pw->shadow_width,
553                   y1 - (pw->passwd_font->ascent + pw->passwd_font->descent),
554                   pw->passwd_field_width, pw->passwd_field_height);
555   XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
556                pw->user_string, strlen(pw->user_string));
557
558   /* the "password" text field
559    */
560   y1 += (spacing + tb_height);
561
562   pw->passwd_field_x = x2 - pw->shadow_width;
563   pw->passwd_field_y = y1 - (pw->passwd_font->ascent +
564                              pw->passwd_font->descent);
565
566   /* The shadow around the text fields
567    */
568   y1 = y2;
569   y1 += (spacing + (pw->shadow_width * 3));
570   x1 = x2 - (pw->shadow_width * 2);
571   x2 = pw->passwd_field_width + (pw->shadow_width * 2);
572   y2 = pw->passwd_field_height + (pw->shadow_width * 2);
573
574   draw_shaded_rectangle (si->dpy, si->passwd_dialog,
575                          x1, y1, x2, y2,
576                          pw->shadow_width,
577                          pw->shadow_bottom, pw->shadow_top);
578
579   y1 += (spacing + pw->passwd_font->ascent + pw->passwd_font->descent +
580          (pw->shadow_width * 4));
581   draw_shaded_rectangle (si->dpy, si->passwd_dialog,
582                          x1, y1, x2, y2,
583                          pw->shadow_width,
584                          pw->shadow_bottom, pw->shadow_top);
585
586
587   /* The date, below the text fields
588    */
589   {
590     char buf[100];
591     time_t now = time ((time_t *) 0);
592     struct tm *tm = localtime (&now);
593     memset (buf, 0, sizeof(buf));
594     strftime (buf, sizeof(buf)-1, pw->date_label, tm);
595
596     XSetFont (si->dpy, gc1, pw->date_font->fid);
597     y1 += pw->shadow_width;
598     y1 += (spacing + tb_height);
599     y1 += spacing/2;
600     sw = string_width (pw->date_font, buf);
601     x2 = x1 + x2 - sw;
602     XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1, buf, strlen(buf));
603   }
604
605
606   /* The logo
607    */
608   x1 = pw->shadow_width * 6;
609   y1 = pw->shadow_width * 6;
610   x2 = pw->logo_width - (pw->shadow_width * 12);
611   y2 = pw->logo_height - (pw->shadow_width * 12);
612
613   if (pw->logo_pixmap)
614     {
615       Window root;
616       int x, y;
617       unsigned int w, h, bw, d;
618       XGetGeometry (si->dpy, pw->logo_pixmap, &root, &x, &y, &w, &h, &bw, &d);
619       XSetForeground (si->dpy, gc1, pw->foreground);
620       XSetBackground (si->dpy, gc1, pw->background);
621       if (d == 1)
622         XCopyPlane (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1,
623                     0, 0, w, h,
624                     x1 + ((x2 - (int)w) / 2),
625                     y1 + ((y2 - (int)h) / 2),
626                     1);
627       else
628         XCopyArea (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1,
629                    0, 0, w, h,
630                    x1 + ((x2 - (int)w) / 2),
631                    y1 + ((y2 - (int)h) / 2));
632     }
633
634   /* The thermometer
635    */
636   XSetForeground (si->dpy, gc1, pw->thermo_foreground);
637   XSetForeground (si->dpy, gc2, pw->thermo_background);
638
639   pw->thermo_field_x = pw->logo_width + pw->shadow_width;
640   pw->thermo_field_y = pw->shadow_width * 5;
641   pw->thermo_field_height = pw->height - (pw->shadow_width * 10);
642
643 #if 0
644   /* Solid border inside the logo box. */
645   XSetForeground (si->dpy, gc1, pw->foreground);
646   XDrawRectangle (si->dpy, si->passwd_dialog, gc1, x1, y1, x2-1, y2-1);
647 #endif
648
649   /* The shadow around the logo
650    */
651   draw_shaded_rectangle (si->dpy, si->passwd_dialog,
652                          pw->shadow_width * 4,
653                          pw->shadow_width * 4,
654                          pw->logo_width - (pw->shadow_width * 8),
655                          pw->logo_height - (pw->shadow_width * 8),
656                          pw->shadow_width,
657                          pw->shadow_bottom, pw->shadow_top);
658
659   /* The shadow around the thermometer
660    */
661   draw_shaded_rectangle (si->dpy, si->passwd_dialog,
662                          pw->logo_width,
663                          pw->shadow_width * 4,
664                          pw->thermo_width + (pw->shadow_width * 2),
665                          pw->height - (pw->shadow_width * 8),
666                          pw->shadow_width,
667                          pw->shadow_bottom, pw->shadow_top);
668
669 #if 1
670   /* Solid border inside the thermometer. */
671   XSetForeground (si->dpy, gc1, pw->foreground);
672   XDrawRectangle (si->dpy, si->passwd_dialog, gc1, 
673                   pw->thermo_field_x, pw->thermo_field_y,
674                   pw->thermo_width - 1, pw->thermo_field_height - 1);
675 #endif
676
677   /* The shadow around the whole window
678    */
679   draw_shaded_rectangle (si->dpy, si->passwd_dialog,
680                          0, 0, pw->width, pw->height, pw->shadow_width,
681                          pw->shadow_top, pw->shadow_bottom);
682
683   XFreeGC (si->dpy, gc1);
684   XFreeGC (si->dpy, gc2);
685
686   update_passwd_window (si, pw->passwd_string, pw->ratio);
687 }
688
689
690 static void
691 update_passwd_window (saver_info *si, const char *printed_passwd, float ratio)
692 {
693   passwd_dialog_data *pw = si->pw_data;
694   XGCValues gcv;
695   GC gc1, gc2;
696   int x, y;
697   XRectangle rects[1];
698
699   pw->ratio = ratio;
700   gcv.foreground = pw->passwd_foreground;
701   gcv.font = pw->passwd_font->fid;
702   gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground|GCFont, &gcv);
703   gcv.foreground = pw->passwd_background;
704   gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
705
706   if (printed_passwd)
707     {
708       char *s = strdup (printed_passwd);
709       if (pw->passwd_string) free (pw->passwd_string);
710       pw->passwd_string = s;
711     }
712
713   /* the "password" text field
714    */
715   rects[0].x =  pw->passwd_field_x;
716   rects[0].y =  pw->passwd_field_y;
717   rects[0].width = pw->passwd_field_width;
718   rects[0].height = pw->passwd_field_height;
719
720   XFillRectangle (si->dpy, si->passwd_dialog, gc2,
721                   rects[0].x, rects[0].y, rects[0].width, rects[0].height);
722
723   XSetClipRectangles (si->dpy, gc1, 0, 0, rects, 1, Unsorted);
724
725   XDrawString (si->dpy, si->passwd_dialog, gc1,
726                rects[0].x + pw->shadow_width,
727                rects[0].y + (pw->passwd_font->ascent +
728                              pw->passwd_font->descent),
729                pw->passwd_string, strlen(pw->passwd_string));
730
731   XSetClipMask (si->dpy, gc1, None);
732
733   /* The I-beam
734    */
735   if (pw->i_beam != 0)
736     {
737       x = (rects[0].x + pw->shadow_width +
738            string_width (pw->passwd_font, pw->passwd_string));
739       y = rects[0].y + pw->shadow_width;
740
741       if (x > rects[0].x + rects[0].width - 1)
742         x = rects[0].x + rects[0].width - 1;
743       XDrawLine (si->dpy, si->passwd_dialog, gc1, 
744                  x, y, x, y + pw->passwd_font->ascent);
745     }
746
747   pw->i_beam = (pw->i_beam + 1) % 4;
748
749
750   /* the thermometer
751    */
752   y = (pw->thermo_field_height - 2) * (1.0 - pw->ratio);
753   if (y > 0)
754     {
755       XFillRectangle (si->dpy, si->passwd_dialog, gc2,
756                       pw->thermo_field_x + 1,
757                       pw->thermo_field_y + 1,
758                       pw->thermo_width-2,
759                       y);
760       XSetForeground (si->dpy, gc1, pw->thermo_foreground);
761       XFillRectangle (si->dpy, si->passwd_dialog, gc1,
762                       pw->thermo_field_x + 1,
763                       pw->thermo_field_y + 1 + y,
764                       pw->thermo_width-2,
765                       MAX (0, pw->thermo_field_height - y - 2));
766     }
767
768   XFreeGC (si->dpy, gc1);
769   XFreeGC (si->dpy, gc2);
770   XSync (si->dpy, False);
771 }
772
773
774 static void
775 destroy_passwd_window (saver_info *si)
776 {
777   saver_preferences *p = &si->prefs;
778   passwd_dialog_data *pw = si->pw_data;
779   saver_screen_info *ssi = pw->prompt_screen;
780   Colormap cmap = DefaultColormapOfScreen (ssi->screen);
781   Pixel black = BlackPixelOfScreen (ssi->screen);
782   Pixel white = WhitePixelOfScreen (ssi->screen);
783   XEvent event;
784
785   memset (pw->typed_passwd, 0, sizeof(pw->typed_passwd));
786   memset (pw->passwd_string, 0, strlen(pw->passwd_string));
787
788   if (pw->timer)
789     XtRemoveTimeOut (pw->timer);
790
791   move_mouse_grab (si, RootWindowOfScreen (ssi->screen),
792                    ssi->cursor, ssi->number);
793
794   if (p->verbose_p)
795     fprintf (stderr, "%s: %d: moving mouse back to %d,%d.\n",
796              blurb(), ssi->number,
797              pw->previous_mouse_x, pw->previous_mouse_y);
798
799   XWarpPointer (si->dpy, None, RootWindowOfScreen (ssi->screen),
800                 0, 0, 0, 0,
801                 pw->previous_mouse_x, pw->previous_mouse_y);
802
803   XSync (si->dpy, False);
804   while (XCheckMaskEvent (si->dpy, PointerMotionMask, &event))
805     if (p->verbose_p)
806       fprintf (stderr, "%s: discarding MotionNotify event.\n", blurb());
807
808   if (si->passwd_dialog)
809     {
810       XDestroyWindow (si->dpy, si->passwd_dialog);
811       si->passwd_dialog = 0;
812     }
813   
814   if (pw->save_under)
815     {
816       XGCValues gcv;
817       GC gc;
818       gcv.function = GXcopy;
819       gc = XCreateGC (si->dpy, ssi->screensaver_window, GCFunction, &gcv);
820       XCopyArea (si->dpy, pw->save_under,
821                  ssi->screensaver_window, gc,
822                  0, 0,
823                  pw->width + (pw->border_width*2) + 1,
824                  pw->height + (pw->border_width*2) + 1,
825                  pw->x - pw->border_width, pw->y - pw->border_width);
826       XFreePixmap (si->dpy, pw->save_under);
827       pw->save_under = 0;
828       XFreeGC (si->dpy, gc);
829     }
830
831   if (pw->heading_label) free (pw->heading_label);
832   if (pw->body_label)    free (pw->body_label);
833   if (pw->user_label)    free (pw->user_label);
834   if (pw->passwd_label)  free (pw->passwd_label);
835   if (pw->date_label)    free (pw->date_label);
836   if (pw->user_string)   free (pw->user_string);
837   if (pw->passwd_string) free (pw->passwd_string);
838
839   if (pw->heading_font) XFreeFont (si->dpy, pw->heading_font);
840   if (pw->body_font)    XFreeFont (si->dpy, pw->body_font);
841   if (pw->label_font)   XFreeFont (si->dpy, pw->label_font);
842   if (pw->passwd_font)  XFreeFont (si->dpy, pw->passwd_font);
843   if (pw->date_font)    XFreeFont (si->dpy, pw->date_font);
844
845   if (pw->foreground != black && pw->foreground != white)
846     XFreeColors (si->dpy, cmap, &pw->foreground, 1, 0L);
847   if (pw->background != black && pw->background != white)
848     XFreeColors (si->dpy, cmap, &pw->background, 1, 0L);
849   if (pw->passwd_foreground != black && pw->passwd_foreground != white)
850     XFreeColors (si->dpy, cmap, &pw->passwd_foreground, 1, 0L);
851   if (pw->passwd_background != black && pw->passwd_background != white)
852     XFreeColors (si->dpy, cmap, &pw->passwd_background, 1, 0L);
853   if (pw->thermo_foreground != black && pw->thermo_foreground != white)
854     XFreeColors (si->dpy, cmap, &pw->thermo_foreground, 1, 0L);
855   if (pw->thermo_background != black && pw->thermo_background != white)
856     XFreeColors (si->dpy, cmap, &pw->thermo_background, 1, 0L);
857   if (pw->shadow_top != black && pw->shadow_top != white)
858     XFreeColors (si->dpy, cmap, &pw->shadow_top, 1, 0L);
859   if (pw->shadow_bottom != black && pw->shadow_bottom != white)
860     XFreeColors (si->dpy, cmap, &pw->shadow_bottom, 1, 0L);
861
862   if (pw->logo_pixmap)
863     XFreePixmap (si->dpy, pw->logo_pixmap);
864   if (pw->logo_pixels)
865     {
866       if (pw->logo_npixels)
867         XFreeColors (si->dpy, cmap, pw->logo_pixels, pw->logo_npixels, 0L);
868       free (pw->logo_pixels);
869       pw->logo_pixels = 0;
870       pw->logo_npixels = 0;
871     }
872
873   if (pw->save_under)
874     XFreePixmap (si->dpy, pw->save_under);
875
876   if (cmap)
877     XInstallColormap (si->dpy, cmap);
878
879   memset (pw, 0, sizeof(*pw));
880   free (pw);
881   si->pw_data = 0;
882 }
883
884
885 #ifdef HAVE_XHPDISABLERESET
886 /* This function enables and disables the C-Sh-Reset hot-key, which
887    normally resets the X server (logging out the logged-in user.)
888    We don't want random people to be able to do that while the
889    screen is locked.
890  */
891 static void
892 hp_lock_reset (saver_info *si, Bool lock_p)
893 {
894   static Bool hp_locked_p = False;
895
896   /* Calls to XHPDisableReset and XHPEnableReset must be balanced,
897      or BadAccess errors occur.  (It's ok for this to be global,
898      since it affects the whole machine, not just the current screen.)
899   */
900   if (hp_locked_p == lock_p)
901     return;
902
903   if (lock_p)
904     XHPDisableReset (si->dpy);
905   else
906     XHPEnableReset (si->dpy);
907   hp_locked_p = lock_p;
908 }
909 #endif /* HAVE_XHPDISABLERESET */
910
911 \f
912 #ifdef HAVE_XF86MISCSETGRABKEYSSTATE
913
914 /* This function enables and disables the Ctrl-Alt-KP_star and 
915    Ctrl-Alt-KP_slash hot-keys, which (in XFree86 4.2) break any
916    grabs and/or kill the grabbing client.  That would effectively
917    unlock the screen, so we don't like that.
918
919    The Ctrl-Alt-KP_star and Ctrl-Alt-KP_slash hot-keys only exist
920    if AllowDeactivateGrabs and/or AllowClosedownGrabs are turned on
921    in XF86Config.  I believe they are disabled by default.
922
923    This does not affect any other keys (specifically Ctrl-Alt-BS or
924    Ctrl-Alt-F1) but I wish it did.  Maybe it will someday.
925  */
926 static void
927 xfree_lock_grab_smasher (saver_info *si, Bool lock_p)
928 {
929   saver_preferences *p = &si->prefs;
930   int status = XF86MiscSetGrabKeysState (si->dpy, !lock_p);
931
932   if (p->verbose_p && status != MiscExtGrabStateSuccess)
933     fprintf (stderr, "%s: error: XF86MiscSetGrabKeysState returned %s\n",
934              blurb(),
935              (status == MiscExtGrabStateSuccess ? "MiscExtGrabStateSuccess" :
936               status == MiscExtGrabStateLocked  ? "MiscExtGrabStateLocked"  :
937               status == MiscExtGrabStateAlready ? "MiscExtGrabStateAlready" :
938               "unknown value"));
939 }
940 #endif /* HAVE_XF86MISCSETGRABKEYSSTATE */
941
942
943
944 \f
945 /* This function enables and disables the C-Sh-F1 ... F12 hot-keys,
946    which, on Linux systems, switches to another virtual console.
947    We'd like the whole screen/keyboard to be locked, not just one
948    virtual console, so this function disables that while the X
949    screen is locked.
950
951    Unfortunately, this doesn't work -- this ioctl only works when
952    called by root, and we have disavowed our privileges long ago.
953  */
954 #ifdef HAVE_VT_LOCKSWITCH
955 static void
956 linux_lock_vt_switch (saver_info *si, Bool lock_p)
957 {
958   saver_preferences *p = &si->prefs;
959   static Bool vt_locked_p = False;
960   const char *dev_console = "/dev/console";
961   int fd;
962
963   if (lock_p == vt_locked_p)
964     return;
965
966   if (lock_p && !p->lock_vt_p)
967     return;
968
969   fd = open (dev_console, O_RDWR);
970   if (fd < 0)
971     {
972       char buf [255];
973       sprintf (buf, "%s: couldn't %s VTs: %s", blurb(),
974                (lock_p ? "lock" : "unlock"),
975                dev_console);
976 #if 1 /* #### doesn't work yet, so don't bother complaining */
977       perror (buf);
978 #endif
979       return;
980     }
981
982   if (ioctl (fd, (lock_p ? VT_LOCKSWITCH : VT_UNLOCKSWITCH)) == 0)
983     {
984       vt_locked_p = lock_p;
985
986       if (p->verbose_p)
987         fprintf (stderr, "%s: %s VTs\n", blurb(),
988                  (lock_p ? "locked" : "unlocked"));
989     }
990   else
991     {
992       char buf [255];
993       sprintf (buf, "%s: couldn't %s VTs: ioctl", blurb(),
994                (lock_p ? "lock" : "unlock"));
995 #if 0 /* #### doesn't work yet, so don't bother complaining */
996       perror (buf);
997 #endif
998     }
999
1000   close (fd);
1001 }
1002 #endif /* HAVE_VT_LOCKSWITCH */
1003
1004 \f
1005 /* This function enables and disables the C-Alt-Plus and C-Alt-Minus
1006    hot-keys, which normally change the resolution of the X server.
1007    We don't want people to be able to switch the server resolution
1008    while the screen is locked, because if they switch to a higher
1009    resolution, it could cause part of the underlying desktop to become
1010    exposed.
1011  */
1012 #ifdef HAVE_XF86VMODE
1013
1014 static int ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error);
1015 static Bool vp_got_error = False;
1016
1017 static void
1018 xfree_lock_mode_switch (saver_info *si, Bool lock_p)
1019 {
1020   static Bool any_mode_locked_p = False;
1021   saver_preferences *p = &si->prefs;
1022   int screen;
1023   int event, error;
1024   Bool status;
1025   XErrorHandler old_handler;
1026
1027   if (any_mode_locked_p == lock_p)
1028     return;
1029   if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1030     return;
1031
1032   for (screen = 0; screen < si->nscreens; screen++)
1033     {
1034       XSync (si->dpy, False);
1035       old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1036       status = XF86VidModeLockModeSwitch (si->dpy, screen, lock_p);
1037       XSync (si->dpy, False);
1038       XSetErrorHandler (old_handler);
1039       if (vp_got_error) status = False;
1040
1041       if (status)
1042         any_mode_locked_p = lock_p;
1043
1044       if (!status && (p->verbose_p || !lock_p))
1045         /* Only print this when verbose, or when we locked but can't unlock.
1046            I tried printing this message whenever it comes up, but
1047            mode-locking always fails if DontZoom is set in XF86Config. */
1048         fprintf (stderr, "%s: %d: unable to %s mode switching!\n",
1049                  blurb(), screen, (lock_p ? "lock" : "unlock"));
1050       else if (p->verbose_p)
1051         fprintf (stderr, "%s: %d: %s mode switching.\n",
1052                  blurb(), screen, (lock_p ? "locked" : "unlocked"));
1053     }
1054 }
1055
1056 static int
1057 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1058 {
1059   vp_got_error = True;
1060   return 0;
1061 }
1062
1063 #endif /* HAVE_XF86VMODE */
1064
1065 \f
1066 /* If the viewport has been scrolled since the screen was blanked,
1067    then scroll it back to where it belongs.  This function only exists
1068    to patch over a very brief race condition.
1069  */
1070 static void
1071 undo_vp_motion (saver_info *si)
1072 {
1073 #ifdef HAVE_XF86VMODE
1074   saver_preferences *p = &si->prefs;
1075   int screen;
1076   int event, error;
1077
1078   if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1079     return;
1080
1081   for (screen = 0; screen < si->nscreens; screen++)
1082     {
1083       saver_screen_info *ssi = &si->screens[screen];
1084       int x, y;
1085       Bool status;
1086
1087       if (ssi->blank_vp_x == -1 && ssi->blank_vp_y == -1)
1088         break;
1089       if (!XF86VidModeGetViewPort (si->dpy, screen, &x, &y))
1090         return;
1091       if (ssi->blank_vp_x == x && ssi->blank_vp_y == y)
1092         return;
1093     
1094       /* We're going to move the viewport.  The mouse has just been grabbed on
1095          (and constrained to, thus warped to) the password window, so it is no
1096          longer near the edge of the screen.  However, wait a bit anyway, just
1097          to make sure the server drains its last motion event, so that the
1098          screen doesn't continue to scroll after we've reset the viewport.
1099        */
1100       XSync (si->dpy, False);
1101       usleep (250000);  /* 1/4 second */
1102       XSync (si->dpy, False);
1103
1104       status = XF86VidModeSetViewPort (si->dpy, screen,
1105                                        ssi->blank_vp_x, ssi->blank_vp_y);
1106
1107       if (!status)
1108         fprintf (stderr,
1109                  "%s: %d: unable to move vp from (%d,%d) back to (%d,%d)!\n",
1110                  blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1111       else if (p->verbose_p)
1112         fprintf (stderr,
1113                  "%s: %d: vp moved to (%d,%d); moved it back to (%d,%d).\n",
1114                  blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1115     }
1116 #endif /* HAVE_XF86VMODE */
1117 }
1118
1119
1120 \f
1121 /* Interactions
1122  */
1123
1124 static void
1125 passwd_animate_timer (XtPointer closure, XtIntervalId *id)
1126 {
1127   saver_info *si = (saver_info *) closure;
1128   int tick = 166;
1129   passwd_dialog_data *pw = si->pw_data;
1130
1131   if (!pw) return;
1132
1133   pw->ratio -= (1.0 / ((double) si->prefs.passwd_timeout / (double) tick));
1134   if (pw->ratio < 0)
1135     {
1136       pw->ratio = 0;
1137       if (pw->state == pw_read)
1138         pw->state = pw_time;
1139     }
1140
1141   update_passwd_window (si, 0, pw->ratio);
1142
1143   if (pw->state == pw_read)
1144     pw->timer = XtAppAddTimeOut (si->app, tick, passwd_animate_timer,
1145                                  (XtPointer) si);
1146   else
1147     pw->timer = 0;
1148
1149   idle_timer ((XtPointer) si, id);
1150 }
1151
1152
1153 static XComposeStatus *compose_status;
1154
1155 static void
1156 handle_passwd_key (saver_info *si, XKeyEvent *event)
1157 {
1158   saver_preferences *p = &si->prefs;
1159   passwd_dialog_data *pw = si->pw_data;
1160   int pw_size = sizeof (pw->typed_passwd) - 1;
1161   char *typed_passwd = pw->typed_passwd;
1162   char s[2];
1163   char *stars = 0;
1164   int i;
1165   int size = XLookupString (event, s, 1, 0, compose_status);
1166
1167   if (size != 1) return;
1168
1169   s[1] = 0;
1170
1171   switch (*s)
1172     {
1173     case '\010': case '\177':                           /* Backspace */
1174       if (!*typed_passwd)
1175         XBell (si->dpy, 0);
1176       else
1177         typed_passwd [strlen(typed_passwd)-1] = 0;
1178       break;
1179
1180     case '\025': case '\030':                           /* Erase line */
1181       memset (typed_passwd, 0, pw_size);
1182       break;
1183
1184     case '\012': case '\015':                           /* Enter */
1185       if (pw->state != pw_read)
1186         ;  /* already done? */
1187       else if (typed_passwd[0] == 0)
1188         pw->state = pw_null;
1189       else
1190         {
1191           update_passwd_window (si, "Checking...", pw->ratio);
1192           XSync (si->dpy, False);
1193           if (passwd_valid_p (typed_passwd, p->verbose_p))
1194             pw->state = pw_ok;
1195           else
1196             pw->state = pw_fail;
1197           update_passwd_window (si, "", pw->ratio);
1198         }
1199       break;
1200
1201     default:
1202       i = strlen (typed_passwd);
1203       if (i >= pw_size-1)
1204         XBell (si->dpy, 0);
1205       else
1206         {
1207           typed_passwd [i] = *s;
1208           typed_passwd [i+1] = 0;
1209         }
1210       break;
1211     }
1212
1213   i = strlen(typed_passwd);
1214   stars = (char *) malloc(i+1);
1215   memset (stars, '*', i);
1216   stars[i] = 0;
1217   update_passwd_window (si, stars, pw->ratio);
1218   free (stars);
1219 }
1220
1221
1222 static void
1223 passwd_event_loop (saver_info *si)
1224 {
1225   saver_preferences *p = &si->prefs;
1226   char *msg = 0;
1227   XEvent event;
1228   passwd_animate_timer ((XtPointer) si, 0);
1229
1230   while (si->pw_data && si->pw_data->state == pw_read)
1231     {
1232       XtAppNextEvent (si->app, &event);
1233       if (event.xany.window == si->passwd_dialog && event.xany.type == Expose)
1234         draw_passwd_window (si);
1235       else if (event.xany.type == KeyPress)
1236         handle_passwd_key (si, &event.xkey);
1237       else
1238         XtDispatchEvent (&event);
1239     }
1240
1241   switch (si->pw_data->state)
1242     {
1243     case pw_ok:   msg = 0; break;
1244     case pw_null: msg = ""; break;
1245     case pw_time: msg = "Timed out!"; break;
1246     default:      msg = "Sorry!"; break;
1247     }
1248
1249   if (si->pw_data->state == pw_fail)
1250     si->unlock_failures++;
1251
1252   if (p->verbose_p)
1253     switch (si->pw_data->state)
1254       {
1255       case pw_ok:
1256         fprintf (stderr, "%s: password correct.\n", blurb()); break;
1257       case pw_fail:
1258         fprintf (stderr, "%s: password incorrect!\n", blurb()); break;
1259       case pw_null:
1260       case pw_cancel:
1261         fprintf (stderr, "%s: password entry cancelled.\n", blurb()); break;
1262       case pw_time:
1263         fprintf (stderr, "%s: password entry timed out.\n", blurb()); break;
1264       default: break;
1265       }
1266
1267 #ifdef HAVE_SYSLOG
1268   if (si->pw_data->state == pw_fail)
1269     {
1270       /* If they typed a password (as opposed to just hitting return) and
1271          the password was invalid, log it.
1272       */
1273       struct passwd *pw = getpwuid (getuid ());
1274       char *d = DisplayString (si->dpy);
1275       char *u = (pw->pw_name ? pw->pw_name : "???");
1276       int opt = 0;
1277       int fac = 0;
1278
1279 # ifdef LOG_PID
1280       opt = LOG_PID;
1281 # endif
1282
1283 # if defined(LOG_AUTHPRIV)
1284       fac = LOG_AUTHPRIV;
1285 # elif defined(LOG_AUTH)
1286       fac = LOG_AUTH;
1287 # else
1288       fac = LOG_DAEMON;
1289 # endif
1290
1291       if (!d) d = "";
1292       openlog (progname, opt, fac);
1293       syslog (LOG_NOTICE, "FAILED LOGIN %d ON DISPLAY \"%s\", FOR \"%s\"",
1294               si->unlock_failures, d, u);
1295       closelog ();
1296     }
1297 #endif /* HAVE_SYSLOG */
1298
1299   if (si->pw_data->state == pw_fail)
1300     XBell (si->dpy, False);
1301
1302   if (si->pw_data->state == pw_ok && si->unlock_failures != 0)
1303     {
1304       if (si->unlock_failures == 1)
1305         fprintf (real_stderr,
1306                  "%s: WARNING: 1 failed attempt to unlock the screen.\n",
1307                  blurb());
1308       else
1309         fprintf (real_stderr,
1310                  "%s: WARNING: %d failed attempts to unlock the screen.\n",
1311                  blurb(), si->unlock_failures);
1312       fflush (real_stderr);
1313
1314       si->unlock_failures = 0;
1315     }
1316
1317   if (msg)
1318     {
1319       si->pw_data->i_beam = 0;
1320       update_passwd_window (si, msg, 0.0);
1321       XSync (si->dpy, False);
1322       sleep (1);
1323
1324       /* Swallow all pending KeyPress/KeyRelease events. */
1325       {
1326         XEvent e;
1327         while (XCheckMaskEvent (si->dpy, KeyPressMask|KeyReleaseMask, &e))
1328           ;
1329       }
1330     }
1331 }
1332
1333
1334 static void
1335 handle_typeahead (saver_info *si)
1336 {
1337   passwd_dialog_data *pw = si->pw_data;
1338   int i;
1339   if (!si->unlock_typeahead)
1340     return;
1341
1342   i = strlen (si->unlock_typeahead);
1343   if (i >= sizeof(pw->typed_passwd) - 1)
1344     i = sizeof(pw->typed_passwd) - 1;
1345
1346   memcpy (pw->typed_passwd, si->unlock_typeahead, i);
1347   pw->typed_passwd [i] = 0;
1348
1349   memset (si->unlock_typeahead, '*', strlen(si->unlock_typeahead));
1350   si->unlock_typeahead[i] = 0;
1351   update_passwd_window (si, si->unlock_typeahead, pw->ratio);
1352
1353   free (si->unlock_typeahead);
1354   si->unlock_typeahead = 0;
1355 }
1356
1357
1358 Bool
1359 unlock_p (saver_info *si)
1360 {
1361   saver_preferences *p = &si->prefs;
1362   Bool status;
1363
1364   raise_window (si, True, True, True);
1365
1366   if (p->verbose_p)
1367     fprintf (stderr, "%s: prompting for password.\n", blurb());
1368
1369   if (si->pw_data || si->passwd_dialog)
1370     destroy_passwd_window (si);
1371
1372   make_passwd_window (si);
1373
1374   compose_status = calloc (1, sizeof (*compose_status));
1375
1376   handle_typeahead (si);
1377   passwd_event_loop (si);
1378
1379   status = (si->pw_data->state == pw_ok);
1380   destroy_passwd_window (si);
1381
1382   free (compose_status);
1383   compose_status = 0;
1384
1385   return status;
1386 }
1387
1388
1389 void
1390 set_locked_p (saver_info *si, Bool locked_p)
1391 {
1392   si->locked_p = locked_p;
1393
1394 #ifdef HAVE_XHPDISABLERESET
1395   hp_lock_reset (si, locked_p);                 /* turn off/on C-Sh-Reset */
1396 #endif
1397 #ifdef HAVE_VT_LOCKSWITCH
1398   linux_lock_vt_switch (si, locked_p);          /* turn off/on C-Alt-F1 */
1399 #endif
1400 #ifdef HAVE_XF86VMODE
1401   xfree_lock_mode_switch (si, locked_p);        /* turn off/on C-Alt-Plus */
1402 #endif
1403 #ifdef HAVE_XF86MISCSETGRABKEYSSTATE
1404   xfree_lock_grab_smasher (si, locked_p);       /* turn off/on C-Alt-KP-*,/ */
1405 #endif
1406
1407   store_saver_status (si);                      /* store locked-p */
1408 }
1409
1410
1411 #else  /*  NO_LOCKING -- whole file */
1412
1413 void
1414 set_locked_p (saver_info *si, Bool locked_p)
1415 {
1416   if (locked_p) abort();
1417 }
1418
1419 #endif /* !NO_LOCKING */