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