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