home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / lib / Xt / Event.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-21  |  34.4 KB  |  1,285 lines

  1. /* $XConsortium: Event.c,v 1.137 92/11/19 17:24:47 converse Exp $ */
  2.  
  3. /***********************************************************
  4. Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
  5. and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
  6.  
  7.                         All Rights Reserved
  8.  
  9. Permission to use, copy, modify, and distribute this software and its 
  10. documentation for any purpose and without fee is hereby granted, 
  11. provided that the above copyright notice appear in all copies and that
  12. both that copyright notice and this permission notice appear in 
  13. supporting documentation, and that the names of Digital or MIT not be
  14. used in advertising or publicity pertaining to distribution of the
  15. software without specific, written prior permission.  
  16.  
  17. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  18. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  19. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  20. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  22. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  23. SOFTWARE.
  24.  
  25. ******************************************************************/
  26.  
  27. #include "IntrinsicI.h"
  28. #include "Shell.h"
  29. #include "StringDefs.h"
  30.  
  31. #if __STDC__
  32. #define Const const
  33. #else
  34. #define Const /**/
  35. #endif
  36.  
  37. #define NonMaskableMask ((EventMask)0x80000000L)
  38.  
  39. /*
  40.  * These are definitions to make the code that handles exposure compresssion
  41.  * easier to read.
  42.  *
  43.  * COMP_EXPOSE      - The compression exposure field of "widget"
  44.  * COMP_EXPOSE_TYPE - The type of compression (lower 4 bits of COMP_EXPOSE.
  45.  * GRAPHICS_EXPOSE  - TRUE if the widget wants graphics expose events
  46.  *                    dispatched.
  47.  * NO_EXPOSE        - TRUE if the widget wants No expose events dispatched.
  48.  */
  49.  
  50. #define COMP_EXPOSE   (widget->core.widget_class->core_class.compress_exposure)
  51. #define COMP_EXPOSE_TYPE (COMP_EXPOSE & 0x0f)
  52. #define GRAPHICS_EXPOSE  ((XtExposeGraphicsExpose & COMP_EXPOSE) || \
  53.               (XtExposeGraphicsExposeMerged & COMP_EXPOSE))
  54. #define NO_EXPOSE        (XtExposeNoExpose & COMP_EXPOSE)
  55.  
  56. EventMask XtBuildEventMask(widget)
  57.     Widget widget;
  58. {
  59.     XtEventTable ev;
  60.     EventMask    mask = 0L;
  61.  
  62.     for (ev = widget->core.event_table; ev != NULL; ev = ev->next)
  63.     if (ev->select) mask |= ev->mask;
  64.     if (widget->core.widget_class->core_class.expose != NULL)
  65.     mask |= ExposureMask;
  66.     if (widget->core.widget_class->core_class.visible_interest) 
  67.     mask |= VisibilityChangeMask;
  68.     if (widget->core.tm.translations)
  69.     mask |= widget->core.tm.translations->eventMask;
  70.  
  71.     return mask & ~NonMaskableMask;
  72. }
  73.  
  74. static void
  75. RemoveEventHandler(widget, eventMask, other, proc, closure, raw)
  76. Widget            widget;
  77. EventMask       eventMask;
  78. Boolean            other;
  79. XtEventHandler  proc;
  80. XtPointer    closure;
  81. Boolean            raw;
  82. {
  83.     XtEventRec *p, **pp;
  84.     EventMask oldMask = XtBuildEventMask(widget);
  85.  
  86.     if (raw) raw = 1;
  87.     pp = &widget->core.event_table;
  88.     while ((p = *pp) &&
  89.        (p->proc != proc || p->closure != closure || p->select == raw))
  90.     pp = &p->next;
  91.     if (!p) return;
  92.  
  93.     /* un-register it */
  94.     eventMask &= ~NonMaskableMask;
  95.     if (other)
  96.     eventMask |= NonMaskableMask;
  97.     p->mask &= ~eventMask;
  98.  
  99.     if (!p->mask) {        /* delete it entirely */
  100.         *pp = p->next;
  101.     XtFree((char *)p);    
  102.     }
  103.  
  104.     /* Reset select mask if realized and not raw. */
  105.     if ( !raw && XtIsRealized(widget) && !widget->core.being_destroyed) {
  106.     EventMask mask = XtBuildEventMask(widget);
  107.  
  108.     if (oldMask != mask) 
  109.         XSelectInput(XtDisplay(widget), XtWindow(widget), mask);
  110.     }
  111. }
  112.  
  113. /*    Function Name: AddEventHandler
  114.  *    Description: An Internal routine that does the actual work of
  115.  *                   adding the event handlers.
  116.  *    Arguments: widget - widget to register an event handler for.
  117.  *                 eventMask - events to mask for.
  118.  *                 other - pass non maskable events to this proceedure.
  119.  *                 proc - proceedure to register.
  120.  *                 closure - data to pass to the event hander.
  121.  *                 position - where to add this event handler.
  122.  *                 force_new_position - If the element is already in the
  123.  *                                      list, this will force it to the 
  124.  *                                      beginning or end depending on position.
  125.  *                 raw - If FALSE call XSelectInput for events in mask.
  126.  *    Returns: none
  127.  */
  128.  
  129. static void 
  130. AddEventHandler(widget, eventMask, other, proc, 
  131.         closure, position, force_new_position, raw)
  132. Widget            widget;
  133. EventMask       eventMask;
  134. Boolean         other, force_new_position, raw;
  135. XtEventHandler  proc;
  136. XtPointer    closure;
  137. XtListPosition  position;
  138. {
  139.     register XtEventRec *p, **pp;
  140.     EventMask oldMask;
  141.     
  142.     eventMask &= ~NonMaskableMask;
  143.     if (other)
  144.     eventMask |= NonMaskableMask;
  145.     if (!eventMask) return;
  146.     
  147.     if (XtIsRealized(widget) && !raw) oldMask = XtBuildEventMask(widget);
  148.     
  149.     if (raw) raw = 1;
  150.     pp = &widget->core.event_table;
  151.     while ((p = *pp) &&
  152.        (p->proc != proc || p->closure != closure || p->select == raw))
  153.     pp = &p->next;
  154.  
  155.     if (!p) {                        /* New proc to add to list */
  156.     p = XtNew(XtEventRec);
  157.     p->proc = proc;
  158.     p->closure = closure;
  159.     p->mask = eventMask;
  160.     p->select = ! raw;
  161.     
  162.     if (position == XtListHead) {
  163.         p->next = widget->core.event_table;
  164.         widget->core.event_table = p;
  165.     } else {
  166.         *pp = p;
  167.         p->next = NULL;
  168.     }
  169.     } 
  170.     else {
  171.     if (force_new_position) {
  172.         *pp = p->next;
  173.  
  174.         if (position == XtListHead) {
  175.         p->next = widget->core.event_table;
  176.         widget->core.event_table = p;
  177.         } else {
  178.                /*
  179.          * Find the last element in the list.
  180.          */
  181.         while (*pp)
  182.             pp = &(*pp)->next;
  183.         *pp = p;
  184.         p->next = NULL;
  185.         }
  186.     }
  187.  
  188.     /* update existing proc */
  189.     p->mask |= eventMask;
  190.     }
  191.  
  192.     if (XtIsRealized(widget) && !raw) {
  193.     EventMask mask = XtBuildEventMask(widget);
  194.  
  195.     if (oldMask != mask) 
  196.         XSelectInput(XtDisplay(widget), XtWindow(widget), mask);
  197.     }
  198.  
  199. }
  200.  
  201. #if NeedFunctionPrototypes
  202. void XtRemoveEventHandler(
  203.     Widget        widget,
  204.     EventMask       eventMask,
  205.     _XtBoolean        other,
  206.     XtEventHandler  proc,
  207.     XtPointer        closure
  208.     )
  209. #else
  210. void XtRemoveEventHandler(widget, eventMask, other, proc, closure)
  211.     Widget        widget;
  212.     EventMask       eventMask;
  213.     Boolean        other;
  214.     XtEventHandler  proc;
  215.     XtPointer        closure;
  216. #endif
  217. {
  218.     RemoveEventHandler(widget, eventMask, other, proc, closure, FALSE);
  219. }
  220.  
  221. #if NeedFunctionPrototypes
  222. void XtAddEventHandler(
  223.     Widget        widget,
  224.     EventMask       eventMask,
  225.     _XtBoolean      other,
  226.     XtEventHandler  proc,
  227.     XtPointer        closure
  228.     )
  229. #else
  230. void XtAddEventHandler(widget, eventMask, other, proc, closure)
  231.     Widget        widget;
  232.     EventMask       eventMask;
  233.     Boolean         other;
  234.     XtEventHandler  proc;
  235.     XtPointer        closure;
  236. #endif
  237. {
  238.     AddEventHandler(widget, eventMask, other, 
  239.             proc, closure, XtListTail, FALSE, FALSE);
  240. }
  241.  
  242. #if NeedFunctionPrototypes
  243. void XtInsertEventHandler(
  244.     Widget        widget,
  245.     EventMask       eventMask,
  246.     _XtBoolean      other,
  247.     XtEventHandler  proc,
  248.     XtPointer        closure,
  249.     XtListPosition  position
  250.     )
  251. #else
  252. void XtInsertEventHandler(widget, eventMask, other, proc, closure, position)
  253.     Widget        widget;
  254.     EventMask       eventMask;
  255.     Boolean         other;
  256.     XtEventHandler  proc;
  257.     XtPointer        closure;
  258.     XtListPosition  position;
  259. #endif
  260. {
  261.     AddEventHandler(widget, eventMask, other, 
  262.             proc, closure, position, TRUE, FALSE);
  263. }
  264.  
  265. #if NeedFunctionPrototypes
  266. void XtRemoveRawEventHandler(
  267.     Widget        widget,
  268.     EventMask       eventMask,
  269.     _XtBoolean        other,
  270.     XtEventHandler  proc,
  271.     XtPointer        closure
  272.     )
  273. #else
  274. void XtRemoveRawEventHandler(widget, eventMask, other, proc, closure)
  275.     Widget        widget;
  276.     EventMask       eventMask;
  277.     Boolean        other;
  278.     XtEventHandler  proc;
  279.     XtPointer        closure;
  280. #endif
  281. {
  282.     RemoveEventHandler(widget, eventMask, other, proc, closure, TRUE);
  283. }
  284.  
  285. #if NeedFunctionPrototypes
  286. void XtInsertRawEventHandler(
  287.     Widget        widget,
  288.     EventMask       eventMask,
  289.     _XtBoolean        other,
  290.     XtEventHandler  proc,
  291.     XtPointer        closure,
  292.     XtListPosition  position
  293.     )
  294. #else
  295. void XtInsertRawEventHandler(widget, eventMask, other, proc, closure, position)
  296.     Widget        widget;
  297.     EventMask       eventMask;
  298.     Boolean        other;
  299.     XtEventHandler  proc;
  300.     XtPointer        closure;
  301.     XtListPosition  position;
  302. #endif
  303. {
  304.     AddEventHandler(widget, eventMask, other, 
  305.             proc, closure, position, TRUE, TRUE);
  306. }
  307.  
  308. #if NeedFunctionPrototypes
  309. void XtAddRawEventHandler(
  310.     Widget        widget,
  311.     EventMask       eventMask,
  312.     _XtBoolean      other,
  313.     XtEventHandler  proc,
  314.     XtPointer        closure
  315.     )
  316. #else
  317. void XtAddRawEventHandler(widget, eventMask, other, proc, closure)
  318.     Widget        widget;
  319.     EventMask       eventMask;
  320.     Boolean         other;
  321.     XtEventHandler  proc;
  322.     XtPointer        closure;
  323. #endif
  324. {
  325.     AddEventHandler(widget, eventMask, other, 
  326.             proc, closure, XtListTail, FALSE, TRUE);
  327. }
  328.  
  329. typedef struct _WWPair {
  330.     struct _WWPair *next;
  331.     Window window;
  332.     Widget widget;
  333. } *WWPair;
  334.  
  335. typedef struct _WWTable {
  336.     unsigned int mask;        /* size of hash table - 1 */
  337.     unsigned int rehash;    /* mask - 2 */
  338.     unsigned int occupied;    /* number of occupied entries */
  339.     unsigned int fakes;        /* number occupied by WWfake */
  340.     Widget *entries;        /* the entries */
  341.     WWPair pairs;        /* bogus entries */
  342. } *WWTable;
  343.  
  344. static Const WidgetRec WWfake;    /* placeholder for deletions */
  345.  
  346. #define WWHASH(tab,win) ((win) & tab->mask)
  347. #define WWREHASHVAL(tab,win) ((((win) % tab->rehash) + 2) | 1)
  348. #define WWREHASH(tab,idx,rehash) ((idx + rehash) & tab->mask)
  349. #define WWTABLE(display) (_XtGetPerDisplay(display)->WWtable)
  350.  
  351. static void ExpandWWTable();
  352.  
  353. void _XtRegisterWindow(window, widget)
  354.     register Window window;
  355.     register Widget widget;
  356. {
  357.     register WWTable tab;
  358.     register int idx, rehash;
  359.     register Widget entry;
  360.  
  361.     tab = WWTABLE(XtDisplay(widget));
  362.     if (window != XtWindow(widget)) {
  363.     WWPair pair;
  364.     pair = XtNew(struct _WWPair);
  365.     pair->next = tab->pairs;
  366.     pair->window = window;
  367.     pair->widget = widget;
  368.     tab->pairs = pair;
  369.     return;
  370.     }
  371.     if ((tab->occupied + (tab->occupied >> 2)) > tab->mask)
  372.     ExpandWWTable(tab);
  373.  
  374.     idx = WWHASH(tab, window);
  375.     if ((entry = tab->entries[idx]) && entry != &WWfake) {
  376.     rehash = WWREHASHVAL(tab, window);
  377.     do {
  378.         idx = WWREHASH(tab, idx, rehash);
  379.     } while ((entry = tab->entries[idx]) && entry != &WWfake);
  380.     }
  381.     if (!entry)
  382.     tab->occupied++;
  383.     else if (entry == &WWfake)
  384.     tab->fakes--;
  385.     tab->entries[idx] = widget;
  386. }
  387.  
  388. void _XtUnregisterWindow(window, widget)
  389.     register Window window;
  390.     register Widget widget;
  391. {
  392.     register WWTable tab;
  393.     register int idx, rehash;
  394.     register Widget entry;
  395.  
  396.     tab = WWTABLE(XtDisplay(widget));
  397.     if (window != XtWindow(widget)) {
  398.     WWPair *prev, pair;
  399.  
  400.     prev = &tab->pairs;
  401.     while ((pair = *prev) && pair->window != window)
  402.         prev = &pair->next;
  403.     if (pair) {
  404.         *prev = pair->next;
  405.         XtFree((char *)pair);
  406.     }
  407.     return;
  408.     }
  409.     idx = WWHASH(tab, window);
  410.     if (entry = tab->entries[idx]) {
  411.     if (entry != widget) {
  412.         rehash = WWREHASHVAL(tab, window);
  413.         do {
  414.         idx = WWREHASH(tab, idx, rehash);
  415.         if (!(entry = tab->entries[idx]))
  416.             return;
  417.         } while (entry != widget);
  418.     }
  419.     tab->entries[idx] = (Widget)&WWfake;
  420.     tab->fakes++;
  421.     }
  422. }
  423.  
  424. static void ExpandWWTable(tab)
  425.     register WWTable tab;
  426. {
  427.     unsigned int oldmask;
  428.     register Widget *oldentries, *entries;
  429.     register int oldidx, newidx, rehash;
  430.     register Widget entry;
  431.  
  432.     oldmask = tab->mask;
  433.     oldentries = tab->entries;
  434.     tab->occupied -= tab->fakes;
  435.     tab->fakes = 0;
  436.     if ((tab->occupied + (tab->occupied >> 2)) > tab->mask) {
  437.     tab->mask = (tab->mask << 1) + 1;
  438.     tab->rehash = tab->mask - 2;
  439.     }
  440.     entries = tab->entries = (Widget *) XtCalloc(tab->mask+1, sizeof(Widget));
  441.     for (oldidx = 0; oldidx <= oldmask; oldidx++) {
  442.     if ((entry = oldentries[oldidx]) && entry != &WWfake) {
  443.         newidx = WWHASH(tab, XtWindow(entry));
  444.         if (entries[newidx]) {
  445.         rehash = WWREHASHVAL(tab, XtWindow(entry));
  446.         do {
  447.             newidx = WWREHASH(tab, newidx, rehash);
  448.         } while (entries[newidx]);
  449.         }
  450.         entries[newidx] = entry;
  451.     }
  452.     }
  453.     XtFree((char *)oldentries);
  454. }
  455.  
  456. Widget XtWindowToWidget(display, window)
  457.     register Display *display;
  458.     register Window window;
  459. {
  460.     register WWTable tab;
  461.     register int idx, rehash;
  462.     register Widget entry;
  463.     WWPair pair;
  464.  
  465.     if (!window) return NULL;
  466.     tab = WWTABLE(display);
  467.     idx = WWHASH(tab, window);
  468.     if ((entry = tab->entries[idx]) && XtWindow(entry) != window) {
  469.     rehash = WWREHASHVAL(tab, window);
  470.     do {
  471.         idx = WWREHASH(tab, idx, rehash);
  472.     } while ((entry = tab->entries[idx]) && XtWindow(entry) != window);
  473.     }
  474.     if (entry)
  475.     return entry;
  476.     for (pair = tab->pairs; pair; pair = pair->next) {
  477.     if (pair->window == window)
  478.         return pair->widget;
  479.     }
  480.     return NULL;
  481. }
  482.  
  483. void _XtAllocWWTable(pd)
  484.     XtPerDisplay pd;
  485. {
  486.     register WWTable tab;
  487.  
  488.     tab = (WWTable) XtMalloc(sizeof(struct _WWTable));
  489.     tab->mask = 0x7f;
  490.     tab->rehash = tab->mask - 2;
  491.     tab->entries = (Widget *) XtCalloc(tab->mask+1, sizeof(Widget));
  492.     tab->occupied = 0;
  493.     tab->fakes = 0;
  494.     tab->pairs = NULL;
  495.     pd->WWtable = tab;
  496. }
  497.  
  498. void _XtFreeWWTable(pd)
  499.     register XtPerDisplay pd;
  500. {
  501.     register WWPair pair, next;
  502.  
  503.     for (pair = pd->WWtable->pairs; pair; pair = next) {
  504.     next = pair->next;
  505.     XtFree((char *)pair);
  506.     }
  507.     XtFree((char *)pd->WWtable->entries);
  508.     XtFree((char *)pd->WWtable);
  509. }
  510.  
  511. #define EHMAXSIZE 25 /* do not make whopping big */
  512.  
  513. static Boolean CallEventHandlers(widget, event, mask)
  514.     Widget     widget;
  515.     XEvent    *event;
  516.     EventMask  mask;
  517. {
  518.     register XtEventRec *p;   
  519.     XtEventHandler *proc;
  520.     XtPointer *closure;
  521.     XtEventHandler procs[EHMAXSIZE];
  522.     XtPointer closures[EHMAXSIZE];
  523.     Boolean cont_to_disp = True;
  524.     int i, numprocs;
  525.  
  526.     /* Have to copy the procs into an array, because one of them might
  527.      * call XtRemoveEventHandler, which would break our linked list. */
  528.  
  529.     numprocs = 0;
  530.     for (p=widget->core.event_table; p; p = p->next) {
  531.     if (mask & p->mask)
  532.         numprocs++;
  533.     }
  534.     if (numprocs > EHMAXSIZE) {
  535.     proc = (XtEventHandler *)XtMalloc(numprocs * (sizeof(XtEventHandler) +
  536.                               sizeof(XtPointer)));
  537.     closure = (XtPointer *)(proc + numprocs);
  538.     } else {
  539.     proc = procs;
  540.     closure = closures;
  541.     }
  542.     numprocs = 0;
  543.     for (p=widget->core.event_table; p; p = p->next) {
  544.     if (mask & p->mask) {
  545.         proc[numprocs] = p->proc;
  546.         closure[numprocs] = p->closure;
  547.         numprocs++;
  548.     }
  549.     }
  550.     for (i = 0; i < numprocs && cont_to_disp; i++)
  551.     (*(proc[i]))(widget, closure[i], event, &cont_to_disp);
  552.     if (numprocs > EHMAXSIZE)
  553.     XtFree((char *)proc);
  554.     return cont_to_disp;
  555. }
  556.  
  557. static Region nullRegion;
  558. static void CompressExposures();
  559.  
  560. /* keep this SMALL to avoid blowing stack cache! */
  561. /* because some compilers allocate all local locals on procedure entry */
  562. #define EHSIZE 4
  563.  
  564. #define XtDidNothing    False
  565. #define XtDidDispatch    True
  566. #define XtDidFilter    2
  567.  
  568. static Boolean DispatchEvent(event, widget, mask, pd)
  569.     register XEvent    *event;
  570.     Widget    widget;
  571.     EventMask mask;
  572.     XtPerDisplay pd;
  573. {
  574.     register XtEventRec *p;   
  575.     XEvent nextEvent;
  576.     Boolean was_dispatched = XtDidNothing;
  577.     Boolean call_tm = XtDidNothing;
  578.     Boolean cont_to_disp;
  579.  
  580.     if (XFilterEvent(event, XtWindow(widget)))
  581.     return XtDidFilter;
  582.     
  583.     if ( (mask == ExposureMask) ||
  584.      ((event->type == NoExpose) && NO_EXPOSE) ||
  585.      ((event->type == GraphicsExpose) && GRAPHICS_EXPOSE) ) {
  586.  
  587.     if (widget->core.widget_class->core_class.expose != NULL ) {
  588.  
  589.         /* We need to mask off the bits that could contain the information
  590.          * about whether or not we desire Graphics and NoExpose events.  */
  591.  
  592.         if ( (COMP_EXPOSE_TYPE == XtExposeNoCompress) || 
  593.          (event->type == NoExpose) )
  594.  
  595.         (*widget->core.widget_class->core_class.expose)
  596.             (widget, event, (Region)NULL);
  597.         else {
  598.         CompressExposures(event, widget, pd);
  599.         }
  600.         was_dispatched = XtDidDispatch;
  601.     }
  602.     }
  603.  
  604.     if (mask == EnterWindowMask &&
  605.         widget->core.widget_class->core_class.compress_enterleave) {
  606.     if (XPending(event->xcrossing.display)) {
  607.         XPeekEvent(event->xcrossing.display, &nextEvent);
  608.         if (nextEvent.type == LeaveNotify &&
  609.           event->xcrossing.window == nextEvent.xcrossing.window &&
  610.         (event->xcrossing.detail != NotifyInferior &&
  611.          nextEvent.xcrossing.detail != NotifyInferior ||
  612.          event->xcrossing.detail == NotifyInferior &&
  613.          nextEvent.xcrossing.detail == NotifyInferior)) {
  614.         /* skip the enter/leave pair */
  615.         XNextEvent(event->xcrossing.display, &nextEvent);
  616.         return XtDidNothing;
  617.         }
  618.     }
  619.     }
  620.  
  621.     if (event->type == MotionNotify &&
  622.         widget->core.widget_class->core_class.compress_motion) {
  623.     while (XPending(event->xmotion.display)) {
  624.         XPeekEvent(event->xmotion.display, &nextEvent);
  625.         if (nextEvent.type == MotionNotify &&
  626.             event->xmotion.window == nextEvent.xmotion.window &&
  627.             event->xmotion.subwindow == nextEvent.xmotion.subwindow) {
  628.         /* replace the current event with the next one */
  629.         XNextEvent(event->xmotion.display, event);
  630.         } else break;
  631.     }
  632.     }
  633.  
  634.     if ((mask == VisibilityChangeMask) &&
  635.         XtClass(widget)->core_class.visible_interest) {
  636.         was_dispatched = XtDidDispatch;
  637.         /* our visibility just changed... */
  638.         switch (((XVisibilityEvent *)event)->state) {
  639.         case VisibilityUnobscured:
  640.             widget->core.visible = TRUE;
  641.             break;
  642.  
  643.         case VisibilityPartiallyObscured:
  644.             /* what do we want to say here? */
  645.             /* well... some of us is visible */
  646.             widget->core.visible = TRUE;
  647.             break;
  648.  
  649.         case VisibilityFullyObscured:
  650.             widget->core.visible = FALSE;
  651.             /* do we want to mark our children obscured? */
  652.             break;
  653.         }
  654.     }
  655.  
  656.     /* to maintain "copy" semantics we check TM now but call later */
  657.     if (widget->core.tm.translations &&
  658.     (mask & widget->core.tm.translations->eventMask))
  659.     call_tm = XtDidDispatch;
  660.  
  661.     cont_to_disp = True;
  662.     p=widget->core.event_table;
  663.     if (p) {
  664.     if (p->next) {
  665.         XtEventHandler proc[EHSIZE];
  666.         XtPointer closure[EHSIZE];
  667.         int numprocs = 0;
  668.  
  669.         /* Have to copy the procs into an array, because one of them might
  670.          * call XtRemoveEventHandler, which would break our linked list. */
  671.  
  672.         for (; p; p = p->next) {
  673.         if (mask & p->mask) {
  674.             if (numprocs >= EHSIZE)
  675.             break;
  676.             proc[numprocs] = p->proc;
  677.             closure[numprocs] = p->closure;
  678.             numprocs++;
  679.         }
  680.         }
  681.         if (numprocs) {
  682.         if (p) {
  683.             cont_to_disp = CallEventHandlers(widget, event, mask);
  684.         } else {
  685.             int i;
  686.             for (i = 0; i < numprocs && cont_to_disp; i++)
  687.             (*(proc[i]))(widget, closure[i], event, &cont_to_disp);
  688.         }
  689.         was_dispatched = XtDidDispatch;
  690.         }
  691.     } else if (mask & p->mask) {
  692.         (*p->proc)(widget, p->closure, event, &cont_to_disp);
  693.         was_dispatched = XtDidDispatch;
  694.     }
  695.     }
  696.     if (call_tm && cont_to_disp)
  697.     _XtTranslateEvent(widget, event);
  698.     return (was_dispatched|call_tm);
  699. }
  700.  
  701. /*
  702.  * This structure is passed into the check exposure proc.
  703.  */
  704.  
  705. typedef struct _CheckExposeInfo {
  706.     int type1, type2;        /* Types of events to check for. */
  707.     Boolean maximal;        /* Ignore non-exposure events? */
  708.     Boolean non_matching;    /* Was there an event that did not 
  709.                    match eighter type? */
  710.     Window window;        /* Window to match. */
  711. } CheckExposeInfo;
  712.  
  713. #define GetCount(ev) ( ((ev)->type == GraphicsExpose) ? \
  714.                (ev)->xgraphicsexpose.count : (ev)->xexpose.count)
  715.  
  716. /*    Function Name: CompressExposures
  717.  *    Description: Handles all exposure compression
  718.  *    Arguments: event - the xevent that is to be dispatched
  719.  *                 widget - the widget that this event occured in.
  720.  *    Returns: none.
  721.  *
  722.  *      NOTE: Event must be of type Expose or GraphicsExpose.
  723.  */
  724.  
  725. static void SendExposureEvent();
  726. static Bool CheckExposureEvent();
  727.  
  728. static void
  729. CompressExposures(event, widget, pd)
  730. Widget widget;
  731. XEvent * event;
  732. XtPerDisplay pd;
  733. {
  734.     CheckExposeInfo info;
  735.     int count;
  736.  
  737.     XtAddExposureToRegion(event, pd->region);
  738.  
  739.     if ( GetCount(event) != 0 )
  740.     return;
  741.  
  742.     if ( (COMP_EXPOSE_TYPE == XtExposeCompressSeries) ||
  743.      (XEventsQueued(XtDisplay(widget), QueuedAfterReading) == 0) ) {
  744.     SendExposureEvent(event, widget, pd);
  745.     return;
  746.     }
  747.  
  748.     if (COMP_EXPOSE & XtExposeGraphicsExposeMerged) {
  749.     info.type1 = Expose;
  750.     info.type2 = GraphicsExpose;
  751.     }
  752.     else {
  753.     info.type1 = event->type;
  754.     info.type2 = 0;
  755.     }
  756.     info.maximal =(COMP_EXPOSE_TYPE == XtExposeCompressMaximal) ? True : False;
  757.     info.non_matching = FALSE;
  758.     info.window = XtWindow(widget);
  759.  
  760. /*
  761.  * We have to be very careful here not to hose down the processor
  762.  * when blocking until count gets to zero.
  763.  *
  764.  * First, check to see if there are any events in the queue for this
  765.  * widget, and of the correct type.
  766.  *
  767.  * Once we cannot find any more events, check to see that count is zero. 
  768.  * If it is not then block until we get another exposure event.
  769.  *
  770.  * If we find no more events, and count on the last one we saw was zero we
  771.  * we can be sure that all events have been processed.
  772.  *
  773.  * Unfortunately, we wind up having to look at the entire queue
  774.  * event if we're not doing Maximal compression, due to the
  775.  * semantics of XCheckIfEvent (we can't abort without re-ordering
  776.  * the event queue as a side-effect).
  777.  */
  778.  
  779.     count = 0;
  780.     while (TRUE) {
  781.     XEvent event_return;
  782.  
  783.     if (XCheckIfEvent(XtDisplay(widget), &event_return, 
  784.               CheckExposureEvent, (char *) &info)) {
  785.  
  786.         count = GetCount(&event_return);
  787.         XtAddExposureToRegion(&event_return, pd->region);
  788.     }
  789.     else if (count != 0) {
  790.         XIfEvent(XtDisplay(widget), &event_return,
  791.              CheckExposureEvent, (char *) &info);
  792.         count = GetCount(&event_return);
  793.         XtAddExposureToRegion(&event_return, pd->region);
  794.     }
  795.     else /* count == 0 && XCheckIfEvent Failed. */
  796.         break;
  797.     }
  798.  
  799.     SendExposureEvent(event, widget, pd);
  800. }
  801.  
  802. /*    Function Name: SendExposureEvent
  803.  *    Description: Sets the x, y, width, and height of the event
  804.  *                   to be the clip box of Expose Region.
  805.  *    Arguments: event  - the X Event to mangle; Expose or GraphicsExpose.
  806.  *                 widget - the widget that this event occured in.
  807.  *                 pd     - the per display information for this widget.
  808.  *    Returns: none.
  809.  */
  810.  
  811. static void
  812. SendExposureEvent(event, widget, pd)
  813. XEvent * event;
  814. Widget widget;
  815. XtPerDisplay pd;
  816. {
  817.     XtExposeProc expose = widget->core.widget_class->core_class.expose;
  818.     XRectangle rect;
  819.  
  820.     XClipBox(pd->region, &rect);
  821.     if (event->type == Expose) {
  822.     event->xexpose.x = rect.x;
  823.     event->xexpose.y = rect.y;
  824.     event->xexpose.width = rect.width;
  825.     event->xexpose.height = rect.height;
  826.     }
  827.     else {            /* Graphics Expose Event. */
  828.     event->xgraphicsexpose.x = rect.x;
  829.     event->xgraphicsexpose.y = rect.y;
  830.     event->xgraphicsexpose.width = rect.width;
  831.     event->xgraphicsexpose.height = rect.height;
  832.     }
  833.     (*expose)(widget, event, pd->region);
  834.     (void) XIntersectRegion(nullRegion, pd->region, pd->region);
  835. }
  836.  
  837. /*    Function Name: CheckExposureEvent
  838.  *    Description: Checks the event cue for an expose event
  839.  *    Arguments: display - the display connection.
  840.  *                 event - the event to check.
  841.  *                 arg - a pointer to the exposure info structure.
  842.  *    Returns: TRUE if we found an event of the correct type
  843.  *               with the right window.
  844.  *
  845.  * NOTE: The only valid types (info.type1 and info.type2) are Expose
  846.  *       and GraphicsExpose.
  847.  */
  848.  
  849. /* ARGSUSED */
  850. static Bool
  851. CheckExposureEvent(disp, event, arg)
  852. Display * disp;
  853. XEvent * event;
  854. char * arg;
  855. {
  856.     CheckExposeInfo * info = ((CheckExposeInfo *) arg);
  857.  
  858.     if ( (info->type1 == event->type) || (info->type2 == event->type)) {
  859.     if (!info->maximal && info->non_matching) return FALSE;
  860.     if (event->type == GraphicsExpose)
  861.         return(event->xgraphicsexpose.drawable == info->window);
  862.     return(event->xexpose.window == info->window);
  863.     }
  864.     info->non_matching = TRUE;
  865.     return(FALSE);
  866. }
  867.  
  868. static EventMask Const masks[] = {
  869.     0,                /* Error, should never see  */
  870.     0,                /* Reply, should never see  */
  871.     KeyPressMask,            /* KeyPress            */
  872.     KeyReleaseMask,            /* KeyRelease        */
  873.     ButtonPressMask,        /* ButtonPress        */
  874.     ButtonReleaseMask,        /* ButtonRelease        */
  875.     PointerMotionMask        /* MotionNotify        */
  876.         | ButtonMotionMask,
  877.     EnterWindowMask,        /* EnterNotify        */
  878.     LeaveWindowMask,        /* LeaveNotify        */
  879.     FocusChangeMask,        /* FocusIn            */
  880.     FocusChangeMask,        /* FocusOut            */
  881.     KeymapStateMask,        /* KeymapNotify        */
  882.     ExposureMask,            /* Expose            */
  883.     NonMaskableMask,        /* GraphicsExpose, in GC    */
  884.     NonMaskableMask,        /* NoExpose, in GC        */
  885.     VisibilityChangeMask,       /* VisibilityNotify        */
  886.     SubstructureNotifyMask,     /* CreateNotify        */
  887.     StructureNotifyMask        /* DestroyNotify        */
  888.         | SubstructureNotifyMask,
  889.     StructureNotifyMask        /* UnmapNotify        */
  890.         | SubstructureNotifyMask,
  891.     StructureNotifyMask        /* MapNotify        */
  892.         | SubstructureNotifyMask,
  893.     SubstructureRedirectMask,   /* MapRequest        */
  894.     StructureNotifyMask        /* ReparentNotify        */
  895.         | SubstructureNotifyMask,
  896.     StructureNotifyMask        /* ConfigureNotify        */
  897.         | SubstructureNotifyMask,
  898.     SubstructureRedirectMask,   /* ConfigureRequest        */
  899.     StructureNotifyMask        /* GravityNotify        */
  900.         | SubstructureNotifyMask,
  901.     ResizeRedirectMask,        /* ResizeRequest        */
  902.     StructureNotifyMask        /* CirculateNotify        */
  903.         | SubstructureNotifyMask,
  904.     SubstructureRedirectMask,   /* CirculateRequest        */
  905.     PropertyChangeMask,        /* PropertyNotify        */
  906.     NonMaskableMask,        /* SelectionClear        */
  907.     NonMaskableMask,        /* SelectionRequest        */
  908.     NonMaskableMask,        /* SelectionNotify        */
  909.     ColormapChangeMask,        /* ColormapNotify        */
  910.     NonMaskableMask,        /* ClientMessage        */
  911.     NonMaskableMask            /* MappingNotify        */
  912. };
  913.  
  914. EventMask _XtConvertTypeToMask (eventType)
  915.     int        eventType;
  916. {
  917.     eventType &= 0x7f;    /* Events sent with XSendEvent have high bit set. */
  918.     if (eventType < XtNumber(masks))
  919.     return masks[eventType];
  920.     else
  921.     return 0;
  922. }
  923.  
  924. Boolean _XtOnGrabList(widget, grabList)
  925.     register Widget widget;
  926.     XtGrabRec  *grabList;
  927. {
  928.     register XtGrabRec* gl;
  929.     for (; widget != NULL; widget = (Widget)widget->core.parent) {
  930.     for (gl = grabList; gl != NULL; gl = gl->next) {
  931.         if (gl->widget == widget) return TRUE;
  932.         if (gl->exclusive) break;
  933.     }
  934.     }
  935.     return FALSE;
  936. }
  937.  
  938. static Widget LookupSpringLoaded(grabList)
  939.     XtGrabList    grabList;
  940. {
  941.     XtGrabList    gl;
  942.  
  943.     for (gl = grabList; gl != NULL; gl = gl->next) {
  944.     if (gl->spring_loaded)
  945.       if (XtIsSensitive(gl->widget))
  946.         return gl->widget;
  947.       else
  948.         return NULL;
  949.     if (gl->exclusive) break;
  950.     }
  951.     return NULL;
  952. }
  953.  
  954. typedef enum _GrabType {pass, ignore, remap} GrabType;
  955.  
  956. static Boolean DecideToDispatch(event)
  957.     XEvent  *event;
  958. {
  959.     register    Widget widget;
  960.     EventMask   mask;
  961.     GrabType    grabType;
  962.     Widget    dspWidget;
  963.     Time    time = 0;
  964.     XtPerDisplay pd;
  965.     XtPerDisplayInput pdi;
  966.     XtGrabList  grabList;
  967.  
  968.     widget = XtWindowToWidget (event->xany.display, event->xany.window);
  969.     pd = _XtGetPerDisplay(event->xany.display);
  970.     pdi = _XtGetPerDisplayInput(event->xany.display);
  971.     grabList = *_XtGetGrabList(pdi);
  972.     
  973.     mask = _XtConvertTypeToMask(event->xany.type);
  974.  
  975.     grabType = pass;
  976.     switch (event->xany.type & 0x7f) {
  977.  
  978.       case KeyPress:
  979.       case KeyRelease:        grabType = remap; time = event->xkey.time;
  980.                 break;
  981.  
  982.       case ButtonPress:
  983.       case ButtonRelease:    grabType = remap; time = event->xbutton.time;
  984.                 break;
  985.  
  986.       case MotionNotify:    grabType = ignore; time = event->xmotion.time;
  987. #define XKnownButtons (Button1MotionMask|Button2MotionMask|Button3MotionMask|\
  988.                        Button4MotionMask|Button5MotionMask)
  989.                             mask |= (event->xmotion.state & XKnownButtons);
  990. #undef XKnownButtons
  991.                 break;
  992.  
  993.       case EnterNotify:
  994.                 grabType = ignore; /* fall through */
  995.       case LeaveNotify:        time = event->xcrossing.time; break;
  996.  
  997.       case PropertyNotify:    time = event->xproperty.time; break;
  998.  
  999.       case SelectionClear:    time = event->xselectionclear.time; break;
  1000.     }
  1001.  
  1002.     if (time) pd->last_timestamp = time;
  1003.  
  1004.     if (widget == NULL) {
  1005.     if (grabType != remap)
  1006.         return XFilterEvent(event, None);
  1007.     /* event occurred in a non-widget window, but we've promised also
  1008.        to dispatch it to the nearest accessible spring_loaded widget */
  1009.     else if ((widget = LookupSpringLoaded(grabList)) != NULL)
  1010.         return DispatchEvent(event, widget, mask, pd);
  1011.     return XFilterEvent(event, None);
  1012.     }
  1013.  
  1014.     switch(grabType) {
  1015.     case pass:
  1016.         return DispatchEvent(event, widget, mask, pd);
  1017.  
  1018.     case ignore:
  1019.         if ((grabList == NULL || _XtOnGrabList(widget,grabList))
  1020.         && XtIsSensitive(widget)) {
  1021.         return DispatchEvent(event, widget, mask, pd);
  1022.         }
  1023.         return XtDidNothing;
  1024.  
  1025.     case remap:
  1026.         
  1027.         {
  1028.         Boolean was_dispatched = XtDidNothing;
  1029.         extern Widget _XtFindRemapWidget();
  1030.         extern void _XtUngrabBadGrabs();
  1031.  
  1032.         dspWidget = _XtFindRemapWidget(event, widget, mask, pdi);
  1033.         
  1034.         if ((grabList == NULL || 
  1035.              _XtOnGrabList(dspWidget, grabList)) &&
  1036.             XtIsSensitive(dspWidget)) {
  1037.             was_dispatched = DispatchEvent(event, dspWidget,
  1038.                            mask, pd);
  1039.             if (was_dispatched & XtDidFilter)
  1040.             return was_dispatched;
  1041.         }
  1042.         else _XtUngrabBadGrabs(event, widget, mask, pdi);
  1043.         
  1044.         /* Also dispatch to nearest accessible spring_loaded. */
  1045.         /* Fetch this afterward to reflect modal list changes */
  1046.         grabList = *_XtGetGrabList(pdi);
  1047.         widget = LookupSpringLoaded(grabList);
  1048.         if (widget != NULL && widget != dspWidget) {
  1049.             was_dispatched |= DispatchEvent(event, widget,
  1050.                             mask, pd);
  1051.         }
  1052.         
  1053.         return was_dispatched;
  1054.         }
  1055.     }
  1056.     /* should never reach here */
  1057.     return XtDidNothing;
  1058. }
  1059.  
  1060. Boolean XtDispatchEvent (event)
  1061.     XEvent  *event;
  1062. {
  1063.     Boolean was_dispatched;
  1064.     XtAppContext app = XtDisplayToApplicationContext(event->xany.display);
  1065.     int dispatch_level = ++app->dispatch_level;
  1066.     int starting_count = app->destroy_count;
  1067.     void _XtRefreshMapping();
  1068.  
  1069.     if (event->xany.type == MappingNotify)
  1070.     _XtRefreshMapping(event, True);
  1071.  
  1072.     /*
  1073.      * To make recursive XtDispatchEvent work, we need to do phase 2 destroys
  1074.      * only on those widgets destroyed by this particular dispatch.
  1075.      *
  1076.      */
  1077.  
  1078.     was_dispatched = DecideToDispatch(event);
  1079.  
  1080.     if (app->destroy_count > starting_count)
  1081.     _XtDoPhase2Destroy(app, dispatch_level);
  1082.  
  1083.     app->dispatch_level = dispatch_level - 1;
  1084.  
  1085.     if (_XtSafeToDestroy(app)) {
  1086.     if (_XtAppDestroyCount != 0) _XtDestroyAppContexts();
  1087.     if (_XtDpyDestroyCount != 0) _XtCloseDisplays();
  1088.     }
  1089.     
  1090.     return (was_dispatched != XtDidNothing);
  1091. }
  1092.  
  1093. /* ARGSUSED */
  1094. static void GrabDestroyCallback(widget, closure, call_data)
  1095.     Widget  widget;
  1096.     XtPointer closure;
  1097.     XtPointer call_data;
  1098. {
  1099.     /* Remove widget from grab list if it destroyed */
  1100.     XtRemoveGrab(widget);
  1101. }
  1102.  
  1103. static XtGrabRec *NewGrabRec(widget, exclusive, spring_loaded)
  1104.     Widget  widget;
  1105.     Boolean exclusive;
  1106.     Boolean spring_loaded;
  1107. {
  1108.     register XtGrabList    gl;
  1109.  
  1110.     gl              = XtNew(XtGrabRec);
  1111.     gl->next          = NULL;
  1112.     gl->widget        = widget;
  1113.     gl->exclusive     = exclusive;
  1114.     gl->spring_loaded = spring_loaded;
  1115.  
  1116.     return gl;
  1117. }
  1118.  
  1119. #if NeedFunctionPrototypes
  1120. void XtAddGrab(
  1121.     Widget  widget,
  1122.     _XtBoolean exclusive,
  1123.     _XtBoolean spring_loaded
  1124.     )
  1125. #else
  1126. void XtAddGrab(widget, exclusive, spring_loaded)
  1127.     Widget  widget;
  1128.     Boolean exclusive;
  1129.     Boolean spring_loaded;
  1130. #endif
  1131. {
  1132.     register    XtGrabList gl;
  1133.     XtGrabList    *grabListPtr;
  1134.  
  1135.     grabListPtr = 
  1136.       _XtGetGrabList(_XtGetPerDisplayInput(XtDisplay(widget)));
  1137.       
  1138.                      
  1139.  
  1140.     if (spring_loaded && !exclusive) {
  1141.     XtAppWarningMsg(XtWidgetToApplicationContext(widget),
  1142.         "grabError", "xtAddGrab", XtCXtToolkitError,
  1143.         "XtAddGrab requires exclusive grab if spring_loaded is TRUE",
  1144.         (String *) NULL, (Cardinal *) NULL);
  1145.     exclusive = TRUE;
  1146.     }
  1147.  
  1148.     gl = NewGrabRec(widget, exclusive, spring_loaded);
  1149.     gl->next = *grabListPtr;
  1150.     *grabListPtr = gl;
  1151.  
  1152.     XtAddCallback (widget, XtNdestroyCallback, 
  1153.         GrabDestroyCallback, (XtPointer) NULL);
  1154. }
  1155.  
  1156. void XtRemoveGrab(widget)
  1157.     Widget  widget;
  1158. {
  1159.     register XtGrabList gl;
  1160.     register Boolean done;
  1161.     XtGrabList    *grabListPtr;
  1162.  
  1163.     grabListPtr = 
  1164.       _XtGetGrabList(_XtGetPerDisplayInput(XtDisplay(widget)));
  1165.       
  1166.     for (gl = *grabListPtr; gl != NULL; gl = gl->next) {
  1167.     if (gl->widget == widget) break;
  1168.     }
  1169.  
  1170.     if (gl == NULL) {
  1171.         XtAppWarningMsg(XtWidgetToApplicationContext(widget),
  1172.                "grabError","xtRemoveGrab",XtCXtToolkitError,
  1173.                "XtRemoveGrab asked to remove a widget not on the list",
  1174.                (String *)NULL, (Cardinal *)NULL);
  1175.         return;
  1176.     }    
  1177.  
  1178.     do {
  1179.     gl = *grabListPtr;
  1180.     done = (gl->widget == widget);
  1181.     *grabListPtr = gl->next;
  1182.     XtRemoveCallback(gl->widget, XtNdestroyCallback,
  1183.         GrabDestroyCallback, (XtPointer)NULL);
  1184.     XtFree((char *)gl);
  1185.     } while (! done);
  1186.     return;
  1187. }
  1188.  
  1189. void XtMainLoop()
  1190. {
  1191.     XtAppMainLoop(_XtDefaultAppContext());
  1192. }
  1193.  
  1194. void XtAppMainLoop(app)
  1195.     XtAppContext app;
  1196. {
  1197.     XEvent event;
  1198.  
  1199.     for (;;) {
  1200.         XtAppNextEvent(app, &event);
  1201.     XtDispatchEvent(&event);
  1202.     }
  1203. }
  1204.  
  1205.  
  1206. void _XtEventInitialize()
  1207. {
  1208.     static Boolean initialized = FALSE;
  1209.     if (initialized) return;
  1210.     initialized = TRUE;
  1211.  
  1212.     nullRegion = XCreateRegion();
  1213. }
  1214.  
  1215. void XtAddExposureToRegion(event, region)
  1216.     XEvent   *event;
  1217.     Region   region;
  1218. {
  1219.     XRectangle rect;
  1220.  
  1221.     switch (event->type) {
  1222.     case Expose:
  1223.         rect.x = event->xexpose.x;
  1224.         rect.y = event->xexpose.y;
  1225.         rect.width = event->xexpose.width;
  1226.         rect.height = event->xexpose.height;
  1227.         break;
  1228.     case GraphicsExpose:
  1229.         rect.x = event->xgraphicsexpose.x;
  1230.         rect.y = event->xgraphicsexpose.y;
  1231.         rect.width = event->xgraphicsexpose.width;
  1232.         rect.height = event->xgraphicsexpose.height;
  1233.         break;
  1234.     default:
  1235.         return;
  1236.     }
  1237.  
  1238.     XUnionRectWithRegion(&rect, region, region);
  1239. }
  1240.  
  1241.  
  1242. void _XtFreeEventTable(event_table)
  1243.     XtEventTable *event_table;
  1244. {
  1245.     register XtEventTable event;
  1246.  
  1247.     event = *event_table;
  1248.     while (event != NULL) {
  1249.     register XtEventTable next = event->next;
  1250.     XtFree((char *) event);
  1251.     event = next;
  1252.     }
  1253. }
  1254.  
  1255. Time XtLastTimestampProcessed(dpy)
  1256.     Display *dpy;
  1257. {
  1258.     return _XtGetPerDisplay(dpy)->last_timestamp;
  1259. }
  1260.       
  1261.  
  1262. void _XtSendFocusEvent(child, type)
  1263.     Widget child;
  1264.     int type;
  1265. {
  1266.  
  1267.     child = XtIsWidget(child) ? child : _XtWindowedAncestor(child);
  1268.     if (XtIsSensitive(child) && !child->core.being_destroyed
  1269.     && XtIsRealized(child)
  1270.     && (XtBuildEventMask(child) & FocusChangeMask))
  1271.     {
  1272.     XFocusChangeEvent event;
  1273.  
  1274.     event.type = type;
  1275.     event.serial = LastKnownRequestProcessed(XtDisplay(child));
  1276.     event.send_event = True;
  1277.     event.display = XtDisplay(child);
  1278.     event.window = XtWindow(child);
  1279.     event.mode = NotifyNormal;
  1280.     event.detail = NotifyAncestor;
  1281.     DispatchEvent((XEvent*)&event, child, _XtConvertTypeToMask(type),
  1282.               _XtGetPerDisplay(XtDisplay(child)));
  1283.     }
  1284. }
  1285.