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 )