This is Percentages.m in view mode; [Download] [Up]
// Copyright 1991, 1994 Scott Hess. Permission to use, copy, // modify, and distribute this software and its documentation for // any purpose and without fee is hereby granted, provided that // this copyright notice appear in all copies. // // Scott Hess makes no representations about the suitability of // this software for any purpose. It is provided "as is" without // express or implied warranty. // #import "Percentages.h" #import "TimeMonWraps.h" #import "loadave.h" #import "AppDefaults.h" #import "TimeMonColors.h" #import <syslog.h> // Determines how much movement is needed for a display/redisplay. #define MINSHOWN 0.01 // Minimum values for the defaults. #define MINPERIOD 0.1 #define MINFACTOR 4 #define MINLAGFACTOR 1 @implementation Percentages - initFrame:(const NXRect *)r { self=[super initFrame:r]; if( self) { // Cache the stipple image to use as a background. // This is a holdover from the NS2.x code - under NS2.x, // this would leave stipple==nil, and I check that and // do rectfills to clear. stipple=[NXImage findImageNamed:"NXAppTile"]; } return self; } - update { static float radii[ 3]={ 23, 17, 11}; int i; BOOL drawn=NO; PSsetlinewidth( 1.0); // Clear to the background color if all rings are to be // redrawn. if( updateFlags[ 0]) { if( stipple) { [stipple composite:NX_COPY toPoint:&(bounds.origin)]; } else { PSsetgray( NX_LTGRAY); NXRectFill( &bounds); } } // For each ring, if it's changed, redraw that ring. for( i=0; i<3; i++) { if( updateFlags[ i]) { // Note that we need a redraw. drawn=YES; // Note that we redrew this ring. updateFlags[ i]=NO; // Store away the values we redraw. bcopy( pcents[ i], lpcents[ i], sizeof( lpcents[ i])); // Don't draw the "nice" segment if there isn't one. if( pcents[ i][ 2]>=MINSHOWN) { drawArc2( radii[ i], 90-(pcents[ i][ 0])*360, 90-(pcents[ i][ 0]+pcents[ i][ 1])*360, 90-(pcents[ i][ 0]+pcents[ i][ 1]+pcents[ i][ 2])*360); } else { drawArc1( radii[ i], 90-(pcents[ i][ 0])*360, 90-(pcents[ i][ 0]+pcents[ i][ 1])*360); } } } // If any rings redrew, redraw the circles. Since the // circles are constant, this _should_ be cached by the // server and future draws should be insanely fast. Or // something like that. if( drawn) { static float bbox[]={ 0, 0, 64, 64}; static float coords[]={ 55.5, 32, // moveto 32, 32, 23.5, 0, 360, // arc 49.5, 32, // moveto 32, 32, 17.5, 0, 360, // arc 43.5, 32, // moveto 32, 32, 11.5, 0, 360, // arc 32, 32, // moveto 32, 56, // lineto }; static char ops[]={ dps_ucache, dps_moveto, dps_arc, dps_moveto, dps_arc, dps_moveto, dps_arc, dps_moveto, dps_lineto}; PSsetgray( NX_BLACK); DPSDoUserPath( coords, sizeof( coords)/sizeof( coords[ 0]), dps_float, ops, sizeof( ops)/sizeof( ops[ 0]), bbox, dps_ustroke); } return self; } - drawSelf:(const NXRect *)r :(int)count { // If we are paused, draw differently. if( !te) { static NXImage *app=nil, *pause=nil; NXPoint p={ 8, 8}; // Cache the app and pause tiffs. if( !app) { app=[NXImage findImageNamed:"app"]; pause=[NXImage findImageNamed:"TimeMonP.tiff"]; } // Put af background on the icon. if( stipple) { [stipple composite:NX_COPY toPoint:&(bounds.origin)]; } else { PSsetgray( NX_LTGRAY); NXRectFill( &bounds); } // Layer over the app and pause tiffs. [app composite:NX_SOVER toPoint:&p]; [pause composite:NX_SOVER toPoint:&p]; } else { // Redrawing normally is simple - just mark all rings // for update and update it. updateFlags[ 0]=updateFlags[ 1]=updateFlags[ 2]=YES; [self update]; } return self; } - step { int i, j, oIndex; float total; // Read the new CPU times. la_read( oldTimes[ laIndex]); // The general idea for calculating the ring values is to // first find the earliest valid index into the oldTimes // table for that ring. Once in a "steady state", this is // determined by the lagFactor and/or layerFactor values. // Prior to steady state, things are restricted by how many // steps have been performed. Note that the index must // also be wrapped around to remain within the table. // // The values are all then easily calculated by subtracting // the info at the old index from the info at the current // index. // Calculate values for the innermost "lag" ring. oIndex=(laIndex-MIN( lagFactor, steps)+laSize)%laSize; for( total=0, i=0; i<CPUSTATES; i++) { total+=oldTimes[ laIndex][ i]-oldTimes[ oIndex][ i]; } if( total) { pcents[ 2][ 0]=(oldTimes[ laIndex][ CP_SYS]-oldTimes[ oIndex][ CP_SYS])/total; pcents[ 2][ 1]=(oldTimes[ laIndex][ CP_USER]-oldTimes[ oIndex][ CP_USER])/total; pcents[ 2][ 2]=(oldTimes[ laIndex][ CP_NICE]-oldTimes[ oIndex][ CP_NICE])/total; } // Calculate the middle ring. oIndex=(laIndex-MIN( lagFactor+layerFactor, steps)+laSize)%laSize; for( total=0, i=0; i<CPUSTATES; i++) { total+=oldTimes[ laIndex][ i]-oldTimes[ oIndex][ i]; } if( total) { pcents[ 1][ 0]=(oldTimes[ laIndex][ CP_SYS]-oldTimes[ oIndex][ CP_SYS])/total; pcents[ 1][ 1]=(oldTimes[ laIndex][ CP_USER]-oldTimes[ oIndex][ CP_USER])/total; pcents[ 1][ 2]=(oldTimes[ laIndex][ CP_NICE]-oldTimes[ oIndex][ CP_NICE])/total; } // Calculate the outer ring. oIndex=(laIndex-MIN( lagFactor+layerFactor*layerFactor, steps)+laSize)%laSize; for( total=0, i=0; i<CPUSTATES; i++) { total+=oldTimes[ laIndex][ i]-oldTimes[ oIndex][ i]; } if( total) { pcents[ 0][ 0]=(oldTimes[ laIndex][ CP_SYS]-oldTimes[ oIndex][ CP_SYS])/total; pcents[ 0][ 1]=(oldTimes[ laIndex][ CP_USER]-oldTimes[ oIndex][ CP_USER])/total; pcents[ 0][ 2]=(oldTimes[ laIndex][ CP_NICE]-oldTimes[ oIndex][ CP_NICE])/total; } // Move the index forward for the next cycle. laIndex=(laIndex+1)%laSize; steps++; // Look through the rings and see if any values changed by // one percent or more, and if so mark that and inner rings // for update. for( i=0; i<3; i++) { for( j=0; j<3; j++) { if( rint( pcents[ i][ j]*100)!=rint( lpcents[ i][ j]*100)) { for( ; i<3; i++) { updateFlags[ i]=YES; } break; } } } // If there's a need for updating of any rings, call update. if( updateFlags[ 2]) { [self lockFocus]; [self update]; [window flushWindow]; [self unlockFocus]; NXPing(); } return self; } // This was for debugging, no longer needed. I used it to hook // up a menu item to manually call step. - cycle:sender { return [self step]; } // Callback for timed entry. static void _step( DPSTimedEntry te, double curTime, id self) { [self step]; } // Set up to have a low priority from the get-go. - appWillInit:sender { struct task_basic_info tbi; unsigned ic=TASK_BASIC_INFO_COUNT; if( task_info( task_self(), TASK_BASIC_INFO, (task_info_t)&tbi, &ic)!=KERN_SUCCESS) { return nil; } task_priority( task_self(), tbi.base_priority-4, TRUE); return self; } // Resize the oldTimes array and rearrange the values within // so that as many as possible are retained, but no bad values // are introduced. - __reallocOldTimes { CPUTime *newTimes; // Get the new size for the array. unsigned newSize=layerFactor*layerFactor+lagFactor+1; // Allocate info for the array. newTimes=NXZoneMalloc( [self zone], sizeof( float)*CPUSTATES*newSize); bzero( newTimes, sizeof( float)*CPUSTATES*newSize); // If there was a previous array, copy over values. First, // an index is found for the first valid time. Then enough // times to fill the rings are copied, if available. if( oldTimes) { unsigned ii, jj, elts; elts=MIN( lagFactor+layerFactor*layerFactor+1, steps); ii=(laIndex+laSize-elts)%laSize; jj=MIN( laSize-ii, elts); if( jj) { bcopy( oldTimes+ii, newTimes+0, jj*sizeof( oldTimes[ 0])); } if( jj<elts) { bcopy( oldTimes+0, newTimes+jj, (elts-jj)*sizeof( oldTimes[ 0])); } // Free the old times. NXZoneFree( [self zone], oldTimes); } // Reset everything so that we only access valid data. oldTimes=newTimes; laIndex=MIN( steps, laSize); laIndex=MIN( laIndex, newSize)%newSize; steps=MIN( steps, laSize); steps=MIN( steps, newSize); laSize=newSize; return self; } - appDidInit:sender { Window *iw; float f; int ret; CPUTime cp_time; NXDefaultsVector defs={ { "UpdatePeriod", "0.5"}, { "LagFactor", "4"}, { "LayerFactor", "16"}, { "HideOnAutolaunch", "YES"}, { "NXAutoLaunch", "NO"}, // For color systems. { "IdleColor", "1.000 1.000 1.000"}, // White { "NiceColor", "0.333 0.667 0.867"}, // A light blue-green { "UserColor", "0.200 0.467 0.800"}, // A darker blue-green { "SystemColor", "0.000 0.000 1.000"}, // Blue // For monochrome systems. { "IdleGray", "1.000"}, // White { "NiceGray", "0.667"}, // Light gray { "UserGray", "0.333"}, // Dark gray { "SystemGray", "0.000"}, // Black { NULL, NULL}, }; // Register the defaults. NXRegisterDefaults( [NXApp appName], defs); // Shoot out error codes if there was an error. if( ret=la_init( cp_time)) { const char *syslogs[]={ NULL, // LA_NOERR "Cannot nlist /mach.", // LA_NLIST "Must be installed setgid kmem.", // LA_PERM "Cannot open /dev/kmem.", // LA_KMEM "Unable to seek in /dev/kmem", // LA_SEEK "Unable to read from /dev/kmem", // LA_READ "table() call failed.", // LA_TABLE }; char buf[ 64]; sprintf( buf, "TimeMon: %s\n", syslogs[ ret]); syslog( LOG_WARNING, buf); sprintf( buf, "%s Exitting.", syslogs[ ret]); NXRunAlertPanel( "TimeMon", "%s.", "OK", NULL, NULL, syslogs[ ret]); [NXApp terminate:sender]; } // Load up the needed DPS procedures. drawInit(); // Move ourselves over to the appIcon window. iw=[NXApp appIcon]; [[iw contentView] addSubview:self]; // Get us registered for periodic exec. f=[NXApp defaultAsFloat:"UpdatePeriod"]; f=MAX( f, MINPERIOD); [periodText setFloatValue:f]; te=DPSAddTimedEntry( f, (void *)_step, self, NX_MODALRESPTHRESHOLD); // Get the lag factor. lagFactor=[NXApp defaultAsInt:"LagFactor"]; lagFactor=MAX( lagFactor, MINLAGFACTOR); [lagText setIntValue:lagFactor]; // Get the layer factor. layerFactor=[NXApp defaultAsInt:"LayerFactor"]; layerFactor=MAX( layerFactor, MINFACTOR); [factorText setIntValue:layerFactor]; [self __reallocOldTimes]; bcopy( cp_time, oldTimes[ 0], sizeof( CPUTime)); laIndex=1; steps=1; [colorFields readColors]; [self display]; if( [NXApp defaultAsBOOL:"HideOnAutolaunch" default:YES] && [NXApp defaultAsBOOL:"NXAutoLaunch" default:NO]) { [NXApp hide:self]; } return self; } - appWillTerminate:sender { // If te is installed, remove it. if( te) { DPSRemoveTimedEntry( te); te=(DPSTimedEntry)0; } la_finish(); return self; } - togglePause:sender { if( te) { [pauseMenuCell setTitle:"Continue"]; DPSRemoveTimedEntry( te); te=(DPSTimedEntry)0; } else { float f; [pauseMenuCell setTitle:"Pause"]; f=[NXApp defaultAsFloat:"UpdatePeriod"]; f=MAX( f, MINPERIOD); [periodText setFloatValue:f]; te=DPSAddTimedEntry( f, (void *)_step, self, NX_MODALRESPTHRESHOLD); } return [self display]; } - setPeriod:sender { [NXApp default:"UpdatePeriod" asFloat:[periodText floatValue]]; if( te) { float f; DPSRemoveTimedEntry( te); f=[NXApp defaultAsFloat:"UpdatePeriod"]; f=MAX( f, MINPERIOD); [periodText setFloatValue:f]; te=DPSAddTimedEntry( f, (void *)_step, self, NX_MODALRESPTHRESHOLD); } return self; } - setLag:sender { [NXApp default:"LagFactor" asInt:[lagText intValue]]; lagFactor=[NXApp defaultAsInt:"LagFactor"]; lagFactor=MAX( lagFactor, MINLAGFACTOR); [lagText setIntValue:lagFactor]; [self __reallocOldTimes]; return [self display]; } - setFactor:sender { [NXApp default:"LayerFactor" asInt:[factorText intValue]]; layerFactor=[NXApp defaultAsInt:"LayerFactor"]; layerFactor=MAX( layerFactor, MINFACTOR); [factorText setIntValue:layerFactor]; [self __reallocOldTimes]; return [self display]; } -(BOOL)textWillEnd:sender { id delegate=[sender delegate]; if( delegate==factorText) { [self setFactor:factorText]; } else if( delegate==periodText) { [self setPeriod:periodText]; } else if( delegate==lagText) { [self setLag:lagText]; } return NO; } - windowWillResize:sender toSize:(NXSize *)aSize { static BOOL gotSize=NO; static NXSize minSize={ 0, 0}; if( !gotSize) { NXRect r; [sender getFrame:&r]; minSize=r.size; gotSize=YES; } aSize->width=MAX( aSize->width, minSize.width); aSize->height=MAX( aSize->height, minSize.height); return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.