Mercurial > hg > xemacs-beta
comparison src/ExternalShell.c @ 428:3ecd8885ac67 r21-2-22
Import from CVS: tag r21-2-22
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:28:15 +0200 |
parents | |
children | 8de8e3f6228a |
comparison
equal
deleted
inserted
replaced
427:0a0253eac470 | 428:3ecd8885ac67 |
---|---|
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 | |
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 } |