/* $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",
¶ms, &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 */
|