--- a/greeter/Login.h 2020-09-22 08:15:48.445614405 -0700 +++ b/greeter/Login.h 2020-09-22 08:16:04.418229439 -0700 @@ -95,6 +95,7 @@ # define XtNgreetFace "greetFace" # define XtNfailFace "failFace" # define XtNfailTimeout "failTimeout" +# define XtNgrabDelay "grabDelay" # define XtNsessionArgument "sessionArgument" # define XtNsecureSession "secureSession" # define XtNallowAccess "allowAccess" --- a/greeter/LoginP.h 2020-09-22 08:16:19.588151594 -0700 +++ b/greeter/LoginP.h 2020-09-22 08:16:33.452749073 -0700 @@ -127,6 +127,7 @@ char *sessionArg; /* argument passed to session */ LoginFunc notify_done; /* proc to call when done */ int failTimeout; /* seconds til drop fail msg */ + int grabDelay; /* time to retry to set the input focus to the login widget */ XtIntervalId interval_id; /* drop fail message note */ Boolean secure_session; /* session is secured */ Boolean allow_access; /* disable access control on login */ --- a/greeter/Login.c 2020-09-22 08:16:45.129246397 -0700 +++ b/greeter/Login.c 2020-09-22 08:19:03.626851807 -0700 @@ -210,6 +210,8 @@ (XtPointer) "Password Change Required" }, {XtNfailTimeout, XtCFailTimeout, XtRInt, sizeof (int), offset(failTimeout), XtRImmediate, (XtPointer) 10}, + {XtNgrabDelay, XtCGrabDelay, XtRInt, sizeof (int), + offset(grabDelay), XtRImmediate, (XtPointer) 10}, {XtNnotifyDone, XtCCallback, XtRFunction, sizeof (XtPointer), offset(notify_done), XtRFunction, (XtPointer) 0}, {XtNsessionArgument, XtCSessionArgument, XtRString, sizeof (char *), @@ -695,6 +697,37 @@ ErrorMessage(ctx, w->login.passwdChangeMsg, False); } +const char * +xerrMessage(int e) +{ + const char *s; + + switch (e) { + + case BadMatch: + s = "window is not visible"; + break; + + case BadWindow: + s = "window is no longer valid"; + break; + + default: + s = "generic failure"; + break; + } + return s; +} + +static volatile int xerr; + +static int +xErrorHandler(Display *d, XErrorEvent *xeep) +{ + xerr = xeep->error_code; + return xerr; +} + static void draw_it (LoginWidget w) { @@ -802,8 +835,40 @@ } RedrawFail (w); XorCursor (w); - XSetInputFocus (XtDisplay (w), XtWindow (w), - RevertToPointerRoot, CurrentTime); + + if (XGrabKeyboard (XtDisplay (w), XtWindow (w), False, GrabModeAsync, + GrabModeAsync, CurrentTime) != GrabSuccess) + { + typedef int (*x_e_h)(Display *, XErrorEvent *); + x_e_h originalHandler = XSetErrorHandler(xErrorHandler); + int waitsecs = w->login.grabDelay; + for (;;) { + xerr = Success; + XSetInputFocus (XtDisplay (w), XtWindow (w), + RevertToPointerRoot, CurrentTime); + XSync(XtDisplay (w), False); + + if (xerr != BadMatch) { + break; + } + + if (waitsecs == 0) { /* timed out */ + break; + } + + if (waitsecs > 0) { + sleep(1); + --waitsecs; + } + } + (void) XSetErrorHandler(originalHandler); + + if (xerr != Success) { + fprintf(stderr, "%s: failed to set focus; %s\n", + "greeter", xerrMessage(xerr)); + } + } + } /* Returns 0 on success, -1 on failure */ --- a/config/Xresources.in 2020-09-22 08:19:33.923767351 -0700 +++ b/config/Xresources.in 2020-09-22 08:20:02.447969714 -0700 @@ -1,4 +1,5 @@ Xcursor.theme: whiteglass +xlogin*grabDelay: 5 xlogin*login.translations: #override BS CtrlR: abort-display()NLBS --- a/greeter/Login.h 2020-09-22 10:42:07.782375282 -0700 +++ b/greeter/Login.h 2020-09-22 10:43:04.572299383 -0700 @@ -139,6 +139,7 @@ # define XtCPasswdPrompt "PasswdPrompt" # define XtCFail "Fail" # define XtCFailTimeout "FailTimeout" +# define XtCGrabDelay "GrabDelay" # define XtCSessionArgument "SessionArgument" # define XtCSecureSession "SecureSession" # define XtCAllowAccess "AllowAccess"