To: ouster@sprite.berkeley.edu
Cc: hopkins
Subject: more multiple display stuff
--text follows this line--
A problem I fixed is that the "focus" command only returns the focus
of the main window's display, and there's no way to find out the focus
on other displays.  I fixed this by adding a "focus -query .window"
form, that returns the focus of the display of the named window.  When
the tcl menu tracking code supports multiple displays, it will need to
use this form to save the focus of the appropriate display before
popping up a menu. 

A problem I haven't fixed yet is with the "selection" command, which
right now will only retrieve the selection from the display of the
main window.  Pasting into a text field on another display with ^V
inserts the selection from the main display.  It could be changed to
take a window argument similar to "focus". 

I wish I could think of a better flag name than "-query"...  

I had a go at hacking the Tk C code to keep track of one focus per
display instead of per main window.  (Should I be using one main
window per display?  I'm not now, I'm just creating remote toplevels
with the -screen argument.)  I moved the "struct TkWindow *focusPtr;"
from the TkMainInfo to the TkDisplay structure, and modified the code
in tkEvent.c that handled it and tkWindow.c that initialized it.  

In tkEvent.c, I changed 3 "winPtr->mainPtr->focusPtr"'s to
"winPtr->dispPtr->focusPtr", in Tk_HandleEvent and TkEventDeadWindow.  
I worked over Tk_FocusCmd and TkFocusEventProc, included below.  
I'm not sure what the "winPtr == winPtr->dispPtr->mouseMainPtr" test
at the end of Tk_FocusCmd really intends, but the transformation was
pretty straightforward, and it seems to work for my cases.  

I've looked at the tcl code to try to figure out how to make it track
properly with multiple displays.  I think I'll need a function that
given the name of a window, returns a unique string describing the
display, that I can use to make tk_priv keys that distinguish between
displays.  The tcl functions tk_mbUnpost, tk_nextMenu, and
tk_nextMenuEntry all need to take an argument so they can figure out
which display to work on. 

Another unrelated fix I made to Tk and Tcl was to put the TK_LIBRARY
and TCL_LIBRARY strings into global variables, and refer to those
variables instead of embeding strings in the code, so it's possible to
set them up properly before initializing, since I want to be able to
set a couple environment variables and run the application with no
installation.  Is there a more appropriate way to do this? 

	-Don

Here is the code for Tk_FocusCmd and TkFocusEventProc:


/*
 *--------------------------------------------------------------
 *
 * Tk_FocusCmd --
 *
 *	This procedure is invoked to process the "focus" Tcl command.
 *	See the user documentation for details on what it does.
 *
 * Results:
 *	A standard Tcl result.
 *
 * Side effects:
 *	See the user documentation.
 *
 *--------------------------------------------------------------
 */

int
Tk_FocusCmd(clientData, interp, argc, argv)
    ClientData clientData;	/* Main window associated with
				 * interpreter. */
    Tcl_Interp *interp;		/* Current interpreter. */
    int argc;			/* Number of arguments. */
    char **argv;		/* Argument strings. */
{
    Tk_Window tkwin = (Tk_Window) clientData;
    register TkWindow *winPtr = (TkWindow *) clientData;
    register TkWindow *newPtr;

    if (argc > 3) {
	focusSyntax:
	Tcl_AppendResult(interp, "too many args: should be \"",
		argv[0], " ?-query? ?window?\"", (char *) NULL);
	return TCL_ERROR;
    }

    if (argc == 1) {
	if (winPtr->dispPtr->focusPtr == NULL) {
	    interp->result = "none";
	} else {
	    interp->result = winPtr->dispPtr->focusPtr->pathName;
	}
	return TCL_OK;
    }

    if (argv[1][0] == '-') {
	int switchLength;

	switchLength = strlen(argv[1]);
	if ((switchLength >= 2)
		&& (strncmp(argv[1], "-query", switchLength) == 0)) {

	    if (argc != 3) {
		goto focusSyntax;
	    }

	    newPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin);
	    if (newPtr == NULL) {
		return TCL_ERROR;
	    }
	    if (newPtr->dispPtr->focusPtr == NULL) {
		interp->result = "none";
	    } else {
		interp->result = newPtr->dispPtr->focusPtr->pathName;
	    }
	    return TCL_OK;
	}
    }

    if (argc != 2) {
	goto focusSyntax;
    }

    if (strcmp(argv[1], "none") == 0) {
	newPtr = NULL;
    } else {
	newPtr = (TkWindow *) Tk_NameToWindow(interp, argv[1], tkwin);
	if (newPtr == NULL) {
	    return TCL_ERROR;
	}
    }
    if (newPtr->dispPtr->focusPtr == newPtr) {
	return TCL_OK;
    }
    if (winPtr == newPtr->dispPtr->mouseMainPtr) { /* XXX: ??? presumably */
	if ((newPtr->dispPtr->focusPtr != NULL)
		&& (newPtr->dispPtr->focusPtr->focusProc != NULL)) {
	    (*newPtr->dispPtr->focusPtr->focusProc)(
		    newPtr->dispPtr->focusPtr->focusData, 0);
	}
	newPtr->dispPtr->focusPtr = newPtr;
	if ((newPtr != NULL) && (newPtr->focusProc != NULL)) {
	    (*newPtr->focusProc)(newPtr->focusData, 1);
	}
    } else {
	newPtr->dispPtr->focusPtr = newPtr;
    }
    return TCL_OK;
}

/*
 *--------------------------------------------------------------
 *
 * TkFocusEventProc --
 *
 *	This procedure is invoked whenever the pointer enters
 *	or leaves a top-level window.  It notifies the current
 *	owner of the focus, if any.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */

void
TkFocusEventProc(winPtr, eventPtr)
    register TkWindow *winPtr;	/* Top-level window just entered or left. */
    XEvent *eventPtr;		/* EnterWindow or LeaveWindow event. */
{
    register TkWindow *focusPtr;
    TkWindow *newMouseMainPtr = NULL;

    if (eventPtr->type == EnterNotify) {
	newMouseMainPtr = winPtr->mainPtr->winPtr;
    }
    if (winPtr->dispPtr->mouseMainPtr == newMouseMainPtr) {
	return;
    }
    if (winPtr->dispPtr->mouseMainPtr != NULL) {
	focusPtr = winPtr->dispPtr->focusPtr;
	if ((focusPtr != NULL)
		&& (focusPtr->focusProc != NULL)) {
	    (*focusPtr->focusProc)(focusPtr->focusData, 0);
	}
    }
    winPtr->dispPtr->mouseMainPtr = newMouseMainPtr;
    if (newMouseMainPtr != NULL) {
	focusPtr = newMouseMainPtr->dispPtr->focusPtr;
	if ((focusPtr != NULL)
		&& (focusPtr->focusProc != NULL)) {
	    (*focusPtr->focusProc)(focusPtr->focusData, 1);
	}
    }
}
