This is Spewer.m in view mode; [Download] [Up]
// Copyright (c) 1997 by Don Yacktman // All rights reserved. // Permission to use this code in your application, whether // commercial, shareware, or freeware, is granted. // This notice may not be removed or altered. #import "Spewer.h" #import "FlyingWindow.h" #import "Animator.h" #import <libc.h> @implementation Spewer:NSObject - init { [super init]; // seed the random number generator with the current time. // This call should really only be done once, before the random // number generator is ever used. Since this object is typically // only instantiated once so that's not a problem. srandom(time(0)); // clear this out, since we've not been started yet. initiator = nil; // get an animator instance to help us run the animation. animator = [[Animator allocWithZone:[self zone]] initChronon:0.05 adaptation:0.0 target:self action:@selector(move:) autoStart:NO eventMask:0]; // set up an extra list used for swapping during animation _extraList = [[NSMutableArray allocWithZone:[self zone]] init]; // set up the list of extra, idle windows idleWindows = [[NSMutableArray allocWithZone:[self zone]] init]; // set up the list of active windows windowList = [[NSMutableArray allocWithZone:[self zone]] init]; // it is not currently OK to create ne windows. createOK = NO; return self; } - start:sender { // start the animation. It is OK to instantiate new windows. createOK = YES; // the sender is the one who started us off, so cache that info initiator = sender; // get a new window so that we have at least one window to animate [self addWindow]; // start the animation [animator startEntry]; return self; } - (void)stop:(id)sender { // we need to stop the animation, but need all the windows to // fall off the screen first. So we tell ourself that the // initiator is gone and disallow creation of new windows. createOK = NO; initiator = nil; } - (BOOL)windowShouldClose:(id)sender { // if the window is closing, then we automatically stop the // animation. Make sure we are the winow's delegate (hooked // up as such in IB) or else we won't get this message! [self stop:self]; return YES; } - (void)dealloc { // clean out any windows, remove the timed antry and free everything int i; // stop the animation and get rid of the animator [animator stopEntry]; [animator release]; animator = nil; // get rid of all our windows--get them off the screen for (i=0; i<[windowList count]; i++) { [[windowList objectAtIndex:i] orderOut:self]; } // free the active window list and its contents [windowList release]; windowList = nil; // free the idle window list and its contents [idleWindows release]; idleWindows = nil; [super dealloc]; return; } - addWindow { // put up a new window on the screen NSPoint theCenterPoint; NSRect senderFrame; id newWindow = nil; // if we're not allowed to start any new windows, then return immediately if (!createOK) return nil; // find the point where the new window should appear on the screen. // find out the frame of the control which sent the -start: message senderFrame = [initiator frame]; // Get the center point of the initiator's frame theCenterPoint.x = NSMinX(senderFrame) + NSWidth(senderFrame) / 2; theCenterPoint.y = NSMinY(senderFrame) + NSHeight(senderFrame) / 2; // Convert the point from view to screen coordinates theCenterPoint = [[initiator window] convertBaseToScreen:theCenterPoint]; // recycle a window if there are any idle ones; otherwise make a new one // get an idle window newWindow = [idleWindows lastObject]; // if we got one, then take it out of the list of idle windows if (newWindow) [idleWindows removeLastObject]; // if there weeren't any idle windows, then create a new one and set it // to appear at the point calculated above. If we found an idle window, // then get it to set itself up as the same point. if (!newWindow) newWindow = [[FlyingWindow allocWithZone:[self zone]] initAt:&theCenterPoint]; else [newWindow reInitAt:&theCenterPoint]; // add the new window to the list of active windows. [windowList addObject:newWindow]; return self; } - move:sender { // get a new active list int i; id newList = _extraList; // add any new windows spewing about if necessary... // if we don't have too many windows out already, then check // against a random number to decide if we should add a new // window. The larger "FREQUENCY" is, the longer the average // interval will be between new windows coming onto the screen. if (([windowList count] < MAX_SPEWS) && !(random() % FREQUENCY)) { [self addWindow]; } // move all the active windows for (i=0; i<[windowList count]; i++) [[windowList objectAtIndex:i] move]; // remove any windows that left the screen for (i=0; i<[windowList count]; i++) { id theWindow = [windowList objectAtIndex:i]; // if the window is on the screen, transfer it to a new active list if ([theWindow onScreen]) [newList addObject:theWindow]; // windows that left the screen are taken out of the animation and moved to the idle list else { [theWindow orderOut:self]; [idleWindows addObject:theWindow]; // put in recycler } } // make sure no stray windows were left behind. [windowList removeAllObjects]; // get rid of the old active list and set up the new one. _extraList = windowList; windowList = newList; // if there are no more windows in the active list, and it is no longer // OK to create new ones, then the animation has ended, so we'll stop // the timer. if (([windowList count] < 1) && !(createOK)) // stop TE after all windows gone [animator stopEntry]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.