/[dtapublic]/projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkfocus.c
ViewVC logotype

Diff of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkfocus.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.44  
changed lines
  Added in v.71

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25