#include "IntrinsicI.h"
#include "PassivGraI.h"
#include "EventI.h"
#define _GetWindowedAncestor(w) (XtIsWidget(w) ? w : _XtWindowedAncestor(w))
extern void _XtSendFocusEvent();
static Widget *pathTrace = NULL;
static int pathTraceDepth = 0;
static int pathTraceMax = 0;
static Widget *pseudoTrace = NULL;
static int pseudoTraceDepth = 0;
static int pseudoTraceMax = 0;
void _XtClearAncestorCache(widget)
Widget widget;
{
if (pathTraceDepth && pathTrace[0] == widget)
pathTraceDepth = 0;
}
static XtServerGrabPtr CheckServerGrabs(event, trace, traceDepth)
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(a, b)
Widget a, 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(a, b, relTypeRtn)
register Widget a, 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, trace, traceDepth, activeCheck, isTarget)
Widget widget;
Widget *trace;
int traceDepth;
Boolean activeCheck;
Boolean *isTarget;
{
int src;
Widget dst;
XtPerWidgetInput pwi = NULL;
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, pdi)
Widget widget;
XtPerDisplayInput pdi;
{
if (pdi->focusWidget)
return pdi->focusWidget;
else
return _FindFocusWidget(widget, pdi->trace, pdi->traceDepth, FALSE, NULL);
}
Widget XtGetKeyboardFocusWidget(widget)
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(e, w)
XKeyEvent *e;
Widget w;
{
Position left, right, top, bottom;
XtTranslateCoords(w, 0, 0, &left, &top);
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, event,
prevGrab, prevGrabType,
devGrab, devGrabType,
pdi)
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 (IsAnyGrab(prevGrabType))
{
if (prevGrab->ownerEvents)
dspWidget = focusWidget;
else
dspWidget = prevGrab->widget;
}
else
{
if (focusWidget != widget)
{
XtGeneology ewRelFw;
Widget lca;
lca = CommonAncestor(widget, focusWidget, &ewRelFw);
if ((ewRelFw == XtMyAncestor) &&
(devGrabType == XtPassiveServerGrab))
{
if (IsOutside(event, widget) ||
event->type ==KeyPress
)
dspWidget = devGrab->widget;
}
else
{
if ((ewRelFw != XtMyAncestor)
&& (devGrabType == XtPassiveServerGrab)
&& (!IsAnyGrab(prevGrabType))
)
{
XtUngrabKeyboard(devGrab->widget,
event->time);
devGrabType = XtNoServerGrab;
}
if (
(event->type != KeyPress) ||
(event->keycode == 0)
)
dspWidget = focusWidget;
else
{
XtServerGrabPtr grab;
if (!pseudoTraceDepth ||
!(focusWidget == pseudoTrace[0]) ||
!(lca == pseudoTrace[pseudoTraceDepth]))
{
_XtFillAncestorList(&pseudoTrace,
&pseudoTraceMax,
&pseudoTraceDepth,
focusWidget,
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(event, widget, pdi)
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 &&
!IsServerGrab(device->grabType) &&
(newGrab = CheckServerGrabs((XEvent*)event,
pdi->trace,
pdi->traceDepth)))
{
if (IsPseudoGrab(prevGrabType))
XUngrabKeyboard(XtDisplay(newGrab->widget),
event->time);
else
{
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)
{
device->grabType = XtNoServerGrab;
pdi->activatingKey = 0;
}
return dspWidget;
}
static Widget GetShell(widget)
Widget widget;
{
Widget shell;
for (shell = widget;
shell && !XtIsShell(shell);
shell = XtParent(shell)){}
return shell;
}
typedef enum {NotActive = 0, IsActive, IsTarget} ActiveType;
static ActiveType InActiveSubtree(widget)
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;
}
void _XtHandleFocus(widget, client_data, event, cont)
Widget widget;
XtPointer client_data;
XEvent *event;
Boolean *cont;
{
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:
return;
case EnterNotify:
case LeaveNotify:
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;
pwi->haveFocus = TRUE;
add = TRUE;
}
else if (newFocalPoint == XtUnrelated)
{
pdi->focusWidget = NULL;
pwi->haveFocus = FALSE;
add = FALSE;
}
else
return;
if (descendant)
{
if (add)
{
_XtSendFocusEvent(descendant, FocusIn);
}
else
{
_XtSendFocusEvent(descendant, FocusOut);
}
}
}
}
static void AddFocusHandler(widget, descendant, pwi, psi, pdi, oldEventMask)
Widget widget, descendant;
XtPerWidgetInput pwi;
XtPerWidgetInput psi;
XtPerDisplayInput pdi;
EventMask oldEventMask;
{
EventMask eventMask, targetEventMask;
Widget target;
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);
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 ((act = InActiveSubtree(widget)) == IsTarget)
pwi->haveFocus = TRUE;
else if (act == IsActive) {
if (XQueryPointer(XtDisplay(widget), XtWindow(widget),
&root, &child,
&root_x, &root_y, &win_x, &win_y, &modMask))
{
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;
_XtSendFocusEvent(target, FocusIn);
}
}
static void QueryEventMask(widget, client_data, event, cont)
Widget widget;
XtPointer client_data;
XEvent *event;
Boolean *cont;
{
Widget ancestor = (Widget)client_data;
XtPerWidgetInput pwi = _XtGetPerWidgetInput(ancestor, FALSE);
Widget target = pwi->queryEventDescendant;
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;
}
static void FocusDestroyCallback(widget, closure, call_data)
Widget widget;
XtPointer closure;
XtPointer call_data;
{
XtSetKeyboardFocus((Widget)closure, None);
}
void XtSetKeyboardFocus(widget, descendant)
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) {
pwi->focusKid = descendant;
if (oldDesc) {
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;
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);
}