diff options
Diffstat (limited to 'tk8.6/generic/tkFocus.c')
-rw-r--r-- | tk8.6/generic/tkFocus.c | 1201 |
1 files changed, 0 insertions, 1201 deletions
diff --git a/tk8.6/generic/tkFocus.c b/tk8.6/generic/tkFocus.c deleted file mode 100644 index 60f631d..0000000 --- a/tk8.6/generic/tkFocus.c +++ /dev/null @@ -1,1201 +0,0 @@ -/* - * tkFocus.c -- - * - * This file contains functions 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. - */ - -#include "tkInt.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; - -/* - * Debugging support... - */ - -#define DEBUG(dispPtr, arguments) \ - if ((dispPtr)->focusDebug) { \ - printf arguments; \ - } - -/* - * Forward declarations for functions defined in this file: - */ - -static DisplayFocusInfo*FindDisplayFocusInfo(TkMainInfo *mainPtr, - TkDisplay *dispPtr); -static void FocusMapProc(ClientData clientData, XEvent *eventPtr); -static void GenerateFocusEvents(TkWindow *sourcePtr, - TkWindow *destPtr); - -/* - *-------------------------------------------------------------- - * - * Tk_FocusObjCmd -- - * - * This function 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 clientData, /* Main window associated with interpreter. */ - Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ - Tcl_Obj *const objv[]) /* Argument objects. */ -{ - static const char *const focusOptions[] = { - "-displayof", "-force", "-lastfor", NULL - }; - Tk_Window tkwin = clientData; - TkWindow *winPtr = clientData; - TkWindow *newPtr, *topLevelPtr; - ToplevelFocusInfo *tlFocusPtr; - const char *windowName; - int index; - - /* - * If invoked with no arguments, just return the current focus window. - */ - - if (objc == 1) { - Tk_Window focusWin = (Tk_Window) TkGetFocusWin(winPtr); - - if (focusWin != NULL) { - Tcl_SetObjResult(interp, TkNewWindowObj(focusWin)); - } - return TCL_OK; - } - - /* - * If invoked with a single argument beginning with "." then focus on that - * window. - */ - - if (objc == 2) { - windowName = Tcl_GetString(objv[1]); - - /* - * 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; - } - TkSetFocusWin(newPtr, 0); - return TCL_OK; - } - } - - /* - * We have a subcommand to parse and act upon. - */ - - if (Tcl_GetIndexFromObjStruct(interp, objv[1], focusOptions, - sizeof(char *), "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_GetString(objv[2]); - newPtr = (TkWindow *) Tk_NameToWindow(interp, windowName, tkwin); - if (newPtr == NULL) { - return TCL_ERROR; - } - newPtr = TkGetFocusWin(newPtr); - if (newPtr != NULL) { - Tcl_SetObjResult(interp, TkNewWindowObj((Tk_Window) newPtr)); - } - break; - case 1: /* -force */ - windowName = Tcl_GetString(objv[2]); - - /* - * 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_GetString(objv[2]); - 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_HIERARCHY)) { - continue; - } - for (tlFocusPtr = newPtr->mainPtr->tlFocusPtr; tlFocusPtr != NULL; - tlFocusPtr = tlFocusPtr->nextPtr) { - if (tlFocusPtr->topLevelPtr == topLevelPtr) { - Tcl_SetObjResult(interp, TkNewWindowObj((Tk_Window) - tlFocusPtr->focusWinPtr)); - return TCL_OK; - } - } - Tcl_SetObjResult(interp, TkNewWindowObj((Tk_Window) topLevelPtr)); - return TCL_OK; - } - break; - default: - Tcl_Panic("bad const entries to focusOptions in focus command"); - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * TkFocusFilterEvent -- - * - * This function 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( - 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 function 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 function; - * 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_FOCUS_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 = ckalloc(sizeof(ToplevelFocusInfo)); - tlFocusPtr->topLevelPtr = tlFocusPtr->focusWinPtr = winPtr; - tlFocusPtr->nextPtr = winPtr->mainPtr->tlFocusPtr; - winPtr->mainPtr->tlFocusPtr = tlFocusPtr; - } - newFocusPtr = tlFocusPtr->focusWinPtr; - - /* - * Ignore event if newFocus window is already dead! - */ - - if (newFocusPtr->flags & TK_ALREADY_DEAD) { - return retValue; - } - - 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, 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)) { - DEBUG(dispPtr, - ("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)) { - DEBUG(dispPtr, ("Defocussed implicit Async\n")); - GenerateFocusEvents(displayFocusPtr->focusWinPtr, NULL); - XSetInputFocus(dispPtr->display, PointerRoot, RevertToPointerRoot, - CurrentTime); - displayFocusPtr->focusWinPtr = NULL; - dispPtr->implicitWinPtr = NULL; - } - } - return retValue; -} - -/* - *---------------------------------------------------------------------- - * - * TkSetFocusWin -- - * - * This function 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( - 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; - - /* - * Don't set focus if window is already dead. [Bug 3574708] - */ - - if (winPtr->flags & TK_ALREADY_DEAD) { - return; - } - - 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_HIERARCHY) { - 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, - displayFocusPtr->focusOnMapPtr); - displayFocusPtr->focusOnMapPtr = NULL; - } - if (!allMapped) { - Tk_CreateEventHandler((Tk_Window) winPtr, VisibilityChangeMask, - FocusMapProc, 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 = 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 function 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( - TkWindow *winPtr) /* Window that selects an application and a - * display. */ -{ - DisplayFocusInfo *displayFocusPtr; - - if (winPtr == NULL) { - return 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( - 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; - - 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_GetRootCoords((Tk_Window) focusWinPtr, &focusX, &focusY); - eventPtr->xkey.x = eventPtr->xkey.x_root - focusX; - eventPtr->xkey.y = eventPtr->xkey.y_root - 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 NULL; -} - -/* - *---------------------------------------------------------------------- - * - * TkFocusDeadWindow -- - * - * This function 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( - register TkWindow *winPtr) /* Information about the window that is being - * deleted. */ -{ - ToplevelFocusInfo *tlFocusPtr, *prevPtr; - DisplayFocusInfo *displayFocusPtr; - TkDisplay *dispPtr = winPtr->dispPtr; - - /* - * Certain special windows like those used for send and clipboard have no - * mainPtr. - */ - - if (winPtr->mainPtr == NULL) { - return; - } - - /* - * 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) { - DEBUG(dispPtr, ("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(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)) { - DEBUG(dispPtr, ("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; - } - } - - /* - * Occasionally, things can become unsynchronized. Move them back into - * synch now. [Bug 2496114] - */ - - if (displayFocusPtr->focusWinPtr == winPtr) { - DEBUG(dispPtr, ("focus cleared after %s died\n", winPtr->pathName)); - displayFocusPtr->focusWinPtr = NULL; - } - - if (displayFocusPtr->focusOnMapPtr == winPtr) { - displayFocusPtr->focusOnMapPtr = NULL; - } -} - -/* - *---------------------------------------------------------------------- - * - * GenerateFocusEvents -- - * - * This function 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( - 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_FOCUS_EVENT_MAGIC; - event.xfocus.display = winPtr->display; - event.xfocus.mode = NotifyNormal; - TkInOutEvents(&event, sourcePtr, destPtr, FocusOut, FocusIn, - TCL_QUEUE_MARK); -} - -/* - *---------------------------------------------------------------------- - * - * FocusMapProc -- - * - * This function 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 function 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 clientData, /* Toplevel window. */ - XEvent *eventPtr) /* Information about event. */ -{ - TkWindow *winPtr = clientData; - DisplayFocusInfo *displayFocusPtr; - - if (eventPtr->type == VisibilityNotify) { - displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, - winPtr->dispPtr); - DEBUG(winPtr->dispPtr, ("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 function 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( - 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 = 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; -} - -/* - *---------------------------------------------------------------------- - * - * TkFocusFree -- - * - * Free resources associated with maintaining the focus. - * - * Results: - * None. - * - * Side effects: - * This mainPtr should no long access focus information. - * - *---------------------------------------------------------------------- - */ - -void -TkFocusFree( - TkMainInfo *mainPtr) /* Record that identifies a particular - * application. */ -{ - while (mainPtr->displayFocusPtr != NULL) { - DisplayFocusInfo *displayFocusPtr = mainPtr->displayFocusPtr; - - mainPtr->displayFocusPtr = mainPtr->displayFocusPtr->nextPtr; - ckfree(displayFocusPtr); - } - while (mainPtr->tlFocusPtr != NULL) { - ToplevelFocusInfo *tlFocusPtr = mainPtr->tlFocusPtr; - - mainPtr->tlFocusPtr = mainPtr->tlFocusPtr->nextPtr; - ckfree(tlFocusPtr); - } -} - -/* - *---------------------------------------------------------------------- - * - * TkFocusSplit -- - * - * Adjust focus window for a newly managed toplevel, thus splitting the - * toplevel into two toplevels. - * - * Results: - * None. - * - * Side effects: - * A new record is allocated for the new toplevel window. - * - *---------------------------------------------------------------------- - */ - -void -TkFocusSplit( - TkWindow *winPtr) /* Window is the new toplevel. Any focus point - * at or below window must be moved to this - * new toplevel. */ -{ - ToplevelFocusInfo *tlFocusPtr; - TkWindow *topLevelPtr, *subWinPtr; - - FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr); - - /* - * 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. - */ - - 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_TOP_HIERARCHY) { - break; - } - } - - /* - * Search all focus records to find child windows of winPtr. - */ - - for (tlFocusPtr = winPtr->mainPtr->tlFocusPtr; tlFocusPtr != NULL; - tlFocusPtr = tlFocusPtr->nextPtr) { - if (tlFocusPtr->topLevelPtr == topLevelPtr) { - break; - } - } - - if (tlFocusPtr == NULL) { - /* - * No focus record for this toplevel, nothing to do. - */ - - return; - } - - /* - * See if current focusWin is child of the new toplevel. - */ - - for (subWinPtr = tlFocusPtr->focusWinPtr; - subWinPtr && subWinPtr != winPtr && subWinPtr != topLevelPtr; - subWinPtr = subWinPtr->parentPtr) { - /* EMPTY */ - } - - if (subWinPtr == winPtr) { - /* - * Move focus to new toplevel. - */ - - ToplevelFocusInfo *newTlFocusPtr = ckalloc(sizeof(ToplevelFocusInfo)); - - newTlFocusPtr->topLevelPtr = winPtr; - newTlFocusPtr->focusWinPtr = tlFocusPtr->focusWinPtr; - newTlFocusPtr->nextPtr = winPtr->mainPtr->tlFocusPtr; - winPtr->mainPtr->tlFocusPtr = newTlFocusPtr; - - /* - * Move old toplevel's focus to the toplevel itself. - */ - - tlFocusPtr->focusWinPtr = topLevelPtr; - } - - /* - * If it's not, then let focus progress naturally. - */ -} - -/* - *---------------------------------------------------------------------- - * - * TkFocusJoin -- - * - * Remove the focus record for this window that is nolonger managed - * - * Results: - * None. - * - * Side effects: - * A tlFocusPtr record is removed - * - *---------------------------------------------------------------------- - */ - -void -TkFocusJoin( - TkWindow *winPtr) /* Window is no longer a toplevel. */ -{ - ToplevelFocusInfo *tlFocusPtr, *tmpPtr; - - /* - * Remove old toplevel record - */ - - if (winPtr && winPtr->mainPtr && winPtr->mainPtr->tlFocusPtr - && winPtr->mainPtr->tlFocusPtr->topLevelPtr == winPtr) { - tmpPtr = winPtr->mainPtr->tlFocusPtr; - winPtr->mainPtr->tlFocusPtr = tmpPtr->nextPtr; - ckfree(tmpPtr); - } else if (winPtr && winPtr->mainPtr) { - for (tlFocusPtr = winPtr->mainPtr->tlFocusPtr; tlFocusPtr != NULL; - tlFocusPtr = tlFocusPtr->nextPtr) { - if (tlFocusPtr->nextPtr && - tlFocusPtr->nextPtr->topLevelPtr == winPtr) { - tmpPtr = tlFocusPtr->nextPtr; - tlFocusPtr->nextPtr = tmpPtr->nextPtr; - ckfree(tmpPtr); - break; - } - } - } -} - -/* - * Local Variables: - * mode: c - * c-basic-offset: 4 - * fill-column: 78 - * End: - */ |