(U-00024532): Use `->denotational' and `->subsumptive'.
[chise/xemacs-chise.git-] / 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,
175     XtRWindow, sizeof (Window),
176     offset (external_window), XtRImmediate, (XtPointer)0 },
177   { XtNclientTimeout, XtCClientTimeout,
178     XtRInt, sizeof (int),
179     offset(client_timeout), XtRImmediate,(XtPointer)DEFAULT_WM_TIMEOUT },
180   { XtNdeadClient, XtCDeadClient,
181     XtRBoolean, sizeof (Boolean),
182     offset(dead_client), XtRImmediate, (XtPointer)False },
183 };
184
185 static CompositeClassExtensionRec compositeClassExtRec = {
186     NULL,
187     NULLQUARK,
188     XtCompositeExtensionVersion,
189     sizeof (CompositeClassExtensionRec),
190     TRUE,
191 };
192
193 static ShellClassExtensionRec shellClassExtRec = {
194     NULL,
195     NULLQUARK,
196     XtShellExtensionVersion,
197     sizeof (ShellClassExtensionRec),
198     ExternalShellRootGeometryManager
199 };
200
201 ExternalShellClassRec externalShellClassRec = {
202     { /*
203        *        core_class fields
204        */
205     /* superclass         */    (WidgetClass) &shellClassRec,
206     /* class_name         */    "ExternalShell",
207     /* size               */    sizeof (ExternalShellRec),
208     /* Class Initializer  */    NULL,
209     /* class_part_initialize*/  NULL, /* XtInheritClassPartInitialize, */
210     /* Class init'ed ?    */    FALSE,
211     /* initialize         */    ExternalShellInitialize,
212     /* initialize_notify  */    NULL,
213     /* realize            */    ExternalShellRealize,
214     /* actions            */    NULL,
215     /* num_actions        */    0,
216     /* resources          */    resources,
217     /* resource_count     */    XtNumber (resources),
218     /* xrm_class          */    NULLQUARK,
219     /* compress_motion    */    FALSE,
220     /* compress_exposure  */    TRUE,
221     /* compress_enterleave*/    FALSE,
222     /* visible_interest   */    TRUE,
223     /* destroy            */    ExternalShellDestroy, /* XtInheritDestroy, */
224     /* resize             */    XtInheritResize,
225     /* expose             */    NULL,
226     /* set_values         */    NULL, /* XtInheritSetValues, */
227     /* set_values_hook    */    NULL,
228     /* set_values_almost  */    XtInheritSetValuesAlmost,
229     /* get_values_hook    */    NULL,
230     /* accept_focus       */    NULL,
231     /* intrinsics version */    XtVersion,
232     /* callback offsets   */    NULL,
233     /* tm_table           */    NULL,
234     /* query_geometry     */    NULL,
235     /* display_accelerator*/    NULL,
236     /* extension          */    NULL
237   },{ /* Composite */
238     /* geometry_manager   */    XtInheritGeometryManager,
239     /* change_managed     */    ChangeManaged,  /* XtInheritChangeManaged */
240     /* insert_child       */    XtInheritInsertChild,
241     /* delete_child       */    XtInheritDeleteChild,
242     /* extension          */    (XtPointer)&compositeClassExtRec
243   },{ /* Shell */
244     /* extension          */    (XtPointer)&shellClassExtRec
245   },{ /* ExternalShell */
246     0
247   }
248 };
249
250 WidgetClass externalShellWidgetClass = (WidgetClass) &externalShellClassRec;
251
252 static void
253 ExternalShellInitialize (Widget req, Widget new, ArgList args,
254                          Cardinal *num_args)
255 {
256   XtAddEventHandler(new, 0,
257                     TRUE, EventHandler, (XtPointer) NULL);
258   extw_initialize_atoms(XtDisplay(req));
259   extw_which_side = extw_shell_send;
260 }
261
262 static Widget
263 find_managed_child (CompositeWidget w)
264 {
265   int i;
266   Widget *childP = w->composite.children;
267
268   for (i = w->composite.num_children; i; i--, childP++)
269     if (XtIsWidget(*childP) && XtIsManaged(*childP))
270       return *childP;
271   return NULL;
272 }
273
274 #ifndef XtCXtToolkitError
275 # define XtCXtToolkitError "XtToolkitError"
276 #endif
277
278 static void EventHandler(wid, closure, event, continue_to_dispatch)
279      Widget wid;
280      XtPointer closure; /* unused */
281      XEvent *event;
282      Boolean *continue_to_dispatch; /* unused */
283 {
284   ExternalShellWidget w = (ExternalShellWidget) wid;
285
286   if(w->core.window != event->xany.window) {
287     XtAppErrorMsg(XtWidgetToApplicationContext(wid),
288                   "invalidWindow","eventHandler",XtCXtToolkitError,
289                   "Event with wrong window",
290                   (String *)NULL, (Cardinal *)NULL);
291     return;
292   }
293
294   if (event->type == ClientMessage &&
295       event->xclient.data.l[0] == extw_client_send &&
296       event->xclient.message_type == a_EXTW_NOTIFY)
297     switch (event->xclient.data.l[1]) {
298
299     case extw_notify_gm:
300       /* client is alive again. */
301       w->externalShell.dead_client = False;
302       break;
303
304     case extw_notify_qg: {
305       XtWidgetGeometry xwg, xwg_return;
306       XtGeometryResult result;
307       Widget child = find_managed_child((CompositeWidget) w);
308
309       if (child) {
310         extw_get_geometry_value(XtDisplay(wid), XtWindow(wid),
311                                 a_EXTW_QUERY_GEOMETRY, &xwg);
312         result = XtQueryGeometry(child, &xwg, &xwg_return);
313       } else
314         result = XtGeometryYes;
315
316       extw_send_geometry_value(XtDisplay(wid), XtWindow(wid),
317                                a_EXTW_QUERY_GEOMETRY, extw_notify_qg,
318                                result == XtGeometryAlmost ? &xwg_return :
319                                NULL, result);
320       break;
321     }
322
323     case extw_notify_focus_in: {
324       XFocusChangeEvent evnt;
325
326       evnt.type = FocusIn;
327       evnt.serial = LastKnownRequestProcessed (XtDisplay (wid));
328       evnt.send_event = True;
329       evnt.display = XtDisplay (wid);
330       evnt.window = XtWindow (wid);
331       evnt.mode = NotifyNormal;
332       evnt.detail = NotifyAncestor;
333 #ifdef emacs
334       emacs_Xt_handle_focus_event ((XEvent *) &evnt);
335 #else
336       XtDispatchEvent ((XEvent *) &evnt);
337 #endif
338       break;
339     }
340
341     case extw_notify_focus_out: {
342       XFocusChangeEvent evnt;
343
344       evnt.type = FocusOut;
345       evnt.serial = LastKnownRequestProcessed (XtDisplay (wid));
346       evnt.send_event = True;
347       evnt.display = XtDisplay (wid);
348       evnt.window = XtWindow (wid);
349       evnt.mode = NotifyNormal;
350       evnt.detail = NotifyAncestor;
351 #ifdef emacs
352       emacs_Xt_handle_focus_event ((XEvent *) &evnt);
353 #else
354       XtDispatchEvent ((XEvent *) &evnt);
355 #endif
356       break;
357     }
358
359     case extw_notify_end:
360       /* frame should be destroyed. */
361       break;
362     }
363 }
364
365 /* Lifted almost entirely from GetGeometry() in Shell.c
366  */
367 static void
368 GetGeometry (Widget W, Widget child)
369 {
370     ExternalShellWidget w = (ExternalShellWidget)W;
371     int x, y, win_gravity = -1, flag;
372     XSizeHints hints;
373     Window win = w->externalShell.external_window;
374
375     {
376       Window dummy_root;
377       unsigned int dummy_bd_width, dummy_depth, width, height;
378
379       /* determine the existing size of the window. */
380       XGetGeometry(XtDisplay(W), win, &dummy_root, &x, &y, &width,
381                    &height, &dummy_bd_width, &dummy_depth);
382       w->core.width = width;
383       w->core.height = height;
384     }
385
386     if(w->shell.geometry != NULL) {
387         char def_geom[128];
388         int width, height;
389
390         x = w->core.x;
391         y = w->core.y;
392         width = w->core.width;
393         height = w->core.height;
394         hints.flags = 0;
395
396         sprintf( def_geom, "%dx%d+%d+%d", width, height, x, y );
397         flag = XWMGeometry( XtDisplay(W),
398                             XScreenNumberOfScreen(XtScreen(W)),
399                             w->shell.geometry, def_geom,
400                             (unsigned int)w->core.border_width,
401                             &hints, &x, &y, &width, &height,
402                             &win_gravity
403                            );
404         if (flag) {
405             if (flag & XValue) w->core.x = (Position)x;
406             if (flag & YValue) w->core.y = (Position)y;
407             if (flag & WidthValue) w->core.width = (Dimension)width;
408             if (flag & HeightValue) w->core.height = (Dimension)height;
409         }
410         else {
411             String params[2];
412             Cardinal num_params = 2;
413             params[0] = XtName(W);
414             params[1] = w->shell.geometry;
415             XtAppWarningMsg(XtWidgetToApplicationContext(W),
416        "badGeometry", "shellRealize", XtCXtToolkitError,
417        "Shell widget \"%s\" has an invalid geometry specification: \"%s\"",
418                             params, &num_params);
419         }
420     }
421     else
422         flag = 0;
423
424     w->shell.client_specified |= _XtShellGeometryParsed;
425 }
426
427 /* Lifted almost entirely from Realize() in Shell.c
428  */
429 static void ExternalShellRealize (Widget wid, Mask *vmask,
430                                   XSetWindowAttributes *attr)
431 {
432         ExternalShellWidget w = (ExternalShellWidget) wid;
433         Mask mask = *vmask;
434         Window win = w->externalShell.external_window;
435
436         if (!win) {
437           Cardinal count = 1;
438           XtErrorMsg("invalidWindow","shellRealize", XtCXtToolkitError,
439                      "No external window specified for ExternalShell widget %s",
440                      &wid->core.name, &count);
441         }
442
443         if (! (w->shell.client_specified & _XtShellGeometryParsed)) {
444             /* we'll get here only if there was no child the first
445                time we were realized.  If the shell was Unrealized
446                and then re-Realized, we probably don't want to
447                re-evaluate the defaults anyway.
448              */
449             GetGeometry(wid, (Widget)NULL);
450         }
451         else if (w->core.background_pixmap == XtUnspecifiedPixmap) {
452             /* I attempt to inherit my child's background to avoid screen flash
453              * if there is latency between when I get resized and when my child
454              * is resized.  Background=None is not satisfactory, as I want the
455              * user to get immediate feedback on the new dimensions (most
456              * particularly in the case of a non-reparenting wm).  It is
457              * especially important to have the server clear any old cruft
458              * from the display when I am resized larger.
459              */
460             Widget *childP = w->composite.children;
461             int i;
462             for (i = w->composite.num_children; i; i--, childP++) {
463                 if (XtIsWidget(*childP) && XtIsManaged(*childP)) {
464                     if ((*childP)->core.background_pixmap
465                             != XtUnspecifiedPixmap) {
466                         mask &= ~(CWBackPixel);
467                         mask |= CWBackPixmap;
468                         attr->background_pixmap =
469                             w->core.background_pixmap =
470                                 (*childP)->core.background_pixmap;
471                     } else {
472                         attr->background_pixel =
473                             w->core.background_pixel =
474                                 (*childP)->core.background_pixel;
475                     }
476                     break;
477                 }
478             }
479         }
480
481         if(w->shell.save_under) {
482                 mask |= CWSaveUnder;
483                 attr->save_under = TRUE;
484         }
485         if(w->shell.override_redirect) {
486                 mask |= CWOverrideRedirect;
487                 attr->override_redirect = TRUE;
488         }
489         if (wid->core.width == 0 || wid->core.height == 0) {
490             Cardinal count = 1;
491             XtErrorMsg("invalidDimension", "shellRealize", XtCXtToolkitError,
492                        "Shell widget %s has zero width and/or height",
493                        &wid->core.name, &count);
494         }
495         wid->core.window = win;
496         XChangeWindowAttributes(XtDisplay(wid), wid->core.window,
497                                 mask, attr);
498
499 }
500
501 static void ExternalShellDestroy(wid)
502         Widget wid;
503 {
504   ExternalShellWidget w = (ExternalShellWidget)wid;
505
506   if (XtIsRealized(wid))
507     ExternalShellUnrealize(wid);
508
509   NOTIFY(w, extw_notify_end, 0, 0, 0);
510 }
511
512 /* Invoke matching routine from superclass, but first override its
513    geometry opinions with our own routine */
514
515 static void ChangeManaged(wid)
516     Widget wid;
517 {
518   if (!XtIsRealized (wid))
519     GetGeometry(wid, (Widget)NULL);
520   (*((ShellClassRec*)externalShellClassRec.core_class.superclass)->
521    composite_class.change_managed)(wid);
522 }
523
524 /* Based on RootGeometryManager() in Shell.c */
525
526 static XtGeometryResult ExternalShellRootGeometryManager(gw, request, reply)
527     Widget gw;
528     XtWidgetGeometry *request, *reply;
529 {
530     ExternalShellWidget w = (ExternalShellWidget)gw;
531     unsigned int mask = request->request_mode;
532     XEvent event;
533     int oldx, oldy, oldwidth, oldheight, oldborder_width;
534     unsigned long request_num;
535     XtWidgetGeometry req = *request; /* don't modify caller's structure */
536
537     oldx = w->core.x;
538     oldy = w->core.y;
539     oldwidth = w->core.width;
540     oldheight = w->core.height;
541     oldborder_width = w->core.border_width;
542
543 #define PutBackGeometry() \
544         { w->core.x = oldx; \
545           w->core.y = oldy; \
546           w->core.width = oldwidth; \
547           w->core.height = oldheight; \
548           w->core.border_width = oldborder_width; }
549
550     if (mask & CWX) {
551       if (w->core.x == request->x) mask &= ~CWX;
552       else
553         w->core.x = request->x;
554     }
555     if (mask & CWY) {
556       if (w->core.y == request->y) mask &= ~CWY;
557       else w->core.y = request->y;
558     }
559     if (mask & CWBorderWidth) {
560       if (w->core.border_width == request->border_width)
561               mask &= ~CWBorderWidth;
562       else w->core.border_width = request->border_width;
563     }
564     if (mask & CWWidth) {
565       if (w->core.width == request->width) mask &= ~CWWidth;
566       else w->core.width = request->width;
567     }
568     if (mask & CWHeight) {
569       if (w->core.height == request->height) mask &= ~CWHeight;
570       else w->core.height = request->height;
571     }
572
573     if (!XtIsRealized((Widget)w)) return XtGeometryYes;
574
575     req.sibling = None;
576     req.request_mode = mask & ~CWSibling;
577     request_num = NextRequest(XtDisplay(w));
578     extw_send_geometry_value(XtDisplay(w), XtWindow(w),
579                              a_EXTW_GEOMETRY_MANAGER,
580                              extw_notify_gm, &req, 0);
581
582     if (w->externalShell.dead_client == TRUE) {
583       /* The client is sick.  Refuse the request.
584        * If the client recovers and decides to honor the
585        * request, it will be handled by Shell's EventHandler().
586        */
587       PutBackGeometry();
588       return XtGeometryNo;
589     }
590
591     if (extw_wait_for_response(gw, &event, request_num, extw_notify_gm,
592                                w->externalShell.client_timeout)) {
593       XtGeometryResult result = (XtGeometryResult) event.xclient.data.l[2];
594
595       if (result != XtGeometryYes)
596         PutBackGeometry();
597       if (result == XtGeometryAlmost) {
598         extw_get_geometry_value(XtDisplay(w), XtWindow(w),
599                                 a_EXTW_GEOMETRY_MANAGER, reply);
600       }
601       return result;
602     } else {
603       w->externalShell.dead_client = TRUE; /* timed out; must be broken */
604       PutBackGeometry();
605       return XtGeometryNo;
606     }
607 #undef PutBackGeometry
608 }
609
610 static void
611 hack_event_masks_1 (Display *display, Window w, int this_window_propagate)
612 {
613   Window root, parent, *children;
614   unsigned int nchildren;
615   unsigned int i;
616
617   if (!XQueryTree (display, w, &root, &parent, &children, &nchildren))
618     return;
619   for (i=0; i<nchildren; i++)
620     hack_event_masks_1 (display, children[i], 1);
621   if (children)
622     XFree (children);
623   {
624     XWindowAttributes xwa;
625     XSetWindowAttributes xswa;
626     if (XGetWindowAttributes (display, w, &xwa)) {
627       xswa.event_mask = xwa.your_event_mask & ~KeyPressMask;
628       if (this_window_propagate)
629         xswa.do_not_propagate_mask = xwa.do_not_propagate_mask & ~KeyPressMask;
630       XChangeWindowAttributes (display, w, CWEventMask, &xswa);
631     }
632   }
633 }
634
635 /* fix all event masks on all subwindows of the specified window so that
636    all key presses in any subwindow filter up to the specified window.
637
638    We have to do this cruftiness with external widgets so that we don't
639    step on Motif's concept of keyboard focus.  (Due to the nature of
640    Xt and Motif, X's idea of who gets the keyboard events may not jive
641    with Xt's idea of same, and Xt redirects the events to the proper
642    window.  This occurs on the client side and we have no knowledge
643    of it, so we have to rely on a SendEvent from the client side to
644    receive our keyboard events.)
645 */
646
647 static void
648 hack_event_masks (Display *display, Window w)
649 {
650   hack_event_masks_1 (display, w, 0);
651 }
652 \f
653 /* external entry points */
654
655 Bool
656 ExternalShellReady (Widget w, Window win, long event_mask)
657 {
658   ExternalShellWidget ew = (ExternalShellWidget) w;
659   XEvent event;
660   unsigned long request_num;
661
662   request_num = NextRequest(XtDisplay(w));
663   NOTIFY(ew, extw_notify_init, (long) win, event_mask, 0);
664   if (extw_wait_for_response(w, &event, request_num, extw_notify_init,
665                              ew->externalShell.client_timeout))
666     {
667       /* Xt/Xm extw's have more elaborate focus needs than mere
668          Xlib ones.
669
670          Rather independently, they *don't* need the
671          ConfigureNotify event, having fixed up the window size in
672          ChangeManaged, above, but Xlib extw's do need this.
673       */
674       ew->externalShell.client_type = event.xclient.data.l[2];
675       if (ew->externalShell.client_type != EXTW_TYPE_XLIB)
676         {
677           hack_event_masks (XtDisplay (w), XtWindow (w));
678         }
679       else
680         {
681           XConfigureEvent ev;
682           XWindowAttributes xwa;
683           ev.type = ConfigureNotify;
684           ev.display = XtDisplay (w);
685           ev.event = ev.window = XtWindow (w);
686           XGetWindowAttributes (ev.display, ev.window, &xwa);
687           ev.x = xwa.x; ev.y = xwa.y;
688           ev.width = xwa.width; ev.height = xwa.height;
689           ev.border_width = xwa.border_width;
690           ev.above = None;
691           ev.override_redirect = xwa.override_redirect;
692           XtDispatchEvent ((XEvent *) &ev);
693         }
694       return TRUE;
695     }
696   else
697     return FALSE;
698 }
699
700 void
701 ExternalShellSetFocus (Widget wid)
702 {
703   ExternalShellWidget w = (ExternalShellWidget) wid;
704
705   NOTIFY(w, extw_notify_set_focus, 0, 0, 0);
706 }
707
708 extern void _XtUnregisterWindow (Window, Widget);
709
710 void
711 ExternalShellUnrealize (Widget w)
712 {
713 #if (XT_REVISION > 5)
714   XtUnregisterDrawable (XtDisplay (w), w->core.window);
715 #else
716   extern void _XtUnregisterWindow (Window, Widget);
717   _XtUnregisterWindow (w->core.window, w);
718 #endif
719   w->core.window = 0;
720 }