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