1/*
2 * tkFocus.c --
3 *
4 *	This file contains functions that manage the input focus for Tk.
5 *
6 * Copyright (c) 1990-1994 The Regents of the University of California.
7 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
8 *
9 * See the file "license.terms" for information on usage and redistribution of
10 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 *
12 * RCS: @(#) $Id$
13 */
14
15#include "tkInt.h"
16
17/*
18 * For each top-level window that has ever received the focus, there is a
19 * record of the following type:
20 */
21
22typedef struct TkToplevelFocusInfo {
23    TkWindow *topLevelPtr;	/* Information about top-level window. */
24    TkWindow *focusWinPtr;	/* The next time the focus comes to this
25				 * top-level, it will be given to this
26				 * window. */
27    struct TkToplevelFocusInfo *nextPtr;
28				/* Next in list of all toplevel focus records
29				 * for a given application. */
30} ToplevelFocusInfo;
31
32/*
33 * One of the following structures exists for each display used by each
34 * application. These are linked together from the TkMainInfo structure.
35 * These structures are needed because it isn't sufficient to store a single
36 * piece of focus information in each display or in each application: we need
37 * the cross-product. There needs to be separate information for each display,
38 * because it's possible to have multiple focus windows active simultaneously
39 * on different displays. There also needs to be separate information for each
40 * application, because of embedding: if an embedded application has the
41 * focus, its container application also has the focus. Thus we keep a list of
42 * structures for each application: the same display can appear in structures
43 * for several applications at once.
44 */
45
46typedef struct TkDisplayFocusInfo {
47    TkDisplay *dispPtr;		/* Display that this information pertains
48				 * to. */
49    struct TkWindow *focusWinPtr;
50				/* Window that currently has the focus for
51				 * this application on this display, or NULL
52				 * if none. */
53    struct TkWindow *focusOnMapPtr;
54				/* This points to a toplevel window that is
55				 * supposed to receive the X input focus as
56				 * soon as it is mapped (needed to handle the
57				 * fact that X won't allow the focus on an
58				 * unmapped window). NULL means no delayed
59				 * focus op in progress for this display. */
60    int forceFocus;		/* Associated with focusOnMapPtr: non-zero
61				 * means claim the focus even if some other
62				 * application currently has it. */
63    unsigned long focusSerial;	/* Serial number of last request this
64				 * application made to change the focus on
65				 * this display. Used to identify stale focus
66				 * notifications coming from the X server. */
67    struct TkDisplayFocusInfo *nextPtr;
68				/* Next in list of all display focus records
69				 * for a given application. */
70} DisplayFocusInfo;
71
72/*
73 * The following magic value is stored in the "send_event" field of FocusIn
74 * and FocusOut events that are generated in this file. This allows us to
75 * separate "real" events coming from the server from those that we generated.
76 */
77
78#define GENERATED_EVENT_MAGIC	((Bool) 0x547321ac)
79
80/*
81 * Debugging support...
82 */
83
84#define DEBUG(dispPtr, arguments) \
85    if ((dispPtr)->focusDebug) { \
86	printf arguments; \
87    }
88
89/*
90 * Forward declarations for functions defined in this file:
91 */
92
93static DisplayFocusInfo*FindDisplayFocusInfo(TkMainInfo *mainPtr,
94			    TkDisplay *dispPtr);
95static void		FocusMapProc(ClientData clientData, XEvent *eventPtr);
96static void		GenerateFocusEvents(TkWindow *sourcePtr,
97			    TkWindow *destPtr);
98
99/*
100 *--------------------------------------------------------------
101 *
102 * Tk_FocusObjCmd --
103 *
104 *	This function is invoked to process the "focus" Tcl command. See the
105 *	user documentation for details on what it does.
106 *
107 * Results:
108 *	A standard Tcl result.
109 *
110 * Side effects:
111 *	See the user documentation.
112 *
113 *--------------------------------------------------------------
114 */
115
116int
117Tk_FocusObjCmd(
118    ClientData clientData,	/* Main window associated with interpreter. */
119    Tcl_Interp *interp,		/* Current interpreter. */
120    int objc,			/* Number of arguments. */
121    Tcl_Obj *CONST objv[])	/* Argument objects. */
122{
123    static CONST char *focusOptions[] = {
124	"-displayof", "-force", "-lastfor", NULL
125    };
126    Tk_Window tkwin = (Tk_Window) clientData;
127    TkWindow *winPtr = (TkWindow *) clientData;
128    TkWindow *newPtr, *focusWinPtr, *topLevelPtr;
129    ToplevelFocusInfo *tlFocusPtr;
130    char *windowName;
131    int index;
132
133    /*
134     * If invoked with no arguments, just return the current focus window.
135     */
136
137    if (objc == 1) {
138	focusWinPtr = TkGetFocusWin(winPtr);
139	if (focusWinPtr != NULL) {
140	    Tcl_SetResult(interp, focusWinPtr->pathName, TCL_STATIC);
141	}
142	return TCL_OK;
143    }
144
145    /*
146     * If invoked with a single argument beginning with "." then focus on that
147     * window.
148     */
149
150    if (objc == 2) {
151	windowName = Tcl_GetString(objv[1]);
152
153	/*
154	 * The empty string case exists for backwards compatibility.
155	 */
156
157	if (windowName[0] == '\0') {
158	    return TCL_OK;
159	}
160	if (windowName[0] == '.') {
161	    newPtr = (TkWindow *) Tk_NameToWindow(interp, windowName, tkwin);
162	    if (newPtr == NULL) {
163		return TCL_ERROR;
164	    }
165	    if (!(newPtr->flags & TK_ALREADY_DEAD)) {
166		TkSetFocusWin(newPtr, 0);
167	    }
168	    return TCL_OK;
169	}
170    }
171
172    /*
173     * We have a subcommand to parse and act upon.
174     */
175
176    if (Tcl_GetIndexFromObj(interp, objv[1], focusOptions, "option", 0,
177	    &index) != TCL_OK) {
178    	return TCL_ERROR;
179    }
180    if (objc != 3) {
181	Tcl_WrongNumArgs(interp, 2, objv, "window");
182	return TCL_ERROR;
183    }
184    switch (index) {
185    case 0:			/* -displayof */
186	windowName = Tcl_GetString(objv[2]);
187	newPtr = (TkWindow *) Tk_NameToWindow(interp, windowName, tkwin);
188	if (newPtr == NULL) {
189	    return TCL_ERROR;
190	}
191	newPtr = TkGetFocusWin(newPtr);
192	if (newPtr != NULL) {
193	    Tcl_SetResult(interp, newPtr->pathName, TCL_STATIC);
194	}
195	break;
196    case 1:			/* -force */
197	windowName = Tcl_GetString(objv[2]);
198
199	/*
200	 * The empty string case exists for backwards compatibility.
201	 */
202
203	if (windowName[0] == '\0') {
204	    return TCL_OK;
205	}
206	newPtr = (TkWindow *) Tk_NameToWindow(interp, windowName, tkwin);
207	if (newPtr == NULL) {
208	    return TCL_ERROR;
209	}
210	TkSetFocusWin(newPtr, 1);
211	break;
212    case 2:			/* -lastfor */
213	windowName = Tcl_GetString(objv[2]);
214	newPtr = (TkWindow *) Tk_NameToWindow(interp, windowName, tkwin);
215	if (newPtr == NULL) {
216	    return TCL_ERROR;
217	}
218	for (topLevelPtr = newPtr; topLevelPtr != NULL;
219		topLevelPtr = topLevelPtr->parentPtr)  {
220	    if (!(topLevelPtr->flags & TK_TOP_HIERARCHY)) {
221		continue;
222	    }
223	    for (tlFocusPtr = newPtr->mainPtr->tlFocusPtr; tlFocusPtr != NULL;
224		    tlFocusPtr = tlFocusPtr->nextPtr) {
225		if (tlFocusPtr->topLevelPtr == topLevelPtr) {
226		    Tcl_SetResult(interp,
227			    tlFocusPtr->focusWinPtr->pathName, TCL_STATIC);
228		    return TCL_OK;
229		}
230	    }
231	    Tcl_SetResult(interp, topLevelPtr->pathName, TCL_STATIC);
232	    return TCL_OK;
233	}
234	break;
235    default:
236	Tcl_Panic("bad const entries to focusOptions in focus command");
237    }
238    return TCL_OK;
239}
240
241/*
242 *--------------------------------------------------------------
243 *
244 * TkFocusFilterEvent --
245 *
246 *	This function is invoked by Tk_HandleEvent when it encounters a
247 *	FocusIn, FocusOut, Enter, or Leave event.
248 *
249 * Results:
250 *	A return value of 1 means that Tk_HandleEvent should process the event
251 *	normally (i.e. event handlers should be invoked). A return value of 0
252 *	means that this event should be ignored.
253 *
254 * Side effects:
255 *	Additional events may be generated, and the focus may switch.
256 *
257 *--------------------------------------------------------------
258 */
259
260int
261TkFocusFilterEvent(
262    TkWindow *winPtr,		/* Window that focus event is directed to. */
263    XEvent *eventPtr)		/* FocusIn, FocusOut, Enter, or Leave
264				 * event. */
265{
266    /*
267     * Design notes: the window manager and X server work together to transfer
268     * the focus among top-level windows. This function takes care of
269     * transferring the focus from a top-level or wrapper window to the actual
270     * window within that top-level that has the focus. We do this by
271     * synthesizing X events to move the focus around. None of the FocusIn and
272     * FocusOut events generated by X are ever used outside of this function;
273     * only the synthesized events get through to the rest of the application.
274     * At one point (e.g. Tk4.0b1) Tk used to call X to move the focus from a
275     * top-level to one of its descendants, then just pass through the events
276     * generated by X. This approach didn't work very well, for a variety of
277     * reasons. For example, if X generates the events they go at the back of
278     * the event queue, which could cause problems if other things have
279     * already happened, such as moving the focus to yet another window.
280     */
281
282    ToplevelFocusInfo *tlFocusPtr;
283    DisplayFocusInfo *displayFocusPtr;
284    TkDisplay *dispPtr = winPtr->dispPtr;
285    TkWindow *newFocusPtr;
286    int retValue, delta;
287
288    /*
289     * If this was a generated event, just turn off the generated flag and
290     * pass the event through to Tk bindings.
291     */
292
293    if (eventPtr->xfocus.send_event == GENERATED_EVENT_MAGIC) {
294	eventPtr->xfocus.send_event = 0;
295	return 1;
296    }
297
298    /*
299     * Check for special events generated by embedded applications to request
300     * the input focus. If this is one of those events, make the change in
301     * focus and return without any additional processing of the event (note:
302     * the "detail" field of the event indicates whether to claim the focus
303     * even if we don't already have it).
304     */
305
306    if ((eventPtr->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS)
307	    && (eventPtr->type == FocusIn)) {
308	TkSetFocusWin(winPtr, eventPtr->xfocus.detail);
309	return 0;
310    }
311
312    /*
313     * This was not a generated event. We'll return 1 (so that the event will
314     * be processed) if it's an Enter or Leave event, and 0 (so that the event
315     * won't be processed) if it's a FocusIn or FocusOut event.
316     */
317
318    retValue = 0;
319    displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr);
320    if (eventPtr->type == FocusIn) {
321	/*
322	 * Skip FocusIn events that cause confusion
323	 * NotifyVirtual and NotifyNonlinearVirtual - Virtual events occur on
324	 *	windows in between the origin and destination of the focus
325	 *	change. For FocusIn we may see this when focus goes into an
326	 *	embedded child. We don't care about this, although we may end
327	 *	up getting a NotifyPointer later.
328	 * NotifyInferior - focus is coming to us from an embedded child. When
329	 *	focus is on an embeded focus, we still think we have the
330	 *	focus, too, so this message doesn't change our state.
331	 * NotifyPointerRoot - should never happen because this is sent to the
332	 *	root window.
333	 *
334	 * Interesting FocusIn events are
335	 * NotifyAncestor - focus is coming from our parent, probably the root.
336	 * NotifyNonlinear - focus is coming from a different branch, probably
337	 *	another toplevel.
338	 * NotifyPointer - implicit focus because of the mouse position. This
339	 *	is only interesting on toplevels, when it means that the focus
340	 *	has been set to the root window but the mouse is over this
341	 *	toplevel. We take the focus implicitly (probably no window
342	 *	manager)
343	 */
344
345	if ((eventPtr->xfocus.detail == NotifyVirtual)
346		|| (eventPtr->xfocus.detail == NotifyNonlinearVirtual)
347		|| (eventPtr->xfocus.detail == NotifyPointerRoot)
348		|| (eventPtr->xfocus.detail == NotifyInferior)) {
349	    return retValue;
350	}
351    } else if (eventPtr->type == FocusOut) {
352	/*
353	 * Skip FocusOut events that cause confusion.
354	 * NotifyPointer - the pointer is in us or a child, and we are losing
355	 *	focus because of an XSetInputFocus. Other focus events will
356	 *	set our state properly.
357	 * NotifyPointerRoot - should never happen because this is sent to the
358	 *	root window.
359	 * NotifyInferior - focus leaving us for an embedded child. We retain
360	 *	a notion of focus when an embedded child has focus.
361	 *
362	 * Interesting events are:
363	 * NotifyAncestor - focus is going to root.
364	 * NotifyNonlinear - focus is going to another branch, probably
365	 *	another toplevel.
366	 * NotifyVirtual, NotifyNonlinearVirtual - focus is passing through,
367	 *	and we need to make sure we track this.
368	 */
369
370	if ((eventPtr->xfocus.detail == NotifyPointer)
371		|| (eventPtr->xfocus.detail == NotifyPointerRoot)
372		|| (eventPtr->xfocus.detail == NotifyInferior)) {
373	    return retValue;
374	}
375    } else {
376	retValue = 1;
377	if (eventPtr->xcrossing.detail == NotifyInferior) {
378	    return retValue;
379	}
380    }
381
382    /*
383     * If winPtr isn't a top-level window than just ignore the event.
384     */
385
386    winPtr = TkWmFocusToplevel(winPtr);
387    if (winPtr == NULL) {
388	return retValue;
389    }
390
391    /*
392     * If there is a grab in effect and this window is outside the grabbed
393     * tree, then ignore the event.
394     */
395
396    if (TkGrabState(winPtr) == TK_GRAB_EXCLUDED)  {
397	return retValue;
398    }
399
400    /*
401     * It is possible that there were outstanding FocusIn and FocusOut events
402     * on their way to us at the time the focus was changed internally with
403     * the "focus" command. If so, these events could potentially cause us to
404     * lose the focus (switch it to the window of the last FocusIn event) even
405     * though the focus change occurred after those events. The following code
406     * detects this and ignores the stale events.
407     *
408     * Note: the focusSerial is only generated by TkpChangeFocus, whereas in
409     * Tk 4.2 there was always a nop marker generated.
410     */
411
412    delta = eventPtr->xfocus.serial - displayFocusPtr->focusSerial;
413    if (delta < 0) {
414	return retValue;
415    }
416
417    /*
418     * Find the ToplevelFocusInfo structure for the window, and make a new one
419     * if there isn't one already.
420     */
421
422    for (tlFocusPtr = winPtr->mainPtr->tlFocusPtr; tlFocusPtr != NULL;
423	    tlFocusPtr = tlFocusPtr->nextPtr) {
424	if (tlFocusPtr->topLevelPtr == winPtr) {
425	    break;
426	}
427    }
428    if (tlFocusPtr == NULL) {
429	tlFocusPtr = (ToplevelFocusInfo *) ckalloc(sizeof(ToplevelFocusInfo));
430	tlFocusPtr->topLevelPtr = tlFocusPtr->focusWinPtr = winPtr;
431	tlFocusPtr->nextPtr = winPtr->mainPtr->tlFocusPtr;
432	winPtr->mainPtr->tlFocusPtr = tlFocusPtr;
433    }
434    newFocusPtr = tlFocusPtr->focusWinPtr;
435
436    /*
437     * Ignore event if newFocus window is already dead!
438     */
439
440    if (newFocusPtr->flags & TK_ALREADY_DEAD) {
441	return retValue;
442    }
443
444    if (eventPtr->type == FocusIn) {
445	GenerateFocusEvents(displayFocusPtr->focusWinPtr, newFocusPtr);
446	displayFocusPtr->focusWinPtr = newFocusPtr;
447	dispPtr->focusPtr = newFocusPtr;
448
449	/*
450	 * NotifyPointer gets set when the focus has been set to the root
451	 * window but we have the pointer. We'll treat this like an implicit
452	 * focus in event so that upon Leave events we release focus.
453	 */
454
455	if (!(winPtr->flags & TK_EMBEDDED)) {
456	    if (eventPtr->xfocus.detail == NotifyPointer) {
457		dispPtr->implicitWinPtr = winPtr;
458	    } else {
459		dispPtr->implicitWinPtr = NULL;
460	    }
461	}
462    } else if (eventPtr->type == FocusOut) {
463	GenerateFocusEvents(displayFocusPtr->focusWinPtr, NULL);
464
465	/*
466	 * Reset dispPtr->focusPtr, but only if it currently is the same as
467	 * this application's focusWinPtr: this check is needed to handle
468	 * embedded applications in the same process.
469	 */
470
471	if (dispPtr->focusPtr == displayFocusPtr->focusWinPtr) {
472	    dispPtr->focusPtr = NULL;
473	}
474	displayFocusPtr->focusWinPtr = NULL;
475    } else if (eventPtr->type == EnterNotify) {
476	/*
477	 * If there is no window manager, or if the window manager isn't
478	 * moving the focus around (e.g. the disgusting "NoTitleFocus" option
479	 * has been selected in twm), then we won't get FocusIn or FocusOut
480	 * events. Instead, the "focus" field will be set in an Enter event to
481	 * indicate that we've already got the focus when the mouse enters the
482	 * window (even though we didn't get a FocusIn event). Watch for this
483	 * and grab the focus when it happens. Note: if this is an embedded
484	 * application then don't accept the focus implicitly like this; the
485	 * container application will give us the focus explicitly if it wants
486	 * us to have it.
487	 */
488
489	if (eventPtr->xcrossing.focus &&
490		(displayFocusPtr->focusWinPtr == NULL)
491		&& !(winPtr->flags & TK_EMBEDDED)) {
492	    DEBUG(dispPtr,
493		    ("Focussed implicitly on %s\n", newFocusPtr->pathName));
494
495	    GenerateFocusEvents(displayFocusPtr->focusWinPtr, newFocusPtr);
496	    displayFocusPtr->focusWinPtr = newFocusPtr;
497	    dispPtr->implicitWinPtr = winPtr;
498	    dispPtr->focusPtr = newFocusPtr;
499	}
500    } else if (eventPtr->type == LeaveNotify) {
501	/*
502	 * If the pointer just left a window for which we automatically
503	 * claimed the focus on enter, move the focus back to the root
504	 * window, where it was before we claimed it above. Note:
505	 * dispPtr->implicitWinPtr may not be the same as
506	 * displayFocusPtr->focusWinPtr (e.g. because the "focus" command
507	 * was used to redirect the focus after it arrived at
508	 * dispPtr->implicitWinPtr)!! In addition, we generate events
509	 * because the window manager won't give us a FocusOut event when
510	 * we focus on the root.
511	 */
512
513	if ((dispPtr->implicitWinPtr != NULL)
514		&& !(winPtr->flags & TK_EMBEDDED)) {
515	    DEBUG(dispPtr, ("Defocussed implicit Async\n"));
516	    GenerateFocusEvents(displayFocusPtr->focusWinPtr, NULL);
517	    XSetInputFocus(dispPtr->display, PointerRoot, RevertToPointerRoot,
518		    CurrentTime);
519	    displayFocusPtr->focusWinPtr = NULL;
520	    dispPtr->implicitWinPtr = NULL;
521	}
522    }
523    return retValue;
524}
525
526/*
527 *----------------------------------------------------------------------
528 *
529 * TkSetFocusWin --
530 *
531 *	This function is invoked to change the focus window for a given
532 *	display in a given application.
533 *
534 * Results:
535 *	None.
536 *
537 * Side effects:
538 *	Event handlers may be invoked to process the change of
539 *	focus.
540 *
541 *----------------------------------------------------------------------
542 */
543
544void
545TkSetFocusWin(
546    TkWindow *winPtr,		/* Window that is to be the new focus for its
547				 * display and application. */
548    int force)			/* If non-zero, set the X focus to this window
549				 * even if the application doesn't currently
550				 * have the X focus. */
551{
552    ToplevelFocusInfo *tlFocusPtr;
553    DisplayFocusInfo *displayFocusPtr;
554    TkWindow *topLevelPtr;
555    int allMapped, serial;
556
557    displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr);
558
559    /*
560     * If force is set, we should make sure we grab the focus regardless of
561     * the current focus window since under Windows, we may need to take
562     * control away from another application.
563     */
564
565    if (winPtr == displayFocusPtr->focusWinPtr && !force) {
566	return;
567    }
568
569    /*
570     * Find the top-level window for winPtr, then find (or create) a record
571     * for the top-level. Also see whether winPtr and all its ancestors are
572     * mapped.
573     */
574
575    allMapped = 1;
576    for (topLevelPtr = winPtr; ; topLevelPtr = topLevelPtr->parentPtr)  {
577	if (topLevelPtr == NULL) {
578	    /*
579	     * The window is being deleted. No point in worrying about giving
580	     * it the focus.
581	     */
582
583	    return;
584	}
585	if (!(topLevelPtr->flags & TK_MAPPED)) {
586	    allMapped = 0;
587	}
588	if (topLevelPtr->flags & TK_TOP_HIERARCHY) {
589	    break;
590	}
591    }
592
593    /*
594     * If the new focus window isn't mapped, then we can't focus on it (X will
595     * generate an error, for example). Instead, create an event handler that
596     * will set the focus to this window once it gets mapped. At the same
597     * time, delete any old handler that might be around; it's no longer
598     * relevant.
599     */
600
601    if (displayFocusPtr->focusOnMapPtr != NULL) {
602	Tk_DeleteEventHandler(
603		(Tk_Window) displayFocusPtr->focusOnMapPtr,
604		StructureNotifyMask, FocusMapProc,
605		(ClientData) displayFocusPtr->focusOnMapPtr);
606	displayFocusPtr->focusOnMapPtr = NULL;
607    }
608    if (!allMapped) {
609	Tk_CreateEventHandler((Tk_Window) winPtr,
610		VisibilityChangeMask, FocusMapProc,
611		(ClientData) winPtr);
612	displayFocusPtr->focusOnMapPtr = winPtr;
613	displayFocusPtr->forceFocus = force;
614	return;
615    }
616
617    for (tlFocusPtr = winPtr->mainPtr->tlFocusPtr; tlFocusPtr != NULL;
618	    tlFocusPtr = tlFocusPtr->nextPtr) {
619	if (tlFocusPtr->topLevelPtr == topLevelPtr) {
620	    break;
621	}
622    }
623    if (tlFocusPtr == NULL) {
624	tlFocusPtr = (ToplevelFocusInfo *) ckalloc(sizeof(ToplevelFocusInfo));
625	tlFocusPtr->topLevelPtr = topLevelPtr;
626	tlFocusPtr->nextPtr = winPtr->mainPtr->tlFocusPtr;
627	winPtr->mainPtr->tlFocusPtr = tlFocusPtr;
628    }
629    tlFocusPtr->focusWinPtr = winPtr;
630
631    /*
632     * Reset the window system's focus window and generate focus events, with
633     * two special cases:
634     *
635     * 1. If the application is embedded and doesn't currently have the focus,
636     *    don't set the focus directly. Instead, see if the embedding code can
637     *    claim the focus from the enclosing container.
638     * 2. Otherwise, if the application doesn't currently have the focus,
639     *    don't change the window system's focus unless it was already in this
640     *    application or "force" was specified.
641     */
642
643    if ((topLevelPtr->flags & TK_EMBEDDED)
644	    && (displayFocusPtr->focusWinPtr == NULL)) {
645	TkpClaimFocus(topLevelPtr, force);
646    } else if ((displayFocusPtr->focusWinPtr != NULL) || force) {
647	/*
648	 * Generate events to shift focus between Tk windows. We do this
649	 * regardless of what TkpChangeFocus does with the real X focus so
650	 * that Tk widgets track focus commands when there is no window
651	 * manager. GenerateFocusEvents will set up a serial number marker so
652	 * we discard focus events that are triggered by the ChangeFocus.
653	 */
654
655	serial = TkpChangeFocus(TkpGetWrapperWindow(topLevelPtr), force);
656	if (serial != 0) {
657	    displayFocusPtr->focusSerial = serial;
658	}
659	GenerateFocusEvents(displayFocusPtr->focusWinPtr, winPtr);
660	displayFocusPtr->focusWinPtr = winPtr;
661	winPtr->dispPtr->focusPtr = winPtr;
662    }
663}
664
665/*
666 *----------------------------------------------------------------------
667 *
668 * TkGetFocusWin --
669 *
670 *	Given a window, this function returns the current focus window for its
671 *	application and display.
672 *
673 * Results:
674 *	The return value is a pointer to the window that currently has the
675 *	input focus for the specified application and display, or NULL if
676 *	none.
677 *
678 * Side effects:
679 *	None.
680 *
681 *----------------------------------------------------------------------
682 */
683
684TkWindow *
685TkGetFocusWin(
686    TkWindow *winPtr)		/* Window that selects an application and a
687				 * display. */
688{
689    DisplayFocusInfo *displayFocusPtr;
690
691    if (winPtr == NULL) {
692	return NULL;
693    }
694
695    displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr);
696    return displayFocusPtr->focusWinPtr;
697}
698
699/*
700 *----------------------------------------------------------------------
701 *
702 * TkFocusKeyEvent --
703 *
704 *	Given a window and a key press or release event that arrived for the
705 *	window, use information about the keyboard focus to compute which
706 *	window should really get the event. In addition, update the event to
707 *	refer to its new window.
708 *
709 * Results:
710 *	The return value is a pointer to the window that has the input focus
711 *	in winPtr's application, or NULL if winPtr's application doesn't have
712 *	the input focus. If a non-NULL value is returned, eventPtr will be
713 *	updated to refer properly to the focus window.
714 *
715 * Side effects:
716 *	None.
717 *
718 *----------------------------------------------------------------------
719 */
720
721TkWindow *
722TkFocusKeyEvent(
723    TkWindow *winPtr,		/* Window that selects an application and a
724				 * display. */
725    XEvent *eventPtr)		/* X event to redirect (should be KeyPress or
726				 * KeyRelease). */
727{
728    DisplayFocusInfo *displayFocusPtr;
729    TkWindow *focusWinPtr;
730    int focusX, focusY, vRootX, vRootY, vRootWidth, vRootHeight;
731
732    displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr);
733    focusWinPtr = displayFocusPtr->focusWinPtr;
734
735    /*
736     * The code below is a debugging aid to make sure that dispPtr->focusPtr
737     * is kept properly in sync with the "truth", which is the value in
738     * displayFocusPtr->focusWinPtr.
739     */
740
741#ifdef TCL_MEM_DEBUG
742    if (focusWinPtr != winPtr->dispPtr->focusPtr) {
743	printf("TkFocusKeyEvent found dispPtr->focusPtr out of sync:\n");
744	printf("expected %s, got %s\n",
745		(focusWinPtr != NULL) ? focusWinPtr->pathName : "??",
746		(winPtr->dispPtr->focusPtr != NULL) ?
747		winPtr->dispPtr->focusPtr->pathName : "??");
748    }
749#endif
750
751    if ((focusWinPtr != NULL) && (focusWinPtr->mainPtr == winPtr->mainPtr)) {
752	/*
753	 * Map the x and y coordinates to make sense in the context of the
754	 * focus window, if possible (make both -1 if the map-from and map-to
755	 * windows don't share the same screen).
756	 */
757
758	if ((focusWinPtr->display != winPtr->display)
759		|| (focusWinPtr->screenNum != winPtr->screenNum)) {
760	    eventPtr->xkey.x = -1;
761	    eventPtr->xkey.y = -1;
762	} else {
763	    Tk_GetVRootGeometry((Tk_Window) focusWinPtr, &vRootX, &vRootY,
764		    &vRootWidth, &vRootHeight);
765	    Tk_GetRootCoords((Tk_Window) focusWinPtr, &focusX, &focusY);
766	    eventPtr->xkey.x = eventPtr->xkey.x_root - vRootX - focusX;
767	    eventPtr->xkey.y = eventPtr->xkey.y_root - vRootY - focusY;
768	}
769	eventPtr->xkey.window = focusWinPtr->window;
770	return focusWinPtr;
771    }
772
773    /*
774     * The event doesn't belong to us. Perhaps, due to embedding, it really
775     * belongs to someone else. Give the embedding code a chance to redirect
776     * the event.
777     */
778
779    TkpRedirectKeyEvent(winPtr, eventPtr);
780    return NULL;
781}
782
783/*
784 *----------------------------------------------------------------------
785 *
786 * TkFocusDeadWindow --
787 *
788 *	This function is invoked when it is determined that a window is dead.
789 *	It cleans up focus-related information about the window.
790 *
791 * Results:
792 *	None.
793 *
794 * Side effects:
795 *	Various things get cleaned up and recycled.
796 *
797 *----------------------------------------------------------------------
798 */
799
800void
801TkFocusDeadWindow(
802    register TkWindow *winPtr)	/* Information about the window that is being
803				 * deleted. */
804{
805    ToplevelFocusInfo *tlFocusPtr, *prevPtr;
806    DisplayFocusInfo *displayFocusPtr;
807    TkDisplay *dispPtr = winPtr->dispPtr;
808
809    /*
810     * Certain special windows like those used for send and clipboard have no
811     * mainPtr.
812     */
813
814    if (winPtr->mainPtr == NULL) {
815	return;
816    }
817
818    /*
819     * Search for focus records that refer to this window either as the
820     * top-level window or the current focus window.
821     */
822
823    displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr);
824    for (prevPtr = NULL, tlFocusPtr = winPtr->mainPtr->tlFocusPtr;
825	    tlFocusPtr != NULL;
826	    prevPtr = tlFocusPtr, tlFocusPtr = tlFocusPtr->nextPtr) {
827	if (winPtr == tlFocusPtr->topLevelPtr) {
828	    /*
829	     * The top-level window is the one being deleted: free the focus
830	     * record and release the focus back to PointerRoot if we acquired
831	     * it implicitly.
832	     */
833
834	    if (dispPtr->implicitWinPtr == winPtr) {
835		DEBUG(dispPtr, ("releasing focus to root after %s died\n",
836			tlFocusPtr->topLevelPtr->pathName));
837		dispPtr->implicitWinPtr = NULL;
838		displayFocusPtr->focusWinPtr = NULL;
839		dispPtr->focusPtr = NULL;
840	    }
841	    if (displayFocusPtr->focusWinPtr == tlFocusPtr->focusWinPtr) {
842		displayFocusPtr->focusWinPtr = NULL;
843		dispPtr->focusPtr = NULL;
844	    }
845	    if (prevPtr == NULL) {
846		winPtr->mainPtr->tlFocusPtr = tlFocusPtr->nextPtr;
847	    } else {
848		prevPtr->nextPtr = tlFocusPtr->nextPtr;
849	    }
850	    ckfree((char *) tlFocusPtr);
851	    break;
852	} else if (winPtr == tlFocusPtr->focusWinPtr) {
853	    /*
854	     * The deleted window had the focus for its top-level: move the
855	     * focus to the top-level itself.
856	     */
857
858	    tlFocusPtr->focusWinPtr = tlFocusPtr->topLevelPtr;
859	    if ((displayFocusPtr->focusWinPtr == winPtr)
860		    && !(tlFocusPtr->topLevelPtr->flags & TK_ALREADY_DEAD)) {
861		DEBUG(dispPtr, ("forwarding focus to %s after %s died\n",
862			tlFocusPtr->topLevelPtr->pathName, winPtr->pathName));
863		GenerateFocusEvents(displayFocusPtr->focusWinPtr,
864			tlFocusPtr->topLevelPtr);
865		displayFocusPtr->focusWinPtr = tlFocusPtr->topLevelPtr;
866		dispPtr->focusPtr = tlFocusPtr->topLevelPtr;
867	    }
868	    break;
869	}
870    }
871
872    /*
873     * Occasionally, things can become unsynchronized. Move them back into
874     * synch now. [Bug 2496114]
875     */
876
877    if (displayFocusPtr->focusWinPtr == winPtr) {
878	DEBUG(dispPtr, ("focus cleared after %s died\n", winPtr->pathName));
879	displayFocusPtr->focusWinPtr = NULL;
880    }
881
882    if (displayFocusPtr->focusOnMapPtr == winPtr) {
883	displayFocusPtr->focusOnMapPtr = NULL;
884    }
885}
886
887/*
888 *----------------------------------------------------------------------
889 *
890 * GenerateFocusEvents --
891 *
892 *	This function is called to create FocusIn and FocusOut events to move
893 *	the input focus from one window to another.
894 *
895 * Results:
896 *	None.
897 *
898 * Side effects:
899 *	FocusIn and FocusOut events are generated.
900 *
901 *----------------------------------------------------------------------
902 */
903
904static void
905GenerateFocusEvents(
906    TkWindow *sourcePtr,	/* Window that used to have the focus (may be
907				 * NULL). */
908    TkWindow *destPtr)		/* New window to have the focus (may be
909				 * NULL). */
910{
911    XEvent event;
912    TkWindow *winPtr;
913
914    winPtr = sourcePtr;
915    if (winPtr == NULL) {
916	winPtr = destPtr;
917	if (winPtr == NULL) {
918	    return;
919	}
920    }
921
922    event.xfocus.serial = LastKnownRequestProcessed(winPtr->display);
923    event.xfocus.send_event = GENERATED_EVENT_MAGIC;
924    event.xfocus.display = winPtr->display;
925    event.xfocus.mode = NotifyNormal;
926    TkInOutEvents(&event, sourcePtr, destPtr, FocusOut, FocusIn,
927	    TCL_QUEUE_MARK);
928}
929
930/*
931 *----------------------------------------------------------------------
932 *
933 * FocusMapProc --
934 *
935 *	This function is called as an event handler for VisibilityNotify
936 *	events, if a window receives the focus at a time when its toplevel
937 *	isn't mapped. The function is needed because X won't allow the focus
938 *	to be set to an unmapped window; we detect when the toplevel is mapped
939 *	and set the focus to it then.
940 *
941 * Results:
942 *	None.
943 *
944 * Side effects:
945 *	If this is a map event, the focus gets set to the toplevel given by
946 *	clientData.
947 *
948 *----------------------------------------------------------------------
949 */
950
951static void
952FocusMapProc(
953    ClientData clientData,	/* Toplevel window. */
954    XEvent *eventPtr)		/* Information about event. */
955{
956    TkWindow *winPtr = (TkWindow *) clientData;
957    DisplayFocusInfo *displayFocusPtr;
958
959    if (eventPtr->type == VisibilityNotify) {
960	displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr,
961		winPtr->dispPtr);
962	DEBUG(winPtr->dispPtr, ("auto-focussing on %s, force %d\n",
963		winPtr->pathName, displayFocusPtr->forceFocus));
964	Tk_DeleteEventHandler((Tk_Window) winPtr, VisibilityChangeMask,
965		FocusMapProc, clientData);
966	displayFocusPtr->focusOnMapPtr = NULL;
967	TkSetFocusWin(winPtr, displayFocusPtr->forceFocus);
968    }
969}
970
971/*
972 *----------------------------------------------------------------------
973 *
974 * FindDisplayFocusInfo --
975 *
976 *	Given an application and a display, this function locate the focus
977 *	record for that combination. If no such record exists, it creates a
978 *	new record and initializes it.
979 *
980 * Results:
981 *	The return value is a pointer to the record.
982 *
983 * Side effects:
984 *	A new record will be allocated if there wasn't one already.
985 *
986 *----------------------------------------------------------------------
987 */
988
989static DisplayFocusInfo *
990FindDisplayFocusInfo(
991    TkMainInfo *mainPtr,	/* Record that identifies a particular
992				 * application. */
993    TkDisplay *dispPtr)		/* Display whose focus information is
994				 * needed. */
995{
996    DisplayFocusInfo *displayFocusPtr;
997
998    for (displayFocusPtr = mainPtr->displayFocusPtr;
999	    displayFocusPtr != NULL;
1000	    displayFocusPtr = displayFocusPtr->nextPtr) {
1001	if (displayFocusPtr->dispPtr == dispPtr) {
1002	    return displayFocusPtr;
1003	}
1004    }
1005
1006    /*
1007     * The record doesn't exist yet. Make a new one.
1008     */
1009
1010    displayFocusPtr = (DisplayFocusInfo *) ckalloc(sizeof(DisplayFocusInfo));
1011    displayFocusPtr->dispPtr = dispPtr;
1012    displayFocusPtr->focusWinPtr = NULL;
1013    displayFocusPtr->focusOnMapPtr = NULL;
1014    displayFocusPtr->forceFocus = 0;
1015    displayFocusPtr->focusSerial = 0;
1016    displayFocusPtr->nextPtr = mainPtr->displayFocusPtr;
1017    mainPtr->displayFocusPtr = displayFocusPtr;
1018    return displayFocusPtr;
1019}
1020
1021/*
1022 *----------------------------------------------------------------------
1023 *
1024 * TkFocusFree --
1025 *
1026 *	Free resources associated with maintaining the focus.
1027 *
1028 * Results:
1029 *	None.
1030 *
1031 * Side effects:
1032 *	This mainPtr should no long access focus information.
1033 *
1034 *----------------------------------------------------------------------
1035 */
1036
1037void
1038TkFocusFree(
1039    TkMainInfo *mainPtr)	/* Record that identifies a particular
1040				 * application. */
1041{
1042    while (mainPtr->displayFocusPtr != NULL) {
1043	DisplayFocusInfo *displayFocusPtr = mainPtr->displayFocusPtr;
1044
1045	mainPtr->displayFocusPtr = mainPtr->displayFocusPtr->nextPtr;
1046	ckfree((char *) displayFocusPtr);
1047    }
1048    while (mainPtr->tlFocusPtr != NULL) {
1049	ToplevelFocusInfo *tlFocusPtr = mainPtr->tlFocusPtr;
1050
1051	mainPtr->tlFocusPtr = mainPtr->tlFocusPtr->nextPtr;
1052	ckfree((char *) tlFocusPtr);
1053    }
1054}
1055
1056/*
1057 *----------------------------------------------------------------------
1058 *
1059 * TkFocusSplit --
1060 *
1061 *	Adjust focus window for a newly managed toplevel, thus splitting
1062 *      the toplevel into two toplevels.
1063 *
1064 * Results:
1065 *	None.
1066 *
1067 * Side effects:
1068 *	A new record is allocated for the new toplevel window.
1069 *
1070 *----------------------------------------------------------------------
1071 */
1072
1073void
1074TkFocusSplit(winPtr)
1075    TkWindow *winPtr;          /* Window is the new toplevel
1076                                * Any focus point at or below window
1077				* must be moved to this new toplevel */
1078{
1079    ToplevelFocusInfo *tlFocusPtr;
1080    DisplayFocusInfo *displayFocusPtr;
1081    TkWindow *topLevelPtr;
1082    TkWindow *subWinPtr;
1083
1084    displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr);
1085
1086    /*
1087     * Find the top-level window for winPtr, then find (or create)
1088     * a record for the top-level.  Also see whether winPtr and all its
1089     * ancestors are mapped.
1090     */
1091
1092    for (topLevelPtr = winPtr; ; topLevelPtr = topLevelPtr->parentPtr)  {
1093	if (topLevelPtr == NULL) {
1094	    /*
1095	     * The window is being deleted.  No point in worrying about
1096	     * giving it the focus.
1097	     */
1098	    return;
1099	}
1100	if (topLevelPtr->flags & TK_TOP_HIERARCHY) {
1101	    break;
1102	}
1103    }
1104
1105    /* Search all focus records to find child windows of winPtr */
1106    for (tlFocusPtr = winPtr->mainPtr->tlFocusPtr; tlFocusPtr != NULL;
1107	 tlFocusPtr = tlFocusPtr->nextPtr) {
1108	if (tlFocusPtr->topLevelPtr == topLevelPtr) {
1109	    break;
1110	}
1111    }
1112
1113    if (tlFocusPtr == NULL) {
1114	/* No focus record for this toplevel, nothing to do. */
1115	return;
1116    }
1117
1118    /* See if current focusWin is child of the new toplevel */
1119    for (subWinPtr = tlFocusPtr->focusWinPtr;
1120	 subWinPtr && subWinPtr != winPtr && subWinPtr != topLevelPtr;
1121	 subWinPtr = subWinPtr->parentPtr) {}
1122
1123    if (subWinPtr == winPtr) {
1124	/* Move focus to new toplevel */
1125	ToplevelFocusInfo *newTlFocusPtr;
1126
1127	newTlFocusPtr = (ToplevelFocusInfo *) ckalloc(sizeof(ToplevelFocusInfo));
1128	newTlFocusPtr->topLevelPtr = winPtr;
1129	newTlFocusPtr->focusWinPtr = tlFocusPtr->focusWinPtr;
1130	newTlFocusPtr->nextPtr = winPtr->mainPtr->tlFocusPtr;
1131	winPtr->mainPtr->tlFocusPtr = newTlFocusPtr;
1132	/* Move old toplevel's focus to the toplevel itself */
1133	tlFocusPtr->focusWinPtr = topLevelPtr;
1134    }
1135    /* If it's not, then let focus progress naturally */
1136}
1137
1138/*
1139 *----------------------------------------------------------------------
1140 *
1141 * TkFocusJoin --
1142 *
1143 *	Remove the focus record for this window that is nolonger managed
1144 *
1145 * Results:
1146 *	None.
1147 *
1148 * Side effects:
1149 *	A tlFocusPtr record is removed
1150 *
1151 *----------------------------------------------------------------------
1152 */
1153
1154void
1155TkFocusJoin(winPtr)
1156    TkWindow *winPtr;          /* Window is no longer a toplevel */
1157{
1158    ToplevelFocusInfo *tlFocusPtr;
1159    ToplevelFocusInfo *tmpPtr;
1160
1161    /*
1162     * Remove old toplevel record
1163     */
1164    if (winPtr && winPtr->mainPtr && winPtr->mainPtr->tlFocusPtr
1165	&& winPtr->mainPtr->tlFocusPtr->topLevelPtr == winPtr) {
1166	tmpPtr = winPtr->mainPtr->tlFocusPtr;
1167	winPtr->mainPtr->tlFocusPtr = tmpPtr->nextPtr;
1168	ckfree((char *)tmpPtr);
1169    } else {
1170	for (tlFocusPtr = winPtr->mainPtr->tlFocusPtr; tlFocusPtr != NULL;
1171	     tlFocusPtr = tlFocusPtr->nextPtr) {
1172	    if (tlFocusPtr->nextPtr &&
1173		tlFocusPtr->nextPtr->topLevelPtr == winPtr) {
1174		tmpPtr = tlFocusPtr->nextPtr;
1175		tlFocusPtr->nextPtr = tmpPtr->nextPtr;
1176		ckfree((char *)tmpPtr);
1177		break;
1178	    }
1179	}
1180    }
1181}
1182
1183/*
1184 * Local Variables:
1185 * mode: c
1186 * c-basic-offset: 4
1187 * fill-column: 78
1188 * End:
1189 */
1190