MyApplication.c

/*
    File:       MyApplication.c
    
    Contains:   My Application Shell.
 
    Written by: John Wang
 
    Copyright:  © 1994 by Apple Computer, Inc., all rights reserved.
 
    Change History (most recent first):
 
        <1>     03/14/94    JW      Re-Created for Universal Headers.
 
    To Do:
    
*/
 
#ifdef THINK_C
#define     applec
#endif
 
#include    <Types.h>
#include    <Memory.h>
#include    <QuickDraw.h>
#include    <Palettes.h>
#include    <QDOffscreen.h>
#include    <Errors.h>
#include    <Fonts.h>
#include    <Dialogs.h>
#include    <Windows.h>
#include    <Menus.h>
#include    <Events.h>
#include    <Desk.h>
#include    <DiskInit.h>
#include    <OSUtils.h>
#include    <Resources.h>
#include    <ToolUtils.h>
#include    <AppleEvents.h>
#include    <EPPC.h>
#include    <GestaltEqu.h>
#include    <Processes.h>
#include    <Balloons.h>
#include    <Aliases.h>
#include    <MixedMode.h>
#include    <Scrap.h>
#include    <LowMem.h>
 
#include    <Movies.h>
 
#include    "MyApplication Shell (2.01).h"
#include    "MyApplication.h"
 
/* ------------------------------------------------------------------------- */
 
//  These globals are used by the shell and must be defined:
 
Str255      gMyAboutTitle = "\pSample QuickTime Playback Application";
Str255      gMyAboutDesc = "\pThis uses a sample application shell.";
 
struct WindowInfo {
    Movie           theMovie;
    MovieController theMC;
    Rect            movieRect;
    short           refNum;
    short           resId;
};
typedef     struct WindowInfo WindowInfo, *WindowInfoPtr, **WindowInfoHandle;
 
/* ------------------------------------------------------------------------- */
 
pascal Boolean MyPlayerFilter(MovieController theController, short action, void *params, long refCon);
pascal Boolean MyPlayerFilter(MovieController theController, short action, void *params, long refCon)
{
    Rect        movieBounds;
    
    switch ( action ) {
        case  mcActionControllerSizeChanged:
            MCGetControllerBoundsRect(theController, &movieBounds);
            SizeWindow((WindowPtr) refCon, movieBounds.right - movieBounds.left, movieBounds.bottom - movieBounds.top, true);
            break;
    }
    return ( false );
}
 
/* ------------------------------------------------------------------------- */
 
//  MyInitialize is called at init time after the toolbox is initialized.  This routine is
//  called only once.
 
OSErr MyInitialize()
{
    OSErr       err;
    long        QDfeature;
    
    //  We require QuickTime so make sure it is available.
    err = Gestalt(gestaltQuickTime, &QDfeature);
    if ( err != noErr )
        return(err);
    
    err = EnterMovies();
    if ( err != noErr )
        return(err);
 
    return(noErr);
}
 
//  Depending on the value of the constant MYEVENTDEF, this routine may have different
//  calling frequency.
//  If MYEVENTDEF == 2, then this routine gets called for every
//     window owned by the application of type MAS_WINDOWDOC per iteration of the event loop
//     if the event is NOT a null event.  MyEvent can assume that the grafport and gdevice
//     are set to the window being passed.
//  If MYEVENTDEF == 1, then this routine gets called once per event loop is the
//     event is NOT a null event.  theWindow will be nil.
//  If MYEVENTDEF == 0, this routine never gets called.
//  Returning true indicates that the event was handled and can be ignored by the normal
//  event handler.
 
Boolean MyEvent(WindowPtr theWindow, EventRecord *myEvent)
{
    WindowInfoHandle    myWinfo;
    
    myWinfo = (WindowInfoHandle) GetWRefCon(theWindow);
    if ( MCIsPlayerEvent((**myWinfo).theMC, myEvent) )
        return ( true );
    else
        return ( false );
}
 
//  Depending on the value of the constant MYIDLEDEF, this routine may have different
//  calling frequency.
//  If MYIDLEDEF == 2, then this routine gets called for every
//     window owned by the application of type MAS_WINDOWDOC per iteration of
//     the event loop.  You can assume that the port and gdevice are set to the window.
//  If MYIDLEDEF == 1, then this routine gets called once per event loop.  theWindow will be nil.
//  If MYIDLEDEF == 0, this routine never gets called.
 
void MyIdle(WindowPtr theWindow)
{
    WindowInfoHandle    myWinfo;
    
    myWinfo = (WindowInfoHandle) GetWRefCon(theWindow);
    MCIdle((**myWinfo).theMC);
}
 
//  MyDraw is called when redrawing the window is needed.  The port and gdevice
//  is already set and begin and end update are called for MyDraw.
 
void MyDraw(WindowPtr theWindow)
{
}
 
//  This routine gets called once when the application is quitting.
//  This gives the app the chance to clean up.
 
void MyFinishup()
{
}
 
//  This routine is called whenever the app receives a suspend or resume event.  This
//  allows the yield time (passed to WaitNextEvent) to be changed.  I.e., if you don't
//  do much processing the in background, you should set the yield to a high value
//  when the suspend message is received.
 
long MyYieldTime(long message)
{
    if ( message )
        //  Resume message
        return ( 0 );
    else
        //  Suspend message
        return ( 30 );
}
 
//  If the shell's doCommand routine can not process the menu selection, then this routine is
//  called.  Do not call HiliteMenu because it is called by the shell.
//  If the command can not be handled, this it must be an error and the shell will
//  present a FATAL error to the user.
 
OSErr MyDoCommand(short theMenu, short theItem)
{
    switch ( theMenu ) {
        case kMENU_NEXTID:
            switch ( theItem ) {
                case kMENU_NEXT1stITEM:
                    break;
                default:
                    return ( theItem );
            }
            break;
            
        default:
            return ( theItem );
    }
    
    return ( noErr );
}
 
void MyDoKeyDown(EventRecord *myEvent)
{
}
 
void MyInContent(WindowPtr foundWindow, Point where)
{
}
 
void MyZoomWindow(WindowPtr foundWindow, short windowPart)
{
    WStateData          *zoomData;
    WindowInfoHandle    myWinfo;
    Rect                movieBounds;
    
    //  IMPORTANT: Must not change stdState if not zooming out.  Otherwise, it will fool
    //  the WDEF into thinking that it is not zoomed out when it really is.
 
    //  Get the original movie rect.
    myWinfo = (WindowInfoHandle) GetWRefCon(foundWindow);
    movieBounds = (**myWinfo).movieRect;
 
    //  Now set the movie to the new bounds and then get the updated movieBounds.
    if ( windowPart == 8 ) {
        Rect    stdRect, userRect;  //  Get it first because MCMovieChanged changes the zoomRects.
        
        zoomData = (WStateData *) *(((CWindowPeek) foundWindow)->dataHandle);
        stdRect = zoomData->stdState;
        userRect = zoomData->userState;
        
        //  Double the size.  Set the movie size.  Then get the bounds back from MC.
        movieBounds.bottom = movieBounds.bottom << 1;
        movieBounds.right = movieBounds.right << 1;
        SetMovieBox((**myWinfo).theMovie, &movieBounds);
        MCMovieChanged((**myWinfo).theMC, (**myWinfo).theMovie);
        MCGetControllerBoundsRect((**myWinfo).theMC, &movieBounds);
        
        zoomData = (WStateData *) *(((CWindowPeek) foundWindow)->dataHandle);
        stdRect.right = stdRect.left + movieBounds.right;
        stdRect.bottom = stdRect.top + movieBounds.bottom;
        zoomData->stdState = stdRect;
        zoomData->userState = userRect;
        MoveWindow(foundWindow, stdRect.left, stdRect.top, false);
        SizeWindow(foundWindow, movieBounds.right, movieBounds.bottom, true);
    } else {
        Rect    stdRect, userRect;  //  Get it first because MCMovieChanged changes the zoomRects.
        
        zoomData = (WStateData *) *(((CWindowPeek) foundWindow)->dataHandle);
        stdRect = zoomData->stdState;
        userRect = zoomData->userState;
        
        //  Double the size.  Set the movie size.  Then get the bounds back from MC.
        SetMovieBox((**myWinfo).theMovie, &movieBounds);
        MCMovieChanged((**myWinfo).theMC, (**myWinfo).theMovie);
        MCGetControllerBoundsRect((**myWinfo).theMC, &movieBounds);
        zoomData = (WStateData *) *(((CWindowPeek) foundWindow)->dataHandle);
        
        userRect.right = userRect.left + movieBounds.right;
        userRect.bottom = userRect.top + movieBounds.bottom;
        zoomData->stdState = stdRect;
        zoomData->userState = userRect;
        MoveWindow(foundWindow, userRect.left, userRect.top, false);
        SizeWindow(foundWindow, movieBounds.right, movieBounds.bottom, true);
    }
}
 
void MyAdjustMenus()
{
}
 
/* ------------------------------------------------------------------------- */
 
void MyNew()
{
    Movie               myMovie;
    Rect                movieBounds;
    MovieController     mcPlay;
    WindowPtr           myWindow;
    WindowInfoHandle    myWinfo;
    Rect                limitRect = {0, 0, 480, 640};
    long                controllerFlags;
    
    myMovie = NewMovie(newMovieActive);
    if ( myMovie != nil ) {
        GetMovieBox(myMovie, &movieBounds);
        OffsetRect(&movieBounds, -movieBounds.left, -movieBounds.top);
        SetMovieBox(myMovie, &movieBounds);
        OffsetRect(&movieBounds, 50, 50);
        
        myWindow = NewCWindow(0L, &movieBounds, "\pMovie!", 1, zoomDocProc, (WindowPtr) -1, true, 0L);
        SetMyWindow(myWindow);
        OffsetRect(&movieBounds, -50, -50);
        
        SetPort(myWindow);
        SetMovieGWorld(myMovie, (CGrafPtr) myWindow, 0);
        mcPlay = NewMovieController(myMovie, &movieBounds, mcTopLeftMovie);
 
        myWinfo = (WindowInfoHandle) NewHandle(sizeof(WindowInfo));
        SetWRefCon(myWindow, (long) myWinfo);
        (**myWinfo).movieRect = movieBounds;
        (**myWinfo).theMC = mcPlay;
        (**myWinfo).theMovie = myMovie;
        (**myWinfo).refNum = -1;
        (**myWinfo).resId = 128;
 
        MCGetControllerBoundsRect(mcPlay, &movieBounds);
        SizeWindow(myWindow, movieBounds.right - movieBounds.left, movieBounds.bottom - movieBounds.top, true);
    
        //  Enable editing of movie controller
        MCEnableEditing(mcPlay,true);
    
        //  Turn on the grow box
        MCDoAction(mcPlay, mcActionSetGrowBoxBounds, (void *)&limitRect);
        
        //  Tell the controller to attach a movieÕs CLUT to the window as appropriate.
        MCDoAction(mcPlay, mcActionGetFlags, &controllerFlags);
        MCDoAction(mcPlay, mcActionSetFlags, 
                            (void *)(controllerFlags | mcFlagsUseWindowPalette));
    
        //  Allow the controller to accept keyboard events
        MCDoAction(mcPlay, mcActionSetKeysEnabled, (void *)true);
 
        //  Set the filter for events we want to know about
        MCSetActionFilterWithRefCon(mcPlay, NewMCActionFilterWithRefConProc(MyPlayerFilter), (long) myWindow);
    }
}
 
Movie getMovieFromFile(FSSpec *theFSS, short *refNum, short *resId);
Movie getMovieFromFile(FSSpec *theFSS, short *refNum, short *resId)
{
    OSErr                   err;
    StandardFileReply       reply;
    SFTypeList              types;
    Movie                   theMovie;
    FSSpec                  myFSSpec;
 
    if (theFSS == nil) {
        types[0] = 'MooV';
        StandardGetFilePreview(nil, 1, types, &reply);
        if (!reply.sfGood) return((Movie) 0);
        myFSSpec = reply.sfFile;
    } else {
        myFSSpec = *theFSS;
    }
    
    err = OpenMovieFile(&myFSSpec, refNum, fsRdWrPerm);
    if (GetMoviesError()) return((Movie) 0);
    if (err) return ((Movie) 0);
 
    *resId = 0;
    err = NewMovieFromFile(&theMovie, *refNum, resId, (StringPtr) 0,
                        newMovieActive, (Boolean *) 0);
    if (GetMoviesError()) return((Movie) 0);
    if (err) return ((Movie) 0);
 
    return (theMovie);
}
 
//  If theFSS is not nil, then the file to be opened is specified in the FSSpec.
//  MyOpen must make window frontmost so that it can be printed from finder.
void MyOpen(FSSpec *theFSS)
{
    Movie               myMovie;
    Rect                movieBounds;
    short               loopInfo;
    Handle              theLoop;
    UserData            theUserData;
    MovieController     mcPlay;
    WindowPtr           myWindow;
    WindowInfoHandle    myWinfo;
    Rect                limitRect = {0, 0, 480, 640};
    long                controllerFlags;
    short               refNum, resId;
    
    myMovie =  getMovieFromFile(theFSS, &refNum, &resId);
    if ( myMovie != nil ) {
        GetMovieBox(myMovie, &movieBounds);
        OffsetRect(&movieBounds, -movieBounds.left, -movieBounds.top);
        SetMovieBox(myMovie, &movieBounds);
        OffsetRect(&movieBounds, 50, 50);
        
        myWindow = NewCWindow(0L, &movieBounds, "\pMovie!", 1, zoomDocProc, (WindowPtr) -1, true, 0L);
        SetMyWindow(myWindow);
        OffsetRect(&movieBounds, -50, -50);
        
        SetPort(myWindow);
        SetMovieGWorld(myMovie, (CGrafPtr) myWindow, 0);
        mcPlay = NewMovieController(myMovie, &movieBounds, mcTopLeftMovie);
 
        myWinfo = (WindowInfoHandle) NewHandle(sizeof(WindowInfo));
        SetWRefCon(myWindow, (long) myWinfo);
        (**myWinfo).movieRect = movieBounds;
        (**myWinfo).theMC = mcPlay;
        (**myWinfo).theMovie = myMovie;
        (**myWinfo).refNum = refNum;
        (**myWinfo).resId = resId;
 
        MCGetControllerBoundsRect(mcPlay, &movieBounds);
        SizeWindow(myWindow, movieBounds.right - movieBounds.left, movieBounds.bottom - movieBounds.top, true);
    
        //  Enable editing of movie controller
        MCEnableEditing(mcPlay,true);
    
        //  Turn on the grow box
        MCDoAction(mcPlay, mcActionSetGrowBoxBounds, (void *)&limitRect);
        
        //  Tell the controller to attach a movieÕs CLUT to the window as appropriate.
        MCDoAction(mcPlay, mcActionGetFlags, &controllerFlags);
        MCDoAction(mcPlay, mcActionSetFlags, 
                            (void *)(controllerFlags | mcFlagsUseWindowPalette));
    
        //  Allow the controller to accept keyboard events
        MCDoAction(mcPlay, mcActionSetKeysEnabled, (void *)true);
 
        //  Set the filter for events we want to know about
        MCSetActionFilterWithRefCon(mcPlay, NewMCActionFilterWithRefConProc(MyPlayerFilter), (long) myWindow);
    
        //  See my tech note on User Data Atoms for more information about the below code...
        loopInfo = 0;
        theLoop = NewHandle(0);
        theUserData = GetMovieUserData(myMovie);
        if ( CountUserDataType(theUserData, 'LOOP') ) {
            loopInfo = 1;
            GetUserData(theUserData, theLoop, 'LOOP', 1);
            if ( GetHandleSize(theLoop) )
                if ( (** (long **) theLoop) == 1 )
                    loopInfo = 2;
        }
        if ( loopInfo )
            MCDoAction(mcPlay, mcActionSetLooping, (Ptr) true);
        if ( loopInfo == 2 )
            MCDoAction(mcPlay, mcActionSetLoopIsPalindrome, (Ptr) true);
    }
}
 
void MyClose()
{
    WindowPtr           closeWindow;
    WindowInfoHandle    myWinfo;
    
    closeWindow = FrontWindow();
    if ( closeWindow == nil )
        return;
        
    myWinfo = (WindowInfoHandle) GetWRefCon(closeWindow);
 
    CloseMovieFile((**myWinfo).refNum);
    DisposeMovieController((**myWinfo).theMC);
    DisposeMovie((**myWinfo).theMovie);
    DisposHandle((Handle) myWinfo);
    DisposeWindow(closeWindow);
}
 
void MySave()
{
    WindowPtr           frontWindow;
    WindowInfoHandle    myWinfo;
    OSErr               myErr;
 
    frontWindow = FrontWindow();
    if ( frontWindow == nil ) 
        return;
        
    myWinfo = (WindowInfoHandle) GetWRefCon(frontWindow);
    if ( (**myWinfo).refNum != -1 ) {
        myErr = UpdateMovieResource((**myWinfo).theMovie, (**myWinfo).refNum,
                                        (**myWinfo).resId, nil);
    } else {
        MySaveAs();
    }
}
 
void MySaveAs()
{
    SysBeep(50);
}
 
void MyPageSetup()
{
    SysBeep(50);
}
 
void MyPrint()
{
    SysBeep(50);
}
 
/* ------------------------------------------------------------------------- */
 
void MyUndo(void)
{
    WindowPtr           frontWindow;
    WindowInfoHandle    myWinfo;
    ComponentResult     err;
    
    frontWindow = FrontWindow();
    if ( frontWindow == nil )
        return;
        
    if ( IsMyWindow(frontWindow) ) {
        myWinfo = (WindowInfoHandle) GetWRefCon(frontWindow);
        err = MCUndo((**myWinfo).theMC);
    }   
}
 
void MyCut(void)
{
    WindowPtr           frontWindow;
    WindowInfoHandle    myWinfo;
    Movie               scrapMovie;
    
    frontWindow = FrontWindow();
    if ( frontWindow == nil )
        return;
        
    if ( IsMyWindow(frontWindow) ) {
        myWinfo = (WindowInfoHandle) GetWRefCon(frontWindow);
        scrapMovie = MCCut((**myWinfo).theMC);
        if ( scrapMovie ) {
            PutMovieOnScrap(scrapMovie, 0L);
            DisposeMovie(scrapMovie);
        }
    }   
}
 
void MyCopy(void)
{
    WindowPtr           frontWindow;
    WindowInfoHandle    myWinfo;
    Movie               scrapMovie;
    
    frontWindow = FrontWindow();
    if ( frontWindow == nil )
        return;
        
    if ( IsMyWindow(frontWindow) ) {
        myWinfo = (WindowInfoHandle) GetWRefCon(frontWindow);
        scrapMovie = MCCopy((**myWinfo).theMC);
        if ( scrapMovie ) {
            PutMovieOnScrap(scrapMovie, 0L);
            DisposeMovie(scrapMovie);
        }
    }   
}
 
void MyPaste(void)
{
    WindowPtr           frontWindow;
    WindowInfoHandle    myWinfo;
    ComponentResult     err;
    
    frontWindow = FrontWindow();
    if ( frontWindow == nil )
        return;
        
    if ( IsMyWindow(frontWindow) ) {
        myWinfo = (WindowInfoHandle) GetWRefCon(frontWindow);
        err = MCPaste((**myWinfo).theMC, nil);
    }   
}
 
void MyClear(void)
{
    WindowPtr           frontWindow;
    WindowInfoHandle    myWinfo;
    ComponentResult     err;
    
    frontWindow = FrontWindow();
    if ( frontWindow == nil )
        return;
        
    if ( IsMyWindow(frontWindow) ) {
        myWinfo = (WindowInfoHandle) GetWRefCon(frontWindow);
        err = MCClear((**myWinfo).theMC);
    }   
}
 
void MySelectAll(void)
{
    WindowPtr           frontWindow;
    WindowInfoHandle    myWinfo;
    TimeRecord          tr;
    
    frontWindow = FrontWindow();
    if ( frontWindow == nil )
        return;
        
    if ( IsMyWindow(frontWindow) ) {
        myWinfo = (WindowInfoHandle) GetWRefCon(frontWindow);
    
        tr.value.hiLong = 0;
        tr.value.loLong = 0;
        tr.base = 0;
        tr.scale = GetMovieTimeScale((**myWinfo).theMovie);
        MCDoAction((**myWinfo).theMC, mcActionSetSelectionBegin, &tr);
        tr.value.loLong = GetMovieDuration((**myWinfo).theMovie);
        MCDoAction((**myWinfo).theMC, mcActionSetSelectionDuration, &tr);
    }
}