1 /* xscreensaver, Copyright (c) 1993 Jamie Zawinski <jwz@lucid.com>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
21 #include <X11/Intrinsic.h>
31 #include "xscreensaver.h"
37 extern char *screensaver_version;
38 extern char *progname;
39 extern XtAppContext app;
40 extern Bool verbose_p;
42 extern Widget passwd_dialog;
43 extern Widget passwd_form;
44 extern Widget roger_label;
45 extern Widget passwd_label1;
46 extern Widget passwd_label3;
47 extern Widget passwd_text;
48 extern Widget passwd_done;
49 extern Widget passwd_cancel;
51 extern create_passwd_dialog ();
53 static enum { pw_read, pw_ok, pw_fail, pw_cancel, pw_time } passwd_state;
54 static char typed_passwd [1024];
56 static char root_passwd [255];
57 static char user_passwd [255];
65 p = getpwnam ("root");
66 if (p && p->pw_passwd && p->pw_passwd[0] != '*')
67 strcpy (root_passwd, p->pw_passwd);
70 fprintf (stderr, "%s: couldn't get root's password\n", progname);
71 strcpy (root_passwd, "*");
79 /* getlogin() fails if not attached to a terminal;
80 in that case, use getpwuid(). */
81 p = getpwuid (getuid ());
85 if (p && p->pw_passwd && p->pw_passwd[0] != '*')
86 strcpy (user_passwd, p->pw_passwd);
89 fprintf (stderr, "%s: couldn't get password of \"%s\"\n", progname, u);
90 strcpy (user_passwd, "*");
97 passwd_cancel_cb (button, client_data, call_data)
99 XtPointer client_data, call_data;
101 passwd_state = pw_cancel;
105 passwd_done_cb (button, client_data, call_data)
107 XtPointer client_data, call_data;
109 if (passwd_state != pw_read) return; /* already done */
110 if (!strcmp ((char *) crypt (typed_passwd, user_passwd), user_passwd))
111 passwd_state = pw_ok;
112 /* do not allow root to have empty passwd */
113 else if (typed_passwd [0] &&
114 !strcmp ((char *) crypt (typed_passwd, root_passwd), root_passwd))
115 passwd_state = pw_ok;
117 passwd_state = pw_fail;
120 #ifdef VERIFY_CALLBACK_WORKS
122 /* #### It looks to me like adding any modifyVerify callback causes
123 #### Motif 1.1.4 to free the the TextF_Value() twice. I can't see
124 #### the bug in the Motif source, but Purify complains, even if
125 #### check_passwd_cb() is a no-op.
129 check_passwd_cb (button, client_data, call_data)
131 XtPointer client_data, call_data;
133 XmTextVerifyCallbackStruct *vcb = (XmTextVerifyCallbackStruct *) call_data;
135 if (passwd_state != pw_read)
137 else if (vcb->reason == XmCR_ACTIVATE)
139 passwd_done_cb (0, 0, 0);
141 else if (vcb->text->length > 1) /* don't allow "paste" operations */
145 else if (vcb->text->ptr != 0)
148 strncat (typed_passwd, vcb->text->ptr, vcb->text->length);
149 typed_passwd [vcb->endPos + vcb->text->length] = 0;
150 for (i = 0; i < vcb->text->length; i++)
151 vcb->text->ptr [i] = '*';
155 #else /* !VERIFY_CALLBACK_WORKS */
157 static void keypress();
158 static void backspace();
159 static void kill_line();
162 static XtActionsRec actions[] = {{"keypress", keypress},
163 {"backspace", backspace},
164 {"kill_line", kill_line},
168 #if 0 /* oh fuck, why doesn't this work? */
169 static char translations[] = "\
170 <Key>BackSpace: backspace()\n\
171 <Key>Delete: backspace()\n\
172 Ctrl<Key>H: backspace()\n\
173 Ctrl<Key>U: kill_line()\n\
174 Ctrl<Key>X: kill_line()\n\
175 Ctrl<Key>J: done()\n\
176 Ctrl<Key>M: done()\n\
180 static char translations[] = "<Key>:keypress()";
184 keypress (w, event, argv, argc)
191 char s [sizeof (typed_passwd)];
192 int size = XLookupString ((XKeyEvent *) event, s, sizeof (s), 0, 0);
193 if (size != 1) return;
195 /* hack because I can't get translations to dance to my tune... */
196 if (*s == '\010') { backspace (w, event, argv, argc); return; }
197 if (*s == '\177') { backspace (w, event, argv, argc); return; }
198 if (*s == '\025') { kill_line (w, event, argv, argc); return; }
199 if (*s == '\030') { kill_line (w, event, argv, argc); return; }
200 if (*s == '\012') { done (w, event, argv, argc); return; }
201 if (*s == '\015') { done (w, event, argv, argc); return; }
203 i = j = strlen (typed_passwd);
204 typed_passwd [i] = *s;
208 XmTextFieldSetString (passwd_text, s);
209 XmTextFieldSetInsertionPosition (passwd_text, j + 1);
213 backspace (w, event, argv, argc)
219 char s [sizeof (typed_passwd)];
220 int i = strlen (typed_passwd);
224 typed_passwd [--i] = 0;
228 XmTextFieldSetString (passwd_text, s);
229 XmTextFieldSetInsertionPosition (passwd_text, j + 1);
233 kill_line (w, event, argv, argc)
239 memset (typed_passwd, 0, sizeof (typed_passwd));
240 XmTextFieldSetString (passwd_text, "");
244 done (w, event, argv, argc)
250 passwd_done_cb (w, 0, 0);
253 #endif /* !VERIFY_CALLBACK_WORKS */
256 format_into_label (widget, string)
262 XmString xm_label = 0;
263 XmString new_xm_label;
266 XtSetArg (av [ac], XmNlabelString, &xm_label); ac++;
267 XtGetValues (widget, av, ac);
268 XmStringGetLtoR (xm_label, XmSTRING_DEFAULT_CHARSET, &label);
269 if (!strcmp (label, XtName (widget)))
270 strcpy (buf, "ERROR: RESOURCES ARE NOT INSTALLED CORRECTLY");
272 sprintf (buf, label, string);
273 new_xm_label = XmStringCreate (buf, XmSTRING_DEFAULT_CHARSET);
275 XtSetArg (av [ac], XmNlabelString, new_xm_label); ac++;
276 XtSetValues (widget, av, ac);
277 XmStringFree (new_xm_label);
282 extern void skull (Display *, Window, GC, GC, int, int, int, int);
286 roger (button, client_data, call_data)
288 XtPointer client_data, call_data;
290 Display *dpy = XtDisplay (button);
291 Screen *screen = XtScreen (button);
292 Window window = XtWindow (button);
297 GC draw_gc, erase_gc;
300 XWindowAttributes xgwa;
301 XGetWindowAttributes (dpy, window, &xgwa);
302 cmap = xgwa.colormap;
303 if (xgwa.width > xgwa.height) size = xgwa.height;
304 else size = xgwa.width;
305 if (size > 40) size -= 30;
306 x = (xgwa.width - size) / 2;
307 y = (xgwa.height - size) / 2;
308 XtSetArg (av [ac], XmNforeground, &fg); ac++;
309 XtSetArg (av [ac], XmNbackground, &bg); ac++;
310 XtGetValues (button, av, ac);
311 /* if it's black on white, swap it cause it looks better (hack hack) */
312 if (fg == BlackPixelOfScreen (screen) && bg == WhitePixelOfScreen (screen))
313 fg = WhitePixelOfScreen (screen), bg = BlackPixelOfScreen (screen);
315 erase_gc = XCreateGC (dpy, window, GCForeground, &gcv);
317 draw_gc = XCreateGC (dpy, window, GCForeground, &gcv);
318 XFillRectangle (dpy, window, erase_gc, 0, 0, xgwa.width, xgwa.height);
319 skull (dpy, window, draw_gc, erase_gc, x, y, size, size);
320 XFreeGC (dpy, draw_gc);
321 XFreeGC (dpy, erase_gc);
325 make_passwd_dialog (parent)
329 create_passwd_dialog (parent);
331 XtAddCallback (passwd_done, XmNactivateCallback, passwd_done_cb, 0);
332 XtAddCallback (passwd_cancel, XmNactivateCallback, passwd_cancel_cb, 0);
333 XtAddCallback (roger_label, XmNexposeCallback, roger, 0);
335 #ifdef VERIFY_CALLBACK_WORKS
336 XtAddCallback (passwd_text, XmNmodifyVerifyCallback, check_passwd_cb, 0);
337 XtAddCallback (passwd_text, XmNactivateCallback, check_passwd_cb, 0);
339 XtAddCallback (passwd_text, XmNactivateCallback, passwd_done_cb, 0);
340 XtOverrideTranslations (passwd_text, XtParseTranslationTable (translations));
343 pw = getpwuid (getuid ());
344 format_into_label (passwd_label3, (pw->pw_name ? pw->pw_name : "???"));
345 format_into_label (passwd_label1, screensaver_version);
349 extern void idle_timer ();
351 static int passwd_idle_timer_tick;
352 static XtIntervalId id;
355 passwd_idle_timer (junk1, junk2)
359 Display *dpy = XtDisplay (passwd_form);
360 Window window = XtWindow (passwd_form);
361 static Dimension x, y, d, s, ss;
363 int max = passwd_timeout / 1000;
365 idle_timer (junk1, junk2);
367 if (passwd_idle_timer_tick == max) /* first time */
372 unsigned long fg, bg;
373 XtSetArg (av [ac], XmNheight, &d); ac++;
374 XtGetValues (passwd_done, av, ac);
376 XtSetArg (av [ac], XmNwidth, &x); ac++;
377 XtSetArg (av [ac], XmNheight, &y); ac++;
378 XtSetArg (av [ac], XmNforeground, &fg); ac++;
379 XtSetArg (av [ac], XmNbackground, &bg); ac++;
380 XtGetValues (passwd_form, av, ac);
385 if (gc) XFreeGC (dpy, gc);
386 gc = XCreateGC (dpy, window, GCForeground, &gcv);
387 s = 360*64 / (passwd_idle_timer_tick - 1);
389 XFillArc (dpy, window, gc, x, y, d, d, 0, 360*64);
390 XSetForeground (dpy, gc, bg);
396 if (--passwd_idle_timer_tick)
398 id = XtAppAddTimeOut (app, 1000, passwd_idle_timer, 0);
399 XFillArc (dpy, window, gc, x, y, d, d, ss, s);
404 extern void pop_up_dialog_box ();
405 extern int BadWindow_ehandler ();
408 pop_passwd_dialog (parent)
411 Display *dpy = XtDisplay (passwd_dialog);
414 typed_passwd [0] = 0;
415 passwd_state = pw_read;
416 XmTextFieldSetString (passwd_text, "");
418 XGetInputFocus (dpy, &focus, &revert_to);
419 #ifndef DESTROY_WORKS
420 /* This fucker blows up if we destroy the widget. I can't figure
421 out why. The second destroy phase dereferences freed memory...
422 So we just keep it around; but unrealizing or unmanaging it
423 doesn't work right either, so we hack the window directly. FMH.
425 if (XtWindow (passwd_form))
426 XMapWindow (dpy, XtWindow (passwd_dialog));
428 pop_up_dialog_box (passwd_dialog, passwd_form, 2);
430 XtManageChild (passwd_form);
431 XSetInputFocus (dpy, XtWindow (passwd_dialog), revert_to, CurrentTime);
432 XmProcessTraversal (passwd_text, 0);
434 passwd_idle_timer_tick = passwd_timeout / 1000;
435 id = XtAppAddTimeOut (app, 1000, passwd_idle_timer, 0);
438 XGrabServer (dpy); /* ############ DANGER! */
440 while (passwd_state == pw_read)
443 XtAppNextEvent (app, &event);
444 /* wait for timer event */
445 if (event.xany.type == 0 && passwd_idle_timer_tick == 0)
446 passwd_state = pw_time;
447 XtDispatchEvent (&event);
450 XSync (dpy, False); /* ###### (danger over) */
452 if (passwd_state != pw_time)
453 XtRemoveTimeOut (id);
455 if (passwd_state != pw_ok)
458 switch (passwd_state)
460 case pw_time: lose = "Timed out!"; break;
461 case pw_fail: lose = "Sorry!"; break;
462 case pw_cancel: lose = 0; break;
465 XmProcessTraversal (passwd_cancel, 0); /* turn off I-beam */
468 XmTextFieldSetString (passwd_text, lose);
469 XmTextFieldSetInsertionPosition (passwd_text, strlen (lose) + 1);
470 passwd_idle_timer_tick = 1;
471 id = XtAppAddTimeOut (app, 3000, passwd_idle_timer, 0);
475 XtAppNextEvent (app, &event);
476 if (event.xany.type == 0 && /* wait for timer event */
477 passwd_idle_timer_tick == 0)
479 XtDispatchEvent (&event);
483 memset (typed_passwd, 0, sizeof (typed_passwd));
484 XmTextFieldSetString (passwd_text, "");
485 XtSetKeyboardFocus (parent, None);
487 #ifndef DESTROY_WORKS
488 XtDestroyWidget (passwd_dialog);
491 XUnmapWindow (XtDisplay (passwd_dialog), XtWindow (passwd_dialog));
494 int (*old_handler) ();
495 old_handler = XSetErrorHandler (BadWindow_ehandler);
496 /* I don't understand why this doesn't refocus on the old selected
497 window when MWM is running in click-to-type mode. The value of
498 `focus' seems to be correct. */
499 XSetInputFocus (dpy, focus, revert_to, CurrentTime);
501 XSetErrorHandler (old_handler);
504 return (passwd_state == pw_ok ? True : False);
511 static Bool initted = False;
514 #ifndef VERIFY_CALLBACK_WORKS
515 XtAppAddActions (app, actions, XtNumber (actions));
521 make_passwd_dialog (parent);
522 return pop_passwd_dialog (parent);
525 #endif /* !NO_LOCKING */