Home | History | Annotate | Line # | Download | only in src
      1 /***********************************************************
      2 Copyright (c) 1993, Oracle and/or its affiliates.
      3 
      4 Permission is hereby granted, free of charge, to any person obtaining a
      5 copy of this software and associated documentation files (the "Software"),
      6 to deal in the Software without restriction, including without limitation
      7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 and/or sell copies of the Software, and to permit persons to whom the
      9 Software is furnished to do so, subject to the following conditions:
     10 
     11 The above copyright notice and this permission notice (including the next
     12 paragraph) shall be included in all copies or substantial portions of the
     13 Software.
     14 
     15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     21 DEALINGS IN THE SOFTWARE.
     22 
     23 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
     24 
     25                         All Rights Reserved
     26 
     27 Permission to use, copy, modify, and distribute this software and its
     28 documentation for any purpose and without fee is hereby granted,
     29 provided that the above copyright notice appear in all copies and that
     30 both that copyright notice and this permission notice appear in
     31 supporting documentation, and that the name of Digital not be
     32 used in advertising or publicity pertaining to distribution of the
     33 software without specific, written prior permission.
     34 
     35 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
     36 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
     37 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
     38 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
     39 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
     40 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
     41 SOFTWARE.
     42 
     43 ******************************************************************/
     44 
     45 /*
     46 
     47 Copyright 1987, 1988, 1994, 1998  The Open Group
     48 
     49 Permission to use, copy, modify, distribute, and sell this software and its
     50 documentation for any purpose is hereby granted without fee, provided that
     51 the above copyright notice appear in all copies and that both that
     52 copyright notice and this permission notice appear in supporting
     53 documentation.
     54 
     55 The above copyright notice and this permission notice shall be included in
     56 all copies or substantial portions of the Software.
     57 
     58 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     59 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     60 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     61 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     62 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     63 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     64 
     65 Except as contained in this notice, the name of The Open Group shall not be
     66 used in advertising or otherwise to promote the sale, use or other dealings
     67 in 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 
     89 String XtCXtToolkitError = "XtToolkitError";
     90 
     91 Boolean
     92 XtIsSubclass(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 
    111 Boolean
    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 
    125 Boolean
    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 
    151 XtPointer
    152 XtGetClassExtension(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 
    170 static void
    171 ComputeWindowAttributes(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 
    207 static void
    208 CallChangeManaged(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 
    247 static void
    248 MapChildren(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 
    265 static Boolean
    266 ShouldMapAllChildren(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 
    287 static void
    288 RealizeWidget(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 
    388 void
    389 XtRealizeWidget(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 
    403 static void
    404 UnrealizeWidget(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 
    449 void
    450 XtUnrealizeWidget(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 
    481 void
    482 XtCreateWindow(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 
    518 static Widget NameListToWidget(Widget root,
    519                                XrmNameList names,
    520                                XrmBindingList bindings,
    521                                int in_depth, int *out_depth, int *found_depth);
    522 
    523 typedef Widget(*NameMatchProc) (XrmNameList,
    524                                 XrmBindingList,
    525                                 WidgetList, Cardinal, int, int *, int *);
    526 
    527 static Widget
    528 MatchExactChildren(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 
    555 static Widget
    556 MatchWildChildren(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 
    580 static Widget
    581 SearchChildren(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 
    606 static Widget
    607 NameListToWidget(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 
    648 Widget
    649 XtNameToWidget(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
    688 Display *
    689 XtDisplayOfObject(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
    698 Display *
    699 XtDisplay(Widget widget)
    700 {
    701     /* Attempts to LockApp() here will generate endless recursive loops */
    702     return DisplayOfScreen(widget->core.screen);
    703 }
    704 
    705 #undef XtScreenOfObject
    706 Screen *
    707 XtScreenOfObject(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
    716 Screen *
    717 XtScreen(Widget widget)
    718 {
    719     /* Attempts to LockApp() here will generate endless recursive loops */
    720     return widget->core.screen;
    721 }
    722 
    723 #undef XtWindowOfObject
    724 Window
    725 XtWindowOfObject(Widget object)
    726 {
    727     return XtWindow(XtIsWidget(object) ? object : _XtWindowedAncestor(object));
    728 }
    729 
    730 #undef XtWindow
    731 Window
    732 XtWindow(Widget widget)
    733 {
    734     return widget->core.window;
    735 }
    736 
    737 #undef XtSuperclass
    738 WidgetClass
    739 XtSuperclass(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
    750 WidgetClass
    751 XtClass(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
    762 Boolean
    763 XtIsManaged(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
    779 Boolean
    780 XtIsRealized(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
    793 Boolean
    794 XtIsSensitive(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  */
    812 Widget
    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                    &params, &num_params);
    827     }
    828 
    829     return object;
    830 }
    831 
    832 #undef XtParent
    833 Widget
    834 XtParent(Widget widget)
    835 {
    836     /* Attempts to LockApp() here will generate endless recursive loops */
    837     return widget->core.parent;
    838 }
    839 
    840 #undef XtName
    841 String
    842 XtName(Widget object)
    843 {
    844     /* Attempts to LockApp() here will generate endless recursive loops */
    845     return XrmQuarkToString(object->core.xrm_name);
    846 }
    847 
    848 Boolean
    849 XtIsObject(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)
    879 static int
    880 access_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 
    895 static int
    896 AccessFile(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 
    962 static Boolean
    963 TestFile(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 
    992 static 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
   1084 XtFindFile(_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 
   1163 static String
   1164 ExtractLocaleName(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 
   1253 static void
   1254 FillInLangSubs(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  */
   1318 static const char *
   1319 implementation_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* */
   1332 static 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
   1345 XtResolvePathname(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 
   1501 Boolean
   1502 XtCallAcceptFocus(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 
   1548 typedef struct {
   1549     Boolean geo_tattler;
   1550 } GeoDataRec;
   1551 
   1552 /* *INDENT-OFF* */
   1553 static 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. */
   1563 static Boolean
   1564 IsTattled(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 
   1576 static int n_tab = 0;           /* not MT for now */
   1577 
   1578 void
   1579 _XtGeoTab(int direction)
   1580 {                               /* +1 or -1 */
   1581     n_tab += direction;
   1582 }
   1583 
   1584 void
   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