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