Contents in 1999-06-04-13 of release-21-2.
[chise/xemacs-chise.git.1] / src / ExternalShell.c
1 /* External shell 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
16 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA. */
18
19 /* Synched up with: Not in FSF. */
20
21 /* Written by Ben Wing, September 1993. */
22
23 /* This is a special Shell that is designed to use an externally-
24    provided window created by someone else (possibly another process).
25    That other window should have an associated widget of class
26    ExternalClient.  The two widgets communicate with each other using
27    ClientMessage events and properties on the external window.
28
29    Ideally this feature should be independent of Emacs.  Unfortunately
30    there are lots and lots of specifics that need to be dealt with
31    for this to work properly, and some of them can't conveniently
32    be handled within the widget's methods.  Some day the code may
33    be rewritten so that the embedded-widget feature can be used by
34    any application, with appropriate entry points that are called
35    at specific points within the application.
36
37    This feature is similar to the OLE (Object Linking & Embedding)
38    feature provided by MS Windows.
39  */
40
41 #ifdef emacs
42
43 #include <config.h>
44
45 #ifndef EXTERNAL_WIDGET
46 ERROR!  This ought not be getting compiled if EXTERNAL_WIDGET is undefined
47 #endif
48
49 #endif /* emacs */
50
51 #include <stdio.h>
52 #include <string.h>
53 #include <X11/StringDefs.h>
54 #include "xintrinsicp.h"
55 #include <X11/Shell.h>
56 #include <X11/ShellP.h>
57 #include <X11/Vendor.h>
58 #include <X11/VendorP.h>
59 #include "ExternalShellP.h"
60 #include "extw-Xt.h"
61
62 #ifdef emacs
63 extern void emacs_Xt_handle_focus_event (XEvent *event);
64 #endif
65
66 /* Communication between this shell and the client widget:
67
68    Communication is through ClientMessage events with message_type
69    EXTW_NOTIFY and format 32.  Both the shell and the client widget
70    communicate with each other by sending the message to the same
71    window (the "external window" below), and the data.l[0] value is
72    used to determine who sent the message.
73
74    The data is formatted as follows:
75
76    data.l[0] = who sent this message: external_shell_send (0) or
77                external_client_send (1)
78    data.l[1] = message type (see enum en_extw_notify below)
79    data.l[2-4] = data associated with this message
80
81    EventHandler() handles messages from the other side.
82
83    extw_send_notify_3() sends a message to the other side.
84
85    extw_send_geometry_value() is used when an XtWidgetGeometry structure
86       needs to be sent.  This is too much data to fit into a
87       ClientMessage, so the data is stored in a property and then
88       extw_send_notify_3() is called.
89
90    extw_get_geometry_value() receives an XtWidgetGeometry structure from a
91       property.
92
93    extw_wait_for_response() is used when a response to a sent message
94       is expected.  It looks for a matching event within a
95       particular timeout.
96
97    The particular message types are as follows:
98
99 1) extw_notify_init (event_window, event_mask)
100
101    This is sent from the shell to the client after the shell realizes
102    its EmacsFrame widget on the client's "external window".  This
103    tells the client that it should start passing along events of the
104    types specified in event_mask.  event_window specifies the window
105    of the EmacsFrame widget, which is a child of the client's
106    external window.
107
108    extw_notify_init (client_type)
109
110    When the client receives an extw_notify_init message from the
111    shell, it sends back a message of the same sort specifying the type
112    of the toolkit used by the client (Motif, generic Xt, or Xlib).
113
114 2) extw_notify_end ()
115
116    This is sent from the shell to the client when the shell's
117    EmacsFrame widget is destroyed, and tells the client to stop
118    passing events along.
119
120 3) extw_notify_qg (result)
121
122    This is sent from the client to the shell when a QueryGeometry
123    request is received on the client.  The XtWidgetGeometry structure
124    specified in the QueryGeometry request is passed on in the
125    EXTW_QUERY_GEOMETRY property (of type EXTW_WIDGET_GEOMETRY) on the
126    external window.  result is unused.
127
128    In response, the shell passes the QueryGeometry request down the
129    widget tree, and when a response is received, sends a message of
130    type extw_notify_qg back to the client, with result specifying the
131    GeometryResult value.  If this value is XtGeometryAlmost, the
132    returned XtWidgetGeometry structure is stored into the same property
133    as above. [BPW is there a possible race condition here?]
134
135 4) extw_notify_gm (result)
136
137    A very similar procedure to that for extw_notify_qg is followed
138    when the shell's RootGeometryManager method is called, indicating
139    that a child widget wishes to change the shell's geometry.  The
140    XtWidgetGeometry structure is stored in the EXTW_GEOMETRY_MANAGER
141    property.
142
143 5) extw_notify_focus_in (), extw_notify_focus_out ()
144
145    These are sent from the client to the shell when the client gains
146    or loses the keyboard focus.  It is done this way because Xt
147    maintains its own concept of keyboard focus and only the client
148    knows this information.
149 */
150
151 #define NOTIFY(w, type, l0, l1, l2) \
152   extw_send_notify_3(XtDisplay((Widget)(w)),\
153    (w)->externalShell.external_window, type, l0, l1, l2)
154
155 static void ExternalShellInitialize (Widget req, Widget new, ArgList args,
156                                      Cardinal *num_args);
157 static void ExternalShellRealize (Widget wid, Mask *vmask, XSetWindowAttributes
158                                   *attr);
159 static void ExternalShellDestroy (Widget w);
160 static void ChangeManaged (Widget wid);
161 static XtGeometryResult ExternalShellRootGeometryManager (Widget gw,
162   XtWidgetGeometry *request, XtWidgetGeometry *reply);
163 static void EventHandler (Widget wid, XtPointer closure, XEvent *event,
164                           Boolean *continue_to_dispatch);
165
166 #ifndef DEFAULT_WM_TIMEOUT
167 # define DEFAULT_WM_TIMEOUT 5000
168 #endif
169
170 void ExternalShellUnrealize (Widget w);
171
172 static XtResource resources[] = {
173 #define offset(field) XtOffset(ExternalShellWidget, externalShell.field)
174   { XtNwindow, XtCWindow, XtRWindow, sizeof (Window),
175       offset (external_window), XtRImmediate, (XtPointer)0},
176   { XtNclientTimeout, XtCClientTimeout, XtRInt, sizeof(int),
177       offset(client_timeout), XtRImmediate,(XtPointer)DEFAULT_WM_TIMEOUT},
178   { XtNdeadClient, XtCDeadClient, XtRBoolean, sizeof(Boolean),
179       offset(dead_client), XtRImmediate, (XtPointer)False},
180 };
181
182 static CompositeClassExtensionRec compositeClassExtRec = {
183     NULL,
184     NULLQUARK,
185     XtCompositeExtensionVersion,
186     sizeof(CompositeClassExtensionRec),
187     TRUE,
188 };
189
190 static ShellClassExtensionRec shellClassExtRec = {
191     NULL,
192     NULLQUARK,
193     XtShellExtensionVersion,
194     sizeof(ShellClassExtensionRec),
195     ExternalShellRootGeometryManager
196 };
197
198 ExternalShellClassRec externalShellClassRec = {
199     { /*
200        *        core_class fields
201        */
202     /* superclass         */    (WidgetClass) &shellClassRec,
203     /* class_name         */    "ExternalShell",
204     /* size               */    sizeof(ExternalShellRec),
205     /* Class Initializer  */    NULL,
206     /* class_part_initialize*/  NULL, /* XtInheritClassPartInitialize, */
207     /* Class init'ed ?    */    FALSE,
208     /* initialize         */    ExternalShellInitialize,
209     /* initialize_notify  */    NULL,
210     /* realize            */    ExternalShellRealize,
211     /* actions            */    NULL,
212     /* num_actions        */    0,
213     /* resources          */    resources,
214     /* resource_count     */    XtNumber (resources),
215     /* xrm_class          */    NULLQUARK,
216     /* compress_motion    */    FALSE,
217     /* compress_exposure  */    TRUE,
218     /* compress_enterleave*/    FALSE,
219     /* visible_interest   */    TRUE,
220     /* destroy            */    ExternalShellDestroy, /* XtInheritDestroy, */
221     /* resize             */    XtInheritResize,
222     /* expose             */    NULL,
223     /* set_values         */    NULL, /* XtInheritSetValues, */
224     /* set_values_hook    */    NULL,                   
225     /* set_values_almost  */    XtInheritSetValuesAlmost,  
226     /* get_values_hook    */    NULL,                   
227     /* accept_focus       */    NULL,
228     /* intrinsics version */    XtVersion,
229     /* callback offsets   */    NULL,
230     /* tm_table           */    NULL,
231     /* query_geometry     */    NULL,
232     /* display_accelerator*/    NULL,
233     /* extension          */    NULL
234   },{ /* Composite */
235     /* geometry_manager   */    XtInheritGeometryManager,
236     /* change_managed     */    ChangeManaged,  /* XtInheritChangeManaged */
237     /* insert_child       */    XtInheritInsertChild,
238     /* delete_child       */    XtInheritDeleteChild,
239     /* extension          */    (XtPointer)&compositeClassExtRec
240   },{ /* Shell */
241     /* extension          */    (XtPointer)&shellClassExtRec
242   },{ /* ExternalShell */
243     0
244   }
245 };
246
247 WidgetClass externalShellWidgetClass = (WidgetClass) &externalShellClassRec;
248
249 static void
250 ExternalShellInitialize (Widget req, Widget new, ArgList args,
251                          Cardinal *num_args)
252 {
253   XtAddEventHandler(new, 0,
254                     TRUE, EventHandler, (XtPointer) NULL);
255   extw_initialize_atoms(XtDisplay(req));
256   extw_which_side = extw_shell_send;
257 }
258
259 static Widget
260 find_managed_child (CompositeWidget w)
261 {
262   int i;
263   Widget *childP = w->composite.children;
264
265   for (i = w->composite.num_children; i; i--, childP++)
266     if (XtIsWidget(*childP) && XtIsManaged(*childP))
267       return *childP;
268   return NULL;
269 }
270
271 #ifndef XtCXtToolkitError
272 # define XtCXtToolkitError "XtToolkitError"
273 #endif
274
275 static void EventHandler(wid, closure, event, continue_to_dispatch)
276      Widget wid;
277      XtPointer closure; /* unused */
278      XEvent *event;
279      Boolean *continue_to_dispatch; /* unused */
280 {
281   ExternalShellWidget w = (ExternalShellWidget) wid;
282
283   if(w->core.window != event->xany.window) {
284     XtAppErrorMsg(XtWidgetToApplicationContext(wid),
285                   "invalidWindow","eventHandler",XtCXtToolkitError,
286                   "Event with wrong window",
287                   (String *)NULL, (Cardinal *)NULL);
288     return;
289   }
290
291   if (event->type == ClientMessage &&
292       event->xclient.data.l[0] == extw_client_send &&
293       event->xclient.message_type == a_EXTW_NOTIFY)
294     switch (event->xclient.data.l[1]) {
295
296     case extw_notify_gm:
297       /* client is alive again. */
298       w->externalShell.dead_client = False;
299       break;
300
301     case extw_notify_qg: {
302       XtWidgetGeometry xwg, xwg_return;
303       XtGeometryResult result;
304       Widget child = find_managed_child((CompositeWidget) w);
305
306       if (child) {
307         extw_get_geometry_value(XtDisplay(wid), XtWindow(wid),
308                                 a_EXTW_QUERY_GEOMETRY, &xwg);
309         result = XtQueryGeometry(child, &xwg, &xwg_return);
310       } else
311         result = XtGeometryYes;
312
313       extw_send_geometry_value(XtDisplay(wid), XtWindow(wid),
314                                a_EXTW_QUERY_GEOMETRY, extw_notify_qg,
315                                result == XtGeometryAlmost ? &xwg_return :
316                                NULL, result);
317       break;
318     }
319
320     case extw_notify_focus_in: {
321       XFocusChangeEvent evnt;
322       
323       evnt.type = FocusIn;
324       evnt.serial = LastKnownRequestProcessed (XtDisplay (wid));
325       evnt.send_event = True;
326       evnt.display = XtDisplay (wid);
327       evnt.window = XtWindow (wid);
328       evnt.mode = NotifyNormal;
329       evnt.detail = NotifyAncestor;
330 #ifdef emacs
331       emacs_Xt_handle_focus_event ((XEvent *) &evnt);
332 #else
333       XtDispatchEvent ((XEvent *) &evnt);
334 #endif
335       break;
336     }
337       
338     case extw_notify_focus_out: {
339       XFocusChangeEvent evnt;
340       
341       evnt.type = FocusOut;
342       evnt.serial = LastKnownRequestProcessed (XtDisplay (wid));
343       evnt.send_event = True;
344       evnt.display = XtDisplay (wid);
345       evnt.window = XtWindow (wid);
346       evnt.mode = NotifyNormal;
347       evnt.detail = NotifyAncestor;
348 #ifdef emacs
349       emacs_Xt_handle_focus_event ((XEvent *) &evnt);
350 #else
351       XtDispatchEvent ((XEvent *) &evnt);
352 #endif
353       break;
354     }
355
356     case extw_notify_end:
357       /* frame should be destroyed. */
358       break;
359     }
360 }
361
362 /* Lifted almost entirely from GetGeometry() in Shell.c
363  */
364 static void
365 GetGeometry (Widget W, Widget child)
366 {
367     ExternalShellWidget w = (ExternalShellWidget)W;
368     int x, y, win_gravity = -1, flag;
369     XSizeHints hints;
370     Window win = w->externalShell.external_window;
371     
372     {
373       Window dummy_root;
374       unsigned int dummy_bd_width, dummy_depth, width, height;
375       
376       /* determine the existing size of the window. */
377       XGetGeometry(XtDisplay(W), win, &dummy_root, &x, &y, &width,
378                    &height, &dummy_bd_width, &dummy_depth);
379       w->core.width = width;
380       w->core.height = height;
381     }
382
383     if(w->shell.geometry != NULL) {
384         char def_geom[128];
385         int width, height;
386
387         x = w->core.x;
388         y = w->core.y;
389         width = w->core.width;
390         height = w->core.height;
391         hints.flags = 0;
392
393         sprintf( def_geom, "%dx%d+%d+%d", width, height, x, y );
394         flag = XWMGeometry( XtDisplay(W),
395                             XScreenNumberOfScreen(XtScreen(W)),
396                             w->shell.geometry, def_geom,
397                             (unsigned int)w->core.border_width,
398                             &hints, &x, &y, &width, &height,
399                             &win_gravity
400                            );
401         if (flag) {
402             if (flag & XValue) w->core.x = (Position)x;
403             if (flag & YValue) w->core.y = (Position)y;
404             if (flag & WidthValue) w->core.width = (Dimension)width;
405             if (flag & HeightValue) w->core.height = (Dimension)height;
406         }
407         else {
408             String params[2];
409             Cardinal num_params = 2;
410             params[0] = XtName(W);
411             params[1] = w->shell.geometry;
412             XtAppWarningMsg(XtWidgetToApplicationContext(W),
413        "badGeometry", "shellRealize", XtCXtToolkitError,
414        "Shell widget \"%s\" has an invalid geometry specification: \"%s\"",
415                             params, &num_params);
416         }
417     }
418     else
419         flag = 0;
420
421     w->shell.client_specified |= _XtShellGeometryParsed;
422 }
423
424 /* Lifted almost entirely from Realize() in Shell.c
425  */
426 static void ExternalShellRealize (Widget wid, Mask *vmask,
427                                   XSetWindowAttributes *attr)
428 {
429         ExternalShellWidget w = (ExternalShellWidget) wid;
430         Mask mask = *vmask;
431         Window win = w->externalShell.external_window;
432
433         if (!win) {
434           Cardinal count = 1;
435           XtErrorMsg("invalidWindow","shellRealize", XtCXtToolkitError,
436                      "No external window specified for ExternalShell widget %s",
437                      &wid->core.name, &count);
438         }
439
440         if (! (w->shell.client_specified & _XtShellGeometryParsed)) {
441             /* we'll get here only if there was no child the first
442                time we were realized.  If the shell was Unrealized
443                and then re-Realized, we probably don't want to
444                re-evaluate the defaults anyway.
445              */
446             GetGeometry(wid, (Widget)NULL);
447         }
448         else if (w->core.background_pixmap == XtUnspecifiedPixmap) {
449             /* I attempt to inherit my child's background to avoid screen flash
450              * if there is latency between when I get resized and when my child
451              * is resized.  Background=None is not satisfactory, as I want the
452              * user to get immediate feedback on the new dimensions (most
453              * particularly in the case of a non-reparenting wm).  It is
454              * especially important to have the server clear any old cruft
455              * from the display when I am resized larger.
456              */
457             Widget *childP = w->composite.children;
458             int i;
459             for (i = w->composite.num_children; i; i--, childP++) {
460                 if (XtIsWidget(*childP) && XtIsManaged(*childP)) {
461                     if ((*childP)->core.background_pixmap
462                             != XtUnspecifiedPixmap) {
463                         mask &= ~(CWBackPixel);
464                         mask |= CWBackPixmap;
465                         attr->background_pixmap =
466                             w->core.background_pixmap =
467                                 (*childP)->core.background_pixmap;
468                     } else {
469                         attr->background_pixel = 
470                             w->core.background_pixel = 
471                                 (*childP)->core.background_pixel;
472                     }
473                     break;
474                 }
475             }
476         }
477
478         if(w->shell.save_under) {
479                 mask |= CWSaveUnder;
480                 attr->save_under = TRUE;
481         }
482         if(w->shell.override_redirect) {
483                 mask |= CWOverrideRedirect;
484                 attr->override_redirect = TRUE;
485         }
486         if (wid->core.width == 0 || wid->core.height == 0) {
487             Cardinal count = 1;
488             XtErrorMsg("invalidDimension", "shellRealize", XtCXtToolkitError,
489                        "Shell widget %s has zero width and/or height",
490                        &wid->core.name, &count);
491         }
492         wid->core.window = win;
493         XChangeWindowAttributes(XtDisplay(wid), wid->core.window,
494                                 mask, attr);
495
496 }
497
498 static void ExternalShellDestroy(wid)
499         Widget wid;
500 {
501   ExternalShellWidget w = (ExternalShellWidget)wid;
502
503   if (XtIsRealized(wid))
504     ExternalShellUnrealize(wid);
505
506   NOTIFY(w, extw_notify_end, 0, 0, 0);
507 }
508
509 /* Invoke matching routine from superclass, but first override its
510    geometry opinions with our own routine */
511
512 static void ChangeManaged(wid)
513     Widget wid;
514 {
515   if (!XtIsRealized (wid))
516     GetGeometry(wid, (Widget)NULL);
517   (*((ShellClassRec*)externalShellClassRec.core_class.superclass)->
518    composite_class.change_managed)(wid);
519 }
520
521 /* Based on RootGeometryManager() in Shell.c */
522
523 static XtGeometryResult ExternalShellRootGeometryManager(gw, request, reply)
524     Widget gw;
525     XtWidgetGeometry *request, *reply;
526 {
527     ExternalShellWidget w = (ExternalShellWidget)gw;
528     unsigned int mask = request->request_mode;
529     XEvent event;
530     int oldx, oldy, oldwidth, oldheight, oldborder_width;
531     unsigned long request_num;
532     XtWidgetGeometry req = *request; /* don't modify caller's structure */
533
534     oldx = w->core.x;
535     oldy = w->core.y;
536     oldwidth = w->core.width;
537     oldheight = w->core.height;
538     oldborder_width = w->core.border_width;
539
540 #define PutBackGeometry() \
541         { w->core.x = oldx; \
542           w->core.y = oldy; \
543           w->core.width = oldwidth; \
544           w->core.height = oldheight; \
545           w->core.border_width = oldborder_width; }
546
547     if (mask & CWX) {
548       if (w->core.x == request->x) mask &= ~CWX;
549       else
550         w->core.x = request->x;
551     }
552     if (mask & CWY) {
553       if (w->core.y == request->y) mask &= ~CWY;
554       else w->core.y = request->y;
555     }
556     if (mask & CWBorderWidth) {
557       if (w->core.border_width == request->border_width)
558               mask &= ~CWBorderWidth;
559       else w->core.border_width = request->border_width;
560     }
561     if (mask & CWWidth) {
562       if (w->core.width == request->width) mask &= ~CWWidth;
563       else w->core.width = request->width;
564     }
565     if (mask & CWHeight) {
566       if (w->core.height == request->height) mask &= ~CWHeight;
567       else w->core.height = request->height;
568     }
569
570     if (!XtIsRealized((Widget)w)) return XtGeometryYes;
571
572     req.sibling = None;
573     req.request_mode = mask & ~CWSibling;
574     request_num = NextRequest(XtDisplay(w));
575     extw_send_geometry_value(XtDisplay(w), XtWindow(w),
576                              a_EXTW_GEOMETRY_MANAGER,
577                              extw_notify_gm, &req, 0);
578
579     if (w->externalShell.dead_client == TRUE) {
580       /* The client is sick.  Refuse the request.
581        * If the client recovers and decides to honor the
582        * request, it will be handled by Shell's EventHandler().
583        */
584       PutBackGeometry();
585       return XtGeometryNo;
586     }
587
588     if (extw_wait_for_response(gw, &event, request_num, extw_notify_gm,
589                                w->externalShell.client_timeout)) {
590       XtGeometryResult result = (XtGeometryResult) event.xclient.data.l[2];
591
592       if (result != XtGeometryYes)
593         PutBackGeometry();
594       if (result == XtGeometryAlmost) {
595         extw_get_geometry_value(XtDisplay(w), XtWindow(w),
596                                 a_EXTW_GEOMETRY_MANAGER, reply);
597       }
598       return result;
599     } else {
600       w->externalShell.dead_client = TRUE; /* timed out; must be broken */
601       PutBackGeometry();
602       return XtGeometryNo;
603     }
604 #undef PutBackGeometry
605 }
606
607 static void
608 hack_event_masks_1 (Display *display, Window w, int this_window_propagate)
609 {
610   Window root, parent, *children;
611   unsigned int nchildren;
612   int i;
613
614   if (!XQueryTree (display, w, &root, &parent, &children, &nchildren))
615     return;
616   for (i=0; i<nchildren; i++)
617     hack_event_masks_1 (display, children[i], 1);
618   if (children)
619     XFree (children);
620   {
621     XWindowAttributes xwa;
622     XSetWindowAttributes xswa;
623     if (XGetWindowAttributes (display, w, &xwa)) {
624       xswa.event_mask = xwa.your_event_mask & ~KeyPressMask;
625       if (this_window_propagate)
626         xswa.do_not_propagate_mask = xwa.do_not_propagate_mask & ~KeyPressMask;
627       XChangeWindowAttributes (display, w, CWEventMask, &xswa);
628     }
629   }
630 }
631
632 /* fix all event masks on all subwindows of the specified window so that
633    all key presses in any subwindow filter up to the specified window.
634
635    We have to do this cruftiness with external widgets so that we don't
636    step on Motif's concept of keyboard focus.  (Due to the nature of
637    Xt and Motif, X's idea of who gets the keyboard events may not jive
638    with Xt's idea of same, and Xt redirects the events to the proper
639    window.  This occurs on the client side and we have no knowledge
640    of it, so we have to rely on a SendEvent from the client side to
641    receive our keyboard events.)
642 */
643
644 static void
645 hack_event_masks (Display *display, Window w)
646 {
647   hack_event_masks_1 (display, w, 0);
648 }
649 \f
650 /* external entry points */
651
652 Bool
653 ExternalShellReady (Widget w, Window win, long event_mask)
654 {
655   ExternalShellWidget ew = (ExternalShellWidget) w;
656   XEvent event;
657   unsigned long request_num;
658
659   request_num = NextRequest(XtDisplay(w));
660   NOTIFY(ew, extw_notify_init, (long) win, event_mask, 0);
661   if (extw_wait_for_response(w, &event, request_num, extw_notify_init,
662                              ew->externalShell.client_timeout))
663     {
664       /* Xt/Xm extw's have more elaborate focus needs than mere
665          Xlib ones.
666
667          Rather independently, they *don't* need the
668          ConfigureNotify event, having fixed up the window size in
669          ChangeManaged, above, but Xlib extw's do need this.
670       */
671       ew->externalShell.client_type = event.xclient.data.l[2];
672       if (ew->externalShell.client_type != EXTW_TYPE_XLIB)
673         {
674           hack_event_masks (XtDisplay (w), XtWindow (w));
675         }
676       else
677         {
678           XConfigureEvent ev;
679           XWindowAttributes xwa;
680           ev.type = ConfigureNotify;
681           ev.display = XtDisplay (w);
682           ev.event = ev.window = XtWindow (w);
683           XGetWindowAttributes (ev.display, ev.window, &xwa);
684           ev.x = xwa.x; ev.y = xwa.y;
685           ev.width = xwa.width; ev.height = xwa.height;
686           ev.border_width = xwa.border_width;
687           ev.above = None;
688           ev.override_redirect = xwa.override_redirect;
689           XtDispatchEvent ((XEvent *) &ev);
690         }
691       return TRUE;
692     }
693   else
694     return FALSE;
695 }
696
697 void
698 ExternalShellSetFocus (Widget wid)
699 {
700   ExternalShellWidget w = (ExternalShellWidget) wid;
701
702   NOTIFY(w, extw_notify_set_focus, 0, 0, 0);
703 }
704
705 extern void _XtUnregisterWindow (Window, Widget);
706
707 void
708 ExternalShellUnrealize (Widget w)
709 {
710 #if (XT_REVISION > 5)
711   XtUnregisterDrawable (XtDisplay (w), w->core.window);
712 #else
713   extern void _XtUnregisterWindow (Window, Widget);
714   _XtUnregisterWindow (w->core.window, w);
715 #endif
716   w->core.window = 0;
717 }