Event.c revision a3bd7f05
1444c061aSmrg/***********************************************************
2249c3046SmrgCopyright (c) 1993, Oracle and/or its affiliates. All rights reserved.
31477040fSmrg
41477040fSmrgPermission is hereby granted, free of charge, to any person obtaining a
51477040fSmrgcopy of this software and associated documentation files (the "Software"),
61477040fSmrgto deal in the Software without restriction, including without limitation
71477040fSmrgthe rights to use, copy, modify, merge, publish, distribute, sublicense,
81477040fSmrgand/or sell copies of the Software, and to permit persons to whom the
91477040fSmrgSoftware is furnished to do so, subject to the following conditions:
101477040fSmrg
111477040fSmrgThe above copyright notice and this permission notice (including the next
121477040fSmrgparagraph) shall be included in all copies or substantial portions of the
131477040fSmrgSoftware.
141477040fSmrg
151477040fSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
161477040fSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
171477040fSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
181477040fSmrgTHE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
191477040fSmrgLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
201477040fSmrgFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
211477040fSmrgDEALINGS IN THE SOFTWARE.
221477040fSmrg
231477040fSmrgCopyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
24444c061aSmrg
25444c061aSmrg                        All Rights Reserved
26444c061aSmrg
27444c061aSmrgPermission to use, copy, modify, and distribute this software and its
28444c061aSmrgdocumentation for any purpose and without fee is hereby granted,
29444c061aSmrgprovided that the above copyright notice appear in all copies and that
30444c061aSmrgboth that copyright notice and this permission notice appear in
311477040fSmrgsupporting documentation, and that the name of Digital not be
32444c061aSmrgused in advertising or publicity pertaining to distribution of the
33444c061aSmrgsoftware without specific, written prior permission.
34444c061aSmrg
35444c061aSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
36444c061aSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
37444c061aSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
38444c061aSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
39444c061aSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
40444c061aSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
41444c061aSmrgSOFTWARE.
42444c061aSmrg
43444c061aSmrg******************************************************************/
44444c061aSmrg
45444c061aSmrg/*
46444c061aSmrg
47444c061aSmrgCopyright 1987, 1988, 1998  The Open Group
48444c061aSmrg
49444c061aSmrgPermission to use, copy, modify, distribute, and sell this software and its
50444c061aSmrgdocumentation for any purpose is hereby granted without fee, provided that
51444c061aSmrgthe above copyright notice appear in all copies and that both that
52444c061aSmrgcopyright notice and this permission notice appear in supporting
53444c061aSmrgdocumentation.
54444c061aSmrg
55444c061aSmrgThe above copyright notice and this permission notice shall be included in
56444c061aSmrgall copies or substantial portions of the Software.
57444c061aSmrg
58444c061aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59444c061aSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60444c061aSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
61444c061aSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
62444c061aSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
63444c061aSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
64444c061aSmrg
65444c061aSmrgExcept as contained in this notice, the name of The Open Group shall not be
66444c061aSmrgused in advertising or otherwise to promote the sale, use or other dealings
67444c061aSmrgin this Software without prior written authorization from The Open Group.
68444c061aSmrg
69444c061aSmrg*/
70444c061aSmrg
71444c061aSmrg#ifdef HAVE_CONFIG_H
72444c061aSmrg#include <config.h>
73444c061aSmrg#endif
74444c061aSmrg#include "IntrinsicI.h"
75444c061aSmrg#include "Shell.h"
76444c061aSmrg#include "StringDefs.h"
77444c061aSmrg
78444c061aSmrgtypedef struct _XtEventRecExt {
79444c061aSmrg    int type;
80a3bd7f05Smrg    XtPointer select_data[1];   /* actual dimension is [mask] */
81444c061aSmrg} XtEventRecExt;
82444c061aSmrg
83444c061aSmrg#define EXT_TYPE(p) (((XtEventRecExt*) ((p)+1))->type)
84444c061aSmrg#define EXT_SELECT_DATA(p,n) (((XtEventRecExt*) ((p)+1))->select_data[n])
85444c061aSmrg
86444c061aSmrg#define NonMaskableMask ((EventMask)0x80000000L)
87444c061aSmrg
88444c061aSmrg/*
89444c061aSmrg * These are definitions to make the code that handles exposure compresssion
90444c061aSmrg * easier to read.
91444c061aSmrg *
92444c061aSmrg * COMP_EXPOSE      - The compression exposure field of "widget"
93444c061aSmrg * COMP_EXPOSE_TYPE - The type of compression (lower 4 bits of COMP_EXPOSE.
94444c061aSmrg * GRAPHICS_EXPOSE  - TRUE if the widget wants graphics expose events
95444c061aSmrg *                    dispatched.
96444c061aSmrg * NO_EXPOSE        - TRUE if the widget wants No expose events dispatched.
97444c061aSmrg */
98444c061aSmrg
99444c061aSmrg#define COMP_EXPOSE   (widget->core.widget_class->core_class.compress_exposure)
100444c061aSmrg#define COMP_EXPOSE_TYPE (COMP_EXPOSE & 0x0f)
101444c061aSmrg#define GRAPHICS_EXPOSE  ((XtExposeGraphicsExpose & COMP_EXPOSE) || \
102a3bd7f05Smrg                          (XtExposeGraphicsExposeMerged & COMP_EXPOSE))
103444c061aSmrg#define NO_EXPOSE        (XtExposeNoExpose & COMP_EXPOSE)
104444c061aSmrg
105a3bd7f05SmrgEventMask
106a3bd7f05SmrgXtBuildEventMask(Widget widget)
107444c061aSmrg{
108444c061aSmrg    XtEventTable ev;
109a3bd7f05Smrg    EventMask mask = 0L;
110a3bd7f05Smrg
111444c061aSmrg    WIDGET_TO_APPCON(widget);
112444c061aSmrg
113444c061aSmrg    LOCK_APP(app);
1140568f49bSmrg    for (ev = widget->core.event_table; ev != NULL; ev = ev->next) {
115a3bd7f05Smrg        if (!ev->select)
116a3bd7f05Smrg            continue;
117a3bd7f05Smrg
118a3bd7f05Smrg        if (!ev->has_type_specifier)
119a3bd7f05Smrg            mask |= ev->mask;
120a3bd7f05Smrg        else {
121a3bd7f05Smrg            if (EXT_TYPE(ev) < LASTEvent) {
122a3bd7f05Smrg                Cardinal i;
123a3bd7f05Smrg
124a3bd7f05Smrg                for (i = 0; i < ev->mask; i++)
125a3bd7f05Smrg                    if (EXT_SELECT_DATA(ev, i))
126a3bd7f05Smrg                        mask |= *(EventMask *) EXT_SELECT_DATA(ev, i);
127a3bd7f05Smrg            }
128a3bd7f05Smrg        }
129a3bd7f05Smrg    }
130444c061aSmrg    LOCK_PROCESS;
131444c061aSmrg    if (widget->core.widget_class->core_class.expose != NULL)
132a3bd7f05Smrg        mask |= ExposureMask;
133444c061aSmrg    if (widget->core.widget_class->core_class.visible_interest)
134a3bd7f05Smrg        mask |= VisibilityChangeMask;
135444c061aSmrg    UNLOCK_PROCESS;
136444c061aSmrg    if (widget->core.tm.translations)
137a3bd7f05Smrg        mask |= widget->core.tm.translations->eventMask;
138444c061aSmrg
139a3bd7f05Smrg    mask = mask & ~NonMaskableMask;
140444c061aSmrg    UNLOCK_APP(app);
141444c061aSmrg    return mask;
142444c061aSmrg}
143444c061aSmrg
144a3bd7f05Smrgstatic void
145a3bd7f05SmrgCallExtensionSelector(Widget widget, ExtSelectRec *rec, Boolean forceCall)
146444c061aSmrg{
147a3bd7f05Smrg    XtEventRec *p;
148a3bd7f05Smrg    XtPointer *data;
149a3bd7f05Smrg    int *types;
150444c061aSmrg    Cardinal i, count = 0;
151444c061aSmrg
152444c061aSmrg    for (p = widget->core.event_table; p != NULL; p = p->next)
153a3bd7f05Smrg        if (p->has_type_specifier &&
154a3bd7f05Smrg            EXT_TYPE(p) >= rec->min && EXT_TYPE(p) <= rec->max)
155a3bd7f05Smrg            count = (Cardinal) (count + p->mask);
156444c061aSmrg
157a3bd7f05Smrg    if (count == 0 && !forceCall)
158a3bd7f05Smrg        return;
159444c061aSmrg
160a3bd7f05Smrg    data = (XtPointer *) ALLOCATE_LOCAL(count * sizeof(XtPointer));
161a3bd7f05Smrg    types = (int *) ALLOCATE_LOCAL(count * sizeof(int));
162444c061aSmrg    count = 0;
163444c061aSmrg
164444c061aSmrg    for (p = widget->core.event_table; p != NULL; p = p->next)
165a3bd7f05Smrg        if (p->has_type_specifier &&
166a3bd7f05Smrg            EXT_TYPE(p) >= rec->min && EXT_TYPE(p) <= rec->max)
167a3bd7f05Smrg            for (i = 0; i < p->mask; i++) {
168a3bd7f05Smrg                types[count] = EXT_TYPE(p);
169a3bd7f05Smrg                data[count++] = EXT_SELECT_DATA(p, i);
170a3bd7f05Smrg            }
171a3bd7f05Smrg
172a3bd7f05Smrg    (*rec->proc) (widget, types, data, (int) count, rec->client_data);
173a3bd7f05Smrg    DEALLOCATE_LOCAL((char *) types);
174a3bd7f05Smrg    DEALLOCATE_LOCAL((char *) data);
175444c061aSmrg}
176444c061aSmrg
177444c061aSmrgstatic void
178a3bd7f05SmrgRemoveEventHandler(Widget widget,
179a3bd7f05Smrg                   XtPointer select_data,
180a3bd7f05Smrg                   int type,
181a3bd7f05Smrg                   Boolean has_type_specifier,
182a3bd7f05Smrg                   Boolean other,
183a3bd7f05Smrg                   XtEventHandler proc,
184a3bd7f05Smrg                   XtPointer closure,
185a3bd7f05Smrg                   Boolean raw)
186444c061aSmrg{
187444c061aSmrg    XtEventRec *p, **pp;
1880568f49bSmrg    EventMask oldMask = XtBuildEventMask(widget);
189444c061aSmrg
190a3bd7f05Smrg    if (raw)
191a3bd7f05Smrg        raw = 1;
192444c061aSmrg    pp = &widget->core.event_table;
193444c061aSmrg    while ((p = *pp) &&
194a3bd7f05Smrg           (p->proc != proc || p->closure != closure || p->select == raw ||
195a3bd7f05Smrg            has_type_specifier != p->has_type_specifier ||
196a3bd7f05Smrg            (has_type_specifier && EXT_TYPE(p) != type)))
197a3bd7f05Smrg        pp = &p->next;
198a3bd7f05Smrg    if (!p)
199a3bd7f05Smrg        return;
200444c061aSmrg
201444c061aSmrg    /* un-register it */
202444c061aSmrg    if (!has_type_specifier) {
203a3bd7f05Smrg        EventMask eventMask = *(EventMask *) select_data;
204a3bd7f05Smrg
205a3bd7f05Smrg        eventMask &= ~NonMaskableMask;
206a3bd7f05Smrg        if (other)
207a3bd7f05Smrg            eventMask |= NonMaskableMask;
208a3bd7f05Smrg        p->mask &= ~eventMask;
209a3bd7f05Smrg    }
210a3bd7f05Smrg    else {
211a3bd7f05Smrg        Cardinal i;
212a3bd7f05Smrg
213a3bd7f05Smrg        /* p->mask specifies count of EXT_SELECT_DATA(p,i)
214a3bd7f05Smrg         * search through the list of selection data, if not found
215a3bd7f05Smrg         * dont remove this handler
216a3bd7f05Smrg         */
217a3bd7f05Smrg        for (i = 0; i < p->mask && select_data != EXT_SELECT_DATA(p, i);)
218a3bd7f05Smrg            i++;
219a3bd7f05Smrg        if (i == p->mask)
220a3bd7f05Smrg            return;
221a3bd7f05Smrg        if (p->mask == 1)
222a3bd7f05Smrg            p->mask = 0;
223a3bd7f05Smrg        else {
224a3bd7f05Smrg            p->mask--;
225a3bd7f05Smrg            while (i < p->mask) {
226a3bd7f05Smrg                EXT_SELECT_DATA(p, i) = EXT_SELECT_DATA(p, i + 1);
227a3bd7f05Smrg                i++;
228a3bd7f05Smrg            }
229a3bd7f05Smrg        }
230444c061aSmrg    }
231444c061aSmrg
232a3bd7f05Smrg    if (!p->mask) {             /* delete it entirely */
233444c061aSmrg        *pp = p->next;
234a3bd7f05Smrg        XtFree((char *) p);
235444c061aSmrg    }
236444c061aSmrg
237444c061aSmrg    /* Reset select mask if realized and not raw. */
238a3bd7f05Smrg    if (!raw && XtIsRealized(widget) && !widget->core.being_destroyed) {
239a3bd7f05Smrg        EventMask mask = XtBuildEventMask(widget);
240a3bd7f05Smrg        Display *dpy = XtDisplay(widget);
241a3bd7f05Smrg
242a3bd7f05Smrg        if (oldMask != mask)
243a3bd7f05Smrg            XSelectInput(dpy, XtWindow(widget), (long) mask);
244a3bd7f05Smrg
245a3bd7f05Smrg        if (has_type_specifier) {
246a3bd7f05Smrg            XtPerDisplay pd = _XtGetPerDisplay(dpy);
247a3bd7f05Smrg            int i;
248a3bd7f05Smrg
249a3bd7f05Smrg            for (i = 0; i < pd->ext_select_count; i++) {
250a3bd7f05Smrg                if (type >= pd->ext_select_list[i].min &&
251a3bd7f05Smrg                    type <= pd->ext_select_list[i].max) {
252a3bd7f05Smrg                    CallExtensionSelector(widget, pd->ext_select_list + i,
253a3bd7f05Smrg                                          TRUE);
254a3bd7f05Smrg                    break;
255a3bd7f05Smrg                }
256a3bd7f05Smrg                if (type < pd->ext_select_list[i].min)
257a3bd7f05Smrg                    break;
258a3bd7f05Smrg            }
259a3bd7f05Smrg        }
260444c061aSmrg    }
261444c061aSmrg}
262444c061aSmrg
263a3bd7f05Smrg/*      Function Name: AddEventHandler
264a3bd7f05Smrg *      Description: An Internal routine that does the actual work of
265444c061aSmrg *                   adding the event handlers.
266a3bd7f05Smrg *      Arguments: widget - widget to register an event handler for.
267444c061aSmrg *                 eventMask - events to mask for.
268444c061aSmrg *                 other - pass non maskable events to this proceedure.
269444c061aSmrg *                 proc - proceedure to register.
270444c061aSmrg *                 closure - data to pass to the event hander.
271444c061aSmrg *                 position - where to add this event handler.
272444c061aSmrg *                 force_new_position - If the element is already in the
273444c061aSmrg *                                      list, this will force it to the
274444c061aSmrg *                                      beginning or end depending on position.
275444c061aSmrg *                 raw - If FALSE call XSelectInput for events in mask.
276a3bd7f05Smrg *      Returns: none
277444c061aSmrg */
278444c061aSmrg
279444c061aSmrgstatic void
280a3bd7f05SmrgAddEventHandler(Widget widget,
281a3bd7f05Smrg                XtPointer select_data,
282a3bd7f05Smrg                int type,
283a3bd7f05Smrg                Boolean has_type_specifier,
284a3bd7f05Smrg                Boolean other,
285a3bd7f05Smrg                XtEventHandler proc,
286a3bd7f05Smrg                XtPointer closure,
287a3bd7f05Smrg                XtListPosition position,
288a3bd7f05Smrg                Boolean force_new_position,
289a3bd7f05Smrg                Boolean raw)
290444c061aSmrg{
291444c061aSmrg    register XtEventRec *p, **pp;
292444c061aSmrg    EventMask oldMask = 0, eventMask = 0;
293444c061aSmrg
294444c061aSmrg    if (!has_type_specifier) {
295a3bd7f05Smrg        eventMask = *(EventMask *) select_data & ~NonMaskableMask;
296a3bd7f05Smrg        if (other)
297a3bd7f05Smrg            eventMask |= NonMaskableMask;
298a3bd7f05Smrg        if (!eventMask)
299a3bd7f05Smrg            return;
300a3bd7f05Smrg    }
301a3bd7f05Smrg    else if (!type)
302a3bd7f05Smrg        return;
303444c061aSmrg
304a3bd7f05Smrg    if (XtIsRealized(widget) && !raw)
305a3bd7f05Smrg        oldMask = XtBuildEventMask(widget);
306444c061aSmrg
307a3bd7f05Smrg    if (raw)
308a3bd7f05Smrg        raw = 1;
309444c061aSmrg    pp = &widget->core.event_table;
310444c061aSmrg    while ((p = *pp) &&
311a3bd7f05Smrg           (p->proc != proc || p->closure != closure || p->select == raw ||
312a3bd7f05Smrg            has_type_specifier != p->has_type_specifier ||
313a3bd7f05Smrg            (has_type_specifier && EXT_TYPE(p) != type)))
314a3bd7f05Smrg        pp = &p->next;
315a3bd7f05Smrg
316a3bd7f05Smrg    if (!p) {                   /* New proc to add to list */
317a3bd7f05Smrg        if (has_type_specifier) {
318a3bd7f05Smrg            p = (XtEventRec *) __XtMalloc(sizeof(XtEventRec) +
319a3bd7f05Smrg                                          sizeof(XtEventRecExt));
320a3bd7f05Smrg            EXT_TYPE(p) = type;
321a3bd7f05Smrg            EXT_SELECT_DATA(p, 0) = select_data;
322a3bd7f05Smrg            p->mask = 1;
323a3bd7f05Smrg            p->has_type_specifier = True;
324a3bd7f05Smrg        }
325a3bd7f05Smrg        else {
326a3bd7f05Smrg            p = (XtEventRec *) __XtMalloc(sizeof(XtEventRec));
327a3bd7f05Smrg            p->mask = eventMask;
328a3bd7f05Smrg            p->has_type_specifier = False;
329a3bd7f05Smrg        }
330a3bd7f05Smrg        p->proc = proc;
331a3bd7f05Smrg        p->closure = closure;
332a3bd7f05Smrg        p->select = !raw;
333a3bd7f05Smrg
334a3bd7f05Smrg        if (position == XtListHead) {
335a3bd7f05Smrg            p->next = widget->core.event_table;
336a3bd7f05Smrg            widget->core.event_table = p;
337a3bd7f05Smrg        }
338a3bd7f05Smrg        else {
339a3bd7f05Smrg            *pp = p;
340a3bd7f05Smrg            p->next = NULL;
341a3bd7f05Smrg        }
342444c061aSmrg    }
343444c061aSmrg    else {
344a3bd7f05Smrg        if (force_new_position) {
345a3bd7f05Smrg            *pp = p->next;
346a3bd7f05Smrg
347a3bd7f05Smrg            if (position == XtListHead) {
348a3bd7f05Smrg                p->next = widget->core.event_table;
349a3bd7f05Smrg                widget->core.event_table = p;
350a3bd7f05Smrg            }
351a3bd7f05Smrg            else {
352a3bd7f05Smrg                /*
353a3bd7f05Smrg                 * Find the last element in the list.
354a3bd7f05Smrg                 */
355a3bd7f05Smrg                while (*pp)
356a3bd7f05Smrg                    pp = &(*pp)->next;
357a3bd7f05Smrg                *pp = p;
358a3bd7f05Smrg                p->next = NULL;
359a3bd7f05Smrg            }
360a3bd7f05Smrg        }
361a3bd7f05Smrg
362a3bd7f05Smrg        if (!has_type_specifier)
363a3bd7f05Smrg            p->mask |= eventMask;
364a3bd7f05Smrg        else {
365a3bd7f05Smrg            Cardinal i;
366a3bd7f05Smrg
367a3bd7f05Smrg            /* p->mask specifies count of EXT_SELECT_DATA(p,i) */
368a3bd7f05Smrg            for (i = 0; i < p->mask && select_data != EXT_SELECT_DATA(p, i);)
369a3bd7f05Smrg                i++;
370a3bd7f05Smrg            if (i == p->mask) {
371a3bd7f05Smrg                p = (XtEventRec *) XtRealloc((char *) p,
372a3bd7f05Smrg                                             (Cardinal) (sizeof(XtEventRec) +
373a3bd7f05Smrg                                                         sizeof(XtEventRecExt) +
374a3bd7f05Smrg                                                         p->mask *
375a3bd7f05Smrg                                                         sizeof(XtPointer)));
376a3bd7f05Smrg                EXT_SELECT_DATA(p, i) = select_data;
377a3bd7f05Smrg                p->mask++;
378a3bd7f05Smrg                *pp = p;
379a3bd7f05Smrg            }
380a3bd7f05Smrg        }
381444c061aSmrg    }
382444c061aSmrg
383444c061aSmrg    if (XtIsRealized(widget) && !raw) {
384a3bd7f05Smrg        EventMask mask = XtBuildEventMask(widget);
385a3bd7f05Smrg        Display *dpy = XtDisplay(widget);
386a3bd7f05Smrg
387a3bd7f05Smrg        if (oldMask != mask)
388a3bd7f05Smrg            XSelectInput(dpy, XtWindow(widget), (long) mask);
389a3bd7f05Smrg
390a3bd7f05Smrg        if (has_type_specifier) {
391a3bd7f05Smrg            XtPerDisplay pd = _XtGetPerDisplay(dpy);
392a3bd7f05Smrg            int i;
393a3bd7f05Smrg
394a3bd7f05Smrg            for (i = 0; i < pd->ext_select_count; i++) {
395a3bd7f05Smrg                if (type >= pd->ext_select_list[i].min &&
396a3bd7f05Smrg                    type <= pd->ext_select_list[i].max) {
397a3bd7f05Smrg                    CallExtensionSelector(widget, pd->ext_select_list + i,
398a3bd7f05Smrg                                          FALSE);
399a3bd7f05Smrg                    break;
400a3bd7f05Smrg                }
401a3bd7f05Smrg                if (type < pd->ext_select_list[i].min)
402a3bd7f05Smrg                    break;
403a3bd7f05Smrg            }
404a3bd7f05Smrg        }
405444c061aSmrg    }
406444c061aSmrg}
407444c061aSmrg
408a3bd7f05Smrgvoid
409a3bd7f05SmrgXtRemoveEventHandler(Widget widget,
410a3bd7f05Smrg                     EventMask eventMask,
411a3bd7f05Smrg                     _XtBoolean other,
412a3bd7f05Smrg                     XtEventHandler proc,
413a3bd7f05Smrg                     XtPointer closure)
414444c061aSmrg{
415444c061aSmrg    WIDGET_TO_APPCON(widget);
416444c061aSmrg    LOCK_APP(app);
417444c061aSmrg    RemoveEventHandler(widget, (XtPointer) &eventMask, 0, FALSE,
418a3bd7f05Smrg                       (Boolean) other, proc, closure, FALSE);
419444c061aSmrg    UNLOCK_APP(app);
420444c061aSmrg}
421444c061aSmrg
422a3bd7f05Smrgvoid
423a3bd7f05SmrgXtAddEventHandler(Widget widget,
424a3bd7f05Smrg                  EventMask eventMask,
425a3bd7f05Smrg                  _XtBoolean other,
426a3bd7f05Smrg                  XtEventHandler proc,
427a3bd7f05Smrg                  XtPointer closure)
428444c061aSmrg{
429444c061aSmrg    WIDGET_TO_APPCON(widget);
430444c061aSmrg    LOCK_APP(app);
4310568f49bSmrg    AddEventHandler(widget, (XtPointer) &eventMask, 0, FALSE, (Boolean) other,
432a3bd7f05Smrg                    proc, closure, XtListTail, FALSE, FALSE);
433444c061aSmrg    UNLOCK_APP(app);
434444c061aSmrg}
435444c061aSmrg
436a3bd7f05Smrgvoid
437a3bd7f05SmrgXtInsertEventHandler(Widget widget,
438a3bd7f05Smrg                     EventMask eventMask,
439a3bd7f05Smrg                     _XtBoolean other,
440a3bd7f05Smrg                     XtEventHandler proc,
441a3bd7f05Smrg                     XtPointer closure,
442a3bd7f05Smrg                     XtListPosition position)
443444c061aSmrg{
444444c061aSmrg    WIDGET_TO_APPCON(widget);
445444c061aSmrg    LOCK_APP(app);
4460568f49bSmrg    AddEventHandler(widget, (XtPointer) &eventMask, 0, FALSE, (Boolean) other,
447a3bd7f05Smrg                    proc, closure, position, TRUE, FALSE);
448444c061aSmrg    UNLOCK_APP(app);
449444c061aSmrg}
450444c061aSmrg
451a3bd7f05Smrgvoid
452a3bd7f05SmrgXtRemoveRawEventHandler(Widget widget,
453a3bd7f05Smrg                        EventMask eventMask,
454a3bd7f05Smrg                        _XtBoolean other,
455a3bd7f05Smrg                        XtEventHandler proc,
456a3bd7f05Smrg                        XtPointer closure)
457444c061aSmrg{
458444c061aSmrg    WIDGET_TO_APPCON(widget);
459444c061aSmrg    LOCK_APP(app);
460444c061aSmrg    RemoveEventHandler(widget, (XtPointer) &eventMask, 0, FALSE,
461a3bd7f05Smrg                       (Boolean) other, proc, closure, TRUE);
462444c061aSmrg    UNLOCK_APP(app);
463444c061aSmrg}
464444c061aSmrg
465a3bd7f05Smrgvoid
466a3bd7f05SmrgXtInsertRawEventHandler(Widget widget,
467a3bd7f05Smrg                        EventMask eventMask,
468a3bd7f05Smrg                        _XtBoolean other,
469a3bd7f05Smrg                        XtEventHandler proc,
470a3bd7f05Smrg                        XtPointer closure,
471a3bd7f05Smrg                        XtListPosition position)
472444c061aSmrg{
473444c061aSmrg    WIDGET_TO_APPCON(widget);
474444c061aSmrg    LOCK_APP(app);
4750568f49bSmrg    AddEventHandler(widget, (XtPointer) &eventMask, 0, FALSE, (Boolean) other,
476a3bd7f05Smrg                    proc, closure, position, TRUE, TRUE);
477444c061aSmrg    UNLOCK_APP(app);
478444c061aSmrg}
479444c061aSmrg
480a3bd7f05Smrgvoid
481a3bd7f05SmrgXtAddRawEventHandler(Widget widget,
482a3bd7f05Smrg                     EventMask eventMask,
483a3bd7f05Smrg                     _XtBoolean other,
484a3bd7f05Smrg                     XtEventHandler proc,
485a3bd7f05Smrg                     XtPointer closure)
486444c061aSmrg{
487444c061aSmrg    WIDGET_TO_APPCON(widget);
488444c061aSmrg    LOCK_APP(app);
4890568f49bSmrg    AddEventHandler(widget, (XtPointer) &eventMask, 0, FALSE, (Boolean) other,
490a3bd7f05Smrg                    proc, closure, XtListTail, FALSE, TRUE);
491444c061aSmrg    UNLOCK_APP(app);
492444c061aSmrg}
493444c061aSmrg
494a3bd7f05Smrgvoid
495a3bd7f05SmrgXtRemoveEventTypeHandler(Widget widget,
496a3bd7f05Smrg                         int type,
497a3bd7f05Smrg                         XtPointer select_data,
498a3bd7f05Smrg                         XtEventHandler proc,
499a3bd7f05Smrg                         XtPointer closure)
500444c061aSmrg{
501444c061aSmrg    WIDGET_TO_APPCON(widget);
502444c061aSmrg    LOCK_APP(app);
503444c061aSmrg    RemoveEventHandler(widget, select_data, type, TRUE,
504a3bd7f05Smrg                       FALSE, proc, closure, FALSE);
505444c061aSmrg    UNLOCK_APP(app);
506444c061aSmrg}
507444c061aSmrg
508a3bd7f05Smrgvoid
509a3bd7f05SmrgXtInsertEventTypeHandler(Widget widget,
510a3bd7f05Smrg                         int type,
511a3bd7f05Smrg                         XtPointer select_data,
512a3bd7f05Smrg                         XtEventHandler proc,
513a3bd7f05Smrg                         XtPointer closure,
514a3bd7f05Smrg                         XtListPosition position)
515444c061aSmrg{
516444c061aSmrg    WIDGET_TO_APPCON(widget);
517444c061aSmrg    LOCK_APP(app);
518444c061aSmrg    AddEventHandler(widget, select_data, type, TRUE, FALSE,
519a3bd7f05Smrg                    proc, closure, position, TRUE, FALSE);
520444c061aSmrg    UNLOCK_APP(app);
521444c061aSmrg}
522444c061aSmrg
523444c061aSmrgtypedef struct _WWPair {
524444c061aSmrg    struct _WWPair *next;
525444c061aSmrg    Window window;
526444c061aSmrg    Widget widget;
527444c061aSmrg} *WWPair;
528444c061aSmrg
529444c061aSmrgtypedef struct _WWTable {
530a3bd7f05Smrg    unsigned int mask;          /* size of hash table - 1 */
531a3bd7f05Smrg    unsigned int rehash;        /* mask - 2 */
532a3bd7f05Smrg    unsigned int occupied;      /* number of occupied entries */
533a3bd7f05Smrg    unsigned int fakes;         /* number occupied by WWfake */
534a3bd7f05Smrg    Widget *entries;            /* the entries */
535a3bd7f05Smrg    WWPair pairs;               /* bogus entries */
536444c061aSmrg} *WWTable;
537444c061aSmrg
538a3bd7f05Smrgstatic const WidgetRec WWfake;  /* placeholder for deletions */
539444c061aSmrg
540444c061aSmrg#define WWHASH(tab,win) ((win) & tab->mask)
541444c061aSmrg#define WWREHASHVAL(tab,win) ((((win) % tab->rehash) + 2) | 1)
5420568f49bSmrg#define WWREHASH(tab,idx,rehash) ((unsigned)(idx + rehash) & (tab->mask))
543444c061aSmrg#define WWTABLE(display) (_XtGetPerDisplay(display)->WWtable)
544444c061aSmrg
545444c061aSmrgstatic void ExpandWWTable(WWTable);
546444c061aSmrg
547a3bd7f05Smrgvoid
548a3bd7f05SmrgXtRegisterDrawable(Display *display, Drawable drawable, Widget widget)
549444c061aSmrg{
550444c061aSmrg    WWTable tab;
5510568f49bSmrg    int idx;
552444c061aSmrg    Widget entry;
553444c061aSmrg    Window window = (Window) drawable;
554a3bd7f05Smrg
555444c061aSmrg    WIDGET_TO_APPCON(widget);
556444c061aSmrg
557444c061aSmrg    LOCK_APP(app);
558444c061aSmrg    LOCK_PROCESS;
559444c061aSmrg    tab = WWTABLE(display);
560a3bd7f05Smrg
561444c061aSmrg    if (window != XtWindow(widget)) {
562a3bd7f05Smrg        WWPair pair;
563a3bd7f05Smrg        pair = XtNew(struct _WWPair);
564a3bd7f05Smrg
565a3bd7f05Smrg        pair->next = tab->pairs;
566a3bd7f05Smrg        pair->window = window;
567a3bd7f05Smrg        pair->widget = widget;
568a3bd7f05Smrg        tab->pairs = pair;
569a3bd7f05Smrg        UNLOCK_PROCESS;
570a3bd7f05Smrg        UNLOCK_APP(app);
571a3bd7f05Smrg        return;
572444c061aSmrg    }
573444c061aSmrg    if ((tab->occupied + (tab->occupied >> 2)) > tab->mask)
574a3bd7f05Smrg        ExpandWWTable(tab);
575444c061aSmrg
5760568f49bSmrg    idx = (int) WWHASH(tab, window);
577444c061aSmrg    if ((entry = tab->entries[idx]) && entry != &WWfake) {
578a3bd7f05Smrg        int rehash = (int) WWREHASHVAL(tab, window);
579a3bd7f05Smrg
580a3bd7f05Smrg        do {
581a3bd7f05Smrg            idx = (int) WWREHASH(tab, idx, rehash);
582a3bd7f05Smrg        } while ((entry = tab->entries[idx]) && entry != &WWfake);
583444c061aSmrg    }
584444c061aSmrg    if (!entry)
585a3bd7f05Smrg        tab->occupied++;
586444c061aSmrg    else if (entry == &WWfake)
587a3bd7f05Smrg        tab->fakes--;
588444c061aSmrg    tab->entries[idx] = widget;
589444c061aSmrg    UNLOCK_PROCESS;
590444c061aSmrg    UNLOCK_APP(app);
591444c061aSmrg}
592444c061aSmrg
593a3bd7f05Smrgvoid
594a3bd7f05SmrgXtUnregisterDrawable(Display *display, Drawable drawable)
595444c061aSmrg{
596444c061aSmrg    WWTable tab;
5970568f49bSmrg    int idx;
598444c061aSmrg    Widget entry;
599444c061aSmrg    Window window = (Window) drawable;
600a3bd7f05Smrg    Widget widget = XtWindowToWidget(display, window);
601444c061aSmrg    DPY_TO_APPCON(display);
602444c061aSmrg
603a3bd7f05Smrg    if (widget == NULL)
604a3bd7f05Smrg        return;
605444c061aSmrg
606444c061aSmrg    LOCK_APP(app);
607444c061aSmrg    LOCK_PROCESS;
608444c061aSmrg    tab = WWTABLE(display);
609444c061aSmrg    if (window != XtWindow(widget)) {
610a3bd7f05Smrg        WWPair *prev, pair;
611a3bd7f05Smrg
612a3bd7f05Smrg        prev = &tab->pairs;
613a3bd7f05Smrg        while ((pair = *prev) && pair->window != window)
614a3bd7f05Smrg            prev = &pair->next;
615a3bd7f05Smrg        if (pair) {
616a3bd7f05Smrg            *prev = pair->next;
617a3bd7f05Smrg            XtFree((char *) pair);
618a3bd7f05Smrg        }
619a3bd7f05Smrg        UNLOCK_PROCESS;
620a3bd7f05Smrg        UNLOCK_APP(app);
621a3bd7f05Smrg        return;
622444c061aSmrg    }
6230568f49bSmrg    idx = (int) WWHASH(tab, window);
624444c061aSmrg    if ((entry = tab->entries[idx])) {
625a3bd7f05Smrg        if (entry != widget) {
626a3bd7f05Smrg            int rehash = (int) WWREHASHVAL(tab, window);
627a3bd7f05Smrg
628a3bd7f05Smrg            do {
629a3bd7f05Smrg                idx = (int) WWREHASH(tab, idx, rehash);
630a3bd7f05Smrg                if (!(entry = tab->entries[idx])) {
631a3bd7f05Smrg                    UNLOCK_PROCESS;
632a3bd7f05Smrg                    UNLOCK_APP(app);
633a3bd7f05Smrg                    return;
634a3bd7f05Smrg                }
635a3bd7f05Smrg            } while (entry != widget);
636a3bd7f05Smrg        }
637a3bd7f05Smrg        tab->entries[idx] = (Widget) &WWfake;
638a3bd7f05Smrg        tab->fakes++;
639444c061aSmrg    }
640444c061aSmrg    UNLOCK_PROCESS;
641444c061aSmrg    UNLOCK_APP(app);
642444c061aSmrg}
643444c061aSmrg
644a3bd7f05Smrgstatic void
645a3bd7f05SmrgExpandWWTable(register WWTable tab)
646444c061aSmrg{
647444c061aSmrg    unsigned int oldmask;
648444c061aSmrg    register Widget *oldentries, *entries;
649444c061aSmrg    register Cardinal oldidx, newidx, rehash;
650444c061aSmrg    register Widget entry;
651444c061aSmrg
652444c061aSmrg    LOCK_PROCESS;
653444c061aSmrg    oldmask = tab->mask;
654444c061aSmrg    oldentries = tab->entries;
655444c061aSmrg    tab->occupied -= tab->fakes;
656444c061aSmrg    tab->fakes = 0;
657444c061aSmrg    if ((tab->occupied + (tab->occupied >> 2)) > tab->mask) {
658a3bd7f05Smrg        tab->mask = (tab->mask << 1) + 1;
659a3bd7f05Smrg        tab->rehash = tab->mask - 2;
660444c061aSmrg    }
661a3bd7f05Smrg    entries = tab->entries =
662a3bd7f05Smrg        (Widget *) __XtCalloc(tab->mask + 1, sizeof(Widget));
663444c061aSmrg    for (oldidx = 0; oldidx <= oldmask; oldidx++) {
664a3bd7f05Smrg        if ((entry = oldentries[oldidx]) && entry != &WWfake) {
665a3bd7f05Smrg            newidx = (Cardinal) WWHASH(tab, XtWindow(entry));
666a3bd7f05Smrg            if (entries[newidx]) {
667a3bd7f05Smrg                rehash = (Cardinal) WWREHASHVAL(tab, XtWindow(entry));
668a3bd7f05Smrg                do {
669a3bd7f05Smrg                    newidx = (Cardinal) WWREHASH(tab, newidx, rehash);
670a3bd7f05Smrg                } while (entries[newidx]);
671a3bd7f05Smrg            }
672a3bd7f05Smrg            entries[newidx] = entry;
673a3bd7f05Smrg        }
674444c061aSmrg    }
675a3bd7f05Smrg    XtFree((char *) oldentries);
676444c061aSmrg    UNLOCK_PROCESS;
677444c061aSmrg}
678444c061aSmrg
679a3bd7f05SmrgWidget
680a3bd7f05SmrgXtWindowToWidget(register Display *display, register Window window)
681444c061aSmrg{
6820568f49bSmrg    WWTable tab;
6830568f49bSmrg    int idx;
6840568f49bSmrg    Widget entry;
685444c061aSmrg    WWPair pair;
686444c061aSmrg    DPY_TO_APPCON(display);
687444c061aSmrg
688a3bd7f05Smrg    if (!window)
689a3bd7f05Smrg        return NULL;
690444c061aSmrg
691444c061aSmrg    LOCK_APP(app);
692444c061aSmrg    LOCK_PROCESS;
693444c061aSmrg    tab = WWTABLE(display);
6940568f49bSmrg    idx = (int) WWHASH(tab, window);
695444c061aSmrg    if ((entry = tab->entries[idx]) && XtWindow(entry) != window) {
696a3bd7f05Smrg        int rehash = (int) WWREHASHVAL(tab, window);
697a3bd7f05Smrg
698a3bd7f05Smrg        do {
699a3bd7f05Smrg            idx = (int) WWREHASH(tab, idx, rehash);
700a3bd7f05Smrg        } while ((entry = tab->entries[idx]) && XtWindow(entry) != window);
701444c061aSmrg    }
702444c061aSmrg    if (entry) {
703a3bd7f05Smrg        UNLOCK_PROCESS;
704a3bd7f05Smrg        UNLOCK_APP(app);
705a3bd7f05Smrg        return entry;
706444c061aSmrg    }
707444c061aSmrg    for (pair = tab->pairs; pair; pair = pair->next) {
708a3bd7f05Smrg        if (pair->window == window) {
709a3bd7f05Smrg            entry = pair->widget;
710a3bd7f05Smrg            UNLOCK_PROCESS;
711a3bd7f05Smrg            UNLOCK_APP(app);
712a3bd7f05Smrg            return entry;
713a3bd7f05Smrg        }
714444c061aSmrg    }
715444c061aSmrg    UNLOCK_PROCESS;
716444c061aSmrg    UNLOCK_APP(app);
717444c061aSmrg    return NULL;
718444c061aSmrg}
719444c061aSmrg
720a3bd7f05Smrgvoid
721a3bd7f05Smrg_XtAllocWWTable(XtPerDisplay pd)
722444c061aSmrg{
723444c061aSmrg    register WWTable tab;
724444c061aSmrg
725444c061aSmrg    tab = (WWTable) __XtMalloc(sizeof(struct _WWTable));
726444c061aSmrg    tab->mask = 0x7f;
727444c061aSmrg    tab->rehash = tab->mask - 2;
728a3bd7f05Smrg    tab->entries = (Widget *) __XtCalloc(tab->mask + 1, sizeof(Widget));
729444c061aSmrg    tab->occupied = 0;
730444c061aSmrg    tab->fakes = 0;
731444c061aSmrg    tab->pairs = NULL;
732444c061aSmrg    pd->WWtable = tab;
733444c061aSmrg}
734444c061aSmrg
735a3bd7f05Smrgvoid
736a3bd7f05Smrg_XtFreeWWTable(register XtPerDisplay pd)
737444c061aSmrg{
738444c061aSmrg    register WWPair pair, next;
739444c061aSmrg
740444c061aSmrg    for (pair = pd->WWtable->pairs; pair; pair = next) {
741a3bd7f05Smrg        next = pair->next;
742a3bd7f05Smrg        XtFree((char *) pair);
743444c061aSmrg    }
744a3bd7f05Smrg    XtFree((char *) pd->WWtable->entries);
745a3bd7f05Smrg    XtFree((char *) pd->WWtable);
746444c061aSmrg}
747444c061aSmrg
748a3bd7f05Smrg#define EHMAXSIZE 25            /* do not make whopping big */
749444c061aSmrg
750a3bd7f05Smrgstatic Boolean
751a3bd7f05SmrgCallEventHandlers(Widget widget, XEvent *event, EventMask mask)
752444c061aSmrg{
753444c061aSmrg    register XtEventRec *p;
754444c061aSmrg    XtEventHandler *proc;
755444c061aSmrg    XtPointer *closure;
756444c061aSmrg    Boolean cont_to_disp = True;
757444c061aSmrg    int i, numprocs;
758444c061aSmrg
759444c061aSmrg    /* Have to copy the procs into an array, because one of them might
760444c061aSmrg     * call XtRemoveEventHandler, which would break our linked list. */
761444c061aSmrg
762444c061aSmrg    numprocs = 0;
763a3bd7f05Smrg    for (p = widget->core.event_table; p; p = p->next) {
764a3bd7f05Smrg        if ((!p->has_type_specifier && (mask & p->mask)) ||
765a3bd7f05Smrg            (p->has_type_specifier && event->type == EXT_TYPE(p)))
766a3bd7f05Smrg            numprocs++;
767444c061aSmrg    }
768a3bd7f05Smrg    proc = (XtEventHandler *)
769a3bd7f05Smrg        __XtMalloc((Cardinal)
770a3bd7f05Smrg                   ((size_t) numprocs *
771a3bd7f05Smrg                    (sizeof(XtEventHandler) + sizeof(XtPointer))));
772a3bd7f05Smrg    closure = (XtPointer *) (proc + numprocs);
7730568f49bSmrg
774444c061aSmrg    numprocs = 0;
775a3bd7f05Smrg    for (p = widget->core.event_table; p; p = p->next) {
776a3bd7f05Smrg        if ((!p->has_type_specifier && (mask & p->mask)) ||
777a3bd7f05Smrg            (p->has_type_specifier && event->type == EXT_TYPE(p))) {
778a3bd7f05Smrg            proc[numprocs] = p->proc;
779a3bd7f05Smrg            closure[numprocs] = p->closure;
780a3bd7f05Smrg            numprocs++;
781a3bd7f05Smrg        }
782444c061aSmrg    }
783a3bd7f05Smrg    /* FUNCTIONS CALLED THROUGH POINTER proc:
784a3bd7f05Smrg       Selection.c:ReqCleanup,
785a3bd7f05Smrg       "Shell.c":EventHandler,
786a3bd7f05Smrg       PassivGrab.c:ActiveHandler,
787a3bd7f05Smrg       PassivGrab.c:RealizeHandler,
788a3bd7f05Smrg       Keyboard.c:QueryEventMask,
789a3bd7f05Smrg       _XtHandleFocus,
790a3bd7f05Smrg       Selection.c:HandleSelectionReplies,
791a3bd7f05Smrg       Selection.c:HandleGetIncrement,
792a3bd7f05Smrg       Selection.c:HandleIncremental,
793a3bd7f05Smrg       Selection.c:HandlePropertyGone,
794a3bd7f05Smrg       Selection.c:HandleSelectionEvents
795a3bd7f05Smrg     */
796444c061aSmrg    for (i = 0; i < numprocs && cont_to_disp; i++)
797a3bd7f05Smrg        (*(proc[i])) (widget, closure[i], event, &cont_to_disp);
798a3bd7f05Smrg    XtFree((char *) proc);
799444c061aSmrg    return cont_to_disp;
800444c061aSmrg}
801444c061aSmrg
802444c061aSmrgstatic void CompressExposures(XEvent *, Widget);
803444c061aSmrg
804444c061aSmrg#define KnownButtons (Button1MotionMask|Button2MotionMask|Button3MotionMask|\
805a3bd7f05Smrg                      Button4MotionMask|Button5MotionMask)
806444c061aSmrg
807444c061aSmrg/* keep this SMALL to avoid blowing stack cache! */
808444c061aSmrg/* because some compilers allocate all local locals on procedure entry */
809444c061aSmrg#define EHSIZE 4
810444c061aSmrg
811a3bd7f05SmrgBoolean
812a3bd7f05SmrgXtDispatchEventToWidget(Widget widget, XEvent *event)
813444c061aSmrg{
814444c061aSmrg    register XtEventRec *p;
815444c061aSmrg    Boolean was_dispatched = False;
816444c061aSmrg    Boolean call_tm = False;
817444c061aSmrg    Boolean cont_to_disp;
818444c061aSmrg    EventMask mask;
819a3bd7f05Smrg
820444c061aSmrg    WIDGET_TO_APPCON(widget);
821444c061aSmrg
822444c061aSmrg    LOCK_APP(app);
823444c061aSmrg
824444c061aSmrg    mask = _XtConvertTypeToMask(event->type);
825444c061aSmrg    if (event->type == MotionNotify)
826a3bd7f05Smrg        mask |= (event->xmotion.state & KnownButtons);
827444c061aSmrg
828444c061aSmrg    LOCK_PROCESS;
829a3bd7f05Smrg    if ((mask == ExposureMask) ||
830a3bd7f05Smrg        ((event->type == NoExpose) && NO_EXPOSE) ||
831a3bd7f05Smrg        ((event->type == GraphicsExpose) && GRAPHICS_EXPOSE)) {
832444c061aSmrg
833a3bd7f05Smrg        if (widget->core.widget_class->core_class.expose != NULL) {
834444c061aSmrg
835a3bd7f05Smrg            /* We need to mask off the bits that could contain the information
836a3bd7f05Smrg             * about whether or not we desire Graphics and NoExpose events.  */
837444c061aSmrg
838a3bd7f05Smrg            if ((COMP_EXPOSE_TYPE == XtExposeNoCompress) ||
839a3bd7f05Smrg                (event->type == NoExpose))
840444c061aSmrg
841a3bd7f05Smrg                (*widget->core.widget_class->core_class.expose)
842a3bd7f05Smrg                    (widget, event, (Region) NULL);
843a3bd7f05Smrg            else {
844a3bd7f05Smrg                CompressExposures(event, widget);
845a3bd7f05Smrg            }
846a3bd7f05Smrg            was_dispatched = True;
847a3bd7f05Smrg        }
848444c061aSmrg    }
849444c061aSmrg
850444c061aSmrg    if ((mask == VisibilityChangeMask) &&
851444c061aSmrg        XtClass(widget)->core_class.visible_interest) {
852a3bd7f05Smrg        was_dispatched = True;
853a3bd7f05Smrg        /* our visibility just changed... */
854a3bd7f05Smrg        switch (((XVisibilityEvent *) event)->state) {
855a3bd7f05Smrg        case VisibilityUnobscured:
856a3bd7f05Smrg            widget->core.visible = TRUE;
857a3bd7f05Smrg            break;
858a3bd7f05Smrg
859a3bd7f05Smrg        case VisibilityPartiallyObscured:
860a3bd7f05Smrg            /* what do we want to say here? */
861a3bd7f05Smrg            /* well... some of us is visible */
862a3bd7f05Smrg            widget->core.visible = TRUE;
863a3bd7f05Smrg            break;
864a3bd7f05Smrg
865a3bd7f05Smrg        case VisibilityFullyObscured:
866a3bd7f05Smrg            widget->core.visible = FALSE;
867a3bd7f05Smrg            /* do we want to mark our children obscured? */
868a3bd7f05Smrg            break;
869a3bd7f05Smrg        }
870a3bd7f05Smrg    }
871444c061aSmrg    UNLOCK_PROCESS;
872444c061aSmrg
873444c061aSmrg    /* to maintain "copy" semantics we check TM now but call later */
874444c061aSmrg    if (widget->core.tm.translations &&
875a3bd7f05Smrg        (mask & widget->core.tm.translations->eventMask))
876a3bd7f05Smrg        call_tm = True;
877444c061aSmrg
878444c061aSmrg    cont_to_disp = True;
879a3bd7f05Smrg    p = widget->core.event_table;
880444c061aSmrg    if (p) {
881a3bd7f05Smrg        if (p->next) {
882a3bd7f05Smrg            XtEventHandler proc[EHSIZE];
883a3bd7f05Smrg            XtPointer closure[EHSIZE];
884a3bd7f05Smrg            int numprocs = 0;
885a3bd7f05Smrg
886a3bd7f05Smrg            /* Have to copy the procs into an array, because one of them might
887a3bd7f05Smrg             * call XtRemoveEventHandler, which would break our linked list. */
888a3bd7f05Smrg
889a3bd7f05Smrg            for (; p; p = p->next) {
890a3bd7f05Smrg                if ((!p->has_type_specifier && (mask & p->mask)) ||
891a3bd7f05Smrg                    (p->has_type_specifier && event->type == EXT_TYPE(p))) {
892a3bd7f05Smrg                    if (numprocs >= EHSIZE)
893a3bd7f05Smrg                        break;
894a3bd7f05Smrg                    proc[numprocs] = p->proc;
895a3bd7f05Smrg                    closure[numprocs] = p->closure;
896a3bd7f05Smrg                    numprocs++;
897a3bd7f05Smrg                }
898a3bd7f05Smrg            }
899a3bd7f05Smrg            if (numprocs) {
900a3bd7f05Smrg                if (p) {
901a3bd7f05Smrg                    cont_to_disp = CallEventHandlers(widget, event, mask);
902a3bd7f05Smrg                }
903a3bd7f05Smrg                else {
904a3bd7f05Smrg                    int i;
905a3bd7f05Smrg
906a3bd7f05Smrg                    for (i = 0; i < numprocs && cont_to_disp; i++)
907a3bd7f05Smrg                        (*(proc[i])) (widget, closure[i], event, &cont_to_disp);
908a3bd7f05Smrg                    /* FUNCTIONS CALLED THROUGH POINTER proc:
909a3bd7f05Smrg                       Selection.c:ReqCleanup,
910a3bd7f05Smrg                       "Shell.c":EventHandler,
911a3bd7f05Smrg                       PassivGrab.c:ActiveHandler,
912a3bd7f05Smrg                       PassivGrab.c:RealizeHandler,
913a3bd7f05Smrg                       Keyboard.c:QueryEventMask,
914a3bd7f05Smrg                       _XtHandleFocus,
915a3bd7f05Smrg                       Selection.c:HandleSelectionReplies,
916a3bd7f05Smrg                       Selection.c:HandleGetIncrement,
917a3bd7f05Smrg                       Selection.c:HandleIncremental,
918a3bd7f05Smrg                       Selection.c:HandlePropertyGone,
919a3bd7f05Smrg                       Selection.c:HandleSelectionEvents
920a3bd7f05Smrg                     */
921a3bd7f05Smrg                }
922a3bd7f05Smrg                was_dispatched = True;
923a3bd7f05Smrg            }
924a3bd7f05Smrg        }
925a3bd7f05Smrg        else if ((!p->has_type_specifier && (mask & p->mask)) ||
926a3bd7f05Smrg                 (p->has_type_specifier && event->type == EXT_TYPE(p))) {
927a3bd7f05Smrg            (*p->proc) (widget, p->closure, event, &cont_to_disp);
928a3bd7f05Smrg            was_dispatched = True;
929a3bd7f05Smrg        }
930444c061aSmrg    }
931444c061aSmrg    if (call_tm && cont_to_disp)
932a3bd7f05Smrg        _XtTranslateEvent(widget, event);
933444c061aSmrg    UNLOCK_APP(app);
934a3bd7f05Smrg    return (was_dispatched | call_tm);
935444c061aSmrg}
936444c061aSmrg
937444c061aSmrg/*
938444c061aSmrg * This structure is passed into the check exposure proc.
939444c061aSmrg */
940444c061aSmrg
941444c061aSmrgtypedef struct _CheckExposeInfo {
942a3bd7f05Smrg    int type1, type2;           /* Types of events to check for. */
943a3bd7f05Smrg    Boolean maximal;            /* Ignore non-exposure events? */
944a3bd7f05Smrg    Boolean non_matching;       /* Was there an event that did not
945a3bd7f05Smrg                                   match either type? */
946a3bd7f05Smrg    Window window;              /* Window to match. */
947444c061aSmrg} CheckExposeInfo;
948444c061aSmrg
949444c061aSmrg#define GetCount(ev) (((XExposeEvent *)(ev))->count)
950444c061aSmrg
951444c061aSmrgstatic void SendExposureEvent(XEvent *, Widget, XtPerDisplay);
952444c061aSmrgstatic Bool CheckExposureEvent(Display *, XEvent *, char *);
953444c061aSmrgstatic void AddExposureToRectangularRegion(XEvent *, Region);
954444c061aSmrg
955a3bd7f05Smrg/*      Function Name: CompressExposures
956a3bd7f05Smrg *      Description: Handles all exposure compression
957a3bd7f05Smrg *      Arguments: event - the xevent that is to be dispatched
958444c061aSmrg *                 widget - the widget that this event occured in.
959a3bd7f05Smrg *      Returns: none.
960444c061aSmrg *
961444c061aSmrg *      NOTE: Event must be of type Expose or GraphicsExpose.
962444c061aSmrg */
963444c061aSmrg
964444c061aSmrgstatic void
965a3bd7f05SmrgCompressExposures(XEvent *event, Widget widget)
966444c061aSmrg{
967444c061aSmrg    CheckExposeInfo info;
968444c061aSmrg    int count;
969a3bd7f05Smrg    Display *dpy = XtDisplay(widget);
970444c061aSmrg    XtPerDisplay pd = _XtGetPerDisplay(dpy);
971444c061aSmrg    XtEnum comp_expose;
972444c061aSmrg    XtEnum comp_expose_type;
973444c061aSmrg    Boolean no_region;
974444c061aSmrg
975444c061aSmrg    LOCK_PROCESS;
976444c061aSmrg    comp_expose = COMP_EXPOSE;
977444c061aSmrg    UNLOCK_PROCESS;
978444c061aSmrg    comp_expose_type = comp_expose & 0x0f;
979444c061aSmrg    no_region = ((comp_expose & XtExposeNoRegion) ? True : False);
980444c061aSmrg
981444c061aSmrg    if (no_region)
982a3bd7f05Smrg        AddExposureToRectangularRegion(event, pd->region);
983444c061aSmrg    else
984a3bd7f05Smrg        XtAddExposureToRegion(event, pd->region);
985444c061aSmrg
986a3bd7f05Smrg    if (GetCount(event) != 0)
987a3bd7f05Smrg        return;
988444c061aSmrg
989444c061aSmrg    if ((comp_expose_type == XtExposeCompressSeries) ||
990a3bd7f05Smrg        (XEventsQueued(dpy, QueuedAfterReading) == 0)) {
991a3bd7f05Smrg        SendExposureEvent(event, widget, pd);
992a3bd7f05Smrg        return;
993444c061aSmrg    }
994444c061aSmrg
995444c061aSmrg    if (comp_expose & XtExposeGraphicsExposeMerged) {
996a3bd7f05Smrg        info.type1 = Expose;
997a3bd7f05Smrg        info.type2 = GraphicsExpose;
998444c061aSmrg    }
999444c061aSmrg    else {
1000a3bd7f05Smrg        info.type1 = event->type;
1001a3bd7f05Smrg        info.type2 = 0;
1002444c061aSmrg    }
1003444c061aSmrg    info.maximal = (comp_expose_type == XtExposeCompressMaximal);
1004444c061aSmrg    info.non_matching = FALSE;
1005444c061aSmrg    info.window = XtWindow(widget);
1006444c061aSmrg
1007a3bd7f05Smrg    /*
1008a3bd7f05Smrg     * We have to be very careful here not to hose down the processor
1009a3bd7f05Smrg     * when blocking until count gets to zero.
1010a3bd7f05Smrg     *
1011a3bd7f05Smrg     * First, check to see if there are any events in the queue for this
1012a3bd7f05Smrg     * widget, and of the correct type.
1013a3bd7f05Smrg     *
1014a3bd7f05Smrg     * Once we cannot find any more events, check to see that count is zero.
1015a3bd7f05Smrg     * If it is not then block until we get another exposure event.
1016a3bd7f05Smrg     *
1017a3bd7f05Smrg     * If we find no more events, and count on the last one we saw was zero we
1018a3bd7f05Smrg     * we can be sure that all events have been processed.
1019a3bd7f05Smrg     *
1020a3bd7f05Smrg     * Unfortunately, we wind up having to look at the entire queue
1021a3bd7f05Smrg     * event if we're not doing Maximal compression, due to the
1022a3bd7f05Smrg     * semantics of XCheckIfEvent (we can't abort without re-ordering
1023a3bd7f05Smrg     * the event queue as a side-effect).
1024a3bd7f05Smrg     */
1025444c061aSmrg
1026444c061aSmrg    count = 0;
1027444c061aSmrg    while (TRUE) {
1028a3bd7f05Smrg        XEvent event_return;
1029a3bd7f05Smrg
1030a3bd7f05Smrg        if (XCheckIfEvent(dpy, &event_return,
1031a3bd7f05Smrg                          CheckExposureEvent, (char *) &info)) {
1032a3bd7f05Smrg
1033a3bd7f05Smrg            count = GetCount(&event_return);
1034a3bd7f05Smrg            if (no_region)
1035a3bd7f05Smrg                AddExposureToRectangularRegion(&event_return, pd->region);
1036a3bd7f05Smrg            else
1037a3bd7f05Smrg                XtAddExposureToRegion(&event_return, pd->region);
1038a3bd7f05Smrg        }
1039a3bd7f05Smrg        else if (count != 0) {
1040a3bd7f05Smrg            XIfEvent(dpy, &event_return, CheckExposureEvent, (char *) &info);
1041a3bd7f05Smrg            count = GetCount(&event_return);
1042a3bd7f05Smrg            if (no_region)
1043a3bd7f05Smrg                AddExposureToRectangularRegion(&event_return, pd->region);
1044a3bd7f05Smrg            else
1045a3bd7f05Smrg                XtAddExposureToRegion(&event_return, pd->region);
1046a3bd7f05Smrg        }
1047a3bd7f05Smrg        else                    /* count == 0 && XCheckIfEvent Failed. */
1048a3bd7f05Smrg            break;
1049444c061aSmrg    }
1050444c061aSmrg
1051444c061aSmrg    SendExposureEvent(event, widget, pd);
1052444c061aSmrg}
1053444c061aSmrg
1054a3bd7f05Smrgvoid
1055a3bd7f05SmrgXtAddExposureToRegion(XEvent *event, Region region)
1056444c061aSmrg{
1057444c061aSmrg    XRectangle rect;
1058444c061aSmrg    XExposeEvent *ev = (XExposeEvent *) event;
1059a3bd7f05Smrg
1060444c061aSmrg    /* These Expose and GraphicsExpose fields are at identical offsets */
1061444c061aSmrg
1062444c061aSmrg    if (event->type == Expose || event->type == GraphicsExpose) {
1063a3bd7f05Smrg        rect.x = (Position) ev->x;
1064a3bd7f05Smrg        rect.y = (Position) ev->y;
1065a3bd7f05Smrg        rect.width = (Dimension) ev->width;
1066a3bd7f05Smrg        rect.height = (Dimension) ev->height;
1067a3bd7f05Smrg        XUnionRectWithRegion(&rect, region, region);
1068444c061aSmrg    }
1069444c061aSmrg}
1070444c061aSmrg
1071444c061aSmrg#ifndef MAX
1072444c061aSmrg#define MAX(a,b) (((a) > (b)) ? (a) : (b))
1073444c061aSmrg#endif
1074444c061aSmrg
1075444c061aSmrg#ifndef MIN
1076444c061aSmrg#define MIN(a,b) (((a) < (b)) ? (a) : (b))
1077444c061aSmrg#endif
1078444c061aSmrg
1079a3bd7f05Smrgstatic void
1080a3bd7f05SmrgAddExposureToRectangularRegion(XEvent *event,   /* when called internally, type is always appropriate */
1081a3bd7f05Smrg                               Region region)
1082444c061aSmrg{
1083444c061aSmrg    XRectangle rect;
1084444c061aSmrg    XExposeEvent *ev = (XExposeEvent *) event;
1085a3bd7f05Smrg
1086444c061aSmrg    /* These Expose and GraphicsExpose fields are at identical offsets */
1087444c061aSmrg
10880568f49bSmrg    rect.x = (Position) ev->x;
10890568f49bSmrg    rect.y = (Position) ev->y;
10900568f49bSmrg    rect.width = (Dimension) ev->width;
10910568f49bSmrg    rect.height = (Dimension) ev->height;
1092444c061aSmrg
1093444c061aSmrg    if (XEmptyRegion(region)) {
1094a3bd7f05Smrg        XUnionRectWithRegion(&rect, region, region);
1095a3bd7f05Smrg    }
1096a3bd7f05Smrg    else {
1097a3bd7f05Smrg        XRectangle merged, bbox;
1098a3bd7f05Smrg
1099a3bd7f05Smrg        XClipBox(region, &bbox);
1100a3bd7f05Smrg        merged.x = MIN(rect.x, bbox.x);
1101a3bd7f05Smrg        merged.y = MIN(rect.y, bbox.y);
1102a3bd7f05Smrg        merged.width = (unsigned short) (MAX(rect.x + rect.width,
1103a3bd7f05Smrg                                             bbox.x + bbox.width) - merged.x);
1104a3bd7f05Smrg        merged.height = (unsigned short) (MAX(rect.y + rect.height,
1105a3bd7f05Smrg                                              bbox.y + bbox.height) - merged.y);
1106a3bd7f05Smrg        XUnionRectWithRegion(&merged, region, region);
1107444c061aSmrg    }
1108444c061aSmrg}
1109444c061aSmrg
1110444c061aSmrgstatic Region nullRegion;
1111a3bd7f05Smrg
1112444c061aSmrg/* READ-ONLY VARIABLES: nullRegion */
1113444c061aSmrg
1114a3bd7f05Smrgvoid
1115a3bd7f05Smrg_XtEventInitialize(void)
1116444c061aSmrg{
1117444c061aSmrg#ifndef __lock_lint
1118444c061aSmrg    nullRegion = XCreateRegion();
1119444c061aSmrg#endif
1120444c061aSmrg}
1121444c061aSmrg
1122a3bd7f05Smrg/*      Function Name: SendExposureEvent
1123a3bd7f05Smrg *      Description: Sets the x, y, width, and height of the event
1124444c061aSmrg *                   to be the clip box of Expose Region.
1125a3bd7f05Smrg *      Arguments: event  - the X Event to mangle; Expose or GraphicsExpose.
1126444c061aSmrg *                 widget - the widget that this event occured in.
1127444c061aSmrg *                 pd     - the per display information for this widget.
1128a3bd7f05Smrg *      Returns: none.
1129444c061aSmrg */
1130444c061aSmrg
1131444c061aSmrgstatic void
1132a3bd7f05SmrgSendExposureEvent(XEvent *event, Widget widget, XtPerDisplay pd)
1133444c061aSmrg{
1134444c061aSmrg    XtExposeProc expose;
1135444c061aSmrg    XRectangle rect;
1136444c061aSmrg    XtEnum comp_expose;
1137444c061aSmrg    XExposeEvent *ev = (XExposeEvent *) event;
1138444c061aSmrg
1139444c061aSmrg    XClipBox(pd->region, &rect);
1140444c061aSmrg    ev->x = rect.x;
1141444c061aSmrg    ev->y = rect.y;
1142444c061aSmrg    ev->width = rect.width;
1143444c061aSmrg    ev->height = rect.height;
1144444c061aSmrg
1145444c061aSmrg    LOCK_PROCESS;
1146444c061aSmrg    comp_expose = COMP_EXPOSE;
1147444c061aSmrg    expose = widget->core.widget_class->core_class.expose;
1148444c061aSmrg    UNLOCK_PROCESS;
1149444c061aSmrg    if (comp_expose & XtExposeNoRegion)
1150a3bd7f05Smrg        (*expose) (widget, event, NULL);
1151444c061aSmrg    else
1152a3bd7f05Smrg        (*expose) (widget, event, pd->region);
1153444c061aSmrg    (void) XIntersectRegion(nullRegion, pd->region, pd->region);
1154444c061aSmrg}
1155444c061aSmrg
1156a3bd7f05Smrg/*      Function Name: CheckExposureEvent
1157a3bd7f05Smrg *      Description: Checks the event queue for an expose event
1158a3bd7f05Smrg *      Arguments: display - the display connection.
1159444c061aSmrg *                 event - the event to check.
1160444c061aSmrg *                 arg - a pointer to the exposure info structure.
1161a3bd7f05Smrg *      Returns: TRUE if we found an event of the correct type
1162444c061aSmrg *               with the right window.
1163444c061aSmrg *
1164444c061aSmrg * NOTE: The only valid types (info.type1 and info.type2) are Expose
1165444c061aSmrg *       and GraphicsExpose.
1166444c061aSmrg */
1167444c061aSmrg
1168444c061aSmrgstatic Bool
1169a3bd7f05SmrgCheckExposureEvent(Display *disp _X_UNUSED, XEvent *event, char *arg)
1170444c061aSmrg{
1171a3bd7f05Smrg    CheckExposeInfo *info = ((CheckExposeInfo *) arg);
1172a3bd7f05Smrg
1173a3bd7f05Smrg    if ((info->type1 == event->type) || (info->type2 == event->type)) {
1174a3bd7f05Smrg        if (!info->maximal && info->non_matching)
1175a3bd7f05Smrg            return FALSE;
1176a3bd7f05Smrg        if (event->type == GraphicsExpose)
1177a3bd7f05Smrg            return (event->xgraphicsexpose.drawable == info->window);
1178a3bd7f05Smrg        return (event->xexpose.window == info->window);
1179444c061aSmrg    }
1180444c061aSmrg    info->non_matching = TRUE;
1181a3bd7f05Smrg    return (FALSE);
1182444c061aSmrg}
1183444c061aSmrg
1184444c061aSmrgstatic EventMask const masks[] = {
1185a3bd7f05Smrg    0,                          /* Error, should never see  */
1186a3bd7f05Smrg    0,                          /* Reply, should never see  */
1187a3bd7f05Smrg    KeyPressMask,               /* KeyPress                 */
1188a3bd7f05Smrg    KeyReleaseMask,             /* KeyRelease               */
1189a3bd7f05Smrg    ButtonPressMask,            /* ButtonPress              */
1190a3bd7f05Smrg    ButtonReleaseMask,          /* ButtonRelease            */
1191a3bd7f05Smrg    PointerMotionMask           /* MotionNotify             */
1192a3bd7f05Smrg        | ButtonMotionMask,
1193a3bd7f05Smrg    EnterWindowMask,            /* EnterNotify              */
1194a3bd7f05Smrg    LeaveWindowMask,            /* LeaveNotify              */
1195a3bd7f05Smrg    FocusChangeMask,            /* FocusIn                  */
1196a3bd7f05Smrg    FocusChangeMask,            /* FocusOut                 */
1197a3bd7f05Smrg    KeymapStateMask,            /* KeymapNotify             */
1198a3bd7f05Smrg    ExposureMask,               /* Expose                   */
1199a3bd7f05Smrg    NonMaskableMask,            /* GraphicsExpose, in GC    */
1200a3bd7f05Smrg    NonMaskableMask,            /* NoExpose, in GC          */
1201a3bd7f05Smrg    VisibilityChangeMask,       /* VisibilityNotify         */
1202a3bd7f05Smrg    SubstructureNotifyMask,     /* CreateNotify             */
1203a3bd7f05Smrg    StructureNotifyMask         /* DestroyNotify            */
1204a3bd7f05Smrg        | SubstructureNotifyMask,
1205a3bd7f05Smrg    StructureNotifyMask         /* UnmapNotify              */
1206a3bd7f05Smrg        | SubstructureNotifyMask,
1207a3bd7f05Smrg    StructureNotifyMask         /* MapNotify                */
1208a3bd7f05Smrg        | SubstructureNotifyMask,
1209a3bd7f05Smrg    SubstructureRedirectMask,   /* MapRequest               */
1210a3bd7f05Smrg    StructureNotifyMask         /* ReparentNotify           */
1211a3bd7f05Smrg        | SubstructureNotifyMask,
1212a3bd7f05Smrg    StructureNotifyMask         /* ConfigureNotify          */
1213a3bd7f05Smrg        | SubstructureNotifyMask,
1214a3bd7f05Smrg    SubstructureRedirectMask,   /* ConfigureRequest         */
1215a3bd7f05Smrg    StructureNotifyMask         /* GravityNotify            */
1216a3bd7f05Smrg        | SubstructureNotifyMask,
1217a3bd7f05Smrg    ResizeRedirectMask,         /* ResizeRequest            */
1218a3bd7f05Smrg    StructureNotifyMask         /* CirculateNotify          */
1219a3bd7f05Smrg        | SubstructureNotifyMask,
1220a3bd7f05Smrg    SubstructureRedirectMask,   /* CirculateRequest         */
1221a3bd7f05Smrg    PropertyChangeMask,         /* PropertyNotify           */
1222a3bd7f05Smrg    NonMaskableMask,            /* SelectionClear           */
1223a3bd7f05Smrg    NonMaskableMask,            /* SelectionRequest         */
1224a3bd7f05Smrg    NonMaskableMask,            /* SelectionNotify          */
1225a3bd7f05Smrg    ColormapChangeMask,         /* ColormapNotify           */
1226a3bd7f05Smrg    NonMaskableMask,            /* ClientMessage            */
1227a3bd7f05Smrg    NonMaskableMask             /* MappingNotify            */
1228444c061aSmrg};
1229444c061aSmrg
1230a3bd7f05SmrgEventMask
1231a3bd7f05Smrg_XtConvertTypeToMask(int eventType)
1232444c061aSmrg{
1233444c061aSmrg    if ((Cardinal) eventType < XtNumber(masks))
1234a3bd7f05Smrg        return masks[eventType];
1235444c061aSmrg    else
1236a3bd7f05Smrg        return NoEventMask;
1237444c061aSmrg}
1238444c061aSmrg
1239a3bd7f05SmrgBoolean
1240a3bd7f05Smrg_XtOnGrabList(register Widget widget, XtGrabRec *grabList)
1241444c061aSmrg{
1242a3bd7f05Smrg    register XtGrabRec *gl;
1243a3bd7f05Smrg
1244a3bd7f05Smrg    for (; widget != NULL; widget = (Widget) widget->core.parent) {
1245a3bd7f05Smrg        for (gl = grabList; gl != NULL; gl = gl->next) {
1246a3bd7f05Smrg            if (gl->widget == widget)
1247a3bd7f05Smrg                return TRUE;
1248a3bd7f05Smrg            if (gl->exclusive)
1249a3bd7f05Smrg                break;
1250a3bd7f05Smrg        }
1251444c061aSmrg    }
1252444c061aSmrg    return FALSE;
1253444c061aSmrg}
1254444c061aSmrg
1255a3bd7f05Smrgstatic Widget
1256a3bd7f05SmrgLookupSpringLoaded(XtGrabList grabList)
1257444c061aSmrg{
1258a3bd7f05Smrg    XtGrabList gl;
1259444c061aSmrg
1260444c061aSmrg    for (gl = grabList; gl != NULL; gl = gl->next) {
1261a3bd7f05Smrg        if (gl->spring_loaded) {
1262a3bd7f05Smrg            if (XtIsSensitive(gl->widget))
1263a3bd7f05Smrg                return gl->widget;
1264a3bd7f05Smrg            else
1265a3bd7f05Smrg                return NULL;
1266a3bd7f05Smrg        }
1267a3bd7f05Smrg        if (gl->exclusive)
1268a3bd7f05Smrg            break;
1269444c061aSmrg    }
1270444c061aSmrg    return NULL;
1271444c061aSmrg}
1272444c061aSmrg
1273a3bd7f05Smrgstatic Boolean
1274a3bd7f05SmrgDispatchEvent(XEvent *event, Widget widget)
1275444c061aSmrg{
1276444c061aSmrg
1277444c061aSmrg    if (event->type == EnterNotify &&
1278a3bd7f05Smrg        event->xcrossing.mode == NotifyNormal &&
1279a3bd7f05Smrg        widget->core.widget_class->core_class.compress_enterleave) {
1280a3bd7f05Smrg        if (XPending(event->xcrossing.display)) {
1281a3bd7f05Smrg            XEvent nextEvent;
1282a3bd7f05Smrg            XPeekEvent(event->xcrossing.display, &nextEvent);
1283a3bd7f05Smrg
1284a3bd7f05Smrg            if (nextEvent.type == LeaveNotify &&
1285a3bd7f05Smrg                event->xcrossing.window == nextEvent.xcrossing.window &&
1286a3bd7f05Smrg                nextEvent.xcrossing.mode == NotifyNormal &&
1287a3bd7f05Smrg                ((event->xcrossing.detail != NotifyInferior &&
1288a3bd7f05Smrg                  nextEvent.xcrossing.detail != NotifyInferior) ||
1289a3bd7f05Smrg                 (event->xcrossing.detail == NotifyInferior &&
1290a3bd7f05Smrg                  nextEvent.xcrossing.detail == NotifyInferior))) {
1291a3bd7f05Smrg                /* skip the enter/leave pair */
1292a3bd7f05Smrg                XNextEvent(event->xcrossing.display, &nextEvent);
1293a3bd7f05Smrg
1294a3bd7f05Smrg                return False;
1295a3bd7f05Smrg            }
1296a3bd7f05Smrg        }
1297444c061aSmrg    }
1298444c061aSmrg
1299444c061aSmrg    if (event->type == MotionNotify &&
1300a3bd7f05Smrg        widget->core.widget_class->core_class.compress_motion) {
1301a3bd7f05Smrg        while (XPending(event->xmotion.display)) {
1302a3bd7f05Smrg            XEvent nextEvent;
1303a3bd7f05Smrg            XPeekEvent(event->xmotion.display, &nextEvent);
1304a3bd7f05Smrg
1305a3bd7f05Smrg            if (nextEvent.type == MotionNotify &&
1306a3bd7f05Smrg                event->xmotion.window == nextEvent.xmotion.window &&
1307a3bd7f05Smrg                event->xmotion.subwindow == nextEvent.xmotion.subwindow) {
1308a3bd7f05Smrg                /* replace the current event with the next one */
1309a3bd7f05Smrg                XNextEvent(event->xmotion.display, event);
1310a3bd7f05Smrg            }
1311a3bd7f05Smrg            else
1312a3bd7f05Smrg                break;
1313a3bd7f05Smrg        }
1314444c061aSmrg    }
1315444c061aSmrg
1316444c061aSmrg    return XtDispatchEventToWidget(widget, event);
1317444c061aSmrg}
1318444c061aSmrg
1319a3bd7f05Smrgtypedef enum _GrabType { pass, ignore, remap } GrabType;
1320444c061aSmrg
1321444c061aSmrg#if !defined(AIXV3) || !defined(AIXSHLIB)
1322a3bd7f05Smrgstatic                          /* AIX shared libraries are broken */
1323444c061aSmrg#endif
1324a3bd7f05SmrgBoolean
1325a3bd7f05Smrg_XtDefaultDispatcher(XEvent *event)
1326444c061aSmrg{
1327a3bd7f05Smrg    register Widget widget;
1328a3bd7f05Smrg    GrabType grabType;
1329444c061aSmrg    XtPerDisplayInput pdi;
1330a3bd7f05Smrg    XtGrabList grabList;
1331a3bd7f05Smrg    Boolean was_dispatched = False;
1332444c061aSmrg    DPY_TO_APPCON(event->xany.display);
1333444c061aSmrg
1334444c061aSmrg    /* the default dispatcher discards all extension events */
1335444c061aSmrg    if (event->type >= LASTEvent)
1336a3bd7f05Smrg        return False;
1337444c061aSmrg
1338444c061aSmrg    LOCK_APP(app);
1339444c061aSmrg
1340444c061aSmrg    switch (event->type) {
1341a3bd7f05Smrg    case KeyPress:
1342a3bd7f05Smrg    case KeyRelease:
1343a3bd7f05Smrg    case ButtonPress:
1344a3bd7f05Smrg    case ButtonRelease:
1345a3bd7f05Smrg        grabType = remap;
1346a3bd7f05Smrg        break;
1347a3bd7f05Smrg    case MotionNotify:
1348a3bd7f05Smrg    case EnterNotify:
1349a3bd7f05Smrg        grabType = ignore;
1350a3bd7f05Smrg        break;
1351a3bd7f05Smrg    default:
1352a3bd7f05Smrg        grabType = pass;
1353a3bd7f05Smrg        break;
1354444c061aSmrg    }
1355444c061aSmrg
1356a3bd7f05Smrg    widget = XtWindowToWidget(event->xany.display, event->xany.window);
1357444c061aSmrg    pdi = _XtGetPerDisplayInput(event->xany.display);
1358a3bd7f05Smrg
1359444c061aSmrg    grabList = *_XtGetGrabList(pdi);
1360444c061aSmrg
1361444c061aSmrg    if (widget == NULL) {
1362a3bd7f05Smrg        if (grabType == remap
1363a3bd7f05Smrg            && (widget = LookupSpringLoaded(grabList)) != NULL) {
1364a3bd7f05Smrg            /* event occurred in a non-widget window, but we've promised also
1365a3bd7f05Smrg               to dispatch it to the nearest accessible spring_loaded widget */
1366a3bd7f05Smrg            was_dispatched = (XFilterEvent(event, XtWindow(widget))
1367a3bd7f05Smrg                              || XtDispatchEventToWidget(widget, event));
1368a3bd7f05Smrg        }
1369a3bd7f05Smrg        else
1370a3bd7f05Smrg            was_dispatched = (Boolean) XFilterEvent(event, None);
1371444c061aSmrg    }
1372444c061aSmrg    else if (grabType == pass) {
1373a3bd7f05Smrg        if (event->type == LeaveNotify ||
1374a3bd7f05Smrg            event->type == FocusIn || event->type == FocusOut) {
1375a3bd7f05Smrg            if (XtIsSensitive(widget))
1376a3bd7f05Smrg                was_dispatched = (XFilterEvent(event, XtWindow(widget)) ||
1377a3bd7f05Smrg                                  XtDispatchEventToWidget(widget, event));
1378a3bd7f05Smrg        }
1379a3bd7f05Smrg        else
1380a3bd7f05Smrg            was_dispatched = (XFilterEvent(event, XtWindow(widget)) ||
1381a3bd7f05Smrg                              XtDispatchEventToWidget(widget, event));
1382444c061aSmrg    }
1383444c061aSmrg    else if (grabType == ignore) {
1384a3bd7f05Smrg        if ((grabList == NULL || _XtOnGrabList(widget, grabList))
1385a3bd7f05Smrg            && XtIsSensitive(widget)) {
1386a3bd7f05Smrg            was_dispatched = (XFilterEvent(event, XtWindow(widget))
1387a3bd7f05Smrg                              || DispatchEvent(event, widget));
1388a3bd7f05Smrg        }
1389444c061aSmrg    }
1390444c061aSmrg    else if (grabType == remap) {
1391a3bd7f05Smrg        EventMask mask = _XtConvertTypeToMask(event->type);
1392a3bd7f05Smrg        Widget dspWidget;
1393a3bd7f05Smrg        Boolean was_filtered = False;
1394a3bd7f05Smrg
1395a3bd7f05Smrg        dspWidget = _XtFindRemapWidget(event, widget, mask, pdi);
1396a3bd7f05Smrg
1397a3bd7f05Smrg        if ((grabList == NULL || _XtOnGrabList(dspWidget, grabList))
1398a3bd7f05Smrg            && XtIsSensitive(dspWidget)) {
1399a3bd7f05Smrg            if ((was_filtered =
1400a3bd7f05Smrg                 (Boolean) XFilterEvent(event, XtWindow(dspWidget)))) {
1401a3bd7f05Smrg                /* If this event activated a device grab, release it. */
1402a3bd7f05Smrg                _XtUngrabBadGrabs(event, widget, mask, pdi);
1403a3bd7f05Smrg                was_dispatched = True;
1404a3bd7f05Smrg            }
1405a3bd7f05Smrg            else
1406a3bd7f05Smrg                was_dispatched = XtDispatchEventToWidget(dspWidget, event);
1407a3bd7f05Smrg        }
1408a3bd7f05Smrg        else
1409a3bd7f05Smrg            _XtUngrabBadGrabs(event, widget, mask, pdi);
1410a3bd7f05Smrg
1411a3bd7f05Smrg        if (!was_filtered) {
1412a3bd7f05Smrg            /* Also dispatch to nearest accessible spring_loaded. */
1413a3bd7f05Smrg            /* Fetch this afterward to reflect modal list changes */
1414a3bd7f05Smrg            grabList = *_XtGetGrabList(pdi);
1415a3bd7f05Smrg            widget = LookupSpringLoaded(grabList);
1416a3bd7f05Smrg            if (widget != NULL && widget != dspWidget) {
1417a3bd7f05Smrg                was_dispatched = (XFilterEvent(event, XtWindow(widget))
1418a3bd7f05Smrg                                  || XtDispatchEventToWidget(widget, event)
1419a3bd7f05Smrg                                  || was_dispatched);
1420a3bd7f05Smrg            }
1421a3bd7f05Smrg        }
1422444c061aSmrg    }
1423444c061aSmrg    UNLOCK_APP(app);
1424444c061aSmrg    return was_dispatched;
1425444c061aSmrg}
1426444c061aSmrg
1427a3bd7f05SmrgBoolean
1428a3bd7f05SmrgXtDispatchEvent(XEvent *event)
1429444c061aSmrg{
1430444c061aSmrg    Boolean was_dispatched, safe;
1431444c061aSmrg    int dispatch_level;
1432444c061aSmrg    int starting_count;
1433444c061aSmrg    XtPerDisplay pd;
1434a3bd7f05Smrg    Time time = 0;
1435444c061aSmrg    XtEventDispatchProc dispatch = _XtDefaultDispatcher;
1436444c061aSmrg    XtAppContext app = XtDisplayToApplicationContext(event->xany.display);
1437444c061aSmrg
1438444c061aSmrg    LOCK_APP(app);
1439444c061aSmrg    dispatch_level = ++app->dispatch_level;
1440444c061aSmrg    starting_count = app->destroy_count;
1441444c061aSmrg
1442444c061aSmrg    switch (event->type) {
1443a3bd7f05Smrg    case KeyPress:
1444a3bd7f05Smrg    case KeyRelease:
1445a3bd7f05Smrg        time = event->xkey.time;
1446a3bd7f05Smrg        break;
1447a3bd7f05Smrg    case ButtonPress:
1448a3bd7f05Smrg    case ButtonRelease:
1449a3bd7f05Smrg        time = event->xbutton.time;
1450a3bd7f05Smrg        break;
1451a3bd7f05Smrg    case MotionNotify:
1452a3bd7f05Smrg        time = event->xmotion.time;
1453a3bd7f05Smrg        break;
1454a3bd7f05Smrg    case EnterNotify:
1455a3bd7f05Smrg    case LeaveNotify:
1456a3bd7f05Smrg        time = event->xcrossing.time;
1457a3bd7f05Smrg        break;
1458a3bd7f05Smrg    case PropertyNotify:
1459a3bd7f05Smrg        time = event->xproperty.time;
1460a3bd7f05Smrg        break;
1461a3bd7f05Smrg    case SelectionClear:
1462a3bd7f05Smrg        time = event->xselectionclear.time;
1463a3bd7f05Smrg        break;
1464a3bd7f05Smrg
1465a3bd7f05Smrg    case MappingNotify:
1466a3bd7f05Smrg        _XtRefreshMapping(event, True);
1467a3bd7f05Smrg        break;
1468444c061aSmrg    }
1469444c061aSmrg    pd = _XtGetPerDisplay(event->xany.display);
1470a3bd7f05Smrg
1471a3bd7f05Smrg    if (time)
1472a3bd7f05Smrg        pd->last_timestamp = time;
1473444c061aSmrg    pd->last_event = *event;
1474444c061aSmrg
1475444c061aSmrg    if (pd->dispatcher_list) {
1476a3bd7f05Smrg        dispatch = pd->dispatcher_list[event->type];
1477a3bd7f05Smrg        if (dispatch == NULL)
1478a3bd7f05Smrg            dispatch = _XtDefaultDispatcher;
1479444c061aSmrg    }
1480a3bd7f05Smrg    was_dispatched = (*dispatch) (event);
1481444c061aSmrg
1482444c061aSmrg    /*
1483444c061aSmrg     * To make recursive XtDispatchEvent work, we need to do phase 2 destroys
1484444c061aSmrg     * only on those widgets destroyed by this particular dispatch.
1485444c061aSmrg     *
1486444c061aSmrg     */
1487444c061aSmrg
1488444c061aSmrg    if (app->destroy_count > starting_count)
1489a3bd7f05Smrg        _XtDoPhase2Destroy(app, dispatch_level);
1490444c061aSmrg
1491444c061aSmrg    app->dispatch_level = dispatch_level - 1;
1492444c061aSmrg
1493444c061aSmrg    if ((safe = _XtSafeToDestroy(app))) {
1494a3bd7f05Smrg        if (app->dpy_destroy_count != 0)
1495a3bd7f05Smrg            _XtCloseDisplays(app);
1496a3bd7f05Smrg        if (app->free_bindings)
1497a3bd7f05Smrg            _XtDoFreeBindings(app);
1498444c061aSmrg    }
1499444c061aSmrg    UNLOCK_APP(app);
1500444c061aSmrg    LOCK_PROCESS;
1501a3bd7f05Smrg    if (_XtAppDestroyCount != 0 && safe)
1502a3bd7f05Smrg        _XtDestroyAppContexts();
1503444c061aSmrg    UNLOCK_PROCESS;
1504444c061aSmrg    return was_dispatched;
1505444c061aSmrg}
1506444c061aSmrg
1507a3bd7f05Smrgstatic void
1508a3bd7f05SmrgGrabDestroyCallback(Widget widget,
1509a3bd7f05Smrg                    XtPointer closure _X_UNUSED,
1510a3bd7f05Smrg                    XtPointer call_data _X_UNUSED)
1511444c061aSmrg{
1512444c061aSmrg    /* Remove widget from grab list if it destroyed */
1513444c061aSmrg    XtRemoveGrab(widget);
1514444c061aSmrg}
1515444c061aSmrg
1516a3bd7f05Smrgstatic XtGrabRec *
1517a3bd7f05SmrgNewGrabRec(Widget widget, Boolean exclusive, Boolean spring_loaded)
1518444c061aSmrg{
1519a3bd7f05Smrg    register XtGrabList gl;
1520444c061aSmrg
1521a3bd7f05Smrg    gl = XtNew(XtGrabRec);
1522a3bd7f05Smrg    gl->next = NULL;
1523a3bd7f05Smrg    gl->widget = widget;
1524a3bd7f05Smrg    XtSetBit(gl->exclusive, exclusive);
15250568f49bSmrg    XtSetBit(gl->spring_loaded, spring_loaded);
1526444c061aSmrg
1527444c061aSmrg    return gl;
1528444c061aSmrg}
1529444c061aSmrg
1530a3bd7f05Smrgvoid
1531a3bd7f05SmrgXtAddGrab(Widget widget, _XtBoolean exclusive, _XtBoolean spring_loaded)
1532444c061aSmrg{
1533a3bd7f05Smrg    register XtGrabList gl;
1534a3bd7f05Smrg    XtGrabList *grabListPtr;
1535444c061aSmrg    XtAppContext app = XtWidgetToApplicationContext(widget);
1536444c061aSmrg
1537444c061aSmrg    LOCK_APP(app);
1538444c061aSmrg    LOCK_PROCESS;
1539444c061aSmrg    grabListPtr = _XtGetGrabList(_XtGetPerDisplayInput(XtDisplay(widget)));
1540444c061aSmrg
1541444c061aSmrg    if (spring_loaded && !exclusive) {
1542a3bd7f05Smrg        XtAppWarningMsg(app,
1543a3bd7f05Smrg                        "grabError", "xtAddGrab", XtCXtToolkitError,
1544a3bd7f05Smrg                        "XtAddGrab requires exclusive grab if spring_loaded is TRUE",
1545a3bd7f05Smrg                        NULL, NULL);
1546a3bd7f05Smrg        exclusive = TRUE;
1547444c061aSmrg    }
1548444c061aSmrg
15490568f49bSmrg    gl = NewGrabRec(widget, (Boolean) exclusive, (Boolean) spring_loaded);
1550444c061aSmrg    gl->next = *grabListPtr;
1551444c061aSmrg    *grabListPtr = gl;
1552444c061aSmrg
1553a3bd7f05Smrg    XtAddCallback(widget, XtNdestroyCallback,
1554a3bd7f05Smrg                  GrabDestroyCallback, (XtPointer) NULL);
1555444c061aSmrg    UNLOCK_PROCESS;
1556444c061aSmrg    UNLOCK_APP(app);
1557444c061aSmrg}
1558444c061aSmrg
1559a3bd7f05Smrgvoid
1560a3bd7f05SmrgXtRemoveGrab(Widget widget)
1561444c061aSmrg{
1562444c061aSmrg    register XtGrabList gl;
1563444c061aSmrg    register Boolean done;
1564a3bd7f05Smrg    XtGrabList *grabListPtr;
1565444c061aSmrg    XtAppContext app = XtWidgetToApplicationContext(widget);
1566444c061aSmrg
1567444c061aSmrg    LOCK_APP(app);
1568444c061aSmrg    LOCK_PROCESS;
1569444c061aSmrg
1570444c061aSmrg    grabListPtr = _XtGetGrabList(_XtGetPerDisplayInput(XtDisplay(widget)));
1571444c061aSmrg
1572444c061aSmrg    for (gl = *grabListPtr; gl != NULL; gl = gl->next) {
1573a3bd7f05Smrg        if (gl->widget == widget)
1574a3bd7f05Smrg            break;
1575444c061aSmrg    }
1576444c061aSmrg
1577444c061aSmrg    if (gl == NULL) {
1578a3bd7f05Smrg        XtAppWarningMsg(app,
1579a3bd7f05Smrg                        "grabError", "xtRemoveGrab", XtCXtToolkitError,
1580a3bd7f05Smrg                        "XtRemoveGrab asked to remove a widget not on the list",
1581a3bd7f05Smrg                        NULL, NULL);
1582a3bd7f05Smrg        UNLOCK_PROCESS;
1583a3bd7f05Smrg        UNLOCK_APP(app);
1584a3bd7f05Smrg        return;
1585a3bd7f05Smrg    }
1586444c061aSmrg
1587444c061aSmrg    do {
1588a3bd7f05Smrg        gl = *grabListPtr;
1589a3bd7f05Smrg        done = (gl->widget == widget);
1590a3bd7f05Smrg        *grabListPtr = gl->next;
1591a3bd7f05Smrg        XtRemoveCallback(gl->widget, XtNdestroyCallback,
1592a3bd7f05Smrg                         GrabDestroyCallback, (XtPointer) NULL);
1593a3bd7f05Smrg        XtFree((char *) gl);
1594a3bd7f05Smrg    } while (!done);
1595444c061aSmrg    UNLOCK_PROCESS;
1596444c061aSmrg    UNLOCK_APP(app);
1597444c061aSmrg    return;
1598444c061aSmrg}
1599444c061aSmrg
1600a3bd7f05Smrgvoid
1601a3bd7f05SmrgXtMainLoop(void)
1602444c061aSmrg{
1603a3bd7f05Smrg    XtAppMainLoop(_XtDefaultAppContext());
1604444c061aSmrg}
1605444c061aSmrg
1606a3bd7f05Smrgvoid
1607a3bd7f05SmrgXtAppMainLoop(XtAppContext app)
1608444c061aSmrg{
16090568f49bSmrg    XtInputMask m = XtIMAll;
16100568f49bSmrg    XtInputMask t;
1611a3bd7f05Smrg
1612444c061aSmrg    LOCK_APP(app);
1613444c061aSmrg    do {
1614a3bd7f05Smrg        if (m == 0) {
1615a3bd7f05Smrg            m = XtIMAll;
1616a3bd7f05Smrg            /* wait for any event, blocking */
1617a3bd7f05Smrg            XtAppProcessEvent(app, m);
1618a3bd7f05Smrg        }
1619a3bd7f05Smrg        else if (((t = XtAppPending(app)) & m)) {
1620a3bd7f05Smrg            /* wait for certain events, stepping through choices */
1621a3bd7f05Smrg            XtAppProcessEvent(app, t & m);
1622a3bd7f05Smrg        }
1623a3bd7f05Smrg        m >>= 1;
1624a3bd7f05Smrg    } while (app->exit_flag == FALSE);
1625444c061aSmrg    UNLOCK_APP(app);
1626444c061aSmrg}
1627444c061aSmrg
1628a3bd7f05Smrgvoid
1629a3bd7f05Smrg_XtFreeEventTable(XtEventTable *event_table)
1630444c061aSmrg{
1631444c061aSmrg    register XtEventTable event;
1632444c061aSmrg
1633444c061aSmrg    event = *event_table;
1634444c061aSmrg    while (event != NULL) {
1635a3bd7f05Smrg        register XtEventTable next = event->next;
1636a3bd7f05Smrg
1637a3bd7f05Smrg        XtFree((char *) event);
1638a3bd7f05Smrg        event = next;
1639444c061aSmrg    }
1640444c061aSmrg}
1641444c061aSmrg
1642a3bd7f05SmrgTime
1643a3bd7f05SmrgXtLastTimestampProcessed(Display *dpy)
1644444c061aSmrg{
1645444c061aSmrg    Time time;
1646a3bd7f05Smrg
1647444c061aSmrg    DPY_TO_APPCON(dpy);
1648444c061aSmrg
1649444c061aSmrg    LOCK_APP(app);
1650444c061aSmrg    LOCK_PROCESS;
1651a3bd7f05Smrg    time = _XtGetPerDisplay(dpy)->last_timestamp;
1652444c061aSmrg    UNLOCK_PROCESS;
1653444c061aSmrg    UNLOCK_APP(app);
1654a3bd7f05Smrg    return (time);
1655444c061aSmrg}
1656444c061aSmrg
1657a3bd7f05SmrgXEvent *
1658a3bd7f05SmrgXtLastEventProcessed(Display *dpy)
1659444c061aSmrg{
1660a3bd7f05Smrg    XEvent *le = NULL;
1661a3bd7f05Smrg
1662444c061aSmrg    DPY_TO_APPCON(dpy);
1663444c061aSmrg
1664444c061aSmrg    LOCK_APP(app);
1665444c061aSmrg    le = &_XtGetPerDisplay(dpy)->last_event;
1666444c061aSmrg    if (!le->xany.serial)
1667a3bd7f05Smrg        le = NULL;
1668444c061aSmrg    UNLOCK_APP(app);
1669444c061aSmrg    return le;
1670444c061aSmrg}
1671444c061aSmrg
1672a3bd7f05Smrgvoid
1673a3bd7f05Smrg_XtSendFocusEvent(Widget child, int type)
1674444c061aSmrg{
1675444c061aSmrg    child = XtIsWidget(child) ? child : _XtWindowedAncestor(child);
1676444c061aSmrg    if (XtIsSensitive(child) && !child->core.being_destroyed
1677a3bd7f05Smrg        && XtIsRealized(child)
1678a3bd7f05Smrg        && (XtBuildEventMask(child) & FocusChangeMask)) {
1679a3bd7f05Smrg        XFocusChangeEvent event;
1680a3bd7f05Smrg        Display *dpy = XtDisplay(child);
1681a3bd7f05Smrg
1682a3bd7f05Smrg        event.type = type;
1683a3bd7f05Smrg        event.serial = LastKnownRequestProcessed(dpy);
1684a3bd7f05Smrg        event.send_event = True;
1685a3bd7f05Smrg        event.display = dpy;
1686a3bd7f05Smrg
1687a3bd7f05Smrg        event.window = XtWindow(child);
1688a3bd7f05Smrg        event.mode = NotifyNormal;
1689a3bd7f05Smrg        event.detail = NotifyAncestor;
1690a3bd7f05Smrg        if (XFilterEvent((XEvent *) &event, XtWindow(child)))
1691a3bd7f05Smrg            return;
1692a3bd7f05Smrg        XtDispatchEventToWidget(child, (XEvent *) &event);
1693444c061aSmrg    }
1694444c061aSmrg}
1695444c061aSmrg
1696a3bd7f05Smrgstatic XtEventDispatchProc *
1697a3bd7f05SmrgNewDispatcherList(void)
1698444c061aSmrg{
1699a3bd7f05Smrg    XtEventDispatchProc *l = (XtEventDispatchProc *)
1700a3bd7f05Smrg        __XtCalloc((Cardinal) 128,
1701a3bd7f05Smrg                   (Cardinal)
1702a3bd7f05Smrg                   sizeof(XtEventDispatchProc));
1703a3bd7f05Smrg
1704444c061aSmrg    return l;
1705444c061aSmrg}
1706444c061aSmrg
1707a3bd7f05SmrgXtEventDispatchProc
1708a3bd7f05SmrgXtSetEventDispatcher(Display *dpy,
1709a3bd7f05Smrg                     int event_type,
1710a3bd7f05Smrg                     XtEventDispatchProc proc)
1711444c061aSmrg{
1712444c061aSmrg    XtEventDispatchProc *list;
1713444c061aSmrg    XtEventDispatchProc old_proc;
1714444c061aSmrg    register XtPerDisplay pd;
1715a3bd7f05Smrg
1716444c061aSmrg    DPY_TO_APPCON(dpy);
1717444c061aSmrg
1718444c061aSmrg    LOCK_APP(app);
1719444c061aSmrg    LOCK_PROCESS;
1720444c061aSmrg    pd = _XtGetPerDisplay(dpy);
1721444c061aSmrg
1722444c061aSmrg    list = pd->dispatcher_list;
1723444c061aSmrg    if (!list) {
1724a3bd7f05Smrg        if (proc)
1725a3bd7f05Smrg            list = pd->dispatcher_list = NewDispatcherList();
1726a3bd7f05Smrg        else
1727a3bd7f05Smrg            return _XtDefaultDispatcher;
1728444c061aSmrg    }
1729444c061aSmrg    old_proc = list[event_type];
1730444c061aSmrg    list[event_type] = proc;
1731a3bd7f05Smrg    if (old_proc == NULL)
1732a3bd7f05Smrg        old_proc = _XtDefaultDispatcher;
1733444c061aSmrg    UNLOCK_PROCESS;
1734444c061aSmrg    UNLOCK_APP(app);
1735444c061aSmrg    return old_proc;
1736444c061aSmrg}
1737444c061aSmrg
1738a3bd7f05Smrgvoid
1739a3bd7f05SmrgXtRegisterExtensionSelector(Display *dpy,
1740a3bd7f05Smrg                            int min_event_type,
1741a3bd7f05Smrg                            int max_event_type,
1742a3bd7f05Smrg                            XtExtensionSelectProc proc,
1743a3bd7f05Smrg                            XtPointer client_data)
1744444c061aSmrg{
1745444c061aSmrg    XtPerDisplay pd;
1746444c061aSmrg    int i;
1747a3bd7f05Smrg
1748444c061aSmrg    DPY_TO_APPCON(dpy);
1749444c061aSmrg
1750a3bd7f05Smrg    if (dpy == NULL)
1751a3bd7f05Smrg        XtErrorMsg("nullDisplay",
1752a3bd7f05Smrg                   "xtRegisterExtensionSelector", XtCXtToolkitError,
1753a3bd7f05Smrg                   "XtRegisterExtensionSelector requires a non-NULL display",
1754a3bd7f05Smrg                   NULL, NULL);
1755444c061aSmrg
1756444c061aSmrg    LOCK_APP(app);
1757444c061aSmrg    LOCK_PROCESS;
1758444c061aSmrg    pd = _XtGetPerDisplay(dpy);
1759444c061aSmrg
1760444c061aSmrg    for (i = 0; i < pd->ext_select_count; i++) {
17610568f49bSmrg        ExtSelectRec *e = &pd->ext_select_list[i];
1762a3bd7f05Smrg
1763a3bd7f05Smrg        if (e->min == min_event_type && e->max == max_event_type) {
1764a3bd7f05Smrg            e->proc = proc;
1765a3bd7f05Smrg            e->client_data = client_data;
1766a3bd7f05Smrg            return;
1767a3bd7f05Smrg        }
1768a3bd7f05Smrg        if ((min_event_type >= e->min && min_event_type <= e->max) ||
1769a3bd7f05Smrg            (max_event_type >= e->min && max_event_type <= e->max)) {
1770a3bd7f05Smrg            XtErrorMsg("rangeError", "xtRegisterExtensionSelector",
1771a3bd7f05Smrg                       XtCXtToolkitError,
1772a3bd7f05Smrg                       "Attempt to register multiple selectors for one extension event type",
1773a3bd7f05Smrg                       NULL, NULL);
1774a3bd7f05Smrg            UNLOCK_PROCESS;
1775a3bd7f05Smrg            UNLOCK_APP(app);
1776a3bd7f05Smrg            return;
1777a3bd7f05Smrg        }
1778444c061aSmrg    }
1779444c061aSmrg    pd->ext_select_count++;
1780444c061aSmrg    pd->ext_select_list =
1781a3bd7f05Smrg        (ExtSelectRec *) XtRealloc((char *) pd->ext_select_list,
1782a3bd7f05Smrg                                   (Cardinal) ((size_t) pd->ext_select_count *
1783a3bd7f05Smrg                                               sizeof(ExtSelectRec)));
1784444c061aSmrg    for (i = pd->ext_select_count - 1; i > 0; i--) {
1785a3bd7f05Smrg        if (pd->ext_select_list[i - 1].min > min_event_type) {
1786a3bd7f05Smrg            pd->ext_select_list[i] = pd->ext_select_list[i - 1];
1787a3bd7f05Smrg        }
1788a3bd7f05Smrg        else
1789a3bd7f05Smrg            break;
1790444c061aSmrg    }
1791444c061aSmrg    pd->ext_select_list[i].min = min_event_type;
1792444c061aSmrg    pd->ext_select_list[i].max = max_event_type;
1793444c061aSmrg    pd->ext_select_list[i].proc = proc;
1794444c061aSmrg    pd->ext_select_list[i].client_data = client_data;
1795444c061aSmrg    UNLOCK_PROCESS;
1796444c061aSmrg    UNLOCK_APP(app);
1797444c061aSmrg}
1798444c061aSmrg
1799a3bd7f05Smrgvoid
1800a3bd7f05Smrg_XtExtensionSelect(Widget widget)
1801444c061aSmrg{
1802444c061aSmrg    int i;
1803444c061aSmrg    XtPerDisplay pd;
1804a3bd7f05Smrg
1805444c061aSmrg    WIDGET_TO_APPCON(widget);
1806444c061aSmrg
1807444c061aSmrg    LOCK_APP(app);
1808444c061aSmrg    LOCK_PROCESS;
1809444c061aSmrg
1810444c061aSmrg    pd = _XtGetPerDisplay(XtDisplay(widget));
1811444c061aSmrg
1812444c061aSmrg    for (i = 0; i < pd->ext_select_count; i++) {
1813a3bd7f05Smrg        CallExtensionSelector(widget, pd->ext_select_list + i, FALSE);
1814444c061aSmrg    }
1815444c061aSmrg    UNLOCK_PROCESS;
1816444c061aSmrg    UNLOCK_APP(app);
1817444c061aSmrg}
1818