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

  1. /* $XConsortium: Keyboard.c,v 1.26 92/10/06 14:01:53 converse Exp $ */
  2.  
  3. /********************************************************
  4.  
  5. Copyright (c) 1988 by Hewlett-Packard Company
  6. Copyright (c) 1987, 1988, 1989 by Digital Equipment Corporation, Maynard, 
  7.               Massachusetts, and the Massachusetts Institute of Technology, 
  8.               Cambridge, Massachusetts
  9.  
  10. Permission to use, copy, modify, and distribute this software 
  11. and its documentation for any purpose and without fee is hereby 
  12. granted, provided that the above copyright notice appear in all 
  13. copies and that both that copyright notice and this permission 
  14. notice appear in supporting documentation, and that the names of 
  15. Hewlett-Packard, Digital or  M.I.T.  not be used in advertising or 
  16. publicity pertaining to distribution of the software without specific, 
  17. written prior permission.
  18.  
  19. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  20. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  21. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  22. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  23. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  24. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  25. SOFTWARE.
  26.  
  27. ********************************************************/
  28.  
  29. #include "IntrinsicI.h"
  30. #include "StringDefs.h"
  31.  
  32. #include "PassivGraI.h"
  33.  
  34. #define _GetWindowedAncestor(w) (XtIsWidget(w) ? w : _XtWindowedAncestor(w))
  35. extern void _XtFillAncestorList();
  36. extern void _XtSendFocusEvent();
  37.  
  38. /* FindKeyDestination, ancestor list for Xt focus management */
  39. static Display    *pseudoTraceDisplay = NULL;
  40. static Widget    *pseudoTrace = NULL;
  41. static int    pseudoTraceDepth = 0;
  42. static int    pseudoTraceMax = 0;
  43.  
  44.  
  45. static XtServerGrabPtr CheckServerGrabs(event, trace, traceDepth)
  46.     XEvent    *event;
  47.     Widget    *trace;
  48.     Cardinal    traceDepth;
  49. {
  50.     XtServerGrabPtr     grab;
  51.     Cardinal        i;
  52.  
  53.     for (i = traceDepth;  i > 0; i--)
  54.       {
  55.      if (grab = _XtCheckServerGrabsOnWidget(event, trace[i-1], KEYBOARD))
  56.        return (grab);
  57.      }
  58.     return (XtServerGrabPtr)0;
  59. }
  60.  
  61. static Boolean IsParent(a, b)
  62.     Widget    a, b;
  63. {
  64.     for (b = XtParent(b); b; b = XtParent(b)) {
  65.       if (b == a) return TRUE;
  66.       if (XtIsShell(b)) return FALSE;
  67.     }
  68.     return FALSE;
  69. }
  70.  
  71. #define RelRtn(lca, type) {*relTypeRtn = type; return lca;}
  72.  
  73. static Widget CommonAncestor(a, b, relTypeRtn)
  74.     register Widget a, b;
  75.     XtGeneology  * relTypeRtn;
  76. {
  77.     if (a == b) 
  78.       {
  79.       RelRtn(a, XtMySelf)
  80.     }
  81.     else if (IsParent(a, b))
  82.       {
  83.       RelRtn(a, XtMyAncestor)
  84.     }
  85.     else if (IsParent(b, a))
  86.       {
  87.       RelRtn(b, XtMyDescendant)
  88.     }
  89.     else
  90.       for (b = XtParent(b);
  91.        b && !XtIsShell(b); 
  92.        b = XtParent(b))
  93.     if (IsParent(b, a)) 
  94.       {
  95.           RelRtn(b, XtMyCousin)
  96.         }
  97.     RelRtn(NULL, XtUnrelated)
  98. }
  99. #undef RelRtn
  100.  
  101.       
  102.     
  103.  
  104.  
  105. static Widget _FindFocusWidget(widget, trace, traceDepth, activeCheck, isTarget)
  106.     Widget     widget;
  107.     Widget    *trace;
  108.     int        traceDepth;
  109.     Boolean    activeCheck;
  110.     Boolean    *isTarget;
  111. {
  112.     int src;
  113.     Widget dst;
  114.     XtPerWidgetInput    pwi = NULL;
  115.     
  116.     /* For each ancestor, starting at the top, see if it's forwarded */
  117.  
  118.  
  119.     /* first check the trace list till done or we go to branch */
  120.     for (src = traceDepth-1, dst = widget; src > 0;)
  121.       {
  122.       if (pwi = _XtGetPerWidgetInput(trace[src], FALSE))
  123.         {
  124.         if (pwi->focusKid)
  125.           {
  126.               dst = pwi->focusKid;
  127.               for (src--; src > 0 && trace[src] != dst; src--) {}
  128.           }
  129.         else dst = trace[--src];
  130.         }
  131.       else dst = trace[--src];
  132.       }
  133.  
  134.     if (isTarget) {
  135.     if (pwi && pwi->focusKid == widget)
  136.         *isTarget = TRUE;
  137.     else
  138.         *isTarget = FALSE;
  139.     }
  140.  
  141.     if (!activeCheck)
  142.       while (XtIsWidget(dst)
  143.          && (pwi = _XtGetPerWidgetInput(dst, FALSE))
  144.          && pwi->focusKid)
  145.     dst = pwi->focusKid;
  146.  
  147.     return dst;
  148. }
  149.  
  150.  
  151. static Widget FindFocusWidget(widget, pdi)
  152.     Widget        widget;
  153.     XtPerDisplayInput     pdi; 
  154. {
  155.     if (pdi->focusWidget) 
  156.       return  pdi->focusWidget;
  157.     else
  158.       return _FindFocusWidget(widget, pdi->trace, pdi->traceDepth, FALSE, NULL);
  159. }
  160.  
  161.  
  162. static Boolean IsOutside(e, w) 
  163.     XKeyEvent    *e;
  164.     Widget    w;
  165. {
  166.     Position left, right, top, bottom;
  167.     
  168.     /*
  169.      * if the pointer is outside the shell or inside
  170.      * the window try to see if it would recieve the
  171.      * focus 
  172.      */
  173.     XtTranslateCoords(w, 0, 0, &left, &top);
  174.     /* We need to take borders into consideration */
  175.     left = left - w->core.border_width;
  176.     top =  top - w->core.border_width;
  177.     right = left +  w->core.width + w->core.border_width;
  178.     bottom = top +  w->core.height + w->core.border_width;
  179.  
  180.     if (
  181.     (e->x_root < left) || (e->y_root < top) ||
  182.         (e->x_root > right) || (e->y_root > bottom))
  183.       return TRUE;
  184.     else
  185.       return FALSE;
  186. }
  187.  
  188. static Widget     FindKeyDestination(widget, event,
  189.                    prevGrab, prevGrabType,
  190.                    devGrab, devGrabType,
  191.                    pdi)
  192.     Widget        widget;
  193.     XKeyEvent        *event;
  194.     XtServerGrabPtr    prevGrab;
  195.     XtServerGrabType     prevGrabType;
  196.     XtServerGrabPtr    devGrab;
  197.     XtServerGrabType    devGrabType;
  198.     XtPerDisplayInput    pdi;
  199. {
  200.     
  201.     Widget        dspWidget;
  202.     Widget        focusWidget;
  203.     
  204.     dspWidget = 
  205.       focusWidget = 
  206.     pdi->focusWidget = 
  207.       _GetWindowedAncestor(FindFocusWidget(widget, pdi));
  208.     
  209.     
  210.     /*
  211.      * If a grab is active from a previous activation then dispatch
  212.      * based on owner_events ala protocol but with focus being
  213.      * determined by XtSetKeyboardFocus.
  214.      */
  215.     if     (IsAnyGrab(prevGrabType))
  216.       {
  217.       if (prevGrab->ownerEvents) 
  218.         dspWidget = focusWidget;
  219.       else
  220.         dspWidget = prevGrab->widget;
  221.       }
  222.     else 
  223.       {
  224.       /*
  225.            * If the focus widget is the event widget or a descendant
  226.        * then we can avoid the rest of this. Else ugh...
  227.        */
  228.       if (focusWidget != widget) 
  229.         {
  230.         XtGeneology     ewRelFw; /* relationship of event widget to
  231.                         focusWidget */
  232.         Widget        lca;
  233.  
  234.         lca = CommonAncestor(widget, focusWidget, &ewRelFw);
  235.             
  236.         /*
  237.          * if the event widget is an ancestor of focus due to the pointer
  238.          * and/or the grab being in an ancestor and it's a passive grab
  239.          * send to grab widget.
  240.          * we are also dispatching to widget if ownerEvents and the event
  241.          * is outside the client
  242.          */
  243.         if ((ewRelFw == XtMyAncestor) &&
  244.             (devGrabType == XtPassiveServerGrab))
  245.              {
  246.              if (IsOutside(event, widget) ||
  247.                  event->type ==KeyPress
  248.                  )
  249.                dspWidget = devGrab->widget;
  250.              }
  251.         else 
  252.           {
  253.               /*
  254.                * if the grab widget is not an ancestor of the focus
  255.                * release the grab in order to avoid locking. There
  256.                * is a possible case  in that ownerEvents true will fall
  257.                * through and if synch is set and the event widget
  258.                * could turn it off we'll lock. check for it ? why not
  259.                */
  260.               if ((ewRelFw != XtMyAncestor) 
  261.               && (devGrabType == XtPassiveServerGrab)
  262.               && (!IsAnyGrab(prevGrabType))
  263.               )
  264.             {
  265.                 XtUngrabKeyboard(devGrab->widget,
  266.                          event->time);
  267.                 devGrabType = XtNoServerGrab;
  268.             }
  269.               /*
  270.                * if there isn't a grab with then check
  271.                * for a logical grab that would have been activated
  272.                * if the server was using Xt focus instead of server
  273.                * focus 
  274.                */
  275.               if (
  276.               (event->type != KeyPress) ||
  277.               (event->keycode == 0) /* Xlib XIM composed input */
  278.               )
  279.             dspWidget = focusWidget;
  280.               else
  281.             {
  282.                 XtServerGrabPtr    grab;
  283.  
  284.                 if (!pseudoTraceDepth || 
  285.                 !(pseudoTraceDisplay ==
  286.                  XtDisplay(widget)) ||
  287.                 !(focusWidget == pseudoTrace[0]) ||
  288.                 !(lca == pseudoTrace[pseudoTraceDepth]))
  289.                   {
  290.                   /*
  291.                    * fill ancestor list from lca
  292.                    * (non-inclusive)to focusWidget by
  293.                    * passing in lca as breakWidget
  294.                    */
  295.                   _XtFillAncestorList(&pseudoTrace, 
  296.                            &pseudoTraceMax, 
  297.                            &pseudoTraceDepth,
  298.                            focusWidget,
  299.                            lca);
  300.                   pseudoTraceDisplay = XtDisplay(widget);
  301.                   /* ignore lca */
  302.                   pseudoTraceDepth--;
  303.                   }
  304.                 if (grab = CheckServerGrabs((XEvent*)event,
  305.                             pseudoTrace,
  306.                             pseudoTraceDepth))
  307.                   {
  308.                   XtDevice device = &pdi->keyboard;
  309.                   
  310.                   device->grabType = XtPseudoPassiveServerGrab;
  311.                   pdi->activatingKey = event->keycode;
  312.                   device->grab = *grab;
  313.  
  314.                   if (grab 
  315.                       )
  316.                     dspWidget = grab->widget;
  317.                   else
  318.                     dspWidget = focusWidget;
  319.                   }
  320.             }
  321.           }
  322.         }
  323.       }
  324.     return dspWidget;
  325. }
  326.  
  327. Widget _XtProcessKeyboardEvent(event, widget, pdi)
  328.     XKeyEvent  *event;
  329.     Widget widget;
  330.     XtPerDisplayInput pdi;
  331. {    
  332.     XtDevice        device = &pdi->keyboard;
  333.     XtServerGrabPtr    newGrab, devGrab = &device->grab;
  334.     XtServerGrabRec    prevGrabRec;
  335.     XtServerGrabType    prevGrabType = device->grabType;
  336.     Widget        dspWidget = NULL;
  337.     Boolean        deactivateGrab = FALSE;
  338.  
  339.     prevGrabRec = *devGrab;
  340.  
  341.     switch (event->type)
  342.       {
  343.     case KeyPress:
  344.       {
  345.           if (event->keycode != 0 && /* Xlib XIM composed input */
  346.           !IsServerGrab(device->grabType) && 
  347.           (newGrab = CheckServerGrabs((XEvent*)event,
  348.                           pdi->trace,
  349.                           pdi->traceDepth)))
  350.         {
  351.             /*
  352.              * honor pseudo-grab from prior event by X
  353.              * unlocking keyboard. Not Xt Unlock !
  354.              */
  355.             if (IsPseudoGrab(prevGrabType))
  356.               XUngrabKeyboard(XtDisplay(newGrab->widget),
  357.                       event->time);
  358.             else
  359.               {
  360.               /* Activate the grab */
  361.               device->grab = *newGrab;
  362.               pdi->activatingKey = event->keycode;
  363.               device->grabType = XtPassiveServerGrab;
  364.               }
  365.         }
  366.         }
  367.       break;
  368.       
  369.     case KeyRelease:
  370.       {
  371.           if (IsEitherPassiveGrab(device->grabType) && 
  372.           (event->keycode == pdi->activatingKey))
  373.         deactivateGrab = TRUE;
  374.       }
  375.       break;
  376.       }
  377.     dspWidget = FindKeyDestination(widget, event,
  378.                    &prevGrabRec, prevGrabType,
  379.                    devGrab, device->grabType,
  380.                    pdi);
  381.     if (deactivateGrab)
  382.       {
  383.       /* Deactivate the grab */
  384.       device->grabType = XtNoServerGrab;
  385.       pdi->activatingKey = 0;
  386.       }
  387.     return dspWidget;
  388. }    
  389.     
  390. static Widget GetShell(widget)
  391.     Widget    widget;
  392. {
  393.     Widget    shell;
  394.  
  395.     for (shell = widget; 
  396.      shell && !XtIsShell(shell);
  397.      shell = XtParent(shell)){}
  398.     return shell;
  399. }
  400.  
  401.  
  402. /*
  403.  * Check that widget really has Xt focus due to it having recieved an
  404.  * event 
  405.  */
  406. typedef enum {NotActive = 0, IsActive, IsTarget} ActiveType;
  407. static ActiveType InActiveSubtree(widget)
  408.     Widget    widget;
  409. {
  410.     static Widget    *pathTrace = NULL;
  411.     static int        pathTraceDepth = 0;
  412.     static int        pathTraceMax = 0;
  413.     static Display    *display = NULL;
  414.     Boolean        isTarget;
  415.     
  416.     if (!pathTraceDepth || 
  417.     !(display == XtDisplay(widget)) ||
  418.     !(widget == pathTrace[0]))
  419.       {
  420.       _XtFillAncestorList(&pathTrace, 
  421.                   &pathTraceMax, 
  422.                   &pathTraceDepth,
  423.                   widget,
  424.                   NULL);
  425.       display = XtDisplay(widget);
  426.       }
  427.     if (widget == _FindFocusWidget(widget, 
  428.                    pathTrace,
  429.                    pathTraceDepth, 
  430.                    TRUE,
  431.                    &isTarget))
  432.       return isTarget ? IsTarget : IsActive;
  433.     else
  434.       return NotActive;
  435. }
  436.  
  437.  
  438.  
  439.  
  440. /* ARGSUSED */
  441. void _XtHandleFocus(widget, client_data, event, cont)
  442.     Widget widget;
  443.     XtPointer client_data;    /* child who wants focus */
  444.     XEvent *event;
  445.     Boolean *cont;        /* unused */
  446. {
  447.     XtPerDisplayInput     pdi = _XtGetPerDisplayInput(XtDisplay(widget));
  448.     XtPerWidgetInput    pwi = (XtPerWidgetInput)client_data;
  449.     XtGeneology        oldFocalPoint = pwi->focalPoint;
  450.     XtGeneology        newFocalPoint = pwi->focalPoint;
  451.  
  452.     switch( event->type ) {
  453.     
  454.       case KeyPress:
  455.       case KeyRelease:
  456.     /*
  457.      * We're getting the keyevents used to guarantee propagating
  458.          * child interest ala ForwardEvent in R3
  459.      */
  460.     return;
  461.  
  462.       case EnterNotify:
  463.       case LeaveNotify:
  464.     
  465.     /*
  466.      * If operating in a focus driven model, then enter and
  467.      * leave events do not affect the keyboard focus.
  468.      */
  469.     if ((event->xcrossing.detail != NotifyInferior)
  470.         &&    (event->xcrossing.focus))
  471.       {          
  472.           switch (oldFocalPoint)
  473.         {
  474.           case XtMyAncestor:
  475.             if (event->type == LeaveNotify)
  476.               newFocalPoint = XtUnrelated;
  477.             break;
  478.           case XtUnrelated:
  479.             if (event->type == EnterNotify)
  480.               newFocalPoint = XtMyAncestor;
  481.             break;
  482.           case XtMySelf:
  483.             break;
  484.           case XtMyDescendant:
  485.             break;
  486.             
  487.         }    
  488.       }
  489.     break;
  490.       case FocusIn:
  491.     switch (event->xfocus.detail)
  492.       {
  493.         case NotifyNonlinear:
  494.         case NotifyAncestor:
  495.         case NotifyInferior:
  496.           newFocalPoint = XtMySelf;
  497.           break;
  498.         case NotifyNonlinearVirtual:
  499.         case NotifyVirtual:
  500.           newFocalPoint = XtMyDescendant;
  501.           break;
  502.         case NotifyPointer:
  503.           newFocalPoint = XtMyAncestor;
  504.           break;
  505.       }
  506.     break;
  507.       case FocusOut:
  508.     switch (event->xfocus.detail)
  509.       {
  510.         case NotifyPointer:
  511.         case NotifyNonlinear:
  512.         case NotifyAncestor:
  513.         case NotifyNonlinearVirtual:
  514.         case NotifyVirtual:
  515.           newFocalPoint = XtUnrelated;
  516.           break;
  517.         case NotifyInferior:
  518.           newFocalPoint = XtMyDescendant;
  519.           return;
  520.           break;
  521.       }
  522.     break;
  523.     }
  524.     
  525.     if (newFocalPoint != oldFocalPoint)
  526.       {
  527.       Boolean     add;
  528.       Widget    descendant = pwi->focusKid;
  529.  
  530.       pwi->focalPoint = newFocalPoint;
  531.  
  532.       if ((oldFocalPoint == XtUnrelated) &&
  533.           InActiveSubtree(widget) != NotActive)
  534.         {
  535.         pdi->focusWidget = NULL; /* invalidate the cache */
  536.         pwi->haveFocus = TRUE;
  537.         add = TRUE;
  538.         }
  539.       else if (newFocalPoint == XtUnrelated)
  540.         {
  541.         pdi->focusWidget = NULL; /* invalidate the cache */
  542.         pwi->haveFocus = FALSE;
  543.         add = FALSE;
  544.         }
  545.       else
  546.         return;
  547.  
  548.       if (descendant)
  549.         {
  550.         if (add)
  551.           {
  552.               _XtSendFocusEvent(descendant, FocusIn);
  553.           }
  554.         else
  555.           {
  556.               _XtSendFocusEvent(descendant, FocusOut);
  557.           }
  558.         }
  559.       }
  560. }
  561.  
  562.  
  563. static void AddFocusHandler(widget, descendant, pwi, psi, pdi, oldEventMask)
  564.     Widget widget, descendant;
  565.     XtPerWidgetInput pwi;
  566.     XtPerWidgetInput psi;
  567.     XtPerDisplayInput pdi;
  568.     EventMask oldEventMask;
  569. {
  570.     EventMask         eventMask, targetEventMask;
  571.     Widget        target;
  572.  
  573.     /*
  574.      * widget must now select for key events if the descendant is
  575.      * interested in them.
  576.      *
  577.      * shell borders are not occluded by the child, they're occluded
  578.      * by reparenting window managers. !!!
  579.      */
  580.     target = descendant ? _GetWindowedAncestor(descendant) : NULL;
  581.     targetEventMask = XtBuildEventMask(target);
  582.     eventMask = targetEventMask & (KeyPressMask | KeyReleaseMask);
  583.     eventMask |= FocusChangeMask | EnterWindowMask | LeaveWindowMask;
  584.  
  585.     if (oldEventMask) {
  586.     oldEventMask &= KeyPressMask | KeyReleaseMask;
  587.     oldEventMask |= FocusChangeMask | EnterWindowMask | LeaveWindowMask;
  588.  
  589.     if (oldEventMask != eventMask)
  590.         XtRemoveEventHandler(widget, (oldEventMask & ~eventMask), 
  591.                  False, _XtHandleFocus, (XtPointer)pwi);
  592.     }
  593.  
  594.     if (oldEventMask != eventMask)
  595.     XtAddEventHandler(widget, eventMask, False, 
  596.               _XtHandleFocus, (XtPointer)pwi);
  597.  
  598.     /* What follows is too much grief to go through if the
  599.      * target doesn't actually care about focus change events,
  600.      * so just invalidate the focus cache & refill it when
  601.      * the next input event actually arrives.
  602.      */
  603.  
  604.     if (!(targetEventMask & FocusChangeMask)) {
  605.     pdi->focusWidget = NULL;
  606.     return;
  607.     }
  608.  
  609.     if (XtIsRealized(widget) && !pwi->haveFocus) {
  610.     if (psi->haveFocus) {
  611.         Window root, child;
  612.         int root_x, root_y, win_x, win_y;
  613.         int left, right, top, bottom;
  614.         unsigned int modMask;
  615.         ActiveType act;
  616.  
  617.         /*
  618.          * If the shell has the focus but the source widget
  619.          * doesn't, it may only be because the source widget
  620.          * wasn't previously tracking focus or crossing events.
  621.          * If the target wants focus events, we have to
  622.          * now determine whether the source has the focus.
  623.          */
  624.  
  625.         if ((act = InActiveSubtree(widget)) == IsTarget)
  626.         pwi->haveFocus = TRUE;
  627.         else if (act == IsActive) {
  628.         /*
  629.          * An ancestor contains the focus, so if source
  630.          * contains the pointer, then source has the focus.
  631.          */
  632.  
  633.         if (XQueryPointer(XtDisplay(widget), XtWindow(widget),
  634.                   &root, &child,
  635.                   &root_x, &root_y, &win_x, &win_y, &modMask))
  636.         {
  637.             /* We need to take borders into consideration */
  638.             left = top = -((int) widget->core.border_width);
  639.             right = (int) (widget->core.width + (widget->core.border_width << 1));
  640.             bottom = (int) (widget->core.height + (widget->core.border_width << 1));
  641.  
  642.             if (win_x >= left && win_x < right &&
  643.             win_y >= top && win_y < bottom)
  644.             pwi->haveFocus = TRUE;
  645.         }
  646.         }
  647.     }
  648.     }
  649.     if (pwi->haveFocus) {
  650.       pdi->focusWidget = NULL; /* invalidate the cache */
  651.       _XtSendFocusEvent(target, FocusIn);
  652.     }
  653. }
  654.  
  655.  
  656. /* ARGSUSED */
  657. static void QueryEventMask(widget, client_data, event, cont)
  658.     Widget widget;        /* child who gets focus */
  659.     XtPointer client_data;    /* ancestor giving it */
  660.     XEvent *event;
  661.     Boolean *cont;        /* unused */
  662. {
  663.     /* widget was once the target of an XtSetKeyboardFocus but
  664.      * was unrealized at the time.   Make sure ancestor still wants
  665.      * focus set here then install the handler now that we know the
  666.      * complete event mask.
  667.      */
  668.     Widget ancestor = (Widget)client_data;
  669.     XtPerWidgetInput pwi = _XtGetPerWidgetInput(ancestor, FALSE);
  670.     Widget target = pwi->queryEventDescendant;
  671.  
  672.     /* use of 'target' is non-standard hackery; allows focus to non-widget */
  673.     if (pwi && (pwi->focusKid == target)) {
  674.     AddFocusHandler(ancestor, target, pwi,
  675.             _XtGetPerWidgetInput(GetShell(ancestor), TRUE),
  676.             _XtGetPerDisplayInput(XtDisplay(ancestor)),
  677.             (EventMask)0);
  678.     }
  679.     XtRemoveEventHandler(widget, XtAllEvents, True,
  680.              QueryEventMask, client_data);
  681.     pwi->map_handler_added = FALSE;
  682. }
  683.  
  684.  
  685. /* ARGSUSED */
  686. static void FocusDestroyCallback(widget, closure, call_data)
  687.     Widget  widget;
  688.     XtPointer closure;        /* Widget */
  689.     XtPointer call_data;
  690. {
  691.     XtSetKeyboardFocus((Widget)closure, None);
  692.     /* invalidate FindKeyDestination's ancestor list if it is still for us */
  693.     if (pseudoTraceDepth &&
  694.     pseudoTraceDisplay == XtDisplay((Widget)closure) &&
  695.     _GetWindowedAncestor(widget) == pseudoTrace[0])
  696.     pseudoTraceDepth = 0;
  697. }
  698.  
  699. void XtSetKeyboardFocus(widget, descendant)
  700.     Widget widget;
  701.     Widget descendant;
  702. {
  703.     XtPerDisplayInput pdi = _XtGetPerDisplayInput(XtDisplay(widget));
  704.     XtPerWidgetInput pwi = _XtGetPerWidgetInput(widget, TRUE);
  705.     Widget oldDesc = pwi->focusKid;
  706.     Widget oldTarget, target;
  707.     
  708.     if (descendant == widget) descendant = (Widget)None;
  709.  
  710.     target = descendant ? _GetWindowedAncestor(descendant) : NULL;
  711.     oldTarget = oldDesc ? _GetWindowedAncestor(oldDesc) : NULL;
  712.     
  713.     if (descendant != oldDesc) {
  714.     
  715.     /* update the forward path */
  716.     pwi->focusKid = descendant;
  717.  
  718.  
  719.     /* all the rest handles focus ins and focus outs and misc gunk */
  720.     
  721.     if (oldDesc) {
  722.         if (!oldDesc->core.being_destroyed) {
  723.         XtRemoveCallback (oldDesc, XtNdestroyCallback, 
  724.                   FocusDestroyCallback, (XtPointer) widget);
  725.         }
  726.  
  727.         if (!oldTarget->core.being_destroyed) {
  728.         if (pwi->map_handler_added) {
  729.             XtRemoveEventHandler(oldTarget, XtAllEvents, True,
  730.                      QueryEventMask, (XtPointer)widget);
  731.             pwi->map_handler_added = FALSE;
  732.         }
  733.         if (pwi->haveFocus) {
  734.             _XtSendFocusEvent( oldTarget, FocusOut);
  735.         }
  736.         }
  737.         else if (pwi->map_handler_added) {
  738.         pwi->map_handler_added = FALSE;
  739.         }
  740.  
  741.         if (pwi->haveFocus)
  742.         pdi->focusWidget = NULL; /* invalidate cache */
  743.  
  744.         /*
  745.          * If there was a forward path then remove the handler if
  746.          * the path is being set to null and it isn't a shell.
  747.          * shells always have a handler for tracking focus for the
  748.          * hierarchy.
  749.          *
  750.          * Keep the pwi record on the assumption that the client
  751.          * will continue to dynamically assign focus for this widget.
  752.          */
  753.         if (!XtIsShell(widget) && !descendant) {
  754.           XtRemoveEventHandler(widget, XtAllEvents, True, 
  755.                    _XtHandleFocus, (XtPointer)pwi);
  756.           pwi->haveFocus = FALSE;
  757.       }
  758.     }
  759.     
  760.     if (descendant) {
  761.         Widget shell = GetShell(widget);
  762.         XtPerWidgetInput psi = _XtGetPerWidgetInput(shell, TRUE);
  763.         XtAddCallback (descendant, XtNdestroyCallback, 
  764.                FocusDestroyCallback, (XtPointer) widget);
  765.  
  766.         AddFocusHandler(widget, descendant, pwi, psi, pdi,
  767.                 oldTarget ? XtBuildEventMask(oldTarget) : 0);
  768.  
  769.         if (widget != shell)
  770.         XtAddEventHandler(
  771.             shell,
  772.             FocusChangeMask | EnterWindowMask | LeaveWindowMask,
  773.             False,
  774.             _XtHandleFocus,
  775.             (XtPointer)psi
  776.                );
  777.  
  778.         if (! XtIsRealized(target)) {
  779.         XtAddEventHandler(target, (EventMask)StructureNotifyMask,
  780.                   False, QueryEventMask, (XtPointer)widget);
  781.         pwi->map_handler_added = TRUE;
  782.         pwi->queryEventDescendant = descendant;
  783.         }
  784.     }
  785.     }
  786. }    
  787.