home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.2 (Developer) / NS_dev_3.2.iso / NextDeveloper / Examples / AppKit / Backspace / Thinker.m < prev    next >
Encoding:
Text File  |  1993-07-15  |  18.6 KB  |  882 lines

  1. //  Thinker.m
  2. //
  3. //  This class is the brains behind the BackSpace app; it is the Application
  4. //  object's delegate, and it watches the system to determine when to
  5. //  initiate the screen saver mode.
  6. //
  7. //  You may freely copy, distribute, and reuse the code in this example.
  8. //  NeXT disclaims any warranty of any kind, expressed or  implied, as to its
  9. //  fitness for any particular use.
  10.  
  11.  
  12. #import "Thinker.h"
  13. #import "BackWindow.h"
  14. #import "BackView.h"
  15. #import "SpaceView.h"
  16. #import "MySlider.h"
  17. #import "Password.h"
  18. #import "psfuncts.h"
  19.  
  20. #import <appkit/appkit.h>
  21. #import <objc/NXBundle.h>
  22.  
  23. // convert vertical blank time to milliseconds
  24. #define SEC2MS(x) ((x * 1000) + 20)
  25.  
  26. //#define SHOWITERATIONSPERSEC
  27.  
  28. #ifdef SHOWITERATIONSPERSEC
  29. unsigned iterations;
  30. BStimeval then, now, targetTime;
  31. #endif
  32.  
  33. static id _BSThinker;
  34.  
  35. id BSThinker()
  36. {    return _BSThinker;
  37. }
  38.  
  39.  
  40. @implementation Thinker
  41.  
  42. - appDidInit:sender
  43. {
  44.     const char *autoLaunch;
  45.     globalTier = BACKGROUNDTIER;
  46.     openAnother = YES;
  47.     _BSThinker = self;
  48.  
  49.     backZone = NXCreateZone(vm_page_size, vm_page_size, YES);
  50.  
  51.     NXSetRect(&windowRect, 475, 300, 500, 450);
  52.  
  53.     [NXApp getScreens:&screens count:&screenCount];
  54.  
  55.     [commonImageInspector getFrame: &inspectorFrame];
  56.     currentInspector = commonImageInspector;
  57.     
  58.     [self getViewType];
  59.     [self setVirtualViewIndexAndIncrement:NO];
  60.     [self getWindowType];
  61.  
  62.     [self getScreenSaverSetting];
  63.     [self getScreenLockerSetting];
  64.     [self getPrioritySetting];
  65.     [self getImageFile];
  66.     [self getHotCornerSetting];
  67.  
  68.     autoLaunch = NXGetDefaultValue([NXApp appName], "NXAutoLaunch");
  69.     if (strcmp(autoLaunch,"YES"))
  70.     {
  71.         [[windMatrix window] makeKeyAndOrderFront:self];
  72.         windowHasBeenDisplayed = YES;
  73.     }
  74.     else [NXApp hide:self];
  75.     
  76. #ifdef SHOWITERATIONSPERSEC
  77.     then = currentTimeInMs();
  78.     targetTime = then + 10000;
  79. #endif
  80.     
  81.     srandom(time(0));
  82.  
  83.     return self;
  84. }
  85.  
  86. - appDidHide:sender
  87. {
  88.     if (windowType != BACKWINDOW) [self removeTimer];
  89.     return self;
  90. }
  91.  
  92. - appDidUnhide:sender
  93. {
  94.     if (!windowHasBeenDisplayed)
  95.     {
  96.         [[windMatrix window] makeKeyAndOrderFront:self];
  97.         windowHasBeenDisplayed = YES;
  98.     }
  99.  
  100.     if (windowType != NOWINDOW) [self createTimer];
  101.     return self;
  102. }
  103.  
  104.  
  105.  
  106. // Pretty much a dummy function to invoke the step method.
  107.  
  108. void timedEntryFunction (DPSTimedEntry timedEntry, double timeNow, void *theObject)
  109. {    [(id)theObject doDistributorLoop];
  110. }
  111.  
  112. - createTimer
  113. {
  114.     if (!timerValid)
  115.     {
  116.         timerValid = YES;
  117.         timer = DPSAddTimedEntry(0.02, &timedEntryFunction, self, NX_BASETHRESHOLD);
  118.     }
  119.     return self;
  120. }
  121.  
  122. - removeTimer
  123. {
  124.     if (timerValid) DPSRemoveTimedEntry (timer);
  125.     timerValid = NO;
  126.     return self;
  127. }
  128.  
  129. - doDistributorLoop
  130. {
  131.     NXEvent dummyEvent;
  132.     
  133.     keepLooping = YES;
  134.     [spaceView lockFocus];
  135.     if ([spaceView respondsTo:@selector(didLockFocus)]) [spaceView didLockFocus];
  136.  
  137.     do {
  138.         [spaceView oneStep];
  139.         [spaceWindow flushWindow];
  140.         NXPing ();    // Synchronize postscript for smoother animation
  141.  
  142.         [spaceView oneStep];
  143.         [spaceWindow flushWindow];
  144.         NXPing ();    // Synchronize postscript for smoother animation
  145.  
  146. #ifdef SHOWITERATIONSPERSEC
  147.             iterations++;
  148.             if ((now = currentTimeInMs()) > targetTime)
  149.             {
  150.                 printf("BackSpace: %5.1f its/sec\n",
  151.                     (double)iterations*1000.0/(double)(now - then));
  152.                 iterations = 0;
  153.                 targetTime = now + 10000;
  154.                 then = now;
  155.             }
  156. #endif
  157.             
  158.        } while (timerValid && keepLooping &&
  159.             ([NXApp peekNextEvent:NX_ALLEVENTS into:&dummyEvent 
  160.                 waitFor:0 threshold:NX_BASETHRESHOLD] == NULL));
  161.  
  162.     [spaceView unlockFocus];
  163.     
  164.     return self;
  165.  
  166. }
  167.  
  168. - installSpaceViewIntoWindow:w
  169. {
  170.     NXRect cvrect;
  171.     int i;
  172.     id subviews, contentView;
  173.     
  174.     if (!w) return nil;
  175.     contentView = [w contentView];
  176.  
  177.     // get size of content view
  178.     [contentView getBounds:&cvrect];
  179.     
  180.     // remove old subviews, this is overkill really...
  181.     subviews = [contentView subviews];
  182.     for (i=([subviews count]-1); i>=0; i--)
  183.     {    [[subviews objectAt:i] removeFromSuperview];
  184.     }
  185.     
  186.     // install it into the window's content view
  187.     [contentView addSubview:spaceView];
  188.     [contentView setAutoresizeSubviews:YES];
  189.     [spaceView setAutosizing:NX_WIDTHSIZABLE | NX_HEIGHTSIZABLE];
  190.  
  191.     // size the spaceview
  192.     [spaceView sizeTo:cvrect.size.width :cvrect.size.height];
  193.     
  194.     return self;
  195. }
  196.  
  197. - useNormalWindow
  198. {
  199.     int myBacking;
  200.     
  201.     spaceView = [self backView];
  202.     myBacking = [self backingTypeForView:spaceView];
  203.  
  204.     if (!normalWindow)
  205.     {
  206.         normalWindow = [[Window allocFromZone:backZone]
  207.             initContent:&windowRect style:NX_RESIZEBARSTYLE
  208.             backing:myBacking 
  209.             buttonMask:NX_CLOSEBUTTONMASK
  210.             defer:NO];
  211.         
  212.         [self setWindowTitle];
  213.         [normalWindow useOptimizedDrawing:YES];
  214.         [normalWindow setDynamicDepthLimit:YES]; //want window depth to match device!
  215.         [normalWindow setOneShot:YES];
  216.         [normalWindow setDelegate:self];
  217.         [normalWindow setBackgroundGray:NX_BLACK];
  218.     }
  219.  
  220.     spaceWindow = normalWindow;
  221.     [self installSpaceViewIntoWindow:spaceWindow];
  222.  
  223.     if ([spaceView respondsTo:@selector(setImage:)])
  224.         [spaceView setImage: image];
  225.     if ([spaceView respondsTo:@selector(newWindow)]) [spaceView newWindow];
  226.     [spaceWindow display];
  227.  
  228.     [spaceWindow makeKeyAndOrderFront:self];
  229.     
  230.     // need to do this so flushing always works!
  231.     // must do it late because kit does lazy window creation ie the PostScript
  232.     // window might not exist until you actually draw to it
  233.     
  234.     if (myBacking == NX_RETAINED)
  235.         [spaceWindow setBackingType:NX_RETAINED];
  236.     else [spaceWindow setBackingType:NX_BUFFERED];
  237.  
  238.     return self;
  239. }
  240.  
  241. - (int) backingTypeForView:aView
  242. {
  243.     if ([aView respondsTo:@selector(useBufferedWindow)] 
  244.         && [aView useBufferedWindow])
  245.         return NX_BUFFERED;
  246.     return NX_RETAINED;
  247. }
  248.  
  249. - useBackWindow:(int)tier
  250. {
  251.     NXRect r={{0, 0}};
  252.     int myBacking;
  253.     
  254.     [NXApp getScreenSize:&(r.size)];
  255.  
  256.     spaceView = [self backView];
  257.     myBacking = [self backingTypeForView:spaceView];
  258.     
  259.     [self createBigWindowIfNecessaryForView:spaceView];
  260.  
  261.     if (myBacking == NX_RETAINED)
  262.     {    spaceWindow = bigUnbufferedWindow;
  263.         tweakWindow([spaceWindow windowNum], tier);
  264.     }
  265.     else
  266.     {    spaceWindow = bigBufferedWindow;
  267.     }
  268.  
  269.     [self installSpaceViewIntoWindow:spaceWindow];
  270.  
  271.     if ([spaceView respondsTo:@selector(setImage:)])
  272.         [spaceView setImage: image];
  273.  
  274.     [spaceWindow placeWindow:&r];
  275.     if (myBacking == NX_BUFFERED) [spaceWindow display];
  276.  
  277.     [spaceWindow orderFront:self];
  278.     if (myBacking == NX_BUFFERED) tweakWindow([spaceWindow windowNum], tier);
  279.     else [spaceWindow display];
  280.  
  281.     if ([spaceView respondsTo:@selector(newWindow)]) [spaceView newWindow];
  282.  
  283.     return self;
  284. }
  285.  
  286. - createBigWindowIfNecessaryForView:aView
  287. {
  288.     NXRect r={{0, 0}};
  289.     int myBacking = [self backingTypeForView:aView];
  290.     
  291.     [NXApp getScreenSize:&(r.size)];
  292.  
  293.     if ((myBacking == NX_RETAINED) && !bigUnbufferedWindow)
  294.     {
  295.     
  296.         bigUnbufferedWindow = [[BackWindow allocFromZone:backZone]
  297.             initContent:&r style:NX_TOKENSTYLE
  298.             backing:NX_NONRETAINED buttonMask:0 defer:NO];
  299.  
  300.         [bigUnbufferedWindow useOptimizedDrawing:YES];
  301.  
  302.         [bigUnbufferedWindow removeFromEventMask:(NX_LMOUSEDOWNMASK | NX_LMOUSEUPMASK
  303.                  | NX_MOUSEMOVEDMASK | NX_LMOUSEDRAGGEDMASK
  304.                | NX_MOUSEENTEREDMASK | NX_MOUSEEXITEDMASK
  305.                | NX_KEYDOWNMASK | NX_KEYUPMASK
  306.                | NX_CURSORUPDATEMASK)];
  307.         [bigUnbufferedWindow setBackgroundGray:NX_BLACK];
  308.     }
  309.  
  310.     if ((myBacking == NX_BUFFERED) && !bigBufferedWindow)
  311.     {
  312.  
  313.         bigBufferedWindow = [[BackWindow allocFromZone:backZone]
  314.             initContent:&r style:NX_TOKENSTYLE
  315.             backing:NX_BUFFERED buttonMask:0 defer:NO];
  316.  
  317.         [bigBufferedWindow useOptimizedDrawing:YES];
  318.  
  319.         [bigBufferedWindow removeFromEventMask:(NX_LMOUSEDOWNMASK | NX_LMOUSEUPMASK
  320.                  | NX_MOUSEMOVEDMASK | NX_LMOUSEDRAGGEDMASK
  321.                | NX_MOUSEENTEREDMASK | NX_MOUSEEXITEDMASK
  322.                | NX_KEYDOWNMASK | NX_KEYUPMASK
  323.                | NX_CURSORUPDATEMASK)];
  324.  
  325.         [bigBufferedWindow setDynamicDepthLimit:YES]; //want window depth to match device!
  326.         [bigBufferedWindow setOneShot:YES];
  327.         [bigBufferedWindow setBackgroundGray:NX_BLACK];
  328.     }
  329.  
  330.     return self;
  331. }
  332.  
  333. - changeWindowType:sender
  334. {
  335.     [self changeWindowTypeAndRemember:YES];
  336.     return self;
  337. }
  338.  
  339. - changeWindowTypeAndRemember:(BOOL)rem
  340. {
  341.     char str[10];
  342.     int newWindowType;
  343.  
  344.     newWindowType = [windMatrix selectedRow];
  345.     if (newWindowType == windowType) return self;
  346.     
  347.     windowType = newWindowType;
  348.  
  349.     if (rem)
  350.     {
  351.         sprintf(str,"%1d", windowType);
  352.         NXWriteDefault([NXApp appName], "windowType", str);
  353.     }
  354.  
  355.     [spaceWindow orderOut:self];
  356.     
  357.     switch (windowType)
  358.     {
  359.         case NOWINDOW:
  360.             [self removeTimer];
  361.             break;
  362.         case NORMALWINDOW:
  363.             [self useNormalWindow];
  364.             [self createTimer];
  365.             break;
  366.         case BACKWINDOW:
  367.             [self useBackWindow: globalTier];
  368.             [self createTimer];
  369.             break;
  370.     }
  371.     
  372.     return self;
  373. }
  374.  
  375. - getWindowType
  376. {
  377.     int tWindowType = NORMALWINDOW;
  378.     const char *ptr;
  379.     int val;
  380.  
  381.     ptr = NXGetDefaultValue([NXApp appName], "windowType");
  382.     if (ptr)
  383.     {
  384.         sscanf(ptr,"%d",&val);
  385.         if (val >= 0 && val <= 2) tWindowType = val;
  386.     }
  387.     
  388.     [windMatrix selectCellAt:tWindowType :0];
  389.     [self changeWindowTypeAndRemember:NO];
  390.  
  391.     return self;
  392. }
  393.  
  394. - getScreenSaverSetting
  395. {
  396.     const char *ptr;
  397.     
  398.     if((evs = NXOpenEventStatus()) == 0)
  399.     {    perror("NXOpenEventStatus failed.");
  400.         exit(10);
  401.     }
  402.     
  403.     [self getDimBrightness:&dimBrightness];
  404.     
  405.     //in case the old dim brightness is somehow invalid, I reset it
  406.     if (dimBrightness > .25)
  407.     {
  408.         dimBrightness = .25;
  409.         [self _setDimBrightness:&dimBrightness];
  410.     }
  411.  
  412.     [screenSaver setState:0];
  413.     
  414.     ptr = NXGetDefaultValue([NXApp appName], "screenSaver");
  415.  
  416.     if (!ptr || !strcmp(ptr,"Off")) [self setScreenSaver:NO andRemember:NO];
  417.     else [self setScreenSaver:YES andRemember:NO];
  418.     
  419.     return self;
  420. }
  421.  
  422. - changeScreenSaverSetting:sender
  423. {
  424.     [self setScreenSaver:([screenSaver state])andRemember:YES];
  425.     return self;
  426. }
  427.  
  428. - setScreenSaver:(BOOL)val andRemember:(BOOL)rem
  429. {
  430.     [screenSaver setState:val];
  431.     screenSaverVal = val;
  432.     
  433.     if (val)
  434.     {
  435.         // turn it on...
  436.         [self calcDimTime];
  437.         if (rem) NXWriteDefault([NXApp appName], "screenSaver", "On");
  438.     }
  439.     else
  440.     {
  441.         // turn it off...
  442.         if (rem) NXRemoveDefault([NXApp appName], "screenSaver");
  443.     }
  444.     
  445.     return self;
  446. }
  447.  
  448. - calcDimTime
  449. {
  450.     double dimTime;
  451.     [self getDimTime :&dimTime];
  452.     
  453.     if (dimTime < 0) dimTime = .1;
  454.     
  455.     if (screenSaverVal && !doingSaver)
  456.     {
  457.         // printf("BackSpace calcDimTime: dims in %f seconds\n",dimTime);
  458.     
  459.         [self perform:@selector(maybeDoScreenSaver:)
  460.             with:self
  461.             afterDelay:SEC2MS(dimTime)
  462.             cancelPrevious:YES];
  463.     }
  464.             
  465.     return self;
  466. }
  467.  
  468. - maybeDoScreenSaver:sender
  469. {
  470.     NXEvent anEvent;
  471.     BOOL autoDimmed;
  472.  
  473.     // in case timed entry fires but user has killed screen saver
  474.     if (!screenSaverVal || doingSaver) return self;
  475.     
  476.     autoDimmed = NXAutoDimState(evs);
  477.     if (!autoDimmed)
  478.     {
  479.         [self calcDimTime];
  480.         return self;
  481.     }
  482.  
  483.     // The perform:afterDelay: method starts a timed entry to
  484.     // invoke maybeDoScreenSaver, so we are in a timed entry
  485.     // right now.  If we just jumped into doScreenSaver:, we
  486.     // would interrupt the doDistributorLoop method while
  487.     // it's still focused on the spaceView.  By posting an
  488.     // event, we force that loop to bail out so we can jump
  489.     // into the screen saver cleanly.
  490.     
  491.     keepLooping = NO;    // There was a bug related to this at one point.
  492.                         // I don't think it's necessary anymore.
  493.     anEvent.type = NX_APPDEFINED;
  494.     anEvent.data.compound.subtype = BSDOSAVER;
  495.     anEvent.ctxt = [NXApp context];
  496.     DPSPostEvent(&anEvent,0);
  497.     
  498.     return self;
  499. }
  500.  
  501. - applicationDefined:(NXEvent *)theEvent
  502. {
  503.     switch (theEvent->data.compound.subtype)
  504.     {
  505.     case BSDOSAVER:
  506.         [self doScreenSaver:self];
  507.         [self calcDimTime];            // reset to fire again
  508.         break;
  509.     case BSOPENFILE:
  510.         [self doDelayedOpenFile];
  511.         break;
  512.     default:
  513.         break;
  514.     }
  515.     return self;
  516. }
  517.  
  518. - showFakeScreenSaverAfterPause:sender
  519. {
  520.     usleep(250000);
  521.     return [self showFakeScreenSaver:sender];
  522. }
  523.  
  524. - showFakeScreenSaver:sender
  525. {
  526.     [self screenSaverMode];
  527.     NXSetAutoDimState(evs, YES);
  528.     [self doScreenSaver:self];
  529.     NXSetAutoDimState(evs, NO);
  530.     [self normalMode];            //usually not necessary
  531.     
  532.     // reset to fire again
  533.     [self calcDimTime];
  534.         
  535.     return self;
  536. }
  537.  
  538.  
  539. - doScreenSaver:sender
  540. {
  541.     BOOL autoDimmed;
  542.     int oldWindowType;
  543.     BOOL mouseOK, oldTimerValid;
  544.     BOOL ignoreMouseMovement = NO;
  545.     BOOL isHidden;
  546.     NXRect trackingRect;
  547.     NXPoint mouseLoc;
  548.     BOOL passwordOK;
  549.     BOOL stoleActivation = NO;
  550.     int oldActiveApp = 0;
  551.         
  552.     // must be sure we don't enter on timed entry after faking saver
  553.     doingSaver = YES;
  554.     
  555.     isHidden = [NXApp isHidden];
  556.     if (isHidden)
  557.     {
  558.         [NXApp unhideWithoutActivation:self];
  559.     }
  560.  
  561.     if ([password isLocked])
  562.     {
  563.         oldActiveApp = [NXApp activateSelf:YES];
  564.         stoleActivation = YES;
  565.     }
  566.     
  567.     [self setVirtualViewIndexAndIncrement:YES];
  568.  
  569.     //save old window state
  570.     oldWindowType = [windMatrix selectedRow];
  571.  
  572.     globalTier = SAVERTIER;
  573.  
  574.     [self blackOutAllScreens];
  575.     
  576.     //background window on screen
  577.     [windMatrix selectCellAt:BACKWINDOW :0];
  578.     [self changeWindowTypeAndRemember:NO];
  579.     
  580.     //nuke timer so timed entry doesn't fire
  581.     oldTimerValid = timerValid;
  582.     [self removeTimer];
  583.  
  584.  
  585.     //set background window tier to SAVERTIER
  586.     if ([self backingTypeForView:spaceView] == NX_BUFFERED)
  587.     {
  588.         // make sure the one shot buffer really exists
  589.         //[spaceWindow display];    //xxx
  590.         if ([spaceWindow windowNum] <= 0) [spaceWindow display];
  591.         PSsetwindowlevel(SAVERTIER, [spaceWindow windowNum]);
  592.     }
  593.     else 
  594.     {
  595.         PSsetwindowlevel(SAVERTIER, [spaceWindow windowNum]);
  596.         [spaceView fillBoundsWithBlack];
  597.         [spaceView display];
  598.     }
  599.  
  600.     NXPing();
  601.     [self screenSaverMode];
  602.  
  603.     if ([spaceView respondsTo:@selector(enteredScreenSaverMode)])
  604.         [spaceView enteredScreenSaverMode];
  605.  
  606.     do {
  607.         //obscure cursor
  608.         PShidecursor();
  609.     
  610.         [spaceView lockFocus];
  611.         if ([spaceView respondsTo:@selector(didLockFocus)])
  612.             [spaceView didLockFocus];
  613.  
  614.  
  615.         if ([spaceView respondsTo:@selector(ignoreMouseMovement)])
  616.             ignoreMouseMovement = [spaceView ignoreMouseMovement];
  617.  
  618.         [spaceWindow getMouseLocation:&mouseLoc];
  619.         trackingRect.origin.x = mouseLoc.x - 100;
  620.         trackingRect.origin.y = mouseLoc.y - 100;
  621.         trackingRect.size.width = trackingRect.size.height = 200;
  622.     
  623.         do {
  624.             [spaceView oneStep];
  625.             [spaceWindow flushWindow];
  626.             NXPing();    // Synchronize postscript for smoother animation
  627.  
  628.             // note: window and view coordinates the same!
  629.             // so I don't have to convert to view coord system
  630.             if (ignoreMouseMovement) mouseOK = YES;
  631.             else
  632.             {
  633.                 [spaceWindow getMouseLocation:&mouseLoc];
  634.                 mouseOK = [spaceView mouse:&mouseLoc inRect:&trackingRect];
  635.             }
  636.         
  637.             [spaceView oneStep];
  638.             [spaceWindow flushWindow];
  639.             NXPing();    // Synchronize postscript for smoother animation
  640.  
  641.             autoDimmed = NXAutoDimState(evs);
  642.         } while (autoDimmed && mouseOK);
  643.     
  644.         [spaceView unlockFocus];
  645.     
  646.         //restore cursor
  647.         PSshowcursor();
  648.         
  649.         passwordOK = [password checkPassword: 
  650.             NXLocalString("Screen is locked.  Enter password to unlock:",0,0) 
  651.             randomPos:YES checkLock:YES withView:spaceView];
  652.  
  653.         if (!passwordOK) NXSetAutoDimState(evs, YES);
  654.  
  655.     } while (!passwordOK);
  656.  
  657.     if ([spaceView respondsTo:@selector(willExitScreenSaverMode)])
  658.         [spaceView willExitScreenSaverMode];
  659.  
  660.     NXSetAutoDimState(evs, NO);
  661.     [self normalMode];
  662.  
  663.     //background window tier to BACKGROUNDTIER
  664.     PSsetwindowlevel(BACKGROUNDTIER, [spaceWindow windowNum]);
  665.     globalTier = BACKGROUNDTIER;
  666.     
  667.     if (([self backingTypeForView:spaceView] != NX_BUFFERED) &&
  668.             oldWindowType == BACKWINDOW)
  669.         // this justs fixes a display bug for really lazy nonretained windows
  670.     {
  671.         [spaceView fillBoundsWithBlack];
  672.         [spaceView display];
  673.     }
  674.  
  675.     if (oldTimerValid)    [self createTimer];
  676.  
  677.     [self unBlackOutAllScreens];
  678.     
  679.     //restore old window state
  680.     [windMatrix selectCellAt:oldWindowType :0];
  681.     [self changeWindowTypeAndRemember:NO];
  682.     
  683.     if (stoleActivation) 
  684.     {
  685.         if (oldActiveApp) [NXApp activate:oldActiveApp];
  686.         else [NXApp deactivateSelf];
  687.     }
  688.  
  689.     if (isHidden)
  690.     {
  691.         [NXApp hide:self];
  692.     }
  693.  
  694.     doingSaver = NO;
  695.  
  696.     return self;
  697. }
  698.  
  699. - appWillTerminate:sender
  700. {
  701.     [self normalMode];
  702.     return self;
  703. }
  704.  
  705. - appDidBecomeActive:sender
  706. {
  707.     id theMatrix;
  708.  
  709.     theMatrix = [viewSelectionBrowser matrixInColumn:0];
  710.     [theMatrix scrollCellToVisible:realViewIndex :0];
  711.     return self;
  712. }
  713.  
  714. - app:sender powerOffIn:(int)ms andSave:(int)aFlag
  715. {
  716.     return [NXApp terminate:self];
  717. }
  718.  
  719. - getPrioritySetting
  720. {
  721.     const char *ptr;
  722.     int val;
  723.  
  724.     [mySlider setMinValue: 0];
  725.     [mySlider setMaxValue: 10];
  726.     
  727.     ptr = NXGetDefaultValue([NXApp appName], "priority");
  728.     if (ptr)
  729.     {
  730.         sscanf(ptr,"%d",&val);
  731.         if (val >= 0 && val <= 10) priority = val;
  732.         else priority = 4;
  733.     }
  734.     else priority = 4;
  735.     
  736.     [[mySlider cell] setIntValue:priority];
  737.     [[priorityLevel cell] setIntValue:priority];
  738.  
  739. //    use mach call rather than unix - mach lets me increase priority!
  740. //    setpriority(PRIO_PROCESS, 0, priority);
  741.     cthread_priority(cthread_self(), priority, FALSE);
  742.  
  743.     return self;
  744. }
  745.  
  746. - changeSliderValue:sender
  747. {
  748.     priority = [[mySlider cell] intValue];
  749.     [[priorityLevel cell] setIntValue:priority];
  750.     return self;
  751. }
  752.  
  753. - saveSliderValue
  754. {
  755.     char str[50];
  756. //    setpriority(PRIO_PROCESS, 0, priority);
  757.     cthread_priority(cthread_self(), priority, FALSE);
  758.  
  759.     sprintf(str,"%d", priority);
  760.     NXWriteDefault([NXApp appName], "priority", str);
  761.     return self;
  762. }
  763.  
  764. - windowWillResize:sender toSize:(NXSize *)frameSize
  765. {
  766.     if (frameSize->width < 100) frameSize->width = 100;
  767.     if (frameSize->height < 100) frameSize->height = 100;
  768.     return self;
  769. }
  770.  
  771. - windowWillClose:sender
  772. {
  773.     [windMatrix selectCellAt:NOWINDOW :0];
  774.     [self perform:@selector(changeWindowType:) with:self
  775.         afterDelay:1 cancelPrevious:YES];
  776.     return nil;
  777. }
  778.  
  779. BStimeval currentTimeInMs()
  780. {
  781.     struct timeval curTime;
  782.     gettimeofday (&curTime, NULL);
  783.     return (curTime.tv_sec) * 1000 + curTime.tv_usec / 1000;
  784. }
  785.  
  786. //
  787. //  Additional methods to handle a common image object for views.
  788. //  Lennart Lovstrad, Rank Xerox EuroPARC, August 1991.
  789. //
  790.  
  791. - setImageFromFile: (const char *) filename
  792. {
  793.     [image free];
  794.  
  795.     image = [[NXImage alloc] initFromFile: filename];
  796.     if (image == nil)
  797.     {
  798.         NXRunAlertPanel([NXApp appName], NXLocalString("Could not open %s",0,0),
  799.                 NULL, NULL, NULL, filename);
  800.         image = nil;
  801.         //return nil;    //can't return, image is invalid
  802.     }
  803.     
  804.     return [self commonImageInit];
  805. }
  806.  
  807. - setImageFromName: (const char *) name
  808. {
  809.     [image free];
  810.     image = [[NXImage alloc] initFromSection: name];
  811.     
  812.     return [self commonImageInit];
  813. }
  814.  
  815. - commonImageInit
  816. {
  817.     [imageView setImage: image];
  818.     [imageView display];
  819.  
  820.     if ([spaceView respondsTo:@selector(setImage:)])
  821.         [spaceView setImage: image];
  822.  
  823.     if ([self backingTypeForView:spaceView] != NX_BUFFERED)
  824.     {
  825.         [spaceView fillBoundsWithBlack];
  826.         [spaceView display];
  827.     }
  828.  
  829.     return self;
  830. }
  831.  
  832. - getImageFile
  833. {
  834.     const char *filename;
  835.  
  836.     filename = NXGetDefaultValue([NXApp appName], "imageFile");
  837.     if (filename)
  838.         [self setImageFromFile: filename];
  839.     else [self setImageFromName: "defaultImage"];
  840.  
  841.     return self;
  842. }
  843.  
  844. - setImageFileFrom: sender
  845. {
  846.     id openPanel = [OpenPanel new];
  847.     const char *fileTypes[] = {"tiff", "eps", NULL};
  848.     
  849.     if ([openPanel runModalForTypes: fileTypes])
  850.     {
  851.         [self setImageFromFile: [openPanel filename]];
  852.         NXWriteDefault([NXApp appName], "imageFile", [openPanel filename]);
  853.     }
  854.  
  855.     [spaceView display];    //don't know why this is necessary...
  856.  
  857.     return self;
  858. }
  859.  
  860. // This should return a float between 0 and 1
  861. float frandom()
  862. {
  863.     float val = (random() & 0x7fffffff);
  864.     val /= 0x7fffffff;
  865.     return val;
  866. }
  867.  
  868. float randBetween(float a, float b)
  869. {
  870.     float val, scale, t;
  871.  
  872.     if (a > b)
  873.     {    t = a; a = b; b = t;
  874.     }
  875.     
  876.     scale = (b-a);
  877.     val = scale * frandom();
  878.     return (a + val);
  879. }
  880.  
  881. @end
  882.