Edit

IABSD.fr/xenocara/lib/libXt/src/Intrinsic.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2006-11-25 18:01:46
    Hash : 799832a0
    Message : import from X.Org 7.2RC2

  • lib/libXt/src/Intrinsic.c
  • /* $Xorg: Intrinsic.c,v 1.4 2001/02/09 02:03:55 xorgcvs Exp $ */
    
    /***********************************************************
    Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
    Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA.
    
                            All Rights Reserved
    
    Permission to use, copy, modify, and distribute this software and its
    documentation for any purpose and without fee is hereby granted,
    provided that the above copyright notice appear in all copies and that
    both that copyright notice and this permission notice appear in
    supporting documentation, and that the names of Digital or Sun not be
    used in advertising or publicity pertaining to distribution of the
    software without specific, written prior permission.
    
    DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
    ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
    DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
    ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
    WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
    ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
    SOFTWARE.
    
    SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO  THIS  SOFTWARE,
    INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
    NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE  LI-
    ABLE  FOR  ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
    ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,  DATA  OR
    PROFITS,  WHETHER  IN  AN  ACTION OF CONTRACT, NEGLIGENCE OR
    OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
    THE USE OR PERFORMANCE OF THIS SOFTWARE.
    
    ******************************************************************/
    /* $XFree86: xc/lib/Xt/Intrinsic.c,v 3.22 2003/01/12 03:55:46 tsi Exp $ */
    
    /*
    
    Copyright 1987, 1988, 1994, 1998  The Open Group
    
    Permission to use, copy, modify, distribute, and sell this software and its
    documentation for any purpose is hereby granted without fee, provided that
    the above copyright notice appear in all copies and that both that
    copyright notice and this permission notice appear in supporting
    documentation.
    
    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.
    
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
    AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    
    Except as contained in this notice, the name of The Open Group shall not be
    used in advertising or otherwise to promote the sale, use or other dealings
    in this Software without prior written authorization from The Open Group.
    
    */
    
    #define INTRINSIC_C
    
    #ifdef HAVE_CONFIG_H
    #include <config.h>
    #endif
    #include "IntrinsicI.h"
    #include "VarargsI.h"        /* for geoTattler */
    #ifndef NO_IDENTIFY_WINDOWS
    #include <X11/Xatom.h>
    #endif
    #ifndef VMS
    #include <sys/stat.h>
    #endif /* VMS */
    
    #include <stdlib.h>
    
    String XtCXtToolkitError = "XtToolkitError";
    
    Boolean XtIsSubclass(
        Widget    widget,
        WidgetClass widgetClass)
    {
        register WidgetClass w;
        Boolean retval = FALSE;
        WIDGET_TO_APPCON(widget);
    
        LOCK_APP(app);
        LOCK_PROCESS;
        for (w = widget->core.widget_class; w != NULL; w = w->core_class.superclass)
    	if (w == widgetClass) {
    	    retval = TRUE;
    	    break;
    	}
        UNLOCK_PROCESS;
        UNLOCK_APP(app);
        return retval;
    } /* XtIsSubclass */
    
    
    Boolean _XtCheckSubclassFlag(
        Widget object,
        _XtXtEnum flag)
    {
        Boolean retval;
    
        LOCK_PROCESS;
        if (object->core.widget_class->core_class.class_inited & flag)
    	retval = TRUE;
        else
    	retval = FALSE;
        UNLOCK_PROCESS;
        return retval;
    } /*_XtVerifySubclass */
    
    
    Boolean _XtIsSubclassOf(
        Widget object,
        WidgetClass widgetClass,
        WidgetClass superClass,
        _XtXtEnum flag)
    {
        LOCK_PROCESS;
        if (!(object->core.widget_class->core_class.class_inited & flag)) {
    	UNLOCK_PROCESS;
    	return False;
        } else {
    	register WidgetClass c = object->core.widget_class;
    	while (c != superClass) {
    	    if (c == widgetClass) {
    		UNLOCK_PROCESS;
    		return True;
    	    }
    	    c = c->core_class.superclass;
    	}
    	UNLOCK_PROCESS;
    	return False;
        }
    } /*_XtIsSubclassOf */
    
    
    XtPointer XtGetClassExtension(
        WidgetClass	object_class,
        Cardinal	byte_offset,
        XrmQuark	type,
        long	version,
        Cardinal	record_size)
    {
        ObjectClassExtension ext;
        LOCK_PROCESS;
    
        ext = *(ObjectClassExtension *)((char *)object_class + byte_offset);
        while (ext && (ext->record_type != type || ext->version < version
    		   || ext->record_size < record_size)) {
    	ext = (ObjectClassExtension) ext->next_extension;
        }
    
        UNLOCK_PROCESS;
        return (XtPointer) ext;
    }
    
    
    static void ComputeWindowAttributes(
        Widget		 widget,
        XtValueMask		 *value_mask,
        XSetWindowAttributes *values)
    {
        XtExposeProc expose;
    
        *value_mask = CWEventMask | CWColormap;
        (*values).event_mask = XtBuildEventMask(widget);
        (*values).colormap = widget->core.colormap;
        if (widget->core.background_pixmap != XtUnspecifiedPixmap) {
    	*value_mask |= CWBackPixmap;
    	(*values).background_pixmap = widget->core.background_pixmap;
        } else {
    	*value_mask |= CWBackPixel;
    	(*values).background_pixel = widget->core.background_pixel;
        }
        if (widget->core.border_pixmap != XtUnspecifiedPixmap) {
    	*value_mask |= CWBorderPixmap;
    	(*values).border_pixmap = widget->core.border_pixmap;
        } else {
    	*value_mask |= CWBorderPixel;
    	(*values).border_pixel = widget->core.border_pixel;
        }
        LOCK_PROCESS;
        expose = widget->core.widget_class->core_class.expose;
        UNLOCK_PROCESS;
        if (expose == (XtExposeProc) NULL) {
    	/* Try to avoid redisplay upon resize by making bit_gravity the same
    	   as the default win_gravity */
    	*value_mask |= CWBitGravity;
    	(*values).bit_gravity = NorthWestGravity;
        }
    } /* ComputeWindowAttributes */
    
    static void CallChangeManaged(
        register Widget		widget)
    {
        register Cardinal		i;
        XtWidgetProc		change_managed;
        register WidgetList		children;
        int    			managed_children = 0;
    
        register CompositePtr cpPtr;
        register CompositePartPtr clPtr;
    
        if (XtIsComposite (widget)) {
    	cpPtr = (CompositePtr)&((CompositeWidget) widget)->composite;
            clPtr = (CompositePartPtr)&((CompositeWidgetClass)
                       widget->core.widget_class)->composite_class;
        } else return;
    
        children = cpPtr->children;
        LOCK_PROCESS;
        change_managed = clPtr->change_managed;
        UNLOCK_PROCESS;
    
        /* CallChangeManaged for all children */
        for (i = cpPtr->num_children; i != 0; --i) {
    	CallChangeManaged (children[i-1]);
    	if (XtIsManaged(children[i-1])) managed_children++;
        }
    
        if (change_managed != NULL && managed_children != 0) {
    	CALLGEOTAT(_XtGeoTrace(widget,"Call \"%s\"[%d,%d]'s changemanaged\n",
    		       XtName(widget),
    		       widget->core.width, widget->core.height));
    	(*change_managed) (widget);
        }
    } /* CallChangeManaged */
    
    
    static void MapChildren(
        CompositePart *cwp)
    {
        Cardinal i;
        WidgetList children;
        register Widget child;
    
        children = cwp->children;
        for (i = 0; i <  cwp->num_children; i++) {
    	child = children[i];
    	if (XtIsWidget (child)){
    	    if (child->core.managed && child->core.mapped_when_managed) {
    		XtMapWidget (children[i]);
    	    }
    	}
        }
    } /* MapChildren */
    
    
    static Boolean ShouldMapAllChildren(
        CompositePart *cwp)
    {
        Cardinal i;
        WidgetList children;
        register Widget child;
    
        children = cwp->children;
        for (i = 0; i < cwp->num_children; i++) {
    	child = children[i];
    	if (XtIsWidget(child)) {
    	    if (XtIsRealized(child) && (! (child->core.managed
    					  && child->core.mapped_when_managed))){
    		    return False;
    	    }
    	}
        }
    
        return True;
    } /* ShouldMapAllChildren */
    
    
    static void RealizeWidget(
        Widget			widget)
    {
        XtValueMask			value_mask;
        XSetWindowAttributes	values;
        XtRealizeProc		realize;
        Window			window;
        Display*			display;
        String			class_name;
        Widget			hookobj;
    
        if (!XtIsWidget(widget) || XtIsRealized(widget)) return;
        display = XtDisplay(widget);
        _XtInstallTranslations(widget);
    
        ComputeWindowAttributes (widget, &value_mask, &values);
        LOCK_PROCESS;
        realize = widget->core.widget_class->core_class.realize;
        class_name = widget->core.widget_class->core_class.class_name;
        UNLOCK_PROCESS;
        if (realize == NULL)
    	XtAppErrorMsg(XtWidgetToApplicationContext(widget),
    		      "invalidProcedure","realizeProc",XtCXtToolkitError,
    		      "No realize class procedure defined",
    		      (String *)NULL, (Cardinal *)NULL);
        else {
    	CALLGEOTAT(_XtGeoTrace(widget,"Call \"%s\"[%d,%d]'s realize proc\n",
    		       XtName(widget),
    		       widget->core.width, widget->core.height));
    	(*realize) (widget, &value_mask, &values);
        }
        window = XtWindow(widget);
        hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget));
        if (XtHasCallbacks(hookobj,XtNchangeHook) == XtCallbackHasSome) {
    	XtChangeHookDataRec call_data;
    
    	call_data.type = XtHrealizeWidget;
    	call_data.widget = widget;
    	XtCallCallbackList(hookobj,
    		((HookObject)hookobj)->hooks.changehook_callbacks,
    		(XtPointer)&call_data);
        }
    #ifndef NO_IDENTIFY_WINDOWS
        if (_XtGetPerDisplay(display)->appContext->identify_windows) {
    	int len_nm, len_cl;
    	char *s;
    
    	len_nm = widget->core.name ? strlen(widget->core.name) : 0;
    	len_cl = strlen(class_name);
    	s = __XtMalloc((unsigned) (len_nm + len_cl + 2));
    	s[0] = '\0';
    	if (len_nm)
    	    strcpy(s, widget->core.name);
    	strcpy(s + len_nm + 1, class_name);
    	XChangeProperty(display, window,
    			XInternAtom(display, "_MIT_OBJ_CLASS",
    				    False),
    			XA_STRING, 8, PropModeReplace, (unsigned char *) s,
    			len_nm + len_cl + 2);
    	XtFree(s);
        }
    #endif
    #ifdef notdef
        _XtRegisterAsyncHandlers(widget);
    #endif
        /* (re)register any grabs extant in the translations */
        _XtRegisterGrabs(widget);
        /* reregister any grabs added with XtGrab{Button,Key} */
        _XtRegisterPassiveGrabs(widget);
        XtRegisterDrawable (display, window, widget);
        _XtExtensionSelect(widget);
    
        if (XtIsComposite (widget)) {
    	Cardinal		i;
    	CompositePart *cwp = &(((CompositeWidget)widget)->composite);
    	WidgetList children = cwp->children;
    	/* Realize all children */
    	for (i = cwp->num_children; i != 0; --i) {
    	    RealizeWidget (children[i-1]);
    	}
    	/* Map children that are managed and mapped_when_managed */
    
    	if (cwp->num_children != 0) {
    	    if (ShouldMapAllChildren(cwp)) {
    		XMapSubwindows (display, window);
    	    } else {
    		MapChildren(cwp);
    	    }
    	}
        }
    
        /* If this is the application's popup shell, map it */
        if (widget->core.parent == NULL && widget->core.mapped_when_managed) {
    	XtMapWidget (widget);
        }
    } /* RealizeWidget */
    
    void XtRealizeWidget (
        Widget		widget)
    {
        WIDGET_TO_APPCON(widget);
    
        LOCK_APP(app);
        if (XtIsRealized (widget)) {
    	UNLOCK_APP(app);
    	return;
        }
        CallChangeManaged(widget);
        RealizeWidget(widget);
        UNLOCK_APP(app);
    } /* XtRealizeWidget */
    
    
    static void UnrealizeWidget(
        Widget		widget)
    {
        CompositeWidget	cw;
        Cardinal		i;
        WidgetList		children;
    
        if (!XtIsWidget(widget) || !XtIsRealized(widget)) return;
    
        /* If this is the application's popup shell, unmap it? */
        /* no, the window is being destroyed */
    
        /* Recurse on children */
        if (XtIsComposite (widget)) {
    	cw = (CompositeWidget) widget;
    	children = cw->composite.children;
    	/* Unrealize all children */
    	for (i = cw->composite.num_children; i != 0; --i) {
    	    UnrealizeWidget (children[i-1]);
    	}
    	/* Unmap children that are managed and mapped_when_managed? */
    	/* No, it's ok to be managed and unrealized as long as your parent */
    	/* is unrealized. XtUnrealize widget makes sure the "top" widget */
    	/* is unmanaged, we can ignore all descendents */
        }
    
        if (XtHasCallbacks(widget, XtNunrealizeCallback) == XtCallbackHasSome)
    	XtCallCallbacks(widget, XtNunrealizeCallback, NULL);
    
        /* Unregister window */
        XtUnregisterDrawable(XtDisplay(widget), XtWindow(widget));
    
        /* Remove Event Handlers */
        /* remove grabs. Happens automatically when window is destroyed. */
    
        /* Destroy X Window, done at outer level with one request */
        widget->core.window = None;
    
        /* Removing the event handler here saves having to keep track if
         * the translation table is changed while the widget is unrealized.
         */
        _XtRemoveTranslations(widget);
    } /* UnrealizeWidget */
    
    
    void XtUnrealizeWidget (
        Widget		widget)
    {
        Window window;
        Widget hookobj;
        WIDGET_TO_APPCON(widget);
    
        LOCK_APP(app);
        window = XtWindow(widget);
        if (! XtIsRealized (widget)) {
    	UNLOCK_APP(app);
    	return;
        }
        if (widget->core.managed && widget->core.parent != NULL)
    	XtUnmanageChild(widget);
        UnrealizeWidget(widget);
        if (window != None)
    	XDestroyWindow(XtDisplay(widget), window);
        hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget));
        if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
    	XtChangeHookDataRec call_data;
    
    	call_data.type = XtHunrealizeWidget;
    	call_data.widget = widget;
    	XtCallCallbackList(hookobj,
    		((HookObject)hookobj)->hooks.changehook_callbacks,
    		(XtPointer)&call_data);
        }
        UNLOCK_APP(app);
    } /* XtUnrealizeWidget */
    
    
    void XtCreateWindow(
        Widget		 widget,
        unsigned int	 window_class,
        Visual		 *visual,
        XtValueMask		 value_mask,
        XSetWindowAttributes *attributes)
    {
        XtAppContext app = XtWidgetToApplicationContext(widget);
    
        LOCK_APP(app);
        if (widget->core.window == None) {
    	if (widget->core.width == 0 || widget->core.height == 0) {
    	    Cardinal count = 1;
    	    XtAppErrorMsg(app,
    		       "invalidDimension", "xtCreateWindow", XtCXtToolkitError,
    		       "Widget %s has zero width and/or height",
    		       &widget->core.name, &count);
    	}
    	widget->core.window =
    	    XCreateWindow (
    		XtDisplay (widget),
    		(widget->core.parent ?
    		    widget->core.parent->core.window :
    		    widget->core.screen->root),
    		(int)widget->core.x, (int)widget->core.y,
    		(unsigned)widget->core.width, (unsigned)widget->core.height,
    		(unsigned)widget->core.border_width, (int) widget->core.depth,
    		window_class, visual, value_mask, attributes);
        }
        UNLOCK_APP(app);
    } /* XtCreateWindow */
    
    
    /* ---------------- XtNameToWidget ----------------- */
    
    static Widget NameListToWidget(
        Widget root,
        XrmNameList     names,
        XrmBindingList  bindings,
        int in_depth, int *out_depth, int *found_depth);
    
    typedef Widget (*NameMatchProc)(XrmNameList,
        XrmBindingList,
        WidgetList, Cardinal, int, int *, int *);
    
    static Widget MatchExactChildren(
        XrmNameList     names,
        XrmBindingList  bindings,
        register WidgetList children,
        register Cardinal num,
        int in_depth, int *out_depth, int *found_depth)
    {
        register Cardinal   i;
        register XrmName    name = *names;
        Widget w, result = NULL;
        int d, min = 10000;
    
        for (i = 0; i < num; i++) {
    	if (name == children[i]->core.xrm_name) {
    	    w = NameListToWidget(children[i], &names[1], &bindings[1],
    		    in_depth+1, &d, found_depth);
    	    if (w != NULL && d < min) {result = w; min = d;}
    	}
        }
        *out_depth = min;
        return result;
    }
    
    static Widget MatchWildChildren(
        XrmNameList     names,
        XrmBindingList  bindings,
        register WidgetList children,
        register Cardinal num,
        int in_depth, int *out_depth, int *found_depth)
    {
        register Cardinal   i;
        Widget w, result = NULL;
        int d, min = 10000;
    
        for (i = 0; i < num; i++) {
    	w = NameListToWidget(children[i], names, bindings,
    		in_depth+1, &d, found_depth);
    	if (w != NULL && d < min) {result = w; min = d;}
        }
        *out_depth = min;
        return result;
    }
    
    static Widget SearchChildren(
        Widget root,
        XrmNameList     names,
        XrmBindingList  bindings,
        NameMatchProc matchproc,
        int in_depth, int *out_depth, int *found_depth)
    {
        Widget w1 = 0, w2;
        int d1, d2;
    
        if (XtIsComposite(root)) {
    	w1 = (*matchproc)(names, bindings,
    		((CompositeWidget) root)->composite.children,
    		((CompositeWidget) root)->composite.num_children,
    		in_depth, &d1, found_depth);
        } else d1 = 10000;
        w2 = (*matchproc)(names, bindings, root->core.popup_list,
    	    root->core.num_popups, in_depth, &d2, found_depth);
        *out_depth = (d1 < d2 ? d1 : d2);
        return (d1 < d2 ? w1 : w2);
    }
    
    static Widget NameListToWidget(
        register Widget root,
        XrmNameList     names,
        XrmBindingList  bindings,
        int in_depth, int *out_depth, int *found_depth)
    {
        Widget w1, w2;
        int d1, d2;
    
        if (in_depth >= *found_depth) {
    	*out_depth = 10000;
    	return NULL;
        }
    
        if (names[0] == NULLQUARK) {
    	*out_depth = *found_depth = in_depth;
    	return root;
        }
    
        if (! XtIsWidget(root)) {
    	*out_depth = 10000;
    	return NULL;
        }
    
        if (*bindings == XrmBindTightly) {
    	return SearchChildren(root, names, bindings, MatchExactChildren,
    		in_depth, out_depth, found_depth);
    
        } else {	/* XrmBindLoosely */
    	w1 = SearchChildren(root, names, bindings, MatchExactChildren,
    		in_depth, &d1, found_depth);
    	w2 = SearchChildren(root, names, bindings, MatchWildChildren,
    		in_depth, &d2, found_depth);
    	*out_depth = (d1 < d2 ? d1 : d2);
    	return (d1 < d2 ? w1 : w2);
        }
    } /* NameListToWidget */
    
    Widget XtNameToWidget(
        Widget root,
        _Xconst char* name)
    {
        XrmName *names;
        XrmBinding *bindings;
        int len, depth, found = 10000;
        Widget result;
        WIDGET_TO_APPCON(root);
    
        len = strlen(name);
        if (len == 0) return NULL;
    
        LOCK_APP(app);
        names = (XrmName *) ALLOCATE_LOCAL((unsigned) (len+1) * sizeof(XrmName));
        bindings = (XrmBinding *)
    	ALLOCATE_LOCAL((unsigned) (len+1) * sizeof(XrmBinding));
        if (names == NULL || bindings == NULL) _XtAllocError(NULL);
    
        XrmStringToBindingQuarkList(name, bindings, names);
        if (names[0] == NULLQUARK) {
    	DEALLOCATE_LOCAL((char *) bindings);
    	DEALLOCATE_LOCAL((char *) names);
    	UNLOCK_APP(app);
    	return NULL;
        }
    
        result = NameListToWidget(root, names, bindings, 0, &depth, &found);
    
        DEALLOCATE_LOCAL((char *) bindings);
        DEALLOCATE_LOCAL((char *) names);
        UNLOCK_APP(app);
        return result;
    } /* XtNameToWidget */
    
    /* Define user versions of intrinsics macros */
    
    #undef XtDisplayOfObject
    Display *XtDisplayOfObject(
         Widget object)
    {
        /* Attempts to LockApp() here will generate endless recursive loops */
        if (XtIsSubclass(object, hookObjectClass))
    	return DisplayOfScreen(((HookObject)object)->hooks.screen);
        return XtDisplay(XtIsWidget(object) ? object : _XtWindowedAncestor(object));
    }
    
    #undef XtDisplay
    Display *XtDisplay(
    	Widget widget)
    {
        /* Attempts to LockApp() here will generate endless recursive loops */
        return DisplayOfScreen(widget->core.screen);
    }
    
    #undef XtScreenOfObject
    Screen *XtScreenOfObject(
         Widget object)
    {
        /* Attempts to LockApp() here will generate endless recursive loops */
        if (XtIsSubclass(object, hookObjectClass))
    	return ((HookObject)object)->hooks.screen;
        return XtScreen(XtIsWidget(object) ? object : _XtWindowedAncestor(object));
    }
    
    #undef XtScreen
    Screen *XtScreen(
    	Widget widget)
    {
        /* Attempts to LockApp() here will generate endless recursive loops */
        return widget->core.screen;
    }
    
    #undef XtWindowOfObject
    Window XtWindowOfObject(
         Widget object)
    {
        return XtWindow(XtIsWidget(object) ? object : _XtWindowedAncestor(object));
    }
    
    
    #undef XtWindow
    Window XtWindow(
    	Widget widget)
    {
        return widget->core.window;
    }
    
    #undef XtSuperclass
    WidgetClass XtSuperclass(
        Widget widget)
    {
        WidgetClass retval;
    
        LOCK_PROCESS;
        retval = XtClass(widget)->core_class.superclass;
        UNLOCK_PROCESS;
        return retval;
    }
    
    #undef XtClass
    WidgetClass XtClass(
        Widget widget)
    {
        WidgetClass retval;
    
        LOCK_PROCESS;
        retval = widget->core.widget_class;
        UNLOCK_PROCESS;
        return retval;
    }
    
    #undef XtIsManaged
    Boolean XtIsManaged(
    	Widget object)
    {
        Boolean retval;
        WIDGET_TO_APPCON(object);
    
        LOCK_APP(app);
        if (XtIsRectObj(object))
    	retval = object->core.managed;
        else
    	retval = False;
        UNLOCK_APP(app);
        return retval;
    }
    
    #undef XtIsRealized
    Boolean XtIsRealized (
        Widget   object)
    {
        Boolean retval;
        WIDGET_TO_APPCON(object);
    
        LOCK_APP(app);
        retval = XtWindowOfObject(object) != None;
        UNLOCK_APP(app);
        return retval;
    } /* XtIsRealized */
    
    #undef XtIsSensitive
    Boolean XtIsSensitive(
    	Widget	object)
    {
        Boolean retval;
        WIDGET_TO_APPCON(object);
    
        LOCK_APP(app);
        if (XtIsRectObj(object))
    	retval = object->core.sensitive && object->core.ancestor_sensitive;
        else
    	retval = False;
        UNLOCK_APP(app);
        return retval;
    }
    
    /*
     * Internal routine; must be called only after XtIsWidget returns false
     */
    Widget _XtWindowedAncestor(
        register Widget object)
    {
        Widget obj = object;
        for (object = XtParent(object); object && !XtIsWidget(object);)
    	object = XtParent(object);
    
        if (object == NULL) {
    	String params = XtName(obj);
    	Cardinal num_params = 1;
    	XtErrorMsg("noWidgetAncestor", "windowedAncestor", XtCXtToolkitError,
    		   "Object \"%s\" does not have windowed ancestor",
    		   &params, &num_params);
        }
    
        return object;
    }
    
    #undef XtParent
    Widget XtParent(
        Widget widget)
    {
        /* Attempts to LockApp() here will generate endless recursive loops */
        return widget->core.parent;
    }
    
    #undef XtName
    String XtName(
         Widget object)
    {
        /* Attempts to LockApp() here will generate endless recursive loops */
        return XrmQuarkToString(object->core.xrm_name);
    }
    
    
    Boolean XtIsObject(
        Widget object)
    {
        WidgetClass wc;
        String class_name;
    
        /* perform basic sanity checks */
        if (object->core.self != object || object->core.xrm_name == NULLQUARK)
    	return False;
    
        LOCK_PROCESS;
        wc = object->core.widget_class;
        if (wc->core_class.class_name == NULL ||
    	wc->core_class.xrm_class == NULLQUARK ||
    	(class_name = XrmClassToString(wc->core_class.xrm_class)) == NULL ||
    	strcmp(wc->core_class.class_name, class_name) != 0) {
    	    UNLOCK_PROCESS;
    	    return False;
    	}
        UNLOCK_PROCESS;
    
        if (XtIsWidget(object)) {
    	if (object->core.name == NULL ||
    	    (class_name = XrmNameToString(object->core.xrm_name)) == NULL ||
    	    strcmp(object->core.name, class_name) != 0)
    	    return False;
        }
        return True;
    }
    
    #if defined(WIN32)
    static int access_file (
        char* path,
        char* pathbuf,
        int len_pathbuf,
        char** pathret)
    {
        if (access (path, F_OK) == 0) {
    	if (strlen (path) < len_pathbuf)
    	    *pathret = pathbuf;
    	else
    	    *pathret = XtMalloc (strlen (path));
    	if (*pathret) {
    	    strcpy (*pathret, path);
    	    return 1;
    	}
        }
        return 0;
    }
    
    static int AccessFile (
        char* path,
        char* pathbuf,
        int len_pathbuf,
        char** pathret)
    {
        unsigned long drives;
        int i, len;
        char* drive;
        char buf[MAX_PATH];
        char* bufp;
    
        /* just try the "raw" name first and see if it works */
        if (access_file (path, pathbuf, len_pathbuf, pathret))
    	return 1;
    
        /* try the places set in the environment */
        drive = getenv ("_XBASEDRIVE");
    #ifdef __UNIXOS2__
        if (!drive)
    	drive = getenv ("X11ROOT");
    #endif
        if (!drive)
    	drive = "C:";
        len = strlen (drive) + strlen (path);
        bufp = XtStackAlloc (len + 1, buf);
        strcpy (bufp, drive);
        strcat (bufp, path);
        if (access_file (bufp, pathbuf, len_pathbuf, pathret)) {
    	XtStackFree (bufp, buf);
    	return 1;
        }
    
    #ifndef __UNIXOS2__
        /* one last place to look */
        drive = getenv ("HOMEDRIVE");
        if (drive) {
    	len = strlen (drive) + strlen (path);
    	bufp = XtStackAlloc (len + 1, buf);
    	strcpy (bufp, drive);
    	strcat (bufp, path);
    	if (access_file (bufp, pathbuf, len_pathbuf, pathret)) {
    	    XtStackFree (bufp, buf);
    	    return 1;
    	}
        }
    
        /* does OS/2 (with or with gcc-emx) have getdrives()? */
        /* tried everywhere else, go fishing */
        drives = _getdrives ();
    #define C_DRIVE ('C' - 'A')
    #define Z_DRIVE ('Z' - 'A')
        for (i = C_DRIVE; i <= Z_DRIVE; i++) { /* don't check on A: or B: */
    	if ((1 << i) & drives) {
    	    len = 2 + strlen (path);
    	    bufp = XtStackAlloc (len + 1, buf);
    	    *bufp = 'A' + i;
    	    *(bufp + 1) = ':';
    	    *(bufp + 2) = '\0';
    	    strcat (bufp, path);
    	    if (access_file (bufp, pathbuf, len_pathbuf, pathret)) {
    		XtStackFree (bufp, buf);
    		return 1;
    	    }
    	}
        }
    #endif
        return 0;
    }
    #endif
    
    static Boolean TestFile(
        String path)
    {
    #ifndef VMS
        int ret = 0;
        struct stat status;
    #if defined(WIN32)
        char buf[MAX_PATH];
        char* bufp;
        int len;
        UINT olderror = SetErrorMode (SEM_FAILCRITICALERRORS);
    
        if (AccessFile (path, buf, MAX_PATH, &bufp))
    	path = bufp;
    
        (void) SetErrorMode (olderror);
    #endif
        ret = (access(path, R_OK) == 0 &&		/* exists and is readable */
    	    stat(path, &status) == 0 &&		/* get the status */
    #ifndef X_NOT_POSIX
    	    S_ISDIR(status.st_mode) == 0);	/* not a directory */
    #else
    	    (status.st_mode & S_IFMT) != S_IFDIR);	/* not a directory */
    #endif /* X_NOT_POSIX else */
    #if defined(WIN32)
        XtStackFree ((XtPointer)bufp, buf);
    #endif
        return ret;
    #else /* VMS */
        return TRUE;	/* Who knows what to do here? */
    #endif /* VMS */
    }
    
    /* return of TRUE = resolved string fit, FALSE = didn't fit.  Not
       null-terminated and not collapsed if it didn't fit */
    
    static Boolean Resolve(
        register _Xconst char *source,	/* The source string */
        register int len,		/* The length in bytes of *source */
        Substitution sub,	/* Array of string values to substitute */
        Cardinal num,	/* Number of substitution entries */
        char *buf,		/* Where to put the resolved string; */
        char collapse)	/* Character to collapse */
    {
        register int bytesLeft = PATH_MAX;
        register char* bp = buf;
    #ifndef DONT_COLLAPSE
        Boolean atBeginning = TRUE;
        Boolean prevIsCollapse = FALSE;
    
    #define PUT(ch) \
        { \
    	if (--bytesLeft == 0) return FALSE; \
            if (prevIsCollapse) \
    	    if ((*bp = ch) != collapse) { \
    		prevIsCollapse = FALSE; \
    		bp++; \
    	    } \
    	    else bytesLeft++; \
            else if ((*bp++ = ch) == collapse && !atBeginning) \
    	    prevIsCollapse = TRUE; \
        }
    #else /* DONT_COLLAPSE */
    
    #define PUT(ch) \
        { \
    	if (--bytesLeft == 0) return FALSE; \
    	*bp++ = ch; \
        }
    #endif /* DONT_COLLAPSE */
    #define escape '%'
    
        while (len--) {
    #ifndef DONT_COLLAPSE
    	if (*source == collapse) {
    	    PUT(*source);
    	    source++;
    	    continue;
    	}
    	else
    #endif /* DONT_COLLAPSE */
    	    if (*source != escape) {
    		PUT(*source);
    	}
    	else {
    	    source++;
    	    if (len-- == 0) {
    		PUT(escape);
    		break;
    	    }
    
    	    if (*source == ':' || *source == escape)
    		PUT(*source)
    	    else {
    		/* Match the character against the match array */
    		register Cardinal j;
    
    		for (j = 0; j < num && sub[j].match != *source; j++) {}
    
    		/* Substitute the substitution string */
    
    		if (j >= num) PUT(*source)
    		else if (sub[j].substitution != NULL) {
    		    char *sp = sub[j].substitution;
    		    while (*sp) {
    			PUT(*sp);
    			sp++;
    		    }
    		}
    	    }
    	}
    	source++;
    #ifndef DONT_COLLAPSE
    	atBeginning = FALSE;
    #endif /* DONT_COLLAPSE */
        }
        PUT('\0');
    
        return TRUE;
    #undef PUT
    #undef escape
    }
    
    
    String XtFindFile(
        _Xconst char* path,
        Substitution substitutions,
        Cardinal num_substitutions,
        XtFilePredicate predicate)
    {
        char *buf, *buf1, *buf2, *colon;
        int len;
        Boolean firstTime = TRUE;
    
        buf = buf1 = __XtMalloc((unsigned)PATH_MAX);
        buf2 = __XtMalloc((unsigned)PATH_MAX);
    
        if (predicate == NULL) predicate = TestFile;
    
        while (1) {
    	colon = (String)path;
    	/* skip leading colons */
    	while (*colon) {
    	    if (*colon != ':') break;
    	    colon++;
    	    path++;
    	}
    	/* now look for an un-escaped colon */
    	for ( ; *colon ; colon++) {
    	    if (*colon == '%' && *(path+1)) {
    		colon++;	/* bump it an extra time to skip %. */
    		continue;
    	    }
    	    if (*colon == ':')
    #ifdef __UNIXOS2__
    	      if (colon > (path+1))
    #endif
    		break;
    	}
    	len = colon - path;
    	if (Resolve(path, len, substitutions, num_substitutions,
    		    buf, '/')) {
    	    if (firstTime || strcmp(buf1,buf2) != 0) {
    #ifdef __UNIXOS2__
    		{
    			char *bufx = (char*)__XOS2RedirRoot(buf);
    			strcpy(buf,bufx);
    		}
    #endif
    #ifdef XNL_DEBUG
    		printf("Testing file %s\n", buf);
    #endif /* XNL_DEBUG */
    		/* Check out the file */
    		if ((*predicate) (buf)) {
    		    /* We've found it, return it */
    #ifdef XNL_DEBUG
    		    printf("File found.\n");
    #endif /* XNL_DEBUG */
    		    if (buf == buf1) XtFree(buf2);
    		    else XtFree(buf1);
    		    return buf;
    		}
    		if (buf == buf1)
    		    buf = buf2;
    		else
    		    buf = buf1;
    		firstTime = FALSE;
    	    }
    	}
    
    	/* Nope...any more paths? */
    
    	if (*colon == '\0') break;
    	path = colon+1;
        }
    
        /* No file found */
    
        XtFree(buf1);
        XtFree(buf2);
        return NULL;
    }
    
    
    /* The implementation of this routine is operating system dependent */
    /* Should match the code in Xlib _XlcMapOSLocaleName */
    
    static char *ExtractLocaleName(
        String	lang)
    {
    
    #if defined(hpux) || defined(CSRG_BASED) || defined(sun) || defined(SVR4) || defined(sgi) || defined(__osf__) || defined(AIXV3) || defined(ultrix) || defined(WIN32) || defined(__UNIXOS2__) || defined (linux)
    # ifdef hpux
    /*
     * We need to discriminated between HPUX 9 and HPUX 10. The equivalent
     * code in Xlib in SetLocale.c does include locale.h via X11/Xlocale.h.
     */
    #  include <locale.h>
    #  ifndef _LastCategory
       /* HPUX 9 and earlier */
    #   define SKIPCOUNT 2
    #   define STARTCHAR ':'
    #   define ENDCHAR ';'
    #  else
        /* HPUX 10 */
    #   define ENDCHAR ' '
    #  endif
    # else
    #  ifdef ultrix
    #   define SKIPCOUNT 2
    #   define STARTCHAR '\001'
    #   define ENDCHAR '\001'
    #  else
    #   if defined(WIN32) || defined(__UNIXOS2__)
    #    define SKIPCOUNT 1
    #    define STARTCHAR '='
    #    define ENDCHAR ';'
    #    define WHITEFILL
    #   else
    #    if defined(__osf__) || (defined(AIXV3) && !defined(AIXV4))
    #     define STARTCHAR ' '
    #     define ENDCHAR ' '
    #    else
    #     if defined(linux)
    #      define STARTSTR "LC_CTYPE="
    #      define ENDCHAR ';'
    #     else
    #      if !defined(sun) || defined(SVR4)
    #       define STARTCHAR '/'
    #       define ENDCHAR '/'
    #      endif
    #     endif
    #    endif
    #   endif
    #  endif
    # endif
    
        char           *start;
        char           *end;
        int             len;
    # ifdef SKIPCOUNT
        int		    n;
    # endif
        static char*    buf = NULL;
    
        start = lang;
    # ifdef SKIPCOUNT
        for (n = SKIPCOUNT;
    	 --n >= 0 && start && (start = strchr (start, STARTCHAR));
    	 start++)
    	;
        if (!start)
    	start = lang;
    # endif
    # ifdef STARTCHAR
        if (start && (start = strchr (start, STARTCHAR)))
    # elif  defined (STARTSTR)
        if (start && (start = strstr (start,STARTSTR)))
    # endif
        {
    # ifdef STARTCHAR
    	start++;
    # elif defined (STARTSTR)
    	start += strlen(STARTSTR);
    # endif
    
    	if ((end = strchr (start, ENDCHAR))) {
    	    len = end - start;
    	    if (buf != NULL) XtFree (buf);
    	    buf = XtMalloc (len + 1);
    	    if (buf == NULL) return NULL;
    	    strncpy(buf, start, len);
    	    *(buf + len) = '\0';
    # ifdef WHITEFILL
    	    for (start = buf; start = strchr(start, ' '); )
    		*start++ = '-';
    # endif
    	    return buf;
    	} else  /* if no ENDCHAR is found we are at the end of the line */
    	    return start;
        }
    # ifdef WHITEFILL
        if (strchr(lang, ' ')) {
    	if (buf != NULL) XtFree (buf);
    	else buf = XtMalloc (strlen (lang) + 1);
    	if (buf == NULL) return NULL;
    	strcpy(buf, lang);
    	for (start = buf; start = strchr(start, ' '); )
    	    *start++ = '-';
    	return buf;
        }
    # endif
    # undef STARTCHAR
    # undef ENDCHAR
    # undef WHITEFILL
    #endif
    
        return lang;
    }
    
    static void FillInLangSubs(
        Substitution subs,
        XtPerDisplay pd)
    {
        int len;
        char *string, *p1, *p2, *p3;
        char **rest;
        char *ch;
    
        if (pd->language == NULL ||
    	(pd->language != NULL && pd->language[0] == '\0')) {
    	subs[0].substitution = subs[1].substitution =
    		subs[2].substitution = subs[3].substitution = NULL;
    	return;
        }
    
        string = ExtractLocaleName(pd->language);
    
        if (string == NULL ||
    	(string != NULL && string[0] == '\0')) {
    	subs[0].substitution = subs[1].substitution =
    		subs[2].substitution = subs[3].substitution = NULL;
    	return;
        }
    
        len = strlen(string) + 1;
        subs[0].substitution = string;
        p1 = subs[1].substitution = __XtMalloc((Cardinal) 3*len);
        p2 = subs[2].substitution = subs[1].substitution + len;
        p3 = subs[3].substitution = subs[2].substitution + len;
    
        /* Everything up to the first "_" goes into p1.  From "_" to "." in
           p2.  The rest in p3.  If no delimiters, all goes into p1.  We
           assume p1, p2, and p3 are large enough. */
    
        *p1 = *p2 = *p3 = '\0';
    
        ch = strchr(string, '_');
        if (ch != NULL) {
    	len = ch - string;
    	(void) strncpy(p1, string, len);
    	p1[len] = '\0';
    	string = ch + 1;
    	rest = &p2;
        } else rest = &p1;
    
        /* Rest points to where we put the first part */
    
        ch = strchr(string, '.');
        if (ch != NULL) {
    	len = ch - string;
    	strncpy(*rest, string, len);
    	(*rest)[len] = '\0';
    	(void) strcpy(p3, ch+1);
        } else (void) strcpy(*rest, string);
    }
    
    /*
     * default path used if environment variable XFILESEARCHPATH
     * is not defined.  Also substitued for %D.
     * The exact value should be documented in the implementation
     * notes for any Xt implementation.
     */
    static char *implementation_default_path(void)
    {
    #if defined(WIN32) || defined(__UNIXOS2__)
        /* if you know how to pass % thru the compiler let me know */
        static char xfilesearchpath[] = XFILESEARCHPATHDEFAULT;
        static Bool fixed;
        char *ch;
    
        if (!fixed) {
    	for (ch = xfilesearchpath; ch = strchr(ch, ';'); ch++)
    	    *ch = '%';
    	fixed = True;
        }
        return xfilesearchpath;
    #else
        return XFILESEARCHPATHDEFAULT;
    #endif
    }
    
    
    static SubstitutionRec defaultSubs[] = {
        {'N', NULL},
        {'T', NULL},
        {'S', NULL},
        {'C', NULL},
        {'L', NULL},
        {'l', NULL},
        {'t', NULL},
        {'c', NULL}
    };
    
    
    String XtResolvePathname(
        Display *dpy,
        _Xconst char* type,
        _Xconst char* filename,
        _Xconst char* suffix,
        _Xconst char* path,
        Substitution substitutions,
        Cardinal num_substitutions,
        XtFilePredicate predicate)
    {
        XtPerDisplay pd;
        static char *defaultPath = NULL;
        char *impl_default = implementation_default_path();
        int idef_len = strlen(impl_default);
        char *massagedPath;
        int bytesAllocd, bytesLeft;
        char *ch, *result;
        Substitution merged_substitutions;
        XrmRepresentation db_type;
        XrmValue value;
        XrmName name_list[3];
        XrmClass class_list[3];
        Boolean pathMallocd = False;
    
        LOCK_PROCESS;
        pd = _XtGetPerDisplay(dpy);
        if (path == NULL) {
    #ifndef VMS
    	if (defaultPath == NULL) {
    	    defaultPath = getenv("XFILESEARCHPATH");
    	    if (defaultPath == NULL)
    		defaultPath = impl_default;
    	}
    	path = defaultPath;
    #else
    	path = "";	/* NULL would kill us later */
    #endif /* VMS */
        }
    
        if (filename == NULL) {
    	filename = XrmClassToString(pd->class);
        }
    
        bytesAllocd = bytesLeft = 1000;
        massagedPath = ALLOCATE_LOCAL(bytesAllocd);
        if (massagedPath == NULL) _XtAllocError(NULL);
    
        if (path[0] == ':') {
    	strcpy(massagedPath, "%N%S");
    	ch = &massagedPath[4];
    	bytesLeft -= 4;
        } else ch = massagedPath;
    
        /* Insert %N%S between adjacent colons
         * and default path for %D.
         * Default path should not have any adjacent colons of its own.
         */
    
        while (*path != '\0') {
    	if (bytesLeft < idef_len) {
    	    int bytesUsed = bytesAllocd - bytesLeft;
    	    char *new;
    	    bytesAllocd +=1000;
    	    new = __XtMalloc((Cardinal) bytesAllocd);
    	    strncpy( new, massagedPath, bytesUsed );
    	    ch = new + bytesUsed;
    	    if (pathMallocd)
    		XtFree(massagedPath);
    	    else
    		DEALLOCATE_LOCAL(massagedPath);
    	    pathMallocd = True;
    	    massagedPath = new;
    	    bytesLeft = bytesAllocd - bytesUsed;
    	}
    	if (*path == '%' && *(path+1) == ':') {
    	    *ch++ = '%';
    	    *ch++ = ':';
    	    path += 2;
    	    bytesLeft -= 2;
    	    continue;
    	}
    	if (*path == ':' && *(path+1) == ':') {
    	    strcpy(ch, ":%N%S:");
    	    ch += 6;
    	    bytesLeft -= 6;
    	    while (*path == ':') path++;
    	    continue;
    	}
    	if (*path == '%' && *(path+1) == 'D') {
    	    strcpy(ch, impl_default);
    	    ch += idef_len;
    	    bytesLeft -= idef_len;
    	    path += 2;
    	    continue;
    	}
    	*ch++ = *path++;
    	bytesLeft--;
        }
        *ch = '\0';
    #ifdef XNL_DEBUG
        printf("Massaged path: %s\n", massagedPath);
    #endif /* XNL_DEBUG */
    
        if (num_substitutions == 0)
    	merged_substitutions = defaultSubs;
        else {
    	int i = XtNumber(defaultSubs);
    	Substitution sub, def;
    	merged_substitutions = sub = (Substitution)
    	    ALLOCATE_LOCAL((unsigned)(num_substitutions+i)*sizeof(SubstitutionRec));
    	if (sub == NULL) _XtAllocError(NULL);
    	for (def = defaultSubs; i--; sub++, def++) sub->match = def->match;
    	for (i = num_substitutions; i--; ) *sub++ = *substitutions++;
        }
        merged_substitutions[0].substitution = (String)filename;
        merged_substitutions[1].substitution = (String)type;
        merged_substitutions[2].substitution = (String)suffix;
        name_list[0] = pd->name;
        name_list[1] = XrmPermStringToQuark("customization");
        name_list[2] = NULLQUARK;
        class_list[0] = pd->class;
        class_list[1] = XrmPermStringToQuark("Customization");
        class_list[2] = NULLQUARK;
        if (XrmQGetResource(XrmGetDatabase(dpy), name_list, class_list,
    			&db_type, &value) &&
    	db_type == _XtQString)
    	merged_substitutions[3].substitution = (char *)value.addr;
        else
    	merged_substitutions[3].substitution = NULL;
        FillInLangSubs(&merged_substitutions[4], pd);
    
        result = XtFindFile(massagedPath, merged_substitutions,
    			num_substitutions + XtNumber(defaultSubs),
    			predicate);
    
        if (merged_substitutions[5].substitution != NULL)
    	XtFree( (XtPointer)merged_substitutions[5].substitution );
    
        if (merged_substitutions != defaultSubs)
    	DEALLOCATE_LOCAL(merged_substitutions);
    
        if (pathMallocd)
    	XtFree(massagedPath);
        else
    	DEALLOCATE_LOCAL(massagedPath);
    
        UNLOCK_PROCESS;
        return result;
    }
    
    
    Boolean XtCallAcceptFocus(
        Widget widget,
        Time *time)
    {
        XtAcceptFocusProc ac;
        Boolean retval;
        WIDGET_TO_APPCON(widget);
    
        LOCK_APP(app);
        LOCK_PROCESS;
        ac = XtClass(widget)->core_class.accept_focus;
        UNLOCK_PROCESS;
    
        if (ac != NULL)
    	retval = (*ac) (widget, time);
        else
    	retval = FALSE;
        UNLOCK_APP(app);
        return retval;
    }
    
    #ifdef XT_GEO_TATTLER
    /**************************************************************************
     GeoTattler:  This is used to debug Geometry management in Xt.
    
      It uses a pseudo resource XtNgeotattler.
    
      E.G. if those lines are found in the resource database:
    
        myapp*draw.XmScale.geoTattler: ON
        *XmScrollBar.geoTattler:ON
        *XmRowColumn.exit_button.geoTattler:ON
    
       then:
    
        all the XmScale children of the widget named draw,
        all the XmScrollBars,
        the widget named exit_button in any XmRowColumn
    
       will return True to the function IsTattled(), and will generate
       outlined trace to stdout.
    
    *************************************************************************/
    
    #define XtNgeoTattler "geoTattler"
    #define XtCGeoTattler "GeoTattler"
    
    typedef struct { Boolean   geo_tattler ;} GeoDataRec ;
    
    static XtResource geo_resources[] = {
        { XtNgeoTattler, XtCGeoTattler, XtRBoolean, sizeof(Boolean),
          XtOffsetOf(GeoDataRec, geo_tattler),
          XtRImmediate, (XtPointer) False }
    };
    
    /************************************************************************
      This function uses XtGetSubresources to find out if a widget
      needs to be geo-spied by the caller. */
    static Boolean IsTattled (Widget widget)
    {
        GeoDataRec geo_data ;
    
        XtGetSubresources(widget, (XtPointer)&geo_data,
                          (String)NULL, (String)NULL,
    		      geo_resources, XtNumber(geo_resources),
    		      NULL, 0);
    
        return geo_data.geo_tattler;
    
    }  /* IsTattled */
    
    static int n_tab = 0 ;  /* not MT for now */
    
    void
    _XtGeoTab (int direction)  /* +1 or -1 */
    {
        n_tab += direction ;
    }
    
    
    void
    _XtGeoTrace (Widget widget, ...)
    {
        va_list args;
        char *fmt;
        int i ;
        if (IsTattled(widget)) {
    	va_start(args, widget);
    	fmt = va_arg(args, char *);
    	for (i=0; i<n_tab; i++) printf("     ");
    	(void) vprintf(fmt, args);
    	va_end(args);
        }
    }
    
    #endif /* XT_GEO_TATTLER */