[comp.windows.x] bug in XtSetKeyboardFocus?

pms@ARBORTEXT.COM (Pat Sherry) (08/17/90)

The attached test program shows what I think is a bug in XtSetKeyboardFocus().
It seems to me that the call
	XtSetKeyboardFocus(widget, None)
does not clear the cached per display focus widget with the result
that events are still delivered to the widget which was set in
a previous call to XtSetKeyboardFocus().

Run this test program and type some characters with the pointer positioned
anywhere in the box but outside of the text widget. The keypress events
are delivered to the text widget as expected. Press the Escape key
which is supposed to revert the focus from the text widget to the
box. Subsequent keypresses should not be delivered to the text widget
but should result in the message "KeyPress in box" printed on stderr.
Instead the keypress events still go to the text widget. If you move
the pointer out of the application shell and back into the box, then
the cached focus widget is cleared and events will be dispatched
to the box.

If I apply the following patch to $(TOP)/lib/Xt/Keyboard.c (X11R4, patch
level 14), then the program works as I would expect. Is this really
a bug or am I misinterpreting the documentation?

Pat Sherry
pms@arbortext.com
ArborText, Inc


My patch to XtSetKeyboardFocus():

*** /usr/src/local/X11R4/src/mit/lib/Xt/Keyboard.c	Mon Apr 23 23:26:04 1990
--- Keyboard.c	Thu Aug 16 16:42:35 1990
***************
*** 770,775 ****
--- 770,777 ----
  				   _XtHandleFocus, (XtPointer)pwi);
  	      pwi->haveFocus = FALSE;
  	  }
+ 	  if (pdi->focusWidget == oldDesc)
+ 	      pdi->focusWidget = NULL;
  	}
  	
  	if (descendant) {


-----------------------------------------

#include <stdio.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>

#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Box.h>

static void Quit(), KeyPressed(), Focus(), UnFocus();

String fallback_resources[] = { 
    "*input:                  True",
    "*Text*width: 	      400", 
    "*Text*editType:          edit",
    "*Text*translations:      #override <Key>Escape: UnFocus()",
    "*quit.label:             Quit",
    "*focus.label:            Set Focus",
    "*box.translations:       <Key>: KeyPressed()",
    NULL,
};
 
main(argc, argv)
int argc;
char **argv;
{
    static void Syntax();
    XtAppContext app_con;
    Widget toplevel, box, quit, focus, text;
    Arg args[5];
    static char buffer[100];
    static XtActionsRec actionTable[] = {
	{ "KeyPressed", KeyPressed },
	{ "UnFocus", UnFocus }
    };

    toplevel = XtAppInitialize(&app_con, "XFocus", NULL, 0,
			       &argc, argv, fallback_resources, NULL, 0);


    box = XtCreateManagedWidget("box", boxWidgetClass, toplevel, 
				    NULL, 0);

    quit = XtCreateManagedWidget("quit", commandWidgetClass, box, 
				  NULL, 0);
    focus = XtCreateManagedWidget("focus", commandWidgetClass, box, 
				  NULL, 0);

    XtSetArg(args[0], XtNuseStringInPlace, True);
    XtSetArg(args[1], XtNstring, buffer);
    XtSetArg(args[2], XtNlength, sizeof(buffer));
    text = XtCreateManagedWidget("text", asciiTextWidgetClass, box, 
				 args, 3);

    XtAppAddActions(app_con, actionTable, XtNumber(actionTable));
    XtAddCallback(quit, XtNcallback, Quit, (XtPointer) NULL);
    XtAddCallback(focus, XtNcallback, Focus, (XtPointer) text);
    XtSetKeyboardFocus(box, text);

    XtRealizeWidget(toplevel);
    XtAppMainLoop(app_con);
}

static void
Quit(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
    exit(0);
}

static void
Focus(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
    XtSetKeyboardFocus(XtParent(w), (Widget)client_data);
}

static void
UnFocus(w, event, params, num_params)
Widget w;
XEvent *event;
String *params;
Cardinal *num_params;
{
    XtSetKeyboardFocus(XtParent(w), None);
}

static void
KeyPressed(w, event, params, num_params)
Widget w;
XEvent *event;
String *params;
Cardinal *num_params;
{
	fprintf(stderr, "KeyPress in box\n");
}

swick@ATHENA.MIT.EDU (Ralph Swick) (08/24/90)

    It seems to me that the call
	XtSetKeyboardFocus(widget, None)
    does not clear the cached per display focus widget with the result
    that events are still delivered to the widget which was set in
    a previous call to XtSetKeyboardFocus().

Your analysis is correct.  The fix will be included in the next
public patch (in a few days).