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