This is Thinker.m in view mode; [Download] [Up]
// Thinker.m // // This class is the brains behind the BackSpace app; it is the Application // object's delegate, and it watches the system to determine when to // initiate the screen saver mode. // // You may freely copy, distribute, and reuse the code in this example. // NeXT disclaims any warranty of any kind, expressed or implied, as to its // fitness for any particular use. #import "Thinker.h" #import "BackWindow.h" #import "BackView.h" #import "SpaceView.h" #import "MySlider.h" #import "Password.h" #import "psfuncts.h" #import <appkit/appkit.h> #import <objc/NXBundle.h> // convert vertical blank time to milliseconds #define SEC2MS(x) ((x * 1000) + 20) //#define SHOWITERATIONSPERSEC #ifdef SHOWITERATIONSPERSEC unsigned iterations; BStimeval then, now, targetTime; #endif static id _BSThinker; id BSThinker() { return _BSThinker; } @implementation Thinker - appDidInit:sender { const char *autoLaunch; globalTier = BACKGROUNDTIER; openAnother = YES; _BSThinker = self; backZone = NXCreateZone(vm_page_size, vm_page_size, YES); NXSetRect(&windowRect, 475, 300, 500, 450); [NXApp getScreens:&screens count:&screenCount]; [commonImageInspector getFrame: &inspectorFrame]; currentInspector = commonImageInspector; [self getViewType]; [self setVirtualViewIndexAndIncrement:NO]; [self getWindowType]; [self getScreenSaverSetting]; [self getScreenLockerSetting]; [self getPrioritySetting]; [self getImageFile]; [self getHotCornerSetting]; autoLaunch = NXGetDefaultValue([NXApp appName], "NXAutoLaunch"); if (strcmp(autoLaunch,"YES")) { [[windMatrix window] makeKeyAndOrderFront:self]; windowHasBeenDisplayed = YES; } else [NXApp hide:self]; #ifdef SHOWITERATIONSPERSEC then = currentTimeInMs(); targetTime = then + 10000; #endif srandom(time(0)); return self; } - appDidHide:sender { if (windowType != BACKWINDOW) [self removeTimer]; return self; } - appDidUnhide:sender { if (!windowHasBeenDisplayed) { [[windMatrix window] makeKeyAndOrderFront:self]; windowHasBeenDisplayed = YES; } 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.02, &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]; [spaceWindow flushWindow]; NXPing (); // Synchronize postscript for smoother animation [spaceView oneStep]; [spaceWindow flushWindow]; NXPing (); // Synchronize postscript for smoother animation #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; } - installSpaceViewIntoWindow:w { NXRect cvrect; int i; id subviews, contentView; if (!w) return nil; contentView = [w contentView]; // get size of content view [contentView getBounds:&cvrect]; // remove old subviews, this is overkill really... subviews = [contentView subviews]; for (i=([subviews count]-1); i>=0; i--) { [[subviews objectAt:i] removeFromSuperview]; } // install it into the window's content view [contentView addSubview:spaceView]; [contentView setAutoresizeSubviews:YES]; [spaceView setAutosizing:NX_WIDTHSIZABLE | NX_HEIGHTSIZABLE]; // size the spaceview [spaceView sizeTo:cvrect.size.width :cvrect.size.height]; return self; } - useNormalWindow { int myBacking; spaceView = [self backView]; myBacking = [self backingTypeForView:spaceView]; if (!normalWindow) { normalWindow = [[Window allocFromZone:backZone] initContent:&windowRect style:NX_RESIZEBARSTYLE backing:myBacking buttonMask:NX_CLOSEBUTTONMASK defer:NO]; [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; [self installSpaceViewIntoWindow:spaceWindow]; 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) [spaceWindow setBackingType:NX_RETAINED]; else [spaceWindow setBackingType:NX_BUFFERED]; 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 backView]; myBacking = [self backingTypeForView:spaceView]; [self createBigWindowIfNecessaryForView:spaceView]; if (myBacking == NX_RETAINED) { spaceWindow = bigUnbufferedWindow; tweakWindow([spaceWindow windowNum], tier); } else { spaceWindow = bigBufferedWindow; } [self installSpaceViewIntoWindow:spaceWindow]; if ([spaceView respondsTo:@selector(setImage:)]) [spaceView setImage: image]; [spaceWindow placeWindow:&r]; if (myBacking == NX_BUFFERED) [spaceWindow display]; [spaceWindow orderFront:self]; if (myBacking == NX_BUFFERED) tweakWindow([spaceWindow windowNum], tier); else [spaceWindow display]; if ([spaceView respondsTo:@selector(newWindow)]) [spaceView newWindow]; 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 useOptimizedDrawing:YES]; [bigUnbufferedWindow removeFromEventMask:(NX_LMOUSEDOWNMASK | NX_MOUSEMOVEDMASK | NX_LMOUSEDRAGGEDMASK | NX_MOUSEENTEREDMASK | NX_MOUSEEXITEDMASK | NX_CURSORUPDATEMASK)]; [bigUnbufferedWindow addToEventMask:NX_FLAGSCHANGEDMASK]; [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 useOptimizedDrawing:YES]; [bigBufferedWindow removeFromEventMask:(NX_LMOUSEDOWNMASK | NX_MOUSEMOVEDMASK | NX_LMOUSEDRAGGEDMASK | NX_MOUSEENTEREDMASK | NX_MOUSEEXITEDMASK | NX_CURSORUPDATEMASK)]; [bigBufferedWindow addToEventMask:NX_FLAGSCHANGEDMASK]; [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[10]; 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 = NORMALWINDOW; const char *ptr; int val; ptr = NXGetDefaultValue([NXApp appName], "windowType"); if (ptr) { sscanf(ptr,"%d",&val); if (val >= 0 && val <= 2) tWindowType = val; } [windMatrix selectCellAt:tWindowType :0]; [self changeWindowTypeAndRemember:NO]; return self; } - getScreenSaverSetting { const char *ptr; if((evs = NXOpenEventStatus()) == 0) { perror("NXOpenEventStatus failed."); exit(10); } [self getDimBrightness:&dimBrightness]; //in case the old dim brightness is somehow invalid, I reset it if (dimBrightness > .25) { dimBrightness = .25; [self _setDimBrightness:&dimBrightness]; } [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... [self calcDimTime]; if (rem) NXWriteDefault([NXApp appName], "screenSaver", "On"); } else { // turn it off... if (rem) NXRemoveDefault([NXApp appName], "screenSaver"); } return self; } - calcDimTime { double dimTime; [self getDimTime :&dimTime]; if (dimTime < 0) dimTime = .1; if (screenSaverVal && !doingSaver) { // printf("BackSpace calcDimTime: dims in %f seconds\n",dimTime); [self perform:@selector(maybeDoScreenSaver:) with:self afterDelay:SEC2MS(dimTime) cancelPrevious:YES]; } return self; } - maybeDoScreenSaver:sender { NXEvent anEvent; BOOL autoDimmed; // in case timed entry fires but user has killed screen saver if (!screenSaverVal || doingSaver) return self; autoDimmed = NXAutoDimState(evs); if (!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.data.compound.subtype = BSDOSAVER; anEvent.ctxt = [NXApp context]; DPSPostEvent(&anEvent,0); return self; } - applicationDefined:(NXEvent *)theEvent { switch (theEvent->data.compound.subtype) { case BSDOSAVER: [self doScreenSaver:self]; [self calcDimTime]; // reset to fire again break; case BSOPENFILE: [self doDelayedOpenFile]; break; default: break; } return self; } - showFakeScreenSaverAfterPause:sender { usleep(250000); return [self showFakeScreenSaver:sender]; } - showFakeScreenSaver:sender { [self screenSaverMode]; NXSetAutoDimState(evs, YES); [self doScreenSaver:self]; NXSetAutoDimState(evs, NO); [self normalMode]; //usually not necessary // reset to fire again [self calcDimTime]; return self; } - doScreenSaver:sender { int oldWindowType; BOOL mouseOK, oldTimerValid; BOOL ignoreMouseMovement = NO; BOOL isHidden; NXRect trackingRect; NXPoint mouseLoc; NXEvent dummyEvent; BOOL passwordOK; BOOL stoleActivation = NO; int oldActiveApp = 0; // must be sure we don't enter on timed entry after faking saver doingSaver = YES; isHidden = [NXApp isHidden]; if (isHidden) { [NXApp unhideWithoutActivation:self]; } 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]; //xxx if ([spaceWindow windowNum] <= 0) [spaceWindow display]; PSsetwindowlevel(SAVERTIER, [spaceWindow windowNum]); } else { PSsetwindowlevel(SAVERTIER, [spaceWindow windowNum]); [spaceView fillBoundsWithBlack]; [spaceView display]; } NXPing(); [self screenSaverMode]; if ([spaceView respondsTo:@selector(enteredScreenSaverMode)]) [spaceView enteredScreenSaverMode]; do { //obscure cursor PShidecursor(); [spaceView lockFocus]; if ([spaceView respondsTo:@selector(didLockFocus)]) [spaceView didLockFocus]; if ([spaceView respondsTo:@selector(ignoreMouseMovement)]) ignoreMouseMovement = [spaceView ignoreMouseMovement]; [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]; [spaceWindow flushWindow]; NXPing(); // Synchronize postscript for smoother animation // note: window and view coordinates the same! // so I don't have to convert to view coord system if (ignoreMouseMovement) mouseOK = YES; else { [spaceWindow getMouseLocation:&mouseLoc]; mouseOK = [spaceView mouse:&mouseLoc inRect:&trackingRect]; } [spaceView oneStep]; [spaceWindow flushWindow]; NXPing(); // Synchronize postscript for smoother animation } while (mouseOK && ([NXApp peekNextEvent: (NX_MOUSEUPMASK|NX_KEYDOWNMASK) into:&dummyEvent waitFor:0.0 threshold:NX_BASETHRESHOLD] == NULL)); [spaceView unlockFocus]; //restore cursor PSshowcursor(); passwordOK = [password checkPassword: NXLocalString("Screen is locked. Enter password to unlock:",0,0) randomPos:YES checkLock:YES withView:spaceView]; if (!passwordOK) NXSetAutoDimState(evs, YES); } while (!passwordOK); if ([spaceView respondsTo:@selector(willExitScreenSaverMode)]) [spaceView willExitScreenSaverMode]; NXSetAutoDimState(evs, NO); [self normalMode]; //background window tier to BACKGROUNDTIER PSsetwindowlevel(BACKGROUNDTIER, [spaceWindow windowNum]); globalTier = BACKGROUNDTIER; 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]; } if (isHidden) { [NXApp hide:self]; } doingSaver = NO; return self; } - appWillTerminate:sender { [self normalMode]; return self; } - appDidBecomeActive:sender { id theMatrix; theMatrix = [viewSelectionBrowser matrixInColumn:0]; [theMatrix scrollCellToVisible:realViewIndex :0]; return self; } - app:sender powerOffIn:(int)ms andSave:(int)aFlag { return [NXApp terminate: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], NXLocalString("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.