Intrinsic.c revision 444c061a
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 = 0, 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    /* try the places set in the environment */
877    drive = getenv ("_XBASEDRIVE");
878#ifdef __UNIXOS2__
879    if (!drive)
880	drive = getenv ("X11ROOT");
881#endif
882    if (!drive)
883	drive = "C:";
884    len = strlen (drive) + strlen (path);
885    bufp = XtStackAlloc (len + 1, buf);
886    strcpy (bufp, drive);
887    strcat (bufp, path);
888    if (access_file (bufp, pathbuf, len_pathbuf, pathret)) {
889	XtStackFree (bufp, buf);
890	return 1;
891    }
892
893#ifndef __UNIXOS2__
894    /* one last place to look */
895    drive = getenv ("HOMEDRIVE");
896    if (drive) {
897	len = strlen (drive) + strlen (path);
898	bufp = XtStackAlloc (len + 1, buf);
899	strcpy (bufp, drive);
900	strcat (bufp, path);
901	if (access_file (bufp, pathbuf, len_pathbuf, pathret)) {
902	    XtStackFree (bufp, buf);
903	    return 1;
904	}
905    }
906
907    /* does OS/2 (with or with gcc-emx) have getdrives()? */
908    /* tried everywhere else, go fishing */
909    drives = _getdrives ();
910#define C_DRIVE ('C' - 'A')
911#define Z_DRIVE ('Z' - 'A')
912    for (i = C_DRIVE; i <= Z_DRIVE; i++) { /* don't check on A: or B: */
913	if ((1 << i) & drives) {
914	    len = 2 + strlen (path);
915	    bufp = XtStackAlloc (len + 1, buf);
916	    *bufp = 'A' + i;
917	    *(bufp + 1) = ':';
918	    *(bufp + 2) = '\0';
919	    strcat (bufp, path);
920	    if (access_file (bufp, pathbuf, len_pathbuf, pathret)) {
921		XtStackFree (bufp, buf);
922		return 1;
923	    }
924	}
925    }
926#endif
927    return 0;
928}
929#endif
930
931static Boolean TestFile(
932    String path)
933{
934#ifndef VMS
935    int ret = 0;
936    struct stat status;
937#if defined(WIN32)
938    char buf[MAX_PATH];
939    char* bufp;
940    int len;
941    UINT olderror = SetErrorMode (SEM_FAILCRITICALERRORS);
942
943    if (AccessFile (path, buf, MAX_PATH, &bufp))
944	path = bufp;
945
946    (void) SetErrorMode (olderror);
947#endif
948    ret = (access(path, R_OK) == 0 &&		/* exists and is readable */
949	    stat(path, &status) == 0 &&		/* get the status */
950#ifndef X_NOT_POSIX
951	    S_ISDIR(status.st_mode) == 0);	/* not a directory */
952#else
953	    (status.st_mode & S_IFMT) != S_IFDIR);	/* not a directory */
954#endif /* X_NOT_POSIX else */
955#if defined(WIN32)
956    XtStackFree ((XtPointer)bufp, buf);
957#endif
958    return ret;
959#else /* VMS */
960    return TRUE;	/* Who knows what to do here? */
961#endif /* VMS */
962}
963
964/* return of TRUE = resolved string fit, FALSE = didn't fit.  Not
965   null-terminated and not collapsed if it didn't fit */
966
967static Boolean Resolve(
968    register _Xconst char *source,	/* The source string */
969    register int len,		/* The length in bytes of *source */
970    Substitution sub,	/* Array of string values to substitute */
971    Cardinal num,	/* Number of substitution entries */
972    char *buf,		/* Where to put the resolved string; */
973    char collapse)	/* Character to collapse */
974{
975    register int bytesLeft = PATH_MAX;
976    register char* bp = buf;
977#ifndef DONT_COLLAPSE
978    Boolean atBeginning = TRUE;
979    Boolean prevIsCollapse = FALSE;
980
981#define PUT(ch) \
982    { \
983	if (--bytesLeft == 0) return FALSE; \
984        if (prevIsCollapse) \
985	    if ((*bp = ch) != collapse) { \
986		prevIsCollapse = FALSE; \
987		bp++; \
988	    } \
989	    else bytesLeft++; \
990        else if ((*bp++ = ch) == collapse && !atBeginning) \
991	    prevIsCollapse = TRUE; \
992    }
993#else /* DONT_COLLAPSE */
994
995#define PUT(ch) \
996    { \
997	if (--bytesLeft == 0) return FALSE; \
998	*bp++ = ch; \
999    }
1000#endif /* DONT_COLLAPSE */
1001#define escape '%'
1002
1003    while (len--) {
1004#ifndef DONT_COLLAPSE
1005	if (*source == collapse) {
1006	    PUT(*source);
1007	    source++;
1008	    continue;
1009	}
1010	else
1011#endif /* DONT_COLLAPSE */
1012	    if (*source != escape) {
1013		PUT(*source);
1014	}
1015	else {
1016	    source++;
1017	    if (len-- == 0) {
1018		PUT(escape);
1019		break;
1020	    }
1021
1022	    if (*source == ':' || *source == escape)
1023		PUT(*source)
1024	    else {
1025		/* Match the character against the match array */
1026		register Cardinal j;
1027
1028		for (j = 0; j < num && sub[j].match != *source; j++) {}
1029
1030		/* Substitute the substitution string */
1031
1032		if (j >= num) PUT(*source)
1033		else if (sub[j].substitution != NULL) {
1034		    char *sp = sub[j].substitution;
1035		    while (*sp) {
1036			PUT(*sp);
1037			sp++;
1038		    }
1039		}
1040	    }
1041	}
1042	source++;
1043#ifndef DONT_COLLAPSE
1044	atBeginning = FALSE;
1045#endif /* DONT_COLLAPSE */
1046    }
1047    PUT('\0');
1048
1049    return TRUE;
1050#undef PUT
1051#undef escape
1052}
1053
1054
1055String XtFindFile(
1056    _Xconst char* path,
1057    Substitution substitutions,
1058    Cardinal num_substitutions,
1059    XtFilePredicate predicate)
1060{
1061    char *buf, *buf1, *buf2, *colon;
1062    int len;
1063    Boolean firstTime = TRUE;
1064
1065    buf = buf1 = __XtMalloc((unsigned)PATH_MAX);
1066    buf2 = __XtMalloc((unsigned)PATH_MAX);
1067
1068    if (predicate == NULL) predicate = TestFile;
1069
1070    while (1) {
1071	colon = (String)path;
1072	/* skip leading colons */
1073	while (*colon) {
1074	    if (*colon != ':') break;
1075	    colon++;
1076	    path++;
1077	}
1078	/* now look for an un-escaped colon */
1079	for ( ; *colon ; colon++) {
1080	    if (*colon == '%' && *(path+1)) {
1081		colon++;	/* bump it an extra time to skip %. */
1082		continue;
1083	    }
1084	    if (*colon == ':')
1085#ifdef __UNIXOS2__
1086	      if (colon > (path+1))
1087#endif
1088		break;
1089	}
1090	len = colon - path;
1091	if (Resolve(path, len, substitutions, num_substitutions,
1092		    buf, '/')) {
1093	    if (firstTime || strcmp(buf1,buf2) != 0) {
1094#ifdef __UNIXOS2__
1095		{
1096			char *bufx = (char*)__XOS2RedirRoot(buf);
1097			strcpy(buf,bufx);
1098		}
1099#endif
1100#ifdef XNL_DEBUG
1101		printf("Testing file %s\n", buf);
1102#endif /* XNL_DEBUG */
1103		/* Check out the file */
1104		if ((*predicate) (buf)) {
1105		    /* We've found it, return it */
1106#ifdef XNL_DEBUG
1107		    printf("File found.\n");
1108#endif /* XNL_DEBUG */
1109		    if (buf == buf1) XtFree(buf2);
1110		    else XtFree(buf1);
1111		    return buf;
1112		}
1113		if (buf == buf1)
1114		    buf = buf2;
1115		else
1116		    buf = buf1;
1117		firstTime = FALSE;
1118	    }
1119	}
1120
1121	/* Nope...any more paths? */
1122
1123	if (*colon == '\0') break;
1124	path = colon+1;
1125    }
1126
1127    /* No file found */
1128
1129    XtFree(buf1);
1130    XtFree(buf2);
1131    return NULL;
1132}
1133
1134
1135/* The implementation of this routine is operating system dependent */
1136/* Should match the code in Xlib _XlcMapOSLocaleName */
1137
1138static char *ExtractLocaleName(
1139    String	lang)
1140{
1141
1142#if defined(hpux) || defined(CSRG_BASED) || defined(sun) || defined(SVR4) || defined(sgi) || defined(__osf__) || defined(AIXV3) || defined(ultrix) || defined(WIN32) || defined(__UNIXOS2__) || defined (linux)
1143# ifdef hpux
1144/*
1145 * We need to discriminated between HPUX 9 and HPUX 10. The equivalent
1146 * code in Xlib in SetLocale.c does include locale.h via X11/Xlocale.h.
1147 */
1148#  include <locale.h>
1149#  ifndef _LastCategory
1150   /* HPUX 9 and earlier */
1151#   define SKIPCOUNT 2
1152#   define STARTCHAR ':'
1153#   define ENDCHAR ';'
1154#  else
1155    /* HPUX 10 */
1156#   define ENDCHAR ' '
1157#  endif
1158# else
1159#  ifdef ultrix
1160#   define SKIPCOUNT 2
1161#   define STARTCHAR '\001'
1162#   define ENDCHAR '\001'
1163#  else
1164#   if defined(WIN32) || defined(__UNIXOS2__)
1165#    define SKIPCOUNT 1
1166#    define STARTCHAR '='
1167#    define ENDCHAR ';'
1168#    define WHITEFILL
1169#   else
1170#    if defined(__osf__) || (defined(AIXV3) && !defined(AIXV4))
1171#     define STARTCHAR ' '
1172#     define ENDCHAR ' '
1173#    else
1174#     if defined(linux)
1175#      define STARTSTR "LC_CTYPE="
1176#      define ENDCHAR ';'
1177#     else
1178#      if !defined(sun) || defined(SVR4)
1179#       define STARTCHAR '/'
1180#       define ENDCHAR '/'
1181#      endif
1182#     endif
1183#    endif
1184#   endif
1185#  endif
1186# endif
1187
1188    char           *start;
1189    char           *end;
1190    int             len;
1191# ifdef SKIPCOUNT
1192    int		    n;
1193# endif
1194    static char*    buf = NULL;
1195
1196    start = lang;
1197# ifdef SKIPCOUNT
1198    for (n = SKIPCOUNT;
1199	 --n >= 0 && start && (start = strchr (start, STARTCHAR));
1200	 start++)
1201	;
1202    if (!start)
1203	start = lang;
1204# endif
1205# ifdef STARTCHAR
1206    if (start && (start = strchr (start, STARTCHAR)))
1207# elif  defined (STARTSTR)
1208    if (start && (start = strstr (start,STARTSTR)))
1209# endif
1210    {
1211# ifdef STARTCHAR
1212	start++;
1213# elif defined (STARTSTR)
1214	start += strlen(STARTSTR);
1215# endif
1216
1217	if ((end = strchr (start, ENDCHAR))) {
1218	    len = end - start;
1219	    if (buf != NULL) XtFree (buf);
1220	    buf = XtMalloc (len + 1);
1221	    if (buf == NULL) return NULL;
1222	    strncpy(buf, start, len);
1223	    *(buf + len) = '\0';
1224# ifdef WHITEFILL
1225	    for (start = buf; start = strchr(start, ' '); )
1226		*start++ = '-';
1227# endif
1228	    return buf;
1229	} else  /* if no ENDCHAR is found we are at the end of the line */
1230	    return start;
1231    }
1232# ifdef WHITEFILL
1233    if (strchr(lang, ' ')) {
1234	if (buf != NULL) XtFree (buf);
1235	else buf = XtMalloc (strlen (lang) + 1);
1236	if (buf == NULL) return NULL;
1237	strcpy(buf, lang);
1238	for (start = buf; start = strchr(start, ' '); )
1239	    *start++ = '-';
1240	return buf;
1241    }
1242# endif
1243# undef STARTCHAR
1244# undef ENDCHAR
1245# undef WHITEFILL
1246#endif
1247
1248    return lang;
1249}
1250
1251static void FillInLangSubs(
1252    Substitution subs,
1253    XtPerDisplay pd)
1254{
1255    int len;
1256    char *string, *p1, *p2, *p3;
1257    char **rest;
1258    char *ch;
1259
1260    if (pd->language == NULL ||
1261	(pd->language != NULL && pd->language[0] == '\0')) {
1262	subs[0].substitution = subs[1].substitution =
1263		subs[2].substitution = subs[3].substitution = NULL;
1264	return;
1265    }
1266
1267    string = ExtractLocaleName(pd->language);
1268
1269    if (string == NULL ||
1270	(string != NULL && string[0] == '\0')) {
1271	subs[0].substitution = subs[1].substitution =
1272		subs[2].substitution = subs[3].substitution = NULL;
1273	return;
1274    }
1275
1276    len = strlen(string) + 1;
1277    subs[0].substitution = string;
1278    p1 = subs[1].substitution = __XtMalloc((Cardinal) 3*len);
1279    p2 = subs[2].substitution = subs[1].substitution + len;
1280    p3 = subs[3].substitution = subs[2].substitution + len;
1281
1282    /* Everything up to the first "_" goes into p1.  From "_" to "." in
1283       p2.  The rest in p3.  If no delimiters, all goes into p1.  We
1284       assume p1, p2, and p3 are large enough. */
1285
1286    *p1 = *p2 = *p3 = '\0';
1287
1288    ch = strchr(string, '_');
1289    if (ch != NULL) {
1290	len = ch - string;
1291	(void) strncpy(p1, string, len);
1292	p1[len] = '\0';
1293	string = ch + 1;
1294	rest = &p2;
1295    } else rest = &p1;
1296
1297    /* Rest points to where we put the first part */
1298
1299    ch = strchr(string, '.');
1300    if (ch != NULL) {
1301	len = ch - string;
1302	strncpy(*rest, string, len);
1303	(*rest)[len] = '\0';
1304	(void) strcpy(p3, ch+1);
1305    } else (void) strcpy(*rest, string);
1306}
1307
1308/*
1309 * default path used if environment variable XFILESEARCHPATH
1310 * is not defined.  Also substitued for %D.
1311 * The exact value should be documented in the implementation
1312 * notes for any Xt implementation.
1313 */
1314static char *implementation_default_path(void)
1315{
1316#if defined(WIN32) || defined(__UNIXOS2__)
1317    /* if you know how to pass % thru the compiler let me know */
1318    static char xfilesearchpath[] = XFILESEARCHPATHDEFAULT;
1319    static Bool fixed;
1320    char *ch;
1321
1322    if (!fixed) {
1323	for (ch = xfilesearchpath; ch = strchr(ch, ';'); ch++)
1324	    *ch = '%';
1325	fixed = True;
1326    }
1327    return xfilesearchpath;
1328#else
1329    return XFILESEARCHPATHDEFAULT;
1330#endif
1331}
1332
1333
1334static SubstitutionRec defaultSubs[] = {
1335    {'N', NULL},
1336    {'T', NULL},
1337    {'S', NULL},
1338    {'C', NULL},
1339    {'L', NULL},
1340    {'l', NULL},
1341    {'t', NULL},
1342    {'c', NULL}
1343};
1344
1345
1346String XtResolvePathname(
1347    Display *dpy,
1348    _Xconst char* type,
1349    _Xconst char* filename,
1350    _Xconst char* suffix,
1351    _Xconst char* path,
1352    Substitution substitutions,
1353    Cardinal num_substitutions,
1354    XtFilePredicate predicate)
1355{
1356    XtPerDisplay pd;
1357    static char *defaultPath = NULL;
1358    char *impl_default = implementation_default_path();
1359    int idef_len = strlen(impl_default);
1360    char *massagedPath;
1361    int bytesAllocd, bytesLeft;
1362    char *ch, *result;
1363    Substitution merged_substitutions;
1364    XrmRepresentation db_type;
1365    XrmValue value;
1366    XrmName name_list[3];
1367    XrmClass class_list[3];
1368    Boolean pathMallocd = False;
1369
1370    LOCK_PROCESS;
1371    pd = _XtGetPerDisplay(dpy);
1372    if (path == NULL) {
1373#ifndef VMS
1374	if (defaultPath == NULL) {
1375	    defaultPath = getenv("XFILESEARCHPATH");
1376	    if (defaultPath == NULL)
1377		defaultPath = impl_default;
1378	}
1379	path = defaultPath;
1380#else
1381	path = "";	/* NULL would kill us later */
1382#endif /* VMS */
1383    }
1384
1385    if (filename == NULL) {
1386	filename = XrmClassToString(pd->class);
1387    }
1388
1389    bytesAllocd = bytesLeft = 1000;
1390    massagedPath = ALLOCATE_LOCAL(bytesAllocd);
1391    if (massagedPath == NULL) _XtAllocError(NULL);
1392
1393    if (path[0] == ':') {
1394	strcpy(massagedPath, "%N%S");
1395	ch = &massagedPath[4];
1396	bytesLeft -= 4;
1397    } else ch = massagedPath;
1398
1399    /* Insert %N%S between adjacent colons
1400     * and default path for %D.
1401     * Default path should not have any adjacent colons of its own.
1402     */
1403
1404    while (*path != '\0') {
1405	if (bytesLeft < idef_len) {
1406	    int bytesUsed = bytesAllocd - bytesLeft;
1407	    char *new;
1408	    bytesAllocd +=1000;
1409	    new = __XtMalloc((Cardinal) bytesAllocd);
1410	    strncpy( new, massagedPath, bytesUsed );
1411	    ch = new + bytesUsed;
1412	    if (pathMallocd)
1413		XtFree(massagedPath);
1414	    else
1415		DEALLOCATE_LOCAL(massagedPath);
1416	    pathMallocd = True;
1417	    massagedPath = new;
1418	    bytesLeft = bytesAllocd - bytesUsed;
1419	}
1420	if (*path == '%' && *(path+1) == ':') {
1421	    *ch++ = '%';
1422	    *ch++ = ':';
1423	    path += 2;
1424	    bytesLeft -= 2;
1425	    continue;
1426	}
1427	if (*path == ':' && *(path+1) == ':') {
1428	    strcpy(ch, ":%N%S:");
1429	    ch += 6;
1430	    bytesLeft -= 6;
1431	    while (*path == ':') path++;
1432	    continue;
1433	}
1434	if (*path == '%' && *(path+1) == 'D') {
1435	    strcpy(ch, impl_default);
1436	    ch += idef_len;
1437	    bytesLeft -= idef_len;
1438	    path += 2;
1439	    continue;
1440	}
1441	*ch++ = *path++;
1442	bytesLeft--;
1443    }
1444    *ch = '\0';
1445#ifdef XNL_DEBUG
1446    printf("Massaged path: %s\n", massagedPath);
1447#endif /* XNL_DEBUG */
1448
1449    if (num_substitutions == 0)
1450	merged_substitutions = defaultSubs;
1451    else {
1452	int i = XtNumber(defaultSubs);
1453	Substitution sub, def;
1454	merged_substitutions = sub = (Substitution)
1455	    ALLOCATE_LOCAL((unsigned)(num_substitutions+i)*sizeof(SubstitutionRec));
1456	if (sub == NULL) _XtAllocError(NULL);
1457	for (def = defaultSubs; i--; sub++, def++) sub->match = def->match;
1458	for (i = num_substitutions; i--; ) *sub++ = *substitutions++;
1459    }
1460    merged_substitutions[0].substitution = (String)filename;
1461    merged_substitutions[1].substitution = (String)type;
1462    merged_substitutions[2].substitution = (String)suffix;
1463    name_list[0] = pd->name;
1464    name_list[1] = XrmPermStringToQuark("customization");
1465    name_list[2] = NULLQUARK;
1466    class_list[0] = pd->class;
1467    class_list[1] = XrmPermStringToQuark("Customization");
1468    class_list[2] = NULLQUARK;
1469    if (XrmQGetResource(XrmGetDatabase(dpy), name_list, class_list,
1470			&db_type, &value) &&
1471	db_type == _XtQString)
1472	merged_substitutions[3].substitution = (char *)value.addr;
1473    else
1474	merged_substitutions[3].substitution = NULL;
1475    FillInLangSubs(&merged_substitutions[4], pd);
1476
1477    result = XtFindFile(massagedPath, merged_substitutions,
1478			num_substitutions + XtNumber(defaultSubs),
1479			predicate);
1480
1481    if (merged_substitutions[5].substitution != NULL)
1482	XtFree( (XtPointer)merged_substitutions[5].substitution );
1483
1484    if (merged_substitutions != defaultSubs)
1485	DEALLOCATE_LOCAL(merged_substitutions);
1486
1487    if (pathMallocd)
1488	XtFree(massagedPath);
1489    else
1490	DEALLOCATE_LOCAL(massagedPath);
1491
1492    UNLOCK_PROCESS;
1493    return result;
1494}
1495
1496
1497Boolean XtCallAcceptFocus(
1498    Widget widget,
1499    Time *time)
1500{
1501    XtAcceptFocusProc ac;
1502    Boolean retval;
1503    WIDGET_TO_APPCON(widget);
1504
1505    LOCK_APP(app);
1506    LOCK_PROCESS;
1507    ac = XtClass(widget)->core_class.accept_focus;
1508    UNLOCK_PROCESS;
1509
1510    if (ac != NULL)
1511	retval = (*ac) (widget, time);
1512    else
1513	retval = FALSE;
1514    UNLOCK_APP(app);
1515    return retval;
1516}
1517
1518#ifdef XT_GEO_TATTLER
1519/**************************************************************************
1520 GeoTattler:  This is used to debug Geometry management in Xt.
1521
1522  It uses a pseudo resource XtNgeotattler.
1523
1524  E.G. if those lines are found in the resource database:
1525
1526    myapp*draw.XmScale.geoTattler: ON
1527    *XmScrollBar.geoTattler:ON
1528    *XmRowColumn.exit_button.geoTattler:ON
1529
1530   then:
1531
1532    all the XmScale children of the widget named draw,
1533    all the XmScrollBars,
1534    the widget named exit_button in any XmRowColumn
1535
1536   will return True to the function IsTattled(), and will generate
1537   outlined trace to stdout.
1538
1539*************************************************************************/
1540
1541#define XtNgeoTattler "geoTattler"
1542#define XtCGeoTattler "GeoTattler"
1543
1544typedef struct { Boolean   geo_tattler ;} GeoDataRec ;
1545
1546static XtResource geo_resources[] = {
1547    { XtNgeoTattler, XtCGeoTattler, XtRBoolean, sizeof(Boolean),
1548      XtOffsetOf(GeoDataRec, geo_tattler),
1549      XtRImmediate, (XtPointer) False }
1550};
1551
1552/************************************************************************
1553  This function uses XtGetSubresources to find out if a widget
1554  needs to be geo-spied by the caller. */
1555static Boolean IsTattled (Widget widget)
1556{
1557    GeoDataRec geo_data ;
1558
1559    XtGetSubresources(widget, (XtPointer)&geo_data,
1560                      (String)NULL, (String)NULL,
1561		      geo_resources, XtNumber(geo_resources),
1562		      NULL, 0);
1563
1564    return geo_data.geo_tattler;
1565
1566}  /* IsTattled */
1567
1568static int n_tab = 0 ;  /* not MT for now */
1569
1570void
1571_XtGeoTab (int direction)  /* +1 or -1 */
1572{
1573    n_tab += direction ;
1574}
1575
1576
1577void
1578_XtGeoTrace (Widget widget, ...)
1579{
1580    va_list args;
1581    char *fmt;
1582    int i ;
1583    if (IsTattled(widget)) {
1584	va_start(args, widget);
1585	fmt = va_arg(args, char *);
1586	for (i=0; i<n_tab; i++) printf("     ");
1587	(void) vprintf(fmt, args);
1588	va_end(args);
1589    }
1590}
1591
1592#endif /* XT_GEO_TATTLER */
1593
1594