Src/SCSIAsyncSampleMain.c

/*                              ScsiSimpleSample.c                              */
/*
 * ScsiSimpleSample.c
 * Copyright © 1992-93 Apple Computer Inc. All Rights Reserved.
 *
 * Edit history:
 *  1.0     MM      First release
 *  1.0.1   MM      Added dialog for timeout and explicit display of "asych"
 *                  No substantative changes.
 *  1.0.2   MM      Removed references to the message byte field as it is
 *                  no longer returned by the asynchronous SCSI Manager.
 */
#define EXTERN
#include    "SCSIAsyncSample.h"
#include    <Packages.h>
#include    <Desk.h>
#include    <OSEvents.h>
#include    <GestaltEqu.h>
#include    <Errors.h>
#pragma segment MainCode
 
void                                main(void);
void                                EventLoop(void);
void                                DoMouseEvent(void);
void                                DoContentClick(
        WindowPtr                       theWindow
    );
void                                DoCommand(
        WindowPtr                       theWindow,
        long                            menuChoice
    );
void                                DoWindowKeyDown(
        WindowPtr                       theWindow
    );
void                                SetupEverything(void);
void                                AdjustMenus(void);
void                                AdjustEditMenu(
        Boolean                         isDeskAccessory
    );
void                                SetupMenus(void);
void                                BuildWindow(void);
void                                DecorateDisplay(
        WindowPtr                       theWindow,
        Boolean                         redraw
    );
void                                DrawWindow(
        WindowPtr                       theWindow
    );
void                                DoAbout(void);
void                                DoPageSetup(void);
void                                HexToString(
        unsigned long                   value,
        short                           hexDigits,
        Str255                          result
    );
Boolean                             HexToNum(
        ConstStr255Param                hexString,
        unsigned long                   *result
    );
 
void                                SetupAnimatedCursor(
        short                           acurResID
    );
void                                SpinCursor(void);
Boolean                             IsVirtualMemoryRunning(void);
 
 
#define IsOurWindow(theWindow)  ((theWindow) == gMainWindow)
 
void
main(void)
{
        void                        *vmStackTop;
        short                       i;
        
        SetupEverything();
        if (AsyncSCSIPresent() == FALSE
         || GetHostBusCount(&gMaxHostBus) != noErr) {
            InitCursor();
            StopAlert(ALRT_NoNewSCSI, NULL);
            ExitToShell();
        }
        else if (MicrosecondTrapPresent() == FALSE)
            FatalError(unimpErr, "\pNo timer support");
        else {
            GetDevicesToTest();
            BuildWindow();
            DisplayTestParameters();
            SetupAnimatedCursor(ACUR_Animator);
            if (gVirtualMemoryEnabled) {
                gVMHoldRecord[kVMFunction].ptr = (void *) VMStartMarker;
                gVMHoldRecord[kVMFunction].size = 
                    ((unsigned long) VMEndMarker) - ((unsigned long) VMStartMarker);
                gVMHoldRecord[kVMStack].ptr = (void *) &vmStackTop;
                gVMHoldRecord[kVMStack].size = kVMStackSize;
                for (i = kVMFunction; i <= kVMStack; i++) {
                    if (HoldMemory(gVMHoldRecord[i].ptr, gVMHoldRecord[i].size) != noErr)
                        gVMHoldRecord[i].ptr = NULL;
                }
            }
            while (gQuitNow == FALSE) {
                EventLoop();
            }
        }
        /* KillActiveDevices */
        for (i = kVMFunction; i <= kVMStack; i++) {
            if (gVMHoldRecord[i].ptr != NULL)
                UnholdMemory(gVMHoldRecord[i].ptr, gVMHoldRecord[i].size);
        }
        /* Release memory */
        ExitToShell();
}
 
void
BuildWindow()
{
        short                   fontSize;
        short                   fontNumber;
        Rect                    viewRect;
        
        fontSize = 10;
        GetFNum("\pCourier", &fontNumber);
        if (RealFont(fontNumber, fontSize) == FALSE)
            fontNumber = applFont;
        viewRect = qd.screenBits.bounds;
        viewRect.top += (GetMBarHeight() * 2);
        viewRect.bottom -= 4;
        viewRect.left += 4;
        viewRect.right = (width(viewRect) / 2);
        gMainWindow = NewWindow(
                        NULL,
                        &viewRect,
                        "\pSCSI Simple Sample",
                        TRUE,
                        zoomDocProc,
                        (WindowPtr) -1L,
                        TRUE,               /* Has GoAway box       */
                        0                   /* No refCon            */
                    );
        if (gMainWindow == NULL) {
            SysBeep(10);
            ExitToShell();
        }
        SetPort(gMainWindow);
        viewRect = gMainWindow->portRect;
        viewRect.right -= kScrollBarOffset;
        viewRect.bottom -= kScrollBarOffset;
        gLogListHandle = CreateLog(
                    &viewRect,
                    fontNumber,
                    fontSize,
                    kLogLines
                );
        if (gLogListHandle == NULL) {
            SysBeep(10);
            ExitToShell();
        }
}
 
void
EventLoop(void)
{
        long                            menuChoice;
        register WindowPtr              theWindow;
        GrafPtr                         savePort;
        Boolean                         isActivating;
        static Boolean                  testingStarted = FALSE;
        
        if (gUpdateMenusNeeded) {
            gUpdateMenusNeeded = FALSE;
            AdjustMenus();
        }
        WaitNextEvent(
            everyEvent,
            &EVENT,
            (gInForeground) ? 10L : 60L,
            NULL
        );
        theWindow = FrontWindow();
        switch (EVENT.what) {
        case nullEvent:
            break;
        case keyDown:
        case autoKey:
            if ((EVENT.message & charCodeMask) == '.'
             && (EVENT.modifiers & cmdKey) != 0) {
                FlushEvents(keyDown | autoKey, 0);
                gStopNow = TRUE;
            }
            else if ((EVENT.modifiers & cmdKey) != 0) {
                if (EVENT.what == keyDown) {
                    menuChoice = MenuKey(EVENT.message & charCodeMask);
                    if (HiWord(menuChoice) != 0)
                        DoCommand(theWindow, menuChoice);
                    else if (IsOurWindow(theWindow)) {
                        DoWindowKeyDown(theWindow);
                    }
                }
            }
            else if (IsOurWindow(theWindow)) {
                DoWindowKeyDown(theWindow);
            }
            break;
        case mouseDown:
            DoMouseEvent();
            break;
        case updateEvt:
            theWindow = (WindowPtr) EVENT.message;
            GetPort(&savePort);
            SetPort(theWindow);
            BeginUpdate(theWindow);
            EraseRect(&theWindow->portRect);
            DrawControls(theWindow);
            DrawGrowIcon(theWindow);
            if (IsOurWindow(theWindow))
                DrawWindow(theWindow);
            EndUpdate(theWindow);
            SetPort(savePort);
            break;
        case activateEvt:
            theWindow = (WindowPtr) EVENT.message;
            isActivating = ((EVENT.modifiers & activeFlag) != 0);
            goto activateEvent;
            break;
        case osEvt:
            switch (((unsigned long) EVENT.message) >> 24) {
            case mouseMovedMessage:
                break;
            case suspendResumeMessage:
                isActivating = ((EVENT.message & 0x01) != 0);
activateEvent:      if (isActivating) {
                    /*
                     * Activate this window. Activate events define theWindow
                     * from the event record, while suspend/resume uses the
                     * pre-set FrontWindow value.
                     */
                    SelectWindow(theWindow);
                    (void) TEFromScrap();
                }
                if (IsOurWindow(theWindow) && gLogListHandle != NULL)
                    LActivate(isActivating, gLogListHandle);
                else {
                    /* Desk accessory or what? */
                }
                gInForeground = isActivating;
                gUpdateMenusNeeded = TRUE;
                break;
            }
            break;
        }
        if (gStopNow == FALSE && gQuitNow == FALSE) {
            SpinCursor();
            if (testingStarted)
                ContinueTesting();
            else {
                testingStarted = TRUE;
                StartTesting();
            }
        }
}
 
/*
 * DoMouseEvent
 * The user clicked on something. Handle application-wide processing here, or call
 * a Catalog Browser function for specific action.
 */
void
DoMouseEvent(void)
{
        WindowPtr       theWindow;
        short           whichPart;
        
        whichPart = FindWindow(EVENT.where, &theWindow);
        if (theWindow == NULL)
            theWindow = FrontWindow();
        if (whichPart == inMenuBar && IsOurWindow(theWindow) == FALSE)
            theWindow = FrontWindow();
        switch (whichPart) {
        case inDesk:
            break;
        case inMenuBar:
            InitCursor();
            DoCommand(theWindow, MenuSelect(EVENT.where));
            break;
        case inDrag:
            DragWindow(theWindow, EVENT.where, &qd.screenBits.bounds);
            break;
        case inGoAway:
            if (TrackGoAway(theWindow, EVENT.where)) {
                if (IsOurWindow(theWindow)) {
                    /*
                     * Not quite so simple: we need to handle open files, too.
                     */
                    gQuitNow = TRUE;
                }
            }
            break;
        case inZoomIn:
        case inZoomOut:
            if (IsOurWindow(theWindow)
             && TrackBox(theWindow, EVENT.where, whichPart)) {
                DoZoomWindow(theWindow, whichPart);
                goto resizeWindow;
            }
            break;
        case inGrow:
            if (IsOurWindow(theWindow)) {
                if (DoGrowWindow(
                            theWindow,
                            EVENT.where,
                            kMinWindowWidth,
                            kMinWindowHeight
                        )) {
resizeWindow:       DecorateDisplay(theWindow, TRUE);
                }
            }
            break;
        case inContent:
            if (theWindow != FrontWindow())
                SelectWindow(theWindow);
            else if (IsOurWindow(theWindow)) {
                DoContentClick(theWindow);
            }
            else {
                /* Nothing happens here     */
            }
            break;
        default:
            break;                      /* Might be for the SDP Panel   */
        }
        /*
         * Do not touch theWindow here.
         */
}
 
void
DoContentClick(
        WindowPtr               theWindow
    )
{
        if (0) {
            theWindow;
        }
        DoClickInLog(gLogListHandle, &EVENT);
        /*
         * More to follow.
         */
}
 
void
DoWindowKeyDown(
        WindowPtr                       theWindow
    )
{
        if (0) {
            theWindow;
        }
        /* Nothing happens here */
}
 
void
DrawWindow(
        WindowPtr                       theWindow
    )
{
        if (0) {
            theWindow;
        }
        UpdateLog(gLogListHandle);
}
 
void
DecorateDisplay(
        WindowPtr                       theWindow,
        Boolean                         redraw
    )
{
        Rect                            viewRect;
        
        if (0) {
            redraw;
        }
        viewRect = theWindow->portRect;
        viewRect.right -= kScrollBarOffset;
        viewRect.bottom -= kScrollBarOffset;
        if (gLogListHandle != NULL) {
            MoveLog(gLogListHandle, viewRect.left, viewRect.top);
            SizeLog(gLogListHandle, width(viewRect), height(viewRect));
        }
}
 
void
DoCommand(
        WindowPtr                       theWindow,
        long                            menuChoice
    )
{
        short                           menuItem;
        Str255                          menuText;
        GrafPtr                         savePort;
        OSErr                           status;
 
        menuItem = LoWord(menuChoice);
        switch (HiWord(menuChoice)) {
        case MENU_Apple:
            if (menuItem == kAppleAbout)
                DoAbout();
            else {
                GetItem(gAppleMenu, menuItem, menuText);
                AdjustEditMenu(TRUE);
                GetPort(&savePort);
                OpenDeskAcc(menuText);
                SetPort(savePort);
                AdjustEditMenu(IsOurWindow(theWindow) == FALSE);
            }
            break;
        case MENU_File:
            switch (menuItem) {
            case kFileCreateLogFile:
                status = SaveLogFile(
                            gLogListHandle,
                            "\pSave Log",
                            "\pSCSI Test Log",
                            'ttxt'
                        );
                break;
            case kFileCloseLogFile:
                status = CloseLogFile(gLogListHandle);
                break;
            case kFilePageSetup:
                DoPageSetup();
                break;
            case kFilePrint:
                PrintLog(gLogListHandle, gPrintHandle);
                break;
            case kFileDebug:
                Debugger();
                break;
            case kFileQuit:
                gQuitNow = TRUE;
                break;
            }
            break;
        }
        HiliteMenu(0);
}
 
void
SetupEverything()
{
        int                 i;
        
        MaxApplZone();
        InitGraf(&qd.thePort);
        InitFonts();
        InitWindows();
        InitMenus();
        TEInit();
        InitDialogs(0);
        for (i = 0; i < 8; i++)
            MoreMasters();
        HNoPurge((Handle) GetCursor(watchCursor));
        SetCursor(*GetCursor(watchCursor));
        SetupMenus();
        gVirtualMemoryEnabled = IsVirtualMemoryRunning();
}
 
void
SetupMenus()
{
        register Handle     menuBarHdl;
 
        /*
         * We ought to do some error checking here.
         */
        menuBarHdl = GetNewMBar(MBAR_MenuBar);
        SetMenuBar(menuBarHdl);
        gAppleMenu = GetMHandle(MENU_Apple);
        AddResMenu(gAppleMenu, 'DRVR');
        gFileMenu = GetMHandle(MENU_File);
        gEditMenu = GetMHandle(MENU_Edit);
        DrawMenuBar();
        gUpdateMenusNeeded = TRUE;
}
 
void
AdjustMenus(void)
{
        EnableItem(gFileMenu, kFileQuit);
        EnableItem(gFileMenu, kFileDebug);
        if (IsOurWindow(FrontWindow())) {
            EnableItem(gFileMenu, kFilePageSetup);
            EnableItem(gFileMenu, kFilePrint);
            if (HasLogFile(gLogListHandle)) {
                EnableItem(gFileMenu, kFileCloseLogFile);
                DisableItem(gFileMenu, kFileCreateLogFile);
            }
            else {
                EnableItem(gFileMenu, kFileCreateLogFile);
                DisableItem(gFileMenu, kFileCloseLogFile);
            }
        }
        AdjustEditMenu(IsOurWindow(FrontWindow()) == FALSE);
}
 
/*
 * AdjustEditMenu
 * Enable/disable Edit Menu options.
 */
void
AdjustEditMenu(
        Boolean             isDeskAcc
    )
{
        if (isDeskAcc) {
            EnableItem(gEditMenu, kEditUndo);
            EnableItem(gEditMenu, kEditCut);
            EnableItem(gEditMenu, kEditCopy);
            EnableItem(gEditMenu, kEditPaste);
            EnableItem(gEditMenu, kEditClear);
        }
        else {
            DisableItem(gEditMenu, kEditUndo);
            DisableItem(gEditMenu, kEditCut);
            DisableItem(gEditMenu, kEditCopy);
            DisableItem(gEditMenu, kEditPaste);
            DisableItem(gEditMenu, kEditClear);
        }
}
 
void
DoAbout()
{
        GrafPtr                         savePort;
        DialogPtr                       dialog;
        short                           item;
        
        GetPort(&savePort);
        dialog = GetNewDialog(DLOG_About, NULL, (WindowPtr) -1L);
        ShowWindow(dialog);
        SetPort(dialog);
        ModalDialog(NULL, &item);
        DisposDialog(dialog);
        SetPort(savePort);
}
 
void
HexToString(
        unsigned long                   value,
        short                           hexDigits,
        Str255                          result
    )
{
        register unsigned short         digit;
        register char                   *text;
        
        text = (char *) result;
        text[0] = hexDigits;
        for (; hexDigits > 0; --hexDigits) {
            digit = value & 0xF;
            if (digit >= 10)
                text[hexDigits] = digit - 10 + 'a';
            else {
                text[hexDigits] = digit + '0';
            }
            value >>= 4;
        }
}
 
Boolean
HexToNum(
        ConstStr255Param                hexString,
        unsigned long                   *result
    )
{
        register short                  i;
        register unsigned short         digit;
        
        *result = 0;
        for (i = 1; i <= hexString[0]; i++) {
            digit = hexString[i];
            if (digit >= '0' && digit <= '9')
                digit -= '0';
            else if (digit >= 'a' && digit <= 'f')
                digit = digit - 'a' + 10;
            else if (digit >= 'A' && digit <= 'F')
                digit = digit - 'A' + 10;
            else {
                return (FALSE);
            }
            *result <<= 4;
            *result |= digit;
        }
        return (TRUE);
}
 
void
DoPageSetup(void)
{
        PrOpen();
        if (PrError() == noErr) {
            if (gPrintHandle == NULL) {
                gPrintHandle = (THPrint) NewHandle(sizeof (TPrint));
                if (gPrintHandle != NULL)
                    PrintDefault(gPrintHandle);
            }
            if (gPrintHandle != NULL)
                (void) PrStlDialog(gPrintHandle);
            PrClose();
        }
}
 
void
NonFatalError(
        OSErr                   errorStatus,
        ConstStr255Param        errorMsg
    )
{
        Handle                  errorTextHdl;
        StringPtr               errorTextPtr;
        Str15                   errorStatusText;
        short                   userChoice;
        
        NumToString(errorStatus, errorStatusText);
        errorTextHdl = GetResource('Estr', errorStatus);
        if (errorTextHdl != NULL) {
            HLock(errorTextHdl);
            errorTextPtr = (StringPtr) *errorTextHdl;
        }
        else {
            errorTextPtr = "\pSystem Error";
        }
        ParamText(errorStatusText, errorTextPtr, errorMsg, "\p");
        userChoice = StopAlert(ALRT_NonFatalError, NULL);
        if (userChoice == 1)
            ExitToShell();
}
 
 
void
FatalError(
        OSErr               errorStatus,
        ConstStr255Param    errorMsg
    )
{
        Handle              errorTextHdl;
        StringPtr           errorTextPtr;
        Str15               errorStatusText;
        
        NumToString(errorStatus, errorStatusText);
        errorTextHdl = GetResource('Estr', errorStatus);
        if (errorTextHdl != NULL) {
            HLock(errorTextHdl);
            errorTextPtr = (StringPtr) *errorTextHdl;
        }
        else {
            errorTextPtr = "\pSystem Error";
        }
        ParamText(errorStatusText, errorTextPtr, errorMsg, "\p");
        StopAlert(ALRT_FatalError, NULL);
        ExitToShell();
}
 
Boolean
IsVirtualMemoryRunning(void)
{
        OSErr                       status;
        long                        response;
        
        status = Gestalt(gestaltVMAttr, &response);
        /*
         * VM is active iff Gestalt succeeded and the response is appropriate.
         */
        return (status == noErr && ((response & (1 << gestaltVMPresent)) != 0));
}