1 To: ouster@sprite.berkeley.edu
3 Subject: more multiple display stuff
4 --text follows this line--
5 A problem I fixed is that the "focus" command only returns the focus
6 of the main window's display, and there's no way to find out the focus
7 on other displays. I fixed this by adding a "focus -query .window"
8 form, that returns the focus of the display of the named window. When
9 the tcl menu tracking code supports multiple displays, it will need to
10 use this form to save the focus of the appropriate display before
13 A problem I haven't fixed yet is with the "selection" command, which
14 right now will only retrieve the selection from the display of the
15 main window. Pasting into a text field on another display with ^V
16 inserts the selection from the main display. It could be changed to
17 take a window argument similar to "focus".
19 I wish I could think of a better flag name than "-query"...
21 I had a go at hacking the Tk C code to keep track of one focus per
22 display instead of per main window. (Should I be using one main
23 window per display? I'm not now, I'm just creating remote toplevels
24 with the -screen argument.) I moved the "struct TkWindow *focusPtr;"
25 from the TkMainInfo to the TkDisplay structure, and modified the code
26 in tkEvent.c that handled it and tkWindow.c that initialized it.
28 In tkEvent.c, I changed 3 "winPtr->mainPtr->focusPtr"'s to
29 "winPtr->dispPtr->focusPtr", in Tk_HandleEvent and TkEventDeadWindow.
30 I worked over Tk_FocusCmd and TkFocusEventProc, included below.
31 I'm not sure what the "winPtr == winPtr->dispPtr->mouseMainPtr" test
32 at the end of Tk_FocusCmd really intends, but the transformation was
33 pretty straightforward, and it seems to work for my cases.
35 I've looked at the tcl code to try to figure out how to make it track
36 properly with multiple displays. I think I'll need a function that
37 given the name of a window, returns a unique string describing the
38 display, that I can use to make tk_priv keys that distinguish between
39 displays. The tcl functions tk_mbUnpost, tk_nextMenu, and
40 tk_nextMenuEntry all need to take an argument so they can figure out
41 which display to work on.
43 Another unrelated fix I made to Tk and Tcl was to put the TK_LIBRARY
44 and TCL_LIBRARY strings into global variables, and refer to those
45 variables instead of embeding strings in the code, so it's possible to
46 set them up properly before initializing, since I want to be able to
47 set a couple environment variables and run the application with no
48 installation. Is there a more appropriate way to do this?
52 Here is the code for Tk_FocusCmd and TkFocusEventProc:
56 *--------------------------------------------------------------
60 * This procedure is invoked to process the "focus" Tcl command.
61 * See the user documentation for details on what it does.
64 * A standard Tcl result.
67 * See the user documentation.
69 *--------------------------------------------------------------
73 Tk_FocusCmd(clientData, interp, argc, argv)
74 ClientData clientData; /* Main window associated with
76 Tcl_Interp *interp; /* Current interpreter. */
77 int argc; /* Number of arguments. */
78 char **argv; /* Argument strings. */
80 Tk_Window tkwin = (Tk_Window) clientData;
81 register TkWindow *winPtr = (TkWindow *) clientData;
82 register TkWindow *newPtr;
86 Tcl_AppendResult(interp, "too many args: should be \"",
87 argv[0], " ?-query? ?window?\"", (char *) NULL);
92 if (winPtr->dispPtr->focusPtr == NULL) {
93 interp->result = "none";
95 interp->result = winPtr->dispPtr->focusPtr->pathName;
100 if (argv[1][0] == '-') {
103 switchLength = strlen(argv[1]);
104 if ((switchLength >= 2)
105 && (strncmp(argv[1], "-query", switchLength) == 0)) {
111 newPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin);
112 if (newPtr == NULL) {
115 if (newPtr->dispPtr->focusPtr == NULL) {
116 interp->result = "none";
118 interp->result = newPtr->dispPtr->focusPtr->pathName;
128 if (strcmp(argv[1], "none") == 0) {
131 newPtr = (TkWindow *) Tk_NameToWindow(interp, argv[1], tkwin);
132 if (newPtr == NULL) {
136 if (newPtr->dispPtr->focusPtr == newPtr) {
139 if (winPtr == newPtr->dispPtr->mouseMainPtr) { /* XXX: ??? presumably */
140 if ((newPtr->dispPtr->focusPtr != NULL)
141 && (newPtr->dispPtr->focusPtr->focusProc != NULL)) {
142 (*newPtr->dispPtr->focusPtr->focusProc)(
143 newPtr->dispPtr->focusPtr->focusData, 0);
145 newPtr->dispPtr->focusPtr = newPtr;
146 if ((newPtr != NULL) && (newPtr->focusProc != NULL)) {
147 (*newPtr->focusProc)(newPtr->focusData, 1);
150 newPtr->dispPtr->focusPtr = newPtr;
156 *--------------------------------------------------------------
158 * TkFocusEventProc --
160 * This procedure is invoked whenever the pointer enters
161 * or leaves a top-level window. It notifies the current
162 * owner of the focus, if any.
170 *--------------------------------------------------------------
174 TkFocusEventProc(winPtr, eventPtr)
175 register TkWindow *winPtr; /* Top-level window just entered or left. */
176 XEvent *eventPtr; /* EnterWindow or LeaveWindow event. */
178 register TkWindow *focusPtr;
179 TkWindow *newMouseMainPtr = NULL;
181 if (eventPtr->type == EnterNotify) {
182 newMouseMainPtr = winPtr->mainPtr->winPtr;
184 if (winPtr->dispPtr->mouseMainPtr == newMouseMainPtr) {
187 if (winPtr->dispPtr->mouseMainPtr != NULL) {
188 focusPtr = winPtr->dispPtr->focusPtr;
189 if ((focusPtr != NULL)
190 && (focusPtr->focusProc != NULL)) {
191 (*focusPtr->focusProc)(focusPtr->focusData, 0);
194 winPtr->dispPtr->mouseMainPtr = newMouseMainPtr;
195 if (newMouseMainPtr != NULL) {
196 focusPtr = newMouseMainPtr->dispPtr->focusPtr;
197 if ((focusPtr != NULL)
198 && (focusPtr->focusProc != NULL)) {
199 (*focusPtr->focusProc)(focusPtr->focusData, 1);