Mercurial > hg > xemacs-beta
annotate src/ExternalShell.c @ 5561:9a93bc90b3bd
Add a defsetf for get-char-table, necessary for the tests in the last commit.
lisp/ChangeLog addition:
2011-09-04 Aidan Kehoe <kehoea@parhasard.net>
* cl-macs.el (get-char-table): Add a defsetf for this.
| author | Aidan Kehoe <kehoea@parhasard.net> |
|---|---|
| date | Sun, 04 Sep 2011 20:35:31 +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 } |
