home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-09-09 | 11.0 KB | 357 lines | [TEXT/KAHL] |
- ///////////////////////////////////////////////////////////////////////////////
- //
- // SpinCursor Library
- // ------------------
- //
- // Add this library to your project, and #include "SpinCursor.h", and you
- // too can have smooth, spinning cursors in your programs!
- //
- //
- // NOTICE:
- //
- // There is no legal problem if you include this library or header file in
- // your own projects. The only problem that may occur is if you attempt
- // to sell any or all of this code, or if you edit it and repost it anywhere.
- //
- // If you distribute this code, which I strongly urge, please leave the
- // folders, files, and libraries untouched. If you want to mess around, make
- // a duplicate copy and edit that one.
- //
- // If you have questions, comments, or suggestions, please feel free to write
- // me (although I should mention that this address is only valid until May
- // of 1993; after that I'm a certified gradge-U-aite of the University of
- // Michigan.
- //
- // EMAIL: rudman@engin.umich.edu
- //
- // Modifications:
- //
- // 09/09/92 DER Added global installation variable to avoid multiple
- // installations of a cursor task.
- //
- ///////////////////////////////////////////////////////////////////////////////
- #include "CSpinner.h"
-
- CursorTask gCursTask; /* Global structure */
- Boolean gCursInstalled = false; /* installation global */
-
- /* --------- */
- /* SetCQDVar */
- /* --------- */
- /*
- This assertains whether or not Color QuickDraw is available.
- Obviously, this affects whether or not we can utilize
- color cursor calls. We store the results in the global
- structure so that we can access it during the main calls.
- */
-
- void
- SetCQDVar (void)
- {
- OSErr err;
- long int result;
- SysEnvRec sysEnv;
-
- if (WeCanUseGestalt ()) {
- err = Gestalt (gestaltQuickdrawVersion, &result);
- gCursTask.cQD = (result >= 0x100);
- }
- else {
- err = SysEnvirons (1, &sysEnv);
- gCursTask.cQD = sysEnv.hasColorQD;
- }
- }
-
- /* ---------------- */
- /* BeginResSpinning */
- /* ---------------- */
- /*
- This is a higher level call to BeginSpinning() which will
- utilize a 'SPIN' resource of resID. All color checking
- and error checking is handled within this call, and the
- error is returned in the form of a CursErr (see the
- header file for #defines). A call to BeginResSpinning()
- should be accompanied by a later call to StopSpinning().
- */
-
- CursErr
- BeginResSpinning (short int resID)
- {
- Handle spinH;
- short int attrs;
-
- Boolean color;
- short int initResID;
- short int numCursors;
- short int initDelay;
- short int frequency;
-
- if (gCursInstalled) /* if we are already installed, */
- return (cursAlreadyInstalled); /* return an error! */
-
- gCursInstalled = false; /* make sure we know we are not in yet */
-
- spinH = GetResource ('SPIN', resID); /* grab the 'SPIN' resource */
-
- if (spinH == nil) /* if we grabbed a nil handle, */
- return (cursResNotFound); /* return an error */
-
- if (ResError () != noErr) /* if we grabbed a handle but */
- return (cursSpinCursResErr); /* had an error, return it */
-
- attrs = GetResAttrs (spinH); /* store original attribs */
- HLock (spinH); /* lock the handle down */
- HNoPurge (spinH); /* make it unpurgeable */
-
- BlockMove (&((*spinH)[0]), &color, 1); /* pull 1 byte */
- BlockMove (&((*spinH)[2]), &initResID, 2); /* pull 2 bytes */
- BlockMove (&((*spinH)[4]), &numCursors, 2); /* pull 2 bytes */
- BlockMove (&((*spinH)[6]), &initDelay, 2); /* pull 2 bytes */
- BlockMove (&((*spinH)[8]), &frequency, 2); /* pull 2 bytes */
-
- SetResAttrs (spinH, attrs); /* restore original attribs */
- ReleaseResource (spinH); /* let go of the resource */
-
- if (ResError () != noErr) /* if we get any errors, */
- return (cursSpinCursResErr); /* return them */
-
- return (BeginSpinning (color, initResID,
- numCursors, initDelay, frequency)); /* call BeginSpinning () */
- }
-
- /* ------------- */
- /* BeginSpinning */
- /* ------------- */
- /*
- This call is identical to BeginResSpinning(), except that you
- specify all of the cursor information yourself. Again, all
- error handling is done for you; it will return a CursErr, but
- you really need not worry about this.
- */
-
- CursErr
- BeginSpinning ( Boolean color,
- short int initResID,
- short int numCursors,
- short int initDelay,
- short int frequency)
- {
- OSErr err; /* returnable error */
- short int i; /* dummy counter */
- CursorList *cp; /* pointing index */
-
- if (gCursInstalled) /* if we are already installed, */
- return (cursAlreadyInstalled); /* return an error! */
-
- gCursInstalled = false; /* we are not installed yet */
- SetCQDVar (); /* set our CQD variable */
- gCursTask.grec.cursors =
- (CursorList *)NewPtr (sizeof (CursorList)); /* allocate cursor memory */
-
- /* now set up the first field */
-
- if (gCursTask.cQD && color) {
- (gCursTask.grec.cursors)->curs = (CursHandle)GetCCursor (initResID);
- }
- else {
- (gCursTask.grec.cursors)->curs = GetCursor (initResID);
- }
-
- if ((gCursTask.grec.cursors)->curs == nil) /* if we did not get a cursor, */
- return (cursResNotFound); /* return an error */
-
- HNoPurge ((Handle)(gCursTask.grec.cursors)->curs); /* set it unpurgeable */
- HLockHi ((Handle)(gCursTask.grec.cursors)->curs); /* and lock it high in memory */
-
- gCursTask.grec.frame = cp = gCursTask.grec.cursors; /* set the frame to the first field */
-
- for (i=1; i < numCursors; i++) { /* cycle through the rest */
-
- cp->nextCurs = (struct CursorList *)NewPtr (sizeof (CursorList));
- cp = (CursorList *)cp->nextCurs; /* allocate cursor space and jump */
-
- if ((MemError () != noErr) || (cp == nil)) /* check for any errors, */
- return (cursMemReqFailed); /* and return them */
-
- if (gCursTask.cQD && color) {
- cp->curs = (CursHandle)GetCCursor (initResID+i);/* color cursors if desired */
- }
- else {
- cp->curs = GetCursor (initResID+i); /* black and white otherwise */
- }
-
- if (cp->curs == nil) /* did we get the cursor */
- return (cursResNotFound); /* if no, return error */
-
- HNoPurge ((Handle)cp->curs); /* force it unpurgeable */
- HLockHi ((Handle)cp->curs); /* and lock it high */
- }
-
- cp->nextCurs = nil; /* set the last field; EOL */
-
- gCursTask.grec.frequency = frequency; /* set the frequency field */
- gCursTask.color = color; /* set the color field */
-
- gCursTask.vblTask.qType = vType; /* set up the VBL task record */
- gCursTask.vblTask.vblAddr = (ProcPtr)SpinCursor;
- gCursTask.vblTask.vblCount = initDelay;
- gCursTask.vblTask.vblPhase = 0;
-
- err = VInstall ((QElemPtr)&gCursTask.vblTask); /* install the VBL task */
-
- if (err)
- return (cursVBLReqFailed); /* if errors, return them, else */
- else {
- gCursInstalled = true; /* declare the task installed */
- return (cursNoErr); /* and return no error */
- }
- }
-
- /* ---------- */
- /* SpinCursor */
- /* ---------- */
- /*
- This is the meat and bones of the spinning cursor calls.
- When the VBL task count (vblCount) goes to zero, the
- Vertical Retrace Manager will call SpinCursor(). Our job
- will be to set the cursor to the current frame, and then
- to advance the frame. The thing to remember is that we
- are executed during interrupt, and we are not allowed to
- use Memory Manager calls... as well as a billion other
- things.
-
- Another cool thing to note is that at the time of our
- interrupt, a pointer to the installed VBL task will be
- placed in A0. Since we installed with some more globals
- attached, these will also be available to us; kind of
- a sneaky way around the messed up A5 problem.
-
- Also remember that the vblCount is zero at this time. If
- we leave this function without returning a nonzero value,
- the task will never return to SpinCursor again. So, we
- articulately return the vblCount to frequency, which is
- why the task happens so regulary...
- */
-
- pascal void
- SpinCursor (void)
- {
- CursorTaskPtr taskPtr;
- Boolean busy;
-
- asm {
- move.l a0, taskPtr; /* grab our globals from A0 */
- }
-
- busy = (*(Boolean *)CrsrBusy); /* determine the cursor state */
-
- if (!busy) { /* if it is available to us */
- /* set the cursor and frame advance */
-
- if (taskPtr->color && taskPtr->cQD) {
- SetCCursor ((CCrsrHandle)(taskPtr->grec.frame)->curs);
- }
- else {
- SetCursor ((CursPtr)(*((taskPtr->grec.frame)->curs)));
- }
-
- taskPtr->grec.frame = (CursorList *)(taskPtr->grec.frame)->nextCurs;
-
- if (taskPtr->grec.frame == nil) /* if at EOL, */
- taskPtr->grec.frame = taskPtr->grec.cursors; /* return us back to first frame */
-
- }
-
- taskPtr->vblTask.vblCount = taskPtr->grec.frequency; /* restore the VBL task */
- }
-
- /* ------------ */
- /* StopSpinning */
- /* ------------ */
- /*
- When you have finished whatever task you were doing when
- you decided to BeginSpinning(), call StopSpinning() to
- end the spinning cursor, and to deallocate the memory and
- remove the VBL task. It would be unwise to exit your
- program without removing the VBL task. Why? Because if
- you do not do it, who will? Of course, the vblCount will
- zero out and the call to SpinCursor will never happen,
- but hey.. we program here, right?
- */
-
- CursErr
- StopSpinning (void)
- {
- OSErr err;
- short int i;
- CursorList *cp, *temp;
-
- if (!gCursInstalled) /* if we were not installed, */
- return (cursTaskNotInstalled); /* alert them and exit */
-
- err = VRemove ((QElemPtr)&gCursTask.vblTask); /* remove the VBL task */
-
- cp = gCursTask.grec.cursors; /* set the pointing index */
-
- while (cp) { /* while the index is not empty, */
-
- HUnlock ((Handle)(cp->curs)); /* unlock the cursors */
- HPurge ((Handle)(cp->curs)); /* make them purgeable */
- /* and dispose of them */
-
- if (gCursTask.color && gCursTask.cQD) {
- DisposCCursor ((CCrsrHandle)(cp->curs));
- err = noErr;
- }
- else {
- ReleaseResource ((Handle)(cp->curs));
- err = ResError ();
- }
-
- if (err != noErr) /* any errors, we will return */
- return (cursCouldNotRelease);
-
- temp = (CursorList *)cp->nextCurs; /* set a pointer to the next field */
- DisposPtr ((Ptr)cp); /* deallocate the current index */
- err = MemError (); /* grab any errors */
-
- if (err != noErr) /* and return them */
- return (err);
- cp = temp; /* set the index to the next field */
- }
-
- InitCursor (); /* restore the cursor to an arrow */
- return (cursNoErr); /* and return no error */
- }
-
- Boolean
- WeCanUseGestalt (void)
- {
- return (IsThisTrapAvailable (_Gestalt));
- }
-
- Boolean
- IsThisTrapAvailable (unsigned long int trap)
- {
- TrapType trapType = ToolTrap;
- unsigned long int numToolBoxTraps;
-
- if (NGetTrapAddress (_InitGraf, ToolTrap) ==
- NGetTrapAddress (0xAA6E, ToolTrap))
- numToolBoxTraps = 0x200;
- else
- numToolBoxTraps = 0x400;
-
- if (BitAnd (trap, 0x0800) > 0)
- trapType = ToolTrap;
- else
- trapType = OSTrap;
-
- if (trapType == ToolTrap) {
- trap = BitAnd (trap, 0x07FF);
- if (trap >= numToolBoxTraps)
- trap = _Unimplemented;
- }
- return (NGetTrapAddress(trap, trapType) !=
- NGetTrapAddress(_Unimplemented, ToolTrap));
- }