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