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