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