summaryrefslogtreecommitdiffstats
path: root/tk8.6/generic/tkFocus.c
diff options
context:
space:
mode:
Diffstat (limited to 'tk8.6/generic/tkFocus.c')
-rw-r--r--tk8.6/generic/tkFocus.c1201
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:
- */