This is Thinker.m in view mode; [Download] [Up]
#import "Thinker.h" #import "BackWindow.h" #import "BackView.h" #import "SpaceView.h" #import "BezierViewPart.h" #import "MySlider.h" #import "Password.h" #import "psfuncts.h" #import "Localization.h" #import <appkit/Application.h> #import <appkit/Matrix.h> #import <appkit/Button.h> #import <appkit/Cell.h> #import <appkit/publicWraps.h> #import <dpsclient/wraps.h> #import <dpsclient/dpsclient.h> #import <appkit/defaults.h> #import <appkit/graphics.h> #import <dpsclient/dpsNeXT.h> #import <sys/resource.h> #import <sys/file.h> #import <mach.h> #import <cthreads.h> #import <c.h> #import <libc.h> #import <appkit/OpenPanel.h> #import <appkit/NXImage.h> // convert vertical blank time to milliseconds #define VB2MS(x) (((x * 1000)/(68)) + 1000) //#define SHOWITERATIONSPERSEC #ifdef SHOWITERATIONSPERSEC unsigned iterations; BStimeval then, now, targetTime; #endif @implementation Thinker - appDidInit:sender { globalTier = -1; doingSaver = NO; backZone = NXCreateZone(vm_page_size, vm_page_size, YES); NXSetRect(&windowRect, 475, 300, 500, 450); [NXApp getScreens:&screens count:&screenCount]; [self getViewType]; [self createViewLists]; [self setVirtualViewIndexAndIncrement:NO]; [self getWindowType]; [self getScreenSaverSetting]; [self getScreenLockerSetting]; [self getBackgroundColor]; [self getPrioritySetting]; [self getImageFile]; #ifdef SHOWITERATIONSPERSEC then = currentTimeInMs(); targetTime = then + 10000; #endif return self; } - appDidHide:sender { if (windowType != BACKWINDOW) [self removeTimer]; return self; } - appDidUnhide:sender { if (windowType != NOWINDOW) [self createTimer]; return self; } // Pretty much a dummy function to invoke the step method. void timedEntryFunction (DPSTimedEntry timedEntry, double timeNow, void *theObject) { [(id)theObject doDistributorLoop]; } - createTimer { if (!timerValid) { timerValid = YES; timer = DPSAddTimedEntry(0.03, &timedEntryFunction, self, NX_BASETHRESHOLD); } return self; } - removeTimer { if (timerValid) DPSRemoveTimedEntry (timer); timerValid = NO; return self; } - doDistributorLoop { NXEvent dummyEvent; keepLooping = YES; [spaceView lockFocus]; if ([spaceView respondsTo:@selector(didLockFocus)]) [spaceView didLockFocus]; do { [spaceView oneStep]; NXPing (); // Synchronize postscript for smoother animation [spaceWindow flushWindow]; [spaceView oneStep]; NXPing (); // Synchronize postscript for smoother animation [spaceWindow flushWindow]; #ifdef SHOWITERATIONSPERSEC iterations++; if ((now = currentTimeInMs()) > targetTime) { printf("BackSpace: %5.1f its/sec\n", (double)iterations*1000.0/(double)(now - then)); iterations = 0; targetTime = now + 10000; then = now; } #endif } while (timerValid && keepLooping && ([NXApp peekNextEvent:NX_ALLEVENTS into:&dummyEvent waitFor:0 threshold:NX_BASETHRESHOLD] == NULL)); [spaceView unlockFocus]; return self; } - useNormalWindow { int myBacking; spaceView = [self normalView]; myBacking = [self backingTypeForView:spaceView]; if (!normalWindow) { // window must be created as buffered or flushing will never work // ie the Kit won't believe its buffered if it was created retained normalWindow = [[Window allocFromZone:backZone] initContent:&windowRect style:NX_RESIZEBARSTYLE backing:NX_BUFFERED buttonMask:NX_RESIZEBUTTONMASK | NX_CLOSEBUTTONMASK defer:NO]; [spaceView setAutosizing:NX_WIDTHSIZABLE | NX_HEIGHTSIZABLE]; [[normalWindow setContentView:spaceView] free]; [self setWindowTitle]; [normalWindow useOptimizedDrawing:YES]; [normalWindow setDynamicDepthLimit:YES]; //want window depth to match device! [normalWindow setOneShot:YES]; [normalWindow setDelegate:self]; [normalWindow setBackgroundGray:NX_BLACK]; } spaceWindow = normalWindow; if ([spaceView respondsTo:@selector(setImage:)]) [spaceView setImage: image]; if ([spaceView respondsTo:@selector(newWindow)]) [spaceView newWindow]; [spaceWindow display]; [spaceWindow makeKeyAndOrderFront:self]; // need to do this so flushing always works! // must do it late because kit does lazy window creation ie the PostScript // window might not exist until you actually draw to it if (myBacking == NX_RETAINED) convertToRetained([spaceWindow windowNum]); else convertToBuffered([spaceWindow windowNum]); return self; } - (int) backingTypeForView:aView { if ([aView respondsTo:@selector(useBufferedWindow)] && [aView useBufferedWindow]) return NX_BUFFERED; return NX_RETAINED; } - useBackWindow:(int)tier { NXRect r={{0, 0}}; int myBacking; [NXApp getScreenSize:&(r.size)]; spaceView = [self bigView]; myBacking = [self backingTypeForView:spaceView]; [self createBigWindowIfNecessaryForView:spaceView]; if (myBacking == NX_RETAINED) { spaceWindow = bigUnbufferedWindow; tweakWindow([spaceWindow windowNum], tier); } else { spaceWindow = bigBufferedWindow; } [spaceWindow setContentView:spaceView]; if ([spaceView respondsTo:@selector(setImage:)]) [spaceView setImage: image]; [spaceWindow placeWindowAndDisplay:&r]; [spaceWindow orderFront:self]; if (myBacking == NX_BUFFERED) tweakWindow([spaceWindow windowNum], tier); if ([spaceView respondsTo:@selector(newWindow)]) [spaceView newWindow]; [spaceWindow display]; return self; } - createBigWindowIfNecessaryForView:aView { NXRect r={{0, 0}}; int myBacking = [self backingTypeForView:aView]; [NXApp getScreenSize:&(r.size)]; if ((myBacking == NX_RETAINED) && !bigUnbufferedWindow) { bigUnbufferedWindow = [[BackWindow allocFromZone:backZone] initContent:&r style:NX_TOKENSTYLE backing:NX_NONRETAINED buttonMask:0 defer:NO]; [[bigUnbufferedWindow setContentView:aView] free]; [bigUnbufferedWindow useOptimizedDrawing:YES]; [bigUnbufferedWindow removeFromEventMask:(NX_LMOUSEDOWNMASK | NX_LMOUSEUPMASK | NX_MOUSEMOVEDMASK | NX_LMOUSEDRAGGEDMASK | NX_MOUSEENTEREDMASK | NX_MOUSEEXITEDMASK | NX_KEYDOWNMASK | NX_KEYUPMASK | NX_CURSORUPDATEMASK)]; [bigUnbufferedWindow setBackgroundGray:NX_BLACK]; } if ((myBacking == NX_BUFFERED) && !bigBufferedWindow) { bigBufferedWindow = [[BackWindow allocFromZone:backZone] initContent:&r style:NX_TOKENSTYLE backing:NX_BUFFERED buttonMask:0 defer:NO]; [[bigBufferedWindow setContentView:aView] free]; [bigBufferedWindow useOptimizedDrawing:YES]; [bigBufferedWindow removeFromEventMask:(NX_LMOUSEDOWNMASK | NX_LMOUSEUPMASK | NX_MOUSEMOVEDMASK | NX_LMOUSEDRAGGEDMASK | NX_MOUSEENTEREDMASK | NX_MOUSEEXITEDMASK | NX_KEYDOWNMASK | NX_KEYUPMASK | NX_CURSORUPDATEMASK)]; [bigBufferedWindow setDynamicDepthLimit:YES]; //want window depth to match device! [bigBufferedWindow setOneShot:YES]; [bigBufferedWindow setBackgroundGray:NX_BLACK]; } return self; } - changeWindowType:sender { [self changeWindowTypeAndRemember:YES]; return self; } - changeWindowTypeAndRemember:(BOOL)rem { char str[50]; int newWindowType; newWindowType = [windMatrix selectedRow]; if (newWindowType == windowType) return self; windowType = newWindowType; if (rem) { sprintf(str,"%1d", windowType); NXWriteDefault([NXApp appName], "windowType", str); } [spaceWindow orderOut:self]; switch (windowType) { case NOWINDOW: [self removeTimer]; break; case NORMALWINDOW: [self useNormalWindow]; [self createTimer]; break; case BACKWINDOW: [self useBackWindow: globalTier]; [self createTimer]; break; } return self; } - getWindowType { int tWindowType; const char *ptr; int val; ptr = NXGetDefaultValue([NXApp appName], "windowType"); if (ptr) { sscanf(ptr,"%d",&val); if (val >= 0 && val <= 2) tWindowType = val; else tWindowType = NORMALWINDOW; } else tWindowType = NORMALWINDOW; [windMatrix selectCellAt:tWindowType :0]; [self changeWindowTypeAndRemember:NO]; return self; } - getScreenSaverSetting { const char *ptr; if((evs = open("/dev/evs0",O_RDWR)) < 0) { perror("/dev/evs0"); exit(10); } [self getDimBrightness:&oldDimBrightness]; //in case the old dim brightness is somehow invalid, I reset it if (oldDimBrightness > 15) { oldDimBrightness = 15; [self _setDimBrightness:&oldDimBrightness]; } [screenSaver setState:0]; ptr = NXGetDefaultValue([NXApp appName], "screenSaver"); if (!ptr || !strcmp(ptr,"Off")) [self setScreenSaver:NO andRemember:NO]; else [self setScreenSaver:YES andRemember:NO]; return self; } - changeScreenSaverSetting:sender { [self setScreenSaver:([screenSaver state])andRemember:YES]; return self; } - setScreenSaver:(BOOL)val andRemember:(BOOL)rem { [screenSaver setState:val]; screenSaverVal = val; if (val) { // turn it on... // I don't like turning on bright autodim here - It should be // in the doScreenSaver: method, but setting the dim value // there doesn't work if the screen is dim! [self screenSaverMode]; // we never really know what time it is, but we get an idea // by watching the dim time progress [self getDimTime :&dimTime]; [self getDimInterval :&realDimInterval]; // printf("BackSpace Interval: %d\n", realDimInterval/68); [self perform:@selector(maybeDoScreenSaver:) with:self afterDelay:VB2MS(realDimInterval) cancelPrevious:YES]; if (rem) NXWriteDefault([NXApp appName], "screenSaver", "On"); } else { // turn it off... [self normalMode]; if (rem) NXRemoveDefault([NXApp appName], "screenSaver"); } return self; } - calcDimTime { int newTime, newInterval, maxInterval; [self getDimTime :&newTime]; [self getDimInterval :&maxInterval]; newInterval = newTime - dimTime; if (newInterval > maxInterval) newInterval = maxInterval; if (doingSaver) newInterval = realDimInterval; // printf("newTime:%d dimTime: %d\n",newTime, dimTime); [self perform:@selector(maybeDoScreenSaver:) with:self afterDelay:VB2MS(newInterval) cancelPrevious:YES]; // printf("BackSpace:waiting %d seconds\n",((VB2MS(newInterval))/1000)); dimTime = newTime; return self; } - maybeDoScreenSaver:sender { NXEvent anEvent; int autoDimmed; // in case timed entry fires but user has killed screen saver if (!screenSaverVal) return self; [self getDimStatus :&autoDimmed]; if (doingSaver || !autoDimmed) { [self calcDimTime]; return self; } // The perform:afterDelay: method starts a timed entry to // invoke maybeDoScreenSaver, so we are in a timed entry // right now. If we just jumped into doScreenSaver:, we // would interrupt the doDistributorLoop method while // it's still focused on the spaceView. By posting an // event, we force that loop to bail out so we can jump // into the screen saver cleanly. keepLooping = NO; // There was a bug related to this at one point. // I don't think it's necessary anymore. anEvent.type = NX_APPDEFINED; anEvent.ctxt = [NXApp context]; DPSPostEvent(&anEvent,0); return self; } - applicationDefined:(NXEvent *)theEvent { [self doScreenSaverAndResetTimer]; return self; } // This method invokes the screen saver. After the screen // saver terminates, it resets the timer to fire the screen // saver again - doScreenSaverAndResetTimer { int dimInterval; [self doScreenSaver:self]; // reset to fire again [self getDimTime :&dimTime]; [self getDimInterval :&dimInterval]; [self perform:@selector(maybeDoScreenSaver:) with:self afterDelay:VB2MS(dimInterval) cancelPrevious:YES]; return self; } - showFakeScreenSaver:sender { // dim intervals in vblanks int oldDimInterval, tempDimInterval = 11; [self screenSaverMode]; [self getDimInterval :&oldDimInterval]; [self setDimInterval :&tempDimInterval]; // now I wait until the screen "should" be dim. I don't really // like this solution, but at least it's relatively harmless. // You mustn't loop until the screen dims, because it might never // dim. Also note that the dim interval must be long enough that // the bright screen will be caught in doScreenSaver: before the // screen goes dim again. usleep((13*1000000)/68); //sleep till dim (yuck!) // This is kind of a drag; we are running the screen saver with // a very short dim interval. This means if somebody recompiles // backspace (changing the executable) while somebody else is // running the app as a fake screen saver (ie demo), the app will // die leaving the dim interval horribly short. I don't know a good // workaround, unfortunately. [self doScreenSaver:self]; [self setDimInterval :&oldDimInterval]; //restore dim interval if (!screenSaverVal) [self normalMode]; // reset to fire again [self getDimTime :&dimTime]; [self perform:@selector(maybeDoScreenSaver:) with:self afterDelay:VB2MS(oldDimInterval) cancelPrevious:YES]; return self; } //don't call next 2 methods, they are hacks only for doScreenSaver with screen locking static int dimIntervalToRestore; - forceScreenToDimHack { int tempDimInterval = 11; [self getDimInterval :&dimIntervalToRestore]; [self setDimInterval :&tempDimInterval]; usleep((13*1000000)/68); //sleep till dim (yuck!) return self; } - forceScreenToUnDimhack { dimIntervalToRestore = MAX(dimIntervalToRestore,680); [self setDimInterval :&dimIntervalToRestore]; //restore dim interval return self; } - doScreenSaver:sender { int autoDimmed; int oldWindowType; BOOL mouseOK, oldTimerValid; // BOOL isHidden; NXRect trackingRect; NXPoint mouseLoc; BOOL passwordOK; BOOL mustRestoreOldDimInterval = NO; BOOL stoleActivation = NO; int oldActiveApp = 0; // must be sure we don't enter on timed entry after faking saver doingSaver = YES; #ifdef VANNA // using tokenstyle windows (the only kind that don't hide) // triggers a weird activation bug that makes some windows // unresponsive to events until you hide and unhide the app. // The following code should be necessary, but isn't, and // should cure the bug, but doesn't... isHidden = [NXApp isHidden]; if (isHidden) { [NXApp unhideWithoutActivation:self]; } #endif if ([password isLocked]) { oldActiveApp = [NXApp activateSelf:YES]; stoleActivation = YES; } [self setVirtualViewIndexAndIncrement:YES]; //save old window state oldWindowType = [windMatrix selectedRow]; globalTier = SAVERTIER; [self blackOutAllScreens]; //background window on screen [windMatrix selectCellAt:BACKWINDOW :0]; [self changeWindowTypeAndRemember:NO]; //nuke timer so timed entry doesn't fire oldTimerValid = timerValid; [self removeTimer]; //set background window tier to SAVERTIER if ([self backingTypeForView:spaceView] == NX_BUFFERED) { // make sure the one shot buffer really exists [spaceWindow display]; setWindowLevel([spaceWindow windowNum],SAVERTIER); } else { setWindowLevel([spaceWindow windowNum],SAVERTIER); [spaceView fillBoundsWithBlack]; [spaceView display]; } do { //obscure cursor PShidecursor(); [spaceView lockFocus]; if ([spaceView respondsTo:@selector(didLockFocus)]) [spaceView didLockFocus]; [spaceWindow getMouseLocation:&mouseLoc]; trackingRect.origin.x = mouseLoc.x - 100; trackingRect.origin.y = mouseLoc.y - 100; trackingRect.size.width = trackingRect.size.height = 200; do { [spaceView oneStep]; NXPing (); // Synchronize postscript for smoother animation [spaceWindow flushWindow]; // note: window and view coordinates the same! // so I don't have to convert to view coord system [spaceWindow getMouseLocation:&mouseLoc]; mouseOK = [spaceView mouse:&mouseLoc inRect:&trackingRect]; [spaceView oneStep]; NXPing (); // Synchronize postscript for smoother animation [spaceWindow flushWindow]; [self getDimStatus :&autoDimmed]; //get dim status } while (autoDimmed && mouseOK); [spaceView unlockFocus]; //restore cursor PSshowcursor(); passwordOK = [password checkPassword: LocalString("Screen is locked. Enter password to unlock:",0,0) randomPos:YES checkLock:YES withView:spaceView]; if (!passwordOK && !mustRestoreOldDimInterval) { [self forceScreenToDimHack]; mustRestoreOldDimInterval = YES; } } while (!passwordOK); if (mustRestoreOldDimInterval) [self forceScreenToUnDimhack]; //background window tier to -1 setWindowLevel([spaceWindow windowNum],-1); globalTier = -1; if (([self backingTypeForView:spaceView] != NX_BUFFERED) && oldWindowType == BACKWINDOW) // this justs fixes a display bug for really lazy nonretained windows { [spaceView fillBoundsWithBlack]; [spaceView display]; } if (oldTimerValid) [self createTimer]; [self unBlackOutAllScreens]; //restore old window state [windMatrix selectCellAt:oldWindowType :0]; [self changeWindowTypeAndRemember:NO]; if (stoleActivation) { if (oldActiveApp) [NXApp activate:oldActiveApp]; else [NXApp deactivateSelf]; } #ifdef VANNA if (isHidden) { [NXApp hide:self]; } #endif doingSaver = NO; return self; } - appWillTerminate:sender { [self normalMode]; return self; } - getPrioritySetting { const char *ptr; int val; [mySlider setMinValue: 0]; [mySlider setMaxValue: 10]; ptr = NXGetDefaultValue([NXApp appName], "priority"); if (ptr) { sscanf(ptr,"%d",&val); if (val >= 0 && val <= 10) priority = val; else priority = 4; } else priority = 4; [[mySlider cell] setIntValue:priority]; [[priorityLevel cell] setIntValue:priority]; // use mach call rather than unix - mach lets me increase priority! // setpriority(PRIO_PROCESS, 0, priority); cthread_priority(cthread_self(), priority, FALSE); return self; } - changeSliderValue:sender { priority = [[mySlider cell] intValue]; [[priorityLevel cell] setIntValue:priority]; return self; } - saveSliderValue { char str[50]; // setpriority(PRIO_PROCESS, 0, priority); cthread_priority(cthread_self(), priority, FALSE); sprintf(str,"%d", priority); NXWriteDefault([NXApp appName], "priority", str); return self; } - windowWillResize:sender toSize:(NXSize *)frameSize { if (frameSize->width < 100) frameSize->width = 100; if (frameSize->height < 100) frameSize->height = 100; return self; } - windowWillClose:sender { [windMatrix selectCellAt:NOWINDOW :0]; [self perform:@selector(changeWindowType:) with:self afterDelay:1 cancelPrevious:YES]; return nil; } BStimeval currentTimeInMs() { struct timeval curTime; gettimeofday (&curTime, NULL); return (curTime.tv_sec) * 1000 + curTime.tv_usec / 1000; } // // Additional methods to handle a common image object for views. // Lennart Lovstrad, Rank Xerox EuroPARC, August 1991. // - setImageFromFile: (const char *) filename { [image free]; image = [[NXImage alloc] initFromFile: filename]; if (image == nil) { NXRunAlertPanel([NXApp appName], LocalString("Could not open %s",0,0), NULL, NULL, NULL, filename); image = nil; //return nil; //can't return, image is invalid } return [self commonImageInit]; } - setImageFromName: (const char *) name { [image free]; image = [[NXImage alloc] initFromSection: name]; return [self commonImageInit]; } - commonImageInit { [imageView setImage: image]; [imageView display]; if ([spaceView respondsTo:@selector(setImage:)]) [spaceView setImage: image]; if ([self backingTypeForView:spaceView] != NX_BUFFERED) { [spaceView fillBoundsWithBlack]; [spaceView display]; } return self; } - getImageFile { const char *filename; filename = NXGetDefaultValue([NXApp appName], "imageFile"); if (filename) [self setImageFromFile: filename]; else [self setImageFromName: "defaultImage"]; return self; } - setImageFileFrom: sender { id openPanel = [OpenPanel new]; const char *fileTypes[] = {"tiff", "eps", NULL}; if ([openPanel runModalForTypes: fileTypes]) { [self setImageFromFile: [openPanel filename]]; NXWriteDefault([NXApp appName], "imageFile", [openPanel filename]); } [spaceView display]; //don't know why this is necessary... return self; } // This should return a float between 0 and 1 float frandom() { float val = (random() & 0x7fffffff); val /= 0x7fffffff; return val; } float randBetween(float a, float b) { float val, scale, t; if (a > b) { t = a; a = b; b = t; } scale = (b-a); val = scale * frandom(); return (a + val); } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.