NOTE: This Technical Q&A has been retired. Please see the Technical Q&As page for current documentation.

Technical Q&A AMTPE19
AMT_PE Freezes


The Apple Media Tool and Apple Media Tool Programming Environment products have been discontinued. For more information check out: AMT/PE Discontinued.

Q: Why do AMT/PE 1.2 applications occasionally freeze during screen switching?

A: This is caused by the Apple Media Kit calling SetCCursor during a VBL task, which can move memory. While this didn't cause problems on earlier models (even on those with the PowerPC 601 chip), it frequently causes problems on PowerPC 604-based systems. This may be because VM is on by default. We do not think it has anything to do with the hardware.

A replacement cursor.c file has been provided in the Apple Media Tool/Programming Environment Runtime folder, and we do have a replacement Runtime Maker:Codes:Program file for Apple Media Tool. If you are currently developing titles, replacing these files and rebuilding your projects will remove the bug.

For existing titles, we have an applet (titled AMK Launch'NPlay) that you can distribute to any of your customers who report this problem. Instruct the customer to launch AMK Launch'NPlayand navigate to the title (what they would ordinarily double click on) in the dialog box presented. The title will be launched and not crash as before. (Spinning cursors will not be drawn, however.)

Here is the code you need for cursor.c.

/*
   File: CURSOR.c
   Folder: RUNTIME
   (c) Encore Développement, SARL, 1992-94
*/
#include "Memory.h"
#include "QuickDraw.h"
#include "Retrace.h"
#include "Key.h"
extern const keyID K_DATA;
extern const keyID K_ID;
extern const keyID K_COUNT;
extern const keyID K_GETAT;
void CursorLoad(key* the)
{
    short anID;
    CCrsrHandle aCCrsrHandle;

    anID = keyToInteger(keyGet(the[SELF], K_ID));
    aCCrsrHandle = GetCCursor(anID);
    keyIfNULL(aCCrsrHandle);
    keyPut(the[SELF], K_DATA, keyFromHandle(aCCrsrHandle));
}
void CursorSet(key* the)
{
    CCrsrHandle aCCrsrHandle;

    aCCrsrHandle = (CCrsrHandle)keyToHandle(keyGet(the[SELF], K_DATA));
    keyCheck(aCCrsrHandle != NULL);
    SetCCursor(aCCrsrHandle);
}
void CursorUnload(key* the)
{
    CCrsrHandle aCCrsrHandle;

    aCCrsrHandle = (CCrsrHandle)keyToHandle(keyGet(the[SELF], K_DATA));
    keyCheck(aCCrsrHandle != NULL);
    DisposCCursor(aCCrsrHandle);
    keyPut(the[SELF], K_DATA, keyVoid);
}
typedef struct {
#ifdef applec
    long globalA5;
    long localA5;
#endif
    VBLTask task;
    short running;
    short index;
    short count;
    CCrsrPtr cursors[64];
} SpinRecord, *SpinPtr;
SpinRecord gSpinRecord;
#ifdef applec
pascal long GetA0() = { 0x2e88 };
pascal long GetA5() = { 0x2e8d };
#endif
pascal void SpinVBLTask()
{
#ifdef applec
    SpinPtr aSpinPtr = (SpinPtr)(GetA0() - (sizeof(long) * 2));
    aSpinPtr->localA5 = SetA5(aSpinPtr->globalA5);
#endif
#ifdef powerc
    SpinPtr aSpinPtr = &gSpinRecord;
#endif
    aSpinPtr->task.vblCount = 10;
    aSpinPtr->index++;
    if (aSpinPtr->index == aSpinPtr->count) {
        aSpinPtr->index = 0;
    }

    /*
    Use the b&w cursor inside the locked color cursor handle
    so it does not move memory...
    */

    SetCursor((Cursor*)&((aSpinPtr->cursors[aSpinPtr->index])->crsr1Data));
#ifdef applec
    SetA5(aSpinPtr->localA5);
#endif
}
void SpinIsRunning(key* the)
{
    the[RESULT] = keyFromBoolean(gSpinRecord.running);
}
void SpinStart(key* the)
{
    static VBLUPP aVBLUPP = NULL;
    short aCount, anIndex;
    Handle aHandle;

    if (aVBLUPP == NULL) {
        aVBLUPP = NewVBLProc(SpinVBLTask);
    }

    aCount = keyToInteger(keyCall0(the[SELF], K_COUNT));
    for (anIndex = 0; anIndex < aCount; anIndex++) {
        the[RESULT] = keyCall1(the[SELF], K_GETAT, keyFromInteger(anIndex + 1));
        aHandle = keyToHandle(keyGet(the[RESULT], K_DATA));
        HLock(aHandle);
        gSpinRecord.cursors[anIndex] = (CCrsrPtr)*aHandle;
    }

#ifdef applec
    gSpinRecord.globalA5 = GetA5();
#endif
    gSpinRecord.task.qType = vType;
    gSpinRecord.task.vblAddr = aVBLUPP;
    gSpinRecord.task.vblCount = 10;
    gSpinRecord.task.vblPhase = 0;
    gSpinRecord.index = 0;
    gSpinRecord.count = aCount;
    if (VInstall((QElemPtr)&(gSpinRecord.task)) == noErr) {
        gSpinRecord.running = 1;
    }
}
void SpinStop(key* the)
{
    short aCount, anIndex;
    Handle aHandle;
    if (VRemove((QElemPtr)&(gSpinRecord.task)) == noErr) {
        gSpinRecord.running = 0;
    }
    aCount = keyToInteger(keyCall0(the[SELF], K_COUNT));
    for (anIndex = 0; anIndex < aCount; anIndex++) {
        the[RESULT] = keyCall1(the[SELF], K_GETAT, keyFromInteger(anIndex + 1));
        aHandle = keyToHandle(keyGet(the[RESULT], K_DATA));
        HUnlock(aHandle);
        gSpinRecord.cursors[anIndex] = NULL;
    }
}
void CursorsShow(key *the)
{
    if (keyIsTrue(the[ARGUMENT(1)]))
        ShowCursor();
    else
        HideCursor();
}

[Aug 01 1995]


Developer Documentation | Technical Notes | Development Kits | Sample Code