sdo@soliado.East.Sun.COM (Scott Oaks - Sun Consulting NYC) (04/29/91)
Submitted-by: sdo@soliado.East.Sun.COM (Scott Oaks - Sun Consulting NYC) Posting-number: Volume 12, Issue 71 Archive-name: olvwm/part15 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 15 (of 16)." # Contents: resources.c # Wrapped by sdo@piccolo on Fri Apr 26 17:31:11 1991 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'resources.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'resources.c'\" else echo shar: Extracting \"'resources.c'\" \(40786 characters\) sed "s/^X//" >'resources.c' <<'END_OF_FILE' X/* X * (c) Copyright 1990 Sun Microsystems, Inc. Sun design patents X * pending in the U.S. and foreign countries. See LEGAL_NOTICE X * file for terms of the license. X * X * Written for Sun Microsystems by Crucible, Santa Cruz, CA. X */ X static char sccsid[] = "@(#)resources.c 1.5 olvwm version 4/26/91"; X X/* X * Based on static char sccsid[] = "@(#) resources.c 25.34 90/06/05 Crucible"; X * X */ X X#include <ctype.h> X#include <errno.h> X#include <stdio.h> X#include <string.h> X#include <sys/file.h> X#include <X11/Xos.h> X#include <X11/Xlib.h> X#include <X11/Xutil.h> X#include <X11/Xresource.h> X#include <X11/keysym.h> X#include <X11/cursorfont.h> X X#include <olgx/olgx.h> X X#include "mem.h" X#include "olwm.h" X#include "win.h" X#include "defaults.h" X#include "globals.h" X#include "resources.h" X#include "olcursor.h" X extern char *AppName; extern Bool ColorDisplay; extern List *ActiveClientList; X extern Graphics_info *olgx_gisbutton; extern Graphics_info *olgx_gistext; extern Graphics_info *olgx_gisnormal; extern Graphics_info *olgx_gisreverse; extern Graphics_info *olgx_gisrevpin; X extern GC DrawNormalGC, DrawReverseGC; extern GC DrawLinesGC, DrawRevLinesGC; extern GC DrawBackgroundGC, DrawSelectedGC; extern GC DrawBusyGC; extern GC IconUnselectedGC, IconBorderGC; extern GC IconNormalGC, IconSelectedGC; X extern Pixmap Gray50; extern int Gray50width; extern int Gray50height; X XXrmDatabase OlwmDB = NULL; GlobalResourceVariables GRV; X Bool WorkspaceColorUsed = False; unsigned long WorkspaceColorPixel; X static Bool windowColorsAllocated = False; X extern void FrameSetupGrabs(); X X/* forward function definitions */ static Bool setMinimalDecor(); static Bool setBeepResource(); static Bool updIconLocation(); static Bool updBorderColor(); X Bool UpdInputFocusStyle(); X X/* NOTICE that the optionTable for command line entries is mostly X * independent of this table. BOTH need to be modified in case of X * changes or additions. X */ X/* quantity of/indices into the RMTable are #define'd in resources.h */ ResourceInfo RMTable[] = { X { ".display", ".Display", NULL, X &(GRV.DisplayName), (BFuncPtr)0, (BFuncPtr)0 }, X { ".name", ".Name", "olwm", X &(GRV.NameTag), SetNameTag, (BFuncPtr)0 }, X { ".workspaceColor", ".WorkspaceColor", NULL, X &(GRV.WorkspaceColor), setCharResource, UpdWorkspace }, X { ".use3D", ".Use3D", "True", X &(GRV.F3dUsed), setDimension, (BFuncPtr)0 }, X { ".WindowColor", ".Background", NULL, X &(GRV.Bg1Color), setBg1Color, UpdBg1Color }, X { ".foreground", ".Foreground", NULL, X &(GRV.Fg1Color), setFg1Color, UpdFg1Color }, X { ".borderColor", ".Foreground", NULL, X &(GRV.BorderColor), setColor, updBorderColor }, X { ".cursorColor", ".Foreground", NULL, X &(GRV.CursorColor), setColor, UpdCursorColor }, X/* NOTICE that font defaults are names, although variables are font infos */ X#ifdef LATER /* ideal name/class setup */ X { ".title.font", ".Title.Font", X "-b&h-lucida-bold-r-normal-sans-*-120-*-*-*-*-*-*", X &(GRV.TitleFontInfo), setFontResource, UpdTitleFont }, X { ".text.font", ".Text.Font", X "-b&h-lucida-medium-r-normal-sans-*-120-*-*-*-*-*-*", X &(GRV.TextFontInfo), setFontResource, UpdTextFont }, X { ".button.font", ".Button.Font", X "-b&h-lucida-medium-r-normal-sans-*-120-*-*-*-*-*-*", X &(GRV.ButtonFontInfo), setFontResource, UpdButtonFont }, X { ".icon.font", ".Icon.Font", X "-b&h-lucida-medium-r-normal-sans-*-120-*-*-*-*-*-*", X &(GRV.IconFontInfo), setFontResource, UpdIconFont }, X#else X { ".titleFont", ".TitleFont", X "-b&h-lucida-bold-r-normal-sans-*-120-*-*-*-*-*-*", X &(GRV.TitleFontInfo), setFontResource, UpdTitleFont }, X { ".textFont", ".TextFont", X "-b&h-lucida-medium-r-normal-sans-*-120-*-*-*-*-*-*", X &(GRV.TextFontInfo), setFontResource, UpdTextFont }, X { ".buttonFont", ".MenuButtonFont", X "-b&h-lucida-medium-r-normal-sans-*-120-*-*-*-*-*-*", X &(GRV.ButtonFontInfo), setFontResource, UpdButtonFont }, X { ".iconFont", ".IconFont", X "-b&h-lucida-medium-r-normal-sans-*-120-*-*-*-*-*-*", X &(GRV.IconFontInfo), setFontResource, UpdIconFont }, X#endif /* LATER */ X { ".glyphFont", ".GlyphFont", X "-sun-open look glyph-*-*-*-*-*-120-*-*-*-*-*-*", X &(GRV.GlyphFontInfo), setGlyphFont, UpdGlyphFont }, X { ".cursorFont", ".CursorFont", X "-sun-open look cursor-*-*-*-*-*-120-*-*-*-*-*-*", X &(GRV.BasicPointer), setCursors, (BFuncPtr)0 }, X { ".inputFocusStyle", ".SetInput", "Select", X &(GRV.FocusFollowsMouse), setInputFocusStyle, UpdInputFocusStyle }, X { ".reparentOK", ".ReparentOK", "True", X &(GRV.ReparentFlag), setBoolResource, (BFuncPtr)0 }, X { ".defaultTitle", ".DefaultTitle", "No Name", X &(GRV.DefaultWinName), setCharResource, (BFuncPtr)0 }, X { ".flashFrequency", ".FlashFrequency", "100000", X &(GRV.FlashTime), setIntResource, (BFuncPtr)0 }, X { ".menu.popup.outlineButton", ".Menu.Popup.OutlineButton", "False", X &(GRV.FShowMenuButtons), setBoolResource, (BFuncPtr)0 }, X { ".menu.pinned.outlineButton", ".Menu.Pinned.OutlineButton", "False", X &(GRV.FShowPinnedMenuButtons), setBoolResource, (BFuncPtr)0 }, X { ".iconLocation", ".IconLocation", "Top", X &(GRV.IconPlacement), setIconLocation, updIconLocation }, X { ".focusLenience", ".FocusLenience", "False", X &(GRV.FocusLenience), setBoolResource, (BFuncPtr)0 }, X { ".dragWindow", ".DragWindow", "False", X &(GRV.DragWindow), setBoolResource, (BFuncPtr)0 }, X { ".autoRaise", ".AutoRaise", "False", X &(GRV.AutoRaise), setBoolResource, (BFuncPtr)0 }, X { ".dragRightDistance", ".DragRightDistance", "100", X &(GRV.DragRightDistance), setIntResource, (BFuncPtr)0 }, X { ".moveThreshold", ".MoveThreshold", "5", X &(GRV.MoveThreshold), setIntResource, (BFuncPtr)0 }, X { ".clickMoveThreshold", ".ClickMoveThreshold", "5", X &(GRV.ClickMoveThreshold), setIntResource, (BFuncPtr)0 }, X { ".mouseClickTimeout", ".MultiClickTimeout", "500", X &(GRV.DoubleClickTime), setClickTimeout, (BFuncPtr)0 }, X/* NOTICE that key defaults are string reps of syms, but vars are keycodes */ X { ".frontKey", ".FrontKey", "Any L5", X &(GRV.FrontKey), setKey, (BFuncPtr)0 }, X { ".helpKey", ".HelpKey", "Help", X &(GRV.HelpKey), setKey, (BFuncPtr)0 }, X { ".openKey", ".OpenKey", "Any L7", X &(GRV.OpenKey), setKey, (BFuncPtr)0 }, X { ".confirmKey", ".ConfirmKey", "Return", X &(GRV.ConfirmKey), setKey, (BFuncPtr)0 }, X { ".print.orphans", ".Print.Debug", "False", X &(GRV.PrintOrphans), setBoolResource, (BFuncPtr)0 }, X { ".print.all", ".Print.Debug", "False", X &(GRV.PrintAll), setBoolResource, (BFuncPtr)0 }, X { ".synchronize", ".Debug", "False", X &(GRV.Synchronize), setBoolResource, UpdSync }, X { ".snapToGrid", ".SnapToGrid", "False", X &(GRV.FSnapToGrid), setBoolResource, (BFuncPtr)0 }, X { ".saveWorkspaceTimeout", ".SaveWorkspaceTimeout", "10", X &(GRV.SaveWorkspaceTimeout), setIntResource, (BFuncPtr)0 }, X { ".popupJumpCursor", ".PopupJumpCursor", "True", X &(GRV.PopupJumpCursor), setBoolResource, (BFuncPtr)0 }, X { ".cancelKey", ".CancelKey", "Escape", X &(GRV.CancelKey), setKey, (BFuncPtr)0 }, X { ".colorLockKey", ".ColorLockKey", "Control L2", X &(GRV.ColorLockKey), setKey, (BFuncPtr)0 }, X { ".colorUnlockKey", ".ColorUnlockKey", "Control L4", X &(GRV.ColorUnlockKey), setKey, (BFuncPtr)0 }, X { ".colorFocusLocked", ".ColorFocusLocked", "False", X &(GRV.ColorFocusLocked), setBoolResource, (BFuncPtr)0 }, X { ".edgeMoveThreshold", ".EdgeMoveThreshold", "10", X &(GRV.EdgeThreshold), setIntResource, (BFuncPtr)0 }, X { ".rubberBandThickness", ".RubberBandThickness", "2", X &(GRV.RubberBandThickness), setIntResource, (BFuncPtr)0 }, X { ".beep", ".Beep", "always", X &(GRV.Beep), setBeepResource, (BFuncPtr)0 }, X { ".pPositionCompat", ".PPositionCompat", "false", X &(GRV.PPositionCompat), setBoolResource, (BFuncPtr)0 }, X { ".minimalDecor", ".MinimalDecor", "", X &(GRV.Minimals), setMinimalDecor, (BFuncPtr)0 }, X { ".use3DFrames", ".Use3DFrames", "False", X &(GRV.F3dFrames), setBoolResource, (BFuncPtr)0 }, X { ".refreshRecursively", ".RefreshRecursively", "True", X &(GRV.RefreshRecursively), setBoolResource, (BFuncPtr)0 }, X { ".virtualDesktop", ".VirtualDesktop", "3x2", X GRV.VirtualDesktop, setStringResource, UpdVirtualDesktop }, X { ".allowMoveIntoDesktop", ".AllowMoveIntoDesktop","true", X &(GRV.AllowMoveIntoDesktop), setBoolResource, (BFuncPtr)0 }, X { ".vdmScale", ".PannerScale", "15", X &(GRV.VDMScale), setIntResource, UpdVDMScale }, X { ".virtualGeometry", ".VirtualGeometry", "0x0", X GRV.VirtualGeometry, setStringResource, UpdVirtualGeometry}, X { ".virtualFont", ".VirtualFont", X "-b&h-lucida-medium-r-normal-sans-*-120-*-*-*-*-*-*", X &(GRV.VirtualFont), setFontResource, UpdVirtualFont }, X { ".allowArrowInRoot", ".AllowArrowInRoot", "True", X &(GRV.ArrowInRoot), setBoolResource, (BFuncPtr) 0 }, X { ".virtualBackgroundColor", ".VirtualBackgroundColor", "-1", X &(GRV.VirtualBackgroundColor), VirtualSetColor, UpdVirtualBgColor }, X { ".virtualBackgroundMap", ".VirtualBackgroundMap", NULL, X &(GRV.VirtualBackgroundMap), setCharResource, UpdVirtualMap }, X { ".virtualIconGeometry", ".VirtualIconGeometry", "0x0", X GRV.VirtualIconGeometry, setStringResource, UpdVirtualIconGeometry}, X { ".virtualForegroundColor", ".VirtualForegroundColor", "-1", X &(GRV.VirtualForegroundColor), VirtualSetColor, UpdVirtualFgColor }, X { ".virtualFontColor", ".VirtualFontColor", "-1", X &(GRV.VirtualFontColor), VirtualSetColor, UpdVirtualFontColor }, X { ".autoShowRootMenu", ".AutoShowRootMenu", "False", X &(GRV.AutoShowRootMenu), setBoolResource, (BFuncPtr) 0 }, X { ".autoRootMenuX", ".AutoRootMenuX", "0", X &(GRV.AutoRootMenuX), setIntResource, (BFuncPtr) 0 }, X { ".autoRootMenuY", ".AutoRootMenuY", "0", X &(GRV.AutoRootMenuY), setIntResource, (BFuncPtr) 0 }, X { ".virtualIconic", ".VirtualIconic", "False", X &(GRV.VirtualIconic), setBoolResource, (BFuncPtr) 0 }, X { ".virtualSticky", ".VirtualSticky", "", X &(GRV.StickyList), setMinimalDecor, (BFuncPtr)0 }, X}; X X/* private data */ X static Bool matchString(); static Bool matchBool(); static Bool matchFocusType(); static Bool matchIconPlace(); static Bool matchBeepKeyword(); X#ifdef NOTDEF static Bool checkClass(); X#endif static void setWorkspaceColor(); X X X#define BSIZE 100 X X/* X * Determine whether value matches pattern, irrespective of case. X * This routine is necessary because not all systems have strcasecmp(). X */ static Bool matchString( value, pattern ) char *value; char *pattern; X{ X char buf[BSIZE]; X char *p; X X strncpy(buf,value,BSIZE); X buf[BSIZE-1] = '\0'; /* force null termination */ X X for ( p=buf; *p; ++p ) X if (isupper(*p)) X *p = tolower(*p); X X return 0 == strcmp(buf,pattern); X} X X X/* X * Match any of the following booleans: yes, no, 1, 0, on, off, t, nil, X * true, false. Pass back the boolean matched in ret, and return True. X * Otherwise, return False. X * X * matchString is case independent. X */ static Bool matchBool( value, ret ) char *value; Bool *ret; X{ X if (matchString(value,"yes") || X matchString(value,"on") || X matchString(value,"t") || X matchString(value,"true") || X (0 == strcmp(value,"1"))) { X *ret = True; X return True; X } X X if (matchString(value,"no") || X matchString(value,"off") || X matchString(value,"nil") || X matchString(value,"false") || X (0 == strcmp(value,"0"))) { X *ret = False; X return True; X } X X return False; X} X X/* X * Match any of the following input focus types: followmouse, follow, f, X * select, s, click, clicktotype, c. Pass back True for focusfollows or X * False for clicktotype in ret (since FocusFollowsMouse is the global X * corresponding to this resource), and return True. X * Otherwise, return False. X * X * matchString is case independent. X */ static Bool matchFocusType( value, ret ) char *value; Bool *ret; X{ X if ( matchString(value, "followmouse") X || matchString(value, "follow") X || matchString(value,"f") ) X { X *ret = True; X return True; X } X X if ( matchString(value, "select") X || matchString(value, "click") X || matchString(value,"clicktotype") X || matchString(value,"c") X || matchString(value,"s") ) X { X *ret = False; X return True; X } X X return False; X} X X/* X * Match any of the three possible beep keywords: always, never, or notices. X * Pass back the BeepStatus value by reference, and return True, if X * a match was found; otherwise return False and do not disturb the X * passed value. X */ static Bool matchBeepKeyword(value,ret) char *value; BeepStatus *ret; X{ X if (matchString(value,"always")) X { X *ret = BeepAlways; X return True; X } X if (matchString(value,"never")) X { X *ret = BeepNever; X return True; X } X if (matchString(value,"notices")) X { X *ret = BeepNotices; X return True; X } X return False; X} X X/* X * Match any of the following icon placement locations: top, bottom, right, X * left, s, click, clicktotype, c. Pass back the IconPreference X * in ret, and return True. X * Otherwise, return False. X * X * matchString is case independent. X */ static Bool matchIconPlace( value, ret ) char *value; IconPreference *ret; X{ X if (matchString(value, "top")) X { X *ret = AlongTop; X return True; X } X if (matchString(value, "bottom")) X { X *ret = AlongBottom; X return True; X } X if (matchString(value, "right")) X { X *ret = AlongRight; X return True; X } X if (matchString(value, "left")) X { X *ret = AlongLeft; X return True; X } X if (matchString(value, "top-lr")) X { X *ret = AlongTop; X return True; X } X if (matchString(value, "top-rl")) X { X *ret = AlongTopRL; X return True; X } X if (matchString(value, "bottom-lr")) X { X *ret = AlongBottom; X return True; X } X if (matchString(value, "bottom-rl")) X { X *ret = AlongBottomRL; X return True; X } X if (matchString(value, "right-tb")) X { X *ret = AlongRight; X return True; X } X if (matchString(value, "right-bt")) X { X *ret = AlongRightBT; X return True; X } X if (matchString(value, "left-tb")) X { X *ret = AlongLeft; X return True; X } X if (matchString(value, "left-bt")) X { X *ret = AlongLeftBT; X return True; X } X X return False; X} X X#ifdef NOTDEF X/* X * checkClass - Check to see if the named class is the same as (or a subset of) X * the compareClass specified. X * X * Note that the fullClassname must be consistently bound! X * (If combine loose and tight bindings, need to convert to using X * XrmStringToBindingQuarkList().) X */ static Bool checkClass( fullClassname, compareClass ) char *fullClassname; char *compareClass; X{ X#define MAX_QUARKS 20 X XrmQuark classQuarks[MAX_QUARKS]; X XrmQuark compareQuark; X int ii; X X compareQuark = XrmStringToQuark( compareClass ); X XrmStringToQuarkList( fullClassname, classQuarks ); X for ( ii = 0 ; (ii < MAX_QUARKS) && (classQuarks[ii] != NULL) ; ii++ ) X if ( compareQuark == classQuarks[ii] ) X return True; X X return False; X} X#endif X X X/* X * The Resource Set Functions X */ X X/* X * setBoolResource - set value of a bool resource X * X */ X/*ARGSUSED*/ /* dpy is std arg for Set fns */ static Bool setBoolResource( dpy, rmIndex, newValue, varSet ) Display *dpy; int rmIndex; char *newValue; Bool varSet; X{ X Bool newBoolValue; X Bool updateNeeded = False; X#define RM_BOOLVAR *((Bool *)(RMTable[rmIndex].varAddr)) X X if ( (newValue == NULL) || !matchBool( newValue, &newBoolValue ) ) X { X if ( varSet ) X return( updateNeeded ); X else /* builtin default */ X matchBool( RMTable[rmIndex].defaultVal, &newBoolValue ); X } X else if ( varSet ) /* a valid newValue and an old value */ X { X if ( newBoolValue == RM_BOOLVAR ) X return( updateNeeded ); X else X updateNeeded = True; X } X X RM_BOOLVAR = newBoolValue; X return( updateNeeded ); X} X X/* X * setFontResource - set font info variable from db resource value X * X * Notice that since comparing XFontStructs would be rather messy, X * we cheat and simply compare the font names in the database. X */ static Bool setFontResource( dpy, rmIndex, newValue, varSet ) Display *dpy; int rmIndex; char *newValue; Bool varSet; X{ X XFontStruct *tmpFontInfo; X Bool updateNeeded = False; X char name[MAX_NAME]; X char class[MAX_CLASS]; X XrmRepresentation rmType; X XrmValue rmValue; X X#define RM_FONTVAR *((XFontStruct **)(RMTable[rmIndex].varAddr)) X X if ( ( newValue == NULL ) || X ( (tmpFontInfo = XLoadQueryFont(dpy, newValue)) == NULL ) ) X { X if ( varSet ) X return( updateNeeded ); X else if ( ( tmpFontInfo = X XLoadQueryFont(dpy, RMTable[rmIndex].defaultVal) ) X == NULL ) X tmpFontInfo = XLoadQueryFont(dpy, DEFAULTFONT); X } X else if ( varSet ) X { X MakeRMName( name, rmIndex ); X MakeRMClass( class, rmIndex ); X /* compare newValue with old value - REMIND if default was used X * last time, and newValue was now set to it vi xrdb, then we X * may do an update unnecessarily (since value will not be in X * OlwmDB, so XrmGetResource will return False and updateNeeded X * will be set to True, since we can't strcmp the value) X */ X if ( XrmGetResource( OlwmDB, name, class, &rmType, &rmValue ) X && !strcmp( newValue, rmValue.addr ) ) X return( updateNeeded ); X else X updateNeeded = True; X } X X RM_FONTVAR = tmpFontInfo; X return( updateNeeded ); X} X X/* X * setGlyphFont - set glyph font info variable from db resource value X * X * Notice that since comparing XFontStructs would be rather messy, X * we cheat and simply compare the font names in the database. X * X * This is essentially the same as SetFontResource, except that X * the absence of a valid glyph font is a fatal error. X */ static Bool setGlyphFont( dpy, rmIndex, newValue, varSet ) Display *dpy; int rmIndex; char *newValue; Bool varSet; X{ X XFontStruct *tmpFontInfo; X Bool updateNeeded = False; X char name[MAX_NAME]; X char class[MAX_CLASS]; X XrmRepresentation rmType; X XrmValue rmValue; X X#ifndef RM_FONTVAR X#define RM_FONTVAR *((XFontStruct **)(RMTable[rmIndex].varAddr)) X#endif X X if ( ( newValue == NULL ) || X ( (tmpFontInfo = XLoadQueryFont(dpy, newValue)) == NULL ) ) X { X if ( varSet ) X return( updateNeeded ); X else if ( ( tmpFontInfo = X XLoadQueryFont(dpy, RMTable[rmIndex].defaultVal) ) X == NULL ) X { X fprintf(stderr, X "OLWM fatal error: can't load glyph font \"%s\"; exiting\n", X RMTable[rmIndex].defaultVal); X exit(1); X } X } X else if ( varSet ) X { X MakeRMName( name, rmIndex ); X MakeRMClass( class, rmIndex ); X /* compare newValue with old value - REMIND if default was used X * last time, and newValue was now set to it vi xrdb, then we X * may do an update unnecessarily (since value will not be in X * OlwmDB, so XrmGetResource will return False and updateNeeded X * will be set to True, since we can't strcmp the value) X */ X if ( XrmGetResource( OlwmDB, name, class, &rmType, &rmValue ) X && !strcmp( newValue, rmValue.addr ) ) X return( updateNeeded ); X else X updateNeeded = True; X } X X RM_FONTVAR = tmpFontInfo; X return( updateNeeded ); X} X X/* X * setCursors - set up ALL cursors from cursor font specified X * X * NOTE that CursorColor and Bg1Color must be set before the cursors! X * X * Notice that six cursors are set up (and stored in six separate X * GRV elements) from this single resource. X * X * Also, since we don't save the actual cursor font name, X * checking to see if the font has been changed must be done by X * comparing the font names in the database. X * X */ static Bool setCursors( dpy, rmIndex, newValue, varSet ) Display *dpy; int rmIndex; char *newValue; Bool varSet; X{ X Font cursorFont = 0; /* init for compare */ X Bool updateNeeded = False; X char name[MAX_NAME]; X char class[MAX_CLASS]; X XrmRepresentation rmType; X XrmValue rmValue; X int ii; X XColor foreColor, backColor; X X if ( ( newValue == NULL ) X || ( (cursorFont = XLoadFont( dpy, newValue )) == 0 ) ) X { X if ( varSet ) X return( updateNeeded ); X else /* use built-in default if possible */ X cursorFont = XLoadFont( dpy, X RMTable[rmIndex].defaultVal ); X } X else if ( varSet ) X { X /* check to see if cursor font in resource actually changed */ X MakeRMName( name, rmIndex ); X MakeRMClass( class, rmIndex ); X /* compare newValue with old value - REMIND doesn't detect X * when built-in default values are used X */ X if ( XrmGetResource( OlwmDB, name, class, &rmType, &rmValue ) X && !strcmp( newValue, rmValue.addr ) ) X return( updateNeeded ); X else X updateNeeded = True; X } X X /* set up cursor rgb values in color structure */ X foreColor.pixel = GRV.CursorColor; X XQueryColor( dpy, CMAP, &foreColor ); X /* REMIND - should backColor be background (GRV.Bg1Color)? */ X backColor.pixel = WhitePixel( dpy, DefaultScreen(dpy) ); X XQueryColor( dpy, CMAP, &backColor ); X X /* loop through and set all six pointers */ X for ( ii = 0 ; ii < NUM_CURSORS ; ii++ ) X { X Cursor *tmpVariable; X unsigned int tmpFontIndex; X unsigned int defaultIndex; X X switch( ii ) X { X /* REMIND - we might need to change these absolute indices to X * #defines of some sort X */ X case BASICPTR: tmpVariable = &GRV.BasicPointer; X tmpFontIndex = OLC_basic; X defaultIndex = XC_left_ptr; X break; X case MOVEPTR: tmpVariable = &GRV.MovePointer; X tmpFontIndex = OLC_basic; X defaultIndex = XC_left_ptr; X break; X case BUSYPTR: tmpVariable = &GRV.BusyPointer; X tmpFontIndex = OLC_busy; X defaultIndex = XC_watch; X break; X case ICONPTR: tmpVariable = &GRV.IconPointer; X tmpFontIndex = OLC_basic; X defaultIndex = XC_left_ptr; X break; X case RESIZEPTR: tmpVariable = &GRV.ResizePointer; X tmpFontIndex = OLC_beye; X defaultIndex = XC_tcross; X break; X case MENUPTR: tmpVariable = &GRV.MenuPointer; X tmpFontIndex = OLC_basic; X defaultIndex = XC_sb_right_arrow; X break; X case QUESTIONPTR: tmpVariable = &GRV.QuestionPointer; X tmpFontIndex = OLC_basic; X defaultIndex = XC_question_arrow; X break; X case TARGETPTR: tmpVariable = &GRV.TargetPointer; X tmpFontIndex = OLC_basic; X defaultIndex = XC_circle; X break; X case PANPTR: tmpVariable = &GRV.PanPointer; X tmpFontIndex = OLC_panning; X defaultIndex = XC_sb_v_double_arrow; X break; X } X X if ( ( cursorFont == 0 ) X || ( (*tmpVariable = XCreateGlyphCursor( dpy, cursorFont, X cursorFont, tmpFontIndex, tmpFontIndex+1, X &foreColor, &backColor )) == 0 ) ) X { X /* use default */ X *tmpVariable = XCreateFontCursor( dpy, defaultIndex ); X#ifdef LATER X /* seems to be a bug in XRecolorCursor() right now */ X XRecolorCursor( dpy, tmpVariable, &foreColor, &backColor ); X#endif X } X } X X return( updateNeeded ); X} X X/* X * setCharResource - set character resource value from db X */ X/*ARGSUSED*/ /* dpy is std arg for Set fns */ static Bool setCharResource( dpy, rmIndex, newValue, varSet ) Display *dpy; int rmIndex; char *newValue; Bool varSet; X{ X char *setValue; X Bool updateNeeded = False; X#define RM_CHARVAR (*((char **)(RMTable[rmIndex].varAddr))) X X if ( newValue == NULL ) X { X if ( varSet ) X return( updateNeeded ); X else /* builtin default - we're assuming varSet is a X * reliable indicator that the value was not set X * previously (else it would need to be MemFree'd X */ X setValue = RMTable[rmIndex].defaultVal; X } X else X { X if (varSet && RM_CHARVAR != NULL && X strcmp(RM_CHARVAR, newValue) == 0) { X return( updateNeeded ); X } else { X updateNeeded = True; X /* REMIND: if not previously set, what will happen? X * Does our global array initialization guarantee a X * NULL ptr there? X */ X MemFree( RM_CHARVAR ); X setValue = newValue; X } X } X X /* REMIND: this is slightly inefficient, since the defaultVal may X * copied, but it makes the MemFree unconditional when updating X * the value X */ X if ( setValue != NULL ) X RM_CHARVAR = MemNewString( setValue ); X else X RM_CHARVAR = NULL; X X return( updateNeeded ); X} X X#ifdef NOTDEF X/* X * setFloatResource - retrieve float resource from OlwmDB X */ X/*ARGSUSED*/ /* dpy is std arg for Set fns */ static Bool setFloatResource( dpy, rmIndex, newValue, varSet ) Display *dpy; int rmIndex; char *newValue; Bool varSet; X{ X Bool updateNeeded = False; X float newFloat; X#define RM_FLOATVAR *((float *)(RMTable[rmIndex].varAddr)) X X if ( newValue == NULL ) X { X if ( varSet ) X return( updateNeeded ); X else /* builtin default */ X sscanf( RMTable[rmIndex].defaultVal, "%f", &newFloat); X } X else X { X sscanf( newValue, "%f", &newFloat); X if ( varSet ) X { X if ( newFloat == RM_FLOATVAR ) X return( updateNeeded ); X else X updateNeeded = True; X } X } X X RM_FLOATVAR = newFloat; X return( updateNeeded ); X} X#endif X X/* X * setIntResource - retrieve integer value from resource db X */ X/*ARGSUSED*/ /* dpy is std arg for Set fns */ static Bool setIntResource( dpy, rmIndex, newValue, varSet ) Display *dpy; int rmIndex; char *newValue; Bool varSet; X{ X Bool updateNeeded = False; X int newInt; X#define RM_INTVAR *((int *)(RMTable[rmIndex].varAddr)) X X if ( newValue == NULL ) X { X if ( varSet ) X return( updateNeeded ); X else /* builtin default */ X newInt = atoi( RMTable[rmIndex].defaultVal ); X } X else X { X newInt = atoi( newValue ); X if ( varSet ) X { X if ( newInt == RM_INTVAR ) X return( updateNeeded ); X else X updateNeeded = True; X } X } X X RM_INTVAR = newInt; X return( updateNeeded ); X} X X/* X * setStringResource - retrieve string value from resource db X */ X/*ARGSUSED*/ /* dpy is std arg for Set fns */ static Bool setStringResource( dpy, rmIndex, newValue, varSet ) Display *dpy; int rmIndex; char *newValue; Bool varSet; X{ X Bool updateNeeded = False; X char *NewS; X X if ( newValue == NULL ) X { X if ( varSet ) X return( updateNeeded ); X else /* builtin default */ X NewS = RMTable[rmIndex].defaultVal; X } X else X { X NewS = newValue; X if ( varSet ) X { X if ( NewS == RMTable[rmIndex].varAddr ) X return( updateNeeded ); X else X updateNeeded = True; X } X } X X strcpy(RMTable[rmIndex].varAddr, NewS); X return( updateNeeded ); X} X X/* X * setClickTimeout - retrieve value for clickTimeout resource X * (Not simply a SetIntResource since must be converted to millisec.) X */ X/*ARGSUSED*/ /* dpy is std arg for Set fns */ static Bool setClickTimeout( dpy, rmIndex, newValue, varSet) Display *dpy; int rmIndex; char *newValue; Bool varSet; X{ X Bool updateNeeded = False; X int newInt; X#ifndef RM_INTVAR X#define RM_INTVAR *((int *)(RMTable[rmIndex].varAddr)) X#endif X X if ( newValue == NULL ) X { X if ( varSet ) X return( updateNeeded ); X else /* builtin default REMIND - need convert to milli? */ X newInt = atoi( RMTable[rmIndex].defaultVal ); X } X else X { X newInt = atoi( newValue ) * 100; /* convert to millisec*/ X if ( varSet ) X { X if ( newInt == RM_INTVAR ) X return( updateNeeded ); X else X updateNeeded = True; X } X } X X /* X * It's nearly impossible for the hardware to actually generate two X * clicks in less than 100ms. We make a special case for this and X * make the minimum timeout value be 150ms. X */ X if (newInt < 150) X newInt = 150; X X RM_INTVAR = newInt; X return( updateNeeded ); X} X X X/* X * setFg1Color - retrieve color name resource from OlwmDB X * and convert to pixel value X */ static Bool setFg1Color( dpy, rmIndex, newValue, varSet ) Display *dpy; int rmIndex; char *newValue; Bool varSet; X{ X XColor exact; X unsigned long newColor; X Bool updateNeeded = False; X#define RM_COLORVAR *((unsigned long *)(RMTable[rmIndex].varAddr)) X X#ifndef COLOR2D X if ( !GRV.F3dUsed ) X newColor = BlackPixel( dpy, DefaultScreen(dpy) ); X else X { X#endif /* COLOR2D */ X if ( (newValue == NULL) X || (!XParseColor( dpy, CMAP, newValue, &exact )) X || (!XAllocColor( dpy, CMAP, &exact )) ) X { X if ( varSet ) X return( updateNeeded ); X else X { X exact.pixel = BlackPixel( dpy, DefaultScreen(dpy) ); X XQueryColor( dpy, CMAP, &exact ); X exact.red = (exact.red*8)/10; X exact.green = (exact.green*8)/10; X exact.blue = (exact.blue*8)/10; X if ( XAllocColor( dpy, CMAP, &exact ) ) X newColor = exact.pixel; X else /* REMIND should OlwmDB value change? */ X newColor = BlackPixel(dpy, DefaultScreen(dpy)); X } X } X else X { X newColor = exact.pixel; X if ( varSet ) X { X if ( newColor == RM_COLORVAR ) X return( updateNeeded ); X else X updateNeeded = True; X } X } X X#ifndef COLOR2D X } /* end GRV.F3dUsed */ X#endif /* COLOR2D */ X X RM_COLORVAR = newColor; X return( updateNeeded ); X} X X X/* X * setBg1Color - retrieve color name resource from OlwmDB X * and convert to pixel value X * X * NOTE that Bg1Color must be set before any other color can be set!!! X */ static Bool setBg1Color( dpy, rmIndex, newValue, varSet ) Display *dpy; int rmIndex; char *newValue; Bool varSet; X{ X XColor exact; X XColor fgc, bg2c, bg3c, whitec; X unsigned long newColor; X unsigned long oldcells[4]; X int oldcellcount = 0; X#ifndef RM_COLORVAR X#define RM_COLORVAR *((unsigned long *)(RMTable[rmIndex].varAddr)) X#endif X X if (windowColorsAllocated) { X /* X * REMIND: this code helps prevent us from freeing the same cell X * twice. We should be able to do this according to the protocol, X * but some servers have bugs where allocating a cell twice and X * then freeing it once will actually free the cell. X */ X if (GRV.Bg0Color != WorkspaceColorPixel) X oldcells[oldcellcount++] = GRV.Bg0Color; X if (GRV.Bg1Color != WorkspaceColorPixel) X oldcells[oldcellcount++] = GRV.Bg1Color; X if (GRV.Bg2Color != WorkspaceColorPixel) X oldcells[oldcellcount++] = GRV.Bg2Color; X if (GRV.Bg3Color != WorkspaceColorPixel) X oldcells[oldcellcount++] = GRV.Bg3Color; X XFreeColors(dpy, CMAP, oldcells, oldcellcount, 0); X windowColorsAllocated = False; X } X X if ((newValue != NULL) && X (XParseColor(dpy, CMAP, newValue, &exact) == 1) && X (XAllocColor(dpy, CMAP, &exact) == 1)) X { X newColor = exact.pixel; X windowColorsAllocated = True; X } else { X /* X * No valid value was found in the resource, so we use X * 20% gray as the default. X */ X exact.pixel = WhitePixel( dpy, DefaultScreen(dpy) ); X XQueryColor( dpy, CMAP, &exact ); X exact.red = (exact.red*8)/10; X exact.green = (exact.green*8)/10; X exact.blue = (exact.blue*8)/10; X if (XAllocColor(dpy, CMAP, &exact) == 1) { X newColor = exact.pixel; X windowColorsAllocated = True; X } else { X /* REMIND should OlwmDB value change? */ X GRV.F3dUsed = False; X newColor = WhitePixel(dpy, DefaultScreen(dpy)); X windowColorsAllocated = False; X } X } X X RM_COLORVAR = newColor; X X /* these colors aren't currently settable directly using resources */ X#ifndef COLOR2D X if ( GRV.F3dUsed ) X { X#endif /* COLOR2D */ X fgc.pixel = GRV.Fg1Color; X XQueryColor(dpy,CMAP,&fgc); X olgx_calculate_3Dcolors(&fgc,&exact,&bg2c,&bg3c,&whitec); X XAllocColor(dpy,CMAP,&bg2c); X GRV.Bg2Color = bg2c.pixel; X XAllocColor(dpy,CMAP,&bg3c); X GRV.Bg3Color = bg3c.pixel; X XAllocColor(dpy,CMAP,&whitec); X GRV.Bg0Color = whitec.pixel; X#ifndef COLOR2D X } X else X { X /* in 2d these are not used by olgx, but olwm may */ X GRV.Bg0Color = WhitePixel( dpy, DefaultScreen(dpy) ); X GRV.Bg1Color = WhitePixel( dpy, DefaultScreen(dpy) ); X GRV.Bg2Color = BlackPixel( dpy, DefaultScreen(dpy) ); X GRV.Bg3Color = BlackPixel( dpy, DefaultScreen(dpy) ); X } X#endif /* COLOR2D */ X X return True; X} X X/* X * setColor - retrieve color name resource from OlwmDB X * and convert to pixel value X * X * REMIND - the default (BlackPixel) is built-in to this function. X */ Bool setColor( dpy, rmIndex, newValue, varSet ) Display *dpy; int rmIndex; char *newValue; Bool varSet; X{ X XColor exact; X unsigned long newColor; X Bool updateNeeded = False; X#ifndef RM_COLORVAR X#define RM_COLORVAR *((unsigned long *)(RMTable[rmIndex].varAddr)) X#endif X X if ( (newValue == NULL) X || (!XParseColor( dpy, CMAP, newValue, &exact )) X || (!XAllocColor( dpy, CMAP, &exact )) ) X { X if ( varSet ) X return( updateNeeded ); X else X newColor = BlackPixel(dpy, DefaultScreen(dpy)); X } X else X { X newColor = exact.pixel; X if ( varSet ) X { X if ( newColor == RM_COLORVAR ) X return( updateNeeded ); X else X updateNeeded = True; X } X } X X RM_COLORVAR = newColor; X return( updateNeeded ); X} X X X/* X * setInputFocusStyle - retrieve value of inputFocusStyle resource and X * return True is it's "followmouse" and False if it's "select" or X * "clicktotype" X */ X/*ARGSUSED*/ /* dpy is std arg for Set fns */ static Bool setInputFocusStyle( dpy, rmIndex, newValue, varSet ) Display *dpy; int rmIndex; char *newValue; Bool varSet; X{ X Bool focusFollows; X Bool updateNeeded = False; X#ifndef RM_BOOLVAR X#define RM_BOOLVAR *((Bool *)(RMTable[rmIndex].varAddr)) X#endif X X if ( (newValue == NULL) || !matchFocusType( newValue, &focusFollows ) ) X { X if ( varSet ) X return( updateNeeded ); X else /* builtin default */ X matchFocusType( RMTable[rmIndex].defaultVal, X &focusFollows ); X } X else if ( varSet ) X { X if ( focusFollows == RM_BOOLVAR ) X return( updateNeeded ); X else X updateNeeded = True; X } X X RM_BOOLVAR = focusFollows; X return( updateNeeded ); X} X X/* X * setBeepResource - retrieve value of Beep resource X */ static Bool setBeepResource( dpy, rmIndex, newValue, varSet ) Display *dpy; int rmIndex; char *newValue; Bool varSet; X{ X BeepStatus newBeep; X Bool updateNeeded = False; X X#ifndef RM_BEEPVAR X#define RM_BEEPVAR *((BeepStatus *)(RMTable[rmIndex].varAddr)) X#endif X X if ((newValue == NULL) || !matchBeepKeyword(newValue, &newBeep)) X { X if (varSet) X return(updateNeeded); X else X matchBeepKeyword(RMTable[rmIndex].defaultVal,&newBeep); X } X else if (varSet) X { X if (newBeep == RM_BEEPVAR) X return(updateNeeded); X else X updateNeeded = True; X } X X RM_BEEPVAR = newBeep; X return(updateNeeded); X} X X X/* X * setIconLocation - return value of iconLocation resource X */ X/*ARGSUSED*/ /* dpy is std arg for Set fns */ static Bool setIconLocation( dpy, rmIndex, newValue, varSet ) Display *dpy; int rmIndex; char *newValue; Bool varSet; X{ X Bool updateNeeded = False; X IconPreference newIconPlace; X#define RM_ICONVAR *((IconPreference *)(RMTable[rmIndex].varAddr)) X X if ( (newValue == NULL) || !matchIconPlace( newValue, &newIconPlace ) ) X { X if ( varSet ) X return( updateNeeded ); X else /* builtin default */ X matchIconPlace( RMTable[rmIndex].defaultVal, X &newIconPlace ); X } X else if ( varSet ) /* a valid newValue and an old value */ X { X if ( newIconPlace == RM_ICONVAR ) X return( updateNeeded ); X else X updateNeeded = True; X } X X RM_ICONVAR = newIconPlace; X return( updateNeeded ); X} X X static Bool parseKeySpec(dpy, str, modmask, keycode) X Display *dpy; X char *str; X int *modmask; X KeyCode *keycode; X{ X char line[100]; X char *word; X extern unsigned int FindModiferMask(); X int kc, m; X int mask = 0; X int code = 0; X KeySym ks; X X strcpy(line, str); X word = strtok(line, " \t"); X if (word == NULL) X return False; X X while (word != NULL) { X ks = XStringToKeysym(word); X if (ks == NoSymbol) { X if (strcmp(word, "Any") == 0) { X mask = AnyModifier; X word = strtok(NULL, " \t"); X continue; X } else if (strcmp(word, "Shift") == 0) X ks = XK_Shift_L; X else if (strcmp(word, "Control") == 0) X ks = XK_Control_L; X else if (strcmp(word, "Meta") == 0) X ks = XK_Meta_L; X else if (strcmp(word, "Alt") == 0) X ks = XK_Alt_L; X else if (strcmp(word, "Super") == 0) X ks = XK_Super_L; X else if (strcmp(word, "Hyper") == 0) X ks = XK_Hyper_L; X else X return False; X } X X kc = XKeysymToKeycode(dpy, ks); X if (kc == 0) X return False; X X m = FindModifierMask(kc); X if (m == 0) { X code = kc; X break; X } X mask |= m; X word = strtok(NULL, " \t"); X } X X if (code == 0) X return False; X X *keycode = code; X *modmask = mask; X return True; X} X X X/* X * setKey - retrieve value for named KeySym and convert it to a KeyCode X * Then grab the key so we'll deal with it as a special command. X */ static Bool setKey( dpy, rmIndex, newValue, varSet ) Display *dpy; int rmIndex; char *newValue; Bool varSet; X{ X unsigned int modMask; X KeyCode newKeyCode = 0; X Bool updateNeeded = False; X#define RM_KEYVAR ((KeySpec *)(RMTable[rmIndex].varAddr)) X X if ( newValue == NULL ) X { X if ( varSet ) X return( updateNeeded ); X else /* builtin default */ X { X (void) parseKeySpec(dpy, RMTable[rmIndex].defaultVal, X &modMask, &newKeyCode); X } X } X else X { X (void) parseKeySpec(dpy, newValue, &modMask, &newKeyCode); X if ( varSet ) X { X if ((newKeyCode == RM_KEYVAR->keycode) && X (modMask == RM_KEYVAR->modmask)) X return( updateNeeded ); X else X updateNeeded = True; X } X } X X /* REMIND perhaps we should have separate functions to deal with X * keys that want grab and don't want grab X * Also, perhaps this activity should be in the updFunc X */ X if (rmIndex != RM_CONFIRMKEY && rmIndex != RM_CANCELKEY && X newKeyCode != 0) { X XGrabKey( dpy, newKeyCode, modMask, X DefaultRootWindow(dpy), False, X GrabModeAsync, GrabModeAsync ); X#ifdef notdef X xkbc.auto_repeat_mode = AutoRepeatModeOff; X xkbc.key = newKeyCode; X XChangeKeyboardControl(dpy, KBKey|KBAutoRepeatMode, &xkbc); X#endif /* notdef */ X } X X RM_KEYVAR->keycode = newKeyCode; X RM_KEYVAR->modmask = modMask; X return( updateNeeded ); X} X X X/* X * setDimension X * X * Look at the default screen and determine whether to use 3D. X */ static Bool setDimension( dpy, rmIndex, newValue, varSet ) X Display *dpy; X int rmIndex; X char *newValue; X Bool varSet; X{ X Bool newDimension; X Bool updateNeeded = False; X int depth = DisplayPlanes(dpy,DefaultScreen(dpy)); X int visclass = (DefaultVisual(dpy,DefaultScreen(dpy)))->class; X X if ((newValue == NULL) || !matchBool(newValue, &newDimension)) { X if (varSet) X return(updateNeeded); X else X matchBool(RMTable[rmIndex].defaultVal, &newDimension); X } else if (varSet) { X if (newDimension == RM_BOOLVAR) X return(updateNeeded); X else X updateNeeded = True; X } X X switch (visclass) { X case StaticGray: X case GrayScale: X if (depth < 2) X newDimension = False; X break; X case DirectColor: X case PseudoColor: X if (depth < 4) X newDimension = False; X break; X case StaticColor: X if (depth < 8) X newDimension = False; X break; X case TrueColor: X if (depth < 6) X newDimension = False; X break; X } X X RM_BOOLVAR = newDimension; X return(updateNeeded); X} X X X/* X * SetNameTag - retrieve value of name resource. If not set, use X * AppName. Not likely to be valuable as a dynamically X * modified resource. X * X * REMIND: currently not called in any resource parsing loop X */ X/*ARGSUSED*/ /* dpy, newValue, varSet are std args for Set fns */ Bool SetNameTag( dpy, rmIndex, newValue, varSet ) Display *dpy; int rmIndex; char *newValue; Bool varSet; X{ X Bool updateNeeded = False; X char name[MAX_NAME]; X char class[MAX_CLASS]; X XrmRepresentation repType; X XrmValue value; X#define RM_NAMEVAR *((char **)(RMTable[rmIndex].varAddr)) X X (void) strcpy( name, AppName ); X (void) strcat( name, RMTable[rmIndex].instance ); X MakeRMClass( class, rmIndex ); X X /* REMIND NameTag will need to be MemFree'd, if X * updating the NameTag is allowed and != AppName X */ X if ( XrmGetResource( OlwmDB, name, class, &repType, &value ) X == True && (value.addr != NULL) ) X { X RM_NAMEVAR = MemNewString( value.addr ); X updateNeeded = True; X } X else X RM_NAMEVAR = AppName; X X return( updateNeeded ); X} X X/* buildMinimalList -- build the list of classes/instances to be X * but minimally decorated; return True if the list was successfully parsed. X * X * Works for sticky windows too X */ static Bool buildMinimalList(str, pplist) char *str; List **pplist; X{ X char *swork, *swork2; X List *l = NULL_LIST; X X if (str == NULL) X return False; X X swork2 = swork = MemNewString(str); X X while ((swork2 = strtok(swork2, " \t")) != NULL) X { X l = ListCons(MemNewString(swork2),l); X swork2 = NULL; X } X MemFree(swork); X *pplist = l; X return True; X} X static void * freeMinimalStrings(str,junk) char *str; void *junk; X{ X MemFree(str); X return NULL; X} X X/* X * setMinimalDecor - set list of windows to be minimally decorated X * X * works for sticky windows too X * X */ X/*ARGSUSED*/ /* dpy is std arg for Set fns */ static Bool setMinimalDecor( dpy, rmIndex, newValue, varSet ) Display *dpy; int rmIndex; char *newValue; Bool varSet; X{ X List *newl = NULL_LIST; X#define RM_LISTVAR *((List **)(RMTable[rmIndex].varAddr)) X X if (newValue == NULL) X { X if (!buildMinimalList( RMTable[rmIndex].defaultVal, &newl )) X return False; X } X else if (!buildMinimalList( newValue, &newl ) ) X return False; X X if (RM_LISTVAR != NULL) X { X ListApply(RM_LISTVAR,freeMinimalStrings,NULL); X ListDestroy(RM_LISTVAR); X } X RM_LISTVAR = newl; X X return( True ); X} END_OF_FILE if test 40786 -ne `wc -c <'resources.c'`; then echo shar: \"'resources.c'\" unpacked with wrong size! fi # end of 'resources.c' fi echo shar: End of archive 15 \(of 16\). cp /dev/null ark15isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 16 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Dan Heller O'Reilly && Associates Z-Code Software Comp-sources-x: Senior Writer President comp-sources.x@uunet.uu.net argv@ora.com argv@zipcode.com