Tk

 view release on metacpan or  search on metacpan

pTk/mTk/generic/tkFocus.c  view on Meta::CPAN

 *
 * 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.

pTk/mTk/generic/tkFocus.c  view on Meta::CPAN


    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;

    /*
     * 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, (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

pTk/mTk/generic/tkFocus.c  view on Meta::CPAN

	}
	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,
		(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 --



( run in 0.589 second using v1.01-cache-2.11-cpan-71847e10f99 )