Event.c revision 1477040f
1/* $Xorg: Event.c,v 1.5 2001/02/09 02:03:54 xorgcvs Exp $ */
2
3/***********************************************************
4Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
5
6Permission is hereby granted, free of charge, to any person obtaining a
7copy of this software and associated documentation files (the "Software"),
8to deal in the Software without restriction, including without limitation
9the rights to use, copy, modify, merge, publish, distribute, sublicense,
10and/or sell copies of the Software, and to permit persons to whom the
11Software is furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice (including the next
14paragraph) shall be included in all copies or substantial portions of the
15Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23DEALINGS IN THE SOFTWARE.
24
25Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
26
27                        All Rights Reserved
28
29Permission to use, copy, modify, and distribute this software and its
30documentation for any purpose and without fee is hereby granted,
31provided that the above copyright notice appear in all copies and that
32both that copyright notice and this permission notice appear in
33supporting documentation, and that the name of Digital not be
34used in advertising or publicity pertaining to distribution of the
35software without specific, written prior permission.
36
37DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43SOFTWARE.
44
45******************************************************************/
46
47/*
48
49Copyright 1987, 1988, 1998  The Open Group
50
51Permission to use, copy, modify, distribute, and sell this software and its
52documentation for any purpose is hereby granted without fee, provided that
53the above copyright notice appear in all copies and that both that
54copyright notice and this permission notice appear in supporting
55documentation.
56
57The above copyright notice and this permission notice shall be included in
58all copies or substantial portions of the Software.
59
60THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
61IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
62FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
63OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
64AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
65CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
66
67Except as contained in this notice, the name of The Open Group shall not be
68used in advertising or otherwise to promote the sale, use or other dealings
69in this Software without prior written authorization from The Open Group.
70
71*/
72/* $XFree86: xc/lib/Xt/Event.c,v 3.10 2001/12/14 19:56:11 dawes Exp $ */
73
74#ifdef HAVE_CONFIG_H
75#include <config.h>
76#endif
77#include "IntrinsicI.h"
78#include "Shell.h"
79#include "StringDefs.h"
80
81typedef struct _XtEventRecExt {
82    int type;
83    XtPointer select_data[1]; /* actual dimension is [mask] */
84} XtEventRecExt;
85
86#define EXT_TYPE(p) (((XtEventRecExt*) ((p)+1))->type)
87#define EXT_SELECT_DATA(p,n) (((XtEventRecExt*) ((p)+1))->select_data[n])
88
89#define NonMaskableMask ((EventMask)0x80000000L)
90
91/*
92 * These are definitions to make the code that handles exposure compresssion
93 * easier to read.
94 *
95 * COMP_EXPOSE      - The compression exposure field of "widget"
96 * COMP_EXPOSE_TYPE - The type of compression (lower 4 bits of COMP_EXPOSE.
97 * GRAPHICS_EXPOSE  - TRUE if the widget wants graphics expose events
98 *                    dispatched.
99 * NO_EXPOSE        - TRUE if the widget wants No expose events dispatched.
100 */
101
102#define COMP_EXPOSE   (widget->core.widget_class->core_class.compress_exposure)
103#define COMP_EXPOSE_TYPE (COMP_EXPOSE & 0x0f)
104#define GRAPHICS_EXPOSE  ((XtExposeGraphicsExpose & COMP_EXPOSE) || \
105			  (XtExposeGraphicsExposeMerged & COMP_EXPOSE))
106#define NO_EXPOSE        (XtExposeNoExpose & COMP_EXPOSE)
107
108EventMask XtBuildEventMask(
109    Widget widget)
110{
111    XtEventTable ev;
112    EventMask	mask = 0L;
113    WIDGET_TO_APPCON(widget);
114
115    LOCK_APP(app);
116    for (ev = widget->core.event_table; ev != NULL; ev = ev->next)
117	if (ev->select) {
118	    if (!ev->has_type_specifier)
119		mask |= ev->mask;
120	    else {
121		if (EXT_TYPE(ev) < LASTEvent) {
122		    Cardinal i;
123		    for (i = 0; i < ev->mask; i++)
124			if (EXT_SELECT_DATA(ev, i))
125			    mask |= *(EventMask*)EXT_SELECT_DATA(ev, i);
126		}
127	    }
128	}
129    LOCK_PROCESS;
130    if (widget->core.widget_class->core_class.expose != NULL)
131	mask |= ExposureMask;
132    if (widget->core.widget_class->core_class.visible_interest)
133	mask |= VisibilityChangeMask;
134    UNLOCK_PROCESS;
135    if (widget->core.tm.translations)
136	mask |= widget->core.tm.translations->eventMask;
137
138    mask =  mask & ~NonMaskableMask;
139    UNLOCK_APP(app);
140    return mask;
141}
142
143static void CallExtensionSelector(
144    Widget widget,
145    ExtSelectRec* rec,
146    Boolean forceCall)
147{
148    XtEventRec* p;
149    XtPointer* data;
150    int* types;
151    Cardinal i, count = 0;
152
153    for (p = widget->core.event_table; p != NULL; p = p->next)
154	if (p->has_type_specifier &&
155	    EXT_TYPE(p) >= rec->min && EXT_TYPE(p) <= rec->max)
156	    count += p->mask;
157
158    if (count == 0 && !forceCall) return;
159
160    data = (XtPointer *) ALLOCATE_LOCAL(count * sizeof (XtPointer));
161    types = (int *) ALLOCATE_LOCAL(count * sizeof (int));
162    count = 0;
163
164    for (p = widget->core.event_table; p != NULL; p = p->next)
165	if (p->has_type_specifier &&
166	    EXT_TYPE(p) >= rec->min && EXT_TYPE(p) <= rec->max)
167	    for (i =0; i < p->mask; i++) {
168		types[count] = EXT_TYPE(p);
169		data[count++] = EXT_SELECT_DATA(p, i);
170	    }
171
172    (*rec->proc)(widget, types, data, count, rec->client_data);
173    DEALLOCATE_LOCAL((char*) types);
174    DEALLOCATE_LOCAL((char*) data);
175}
176
177static void
178RemoveEventHandler(
179    Widget widget,
180    XtPointer select_data,
181    int type,
182    Boolean has_type_specifier,
183    Boolean other,
184    XtEventHandler proc,
185    XtPointer closure,
186    Boolean raw)
187{
188    XtEventRec *p, **pp;
189    EventMask eventMask, oldMask = XtBuildEventMask(widget);
190
191    if (raw) raw = 1;
192    pp = &widget->core.event_table;
193    while ((p = *pp) &&
194	   (p->proc != proc || p->closure != closure || p->select == raw ||
195	    has_type_specifier != p->has_type_specifier ||
196	    (has_type_specifier && EXT_TYPE(p) != type)))
197	pp = &p->next;
198    if (!p) return;
199
200    /* un-register it */
201    if (!has_type_specifier) {
202	eventMask = *(EventMask*)select_data;
203	eventMask &= ~NonMaskableMask;
204	if (other)
205	    eventMask |= NonMaskableMask;
206	p->mask &= ~eventMask;
207    } else {
208	Cardinal i;
209	/* p->mask specifies count of EXT_SELECT_DATA(p,i)
210	 * search through the list of selection data, if not found
211	 * dont remove this handler
212	 */
213	for (i = 0; i < p->mask && select_data != EXT_SELECT_DATA(p,i);) i++;
214	if (i == p->mask) return;
215	if (p->mask == 1) p->mask = 0;
216	else {
217	    p->mask--;
218	    while (i < p->mask) {
219		EXT_SELECT_DATA(p,i) = EXT_SELECT_DATA(p, i+1);
220		i++;
221	    }
222	}
223    }
224
225    if (!p->mask) {        /* delete it entirely */
226        *pp = p->next;
227	XtFree((char *)p);
228    }
229
230    /* Reset select mask if realized and not raw. */
231    if ( !raw && XtIsRealized(widget) && !widget->core.being_destroyed) {
232	EventMask mask = XtBuildEventMask(widget);
233	Display* dpy = XtDisplay (widget);
234
235	if (oldMask != mask)
236	    XSelectInput(dpy, XtWindow(widget), mask);
237
238	if (has_type_specifier) {
239	    XtPerDisplay pd = _XtGetPerDisplay(dpy);
240	    int i;
241	    for (i = 0; i < pd->ext_select_count; i++) {
242		if (type >= pd->ext_select_list[i].min &&
243		    type <= pd->ext_select_list[i].max) {
244		    CallExtensionSelector(widget, pd->ext_select_list+i, TRUE);
245		    break;
246		}
247		if (type < pd->ext_select_list[i].min) break;
248	    }
249	}
250    }
251}
252
253/*	Function Name: AddEventHandler
254 *	Description: An Internal routine that does the actual work of
255 *                   adding the event handlers.
256 *	Arguments: widget - widget to register an event handler for.
257 *                 eventMask - events to mask for.
258 *                 other - pass non maskable events to this proceedure.
259 *                 proc - proceedure to register.
260 *                 closure - data to pass to the event hander.
261 *                 position - where to add this event handler.
262 *                 force_new_position - If the element is already in the
263 *                                      list, this will force it to the
264 *                                      beginning or end depending on position.
265 *                 raw - If FALSE call XSelectInput for events in mask.
266 *	Returns: none
267 */
268
269static void
270AddEventHandler(
271    Widget widget,
272    XtPointer select_data,
273    int type,
274    Boolean         has_type_specifier,
275    Boolean         other,
276    XtEventHandler  proc,
277    XtPointer	closure,
278    XtListPosition  position,
279    Boolean         force_new_position,
280    Boolean         raw)
281{
282    register XtEventRec *p, **pp;
283    EventMask oldMask = 0, eventMask = 0;
284
285    if (!has_type_specifier) {
286	eventMask = *(EventMask*)select_data & ~NonMaskableMask;
287	if (other) eventMask |= NonMaskableMask;
288	if (!eventMask) return;
289    } else if (!type) return;
290
291    if (XtIsRealized(widget) && !raw) oldMask = XtBuildEventMask(widget);
292
293    if (raw) raw = 1;
294    pp = &widget->core.event_table;
295    while ((p = *pp) &&
296	   (p->proc != proc || p->closure != closure || p->select == raw ||
297	    has_type_specifier != p->has_type_specifier ||
298	    (has_type_specifier && EXT_TYPE(p) != type)))
299	pp = &p->next;
300
301    if (!p) {		                /* New proc to add to list */
302	if (has_type_specifier) {
303	    p = (XtEventRec*) __XtMalloc(sizeof(XtEventRec) +
304				       sizeof(XtEventRecExt));
305	    EXT_TYPE(p) = type;
306	    EXT_SELECT_DATA(p,0) = select_data;
307	    p->mask = 1;
308	    p->has_type_specifier = True;
309	} else {
310	    p = (XtEventRec*) __XtMalloc(sizeof(XtEventRec));
311	    p->mask = eventMask;
312	    p->has_type_specifier = False;
313	}
314	p->proc = proc;
315	p->closure = closure;
316	p->select = ! raw;
317
318	if (position == XtListHead) {
319	    p->next = widget->core.event_table;
320	    widget->core.event_table = p;
321	    pp = &widget->core.event_table;
322	} else {
323	    *pp = p;
324	    p->next = NULL;
325	}
326    }
327    else {
328	if (force_new_position) {
329	    *pp = p->next;
330
331	    if (position == XtListHead) {
332		p->next = widget->core.event_table;
333		widget->core.event_table = p;
334	    } else {
335	       	/*
336		 * Find the last element in the list.
337		 */
338		while (*pp)
339		    pp = &(*pp)->next;
340		*pp = p;
341		p->next = NULL;
342	    }
343	}
344
345	if (!has_type_specifier)
346	    p->mask |= eventMask;
347	else {
348	    Cardinal i;
349	    /* p->mask specifies count of EXT_SELECT_DATA(p,i) */
350	    for (i = 0; i < p->mask && select_data != EXT_SELECT_DATA(p,i); )
351		i++;
352	    if (i == p->mask) {
353		p = (XtEventRec*) XtRealloc((char*)p,
354					    sizeof(XtEventRec) +
355					    sizeof(XtEventRecExt) +
356					    p->mask * sizeof(XtPointer));
357		EXT_SELECT_DATA(p,i) = select_data;
358		p->mask++;
359		*pp = p;
360	    }
361	}
362    }
363
364    if (XtIsRealized(widget) && !raw) {
365	EventMask mask = XtBuildEventMask(widget);
366	Display* dpy = XtDisplay (widget);
367
368	if (oldMask != mask)
369	    XSelectInput(dpy, XtWindow(widget), mask);
370
371	if (has_type_specifier) {
372	    XtPerDisplay pd = _XtGetPerDisplay (dpy);
373	    int i;
374	    for (i = 0; i < pd->ext_select_count; i++) {
375		if (type >= pd->ext_select_list[i].min &&
376		    type <= pd->ext_select_list[i].max) {
377		    CallExtensionSelector(widget, pd->ext_select_list+i, FALSE);
378		    break;
379		}
380		if (type < pd->ext_select_list[i].min) break;
381	    }
382	}
383    }
384}
385
386void XtRemoveEventHandler(
387    Widget	    widget,
388    EventMask       eventMask,
389    _XtBoolean	    other,
390    XtEventHandler  proc,
391    XtPointer	    closure)
392{
393    WIDGET_TO_APPCON(widget);
394    LOCK_APP(app);
395    RemoveEventHandler(widget, (XtPointer) &eventMask, 0, FALSE,
396		       other, proc, closure, FALSE);
397    UNLOCK_APP(app);
398}
399
400void XtAddEventHandler(
401    Widget	    widget,
402    EventMask       eventMask,
403    _XtBoolean      other,
404    XtEventHandler  proc,
405    XtPointer	    closure)
406{
407    WIDGET_TO_APPCON(widget);
408    LOCK_APP(app);
409    AddEventHandler(widget, (XtPointer) &eventMask, 0, FALSE, other,
410		    proc, closure, XtListTail, FALSE, FALSE);
411    UNLOCK_APP(app);
412}
413
414void XtInsertEventHandler(
415    Widget	    widget,
416    EventMask       eventMask,
417    _XtBoolean      other,
418    XtEventHandler  proc,
419    XtPointer	    closure,
420    XtListPosition  position)
421{
422    WIDGET_TO_APPCON(widget);
423    LOCK_APP(app);
424    AddEventHandler(widget, (XtPointer) &eventMask, 0, FALSE, other,
425		    proc, closure, position, TRUE, FALSE);
426    UNLOCK_APP(app);
427}
428
429void XtRemoveRawEventHandler(
430    Widget	    widget,
431    EventMask       eventMask,
432    _XtBoolean	    other,
433    XtEventHandler  proc,
434    XtPointer	    closure)
435{
436    WIDGET_TO_APPCON(widget);
437    LOCK_APP(app);
438    RemoveEventHandler(widget, (XtPointer) &eventMask, 0, FALSE,
439		       other, proc, closure, TRUE);
440    UNLOCK_APP(app);
441}
442
443void XtInsertRawEventHandler(
444    Widget	    widget,
445    EventMask       eventMask,
446    _XtBoolean	    other,
447    XtEventHandler  proc,
448    XtPointer	    closure,
449    XtListPosition  position)
450{
451    WIDGET_TO_APPCON(widget);
452    LOCK_APP(app);
453    AddEventHandler(widget, (XtPointer) &eventMask, 0, FALSE, other,
454		    proc, closure, position, TRUE, TRUE);
455    UNLOCK_APP(app);
456}
457
458void XtAddRawEventHandler(
459    Widget	    widget,
460    EventMask       eventMask,
461    _XtBoolean      other,
462    XtEventHandler  proc,
463    XtPointer	    closure)
464{
465    WIDGET_TO_APPCON(widget);
466    LOCK_APP(app);
467    AddEventHandler(widget, (XtPointer) &eventMask, 0, FALSE, other,
468		    proc, closure, XtListTail, FALSE, TRUE);
469    UNLOCK_APP(app);
470}
471
472void XtRemoveEventTypeHandler(
473    Widget	    widget,
474    int		    type,
475    XtPointer	    select_data,
476    XtEventHandler  proc,
477    XtPointer	    closure)
478{
479    WIDGET_TO_APPCON(widget);
480    LOCK_APP(app);
481    RemoveEventHandler(widget, select_data, type, TRUE,
482		       FALSE, proc, closure, FALSE);
483    UNLOCK_APP(app);
484}
485
486void XtInsertEventTypeHandler(
487    Widget	    widget,
488    int		    type,
489    XtPointer	    select_data,
490    XtEventHandler  proc,
491    XtPointer	    closure,
492    XtListPosition  position)
493{
494    WIDGET_TO_APPCON(widget);
495    LOCK_APP(app);
496    AddEventHandler(widget, select_data, type, TRUE, FALSE,
497		    proc, closure, position, TRUE, FALSE);
498    UNLOCK_APP(app);
499}
500
501typedef struct _WWPair {
502    struct _WWPair *next;
503    Window window;
504    Widget widget;
505} *WWPair;
506
507typedef struct _WWTable {
508    unsigned int mask;		/* size of hash table - 1 */
509    unsigned int rehash;	/* mask - 2 */
510    unsigned int occupied;	/* number of occupied entries */
511    unsigned int fakes;		/* number occupied by WWfake */
512    Widget *entries;		/* the entries */
513    WWPair pairs;		/* bogus entries */
514} *WWTable;
515
516static const WidgetRec WWfake;	/* placeholder for deletions */
517
518#define WWHASH(tab,win) ((win) & tab->mask)
519#define WWREHASHVAL(tab,win) ((((win) % tab->rehash) + 2) | 1)
520#define WWREHASH(tab,idx,rehash) ((idx + rehash) & tab->mask)
521#define WWTABLE(display) (_XtGetPerDisplay(display)->WWtable)
522
523static void ExpandWWTable(WWTable);
524
525void XtRegisterDrawable(
526    Display* display,
527    Drawable drawable,
528    Widget widget)
529{
530    WWTable tab;
531    int idx, rehash;
532    Widget entry;
533    Window window = (Window) drawable;
534    WIDGET_TO_APPCON(widget);
535
536    LOCK_APP(app);
537    LOCK_PROCESS;
538    tab = WWTABLE(display);
539    if (window != XtWindow(widget)) {
540	WWPair pair;
541	pair = XtNew(struct _WWPair);
542	pair->next = tab->pairs;
543	pair->window = window;
544	pair->widget = widget;
545	tab->pairs = pair;
546	UNLOCK_PROCESS;
547	UNLOCK_APP(app);
548	return;
549    }
550    if ((tab->occupied + (tab->occupied >> 2)) > tab->mask)
551	ExpandWWTable(tab);
552
553    idx = WWHASH(tab, window);
554    if ((entry = tab->entries[idx]) && entry != &WWfake) {
555	rehash = WWREHASHVAL(tab, window);
556	do {
557	    idx = WWREHASH(tab, idx, rehash);
558	} while ((entry = tab->entries[idx]) && entry != &WWfake);
559    }
560    if (!entry)
561	tab->occupied++;
562    else if (entry == &WWfake)
563	tab->fakes--;
564    tab->entries[idx] = widget;
565    UNLOCK_PROCESS;
566    UNLOCK_APP(app);
567}
568
569void XtUnregisterDrawable(
570    Display* display,
571    Drawable drawable)
572{
573    WWTable tab;
574    int idx, rehash;
575    Widget entry;
576    Window window = (Window) drawable;
577    Widget widget = XtWindowToWidget (display, window);
578    DPY_TO_APPCON(display);
579
580    if (widget == NULL) return;
581
582    LOCK_APP(app);
583    LOCK_PROCESS;
584    tab = WWTABLE(display);
585    if (window != XtWindow(widget)) {
586	WWPair *prev, pair;
587
588	prev = &tab->pairs;
589	while ((pair = *prev) && pair->window != window)
590	    prev = &pair->next;
591	if (pair) {
592	    *prev = pair->next;
593	    XtFree((char *)pair);
594	}
595	UNLOCK_PROCESS;
596	UNLOCK_APP(app);
597	return;
598    }
599    idx = WWHASH(tab, window);
600    if ((entry = tab->entries[idx])) {
601	if (entry != widget) {
602	    rehash = WWREHASHVAL(tab, window);
603	    do {
604		idx = WWREHASH(tab, idx, rehash);
605		if (!(entry = tab->entries[idx])) {
606		    UNLOCK_PROCESS;
607		    UNLOCK_APP(app);
608		    return;
609		}
610	    } while (entry != widget);
611	}
612	tab->entries[idx] = (Widget)&WWfake;
613	tab->fakes++;
614    }
615    UNLOCK_PROCESS;
616    UNLOCK_APP(app);
617}
618
619static void ExpandWWTable(
620    register WWTable tab)
621{
622    unsigned int oldmask;
623    register Widget *oldentries, *entries;
624    register Cardinal oldidx, newidx, rehash;
625    register Widget entry;
626
627    LOCK_PROCESS;
628    oldmask = tab->mask;
629    oldentries = tab->entries;
630    tab->occupied -= tab->fakes;
631    tab->fakes = 0;
632    if ((tab->occupied + (tab->occupied >> 2)) > tab->mask) {
633	tab->mask = (tab->mask << 1) + 1;
634	tab->rehash = tab->mask - 2;
635    }
636    entries = tab->entries = (Widget *) __XtCalloc(tab->mask+1, sizeof(Widget));
637    for (oldidx = 0; oldidx <= oldmask; oldidx++) {
638	if ((entry = oldentries[oldidx]) && entry != &WWfake) {
639	    newidx = WWHASH(tab, XtWindow(entry));
640	    if (entries[newidx]) {
641		rehash = WWREHASHVAL(tab, XtWindow(entry));
642		do {
643		    newidx = WWREHASH(tab, newidx, rehash);
644		} while (entries[newidx]);
645	    }
646	    entries[newidx] = entry;
647	}
648    }
649    XtFree((char *)oldentries);
650    UNLOCK_PROCESS;
651}
652
653Widget XtWindowToWidget(
654    register Display *display,
655    register Window window)
656{
657    register WWTable tab;
658    register int idx, rehash;
659    register Widget entry;
660    WWPair pair;
661    DPY_TO_APPCON(display);
662
663    if (!window) return NULL;
664
665    LOCK_APP(app);
666    LOCK_PROCESS;
667    tab = WWTABLE(display);
668    idx = WWHASH(tab, window);
669    if ((entry = tab->entries[idx]) && XtWindow(entry) != window) {
670	rehash = WWREHASHVAL(tab, window);
671	do {
672	    idx = WWREHASH(tab, idx, rehash);
673	} while ((entry = tab->entries[idx]) && XtWindow(entry) != window);
674    }
675    if (entry) {
676    	UNLOCK_PROCESS;
677    	UNLOCK_APP(app);
678	return entry;
679    }
680    for (pair = tab->pairs; pair; pair = pair->next) {
681	if (pair->window == window) {
682	    entry = pair->widget;
683	    UNLOCK_PROCESS;
684    	    UNLOCK_APP(app);
685	    return entry;
686	}
687    }
688    UNLOCK_PROCESS;
689    UNLOCK_APP(app);
690    return NULL;
691}
692
693void _XtAllocWWTable(
694    XtPerDisplay pd)
695{
696    register WWTable tab;
697
698    tab = (WWTable) __XtMalloc(sizeof(struct _WWTable));
699    tab->mask = 0x7f;
700    tab->rehash = tab->mask - 2;
701    tab->entries = (Widget *) __XtCalloc(tab->mask+1, sizeof(Widget));
702    tab->occupied = 0;
703    tab->fakes = 0;
704    tab->pairs = NULL;
705    pd->WWtable = tab;
706}
707
708void _XtFreeWWTable(
709    register XtPerDisplay pd)
710{
711    register WWPair pair, next;
712
713    for (pair = pd->WWtable->pairs; pair; pair = next) {
714	next = pair->next;
715	XtFree((char *)pair);
716    }
717    XtFree((char *)pd->WWtable->entries);
718    XtFree((char *)pd->WWtable);
719}
720
721#define EHMAXSIZE 25 /* do not make whopping big */
722
723static Boolean CallEventHandlers(
724    Widget     widget,
725    XEvent    *event,
726    EventMask  mask)
727{
728    register XtEventRec *p;
729    XtEventHandler *proc;
730    XtPointer *closure;
731    XtEventHandler procs[EHMAXSIZE];
732    XtPointer closures[EHMAXSIZE];
733    Boolean cont_to_disp = True;
734    int i, numprocs;
735
736    /* Have to copy the procs into an array, because one of them might
737     * call XtRemoveEventHandler, which would break our linked list. */
738
739    numprocs = 0;
740    for (p=widget->core.event_table; p; p = p->next) {
741	if ((!p->has_type_specifier && (mask & p->mask)) ||
742	    (p->has_type_specifier && event->type == EXT_TYPE(p)))
743	    numprocs++;
744    }
745    if (numprocs > EHMAXSIZE) {
746	proc = (XtEventHandler *)__XtMalloc(numprocs * (sizeof(XtEventHandler) +
747						      sizeof(XtPointer)));
748	closure = (XtPointer *)(proc + numprocs);
749    } else {
750	proc = procs;
751	closure = closures;
752    }
753    numprocs = 0;
754    for (p=widget->core.event_table; p; p = p->next) {
755	if ((!p->has_type_specifier && (mask & p->mask)) ||
756	    (p->has_type_specifier && event->type == EXT_TYPE(p))) {
757	    proc[numprocs] = p->proc;
758	    closure[numprocs] = p->closure;
759	    numprocs++;
760	}
761    }
762/* FUNCTIONS CALLED THROUGH POINTER proc:
763		Selection.c:ReqCleanup,
764		"Shell.c":EventHandler,
765		PassivGrab.c:ActiveHandler,
766		PassivGrab.c:RealizeHandler,
767		Keyboard.c:QueryEventMask,
768		_XtHandleFocus,
769		Selection.c:HandleSelectionReplies,
770		Selection.c:HandleGetIncrement,
771		Selection.c:HandleIncremental,
772		Selection.c:HandlePropertyGone,
773		Selection.c:HandleSelectionEvents
774		*/
775    for (i = 0; i < numprocs && cont_to_disp; i++)
776	(*(proc[i]))(widget, closure[i], event, &cont_to_disp);
777    if (numprocs > EHMAXSIZE)
778	XtFree((char *)proc);
779    return cont_to_disp;
780}
781
782static void CompressExposures(XEvent *, Widget);
783
784#define KnownButtons (Button1MotionMask|Button2MotionMask|Button3MotionMask|\
785		      Button4MotionMask|Button5MotionMask)
786
787/* keep this SMALL to avoid blowing stack cache! */
788/* because some compilers allocate all local locals on procedure entry */
789#define EHSIZE 4
790
791Boolean XtDispatchEventToWidget(
792    Widget widget,
793    XEvent* event)
794{
795    register XtEventRec *p;
796    Boolean was_dispatched = False;
797    Boolean call_tm = False;
798    Boolean cont_to_disp;
799    EventMask mask;
800    WIDGET_TO_APPCON(widget);
801
802    LOCK_APP(app);
803
804    mask = _XtConvertTypeToMask(event->type);
805    if (event->type == MotionNotify)
806	mask |= (event->xmotion.state & KnownButtons);
807
808    LOCK_PROCESS;
809    if ( (mask == ExposureMask) ||
810	 ((event->type == NoExpose) && NO_EXPOSE) ||
811	 ((event->type == GraphicsExpose) && GRAPHICS_EXPOSE) ) {
812
813	if (widget->core.widget_class->core_class.expose != NULL ) {
814
815	    /* We need to mask off the bits that could contain the information
816	     * about whether or not we desire Graphics and NoExpose events.  */
817
818	    if ( (COMP_EXPOSE_TYPE == XtExposeNoCompress) ||
819		 (event->type == NoExpose) )
820
821		(*widget->core.widget_class->core_class.expose)
822		    (widget, event, (Region)NULL);
823	    else {
824		CompressExposures(event, widget);
825	    }
826	    was_dispatched = True;
827	}
828    }
829
830    if ((mask == VisibilityChangeMask) &&
831        XtClass(widget)->core_class.visible_interest) {
832	    was_dispatched = True;
833	    /* our visibility just changed... */
834	    switch (((XVisibilityEvent *)event)->state) {
835		case VisibilityUnobscured:
836		    widget->core.visible = TRUE;
837		    break;
838
839		case VisibilityPartiallyObscured:
840		    /* what do we want to say here? */
841		    /* well... some of us is visible */
842		    widget->core.visible = TRUE;
843		    break;
844
845		case VisibilityFullyObscured:
846		    widget->core.visible = FALSE;
847		    /* do we want to mark our children obscured? */
848		    break;
849	    }
850	}
851    UNLOCK_PROCESS;
852
853    /* to maintain "copy" semantics we check TM now but call later */
854    if (widget->core.tm.translations &&
855	(mask & widget->core.tm.translations->eventMask))
856	call_tm = True;
857
858    cont_to_disp = True;
859    p=widget->core.event_table;
860    if (p) {
861	if (p->next) {
862	    XtEventHandler proc[EHSIZE];
863	    XtPointer closure[EHSIZE];
864	    int numprocs = 0;
865
866	    /* Have to copy the procs into an array, because one of them might
867	     * call XtRemoveEventHandler, which would break our linked list. */
868
869	    for (; p; p = p->next) {
870		if ((!p->has_type_specifier && (mask & p->mask)) ||
871		    (p->has_type_specifier && event->type == EXT_TYPE(p))) {
872		    if (numprocs >= EHSIZE)
873			break;
874		    proc[numprocs] = p->proc;
875		    closure[numprocs] = p->closure;
876		    numprocs++;
877		}
878	    }
879	    if (numprocs) {
880		if (p) {
881		    cont_to_disp = CallEventHandlers(widget, event, mask);
882		} else {
883		    int i;
884		    for (i = 0; i < numprocs && cont_to_disp; i++)
885			(*(proc[i]))(widget, closure[i], event, &cont_to_disp);
886/* FUNCTIONS CALLED THROUGH POINTER proc:
887		Selection.c:ReqCleanup,
888		"Shell.c":EventHandler,
889		PassivGrab.c:ActiveHandler,
890		PassivGrab.c:RealizeHandler,
891		Keyboard.c:QueryEventMask,
892		_XtHandleFocus,
893		Selection.c:HandleSelectionReplies,
894		Selection.c:HandleGetIncrement,
895		Selection.c:HandleIncremental,
896		Selection.c:HandlePropertyGone,
897		Selection.c:HandleSelectionEvents
898		*/
899		}
900		was_dispatched = True;
901	    }
902	} else if ((!p->has_type_specifier && (mask & p->mask)) ||
903		   (p->has_type_specifier && event->type == EXT_TYPE(p))) {
904	    (*p->proc)(widget, p->closure, event, &cont_to_disp);
905	    was_dispatched = True;
906	}
907    }
908    if (call_tm && cont_to_disp)
909	_XtTranslateEvent(widget, event);
910    UNLOCK_APP(app);
911    return (was_dispatched|call_tm);
912}
913
914/*
915 * This structure is passed into the check exposure proc.
916 */
917
918typedef struct _CheckExposeInfo {
919    int type1, type2;		/* Types of events to check for. */
920    Boolean maximal;		/* Ignore non-exposure events? */
921    Boolean non_matching;	/* Was there an event that did not
922				   match either type? */
923    Window window;		/* Window to match. */
924} CheckExposeInfo;
925
926#define GetCount(ev) (((XExposeEvent *)(ev))->count)
927
928static void SendExposureEvent(XEvent *, Widget, XtPerDisplay);
929static Bool CheckExposureEvent(Display *, XEvent *, char *);
930static void AddExposureToRectangularRegion(XEvent *, Region);
931
932/*	Function Name: CompressExposures
933 *	Description: Handles all exposure compression
934 *	Arguments: event - the xevent that is to be dispatched
935 *                 widget - the widget that this event occured in.
936 *	Returns: none.
937 *
938 *      NOTE: Event must be of type Expose or GraphicsExpose.
939 */
940
941static void
942CompressExposures(
943XEvent * event,
944Widget widget)
945{
946    CheckExposeInfo info;
947    int count;
948    Display* dpy = XtDisplay (widget);
949    XtPerDisplay pd = _XtGetPerDisplay(dpy);
950    XtEnum comp_expose;
951    XtEnum comp_expose_type;
952    Boolean no_region;
953
954    LOCK_PROCESS;
955    comp_expose = COMP_EXPOSE;
956    UNLOCK_PROCESS;
957    comp_expose_type = comp_expose & 0x0f;
958    no_region = ((comp_expose & XtExposeNoRegion) ? True : False);
959
960    if (no_region)
961	AddExposureToRectangularRegion(event, pd->region);
962    else
963	XtAddExposureToRegion(event, pd->region);
964
965    if ( GetCount(event) != 0 )
966 	return;
967
968    if ((comp_expose_type == XtExposeCompressSeries) ||
969	(XEventsQueued(dpy, QueuedAfterReading) == 0)) {
970	SendExposureEvent(event, widget, pd);
971	return;
972    }
973
974    if (comp_expose & XtExposeGraphicsExposeMerged) {
975	info.type1 = Expose;
976	info.type2 = GraphicsExpose;
977    }
978    else {
979	info.type1 = event->type;
980	info.type2 = 0;
981    }
982    info.maximal = (comp_expose_type == XtExposeCompressMaximal);
983    info.non_matching = FALSE;
984    info.window = XtWindow(widget);
985
986/*
987 * We have to be very careful here not to hose down the processor
988 * when blocking until count gets to zero.
989 *
990 * First, check to see if there are any events in the queue for this
991 * widget, and of the correct type.
992 *
993 * Once we cannot find any more events, check to see that count is zero.
994 * If it is not then block until we get another exposure event.
995 *
996 * If we find no more events, and count on the last one we saw was zero we
997 * we can be sure that all events have been processed.
998 *
999 * Unfortunately, we wind up having to look at the entire queue
1000 * event if we're not doing Maximal compression, due to the
1001 * semantics of XCheckIfEvent (we can't abort without re-ordering
1002 * the event queue as a side-effect).
1003 */
1004
1005    count = 0;
1006    while (TRUE) {
1007	XEvent event_return;
1008
1009	if (XCheckIfEvent(dpy, &event_return,
1010			  CheckExposureEvent, (char *) &info)) {
1011
1012	    count = GetCount(&event_return);
1013 	    if (no_region)
1014		AddExposureToRectangularRegion(&event_return, pd->region);
1015 	    else
1016		XtAddExposureToRegion(&event_return, pd->region);
1017	}
1018	else if (count != 0) {
1019	    XIfEvent(dpy, &event_return,
1020		     CheckExposureEvent, (char *) &info);
1021	    count = GetCount(&event_return);
1022 	    if (no_region)
1023		AddExposureToRectangularRegion(&event_return, pd->region);
1024 	    else
1025		XtAddExposureToRegion(&event_return, pd->region);
1026	}
1027	else /* count == 0 && XCheckIfEvent Failed. */
1028	    break;
1029    }
1030
1031    SendExposureEvent(event, widget, pd);
1032}
1033
1034void XtAddExposureToRegion(
1035    XEvent   *event,
1036    Region   region)
1037{
1038    XRectangle rect;
1039    XExposeEvent *ev = (XExposeEvent *) event;
1040    /* These Expose and GraphicsExpose fields are at identical offsets */
1041
1042    if (event->type == Expose || event->type == GraphicsExpose) {
1043	rect.x = ev->x;
1044	rect.y = ev->y;
1045	rect.width = ev->width;
1046	rect.height = ev->height;
1047	XUnionRectWithRegion(&rect, region, region);
1048    }
1049}
1050
1051#ifndef MAX
1052#define MAX(a,b) (((a) > (b)) ? (a) : (b))
1053#endif
1054
1055#ifndef MIN
1056#define MIN(a,b) (((a) < (b)) ? (a) : (b))
1057#endif
1058
1059static void AddExposureToRectangularRegion(
1060     XEvent *event, /* when called internally, type is always appropriate */
1061     Region  region)
1062{
1063    XRectangle rect;
1064    XExposeEvent *ev = (XExposeEvent *) event;
1065    /* These Expose and GraphicsExpose fields are at identical offsets */
1066
1067    rect.x = ev->x;
1068    rect.y = ev->y;
1069    rect.width = ev->width;
1070    rect.height = ev->height;
1071
1072    if (XEmptyRegion(region)) {
1073	XUnionRectWithRegion(&rect, region, region);
1074    } else {
1075	XRectangle merged, bbox;
1076
1077	XClipBox(region, &bbox);
1078	merged.x = MIN(rect.x, bbox.x);
1079	merged.y = MIN(rect.y, bbox.y);
1080	merged.width = MAX(rect.x + rect.width,
1081			   bbox.x + bbox.width) - merged.x;
1082	merged.height = MAX(rect.y + rect.height,
1083			    bbox.y + bbox.height) - merged.y;
1084	XUnionRectWithRegion(&merged, region, region);
1085    }
1086}
1087
1088static Region nullRegion;
1089/* READ-ONLY VARIABLES: nullRegion */
1090
1091void _XtEventInitialize(void)
1092{
1093#ifndef __lock_lint
1094    nullRegion = XCreateRegion();
1095#endif
1096}
1097
1098/*	Function Name: SendExposureEvent
1099 *	Description: Sets the x, y, width, and height of the event
1100 *                   to be the clip box of Expose Region.
1101 *	Arguments: event  - the X Event to mangle; Expose or GraphicsExpose.
1102 *                 widget - the widget that this event occured in.
1103 *                 pd     - the per display information for this widget.
1104 *	Returns: none.
1105 */
1106
1107static void
1108SendExposureEvent(
1109XEvent * event,
1110Widget widget,
1111XtPerDisplay pd)
1112{
1113    XtExposeProc expose;
1114    XRectangle rect;
1115    XtEnum comp_expose;
1116    XExposeEvent *ev = (XExposeEvent *) event;
1117
1118    XClipBox(pd->region, &rect);
1119    ev->x = rect.x;
1120    ev->y = rect.y;
1121    ev->width = rect.width;
1122    ev->height = rect.height;
1123
1124    LOCK_PROCESS;
1125    comp_expose = COMP_EXPOSE;
1126    expose = widget->core.widget_class->core_class.expose;
1127    UNLOCK_PROCESS;
1128    if (comp_expose & XtExposeNoRegion)
1129	(*expose)(widget, event, NULL);
1130    else
1131	(*expose)(widget, event, pd->region);
1132    (void) XIntersectRegion(nullRegion, pd->region, pd->region);
1133}
1134
1135/*	Function Name: CheckExposureEvent
1136 *	Description: Checks the event queue for an expose event
1137 *	Arguments: display - the display connection.
1138 *                 event - the event to check.
1139 *                 arg - a pointer to the exposure info structure.
1140 *	Returns: TRUE if we found an event of the correct type
1141 *               with the right window.
1142 *
1143 * NOTE: The only valid types (info.type1 and info.type2) are Expose
1144 *       and GraphicsExpose.
1145 */
1146
1147/* ARGSUSED */
1148static Bool
1149CheckExposureEvent(
1150Display * disp,
1151XEvent * event,
1152char * arg)
1153{
1154    CheckExposeInfo * info = ((CheckExposeInfo *) arg);
1155
1156    if ( (info->type1 == event->type) || (info->type2 == event->type)) {
1157	if (!info->maximal && info->non_matching) return FALSE;
1158	if (event->type == GraphicsExpose)
1159	    return(event->xgraphicsexpose.drawable == info->window);
1160	return(event->xexpose.window == info->window);
1161    }
1162    info->non_matching = TRUE;
1163    return(FALSE);
1164}
1165
1166static EventMask const masks[] = {
1167	0,			    /* Error, should never see  */
1168	0,			    /* Reply, should never see  */
1169	KeyPressMask,		    /* KeyPress			*/
1170	KeyReleaseMask,		    /* KeyRelease		*/
1171	ButtonPressMask,	    /* ButtonPress		*/
1172	ButtonReleaseMask,	    /* ButtonRelease		*/
1173	PointerMotionMask	    /* MotionNotify		*/
1174		| ButtonMotionMask,
1175	EnterWindowMask,	    /* EnterNotify		*/
1176	LeaveWindowMask,	    /* LeaveNotify		*/
1177	FocusChangeMask,	    /* FocusIn			*/
1178	FocusChangeMask,	    /* FocusOut			*/
1179	KeymapStateMask,	    /* KeymapNotify		*/
1180	ExposureMask,		    /* Expose			*/
1181	NonMaskableMask,	    /* GraphicsExpose, in GC    */
1182	NonMaskableMask,	    /* NoExpose, in GC		*/
1183	VisibilityChangeMask,       /* VisibilityNotify		*/
1184	SubstructureNotifyMask,     /* CreateNotify		*/
1185	StructureNotifyMask	    /* DestroyNotify		*/
1186		| SubstructureNotifyMask,
1187	StructureNotifyMask	    /* UnmapNotify		*/
1188		| SubstructureNotifyMask,
1189	StructureNotifyMask	    /* MapNotify		*/
1190		| SubstructureNotifyMask,
1191	SubstructureRedirectMask,   /* MapRequest		*/
1192	StructureNotifyMask	    /* ReparentNotify		*/
1193		| SubstructureNotifyMask,
1194	StructureNotifyMask	    /* ConfigureNotify		*/
1195		| SubstructureNotifyMask,
1196	SubstructureRedirectMask,   /* ConfigureRequest		*/
1197	StructureNotifyMask	    /* GravityNotify		*/
1198		| SubstructureNotifyMask,
1199	ResizeRedirectMask,	    /* ResizeRequest		*/
1200	StructureNotifyMask	    /* CirculateNotify		*/
1201		| SubstructureNotifyMask,
1202	SubstructureRedirectMask,   /* CirculateRequest		*/
1203	PropertyChangeMask,	    /* PropertyNotify		*/
1204	NonMaskableMask,	    /* SelectionClear		*/
1205	NonMaskableMask,	    /* SelectionRequest		*/
1206	NonMaskableMask,	    /* SelectionNotify		*/
1207	ColormapChangeMask,	    /* ColormapNotify		*/
1208	NonMaskableMask,	    /* ClientMessage		*/
1209	NonMaskableMask		    /* MappingNotify		*/
1210};
1211
1212EventMask _XtConvertTypeToMask (
1213    int		eventType)
1214{
1215    if ((Cardinal) eventType < XtNumber(masks))
1216	return masks[eventType];
1217    else
1218	return NoEventMask;
1219}
1220
1221Boolean _XtOnGrabList(
1222    register Widget widget,
1223    XtGrabRec  *grabList)
1224{
1225    register XtGrabRec* gl;
1226    for (; widget != NULL; widget = (Widget)widget->core.parent) {
1227	for (gl = grabList; gl != NULL; gl = gl->next) {
1228	    if (gl->widget == widget) return TRUE;
1229	    if (gl->exclusive) break;
1230	}
1231    }
1232    return FALSE;
1233}
1234
1235static Widget LookupSpringLoaded(
1236    XtGrabList	grabList)
1237{
1238    XtGrabList	gl;
1239
1240    for (gl = grabList; gl != NULL; gl = gl->next) {
1241	if (gl->spring_loaded) {
1242	  if (XtIsSensitive(gl->widget))
1243	    return gl->widget;
1244	  else
1245	    return NULL;
1246	}
1247	if (gl->exclusive) break;
1248    }
1249    return NULL;
1250}
1251
1252static Boolean DispatchEvent(
1253    XEvent* event,
1254    Widget widget)
1255{
1256
1257    if (event->type == EnterNotify &&
1258	event->xcrossing.mode == NotifyNormal &&
1259	widget->core.widget_class->core_class.compress_enterleave) {
1260	if (XPending(event->xcrossing.display)) {
1261	    XEvent nextEvent;
1262	    XPeekEvent(event->xcrossing.display, &nextEvent);
1263	    if (nextEvent.type == LeaveNotify &&
1264		event->xcrossing.window == nextEvent.xcrossing.window &&
1265		nextEvent.xcrossing.mode == NotifyNormal &&
1266		((event->xcrossing.detail != NotifyInferior &&
1267		 nextEvent.xcrossing.detail != NotifyInferior) ||
1268		 (event->xcrossing.detail == NotifyInferior &&
1269		 nextEvent.xcrossing.detail == NotifyInferior))) {
1270		/* skip the enter/leave pair */
1271		XNextEvent(event->xcrossing.display, &nextEvent);
1272		return False;
1273	    }
1274	}
1275    }
1276
1277    if (event->type == MotionNotify &&
1278	    widget->core.widget_class->core_class.compress_motion) {
1279	while (XPending(event->xmotion.display)) {
1280	    XEvent nextEvent;
1281	    XPeekEvent(event->xmotion.display, &nextEvent);
1282	    if (nextEvent.type == MotionNotify &&
1283		    event->xmotion.window == nextEvent.xmotion.window &&
1284		    event->xmotion.subwindow == nextEvent.xmotion.subwindow) {
1285		/* replace the current event with the next one */
1286		XNextEvent(event->xmotion.display, event);
1287	    } else break;
1288	}
1289    }
1290
1291    return XtDispatchEventToWidget(widget, event);
1292}
1293
1294typedef enum _GrabType {pass, ignore, remap} GrabType;
1295
1296#if !defined(AIXV3) || !defined(AIXSHLIB)
1297static /* AIX shared libraries are broken */
1298#endif
1299Boolean _XtDefaultDispatcher(
1300    XEvent  *event)
1301{
1302    register    Widget widget;
1303    GrabType    grabType;
1304    XtPerDisplayInput pdi;
1305    XtGrabList  grabList;
1306    Boolean	was_dispatched = False;
1307    DPY_TO_APPCON(event->xany.display);
1308
1309    /* the default dispatcher discards all extension events */
1310    if (event->type >= LASTEvent)
1311	return False;
1312
1313    LOCK_APP(app);
1314
1315    switch (event->type) {
1316      case KeyPress:
1317      case KeyRelease:
1318      case ButtonPress:
1319      case ButtonRelease:	grabType = remap;	break;
1320      case MotionNotify:
1321      case EnterNotify:		grabType = ignore;	break;
1322      default:			grabType = pass;	break;
1323    }
1324
1325    widget = XtWindowToWidget (event->xany.display, event->xany.window);
1326    pdi = _XtGetPerDisplayInput(event->xany.display);
1327    grabList = *_XtGetGrabList(pdi);
1328
1329    if (widget == NULL) {
1330	if (grabType == remap
1331	    && (widget = LookupSpringLoaded(grabList)) != NULL) {
1332	    /* event occurred in a non-widget window, but we've promised also
1333	       to dispatch it to the nearest accessible spring_loaded widget */
1334	    was_dispatched = (XFilterEvent(event, XtWindow(widget))
1335			      || XtDispatchEventToWidget(widget, event));
1336	}
1337	else was_dispatched = XFilterEvent(event, None);
1338    }
1339    else if (grabType == pass) {
1340	if (event->type == LeaveNotify ||
1341	    event->type == FocusIn ||
1342	    event->type == FocusOut) {
1343		if (XtIsSensitive (widget))
1344		    was_dispatched = (XFilterEvent(event, XtWindow(widget)) ||
1345				      XtDispatchEventToWidget(widget, event));
1346	    } else was_dispatched = (XFilterEvent(event, XtWindow(widget)) ||
1347				     XtDispatchEventToWidget(widget, event));
1348    }
1349    else if (grabType == ignore) {
1350	if ((grabList == NULL || _XtOnGrabList(widget, grabList))
1351	    && XtIsSensitive(widget)) {
1352	    was_dispatched = (XFilterEvent(event, XtWindow(widget))
1353			      || DispatchEvent(event, widget));
1354	}
1355    }
1356    else if (grabType == remap) {
1357	EventMask	mask = _XtConvertTypeToMask(event->type);
1358	Widget		dspWidget;
1359	Boolean		was_filtered = False;
1360
1361	dspWidget = _XtFindRemapWidget(event, widget, mask, pdi);
1362
1363	if ((grabList == NULL ||_XtOnGrabList(dspWidget, grabList))
1364	    && XtIsSensitive(dspWidget)) {
1365	    if ((was_filtered = XFilterEvent(event, XtWindow(dspWidget)))) {
1366		/* If this event activated a device grab, release it. */
1367		_XtUngrabBadGrabs(event, widget, mask, pdi);
1368		was_dispatched = True;
1369	    } else
1370		was_dispatched = XtDispatchEventToWidget(dspWidget, event);
1371	}
1372	else _XtUngrabBadGrabs(event, widget, mask, pdi);
1373
1374	if (!was_filtered) {
1375	    /* Also dispatch to nearest accessible spring_loaded. */
1376	    /* Fetch this afterward to reflect modal list changes */
1377	    grabList = *_XtGetGrabList(pdi);
1378	    widget = LookupSpringLoaded(grabList);
1379	    if (widget != NULL && widget != dspWidget) {
1380		was_dispatched = (XFilterEvent(event, XtWindow(widget))
1381				  || XtDispatchEventToWidget(widget, event)
1382				  || was_dispatched);
1383	    }
1384	}
1385    }
1386    UNLOCK_APP(app);
1387    return was_dispatched;
1388}
1389
1390Boolean XtDispatchEvent (
1391    XEvent  *event)
1392{
1393    Boolean was_dispatched, safe;
1394    int dispatch_level;
1395    int starting_count;
1396    XtPerDisplay pd;
1397    Time	time = 0;
1398    XtEventDispatchProc dispatch = _XtDefaultDispatcher;
1399    XtAppContext app = XtDisplayToApplicationContext(event->xany.display);
1400
1401    LOCK_APP(app);
1402    dispatch_level = ++app->dispatch_level;
1403    starting_count = app->destroy_count;
1404
1405    switch (event->type) {
1406      case KeyPress:
1407      case KeyRelease:	   time = event->xkey.time;		break;
1408      case ButtonPress:
1409      case ButtonRelease:  time = event->xbutton.time;		break;
1410      case MotionNotify:   time = event->xmotion.time;		break;
1411      case EnterNotify:
1412      case LeaveNotify:	   time = event->xcrossing.time;	break;
1413      case PropertyNotify: time = event->xproperty.time;	break;
1414      case SelectionClear: time = event->xselectionclear.time;	break;
1415
1416      case MappingNotify:  _XtRefreshMapping(event, True);	break;
1417    }
1418    pd = _XtGetPerDisplay(event->xany.display);
1419    if (time) pd->last_timestamp = time;
1420    pd->last_event = *event;
1421
1422    if (pd->dispatcher_list) {
1423	dispatch = pd->dispatcher_list[event->type];
1424	if (dispatch == NULL) dispatch = _XtDefaultDispatcher;
1425    }
1426    was_dispatched = (*dispatch)(event);
1427
1428    /*
1429     * To make recursive XtDispatchEvent work, we need to do phase 2 destroys
1430     * only on those widgets destroyed by this particular dispatch.
1431     *
1432     */
1433
1434    if (app->destroy_count > starting_count)
1435	_XtDoPhase2Destroy(app, dispatch_level);
1436
1437    app->dispatch_level = dispatch_level - 1;
1438
1439    if ((safe = _XtSafeToDestroy(app))) {
1440	if (app->dpy_destroy_count != 0) _XtCloseDisplays(app);
1441	if (app->free_bindings) _XtDoFreeBindings(app);
1442    }
1443    UNLOCK_APP(app);
1444    LOCK_PROCESS;
1445    if (_XtAppDestroyCount != 0 && safe) _XtDestroyAppContexts();
1446    UNLOCK_PROCESS;
1447    return was_dispatched;
1448}
1449
1450/* ARGSUSED */
1451static void GrabDestroyCallback(
1452    Widget  widget,
1453    XtPointer closure,
1454    XtPointer call_data)
1455{
1456    /* Remove widget from grab list if it destroyed */
1457    XtRemoveGrab(widget);
1458}
1459
1460static XtGrabRec *NewGrabRec(
1461    Widget  widget,
1462    Boolean exclusive,
1463    Boolean spring_loaded)
1464{
1465    register XtGrabList    gl;
1466
1467    gl		      = XtNew(XtGrabRec);
1468    gl->next	      = NULL;
1469    gl->widget        = widget;
1470    gl->exclusive     = exclusive;
1471    gl->spring_loaded = spring_loaded;
1472
1473    return gl;
1474}
1475
1476void XtAddGrab(
1477    Widget  widget,
1478    _XtBoolean exclusive,
1479    _XtBoolean spring_loaded)
1480{
1481    register    XtGrabList gl;
1482    XtGrabList	*grabListPtr;
1483    XtAppContext app = XtWidgetToApplicationContext(widget);
1484
1485    LOCK_APP(app);
1486    LOCK_PROCESS;
1487    grabListPtr = _XtGetGrabList(_XtGetPerDisplayInput(XtDisplay(widget)));
1488
1489    if (spring_loaded && !exclusive) {
1490	XtAppWarningMsg(app,
1491		"grabError", "xtAddGrab", XtCXtToolkitError,
1492		"XtAddGrab requires exclusive grab if spring_loaded is TRUE",
1493		(String *) NULL, (Cardinal *) NULL);
1494	exclusive = TRUE;
1495    }
1496
1497    gl = NewGrabRec(widget, exclusive, spring_loaded);
1498    gl->next = *grabListPtr;
1499    *grabListPtr = gl;
1500
1501    XtAddCallback (widget, XtNdestroyCallback,
1502	    GrabDestroyCallback, (XtPointer) NULL);
1503    UNLOCK_PROCESS;
1504    UNLOCK_APP(app);
1505}
1506
1507void XtRemoveGrab(
1508    Widget  widget)
1509{
1510    register XtGrabList gl;
1511    register Boolean done;
1512    XtGrabList	*grabListPtr;
1513    XtAppContext app = XtWidgetToApplicationContext(widget);
1514
1515    LOCK_APP(app);
1516    LOCK_PROCESS;
1517
1518    grabListPtr = _XtGetGrabList(_XtGetPerDisplayInput(XtDisplay(widget)));
1519
1520    for (gl = *grabListPtr; gl != NULL; gl = gl->next) {
1521	if (gl->widget == widget) break;
1522    }
1523
1524    if (gl == NULL) {
1525	    XtAppWarningMsg(app,
1526		       "grabError","xtRemoveGrab",XtCXtToolkitError,
1527		       "XtRemoveGrab asked to remove a widget not on the list",
1528		       (String *)NULL, (Cardinal *)NULL);
1529	    UNLOCK_PROCESS;
1530    	    UNLOCK_APP(app);
1531	    return;
1532	}
1533
1534    do {
1535	gl = *grabListPtr;
1536	done = (gl->widget == widget);
1537	*grabListPtr = gl->next;
1538	XtRemoveCallback(gl->widget, XtNdestroyCallback,
1539		GrabDestroyCallback, (XtPointer)NULL);
1540	XtFree((char *)gl);
1541    } while (! done);
1542    UNLOCK_PROCESS;
1543    UNLOCK_APP(app);
1544    return;
1545}
1546
1547void XtMainLoop(void)
1548{
1549	XtAppMainLoop(_XtDefaultAppContext());
1550}
1551
1552void XtAppMainLoop(
1553	XtAppContext app)
1554{
1555    XEvent event;
1556
1557    LOCK_APP(app);
1558    do {
1559    	XtAppNextEvent(app, &event);
1560#ifdef XTHREADS
1561	/* assert(app == XtDisplayToApplicationContext(event.xany.display)); */
1562#endif
1563	XtDispatchEvent(&event);
1564    } while(app->exit_flag == FALSE);
1565    UNLOCK_APP(app);
1566}
1567
1568void _XtFreeEventTable(
1569    XtEventTable *event_table)
1570{
1571    register XtEventTable event;
1572
1573    event = *event_table;
1574    while (event != NULL) {
1575	register XtEventTable next = event->next;
1576	XtFree((char *) event);
1577	event = next;
1578    }
1579}
1580
1581Time XtLastTimestampProcessed(
1582    Display *dpy)
1583{
1584    Time time;
1585    DPY_TO_APPCON(dpy);
1586
1587    LOCK_APP(app);
1588    LOCK_PROCESS;
1589    time =  _XtGetPerDisplay(dpy)->last_timestamp;
1590    UNLOCK_PROCESS;
1591    UNLOCK_APP(app);
1592    return(time);
1593}
1594
1595XEvent* XtLastEventProcessed(
1596    Display* dpy)
1597{
1598    XEvent* le = NULL;
1599    DPY_TO_APPCON(dpy);
1600
1601    LOCK_APP(app);
1602    le = &_XtGetPerDisplay(dpy)->last_event;
1603    if (!le->xany.serial)
1604	le =  NULL;
1605    UNLOCK_APP(app);
1606    return le;
1607}
1608
1609void _XtSendFocusEvent(
1610    Widget child,
1611    int type)
1612{
1613    child = XtIsWidget(child) ? child : _XtWindowedAncestor(child);
1614    if (XtIsSensitive(child) && !child->core.being_destroyed
1615	&& XtIsRealized(child)
1616	&& (XtBuildEventMask(child) & FocusChangeMask))
1617    {
1618	XFocusChangeEvent event;
1619	Display* dpy = XtDisplay (child);
1620
1621	event.type = type;
1622	event.serial = LastKnownRequestProcessed(dpy);
1623	event.send_event = True;
1624	event.display = dpy;
1625	event.window = XtWindow(child);
1626	event.mode = NotifyNormal;
1627	event.detail = NotifyAncestor;
1628	if (XFilterEvent((XEvent*)&event, XtWindow(child)))
1629	    return;
1630	XtDispatchEventToWidget(child, (XEvent*)&event);
1631    }
1632}
1633
1634static XtEventDispatchProc* NewDispatcherList(void)
1635{
1636    XtEventDispatchProc* l =
1637	(XtEventDispatchProc*) __XtCalloc((Cardinal) 128,
1638					(Cardinal)sizeof(XtEventDispatchProc));
1639    return l;
1640}
1641
1642XtEventDispatchProc XtSetEventDispatcher(
1643    Display		*dpy,
1644    int			event_type,
1645    XtEventDispatchProc	proc)
1646{
1647    XtEventDispatchProc *list;
1648    XtEventDispatchProc old_proc;
1649    register XtPerDisplay pd;
1650    DPY_TO_APPCON(dpy);
1651
1652    LOCK_APP(app);
1653    LOCK_PROCESS;
1654    pd = _XtGetPerDisplay(dpy);
1655
1656    list = pd->dispatcher_list;
1657    if (!list) {
1658	if (proc) list = pd->dispatcher_list = NewDispatcherList();
1659	else return _XtDefaultDispatcher;
1660    }
1661    old_proc = list[event_type];
1662    list[event_type] = proc;
1663    if (old_proc == NULL) old_proc = _XtDefaultDispatcher;
1664    UNLOCK_PROCESS;
1665    UNLOCK_APP(app);
1666    return old_proc;
1667}
1668
1669void XtRegisterExtensionSelector(
1670    Display		*dpy,
1671    int			min_event_type,
1672    int			max_event_type,
1673    XtExtensionSelectProc	proc,
1674    XtPointer 		client_data)
1675{
1676    ExtSelectRec *e;
1677    XtPerDisplay pd;
1678    int i;
1679    DPY_TO_APPCON(dpy);
1680
1681    if (dpy == NULL) XtErrorMsg("nullDisplay",
1682		"xtRegisterExtensionSelector", XtCXtToolkitError,
1683		"XtRegisterExtensionSelector requires a non-NULL display",
1684		(String *) NULL, (Cardinal *) NULL);
1685
1686    LOCK_APP(app);
1687    LOCK_PROCESS;
1688    pd = _XtGetPerDisplay(dpy);
1689
1690    for (i = 0; i < pd->ext_select_count; i++) {
1691	e = &pd->ext_select_list[i];
1692	if (e->min == min_event_type && e->max == max_event_type) {
1693	    e->proc = proc;
1694	    e->client_data = client_data;
1695	    return;
1696	}
1697	if ((min_event_type >= e->min && min_event_type <= e->max) ||
1698	    (max_event_type >= e->min && max_event_type <= e->max)) {
1699	    XtErrorMsg("rangeError", "xtRegisterExtensionSelector",
1700		       XtCXtToolkitError,
1701	"Attempt to register multiple selectors for one extension event type",
1702		       (String *) NULL, (Cardinal *) NULL);
1703	    UNLOCK_PROCESS;
1704	    UNLOCK_APP(app);
1705	    return;
1706	}
1707    }
1708    pd->ext_select_count++;
1709    pd->ext_select_list =
1710	    (ExtSelectRec *) XtRealloc((char *) pd->ext_select_list,
1711		       pd->ext_select_count * sizeof(ExtSelectRec));
1712    for (i = pd->ext_select_count - 1; i > 0; i--) {
1713	if (pd->ext_select_list[i-1].min > min_event_type) {
1714	    pd->ext_select_list[i] = pd->ext_select_list[i-1];
1715	} else break;
1716    }
1717    pd->ext_select_list[i].min = min_event_type;
1718    pd->ext_select_list[i].max = max_event_type;
1719    pd->ext_select_list[i].proc = proc;
1720    pd->ext_select_list[i].client_data = client_data;
1721    UNLOCK_PROCESS;
1722    UNLOCK_APP(app);
1723}
1724
1725void _XtExtensionSelect(
1726    Widget widget)
1727{
1728    int i;
1729    XtPerDisplay pd;
1730    WIDGET_TO_APPCON(widget);
1731
1732    LOCK_APP(app);
1733    LOCK_PROCESS;
1734
1735    pd = _XtGetPerDisplay(XtDisplay(widget));
1736
1737    for (i = 0; i < pd->ext_select_count; i++) {
1738	CallExtensionSelector(widget, pd->ext_select_list+i, FALSE);
1739    }
1740    UNLOCK_PROCESS;
1741    UNLOCK_APP(app);
1742}
1743