NewCCursor.c

/*******************************************/
/*                                         */
/*  File:       NewCCursor.c               */
/*                                         */
/*  Program:    NewCCursor                 */
/*                                         */
/*  By:         Jason Hodges Harris        */
/*                                         */
/*  Version:    1.0.1                      */
/*                                         */
/*******************************************/
 
//  This Code snippet creates from scratch both Black & White 'CURS'
//  and color 'crsr' Cursors from PICT resources.
 
 
// Mac Toolbox headers
 
#ifndef __DESK__
#include <Desk.h>
#endif
 
#ifndef __DIALOGS__
#include <Dialogs.h>
#endif
 
#ifndef __DISKINIT__
#include <DiskInit.h>
#endif
 
#ifndef __EVENTS__
#include <Events.h>
#endif
 
#ifndef __FILES__
#include <Files.h>
#endif
 
#ifndef __FONTS__
#include <Fonts.h>
#endif
 
#ifndef __MEMORY__
#include <Memory.h>
#endif
 
#ifndef __MENUS__
#include <Menus.h>
#endif
 
#ifndef __QDOFFSCREEN__
#include <QDOffscreen.h>
#endif
 
#ifndef __RESOURCES__
#include <Resources.h>
#endif
 
#ifndef __SCRIPT__
#include <Script.h>
#endif
 
#ifndef __SEGLOAD__
#include <SegLoad.h>
#endif
 
#ifndef __STANDARDFILE__
#include <StandardFile.h>
#endif
 
#ifndef __STRING__
#include <String.H>
#endif
 
#ifndef __TEXTEDIT__
#include <TextEdit.h>
#endif
 
#ifndef __TEXTUTILS__
#include <TextUtils.h>
#endif
 
#ifndef __TOOLUTILS__
#include <ToolUtils.h>
#endif
 
#ifndef __TYPES__
#include <Types.h>
#endif
 
#ifndef __WINDOWS__
#include <Windows.h>
#endif
 
 
#define HiWrd(aLong)    (((aLong) >> 16) & 0xFFFF)
#define LoWrd(aLong)    ((aLong) & 0xFFFF)
 
 
// menu defs
 
#define mApple      128
#define iAbout      1
 
#define mFile       129
#define iQuit       1
 
#define mTest       130
#define iBWCursor   1
#define iCCursor    2
 
 
// Global variables
 
CCrsrHandle     gNewCCursorHndl = nil;
Cursor          gNewCursor;
Boolean         gQuitFlag = false,
                gCustomCursor = false,
                gCursorDepth = 0;
 
 
// function prototypes
 
void    InitToolbox(void);
void    MainEventLoop(void);
void    HandleKeyPress(EventRecord *myEvent); 
void    HandleMenuCommand(long menuResult);
void    CreateCursor(short depth);
 
 
 
// main program function
 
int main()
{
    InitToolbox() ;
    MainEventLoop();
    return 0;
}
 
 
 
// toolbox initialisation
 
void InitToolbox()
{
    OSErr       retCode;
    long        gestResponse;
    Handle      menuBar = nil;
    EventRecord myEvent;
    short       count;
 
 
    MaxApplZone();
    InitGraf((Ptr) &qd.thePort);
    InitFonts();
    InitWindows();
    InitMenus();
    TEInit();
    InitDialogs(0L);
    InitCursor();
 
    menuBar = GetNewMBar(128);
    if (menuBar == nil)
         ExitToShell();
    SetMenuBar(menuBar);
    DisposHandle(menuBar);
    AddResMenu(GetMHandle(mApple), 'DRVR'); // Add DA names to Apple menu, ID 128
    DrawMenuBar();
}
 
 
// Event processing
 
void MainEventLoop()
{
    EventRecord     myEvent;
    WindowPtr       window;
    short           thePart;
    Rect            screenRect;
    Point           aPoint = {100, 100};
    GrafPtr         oldPort ;
 
    while( !gQuitFlag )
    {
        if (WaitNextEvent( everyEvent, &myEvent, 0, nil ))
        {
            switch (myEvent.what)
            {
                case mouseDown:
                    thePart = FindWindow( myEvent.where, &window );
                    switch( thePart )
                    {
                        case inMenuBar: 
                            HandleMenuCommand(MenuSelect(myEvent.where));
                        break;
                        
                        case inDrag:
                        break ;
                    
                        case inContent:
                        break ;
                    
                        case inGoAway:
                        break ;
                            
                        default:
                        break ;
                    }
                    break ;
                        
                case updateEvt:
                break ;
                    
                case keyDown:
 
                case autoKey:
                    HandleKeyPress(&myEvent);
                break;
                    
                case diskEvt:
                    if ( HiWrd(myEvent.message) != noErr ) 
                        (void) DIBadMount(aPoint, myEvent.message);
                break;
                case osEvt:
                case activateEvt:
                    // restore custom cursor on application activate event
                    if (myEvent.message>>24 == resumeFlag)
                    {
                        if (gCustomCursor && gCursorDepth == 1)
                            SetCursor(&gNewCursor);
                        else if (gCustomCursor && gCursorDepth == 8)
                            SetCCursor(gNewCCursorHndl);
                    }
                break;
            }
        }
    }
}
 
 
void HandleKeyPress(EventRecord *myEvent)
{
    char    key;
    long    lByteCnt ;
 
    key = myEvent->message & charCodeMask;
    
    if ( myEvent->modifiers & cmdKey )  //  Cmd key down?
    {
        HandleMenuCommand(MenuKey(key));
    } 
}
 
 
 
// process menubar commands
 
void HandleMenuCommand(long menuResult)
{
    short           menuID;
    short           menuItem;
    Str255          daName;
    DialogPtr       theDialog ; 
    short           itemHit ;
    Rect            cursorRect = {0,0,16,16};
 
    menuID = HiWrd(menuResult);
    menuItem = LoWrd(menuResult);
    switch ( menuID )
    {
        case mApple:
            switch ( menuItem )
            {
                case iAbout:
                    theDialog = GetNewDialog ( 128, nil, (WindowPtr)-1 );
                    do {
                        ModalDialog ( nil, &itemHit );
                    } while( itemHit != ok ) ;
                    DisposDialog ( theDialog );
                break;
                    
                default:
                    GetItem(GetMHandle(mApple), menuItem, daName);
                    (void) OpenDeskAcc(daName);
                break;
            }
            break;
        case mFile:
            switch ( menuItem )
            {
                case iQuit:
                    gQuitFlag = true;
                break;
            }
            break;
        case mTest: 
            switch (menuItem)
            {
                case iBWCursor:
                    CreateCursor(1);        // create 1 bit cursor from PICT rsrc
                break ;
                case iCCursor:
                    CreateCursor(8);        // create 8 bit cursor from PICT rsrc
                break;
            }
            break;
    }
    HiliteMenu(0);      // Unhighlight whatever MenuSelect or MenuKey hilited
}
 
 
// function to create from scratch either a 1 bit CURS or an 8 bit crsr 
// See Inside Macintosh, "Imaging With QuickDraw", Ch 8 Cursor Utilities,
// for an in depth explanation of the crsr and CURS structures.
 
void    CreateCursor(short depth)
{
    PixMapHandle    myPixmap = nil;
    GDHandle        oldDevice = nil;
    PicHandle       cursorPict = nil;
    GWorldPtr       myGWorldPtr = nil,
                    oldPort = nil;
    Ptr             cursorBaseAddr = nil;
    QDErr           myError;
    Rect            cursorRect = {0,0,16,16};
    short           pixRowbytes,
                    count,
                    count2,
                    maskInfo,
                    tempInfo;
    char            myAddrMode = true32b;
    
    GetGWorld(&oldPort,&oldDevice);
    gCursorDepth = depth;
    switch (depth)
    {
        case 1:
            cursorPict=GetPicture(1000);    // 16*16 1 bit B/W PICT to be used as cursor
        break;
        case 8:
            cursorPict=GetPicture(1001);    //16*16 8 bit color PICT to be used as cursor
        break;
    }
    if (cursorPict==nil)
    {
        // handle GWorld creation errors here
        DebugStr("\pFailed to get PICT rsrc");
        return;
    }
    // create GWorld to temp hold of PICT rsrc for conversion.
    myError=NewGWorld(&myGWorldPtr,depth,&cursorRect,nil,nil,0);
    if (myError)
    {
        // handle GWorld creation errors here
        DebugStr("\pFailed to allocate GWorld.");
        return;
    }
    myPixmap = GetGWorldPixMap(myGWorldPtr);    // get GWorld PixMap
    SwapMMUMode (&myAddrMode);                  // switch to 32 bit mode
    LockPixels(myPixmap);                       // lock down PixMap
    SetGWorld(myGWorldPtr,nil);                 // set port to GWorld 
    HLockHi((Handle)cursorPict);
    DrawPicture(cursorPict,&cursorRect);        // draw PICT to GWorld
    HUnlock((Handle)cursorPict);
    ReleaseResource((Handle)cursorPict);        // release PICT as no longer required
    GetGWorld(&oldPort,&oldDevice);             // reset port
    pixRowbytes = (**myPixmap).rowBytes & 0x3FFF;   // get GWorld PixMap rowBytes
    cursorBaseAddr = (**myPixmap).baseAddr;     // get GWorld PixMap base addr
    switch (depth)
    {
        case 1:                                 // B/W Cursor
            for (count=0;count<16;count++)
            {
                memcpy (&gNewCursor.data[count],cursorBaseAddr,2);  // copy pict data into cursor struct
                gNewCursor.mask[count] = gNewCursor.data[count];    // mask = data 
                cursorBaseAddr+=pixRowbytes;
            }
            gNewCursor.hotSpot.v = 15;
            gNewCursor.hotSpot.h = 0;
            gCustomCursor = true;
            SetCursor(&gNewCursor);
        break;
        case 8:                                         // Color Cursor
            // create new Handle to hold Color Table
            if (gNewCCursorHndl !=nil)
            {
                // dispose of old handles if already allocated. Stops memory leaks.
                DisposeHandle((Handle)(**gNewCCursorHndl).crsrData);
                DisposeHandle((Handle)(**(**gNewCCursorHndl).crsrMap).pmTable);
                DisposeHandle((Handle)(**gNewCCursorHndl).crsrMap);
                DisposeHandle((Handle)gNewCCursorHndl);
            }
            gNewCCursorHndl = (CCrsrHandle) NewHandle(sizeof(CCrsr));   // create crsr handle
            (**gNewCCursorHndl).crsrType = 0x8001;  // color cursor
            (**gNewCCursorHndl).crsrMap = NewPixMap();
            (**(**gNewCCursorHndl).crsrMap).bounds = cursorRect;
            (**(**gNewCCursorHndl).crsrMap).rowBytes = 16;      // 16 (8 bits deep) pixels wide
            (**(**gNewCCursorHndl).crsrMap).pixelSize = 8;      // 8 bits deep  
            SetHandleSize((Handle)(**(**gNewCCursorHndl).crsrMap).pmTable,(sizeof(ColorTable)+(sizeof(ColorSpec)*256)));
 
            // copy color table from Pict GWorld to Color Cursor
            HLock((Handle)(**(**gNewCCursorHndl).crsrMap).pmTable);
            HLock((Handle)(**myPixmap).pmTable);
            BlockMove((*(**myPixmap).pmTable),
                (*(**(**gNewCCursorHndl).crsrMap).pmTable),
                (sizeof(ColorTable)+(sizeof(ColorSpec)*256)));
            HUnlock((Handle)(**(**gNewCCursorHndl).crsrMap).pmTable);
            HUnlock((Handle)(**myPixmap).pmTable);
            CTabChanged((**(**gNewCCursorHndl).crsrMap).pmTable);
            (**gNewCCursorHndl).crsrData = NewHandle(256);
            HLock((**gNewCCursorHndl).crsrData);
 
            // copy data from PICT into crsr to build CCursor 
            for (count=0;count<16;count++)
            {
                memcpy ((*(**gNewCCursorHndl).crsrData)+(16*count),cursorBaseAddr,16);  // get data type
                cursorBaseAddr+=pixRowbytes;
            }
            (**gNewCCursorHndl).crsrXValid = 0; // Cursor to be re expanded
            (**gNewCCursorHndl).crsrXHandle = 0; // reserved
 
            // create crsr mask
            for (count=0;count<16;count++)
            {
                maskInfo=0;
                for (count2=0;count2<16;count2++)
                {
                    tempInfo = *((*(**gNewCCursorHndl).crsrData)+(16*count+count2));
                    if (tempInfo)   // if image byte has value mask relevant bit
                        maskInfo = maskInfo | 1<<(15-count2);
                }
                (**gNewCCursorHndl).crsrMask[count] = maskInfo; // place current line of mask into struct
            }
            HUnlock((**gNewCCursorHndl).crsrData);
            (**gNewCCursorHndl).crsrHotSpot.v = 15;
            (**gNewCCursorHndl).crsrHotSpot.h = 0;
            (**gNewCCursorHndl).crsrXTable = 0; // reserved
            gCustomCursor = true;
            SetCCursor(gNewCCursorHndl);
        break;
    }
    UnlockPixels(myPixmap);
    DisposeGWorld(myGWorldPtr);     // Clean up deallocation of GWorld
    SwapMMUMode (&myAddrMode);      // restore addressing mode
}