diff options
Diffstat (limited to 'libXt/src/Keyboard.c')
-rw-r--r-- | libXt/src/Keyboard.c | 1730 |
1 files changed, 866 insertions, 864 deletions
diff --git a/libXt/src/Keyboard.c b/libXt/src/Keyboard.c index c3c5b2732..4970d2d01 100644 --- a/libXt/src/Keyboard.c +++ b/libXt/src/Keyboard.c @@ -1,864 +1,866 @@ -/* $Xorg: Keyboard.c,v 1.5 2001/02/09 02:03:55 xorgcvs Exp $ */ -/* - -Copyright 1993 Sun Microsystems, Inc. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice (including the next -paragraph) shall be included in all copies or substantial portions of the -Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - -*/ -/******************************************************** - -Copyright 1988 by Hewlett-Packard Company -Copyright 1987, 1988, 1989 by Digital Equipment Corporation, Maynard, Massachusetts - -Permission to use, copy, modify, and distribute this software -and its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that copyright notice and this permission -notice appear in supporting documentation, and that the names of -Hewlett-Packard or Digital not be used in advertising or -publicity pertaining to distribution of the software without specific, -written prior permission. - -DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -********************************************************/ - -/* - -Copyright 1987, 1988, 1994, 1998 The Open Group - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that -copyright notice and this permission notice appear in supporting -documentation. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - -*/ -/* $XFree86: xc/lib/Xt/Keyboard.c,v 3.3 2001/08/22 22:52:19 dawes Exp $ */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#include "IntrinsicI.h" - -#include "PassivGraI.h" -#include "EventI.h" - -#define _GetWindowedAncestor(w) (XtIsWidget(w) ? w : _XtWindowedAncestor(w)) - -/* InActiveSubtree cache of the current focus source and its ancestors */ -static Widget *pathTrace = NULL; -static int pathTraceDepth = 0; -static int pathTraceMax = 0; - -/* FindKeyDestination cache of focus destination and ancestors up to source */ -static Widget *pseudoTrace = NULL; -static int pseudoTraceDepth = 0; -static int pseudoTraceMax = 0; - -void _XtClearAncestorCache(Widget widget) -{ - /* the caller must lock the process lock */ - if (pathTraceDepth && pathTrace[0] == widget) - pathTraceDepth = 0; -} - -static XtServerGrabPtr CheckServerGrabs( - XEvent *event, - Widget *trace, - Cardinal traceDepth) -{ - XtServerGrabPtr grab; - Cardinal i; - - for (i = traceDepth; i > 0; i--) - { - if ((grab = _XtCheckServerGrabsOnWidget(event, trace[i-1], KEYBOARD))) - return (grab); - } - return (XtServerGrabPtr)0; -} - -static Boolean IsParent(Widget a, Widget b) -{ - for (b = XtParent(b); b; b = XtParent(b)) { - if (b == a) return TRUE; - if (XtIsShell(b)) return FALSE; - } - return FALSE; -} - -#define RelRtn(lca, type) {*relTypeRtn = type; return lca;} - -static Widget CommonAncestor( - register Widget a, - register Widget b, - XtGeneology * relTypeRtn) -{ - if (a == b) - { - RelRtn(a, XtMySelf) - } - else if (IsParent(a, b)) - { - RelRtn(a, XtMyAncestor) - } - else if (IsParent(b, a)) - { - RelRtn(b, XtMyDescendant) - } - else - for (b = XtParent(b); - b && !XtIsShell(b); - b = XtParent(b)) - if (IsParent(b, a)) - { - RelRtn(b, XtMyCousin) - } - RelRtn(NULL, XtUnrelated) -} -#undef RelRtn - - - - - -static Widget _FindFocusWidget( - Widget widget, - Widget *trace, - int traceDepth, - Boolean activeCheck, - Boolean *isTarget) -{ - int src; - Widget dst; - XtPerWidgetInput pwi = NULL; - - /* For each ancestor, starting at the top, see if it's forwarded */ - - - /* first check the trace list till done or we go to branch */ - for (src = traceDepth-1, dst = widget; src > 0;) - { - if ((pwi = _XtGetPerWidgetInput(trace[src], FALSE))) - { - if (pwi->focusKid) - { - dst = pwi->focusKid; - for (src--; src > 0 && trace[src] != dst; src--) {} - } - else dst = trace[--src]; - } - else dst = trace[--src]; - } - - if (isTarget) { - if (pwi && pwi->focusKid == widget) - *isTarget = TRUE; - else - *isTarget = FALSE; - } - - if (!activeCheck) - while (XtIsWidget(dst) - && (pwi = _XtGetPerWidgetInput(dst, FALSE)) - && pwi->focusKid) - dst = pwi->focusKid; - - return dst; -} - - -static Widget FindFocusWidget( - Widget widget, - XtPerDisplayInput pdi) -{ - if (pdi->focusWidget) - return pdi->focusWidget; - else - return _FindFocusWidget(widget, pdi->trace, pdi->traceDepth, FALSE, NULL); -} - -Widget XtGetKeyboardFocusWidget(Widget widget) -{ - XtPerDisplayInput pdi; - Widget retval; - WIDGET_TO_APPCON(widget); - - LOCK_APP(app); - pdi = _XtGetPerDisplayInput(XtDisplay(widget)); - retval = FindFocusWidget(widget, pdi); - UNLOCK_APP(app); - return retval; -} - -static Boolean IsOutside( - XKeyEvent *e, - Widget w) -{ - Position left, right, top, bottom; - - /* - * if the pointer is outside the shell or inside - * the window try to see if it would recieve the - * focus - */ - XtTranslateCoords(w, 0, 0, &left, &top); - /* We need to take borders into consideration */ - left = left - w->core.border_width; - top = top - w->core.border_width; - right = left + w->core.width + w->core.border_width; - bottom = top + w->core.height + w->core.border_width; - - if ( - (e->x_root < left) || (e->y_root < top) || - (e->x_root > right) || (e->y_root > bottom)) - return TRUE; - else - return FALSE; -} - -static Widget FindKeyDestination( - Widget widget, - XKeyEvent *event, - XtServerGrabPtr prevGrab, - XtServerGrabType prevGrabType, - XtServerGrabPtr devGrab, - XtServerGrabType devGrabType, - XtPerDisplayInput pdi) -{ - - Widget dspWidget; - Widget focusWidget; - - LOCK_PROCESS; - dspWidget = - focusWidget = - pdi->focusWidget = - _GetWindowedAncestor(FindFocusWidget(widget, pdi)); - - - /* - * If a grab is active from a previous activation then dispatch - * based on owner_events ala protocol but with focus being - * determined by XtSetKeyboardFocus. - */ - if (IsAnyGrab(prevGrabType)) - { - if (prevGrab->ownerEvents) - dspWidget = focusWidget; - else - dspWidget = prevGrab->widget; - } - else - { - /* - * If the focus widget is the event widget or a descendant - * then we can avoid the rest of this. Else ugh... - */ - if (focusWidget != widget) - { - XtGeneology ewRelFw; /* relationship of event widget to - focusWidget */ - Widget lca; - - lca = CommonAncestor(widget, focusWidget, &ewRelFw); - - /* - * if the event widget is an ancestor of focus due to the pointer - * and/or the grab being in an ancestor and it's a passive grab - * send to grab widget. - * we are also dispatching to widget if ownerEvents and the event - * is outside the client - */ - if ((ewRelFw == XtMyAncestor) && - (devGrabType == XtPassiveServerGrab)) - { - if (IsOutside(event, widget) || - event->type ==KeyPress - ) - dspWidget = devGrab->widget; - } - else - { - /* - * if the grab widget is not an ancestor of the focus - * release the grab in order to avoid locking. There - * is a possible case in that ownerEvents true will fall - * through and if synch is set and the event widget - * could turn it off we'll lock. check for it ? why not - */ - if ((ewRelFw != XtMyAncestor) - && (devGrabType == XtPassiveServerGrab) - && (!IsAnyGrab(prevGrabType)) - ) - { - XtUngrabKeyboard(devGrab->widget, - event->time); - devGrabType = XtNoServerGrab; - } - /* - * if there isn't a grab with then check - * for a logical grab that would have been activated - * if the server was using Xt focus instead of server - * focus - */ - if ( - (event->type != KeyPress) || - (event->keycode == 0) /* Xlib XIM composed input */ - ) - dspWidget = focusWidget; - else - { - XtServerGrabPtr grab; - - if (!pseudoTraceDepth || - !(focusWidget == pseudoTrace[0]) || - !(lca == pseudoTrace[pseudoTraceDepth])) - { - /* - * fill ancestor list from lca - * (non-inclusive)to focusWidget by - * passing in lca as breakWidget - */ - _XtFillAncestorList(&pseudoTrace, - &pseudoTraceMax, - &pseudoTraceDepth, - focusWidget, - lca); - /* ignore lca */ - pseudoTraceDepth--; - } - if ((grab = CheckServerGrabs((XEvent*)event, - pseudoTrace, - pseudoTraceDepth))) - { - XtDevice device = &pdi->keyboard; - - device->grabType = XtPseudoPassiveServerGrab; - pdi->activatingKey = event->keycode; - device->grab = *grab; - - if (grab - ) - dspWidget = grab->widget; - else - dspWidget = focusWidget; - } - } - } - } - } - UNLOCK_PROCESS; - return dspWidget; -} - -Widget _XtProcessKeyboardEvent( - XKeyEvent *event, - Widget widget, - XtPerDisplayInput pdi) -{ - XtDevice device = &pdi->keyboard; - XtServerGrabPtr newGrab, devGrab = &device->grab; - XtServerGrabRec prevGrabRec; - XtServerGrabType prevGrabType = device->grabType; - Widget dspWidget = NULL; - Boolean deactivateGrab = FALSE; - - prevGrabRec = *devGrab; - - switch (event->type) - { - case KeyPress: - { - if (event->keycode != 0 && /* Xlib XIM composed input */ - !IsServerGrab(device->grabType) && - (newGrab = CheckServerGrabs((XEvent*)event, - pdi->trace, - pdi->traceDepth))) - { - /* - * honor pseudo-grab from prior event by X - * unlocking keyboard. Not Xt Unlock ! - */ - if (IsPseudoGrab(prevGrabType)) - XUngrabKeyboard(XtDisplay(newGrab->widget), - event->time); - else - { - /* Activate the grab */ - device->grab = *newGrab; - pdi->activatingKey = event->keycode; - device->grabType = XtPassiveServerGrab; - } - } - } - break; - - case KeyRelease: - { - if (IsEitherPassiveGrab(device->grabType) && - (event->keycode == pdi->activatingKey)) - deactivateGrab = TRUE; - } - break; - } - dspWidget = FindKeyDestination(widget, event, - &prevGrabRec, prevGrabType, - devGrab, device->grabType, - pdi); - if (deactivateGrab) - { - /* Deactivate the grab */ - device->grabType = XtNoServerGrab; - pdi->activatingKey = 0; - } - return dspWidget; -} - -static Widget GetShell(Widget widget) -{ - Widget shell; - - for (shell = widget; - shell && !XtIsShell(shell); - shell = XtParent(shell)){} - return shell; -} - - -/* - * Check that widget really has Xt focus due to it having recieved an - * event - */ -typedef enum {NotActive = 0, IsActive, IsTarget} ActiveType; -static ActiveType InActiveSubtree(Widget widget) -{ - Boolean isTarget; - ActiveType retval; - - LOCK_PROCESS; - if (!pathTraceDepth || widget != pathTrace[0]) { - _XtFillAncestorList(&pathTrace, - &pathTraceMax, - &pathTraceDepth, - widget, - NULL); - } - if (widget == _FindFocusWidget(widget, - pathTrace, - pathTraceDepth, - TRUE, - &isTarget)) - retval = (isTarget ? IsTarget : IsActive); - else - retval = NotActive; - UNLOCK_PROCESS; - return retval; -} - - - - -/* ARGSUSED */ -void _XtHandleFocus( - Widget widget, - XtPointer client_data, /* child who wants focus */ - XEvent *event, - Boolean *cont) /* unused */ -{ - XtPerDisplayInput pdi = _XtGetPerDisplayInput(XtDisplay(widget)); - XtPerWidgetInput pwi = (XtPerWidgetInput)client_data; - XtGeneology oldFocalPoint = pwi->focalPoint; - XtGeneology newFocalPoint = pwi->focalPoint; - - switch( event->type ) { - - case KeyPress: - case KeyRelease: - /* - * We're getting the keyevents used to guarantee propagating - * child interest ala ForwardEvent in R3 - */ - return; - - case EnterNotify: - case LeaveNotify: - - /* - * If operating in a focus driven model, then enter and - * leave events do not affect the keyboard focus. - */ - if ((event->xcrossing.detail != NotifyInferior) - && (event->xcrossing.focus)) - { - switch (oldFocalPoint) - { - case XtMyAncestor: - if (event->type == LeaveNotify) - newFocalPoint = XtUnrelated; - break; - case XtUnrelated: - if (event->type == EnterNotify) - newFocalPoint = XtMyAncestor; - break; - case XtMySelf: - break; - case XtMyDescendant: - break; - - } - } - break; - case FocusIn: - switch (event->xfocus.detail) - { - case NotifyNonlinear: - case NotifyAncestor: - case NotifyInferior: - newFocalPoint = XtMySelf; - break; - case NotifyNonlinearVirtual: - case NotifyVirtual: - newFocalPoint = XtMyDescendant; - break; - case NotifyPointer: - newFocalPoint = XtMyAncestor; - break; - } - break; - case FocusOut: - switch (event->xfocus.detail) - { - case NotifyPointer: - case NotifyNonlinear: - case NotifyAncestor: - case NotifyNonlinearVirtual: - case NotifyVirtual: - newFocalPoint = XtUnrelated; - break; - case NotifyInferior: - newFocalPoint = XtMyDescendant; - return; - break; - } - break; - } - - if (newFocalPoint != oldFocalPoint) - { - Boolean add; - Widget descendant = pwi->focusKid; - - pwi->focalPoint = newFocalPoint; - - if ((oldFocalPoint == XtUnrelated) && - InActiveSubtree(widget) != NotActive) - { - pdi->focusWidget = NULL; /* invalidate the cache */ - pwi->haveFocus = TRUE; - add = TRUE; - } - else if (newFocalPoint == XtUnrelated) - { - pdi->focusWidget = NULL; /* invalidate the cache */ - pwi->haveFocus = FALSE; - add = FALSE; - } - else - return; - - if (descendant) - { - if (add) - { - _XtSendFocusEvent(descendant, FocusIn); - } - else - { - _XtSendFocusEvent(descendant, FocusOut); - } - } - } -} - - -static void AddFocusHandler( - Widget widget, - Widget descendant, - XtPerWidgetInput pwi, - XtPerWidgetInput psi, - XtPerDisplayInput pdi, - EventMask oldEventMask) -{ - EventMask eventMask, targetEventMask; - Widget target; - - /* - * widget must now select for key events if the descendant is - * interested in them. - * - * shell borders are not occluded by the child, they're occluded - * by reparenting window managers. !!! - */ - target = descendant ? _GetWindowedAncestor(descendant) : NULL; - targetEventMask = XtBuildEventMask(target); - eventMask = targetEventMask & (KeyPressMask | KeyReleaseMask); - eventMask |= FocusChangeMask | EnterWindowMask | LeaveWindowMask; - - if (oldEventMask) { - oldEventMask &= KeyPressMask | KeyReleaseMask; - oldEventMask |= FocusChangeMask | EnterWindowMask | LeaveWindowMask; - - if (oldEventMask != eventMask) - XtRemoveEventHandler(widget, (oldEventMask & ~eventMask), - False, _XtHandleFocus, (XtPointer)pwi); - } - - if (oldEventMask != eventMask) - XtAddEventHandler(widget, eventMask, False, - _XtHandleFocus, (XtPointer)pwi); - - /* What follows is too much grief to go through if the - * target doesn't actually care about focus change events, - * so just invalidate the focus cache & refill it when - * the next input event actually arrives. - */ - - if (!(targetEventMask & FocusChangeMask)) { - pdi->focusWidget = NULL; - return; - } - - if (XtIsRealized(widget) && !pwi->haveFocus) { - if (psi->haveFocus) { - Window root, child; - int root_x, root_y, win_x, win_y; - int left, right, top, bottom; - unsigned int modMask; - ActiveType act; - - /* - * If the shell has the focus but the source widget - * doesn't, it may only be because the source widget - * wasn't previously tracking focus or crossing events. - * If the target wants focus events, we have to - * now determine whether the source has the focus. - */ - - if ((act = InActiveSubtree(widget)) == IsTarget) - pwi->haveFocus = TRUE; - else if (act == IsActive) { - /* - * An ancestor contains the focus, so if source - * contains the pointer, then source has the focus. - */ - - if (XQueryPointer(XtDisplay(widget), XtWindow(widget), - &root, &child, - &root_x, &root_y, &win_x, &win_y, &modMask)) - { - /* We need to take borders into consideration */ - left = top = -((int) widget->core.border_width); - right = (int) (widget->core.width + (widget->core.border_width << 1)); - bottom = (int) (widget->core.height + (widget->core.border_width << 1)); - - if (win_x >= left && win_x < right && - win_y >= top && win_y < bottom) - pwi->haveFocus = TRUE; - } - } - } - } - if (pwi->haveFocus) { - pdi->focusWidget = NULL; /* invalidate the cache */ - _XtSendFocusEvent(target, FocusIn); - } -} - - -/* ARGSUSED */ -static void QueryEventMask( - Widget widget, /* child who gets focus */ - XtPointer client_data, /* ancestor giving it */ - XEvent *event, - Boolean *cont) /* unused */ -{ - /* widget was once the target of an XtSetKeyboardFocus but - * was unrealized at the time. Make sure ancestor still wants - * focus set here then install the handler now that we know the - * complete event mask. - */ - Widget ancestor = (Widget)client_data; - XtPerWidgetInput pwi = _XtGetPerWidgetInput(ancestor, FALSE); - Widget target = pwi->queryEventDescendant; - - /* use of 'target' is non-standard hackery; allows focus to non-widget */ - if (pwi && (pwi->focusKid == target)) { - AddFocusHandler(ancestor, target, pwi, - _XtGetPerWidgetInput(GetShell(ancestor), TRUE), - _XtGetPerDisplayInput(XtDisplay(ancestor)), - (EventMask)0); - } - XtRemoveEventHandler(widget, XtAllEvents, True, - QueryEventMask, client_data); - pwi->map_handler_added = FALSE; -} - - -/* ARGSUSED */ -static void FocusDestroyCallback( - Widget widget, - XtPointer closure, /* Widget */ - XtPointer call_data) -{ - XtSetKeyboardFocus((Widget)closure, NULL); -} - -void XtSetKeyboardFocus( - Widget widget, - Widget descendant) -{ - XtPerDisplayInput pdi; - XtPerWidgetInput pwi; - Widget oldDesc, oldTarget, target, hookobj; - WIDGET_TO_APPCON(widget); - - LOCK_APP(app); - LOCK_PROCESS; - pdi = _XtGetPerDisplayInput(XtDisplay(widget)); - pwi = _XtGetPerWidgetInput(widget, TRUE); - oldDesc = pwi->focusKid; - - if (descendant == widget) descendant = (Widget)None; - - target = descendant ? _GetWindowedAncestor(descendant) : NULL; - oldTarget = oldDesc ? _GetWindowedAncestor(oldDesc) : NULL; - - if (descendant != oldDesc) { - - /* update the forward path */ - pwi->focusKid = descendant; - - - /* all the rest handles focus ins and focus outs and misc gunk */ - - if (oldDesc) { - /* invalidate FindKeyDestination's ancestor list */ - if (pseudoTraceDepth && oldTarget == pseudoTrace[0]) - pseudoTraceDepth = 0; - - XtRemoveCallback(oldDesc, XtNdestroyCallback, - FocusDestroyCallback, (XtPointer)widget); - - if (!oldTarget->core.being_destroyed) { - if (pwi->map_handler_added) { - XtRemoveEventHandler(oldTarget, XtAllEvents, True, - QueryEventMask, (XtPointer)widget); - pwi->map_handler_added = FALSE; - } - if (pwi->haveFocus) { - _XtSendFocusEvent( oldTarget, FocusOut); - } - } - else if (pwi->map_handler_added) { - pwi->map_handler_added = FALSE; - } - - if (pwi->haveFocus) - pdi->focusWidget = NULL; /* invalidate cache */ - - /* - * If there was a forward path then remove the handler if - * the path is being set to null and it isn't a shell. - * shells always have a handler for tracking focus for the - * hierarchy. - * - * Keep the pwi record on the assumption that the client - * will continue to dynamically assign focus for this widget. - */ - if (!XtIsShell(widget) && !descendant) { - XtRemoveEventHandler(widget, XtAllEvents, True, - _XtHandleFocus, (XtPointer)pwi); - pwi->haveFocus = FALSE; - } - } - - if (descendant) { - Widget shell = GetShell(widget); - XtPerWidgetInput psi = _XtGetPerWidgetInput(shell, TRUE); - XtAddCallback (descendant, XtNdestroyCallback, - FocusDestroyCallback, (XtPointer) widget); - - AddFocusHandler(widget, descendant, pwi, psi, pdi, - oldTarget ? XtBuildEventMask(oldTarget) : 0); - - if (widget != shell) - XtAddEventHandler( - shell, - FocusChangeMask | EnterWindowMask | LeaveWindowMask, - False, - _XtHandleFocus, - (XtPointer)psi - ); - - if (! XtIsRealized(target)) { - XtAddEventHandler(target, (EventMask)StructureNotifyMask, - False, QueryEventMask, (XtPointer)widget); - pwi->map_handler_added = TRUE; - pwi->queryEventDescendant = descendant; - } - } - } - hookobj = XtHooksOfDisplay(XtDisplay(widget)); - if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { - XtChangeHookDataRec call_data; - - call_data.type = XtHsetKeyboardFocus; - call_data.widget = widget; - call_data.event_data = (XtPointer) descendant; - XtCallCallbackList(hookobj, - ((HookObject)hookobj)->hooks.changehook_callbacks, - (XtPointer)&call_data); - } - UNLOCK_PROCESS; - UNLOCK_APP(app); -} +/*
+
+Copyright (c) 1993, Oracle and/or its affiliates. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+/********************************************************
+
+Copyright 1988 by Hewlett-Packard Company
+Copyright 1987, 1988, 1989 by Digital Equipment Corporation, Maynard, Massachusetts
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that copyright notice and this permission
+notice appear in supporting documentation, and that the names of
+Hewlett-Packard or Digital not be used in advertising or
+publicity pertaining to distribution of the software without specific,
+written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+********************************************************/
+
+/*
+
+Copyright 1987, 1988, 1994, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "IntrinsicI.h"
+
+#include "PassivGraI.h"
+#include "EventI.h"
+
+#define _GetWindowedAncestor(w) (XtIsWidget(w) ? w : _XtWindowedAncestor(w))
+
+/* InActiveSubtree cache of the current focus source and its ancestors */
+static Widget *pathTrace = NULL;
+static int pathTraceDepth = 0;
+static int pathTraceMax = 0;
+
+/* FindKeyDestination cache of focus destination and ancestors up to source */
+static Widget *pseudoTrace = NULL;
+static int pseudoTraceDepth = 0;
+static int pseudoTraceMax = 0;
+
+void _XtClearAncestorCache(Widget widget)
+{
+ /* the caller must lock the process lock */
+ if (pathTraceDepth && pathTrace[0] == widget)
+ pathTraceDepth = 0;
+}
+
+static XtServerGrabPtr CheckServerGrabs(
+ XEvent *event,
+ Widget *trace,
+ Cardinal traceDepth)
+{
+ XtServerGrabPtr grab;
+ Cardinal i;
+
+ for (i = traceDepth; i > 0; i--)
+ {
+ if ((grab = _XtCheckServerGrabsOnWidget(event, trace[i-1], KEYBOARD)))
+ return (grab);
+ }
+ return (XtServerGrabPtr)0;
+}
+
+static Boolean IsParent(Widget a, Widget b)
+{
+ for (b = XtParent(b); b; b = XtParent(b)) {
+ if (b == a) return TRUE;
+ if (XtIsShell(b)) return FALSE;
+ }
+ return FALSE;
+}
+
+#define RelRtn(lca, type) {*relTypeRtn = type; return lca;}
+
+static Widget CommonAncestor(
+ register Widget a,
+ register Widget b,
+ XtGeneology * relTypeRtn)
+{
+ if (a == b)
+ {
+ RelRtn(a, XtMySelf)
+ }
+ else if (IsParent(a, b))
+ {
+ RelRtn(a, XtMyAncestor)
+ }
+ else if (IsParent(b, a))
+ {
+ RelRtn(b, XtMyDescendant)
+ }
+ else
+ for (b = XtParent(b);
+ b && !XtIsShell(b);
+ b = XtParent(b))
+ if (IsParent(b, a))
+ {
+ RelRtn(b, XtMyCousin)
+ }
+ RelRtn(NULL, XtUnrelated)
+}
+#undef RelRtn
+
+
+
+
+
+static Widget _FindFocusWidget(
+ Widget widget,
+ Widget *trace,
+ int traceDepth,
+ Boolean activeCheck,
+ Boolean *isTarget)
+{
+ int src;
+ Widget dst;
+ XtPerWidgetInput pwi = NULL;
+
+ /* For each ancestor, starting at the top, see if it's forwarded */
+
+
+ /* first check the trace list till done or we go to branch */
+ for (src = traceDepth-1, dst = widget; src > 0;)
+ {
+ if ((pwi = _XtGetPerWidgetInput(trace[src], FALSE)))
+ {
+ if (pwi->focusKid)
+ {
+ dst = pwi->focusKid;
+ for (src--; src > 0 && trace[src] != dst; src--) {}
+ }
+ else dst = trace[--src];
+ }
+ else dst = trace[--src];
+ }
+
+ if (isTarget) {
+ if (pwi && pwi->focusKid == widget)
+ *isTarget = TRUE;
+ else
+ *isTarget = FALSE;
+ }
+
+ if (!activeCheck)
+ while (XtIsWidget(dst)
+ && (pwi = _XtGetPerWidgetInput(dst, FALSE))
+ && pwi->focusKid)
+ dst = pwi->focusKid;
+
+ return dst;
+}
+
+
+static Widget FindFocusWidget(
+ Widget widget,
+ XtPerDisplayInput pdi)
+{
+ if (pdi->focusWidget)
+ return pdi->focusWidget;
+ else
+ return _FindFocusWidget(widget, pdi->trace, pdi->traceDepth, FALSE, NULL);
+}
+
+Widget XtGetKeyboardFocusWidget(Widget widget)
+{
+ XtPerDisplayInput pdi;
+ Widget retval;
+ WIDGET_TO_APPCON(widget);
+
+ LOCK_APP(app);
+ pdi = _XtGetPerDisplayInput(XtDisplay(widget));
+ retval = FindFocusWidget(widget, pdi);
+ UNLOCK_APP(app);
+ return retval;
+}
+
+static Boolean IsOutside(
+ XKeyEvent *e,
+ Widget w)
+{
+ Position left, right, top, bottom;
+
+ /*
+ * if the pointer is outside the shell or inside
+ * the window try to see if it would recieve the
+ * focus
+ */
+ XtTranslateCoords(w, 0, 0, &left, &top);
+ /* We need to take borders into consideration */
+ left = left - w->core.border_width;
+ top = top - w->core.border_width;
+ right = left + w->core.width + w->core.border_width;
+ bottom = top + w->core.height + w->core.border_width;
+
+ if (
+ (e->x_root < left) || (e->y_root < top) ||
+ (e->x_root > right) || (e->y_root > bottom))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static Widget FindKeyDestination(
+ Widget widget,
+ XKeyEvent *event,
+ XtServerGrabPtr prevGrab,
+ XtServerGrabType prevGrabType,
+ XtServerGrabPtr devGrab,
+ XtServerGrabType devGrabType,
+ XtPerDisplayInput pdi)
+{
+
+ Widget dspWidget;
+ Widget focusWidget;
+
+ LOCK_PROCESS;
+ dspWidget =
+ focusWidget =
+ pdi->focusWidget =
+ _GetWindowedAncestor(FindFocusWidget(widget, pdi));
+
+
+ /*
+ * If a grab is active from a previous activation then dispatch
+ * based on owner_events ala protocol but with focus being
+ * determined by XtSetKeyboardFocus.
+ */
+ if (IsAnyGrab(prevGrabType))
+ {
+ if (prevGrab->ownerEvents)
+ dspWidget = focusWidget;
+ else
+ dspWidget = prevGrab->widget;
+ }
+ else
+ {
+ /*
+ * If the focus widget is the event widget or a descendant
+ * then we can avoid the rest of this. Else ugh...
+ */
+ if (focusWidget != widget)
+ {
+ XtGeneology ewRelFw; /* relationship of event widget to
+ focusWidget */
+ Widget lca;
+
+ lca = CommonAncestor(widget, focusWidget, &ewRelFw);
+
+ /*
+ * if the event widget is an ancestor of focus due to the pointer
+ * and/or the grab being in an ancestor and it's a passive grab
+ * send to grab widget.
+ * we are also dispatching to widget if ownerEvents and the event
+ * is outside the client
+ */
+ if ((ewRelFw == XtMyAncestor) &&
+ (devGrabType == XtPassiveServerGrab))
+ {
+ if (IsOutside(event, widget) ||
+ event->type ==KeyPress
+ )
+ dspWidget = devGrab->widget;
+ }
+ else
+ {
+ /*
+ * if the grab widget is not an ancestor of the focus
+ * release the grab in order to avoid locking. There
+ * is a possible case in that ownerEvents true will fall
+ * through and if synch is set and the event widget
+ * could turn it off we'll lock. check for it ? why not
+ */
+ if ((ewRelFw != XtMyAncestor)
+ && (devGrabType == XtPassiveServerGrab)
+ && (!IsAnyGrab(prevGrabType))
+ )
+ {
+ XtUngrabKeyboard(devGrab->widget,
+ event->time);
+ devGrabType = XtNoServerGrab;
+ }
+ /*
+ * if there isn't a grab with then check
+ * for a logical grab that would have been activated
+ * if the server was using Xt focus instead of server
+ * focus
+ */
+ if (
+ (event->type != KeyPress) ||
+ (event->keycode == 0) /* Xlib XIM composed input */
+ )
+ dspWidget = focusWidget;
+ else
+ {
+ XtServerGrabPtr grab;
+
+ if (!pseudoTraceDepth ||
+ !(focusWidget == pseudoTrace[0]) ||
+ !(lca == pseudoTrace[pseudoTraceDepth]))
+ {
+ /*
+ * fill ancestor list from lca
+ * (non-inclusive)to focusWidget by
+ * passing in lca as breakWidget
+ */
+ _XtFillAncestorList(&pseudoTrace,
+ &pseudoTraceMax,
+ &pseudoTraceDepth,
+ focusWidget,
+ lca);
+ /* ignore lca */
+ pseudoTraceDepth--;
+ }
+ if ((grab = CheckServerGrabs((XEvent*)event,
+ pseudoTrace,
+ pseudoTraceDepth)))
+ {
+ XtDevice device = &pdi->keyboard;
+
+ device->grabType = XtPseudoPassiveServerGrab;
+ pdi->activatingKey = event->keycode;
+ device->grab = *grab;
+
+ if (grab
+ )
+ dspWidget = grab->widget;
+ else
+ dspWidget = focusWidget;
+ }
+ }
+ }
+ }
+ }
+ UNLOCK_PROCESS;
+ return dspWidget;
+}
+
+Widget _XtProcessKeyboardEvent(
+ XKeyEvent *event,
+ Widget widget,
+ XtPerDisplayInput pdi)
+{
+ XtDevice device = &pdi->keyboard;
+ XtServerGrabPtr newGrab, devGrab = &device->grab;
+ XtServerGrabRec prevGrabRec;
+ XtServerGrabType prevGrabType = device->grabType;
+ Widget dspWidget = NULL;
+ Boolean deactivateGrab = FALSE;
+
+ prevGrabRec = *devGrab;
+
+ switch (event->type)
+ {
+ case KeyPress:
+ {
+ if (event->keycode != 0 && /* Xlib XIM composed input */
+ !IsServerGrab(device->grabType) &&
+ (newGrab = CheckServerGrabs((XEvent*)event,
+ pdi->trace,
+ pdi->traceDepth)))
+ {
+ /*
+ * honor pseudo-grab from prior event by X
+ * unlocking keyboard. Not Xt Unlock !
+ */
+ if (IsPseudoGrab(prevGrabType))
+ XUngrabKeyboard(XtDisplay(newGrab->widget),
+ event->time);
+ else
+ {
+ /* Activate the grab */
+ device->grab = *newGrab;
+ pdi->activatingKey = event->keycode;
+ device->grabType = XtPassiveServerGrab;
+ }
+ }
+ }
+ break;
+
+ case KeyRelease:
+ {
+ if (IsEitherPassiveGrab(device->grabType) &&
+ (event->keycode == pdi->activatingKey))
+ deactivateGrab = TRUE;
+ }
+ break;
+ }
+ dspWidget = FindKeyDestination(widget, event,
+ &prevGrabRec, prevGrabType,
+ devGrab, device->grabType,
+ pdi);
+ if (deactivateGrab)
+ {
+ /* Deactivate the grab */
+ device->grabType = XtNoServerGrab;
+ pdi->activatingKey = 0;
+ }
+ return dspWidget;
+}
+
+static Widget GetShell(Widget widget)
+{
+ Widget shell;
+
+ for (shell = widget;
+ shell && !XtIsShell(shell);
+ shell = XtParent(shell)){}
+ return shell;
+}
+
+
+/*
+ * Check that widget really has Xt focus due to it having recieved an
+ * event
+ */
+typedef enum {NotActive = 0, IsActive, IsTarget} ActiveType;
+static ActiveType InActiveSubtree(Widget widget)
+{
+ Boolean isTarget;
+ ActiveType retval;
+
+ LOCK_PROCESS;
+ if (!pathTraceDepth || widget != pathTrace[0]) {
+ _XtFillAncestorList(&pathTrace,
+ &pathTraceMax,
+ &pathTraceDepth,
+ widget,
+ NULL);
+ }
+ if (widget == _FindFocusWidget(widget,
+ pathTrace,
+ pathTraceDepth,
+ TRUE,
+ &isTarget))
+ retval = (isTarget ? IsTarget : IsActive);
+ else
+ retval = NotActive;
+ UNLOCK_PROCESS;
+ return retval;
+}
+
+
+
+
+/* ARGSUSED */
+void _XtHandleFocus(
+ Widget widget,
+ XtPointer client_data, /* child who wants focus */
+ XEvent *event,
+ Boolean *cont) /* unused */
+{
+ XtPerDisplayInput pdi = _XtGetPerDisplayInput(XtDisplay(widget));
+ XtPerWidgetInput pwi = (XtPerWidgetInput)client_data;
+ XtGeneology oldFocalPoint = pwi->focalPoint;
+ XtGeneology newFocalPoint = pwi->focalPoint;
+
+ switch( event->type ) {
+
+ case KeyPress:
+ case KeyRelease:
+ /*
+ * We're getting the keyevents used to guarantee propagating
+ * child interest ala ForwardEvent in R3
+ */
+ return;
+
+ case EnterNotify:
+ case LeaveNotify:
+
+ /*
+ * If operating in a focus driven model, then enter and
+ * leave events do not affect the keyboard focus.
+ */
+ if ((event->xcrossing.detail != NotifyInferior)
+ && (event->xcrossing.focus))
+ {
+ switch (oldFocalPoint)
+ {
+ case XtMyAncestor:
+ if (event->type == LeaveNotify)
+ newFocalPoint = XtUnrelated;
+ break;
+ case XtUnrelated:
+ if (event->type == EnterNotify)
+ newFocalPoint = XtMyAncestor;
+ break;
+ case XtMySelf:
+ break;
+ case XtMyDescendant:
+ break;
+
+ }
+ }
+ break;
+ case FocusIn:
+ switch (event->xfocus.detail)
+ {
+ case NotifyNonlinear:
+ case NotifyAncestor:
+ case NotifyInferior:
+ newFocalPoint = XtMySelf;
+ break;
+ case NotifyNonlinearVirtual:
+ case NotifyVirtual:
+ newFocalPoint = XtMyDescendant;
+ break;
+ case NotifyPointer:
+ newFocalPoint = XtMyAncestor;
+ break;
+ }
+ break;
+ case FocusOut:
+ switch (event->xfocus.detail)
+ {
+ case NotifyPointer:
+ case NotifyNonlinear:
+ case NotifyAncestor:
+ case NotifyNonlinearVirtual:
+ case NotifyVirtual:
+ newFocalPoint = XtUnrelated;
+ break;
+ case NotifyInferior:
+ newFocalPoint = XtMyDescendant;
+ return;
+ break;
+ }
+ break;
+ }
+
+ if (newFocalPoint != oldFocalPoint)
+ {
+ Boolean add;
+ Widget descendant = pwi->focusKid;
+
+ pwi->focalPoint = newFocalPoint;
+
+ if ((oldFocalPoint == XtUnrelated) &&
+ InActiveSubtree(widget) != NotActive)
+ {
+ pdi->focusWidget = NULL; /* invalidate the cache */
+ pwi->haveFocus = TRUE;
+ add = TRUE;
+ }
+ else if (newFocalPoint == XtUnrelated)
+ {
+ pdi->focusWidget = NULL; /* invalidate the cache */
+ pwi->haveFocus = FALSE;
+ add = FALSE;
+ }
+ else
+ return;
+
+ if (descendant)
+ {
+ if (add)
+ {
+ _XtSendFocusEvent(descendant, FocusIn);
+ }
+ else
+ {
+ _XtSendFocusEvent(descendant, FocusOut);
+ }
+ }
+ }
+}
+
+
+static void AddFocusHandler(
+ Widget widget,
+ Widget descendant,
+ XtPerWidgetInput pwi,
+ XtPerWidgetInput psi,
+ XtPerDisplayInput pdi,
+ EventMask oldEventMask)
+{
+ EventMask eventMask, targetEventMask;
+ Widget target;
+
+ /*
+ * widget must now select for key events if the descendant is
+ * interested in them.
+ *
+ * shell borders are not occluded by the child, they're occluded
+ * by reparenting window managers. !!!
+ */
+ target = descendant ? _GetWindowedAncestor(descendant) : NULL;
+ targetEventMask = XtBuildEventMask(target);
+ eventMask = targetEventMask & (KeyPressMask | KeyReleaseMask);
+ eventMask |= FocusChangeMask | EnterWindowMask | LeaveWindowMask;
+
+ if (oldEventMask) {
+ oldEventMask &= KeyPressMask | KeyReleaseMask;
+ oldEventMask |= FocusChangeMask | EnterWindowMask | LeaveWindowMask;
+
+ if (oldEventMask != eventMask)
+ XtRemoveEventHandler(widget, (oldEventMask & ~eventMask),
+ False, _XtHandleFocus, (XtPointer)pwi);
+ }
+
+ if (oldEventMask != eventMask)
+ XtAddEventHandler(widget, eventMask, False,
+ _XtHandleFocus, (XtPointer)pwi);
+
+ /* What follows is too much grief to go through if the
+ * target doesn't actually care about focus change events,
+ * so just invalidate the focus cache & refill it when
+ * the next input event actually arrives.
+ */
+
+ if (!(targetEventMask & FocusChangeMask)) {
+ pdi->focusWidget = NULL;
+ return;
+ }
+
+ if (XtIsRealized(widget) && !pwi->haveFocus) {
+ if (psi->haveFocus) {
+ Window root, child;
+ int root_x, root_y, win_x, win_y;
+ int left, right, top, bottom;
+ unsigned int modMask;
+ ActiveType act;
+
+ /*
+ * If the shell has the focus but the source widget
+ * doesn't, it may only be because the source widget
+ * wasn't previously tracking focus or crossing events.
+ * If the target wants focus events, we have to
+ * now determine whether the source has the focus.
+ */
+
+ if ((act = InActiveSubtree(widget)) == IsTarget)
+ pwi->haveFocus = TRUE;
+ else if (act == IsActive) {
+ /*
+ * An ancestor contains the focus, so if source
+ * contains the pointer, then source has the focus.
+ */
+
+ if (XQueryPointer(XtDisplay(widget), XtWindow(widget),
+ &root, &child,
+ &root_x, &root_y, &win_x, &win_y, &modMask))
+ {
+ /* We need to take borders into consideration */
+ left = top = -((int) widget->core.border_width);
+ right = (int) (widget->core.width + (widget->core.border_width << 1));
+ bottom = (int) (widget->core.height + (widget->core.border_width << 1));
+
+ if (win_x >= left && win_x < right &&
+ win_y >= top && win_y < bottom)
+ pwi->haveFocus = TRUE;
+ }
+ }
+ }
+ }
+ if (pwi->haveFocus) {
+ pdi->focusWidget = NULL; /* invalidate the cache */
+ _XtSendFocusEvent(target, FocusIn);
+ }
+}
+
+
+/* ARGSUSED */
+static void QueryEventMask(
+ Widget widget, /* child who gets focus */
+ XtPointer client_data, /* ancestor giving it */
+ XEvent *event,
+ Boolean *cont) /* unused */
+{
+ /* widget was once the target of an XtSetKeyboardFocus but
+ * was unrealized at the time. Make sure ancestor still wants
+ * focus set here then install the handler now that we know the
+ * complete event mask.
+ */
+ Widget ancestor = (Widget)client_data;
+ XtPerWidgetInput pwi = _XtGetPerWidgetInput(ancestor, FALSE);
+
+ if (pwi) {
+ Widget target = pwi->queryEventDescendant;
+
+ /* use of 'target' is non-standard hackery;
+ allows focus to non-widget */
+ if ( pwi->focusKid == target ) {
+ AddFocusHandler(ancestor, target, pwi,
+ _XtGetPerWidgetInput(GetShell(ancestor), TRUE),
+ _XtGetPerDisplayInput(XtDisplay(ancestor)),
+ (EventMask)0);
+ }
+ XtRemoveEventHandler(widget, XtAllEvents, True,
+ QueryEventMask, client_data);
+ pwi->map_handler_added = FALSE;
+ }
+}
+
+
+/* ARGSUSED */
+static void FocusDestroyCallback(
+ Widget widget,
+ XtPointer closure, /* Widget */
+ XtPointer call_data)
+{
+ XtSetKeyboardFocus((Widget)closure, NULL);
+}
+
+void XtSetKeyboardFocus(
+ Widget widget,
+ Widget descendant)
+{
+ XtPerDisplayInput pdi;
+ XtPerWidgetInput pwi;
+ Widget oldDesc, oldTarget, target, hookobj;
+ WIDGET_TO_APPCON(widget);
+
+ LOCK_APP(app);
+ LOCK_PROCESS;
+ pdi = _XtGetPerDisplayInput(XtDisplay(widget));
+ pwi = _XtGetPerWidgetInput(widget, TRUE);
+ oldDesc = pwi->focusKid;
+
+ if (descendant == widget) descendant = (Widget)None;
+
+ target = descendant ? _GetWindowedAncestor(descendant) : NULL;
+ oldTarget = oldDesc ? _GetWindowedAncestor(oldDesc) : NULL;
+
+ if (descendant != oldDesc) {
+
+ /* update the forward path */
+ pwi->focusKid = descendant;
+
+
+ /* all the rest handles focus ins and focus outs and misc gunk */
+
+ if (oldDesc) {
+ /* invalidate FindKeyDestination's ancestor list */
+ if (pseudoTraceDepth && oldTarget == pseudoTrace[0])
+ pseudoTraceDepth = 0;
+
+ XtRemoveCallback(oldDesc, XtNdestroyCallback,
+ FocusDestroyCallback, (XtPointer)widget);
+
+ if (!oldTarget->core.being_destroyed) {
+ if (pwi->map_handler_added) {
+ XtRemoveEventHandler(oldTarget, XtAllEvents, True,
+ QueryEventMask, (XtPointer)widget);
+ pwi->map_handler_added = FALSE;
+ }
+ if (pwi->haveFocus) {
+ _XtSendFocusEvent( oldTarget, FocusOut);
+ }
+ }
+ else if (pwi->map_handler_added) {
+ pwi->map_handler_added = FALSE;
+ }
+
+ if (pwi->haveFocus)
+ pdi->focusWidget = NULL; /* invalidate cache */
+
+ /*
+ * If there was a forward path then remove the handler if
+ * the path is being set to null and it isn't a shell.
+ * shells always have a handler for tracking focus for the
+ * hierarchy.
+ *
+ * Keep the pwi record on the assumption that the client
+ * will continue to dynamically assign focus for this widget.
+ */
+ if (!XtIsShell(widget) && !descendant) {
+ XtRemoveEventHandler(widget, XtAllEvents, True,
+ _XtHandleFocus, (XtPointer)pwi);
+ pwi->haveFocus = FALSE;
+ }
+ }
+
+ if (descendant) {
+ Widget shell = GetShell(widget);
+ XtPerWidgetInput psi = _XtGetPerWidgetInput(shell, TRUE);
+ XtAddCallback (descendant, XtNdestroyCallback,
+ FocusDestroyCallback, (XtPointer) widget);
+
+ AddFocusHandler(widget, descendant, pwi, psi, pdi,
+ oldTarget ? XtBuildEventMask(oldTarget) : 0);
+
+ if (widget != shell)
+ XtAddEventHandler(
+ shell,
+ FocusChangeMask | EnterWindowMask | LeaveWindowMask,
+ False,
+ _XtHandleFocus,
+ (XtPointer)psi
+ );
+
+ if (! XtIsRealized(target)) {
+ XtAddEventHandler(target, (EventMask)StructureNotifyMask,
+ False, QueryEventMask, (XtPointer)widget);
+ pwi->map_handler_added = TRUE;
+ pwi->queryEventDescendant = descendant;
+ }
+ }
+ }
+ hookobj = XtHooksOfDisplay(XtDisplay(widget));
+ if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
+ XtChangeHookDataRec call_data;
+
+ call_data.type = XtHsetKeyboardFocus;
+ call_data.widget = widget;
+ call_data.event_data = (XtPointer) descendant;
+ XtCallCallbackList(hookobj,
+ ((HookObject)hookobj)->hooks.changehook_callbacks,
+ (XtPointer)&call_data);
+ }
+ UNLOCK_PROCESS;
+ UNLOCK_APP(app);
+}
|