1444c061aSmrg/***********************************************************
2fdf6a26fSmrgCopyright (c) 1993, Oracle and/or its affiliates.
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/*
89fdf6a26fSmrg * These are definitions to make the code that handles exposure compression
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{
108a3bd7f05Smrg    EventMask mask = 0L;
109a3bd7f05Smrg
110fdf6a26fSmrg    if (widget != NULL) {
111fdf6a26fSmrg        XtEventTable ev;
112444c061aSmrg
113fdf6a26fSmrg        WIDGET_TO_APPCON(widget);
114a3bd7f05Smrg
115fdf6a26fSmrg        LOCK_APP(app);
116fdf6a26fSmrg        for (ev = widget->core.event_table; ev != NULL; ev = ev->next) {
117fdf6a26fSmrg            if (!ev->select)
118fdf6a26fSmrg                continue;
119a3bd7f05Smrg
120fdf6a26fSmrg            if (!ev->has_type_specifier)
121fdf6a26fSmrg                mask |= ev->mask;
122fdf6a26fSmrg            else {
123fdf6a26fSmrg                if (EXT_TYPE(ev) < LASTEvent) {
124fdf6a26fSmrg                    Cardinal i;
125fdf6a26fSmrg
126fdf6a26fSmrg                    for (i = 0; i < ev->mask; i++)
127fdf6a26fSmrg                        if (EXT_SELECT_DATA(ev, i))
128fdf6a26fSmrg                            mask |= *(EventMask *) EXT_SELECT_DATA(ev, i);
129fdf6a26fSmrg                }
130a3bd7f05Smrg            }
131a3bd7f05Smrg        }
132fdf6a26fSmrg        LOCK_PROCESS;
133fdf6a26fSmrg        if (widget->core.widget_class->core_class.expose != NULL)
134fdf6a26fSmrg            mask |= ExposureMask;
135fdf6a26fSmrg        if (widget->core.widget_class->core_class.visible_interest)
136fdf6a26fSmrg            mask |= VisibilityChangeMask;
137fdf6a26fSmrg        UNLOCK_PROCESS;
138fdf6a26fSmrg        if (widget->core.tm.translations)
139fdf6a26fSmrg            mask |= widget->core.tm.translations->eventMask;
140444c061aSmrg
141fdf6a26fSmrg        mask = mask & ~NonMaskableMask;
142fdf6a26fSmrg        UNLOCK_APP(app);
143fdf6a26fSmrg    }
144444c061aSmrg    return mask;
145444c061aSmrg}
146444c061aSmrg
147a3bd7f05Smrgstatic void
148a3bd7f05SmrgCallExtensionSelector(Widget widget, ExtSelectRec *rec, Boolean forceCall)
149444c061aSmrg{
150a3bd7f05Smrg    XtEventRec *p;
151a3bd7f05Smrg    XtPointer *data;
152a3bd7f05Smrg    int *types;
153444c061aSmrg    Cardinal i, count = 0;
154444c061aSmrg
155444c061aSmrg    for (p = widget->core.event_table; p != NULL; p = p->next)
156a3bd7f05Smrg        if (p->has_type_specifier &&
157a3bd7f05Smrg            EXT_TYPE(p) >= rec->min && EXT_TYPE(p) <= rec->max)
158a3bd7f05Smrg            count = (Cardinal) (count + p->mask);
159444c061aSmrg
160a3bd7f05Smrg    if (count == 0 && !forceCall)
161a3bd7f05Smrg        return;
162444c061aSmrg
163a3bd7f05Smrg    data = (XtPointer *) ALLOCATE_LOCAL(count * sizeof(XtPointer));
164a3bd7f05Smrg    types = (int *) ALLOCATE_LOCAL(count * sizeof(int));
165444c061aSmrg    count = 0;
166444c061aSmrg
167444c061aSmrg    for (p = widget->core.event_table; p != NULL; p = p->next)
168a3bd7f05Smrg        if (p->has_type_specifier &&
169a3bd7f05Smrg            EXT_TYPE(p) >= rec->min && EXT_TYPE(p) <= rec->max)
170a3bd7f05Smrg            for (i = 0; i < p->mask; i++) {
171a3bd7f05Smrg                types[count] = EXT_TYPE(p);
172a3bd7f05Smrg                data[count++] = EXT_SELECT_DATA(p, i);
173a3bd7f05Smrg            }
174a3bd7f05Smrg
175a3bd7f05Smrg    (*rec->proc) (widget, types, data, (int) count, rec->client_data);
176a3bd7f05Smrg    DEALLOCATE_LOCAL((char *) types);
177a3bd7f05Smrg    DEALLOCATE_LOCAL((char *) data);
178444c061aSmrg}
179444c061aSmrg
180444c061aSmrgstatic void
181a3bd7f05SmrgRemoveEventHandler(Widget widget,
182a3bd7f05Smrg                   XtPointer select_data,
183a3bd7f05Smrg                   int type,
184a3bd7f05Smrg                   Boolean has_type_specifier,
185a3bd7f05Smrg                   Boolean other,
186fdf6a26fSmrg                   const XtEventHandler proc,
187fdf6a26fSmrg                   const XtPointer closure,
188a3bd7f05Smrg                   Boolean raw)
189444c061aSmrg{
190444c061aSmrg    XtEventRec *p, **pp;
1910568f49bSmrg    EventMask oldMask = XtBuildEventMask(widget);
192444c061aSmrg
193a3bd7f05Smrg    if (raw)
194a3bd7f05Smrg        raw = 1;
195444c061aSmrg    pp = &widget->core.event_table;
196444c061aSmrg    while ((p = *pp) &&
197a3bd7f05Smrg           (p->proc != proc || p->closure != closure || p->select == raw ||
198a3bd7f05Smrg            has_type_specifier != p->has_type_specifier ||
199a3bd7f05Smrg            (has_type_specifier && EXT_TYPE(p) != type)))
200a3bd7f05Smrg        pp = &p->next;
201a3bd7f05Smrg    if (!p)
202a3bd7f05Smrg        return;
203444c061aSmrg
204444c061aSmrg    /* un-register it */
205444c061aSmrg    if (!has_type_specifier) {
206a3bd7f05Smrg        EventMask eventMask = *(EventMask *) select_data;
207a3bd7f05Smrg
208a3bd7f05Smrg        eventMask &= ~NonMaskableMask;
209a3bd7f05Smrg        if (other)
210a3bd7f05Smrg            eventMask |= NonMaskableMask;
211a3bd7f05Smrg        p->mask &= ~eventMask;
212a3bd7f05Smrg    }
213a3bd7f05Smrg    else {
214a3bd7f05Smrg        Cardinal i;
215a3bd7f05Smrg
216a3bd7f05Smrg        /* p->mask specifies count of EXT_SELECT_DATA(p,i)
217a3bd7f05Smrg         * search through the list of selection data, if not found
218fdf6a26fSmrg         * don't remove this handler
219a3bd7f05Smrg         */
220a3bd7f05Smrg        for (i = 0; i < p->mask && select_data != EXT_SELECT_DATA(p, i);)
221a3bd7f05Smrg            i++;
222a3bd7f05Smrg        if (i == p->mask)
223a3bd7f05Smrg            return;
224a3bd7f05Smrg        if (p->mask == 1)
225a3bd7f05Smrg            p->mask = 0;
226a3bd7f05Smrg        else {
227a3bd7f05Smrg            p->mask--;
228a3bd7f05Smrg            while (i < p->mask) {
229a3bd7f05Smrg                EXT_SELECT_DATA(p, i) = EXT_SELECT_DATA(p, i + 1);
230a3bd7f05Smrg                i++;
231a3bd7f05Smrg            }
232a3bd7f05Smrg        }
233444c061aSmrg    }
234444c061aSmrg
235a3bd7f05Smrg    if (!p->mask) {             /* delete it entirely */
236444c061aSmrg        *pp = p->next;
237a3bd7f05Smrg        XtFree((char *) p);
238444c061aSmrg    }
239444c061aSmrg
240444c061aSmrg    /* Reset select mask if realized and not raw. */
241a3bd7f05Smrg    if (!raw && XtIsRealized(widget) && !widget->core.being_destroyed) {
242a3bd7f05Smrg        EventMask mask = XtBuildEventMask(widget);
243a3bd7f05Smrg        Display *dpy = XtDisplay(widget);
244a3bd7f05Smrg
245a3bd7f05Smrg        if (oldMask != mask)
246a3bd7f05Smrg            XSelectInput(dpy, XtWindow(widget), (long) mask);
247a3bd7f05Smrg
248a3bd7f05Smrg        if (has_type_specifier) {
249a3bd7f05Smrg            XtPerDisplay pd = _XtGetPerDisplay(dpy);
250a3bd7f05Smrg            int i;
251a3bd7f05Smrg
252a3bd7f05Smrg            for (i = 0; i < pd->ext_select_count; i++) {
253a3bd7f05Smrg                if (type >= pd->ext_select_list[i].min &&
254a3bd7f05Smrg                    type <= pd->ext_select_list[i].max) {
255a3bd7f05Smrg                    CallExtensionSelector(widget, pd->ext_select_list + i,
256a3bd7f05Smrg                                          TRUE);
257a3bd7f05Smrg                    break;
258a3bd7f05Smrg                }
259a3bd7f05Smrg                if (type < pd->ext_select_list[i].min)
260a3bd7f05Smrg                    break;
261a3bd7f05Smrg            }
262a3bd7f05Smrg        }
263444c061aSmrg    }
264444c061aSmrg}
265444c061aSmrg
266a3bd7f05Smrg/*      Function Name: AddEventHandler
267a3bd7f05Smrg *      Description: An Internal routine that does the actual work of
268444c061aSmrg *                   adding the event handlers.
269a3bd7f05Smrg *      Arguments: widget - widget to register an event handler for.
270444c061aSmrg *                 eventMask - events to mask for.
271fdf6a26fSmrg *                 other - pass non maskable events to this procedure.
272fdf6a26fSmrg *                 proc - procedure to register.
273fdf6a26fSmrg *                 closure - data to pass to the event handler.
274444c061aSmrg *                 position - where to add this event handler.
275444c061aSmrg *                 force_new_position - If the element is already in the
276444c061aSmrg *                                      list, this will force it to the
277444c061aSmrg *                                      beginning or end depending on position.
278444c061aSmrg *                 raw - If FALSE call XSelectInput for events in mask.
279a3bd7f05Smrg *      Returns: none
280444c061aSmrg */
281444c061aSmrg
282444c061aSmrgstatic void
283a3bd7f05SmrgAddEventHandler(Widget widget,
284a3bd7f05Smrg                XtPointer select_data,
285a3bd7f05Smrg                int type,
286a3bd7f05Smrg                Boolean has_type_specifier,
287a3bd7f05Smrg                Boolean other,
288a3bd7f05Smrg                XtEventHandler proc,
289a3bd7f05Smrg                XtPointer closure,
290a3bd7f05Smrg                XtListPosition position,
291a3bd7f05Smrg                Boolean force_new_position,
292a3bd7f05Smrg                Boolean raw)
293444c061aSmrg{
294444c061aSmrg    register XtEventRec *p, **pp;
295444c061aSmrg    EventMask oldMask = 0, eventMask = 0;
296444c061aSmrg
297444c061aSmrg    if (!has_type_specifier) {
298a3bd7f05Smrg        eventMask = *(EventMask *) select_data & ~NonMaskableMask;
299a3bd7f05Smrg        if (other)
300a3bd7f05Smrg            eventMask |= NonMaskableMask;
301a3bd7f05Smrg        if (!eventMask)
302a3bd7f05Smrg            return;
303a3bd7f05Smrg    }
304a3bd7f05Smrg    else if (!type)
305a3bd7f05Smrg        return;
306444c061aSmrg
307a3bd7f05Smrg    if (XtIsRealized(widget) && !raw)
308a3bd7f05Smrg        oldMask = XtBuildEventMask(widget);
309444c061aSmrg
310a3bd7f05Smrg    if (raw)
311a3bd7f05Smrg        raw = 1;
312444c061aSmrg    pp = &widget->core.event_table;
313444c061aSmrg    while ((p = *pp) &&
314a3bd7f05Smrg           (p->proc != proc || p->closure != closure || p->select == raw ||
315a3bd7f05Smrg            has_type_specifier != p->has_type_specifier ||
316a3bd7f05Smrg            (has_type_specifier && EXT_TYPE(p) != type)))
317a3bd7f05Smrg        pp = &p->next;
318a3bd7f05Smrg
319a3bd7f05Smrg    if (!p) {                   /* New proc to add to list */
320a3bd7f05Smrg        if (has_type_specifier) {
321a3bd7f05Smrg            p = (XtEventRec *) __XtMalloc(sizeof(XtEventRec) +
322a3bd7f05Smrg                                          sizeof(XtEventRecExt));
323a3bd7f05Smrg            EXT_TYPE(p) = type;
324a3bd7f05Smrg            EXT_SELECT_DATA(p, 0) = select_data;
325a3bd7f05Smrg            p->mask = 1;
326a3bd7f05Smrg            p->has_type_specifier = True;
327a3bd7f05Smrg        }
328a3bd7f05Smrg        else {
329a3bd7f05Smrg            p = (XtEventRec *) __XtMalloc(sizeof(XtEventRec));
330a3bd7f05Smrg            p->mask = eventMask;
331a3bd7f05Smrg            p->has_type_specifier = False;
332a3bd7f05Smrg        }
333a3bd7f05Smrg        p->proc = proc;
334a3bd7f05Smrg        p->closure = closure;
335a3bd7f05Smrg        p->select = !raw;
336a3bd7f05Smrg
337a3bd7f05Smrg        if (position == XtListHead) {
338a3bd7f05Smrg            p->next = widget->core.event_table;
339a3bd7f05Smrg            widget->core.event_table = p;
340a3bd7f05Smrg        }
341a3bd7f05Smrg        else {
342a3bd7f05Smrg            *pp = p;
343a3bd7f05Smrg            p->next = NULL;
344a3bd7f05Smrg        }
345444c061aSmrg    }
346444c061aSmrg    else {
347a3bd7f05Smrg        if (force_new_position) {
348a3bd7f05Smrg            *pp = p->next;
349a3bd7f05Smrg
350a3bd7f05Smrg            if (position == XtListHead) {
351a3bd7f05Smrg                p->next = widget->core.event_table;
352a3bd7f05Smrg                widget->core.event_table = p;
353a3bd7f05Smrg            }
354a3bd7f05Smrg            else {
355a3bd7f05Smrg                /*
356a3bd7f05Smrg                 * Find the last element in the list.
357a3bd7f05Smrg                 */
358a3bd7f05Smrg                while (*pp)
359a3bd7f05Smrg                    pp = &(*pp)->next;
360a3bd7f05Smrg                *pp = p;
361a3bd7f05Smrg                p->next = NULL;
362a3bd7f05Smrg            }
363a3bd7f05Smrg        }
364a3bd7f05Smrg
365a3bd7f05Smrg        if (!has_type_specifier)
366a3bd7f05Smrg            p->mask |= eventMask;
367a3bd7f05Smrg        else {
368a3bd7f05Smrg            Cardinal i;
369a3bd7f05Smrg
370a3bd7f05Smrg            /* p->mask specifies count of EXT_SELECT_DATA(p,i) */
371a3bd7f05Smrg            for (i = 0; i < p->mask && select_data != EXT_SELECT_DATA(p, i);)
372a3bd7f05Smrg                i++;
373a3bd7f05Smrg            if (i == p->mask) {
374a3bd7f05Smrg                p = (XtEventRec *) XtRealloc((char *) p,
375a3bd7f05Smrg                                             (Cardinal) (sizeof(XtEventRec) +
376a3bd7f05Smrg                                                         sizeof(XtEventRecExt) +
377a3bd7f05Smrg                                                         p->mask *
378a3bd7f05Smrg                                                         sizeof(XtPointer)));
379a3bd7f05Smrg                EXT_SELECT_DATA(p, i) = select_data;
380a3bd7f05Smrg                p->mask++;
381a3bd7f05Smrg                *pp = p;
382a3bd7f05Smrg            }
383a3bd7f05Smrg        }
384444c061aSmrg    }
385444c061aSmrg
386444c061aSmrg    if (XtIsRealized(widget) && !raw) {
387a3bd7f05Smrg        EventMask mask = XtBuildEventMask(widget);
388a3bd7f05Smrg        Display *dpy = XtDisplay(widget);
389a3bd7f05Smrg
390a3bd7f05Smrg        if (oldMask != mask)
391a3bd7f05Smrg            XSelectInput(dpy, XtWindow(widget), (long) mask);
392a3bd7f05Smrg
393a3bd7f05Smrg        if (has_type_specifier) {
394a3bd7f05Smrg            XtPerDisplay pd = _XtGetPerDisplay(dpy);
395a3bd7f05Smrg            int i;
396a3bd7f05Smrg
397a3bd7f05Smrg            for (i = 0; i < pd->ext_select_count; i++) {
398a3bd7f05Smrg                if (type >= pd->ext_select_list[i].min &&
399a3bd7f05Smrg                    type <= pd->ext_select_list[i].max) {
400a3bd7f05Smrg                    CallExtensionSelector(widget, pd->ext_select_list + i,
401a3bd7f05Smrg                                          FALSE);
402a3bd7f05Smrg                    break;
403a3bd7f05Smrg                }
404a3bd7f05Smrg                if (type < pd->ext_select_list[i].min)
405a3bd7f05Smrg                    break;
406a3bd7f05Smrg            }
407a3bd7f05Smrg        }
408444c061aSmrg    }
409444c061aSmrg}
410444c061aSmrg
411a3bd7f05Smrgvoid
412a3bd7f05SmrgXtRemoveEventHandler(Widget widget,
413a3bd7f05Smrg                     EventMask eventMask,
414a3bd7f05Smrg                     _XtBoolean other,
415a3bd7f05Smrg                     XtEventHandler proc,
416a3bd7f05Smrg                     XtPointer closure)
417444c061aSmrg{
418444c061aSmrg    WIDGET_TO_APPCON(widget);
419444c061aSmrg    LOCK_APP(app);
420444c061aSmrg    RemoveEventHandler(widget, (XtPointer) &eventMask, 0, FALSE,
421a3bd7f05Smrg                       (Boolean) other, proc, closure, FALSE);
422444c061aSmrg    UNLOCK_APP(app);
423444c061aSmrg}
424444c061aSmrg
425a3bd7f05Smrgvoid
426a3bd7f05SmrgXtAddEventHandler(Widget widget,
427a3bd7f05Smrg                  EventMask eventMask,
428a3bd7f05Smrg                  _XtBoolean other,
429a3bd7f05Smrg                  XtEventHandler proc,
430a3bd7f05Smrg                  XtPointer closure)
431444c061aSmrg{
432444c061aSmrg    WIDGET_TO_APPCON(widget);
433444c061aSmrg    LOCK_APP(app);
4340568f49bSmrg    AddEventHandler(widget, (XtPointer) &eventMask, 0, FALSE, (Boolean) other,
435a3bd7f05Smrg                    proc, closure, XtListTail, FALSE, FALSE);
436444c061aSmrg    UNLOCK_APP(app);
437444c061aSmrg}
438444c061aSmrg
439a3bd7f05Smrgvoid
440a3bd7f05SmrgXtInsertEventHandler(Widget widget,
441a3bd7f05Smrg                     EventMask eventMask,
442a3bd7f05Smrg                     _XtBoolean other,
443a3bd7f05Smrg                     XtEventHandler proc,
444a3bd7f05Smrg                     XtPointer closure,
445a3bd7f05Smrg                     XtListPosition position)
446444c061aSmrg{
447444c061aSmrg    WIDGET_TO_APPCON(widget);
448444c061aSmrg    LOCK_APP(app);
4490568f49bSmrg    AddEventHandler(widget, (XtPointer) &eventMask, 0, FALSE, (Boolean) other,
450a3bd7f05Smrg                    proc, closure, position, TRUE, FALSE);
451444c061aSmrg    UNLOCK_APP(app);
452444c061aSmrg}
453444c061aSmrg
454a3bd7f05Smrgvoid
455a3bd7f05SmrgXtRemoveRawEventHandler(Widget widget,
456a3bd7f05Smrg                        EventMask eventMask,
457a3bd7f05Smrg                        _XtBoolean other,
458a3bd7f05Smrg                        XtEventHandler proc,
459a3bd7f05Smrg                        XtPointer closure)
460444c061aSmrg{
461444c061aSmrg    WIDGET_TO_APPCON(widget);
462444c061aSmrg    LOCK_APP(app);
463444c061aSmrg    RemoveEventHandler(widget, (XtPointer) &eventMask, 0, FALSE,
464a3bd7f05Smrg                       (Boolean) other, proc, closure, TRUE);
465444c061aSmrg    UNLOCK_APP(app);
466444c061aSmrg}
467444c061aSmrg
468a3bd7f05Smrgvoid
469a3bd7f05SmrgXtInsertRawEventHandler(Widget widget,
470a3bd7f05Smrg                        EventMask eventMask,
471a3bd7f05Smrg                        _XtBoolean other,
472a3bd7f05Smrg                        XtEventHandler proc,
473a3bd7f05Smrg                        XtPointer closure,
474a3bd7f05Smrg                        XtListPosition position)
475444c061aSmrg{
476444c061aSmrg    WIDGET_TO_APPCON(widget);
477444c061aSmrg    LOCK_APP(app);
4780568f49bSmrg    AddEventHandler(widget, (XtPointer) &eventMask, 0, FALSE, (Boolean) other,
479a3bd7f05Smrg                    proc, closure, position, TRUE, TRUE);
480444c061aSmrg    UNLOCK_APP(app);
481444c061aSmrg}
482444c061aSmrg
483a3bd7f05Smrgvoid
484a3bd7f05SmrgXtAddRawEventHandler(Widget widget,
485a3bd7f05Smrg                     EventMask eventMask,
486a3bd7f05Smrg                     _XtBoolean other,
487a3bd7f05Smrg                     XtEventHandler proc,
488a3bd7f05Smrg                     XtPointer closure)
489444c061aSmrg{
490444c061aSmrg    WIDGET_TO_APPCON(widget);
491444c061aSmrg    LOCK_APP(app);
4920568f49bSmrg    AddEventHandler(widget, (XtPointer) &eventMask, 0, FALSE, (Boolean) other,
493a3bd7f05Smrg                    proc, closure, XtListTail, FALSE, TRUE);
494444c061aSmrg    UNLOCK_APP(app);
495444c061aSmrg}
496444c061aSmrg
497a3bd7f05Smrgvoid
498a3bd7f05SmrgXtRemoveEventTypeHandler(Widget widget,
499a3bd7f05Smrg                         int type,
500a3bd7f05Smrg                         XtPointer select_data,
501a3bd7f05Smrg                         XtEventHandler proc,
502a3bd7f05Smrg                         XtPointer closure)
503444c061aSmrg{
504444c061aSmrg    WIDGET_TO_APPCON(widget);
505444c061aSmrg    LOCK_APP(app);
506444c061aSmrg    RemoveEventHandler(widget, select_data, type, TRUE,
507a3bd7f05Smrg                       FALSE, proc, closure, FALSE);
508444c061aSmrg    UNLOCK_APP(app);
509444c061aSmrg}
510444c061aSmrg
511a3bd7f05Smrgvoid
512a3bd7f05SmrgXtInsertEventTypeHandler(Widget widget,
513a3bd7f05Smrg                         int type,
514a3bd7f05Smrg                         XtPointer select_data,
515a3bd7f05Smrg                         XtEventHandler proc,
516a3bd7f05Smrg                         XtPointer closure,
517a3bd7f05Smrg                         XtListPosition position)
518444c061aSmrg{
519444c061aSmrg    WIDGET_TO_APPCON(widget);
520444c061aSmrg    LOCK_APP(app);
521444c061aSmrg    AddEventHandler(widget, select_data, type, TRUE, FALSE,
522a3bd7f05Smrg                    proc, closure, position, TRUE, FALSE);
523444c061aSmrg    UNLOCK_APP(app);
524444c061aSmrg}
525444c061aSmrg
526444c061aSmrgtypedef struct _WWPair {
527444c061aSmrg    struct _WWPair *next;
528444c061aSmrg    Window window;
529444c061aSmrg    Widget widget;
530444c061aSmrg} *WWPair;
531444c061aSmrg
532444c061aSmrgtypedef struct _WWTable {
533a3bd7f05Smrg    unsigned int mask;          /* size of hash table - 1 */
534a3bd7f05Smrg    unsigned int rehash;        /* mask - 2 */
535a3bd7f05Smrg    unsigned int occupied;      /* number of occupied entries */
536a3bd7f05Smrg    unsigned int fakes;         /* number occupied by WWfake */
537a3bd7f05Smrg    Widget *entries;            /* the entries */
538a3bd7f05Smrg    WWPair pairs;               /* bogus entries */
539444c061aSmrg} *WWTable;
540444c061aSmrg
541a3bd7f05Smrgstatic const WidgetRec WWfake;  /* placeholder for deletions */
542444c061aSmrg
543444c061aSmrg#define WWHASH(tab,win) ((win) & tab->mask)
544444c061aSmrg#define WWREHASHVAL(tab,win) ((((win) % tab->rehash) + 2) | 1)
5450568f49bSmrg#define WWREHASH(tab,idx,rehash) ((unsigned)(idx + rehash) & (tab->mask))
546444c061aSmrg#define WWTABLE(display) (_XtGetPerDisplay(display)->WWtable)
547444c061aSmrg
548444c061aSmrgstatic void ExpandWWTable(WWTable);
549444c061aSmrg
550a3bd7f05Smrgvoid
551a3bd7f05SmrgXtRegisterDrawable(Display *display, Drawable drawable, Widget widget)
552444c061aSmrg{
553444c061aSmrg    WWTable tab;
5540568f49bSmrg    int idx;
555444c061aSmrg    Widget entry;
556444c061aSmrg    Window window = (Window) drawable;
557a3bd7f05Smrg
558444c061aSmrg    WIDGET_TO_APPCON(widget);
559444c061aSmrg
560444c061aSmrg    LOCK_APP(app);
561444c061aSmrg    LOCK_PROCESS;
562444c061aSmrg    tab = WWTABLE(display);
563a3bd7f05Smrg
564444c061aSmrg    if (window != XtWindow(widget)) {
565a3bd7f05Smrg        WWPair pair;
566a3bd7f05Smrg        pair = XtNew(struct _WWPair);
567a3bd7f05Smrg
568a3bd7f05Smrg        pair->next = tab->pairs;
569a3bd7f05Smrg        pair->window = window;
570a3bd7f05Smrg        pair->widget = widget;
571a3bd7f05Smrg        tab->pairs = pair;
572a3bd7f05Smrg        UNLOCK_PROCESS;
573a3bd7f05Smrg        UNLOCK_APP(app);
574a3bd7f05Smrg        return;
575444c061aSmrg    }
576444c061aSmrg    if ((tab->occupied + (tab->occupied >> 2)) > tab->mask)
577a3bd7f05Smrg        ExpandWWTable(tab);
578444c061aSmrg
5790568f49bSmrg    idx = (int) WWHASH(tab, window);
580444c061aSmrg    if ((entry = tab->entries[idx]) && entry != &WWfake) {
581a3bd7f05Smrg        int rehash = (int) WWREHASHVAL(tab, window);
582a3bd7f05Smrg
583a3bd7f05Smrg        do {
584a3bd7f05Smrg            idx = (int) WWREHASH(tab, idx, rehash);
585a3bd7f05Smrg        } while ((entry = tab->entries[idx]) && entry != &WWfake);
586444c061aSmrg    }
587444c061aSmrg    if (!entry)
588a3bd7f05Smrg        tab->occupied++;
589444c061aSmrg    else if (entry == &WWfake)
590a3bd7f05Smrg        tab->fakes--;
591444c061aSmrg    tab->entries[idx] = widget;
592444c061aSmrg    UNLOCK_PROCESS;
593444c061aSmrg    UNLOCK_APP(app);
594444c061aSmrg}
595444c061aSmrg
596a3bd7f05Smrgvoid
597a3bd7f05SmrgXtUnregisterDrawable(Display *display, Drawable drawable)
598444c061aSmrg{
599444c061aSmrg    WWTable tab;
6000568f49bSmrg    int idx;
601444c061aSmrg    Widget entry;
602444c061aSmrg    Window window = (Window) drawable;
603a3bd7f05Smrg    Widget widget = XtWindowToWidget(display, window);
604444c061aSmrg    DPY_TO_APPCON(display);
605444c061aSmrg
606a3bd7f05Smrg    if (widget == NULL)
607a3bd7f05Smrg        return;
608444c061aSmrg
609444c061aSmrg    LOCK_APP(app);
610444c061aSmrg    LOCK_PROCESS;
611444c061aSmrg    tab = WWTABLE(display);
612444c061aSmrg    if (window != XtWindow(widget)) {
613a3bd7f05Smrg        WWPair *prev, pair;
614a3bd7f05Smrg
615a3bd7f05Smrg        prev = &tab->pairs;
616a3bd7f05Smrg        while ((pair = *prev) && pair->window != window)
617a3bd7f05Smrg            prev = &pair->next;
618a3bd7f05Smrg        if (pair) {
619a3bd7f05Smrg            *prev = pair->next;
620a3bd7f05Smrg            XtFree((char *) pair);
621a3bd7f05Smrg        }
622a3bd7f05Smrg        UNLOCK_PROCESS;
623a3bd7f05Smrg        UNLOCK_APP(app);
624a3bd7f05Smrg        return;
625444c061aSmrg    }
6260568f49bSmrg    idx = (int) WWHASH(tab, window);
627444c061aSmrg    if ((entry = tab->entries[idx])) {
628a3bd7f05Smrg        if (entry != widget) {
629a3bd7f05Smrg            int rehash = (int) WWREHASHVAL(tab, window);
630a3bd7f05Smrg
631a3bd7f05Smrg            do {
632a3bd7f05Smrg                idx = (int) WWREHASH(tab, idx, rehash);
633a3bd7f05Smrg                if (!(entry = tab->entries[idx])) {
634a3bd7f05Smrg                    UNLOCK_PROCESS;
635a3bd7f05Smrg                    UNLOCK_APP(app);
636a3bd7f05Smrg                    return;
637a3bd7f05Smrg                }
638a3bd7f05Smrg            } while (entry != widget);
639a3bd7f05Smrg        }
640a3bd7f05Smrg        tab->entries[idx] = (Widget) &WWfake;
641a3bd7f05Smrg        tab->fakes++;
642444c061aSmrg    }
643444c061aSmrg    UNLOCK_PROCESS;
644444c061aSmrg    UNLOCK_APP(app);
645444c061aSmrg}
646444c061aSmrg
647a3bd7f05Smrgstatic void
648a3bd7f05SmrgExpandWWTable(register WWTable tab)
649444c061aSmrg{
650444c061aSmrg    unsigned int oldmask;
651444c061aSmrg    register Widget *oldentries, *entries;
652444c061aSmrg    register Cardinal oldidx, newidx, rehash;
653444c061aSmrg    register Widget entry;
654444c061aSmrg
655444c061aSmrg    LOCK_PROCESS;
656444c061aSmrg    oldmask = tab->mask;
657444c061aSmrg    oldentries = tab->entries;
658444c061aSmrg    tab->occupied -= tab->fakes;
659444c061aSmrg    tab->fakes = 0;
660444c061aSmrg    if ((tab->occupied + (tab->occupied >> 2)) > tab->mask) {
661a3bd7f05Smrg        tab->mask = (tab->mask << 1) + 1;
662a3bd7f05Smrg        tab->rehash = tab->mask - 2;
663444c061aSmrg    }
664a3bd7f05Smrg    entries = tab->entries =
665a3bd7f05Smrg        (Widget *) __XtCalloc(tab->mask + 1, sizeof(Widget));
666444c061aSmrg    for (oldidx = 0; oldidx <= oldmask; oldidx++) {
667a3bd7f05Smrg        if ((entry = oldentries[oldidx]) && entry != &WWfake) {
668a3bd7f05Smrg            newidx = (Cardinal) WWHASH(tab, XtWindow(entry));
669a3bd7f05Smrg            if (entries[newidx]) {
670a3bd7f05Smrg                rehash = (Cardinal) WWREHASHVAL(tab, XtWindow(entry));
671a3bd7f05Smrg                do {
672a3bd7f05Smrg                    newidx = (Cardinal) WWREHASH(tab, newidx, rehash);
673a3bd7f05Smrg                } while (entries[newidx]);
674a3bd7f05Smrg            }
675a3bd7f05Smrg            entries[newidx] = entry;
676a3bd7f05Smrg        }
677444c061aSmrg    }
678a3bd7f05Smrg    XtFree((char *) oldentries);
679444c061aSmrg    UNLOCK_PROCESS;
680444c061aSmrg}
681444c061aSmrg
682a3bd7f05SmrgWidget
683a3bd7f05SmrgXtWindowToWidget(register Display *display, register Window window)
684444c061aSmrg{
6850568f49bSmrg    WWTable tab;
6860568f49bSmrg    int idx;
6870568f49bSmrg    Widget entry;
688444c061aSmrg    WWPair pair;
689444c061aSmrg    DPY_TO_APPCON(display);
690444c061aSmrg
691a3bd7f05Smrg    if (!window)
692a3bd7f05Smrg        return NULL;
693444c061aSmrg
694444c061aSmrg    LOCK_APP(app);
695444c061aSmrg    LOCK_PROCESS;
696444c061aSmrg    tab = WWTABLE(display);
6970568f49bSmrg    idx = (int) WWHASH(tab, window);
698444c061aSmrg    if ((entry = tab->entries[idx]) && XtWindow(entry) != window) {
699a3bd7f05Smrg        int rehash = (int) WWREHASHVAL(tab, window);
700a3bd7f05Smrg
701a3bd7f05Smrg        do {
702a3bd7f05Smrg            idx = (int) WWREHASH(tab, idx, rehash);
703a3bd7f05Smrg        } while ((entry = tab->entries[idx]) && XtWindow(entry) != window);
704444c061aSmrg    }
705444c061aSmrg    if (entry) {
706a3bd7f05Smrg        UNLOCK_PROCESS;
707a3bd7f05Smrg        UNLOCK_APP(app);
708a3bd7f05Smrg        return entry;
709444c061aSmrg    }
710444c061aSmrg    for (pair = tab->pairs; pair; pair = pair->next) {
711a3bd7f05Smrg        if (pair->window == window) {
712a3bd7f05Smrg            entry = pair->widget;
713a3bd7f05Smrg            UNLOCK_PROCESS;
714a3bd7f05Smrg            UNLOCK_APP(app);
715a3bd7f05Smrg            return entry;
716a3bd7f05Smrg        }
717444c061aSmrg    }
718444c061aSmrg    UNLOCK_PROCESS;
719444c061aSmrg    UNLOCK_APP(app);
720444c061aSmrg    return NULL;
721444c061aSmrg}
722444c061aSmrg
723a3bd7f05Smrgvoid
724a3bd7f05Smrg_XtAllocWWTable(XtPerDisplay pd)
725444c061aSmrg{
726444c061aSmrg    register WWTable tab;
727444c061aSmrg
728444c061aSmrg    tab = (WWTable) __XtMalloc(sizeof(struct _WWTable));
729444c061aSmrg    tab->mask = 0x7f;
730444c061aSmrg    tab->rehash = tab->mask - 2;
731a3bd7f05Smrg    tab->entries = (Widget *) __XtCalloc(tab->mask + 1, sizeof(Widget));
732444c061aSmrg    tab->occupied = 0;
733444c061aSmrg    tab->fakes = 0;
734444c061aSmrg    tab->pairs = NULL;
735444c061aSmrg    pd->WWtable = tab;
736444c061aSmrg}
737444c061aSmrg
738a3bd7f05Smrgvoid
739a3bd7f05Smrg_XtFreeWWTable(register XtPerDisplay pd)
740444c061aSmrg{
741444c061aSmrg    register WWPair pair, next;
742444c061aSmrg
743444c061aSmrg    for (pair = pd->WWtable->pairs; pair; pair = next) {
744a3bd7f05Smrg        next = pair->next;
745a3bd7f05Smrg        XtFree((char *) pair);
746444c061aSmrg    }
747a3bd7f05Smrg    XtFree((char *) pd->WWtable->entries);
748a3bd7f05Smrg    XtFree((char *) pd->WWtable);
749444c061aSmrg}
750444c061aSmrg
751a3bd7f05Smrg#define EHMAXSIZE 25            /* do not make whopping big */
752444c061aSmrg
753a3bd7f05Smrgstatic Boolean
754a3bd7f05SmrgCallEventHandlers(Widget widget, XEvent *event, EventMask mask)
755444c061aSmrg{
756444c061aSmrg    register XtEventRec *p;
757444c061aSmrg    XtEventHandler *proc;
758444c061aSmrg    XtPointer *closure;
759444c061aSmrg    Boolean cont_to_disp = True;
760444c061aSmrg    int i, numprocs;
761444c061aSmrg
762444c061aSmrg    /* Have to copy the procs into an array, because one of them might
763444c061aSmrg     * call XtRemoveEventHandler, which would break our linked list. */
764444c061aSmrg
765444c061aSmrg    numprocs = 0;
766a3bd7f05Smrg    for (p = widget->core.event_table; p; p = p->next) {
767a3bd7f05Smrg        if ((!p->has_type_specifier && (mask & p->mask)) ||
768a3bd7f05Smrg            (p->has_type_specifier && event->type == EXT_TYPE(p)))
769a3bd7f05Smrg            numprocs++;
770444c061aSmrg    }
771fdf6a26fSmrg    proc = XtMallocArray((Cardinal) numprocs, (Cardinal)
772fdf6a26fSmrg                         (sizeof(XtEventHandler) + sizeof(XtPointer)));
773a3bd7f05Smrg    closure = (XtPointer *) (proc + numprocs);
7740568f49bSmrg
775444c061aSmrg    numprocs = 0;
776a3bd7f05Smrg    for (p = widget->core.event_table; p; p = p->next) {
777a3bd7f05Smrg        if ((!p->has_type_specifier && (mask & p->mask)) ||
778a3bd7f05Smrg            (p->has_type_specifier && event->type == EXT_TYPE(p))) {
779a3bd7f05Smrg            proc[numprocs] = p->proc;
780a3bd7f05Smrg            closure[numprocs] = p->closure;
781a3bd7f05Smrg            numprocs++;
782a3bd7f05Smrg        }
783444c061aSmrg    }
784a3bd7f05Smrg    /* FUNCTIONS CALLED THROUGH POINTER proc:
785a3bd7f05Smrg       Selection.c:ReqCleanup,
786a3bd7f05Smrg       "Shell.c":EventHandler,
787a3bd7f05Smrg       PassivGrab.c:ActiveHandler,
788a3bd7f05Smrg       PassivGrab.c:RealizeHandler,
789a3bd7f05Smrg       Keyboard.c:QueryEventMask,
790a3bd7f05Smrg       _XtHandleFocus,
791a3bd7f05Smrg       Selection.c:HandleSelectionReplies,
792a3bd7f05Smrg       Selection.c:HandleGetIncrement,
793a3bd7f05Smrg       Selection.c:HandleIncremental,
794a3bd7f05Smrg       Selection.c:HandlePropertyGone,
795a3bd7f05Smrg       Selection.c:HandleSelectionEvents
796a3bd7f05Smrg     */
797444c061aSmrg    for (i = 0; i < numprocs && cont_to_disp; i++)
798a3bd7f05Smrg        (*(proc[i])) (widget, closure[i], event, &cont_to_disp);
799a3bd7f05Smrg    XtFree((char *) proc);
800444c061aSmrg    return cont_to_disp;
801444c061aSmrg}
802444c061aSmrg
803444c061aSmrgstatic void CompressExposures(XEvent *, Widget);
804444c061aSmrg
805444c061aSmrg#define KnownButtons (Button1MotionMask|Button2MotionMask|Button3MotionMask|\
806a3bd7f05Smrg                      Button4MotionMask|Button5MotionMask)
807444c061aSmrg
808444c061aSmrg/* keep this SMALL to avoid blowing stack cache! */
809444c061aSmrg/* because some compilers allocate all local locals on procedure entry */
810444c061aSmrg#define EHSIZE 4
811444c061aSmrg
812a3bd7f05SmrgBoolean
813a3bd7f05SmrgXtDispatchEventToWidget(Widget widget, XEvent *event)
814444c061aSmrg{
815444c061aSmrg    register XtEventRec *p;
816444c061aSmrg    Boolean was_dispatched = False;
817444c061aSmrg    Boolean call_tm = False;
818444c061aSmrg    Boolean cont_to_disp;
819444c061aSmrg    EventMask mask;
820a3bd7f05Smrg
821444c061aSmrg    WIDGET_TO_APPCON(widget);
822444c061aSmrg
823444c061aSmrg    LOCK_APP(app);
824444c061aSmrg
825444c061aSmrg    mask = _XtConvertTypeToMask(event->type);
826444c061aSmrg    if (event->type == MotionNotify)
827a3bd7f05Smrg        mask |= (event->xmotion.state & KnownButtons);
828444c061aSmrg
829444c061aSmrg    LOCK_PROCESS;
830a3bd7f05Smrg    if ((mask == ExposureMask) ||
831a3bd7f05Smrg        ((event->type == NoExpose) && NO_EXPOSE) ||
832a3bd7f05Smrg        ((event->type == GraphicsExpose) && GRAPHICS_EXPOSE)) {
833444c061aSmrg
834a3bd7f05Smrg        if (widget->core.widget_class->core_class.expose != NULL) {
835444c061aSmrg
836a3bd7f05Smrg            /* We need to mask off the bits that could contain the information
837a3bd7f05Smrg             * about whether or not we desire Graphics and NoExpose events.  */
838444c061aSmrg
839a3bd7f05Smrg            if ((COMP_EXPOSE_TYPE == XtExposeNoCompress) ||
840a3bd7f05Smrg                (event->type == NoExpose))
841444c061aSmrg
842a3bd7f05Smrg                (*widget->core.widget_class->core_class.expose)
843a3bd7f05Smrg                    (widget, event, (Region) NULL);
844a3bd7f05Smrg            else {
845a3bd7f05Smrg                CompressExposures(event, widget);
846a3bd7f05Smrg            }
847a3bd7f05Smrg            was_dispatched = True;
848a3bd7f05Smrg        }
849444c061aSmrg    }
850444c061aSmrg
851444c061aSmrg    if ((mask == VisibilityChangeMask) &&
852444c061aSmrg        XtClass(widget)->core_class.visible_interest) {
853a3bd7f05Smrg        was_dispatched = True;
854a3bd7f05Smrg        /* our visibility just changed... */
855a3bd7f05Smrg        switch (((XVisibilityEvent *) event)->state) {
856a3bd7f05Smrg        case VisibilityUnobscured:
857a3bd7f05Smrg            widget->core.visible = TRUE;
858a3bd7f05Smrg            break;
859a3bd7f05Smrg
860a3bd7f05Smrg        case VisibilityPartiallyObscured:
861a3bd7f05Smrg            /* what do we want to say here? */
862a3bd7f05Smrg            /* well... some of us is visible */
863a3bd7f05Smrg            widget->core.visible = TRUE;
864a3bd7f05Smrg            break;
865a3bd7f05Smrg
866a3bd7f05Smrg        case VisibilityFullyObscured:
867a3bd7f05Smrg            widget->core.visible = FALSE;
868a3bd7f05Smrg            /* do we want to mark our children obscured? */
869a3bd7f05Smrg            break;
870a3bd7f05Smrg        }
871a3bd7f05Smrg    }
872444c061aSmrg    UNLOCK_PROCESS;
873444c061aSmrg
874444c061aSmrg    /* to maintain "copy" semantics we check TM now but call later */
875444c061aSmrg    if (widget->core.tm.translations &&
876a3bd7f05Smrg        (mask & widget->core.tm.translations->eventMask))
877a3bd7f05Smrg        call_tm = True;
878444c061aSmrg
879444c061aSmrg    cont_to_disp = True;
880a3bd7f05Smrg    p = widget->core.event_table;
881444c061aSmrg    if (p) {
882a3bd7f05Smrg        if (p->next) {
883a3bd7f05Smrg            XtEventHandler proc[EHSIZE];
884a3bd7f05Smrg            XtPointer closure[EHSIZE];
885a3bd7f05Smrg            int numprocs = 0;
886a3bd7f05Smrg
887a3bd7f05Smrg            /* Have to copy the procs into an array, because one of them might
888a3bd7f05Smrg             * call XtRemoveEventHandler, which would break our linked list. */
889a3bd7f05Smrg
890a3bd7f05Smrg            for (; p; p = p->next) {
891a3bd7f05Smrg                if ((!p->has_type_specifier && (mask & p->mask)) ||
892a3bd7f05Smrg                    (p->has_type_specifier && event->type == EXT_TYPE(p))) {
893a3bd7f05Smrg                    if (numprocs >= EHSIZE)
894a3bd7f05Smrg                        break;
895a3bd7f05Smrg                    proc[numprocs] = p->proc;
896a3bd7f05Smrg                    closure[numprocs] = p->closure;
897a3bd7f05Smrg                    numprocs++;
898a3bd7f05Smrg                }
899a3bd7f05Smrg            }
900a3bd7f05Smrg            if (numprocs) {
901a3bd7f05Smrg                if (p) {
902a3bd7f05Smrg                    cont_to_disp = CallEventHandlers(widget, event, mask);
903a3bd7f05Smrg                }
904a3bd7f05Smrg                else {
905a3bd7f05Smrg                    int i;
906a3bd7f05Smrg
907a3bd7f05Smrg                    for (i = 0; i < numprocs && cont_to_disp; i++)
908a3bd7f05Smrg                        (*(proc[i])) (widget, closure[i], event, &cont_to_disp);
909a3bd7f05Smrg                    /* FUNCTIONS CALLED THROUGH POINTER proc:
910a3bd7f05Smrg                       Selection.c:ReqCleanup,
911a3bd7f05Smrg                       "Shell.c":EventHandler,
912a3bd7f05Smrg                       PassivGrab.c:ActiveHandler,
913a3bd7f05Smrg                       PassivGrab.c:RealizeHandler,
914a3bd7f05Smrg                       Keyboard.c:QueryEventMask,
915a3bd7f05Smrg                       _XtHandleFocus,
916a3bd7f05Smrg                       Selection.c:HandleSelectionReplies,
917a3bd7f05Smrg                       Selection.c:HandleGetIncrement,
918a3bd7f05Smrg                       Selection.c:HandleIncremental,
919a3bd7f05Smrg                       Selection.c:HandlePropertyGone,
920a3bd7f05Smrg                       Selection.c:HandleSelectionEvents
921a3bd7f05Smrg                     */
922a3bd7f05Smrg                }
923a3bd7f05Smrg                was_dispatched = True;
924a3bd7f05Smrg            }
925a3bd7f05Smrg        }
926a3bd7f05Smrg        else if ((!p->has_type_specifier && (mask & p->mask)) ||
927a3bd7f05Smrg                 (p->has_type_specifier && event->type == EXT_TYPE(p))) {
928a3bd7f05Smrg            (*p->proc) (widget, p->closure, event, &cont_to_disp);
929a3bd7f05Smrg            was_dispatched = True;
930a3bd7f05Smrg        }
931444c061aSmrg    }
932444c061aSmrg    if (call_tm && cont_to_disp)
933a3bd7f05Smrg        _XtTranslateEvent(widget, event);
934444c061aSmrg    UNLOCK_APP(app);
935a3bd7f05Smrg    return (was_dispatched | call_tm);
936444c061aSmrg}
937444c061aSmrg
938444c061aSmrg/*
939444c061aSmrg * This structure is passed into the check exposure proc.
940444c061aSmrg */
941444c061aSmrg
942444c061aSmrgtypedef struct _CheckExposeInfo {
943a3bd7f05Smrg    int type1, type2;           /* Types of events to check for. */
944a3bd7f05Smrg    Boolean maximal;            /* Ignore non-exposure events? */
945a3bd7f05Smrg    Boolean non_matching;       /* Was there an event that did not
946a3bd7f05Smrg                                   match either type? */
947a3bd7f05Smrg    Window window;              /* Window to match. */
948444c061aSmrg} CheckExposeInfo;
949444c061aSmrg
950444c061aSmrg#define GetCount(ev) (((XExposeEvent *)(ev))->count)
951444c061aSmrg
952444c061aSmrgstatic void SendExposureEvent(XEvent *, Widget, XtPerDisplay);
953444c061aSmrgstatic Bool CheckExposureEvent(Display *, XEvent *, char *);
954444c061aSmrgstatic void AddExposureToRectangularRegion(XEvent *, Region);
955444c061aSmrg
956a3bd7f05Smrg/*      Function Name: CompressExposures
957a3bd7f05Smrg *      Description: Handles all exposure compression
958a3bd7f05Smrg *      Arguments: event - the xevent that is to be dispatched
959fdf6a26fSmrg *                 widget - the widget that this event occurred in.
960a3bd7f05Smrg *      Returns: none.
961444c061aSmrg *
962444c061aSmrg *      NOTE: Event must be of type Expose or GraphicsExpose.
963444c061aSmrg */
964444c061aSmrg
965444c061aSmrgstatic void
966a3bd7f05SmrgCompressExposures(XEvent *event, Widget widget)
967444c061aSmrg{
968444c061aSmrg    CheckExposeInfo info;
969444c061aSmrg    int count;
970a3bd7f05Smrg    Display *dpy = XtDisplay(widget);
971444c061aSmrg    XtPerDisplay pd = _XtGetPerDisplay(dpy);
972444c061aSmrg    XtEnum comp_expose;
973444c061aSmrg    XtEnum comp_expose_type;
974444c061aSmrg    Boolean no_region;
975444c061aSmrg
976444c061aSmrg    LOCK_PROCESS;
977444c061aSmrg    comp_expose = COMP_EXPOSE;
978444c061aSmrg    UNLOCK_PROCESS;
979444c061aSmrg    comp_expose_type = comp_expose & 0x0f;
980444c061aSmrg    no_region = ((comp_expose & XtExposeNoRegion) ? True : False);
981444c061aSmrg
982444c061aSmrg    if (no_region)
983a3bd7f05Smrg        AddExposureToRectangularRegion(event, pd->region);
984444c061aSmrg    else
985a3bd7f05Smrg        XtAddExposureToRegion(event, pd->region);
986444c061aSmrg
987a3bd7f05Smrg    if (GetCount(event) != 0)
988a3bd7f05Smrg        return;
989444c061aSmrg
990444c061aSmrg    if ((comp_expose_type == XtExposeCompressSeries) ||
991a3bd7f05Smrg        (XEventsQueued(dpy, QueuedAfterReading) == 0)) {
992a3bd7f05Smrg        SendExposureEvent(event, widget, pd);
993a3bd7f05Smrg        return;
994444c061aSmrg    }
995444c061aSmrg
996444c061aSmrg    if (comp_expose & XtExposeGraphicsExposeMerged) {
997a3bd7f05Smrg        info.type1 = Expose;
998a3bd7f05Smrg        info.type2 = GraphicsExpose;
999444c061aSmrg    }
1000444c061aSmrg    else {
1001a3bd7f05Smrg        info.type1 = event->type;
1002a3bd7f05Smrg        info.type2 = 0;
1003444c061aSmrg    }
1004444c061aSmrg    info.maximal = (comp_expose_type == XtExposeCompressMaximal);
1005444c061aSmrg    info.non_matching = FALSE;
1006444c061aSmrg    info.window = XtWindow(widget);
1007444c061aSmrg
1008a3bd7f05Smrg    /*
1009a3bd7f05Smrg     * We have to be very careful here not to hose down the processor
1010a3bd7f05Smrg     * when blocking until count gets to zero.
1011a3bd7f05Smrg     *
1012a3bd7f05Smrg     * First, check to see if there are any events in the queue for this
1013a3bd7f05Smrg     * widget, and of the correct type.
1014a3bd7f05Smrg     *
1015a3bd7f05Smrg     * Once we cannot find any more events, check to see that count is zero.
1016a3bd7f05Smrg     * If it is not then block until we get another exposure event.
1017a3bd7f05Smrg     *
1018a3bd7f05Smrg     * If we find no more events, and count on the last one we saw was zero we
1019a3bd7f05Smrg     * we can be sure that all events have been processed.
1020a3bd7f05Smrg     *
1021a3bd7f05Smrg     * Unfortunately, we wind up having to look at the entire queue
1022a3bd7f05Smrg     * event if we're not doing Maximal compression, due to the
1023a3bd7f05Smrg     * semantics of XCheckIfEvent (we can't abort without re-ordering
1024a3bd7f05Smrg     * the event queue as a side-effect).
1025a3bd7f05Smrg     */
1026444c061aSmrg
1027444c061aSmrg    count = 0;
1028444c061aSmrg    while (TRUE) {
1029a3bd7f05Smrg        XEvent event_return;
1030a3bd7f05Smrg
1031a3bd7f05Smrg        if (XCheckIfEvent(dpy, &event_return,
1032a3bd7f05Smrg                          CheckExposureEvent, (char *) &info)) {
1033a3bd7f05Smrg
1034a3bd7f05Smrg            count = GetCount(&event_return);
1035a3bd7f05Smrg            if (no_region)
1036a3bd7f05Smrg                AddExposureToRectangularRegion(&event_return, pd->region);
1037a3bd7f05Smrg            else
1038a3bd7f05Smrg                XtAddExposureToRegion(&event_return, pd->region);
1039a3bd7f05Smrg        }
1040a3bd7f05Smrg        else if (count != 0) {
1041a3bd7f05Smrg            XIfEvent(dpy, &event_return, CheckExposureEvent, (char *) &info);
1042a3bd7f05Smrg            count = GetCount(&event_return);
1043a3bd7f05Smrg            if (no_region)
1044a3bd7f05Smrg                AddExposureToRectangularRegion(&event_return, pd->region);
1045a3bd7f05Smrg            else
1046a3bd7f05Smrg                XtAddExposureToRegion(&event_return, pd->region);
1047a3bd7f05Smrg        }
1048a3bd7f05Smrg        else                    /* count == 0 && XCheckIfEvent Failed. */
1049a3bd7f05Smrg            break;
1050444c061aSmrg    }
1051444c061aSmrg
1052444c061aSmrg    SendExposureEvent(event, widget, pd);
1053444c061aSmrg}
1054444c061aSmrg
1055a3bd7f05Smrgvoid
1056a3bd7f05SmrgXtAddExposureToRegion(XEvent *event, Region region)
1057444c061aSmrg{
1058444c061aSmrg    XRectangle rect;
1059444c061aSmrg    XExposeEvent *ev = (XExposeEvent *) event;
1060a3bd7f05Smrg
1061444c061aSmrg    /* These Expose and GraphicsExpose fields are at identical offsets */
1062444c061aSmrg
1063444c061aSmrg    if (event->type == Expose || event->type == GraphicsExpose) {
1064a3bd7f05Smrg        rect.x = (Position) ev->x;
1065a3bd7f05Smrg        rect.y = (Position) ev->y;
1066a3bd7f05Smrg        rect.width = (Dimension) ev->width;
1067a3bd7f05Smrg        rect.height = (Dimension) ev->height;
1068a3bd7f05Smrg        XUnionRectWithRegion(&rect, region, region);
1069444c061aSmrg    }
1070444c061aSmrg}
1071444c061aSmrg
1072444c061aSmrg#ifndef MAX
1073444c061aSmrg#define MAX(a,b) (((a) > (b)) ? (a) : (b))
1074444c061aSmrg#endif
1075444c061aSmrg
1076444c061aSmrg#ifndef MIN
1077444c061aSmrg#define MIN(a,b) (((a) < (b)) ? (a) : (b))
1078444c061aSmrg#endif
1079444c061aSmrg
1080a3bd7f05Smrgstatic void
1081a3bd7f05SmrgAddExposureToRectangularRegion(XEvent *event,   /* when called internally, type is always appropriate */
1082a3bd7f05Smrg                               Region region)
1083444c061aSmrg{
1084444c061aSmrg    XRectangle rect;
1085444c061aSmrg    XExposeEvent *ev = (XExposeEvent *) event;
1086a3bd7f05Smrg
1087444c061aSmrg    /* These Expose and GraphicsExpose fields are at identical offsets */
1088444c061aSmrg
10890568f49bSmrg    rect.x = (Position) ev->x;
10900568f49bSmrg    rect.y = (Position) ev->y;
10910568f49bSmrg    rect.width = (Dimension) ev->width;
10920568f49bSmrg    rect.height = (Dimension) ev->height;
1093444c061aSmrg
1094444c061aSmrg    if (XEmptyRegion(region)) {
1095a3bd7f05Smrg        XUnionRectWithRegion(&rect, region, region);
1096a3bd7f05Smrg    }
1097a3bd7f05Smrg    else {
1098a3bd7f05Smrg        XRectangle merged, bbox;
1099a3bd7f05Smrg
1100a3bd7f05Smrg        XClipBox(region, &bbox);
1101a3bd7f05Smrg        merged.x = MIN(rect.x, bbox.x);
1102a3bd7f05Smrg        merged.y = MIN(rect.y, bbox.y);
1103a3bd7f05Smrg        merged.width = (unsigned short) (MAX(rect.x + rect.width,
1104a3bd7f05Smrg                                             bbox.x + bbox.width) - merged.x);
1105a3bd7f05Smrg        merged.height = (unsigned short) (MAX(rect.y + rect.height,
1106a3bd7f05Smrg                                              bbox.y + bbox.height) - merged.y);
1107a3bd7f05Smrg        XUnionRectWithRegion(&merged, region, region);
1108444c061aSmrg    }
1109444c061aSmrg}
1110444c061aSmrg
1111444c061aSmrgstatic Region nullRegion;
1112a3bd7f05Smrg
1113444c061aSmrg/* READ-ONLY VARIABLES: nullRegion */
1114444c061aSmrg
1115a3bd7f05Smrgvoid
1116a3bd7f05Smrg_XtEventInitialize(void)
1117444c061aSmrg{
1118444c061aSmrg#ifndef __lock_lint
1119444c061aSmrg    nullRegion = XCreateRegion();
1120444c061aSmrg#endif
1121444c061aSmrg}
1122444c061aSmrg
1123a3bd7f05Smrg/*      Function Name: SendExposureEvent
1124a3bd7f05Smrg *      Description: Sets the x, y, width, and height of the event
1125444c061aSmrg *                   to be the clip box of Expose Region.
1126a3bd7f05Smrg *      Arguments: event  - the X Event to mangle; Expose or GraphicsExpose.
1127fdf6a26fSmrg *                 widget - the widget that this event occurred in.
1128444c061aSmrg *                 pd     - the per display information for this widget.
1129a3bd7f05Smrg *      Returns: none.
1130444c061aSmrg */
1131444c061aSmrg
1132444c061aSmrgstatic void
1133a3bd7f05SmrgSendExposureEvent(XEvent *event, Widget widget, XtPerDisplay pd)
1134444c061aSmrg{
1135444c061aSmrg    XtExposeProc expose;
1136444c061aSmrg    XRectangle rect;
1137444c061aSmrg    XtEnum comp_expose;
1138444c061aSmrg    XExposeEvent *ev = (XExposeEvent *) event;
1139444c061aSmrg
1140444c061aSmrg    XClipBox(pd->region, &rect);
1141444c061aSmrg    ev->x = rect.x;
1142444c061aSmrg    ev->y = rect.y;
1143444c061aSmrg    ev->width = rect.width;
1144444c061aSmrg    ev->height = rect.height;
1145444c061aSmrg
1146444c061aSmrg    LOCK_PROCESS;
1147444c061aSmrg    comp_expose = COMP_EXPOSE;
1148444c061aSmrg    expose = widget->core.widget_class->core_class.expose;
1149444c061aSmrg    UNLOCK_PROCESS;
1150444c061aSmrg    if (comp_expose & XtExposeNoRegion)
1151a3bd7f05Smrg        (*expose) (widget, event, NULL);
1152444c061aSmrg    else
1153a3bd7f05Smrg        (*expose) (widget, event, pd->region);
1154444c061aSmrg    (void) XIntersectRegion(nullRegion, pd->region, pd->region);
1155444c061aSmrg}
1156444c061aSmrg
1157a3bd7f05Smrg/*      Function Name: CheckExposureEvent
1158a3bd7f05Smrg *      Description: Checks the event queue for an expose event
1159a3bd7f05Smrg *      Arguments: display - the display connection.
1160444c061aSmrg *                 event - the event to check.
1161444c061aSmrg *                 arg - a pointer to the exposure info structure.
1162a3bd7f05Smrg *      Returns: TRUE if we found an event of the correct type
1163444c061aSmrg *               with the right window.
1164444c061aSmrg *
1165444c061aSmrg * NOTE: The only valid types (info.type1 and info.type2) are Expose
1166444c061aSmrg *       and GraphicsExpose.
1167444c061aSmrg */
1168444c061aSmrg
1169444c061aSmrgstatic Bool
1170a3bd7f05SmrgCheckExposureEvent(Display *disp _X_UNUSED, XEvent *event, char *arg)
1171444c061aSmrg{
1172a3bd7f05Smrg    CheckExposeInfo *info = ((CheckExposeInfo *) arg);
1173a3bd7f05Smrg
1174a3bd7f05Smrg    if ((info->type1 == event->type) || (info->type2 == event->type)) {
1175a3bd7f05Smrg        if (!info->maximal && info->non_matching)
1176a3bd7f05Smrg            return FALSE;
1177a3bd7f05Smrg        if (event->type == GraphicsExpose)
1178a3bd7f05Smrg            return (event->xgraphicsexpose.drawable == info->window);
1179a3bd7f05Smrg        return (event->xexpose.window == info->window);
1180444c061aSmrg    }
1181444c061aSmrg    info->non_matching = TRUE;
1182a3bd7f05Smrg    return (FALSE);
1183444c061aSmrg}
1184444c061aSmrg
1185444c061aSmrgstatic EventMask const masks[] = {
1186a3bd7f05Smrg    0,                          /* Error, should never see  */
1187a3bd7f05Smrg    0,                          /* Reply, should never see  */
1188a3bd7f05Smrg    KeyPressMask,               /* KeyPress                 */
1189a3bd7f05Smrg    KeyReleaseMask,             /* KeyRelease               */
1190a3bd7f05Smrg    ButtonPressMask,            /* ButtonPress              */
1191a3bd7f05Smrg    ButtonReleaseMask,          /* ButtonRelease            */
1192a3bd7f05Smrg    PointerMotionMask           /* MotionNotify             */
1193a3bd7f05Smrg        | ButtonMotionMask,
1194a3bd7f05Smrg    EnterWindowMask,            /* EnterNotify              */
1195a3bd7f05Smrg    LeaveWindowMask,            /* LeaveNotify              */
1196a3bd7f05Smrg    FocusChangeMask,            /* FocusIn                  */
1197a3bd7f05Smrg    FocusChangeMask,            /* FocusOut                 */
1198a3bd7f05Smrg    KeymapStateMask,            /* KeymapNotify             */
1199a3bd7f05Smrg    ExposureMask,               /* Expose                   */
1200a3bd7f05Smrg    NonMaskableMask,            /* GraphicsExpose, in GC    */
1201a3bd7f05Smrg    NonMaskableMask,            /* NoExpose, in GC          */
1202a3bd7f05Smrg    VisibilityChangeMask,       /* VisibilityNotify         */
1203a3bd7f05Smrg    SubstructureNotifyMask,     /* CreateNotify             */
1204a3bd7f05Smrg    StructureNotifyMask         /* DestroyNotify            */
1205a3bd7f05Smrg        | SubstructureNotifyMask,
1206a3bd7f05Smrg    StructureNotifyMask         /* UnmapNotify              */
1207a3bd7f05Smrg        | SubstructureNotifyMask,
1208a3bd7f05Smrg    StructureNotifyMask         /* MapNotify                */
1209a3bd7f05Smrg        | SubstructureNotifyMask,
1210a3bd7f05Smrg    SubstructureRedirectMask,   /* MapRequest               */
1211a3bd7f05Smrg    StructureNotifyMask         /* ReparentNotify           */
1212a3bd7f05Smrg        | SubstructureNotifyMask,
1213a3bd7f05Smrg    StructureNotifyMask         /* ConfigureNotify          */
1214a3bd7f05Smrg        | SubstructureNotifyMask,
1215a3bd7f05Smrg    SubstructureRedirectMask,   /* ConfigureRequest         */
1216a3bd7f05Smrg    StructureNotifyMask         /* GravityNotify            */
1217a3bd7f05Smrg        | SubstructureNotifyMask,
1218a3bd7f05Smrg    ResizeRedirectMask,         /* ResizeRequest            */
1219a3bd7f05Smrg    StructureNotifyMask         /* CirculateNotify          */
1220a3bd7f05Smrg        | SubstructureNotifyMask,
1221a3bd7f05Smrg    SubstructureRedirectMask,   /* CirculateRequest         */
1222a3bd7f05Smrg    PropertyChangeMask,         /* PropertyNotify           */
1223a3bd7f05Smrg    NonMaskableMask,            /* SelectionClear           */
1224a3bd7f05Smrg    NonMaskableMask,            /* SelectionRequest         */
1225a3bd7f05Smrg    NonMaskableMask,            /* SelectionNotify          */
1226a3bd7f05Smrg    ColormapChangeMask,         /* ColormapNotify           */
1227a3bd7f05Smrg    NonMaskableMask,            /* ClientMessage            */
1228a3bd7f05Smrg    NonMaskableMask             /* MappingNotify            */
1229444c061aSmrg};
1230444c061aSmrg
1231a3bd7f05SmrgEventMask
1232a3bd7f05Smrg_XtConvertTypeToMask(int eventType)
1233444c061aSmrg{
1234444c061aSmrg    if ((Cardinal) eventType < XtNumber(masks))
1235a3bd7f05Smrg        return masks[eventType];
1236444c061aSmrg    else
1237a3bd7f05Smrg        return NoEventMask;
1238444c061aSmrg}
1239444c061aSmrg
1240a3bd7f05SmrgBoolean
1241a3bd7f05Smrg_XtOnGrabList(register Widget widget, XtGrabRec *grabList)
1242444c061aSmrg{
1243a3bd7f05Smrg    register XtGrabRec *gl;
1244a3bd7f05Smrg
1245a3bd7f05Smrg    for (; widget != NULL; widget = (Widget) widget->core.parent) {
1246a3bd7f05Smrg        for (gl = grabList; gl != NULL; gl = gl->next) {
1247a3bd7f05Smrg            if (gl->widget == widget)
1248a3bd7f05Smrg                return TRUE;
1249a3bd7f05Smrg            if (gl->exclusive)
1250a3bd7f05Smrg                break;
1251a3bd7f05Smrg        }
1252444c061aSmrg    }
1253444c061aSmrg    return FALSE;
1254444c061aSmrg}
1255444c061aSmrg
1256a3bd7f05Smrgstatic Widget
1257a3bd7f05SmrgLookupSpringLoaded(XtGrabList grabList)
1258444c061aSmrg{
1259a3bd7f05Smrg    XtGrabList gl;
1260444c061aSmrg
1261444c061aSmrg    for (gl = grabList; gl != NULL; gl = gl->next) {
1262a3bd7f05Smrg        if (gl->spring_loaded) {
1263a3bd7f05Smrg            if (XtIsSensitive(gl->widget))
1264a3bd7f05Smrg                return gl->widget;
1265a3bd7f05Smrg            else
1266a3bd7f05Smrg                return NULL;
1267a3bd7f05Smrg        }
1268a3bd7f05Smrg        if (gl->exclusive)
1269a3bd7f05Smrg            break;
1270444c061aSmrg    }
1271444c061aSmrg    return NULL;
1272444c061aSmrg}
1273444c061aSmrg
1274a3bd7f05Smrgstatic Boolean
1275a3bd7f05SmrgDispatchEvent(XEvent *event, Widget widget)
1276444c061aSmrg{
1277444c061aSmrg
1278444c061aSmrg    if (event->type == EnterNotify &&
1279a3bd7f05Smrg        event->xcrossing.mode == NotifyNormal &&
1280a3bd7f05Smrg        widget->core.widget_class->core_class.compress_enterleave) {
1281a3bd7f05Smrg        if (XPending(event->xcrossing.display)) {
1282a3bd7f05Smrg            XEvent nextEvent;
1283a3bd7f05Smrg            XPeekEvent(event->xcrossing.display, &nextEvent);
1284a3bd7f05Smrg
1285a3bd7f05Smrg            if (nextEvent.type == LeaveNotify &&
1286a3bd7f05Smrg                event->xcrossing.window == nextEvent.xcrossing.window &&
1287a3bd7f05Smrg                nextEvent.xcrossing.mode == NotifyNormal &&
1288a3bd7f05Smrg                ((event->xcrossing.detail != NotifyInferior &&
1289a3bd7f05Smrg                  nextEvent.xcrossing.detail != NotifyInferior) ||
1290a3bd7f05Smrg                 (event->xcrossing.detail == NotifyInferior &&
1291a3bd7f05Smrg                  nextEvent.xcrossing.detail == NotifyInferior))) {
1292a3bd7f05Smrg                /* skip the enter/leave pair */
1293a3bd7f05Smrg                XNextEvent(event->xcrossing.display, &nextEvent);
1294a3bd7f05Smrg
1295a3bd7f05Smrg                return False;
1296a3bd7f05Smrg            }
1297a3bd7f05Smrg        }
1298444c061aSmrg    }
1299444c061aSmrg
1300444c061aSmrg    if (event->type == MotionNotify &&
1301a3bd7f05Smrg        widget->core.widget_class->core_class.compress_motion) {
1302a3bd7f05Smrg        while (XPending(event->xmotion.display)) {
1303a3bd7f05Smrg            XEvent nextEvent;
1304a3bd7f05Smrg            XPeekEvent(event->xmotion.display, &nextEvent);
1305a3bd7f05Smrg
1306a3bd7f05Smrg            if (nextEvent.type == MotionNotify &&
1307a3bd7f05Smrg                event->xmotion.window == nextEvent.xmotion.window &&
1308a3bd7f05Smrg                event->xmotion.subwindow == nextEvent.xmotion.subwindow) {
1309a3bd7f05Smrg                /* replace the current event with the next one */
1310a3bd7f05Smrg                XNextEvent(event->xmotion.display, event);
1311a3bd7f05Smrg            }
1312a3bd7f05Smrg            else
1313a3bd7f05Smrg                break;
1314a3bd7f05Smrg        }
1315444c061aSmrg    }
1316444c061aSmrg
1317444c061aSmrg    return XtDispatchEventToWidget(widget, event);
1318444c061aSmrg}
1319444c061aSmrg
1320a3bd7f05Smrgtypedef enum _GrabType { pass, ignore, remap } GrabType;
1321444c061aSmrg
132235525df4Smrgstatic Boolean
1323a3bd7f05Smrg_XtDefaultDispatcher(XEvent *event)
1324444c061aSmrg{
1325a3bd7f05Smrg    register Widget widget;
1326a3bd7f05Smrg    GrabType grabType;
1327444c061aSmrg    XtPerDisplayInput pdi;
1328a3bd7f05Smrg    XtGrabList grabList;
1329a3bd7f05Smrg    Boolean was_dispatched = False;
1330444c061aSmrg    DPY_TO_APPCON(event->xany.display);
1331444c061aSmrg
1332444c061aSmrg    /* the default dispatcher discards all extension events */
1333444c061aSmrg    if (event->type >= LASTEvent)
1334a3bd7f05Smrg        return False;
1335444c061aSmrg
1336444c061aSmrg    LOCK_APP(app);
1337444c061aSmrg
1338444c061aSmrg    switch (event->type) {
1339a3bd7f05Smrg    case KeyPress:
1340a3bd7f05Smrg    case KeyRelease:
1341a3bd7f05Smrg    case ButtonPress:
1342a3bd7f05Smrg    case ButtonRelease:
1343a3bd7f05Smrg        grabType = remap;
1344a3bd7f05Smrg        break;
1345a3bd7f05Smrg    case MotionNotify:
1346a3bd7f05Smrg    case EnterNotify:
1347a3bd7f05Smrg        grabType = ignore;
1348a3bd7f05Smrg        break;
1349a3bd7f05Smrg    default:
1350a3bd7f05Smrg        grabType = pass;
1351a3bd7f05Smrg        break;
1352444c061aSmrg    }
1353444c061aSmrg
1354a3bd7f05Smrg    widget = XtWindowToWidget(event->xany.display, event->xany.window);
1355444c061aSmrg    pdi = _XtGetPerDisplayInput(event->xany.display);
1356a3bd7f05Smrg
1357444c061aSmrg    grabList = *_XtGetGrabList(pdi);
1358444c061aSmrg
1359444c061aSmrg    if (widget == NULL) {
1360a3bd7f05Smrg        if (grabType == remap
1361a3bd7f05Smrg            && (widget = LookupSpringLoaded(grabList)) != NULL) {
1362a3bd7f05Smrg            /* event occurred in a non-widget window, but we've promised also
1363a3bd7f05Smrg               to dispatch it to the nearest accessible spring_loaded widget */
1364a3bd7f05Smrg            was_dispatched = (XFilterEvent(event, XtWindow(widget))
1365a3bd7f05Smrg                              || XtDispatchEventToWidget(widget, event));
1366a3bd7f05Smrg        }
1367a3bd7f05Smrg        else
1368a3bd7f05Smrg            was_dispatched = (Boolean) XFilterEvent(event, None);
1369444c061aSmrg    }
1370444c061aSmrg    else if (grabType == pass) {
1371a3bd7f05Smrg        if (event->type == LeaveNotify ||
1372a3bd7f05Smrg            event->type == FocusIn || event->type == FocusOut) {
1373a3bd7f05Smrg            if (XtIsSensitive(widget))
1374a3bd7f05Smrg                was_dispatched = (XFilterEvent(event, XtWindow(widget)) ||
1375a3bd7f05Smrg                                  XtDispatchEventToWidget(widget, event));
1376a3bd7f05Smrg        }
1377a3bd7f05Smrg        else
1378a3bd7f05Smrg            was_dispatched = (XFilterEvent(event, XtWindow(widget)) ||
1379a3bd7f05Smrg                              XtDispatchEventToWidget(widget, event));
1380444c061aSmrg    }
1381444c061aSmrg    else if (grabType == ignore) {
1382a3bd7f05Smrg        if ((grabList == NULL || _XtOnGrabList(widget, grabList))
1383a3bd7f05Smrg            && XtIsSensitive(widget)) {
1384a3bd7f05Smrg            was_dispatched = (XFilterEvent(event, XtWindow(widget))
1385a3bd7f05Smrg                              || DispatchEvent(event, widget));
1386a3bd7f05Smrg        }
1387444c061aSmrg    }
1388444c061aSmrg    else if (grabType == remap) {
1389a3bd7f05Smrg        EventMask mask = _XtConvertTypeToMask(event->type);
1390a3bd7f05Smrg        Widget dspWidget;
1391a3bd7f05Smrg        Boolean was_filtered = False;
1392a3bd7f05Smrg
1393a3bd7f05Smrg        dspWidget = _XtFindRemapWidget(event, widget, mask, pdi);
1394a3bd7f05Smrg
1395a3bd7f05Smrg        if ((grabList == NULL || _XtOnGrabList(dspWidget, grabList))
1396a3bd7f05Smrg            && XtIsSensitive(dspWidget)) {
1397a3bd7f05Smrg            if ((was_filtered =
1398a3bd7f05Smrg                 (Boolean) XFilterEvent(event, XtWindow(dspWidget)))) {
1399a3bd7f05Smrg                /* If this event activated a device grab, release it. */
1400a3bd7f05Smrg                _XtUngrabBadGrabs(event, widget, mask, pdi);
1401a3bd7f05Smrg                was_dispatched = True;
1402a3bd7f05Smrg            }
1403a3bd7f05Smrg            else
1404a3bd7f05Smrg                was_dispatched = XtDispatchEventToWidget(dspWidget, event);
1405a3bd7f05Smrg        }
1406a3bd7f05Smrg        else
1407a3bd7f05Smrg            _XtUngrabBadGrabs(event, widget, mask, pdi);
1408a3bd7f05Smrg
1409a3bd7f05Smrg        if (!was_filtered) {
1410a3bd7f05Smrg            /* Also dispatch to nearest accessible spring_loaded. */
1411a3bd7f05Smrg            /* Fetch this afterward to reflect modal list changes */
1412a3bd7f05Smrg            grabList = *_XtGetGrabList(pdi);
1413a3bd7f05Smrg            widget = LookupSpringLoaded(grabList);
1414a3bd7f05Smrg            if (widget != NULL && widget != dspWidget) {
1415a3bd7f05Smrg                was_dispatched = (XFilterEvent(event, XtWindow(widget))
1416a3bd7f05Smrg                                  || XtDispatchEventToWidget(widget, event)
1417a3bd7f05Smrg                                  || was_dispatched);
1418a3bd7f05Smrg            }
1419a3bd7f05Smrg        }
1420444c061aSmrg    }
1421444c061aSmrg    UNLOCK_APP(app);
1422444c061aSmrg    return was_dispatched;
1423444c061aSmrg}
1424444c061aSmrg
1425a3bd7f05SmrgBoolean
1426a3bd7f05SmrgXtDispatchEvent(XEvent *event)
1427444c061aSmrg{
1428444c061aSmrg    Boolean was_dispatched, safe;
1429444c061aSmrg    int dispatch_level;
1430444c061aSmrg    int starting_count;
1431444c061aSmrg    XtPerDisplay pd;
1432a3bd7f05Smrg    Time time = 0;
1433444c061aSmrg    XtEventDispatchProc dispatch = _XtDefaultDispatcher;
1434444c061aSmrg    XtAppContext app = XtDisplayToApplicationContext(event->xany.display);
1435444c061aSmrg
1436444c061aSmrg    LOCK_APP(app);
1437444c061aSmrg    dispatch_level = ++app->dispatch_level;
1438444c061aSmrg    starting_count = app->destroy_count;
1439444c061aSmrg
1440444c061aSmrg    switch (event->type) {
1441a3bd7f05Smrg    case KeyPress:
1442a3bd7f05Smrg    case KeyRelease:
1443a3bd7f05Smrg        time = event->xkey.time;
1444a3bd7f05Smrg        break;
1445a3bd7f05Smrg    case ButtonPress:
1446a3bd7f05Smrg    case ButtonRelease:
1447a3bd7f05Smrg        time = event->xbutton.time;
1448a3bd7f05Smrg        break;
1449a3bd7f05Smrg    case MotionNotify:
1450a3bd7f05Smrg        time = event->xmotion.time;
1451a3bd7f05Smrg        break;
1452a3bd7f05Smrg    case EnterNotify:
1453a3bd7f05Smrg    case LeaveNotify:
1454a3bd7f05Smrg        time = event->xcrossing.time;
1455a3bd7f05Smrg        break;
1456a3bd7f05Smrg    case PropertyNotify:
1457a3bd7f05Smrg        time = event->xproperty.time;
1458a3bd7f05Smrg        break;
1459a3bd7f05Smrg    case SelectionClear:
1460a3bd7f05Smrg        time = event->xselectionclear.time;
1461a3bd7f05Smrg        break;
1462a3bd7f05Smrg
1463a3bd7f05Smrg    case MappingNotify:
1464a3bd7f05Smrg        _XtRefreshMapping(event, True);
1465a3bd7f05Smrg        break;
1466444c061aSmrg    }
1467444c061aSmrg    pd = _XtGetPerDisplay(event->xany.display);
1468a3bd7f05Smrg
1469a3bd7f05Smrg    if (time)
1470a3bd7f05Smrg        pd->last_timestamp = time;
1471444c061aSmrg    pd->last_event = *event;
1472444c061aSmrg
1473444c061aSmrg    if (pd->dispatcher_list) {
1474a3bd7f05Smrg        dispatch = pd->dispatcher_list[event->type];
1475a3bd7f05Smrg        if (dispatch == NULL)
1476a3bd7f05Smrg            dispatch = _XtDefaultDispatcher;
1477444c061aSmrg    }
1478a3bd7f05Smrg    was_dispatched = (*dispatch) (event);
1479444c061aSmrg
1480444c061aSmrg    /*
1481444c061aSmrg     * To make recursive XtDispatchEvent work, we need to do phase 2 destroys
1482444c061aSmrg     * only on those widgets destroyed by this particular dispatch.
1483444c061aSmrg     *
1484444c061aSmrg     */
1485444c061aSmrg
1486444c061aSmrg    if (app->destroy_count > starting_count)
1487a3bd7f05Smrg        _XtDoPhase2Destroy(app, dispatch_level);
1488444c061aSmrg
1489444c061aSmrg    app->dispatch_level = dispatch_level - 1;
1490444c061aSmrg
1491444c061aSmrg    if ((safe = _XtSafeToDestroy(app))) {
1492a3bd7f05Smrg        if (app->dpy_destroy_count != 0)
1493a3bd7f05Smrg            _XtCloseDisplays(app);
1494a3bd7f05Smrg        if (app->free_bindings)
1495a3bd7f05Smrg            _XtDoFreeBindings(app);
1496444c061aSmrg    }
1497444c061aSmrg    UNLOCK_APP(app);
1498444c061aSmrg    LOCK_PROCESS;
1499a3bd7f05Smrg    if (_XtAppDestroyCount != 0 && safe)
1500a3bd7f05Smrg        _XtDestroyAppContexts();
1501444c061aSmrg    UNLOCK_PROCESS;
1502444c061aSmrg    return was_dispatched;
1503444c061aSmrg}
1504444c061aSmrg
1505a3bd7f05Smrgstatic void
1506a3bd7f05SmrgGrabDestroyCallback(Widget widget,
1507a3bd7f05Smrg                    XtPointer closure _X_UNUSED,
1508a3bd7f05Smrg                    XtPointer call_data _X_UNUSED)
1509444c061aSmrg{
1510444c061aSmrg    /* Remove widget from grab list if it destroyed */
1511444c061aSmrg    XtRemoveGrab(widget);
1512444c061aSmrg}
1513444c061aSmrg
1514a3bd7f05Smrgstatic XtGrabRec *
1515a3bd7f05SmrgNewGrabRec(Widget widget, Boolean exclusive, Boolean spring_loaded)
1516444c061aSmrg{
1517a3bd7f05Smrg    register XtGrabList gl;
1518444c061aSmrg
1519a3bd7f05Smrg    gl = XtNew(XtGrabRec);
1520a3bd7f05Smrg    gl->next = NULL;
1521a3bd7f05Smrg    gl->widget = widget;
1522a3bd7f05Smrg    XtSetBit(gl->exclusive, exclusive);
15230568f49bSmrg    XtSetBit(gl->spring_loaded, spring_loaded);
1524444c061aSmrg
1525444c061aSmrg    return gl;
1526444c061aSmrg}
1527444c061aSmrg
1528a3bd7f05Smrgvoid
1529a3bd7f05SmrgXtAddGrab(Widget widget, _XtBoolean exclusive, _XtBoolean spring_loaded)
1530444c061aSmrg{
1531a3bd7f05Smrg    register XtGrabList gl;
1532a3bd7f05Smrg    XtGrabList *grabListPtr;
1533444c061aSmrg    XtAppContext app = XtWidgetToApplicationContext(widget);
1534444c061aSmrg
1535444c061aSmrg    LOCK_APP(app);
1536444c061aSmrg    LOCK_PROCESS;
1537444c061aSmrg    grabListPtr = _XtGetGrabList(_XtGetPerDisplayInput(XtDisplay(widget)));
1538444c061aSmrg
1539444c061aSmrg    if (spring_loaded && !exclusive) {
1540a3bd7f05Smrg        XtAppWarningMsg(app,
1541a3bd7f05Smrg                        "grabError", "xtAddGrab", XtCXtToolkitError,
1542a3bd7f05Smrg                        "XtAddGrab requires exclusive grab if spring_loaded is TRUE",
1543a3bd7f05Smrg                        NULL, NULL);
1544a3bd7f05Smrg        exclusive = TRUE;
1545444c061aSmrg    }
1546444c061aSmrg
15470568f49bSmrg    gl = NewGrabRec(widget, (Boolean) exclusive, (Boolean) spring_loaded);
1548444c061aSmrg    gl->next = *grabListPtr;
1549444c061aSmrg    *grabListPtr = gl;
1550444c061aSmrg
1551a3bd7f05Smrg    XtAddCallback(widget, XtNdestroyCallback,
1552a3bd7f05Smrg                  GrabDestroyCallback, (XtPointer) NULL);
1553444c061aSmrg    UNLOCK_PROCESS;
1554444c061aSmrg    UNLOCK_APP(app);
1555444c061aSmrg}
1556444c061aSmrg
1557a3bd7f05Smrgvoid
1558a3bd7f05SmrgXtRemoveGrab(Widget widget)
1559444c061aSmrg{
1560444c061aSmrg    register XtGrabList gl;
1561444c061aSmrg    register Boolean done;
1562a3bd7f05Smrg    XtGrabList *grabListPtr;
1563444c061aSmrg    XtAppContext app = XtWidgetToApplicationContext(widget);
1564444c061aSmrg
1565444c061aSmrg    LOCK_APP(app);
1566444c061aSmrg    LOCK_PROCESS;
1567444c061aSmrg
1568444c061aSmrg    grabListPtr = _XtGetGrabList(_XtGetPerDisplayInput(XtDisplay(widget)));
1569444c061aSmrg
1570444c061aSmrg    for (gl = *grabListPtr; gl != NULL; gl = gl->next) {
1571a3bd7f05Smrg        if (gl->widget == widget)
1572a3bd7f05Smrg            break;
1573444c061aSmrg    }
1574444c061aSmrg
1575444c061aSmrg    if (gl == NULL) {
1576a3bd7f05Smrg        XtAppWarningMsg(app,
1577a3bd7f05Smrg                        "grabError", "xtRemoveGrab", XtCXtToolkitError,
1578a3bd7f05Smrg                        "XtRemoveGrab asked to remove a widget not on the list",
1579a3bd7f05Smrg                        NULL, NULL);
1580a3bd7f05Smrg        UNLOCK_PROCESS;
1581a3bd7f05Smrg        UNLOCK_APP(app);
1582a3bd7f05Smrg        return;
1583a3bd7f05Smrg    }
1584444c061aSmrg
1585444c061aSmrg    do {
1586a3bd7f05Smrg        gl = *grabListPtr;
1587a3bd7f05Smrg        done = (gl->widget == widget);
1588a3bd7f05Smrg        *grabListPtr = gl->next;
1589a3bd7f05Smrg        XtRemoveCallback(gl->widget, XtNdestroyCallback,
1590a3bd7f05Smrg                         GrabDestroyCallback, (XtPointer) NULL);
1591a3bd7f05Smrg        XtFree((char *) gl);
1592a3bd7f05Smrg    } while (!done);
1593444c061aSmrg    UNLOCK_PROCESS;
1594444c061aSmrg    UNLOCK_APP(app);
1595444c061aSmrg    return;
1596444c061aSmrg}
1597444c061aSmrg
1598a3bd7f05Smrgvoid
1599a3bd7f05SmrgXtMainLoop(void)
1600444c061aSmrg{
1601a3bd7f05Smrg    XtAppMainLoop(_XtDefaultAppContext());
1602444c061aSmrg}
1603444c061aSmrg
1604a3bd7f05Smrgvoid
1605a3bd7f05SmrgXtAppMainLoop(XtAppContext app)
1606444c061aSmrg{
16070568f49bSmrg    XtInputMask m = XtIMAll;
16080568f49bSmrg    XtInputMask t;
1609a3bd7f05Smrg
1610444c061aSmrg    LOCK_APP(app);
1611444c061aSmrg    do {
1612a3bd7f05Smrg        if (m == 0) {
1613a3bd7f05Smrg            m = XtIMAll;
1614a3bd7f05Smrg            /* wait for any event, blocking */
1615a3bd7f05Smrg            XtAppProcessEvent(app, m);
1616a3bd7f05Smrg        }
1617a3bd7f05Smrg        else if (((t = XtAppPending(app)) & m)) {
1618a3bd7f05Smrg            /* wait for certain events, stepping through choices */
1619a3bd7f05Smrg            XtAppProcessEvent(app, t & m);
1620a3bd7f05Smrg        }
1621a3bd7f05Smrg        m >>= 1;
1622a3bd7f05Smrg    } while (app->exit_flag == FALSE);
1623444c061aSmrg    UNLOCK_APP(app);
1624444c061aSmrg}
1625444c061aSmrg
1626a3bd7f05Smrgvoid
1627a3bd7f05Smrg_XtFreeEventTable(XtEventTable *event_table)
1628444c061aSmrg{
1629444c061aSmrg    register XtEventTable event;
1630444c061aSmrg
1631444c061aSmrg    event = *event_table;
1632444c061aSmrg    while (event != NULL) {
1633a3bd7f05Smrg        register XtEventTable next = event->next;
1634a3bd7f05Smrg
1635a3bd7f05Smrg        XtFree((char *) event);
1636a3bd7f05Smrg        event = next;
1637444c061aSmrg    }
1638444c061aSmrg}
1639444c061aSmrg
1640a3bd7f05SmrgTime
1641a3bd7f05SmrgXtLastTimestampProcessed(Display *dpy)
1642444c061aSmrg{
1643444c061aSmrg    Time time;
1644a3bd7f05Smrg
1645444c061aSmrg    DPY_TO_APPCON(dpy);
1646444c061aSmrg
1647444c061aSmrg    LOCK_APP(app);
1648444c061aSmrg    LOCK_PROCESS;
1649a3bd7f05Smrg    time = _XtGetPerDisplay(dpy)->last_timestamp;
1650444c061aSmrg    UNLOCK_PROCESS;
1651444c061aSmrg    UNLOCK_APP(app);
1652a3bd7f05Smrg    return (time);
1653444c061aSmrg}
1654444c061aSmrg
1655a3bd7f05SmrgXEvent *
1656a3bd7f05SmrgXtLastEventProcessed(Display *dpy)
1657444c061aSmrg{
1658a3bd7f05Smrg    XEvent *le = NULL;
1659a3bd7f05Smrg
1660444c061aSmrg    DPY_TO_APPCON(dpy);
1661444c061aSmrg
1662444c061aSmrg    LOCK_APP(app);
1663444c061aSmrg    le = &_XtGetPerDisplay(dpy)->last_event;
1664444c061aSmrg    if (!le->xany.serial)
1665a3bd7f05Smrg        le = NULL;
1666444c061aSmrg    UNLOCK_APP(app);
1667444c061aSmrg    return le;
1668444c061aSmrg}
1669444c061aSmrg
1670a3bd7f05Smrgvoid
1671a3bd7f05Smrg_XtSendFocusEvent(Widget child, int type)
1672444c061aSmrg{
1673444c061aSmrg    child = XtIsWidget(child) ? child : _XtWindowedAncestor(child);
1674444c061aSmrg    if (XtIsSensitive(child) && !child->core.being_destroyed
1675a3bd7f05Smrg        && XtIsRealized(child)
1676a3bd7f05Smrg        && (XtBuildEventMask(child) & FocusChangeMask)) {
1677a3bd7f05Smrg        XFocusChangeEvent event;
1678a3bd7f05Smrg        Display *dpy = XtDisplay(child);
1679a3bd7f05Smrg
1680a3bd7f05Smrg        event.type = type;
1681a3bd7f05Smrg        event.serial = LastKnownRequestProcessed(dpy);
1682a3bd7f05Smrg        event.send_event = True;
1683a3bd7f05Smrg        event.display = dpy;
1684a3bd7f05Smrg
1685a3bd7f05Smrg        event.window = XtWindow(child);
1686a3bd7f05Smrg        event.mode = NotifyNormal;
1687a3bd7f05Smrg        event.detail = NotifyAncestor;
1688a3bd7f05Smrg        if (XFilterEvent((XEvent *) &event, XtWindow(child)))
1689a3bd7f05Smrg            return;
1690a3bd7f05Smrg        XtDispatchEventToWidget(child, (XEvent *) &event);
1691444c061aSmrg    }
1692444c061aSmrg}
1693444c061aSmrg
1694a3bd7f05Smrgstatic XtEventDispatchProc *
1695a3bd7f05SmrgNewDispatcherList(void)
1696444c061aSmrg{
1697a3bd7f05Smrg    XtEventDispatchProc *l = (XtEventDispatchProc *)
1698a3bd7f05Smrg        __XtCalloc((Cardinal) 128,
1699a3bd7f05Smrg                   (Cardinal)
1700a3bd7f05Smrg                   sizeof(XtEventDispatchProc));
1701a3bd7f05Smrg
1702444c061aSmrg    return l;
1703444c061aSmrg}
1704444c061aSmrg
1705a3bd7f05SmrgXtEventDispatchProc
1706a3bd7f05SmrgXtSetEventDispatcher(Display *dpy,
1707a3bd7f05Smrg                     int event_type,
1708a3bd7f05Smrg                     XtEventDispatchProc proc)
1709444c061aSmrg{
1710444c061aSmrg    XtEventDispatchProc *list;
1711444c061aSmrg    XtEventDispatchProc old_proc;
1712444c061aSmrg    register XtPerDisplay pd;
1713a3bd7f05Smrg
1714444c061aSmrg    DPY_TO_APPCON(dpy);
1715444c061aSmrg
1716444c061aSmrg    LOCK_APP(app);
1717444c061aSmrg    LOCK_PROCESS;
1718444c061aSmrg    pd = _XtGetPerDisplay(dpy);
1719444c061aSmrg
1720444c061aSmrg    list = pd->dispatcher_list;
1721444c061aSmrg    if (!list) {
1722a3bd7f05Smrg        if (proc)
1723a3bd7f05Smrg            list = pd->dispatcher_list = NewDispatcherList();
1724a3bd7f05Smrg        else
1725a3bd7f05Smrg            return _XtDefaultDispatcher;
1726444c061aSmrg    }
1727444c061aSmrg    old_proc = list[event_type];
1728444c061aSmrg    list[event_type] = proc;
1729a3bd7f05Smrg    if (old_proc == NULL)
1730a3bd7f05Smrg        old_proc = _XtDefaultDispatcher;
1731444c061aSmrg    UNLOCK_PROCESS;
1732444c061aSmrg    UNLOCK_APP(app);
1733444c061aSmrg    return old_proc;
1734444c061aSmrg}
1735444c061aSmrg
1736a3bd7f05Smrgvoid
1737a3bd7f05SmrgXtRegisterExtensionSelector(Display *dpy,
1738a3bd7f05Smrg                            int min_event_type,
1739a3bd7f05Smrg                            int max_event_type,
1740a3bd7f05Smrg                            XtExtensionSelectProc proc,
1741a3bd7f05Smrg                            XtPointer client_data)
1742444c061aSmrg{
1743444c061aSmrg    XtPerDisplay pd;
1744444c061aSmrg    int i;
1745a3bd7f05Smrg
1746444c061aSmrg    DPY_TO_APPCON(dpy);
1747444c061aSmrg
1748a3bd7f05Smrg    if (dpy == NULL)
1749a3bd7f05Smrg        XtErrorMsg("nullDisplay",
1750a3bd7f05Smrg                   "xtRegisterExtensionSelector", XtCXtToolkitError,
1751a3bd7f05Smrg                   "XtRegisterExtensionSelector requires a non-NULL display",
1752a3bd7f05Smrg                   NULL, NULL);
1753444c061aSmrg
1754444c061aSmrg    LOCK_APP(app);
1755444c061aSmrg    LOCK_PROCESS;
1756444c061aSmrg    pd = _XtGetPerDisplay(dpy);
1757444c061aSmrg
1758444c061aSmrg    for (i = 0; i < pd->ext_select_count; i++) {
17590568f49bSmrg        ExtSelectRec *e = &pd->ext_select_list[i];
1760a3bd7f05Smrg
1761a3bd7f05Smrg        if (e->min == min_event_type && e->max == max_event_type) {
1762a3bd7f05Smrg            e->proc = proc;
1763a3bd7f05Smrg            e->client_data = client_data;
1764a3bd7f05Smrg            return;
1765a3bd7f05Smrg        }
1766a3bd7f05Smrg        if ((min_event_type >= e->min && min_event_type <= e->max) ||
1767a3bd7f05Smrg            (max_event_type >= e->min && max_event_type <= e->max)) {
1768a3bd7f05Smrg            XtErrorMsg("rangeError", "xtRegisterExtensionSelector",
1769a3bd7f05Smrg                       XtCXtToolkitError,
1770a3bd7f05Smrg                       "Attempt to register multiple selectors for one extension event type",
1771a3bd7f05Smrg                       NULL, NULL);
1772a3bd7f05Smrg            UNLOCK_PROCESS;
1773a3bd7f05Smrg            UNLOCK_APP(app);
1774a3bd7f05Smrg            return;
1775a3bd7f05Smrg        }
1776444c061aSmrg    }
1777444c061aSmrg    pd->ext_select_count++;
1778fdf6a26fSmrg    pd->ext_select_list = XtReallocArray(pd->ext_select_list,
1779fdf6a26fSmrg                                         (Cardinal) pd->ext_select_count,
1780fdf6a26fSmrg                                         (Cardinal) sizeof(ExtSelectRec));
1781444c061aSmrg    for (i = pd->ext_select_count - 1; i > 0; i--) {
1782a3bd7f05Smrg        if (pd->ext_select_list[i - 1].min > min_event_type) {
1783a3bd7f05Smrg            pd->ext_select_list[i] = pd->ext_select_list[i - 1];
1784a3bd7f05Smrg        }
1785a3bd7f05Smrg        else
1786a3bd7f05Smrg            break;
1787444c061aSmrg    }
1788444c061aSmrg    pd->ext_select_list[i].min = min_event_type;
1789444c061aSmrg    pd->ext_select_list[i].max = max_event_type;
1790444c061aSmrg    pd->ext_select_list[i].proc = proc;
1791444c061aSmrg    pd->ext_select_list[i].client_data = client_data;
1792444c061aSmrg    UNLOCK_PROCESS;
1793444c061aSmrg    UNLOCK_APP(app);
1794444c061aSmrg}
1795444c061aSmrg
1796a3bd7f05Smrgvoid
1797a3bd7f05Smrg_XtExtensionSelect(Widget widget)
1798444c061aSmrg{
1799444c061aSmrg    int i;
1800444c061aSmrg    XtPerDisplay pd;
1801a3bd7f05Smrg
1802444c061aSmrg    WIDGET_TO_APPCON(widget);
1803444c061aSmrg
1804444c061aSmrg    LOCK_APP(app);
1805444c061aSmrg    LOCK_PROCESS;
1806444c061aSmrg
1807444c061aSmrg    pd = _XtGetPerDisplay(XtDisplay(widget));
1808444c061aSmrg
1809444c061aSmrg    for (i = 0; i < pd->ext_select_count; i++) {
1810a3bd7f05Smrg        CallExtensionSelector(widget, pd->ext_select_list + i, FALSE);
1811444c061aSmrg    }
1812444c061aSmrg    UNLOCK_PROCESS;
1813444c061aSmrg    UNLOCK_APP(app);
1814444c061aSmrg}
1815