1/*********************************************************** 2Copyright (c) 1993, Oracle and/or its affiliates. 3 4Permission is hereby granted, free of charge, to any person obtaining a 5copy of this software and associated documentation files (the "Software"), 6to deal in the Software without restriction, including without limitation 7the rights to use, copy, modify, merge, publish, distribute, sublicense, 8and/or sell copies of the Software, and to permit persons to whom the 9Software is furnished to do so, subject to the following conditions: 10 11The above copyright notice and this permission notice (including the next 12paragraph) shall be included in all copies or substantial portions of the 13Software. 14 15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21DEALINGS IN THE SOFTWARE. 22 23Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. 24 25 All Rights Reserved 26 27Permission to use, copy, modify, and distribute this software and its 28documentation for any purpose and without fee is hereby granted, 29provided that the above copyright notice appear in all copies and that 30both that copyright notice and this permission notice appear in 31supporting documentation, and that the name of Digital not be 32used in advertising or publicity pertaining to distribution of the 33software without specific, written prior permission. 34 35DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 36ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 37DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 38ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 39WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 40ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 41SOFTWARE. 42 43******************************************************************/ 44 45/* 46 47Copyright 1987, 1988, 1994, 1998 The Open Group 48 49Permission to use, copy, modify, distribute, and sell this software and its 50documentation for any purpose is hereby granted without fee, provided that 51the above copyright notice appear in all copies and that both that 52copyright notice and this permission notice appear in supporting 53documentation. 54 55The above copyright notice and this permission notice shall be included in 56all copies or substantial portions of the Software. 57 58THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 59IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 60FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 61OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 62AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 63CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 64 65Except as contained in this notice, the name of The Open Group shall not be 66used in advertising or otherwise to promote the sale, use or other dealings 67in this Software without prior written authorization from The Open Group. 68 69*/ 70 71#define INTRINSIC_C 72 73#ifdef HAVE_CONFIG_H 74#include <config.h> 75#endif 76#include "IntrinsicI.h" 77#include "VarargsI.h" /* for geoTattler */ 78#ifndef NO_IDENTIFY_WINDOWS 79#include <X11/Xatom.h> 80#endif 81#include <sys/stat.h> 82#ifdef WIN32 83#include <direct.h> /* for _getdrives() */ 84#endif 85 86#include <stdio.h> 87#include <stdlib.h> 88 89String XtCXtToolkitError = "XtToolkitError"; 90 91Boolean 92XtIsSubclass(Widget widget, WidgetClass myWidgetClass) 93{ 94 register WidgetClass w; 95 Boolean retval = FALSE; 96 97 WIDGET_TO_APPCON(widget); 98 99 LOCK_APP(app); 100 LOCK_PROCESS; 101 for (w = widget->core.widget_class; w != NULL; w = w->core_class.superclass) 102 if (w == myWidgetClass) { 103 retval = TRUE; 104 break; 105 } 106 UNLOCK_PROCESS; 107 UNLOCK_APP(app); 108 return retval; 109} /* XtIsSubclass */ 110 111Boolean 112_XtCheckSubclassFlag(Widget object, _XtXtEnum flag) 113{ 114 Boolean retval; 115 116 LOCK_PROCESS; 117 if (object->core.widget_class->core_class.class_inited & flag) 118 retval = TRUE; 119 else 120 retval = FALSE; 121 UNLOCK_PROCESS; 122 return retval; 123} /*_XtVerifySubclass */ 124 125Boolean 126_XtIsSubclassOf(Widget object, 127 WidgetClass myWidgetClass, 128 WidgetClass superClass, 129 _XtXtEnum flag) 130{ 131 LOCK_PROCESS; 132 if (!(object->core.widget_class->core_class.class_inited & flag)) { 133 UNLOCK_PROCESS; 134 return False; 135 } 136 else { 137 register WidgetClass c = object->core.widget_class; 138 139 while (c != superClass) { 140 if (c == myWidgetClass) { 141 UNLOCK_PROCESS; 142 return True; 143 } 144 c = c->core_class.superclass; 145 } 146 UNLOCK_PROCESS; 147 return False; 148 } 149} /*_XtIsSubclassOf */ 150 151XtPointer 152XtGetClassExtension(WidgetClass object_class, 153 Cardinal byte_offset, 154 XrmQuark type, long version, Cardinal record_size) 155{ 156 ObjectClassExtension ext; 157 158 LOCK_PROCESS; 159 160 ext = *(ObjectClassExtension *) ((char *) object_class + byte_offset); 161 while (ext && (ext->record_type != type || ext->version < version 162 || ext->record_size < record_size)) { 163 ext = (ObjectClassExtension) ext->next_extension; 164 } 165 166 UNLOCK_PROCESS; 167 return (XtPointer) ext; 168} 169 170static void 171ComputeWindowAttributes(Widget widget, 172 XtValueMask *value_mask, 173 XSetWindowAttributes *values) 174{ 175 XtExposeProc expose; 176 177 *value_mask = CWEventMask | CWColormap; 178 (*values).event_mask = (long) XtBuildEventMask(widget); 179 (*values).colormap = widget->core.colormap; 180 if (widget->core.background_pixmap != XtUnspecifiedPixmap) { 181 *value_mask |= CWBackPixmap; 182 (*values).background_pixmap = widget->core.background_pixmap; 183 } 184 else { 185 *value_mask |= CWBackPixel; 186 (*values).background_pixel = widget->core.background_pixel; 187 } 188 if (widget->core.border_pixmap != XtUnspecifiedPixmap) { 189 *value_mask |= CWBorderPixmap; 190 (*values).border_pixmap = widget->core.border_pixmap; 191 } 192 else { 193 *value_mask |= CWBorderPixel; 194 (*values).border_pixel = widget->core.border_pixel; 195 } 196 LOCK_PROCESS; 197 expose = widget->core.widget_class->core_class.expose; 198 UNLOCK_PROCESS; 199 if (expose == (XtExposeProc) NULL) { 200 /* Try to avoid redisplay upon resize by making bit_gravity the same 201 as the default win_gravity */ 202 *value_mask |= CWBitGravity; 203 (*values).bit_gravity = NorthWestGravity; 204 } 205} /* ComputeWindowAttributes */ 206 207static void 208CallChangeManaged(register Widget widget) 209{ 210 register Cardinal i; 211 XtWidgetProc change_managed; 212 register WidgetList children; 213 int managed_children = 0; 214 215 register CompositePtr cpPtr; 216 register CompositePartPtr clPtr; 217 218 if (XtIsComposite(widget)) { 219 cpPtr = (CompositePtr) &((CompositeWidget) widget)->composite; 220 clPtr = (CompositePartPtr) &((CompositeWidgetClass) 221 widget->core. 222 widget_class)->composite_class; 223 } 224 else 225 return; 226 227 children = cpPtr->children; 228 LOCK_PROCESS; 229 change_managed = clPtr->change_managed; 230 UNLOCK_PROCESS; 231 232 /* CallChangeManaged for all children */ 233 for (i = cpPtr->num_children; i != 0; --i) { 234 CallChangeManaged(children[i - 1]); 235 if (XtIsManaged(children[i - 1])) 236 managed_children++; 237 } 238 239 if (change_managed != NULL && managed_children != 0) { 240 CALLGEOTAT(_XtGeoTrace(widget, "Call \"%s\"[%d,%d]'s changemanaged\n", 241 XtName(widget), 242 widget->core.width, widget->core.height)); 243 (*change_managed) (widget); 244 } 245} /* CallChangeManaged */ 246 247static void 248MapChildren(CompositePart *cwp) 249{ 250 Cardinal i; 251 WidgetList children; 252 253 children = cwp->children; 254 for (i = 0; i < cwp->num_children; i++) { 255 Widget child = children[i]; 256 257 if (XtIsWidget(child)) { 258 if (child->core.managed && child->core.mapped_when_managed) { 259 XtMapWidget(children[i]); 260 } 261 } 262 } 263} /* MapChildren */ 264 265static Boolean 266ShouldMapAllChildren(CompositePart *cwp) 267{ 268 Cardinal i; 269 WidgetList children; 270 271 children = cwp->children; 272 for (i = 0; i < cwp->num_children; i++) { 273 Widget child = children[i]; 274 275 if (XtIsWidget(child)) { 276 if (XtIsRealized(child) && (!(child->core.managed 277 && child->core. 278 mapped_when_managed))) { 279 return False; 280 } 281 } 282 } 283 284 return True; 285} /* ShouldMapAllChildren */ 286 287static void 288RealizeWidget(Widget widget) 289{ 290 XtValueMask value_mask; 291 XSetWindowAttributes values; 292 XtRealizeProc realize; 293 Window window; 294 Display *display; 295 String class_name; 296 Widget hookobj; 297 298 if (!XtIsWidget(widget) || XtIsRealized(widget)) 299 return; 300 display = XtDisplay(widget); 301 302 _XtInstallTranslations(widget); 303 304 ComputeWindowAttributes(widget, &value_mask, &values); 305 LOCK_PROCESS; 306 realize = widget->core.widget_class->core_class.realize; 307 class_name = widget->core.widget_class->core_class.class_name; 308 UNLOCK_PROCESS; 309 if (realize == NULL) 310 XtAppErrorMsg(XtWidgetToApplicationContext(widget), 311 "invalidProcedure", "realizeProc", XtCXtToolkitError, 312 "No realize class procedure defined", NULL, NULL); 313 else { 314 CALLGEOTAT(_XtGeoTrace(widget, "Call \"%s\"[%d,%d]'s realize proc\n", 315 XtName(widget), 316 widget->core.width, widget->core.height)); 317 (*realize) (widget, &value_mask, &values); 318 } 319 window = XtWindow(widget); 320 hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget)); 321 if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { 322 XtChangeHookDataRec call_data; 323 324 call_data.type = XtHrealizeWidget; 325 call_data.widget = widget; 326 XtCallCallbackList(hookobj, 327 ((HookObject) hookobj)->hooks.changehook_callbacks, 328 (XtPointer) &call_data); 329 } 330#ifndef NO_IDENTIFY_WINDOWS 331 if (_XtGetPerDisplay(display)->appContext->identify_windows) { 332 int len_nm, len_cl; 333 char *s; 334 335 len_nm = widget->core.name ? (int) strlen(widget->core.name) : 0; 336 len_cl = (int) strlen(class_name); 337 s = __XtMalloc((unsigned) (len_nm + len_cl + 2)); 338 s[0] = '\0'; 339 if (len_nm) 340 strcpy(s, widget->core.name); 341 strcpy(s + len_nm + 1, class_name); 342 XChangeProperty(display, window, 343 XInternAtom(display, "_MIT_OBJ_CLASS", 344 False), 345 XA_STRING, 8, PropModeReplace, (unsigned char *) s, 346 len_nm + len_cl + 2); 347 XtFree(s); 348 } 349#endif 350#ifdef notdef 351 _XtRegisterAsyncHandlers(widget); 352#endif 353 /* (re)register any grabs extant in the translations */ 354 _XtRegisterGrabs(widget); 355 /* reregister any grabs added with XtGrab{Button,Key} */ 356 _XtRegisterPassiveGrabs(widget); 357 XtRegisterDrawable(display, window, widget); 358 359 _XtExtensionSelect(widget); 360 361 if (XtIsComposite(widget)) { 362 Cardinal i; 363 CompositePart *cwp = &(((CompositeWidget) widget)->composite); 364 WidgetList children = cwp->children; 365 366 /* Realize all children */ 367 for (i = cwp->num_children; i != 0; --i) { 368 RealizeWidget(children[i - 1]); 369 } 370 /* Map children that are managed and mapped_when_managed */ 371 372 if (cwp->num_children != 0) { 373 if (ShouldMapAllChildren(cwp)) { 374 XMapSubwindows(display, window); 375 } 376 else { 377 MapChildren(cwp); 378 } 379 } 380 } 381 382 /* If this is the application's popup shell, map it */ 383 if (widget->core.parent == NULL && widget->core.mapped_when_managed) { 384 XtMapWidget(widget); 385 } 386} /* RealizeWidget */ 387 388void 389XtRealizeWidget(Widget widget) 390{ 391 WIDGET_TO_APPCON(widget); 392 393 LOCK_APP(app); 394 if (XtIsRealized(widget)) { 395 UNLOCK_APP(app); 396 return; 397 } 398 CallChangeManaged(widget); 399 RealizeWidget(widget); 400 UNLOCK_APP(app); 401} /* XtRealizeWidget */ 402 403static void 404UnrealizeWidget(Widget widget) 405{ 406 CompositeWidget cw; 407 408 if (!XtIsWidget(widget) || !XtIsRealized(widget)) 409 return; 410 411 /* If this is the application's popup shell, unmap it? */ 412 /* no, the window is being destroyed */ 413 414 /* Recurse on children */ 415 if (XtIsComposite(widget)) { 416 Cardinal i; 417 WidgetList children; 418 419 cw = (CompositeWidget) widget; 420 children = cw->composite.children; 421 /* Unrealize all children */ 422 for (i = cw->composite.num_children; i != 0; --i) { 423 UnrealizeWidget(children[i - 1]); 424 } 425 /* Unmap children that are managed and mapped_when_managed? */ 426 /* No, it's ok to be managed and unrealized as long as your parent */ 427 /* is unrealized. XtUnrealize widget makes sure the "top" widget */ 428 /* is unmanaged, we can ignore all descendents */ 429 } 430 431 if (XtHasCallbacks(widget, XtNunrealizeCallback) == XtCallbackHasSome) 432 XtCallCallbacks(widget, XtNunrealizeCallback, NULL); 433 434 /* Unregister window */ 435 XtUnregisterDrawable(XtDisplay(widget), XtWindow(widget)); 436 437 /* Remove Event Handlers */ 438 /* remove grabs. Happens automatically when window is destroyed. */ 439 440 /* Destroy X Window, done at outer level with one request */ 441 widget->core.window = None; 442 443 /* Removing the event handler here saves having to keep track if 444 * the translation table is changed while the widget is unrealized. 445 */ 446 _XtRemoveTranslations(widget); 447} /* UnrealizeWidget */ 448 449void 450XtUnrealizeWidget(Widget widget) 451{ 452 Window window; 453 Widget hookobj; 454 455 WIDGET_TO_APPCON(widget); 456 457 LOCK_APP(app); 458 window = XtWindow(widget); 459 if (!XtIsRealized(widget)) { 460 UNLOCK_APP(app); 461 return; 462 } 463 if (widget->core.managed && widget->core.parent != NULL) 464 XtUnmanageChild(widget); 465 UnrealizeWidget(widget); 466 if (window != None) 467 XDestroyWindow(XtDisplay(widget), window); 468 hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget)); 469 if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { 470 XtChangeHookDataRec call_data; 471 472 call_data.type = XtHunrealizeWidget; 473 call_data.widget = widget; 474 XtCallCallbackList(hookobj, 475 ((HookObject) hookobj)->hooks.changehook_callbacks, 476 (XtPointer) &call_data); 477 } 478 UNLOCK_APP(app); 479} /* XtUnrealizeWidget */ 480 481void 482XtCreateWindow(Widget widget, 483 unsigned int window_class, 484 Visual *visual, 485 XtValueMask value_mask, 486 XSetWindowAttributes *attributes) 487{ 488 XtAppContext app = XtWidgetToApplicationContext(widget); 489 490 LOCK_APP(app); 491 if (widget->core.window == None) { 492 if (widget->core.width == 0 || widget->core.height == 0) { 493 Cardinal count = 1; 494 495 XtAppErrorMsg(app, 496 "invalidDimension", "xtCreateWindow", 497 XtCXtToolkitError, 498 "Widget %s has zero width and/or height", 499 &widget->core.name, &count); 500 } 501 widget->core.window = 502 XCreateWindow(XtDisplay(widget), 503 (widget->core.parent ? 504 widget->core.parent->core.window : 505 widget->core.screen->root), 506 (int) widget->core.x, (int) widget->core.y, 507 (unsigned) widget->core.width, 508 (unsigned) widget->core.height, 509 (unsigned) widget->core.border_width, 510 (int) widget->core.depth, window_class, visual, 511 value_mask, attributes); 512 } 513 UNLOCK_APP(app); 514} /* XtCreateWindow */ 515 516/* ---------------- XtNameToWidget ----------------- */ 517 518static Widget NameListToWidget(Widget root, 519 XrmNameList names, 520 XrmBindingList bindings, 521 int in_depth, int *out_depth, int *found_depth); 522 523typedef Widget(*NameMatchProc) (XrmNameList, 524 XrmBindingList, 525 WidgetList, Cardinal, int, int *, int *); 526 527static Widget 528MatchExactChildren(XrmNameList names, 529 XrmBindingList bindings, 530 register WidgetList children, 531 register Cardinal num, 532 int in_depth, 533 int *out_depth, 534 int *found_depth) 535{ 536 register Cardinal i; 537 register XrmName name = *names; 538 Widget w, result = NULL; 539 int d, min = 10000; 540 541 for (i = 0; i < num; i++) { 542 if (name == children[i]->core.xrm_name) { 543 w = NameListToWidget(children[i], &names[1], &bindings[1], 544 in_depth + 1, &d, found_depth); 545 if (w != NULL && d < min) { 546 result = w; 547 min = d; 548 } 549 } 550 } 551 *out_depth = min; 552 return result; 553} 554 555static Widget 556MatchWildChildren(XrmNameList names, 557 XrmBindingList bindings, 558 register WidgetList children, 559 register Cardinal num, 560 int in_depth, 561 int *out_depth, 562 int *found_depth) 563{ 564 register Cardinal i; 565 Widget w, result = NULL; 566 int d, min = 10000; 567 568 for (i = 0; i < num; i++) { 569 w = NameListToWidget(children[i], names, bindings, 570 in_depth + 1, &d, found_depth); 571 if (w != NULL && d < min) { 572 result = w; 573 min = d; 574 } 575 } 576 *out_depth = min; 577 return result; 578} 579 580static Widget 581SearchChildren(Widget root, 582 XrmNameList names, 583 XrmBindingList bindings, 584 NameMatchProc matchproc, 585 int in_depth, 586 int *out_depth, 587 int *found_depth) 588{ 589 Widget w1 = NULL, w2; 590 int d1, d2; 591 592 if (XtIsComposite(root)) { 593 w1 = (*matchproc) (names, bindings, 594 ((CompositeWidget) root)->composite.children, 595 ((CompositeWidget) root)->composite.num_children, 596 in_depth, &d1, found_depth); 597 } 598 else 599 d1 = 10000; 600 w2 = (*matchproc) (names, bindings, root->core.popup_list, 601 root->core.num_popups, in_depth, &d2, found_depth); 602 *out_depth = (d1 < d2 ? d1 : d2); 603 return (d1 < d2 ? w1 : w2); 604} 605 606static Widget 607NameListToWidget(register Widget root, 608 XrmNameList names, 609 XrmBindingList bindings, 610 int in_depth, 611 int *out_depth, 612 int *found_depth) 613{ 614 int d1, d2; 615 616 if (in_depth >= *found_depth) { 617 *out_depth = 10000; 618 return NULL; 619 } 620 621 if (names[0] == NULLQUARK) { 622 *out_depth = *found_depth = in_depth; 623 return root; 624 } 625 626 if (!XtIsWidget(root)) { 627 *out_depth = 10000; 628 return NULL; 629 } 630 631 if (*bindings == XrmBindTightly) { 632 return SearchChildren(root, names, bindings, MatchExactChildren, 633 in_depth, out_depth, found_depth); 634 635 } 636 else { /* XrmBindLoosely */ 637 Widget w1, w2; 638 639 w1 = SearchChildren(root, names, bindings, MatchExactChildren, 640 in_depth, &d1, found_depth); 641 w2 = SearchChildren(root, names, bindings, MatchWildChildren, 642 in_depth, &d2, found_depth); 643 *out_depth = (d1 < d2 ? d1 : d2); 644 return (d1 < d2 ? w1 : w2); 645 } 646} /* NameListToWidget */ 647 648Widget 649XtNameToWidget(Widget root, _Xconst char *name) 650{ 651 XrmName *names; 652 XrmBinding *bindings; 653 int len, depth, found = 10000; 654 Widget result; 655 656 WIDGET_TO_APPCON(root); 657 658 len = (int) strlen(name); 659 if (len == 0) 660 return NULL; 661 662 LOCK_APP(app); 663 names = (XrmName *) ALLOCATE_LOCAL((unsigned) (len + 1) * sizeof(XrmName)); 664 bindings = (XrmBinding *) 665 ALLOCATE_LOCAL((unsigned) (len + 1) * sizeof(XrmBinding)); 666 if (names == NULL || bindings == NULL) 667 _XtAllocError(NULL); 668 669 XrmStringToBindingQuarkList(name, bindings, names); 670 if (names[0] == NULLQUARK) { 671 DEALLOCATE_LOCAL((char *) bindings); 672 DEALLOCATE_LOCAL((char *) names); 673 UNLOCK_APP(app); 674 return NULL; 675 } 676 677 result = NameListToWidget(root, names, bindings, 0, &depth, &found); 678 679 DEALLOCATE_LOCAL((char *) bindings); 680 DEALLOCATE_LOCAL((char *) names); 681 UNLOCK_APP(app); 682 return result; 683} /* XtNameToWidget */ 684 685/* Define user versions of intrinsics macros */ 686 687#undef XtDisplayOfObject 688Display * 689XtDisplayOfObject(Widget object) 690{ 691 /* Attempts to LockApp() here will generate endless recursive loops */ 692 if (XtIsSubclass(object, hookObjectClass)) 693 return DisplayOfScreen(((HookObject) object)->hooks.screen); 694 return XtDisplay(XtIsWidget(object) ? object : _XtWindowedAncestor(object)); 695} 696 697#undef XtDisplay 698Display * 699XtDisplay(Widget widget) 700{ 701 /* Attempts to LockApp() here will generate endless recursive loops */ 702 return DisplayOfScreen(widget->core.screen); 703} 704 705#undef XtScreenOfObject 706Screen * 707XtScreenOfObject(Widget object) 708{ 709 /* Attempts to LockApp() here will generate endless recursive loops */ 710 if (XtIsSubclass(object, hookObjectClass)) 711 return ((HookObject) object)->hooks.screen; 712 return XtScreen(XtIsWidget(object) ? object : _XtWindowedAncestor(object)); 713} 714 715#undef XtScreen 716Screen * 717XtScreen(Widget widget) 718{ 719 /* Attempts to LockApp() here will generate endless recursive loops */ 720 return widget->core.screen; 721} 722 723#undef XtWindowOfObject 724Window 725XtWindowOfObject(Widget object) 726{ 727 return XtWindow(XtIsWidget(object) ? object : _XtWindowedAncestor(object)); 728} 729 730#undef XtWindow 731Window 732XtWindow(Widget widget) 733{ 734 return widget->core.window; 735} 736 737#undef XtSuperclass 738WidgetClass 739XtSuperclass(Widget widget) 740{ 741 WidgetClass retval; 742 743 LOCK_PROCESS; 744 retval = XtClass(widget)->core_class.superclass; 745 UNLOCK_PROCESS; 746 return retval; 747} 748 749#undef XtClass 750WidgetClass 751XtClass(Widget widget) 752{ 753 WidgetClass retval; 754 755 LOCK_PROCESS; 756 retval = widget->core.widget_class; 757 UNLOCK_PROCESS; 758 return retval; 759} 760 761#undef XtIsManaged 762Boolean 763XtIsManaged(Widget object) 764{ 765 Boolean retval; 766 767 WIDGET_TO_APPCON(object); 768 769 LOCK_APP(app); 770 if (XtIsRectObj(object)) 771 retval = object->core.managed; 772 else 773 retval = False; 774 UNLOCK_APP(app); 775 return retval; 776} 777 778#undef XtIsRealized 779Boolean 780XtIsRealized(Widget object) 781{ 782 Boolean retval; 783 784 WIDGET_TO_APPCON(object); 785 786 LOCK_APP(app); 787 retval = XtWindowOfObject(object) != None; 788 UNLOCK_APP(app); 789 return retval; 790} /* XtIsRealized */ 791 792#undef XtIsSensitive 793Boolean 794XtIsSensitive(Widget object) 795{ 796 Boolean retval; 797 798 WIDGET_TO_APPCON(object); 799 800 LOCK_APP(app); 801 if (XtIsRectObj(object)) 802 retval = object->core.sensitive && object->core.ancestor_sensitive; 803 else 804 retval = False; 805 UNLOCK_APP(app); 806 return retval; 807} 808 809/* 810 * Internal routine; must be called only after XtIsWidget returns false 811 */ 812Widget 813_XtWindowedAncestor(register Widget object) 814{ 815 Widget obj = object; 816 817 for (object = XtParent(object); object && !XtIsWidget(object);) 818 object = XtParent(object); 819 820 if (object == NULL) { 821 String params = XtName(obj); 822 Cardinal num_params = 1; 823 824 XtErrorMsg("noWidgetAncestor", "windowedAncestor", XtCXtToolkitError, 825 "Object \"%s\" does not have windowed ancestor", 826 ¶ms, &num_params); 827 } 828 829 return object; 830} 831 832#undef XtParent 833Widget 834XtParent(Widget widget) 835{ 836 /* Attempts to LockApp() here will generate endless recursive loops */ 837 return widget->core.parent; 838} 839 840#undef XtName 841String 842XtName(Widget object) 843{ 844 /* Attempts to LockApp() here will generate endless recursive loops */ 845 return XrmQuarkToString(object->core.xrm_name); 846} 847 848Boolean 849XtIsObject(Widget object) 850{ 851 WidgetClass wc; 852 String class_name; 853 854 /* perform basic sanity checks */ 855 if (object->core.self != object || object->core.xrm_name == NULLQUARK) 856 return False; 857 858 LOCK_PROCESS; 859 wc = object->core.widget_class; 860 if (wc->core_class.class_name == NULL || 861 wc->core_class.xrm_class == NULLQUARK || 862 (class_name = XrmClassToString(wc->core_class.xrm_class)) == NULL || 863 strcmp(wc->core_class.class_name, class_name) != 0) { 864 UNLOCK_PROCESS; 865 return False; 866 } 867 UNLOCK_PROCESS; 868 869 if (XtIsWidget(object)) { 870 if (object->core.name == NULL || 871 (class_name = XrmNameToString(object->core.xrm_name)) == NULL || 872 strcmp(object->core.name, class_name) != 0) 873 return False; 874 } 875 return True; 876} 877 878#if defined(WIN32) 879static int 880access_file(char *path, char *pathbuf, int len_pathbuf, char **pathret) 881{ 882 if (access(path, F_OK) == 0) { 883 if (strlen(path) < len_pathbuf) 884 *pathret = pathbuf; 885 else 886 *pathret = XtMalloc(strlen(path)); 887 if (*pathret) { 888 strcpy(*pathret, path); 889 return 1; 890 } 891 } 892 return 0; 893} 894 895static int 896AccessFile(char *path, char *pathbuf, int len_pathbuf, char **pathret) 897{ 898 unsigned long drives; 899 int i, len; 900 char *drive; 901 char buf[MAX_PATH]; 902 char *bufp; 903 904 /* just try the "raw" name first and see if it works */ 905 if (access_file(path, pathbuf, len_pathbuf, pathret)) 906 return 1; 907 908#if defined(WIN32) && defined(__MINGW32__) 909 /* don't try others */ 910 return 0; 911#endif 912 913 /* try the places set in the environment */ 914 drive = getenv("_XBASEDRIVE"); 915 if (!drive) 916 drive = "C:"; 917 len = strlen(drive) + strlen(path); 918 bufp = XtStackAlloc(len + 1, buf); 919 strcpy(bufp, drive); 920 strcat(bufp, path); 921 if (access_file(bufp, pathbuf, len_pathbuf, pathret)) { 922 XtStackFree(bufp, buf); 923 return 1; 924 } 925 926 /* one last place to look */ 927 drive = getenv("HOMEDRIVE"); 928 if (drive) { 929 len = strlen(drive) + strlen(path); 930 bufp = XtStackAlloc(len + 1, buf); 931 strcpy(bufp, drive); 932 strcat(bufp, path); 933 if (access_file(bufp, pathbuf, len_pathbuf, pathret)) { 934 XtStackFree(bufp, buf); 935 return 1; 936 } 937 } 938 939 /* does OS/2 (with or with gcc-emx) have getdrives()? */ 940 /* tried everywhere else, go fishing */ 941 drives = _getdrives(); 942#define C_DRIVE ('C' - 'A') 943#define Z_DRIVE ('Z' - 'A') 944 for (i = C_DRIVE; i <= Z_DRIVE; i++) { /* don't check on A: or B: */ 945 if ((1 << i) & drives) { 946 len = 2 + strlen(path); 947 bufp = XtStackAlloc(len + 1, buf); 948 *bufp = 'A' + i; 949 *(bufp + 1) = ':'; 950 *(bufp + 2) = '\0'; 951 strcat(bufp, path); 952 if (access_file(bufp, pathbuf, len_pathbuf, pathret)) { 953 XtStackFree(bufp, buf); 954 return 1; 955 } 956 } 957 } 958 return 0; 959} 960#endif 961 962static Boolean 963TestFile(String path) 964{ 965 int ret = 0; 966 struct stat status; 967 968#if defined(WIN32) 969 char buf[MAX_PATH]; 970 char *bufp; 971 int len; 972 UINT olderror = SetErrorMode(SEM_FAILCRITICALERRORS); 973 974 if (AccessFile(path, buf, MAX_PATH, &bufp)) 975 path = bufp; 976 977 (void) SetErrorMode(olderror); 978#endif 979 ret = (access(path, R_OK) == 0 && /* exists and is readable */ 980 stat(path, &status) == 0 && /* get the status */ 981#ifndef X_NOT_POSIX 982 S_ISDIR(status.st_mode) == 0); /* not a directory */ 983#else 984 (status.st_mode & S_IFMT) != S_IFDIR); /* not a directory */ 985#endif /* X_NOT_POSIX else */ 986 return (Boolean) ret; 987} 988 989/* return of TRUE = resolved string fit, FALSE = didn't fit. Not 990 null-terminated and not collapsed if it didn't fit */ 991 992static Boolean Resolve(register _Xconst char *source, /* The source string */ 993 register int len, /* The length in bytes of *source */ 994 Substitution sub, /* Array of string values to substitute */ 995 Cardinal num, /* Number of substitution entries */ 996 char *buf, /* Where to put the resolved string; */ 997 char collapse) { /* Character to collapse */ 998 register int bytesLeft = PATH_MAX; 999 register char *bp = buf; 1000 1001#ifndef DONT_COLLAPSE 1002 Boolean atBeginning = TRUE; 1003 Boolean prevIsCollapse = FALSE; 1004 1005#define PUT(ch) \ 1006 { \ 1007 if (--bytesLeft == 0) return FALSE; \ 1008 if (prevIsCollapse) \ 1009 if ((*bp = ch) != collapse) { \ 1010 prevIsCollapse = FALSE; \ 1011 bp++; \ 1012 } \ 1013 else bytesLeft++; \ 1014 else if ((*bp++ = ch) == collapse && !atBeginning) \ 1015 prevIsCollapse = TRUE; \ 1016 } 1017#else /* DONT_COLLAPSE */ 1018 1019#define PUT(ch) \ 1020 { \ 1021 if (--bytesLeft == 0) return FALSE; \ 1022 *bp++ = ch; \ 1023 } 1024#endif /* DONT_COLLAPSE */ 1025#define escape '%' 1026 1027 while (len--) { 1028#ifndef DONT_COLLAPSE 1029 if (*source == collapse) { 1030 PUT(*source); 1031 source++; 1032 continue; 1033 } 1034 else 1035#endif /* DONT_COLLAPSE */ 1036 if (*source != escape) { 1037 PUT(*source); 1038 } 1039 else { 1040 source++; 1041 if (len-- == 0) { 1042 PUT(escape); 1043 break; 1044 } 1045 1046 if (*source == ':' || *source == escape) { 1047 PUT(*source); 1048 } 1049 else { 1050 /* Match the character against the match array */ 1051 register Cardinal j; 1052 1053 for (j = 0; j < num && sub[j].match != *source; j++) { 1054 } 1055 1056 /* Substitute the substitution string */ 1057 1058 if (j >= num) { 1059 PUT(*source); 1060 } 1061 else if (sub[j].substitution != NULL) { 1062 char *sp = sub[j].substitution; 1063 1064 while (*sp) { 1065 PUT(*sp); 1066 sp++; 1067 } 1068 } 1069 } 1070 } 1071 source++; 1072#ifndef DONT_COLLAPSE 1073 atBeginning = FALSE; 1074#endif /* DONT_COLLAPSE */ 1075 } 1076 PUT('\0'); 1077 1078 return TRUE; 1079#undef PUT 1080#undef escape 1081} 1082 1083_XtString 1084XtFindFile(_Xconst _XtString path, 1085 Substitution substitutions, 1086 Cardinal num_substitutions, 1087 XtFilePredicate predicate) 1088{ 1089 char *buf, *buf1, *buf2; 1090 _Xconst _XtString colon; 1091 int len; 1092 Boolean firstTime = TRUE; 1093 1094 buf1 = __XtMalloc((unsigned) PATH_MAX); 1095 buf2 = __XtMalloc((unsigned) PATH_MAX); 1096 buf = buf1; 1097 1098 if (predicate == NULL) 1099 predicate = TestFile; 1100 1101 while (1) { 1102 colon = path; 1103 /* skip leading colons */ 1104 while (*colon) { 1105 if (*colon != ':') 1106 break; 1107 colon++; 1108 path++; 1109 } 1110 /* now look for an un-escaped colon */ 1111 for (; *colon; colon++) { 1112 if (*colon == '%' && *(path + 1)) { 1113 colon++; /* bump it an extra time to skip %. */ 1114 continue; 1115 } 1116 if (*colon == ':') 1117 break; 1118 } 1119 len = (int) (colon - path); 1120 if (Resolve(path, len, substitutions, num_substitutions, buf, '/')) { 1121 if (firstTime || strcmp(buf1, buf2) != 0) { 1122#ifdef XNL_DEBUG 1123 printf("Testing file %s\n", buf); 1124#endif /* XNL_DEBUG */ 1125 /* Check out the file */ 1126 if ((*predicate) (buf)) { 1127 /* We've found it, return it */ 1128#ifdef XNL_DEBUG 1129 printf("File found.\n"); 1130#endif /* XNL_DEBUG */ 1131 if (buf == buf1) { 1132 XtFree(buf2); 1133 return buf1; 1134 } 1135 XtFree(buf1); 1136 return buf2; 1137 } 1138 if (buf == buf1) 1139 buf = buf2; 1140 else 1141 buf = buf1; 1142 firstTime = FALSE; 1143 } 1144 } 1145 1146 /* Nope...any more paths? */ 1147 1148 if (*colon == '\0') 1149 break; 1150 path = colon + 1; 1151 } 1152 1153 /* No file found */ 1154 1155 XtFree(buf1); 1156 XtFree(buf2); 1157 return NULL; 1158} 1159 1160/* The implementation of this routine is operating system dependent */ 1161/* Should match the code in Xlib _XlcMapOSLocaleName */ 1162 1163static String 1164ExtractLocaleName(String lang) 1165{ 1166 1167#if defined(CSRG_BASED) || defined(sun) || defined(SVR4) || defined(WIN32) || defined (linux) 1168#ifdef WIN32 1169#define SKIPCOUNT 1 1170#define STARTCHAR '=' 1171#define ENDCHAR ';' 1172#define WHITEFILL 1173#else 1174#if defined(linux) 1175#define STARTSTR "LC_CTYPE=" 1176#define ENDCHAR ';' 1177#else 1178#if !defined(sun) || defined(SVR4) 1179#define STARTCHAR '/' 1180#define ENDCHAR '/' 1181#endif 1182#endif 1183#endif 1184 1185 String start; 1186 String end; 1187 int len; 1188 1189#ifdef SKIPCOUNT 1190 int n; 1191#endif 1192 static char *buf = NULL; 1193 1194#ifdef WHITEFILL 1195 char *temp; 1196#endif 1197 1198 start = lang; 1199#ifdef SKIPCOUNT 1200 for (n = SKIPCOUNT; 1201 --n >= 0 && start && (start = strchr(start, STARTCHAR)); start++); 1202 if (!start) 1203 start = lang; 1204#endif 1205#ifdef STARTCHAR 1206 if (start && (start = strchr(start, STARTCHAR))) 1207#elif defined (STARTSTR) 1208 if (start && (start = strstr(start, STARTSTR))) 1209#endif 1210 { 1211#ifdef STARTCHAR 1212 start++; 1213#elif defined (STARTSTR) 1214 start += strlen(STARTSTR); 1215#endif 1216 1217 if ((end = strchr(start, ENDCHAR))) { 1218 len = (int) (end - start); 1219 XtFree(buf); 1220 buf = XtMalloc((Cardinal) (len + 1)); 1221 if (buf == NULL) 1222 return NULL; 1223 strncpy(buf, start, (size_t) len); 1224 *(buf + len) = '\0'; 1225#ifdef WHITEFILL 1226 for (temp = buf; (temp = strchr(temp, ' ')) != NULL;) 1227 *temp++ = '-'; 1228#endif 1229 return buf; 1230 } 1231 else /* if no ENDCHAR is found we are at the end of the line */ 1232 return start; 1233 } 1234#ifdef WHITEFILL 1235 if (strchr(lang, ' ')) { 1236 XtFree(buf); 1237 buf = strdup(lang); 1238 if (buf == NULL) 1239 return NULL; 1240 for (temp = buf; (temp = strchr(temp, ' ')) != NULL;) 1241 *temp++ = '-'; 1242 return buf; 1243 } 1244#endif 1245#undef STARTCHAR 1246#undef ENDCHAR 1247#undef WHITEFILL 1248#endif 1249 1250 return lang; 1251} 1252 1253static void 1254FillInLangSubs(Substitution subs, XtPerDisplay pd) 1255{ 1256 int len; 1257 String string; 1258 char *p1, *p2, *p3; 1259 char **rest; 1260 char *ch; 1261 1262 if (pd->language == NULL || pd->language[0] == '\0') { 1263 subs[0].substitution = subs[1].substitution = 1264 subs[2].substitution = subs[3].substitution = NULL; 1265 return; 1266 } 1267 1268 string = ExtractLocaleName(pd->language); 1269 1270 if (string == NULL || string[0] == '\0') { 1271 subs[0].substitution = subs[1].substitution = 1272 subs[2].substitution = subs[3].substitution = NULL; 1273 return; 1274 } 1275 1276 len = (int) strlen(string) + 1; 1277 subs[0].substitution = (_XtString) string; 1278 p1 = subs[1].substitution = XtMallocArray(3, (Cardinal) len); 1279 p2 = subs[2].substitution = subs[1].substitution + len; 1280 p3 = subs[3].substitution = subs[2].substitution + len; 1281 1282 /* Everything up to the first "_" goes into p1. From "_" to "." in 1283 p2. The rest in p3. If no delimiters, all goes into p1. We 1284 assume p1, p2, and p3 are large enough. */ 1285 1286 *p1 = *p2 = *p3 = '\0'; 1287 1288 ch = strchr(string, '_'); 1289 if (ch != NULL) { 1290 len = (int) (ch - string); 1291 (void) strncpy(p1, string, (size_t) len); 1292 p1[len] = '\0'; 1293 string = ch + 1; 1294 rest = &p2; 1295 } 1296 else 1297 rest = &p1; 1298 1299 /* Rest points to where we put the first part */ 1300 1301 ch = strchr(string, '.'); 1302 if (ch != NULL) { 1303 len = (int) (ch - string); 1304 strncpy(*rest, string, (size_t) len); 1305 (*rest)[len] = '\0'; 1306 (void) strcpy(p3, ch + 1); 1307 } 1308 else 1309 (void) strcpy(*rest, string); 1310} 1311 1312/* 1313 * default path used if environment variable XFILESEARCHPATH 1314 * is not defined. Also substituted for %D. 1315 * The exact value should be documented in the implementation 1316 * notes for any Xt implementation. 1317 */ 1318static const char * 1319implementation_default_path(void) 1320{ 1321#if defined(WIN32) 1322 static char xfilesearchpath[] = ""; 1323 1324 return xfilesearchpath; 1325#else 1326 return XFILESEARCHPATHDEFAULT; 1327#endif 1328} 1329 1330 1331/* *INDENT-OFF* */ 1332static SubstitutionRec defaultSubs[] = { 1333 {'N', NULL}, 1334 {'T', NULL}, 1335 {'S', NULL}, 1336 {'C', NULL}, 1337 {'L', NULL}, 1338 {'l', NULL}, 1339 {'t', NULL}, 1340 {'c', NULL} 1341}; 1342/* *INDENT-ON* */ 1343 1344_XtString 1345XtResolvePathname(Display *dpy, 1346 _Xconst char *type, 1347 _Xconst char *filename, 1348 _Xconst char *suffix, 1349 _Xconst char *path, 1350 Substitution substitutions, 1351 Cardinal num_substitutions, 1352 XtFilePredicate predicate) 1353{ 1354 XtPerDisplay pd; 1355 static const char *defaultPath = NULL; 1356 const char *impl_default = implementation_default_path(); 1357 int idef_len = (int) strlen(impl_default); 1358 char *massagedPath; 1359 int bytesAllocd, bytesLeft; 1360 char *ch, *result; 1361 Substitution merged_substitutions; 1362 XrmRepresentation db_type; 1363 XrmValue value; 1364 XrmName name_list[3]; 1365 XrmClass class_list[3]; 1366 Boolean pathMallocd = False; 1367 1368 LOCK_PROCESS; 1369 pd = _XtGetPerDisplay(dpy); 1370 if (path == NULL) { 1371 if (defaultPath == NULL) { 1372 defaultPath = getenv("XFILESEARCHPATH"); 1373 if (defaultPath == NULL) 1374 defaultPath = impl_default; 1375 } 1376 path = defaultPath; 1377 } 1378 1379 if (path == NULL) 1380 path = ""; /* NULL would kill us later */ 1381 1382 if (filename == NULL) { 1383 filename = XrmClassToString(pd->class); 1384 } 1385 1386 bytesAllocd = bytesLeft = 1000; 1387 massagedPath = ALLOCATE_LOCAL((size_t) bytesAllocd); 1388 if (massagedPath == NULL) 1389 _XtAllocError(NULL); 1390 1391 if (path[0] == ':') { 1392 strcpy(massagedPath, "%N%S"); 1393 ch = &massagedPath[4]; 1394 bytesLeft -= 4; 1395 } 1396 else 1397 ch = massagedPath; 1398 1399 /* Insert %N%S between adjacent colons 1400 * and default path for %D. 1401 * Default path should not have any adjacent colons of its own. 1402 */ 1403 1404 while (*path != '\0') { 1405 if (bytesLeft < idef_len) { 1406 int bytesUsed = bytesAllocd - bytesLeft; 1407 char *new; 1408 1409 bytesAllocd += 1000; 1410 new = __XtMalloc((Cardinal) bytesAllocd); 1411 strncpy(new, massagedPath, (size_t) bytesUsed); 1412 ch = new + bytesUsed; 1413 if (pathMallocd) 1414 XtFree(massagedPath); 1415 else 1416 DEALLOCATE_LOCAL(massagedPath); 1417 pathMallocd = True; 1418 massagedPath = new; 1419 bytesLeft = bytesAllocd - bytesUsed; 1420 } 1421 if (*path == '%' && *(path + 1) == ':') { 1422 *ch++ = '%'; 1423 *ch++ = ':'; 1424 path += 2; 1425 bytesLeft -= 2; 1426 continue; 1427 } 1428 if (*path == ':' && *(path + 1) == ':') { 1429 strcpy(ch, ":%N%S:"); 1430 ch += 6; 1431 bytesLeft -= 6; 1432 while (*path == ':') 1433 path++; 1434 continue; 1435 } 1436 if (*path == '%' && *(path + 1) == 'D') { 1437 strcpy(ch, impl_default); 1438 ch += idef_len; 1439 bytesLeft -= idef_len; 1440 path += 2; 1441 continue; 1442 } 1443 *ch++ = *path++; 1444 bytesLeft--; 1445 } 1446 *ch = '\0'; 1447#ifdef XNL_DEBUG 1448 printf("Massaged path: %s\n", massagedPath); 1449#endif /* XNL_DEBUG */ 1450 1451 if (num_substitutions == 0) 1452 merged_substitutions = defaultSubs; 1453 else { 1454 int i = XtNumber(defaultSubs); 1455 Substitution sub, def; 1456 1457 merged_substitutions = sub = (Substitution) 1458 ALLOCATE_LOCAL((unsigned) (num_substitutions + (Cardinal) i) * 1459 sizeof(SubstitutionRec)); 1460 if (sub == NULL) 1461 _XtAllocError(NULL); 1462 for (def = defaultSubs; i--; sub++, def++) 1463 sub->match = def->match; 1464 for (i = (int) num_substitutions; i--;) 1465 *sub++ = *substitutions++; 1466 } 1467 merged_substitutions[0].substitution = (_XtString) filename; 1468 merged_substitutions[1].substitution = (_XtString) type; 1469 merged_substitutions[2].substitution = (_XtString) suffix; 1470 name_list[0] = pd->name; 1471 name_list[1] = XrmPermStringToQuark("customization"); 1472 name_list[2] = NULLQUARK; 1473 class_list[0] = pd->class; 1474 class_list[1] = XrmPermStringToQuark("Customization"); 1475 class_list[2] = NULLQUARK; 1476 if (XrmQGetResource(XrmGetDatabase(dpy), name_list, class_list, 1477 &db_type, &value) && db_type == _XtQString) 1478 merged_substitutions[3].substitution = (char *) value.addr; 1479 else 1480 merged_substitutions[3].substitution = NULL; 1481 FillInLangSubs(&merged_substitutions[4], pd); 1482 1483 result = XtFindFile(massagedPath, merged_substitutions, 1484 num_substitutions + XtNumber(defaultSubs), predicate); 1485 1486 if (merged_substitutions[5].substitution != NULL) 1487 XtFree((XtPointer) merged_substitutions[5].substitution); 1488 1489 if (merged_substitutions != defaultSubs) 1490 DEALLOCATE_LOCAL(merged_substitutions); 1491 1492 if (pathMallocd) 1493 XtFree(massagedPath); 1494 else 1495 DEALLOCATE_LOCAL(massagedPath); 1496 1497 UNLOCK_PROCESS; 1498 return result; 1499} 1500 1501Boolean 1502XtCallAcceptFocus(Widget widget, Time *time) 1503{ 1504 XtAcceptFocusProc ac; 1505 Boolean retval; 1506 1507 WIDGET_TO_APPCON(widget); 1508 1509 LOCK_APP(app); 1510 LOCK_PROCESS; 1511 ac = XtClass(widget)->core_class.accept_focus; 1512 UNLOCK_PROCESS; 1513 1514 if (ac != NULL) 1515 retval = (*ac) (widget, time); 1516 else 1517 retval = FALSE; 1518 UNLOCK_APP(app); 1519 return retval; 1520} 1521 1522#ifdef XT_GEO_TATTLER 1523/************************************************************************** 1524 GeoTattler: This is used to debug Geometry management in Xt. 1525 1526 It uses a pseudo resource XtNgeotattler. 1527 1528 E.G. if those lines are found in the resource database: 1529 1530 myapp*draw.XmScale.geoTattler: ON 1531 *XmScrollBar.geoTattler:ON 1532 *XmRowColumn.exit_button.geoTattler:ON 1533 1534 then: 1535 1536 all the XmScale children of the widget named draw, 1537 all the XmScrollBars, 1538 the widget named exit_button in any XmRowColumn 1539 1540 will return True to the function IsTattled(), and will generate 1541 outlined trace to stdout. 1542 1543*************************************************************************/ 1544 1545#define XtNgeoTattler "geoTattler" 1546#define XtCGeoTattler "GeoTattler" 1547 1548typedef struct { 1549 Boolean geo_tattler; 1550} GeoDataRec; 1551 1552/* *INDENT-OFF* */ 1553static XtResource geo_resources[] = { 1554 { XtNgeoTattler, XtCGeoTattler, XtRBoolean, sizeof(Boolean), 1555 XtOffsetOf(GeoDataRec, geo_tattler), 1556 XtRImmediate, (XtPointer) False } 1557}; 1558/* *INDENT-ON* */ 1559 1560/************************************************************************ 1561 This function uses XtGetSubresources to find out if a widget 1562 needs to be geo-spied by the caller. */ 1563static Boolean 1564IsTattled(Widget widget) 1565{ 1566 GeoDataRec geo_data; 1567 1568 XtGetSubresources(widget, (XtPointer) &geo_data, 1569 (String) NULL, (String) NULL, 1570 geo_resources, XtNumber(geo_resources), NULL, 0); 1571 1572 return geo_data.geo_tattler; 1573 1574} /* IsTattled */ 1575 1576static int n_tab = 0; /* not MT for now */ 1577 1578void 1579_XtGeoTab(int direction) 1580{ /* +1 or -1 */ 1581 n_tab += direction; 1582} 1583 1584void 1585_XtGeoTrace(Widget widget, const char *fmt, ...) 1586{ 1587 if (IsTattled(widget)) { 1588 va_list args; 1589 int i; 1590 1591 va_start(args, fmt); 1592 for (i = 0; i < n_tab; i++) 1593 printf(" "); 1594 (void) vprintf(fmt, args); 1595 va_end(args); 1596 } 1597} 1598 1599#endif /* XT_GEO_TATTLER */ 1600