Common Files/ComFramework.c

//////////
//
//  File:       ComFramework.c
//
//  Contains:   Code for the QuickTime sample code framework that is common to both Macintosh and Windows.
//
//  Written by: Tim Monroe
//              Based on the QTShell code written by Tim Monroe, which in turn was based on the MovieShell
//              code written by Kent Sandvik (Apple DTS). This current version is now very far removed from
//              MovieShell.
//
//  Copyright:  © 1999-2000 by Apple Computer, Inc., all rights reserved.
//
//  Change History (most recent first):
//     
//     <25>     02/12/01    rtm     fixed stupid bug in QTFrame_PutFile (was calling NavDisposeReply before
//                                  reading data from reply record); d'oh!
//     <24>     02/01/01    rtm     fixed *Proc names to *UPP, to conform to Universal Header 3.4b4
//     <23>     11/24/00    rtm     added QTFrame_GetWindowReferenceFromWindow
//     <22>     10/09/00    rtm     added QTFrame_IsMovieWindow and QTFrame_IsImageWindow; reworked the function
//                                  QTFrame_SizeWindowToMovie to use these calls
//     <21>     10/02/00    rtm     added code in QTFrame_SaveAsMovieFile to remove empty resource fork created
//                                  by FlattenMovieData; commented out calls to MakeFilePreview, since it always
//                                  adds a resource fork; will replace MakeFilePreview by QTInfo_MakeFilePreview
//     <20>     07/26/00    rtm     converted gValidFileTypes into a handle (it was previously a pointer)
//     <19>     07/07/00    rtm     further work on QTFrame_AdjustMenus and QTFrame_ConvertMacToWinMenuItemLabel 
//     <18>     07/06/00    rtm     added theModifiers parameter to QTFrame_AdjustMenus; updated it to support 
//                                  modifier keys under Windows; added QTFrame_ConvertMacToWinMenuItemLabel
//     <17>     04/24/00    rtm     added calls to MakeFilePreview
//     <16>     03/15/00    rtm     modified QTFrame_SaveAsMovieFile to create a single-fork, self-contained,
//                                  interleaved, Fast Start movie
//     <15>     03/02/00    rtm     made changes to get things running under CarbonLib
//     <14>     02/16/00    rtm     added QTFrame_GetWindowPtrFromWindowReference
//     <13>     01/19/00    rtm     revised QTFrame_IsAppWindow (dialog windows no longer count as application
//                                  windows); added QTFrame_BuildFileTypeList and QTFrame_AddComponentFileTypes
//                                  to avoid calling GetMovieImporterForDataRef in QTFrame_FilterFiles; removed
//                                  the hard-coded file types
//     <12>     01/14/00    rtm     added support for graphics files, using graphics importers
//     <11>     12/28/99    rtm     added QTFrame_ConvertMacToWinRect and QTFrame_ConvertWinToMacRect
//     <10>     12/21/99    rtm     hard-coded some file types into QTFrame_FilterFiles; if we let QuickTime
//                                  to do all the testing (using GetMovieImporterForDataRef), it takes too long
//     <9>      12/17/99    rtm     added some code to QTFrame_SetMenuItemState to work around a problem that
//                                  appears under MacOS 8.5.1 (as far as I can tell...)
//     <8>      12/16/99    rtm     added QTApp_HandleMenu calls to _HandleFileMenuItem and _HandleEditMenuItem
//                                  to allow the application-specific code to intercept menu item selections;
//                                  added QTFrame_FilterFiles
//     <7>      12/15/99    rtm     added QTApp_Idle call to QTFrame_IdleMovieWindows
//     <6>      12/11/99    rtm     added GetMenuState call to Windows portion of QTFrame_SetMenuItemLabel;
//                                  tweaked _SizeWindowToMovie to guard against NULL movie and/or controller
//     <5>      11/30/99    rtm     added QTFrame_CloseMovieWindows
//     <4>      11/27/99    rtm     added QTFrame_GetFileFilterUPP
//     <3>      11/17/99    rtm     finished support for Navigation Services; added QTFrame_IdleMovieWindows
//     <2>      11/16/99    rtm     begun support for Navigation Services
//     <1>      11/05/99    rtm     first file
//
//  This file contains several kinds of functions: (1) functions that use completely cross-platform APIs and
//  which therefore can be compiled and run for both Mac and Windows platforms with no changes whatsoever (a
//  good example of this is QTFrame_SaveAsMovieFile); (2) functions that are substantially the same on both
//  platforms but which require several short platform-dependent #ifdef TARGET_OS_ blocks (a good example of
//  this is QTFrame_AdjustMenus); (3) functions that retrieve data from framework-specific data structures (a
//  good example of this is QTFrame_GetWindowObjectFromWindow); (4) functions that provide a platform-neutral
//  interface to platform-specific operations (a good example of this is QTFrame_Beep). In a nutshell, this
//  file attempts to provide platform-independent services to its callers, typically functions in the files
//  MacFramework.c, WinFramework.c, and ComApplication.c.
//
//  In general, you should not need to modify this file. Your application-specific code should usually be put
//  into the file ComApplication.c.
//
//////////
 
//////////
//
// header files
//
//////////
 
#include "ComFramework.h"
 
 
//////////
//
// global variables
//
//////////
 
Rect                    gMCResizeBounds;                        // maximum size for any movie window
Handle                  gValidFileTypes = NULL;                 // the list of file types that our application can open
long                    gFirstGITypeIndex;                      // the index in gValidFileTypes of the first graphics importer file type
 
#if TARGET_OS_WIN32
extern HWND             ghWnd;
extern HWND             ghWndMDIClient;
extern BOOL             gWeAreSizingWindow;
#endif
 
#if TARGET_OS_MAC
extern Str255           gAppName;
void                    QTFrame_HandleEvent (EventRecord *theEvent);
#endif
 
 
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Menu-handling functions.
//
// Use these functions to handle items in the File and Edit menus.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
//////////
//
// QTFrame_HandleFileMenuItem
// Handle the specified File menu item.
//
//////////
 
void QTFrame_HandleFileMenuItem (WindowReference theWindow, UInt16 theMenuItem)
{
    // give the application-specific code a chance to intercept the menu item selection
    if (QTApp_HandleMenu(theMenuItem))
        return;
        
    switch (theMenuItem) {
    
        case IDM_FILENEW:
            QTFrame_CreateNewMovie();
            break;
 
        case IDM_FILEOPEN:
            QTFrame_OpenMovieInWindow(NULL, NULL);
            break;
 
        case IDM_FILECLOSE:
            QTFrame_DestroyMovieWindow(theWindow);
            break;
 
        case IDM_FILESAVE:
            QTFrame_UpdateMovieFile(theWindow);
            break;
 
        case IDM_FILESAVEAS:
            QTFrame_SaveAsMovieFile(theWindow);
            break;
            
        case IDM_EXIT:
            QTFrame_QuitFramework();
            break;
 
        default:
            break;
    } // switch (theMenuItem)
    
}
 
 
//////////
//
// QTFrame_HandleEditMenuItem
// Perform the specified edit operation on the specified window.
//
//////////
 
void QTFrame_HandleEditMenuItem (WindowReference theWindow, UInt16 theMenuItem)
{
    WindowObject        myWindowObject = NULL;
    MovieController     myMC = NULL;
    Movie               myEditMovie = NULL;             // the movie created by some editing operations
    
    // give the application-specific code a chance to intercept the menu item selection
    if (QTApp_HandleMenu(theMenuItem))
        return;
    
    myWindowObject = QTFrame_GetWindowObjectFromWindow(theWindow);
    myMC = QTFrame_GetMCFromWindow(theWindow);
    
    // make sure we have a valid movie controller and a valid window object
    if ((myMC == NULL) || (myWindowObject == NULL))
        return;
 
    switch (theMenuItem) {
    
        case IDM_EDITUNDO:
            MCUndo(myMC);
            (**myWindowObject).fIsDirty = true;
            break;
 
        case IDM_EDITCUT:
            myEditMovie = MCCut(myMC);
            (**myWindowObject).fIsDirty = true;
            break;
 
        case IDM_EDITCOPY:
            myEditMovie = MCCopy(myMC);
            break;
 
        case IDM_EDITPASTE:
            MCPaste(myMC, NULL);
            (**myWindowObject).fIsDirty = true;
            break;
 
        case IDM_EDITCLEAR:
            MCClear(myMC);
            (**myWindowObject).fIsDirty = true;
            break;
            
        case IDM_EDITSELECTALL:
            QTUtils_SelectAllMovie(myMC);
            break;
 
        case IDM_EDITSELECTNONE:
            QTUtils_SelectNoneMovie(myMC);
            break;
 
        default:
            break;
    } // switch (theMenuItem)
    
    // place any cut or copied movie segment onto the scrap
    if (myEditMovie != NULL) {
        PutMovieOnScrap(myEditMovie, 0L);
        DisposeMovie(myEditMovie);
    }
    
    // if the size of the movie might have changed, invalidate the entire movie box
    if ((theMenuItem == IDM_EDITUNDO) || (theMenuItem == IDM_EDITCUT) || (theMenuItem == IDM_EDITPASTE) || (theMenuItem == IDM_EDITCLEAR)) {
        Rect        myRect;
#if TARGET_OS_WIN32
        RECT        myWinRect;
#endif      
    
        MCGetControllerBoundsRect(myMC, &myRect);
#if TARGET_OS_MAC
        InvalWindowRect(QTFrame_GetWindowFromWindowReference(theWindow), &myRect);
#endif      
#if TARGET_OS_WIN32
        QTFrame_ConvertMacToWinRect(&myRect, &myWinRect);
        InvalidateRect(theWindow, &myWinRect, false);
#endif      
    }
        
}
 
 
//////////
//
// QTFrame_AdjustMenus 
// Adjust the application's menus.
//
// On Windows, the theWindow parameter is a handle to the active MDI *child* window, if any.
// On Mac, the theWindow parameter is a pointer to the frontmost window, if any.
//
//////////
 
int QTFrame_AdjustMenus (WindowReference theWindow, MenuReference theMenu, long theModifiers)
{
    WindowObject        myWindowObject = NULL; 
    MovieController     myMC = NULL;
    MenuReference       myMenu = NULL;
    long                myFlags = 0L;
    
#if TARGET_OS_WIN32
    myMenu = theMenu;
#endif
 
    if (theWindow != NULL)
        myWindowObject = QTFrame_GetWindowObjectFromWindow(theWindow);
 
    if (myWindowObject != NULL)
        myMC = (**myWindowObject).fController;
 
    //////////
    //
    // configure the Edit menu
    //
    //////////
    
#if TARGET_OS_MAC
    myMenu = GetMenuHandle(kEditMenuResID);
#endif
 
    if (myMC == NULL) {
        // if there is no movie controller, disable all the Edit menu items
        QTFrame_SetMenuItemState(myMenu, IDM_EDITUNDO, kDisableMenuItem);
        QTFrame_SetMenuItemState(myMenu, IDM_EDITCUT, kDisableMenuItem);
        QTFrame_SetMenuItemState(myMenu, IDM_EDITCOPY, kDisableMenuItem);
        QTFrame_SetMenuItemState(myMenu, IDM_EDITPASTE, kDisableMenuItem);
        QTFrame_SetMenuItemState(myMenu, IDM_EDITCLEAR, kDisableMenuItem);
        QTFrame_SetMenuItemState(myMenu, IDM_EDITSELECTALL, kDisableMenuItem);
        QTFrame_SetMenuItemState(myMenu, IDM_EDITSELECTNONE, kDisableMenuItem);
    } else {
        MCGetControllerInfo(myMC, &myFlags);
 
        QTFrame_SetMenuItemState(myMenu, IDM_EDITSELECTALL, myFlags & mcInfoEditingEnabled ? kEnableMenuItem : kDisableMenuItem);
        QTFrame_SetMenuItemState(myMenu, IDM_EDITSELECTNONE, myFlags & mcInfoEditingEnabled ? kEnableMenuItem : kDisableMenuItem);
 
#if TARGET_OS_MAC
        // on Macintosh, we can use the MCSetUpEditMenu function to handle the 5 standard Edit menu items
        MCSetUpEditMenu(myMC, theModifiers, myMenu);
#endif
#if TARGET_OS_WIN32
        MCSetUpEditMenu(myMC, theModifiers, NULL);
        
        // on Windows, replicate the menu-updating functionality of MCSetUpEditMenu, as much as possible
        QTFrame_SetMenuItemState(myMenu, IDM_EDITUNDO, myFlags & mcInfoUndoAvailable ? kEnableMenuItem : kDisableMenuItem);
        QTFrame_SetMenuItemState(myMenu, IDM_EDITCUT, myFlags & mcInfoCutAvailable ? kEnableMenuItem : kDisableMenuItem);
        QTFrame_SetMenuItemState(myMenu, IDM_EDITCOPY, myFlags & mcInfoCopyAvailable ? kEnableMenuItem : kDisableMenuItem);
        QTFrame_SetMenuItemState(myMenu, IDM_EDITPASTE, myFlags & mcInfoPasteAvailable ? kEnableMenuItem : kDisableMenuItem);
        QTFrame_SetMenuItemState(myMenu, IDM_EDITCLEAR, myFlags & mcInfoClearAvailable ? kEnableMenuItem : kDisableMenuItem);
    
        QTFrame_ConvertMacToWinMenuItemLabel(myMC, myMenu, theModifiers, IDM_EDITUNDO);
        QTFrame_ConvertMacToWinMenuItemLabel(myMC, myMenu, theModifiers, IDM_EDITCUT);
        QTFrame_ConvertMacToWinMenuItemLabel(myMC, myMenu, theModifiers, IDM_EDITCOPY);
        QTFrame_ConvertMacToWinMenuItemLabel(myMC, myMenu, theModifiers, IDM_EDITPASTE);
        QTFrame_ConvertMacToWinMenuItemLabel(myMC, myMenu, theModifiers, IDM_EDITCLEAR);
#endif
    }
 
    //////////
    //
    // configure the File menu
    //
    //////////
    
#if TARGET_OS_MAC
    myMenu = GetMenuHandle(kFileMenuResID);
#endif
    if (theWindow != NULL) {                // there is a window open
        // handle the Close command
        QTFrame_SetMenuItemState(myMenu, IDM_FILECLOSE, kEnableMenuItem);
        
        // handle the Save As and Save commands
        if (myWindowObject != NULL) {
            QTFrame_SetMenuItemState(myMenu, IDM_FILESAVEAS, kEnableMenuItem);
            QTFrame_SetMenuItemState(myMenu, IDM_FILESAVE, (**myWindowObject).fIsDirty ? kEnableMenuItem : kDisableMenuItem);
        } else {
            QTFrame_SetMenuItemState(myMenu, IDM_FILESAVEAS, kDisableMenuItem);
            QTFrame_SetMenuItemState(myMenu, IDM_FILESAVE, kDisableMenuItem);
        }
    
    } else {                                // there is no window open  
        QTFrame_SetMenuItemState(myMenu, IDM_FILESAVE, kDisableMenuItem);
        QTFrame_SetMenuItemState(myMenu, IDM_FILESAVEAS, kDisableMenuItem);
        QTFrame_SetMenuItemState(myMenu, IDM_FILECLOSE, kDisableMenuItem);      
    }
 
    // adjust any application-specific menus
    QTApp_AdjustMenus(theWindow, theMenu);
 
    return(0);
}
 
 
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Movie-handling functions.
//
// Use these functions to create new movies, open existing movies, save movies, and so forth.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
//////////
//
// QTFrame_CreateNewMovie
// Create a new movie in a window; returns true if successful.
//
// NOTE: There are several user interface issues that are blissfully ignored by this routine,
// principally the preferred names and the on-screen locations of the new windows. 
//
//////////
 
Boolean QTFrame_CreateNewMovie (void)
{
    Movie               myMovie = NULL;
    FSSpec              myFSSpec;
    StringPtr           myName = QTUtils_ConvertCToPascalString(kNewMovieName);
    
    myMovie = NewMovie(newMovieActive);
    if (myMovie == NULL)
        return(false);
    
    // create a default FSSpec
    FSMakeFSSpec(0, 0L, myName, &myFSSpec);
    
    free(myName);
    
    return(QTFrame_OpenMovieInWindow(myMovie, &myFSSpec));
}
 
 
//////////
//
// QTFrame_OpenMovieInWindow
// Open a movie in a new movie window; return true if successful.
//
// This function is called from several places in our framework. The following combinations are possible:
//  * theMovie == NULL, theFSSpec == NULL: no movie, no file; elicit a movie file from user and open it
//  * theMovie != NULL, theFSSpec == NULL: new movie, no file (yet)
//  * theMovie == NULL, theFSSpec != NULL: no movie, but we have an FSSpec; so just open the specified movie file
//  * theMovie != NULL, theFSSpec != NULL: new movie, theFSSpec contains (at least) the movie name
//
//////////
 
Boolean QTFrame_OpenMovieInWindow (Movie theMovie, FSSpec *theFSSpec)
{
    WindowObject            myWindowObject = NULL;
    Movie                   myMovie = NULL;
    MovieController         myMC = NULL;
    GraphicsImportComponent myImporter = NULL;
    WindowReference         myWindow = NULL;
    FSSpec                  myFSSpec;
    short                   myRefNum = kInvalidFileRefNum;
    short                   myResID = 0;
    OSType                  myTypeList[] = {kQTFileTypeMovie, kQTFileTypeQuickTimeImage};
    short                   myNumTypes = 2;
    GrafPtr                 mySavedPort;
    Rect                    myRect = {0, 0, 0, 0};
    Point                   myPoint;
    QTFrameFileFilterUPP    myFileFilterUPP = NULL;
    OSErr                   myErr = noErr;
 
#if TARGET_OS_MAC
    myNumTypes = 0;
#endif
 
    // get the current port; we may need to restore it if we cannot successfully create a new window
    GetPort(&mySavedPort);
    
    // if we got neither a movie nor an FSSpec passed in, prompt the user for a movie file
    if ((theMovie == NULL) && (theFSSpec == NULL)) {
        myFileFilterUPP = QTFrame_GetFileFilterUPP((ProcPtr)QTFrame_FilterFiles);
    
        myErr = QTFrame_GetOneFileWithPreview(myNumTypes, (QTFrameTypeListPtr)myTypeList, &myFSSpec, myFileFilterUPP);
    
        if (myFileFilterUPP != NULL)
            DisposeNavObjectFilterUPP(myFileFilterUPP);
 
        if (myErr != noErr)
            goto bail;
    }
    
    // if we got an FSSpec passed in, copy it into myFSSpec
    if (theFSSpec != NULL) {
        FSMakeFSSpec(theFSSpec->vRefNum, theFSSpec->parID, theFSSpec->name, &myFSSpec);     
    }
 
    // if we got no movie passed in, read one from the specified file
    if (theMovie == NULL) {
        // see if the FSSpec picks out an image file; if so, skip the movie-opening code
        myErr = GetGraphicsImporterForFile(&myFSSpec, &myImporter);
        if (myImporter != NULL)
            goto gotImageFile;
            
        // ideally, we'd like read and write permission, but we'll settle for read-only permission
        myErr = OpenMovieFile(&myFSSpec, &myRefNum, fsRdWrPerm);
        if (myErr != noErr)
            myErr = OpenMovieFile(&myFSSpec, &myRefNum, fsRdPerm);
 
        // if we couldn't open the file with even just read-only permission, bail....
        if (myErr != noErr)
            goto bail;
 
        // now fetch the first movie from the file
        myResID = 0;
        myErr = NewMovieFromFile(&myMovie, myRefNum, &myResID, NULL, newMovieActive, NULL);
        if (myErr != noErr)
            goto bail;
    } else {
        myMovie = theMovie;
    }
 
    //////////
    //
    // at this point, myMovie is an open movie, but myFSSpec may or may not be a valid FSSpec
    //
    //////////
    
    // set the default progress procedure for the movie
    SetMovieProgressProc(myMovie, (MovieProgressUPP)-1, 0);
        
gotImageFile:
    // create a new window to display the movie in
    myWindow = QTFrame_CreateMovieWindow();
    if (myWindow == NULL)
        goto bail;
    
    myWindowObject = QTFrame_GetWindowObjectFromWindow(myWindow);
    if (myWindowObject == NULL)
        goto bail;
    
    // set the window title
    QTFrame_SetWindowTitleFromFSSpec(myWindow, &myFSSpec, true);
 
    // make sure the movie or image file uses the window GWorld
    if (myMovie != NULL)
        SetMovieGWorld(myMovie, (CGrafPtr)QTFrame_GetPortFromWindowReference(myWindow), NULL);
 
    if (myImporter != NULL)
        GraphicsImportSetGWorld(myImporter, (CGrafPtr)QTFrame_GetPortFromWindowReference(myWindow), NULL);
 
    // create and configure the movie controller
    myMC = QTFrame_SetupController(myMovie, myWindow, true);
        
    // store movie info in the window record
    (**myWindowObject).fMovie = myMovie;
    (**myWindowObject).fController = myMC;
    (**myWindowObject).fGraphicsImporter = myImporter;
    (**myWindowObject).fFileResID = myResID;
    (**myWindowObject).fFileRefNum = myRefNum;
    (**myWindowObject).fCanResizeWindow = true;
    (**myWindowObject).fIsDirty = false;
    (**myWindowObject).fIsQTVRMovie = QTUtils_IsQTVRMovie(myMovie);
    (**myWindowObject).fInstance = NULL;
    (**myWindowObject).fAppData = NULL;
    (**myWindowObject).fFileFSSpec = myFSSpec;
    
    // do any application-specific window object initialization
    QTApp_SetupWindowObject(myWindowObject);
    
    // size the window to fit the movie and controller or image
    QTFrame_SizeWindowToMovie(myWindowObject);
 
    // set the movie's play hints to allow dynamic resizing
    SetMoviePlayHints(myMovie, hintsAllowDynamicResize, hintsAllowDynamicResize);
 
    // set the movie's position, if it has a 'WLOC' user data atom
    myErr = QTUtils_GetWindowPositionFromFile(myMovie, &myPoint);
 
    // show the window
#if TARGET_OS_MAC
    MoveWindow(myWindow, myPoint.h, myPoint.v, false);
    ShowWindow(myWindow);
    SelectWindow(myWindow);                             // make it front-most, since it's just been created
    InvalWindowRect(myWindow, GetWindowPortBounds(myWindow, &myRect));
#endif
#if TARGET_OS_WIN32
    SetWindowPos(myWindow, 0, myPoint.h, myPoint.v, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
    ShowWindow(myWindow, SW_SHOW);
    UpdateWindow(myWindow);
#endif
 
    // if the movie is a streamed movie, then start it playing immediately
    if (QTUtils_IsStreamedMovie(myMovie))
        MCDoAction(myMC, mcActionPrerollAndPlay, (void *)GetMoviePreferredRate(myMovie));
        
    // if the movie is an autoplay movie, then start it playing immediately
    if (QTUtils_IsAutoPlayMovie(myMovie))
        MCDoAction(myMC, mcActionPrerollAndPlay, (void *)GetMoviePreferredRate(myMovie));
        
    return(true);
    
bail:
    if (myWindow != NULL)
#if TARGET_OS_MAC
        DisposeWindow(myWindow);
#endif
#if TARGET_OS_WIN32
        SendMessage(ghWndMDIClient, WM_MDIDESTROY, (WPARAM)myWindow, 0L);
#endif
        
    if (myMC != NULL)
        DisposeMovieController(myMC);
        
    if (myMovie != NULL)
        DisposeMovie(myMovie);
        
    if (myRefNum != 0)
        CloseMovieFile(myRefNum);
 
    if (myImporter != NULL)
        CloseComponent(myImporter);
        
    MacSetPort(mySavedPort);    // restore the port that was active when this function was called
 
    return(false);
}
 
 
//////////
//
// QTFrame_SetupController
// Create and configure the movie controller.
//
//////////
 
MovieController QTFrame_SetupController (Movie theMovie, WindowReference theWindow, Boolean theMoveWindow)
{
#if TARGET_OS_WIN32
#pragma unused(theMoveWindow)
#endif
 
    MovieController         myMC = NULL;
    Rect                    myRect;
    WindowObject            myWindowObject = NULL;
    GrafPtr                 mySavedPort;
 
    if ((theMovie == NULL) || (theWindow == NULL))
        return(NULL);
        
    // get our window specific data
    myWindowObject = QTFrame_GetWindowObjectFromWindow(theWindow);
    if (myWindowObject == NULL)
        return(NULL);
        
    GetPort(&mySavedPort);
    MacSetPort(QTFrame_GetPortFromWindowReference(theWindow));
    
    // resize the movie bounding rect and offset to 0,0
    GetMovieBox(theMovie, &myRect);
    MacOffsetRect(&myRect, -myRect.left, -myRect.top);
    SetMovieBox(theMovie, &myRect);
    AlignWindow(QTFrame_GetWindowFromWindowReference(theWindow), false, &myRect, NULL);
 
    // create the movie controller
    myMC = NewMovieController(theMovie, &myRect, mcTopLeftMovie);
    if (myMC == NULL)
        return(NULL);
        
    // enable the default movie controller editing
    MCEnableEditing(myMC, true);
        
    // suppress movie badge
    MCDoAction(myMC, mcActionSetUseBadge, (void *)false);
 
    // set the initial looping state of the movie
    QTUtils_SetLoopingStateFromFile(theMovie, myMC);
    
    // install an action filter that does any application-specific movie controller action processing
    MCSetActionFilterWithRefCon(myMC, NewMCActionFilterWithRefConUPP(QTApp_MCActionFilterProc), (long)myWindowObject);
 
    // add grow box for the movie controller
    if ((**myWindowObject).fCanResizeWindow) {
#if TARGET_OS_WIN32
        RECT                myRect;
 
        GetWindowRect(GetDesktopWindow(), &myRect);
        OffsetRect(&myRect, -myRect.left, -myRect.top);
        QTFrame_ConvertWinToMacRect(&myRect, &gMCResizeBounds);
#endif
#if TARGET_OS_MAC
        GetRegionBounds(GetGrayRgn(), &gMCResizeBounds);
#endif
 
        MCDoAction(myMC, mcActionSetGrowBoxBounds, &gMCResizeBounds);
    }
    
#if TARGET_OS_MAC
    if (theMoveWindow)
        MoveWindow(theWindow, kDefaultWindowX, kDefaultWindowY, false);
#endif
 
    MacSetPort(mySavedPort);
 
    // add any application-specific controller functionality
    QTApp_SetupController(myMC);
        
    return(myMC);
}
 
 
//////////
//
// QTFrame_SaveAsMovieFile
// Save the movie in the specified window under a new name.
//
// Human interface guidelines for "Save As..." dictate that, if the user selects a new file name
// for the current movie, then that new file shall become the active one. This means that we need
// to close the current movie file and open the new one.
//
//////////
 
OSErr QTFrame_SaveAsMovieFile (WindowReference theWindow)
{
    WindowObject        myWindowObject = NULL;
    Movie               myMovie = NULL;
    FSSpec              myFile;
    Boolean             myIsSelected = false;
    Boolean             myIsReplacing = false;  
    StringPtr           myPrompt = QTUtils_ConvertCToPascalString(kSavePrompt);
    StringPtr           myFileName = QTUtils_ConvertCToPascalString(kSaveMovieFileName);
    OSErr               myErr = paramErr;
    
    // get the window object associated with the specified window
    myWindowObject = QTFrame_GetWindowObjectFromWindow(theWindow);
    if (myWindowObject == NULL)
        goto bail;
        
    myMovie = (**myWindowObject).fMovie;
    if (myMovie == NULL)
        goto bail;
        
    QTFrame_PutFile(myPrompt, myFileName, &myFile, &myIsSelected, &myIsReplacing);
    if (myIsSelected) {
        Movie           myNewMovie = NULL;
        MovieController myMC = NULL;
        short           myRefNum = kInvalidFileRefNum;
        short           myResID = movieInDataForkResID;
        
        //////////
        //
        // we have a valid FSSpec for the new movie file; now we want to flatten the existing
        // movie into the new movie file, then open the new movie file and read the movie out
        // of it; then we need to swap the window object data
        //
        //////////
        
        // delete any existing file of that name
        if (myIsReplacing) {
            myErr = DeleteMovieFile(&myFile);
            if (myErr != noErr)
                goto bail;
        }
        
        myNewMovie = FlattenMovieData(  myMovie,
                                        flattenAddMovieToDataFork | flattenForceMovieResourceBeforeMovieData,
                                        &myFile,
                                        sigMoviePlayer,
                                        smSystemScript,
                                        createMovieFileDeleteCurFile | createMovieFileDontCreateResFile);
        myErr = GetMoviesError();
        if ((myNewMovie == NULL) || (myErr != noErr))
            goto bail;
 
        // FlattenMovieData creates a new movie file and returns the movie to us; but it doesn't
        // return the file reference number or the movie resource ID, which we want to have; so
        // we will dump the movie returned by FlattenMovieData and open the movie file ourselves
        DisposeMovie(myNewMovie);
 
        // also, on MacOS, FlattenMovieData *always* creates a resource fork, even if we told it
        // not to do so (didn't we say "createMovieFileDontCreateResFile"?); so we'll explicitly
        // delete the resource fork now....
#if TARGET_OS_MAC
        myErr = FSpOpenRF(&myFile, fsRdWrPerm, &myRefNum);
        if (myErr == noErr) {
            SetEOF(myRefNum, 0L);
            FSClose(myRefNum);
        }
#endif
        
        myErr = OpenMovieFile(&myFile, &myRefNum, fsRdWrPerm);
        if (myErr != noErr)
            goto bail;
 
        // TO DO: use QTInfo_MakeFilePreview here, which doesn't always create a resource fork
//      MakeFilePreview(myRefNum, (ICMProgressProcRecordPtr)-1);
 
        // get the new movie from the file
        myErr = NewMovieFromFile(&myNewMovie, myRefNum, &myResID, NULL, newMovieActive, NULL);      
        if (myErr != noErr)
            goto bail;
 
        // create a new movie controller
        myMC = QTFrame_SetupController(myNewMovie, theWindow, false);
        
        //////////
        //
        // if we got to here, we've successfully created a new movie file, and NewMovieFromFile has
        // returned the new movie to us; so we need to close down the current movie and install the
        // new movie in its place
        //
        //////////
        
        // close the existing movie file
        if ((**myWindowObject).fFileRefNum != kInvalidFileRefNum)
            CloseMovieFile((**myWindowObject).fFileRefNum);
        
        // dispose of the existing movie controller and movie resource
        if ((**myWindowObject).fController != NULL)
            DisposeMovieController((**myWindowObject).fController);
            
        DisposeMovie(myMovie);
        
        // keep track of the new info
        (**myWindowObject).fMovie = myNewMovie;
        (**myWindowObject).fController = myMC;
        (**myWindowObject).fFileFSSpec = myFile;
        (**myWindowObject).fFileResID = myResID;
        (**myWindowObject).fFileRefNum = myRefNum;
        (**myWindowObject).fIsDirty = false;
 
        // make sure the movie uses the window GWorld in all situations
        SetMovieGWorld(myNewMovie, (CGrafPtr)QTFrame_GetPortFromWindowReference((**myWindowObject).fWindow), NULL);
 
        // set the window title
        QTFrame_SetWindowTitleFromFSSpec(theWindow, &myFile, true);
    } else {
        myErr = userCanceledErr;
    }
 
bail:
    free(myPrompt);
    free(myFileName);
    
    return(myErr);
}
 
 
//////////
//
// QTFrame_UpdateMovieFile
// Update the file (if any) attached to the movie.
//
//////////
 
Boolean QTFrame_UpdateMovieFile (WindowReference theWindow)
{
    WindowObject        myWindowObject = NULL;
    Movie               myMovie = NULL;
    OSErr               myErr = noErr;
    
    // get the window object associated with the specified window
    myWindowObject = QTFrame_GetWindowObjectFromWindow(theWindow);
    if (myWindowObject == NULL)
        return(false);
        
    myMovie = (**myWindowObject).fMovie;
    if (myMovie == NULL)
        return(false);
    
    // update the current volume setting
    QTUtils_UpdateMovieVolumeSetting(myMovie);
    
    if ((**myWindowObject).fFileRefNum == kInvalidFileRefNum)       // brand new movie, so no file attached to it
        myErr = QTFrame_SaveAsMovieFile(theWindow);
    else                                                            // we have an existing file; just update the movie resource
        myErr = UpdateMovieResource(myMovie, (**myWindowObject).fFileRefNum, (**myWindowObject).fFileResID, NULL);
    
    // TO DO: use QTInfo_MakeFilePreview here, which doesn't always create a resource fork
    //MakeFilePreview((**myWindowObject).fFileRefNum, (ICMProgressProcRecordPtr)-1);
 
    (**myWindowObject).fIsDirty = false;
 
    return(myErr == noErr);
}
 
 
//////////
//
// QTFrame_IdleMovieWindows
// Do idle-time processing on all open movie windows.
//
//////////
 
void QTFrame_IdleMovieWindows (void)
{   
    WindowReference         myWindow = NULL;
    MovieController         myMC = NULL;
    
    myWindow = QTFrame_GetFrontMovieWindow();
    while (myWindow != NULL) {
        myMC = QTFrame_GetMCFromWindow(myWindow);
        if (myMC != NULL)
            MCIdle(myMC);
            
        QTApp_Idle(myWindow);
        
        myWindow = QTFrame_GetNextMovieWindow(myWindow);
    }
}
 
 
//////////
//
// QTFrame_CloseMovieWindows
// Close all open movie windows.
//
//////////
 
void QTFrame_CloseMovieWindows (void)
{
#if TARGET_OS_MAC   
    WindowReference         myWindow = NULL;
    WindowReference         myNextWindow = NULL;
 
    myWindow = QTFrame_GetFrontMovieWindow();
    while (myWindow != NULL) {
        myNextWindow = QTFrame_GetNextMovieWindow(myWindow);
        QTFrame_DestroyMovieWindow(myWindow);
        myWindow = myNextWindow;
    }
#endif
#if TARGET_OS_WIN32
    SendMessage(ghWnd, WM_COMMAND, (WPARAM)IDM_WINDOWCLOSEALL, 0L);
#endif
}
 
 
//////////
//
// QTFrame_CreateWindowObject
// Create a new window object associated with the specified window.
//
//////////
 
void QTFrame_CreateWindowObject (WindowReference theWindow)
{
    WindowObject            myWindowObject = NULL;
 
    if (theWindow == NULL)
        return;
        
    // allocate space for a window object record and fill in some of its fields
    myWindowObject = (WindowObject)NewHandleClear(sizeof(WindowObjectRecord));
    if (myWindowObject != NULL) {
        (**myWindowObject).fWindow = theWindow;
        (**myWindowObject).fController = NULL;
        (**myWindowObject).fObjectType = kApplicationSignature;
        (**myWindowObject).fCanResizeWindow = true;
        (**myWindowObject).fInstance = NULL;
        (**myWindowObject).fIsDirty = false;
        (**myWindowObject).fAppData = NULL;
    }
    
    // associate myWindowObject (which may be NULL) with the window
#if TARGET_OS_MAC
    SetWRefCon(theWindow, (long)myWindowObject);
#endif
#if TARGET_OS_WIN32
    SetWindowLong(theWindow, GWL_USERDATA, (LPARAM)myWindowObject);
    
    // associate a GrafPort with this window 
    CreatePortAssociation(theWindow, NULL, 0L);
#endif
    
    // set the current port to the new window
    MacSetPort(QTFrame_GetPortFromWindowReference(theWindow));
}
 
 
//////////
//
// QTFrame_CloseWindowObject
// Close a window object and any associated data.
//
//////////
 
void QTFrame_CloseWindowObject (WindowObject theWindowObject)
{
    if (theWindowObject == NULL)
        return;
        
    // close the movie file
    if ((**theWindowObject).fFileRefNum != kInvalidFileRefNum) {
        CloseMovieFile((**theWindowObject).fFileRefNum);
        (**theWindowObject).fFileRefNum = kInvalidFileRefNum;
    }
    
    // dispose movie controller and movie 
    if ((**theWindowObject).fController != NULL) {
        MCSetActionFilterWithRefCon((**theWindowObject).fController, NULL, 0L);
        DisposeMovieController((**theWindowObject).fController);
        (**theWindowObject).fController = NULL;
    }
    
    if ((**theWindowObject).fMovie != NULL) {
        DisposeMovie((**theWindowObject).fMovie);
        (**theWindowObject).fMovie = NULL;
    }
    
    // close the graphics importer, if any
    if ((**theWindowObject).fGraphicsImporter != NULL) {
        CloseComponent((**theWindowObject).fGraphicsImporter);
        (**theWindowObject).fGraphicsImporter = NULL;
    }
    
    // do any application-specific window clean-up
    QTApp_RemoveWindowObject(theWindowObject);
    
    DisposeHandle((Handle)theWindowObject);
}
 
 
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Window-walking utilities.
//
// Use these functions to iterate through all windows or movie windows belonging to the application.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
//////////
//
// QTFrame_GetFrontAppWindow
// Return a reference to the frontmost application window (whether or not it's a movie window).
//
//////////
 
WindowReference QTFrame_GetFrontAppWindow (void)
{
#if TARGET_OS_MAC
    return(FrontWindow());
#endif
#if TARGET_OS_WIN32
    return(GetWindow(ghWnd, GW_HWNDFIRST));
#endif
}
 
 
//////////
//
// QTFrame_GetNextAppWindow
// Return a reference to the next application window (whether or not it's a movie window).
//
//////////
 
WindowReference QTFrame_GetNextAppWindow (WindowReference theWindow)
{
#if TARGET_OS_MAC
    return(theWindow == NULL ? NULL : GetNextWindow(theWindow));
#endif
#if TARGET_OS_WIN32
    return(GetWindow(theWindow, GW_HWNDNEXT));
#endif
}
 
 
//////////
//
// QTFrame_GetFrontMovieWindow
// Return a reference to the frontmost movie window.
//
//////////
 
WindowReference QTFrame_GetFrontMovieWindow (void)
{
    WindowReference         myWindow;
 
#if TARGET_OS_MAC
    myWindow = QTFrame_GetFrontAppWindow();
    while ((myWindow != NULL) && (QTFrame_GetWindowObjectFromWindow(myWindow) == NULL))
        myWindow = QTFrame_GetNextAppWindow(myWindow);
#endif
 
#if TARGET_OS_WIN32
    myWindow = (HWND)SendMessage(ghWndMDIClient, WM_MDIGETACTIVE, 0, 0L);
#endif
 
    return(myWindow);
}
 
 
//////////
//
// QTFrame_GetNextMovieWindow
// Return a reference to the next movie window.
//
//////////
 
WindowReference QTFrame_GetNextMovieWindow (WindowReference theWindow)
{
    WindowReference         myWindow;
 
#if TARGET_OS_MAC
    myWindow = QTFrame_GetNextAppWindow(theWindow);
    while ((myWindow != NULL) && (QTFrame_GetWindowObjectFromWindow(myWindow) == NULL))
        myWindow = QTFrame_GetNextAppWindow(myWindow);
#endif
 
#if TARGET_OS_WIN32
    myWindow = GetWindow(theWindow, GW_HWNDNEXT);
#endif
 
    return(myWindow);
}
 
 
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Data-retrieval utilities.
//
// Use the following functions to retrieve the window object, the application-specific data, or the movie
// controller that is associated with a window.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
//////////
//
// QTFrame_GetWindowObjectFromFrontWindow
// Get the window object (if any) associated with the front window.
//
//////////
 
WindowObject QTFrame_GetWindowObjectFromFrontWindow (void)
{
    return(QTFrame_GetWindowObjectFromWindow(QTFrame_GetFrontMovieWindow()));
}
 
 
//////////
//
// QTFrame_GetWindowObjectFromWindow
// Get the window object (if any) associated with the specified window.
//
//////////
 
WindowObject QTFrame_GetWindowObjectFromWindow (WindowReference theWindow)
{
    WindowObject        myWindowObject = NULL;
 
    if (!QTFrame_IsAppWindow(theWindow))
        return(NULL);
            
#if TARGET_OS_MAC
    myWindowObject = (WindowObject)GetWRefCon(theWindow);
#endif
#if TARGET_OS_WIN32
    myWindowObject = (WindowObject)GetWindowLong(theWindow, GWL_USERDATA);
#endif
 
    // make sure this is a window object
    if (!QTFrame_IsWindowObjectOurs(myWindowObject))
        return(NULL);
        
    return(myWindowObject);
}
 
 
//////////
//
// QTFrame_GetMCFromFrontWindow
// Get the movie controller (if any) associated with the front window.
//
//////////
 
MovieController QTFrame_GetMCFromFrontWindow (void)
{
    return(QTFrame_GetMCFromWindow(QTFrame_GetFrontMovieWindow()));
}
 
 
//////////
//
// QTFrame_GetMCFromWindow
// Get the movie controller (if any) associated with the specified window.
//
//////////
 
MovieController QTFrame_GetMCFromWindow (WindowReference theWindow)
{
    MovieController     myMC = NULL;
    WindowObject        myWindowObject = NULL;
        
    myWindowObject = QTFrame_GetWindowObjectFromWindow(theWindow);
    if (myWindowObject != NULL)
        myMC = (**myWindowObject).fController;
        
    return(myMC);
}
 
 
//////////
//
// QTFrame_GetQTVRInstanceFromFrontWindow
// Get the QTVRInstance (if any) associated with the front window.
//
//////////
 
QTVRInstance QTFrame_GetQTVRInstanceFromFrontWindow (void)
{
    return(QTFrame_GetQTVRInstanceFromWindow(QTFrame_GetFrontMovieWindow()));
}
 
 
//////////
//
// QTFrame_GetQTVRInstanceFromWindow
// Get the QTVRInstance (if any) associated with the specified window.
//
//////////
 
QTVRInstance QTFrame_GetQTVRInstanceFromWindow (WindowReference theWindow)
{
    QTVRInstance        myInstance = NULL;
    WindowObject        myWindowObject = NULL;
    
    myWindowObject = QTFrame_GetWindowObjectFromWindow(theWindow);
    if (myWindowObject != NULL)
        myInstance = (**myWindowObject).fInstance;
        
    return(myInstance);
}
 
 
//////////
//
// QTFrame_GetAppDataFromFrontWindow
// Get the application-specific data associated with the front window.
//
//////////
 
Handle QTFrame_GetAppDataFromFrontWindow (void)
{
    return(QTFrame_GetAppDataFromWindow(QTFrame_GetFrontMovieWindow()));
}
 
 
//////////
//
// QTFrame_GetAppDataFromWindow
// Get the application-specific data associated with the specified window.
//
//////////
 
Handle QTFrame_GetAppDataFromWindow (WindowReference theWindow)
{
    WindowObject        myWindowObject = NULL;
    
    myWindowObject = QTFrame_GetWindowObjectFromWindow(theWindow);
    if (myWindowObject == NULL)
        return(NULL);
        
    return(QTFrame_GetAppDataFromWindowObject(myWindowObject));
}
 
 
//////////
//
// QTFrame_GetAppDataFromWindowObject
// Get the application-specific data associated with the specified window object.
//
//////////
 
Handle QTFrame_GetAppDataFromWindowObject (WindowObject theWindowObject)
{
    // make sure this is a window object belonging to our application
    if (!QTFrame_IsWindowObjectOurs(theWindowObject))
        return(NULL);
    
    return((**theWindowObject).fAppData);
}
 
 
//////////
//
// QTFrame_IsWindowObjectOurs
// Does the specified window object belong to our application?
//
//////////
 
Boolean QTFrame_IsWindowObjectOurs (WindowObject theWindowObject)
{
    OSType      myType = 0L;
 
    if ((theWindowObject == NULL) || (*theWindowObject == NULL))
        return(false);
        
    myType = (**theWindowObject).fObjectType;
    return(myType == kApplicationSignature);
}
 
 
//////////
//
// QTFrame_IsAppWindow
// Does the specified window belong to our application?
//
//////////
 
Boolean QTFrame_IsAppWindow (WindowReference theWindow)
{
    if (theWindow == NULL)
        return(false);
 
#if TARGET_OS_MAC
    return(GetWindowKind(theWindow) >= kApplicationWindowKind);
#endif
#if TARGET_OS_WIN32
    return(true);
#endif
}
 
 
//////////
//
// QTFrame_IsMovieWindow
// Does the specified window contain a movie?
//
//////////
 
Boolean QTFrame_IsMovieWindow (WindowReference theWindow)
{
    WindowObject        myWindowObject = NULL;
 
    if (!QTFrame_IsAppWindow(theWindow))
        return(false);
        
    myWindowObject = QTFrame_GetWindowObjectFromWindow(theWindow);
    if (myWindowObject != NULL)
        return((**myWindowObject).fController != NULL);
        
    return(false);
}
 
 
//////////
//
// QTFrame_IsImageWindow
// Does the specified window contain an image?
//
//////////
 
Boolean QTFrame_IsImageWindow (WindowReference theWindow)
{
    WindowObject        myWindowObject = NULL;
 
    if (!QTFrame_IsAppWindow(theWindow))
        return(false);
        
    myWindowObject = QTFrame_GetWindowObjectFromWindow(theWindow);
    if (myWindowObject != NULL)
        return((**myWindowObject).fGraphicsImporter != NULL);
        
    return(false);
}
 
 
//////////
//
// QTFrame_ActivateController
// Activate or deactivate the movie controller in the specified window.
//
//////////
 
void QTFrame_ActivateController (WindowReference theWindow, Boolean IsActive)
{
    WindowObject        myWindowObject = NULL;
    MovieController     myMC = NULL;
    GrafPtr             mySavedPort = NULL;
    
    if (theWindow == NULL)
        return;
    
    GetPort(&mySavedPort);
    MacSetPort(QTFrame_GetPortFromWindowReference(theWindow));
    
    // get the window object associated with the specified window
    myWindowObject = QTFrame_GetWindowObjectFromWindow(theWindow);
    if (myWindowObject != NULL) {
        myMC = (**myWindowObject).fController;
        if (myMC != NULL)
            MCActivate(myMC, QTFrame_GetWindowFromWindowReference(theWindow), IsActive);
    }
    
    MacSetPort(mySavedPort);
}
 
 
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Miscellaneous utilities.
//
// Use the following functions to play beeps, manipulate menus, and do other miscellaneous things.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
//////////
//
// QTFrame_Beep
// Beep.
//
//////////
 
void QTFrame_Beep (void)
{
#if TARGET_OS_MAC
    SysBeep(30);
#endif
#if TARGET_OS_WIN32
    MessageBeep(MB_OK);
#endif
}
 
 
//////////
//
// QTFrame_SetMenuState
// Set the enabled/disabled state of a menu.
//
// On Windows, the theMenuItem parameter must be the (0-based) index in the menu bar of the
// desired pull-down menu.
//
//////////
 
void QTFrame_SetMenuState (MenuReference theMenu, UInt16 theMenuItem, short theState)
{
#if TARGET_OS_MAC
#pragma unused(theMenuItem)
    QTFrame_SetMenuItemState(theMenu, 0, theState);     // menu item == 0 means the entire menu
#endif
#if TARGET_OS_WIN32
    QTFrame_SetMenuItemState(theMenu, theMenuItem, theState | MF_BYPOSITION);
#endif
}
 
 
//////////
//
// QTFrame_SetMenuItemState
// Set the enabled/disabled state of a menu item.
//
// When running under MacOS 8.5.1, EnableMenuItem and DisableMenuItem seem to do nasty things
// to the keyboard equivalents associated with a menu; so we'll work around that problem here.
//
//////////
 
void QTFrame_SetMenuItemState (MenuReference theMenu, UInt16 theMenuItem, short theState)
{
#if TARGET_OS_MAC
    UInt8       myModifiers;
    
    // get the existing menu item modifiers
    GetMenuItemModifiers(theMenu, MENU_ITEM(theMenuItem), &myModifiers);
    
    if (theState == kEnableMenuItem)
        EnableMenuItem(theMenu, MENU_ITEM(theMenuItem));
    else
        DisableMenuItem(theMenu, MENU_ITEM(theMenuItem));
        
    // restore the previous menu item modifiers
    SetMenuItemModifiers(theMenu, MENU_ITEM(theMenuItem), myModifiers);
#endif
#if TARGET_OS_WIN32
    EnableMenuItem(theMenu, (UINT)theMenuItem, (UINT)theState);
#endif
}
 
 
//////////
//
// QTFrame_SetMenuItemLabel
// Set the label (that is, the text) of a menu item.
//
//////////
 
void QTFrame_SetMenuItemLabel (MenuReference theMenu, UInt16 theMenuItem, char *theText)
{
#if TARGET_OS_MAC
    Str255      myString;
    short       mySIndex, myTIndex;
 
    // we need to remove the '&' character while converting to a Pascal string  
    mySIndex = 1;
    for (myTIndex = 0; myTIndex < strlen(theText); myTIndex++) {
        if (theText[myTIndex] != '&') {
            myString[mySIndex] = theText[myTIndex];
            mySIndex++;
        }
    }
    
    myString[0] = mySIndex - 1;
    
    SetMenuItemText(theMenu, MENU_ITEM(theMenuItem), myString);
#endif
#if TARGET_OS_WIN32
    UINT        myState;
    
    // make sure that we preserve the current menu state
    myState = GetMenuState(theMenu, (UINT)theMenuItem, MF_BYCOMMAND);
    ModifyMenu(theMenu, (UINT)theMenuItem, MF_BYCOMMAND | MF_STRING | myState, (UINT)theMenuItem, (LPSTR)theText);
#endif
}
 
 
//////////
//
// QTFrame_SetMenuItemCheck
// Set the check mark state state of a menu item.
//
//////////
 
void QTFrame_SetMenuItemCheck (MenuReference theMenu, UInt16 theMenuItem, Boolean theState)
{
#if TARGET_OS_MAC
    MacCheckMenuItem(theMenu, MENU_ITEM(theMenuItem), theState);
#endif
#if TARGET_OS_WIN32
    CheckMenuItem(theMenu, (UINT)theMenuItem, theState ? MF_CHECKED : MF_UNCHECKED);
#endif
}
 
 
//////////
//
// QTFrame_GetPortFromWindowReference 
// Return the graphics port associated with a window reference.
//
//////////
 
GrafPtr QTFrame_GetPortFromWindowReference (WindowReference theWindow)
{
#if TARGET_OS_MAC
    return((GrafPtr)GetWindowPort(theWindow));
#endif
#if TARGET_OS_WIN32
    return(GetNativeWindowPort(theWindow));
#endif
}
 
 
//////////
//
// QTFrame_GetWindowReferenceFromPort
// Return the window reference associated with a graphics port.
//
//////////
 
WindowReference QTFrame_GetWindowReferenceFromPort (GrafPtr thePort)
{
#if TARGET_OS_MAC
    return((WindowReference)GetWindowFromPort((CGrafPtr)thePort));
#endif
#if TARGET_OS_WIN32
    return((WindowReference)GetPortNativeWindow(thePort));
#endif
}
 
 
//////////
//
// QTFrame_GetWindowFromWindowReference
// Return the Macintosh window associated with a window reference.
//
//////////
 
WindowPtr QTFrame_GetWindowFromWindowReference (WindowReference theWindow)
{
#if TARGET_OS_MAC
    return((WindowPtr)theWindow);
#endif
#if TARGET_OS_WIN32
    return((WindowPtr)GetNativeWindowPort(theWindow));
#endif
}
 
 
//////////
//
// QTFrame_GetWindowReferenceFromWindow
// Return the window reference associated with a Macintosh window.
//
//////////
 
WindowReference QTFrame_GetWindowReferenceFromWindow (WindowPtr theWindow)
{
#if TARGET_OS_MAC
    return((WindowReference)theWindow);
#endif
#if TARGET_OS_WIN32
    return((WindowReference)GetPortNativeWindow((GrafPtr)theWindow));
#endif
}
 
 
/////////
//
// QTFrame_GetWindowWidth
// Return the width of the specified window.
//
//////////
 
short QTFrame_GetWindowWidth (WindowReference theWindow)
{
#if TARGET_OS_MAC
    Rect        myRect = {0, 0, 0, 0};
 
    if (theWindow != NULL)
        GetWindowPortBounds(theWindow, &myRect);
#endif
#if TARGET_OS_WIN32
    RECT        myRect = {0L, 0L, 0L, 0L};
 
    if (theWindow != NULL)
        GetWindowRect(theWindow, &myRect);
#endif
 
    return((short)(myRect.right - myRect.left));
}
 
 
//////////
//
// QTFrame_SetWindowTitleFromFSSpec
// Set the title of the specified window, using the name contained in the specified FSSpec.
//
//////////
 
void QTFrame_SetWindowTitleFromFSSpec (WindowReference theWindow, FSSpecPtr theFSSpecPtr, Boolean theAddToRecentDocs)
{
#if TARGET_OS_MAC
#pragma unused(theAddToRecentDocs)
    SetWTitle(theWindow, theFSSpecPtr->name);
#endif
#if TARGET_OS_WIN32
    char    *myTempName;
    char    myWindName[MAX_PATH];
 
    // get the full pathname contained in the FSSpec (which is a Str255)
    myTempName = QTUtils_ConvertPascalToCString(theFSSpecPtr->name);
 
    // get the movie file name from the full pathname
    QTFrame_GetDisplayName(myTempName, myWindName);
 
    // set the window title
    SetWindowText(theWindow, myWindName);
    
    // add this document to the Documents list, if so instructed
    if (theAddToRecentDocs)
        SHAddToRecentDocs(SHARD_PATH, myTempName);
    
    free(myTempName);
#endif
}
 
 
//////////
//
// QTFrame_SizeWindowToMovie
// Set the window size to exactly fit the movie and controller (if visible) or the image.
//
//////////
 
void QTFrame_SizeWindowToMovie (WindowObject theWindowObject)
{
    Rect                        myRect;
 
#if TARGET_OS_WIN32
    gWeAreSizingWindow = true;
#endif
 
    if (theWindowObject == NULL)
        goto bail;
 
    if (QTFrame_IsImageWindow((**theWindowObject).fWindow)) {
        // it's an image window
        GraphicsImportGetBoundsRect((**theWindowObject).fGraphicsImporter, &myRect);
    } else if (QTFrame_IsMovieWindow((**theWindowObject).fWindow)) {
        // it's a movie window
        GetMovieBox((**theWindowObject).fMovie, &myRect);
 
        if ((**theWindowObject).fController != NULL)
            if (MCGetVisible((**theWindowObject).fController))
                MCGetControllerBoundsRect((**theWindowObject).fController, &myRect);
        
        // make sure that the movie has a non-zero width;
        // a zero height is okay (for example, with a music movie with no controller bar)
        if (myRect.right - myRect.left == 0) {
            myRect.left = 0;
            myRect.right = QTFrame_GetWindowWidth((**theWindowObject).fWindow);
        }
    } else {
        // it's neither an image window nor a movie window; punt
        goto bail;
    }
 
    SizeWindow(QTFrame_GetWindowFromWindowReference((**theWindowObject).fWindow),
                                            myRect.right - myRect.left,
                                            myRect.bottom - myRect.top,
                                            true);
 
bail:                                       
#if TARGET_OS_WIN32
    gWeAreSizingWindow = false;
#endif
 
    return;
}
 
 
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// File-opening and -saving utilities.
//
// The functions are meant to provide replacements for StandardGetFilePreview and StandardPutFile, which
// are not supported under Carbon. However, Navigation Services is not (yet, at any rate) supported under
// Windows, so we still need to call through to the Standard File Package.
//
// The Navigation Services portion of this code is based selectively on the file NavigationServicesSupport.c
// by Yan Arrouye and on the developer documentation "Programming With Navigation Services 1.1". The code that
// determines which files can be opened by QuickTime is based on code by Sam Bushell in CarbonMovieEditor.c.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
//////////
//
// QTFrame_PutFile
// Save a file under the specified name. Return Boolean values indicating whether the user selected a file
// and whether the selected file is replacing an existing file.
//
//////////
 
OSErr QTFrame_PutFile (ConstStr255Param thePrompt, ConstStr255Param theFileName, FSSpecPtr theFSSpecPtr, Boolean *theIsSelected, Boolean *theIsReplacing)
{
#if TARGET_OS_WIN32
    StandardFileReply   myReply;
#endif
#if TARGET_OS_MAC
    NavReplyRecord      myReply;
    NavDialogOptions    myDialogOptions;
    NavEventUPP         myEventUPP = NewNavEventUPP(QTFrame_HandleNavEvent);
#endif
    OSErr               myErr = noErr;
 
    if ((theFSSpecPtr == NULL) || (theIsSelected == NULL) || (theIsReplacing == NULL))
        return(paramErr);
    
    // deactivate any frontmost movie window
    QTFrame_ActivateController(QTFrame_GetFrontMovieWindow(), false);
 
    // assume we are not replacing an existing file
    *theIsReplacing = false;
    
#if TARGET_OS_WIN32
    StandardPutFile(thePrompt, theFileName, &myReply);
    *theFSSpecPtr = myReply.sfFile;
    *theIsSelected = myReply.sfGood;
    if (myReply.sfGood)
        *theIsReplacing = myReply.sfReplacing;
#endif
 
#if TARGET_OS_MAC
    // specify the options for the dialog box
    NavGetDefaultDialogOptions(&myDialogOptions);
    myDialogOptions.dialogOptionFlags += kNavNoTypePopup;
    myDialogOptions.dialogOptionFlags += kNavDontAutoTranslate;
    BlockMoveData(theFileName, myDialogOptions.savedFileName, theFileName[0] + 1);
    BlockMoveData(gAppName, myDialogOptions.clientName, gAppName[0] + 1);
    BlockMoveData(thePrompt, myDialogOptions.message, thePrompt[0] + 1);
    
    // prompt the user for a file
    myErr = NavPutFile(NULL, &myReply, &myDialogOptions, myEventUPP, MovieFileType, sigMoviePlayer, NULL);
    if ((myErr == noErr) && myReply.validRecord) {
        AEKeyword       myKeyword;
        DescType        myActualType;
        Size            myActualSize = 0;
        
        // get the FSSpec for the selected file
        if (theFSSpecPtr != NULL)
            myErr = AEGetNthPtr(&(myReply.selection), 1, typeFSS, &myKeyword, &myActualType, theFSSpecPtr, sizeof(FSSpec), &myActualSize);
    }
        
    *theIsSelected = myReply.validRecord;
    if (myReply.validRecord)
        *theIsReplacing = myReply.replacing;
        
    NavDisposeReply(&myReply);
    DisposeNavEventUPP(myEventUPP);
#endif
 
    return(myErr);
}
    
 
//////////
//
// QTFrame_GetOneFileWithPreview
// Display the appropriate file-opening dialog box, with an optional QuickTime preview pane. If the user
// selects a file, return information about it using the theFSSpecPtr parameter.
//
// Note that both StandardGetFilePreview and NavGetFile use the function specified by theFilterProc as a
// file filter. This framework always passes NULL in the theFilterProc parameter. If you use this function
// in your own code, keep in mind that on Windows the function specifier must be of type FileFilterUPP and 
// on Macintosh it must be of type NavObjectFilterUPP. (You can use the QTFrame_GetFileFilterUPP to create
// a function specifier of the appropriate type.) Also keep in mind that Navigation Services expects a file 
// filter function to return true if a file is to be displayed, while the Standard File Package expects the
// filter to return false if a file is to be displayed.
//
//////////
 
OSErr QTFrame_GetOneFileWithPreview (short theNumTypes, QTFrameTypeListPtr theTypeList, FSSpecPtr theFSSpecPtr, void *theFilterProc)
{
#if TARGET_OS_WIN32
    StandardFileReply   myReply;
#endif
#if TARGET_OS_MAC
    NavReplyRecord      myReply;
    NavDialogOptions    myDialogOptions;
    NavTypeListHandle   myOpenList = NULL;
    NavEventUPP         myEventUPP = NewNavEventUPP(QTFrame_HandleNavEvent);
#endif
    OSErr               myErr = noErr;
    
    if (theFSSpecPtr == NULL)
        return(paramErr);
    
    // deactivate any frontmost movie window
    QTFrame_ActivateController(QTFrame_GetFrontMovieWindow(), false);
 
#if TARGET_OS_WIN32
    // prompt the user for a file
    StandardGetFilePreview((FileFilterUPP)theFilterProc, theNumTypes, (ConstSFTypeListPtr)theTypeList, &myReply);
    if (!myReply.sfGood)
        return(userCanceledErr);
    
    // make an FSSpec record
    myErr = FSMakeFSSpec(myReply.sfFile.vRefNum, myReply.sfFile.parID, myReply.sfFile.name, theFSSpecPtr);
#endif
 
#if TARGET_OS_MAC
    // specify the options for the dialog box
    NavGetDefaultDialogOptions(&myDialogOptions);
    myDialogOptions.dialogOptionFlags -= kNavNoTypePopup;
    myDialogOptions.dialogOptionFlags -= kNavAllowMultipleFiles;
    BlockMoveData(gAppName, myDialogOptions.clientName, gAppName[0] + 1);
    
    // create a handle to an 'open' resource
    myOpenList = (NavTypeListHandle)QTFrame_CreateOpenHandle(kApplicationSignature, theNumTypes, theTypeList);
    if (myOpenList != NULL)
        HLock((Handle)myOpenList);
    
    // prompt the user for a file
    myErr = NavGetFile(NULL, &myReply, &myDialogOptions, myEventUPP, NULL, (NavObjectFilterUPP)theFilterProc, myOpenList, NULL);
    if ((myErr == noErr) && myReply.validRecord) {
        AEKeyword       myKeyword;
        DescType        myActualType;
        Size            myActualSize = 0;
        
        // get the FSSpec for the selected file
        if (theFSSpecPtr != NULL)
            myErr = AEGetNthPtr(&(myReply.selection), 1, typeFSS, &myKeyword, &myActualType, theFSSpecPtr, sizeof(FSSpec), &myActualSize);
 
        NavDisposeReply(&myReply);
    }
    
    if (myOpenList != NULL) {
        HUnlock((Handle)myOpenList);
        DisposeHandle((Handle)myOpenList);
    }
    
    DisposeNavEventUPP(myEventUPP);
#endif
 
    return(myErr);
}
 
 
//////////
//
// QTFrame_HandleNavEvent
// A callback procedure that handles events while a Navigation Service dialog box is displayed.
//
//////////
 
PASCAL_RTN void QTFrame_HandleNavEvent (NavEventCallbackMessage theCallBackSelector, NavCBRecPtr theCallBackParms, void *theCallBackUD)
{
#pragma unused(theCallBackUD)
    if (theCallBackParms == NULL)
        return;
 
    if (theCallBackParms->eventData.eventDataParms.event == NULL)
        return;
 
    if (theCallBackSelector == kNavCBEvent) {
        switch (theCallBackParms->eventData.eventDataParms.event->what) {
            case updateEvt:
            case activateEvt:
#if TARGET_OS_MAC
                QTFrame_HandleEvent(theCallBackParms->eventData.eventDataParms.event);
#endif
                break;
            case nullEvent:
                QTFrame_IdleMovieWindows();
                break;
        }
    }
}
 
 
//////////
//
// QTFrame_CreateOpenHandle
// Return a handle to a dynamically-created 'open' resource.
//
//////////
 
Handle QTFrame_CreateOpenHandle (OSType theApplicationSignature, short theNumTypes, QTFrameTypeListPtr theTypeList)
{
    Handle          myHandle = NULL;
    
    if (theTypeList == NULL)
        return(myHandle);
    
    if (theNumTypes > 0) {
        myHandle = NewHandle(sizeof(NavTypeList) + (theNumTypes * sizeof(OSType)));
        if (myHandle != NULL) {
            NavTypeListHandle   myOpenResHandle = (NavTypeListHandle)myHandle;
            
            (*myOpenResHandle)->componentSignature = theApplicationSignature;
            (*myOpenResHandle)->osTypeCount = theNumTypes;
            BlockMoveData(theTypeList, (*myOpenResHandle)->osType, theNumTypes * sizeof(OSType));
        }
    }
    
    return(myHandle);
}
 
 
//////////
//
// QTFrame_GetFileFilterUPP
// Return a UPP for the specified file-selection filter function.
//
// The caller is responsible for disposing of the UPP returned by this function (by calling DisposeNavObjectFilterUPP).
//
//////////
 
QTFrameFileFilterUPP QTFrame_GetFileFilterUPP (ProcPtr theFileFilterProc)
{
#if TARGET_OS_MAC
    return(NewNavObjectFilterUPP((NavObjectFilterProcPtr)theFileFilterProc));
#endif
#if TARGET_OS_WIN32
    return(NewFileFilterProc(theFileFilterProc));
#endif
}
 
 
//////////
//
// QTFrame_FilterFiles
// Filter files for a file-opening dialog box.
//
// The default behavior here is to accept all files that can be opened by QuickTime, whether directly
// or using a movie importer or a graphics importer.
//
//////////
 
#if TARGET_OS_MAC
PASCAL_RTN Boolean QTFrame_FilterFiles (AEDesc *theItem, void *theInfo, void *theCallBackUD, NavFilterModes theFilterMode)
{
#pragma unused(theCallBackUD, theFilterMode)
    NavFileOrFolderInfo     *myInfo = (NavFileOrFolderInfo *)theInfo;
    
    if (gValidFileTypes == NULL)
        QTFrame_BuildFileTypeList();
 
    if (theItem->descriptorType == typeFSS) {
        if (!myInfo->isFolder) {
            OSType          myType = myInfo->fileAndFolder.fileInfo.finderInfo.fdType;
            OSType          *myTypes = (OSType *)*gValidFileTypes;
            short           myCount;
            short           myIndex;
            
            // see whether the file type is in the list of file types that our application can open 
            myCount = GetHandleSize(gValidFileTypes) / sizeof(OSType);
            for (myIndex = 0; myIndex < myCount; myIndex++)
                if (myType == myTypes[myIndex])
                    return(true);
 
            // if we got to here, it's a file we cannot open
            return(false);      
        }
    }
    
    // if we got to here, it's a folder or non-HFS object
    return(true);
}
#endif
#if TARGET_OS_WIN32
PASCAL_RTN Boolean QTFrame_FilterFiles (CInfoPBPtr thePBPtr)
{
#pragma unused(thePBPtr)
    return(false);
}
#endif
 
 
//////////
//
// QTFrame_BuildFileTypeList
// Build a list of file types that QuickTime can open.
//
//////////
 
OSErr QTFrame_BuildFileTypeList (void)
{
    long        myIndex = 0;
    OSType      *myTypes;
 
    // if we've already built the list, just return
    if (gValidFileTypes != NULL)
        return(noErr);
    
    // allocate a block of memory to hold a preset number of file types; we'll resize this block
    // while building the list if we need more room; we always resize it after building the list,
    // to truncate it to the exact size required
    gValidFileTypes = NewHandleClear(sizeof(OSType) * kDefaultFileTypeCount);
    if (gValidFileTypes == NULL)
        return(memFullErr);
    
    myTypes = (OSType *)*gValidFileTypes;
    
    // we can open any files of type kQTFileTypeMovie
    myTypes[myIndex++] = kQTFileTypeMovie;
    
    // we can open any files for which QuickTime supplies a movie importer component
    QTFrame_AddComponentFileTypes(MovieImportType, &myIndex);
    
    // we can open any files for which QuickTime supplies a graphics importer component
    gFirstGITypeIndex = myIndex;
    QTFrame_AddComponentFileTypes(GraphicsImporterComponentType, &myIndex);
 
    // resize the pointer to hold the exact number of valid file types
    SetHandleSize(gValidFileTypes, myIndex * sizeof(OSType));
    
    return(MemError());
}
 
 
//////////
//
// QTFrame_AddComponentFileTypes
// Add all subtypes of the specified component type to the global list of file types.
//
//////////
 
static void QTFrame_AddComponentFileTypes (OSType theComponentType, long *theNextIndex)
{
    ComponentDescription        myFindCompDesc = {0, 0, 0, 0, 0};
    ComponentDescription        myInfoCompDesc = {0, 0, 0, 0, 0};
    Component                   myComponent = NULL;
    OSType                      *myTypes = NULL;
 
    myFindCompDesc.componentType = theComponentType;
    myFindCompDesc.componentFlags = 0;
    myFindCompDesc.componentFlagsMask = movieImportSubTypeIsFileExtension;
 
    myComponent = FindNextComponent(myComponent, &myFindCompDesc);
    while (myComponent != NULL) {
        GetComponentInfo(myComponent, &myInfoCompDesc, NULL, NULL, NULL);
        
        if (gValidFileTypes == NULL)
            return;
            
        myTypes = (OSType *)*gValidFileTypes;
        myTypes[*theNextIndex] = myInfoCompDesc.componentSubType;
        *theNextIndex += 1;
        
        // resize the block of file types, if we are about to reach the limit
        if (*theNextIndex == GetHandleSize(gValidFileTypes) / (long)sizeof(OSType)) {
            SetHandleSize(gValidFileTypes, GetHandleSize(gValidFileTypes) + (kDefaultFileTypeCount * sizeof(OSType)));
            if (MemError() != noErr)
                return;
        }
        
        myComponent = FindNextComponent(myComponent, &myFindCompDesc);
    }
}
 
 
#if TARGET_OS_WIN32
//////////
//
// QTFrame_ConvertMacToWinRect
// Convert a Macintosh Rect structure into a Windows RECT structure.
//
//////////
 
void QTFrame_ConvertMacToWinRect (Rect *theMacRect, RECT *theWinRect)
{
    theWinRect->top = (long)theMacRect->top;
    theWinRect->left = (long)theMacRect->left;
    theWinRect->bottom = (long)theMacRect->bottom;
    theWinRect->right = (long)theMacRect->right;
}
 
 
//////////
//
// QTFrame_ConvertWinToMacRect
// Convert a Windows RECT structure into a Macintosh Rect structure.
//
//////////
 
void QTFrame_ConvertWinToMacRect (RECT *theWinRect, Rect *theMacRect)
{
    theMacRect->top = (short)theWinRect->top;
    theMacRect->left = (short)theWinRect->left;
    theMacRect->bottom = (short)theWinRect->bottom;
    theMacRect->right = (short)theWinRect->right;
}
 
 
//////////
//
// QTFrame_ConvertMacToWinMenuItemLabel
// Convert a Mac menu item label into its Windows equivalent.
//
//////////
 
void QTFrame_ConvertMacToWinMenuItemLabel (MovieController theMC, MenuReference theWinMenu, long theModifiers, UInt16 theMenuItem)
{
    Str255      myString;
    char        *myLabelText = NULL;
    char        *myBeginText = NULL;
    char        *myFinalText = NULL;
    short       myLabelSize = 0;
 
    // get the appropriate label for the specified item and keyboard modifiers
    MCGetMenuString(theMC, theModifiers, MENU_ITEM(theMenuItem), myString);
    
    switch (theMenuItem) {
        case IDM_EDITUNDO:
            myBeginText = kAmpersandText;
            myFinalText = kWinUndoAccelerator;
            break;
            
        case IDM_EDITPASTE:
            myBeginText = "";
            myFinalText = kWinPasteAccelerator;
            // note that we are not inserting any ampersand anywhere in this label,
            // so the Alt-key search will use the first letter of the label (which
            // may conflict with some other Alt-key letter); fixing this is left as
            // an exercise for the reader
            break;
            
        case IDM_EDITCLEAR:
            myBeginText = kAmpersandText;
            myFinalText = kWinClearAccelerator;
            break;
            
        default:
            // currently, only the Undo, Paste, and Clear items are modified by MCSetUpEditMenu,
            // so that's all we'll handle here; by returning, we leave the existing label intact
            return;
    }
    
    myLabelSize = strlen(myBeginText) + myString[0] + strlen(myFinalText) + 1;
    myLabelText = malloc(myLabelSize);
    if (myLabelText == NULL)
        return;
    
    BlockMove(myBeginText, myLabelText, strlen(myBeginText));
    BlockMove(&myString[1], myLabelText + strlen(myBeginText), myString[0]);
    BlockMove(myFinalText, myLabelText + strlen(myBeginText) + myString[0], strlen(myFinalText));
    myLabelText[myLabelSize - 1] = '\0';
    
    QTFrame_SetMenuItemLabel(theWinMenu, theMenuItem, myLabelText);
 
    free(myLabelText);
}
#endif  // TARGET_OS_WIN32