DataMuseum.dk

Presents historical artifacts from the history of:

Rational R1000/400 Tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Rational R1000/400 Tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download
Index: ┃ E T

⟦bfe2fd956⟧ TextFile

    Length: 33382 (0x8266)
    Types: TextFile
    Names: »Event.c«

Derivation

└─⟦5f3412b64⟧ Bits:30000745 8mm tape, Rational 1000, ENVIRONMENT 12_6_5 TOOLS 
    └─ ⟦91c658230⟧ »DATA« 
        └─⟦5d656759a⟧ 
            └─⟦144d629ab⟧ 
                └─ ⟦this⟧ »./Xt/Event.c« 
└─⟦5f3412b64⟧ Bits:30000745 8mm tape, Rational 1000, ENVIRONMENT 12_6_5 TOOLS 
    └─ ⟦91c658230⟧ »DATA« 
        └─⟦5d656759a⟧ 
            └─⟦34224b4fb⟧ 
                └─ ⟦this⟧ »./Xt/Event.c« 
└─⟦5f3412b64⟧ Bits:30000745 8mm tape, Rational 1000, ENVIRONMENT 12_6_5 TOOLS 
    └─ ⟦91c658230⟧ »DATA« 
        └─⟦5d656759a⟧ 
            └─⟦5cb9d2efd⟧ 
                └─ ⟦this⟧ »./Xt/Event.c« 
└─⟦5f3412b64⟧ Bits:30000745 8mm tape, Rational 1000, ENVIRONMENT 12_6_5 TOOLS 
    └─ ⟦91c658230⟧ »DATA« 
        └─⟦5d656759a⟧ 
            └─⟦7d9cab9a9⟧ 
└─⟦d10a02448⟧ Bits:30000409 8mm tape, Rational 1000, ENVIRONMENT, D_12_7_3
    └─ ⟦fc9b38f02⟧ »DATA« 
        └─⟦8e9e227a9⟧ 
            └─⟦7d9cab9a9⟧ 
                └─ ⟦this⟧ »./Xt/Event.c« 
└─⟦5f3412b64⟧ Bits:30000745 8mm tape, Rational 1000, ENVIRONMENT 12_6_5 TOOLS 
    └─ ⟦91c658230⟧ »DATA« 
        └─⟦5d656759a⟧ 
            └─⟦85ff0a957⟧ 
└─⟦d10a02448⟧ Bits:30000409 8mm tape, Rational 1000, ENVIRONMENT, D_12_7_3
    └─ ⟦fc9b38f02⟧ »DATA« 
        └─⟦8e9e227a9⟧ 
            └─⟦85ff0a957⟧ 
                └─ ⟦this⟧ »./Xt/Event.c« 
└─⟦5f3412b64⟧ Bits:30000745 8mm tape, Rational 1000, ENVIRONMENT 12_6_5 TOOLS 
    └─ ⟦91c658230⟧ »DATA« 
        └─⟦5d656759a⟧ 
            └─⟦afaca67b5⟧ 
└─⟦d10a02448⟧ Bits:30000409 8mm tape, Rational 1000, ENVIRONMENT, D_12_7_3
    └─ ⟦fc9b38f02⟧ »DATA« 
        └─⟦8e9e227a9⟧ 
            └─⟦afaca67b5⟧ 
                └─ ⟦this⟧ »./Xt/Event.c« 
└─⟦d10a02448⟧ Bits:30000409 8mm tape, Rational 1000, ENVIRONMENT, D_12_7_3
    └─ ⟦fc9b38f02⟧ »DATA« 
        └─⟦8e9e227a9⟧ 
            └─⟦e9895db93⟧ 
                └─ ⟦this⟧ »./Xt/Event.c« 

TextFile

#ifndef lint
static char Xrcsid[] = "$XConsortium: Event.c,v 1.90 88/10/21 08:43:10 swick Exp $";
/* $oHeader: Event.c,v 1.9 88/09/01 11:33:51 asente Exp $ */
#endif lint

/***********************************************************
Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
and the Massachusetts Institute of Technology, Cambridge, Massachusetts.

                        All Rights Reserved

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 Digital or MIT 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.

******************************************************************/

#include "IntrinsicI.h"
#include "Shell.h"
#include "StringDefs.h"

static XtAsyncHandler asyncHandler = NULL;
static caddr_t asyncClosure = NULL;

static GrabList grabList;	/* %%% should this be in the AppContext? */
static GrabList focusList;	/* %%% should this be in the AppContext? */
static Boolean focusTraceGood;	/* %%% ditto */

extern void bzero();

CallbackList *_XtDestroyList;

EventMask XtBuildEventMask(widget)
    Widget widget;
{
    XtEventTable ev;
    EventMask	mask = 0L;

    for (ev = widget->core.event_table; ev != NULL; ev = ev->next)
	if (ev->select) mask |= ev->mask;
    if (widget->core.widget_class->core_class.expose != NULL)
	mask |= ExposureMask;
    if (widget->core.widget_class->core_class.visible_interest) 
	mask |= VisibilityChangeMask;

    return mask;
}

static void RemoveEventHandler(widget, eventMask, other, proc, closure, raw,
			       check_closure)
    Widget	widget;
    EventMask   eventMask;
    Boolean	other;
    XtEventHandler proc;
    caddr_t	closure;
    Boolean	raw;
    Boolean	check_closure;
{
    XtEventRec *p, **pp;
    EventMask oldMask = XtBuildEventMask(widget);

    pp = &widget->core.event_table;
    p = *pp;

    /* find it */
    while (p != NULL &&
	   (p->proc != proc || (check_closure && p->closure != closure))) {
	pp = &p->next;
	p = *pp;
    }
    if (p == NULL) return; /* couldn't find it */
    if (raw) p->raw = FALSE; else p->select = FALSE;
    if (p->raw || p->select) return;

    /* un-register it */
    p->mask &= ~eventMask;
    if (other) p->non_filter = FALSE;

    if (p->mask == 0 && !p->non_filter) {
	/* delete it entirely */
	*pp = p->next;
	XtFree((char *)p);
    }

    /* reset select mask if realized */
    if (XtIsRealized(widget)&& !widget->core.being_destroyed) {
	EventMask mask = XtBuildEventMask(widget);

	if (oldMask != mask) {
	    XSelectInput(XtDisplay(widget), XtWindow(widget), mask);
#ifdef notdef
	    if (asyncHandler != NULL) {
		XSelectAsyncInput(
		    XtDisplay(widget), XtWindow(widget), mask,
		    asyncHandler, (unsigned long) XtDisplay(widget));
	    }
#endif /*notdef*/
	}
    }
}

static void AddEventHandler(widget, eventMask, other, proc, closure, raw,
			    check_closure)
    Widget	    widget;
    EventMask   eventMask;
    Boolean         other;
    XtEventHandler  proc;
    caddr_t	closure;
    Boolean	raw;
    Boolean	check_closure;
{
   register XtEventRec *p,**pp;
   EventMask oldMask;

   if (eventMask == 0 && other == FALSE) return;

   if (XtIsRealized(widget) && ! raw) oldMask = XtBuildEventMask(widget);

   pp = & widget->core.event_table;
   p = *pp;
   while (p != NULL &&
	  (p->proc != proc || (check_closure && p->closure != closure))) {
         pp = &p->next;
         p = *pp;
   }

   if (p == NULL) {
	/* new proc to add to list */
	p = XtNew(XtEventRec);
	p->proc = proc;
	p->closure = closure;
	p->mask = eventMask;
	p->non_filter = other;
	p->select = ! raw;
	p->raw = raw;

	p->next = widget->core.event_table;
	widget->core.event_table = p;

    } else {
	/* update existing proc */
	p->mask |= eventMask;
	p->non_filter = p->non_filter || other;
	p->select |= ! raw;
	p->raw |= raw;
	if (!check_closure) p->closure = closure;
    }

    if (XtIsRealized(widget) && ! raw) {
	EventMask mask = XtBuildEventMask(widget);

	if (oldMask != mask) {
	    XSelectInput(XtDisplay(widget), XtWindow(widget), mask);
#ifdef notdef
	    if (asyncHandler != NULL) {
		XSelectAsyncInput(
		    XtDisplay(widget), XtWindow(widget), mask,
		    asyncHandler, (unsigned long)XtDisplay(widget));
	    }
#endif /*notdef*/
	}
    }

}


void XtRemoveEventHandler(widget, eventMask, other, proc, closure)
    Widget	widget;
    EventMask   eventMask;
    Boolean	other;
    XtEventHandler proc;
    caddr_t	closure;
{
    RemoveEventHandler(widget, eventMask, other, proc, closure, FALSE, TRUE);
}


void XtAddEventHandler(widget, eventMask, other, proc, closure)
    Widget	    widget;
    EventMask   eventMask;
    Boolean         other;
    XtEventHandler  proc;
    caddr_t	closure;
{
    AddEventHandler(widget, eventMask, other, proc, closure, FALSE, TRUE);
}


void XtRemoveRawEventHandler(widget, eventMask, other, proc, closure)
    Widget	widget;
    EventMask   eventMask;
    Boolean	other;
    XtEventHandler proc;
    caddr_t	closure;
{
    RemoveEventHandler(widget, eventMask, other, proc, closure, TRUE, TRUE);
}


void XtAddRawEventHandler(widget, eventMask, other, proc, closure)
    Widget	    widget;
    EventMask   eventMask;
    Boolean         other;
    XtEventHandler  proc;
    caddr_t	closure;
{
    AddEventHandler(widget, eventMask, other, proc, closure, TRUE, TRUE);
}


typedef struct _HashRec *HashPtr;

typedef struct _HashRec {
    Display	*display;
    Window	window;
    Widget	widget;
    HashPtr	next;
} HashRec;

typedef struct {
    unsigned int	size;
    unsigned int	count;
    HashPtr		entries[1];
} HashTableRec, *HashTable;

static HashTable table = NULL;

static void ExpandTable();

void _XtRegisterWindow(window, widget)
    Window window;
    Widget widget;
{
    register HashPtr hp, *hpp;

    if ((table->count + (table->count / 4)) >= table->size) ExpandTable();

    hpp = &table->entries[(unsigned int)window & (table->size-1)];
    hp = *hpp;

    while (hp != NULL) {
        if (hp->window == window && hp->display == XtDisplay(widget)) {
	    if (hp->widget != widget)
		XtAppWarningMsg(XtWidgetToApplicationContext(widget),
			"registerWindowError","xtRegisterWindow",
                         "XtToolkitError",
                        "Attempt to change already registered window.",
                          (String *)NULL, (Cardinal *)NULL);
	    return;
	}
        hpp = &hp->next;
	hp = *hpp;
    }

    hp = *hpp = XtNew(HashRec);
    hp->display = XtDisplay(widget);
    hp->window = window;
    hp->widget = widget;
    hp->next = NULL;
    table->count++;
}


void _XtUnregisterWindow(window, widget)
    Window window;
    Widget widget;
{
    HashPtr hp, *hpp;

    hpp = &table->entries[(unsigned int)window  & (table->size-1)];
    hp = *hpp;

    while (hp != NULL) {
        if (hp->window == window && hp->display == XtDisplay(widget)) {
	    if (hp->widget != widget) {
                XtAppWarningMsg(XtWidgetToApplicationContext(widget),
			"registerWindowError","xtUnregisterWindow",
                         "XtToolkitError",
                        "Attempt to unregister invalid window.",
                          (String *)NULL, (Cardinal *)NULL);

                return;
                }
             else /* found entry to delete */
                  (*hpp) = hp->next;
                  XtFree((char*)hp);
                  table->count--;
                  return;
	}
        hpp = &hp->next;
	hp = *hpp;
    }
    
}

static void ExpandTable()
{
    HashTable	oldTable = table;
    unsigned int i;

    i = oldTable->size * 2;
    table = (HashTable) XtCalloc(1,
	    (unsigned) sizeof(HashTableRec)+i*sizeof(HashPtr));

    table->size = i;
    table->count = 0;
    for (i = 0; i<oldTable->size; i++) {
	HashPtr hp;
	hp = oldTable->entries[i];
	while (hp != NULL) {
	    HashPtr temp = hp;
	    _XtRegisterWindow(hp->window, hp->widget);
	    hp = hp->next;
	    XtFree((char *) temp);
	}
    }
    XtFree((char *)oldTable);
}


/*ARGSUSED*/
Widget XtWindowToWidget(display, window)
    Display *display;
    Window window;
{
    register HashPtr hp;

    for (hp = table->entries[(unsigned int)window & (table->size-1)];
	    hp != NULL; hp = hp->next) {
	if (hp->window == window && hp->display == display) return hp->widget;
    }

    return NULL;
}

static void InitializeHash()
{
    int size = sizeof(HashTableRec)+1024*sizeof(HashPtr);

    table = (HashTable) XtMalloc((unsigned) size);
    bzero((char *) table, size);

    table->size = 1024;
    table->count = 0;
}

static Region nullRegion;

static void DispatchEvent(event, widget, mask)
    register XEvent    *event;
    Widget    widget;
    unsigned long mask;
{
    XtEventRec *p;   
    XtEventHandler proc[100];
    caddr_t closure[100];
    int numprocs, i;
    XEvent nextEvent;

    if (mask == ExposureMask) {
	XtExposeProc expose = widget->core.widget_class->core_class.expose;
	if (expose != NULL) {
	    if (!widget->core.widget_class->core_class.compress_exposure) {
		(*expose)(widget, event, (Region)NULL);
	    }
	    else {
		XtPerDisplay pd = _XtGetPerDisplay(event->xany.display);
		XtAddExposureToRegion(event, pd->region);
		if (event->xexpose.count == 0) {
		    /* Patch event to have the new bounding box.  Unless
		       someone's goofed, it can only be an Expose event */
		    XRectangle rect;
		    XClipBox(pd->region, &rect);
		    event->xexpose.x = rect.x;
		    event->xexpose.y = rect.y;
		    event->xexpose.width = rect.width;
		    event->xexpose.height = rect.height;
		    (*expose)(widget, event, pd->region);
		    (void) XIntersectRegion(
		        nullRegion, pd->region, pd->region);
		}
	    }
	}
    }

    if (mask == EnterWindowMask &&
	    widget->core.widget_class->core_class.compress_enterleave) {
	if (XPending(event->xcrossing.display)) {
	    XPeekEvent(event->xcrossing.display, &nextEvent);
	    if (nextEvent.type == LeaveNotify &&
		    event->xcrossing.window == nextEvent.xcrossing.window &&
		    event->xcrossing.subwindow == nextEvent.xcrossing.subwindow) {
		/* skip the enter/leave pair */
		XNextEvent(event->xcrossing.display, &nextEvent);
		return;
	    }
	}
    }

    if (event->type == MotionNotify &&
	    widget->core.widget_class->core_class.compress_motion) {
	while (XPending(event->xmotion.display)) {
	    XPeekEvent(event->xmotion.display, &nextEvent);
	    if (nextEvent.type == MotionNotify &&
		    event->xmotion.window == nextEvent.xmotion.window &&
		    event->xmotion.subwindow == nextEvent.xmotion.subwindow) {
		/* replace the current event with the next one */
		XNextEvent(event->xmotion.display, event);
	    } else break;
	}
    }

    if ((mask == VisibilityChangeMask) &&
        XtClass(widget)->core_class.visible_interest) {
	    /* our visibility just changed... */
	    switch (((XVisibilityEvent *)event)->state) {
		case VisibilityUnobscured:
		    widget->core.visible = TRUE;
		    break;

		case VisibilityPartiallyObscured:
		    /* what do we want to say here? */
		    /* well... some of us is visible */
		    widget->core.visible = TRUE;
		    break;

		case VisibilityFullyObscured:
		    widget->core.visible = FALSE;
		    /* do we want to mark our children obscured? */
		    break;
	    }
	}

    /* Have to copy the procs into an array, because calling one of them */
    /* might call XtRemoveEventHandler, which would break our linked list.*/

    numprocs = 0;

    for (p=widget->core.event_table; p != NULL; p = p->next) {
	if ((mask & p->mask) != 0 || (mask == 0 && p->non_filter)) {
	    proc[numprocs] = p->proc;
	    closure[numprocs++] = p->closure;
	}
    }

    for (i=0 ; i<numprocs ; i++) (*(proc[i]))(widget, closure[i], event);
}


typedef enum _GrabType {pass, ignore, remap} GrabType;

static void ConvertTypeToMask (eventType, mask, grabType)
    int		eventType;
    EventMask   *mask;
    GrabType    *grabType;
{

static struct {
    EventMask   mask;
    GrabType    grabType;
} masks[] = {
    {0,				pass},      /* shouldn't see 0  */
    {0,				pass},      /* shouldn't see 1  */
    {KeyPressMask,		remap},     /* KeyPress		*/
    {KeyReleaseMask,		remap},     /* KeyRelease       */
    {ButtonPressMask,		remap},     /* ButtonPress      */
    {ButtonReleaseMask,		remap},     /* ButtonRelease    */
    {PointerMotionMask
     | Button1MotionMask
     | Button2MotionMask
     | Button3MotionMask
     | Button4MotionMask
     | Button5MotionMask
     | ButtonMotionMask,	ignore},    /* MotionNotify	*/
    {EnterWindowMask,		ignore},    /* EnterNotify	*/
    {LeaveWindowMask,		ignore},    /* LeaveNotify	*/
    {FocusChangeMask,		pass},      /* FocusIn		*/
    {FocusChangeMask,		pass},      /* FocusOut		*/
    {KeymapStateMask,		pass},      /* KeymapNotify	*/
    {ExposureMask,		pass},      /* Expose		*/
    {0,				pass},      /* GraphicsExpose   */
    {0,				pass},      /* NoExpose		*/
    {VisibilityChangeMask,      pass},      /* VisibilityNotify */
    {SubstructureNotifyMask,    pass},      /* CreateNotify	*/
    {StructureNotifyMask
     | SubstructureNotifyMask,  pass},      /* DestroyNotify	*/
    {StructureNotifyMask
     | SubstructureNotifyMask,  pass},      /* UnmapNotify	*/
    {StructureNotifyMask
     | SubstructureNotifyMask,  pass},      /* MapNotify	*/
    {SubstructureRedirectMask,  pass},      /* MapRequest	*/
    {StructureNotifyMask
     | SubstructureNotifyMask,  pass},      /* ReparentNotify   */
    {StructureNotifyMask
     | SubstructureNotifyMask,  pass},      /* ConfigureNotify  */
    {SubstructureRedirectMask,  pass},      /* ConfigureRequest */
    {StructureNotifyMask
     | SubstructureNotifyMask,  pass},      /* GravityNotify	*/
    {ResizeRedirectMask,	pass},      /* ResizeRequest	*/
    {StructureNotifyMask
     | SubstructureNotifyMask,  pass},      /* CirculateNotify	*/
    {SubstructureRedirectMask,  pass},      /* CirculateRequest */
    {PropertyChangeMask,	pass},      /* PropertyNotify   */
    {0,				pass},      /* SelectionClear   */
    {0,				pass},      /* SelectionRequest */
    {0,				pass},      /* SelectionNotify  */
    {ColormapChangeMask,	pass},      /* ColormapNotify   */
    {0,				pass},      /* ClientMessage	*/
    {0,				pass},      /* MappingNotify ???*/
  };

    eventType &= 0x7f;	/* Events sent with XSendEvent have high bit set. */
    (*mask)      = masks[eventType].mask;
    (*grabType)  = masks[eventType].grabType;
};

static Boolean OnGrabList(widget)
    register Widget widget;
{
    register GrabRec* gl;
    for (; widget != NULL; widget = (Widget)widget->core.parent) {
	for (gl = grabList; gl != NULL; gl = gl->next) {
	    if (gl->widget == widget) return TRUE;
	    if (gl->exclusive) break;
	}
    }
    return FALSE;
}

static Widget FindFocusWidget(widget)
     Widget widget;
{
#define CACHESIZE 20
    register GrabRec* gl;
    GrabRec *start = focusList;
    static Widget *anc = NULL;
    static int ancSize;
    register Widget w;
    register int i;
    int src;
    Widget dst;
    static Widget lastQueryWidget, focusWidget;

    if (focusList == NULL) return widget;

    /* First time in, allocate the ancestor list */
    if (anc == NULL) {
	anc = (Widget *) XtMalloc(CACHESIZE * sizeof(Widget));
	ancSize = CACHESIZE;
    }

    if (!focusTraceGood || widget != lastQueryWidget) {
	lastQueryWidget = widget;
	focusTraceGood = True;
	/* First fill in the ancestor list */

	for (i = 0, w = widget; w != NULL; w = XtParent(w), i++) {
	    if (i == ancSize) {
		/* This should rarely happen, but if it does it'll probably
		   happen again, so grow the ancestor list */
		ancSize += CACHESIZE;
		anc = (Widget *) XtRealloc(anc, sizeof(Widget) * ancSize);
	    }
	    anc[i] = w;
	}
	src = i-1;
	dst = widget;

	/* For each ancestor, starting at the top, see if it's forwarded */

	while (src >= 0) {
	    for (gl = start; gl != NULL && gl->widget != anc[src]; gl = gl->next) ;
	    if (gl == NULL)	src--;	/* not in list, try next anc. */
	    else {
		dst = gl->keyboard_focus;
		start = gl->next;	/* Continue from the one we found */
		/* See if dst is an ancestor */
		for (i = src-1; i > 0 && anc[i] != dst; i--) {}
		/* If out of forwarding, send to dst if it's not an ancestor, and
		   the widget if it is (don't forward events to an ancestor) */

		if (start == NULL) {
		    if (i <= 0) return (focusWidget = dst);
		    else return (focusWidget = widget);
		}
		if (i <= 0) break;		/* We've moved to an uncle */
		else src = i;		/* Continue looking from dst */
	    }
	}

	/* If we haven't moved into some other branch, forwarding is either
	   to the widget or a descendent */

	for (gl = start; gl != NULL; gl = gl->next) {
	    if (gl->widget == dst) dst = gl->keyboard_focus;
	}
	focusWidget = dst;
    }

    return focusWidget;
#undef CACHESIZE
}

void DispatchToSpringLoaded(event, widget, mask)
    XEvent  *event;
    Widget widget;
    EventMask   mask;
{
    register    GrabList gl;

    for (gl = grabList; gl != NULL; gl = gl->next) {
	if (gl->spring_loaded) {
	    if (gl->widget != widget) {
		/* ||| Should this test for sensitive? */
		DispatchEvent(event, gl->widget, mask);
	    }
	    break;
	}
	if (gl->exclusive) break;
    }
}

static void DecideToDispatch(event)
    XEvent  *event;
{
    register    Widget widget;
    EventMask   mask;
    GrabType    grabType;
    GrabList    gl;
    Widget	dspWidget;

    widget = XtWindowToWidget (event->xany.display, event->xany.window);

    /* Lint complains about &grabType not matching the declaration.
       Don't bother trying to fix it, it won't work */
    ConvertTypeToMask(event->xany.type, &mask, &grabType);

    if (widget == NULL) {
	if (grabType != remap) return;
	/* event occurred in a non-widget window, but we've promised also
	   to dispatch it to the nearest accessible spring_loaded widget */
	DispatchToSpringLoaded(event, widget, mask);
	return;
    }

    switch(grabType) {
	case pass:
	    DispatchEvent(event, widget, mask);
	    return;

	case ignore:
	    if ((grabList == NULL || OnGrabList(widget)) && 
		    XtIsSensitive(widget)) DispatchEvent(event, widget, mask);
	    return;

	case remap:

#define IsKeyEvent (mask & (KeyPressMask | KeyReleaseMask))

	    /* If a focus event, see if it has been focussed.  */

	    if (IsKeyEvent) dspWidget = FindFocusWidget(widget);
	    else dspWidget = widget;

	    if ((grabList == NULL || OnGrabList(dspWidget)) &&
		    XtIsSensitive(dspWidget)) {
		DispatchEvent(event, dspWidget, mask);
	    }

	    /* Also dispatch to nearest accessible spring_loaded.  Note we
	       use widget here, not dspWidget */
	    DispatchToSpringLoaded(event, widget, mask);
	    return;

#undef IsKeyEvent
    }
}

void XtDispatchEvent (event)
    XEvent  *event;
{
    CallbackList *oldDestroyList, destroyList;

    /* Skip null events from XtNextEvent */
    if (event->type == 0) return;

    /*
     * To make recursive XtDispatchEvent work, we need to do phase 2 destroys
     * only on those widgets destroyed by this particular dispatch.
     * The "right" way to do this is by passing a local variable through to
     * each recursive instance, and passing the list to XtDestroy, but that
     * causes unwieldy proliferation of arguments. We could do all this stuff
     * with signals (if we had them), but instead we have a global pointer
     * to the "current" destroy list, and XtDispatchEvent and XtDestroy
     * conspire to keep it up to date, and use the right one.
     *
     * This is pretty gross.
     */

    oldDestroyList = _XtDestroyList;
    _XtDestroyList = &destroyList;
    destroyList = NULL;

    DecideToDispatch(event);

    /* To accomodate widgets destroying other widgets in their destroy
     * callbacks, we have to make this a loop */

    while (destroyList != NULL) {
	CallbackList newList = NULL;
	_XtDestroyList = &newList;
	_XtCallCallbacks (&destroyList, (caddr_t) NULL);
	_XtRemoveAllCallbacks (&destroyList);
	destroyList = newList;
    }

    _XtDestroyList = oldDestroyList;

    if (_XtSafeToDestroy) {
	if (_XtAppDestroyCount != 0) _XtDestroyAppContexts();
	if (_XtDpyDestroyCount != 0) _XtCloseDisplays();
    }
}

static Boolean RemoveGrab();

/* ARGSUSED */
static void GrabDestroyCallback(widget, closure, call_data)
    Widget  widget;
    caddr_t closure;
    caddr_t call_data;
{
    /* Remove widget from grab list if it destroyed */
    (void)RemoveGrab(widget, False);
}

/* ARGSUSED */
static void FocusDestroyCallback(widget, closure, call_data)
    Widget  widget;
    caddr_t closure;		/* Widget */
    caddr_t call_data;
{
    /* Remove widget from grab list if it destroyed */
    (void)RemoveGrab((Widget)closure, True);
}

static GrabRec *NewGrabRec(widget, exclusive, spring_loaded, keyboard_focus)
    Widget  widget;
    Boolean exclusive;
    Boolean spring_loaded;
    Widget keyboard_focus;
{
    register GrabList    gl;

    gl		      = XtNew(GrabRec);
    gl->next	      = NULL;
    gl->widget        = widget;
    gl->exclusive     = exclusive;
    gl->spring_loaded = spring_loaded;
    gl->keyboard_focus= keyboard_focus;

    return gl;
}

void XtAddGrab(widget, exclusive, spring_loaded)
    Widget  widget;
    Boolean exclusive;
    Boolean spring_loaded;
{
    register    GrabList gl;

    if (spring_loaded && !exclusive) {
	XtAppWarningMsg(XtWidgetToApplicationContext(widget),
		"grabError", "grabDestroyCallback", "XtToolkitError",
		"XtAddGrab requires exclusive grab if spring_loaded is TRUE",
		(String *) NULL, (Cardinal *) NULL);
	exclusive = TRUE;
    }

    gl = NewGrabRec(widget, exclusive, spring_loaded, NULL);
    gl->next = grabList;
    grabList = gl;

    XtAddCallback (widget, XtNdestroyCallback, 
	    GrabDestroyCallback, (caddr_t) NULL);
}

/* add a focus record to the list, or replace the focus widget in an
   existing grab record.  Returns True if the action was not a no-op.
 */
static Boolean InsertFocusEntry(widget, keyboard_focus)
    Widget  widget;
    Widget  keyboard_focus;
{
    register GrabRec *gl, *prev;
    GrabRec* ge;
    Widget w;

    for (gl = focusList; gl != NULL; gl = gl->next) {
	if (gl->widget == widget) {
	    if (gl->keyboard_focus == keyboard_focus) return False;
	    SendFocusNotify(gl->keyboard_focus, FocusOut);
	    gl->keyboard_focus = keyboard_focus;
	    focusTraceGood = False; /* invalidate the cache */
	    return True;
	}
    }
    focusTraceGood = False;	/* invalidate the cache */

    /* Create a new record and insert it before the first entry with a widget
       that is a child of widget.  This enforces the invariant that if A is an
       ancestor of B, A will precede B on the list. */

    ge = NewGrabRec(widget, False, False, keyboard_focus);

    for (prev = NULL, gl = focusList; gl != NULL; prev = gl, gl = gl->next) {
	for (w = gl->widget; w != NULL && w != widget; w = w->core.parent) {}
	if (w == widget) break;
    }

    if (prev == NULL) focusList = ge;
    else prev->next = ge;
    ge->next = gl;

    XtAddCallback(keyboard_focus, XtNdestroyCallback,
	    FocusDestroyCallback, (caddr_t)widget);

    return True;
}

static Boolean RemoveGrab(widget, keyboard_focus)
    Widget  widget;
    Boolean keyboard_focus;
    /* returns False if no grab entry was found, True otherwise */
{
    GrabList *whichList;
    register GrabList gl, prev, next;
    register Boolean done;

    if (keyboard_focus) whichList = &focusList;
    else whichList = &grabList;

    for (prev = NULL, gl = *whichList; gl != NULL; prev = gl, gl = gl->next) {
	if (gl->widget == widget) {
	    if (!keyboard_focus || gl->keyboard_focus != NULL) break;
	}
    }

    if (gl == NULL) {
	if (!keyboard_focus) {
	    XtAppWarningMsg(XtWidgetToApplicationContext(widget),
		       "grabError","xtRemoveGrab","XtToolkitError",
		       "XtRemoveGrab asked to remove a widget not on the list",
		       (String *)NULL, (Cardinal *)NULL);
	}
	return False;
    }

    if (keyboard_focus) {
	if (gl == focusList) focusList = gl->next;
	else prev->next = gl->next;
	XtRemoveCallback(gl->keyboard_focus, XtNdestroyCallback,
		FocusDestroyCallback, widget);
	XtFree((char *)gl);
	focusTraceGood = False;	/* invalidate the cache */
	return True;
    }

    do {
	gl = grabList;
	done = (gl->widget == widget);
	grabList = gl->next;
	XtRemoveCallback(gl->widget, XtNdestroyCallback,
		GrabDestroyCallback, (caddr_t)NULL);
	XtFree((char *)gl);
    } while (! done);
    return True;
}

void XtRemoveGrab(widget)
    Widget  widget;
{
    (void)RemoveGrab(widget, False);
}

void XtMainLoop()
{
	XtAppMainLoop(_XtDefaultAppContext());
}

void XtAppMainLoop(app)
	XtAppContext app;
{
    XEvent event;

    for (;;) {
    	XtAppNextEvent(app, &event);
	XtDispatchEvent(&event);
    }
}


void _XtEventInitialize()
{
    grabList = focusList = NULL;
    focusTraceGood = False;
    _XtDestroyList = NULL;
    nullRegion = XCreateRegion();
    InitializeHash();
}

void XtAddExposureToRegion(event, region)
    XEvent   *event;
    Region   region;
{
    XRectangle rect;

    switch (event->type) {
	case Expose:
		rect.x = event->xexpose.x;
		rect.y = event->xexpose.y;
		rect.width = event->xexpose.width;
		rect.height = event->xexpose.height;
		break;
	case GraphicsExpose:
		rect.x = event->xgraphicsexpose.x;
		rect.y = event->xgraphicsexpose.y;
		rect.width = event->xgraphicsexpose.width;
		rect.height = event->xgraphicsexpose.height;
		break;
	default:
		return;
    }

    XUnionRectWithRegion(&rect, region, region);
}


void _XtFreeEventTable(event_table)
    XtEventTable *event_table;
{
    register XtEventTable event;

    event = *event_table;
    while (event != NULL) {
	register XtEventTable next = event->next;
	XtFree((char *) event);
	event = next;
    }
}


/*ARGSUSED*/
void _XtAsyncMainLoop(closure)
    caddr_t closure;
{
    XEvent event;

    XtNextEvent(&event);
    XtDispatchEvent(&event);
    XFlush(event.xany.display);
}

void XtMakeToolkitAsync() {
    XtSetAsyncEventHandler(_XtAsyncMainLoop, (caddr_t) NULL);
}


void XtSetAsyncEventHandler(handler, closure)
    XtAsyncHandler handler;
    caddr_t closure;
{
    asyncHandler = handler;
    asyncClosure = closure;
}


extern void _XtRegisterAsyncHandlers(widget)
    Widget widget;
{
    EventMask mask;

    if (asyncHandler == NULL) return;

    mask = XtBuildEventMask(widget);
#ifdef notdef
    XSelectAsyncInput(
	XtDisplay(widget), XtWindow(widget), mask,
	asyncHandler, (unsigned long)XtDisplay(widget));
#endif /*notdef*/
}

/* Stuff for XtSetKeyboardFocus */

/* ARGSUSED */
static void ForwardEvent(widget, client_data, event)
    Widget widget;
    caddr_t client_data;
    XEvent *event;
{
    /* this shouldn't have been necessary, as the keyboard grab will cause
       needed, however, a protocol bug causes us to believe we lost the
       focus during a grab */
    EventMask mask;
    GrabType grabType;

    if (XtIsSensitive(widget)) {
	ConvertTypeToMask(event->xany.type, &mask, &grabType);
	DispatchEvent(event, FindFocusWidget((Widget)client_data), mask);
    }
}

/* ARGSUSED */
static void HandleFocus(widget, client_data, event)
    Widget widget;
    caddr_t client_data;	/* child who wants focus */
    XEvent *event;
{
    Boolean add;
    Widget descendant = (Widget)client_data;

    switch( event->type ) {
      case EnterNotify:
      case LeaveNotify:
		if (!event->xcrossing.focus ||
/* a protocol bug causes us to not receive notification that we've lost
   the focus when the pointer leaves during a grab
			event->xcrossing.mode != NotifyNormal ||
*/
			event->xcrossing.detail == NotifyInferior) return;
		add = (event->type == EnterNotify);
		break;
      case FocusIn:
      case FocusOut:
		if ((event->xfocus.mode != NotifyNormal &&
		     event->xfocus.mode != NotifyWhileGrabbed) ||
		    event->xfocus.detail == NotifyInferior) return;
		add = (event->type == FocusIn);
		break;
    }

    if (add) (void) InsertFocusEntry(widget, descendant);
    else (void)RemoveGrab(widget, True);

    SendFocusNotify(descendant, add ? FocusIn : FocusOut);
}

static void AddForwardingHandler(w, descendant)
    Widget w, descendant;
{
    Window root, child;
    int root_x, root_y, win_x, win_y;
    int left, right, top, bottom;
    unsigned int mask;
    EventMask eventMask;

    /* %%%
       Until we implement a mechanism for propagating keyboard event
       interest to all ancestors for which the descendant may be the
       focus target, the following optimization requires
       XtSetKeyboardFocus calls to be executed from the inside out.
     */
    eventMask = XtBuildEventMask(descendant);
    eventMask &= KeyPressMask | KeyReleaseMask;
    if (eventMask != 0) {
	Boolean have_focus = False;
	register GrabRec *gl;
	AddEventHandler(w, eventMask, False, 
		ForwardEvent, (caddr_t)descendant, FALSE, FALSE);
	/* if we already have the focus, we'll have to change the target */
	for (gl = focusList; gl != NULL; gl = gl->next) {
	    if (gl->widget == w) {
		if (gl->keyboard_focus == descendant)
		    return;	/* simple optimization; list is unchanged */
		else {
		    have_focus = True;
		    break;
		}
	    }
	}
	if (!have_focus) {
	    /* If the widget is the shell parent of the descendent, the server
	       will send the focus notify for us -- we don't need to */
	    if (w != XtParent(descendant) ||
		!XtIsSubclass(w, shellWidgetClass)) {
		/* is the pointer already inside? */
		XQueryPointer(XtDisplay(w), XtWindow(w), &root, &child,
			      &root_x, &root_y, &win_x, &win_y, &mask );
		/* We need to take borders into consideration */
		left = top = -((int) w->core.border_width);
		right = (int) (w->core.width + (w->core.border_width << 1));
		bottom = (int) (w->core.height + (w->core.border_width << 1));
		if (win_x >= left && win_x < right &&
		    win_y >= top && win_y < bottom)
		      have_focus = True;
	    }
	}
	if (have_focus && InsertFocusEntry(w, descendant)) {
	    SendFocusNotify( descendant, FocusIn );
	}
    }
    else {
	/* in case a previous focus widget was registered... */
	RemoveEventHandler(w, XtAllEvents, True,
			   ForwardEvent, NULL, FALSE, FALSE);
    }
}

/* ARGSUSED */
static void QueryEventMask(widget, client_data, event)
    Widget widget;		/* child who gets focus */
    caddr_t client_data;	/* ancestor giving it */
    XEvent *event;
{
    if (event->type == MapNotify) {
	/* make sure ancestor still wants focus set here */
	register XtEventRec* p = ((Widget)client_data)->core.event_table;
	register XtEventHandler proc = HandleFocus; /* compiler bug */
	while (p != NULL && p->proc != proc) p = p->next;
	if (p != NULL && p->closure == (caddr_t)widget)
	    AddForwardingHandler((Widget) client_data, widget);
	RemoveEventHandler(widget, XtAllEvents, True,
			   QueryEventMask, client_data, FALSE, FALSE);
    }
}

void XtSetKeyboardFocus(widget, descendant)
    Widget widget;
    Widget descendant;
{
    EventMask mask;

    if (descendant == (Widget)None) {
        register XtEventRec* p;
        register XtEventHandler proc;
        p = widget->core.event_table;
        proc = HandleFocus;     /* compiler bug */
        while (p != NULL && p->proc != proc) p = p->next;
        if (p != NULL) {
            descendant = (Widget)p->closure;
	    RemoveEventHandler(widget, XtAllEvents, True, HandleFocus, NULL,
			   FALSE, FALSE); /* not raw, don't check closure */
        }
	RemoveEventHandler(widget, XtAllEvents, True, ForwardEvent, NULL,
			   FALSE, FALSE); /* not raw, don't check closure */

        if (RemoveGrab( widget, True ) && descendant != (Widget)None)
            SendFocusNotify( descendant, FocusOut );

	return;
    }

    /* shells are always occluded by their children */
    mask = FocusChangeMask;
    if (widget != XtParent(descendant) || 
	    !XtIsSubclass(widget, shellWidgetClass)) {
	mask |= EnterWindowMask | LeaveWindowMask;
    }

    AddEventHandler(widget, mask, False, HandleFocus, (caddr_t)descendant,
		    FALSE, FALSE);

    /* If his translations aren't installed, we'll have to wait 'till later */

    if (XtIsRealized(descendant)) AddForwardingHandler(widget, descendant);
    else AddEventHandler(descendant, StructureNotifyMask, False,
		QueryEventMask, (caddr_t)widget, FALSE, FALSE);
}

static SendFocusNotify(child, type)
    Widget child;
    int type;
{
    XEvent event;
    EventMask mask;
    GrabType grabType;

    if (XtBuildEventMask(child) & FocusChangeMask) {
	event.xfocus.serial = LastKnownRequestProcessed(XtDisplay(child));
	event.xfocus.send_event = True;
	event.xfocus.display = XtDisplay(child);
	event.xfocus.window = XtWindow(child);
	event.xfocus.type = type;
	event.xfocus.mode = NotifyNormal;
	event.xfocus.detail = NotifyAncestor;
	ConvertTypeToMask(type, &mask, &grabType);
	DispatchEvent(&event, child, mask);
    }
}