4 * This file contains procedures that manage the input
7 * Copyright (c) 1990-1994 The Regents of the University of California.
8 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
10 * See the file "license.terms" for information on usage and redistribution
11 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
21 * For each top-level window that has ever received the focus, there
22 * is a record of the following type:
25 typedef struct TkToplevelFocusInfo {
26 TkWindow *topLevelPtr; /* Information about top-level window. */
27 TkWindow *focusWinPtr; /* The next time the focus comes to this
28 * top-level, it will be given to this
30 struct TkToplevelFocusInfo *nextPtr;
31 /* Next in list of all toplevel focus records
32 * for a given application. */
36 * One of the following structures exists for each display used by
37 * each application. These are linked together from the TkMainInfo
38 * structure. These structures are needed because it isn't
39 * sufficient to store a single piece of focus information in each
40 * display or in each application: we need the cross-product.
41 * There needs to be separate information for each display, because
42 * it's possible to have multiple focus windows active simultaneously
43 * on different displays. There also needs to be separate information
44 * for each application, because of embedding: if an embedded
45 * application has the focus, its container application also has
46 * the focus. Thus we keep a list of structures for each application:
47 * the same display can appear in structures for several applications
51 typedef struct TkDisplayFocusInfo {
52 TkDisplay *dispPtr; /* Display that this information pertains
54 struct TkWindow *focusWinPtr;
55 /* Window that currently has the focus for
56 * this application on this display, or NULL
58 struct TkWindow *focusOnMapPtr;
59 /* This points to a toplevel window that is
60 * supposed to receive the X input focus as
61 * soon as it is mapped (needed to handle the
62 * fact that X won't allow the focus on an
63 * unmapped window). NULL means no delayed
64 * focus op in progress for this display. */
65 int forceFocus; /* Associated with focusOnMapPtr: non-zero
66 * means claim the focus even if some other
67 * application currently has it. */
68 unsigned long focusSerial; /* Serial number of last request this
69 * application made to change the focus on
70 * this display. Used to identify stale
71 * focus notifications coming from the
73 struct TkDisplayFocusInfo *nextPtr;
74 /* Next in list of all display focus
75 * records for a given application. */
79 * The following magic value is stored in the "send_event" field of
80 * FocusIn and FocusOut events that are generated in this file. This
81 * allows us to separate "real" events coming from the server from
82 * those that we generated.
85 #define GENERATED_EVENT_MAGIC ((Bool) 0x547321ac)
88 * Forward declarations for procedures defined in this file:
92 static DisplayFocusInfo *FindDisplayFocusInfo _ANSI_ARGS_((TkMainInfo *mainPtr,
94 static void FocusMapProc _ANSI_ARGS_((ClientData clientData,
96 static void GenerateFocusEvents _ANSI_ARGS_((TkWindow *sourcePtr,
100 *--------------------------------------------------------------
104 * This procedure is invoked to process the "focus" Tcl command.
105 * See the user documentation for details on what it does.
108 * A standard Tcl result.
111 * See the user documentation.
113 *--------------------------------------------------------------
117 Tk_FocusObjCmd(clientData, interp, objc, objv)
118 ClientData clientData; /* Main window associated with
120 Tcl_Interp *interp; /* Current interpreter. */
121 int objc; /* Number of arguments. */
122 Tcl_Obj *CONST objv[]; /* Argument objects. */
124 static char *focusOptions[] = {"-displayof", "-force", "-lastfor",
126 Tk_Window tkwin = (Tk_Window) clientData;
127 TkWindow *winPtr = (TkWindow *) clientData;
128 TkWindow *newPtr, *focusWinPtr, *topLevelPtr;
129 ToplevelFocusInfo *tlFocusPtr;
134 * If invoked with no arguments, just return the current focus window.
138 focusWinPtr = TkGetFocusWin(winPtr);
139 if (focusWinPtr != NULL) {
140 Tcl_SetResult(interp, focusWinPtr->pathName, TCL_STATIC);
146 * If invoked with a single argument beginning with "." then focus
151 windowName = Tcl_GetStringFromObj(objv[1], (int *) NULL);
154 * The empty string case exists for backwards compatibility.
157 if (windowName[0] == '\0') {
160 if (windowName[0] == '.') {
161 newPtr = (TkWindow *) Tk_NameToWindow(interp, windowName, tkwin);
162 if (newPtr == NULL) {
165 if (!(newPtr->flags & TK_ALREADY_DEAD)) {
166 TkSetFocusWin(newPtr, 0);
172 if (Tcl_GetIndexFromObj(interp, objv[1], focusOptions, "option", 0,
177 Tcl_WrongNumArgs(interp, 2, objv, "window");
181 case 0: { /* -displayof */
182 windowName = Tcl_GetStringFromObj(objv[2], (int *) NULL);
183 newPtr = (TkWindow *) Tk_NameToWindow(interp, windowName, tkwin);
184 if (newPtr == NULL) {
187 newPtr = TkGetFocusWin(newPtr);
188 if (newPtr != NULL) {
189 Tcl_SetResult(interp, newPtr->pathName, TCL_STATIC);
193 case 1: { /* -force */
194 windowName = Tcl_GetStringFromObj(objv[2], (int *) NULL);
197 * The empty string case exists for backwards compatibility.
200 if (windowName[0] == '\0') {
203 newPtr = (TkWindow *) Tk_NameToWindow(interp, windowName, tkwin);
204 if (newPtr == NULL) {
207 TkSetFocusWin(newPtr, 1);
210 case 2: { /* -lastfor */
211 windowName = Tcl_GetStringFromObj(objv[2], (int *) NULL);
212 newPtr = (TkWindow *) Tk_NameToWindow(interp, windowName, tkwin);
213 if (newPtr == NULL) {
216 for (topLevelPtr = newPtr; topLevelPtr != NULL;
217 topLevelPtr = topLevelPtr->parentPtr) {
218 if (topLevelPtr->flags & TK_TOP_LEVEL) {
219 for (tlFocusPtr = newPtr->mainPtr->tlFocusPtr;
221 tlFocusPtr = tlFocusPtr->nextPtr) {
222 if (tlFocusPtr->topLevelPtr == topLevelPtr) {
223 Tcl_SetResult(interp,
224 tlFocusPtr->focusWinPtr->pathName,
229 Tcl_SetResult(interp, topLevelPtr->pathName, TCL_STATIC);
236 panic("bad const entries to focusOptions in focus command");
243 *--------------------------------------------------------------
245 * TkFocusFilterEvent --
247 * This procedure is invoked by Tk_HandleEvent when it encounters
248 * a FocusIn, FocusOut, Enter, or Leave event.
251 * A return value of 1 means that Tk_HandleEvent should process
252 * the event normally (i.e. event handlers should be invoked).
253 * A return value of 0 means that this event should be ignored.
256 * Additional events may be generated, and the focus may switch.
258 *--------------------------------------------------------------
262 TkFocusFilterEvent(winPtr, eventPtr)
263 TkWindow *winPtr; /* Window that focus event is directed to. */
264 XEvent *eventPtr; /* FocusIn, FocusOut, Enter, or Leave
268 * Design notes: the window manager and X server work together to
269 * transfer the focus among top-level windows. This procedure takes
270 * care of transferring the focus from a top-level or wrapper window
271 * to the actual window within that top-level that has the focus.
272 * We do this by synthesizing X events to move the focus around.
273 * None of the FocusIn and FocusOut events generated by X are ever
274 * used outside of this procedure; only the synthesized events get
275 * through to the rest of the application. At one point (e.g.
276 * Tk4.0b1) Tk used to call X to move the focus from a top-level to
277 * one of its descendants, then just pass through the events
278 * generated by X. This approach didn't work very well, for a
279 * variety of reasons. For example, if X generates the events they
280 * go at the back of the event queue, which could cause problems if
281 * other things have already happened, such as moving the focus to
282 * yet another window.
285 ToplevelFocusInfo *tlFocusPtr;
286 DisplayFocusInfo *displayFocusPtr;
287 TkDisplay *dispPtr = winPtr->dispPtr;
288 TkWindow *newFocusPtr;
292 * If this was a generated event, just turn off the generated
293 * flag and pass the event through to Tk bindings.
296 if (eventPtr->xfocus.send_event == GENERATED_EVENT_MAGIC) {
297 eventPtr->xfocus.send_event = 0;
302 * Check for special events generated by embedded applications to
303 * request the input focus. If this is one of those events, make
304 * the change in focus and return without any additional processing
305 * of the event (note: the "detail" field of the event indicates
306 * whether to claim the focus even if we don't already have it).
309 if ((eventPtr->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS)
310 && (eventPtr->type == FocusIn)) {
311 TkSetFocusWin(winPtr, eventPtr->xfocus.detail);
316 * This was not a generated event. We'll return 1 (so that the
317 * event will be processed) if it's an Enter or Leave event, and
318 * 0 (so that the event won't be processed) if it's a FocusIn or
323 displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr);
324 if (eventPtr->type == FocusIn) {
326 * Skip FocusIn events that cause confusion
327 * NotifyVirtual and NotifyNonlinearVirtual - Virtual events occur
328 * on windows in between the origin and destination of the
329 * focus change. For FocusIn we may see this when focus
330 * goes into an embedded child. We don't care about this,
331 * although we may end up getting a NotifyPointer later.
332 * NotifyInferior - focus is coming to us from an embedded child.
333 * When focus is on an embeded focus, we still think we have
334 * the focus, too, so this message doesn't change our state.
335 * NotifyPointerRoot - should never happen because this is sent
336 * to the root window.
338 * Interesting FocusIn events are
339 * NotifyAncestor - focus is coming from our parent, probably the root.
340 * NotifyNonlinear - focus is coming from a different branch, probably
342 * NotifyPointer - implicit focus because of the mouse position.
343 * This is only interesting on toplevels, when it means that the
344 * focus has been set to the root window but the mouse is over
345 * this toplevel. We take the focus implicitly (probably no
349 if ((eventPtr->xfocus.detail == NotifyVirtual)
350 || (eventPtr->xfocus.detail == NotifyNonlinearVirtual)
351 || (eventPtr->xfocus.detail == NotifyPointerRoot)
352 || (eventPtr->xfocus.detail == NotifyInferior)) {
355 } else if (eventPtr->type == FocusOut) {
357 * Skip FocusOut events that cause confusion.
358 * NotifyPointer - the pointer is in us or a child, and we are losing
359 * focus because of an XSetInputFocus. Other focus events
360 * will set our state properly.
361 * NotifyPointerRoot - should never happen because this is sent
362 * to the root window.
363 * NotifyInferior - focus leaving us for an embedded child. We
364 * retain a notion of focus when an embedded child has focus.
366 * Interesting events are:
367 * NotifyAncestor - focus is going to root.
368 * NotifyNonlinear - focus is going to another branch, probably
370 * NotifyVirtual, NotifyNonlinearVirtual - focus is passing through,
371 * and we need to make sure we track this.
374 if ((eventPtr->xfocus.detail == NotifyPointer)
375 || (eventPtr->xfocus.detail == NotifyPointerRoot)
376 || (eventPtr->xfocus.detail == NotifyInferior)) {
381 if (eventPtr->xcrossing.detail == NotifyInferior) {
387 * If winPtr isn't a top-level window than just ignore the event.
390 winPtr = TkWmFocusToplevel(winPtr);
391 if (winPtr == NULL) {
396 * If there is a grab in effect and this window is outside the
397 * grabbed tree, then ignore the event.
400 if (TkGrabState(winPtr) == TK_GRAB_EXCLUDED) {
405 * It is possible that there were outstanding FocusIn and FocusOut
406 * events on their way to us at the time the focus was changed
407 * internally with the "focus" command. If so, these events could
408 * potentially cause us to lose the focus (switch it to the window
409 * of the last FocusIn event) even though the focus change occurred
410 * after those events. The following code detects this and ignores
413 * Note: the focusSerial is only generated by TkpChangeFocus,
414 * whereas in Tk 4.2 there was always a nop marker generated.
417 delta = eventPtr->xfocus.serial - displayFocusPtr->focusSerial;
423 * Find the ToplevelFocusInfo structure for the window, and make a new one
424 * if there isn't one already.
427 for (tlFocusPtr = winPtr->mainPtr->tlFocusPtr; tlFocusPtr != NULL;
428 tlFocusPtr = tlFocusPtr->nextPtr) {
429 if (tlFocusPtr->topLevelPtr == winPtr) {
433 if (tlFocusPtr == NULL) {
434 tlFocusPtr = (ToplevelFocusInfo *) ckalloc(sizeof(ToplevelFocusInfo));
435 tlFocusPtr->topLevelPtr = tlFocusPtr->focusWinPtr = winPtr;
436 tlFocusPtr->nextPtr = winPtr->mainPtr->tlFocusPtr;
437 winPtr->mainPtr->tlFocusPtr = tlFocusPtr;
439 newFocusPtr = tlFocusPtr->focusWinPtr;
441 if (eventPtr->type == FocusIn) {
442 GenerateFocusEvents(displayFocusPtr->focusWinPtr, newFocusPtr);
443 displayFocusPtr->focusWinPtr = newFocusPtr;
444 dispPtr->focusPtr = newFocusPtr;
447 * NotifyPointer gets set when the focus has been set to the root window
448 * but we have the pointer. We'll treat this like an implicit
449 * focus in event so that upon Leave events we release focus.
452 if (!(winPtr->flags & TK_EMBEDDED)) {
453 if (eventPtr->xfocus.detail == NotifyPointer) {
454 dispPtr->implicitWinPtr = winPtr;
456 dispPtr->implicitWinPtr = NULL;
459 } else if (eventPtr->type == FocusOut) {
460 GenerateFocusEvents(displayFocusPtr->focusWinPtr, (TkWindow *) NULL);
463 * Reset dispPtr->focusPtr, but only if it currently is the same
464 * as this application's focusWinPtr: this check is needed to
465 * handle embedded applications in the same process.
468 if (dispPtr->focusPtr == displayFocusPtr->focusWinPtr) {
469 dispPtr->focusPtr = NULL;
471 displayFocusPtr->focusWinPtr = NULL;
472 } else if (eventPtr->type == EnterNotify) {
474 * If there is no window manager, or if the window manager isn't
475 * moving the focus around (e.g. the disgusting "NoTitleFocus"
476 * option has been selected in twm), then we won't get FocusIn
477 * or FocusOut events. Instead, the "focus" field will be set
478 * in an Enter event to indicate that we've already got the focus
479 * when the mouse enters the window (even though we didn't get
480 * a FocusIn event). Watch for this and grab the focus when it
481 * happens. Note: if this is an embedded application then don't
482 * accept the focus implicitly like this; the container
483 * application will give us the focus explicitly if it wants us
487 if (eventPtr->xcrossing.focus &&
488 (displayFocusPtr->focusWinPtr == NULL)
489 && !(winPtr->flags & TK_EMBEDDED)) {
490 if (dispPtr->focusDebug) {
491 printf("Focussed implicitly on %s\n",
492 newFocusPtr->pathName);
495 GenerateFocusEvents(displayFocusPtr->focusWinPtr, newFocusPtr);
496 displayFocusPtr->focusWinPtr = newFocusPtr;
497 dispPtr->implicitWinPtr = winPtr;
498 dispPtr->focusPtr = newFocusPtr;
500 } else if (eventPtr->type == LeaveNotify) {
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"
507 * command 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.
513 if ((dispPtr->implicitWinPtr != NULL)
514 && !(winPtr->flags & TK_EMBEDDED)) {
515 if (dispPtr->focusDebug) {
516 printf("Defocussed implicit Async\n");
518 GenerateFocusEvents(displayFocusPtr->focusWinPtr,
520 XSetInputFocus(dispPtr->display, PointerRoot, RevertToPointerRoot,
522 displayFocusPtr->focusWinPtr = NULL;
523 dispPtr->implicitWinPtr = NULL;
530 *----------------------------------------------------------------------
534 * This procedure is invoked to change the focus window for a
535 * given display in a given application.
541 * Event handlers may be invoked to process the change of
544 *----------------------------------------------------------------------
548 TkSetFocusWin(winPtr, force)
549 TkWindow *winPtr; /* Window that is to be the new focus for
550 * its display and application. */
551 int force; /* If non-zero, set the X focus to this
552 * window even if the application doesn't
553 * currently have the X focus. */
555 ToplevelFocusInfo *tlFocusPtr;
556 DisplayFocusInfo *displayFocusPtr;
557 TkWindow *topLevelPtr;
558 int allMapped, serial;
560 displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr);
563 * If force is set, we should make sure we grab the focus regardless
564 * of the current focus window since under Windows, we may need to
565 * take control away from another application.
568 if (winPtr == displayFocusPtr->focusWinPtr && !force) {
573 * Find the top-level window for winPtr, then find (or create)
574 * a record for the top-level. Also see whether winPtr and all its
575 * ancestors are mapped.
579 for (topLevelPtr = winPtr; ; topLevelPtr = topLevelPtr->parentPtr) {
580 if (topLevelPtr == NULL) {
582 * The window is being deleted. No point in worrying about
583 * giving it the focus.
587 if (!(topLevelPtr->flags & TK_MAPPED)) {
590 if (topLevelPtr->flags & TK_TOP_LEVEL) {
596 * If the new focus window isn't mapped, then we can't focus on it
597 * (X will generate an error, for example). Instead, create an
598 * event handler that will set the focus to this window once it gets
599 * mapped. At the same time, delete any old handler that might be
600 * around; it's no longer relevant.
603 if (displayFocusPtr->focusOnMapPtr != NULL) {
604 Tk_DeleteEventHandler(
605 (Tk_Window) displayFocusPtr->focusOnMapPtr,
606 StructureNotifyMask, FocusMapProc,
607 (ClientData) displayFocusPtr->focusOnMapPtr);
608 displayFocusPtr->focusOnMapPtr = NULL;
611 Tk_CreateEventHandler((Tk_Window) winPtr,
612 VisibilityChangeMask, FocusMapProc,
613 (ClientData) winPtr);
614 displayFocusPtr->focusOnMapPtr = winPtr;
615 displayFocusPtr->forceFocus = force;
619 for (tlFocusPtr = winPtr->mainPtr->tlFocusPtr; tlFocusPtr != NULL;
620 tlFocusPtr = tlFocusPtr->nextPtr) {
621 if (tlFocusPtr->topLevelPtr == topLevelPtr) {
625 if (tlFocusPtr == NULL) {
626 tlFocusPtr = (ToplevelFocusInfo *) ckalloc(sizeof(ToplevelFocusInfo));
627 tlFocusPtr->topLevelPtr = topLevelPtr;
628 tlFocusPtr->nextPtr = winPtr->mainPtr->tlFocusPtr;
629 winPtr->mainPtr->tlFocusPtr = tlFocusPtr;
631 tlFocusPtr->focusWinPtr = winPtr;
634 * Reset the window system's focus window and generate focus events,
635 * with two special cases:
637 * 1. If the application is embedded and doesn't currently have the
638 * focus, don't set the focus directly. Instead, see if the
639 * embedding code can claim the focus from the enclosing
641 * 2. Otherwise, if the application doesn't currently have the
642 * focus, don't change the window system's focus unless it was
643 * already in this application or "force" was specified.
646 if ((topLevelPtr->flags & TK_EMBEDDED)
647 && (displayFocusPtr->focusWinPtr == NULL)) {
648 TkpClaimFocus(topLevelPtr, force);
649 } else if ((displayFocusPtr->focusWinPtr != NULL) || force) {
651 * Generate events to shift focus between Tk windows.
652 * We do this regardless of what TkpChangeFocus does with
653 * the real X focus so that Tk widgets track focus commands
654 * when there is no window manager. GenerateFocusEvents will
655 * set up a serial number marker so we discard focus events
656 * that are triggered by the ChangeFocus.
659 serial = TkpChangeFocus(TkpGetWrapperWindow(topLevelPtr), force);
661 displayFocusPtr->focusSerial = serial;
663 GenerateFocusEvents(displayFocusPtr->focusWinPtr, winPtr);
664 displayFocusPtr->focusWinPtr = winPtr;
665 winPtr->dispPtr->focusPtr = winPtr;
670 *----------------------------------------------------------------------
674 * Given a window, this procedure returns the current focus
675 * window for its application and display.
678 * The return value is a pointer to the window that currently
679 * has the input focus for the specified application and
680 * display, or NULL if none.
685 *----------------------------------------------------------------------
689 TkGetFocusWin(winPtr)
690 TkWindow *winPtr; /* Window that selects an application
693 DisplayFocusInfo *displayFocusPtr;
695 if (winPtr == NULL) {
696 return (TkWindow *) NULL;
699 displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr);
700 return displayFocusPtr->focusWinPtr;
704 *----------------------------------------------------------------------
708 * Given a window and a key press or release event that arrived for
709 * the window, use information about the keyboard focus to compute
710 * which window should really get the event. In addition, update
711 * the event to refer to its new window.
714 * The return value is a pointer to the window that has the input
715 * focus in winPtr's application, or NULL if winPtr's application
716 * doesn't have the input focus. If a non-NULL value is returned,
717 * eventPtr will be updated to refer properly to the focus window.
722 *----------------------------------------------------------------------
726 TkFocusKeyEvent(winPtr, eventPtr)
727 TkWindow *winPtr; /* Window that selects an application
729 XEvent *eventPtr; /* X event to redirect (should be KeyPress
732 DisplayFocusInfo *displayFocusPtr;
733 TkWindow *focusWinPtr;
734 int focusX, focusY, vRootX, vRootY, vRootWidth, vRootHeight;
736 displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr);
737 focusWinPtr = displayFocusPtr->focusWinPtr;
740 * The code below is a debugging aid to make sure that dispPtr->focusPtr
741 * is kept properly in sync with the "truth", which is the value in
742 * displayFocusPtr->focusWinPtr.
746 if (focusWinPtr != winPtr->dispPtr->focusPtr) {
747 printf("TkFocusKeyEvent found dispPtr->focusPtr out of sync:\n");
748 printf("expected %s, got %s\n",
749 (focusWinPtr != NULL) ? focusWinPtr->pathName : "??",
750 (winPtr->dispPtr->focusPtr != NULL) ?
751 winPtr->dispPtr->focusPtr->pathName : "??");
755 if ((focusWinPtr != NULL) && (focusWinPtr->mainPtr == winPtr->mainPtr)) {
757 * Map the x and y coordinates to make sense in the context of
758 * the focus window, if possible (make both -1 if the map-from
759 * and map-to windows don't share the same screen).
762 if ((focusWinPtr->display != winPtr->display)
763 || (focusWinPtr->screenNum != winPtr->screenNum)) {
764 eventPtr->xkey.x = -1;
765 eventPtr->xkey.y = -1;
767 Tk_GetVRootGeometry((Tk_Window) focusWinPtr, &vRootX, &vRootY,
768 &vRootWidth, &vRootHeight);
769 Tk_GetRootCoords((Tk_Window) focusWinPtr, &focusX, &focusY);
770 eventPtr->xkey.x = eventPtr->xkey.x_root - vRootX - focusX;
771 eventPtr->xkey.y = eventPtr->xkey.y_root - vRootY - focusY;
773 eventPtr->xkey.window = focusWinPtr->window;
778 * The event doesn't belong to us. Perhaps, due to embedding, it
779 * really belongs to someone else. Give the embedding code a chance
780 * to redirect the event.
783 TkpRedirectKeyEvent(winPtr, eventPtr);
784 return (TkWindow *) NULL;
788 *----------------------------------------------------------------------
790 * TkFocusDeadWindow --
792 * This procedure is invoked when it is determined that
793 * a window is dead. It cleans up focus-related information
800 * Various things get cleaned up and recycled.
802 *----------------------------------------------------------------------
806 TkFocusDeadWindow(winPtr)
807 register TkWindow *winPtr; /* Information about the window
808 * that is being deleted. */
810 ToplevelFocusInfo *tlFocusPtr, *prevPtr;
811 DisplayFocusInfo *displayFocusPtr;
812 TkDisplay *dispPtr = winPtr->dispPtr;
815 * Search for focus records that refer to this window either as
816 * the top-level window or the current focus window.
819 displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr);
820 for (prevPtr = NULL, tlFocusPtr = winPtr->mainPtr->tlFocusPtr;
822 prevPtr = tlFocusPtr, tlFocusPtr = tlFocusPtr->nextPtr) {
823 if (winPtr == tlFocusPtr->topLevelPtr) {
825 * The top-level window is the one being deleted: free
826 * the focus record and release the focus back to PointerRoot
827 * if we acquired it implicitly.
830 if (dispPtr->implicitWinPtr == winPtr) {
831 if (dispPtr->focusDebug) {
832 printf("releasing focus to root after %s died\n",
833 tlFocusPtr->topLevelPtr->pathName);
835 dispPtr->implicitWinPtr = NULL;
836 displayFocusPtr->focusWinPtr = NULL;
837 dispPtr->focusPtr = NULL;
839 if (displayFocusPtr->focusWinPtr == tlFocusPtr->focusWinPtr) {
840 displayFocusPtr->focusWinPtr = NULL;
841 dispPtr->focusPtr = NULL;
843 if (prevPtr == NULL) {
844 winPtr->mainPtr->tlFocusPtr = tlFocusPtr->nextPtr;
846 prevPtr->nextPtr = tlFocusPtr->nextPtr;
848 ckfree((char *) tlFocusPtr);
850 } else if (winPtr == tlFocusPtr->focusWinPtr) {
852 * The deleted window had the focus for its top-level:
853 * move the focus to the top-level itself.
856 tlFocusPtr->focusWinPtr = tlFocusPtr->topLevelPtr;
857 if ((displayFocusPtr->focusWinPtr == winPtr)
858 && !(tlFocusPtr->topLevelPtr->flags & TK_ALREADY_DEAD)) {
859 if (dispPtr->focusDebug) {
860 printf("forwarding focus to %s after %s died\n",
861 tlFocusPtr->topLevelPtr->pathName,
864 GenerateFocusEvents(displayFocusPtr->focusWinPtr,
865 tlFocusPtr->topLevelPtr);
866 displayFocusPtr->focusWinPtr = tlFocusPtr->topLevelPtr;
867 dispPtr->focusPtr = tlFocusPtr->topLevelPtr;
873 if (displayFocusPtr->focusOnMapPtr == winPtr) {
874 displayFocusPtr->focusOnMapPtr = NULL;
879 *----------------------------------------------------------------------
881 * GenerateFocusEvents --
883 * This procedure is called to create FocusIn and FocusOut events to
884 * move the input focus from one window to another.
890 * FocusIn and FocusOut events are generated.
892 *----------------------------------------------------------------------
896 GenerateFocusEvents(sourcePtr, destPtr)
897 TkWindow *sourcePtr; /* Window that used to have the focus (may
899 TkWindow *destPtr; /* New window to have the focus (may be
907 if (winPtr == NULL) {
909 if (winPtr == NULL) {
914 event.xfocus.serial = LastKnownRequestProcessed(winPtr->display);
915 event.xfocus.send_event = GENERATED_EVENT_MAGIC;
916 event.xfocus.display = winPtr->display;
917 event.xfocus.mode = NotifyNormal;
918 TkInOutEvents(&event, sourcePtr, destPtr, FocusOut, FocusIn,
923 *----------------------------------------------------------------------
927 * This procedure is called as an event handler for VisibilityNotify
928 * events, if a window receives the focus at a time when its
929 * toplevel isn't mapped. The procedure is needed because X
930 * won't allow the focus to be set to an unmapped window; we
931 * detect when the toplevel is mapped and set the focus to it then.
937 * If this is a map event, the focus gets set to the toplevel
938 * given by clientData.
940 *----------------------------------------------------------------------
944 FocusMapProc(clientData, eventPtr)
945 ClientData clientData; /* Toplevel window. */
946 XEvent *eventPtr; /* Information about event. */
948 TkWindow *winPtr = (TkWindow *) clientData;
949 DisplayFocusInfo *displayFocusPtr;
951 if (eventPtr->type == VisibilityNotify) {
952 displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr,
954 if (winPtr->dispPtr->focusDebug) {
955 printf("auto-focussing on %s, force %d\n", winPtr->pathName,
956 displayFocusPtr->forceFocus);
958 Tk_DeleteEventHandler((Tk_Window) winPtr, VisibilityChangeMask,
959 FocusMapProc, clientData);
960 displayFocusPtr->focusOnMapPtr = NULL;
961 TkSetFocusWin(winPtr, displayFocusPtr->forceFocus);
966 *----------------------------------------------------------------------
968 * FindDisplayFocusInfo --
970 * Given an application and a display, this procedure locate the
971 * focus record for that combination. If no such record exists,
972 * it creates a new record and initializes it.
975 * The return value is a pointer to the record.
978 * A new record will be allocated if there wasn't one already.
980 *----------------------------------------------------------------------
983 static DisplayFocusInfo *
984 FindDisplayFocusInfo(mainPtr, dispPtr)
985 TkMainInfo *mainPtr; /* Record that identifies a particular
987 TkDisplay *dispPtr; /* Display whose focus information is
990 DisplayFocusInfo *displayFocusPtr;
992 for (displayFocusPtr = mainPtr->displayFocusPtr;
993 displayFocusPtr != NULL;
994 displayFocusPtr = displayFocusPtr->nextPtr) {
995 if (displayFocusPtr->dispPtr == dispPtr) {
996 return displayFocusPtr;
1001 * The record doesn't exist yet. Make a new one.
1004 displayFocusPtr = (DisplayFocusInfo *) ckalloc(sizeof(DisplayFocusInfo));
1005 displayFocusPtr->dispPtr = dispPtr;
1006 displayFocusPtr->focusWinPtr = NULL;
1007 displayFocusPtr->focusOnMapPtr = NULL;
1008 displayFocusPtr->forceFocus = 0;
1009 displayFocusPtr->focusSerial = 0;
1010 displayFocusPtr->nextPtr = mainPtr->displayFocusPtr;
1011 mainPtr->displayFocusPtr = displayFocusPtr;
1012 return displayFocusPtr;