X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=driver%2Flock.c;h=f388c0d61deeceffdc560032f7ed85a88e854280;hb=ce3185de9d9705e259f2b60dd4b5509007fa17d4;hp=244eb0ba02b5f0b9d2f5d806f153c6305b01f8fb;hpb=6edc84f12f15860a71430c45e8392a5e4ef8203c;p=xscreensaver diff --git a/driver/lock.c b/driver/lock.c index 244eb0ba..f388c0d6 100644 --- a/driver/lock.c +++ b/driver/lock.c @@ -1,4 +1,5 @@ -/* xscreensaver, Copyright (c) 1993-1995 Jamie Zawinski +/* lock.c --- handling the password dialog for locking-mode. + * xscreensaver, Copyright (c) 1993-1998 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -9,160 +10,122 @@ * implied warranty. */ -#if __STDC__ -#include -#include -#include -#endif +/* Athena locking code contributed by Jon A. Christopher */ +/* Copyright 1997, with the same permissions as above. */ -#ifdef HAVE_SHADOW -#include +#ifdef HAVE_CONFIG_H +# include "config.h" #endif -#include -#include +#ifndef NO_LOCKING /* whole file */ +#include #include +#include /* for XtResizeWidget */ +#include "xscreensaver.h" +#include "resources.h" -#if !__STDC__ -# define _NO_PROTO -#endif +#ifndef VMS +# include +#else /* VMS */ +extern char *getenv(const char *name); +extern int validate_user(char *name, char *password); +#endif /* VMS */ -#include -#include -#include -#include "xscreensaver.h" +#ifdef HAVE_ATHENA -#ifndef NO_LOCKING +# include +# include +# include +# include +# include -Time passwd_timeout; +#else /* HAVE_MOTIF */ -extern char *screensaver_version; -extern char *progname; -extern XtAppContext app; -extern Bool verbose_p; +# include +# include +# include + +#endif /* HAVE_MOTIF */ + +#ifdef _VROOT_H_ +ERROR! You must not include vroot.h in this file. +#endif extern Widget passwd_dialog; extern Widget passwd_form; extern Widget roger_label; extern Widget passwd_label1; extern Widget passwd_label3; +extern Widget passwd_cancel; + +#ifdef HAVE_MOTIF extern Widget passwd_text; extern Widget passwd_done; -extern Widget passwd_cancel; +#else /* HAVE_ATHENA */ +static Widget passwd_text = 0; /* gag... */ +static Widget passwd_done = 0; +#endif /* HAVE_ATHENA */ -extern create_passwd_dialog P((Widget)); -extern void ungrab_keyboard_and_mouse P((void)); -static enum { pw_read, pw_ok, pw_fail, pw_cancel, pw_time } passwd_state; -static char typed_passwd [1024]; - -static char root_passwd [255]; -static char user_passwd [255]; - -#ifdef HAVE_SHADOW -# define PWTYPE struct spwd * -# define PWSLOT sp_pwdp -# define GETPW getspnam -#else -# define PWTYPE struct passwd * -# define PWSLOT pw_passwd -# define GETPW getpwnam -#endif -Bool -lock_init () -{ - Bool ok = True; - char *u; - PWTYPE p = GETPW ("root"); - if (p && p->PWSLOT && p->PWSLOT[0] != '*') - strcpy (root_passwd, p->PWSLOT); - else - { - fprintf (stderr, "%s: couldn't get root's password\n", progname); - strcpy (root_passwd, "*"); - } +static enum { pw_read, pw_ok, pw_fail, pw_cancel, pw_time } passwd_state; +static char typed_passwd [80]; - /* It has been reported that getlogin() returns the wrong user id on some - very old SGI systems... */ - u = getlogin (); - if (u) - p = GETPW (u); - else - { - /* getlogin() fails if not attached to a terminal; - in that case, use getpwuid(). */ - struct passwd *p2 = getpwuid (getuid ()); - u = p2->pw_name; -#ifdef HAVE_SHADOW - p = GETPW (u); -#else - p = p2; + +#if defined(HAVE_ATHENA) || (XmVersion >= 1002) + /* The `destroy' bug apears to be fixed as of Motif 1.2.1, but + the `verify-callback' bug is still present. */ +# define DESTROY_WORKS #endif - } - if (p && p->PWSLOT && - /* p->PWSLOT[0] != '*' */ /* sensible */ - (strlen (p->PWSLOT) > 4) /* solaris */ - ) - strcpy (user_passwd, p->PWSLOT); - else - { - fprintf (stderr, "%s: couldn't get password of \"%s\"\n", progname, u); - strcpy (user_passwd, "*"); - ok = False; - } - return ok; +static void +passwd_cancel_cb (Widget button, XtPointer client_data, XtPointer call_data) +{ + passwd_state = pw_cancel; } - -#if (XmVersion >= 1002) /* The `destroy' bug apears to be fixed as */ -# define DESTROY_WORKS /* of Motif 1.2.1, but the `verify-callback' */ -#endif /* bug is still present. */ - -static void -passwd_cancel_cb (button, client_data, call_data) - Widget button; - XtPointer client_data, call_data; +#ifdef VMS +static Bool +vms_passwd_valid_p(char *pw) { - passwd_state = pw_cancel; + char *u = getenv("USER"); + return (validate_user (i, typed_passwd) == 1); } +# undef passwd_valid_p +# define passwd_valid_p vms_passwd_valid_p + +#endif /* VMS */ + static void -passwd_done_cb (button, client_data, call_data) - Widget button; - XtPointer client_data, call_data; +passwd_done_cb (Widget button, XtPointer client_data, XtPointer call_data) { if (passwd_state != pw_read) return; /* already done */ - if (!strcmp ((char *) crypt (typed_passwd, user_passwd), user_passwd)) - passwd_state = pw_ok; - /* do not allow root to have empty passwd */ - else if (typed_passwd [0] && - !strcmp ((char *) crypt (typed_passwd, root_passwd), root_passwd)) + + if (passwd_valid_p (typed_passwd)) passwd_state = pw_ok; else passwd_state = pw_fail; } -#ifdef VERIFY_CALLBACK_WORKS - /* #### It looks to me like adding any modifyVerify callback causes - #### Motif 1.1.4 to free the the TextF_Value() twice. I can't see - #### the bug in the Motif source, but Purify complains, even if - #### check_passwd_cb() is a no-op. +#if defined(HAVE_MOTIF) && defined(VERIFY_CALLBACK_WORKS) - #### Update: Motif 1.2.1 also loses, but in a different way: it - #### writes beyond the end of a malloc'ed block in ModifyVerify(). - #### Probably this block is the text field's text. + /* It looks to me like adding any modifyVerify callback causes + Motif 1.1.4 to free the the TextF_Value() twice. I can't see + the bug in the Motif source, but Purify complains, even if + check_passwd_cb() is a no-op. + + Update: Motif 1.2.1 also loses, but in a different way: it + writes beyond the end of a malloc'ed block in ModifyVerify(). + Probably this block is the text field's text. */ static void -check_passwd_cb (button, client_data, call_data) - Widget button; - XtPointer client_data, call_data; +check_passwd_cb (Widget button, XtPointer client_data, XtPointer call_data) { XmTextVerifyCallbackStruct *vcb = (XmTextVerifyCallbackStruct *) call_data; @@ -179,19 +142,22 @@ check_passwd_cb (button, client_data, call_data) else if (vcb->text->ptr != 0) { int i; - strncat (typed_passwd, vcb->text->ptr, vcb->text->length); - typed_passwd [vcb->endPos + vcb->text->length] = 0; + int L = vcb->text->length; + if (L >= sizeof(typed_passwd)) + L = sizeof(typed_passwd)-1; + strncat (typed_passwd, vcb->text->ptr, L); + typed_passwd [vcb->endPos + L] = 0; for (i = 0; i < vcb->text->length; i++) vcb->text->ptr [i] = '*'; } } -#else /* !VERIFY_CALLBACK_WORKS */ +# else /* HAVE_ATHENA || !VERIFY_CALLBACK_WORKS */ -static void keypress(); -static void backspace(); -static void kill_line(); -static void done(); +static void keypress (Widget w, XEvent *event, String *av, Cardinal *ac); +static void backspace (Widget w, XEvent *event, String *av, Cardinal *ac); +static void kill_line (Widget w, XEvent *event, String *av, Cardinal *ac); +static void done (Widget w, XEvent *event, String *av, Cardinal *ac); static XtActionsRec actions[] = {{"keypress", keypress}, {"backspace", backspace}, @@ -199,31 +165,59 @@ static XtActionsRec actions[] = {{"keypress", keypress}, {"done", done} }; -#if 0 /* oh fuck, why doesn't this work? */ -static char translations[] = "\ -BackSpace: backspace()\n\ -Delete: backspace()\n\ -CtrlH: backspace()\n\ -CtrlU: kill_line()\n\ -CtrlX: kill_line()\n\ -CtrlJ: done()\n\ -CtrlM: done()\n\ -: keypress()\n\ -"; -#else -static char translations[] = ":keypress()"; -#endif +# if 0 /* This works for Athena, but not Motif: keypress() gets called + for all keys anyway. So, the implementation of keypress() + has BackSpace, etc, hardcoded into it instead. FMH! + */ +static char translations[] = "BackSpace: backspace()\n" + "Delete: backspace()\n" + "CtrlH: backspace()\n" + "CtrlU: kill_line()\n" + "CtrlX: kill_line()\n" + "CtrlJ: done()\n" + "CtrlM: done()\n" + ": keypress()\n"; +# else /* !0 */ +static char translations[] = ": keypress()\n"; +# endif /* !0 */ + + +static void +text_field_set_string (Widget widget, char *text, int position) +{ +#ifdef HAVE_MOTIF + XmTextFieldSetString (widget, text); + XmTextFieldSetInsertionPosition (widget, position); + +#else /* HAVE_ATHENA */ + char *buf; + int end_pos; + + XawTextBlock block; + block.firstPos = 0; + block.length = strlen (text); + block.ptr = text; + block.format = 0; + if (block.length == 0) + { + buf = XawDialogGetValueString(passwd_form); + if (buf) + end_pos = strlen(buf); + else + end_pos = -1; + } + XawTextReplace (widget, 0, end_pos, &block); + XawTextSetInsertionPoint (widget, position); +#endif /* HAVE_ATHENA */ +} + static void -keypress (w, event, argv, argc) - Widget w; - XEvent *event; - String *argv; - Cardinal *argc; +keypress (Widget w, XEvent *event, String *argv, Cardinal *argc) { int i, j; - char s [sizeof (typed_passwd)]; - int size = XLookupString ((XKeyEvent *) event, s, sizeof (s), 0, 0); + char s [sizeof(typed_passwd)]; + int size = XLookupString ((XKeyEvent *) event, s, sizeof(s)-1, 0, 0); if (size != 1) return; /* hack because I can't get translations to dance to my tune... */ @@ -235,22 +229,25 @@ keypress (w, event, argv, argc) if (*s == '\015') { done (w, event, argv, argc); return; } i = j = strlen (typed_passwd); + + if (i >= (sizeof(typed_passwd)-1)) + { + XBell(XtDisplay(w), 0); + return; + } + typed_passwd [i] = *s; s [++i] = 0; while (i--) s [i] = '*'; - XmTextFieldSetString (passwd_text, s); - XmTextFieldSetInsertionPosition (passwd_text, j + 1); + + text_field_set_string (passwd_text, s, j + 1); } static void -backspace (w, event, argv, argc) - Widget w; - XEvent *event; - String *argv; - Cardinal *argc; +backspace (Widget w, XEvent *event, String *argv, Cardinal *argc) { - char s [sizeof (typed_passwd)]; + char s [sizeof(typed_passwd)]; int i = strlen (typed_passwd); int j = i; if (i == 0) @@ -259,170 +256,190 @@ backspace (w, event, argv, argc) s [i] = 0; while (i--) s [i] = '*'; - XmTextFieldSetString (passwd_text, s); - XmTextFieldSetInsertionPosition (passwd_text, j + 1); + + text_field_set_string (passwd_text, s, j + 1); } static void -kill_line (w, event, argv, argc) - Widget w; - XEvent *event; - String *argv; - Cardinal *argc; +kill_line (Widget w, XEvent *event, String *argv, Cardinal *argc) { - memset (typed_passwd, 0, sizeof (typed_passwd)); - XmTextFieldSetString (passwd_text, ""); + memset (typed_passwd, 0, sizeof(typed_passwd)); + text_field_set_string (passwd_text, "", 0); } static void -done (w, event, argv, argc) - Widget w; - XEvent *event; - String *argv; - Cardinal *argc; +done (Widget w, XEvent *event, String *argv, Cardinal *argc) { passwd_done_cb (w, 0, 0); } -#endif /* !VERIFY_CALLBACK_WORKS */ +#endif /* HAVE_ATHENA || !VERIFY_CALLBACK_WORKS */ + static void -format_into_label (widget, string) - Widget widget; - char *string; +make_passwd_dialog (saver_info *si) { - char *label; - char buf [255]; - XmString xm_label = 0; - XmString new_xm_label; - Arg av[10]; - int ac = 0; - XtSetArg (av [ac], XmNlabelString, &xm_label); ac++; - XtGetValues (widget, av, ac); - XmStringGetLtoR (xm_label, XmSTRING_DEFAULT_CHARSET, &label); - if (!strcmp (label, XtName (widget))) - strcpy (buf, "ERROR: RESOURCES ARE NOT INSTALLED CORRECTLY"); + char *username = 0; + saver_screen_info *ssi = si->default_screen; + Widget parent = ssi->toplevel_shell; + + if (ssi->demo_cmap && + ssi->demo_cmap != ssi->cmap && + ssi->demo_cmap != DefaultColormapOfScreen (ssi->screen)) + { + XFreeColormap (si->dpy, ssi->demo_cmap); + ssi->demo_cmap = 0; + } + + if (ssi->default_visual == DefaultVisualOfScreen (ssi->screen)) + ssi->demo_cmap = DefaultColormapOfScreen (ssi->screen); else - sprintf (buf, label, string); - new_xm_label = XmStringCreate (buf, XmSTRING_DEFAULT_CHARSET); - ac = 0; - XtSetArg (av [ac], XmNlabelString, new_xm_label); ac++; - XtSetValues (widget, av, ac); - XmStringFree (new_xm_label); - XtFree (label); -} + ssi->demo_cmap = XCreateColormap (si->dpy, + RootWindowOfScreen (ssi->screen), + ssi->default_visual, AllocNone); -#if __STDC__ -extern void skull (Display *, Window, GC, GC, int, int, int, int); -#endif + create_passwd_dialog (parent, ssi->default_visual, ssi->demo_cmap); -static void -roger (button, client_data, call_data) - Widget button; - XtPointer client_data, call_data; -{ - Display *dpy = XtDisplay (button); - Screen *screen = XtScreen (button); - Window window = XtWindow (button); - Arg av [10]; - int ac = 0; - XGCValues gcv; - Colormap cmap; - GC draw_gc, erase_gc; - unsigned int fg, bg; - int x, y, size; - XWindowAttributes xgwa; - XGetWindowAttributes (dpy, window, &xgwa); - cmap = xgwa.colormap; - if (xgwa.width > xgwa.height) size = xgwa.height; - else size = xgwa.width; - if (size > 40) size -= 30; - x = (xgwa.width - size) / 2; - y = (xgwa.height - size) / 2; - XtSetArg (av [ac], XmNforeground, &fg); ac++; - XtSetArg (av [ac], XmNbackground, &bg); ac++; - XtGetValues (button, av, ac); - /* if it's black on white, swap it cause it looks better (hack hack) */ - if (fg == BlackPixelOfScreen (screen) && bg == WhitePixelOfScreen (screen)) - fg = WhitePixelOfScreen (screen), bg = BlackPixelOfScreen (screen); - gcv.foreground = bg; - erase_gc = XCreateGC (dpy, window, GCForeground, &gcv); - gcv.foreground = fg; - draw_gc = XCreateGC (dpy, window, GCForeground, &gcv); - XFillRectangle (dpy, window, erase_gc, 0, 0, xgwa.width, xgwa.height); - skull (dpy, window, draw_gc, erase_gc, x, y, size, size); - XFreeGC (dpy, draw_gc); - XFreeGC (dpy, erase_gc); -} +#ifdef HAVE_ATHENA + XtVaSetValues(passwd_form, XtNvalue, typed_passwd, 0); -static void -make_passwd_dialog (parent) - Widget parent; -{ - struct passwd *pw; - create_passwd_dialog (parent); + XawDialogAddButton(passwd_form,"ok", passwd_done_cb, 0); + XawDialogAddButton(passwd_form,"cancel", passwd_cancel_cb, 0); + passwd_done = XtNameToWidget(passwd_form,"ok"); + passwd_text = XtNameToWidget(passwd_form,"value"); + + XtAppAddActions(XtWidgetToApplicationContext(passwd_text), + actions, XtNumber(actions)); + XtOverrideTranslations(passwd_text, XtParseTranslationTable(translations)); + + /* Lose the label on the inner dialog. */ + { + Widget w = XtNameToWidget(passwd_form, "label"); + if (w) XtUnmanageChild(w); + } + +#else /* HAVE_MOTIF */ XtAddCallback (passwd_done, XmNactivateCallback, passwd_done_cb, 0); XtAddCallback (passwd_cancel, XmNactivateCallback, passwd_cancel_cb, 0); XtAddCallback (roger_label, XmNexposeCallback, roger, 0); -#ifdef VERIFY_CALLBACK_WORKS +# ifdef VERIFY_CALLBACK_WORKS XtAddCallback (passwd_text, XmNmodifyVerifyCallback, check_passwd_cb, 0); XtAddCallback (passwd_text, XmNactivateCallback, check_passwd_cb, 0); -#else +# else /* !VERIFY_CALLBACK_WORKS */ XtAddCallback (passwd_text, XmNactivateCallback, passwd_done_cb, 0); XtOverrideTranslations (passwd_text, XtParseTranslationTable (translations)); -#endif +# endif /* !VERIFY_CALLBACK_WORKS */ -#if (XmVersion >= 1002) +# if defined(HAVE_MOTIF) && (XmVersion >= 1002) /* The focus stuff changed around; this didn't exist in 1.1.5. */ XtVaSetValues (passwd_form, XmNinitialFocus, passwd_text, 0); -#endif +# endif /* HAVE_MOTIF && XmVersion >= 1002 */ /* Another random thing necessary in 1.2.1 but not 1.1.5... */ XtVaSetValues (roger_label, XmNborderWidth, 2, 0); - pw = getpwuid (getuid ()); - format_into_label (passwd_label3, (pw->pw_name ? pw->pw_name : "???")); - format_into_label (passwd_label1, screensaver_version); -} +#endif /* HAVE_MOTIF */ +#ifndef VMS + { + struct passwd *pw = getpwuid (getuid ()); + username = pw->pw_name; + } +#else /* VMS -- from "R.S.Niranjan" who says + that on OpenVMS 6.1, using `struct passwd' crashes... */ + username = getenv("USER"); +#endif /* VMS */ -extern void idle_timer (); + format_into_label (passwd_label1, si->version); + format_into_label (passwd_label3, (username ? username : "???")); +} -static int passwd_idle_timer_tick; -static XtIntervalId id; +static int passwd_idle_timer_tick = -1; +static XtIntervalId passwd_idle_id; static void -passwd_idle_timer (junk1, junk2) - void *junk1; - XtPointer junk2; +passwd_idle_timer (XtPointer closure, XtIntervalId *id) { + saver_info *si = (saver_info *) closure; + saver_preferences *p = &si->prefs; + Display *dpy = XtDisplay (passwd_form); +#ifdef HAVE_ATHENA Window window = XtWindow (passwd_form); +#else /* MOTIF */ + Window window = XtWindow (XtParent(passwd_done)); +#endif /* MOTIF */ static Dimension x, y, d, s, ss; static GC gc = 0; - int max = passwd_timeout / 1000; + int max = p->passwd_timeout / 1000; - idle_timer (junk1, junk2); + idle_timer ((XtPointer) si, id); if (passwd_idle_timer_tick == max) /* first time */ { - Arg av [10]; - int ac = 0; XGCValues gcv; - unsigned long fg, bg; - XtSetArg (av [ac], XmNheight, &d); ac++; +#ifdef HAVE_MOTIF + unsigned long fg = 0, bg = 0, ts = 0, bs = 0; + Dimension w = 0, h = 0; + XtVaGetValues(XtParent(passwd_done), + XmNwidth, &w, + 0); + XtVaGetValues(passwd_done, + XmNheight, &h, + XmNy, &y, + 0); + XtVaGetValues(passwd_form, + XtNforeground, &fg, + XtNbackground, &bg, + XmNtopShadowColor, &ts, + XmNbottomShadowColor, &bs, + 0); + + if (ts != bg && ts != fg) + fg = ts; + if (bs != bg && bs != fg) + fg = bs; + + d = h / 2; + if (d & 1) d++; + + x = (w / 2); + +# ifdef __sgi /* Kludge -- SGI's Motif hacks place buttons differently. */ + { + static int sgi_mode = -1; + if (sgi_mode == -1) + sgi_mode = get_boolean_resource("sgiMode", "sgiMode") ? 1 : 0; + + if (sgi_mode) + x = d; + } +# endif /* __sgi */ + + x -= d/2; + y += d/2; + +#else /* HAVE_ATHENA */ + + Arg av [100]; + int ac = 0; + unsigned long fg = 0, bg = 0; + XtSetArg (av [ac], XtNheight, &d); ac++; XtGetValues (passwd_done, av, ac); ac = 0; - XtSetArg (av [ac], XmNwidth, &x); ac++; - XtSetArg (av [ac], XmNheight, &y); ac++; - XtSetArg (av [ac], XmNforeground, &fg); ac++; - XtSetArg (av [ac], XmNbackground, &bg); ac++; + XtSetArg (av [ac], XtNwidth, &x); ac++; + XtSetArg (av [ac], XtNheight, &y); ac++; + XtSetArg (av [ac], XtNforeground, &fg); ac++; + XtSetArg (av [ac], XtNbackground, &bg); ac++; XtGetValues (passwd_form, av, ac); x -= d; y -= d; d -= 4; + +#endif /* HAVE_ATHENA */ + gcv.foreground = fg; if (gc) XFreeGC (dpy, gc); gc = XCreateGC (dpy, window, GCForeground, &gcv); @@ -437,28 +454,37 @@ passwd_idle_timer (junk1, junk2) if (--passwd_idle_timer_tick) { - id = XtAppAddTimeOut (app, 1000, passwd_idle_timer, 0); + passwd_idle_id = XtAppAddTimeOut (si->app, 1000, passwd_idle_timer, + (XtPointer) si); XFillArc (dpy, window, gc, x, y, d, d, ss, s); ss += s; } } -extern void pop_up_dialog_box (); -extern int BadWindow_ehandler (); static Bool -pop_passwd_dialog (parent) - Widget parent; +pop_passwd_dialog (saver_info *si) { + saver_preferences *p = &si->prefs; + saver_screen_info *ssi = si->default_screen; + Widget parent = ssi->toplevel_shell; Display *dpy = XtDisplay (passwd_dialog); Window focus; int revert_to; + int i; + Window grab_window = RootWindowOfScreen(si->screens[0].screen); + typed_passwd [0] = 0; passwd_state = pw_read; - XmTextFieldSetString (passwd_text, ""); + text_field_set_string (passwd_text, "", 0); + + /* In case one of the hacks has unmapped it temporarily... + Get that sucker on stage now! */ + for (i = 0; i < si->nscreens; i++) + XMapRaised(si->dpy, si->screens[i].screensaver_window); XGetInputFocus (dpy, &focus, &revert_to); -#ifndef DESTROY_WORKS +#if defined(HAVE_MOTIF) && !defined(DESTROY_WORKS) /* This fucker blows up if we destroy the widget. I can't figure out why. The second destroy phase dereferences freed memory... So we just keep it around; but unrealizing or unmanaging it @@ -466,31 +492,79 @@ pop_passwd_dialog (parent) */ if (XtWindow (passwd_form)) XMapRaised (dpy, XtWindow (passwd_dialog)); -#endif +#endif /* HAVE_MOTIF && !DESTROY_WORKS */ - pop_up_dialog_box (passwd_dialog, passwd_form, 2); + monitor_power_on (si); + pop_up_dialog_box (passwd_dialog, passwd_form, + /* for debugging -- don't ask */ + (si->prefs.debug_p ? 69 : 0) + + 2); XtManageChild (passwd_form); -#if (XmVersion < 1002) +#ifdef HAVE_ATHENA + steal_focus_and_colormap (passwd_text); + + /* For some reason, the passwd_form box is not stretching all the way + to the right edge of the window, despite being XtChainRight. + So... resize it by hand. + */ + { + Dimension x=0, w=0, h=0; + XtVaGetValues(passwd_form, XtNx, &x, XtNwidth, &w, XtNheight, &h, 0); + XtVaGetValues(XtParent(passwd_form), XtNwidth, &w, 0); + w -= x; + w -= 6; + if (w > 0) XtResizeWidget(passwd_form, w, h, 0); + } + +#endif /* HAVE_ATHENA */ + + +#if defined(HAVE_MOTIF) && (XmVersion < 1002) /* The focus stuff changed around; this causes problems in 1.2.1 but is necessary in 1.1.5. */ XmProcessTraversal (passwd_text, XmTRAVERSE_CURRENT); -#endif +#endif /* HAVE_MOTIF && XmVersion < 1002 */ + + passwd_idle_timer_tick = p->passwd_timeout / 1000; + passwd_idle_id = XtAppAddTimeOut (si->app, 1000, passwd_idle_timer, + (XtPointer) si); - passwd_idle_timer_tick = passwd_timeout / 1000; - id = XtAppAddTimeOut (app, 1000, passwd_idle_timer, 0); +#ifdef HAVE_ATHENA + if (roger_label) + roger(roger_label, 0, 0); +#endif /* HAVE_ATHENA */ - XGrabServer (dpy); /* ############ DANGER! */ + /* Make sure the mouse cursor is visible. + Since the screensaver was already active, we had already called + grab_keyboard_and_mouse() with our "invisible" Cursor object. + Now we need to change that. (cursor == 0 means "server default + cursor.") + */ + if (grab_window != si->mouse_grab_window || + grab_window != si->keyboard_grab_window) + fprintf(stderr, + "%s: WARNING: expected mouse and keyboard grabs on 0x%x,\n" + "\tbut mouse-grab is 0x%x and keyboard-grab is 0x%x.\n", + blurb(), + (unsigned long) grab_window, + (unsigned long) si->mouse_grab_window, + (unsigned long) si->keyboard_grab_window); + + if (p->verbose_p) + fprintf(stderr, "%s: re-grabbing keyboard and mouse to expose cursor.\n", + blurb()); + grab_keyboard_and_mouse (si, grab_window, 0); - /* this call to ungrab used to be in main_loop() - see comment in - xscreensaver.c around line 696. */ - ungrab_keyboard_and_mouse (); + + if (!si->prefs.debug_p) + XGrabServer (dpy); /* ############ DANGER! */ while (passwd_state == pw_read) { XEvent event; - XtAppNextEvent (app, &event); + XtAppNextEvent (si->app, &event); /* wait for timer event */ if (event.xany.type == 0 && passwd_idle_timer_tick == 0) passwd_state = pw_time; @@ -499,8 +573,17 @@ pop_passwd_dialog (parent) XUngrabServer (dpy); XSync (dpy, False); /* ###### (danger over) */ + + /* Now turn off the mouse cursor again. + */ + if (p->verbose_p) + fprintf(stderr, "%s: re-grabbing keyboard and mouse to hide cursor.\n", + blurb()); + grab_keyboard_and_mouse (si, grab_window, si->screens[0].cursor); + + if (passwd_state != pw_time) - XtRemoveTimeOut (id); + XtRemoveTimeOut (passwd_idle_id); if (passwd_state != pw_ok) { @@ -512,17 +595,24 @@ pop_passwd_dialog (parent) case pw_cancel: lose = 0; break; default: abort (); } + +#ifdef HAVE_MOTIF XmProcessTraversal (passwd_cancel, 0); /* turn off I-beam */ +#else /* HAVE_ATHENA */ + steal_focus_and_colormap (passwd_done); +#endif /* HAVE_ATHENA */ + if (lose) { - XmTextFieldSetString (passwd_text, lose); - XmTextFieldSetInsertionPosition (passwd_text, strlen (lose) + 1); + text_field_set_string (passwd_text, lose, strlen (lose) + 1); + passwd_idle_timer_tick = 1; - id = XtAppAddTimeOut (app, 3000, passwd_idle_timer, 0); + passwd_idle_id = XtAppAddTimeOut (si->app, 3000, passwd_idle_timer, + (XtPointer) si); while (1) { XEvent event; - XtAppNextEvent (app, &event); + XtAppNextEvent (si->app, &event); if (event.xany.type == 0 && /* wait for timer event */ passwd_idle_timer_tick == 0) break; @@ -530,19 +620,18 @@ pop_passwd_dialog (parent) } } } - memset (typed_passwd, 0, sizeof (typed_passwd)); - XmTextFieldSetString (passwd_text, ""); + memset (typed_passwd, 0, sizeof(typed_passwd)); + text_field_set_string (passwd_text, "", 0); XtSetKeyboardFocus (parent, None); #ifdef DESTROY_WORKS XtDestroyWidget (passwd_dialog); passwd_dialog = 0; -#else +#else /* !DESTROY_WORKS */ XUnmapWindow (XtDisplay (passwd_dialog), XtWindow (passwd_dialog)); -#endif +#endif /* !DESTROY_WORKS */ { - int (*old_handler) (); - old_handler = XSetErrorHandler (BadWindow_ehandler); + XErrorHandler old_handler = XSetErrorHandler (BadWindow_ehandler); /* I don't understand why this doesn't refocus on the old selected window when MWM is running in click-to-type mode. The value of `focus' seems to be correct. */ @@ -551,25 +640,36 @@ pop_passwd_dialog (parent) XSetErrorHandler (old_handler); } + /* Since we installed our colormap to display the dialog properly, put + the old one back, so that the screensaver_window is now displayed + properly. */ + for (i = 0; i < si->nscreens; i++) + { + saver_screen_info *ssi = &si->screens[i]; + if (ssi->cmap) + XInstallColormap (si->dpy, ssi->cmap); + } + return (passwd_state == pw_ok ? True : False); } Bool -unlock_p (parent) - Widget parent; +unlock_p (saver_info *si) { static Bool initted = False; if (! initted) { + #ifndef VERIFY_CALLBACK_WORKS - XtAppAddActions (app, actions, XtNumber (actions)); -#endif + XtAppAddActions (si->app, actions, XtNumber (actions)); +#endif /* !VERIFY_CALLBACK_WORKS */ + passwd_dialog = 0; initted = True; } if (! passwd_dialog) - make_passwd_dialog (parent); - return pop_passwd_dialog (parent); + make_passwd_dialog (si); + return pop_passwd_dialog (si); } -#endif /* !NO_LOCKING */ +#endif /* !NO_LOCKING -- whole file */