home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / editors / emacs / xemacs / xemacs-1.004 / xemacs-1 / xemacs-19.13 / src / ExternalClient.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-08-29  |  17.6 KB  |  603 lines

  1. /* External client widget.
  2.    Copyright (C) 1993, 1994 Sun Microsystems, Inc.
  3.  
  4. This library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public
  6. License as published by the Free Software Foundation; either
  7. version 2 of the License, or (at your option) any later version.
  8.  
  9. This library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12. Library General Public License for more details.
  13.  
  14. You should have received a copy of the GNU Library General Public
  15. License along with this library; if not, write to the Free
  16. Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
  17.  
  18. /* Synched up with: Not in FSF. */
  19.  
  20. /* Written by Ben Wing, September 1993. */
  21.  
  22. #ifdef emacs
  23.  
  24. #include <config.h>
  25.  
  26. #ifndef EXTERNAL_WIDGET
  27. ERROR!  This ought not be getting compiled if EXTERNAL_WIDGET is undefined
  28. #endif
  29.  
  30. #endif /* emacs */
  31.  
  32. #include <stdio.h>
  33. #include <string.h>
  34. #include <stdlib.h>
  35. #ifdef EXTW_USES_MOTIF
  36. # include <Xm/XmP.h>
  37. # include <Xm/PrimitiveP.h>
  38. # include <X11/keysym.h>
  39. #else
  40. # include "xintrinsicp.h"
  41. # include <X11/StringDefs.h>
  42. #endif
  43.  
  44. #include "ExternalClientP.h"
  45. #include "extw-Xt.h"
  46.  
  47. #ifdef TOOLTALK
  48. #include <tt_c.h>
  49. #endif
  50.  
  51. /* This is the client widget, used to communicate with an ExternalShell
  52.    widget. */
  53.  
  54. #define NOTIFY(w, type, l0, l1, l2) \
  55.   extw_send_notify_3(XtDisplay((Widget)(w)), XtWindow((Widget)(w)),\
  56.              type, l0, l1, l2)
  57.  
  58. static void externalClientInitialize ();
  59. static void externalClientRealize (Widget widget, XtValueMask *mask,
  60.             XSetWindowAttributes *attrs);
  61. static void Destroy (Widget w);
  62. static void EventHandler();
  63. static void MaskableEventHandler();
  64. static XtGeometryResult QueryGeometry(Widget, XtWidgetGeometry *,
  65.                       XtWidgetGeometry *);
  66. static void ExternalClientFocusIn (Widget, XEvent *, String *, Cardinal *);
  67. static void ExternalClientFocusOut (Widget, XEvent *, String *, Cardinal *);
  68. static void ExternalClientEnter (Widget, XEvent *, String *, Cardinal *);
  69. static void ExternalClientLeave (Widget, XEvent *, String *, Cardinal *);
  70.  
  71. static int my_error_handler(Display *display, XErrorEvent *xev);
  72. static int (*error_old_handler)(Display *, XErrorEvent *);
  73.  
  74. static XtResource resources[] = {
  75. #define offset(field) XtOffset(ExternalClientWidget, externalClient.field)
  76.   { XtNshellTimeout, XtCShellTimeout, XtRInt, sizeof(int),
  77.       offset(shell_timeout), XtRImmediate,(XtPointer)DEFAULT_WM_TIMEOUT},
  78.   { XtNdeadShell, XtCDeadShell, XtRBoolean, sizeof(Boolean),
  79.       offset(dead_shell), XtRImmediate, (XtPointer)False},
  80. #ifdef EXTW_USES_MOTIF
  81.   { XmNnavigationType, XmCNavigationType, XmRNavigationType,
  82.       sizeof(XmNavigationType), XtOffset(ExternalClientWidget,
  83.       primitive.navigation_type), XtRImmediate,
  84.       (XtPointer)XmTAB_GROUP},
  85. #endif
  86.   { XtNemacsProcID, XtCEmacsProcID, XtRString, sizeof(String),
  87.       offset(emacs_procid), XtRImmediate, (XtPointer)NULL},
  88.   { XtNshellReadyCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
  89.       offset(shell_ready_callback), XtRImmediate, (XtPointer)NULL},
  90.   { XtNshellName, XtCShellName, XtRString, sizeof(String),
  91.       offset(shell_name), XtRImmediate, (XtPointer)NULL},
  92.   { XtNuseToolTalk, XtCUseToolTalk, XtRBoolean, sizeof(Boolean),
  93.       offset(use_tooltalk), XtRImmediate, (XtPointer)False}
  94. };
  95.  
  96. static XtActionsRec actions[] = {
  97.   {"focusIn",    ExternalClientFocusIn},
  98.   {"focusOut",    ExternalClientFocusOut},
  99.   {"enter",    ExternalClientEnter},
  100.   {"leave",    ExternalClientLeave},
  101. };
  102.  
  103. ExternalClientClassRec externalClientClassRec = {
  104.     { /*
  105.        *    core_class fields
  106.        */
  107. #ifdef EXTW_USES_MOTIF
  108.     /* superclass      */    (WidgetClass) &xmPrimitiveClassRec,
  109. #else
  110.     /* superclass      */    (WidgetClass) &coreClassRec,
  111. #endif
  112.     /* class_name      */    "ExternalClient",
  113.     /* size          */    sizeof(ExternalClientRec),
  114.     /* Class Initializer  */    NULL,
  115.     /* class_part_initialize*/    NULL, /* XtInheritClassPartInitialize, */
  116.     /* Class init'ed ?      */    FALSE,
  117.     /* initialize      */    externalClientInitialize,
  118.     /* initialize_notify  */    NULL,
  119.     /* realize          */    externalClientRealize, 
  120.     /* actions          */    actions,
  121.     /* num_actions      */    XtNumber (actions),
  122.     /* resources      */    resources,
  123.     /* resource_count      */    XtNumber (resources),
  124.     /* xrm_class      */    NULLQUARK,
  125.     /* compress_motion      */    FALSE,
  126.     /* compress_exposure  */    TRUE,
  127.     /* compress_enterleave*/    FALSE,
  128.     /* visible_interest      */    TRUE,
  129.     /* destroy          */    Destroy, /* XtInheritDestroy, */
  130.     /* resize          */    XtInheritResize,
  131.     /* expose          */    NULL,
  132.     /* set_values      */    NULL, /* XtInheritSetValues, */
  133.     /* set_values_hook      */    NULL,            
  134.     /* set_values_almost  */    XtInheritSetValuesAlmost,  
  135.     /* get_values_hook      */    NULL,            
  136.     /* accept_focus      */    NULL,
  137.     /* intrinsics version */    XtVersion,
  138.     /* callback offsets      */    NULL,
  139.     /* tm_table          */    "", /* MUST NOT BE NULL or
  140.                                        XtInheritTranslations in Motif!!!!!
  141.                        Otherwise keyboard focus translations
  142.                        will not work. */
  143.     /* query_geometry      */    QueryGeometry,
  144.     /* display_accelerator*/    NULL,
  145.     /* extension      */    NULL
  146.   },
  147. #ifdef EXTW_USES_MOTIF
  148.   {
  149.     _XtInherit,              /* Primitive border_highlight */
  150.     _XtInherit,              /* Primitive border_unhighlight */
  151.     XtInheritTranslations,   /* translations */
  152.     NULL,                    /* arm_and_activate */
  153.     NULL,                    /* get resources */
  154.     0,                       /* num get_resources */
  155.     NULL,                    /* extension */
  156.   },
  157. #endif
  158.   {
  159.     0
  160.   }
  161. };
  162.  
  163. WidgetClass externalClientWidgetClass = (WidgetClass) &externalClientClassRec;
  164.  
  165. static void externalClientInitialize (req, new, args, num_args)
  166.      Widget req, new;
  167.      ArgList args;
  168.      Cardinal *num_args;
  169. {
  170.   ExternalClientWidget ecw = (ExternalClientWidget) new;
  171.   static int error_handler_added = 0;
  172.  
  173.   extw_initialize_atoms(XtDisplay(new));
  174.   extw_which_side = extw_client_send;
  175.  
  176. #ifdef EXTW_USES_MOTIF
  177.  
  178.   /* yes I know this is horrible.  However, the XmPrimitive class adds
  179.      the Tab translation in its initialization routine, so we have to
  180.      override it here.  This is all the fault of Xt, which doesn't
  181.      provide a proper inheritance mechanism for translations.
  182.  
  183.      -- BPW
  184.  
  185.   */
  186.     
  187.   XtOverrideTranslations(new, XtParseTranslationTable("None<Key>Tab:\n"
  188.                               "<FocusIn>:focusIn()\n"
  189.                               "<FocusOut>:focusOut()\n"
  190.                               "<Enter>:enter()\n"
  191.                               "<Leave>:leave()\n"));
  192.  
  193. #endif
  194.   
  195.   XtAddEventHandler(new, NULL, TRUE, EventHandler, (XtPointer) NULL);
  196.  
  197.   ecw->externalClient.shell_ready = False;
  198.   ecw->externalClient.has_focus = False;
  199.  
  200.   if (!error_handler_added) {
  201.     error_handler_added = 1;
  202.     error_old_handler = XSetErrorHandler(my_error_handler);
  203.   }
  204. }
  205.  
  206.  
  207. #ifdef TOOLTALK
  208. static Tt_callback_action
  209. tt_callback(Tt_message m, Tt_pattern p)
  210. {
  211.   ExternalClientWidget ecw = (ExternalClientWidget)tt_message_user(m, 0);
  212.   
  213.   switch (tt_message_state(m)) {
  214.   case TT_FAILED:
  215.     /* handle errors here */
  216.     break;
  217.   case TT_HANDLED:
  218.     ecw->externalClient.shell_name = tt_message_arg_val(m, 2);
  219.     XtCallCallbackList((Widget)ecw, ecw->externalClient.shell_ready_callback, NULL);
  220.     break;
  221.   }
  222.   
  223.   tt_message_destroy(m);
  224.   return TT_CALLBACK_PROCESSED;
  225. }
  226.  
  227. static void send_tooltalk_handshake (ExternalClientWidget ecw,
  228.                      Window win, char *name)
  229. {
  230.   Tt_message m = tt_message_create();
  231.  
  232.   tt_message_op_set(m, "emacs-make-client-screen");
  233.   tt_message_scope_set(m, TT_SESSION);
  234.   tt_message_class_set(m, TT_REQUEST);
  235.   tt_message_arg_add(m, TT_IN, "string", name);
  236.   tt_message_iarg_add(m, TT_IN, "int", win);
  237.   tt_message_arg_add(m, TT_OUT, "string", NULL); 
  238.   tt_message_user_set(m, 0, (void *)ecw);
  239.   tt_message_callback_add(m, tt_callback);
  240.   if (ecw->externalClient.emacs_procid) {
  241.     tt_message_address_set(m, TT_HANDLER);
  242.     tt_message_handler_set(m, ecw->externalClient.emacs_procid);
  243.   }
  244.   else
  245.     tt_message_address_set(m, TT_PROCEDURE);
  246.   tt_message_send(m);
  247. }
  248.  
  249. #endif
  250.  
  251.  
  252. static void externalClientRealize(Widget w, XtValueMask *vm, XSetWindowAttributes *attrs)
  253. {
  254.  
  255.   ExternalClientWidget ecw = (ExternalClientWidget)w;
  256.  
  257. #ifdef EXTW_USES_MOTIF  
  258.   (*xmPrimitiveWidgetClass->core_class.realize)(w, vm, attrs);
  259. #else
  260.   (*coreWidgetClass->core_class.realize)(w, vm, attrs);
  261. #endif
  262.  
  263. #ifdef TOOLTALK
  264.  
  265.   /* Make sure that the server actually knows about this window id before
  266.    * telling Emacs about it.
  267.    */
  268.   if (ecw->externalClient.use_tooltalk)
  269.     {
  270.       XSync(XtDisplay(w), False);
  271.       send_tooltalk_handshake(ecw, XtWindow(w), XtName(w));
  272.     }
  273. #endif  
  274. }
  275.  
  276.  
  277. /***********************************************************************/
  278.  
  279. /* window-to-widget list. */
  280.  
  281. struct ww_list {
  282.   Window win;
  283.   Widget wid;
  284.   struct ww_list *next;
  285. };
  286.  
  287. struct ww_list ww_list[1];
  288.  
  289. static int add_ww(Window win, Widget wid)
  290. {
  291.   struct ww_list *ww = (struct ww_list *) malloc(sizeof(struct
  292.                             ww_list));
  293.   if (!ww)
  294.     return 0;
  295.   ww->win = win;
  296.   ww->wid = wid;
  297.   ww->next = ww_list->next;
  298.   ww_list->next = ww;
  299.   return 1;
  300. }
  301.  
  302. static Widget remove_ww(Window win)
  303. {
  304.   struct ww_list *w1, *w2;
  305.   Widget wid = 0;
  306.   
  307.   for (w1=ww_list, w2=w1->next; w2; w1=w2, w2=w2->next)
  308.     if (w2->win == win) {
  309.       w1->next = w2->next;
  310.       wid = w2->wid;
  311.       free(w2);
  312.       break;
  313.     }
  314.   return wid;
  315. }
  316.  
  317. /***********************************************************************/
  318.  
  319. /* stolen outright from Intrinsic.c */
  320.  
  321. static void ComputeWindowAttributes(widget,value_mask,values)
  322.      Widget         widget;
  323.      XtValueMask         *value_mask;
  324.      XSetWindowAttributes *values;
  325. {
  326.   *value_mask = CWEventMask | CWColormap;
  327.   (*values).event_mask = XtBuildEventMask(widget);
  328.   (*values).colormap = widget->core.colormap;
  329.   if (widget->core.background_pixmap != XtUnspecifiedPixmap) {
  330.     *value_mask |= CWBackPixmap;
  331.     (*values).background_pixmap = widget->core.background_pixmap;
  332.   } else {
  333.     *value_mask |= CWBackPixel;
  334.     (*values).background_pixel = widget->core.background_pixel;
  335.   }
  336.   if (widget->core.border_pixmap != XtUnspecifiedPixmap) {
  337.     *value_mask |= CWBorderPixmap;
  338.     (*values).border_pixmap = widget->core.border_pixmap;
  339.   } else {
  340.     *value_mask |= CWBorderPixel;
  341.     (*values).border_pixel = widget->core.border_pixel;
  342.   }
  343.   if (widget->core.widget_class->core_class.expose == (XtExposeProc) NULL) {
  344.     /* Try to avoid redisplay upon resize by making bit_gravity the same
  345.        as the default win_gravity */
  346.     *value_mask |= CWBitGravity;
  347.     (*values).bit_gravity = NorthWestGravity;
  348.   }
  349. } /* ComputeWindowAttributes */
  350.  
  351. static void end_connection(ExternalClientWidget w)
  352. {
  353.   XSetWindowAttributes xswa;
  354.   XtValueMask mask;
  355.   Widget wid = (Widget) w;
  356.   
  357.   w->externalClient.shell_ready = False;
  358.   XtRemoveEventHandler(wid, w->externalClient.event_mask,
  359.                FALSE, MaskableEventHandler, (XtPointer) NULL);
  360.   ComputeWindowAttributes(wid, &mask, &xswa);
  361.   XChangeWindowAttributes(XtDisplay(wid), XtWindow(wid), mask, &xswa);
  362.   XClearArea(XtDisplay(wid), XtWindow(wid), 0, 0, 0, 0, True);
  363. }
  364.  
  365. static int error_occurred;
  366.  
  367. static int my_error_handler(Display *display, XErrorEvent *xev)
  368. {
  369.   Widget wid;
  370.   
  371.   if (xev->error_code != BadWindow)
  372.     goto call_old;
  373.   wid = remove_ww(xev->resourceid);
  374.   if (wid) {
  375.     end_connection((ExternalClientWidget) wid);
  376.     return 0;
  377.   }
  378.   
  379.  call_old:
  380.   return error_old_handler(display, xev);
  381. }
  382.  
  383. static void MaskableEventHandler(wid, closure, event, continue_to_dispatch)
  384.      Widget wid;
  385.      XtPointer closure;    /* unused */
  386.      XEvent *event;
  387.      Boolean *continue_to_dispatch; /* unused */
  388. {
  389.   ExternalClientWidget w = (ExternalClientWidget) wid;
  390.   
  391.   if (w->externalClient.shell_ready) {
  392.     if (event->type == KeyPress || event->type == KeyRelease ||
  393.     event->type == ButtonPress || event->type == ButtonRelease ||
  394.     event->type == MotionNotify)
  395.       event->xkey.subwindow = 0;
  396. #ifdef EXTW_USES_MOTIF
  397.     /* hackkkkkkkkkkkkkk!  Suppress CTRL-TAB, SHIFT-TAB, etc. so that
  398.        Emacs doesn't attempt to interpret focus-change keystrokes. */
  399.     if (event->type == KeyPress && XLookupKeysym (event, 0) == XK_Tab &&
  400.     (event->xkey.state & ControlMask ||
  401.      event->xkey.state & ShiftMask))
  402.       return;
  403. #endif
  404.     {
  405.       event->xany.window = w->core.window;
  406.       XSendEvent(XtDisplay(wid), w->externalClient.event_window, FALSE, 0, event);
  407.       XSync(XtDisplay(wid), 0); /* make sure that any BadWindow errors
  408.                    (meaning the server died) get handled
  409.                    before XSendEvent is called again. */
  410.       
  411.     }
  412.   }
  413. }
  414.  
  415. static void EventHandler(wid, closure, event, continue_to_dispatch)
  416.      Widget wid;
  417.      XtPointer closure;    /* unused */
  418.      XEvent *event;
  419.      Boolean *continue_to_dispatch; /* unused */
  420. {
  421.   ExternalClientWidget w = (ExternalClientWidget) wid;
  422.   
  423.   if(w->core.window != event->xany.window) {
  424.     XtAppErrorMsg(XtWidgetToApplicationContext(wid),
  425.           "invalidWindow","eventHandler",XtCXtToolkitError,
  426.           "Event with wrong window",
  427.           (String *)NULL, (Cardinal *)NULL);
  428.     return;
  429.   }
  430.   
  431.   if (event->type == ClientMessage &&
  432.       event->xclient.message_type == a_EXTW_NOTIFY &&
  433.       event->xclient.data.l[0] == extw_shell_send)
  434.     switch (event->xclient.data.l[1]) {
  435.       
  436.     case extw_notify_qg:
  437.       /* shell is alive again. */
  438.  
  439.       w->externalClient.dead_shell = False;
  440.       break;
  441.       
  442.     case extw_notify_gm: {
  443.       XtWidgetGeometry xwg, xwg_return;
  444.       XtGeometryResult result;
  445.       
  446.       extw_get_geometry_value(XtDisplay(wid), XtWindow(wid),
  447.                   a_EXTW_GEOMETRY_MANAGER, &xwg);
  448.       result = XtMakeGeometryRequest(wid, &xwg, &xwg_return);
  449.  
  450.       extw_send_geometry_value(XtDisplay(wid), XtWindow(wid),
  451.                    a_EXTW_GEOMETRY_MANAGER, extw_notify_gm,
  452.                    result == XtGeometryAlmost ? &xwg_return :
  453.                    NULL, result);
  454.       break;
  455.     }
  456.       
  457.     case extw_notify_init:
  458.       w->externalClient.shell_ready = True;
  459.       w->externalClient.event_window = event->xclient.data.l[2];
  460.       w->externalClient.event_mask = event->xclient.data.l[3];
  461.       add_ww(w->externalClient.event_window, (Widget) w);
  462.  
  463.       XtAddEventHandler(wid, w->externalClient.event_mask,
  464.             FALSE, MaskableEventHandler, (XtPointer) NULL);
  465. #ifdef EXTW_USES_MOTIF
  466.       NOTIFY(w, extw_notify_init,
  467.          EXTW_TYPE_MOTIF,
  468.          0, 0);
  469. #else
  470.       NOTIFY(w, extw_notify_init,
  471.          EXTW_TYPE_XT,
  472.          0, 0);
  473. #endif
  474.       break;
  475.       
  476.     case extw_notify_end:
  477.       end_connection(w);
  478.       remove_ww(w->externalClient.event_window);
  479.       break;
  480.       
  481.     case extw_notify_set_focus:
  482. #ifdef EXTW_USES_MOTIF
  483.       XmProcessTraversal(wid, XmTRAVERSE_CURRENT);
  484. #else
  485.       XtSetKeyboardFocus(wid, None);
  486. #endif
  487.       break;
  488.       
  489.     }
  490. }
  491.  
  492. static void Destroy(wid)
  493.      Widget wid;
  494. {
  495.   ExternalClientWidget w = (ExternalClientWidget)wid;
  496.   
  497.   NOTIFY(w, extw_notify_end, 0, 0, 0);
  498. }
  499.  
  500. static XtGeometryResult QueryGeometry(gw, request, reply)
  501.      Widget gw;
  502.      XtWidgetGeometry *request, *reply;
  503. {
  504.   ExternalClientWidget w = (ExternalClientWidget)gw;
  505.   XEvent event;
  506.   unsigned long request_num;
  507.   Display *display = XtDisplay(gw);
  508.   XtWidgetGeometry req = *request; /* don't modify caller's structure */
  509.   
  510.   if (!XtIsRealized((Widget)w) || !w->externalClient.shell_ready)
  511.     return XtGeometryYes;
  512.   
  513.   if (w->externalClient.dead_shell == TRUE)
  514.     /* The shell is sick. */
  515.     return XtGeometryNo;
  516.   
  517.   req.sibling = None;
  518.   req.request_mode &= ~CWSibling;
  519.   request_num = NextRequest(display);
  520.   extw_send_geometry_value(XtDisplay(gw), XtWindow(gw), a_EXTW_QUERY_GEOMETRY,
  521.                extw_notify_qg, &req, 0);
  522.  
  523.   if (extw_wait_for_response(gw, &event, request_num, extw_notify_qg,
  524.                  w->externalClient.shell_timeout)) {
  525.     XtGeometryResult result = (XtGeometryResult) event.xclient.data.l[0];
  526.  
  527.     if (result == XtGeometryAlmost) {
  528.       extw_get_geometry_value(XtDisplay(gw), XtWindow(gw),
  529.                   a_EXTW_QUERY_GEOMETRY, reply);
  530.     }
  531.     return result;
  532.   } else {
  533.     w->externalClient.dead_shell = TRUE; /* timed out; must be broken */
  534.     return XtGeometryNo;
  535.   }
  536. }
  537.  
  538. static void ExternalClientFocusIn (Widget w, XEvent *event, String *params,
  539.                 Cardinal *num_params)
  540. {
  541.   ExternalClientWidget ecw = (ExternalClientWidget) w;
  542.   
  543.   if (event->xfocus.send_event && !ecw->externalClient.has_focus) {
  544.     ecw->externalClient.has_focus = True;
  545.     NOTIFY(ecw, extw_notify_focus_in, 0, 0, 0);
  546.   }
  547. #ifdef EXTW_USES_MOTIF
  548.   _XmPrimitiveFocusIn (w, event, params, num_params);
  549. #endif
  550. }
  551.  
  552. static void ExternalClientFocusOut (Widget w, XEvent *event, String *params,
  553.                  Cardinal *num_params)
  554. {
  555.   ExternalClientWidget ecw = (ExternalClientWidget) w;
  556.   
  557.   if (event->xfocus.send_event && ecw->externalClient.has_focus) {
  558.     ecw->externalClient.has_focus = False;
  559.     NOTIFY(ecw, extw_notify_focus_out, 0, 0, 0);
  560.   }
  561. #ifdef EXTW_USES_MOTIF
  562.   _XmPrimitiveFocusOut(w, event, params, num_params);
  563. #endif
  564. }
  565.  
  566. static void ExternalClientEnter (Widget w, XEvent *event, String *params,
  567.                   Cardinal *num_params)
  568. {
  569.   ExternalClientWidget ecw = (ExternalClientWidget) w;
  570.   
  571.   if (
  572. #ifdef EXTW_USES_MOTIF
  573.       _XmGetFocusPolicy (w) != XmEXPLICIT &&
  574. #endif
  575.       !ecw->externalClient.has_focus &&
  576.       event->xcrossing.focus && event->xcrossing.detail != NotifyInferior) {
  577.     ecw->externalClient.has_focus = True;
  578.     NOTIFY(ecw, extw_notify_focus_in, 0, 0, 0);
  579.   }
  580. #ifdef EXTW_USES_MOTIF
  581.   _XmPrimitiveEnter (w, event, params, num_params);
  582. #endif
  583. }
  584.  
  585. static void ExternalClientLeave (Widget w, XEvent *event, String *params,
  586.                   Cardinal *num_params)
  587. {
  588.   ExternalClientWidget ecw = (ExternalClientWidget) w;
  589.   
  590.   if (
  591. #ifdef EXTW_USES_MOTIF
  592.       _XmGetFocusPolicy (w) != XmEXPLICIT &&
  593. #endif
  594.       ecw->externalClient.has_focus &&
  595.       event->xcrossing.focus && event->xcrossing.detail != NotifyInferior) {
  596.     ecw->externalClient.has_focus = False;
  597.     NOTIFY(ecw, extw_notify_focus_out, 0, 0, 0);
  598.   }
  599. #ifdef EXTW_USES_MOTIF
  600.   _XmPrimitiveLeave (w, event, params, num_params);
  601. #endif
  602. }
  603.