ftp://ftp.linux.ncsu.edu/mirror/ftp.redhat.com/pub/redhat/linux/enterprise/4/en/os...
[xscreensaver] / driver / lock.c
1 /* lock.c --- handling the password dialog for locking-mode.
2  * xscreensaver, Copyright (c) 1993-2004 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 static Bool error_handler_hit_p = False;
886
887 static int
888 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
889 {
890   error_handler_hit_p = True;
891   return 0;
892 }
893
894
895 #ifdef HAVE_XHPDISABLERESET
896 /* This function enables and disables the C-Sh-Reset hot-key, which
897    normally resets the X server (logging out the logged-in user.)
898    We don't want random people to be able to do that while the
899    screen is locked.
900  */
901 static void
902 hp_lock_reset (saver_info *si, Bool lock_p)
903 {
904   static Bool hp_locked_p = False;
905
906   /* Calls to XHPDisableReset and XHPEnableReset must be balanced,
907      or BadAccess errors occur.  (It's ok for this to be global,
908      since it affects the whole machine, not just the current screen.)
909   */
910   if (hp_locked_p == lock_p)
911     return;
912
913   if (lock_p)
914     XHPDisableReset (si->dpy);
915   else
916     XHPEnableReset (si->dpy);
917   hp_locked_p = lock_p;
918 }
919 #endif /* HAVE_XHPDISABLERESET */
920
921 \f
922 #ifdef HAVE_XF86MISCSETGRABKEYSSTATE
923
924 /* This function enables and disables the Ctrl-Alt-KP_star and 
925    Ctrl-Alt-KP_slash hot-keys, which (in XFree86 4.2) break any
926    grabs and/or kill the grabbing client.  That would effectively
927    unlock the screen, so we don't like that.
928
929    The Ctrl-Alt-KP_star and Ctrl-Alt-KP_slash hot-keys only exist
930    if AllowDeactivateGrabs and/or AllowClosedownGrabs are turned on
931    in XF86Config.  I believe they are disabled by default.
932
933    This does not affect any other keys (specifically Ctrl-Alt-BS or
934    Ctrl-Alt-F1) but I wish it did.  Maybe it will someday.
935  */
936 static void
937 xfree_lock_grab_smasher (saver_info *si, Bool lock_p)
938 {
939   saver_preferences *p = &si->prefs;
940   int status;
941
942   XErrorHandler old_handler;
943   XSync (si->dpy, False);
944   error_handler_hit_p = False;
945   old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
946   XSync (si->dpy, False);
947   status = XF86MiscSetGrabKeysState (si->dpy, !lock_p);
948   XSync (si->dpy, False);
949   if (error_handler_hit_p) status = 666;
950
951   if (!lock_p && status == MiscExtGrabStateAlready)
952     status = MiscExtGrabStateSuccess;  /* shut up, consider this success */
953
954   if (p->verbose_p && status != MiscExtGrabStateSuccess)
955     fprintf (stderr, "%s: error: XF86MiscSetGrabKeysState(%d) returned %s\n",
956              blurb(), !lock_p,
957              (status == MiscExtGrabStateSuccess ? "MiscExtGrabStateSuccess" :
958               status == MiscExtGrabStateLocked  ? "MiscExtGrabStateLocked"  :
959               status == MiscExtGrabStateAlready ? "MiscExtGrabStateAlready" :
960               status == 666 ? "an X error" :
961               "unknown value"));
962
963   XSync (si->dpy, False);
964   XSetErrorHandler (old_handler);
965   XSync (si->dpy, False);
966 }
967 #endif /* HAVE_XF86MISCSETGRABKEYSSTATE */
968
969
970
971 \f
972 /* This function enables and disables the C-Sh-F1 ... F12 hot-keys,
973    which, on Linux systems, switches to another virtual console.
974    We'd like the whole screen/keyboard to be locked, not just one
975    virtual console, so this function disables that while the X
976    screen is locked.
977
978    Unfortunately, this doesn't work -- this ioctl only works when
979    called by root, and we have disavowed our privileges long ago.
980  */
981 #ifdef HAVE_VT_LOCKSWITCH
982 static void
983 linux_lock_vt_switch (saver_info *si, Bool lock_p)
984 {
985   saver_preferences *p = &si->prefs;
986   static Bool vt_locked_p = False;
987   const char *dev_console = "/dev/console";
988   int fd;
989
990   if (lock_p == vt_locked_p)
991     return;
992
993   if (lock_p && !p->lock_vt_p)
994     return;
995
996   fd = open (dev_console, O_RDWR);
997   if (fd < 0)
998     {
999       char buf [255];
1000       sprintf (buf, "%s: couldn't %s VTs: %s", blurb(),
1001                (lock_p ? "lock" : "unlock"),
1002                dev_console);
1003 #if 1 /* #### doesn't work yet, so don't bother complaining */
1004       perror (buf);
1005 #endif
1006       return;
1007     }
1008
1009   if (ioctl (fd, (lock_p ? VT_LOCKSWITCH : VT_UNLOCKSWITCH)) == 0)
1010     {
1011       vt_locked_p = lock_p;
1012
1013       if (p->verbose_p)
1014         fprintf (stderr, "%s: %s VTs\n", blurb(),
1015                  (lock_p ? "locked" : "unlocked"));
1016     }
1017   else
1018     {
1019       char buf [255];
1020       sprintf (buf, "%s: couldn't %s VTs: ioctl", blurb(),
1021                (lock_p ? "lock" : "unlock"));
1022 #if 0 /* #### doesn't work yet, so don't bother complaining */
1023       perror (buf);
1024 #endif
1025     }
1026
1027   close (fd);
1028 }
1029 #endif /* HAVE_VT_LOCKSWITCH */
1030
1031 \f
1032 /* This function enables and disables the C-Alt-Plus and C-Alt-Minus
1033    hot-keys, which normally change the resolution of the X server.
1034    We don't want people to be able to switch the server resolution
1035    while the screen is locked, because if they switch to a higher
1036    resolution, it could cause part of the underlying desktop to become
1037    exposed.
1038  */
1039 #ifdef HAVE_XF86VMODE
1040
1041 static void
1042 xfree_lock_mode_switch (saver_info *si, Bool lock_p)
1043 {
1044   static Bool any_mode_locked_p = False;
1045   saver_preferences *p = &si->prefs;
1046   int screen;
1047   int event, error;
1048   Bool status;
1049   XErrorHandler old_handler;
1050
1051   if (any_mode_locked_p == lock_p)
1052     return;
1053   if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1054     return;
1055
1056   for (screen = 0; screen < (si->xinerama_p ? 1 : si->nscreens); screen++)
1057     {
1058       XSync (si->dpy, False);
1059       old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1060       error_handler_hit_p = False;
1061       status = XF86VidModeLockModeSwitch (si->dpy, screen, lock_p);
1062       XSync (si->dpy, False);
1063       XSetErrorHandler (old_handler);
1064       if (error_handler_hit_p) status = False;
1065
1066       if (status)
1067         any_mode_locked_p = lock_p;
1068
1069       if (!status && (p->verbose_p || !lock_p))
1070         /* Only print this when verbose, or when we locked but can't unlock.
1071            I tried printing this message whenever it comes up, but
1072            mode-locking always fails if DontZoom is set in XF86Config. */
1073         fprintf (stderr, "%s: %d: unable to %s mode switching!\n",
1074                  blurb(), screen, (lock_p ? "lock" : "unlock"));
1075       else if (p->verbose_p)
1076         fprintf (stderr, "%s: %d: %s mode switching.\n",
1077                  blurb(), screen, (lock_p ? "locked" : "unlocked"));
1078     }
1079 }
1080 #endif /* HAVE_XF86VMODE */
1081
1082 \f
1083 /* If the viewport has been scrolled since the screen was blanked,
1084    then scroll it back to where it belongs.  This function only exists
1085    to patch over a very brief race condition.
1086  */
1087 static void
1088 undo_vp_motion (saver_info *si)
1089 {
1090 #ifdef HAVE_XF86VMODE
1091   saver_preferences *p = &si->prefs;
1092   int screen;
1093   int event, error;
1094
1095   if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1096     return;
1097
1098   for (screen = 0; screen < si->nscreens; screen++)
1099     {
1100       saver_screen_info *ssi = &si->screens[screen];
1101       int x, y;
1102       Bool status;
1103
1104       if (ssi->blank_vp_x == -1 && ssi->blank_vp_y == -1)
1105         break;
1106       if (!XF86VidModeGetViewPort (si->dpy, screen, &x, &y))
1107         return;
1108       if (ssi->blank_vp_x == x && ssi->blank_vp_y == y)
1109         return;
1110     
1111       /* We're going to move the viewport.  The mouse has just been grabbed on
1112          (and constrained to, thus warped to) the password window, so it is no
1113          longer near the edge of the screen.  However, wait a bit anyway, just
1114          to make sure the server drains its last motion event, so that the
1115          screen doesn't continue to scroll after we've reset the viewport.
1116        */
1117       XSync (si->dpy, False);
1118       usleep (250000);  /* 1/4 second */
1119       XSync (si->dpy, False);
1120
1121       status = XF86VidModeSetViewPort (si->dpy, screen,
1122                                        ssi->blank_vp_x, ssi->blank_vp_y);
1123
1124       if (!status)
1125         fprintf (stderr,
1126                  "%s: %d: unable to move vp from (%d,%d) back to (%d,%d)!\n",
1127                  blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1128       else if (p->verbose_p)
1129         fprintf (stderr,
1130                  "%s: %d: vp moved to (%d,%d); moved it back to (%d,%d).\n",
1131                  blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1132     }
1133 #endif /* HAVE_XF86VMODE */
1134 }
1135
1136
1137 \f
1138 /* Interactions
1139  */
1140
1141 static void
1142 passwd_animate_timer (XtPointer closure, XtIntervalId *id)
1143 {
1144   saver_info *si = (saver_info *) closure;
1145   int tick = 166;
1146   passwd_dialog_data *pw = si->pw_data;
1147
1148   if (!pw) return;
1149
1150   pw->ratio -= (1.0 / ((double) si->prefs.passwd_timeout / (double) tick));
1151   if (pw->ratio < 0)
1152     {
1153       pw->ratio = 0;
1154       if (pw->state == pw_read)
1155         pw->state = pw_time;
1156     }
1157
1158   update_passwd_window (si, 0, pw->ratio);
1159
1160   if (pw->state == pw_read)
1161     pw->timer = XtAppAddTimeOut (si->app, tick, passwd_animate_timer,
1162                                  (XtPointer) si);
1163   else
1164     pw->timer = 0;
1165
1166   idle_timer ((XtPointer) si, 0);
1167 }
1168
1169
1170 static XComposeStatus *compose_status;
1171
1172 static void
1173 handle_passwd_key (saver_info *si, XKeyEvent *event)
1174 {
1175   saver_preferences *p = &si->prefs;
1176   passwd_dialog_data *pw = si->pw_data;
1177   int pw_size = sizeof (pw->typed_passwd) - 1;
1178   char *typed_passwd = pw->typed_passwd;
1179   char s[2];
1180   char *stars = 0;
1181   int i;
1182   int size = XLookupString (event, s, 1, 0, compose_status);
1183
1184   if (size != 1) return;
1185
1186   s[1] = 0;
1187
1188   switch (*s)
1189     {
1190     case '\010': case '\177':                           /* Backspace */
1191       if (!*typed_passwd)
1192         XBell (si->dpy, 0);
1193       else
1194         typed_passwd [strlen(typed_passwd)-1] = 0;
1195       break;
1196
1197     case '\025': case '\030':                           /* Erase line */
1198       memset (typed_passwd, 0, pw_size);
1199       break;
1200
1201     case '\012': case '\015':                           /* Enter */
1202       if (pw->state != pw_read)
1203         ;  /* already done? */
1204       else if (typed_passwd[0] == 0)
1205         pw->state = pw_null;
1206       else
1207         {
1208           update_passwd_window (si, "Checking...", pw->ratio);
1209           XSync (si->dpy, False);
1210           if (passwd_valid_p (typed_passwd, p->verbose_p))
1211             pw->state = pw_ok;
1212           else
1213             pw->state = pw_fail;
1214           update_passwd_window (si, "", pw->ratio);
1215         }
1216       break;
1217
1218     default:
1219       i = strlen (typed_passwd);
1220       if (i >= pw_size-1)
1221         XBell (si->dpy, 0);
1222       else
1223         {
1224           typed_passwd [i] = *s;
1225           typed_passwd [i+1] = 0;
1226         }
1227       break;
1228     }
1229
1230   i = strlen(typed_passwd);
1231   stars = (char *) malloc(i+1);
1232   memset (stars, '*', i);
1233   stars[i] = 0;
1234   update_passwd_window (si, stars, pw->ratio);
1235   free (stars);
1236 }
1237
1238
1239 static void
1240 passwd_event_loop (saver_info *si)
1241 {
1242   saver_preferences *p = &si->prefs;
1243   char *msg = 0;
1244   XEvent event;
1245   passwd_animate_timer ((XtPointer) si, 0);
1246
1247   while (si->pw_data && si->pw_data->state == pw_read)
1248     {
1249       XtAppNextEvent (si->app, &event);
1250       if (event.xany.window == si->passwd_dialog && event.xany.type == Expose)
1251         draw_passwd_window (si);
1252       else if (event.xany.type == KeyPress)
1253         handle_passwd_key (si, &event.xkey);
1254       else
1255         XtDispatchEvent (&event);
1256     }
1257
1258   switch (si->pw_data->state)
1259     {
1260     case pw_ok:   msg = 0; break;
1261     case pw_null: msg = ""; break;
1262     case pw_time: msg = "Timed out!"; break;
1263     default:      msg = "Sorry!"; break;
1264     }
1265
1266   if (si->pw_data->state == pw_fail)
1267     si->unlock_failures++;
1268
1269   if (p->verbose_p)
1270     switch (si->pw_data->state)
1271       {
1272       case pw_ok:
1273         fprintf (stderr, "%s: password correct.\n", blurb()); break;
1274       case pw_fail:
1275         fprintf (stderr, "%s: password incorrect!\n", blurb()); break;
1276       case pw_null:
1277       case pw_cancel:
1278         fprintf (stderr, "%s: password entry cancelled.\n", blurb()); break;
1279       case pw_time:
1280         fprintf (stderr, "%s: password entry timed out.\n", blurb()); break;
1281       default: break;
1282       }
1283
1284 #ifdef HAVE_SYSLOG
1285   if (si->pw_data->state == pw_fail)
1286     {
1287       /* If they typed a password (as opposed to just hitting return) and
1288          the password was invalid, log it.
1289       */
1290       struct passwd *pw = getpwuid (getuid ());
1291       char *d = DisplayString (si->dpy);
1292       char *u = (pw->pw_name ? pw->pw_name : "???");
1293       int opt = 0;
1294       int fac = 0;
1295
1296 # ifdef LOG_PID
1297       opt = LOG_PID;
1298 # endif
1299
1300 # if defined(LOG_AUTHPRIV)
1301       fac = LOG_AUTHPRIV;
1302 # elif defined(LOG_AUTH)
1303       fac = LOG_AUTH;
1304 # else
1305       fac = LOG_DAEMON;
1306 # endif
1307
1308       if (!d) d = "";
1309       openlog (progname, opt, fac);
1310       syslog (LOG_NOTICE, "FAILED LOGIN %d ON DISPLAY \"%s\", FOR \"%s\"",
1311               si->unlock_failures, d, u);
1312       closelog ();
1313     }
1314 #endif /* HAVE_SYSLOG */
1315
1316   if (si->pw_data->state == pw_fail)
1317     XBell (si->dpy, False);
1318
1319   if (si->pw_data->state == pw_ok && si->unlock_failures != 0)
1320     {
1321       if (si->unlock_failures == 1)
1322         fprintf (real_stderr,
1323                  "%s: WARNING: 1 failed attempt to unlock the screen.\n",
1324                  blurb());
1325       else
1326         fprintf (real_stderr,
1327                  "%s: WARNING: %d failed attempts to unlock the screen.\n",
1328                  blurb(), si->unlock_failures);
1329       fflush (real_stderr);
1330
1331       si->unlock_failures = 0;
1332     }
1333
1334   if (msg)
1335     {
1336       si->pw_data->i_beam = 0;
1337       update_passwd_window (si, msg, 0.0);
1338       XSync (si->dpy, False);
1339       sleep (1);
1340
1341       /* Swallow all pending KeyPress/KeyRelease events. */
1342       {
1343         XEvent e;
1344         while (XCheckMaskEvent (si->dpy, KeyPressMask|KeyReleaseMask, &e))
1345           ;
1346       }
1347     }
1348 }
1349
1350
1351 static void
1352 handle_typeahead (saver_info *si)
1353 {
1354   passwd_dialog_data *pw = si->pw_data;
1355   int i;
1356   if (!si->unlock_typeahead)
1357     return;
1358
1359   i = strlen (si->unlock_typeahead);
1360   if (i >= sizeof(pw->typed_passwd) - 1)
1361     i = sizeof(pw->typed_passwd) - 1;
1362
1363   memcpy (pw->typed_passwd, si->unlock_typeahead, i);
1364   pw->typed_passwd [i] = 0;
1365
1366   memset (si->unlock_typeahead, '*', strlen(si->unlock_typeahead));
1367   si->unlock_typeahead[i] = 0;
1368   update_passwd_window (si, si->unlock_typeahead, pw->ratio);
1369
1370   free (si->unlock_typeahead);
1371   si->unlock_typeahead = 0;
1372 }
1373
1374
1375 Bool
1376 unlock_p (saver_info *si)
1377 {
1378   saver_preferences *p = &si->prefs;
1379   Bool status;
1380
1381   raise_window (si, True, True, True);
1382
1383   if (p->verbose_p)
1384     fprintf (stderr, "%s: prompting for password.\n", blurb());
1385
1386   if (si->pw_data || si->passwd_dialog)
1387     destroy_passwd_window (si);
1388
1389   make_passwd_window (si);
1390
1391   compose_status = calloc (1, sizeof (*compose_status));
1392
1393   handle_typeahead (si);
1394   passwd_event_loop (si);
1395
1396   status = (si->pw_data->state == pw_ok);
1397   destroy_passwd_window (si);
1398
1399   free (compose_status);
1400   compose_status = 0;
1401
1402   return status;
1403 }
1404
1405
1406 void
1407 set_locked_p (saver_info *si, Bool locked_p)
1408 {
1409   si->locked_p = locked_p;
1410
1411 #ifdef HAVE_XHPDISABLERESET
1412   hp_lock_reset (si, locked_p);                 /* turn off/on C-Sh-Reset */
1413 #endif
1414 #ifdef HAVE_VT_LOCKSWITCH
1415   linux_lock_vt_switch (si, locked_p);          /* turn off/on C-Alt-F1 */
1416 #endif
1417 #ifdef HAVE_XF86VMODE
1418   xfree_lock_mode_switch (si, locked_p);        /* turn off/on C-Alt-Plus */
1419 #endif
1420 #ifdef HAVE_XF86MISCSETGRABKEYSSTATE
1421   xfree_lock_grab_smasher (si, locked_p);       /* turn off/on C-Alt-KP-*,/ */
1422 #endif
1423
1424   store_saver_status (si);                      /* store locked-p */
1425 }
1426
1427
1428 #else  /*  NO_LOCKING -- whole file */
1429
1430 void
1431 set_locked_p (saver_info *si, Bool locked_p)
1432 {
1433   if (locked_p) abort();
1434 }
1435
1436 #endif /* !NO_LOCKING */