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