/*********************************************************** Copyright (c) 1993, Oracle and/or its affiliates. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice (including the next paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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. Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. 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 name of Digital 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. ******************************************************************/ /* 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 #endif #include "IntrinsicI.h" #include "VarargsI.h" /* for geoTattler */ #ifndef NO_IDENTIFY_WINDOWS #include #endif #ifndef VMS #include #endif /* VMS */ #ifdef WIN32 #include /* for _getdrives() */ #endif #include #include String XtCXtToolkitError = "XtToolkitError"; Boolean XtIsSubclass(Widget widget, WidgetClass myWidgetClass) { 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 == myWidgetClass) { 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 myWidgetClass, 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 == myWidgetClass) { 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 = (long) 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; children = cwp->children; for (i = 0; i < cwp->num_children; i++) { Widget 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; children = cwp->children; for (i = 0; i < cwp->num_children; i++) { Widget 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", NULL, 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 ? (int) strlen(widget->core.name) : 0; len_cl = (int) 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; 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)) { Cardinal i; WidgetList children; 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 = NULL, 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) { 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 */ Widget w1, w2; 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 = (int) 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; #if defined(WIN32) && defined(__MINGW32__) /* don't try others */ return 0; #endif /* try the places set in the environment */ drive = getenv("_XBASEDRIVE"); 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; } /* 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; } } } 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 */ return (Boolean) 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 } _XtString XtFindFile(_Xconst _XtString path, Substitution substitutions, Cardinal num_substitutions, XtFilePredicate predicate) { char *buf, *buf1, *buf2; _Xconst _XtString colon; int len; Boolean firstTime = TRUE; buf1 = __XtMalloc((unsigned) PATH_MAX); buf2 = __XtMalloc((unsigned) PATH_MAX); buf = buf1; if (predicate == NULL) predicate = TestFile; while (1) { colon = 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 == ':') break; } len = (int) (colon - path); if (Resolve(path, len, substitutions, num_substitutions, buf, '/')) { if (firstTime || strcmp(buf1, buf2) != 0) { #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); return buf1; } XtFree(buf1); return buf2; } 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 String ExtractLocaleName(String lang) { #if defined(CSRG_BASED) || defined(sun) || defined(SVR4) || defined(AIXV3) || defined(WIN32) || defined (linux) #ifdef WIN32 #define SKIPCOUNT 1 #define STARTCHAR '=' #define ENDCHAR ';' #define WHITEFILL #else #if (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 String start; String end; int len; #ifdef SKIPCOUNT int n; #endif static char *buf = NULL; #ifdef WHITEFILL char *temp; #endif 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 = (int) (end - start); XtFree(buf); buf = XtMalloc((Cardinal) (len + 1)); if (buf == NULL) return NULL; strncpy(buf, start, (size_t) len); *(buf + len) = '\0'; #ifdef WHITEFILL for (temp = buf; (temp = strchr(temp, ' ')) != NULL;) *temp++ = '-'; #endif return buf; } else /* if no ENDCHAR is found we are at the end of the line */ return start; } #ifdef WHITEFILL if (strchr(lang, ' ')) { XtFree(buf); buf = strdup(lang); if (buf == NULL) return NULL; for (temp = buf; (temp = strchr(temp, ' ')) != NULL;) *temp++ = '-'; return buf; } #endif #undef STARTCHAR #undef ENDCHAR #undef WHITEFILL #endif return lang; } static void FillInLangSubs(Substitution subs, XtPerDisplay pd) { int len; String string; char *p1, *p2, *p3; char **rest; char *ch; if (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[0] == '\0') { subs[0].substitution = subs[1].substitution = subs[2].substitution = subs[3].substitution = NULL; return; } len = (int) strlen(string) + 1; subs[0].substitution = (_XtString) string; p1 = subs[1].substitution = XtMallocArray(3, (Cardinal) 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 = (int) (ch - string); (void) strncpy(p1, string, (size_t) 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 = (int) (ch - string); strncpy(*rest, string, (size_t) 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 substituted for %D. * The exact value should be documented in the implementation * notes for any Xt implementation. */ static const char * implementation_default_path(void) { #if defined(WIN32) static char xfilesearchpath[] = ""; return xfilesearchpath; #else return XFILESEARCHPATHDEFAULT; #endif } /* *INDENT-OFF* */ static SubstitutionRec defaultSubs[] = { {'N', NULL}, {'T', NULL}, {'S', NULL}, {'C', NULL}, {'L', NULL}, {'l', NULL}, {'t', NULL}, {'c', NULL} }; /* *INDENT-ON* */ _XtString 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 const char *defaultPath = NULL; const char *impl_default = implementation_default_path(); int idef_len = (int) 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; #endif /* VMS */ } if (path == NULL) path = ""; /* NULL would kill us later */ if (filename == NULL) { filename = XrmClassToString(pd->class); } bytesAllocd = bytesLeft = 1000; massagedPath = ALLOCATE_LOCAL((size_t) 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, (size_t) 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 + (Cardinal) i) * sizeof(SubstitutionRec)); if (sub == NULL) _XtAllocError(NULL); for (def = defaultSubs; i--; sub++, def++) sub->match = def->match; for (i = (int) num_substitutions; i--;) *sub++ = *substitutions++; } merged_substitutions[0].substitution = (_XtString) filename; merged_substitutions[1].substitution = (_XtString) type; merged_substitutions[2].substitution = (_XtString) 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; /* *INDENT-OFF* */ static XtResource geo_resources[] = { { XtNgeoTattler, XtCGeoTattler, XtRBoolean, sizeof(Boolean), XtOffsetOf(GeoDataRec, geo_tattler), XtRImmediate, (XtPointer) False } }; /* *INDENT-ON* */ /************************************************************************ 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, const char *fmt, ...) { if (IsTattled(widget)) { va_list args; int i; va_start(args, fmt); for (i = 0; i < n_tab; i++) printf(" "); (void) vprintf(fmt, args); va_end(args); } } #endif /* XT_GEO_TATTLER */