home *** CD-ROM | disk | FTP | other *** search
/ develop, the CD; issue 1 / Apple_Develop_1989.bin / Compatibility / compatibility.c < prev    next >
C/C++ Source or Header  |  1989-10-16  |  4KB  |  133 lines

  1. #include <Events.h>
  2. #include <OSEvents.h>
  3. #include <OSUtils.h>
  4. #include <Dialogs.h>
  5. #include <Packages.h>
  6. #include <Retrace.h>
  7. #include <Traps.h>
  8.  
  9. #define    INTERVAL        6
  10. #define rInfoDialog    140
  11. #define rStatTextItem    2
  12.  
  13. /*
  14.  *  These are globals which will be referenced from our VBL Task
  15.  */
  16. long    gCounter;        /* Counter incremented each time our VBL gets called */
  17.  
  18. /*
  19.  *  Define a struct to keep track of what we need.  Put theVBLTask into the 
  20.  *  struct first because its address will be passed to our VBL task in A0
  21.  */
  22. struct VBLRec {
  23.     VBLTask    theVBLTask;    /* the VBL task itself */
  24.     long    VBLA5;        /* saved CurrentA5 where we can find it */
  25. };
  26. typedef struct VBLRec VBLRec, *VBLRecPtr;
  27.  
  28. /*
  29.  *    GetVBLRec returns the address of the VBLRec associated with our VBL task.
  30.  *  This works because on entry into the VBL task, A0 points to the theVBLTask
  31.  *  field in the VBLRec record, which is the first field in the record and 
  32.  *  is the address we return.  Note that this method works whether the VBLRec
  33.  *  is allocated globally, in the heap (as long as the record is locked in 
  34.  *  memory) or if it is allocated on the stack as is the case in this example.
  35.  *  In the latter case this is OK as long as the procedure which installed the
  36.  *  task does not exit while the task is running.  This trick allows us to get
  37.  *  to the saved A5, but it could also be used to get to anything we wanted to
  38.  *  store in the record.
  39.   */
  40. VBLRecPtr GetVBLRec ()
  41.     = 0x2008;            /* MOVE.L    A0,D0 */
  42.  
  43. /*
  44.  *  DoVBL is called only by StartVBL ()
  45.  */
  46. void DoVBL (VRP)
  47. VBLRecPtr    VRP;
  48. {
  49.     gCounter++;                        /* Show we can set a global */
  50.     VRP->theVBLTask.vblCount = INTERVAL;    /* Set ourselves to run again */
  51. }
  52.  
  53. /*
  54.  *  This is the actual VBL task code.  It uses GetVBLRec to get our VBL record
  55.  *  and properly set up A5.  Having done that, it calls DoVBL to increment a
  56.  *  global counter and sets itself to run again.  Because of the vagaries of 
  57.  *  MPW C 3.0 optimization, it calls a separate routine to actually access 
  58.  *  global variables.  See Tech Note #208 - "Setting and Restoring A5" for the 
  59.  *  reasons for this, as well as for a description of SetA5.
  60.  */
  61. void StartVBL ()
  62. {
  63.     long        curA5;
  64.     VBLRecPtr    recPtr;
  65.     
  66.     recPtr = GetVBLRec ();        /* First get our record */
  67.     curA5 = SetA5 (recPtr->VBLA5);/* Get the saved A5 */
  68.     
  69.                             /* Now we can access globals */
  70.     DoVBL (recPtr);            /* Call another routine to do actual work */
  71.     
  72.     (void) SetA5 (curA5);        /* Restore old A5 */
  73. }
  74.  
  75. /*
  76.  *  InstallVBL creates a dialog just to demonstrate that the global variable
  77.  *  is being updated by the VBL Task.  Before installing the VBL, we store
  78.  *  our A5 in the actual VBL Task record, using SetCurrentA5 described in
  79.  *  Tech Note #208.  We'll run the VBL, showing the counter being incremented,
  80.  *  until the mouse button is clicked.  Then we remove the VBL Task, close the
  81.  *  dialog, and remove the mouse down events to prevent the application from
  82.  *  being inadvertently switched by MultiFinder.
  83.  */
  84. void InstallCVBL ()
  85. {
  86.     VBLRec            theVBLRec;
  87.     DialogPtr            infoDPtr;
  88.     DialogRecord        infoDStorage;
  89.     Str255            numStr;
  90.     OSErr            theErr;
  91.     Handle            theItemHandle;
  92.     short            theItemType;
  93.     long            lCounter;
  94.     Rect                theRect;
  95.  
  96.     gCounter = 0;                /* Initialize our global counter */
  97.     infoDPtr = GetNewDialog (rInfoDialog, (Ptr) &infoDStorage, (WindowPtr) -1);
  98.     DrawDialog (infoDPtr);
  99.     GetDItem (infoDPtr, rStatTextItem, &theItemType, &theItemHandle, 
  100.         &theRect);
  101.     
  102.     /* 
  103.      *  Store the current value of A5 in the MyA5 field.  For more
  104.      *  information on SetCurrentA5, see Tech Note #208 - "Setting and
  105.      *  Restoring A5".
  106.      */
  107.     theVBLRec.VBLA5 = SetCurrentA5 ();
  108.     /* Set the address of our routine */
  109.     theVBLRec.theVBLTask.vblAddr = (VBLProcPtr) StartVBL;
  110.     theVBLRec.theVBLTask.vblCount = INTERVAL; /* Frequency of task, in ticks */
  111.     theVBLRec.theVBLTask.qType = vType;      /* qElement is a VBL task */
  112.     theVBLRec.theVBLTask.vblPhase = 0;
  113.     
  114.     /* Now install the VBL task */
  115.     theErr = VInstall ((QElemPtr)&theVBLRec.theVBLTask);
  116.     
  117.     if (!theErr) {
  118.         lCounter = -1;        /* Force the initial update */
  119.         do {
  120.             if (lCounter != gCounter) {
  121.                 NumToString (gCounter, numStr);
  122.                 SetIText (theItemHandle, numStr);
  123.                 lCounter = gCounter;
  124.             }
  125.         } while (!Button ());
  126.         theErr = VRemove ((QElemPtr)&theVBLRec.theVBLTask);    /* Remove it when done */
  127.     }
  128.     
  129.     /* Finish up */
  130.     CloseDialog (infoDPtr);                /* Get rid of our dialog */
  131.     FlushEvents (mDownMask, 0);            /* Flush all mouse down events */
  132. }
  133.