This is AppDelegate.m in view mode; [Download] [Up]
/*---------------------------------------------------------------------------- This file is set up for a width of 130 columns, with tab stops every two spaces. HISTORY 10Oct93 DM New ----------------------------------------------------------------------------*/ #import <mach/cthreads.h> #import "AppDelegate.h" #import "CircleView.h" static any_t increasingFunction(self) AppDelegate *self; { /*--------------------------------------------------------------- Simple function that just generates an increasing series of numbers to display. this runs as an independent thread; we're forked and detached, then grab a connection to the main thread,and start sending messages to it. All four of these functions share some code. It should probably be factored out into a single method so the line count can be reduced. ---------------------------------------------------------------*/ id proxy; // "proxy" object to the main server; essentially "self" int i; // generic int // Get a connection to the main server. This allows us to be detached, // yet talk to appkit and the DPS in a thread-safe way. proxy = [NXConnection connectToName:"fooServer"]; // If we got nothing on the connect attempt, or if the object we got back // does not speak our "language", then punt. if((proxy == nil) || (![proxy conformsTo:@protocol(ServerInterface)])) { printf("Couldn't get connection to server object, or protocol is hosed\n"); cthread_exit(0); } // Loop forever, generating an increasing sequence. We wrap after // some arbitrarily large number so we don't get overflow. while(YES) { i = 0; while(i < 128000) { [proxy showIncreasing:i]; // Tell the main thread to display this number i++; if(!self->isRunning) cthread_exit(0); cthread_yield(); // Be polite to the scheduler (not required) } } return 0; } static any_t fibFunction(self) AppDelegate *self; { /*------------------------------------------------------------------------ Much like the above. We're running as a thread, and attach to the DO server and message that. We just generate a series of fib numbers for display. ------------------------------------------------------------------------*/ id proxy; // Proxy to main server object int i, j, sum; // Get connection to main server proxy = [NXConnection connectToName:"fooServer"]; // If we got nothing on the connect attempt, or if the object we got back // does not speak our "language", then punt. if((proxy == nil) || (![proxy conformsTo:@protocol(ServerInterface)])) { printf("Couldn't get connection to server object\n"); cthread_exit(0); } // Generate new fib numbers forever. Roll over after some arbitrarily // large number to prevent overflow. while(YES) { i = 0; j = 1; sum = 0; [proxy showFib:i]; while(i < 128000) { sum = i + j; [proxy showFib:sum]; i = j; j = sum; if(!self->isRunning) cthread_exit(0); cthread_yield(); // Be polite to the scheduler (not required) } } return 0; } static any_t primeFunction(self) AppDelegate *self; { /*------------------------------------------------------------------------ Much like the above. We're running as a thread, and attach to the DO server and message that. We just generate a series of prime numbers for display. I have no idea how the algo here works; just cut & pasted from something else. ------------------------------------------------------------------------*/ id proxy; // Proxy to main server object int counter, possiblePrime = 5, testLimit; BOOL isPrime; List *primeList; // Get connection to main server proxy = [NXConnection connectToName:"fooServer"]; // If we got nothing on the connect attempt, or if the object we got back // does not speak our "language", then punt. if((proxy == nil) || (![proxy conformsTo:@protocol(ServerInterface)])) { printf("Couldn't get connection to server object\n"); cthread_exit(0); } // Sleaze alert: Lists are intended to hold ids, pointers to objects. If // we squint, and don't care a lot about nicities, we can also store ints // in them. The access is pretty slow, since it takes a function call // to find the contents of an address. But we could fix that if we liked // by just doing some pointer arithmetic into the List. primeList = [[List alloc] init]; [primeList addObject:(id)2]; [primeList addObject:(id)3]; while (YES) // Repeat forever { isPrime = YES; testLimit = sqrt(possiblePrime); for (counter=1; isPrime && ((int)[primeList objectAt:counter]<=testLimit); counter++) if (possiblePrime % (int)[primeList objectAt:counter] == 0) isPrime = NO; if (isPrime) { [primeList addObject:(id)possiblePrime]; [proxy showPrime:possiblePrime]; } possiblePrime += 2; if(!self->isRunning) cthread_exit(0); cthread_yield(); // Be polite to the scheduler (not required) if(possiblePrime > 128000) // Begin again to prevent overflow { possiblePrime = 5; [primeList free]; primeList = [[List alloc] init]; [primeList addObject:(id)2]; [primeList addObject:(id)3]; } } return 0; }; // end of primeFunction static any_t circleFunction(self) AppDelegate *self; { /*------------------------------------------------------------------------ Much like the above. We're running as a thread, and attach to the DO server and message that. We generate a series of points and radii, and send those to the main thread server. that draws the circles. ------------------------------------------------------------------------*/ id proxy; // Proxy to main server object int maxHeight = 156, maxWidth = 255; // aprox. dimensions of the View NXPoint center; float radius; int x,y,r; // int versions of x, y, radius // Get connection to main server. Yeah, this common code ought to // be factored out into its own method. Sue me. proxy = [NXConnection connectToName:"fooServer"]; // If we got nothing on the connect attempt, or if the object we got back // does not speak our "language", then punt. if((proxy == nil) || (![proxy conformsTo:@protocol(ServerInterface)])) { printf("Couldn't get connection to server object\n"); cthread_exit(0); } // Generate a series of points and radii, and pass them off // to the main thread for drawing. srandom(1); // initialize rng while(YES) // loop forever { x = random(); y = random(); r = random(); // Get them scaled back to about the size of the view. center.x = (float)(((double)x/(double)MAXINT) * (double)maxWidth); center.y = (float)(((double)y/(double)MAXINT) * (double)maxHeight); radius = (float)((((double)r/(double)MAXINT)*2.0) * (double)maxHeight); [proxy drawRandomCircleAt:center withRadius:radius]; if(!self->isRunning) cthread_exit(0); cthread_yield(); // Be polite to the scheduler. } return 0; } @implementation AppDelegate // The main methods called by the threads, which output things to the screen. // These are the implementations of the protocol declaration. - showIncreasing // Show an increasing number in the window :(int)pNumber; // INPUT: the number to show { /*------------------------------------------------------------------------- Make an addition to the scrolling display of data in the ScrollView for the "increasing number" display. -------------------------------------------------------------------------*/ Text *textObj; char theNumber[256]; sprintf(theNumber, "%d\n", pNumber); textObj = [increasingDisp docView]; [self addToText:textObj string:theNumber]; return self; } // end of showIncreasing - showPrime // Show a prime number in the window :(int)pPrime; // INPUT: the prime to show { /*------------------------------------------------------------------------- Make an addition to the scrolling display of data in the ScrollView for the "increasing prime" display. -------------------------------------------------------------------------*/ Text *textObj; char theNumber[256]; sprintf(theNumber, "%d\n", pPrime); textObj = [primeDisp docView]; [self addToText:textObj string:theNumber]; return self; } // end of showPrime: - showFib // Show a fibonaci number in the window :(int)pFib; // INPUT: the fib to show { /*------------------------------------------------------------------------- Make an addition to the scrolling display of data in the ScrollView for the "increasing fibonacci" display. -------------------------------------------------------------------------*/ Text *textObj; char theNumber[256]; sprintf(theNumber, "%d\n", pFib); textObj = [fibDisp docView]; [self addToText:textObj string:theNumber]; return self; } // end of showFib: - drawRandomCircleAt // Draw a circle at the given point with the given radius :(NXPoint)pPoint // INPUT: where to draw it at (the center) withRadius:(float)pRadius; // INPUT: the radius { /*------------------------------------------------------------------------------- Add a circle to the view that displays the random circles. This also adds a circle to the display list kept in the CircleView, which is probably overkill. But we will be able to redraw it in its current state anywhere. -------------------------------------------------------------------------------*/ [circleView addCircleAt:pPoint withRadius:pRadius]; [circleView display]; return self; } // App initialization delegate method - appDidInit:sender; { // Vend ourselves to the universe (and our threads, too.) // This is run from the appkit; the idea is to allow anyone // to call us, and we handle all talking to the appkit. [NXConnection setDefaultTimeout:200000]; // Timeout period, in milliseconds connection = [NXConnection registerRoot:self withName:"fooServer"]; [connection runFromAppKit]; return self; } - doThreads:sender; // Starts doing things--slamming numbers to the screen { /*--------------------------------------------------------------- Do some stuff. Namely, start the threads that display things to the screen. We have functions that do nothing but generate output; they message us via distributed objects and tell us what to display, and we do it. ---------------------------------------------------------------*/ // Clear out any existing cruft in the views. [circleView emptyCircles]; [circleView display]; [[increasingDisp docView] selectAll:self]; [[increasingDisp docView] delete:self]; [[fibDisp docView] selectAll:self]; [[fibDisp docView] delete:self]; [[primeDisp docView] selectAll:self]; [[primeDisp docView] delete:self]; // Break off all the threads for the stuff we want to do-- draw circles, // calculate primes, whatever. // "I woke up this morning with a bad hangover, and my cthread was // missing. This happens all the time. It's detachable." // -- Not King Missile isRunning = YES; cthread_detach(cthread_fork(increasingFunction, self)); cthread_detach(cthread_fork(fibFunction, self)); cthread_detach(cthread_fork(primeFunction, self)); cthread_detach(cthread_fork(circleFunction, self)); return self; } - stopThreads:sender; // Stops all the treads { /*----------------------------------------------------------------------- Stops all the threads, while leaving the display as is. -----------------------------------------------------------------------*/ isRunning = NO; return self; } - addToText // Utility method--adds text at end of given text obj :(Text*)pTextObj // INPUT: text obj to add to string:(char*)pString; // INPUT: the text we're adding { /*------------------------------------------------------------------------------ This would be better implemented as a category method to the Text object, but that would probably just confuse things for the rookies out there. We have very similar code in three of our functions, that just add a number to the end of a scrolling text display. This does that, given the text object passed in and the text to append. If we _did_ use a category method, everyone could use this method, which is pretty useful. ------------------------------------------------------------------------------*/ int length; // How many chars are in the text object length = [pTextObj textLength]; // find out how long... [pTextObj setSel:length :length]; // get a null selection at the end... [pTextObj replaceSel:pString]; // and replace it with our new text [pTextObj scrollSelToVisible]; // make sure we can see it. return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.