This is SimpleCounter.m in view mode; [Download] [Up]
/*
* Counter: simple counter object that runs in its own thread.
*/
#import <libc.h>
#import <math.h>
#import <appkit/Button.h>
#import <appkit/Slider.h>
#import "Counter.h"
#import "ThreadedApp.h"
#import "tprintf.h"
#define INITIAL_INTERVAL 500 // in milliseconds
@interface Counter(CounterPrivate)
- (void)counter:sender;
- (int)incCount;
@end
@implementation Counter : Object
// number of counters created
static int counters;
#define STOPPED 0
#define RUNNING 1
#define myrandom() (random()/(double)MAXINT)
+ initialize
{
if( self == [Counter class] ){
srandom(0);
counters = 1;
}
tprintf_init();
return self;
}
- init
{
NXScreen *screen;
NXRect frame;
[super init];
interval = INITIAL_INTERVAL;
running = NO;
mynum = counters++;
count = 0;
if( [NXApp loadNibSection:"Counter.nib" owner:self] ){
// set window title...
title = (char *) malloc( 20*sizeof(char) ); // should be enough...
sprintf( title, "Counter %d\n", mynum );
[window setTitle:title];
// move to random location
[window getFrame:&frame andScreen:&screen];
frame.size.width = screen->screenBounds.size.width
- frame.size.width;
frame.size.height = screen->screenBounds.size.height
- frame.size.height;
frame.origin = screen->screenBounds.origin;
frame.origin.x += myrandom()*frame.size.width;
frame.origin.y += myrandom()*frame.size.height;
[window moveTo:frame.origin.x:frame.origin.y];
[window makeKeyAndOrderFront:self];
// set values
[slider setIntValue:interval];
[intervalField setIntValue:interval];
[countField setIntValue:count];
runlock = [[CJRConditionLock alloc] initWithCondition:STOPPED];
// go!
[self start:self];
}
return self;
}
- free
{
if( running )
[self stop:self];
[runlock free];
if(title){
free(title);
}
return [super free];
}
- windowWillClose:sender
{
[self stop:self];
[NXApp delayedFree:self];
return self;
}
// "private" methods
- dispCount:(int)i
{
[countField setIntValue:i];
return self;
}
- (int)incCount
{
count++;
return count;
}
- (void)counter:sender
{
[runlock lockWhenCondition:RUNNING];
while( running ){
// update countField under main thread
[NXApp callbackTarget:countField perform:@selector(setIntValue:)
with:(id)count];
// use a callback to make absolutely sure a 'reset' isn't lost
[NXApp callbackAndWaitTarget:self perform:@selector(incCount)];
if( interval > 0 )
[NXApp sleepCurrentThread:interval];
}
[runlock unlockWithCondition:STOPPED];
}
// Actions...
- start:sender
{
if( !running ){
[runlock lock];
[NXApp detachNewThreadSelector:@selector(counter:) toTarget:self
withObject:self];
running = YES;
[runlock unlockWithCondition:RUNNING];
}
return self;
}
- stop:sender
{
if( running ){
running = NO;
// wait for thread to finish
[runlock lockWhenCondition:STOPPED];
[runlock unlock];
}
return self;
}
- startOrStop:sender
{
if( [sender state] == 0 ){
[self start:sender];
} else {
[self stop:sender];
}
return self;
}
- reset:sender
{
count = 0;
return self;
}
- setInterval:sender
{
int i, max;
i = [sender intValue];
max = (int) [slider maxValue];
if( i < 0 ){
i = 0;
} else if( i > max ){
i = max;
}
[slider setIntValue:i];
[intervalField setIntValue:i];
interval = i;
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.