Common Files/MacFramework.c

//////////
//
//  File:       MacFramework.c
//
//  Contains:   Code for the QuickTime sample code framework that is specific to the Macintosh. 
//              This code handles windows, menus, events, and other low-level things. Put your
//              application-specific code into the file ComApplication.c. 
//
//  Written by: Tim Monroe
//              Based on the QTShell code written by Tim Monroe, which in turn was based on the MovieShell
//              code written by Apple DTS (Kent Sandvik). This current version is now very far removed from
//              MovieShell.
//
//  Copyright:  © 1999 by Apple Computer, Inc., all rights reserved.
//
//  Change History (most recent first):
//
//     <15>     03/11/02    rtm     added support for Carbon events; set USE_CARBON_EVENTS to 1 to use
//     <14>     03/16/01    rtm     added HideWindow to QTFrame_DestroyMovieWindow to prevent custom
//                                  window definition procs from being called during window tear-down
//     <13>     02/01/01    rtm     fixed *Proc names to *UPP, to conform to Universal Headers 3.4b4
//     <12>     08/11/00    rtm     revised event-handling so that QTFrame_HandleEvent passes event to
//                                  the movie controller
//     <11>     07/06/00    rtm     made changes to support new parameter to QTFrame_AdjustMenus
//     <10>     03/02/00    rtm     made changes to get things running under CarbonLib
//     <9>      01/14/00    rtm     reworked window-dragging and -updating code to support graphics files
//     <8>      12/23/99    rtm     tweaked mouseDown handling in QTFrame_StandardModalDialogEventFilter
//     <7>      12/16/99    rtm     added gMouseClickTime global variable and code to set it in mouseUp
//                                  case in QTFrame_HandleEvent
//     <6>      12/12/99    rtm     tweaked inDrag handling in QTFrame_HandleEvent
//     <5>      11/30/99    rtm     option-click in close box now closes all open movie windows (per HIG)
//     <4>      11/29/99    rtm     reworked QTFrame_DestroyMovieWindow to use NavAskSaveChanges
//     <3>      11/16/99    rtm     factored QTFrame_HandleEvent out of QTFrame_MainEventLoop, so we can
//                                  handle events from other code, if necessary
//     <2>      11/11/99    rtm     made some preliminary changes for Carbon; still some work to be done
//     <1>      11/05/99    rtm     first file; based on earlier sample code
//     
//////////
 
//////////
//
// header files
//
//////////
 
#include "MacFramework.h"
 
 
//////////
//
// global variables
//
//////////
 
Boolean             gShuttingDown = false;              // are we shutting down?
Boolean             gAppInForeground;                   // is our application in the foreground?    
Boolean             gHasNewDialogCalls;                 // are the new Dialog Manager functions available?
 
Str255              gWindowTitle = kDefaultWindowTitle; // default name for created windows
Rect                gWindowRect = kDefaultWindowRect;   // default rectangle for created windows
GrowZoneUPP         gAppGrowZoneUPP;                    // UPP to our grow zone callback
ModalFilterUPP      gModalFilterUPP;                    // UPP to our custom dialog event filter
UserItemUPP         gUserItemProcUPP;                   // UPP to our custom dialog user item procedure
Handle              gEmergencyMemory;                   // handle to our emergency memory reserve
 
short               gAppResFile = kInvalidFileRefNum;   // file reference number for this application's resource file
FSSpec              gAppFSSpec;                         // file specification for the application itself
Str255              gAppName;                           // the name of this application
 
long                gMouseClickTime;                    // for double-click calculation
extern Handle       gValidFileTypes;                    // the list of file types that our application can open
 
long                gRunningUnderX = false;             // are we running under Mac OS X?
 
#if USE_CARBON_EVENTS
EventHandlerUPP     gAppEventHandlerUPP = NULL;
EventHandlerUPP     gWinEventHandlerUPP = NULL;
EventHandlerUPP     gWinEventModalHandlerUPP = NULL;
EventLoopTimerUPP   gWinTimerHandlerUPP = NULL;
Boolean             gMenuIsTracking = false;
#endif
 
#if USE_TASK_MGMT
QTNextTaskNeededSoonerCallbackUPP
                    gQTTaskSoonerUPP = NULL;
#endif
 
 
//////////
//
// main
// The main function for this application.
//
// Set up the application's execution environment; make sure QuickTime (etc.) is installed,
// then start handling events.
//
//////////
 
int main (void)
{
    OSErr       myErr = noErr;
    
    QTFrame_InitMacEnvironment(10L);
    
    // make sure that QuickTime is available and that we can initialize it
    if (!QTUtils_IsQuickTimeInstalled()) {
        QTFrame_ShowWarning("\pQuickTime is not installed on this computer. Exiting.", 0);
        ExitToShell();
    }
 
    myErr = EnterMovies();
    if (myErr != noErr) {
        QTFrame_ShowWarning("\pCould not initialize QuickTime. Exiting.", myErr);
        ExitToShell();
    }
 
    // do any application-specific initialization
    QTApp_Init(kInitAppPhase_BothPhases);
 
    // get and process events until the user quits
    QTFrame_MainEventLoop();
    
    ExitMovies();
    ExitToShell();
    
    return(0);
}
 
 
//////////
//
// QTFrame_InitMacEnvironment
// Initialize the Macintosh runtime environment.
//
//////////
 
static void QTFrame_InitMacEnvironment (long theNumMoreMasters)
{
#if TARGET_API_MAC_CARBON
#pragma unused(theNumMoreMasters)
#endif
 
    short           myVRefNum;
    long            myDirID;
 
#if USE_CARBON_EVENTS
    EventTypeSpec   myEventSpec[] = {   
                                        {kEventClassMenu, kEventMenuBeginTracking},
                                        {kEventClassMenu, kEventMenuEndTracking},
                                        {kEventClassCommand, kEventCommandProcess},
                                        {kEventClassCommand, kEventCommandUpdateStatus}
                                    };
 
    gAppEventHandlerUPP = NewEventHandlerUPP(QTFrame_CarbonEventAppHandler);
    if (gAppEventHandlerUPP != NULL)
        InstallEventHandler(GetApplicationEventTarget(), gAppEventHandlerUPP, GetEventTypeCount(myEventSpec), myEventSpec, NULL, NULL);
    
    gWinEventHandlerUPP = NewEventHandlerUPP(QTFrame_CarbonEventWindowHandler); 
    gWinEventModalHandlerUPP = NewEventHandlerUPP(QTFrame_CarbonEventModalWindowHandler);
    gWinTimerHandlerUPP = NewEventLoopTimerUPP(QTFrame_CarbonEventWindowTimer);
 
    #if USE_TASK_MGMT
    gQTTaskSoonerUPP = NewQTNextTaskNeededSoonerCallbackUPP(QTFrame_NextTaskNeededSoonerProcedure);
    #endif
 
#endif // USE_CARBON_EVENTS
 
#if !TARGET_API_MAC_CARBON  
    long            myIndex;
 
    // add more space to the stack
    SetApplLimit((Ptr)(GetApplLimit() - kExtraStackSpaceSize));
            
    // expand heap zone to its limit
    MaxApplZone();
    
    // allocate some additional master pointer blocks
    for (myIndex = 0; myIndex < theNumMoreMasters; myIndex++)
        MoreMasters();
 
    InitGraf(&qd.thePort);
    InitFonts();
    InitWindows();
    InitMenus();
    TEInit();
    InitDialogs(NULL);
#endif
    InitCursor();
 
    // initialize and install the menu bar
    QTFrame_InitMenuBar();
 
#if !TARGET_API_MAC_CARBON
    // install a grow zone procedure to handle low memory situations
    gEmergencyMemory = NewHandle(kEmergencyMemorySize);
    if (gEmergencyMemory != NULL) {
        gAppGrowZoneUPP = NewGrowZoneUPP(QTFrame_GrowZoneProcedure);
        SetGrowZone(gAppGrowZoneUPP);
    }
#endif
    
    // initialize foreground/background state
    gAppInForeground = true;
 
    // see whether the new Dialog Manager functions are available
#if TARGET_API_MAC_CARBON
    gHasNewDialogCalls = true;
#else
    gHasNewDialogCalls = QTUtils_TrapAvailable(_DialogDispatch);
#endif
        
    // create modal dialog filter and user item UPPs
    gModalFilterUPP = NewModalFilterUPP(QTFrame_StandardModalDialogEventFilter);
    gUserItemProcUPP = NewUserItemUPP(QTFrame_StandardUserItemProcedure);
 
    // get the application's resource file
    gAppResFile = CurResFile();
    
    // get the application's name from the resource file
    GetIndString(gAppName, kAppNameResID, kAppNameResIndex);
    
    // get the application's location and save it in gAppFSSpec
    HGetVol(NULL, &myVRefNum, &myDirID);
    FSMakeFSSpec(myVRefNum, myDirID, gAppName, &gAppFSSpec);
}
 
 
//////////
//
// QTFrame_GrowZoneProcedure
// A grow zone procedure. This is straight out of IM: Memory (pp. 1-46ff)
//
//////////
 
PASCAL_RTN long QTFrame_GrowZoneProcedure (Size theBytesNeeded)
{
#pragma unused(theBytesNeeded)
 
    long        myA5;
    Size        myBytesFreed;
    
    // get current A5; we might get called at a time that A5 isn't valid
    myA5 = SetCurrentA5();
    
    if ((*gEmergencyMemory != NULL) && (gEmergencyMemory != GZSaveHnd())) {
        EmptyHandle(gEmergencyMemory);
        myBytesFreed = kEmergencyMemorySize;
    } else {
        myBytesFreed = 0;                       // no more memory to release    
    }   
        
    myA5 = SetA5(myA5);
    
    return(myBytesFreed);
}
 
 
//////////
//
// QTFrame_InitMenuBar
// Set up the menu bar.
//
//////////
 
static Boolean QTFrame_InitMenuBar (void)
{
    Handle      myMenuBar = NULL;
    long        myResponse;
    OSErr       myErr = noErr;
    MenuRef     myMenu = NULL;
 
    myMenuBar = GetNewMBar(kMenuBarResID);
 
#if TARGET_API_MAC_CARBON   
    // to get the theme-savvy menu bar, we need to call RegisterAppearanceClient.
    RegisterAppearanceClient();
#endif
 
    if (myMenuBar == NULL)
        return(false);
    
    SetMenuBar(myMenuBar);                                  // install the menus
    DisposeHandle(myMenuBar);
    
    // see whether we are running under MacOS X;
    // if so, remove the Quit menu item and its preceding separator line
    myErr = Gestalt(gestaltSystemVersion, &myResponse);
    if (myErr == noErr)
        if (myResponse >= 0x00000A00) {
            DeleteMenuItem(GetMenuHandle(kFileMenuResID), MENU_ITEM(IDM_EXIT));
            DeleteMenuItem(GetMenuHandle(kFileMenuResID), MENU_ITEM(IDM_EXIT) - 1); // the separator line
            gRunningUnderX = true;
        }
        
#if !TARGET_API_MAC_CARBON  
    AppendResMenu(GetMenuHandle(kAppleMenuResID), 'DRVR');  // add desk accessory names to Apple menu
#endif
 
#if USE_CARBON_EVENTS
    myMenu = GetMenuHandle(kAppleMenuResID);
    SetMenuItemCommandID(myMenu, kAboutMenuItem, COMMAND_ID(MENU_IDENTIFIER(kAppleMenuResID,kAboutMenuItem)));
    
    myMenu = GetMenuHandle(kFileMenuResID);
    SetMenuItemCommandID(myMenu, MENU_ITEM(IDM_FILENEW), COMMAND_ID(IDM_FILENEW));
    SetMenuItemCommandID(myMenu, MENU_ITEM(IDM_FILEOPEN), COMMAND_ID(IDM_FILEOPEN));
    SetMenuItemCommandID(myMenu, MENU_ITEM(IDM_FILECLOSE), COMMAND_ID(IDM_FILECLOSE));
    SetMenuItemCommandID(myMenu, MENU_ITEM(IDM_FILESAVE), COMMAND_ID(IDM_FILESAVE));
    SetMenuItemCommandID(myMenu, MENU_ITEM(IDM_FILESAVEAS), COMMAND_ID(IDM_FILESAVEAS));
    SetMenuItemCommandID(myMenu, MENU_ITEM(IDM_EXIT), COMMAND_ID(IDM_EXIT));
 
    myMenu = GetMenuHandle(kEditMenuResID);
    SetMenuItemCommandID(myMenu, MENU_ITEM(IDM_EDITUNDO), COMMAND_ID(IDM_EDITUNDO));
    SetMenuItemCommandID(myMenu, MENU_ITEM(IDM_EDITCUT), COMMAND_ID(IDM_EDITCUT));
    SetMenuItemCommandID(myMenu, MENU_ITEM(IDM_EDITCOPY), COMMAND_ID(IDM_EDITCOPY));
    SetMenuItemCommandID(myMenu, MENU_ITEM(IDM_EDITPASTE), COMMAND_ID(IDM_EDITPASTE));
    SetMenuItemCommandID(myMenu, MENU_ITEM(IDM_EDITCLEAR), COMMAND_ID(IDM_EDITCLEAR));
    SetMenuItemCommandID(myMenu, MENU_ITEM(IDM_EDITSELECTALL), COMMAND_ID(IDM_EDITSELECTALL));
    SetMenuItemCommandID(myMenu, MENU_ITEM(IDM_EDITSELECTNONE), COMMAND_ID(IDM_EDITSELECTNONE));
#endif
 
    QTFrame_AdjustMenus(NULL, NULL, 0L);
    DrawMenuBar();
    
    return(true);
}
 
 
//////////
//
// QTFrame_MainEventLoop
// Retrieve and process events.
//
//////////
 
static void QTFrame_MainEventLoop (void)
{
#if USE_CARBON_EVENTS
    RunApplicationEventLoop();
#else
    EventRecord             myEvent;
    long                    myDuration = kWNEMinimumSleep;
    
    while (!gShuttingDown) {
    #if !TARGET_API_MAC_CARBON
        // make sure we've still got our memory reserve; reallocate it if it's been used
        if ((gEmergencyMemory == NULL) || (*gEmergencyMemory == NULL))
            ReallocateHandle(gEmergencyMemory, kEmergencyMemorySize);
    #endif
 
    #if USE_TASK_MGMT
        // get the number of ticks until QuickTime's next task
        QTGetTimeUntilNextTask(&myDuration, 60);
 
        if (myDuration == 0)
            myDuration = kWNEMinimumSleep;
    #endif
    
        // get the next event in the queue
        WaitNextEvent(everyEvent, &myEvent, myDuration, NULL);
        
        // handle the event
        QTFrame_HandleEvent(&myEvent);
 
    } // while (!gShuttingDown)
#endif // USE_CARBON_EVENTS
}
 
 
//////////
//
// QTFrame_HandleEvent
// Process an event.
//
//////////
 
void QTFrame_HandleEvent (EventRecord *theEvent)
{
    WindowPtr               myWindow = NULL;
    WindowObject            myWindowObject = NULL;
    short                   myWindowPart;
    Rect                    myScreenRect;
    Boolean                 isEventHandled = false;
 
    // first, perform any application-specific event handling
    isEventHandled = QTApp_HandleEvent(theEvent);
        
    // then, if this event hasn't been handled, let all movie controllers have access to the event
    if (!isEventHandled)
        isEventHandled = QTFrame_CheckMovieControllers(theEvent);
 
    // then, if this event has been handled, return; otherwise, handle it here
    if (isEventHandled)
        return;
        
    myWindow = FrontWindow();
 
    switch (theEvent->what) {
        case mouseUp:
            gMouseClickTime = TickCount();      // for double-click calculation
            break;
 
        case mouseDown:
        
            myWindowPart = FindWindow(theEvent->where, &myWindow);
 
            // menu bar and window-related events:          
            switch (myWindowPart) {
                case inSysWindow:
#if !TARGET_API_MAC_CARBON
                    // a mouse click in a window belonging to a desk accessory
                    SystemClick(theEvent, myWindow);
#endif
                    break;
                    
                case inMenuBar:
                    // a mouse click in the menu bar
                    QTFrame_AdjustMenus(FrontWindow(), NULL, (long)theEvent->modifiers);
                    QTFrame_HandleMenuCommand(MenuSelect(theEvent->where));
                    break;
                    
                case inDrag: {
                    Rect                myRect;
                    
                    myWindowObject = QTFrame_GetWindowObjectFromWindow(myWindow);
                    if (myWindowObject != NULL) {
                        
                        if ((**myWindowObject).fMovie != NULL)
                            GetMovieBox((**myWindowObject).fMovie, &myRect);
                        
                        if ((**myWindowObject).fGraphicsImporter != NULL)
                            GraphicsImportGetNaturalBounds((**myWindowObject).fGraphicsImporter, &myRect);
                        
                        GetRegionBounds(GetGrayRgn(), &myScreenRect);
                        DragAlignedWindow(myWindow, theEvent->where, &myScreenRect, &myRect, NULL);
 
                    } else {
                        GetRegionBounds(GetGrayRgn(), &myScreenRect);
                        DragWindow(myWindow, theEvent->where, &myScreenRect);
                    }
                    
                    break;                          
                }
                    
                case inContent:
                    if (myWindow != FrontWindow()) {
                        SelectWindow(myWindow);
                        MacSetPort((GrafPtr)GetWindowPort(myWindow));
                    } else {
                        QTApp_HandleContentClick(myWindow, theEvent);
                    }
                    
                    break;
                
                case inGoAway:
                    if (TrackGoAway(myWindow, theEvent->where)) {
                        // if the option key is down, close all open movie windows; otherwise, close just the frontmost
                        if (theEvent->modifiers & optionKey)
                            QTFrame_CloseMovieWindows();
                        else
                            QTFrame_DestroyMovieWindow(myWindow);
                    }
                    break;
            } // end switch(myWindowPart)
            break;
 
        // system-level events:
        case updateEvt:
            myWindow = (WindowPtr)theEvent->message;
            if (myWindow != NULL) {
                // if the window contains an image, draw it using GraphicsImportDraw
                myWindowObject = QTFrame_GetWindowObjectFromWindow(myWindow);
                if (myWindowObject != NULL)
                    if ((**myWindowObject).fGraphicsImporter != NULL)
                        GraphicsImportDraw((**myWindowObject).fGraphicsImporter);
                
                // now do any application-specific drawing
                QTApp_Draw(myWindow);
            }
            break;
            
        case keyDown:
        case autoKey:
            QTFrame_HandleKeyPress(theEvent);
            break;
        
        case diskEvt: {
#if !TARGET_API_MAC_CARBON
            Point           myPoint = {100, 100};
        
            if (HiWord(theEvent->message) != noErr)
                (void)DIBadMount(myPoint, theEvent->message);
#endif
            break;
        }
        
        case activateEvt:
            myWindow = (WindowReference)theEvent->message;
            
            if (QTFrame_IsMovieWindow(myWindow))
                QTFrame_ActivateController(myWindow, ((theEvent->modifiers & activeFlag) != 0 ));
            break;
            
        case osEvt:
            switch ((theEvent->message >> 24) & 0x00ff) {       // get high byte of message
                case suspendResumeMessage:
                
                    // set the foreground/background state
                    gAppInForeground = (theEvent->message & resumeFlag) != 0;
                    
                    // activate the front window, if there is one   
                    if (myWindow != NULL)
                        QTFrame_ActivateController(myWindow, gAppInForeground);
                    break;
                
                case mouseMovedMessage:
                    break;
            }
            break;
        
        case kHighLevelEvent:
            AEProcessAppleEvent(theEvent);
            break;
            
        case nullEvent:
            // do idle-time processing for all open movie windows
            myWindow = QTFrame_GetFrontMovieWindow();
            while (myWindow != NULL) {
                if (gAppInForeground)
                    QTApp_Idle(myWindow);
                    
                myWindow = QTFrame_GetNextMovieWindow(myWindow);
            }
            break;
    } // switch (theEvent->what)
}
        
 
//////////
//
// QTFrame_HandleMenuCommand
// Handle a menu selection.
//
//////////
 
Boolean QTFrame_HandleMenuCommand (long theMenuResult)
{
    short       myMenuID, myMenuItem;
    Cursor      myArrow;
    Boolean     myIsHandled = false;
    
    MacSetCursor(GetQDGlobalsArrow(&myArrow));
 
    myMenuID = HiWord(theMenuResult);
    myMenuItem = LoWord(theMenuResult);
    
    switch (myMenuID) {
    
        case kAppleMenuResID:
            switch (myMenuItem) {
                case kAboutMenuItem:        // About box
                    QTFrame_ShowAboutBox();
                    myIsHandled = true;
                    break;
                
                default:                    // Apple menu handling
#if !TARGET_API_MAC_CARBON
                    {
                        Str255      myDAName;
                        
                        GetMenuItemText(GetMenuHandle(kAppleMenuResID), myMenuItem, myDAName);
                        (void)OpenDeskAcc(myDAName);
                    }
                    myIsHandled = true;
#endif
                    break;
            }
            break;
 
        case kFileMenuResID:
            myIsHandled = QTFrame_HandleFileMenuItem(QTFrame_GetFrontMovieWindow(), MENU_IDENTIFIER(myMenuID, myMenuItem));
            break;
    
        case kEditMenuResID:
            myIsHandled = QTFrame_HandleEditMenuItem(QTFrame_GetFrontMovieWindow(), MENU_IDENTIFIER(myMenuID, myMenuItem));
            break;
 
        default:
            // do any application-specific menu handling
            myIsHandled = QTApp_HandleMenu(MENU_IDENTIFIER(myMenuID, myMenuItem));
            break;
        
    } // switch (myMenuID)
    
    HiliteMenu(0);
    
    return(myIsHandled);
}
 
 
//////////
//
// QTFrame_HandleKeyPress
// Handle key presses. This is modelled on Inside Macintosh: Macintosh Toolbox Essentials, p. 3-78.
//
//////////
 
void QTFrame_HandleKeyPress (EventRecord *theEvent)
{
    char        myKey;
    
    myKey = theEvent->message & charCodeMask;
    
    if (theEvent->modifiers & cmdKey) {
        // if the command key is down, it must be a keyboard shortcut for a menu selection;
        // adjust the menus and find the menu command that the shortcut picks out
        QTFrame_AdjustMenus(FrontWindow(), NULL, (long)theEvent->modifiers);
        QTFrame_HandleMenuCommand(MenuKey(myKey));
    } else {
        // otherwise, we'll assume it's meant for our application
        QTApp_HandleKeyPress(myKey);
    }
}
 
 
//////////
//
// QTFrame_QuitFramework
// Do any framework-specific shut-down.
//
//////////
 
void QTFrame_QuitFramework (void)
{
    // set our global flag to indicate we're shutting down
    gShuttingDown = true;
    
    // do application-specific processing that must occur before movie windows are closed
    QTApp_Stop(kStopAppPhase_BeforeDestroyWindows);
    
    // close all open movie windows; note that the user can cancel the shutting down
    QTFrame_CloseMovieWindows();
        
    // test the quit flag; a call to QTFrame_DestroyMovieWindow may have reset it
    if (!gShuttingDown)
        return;
    
    // do application-specific processing that must occur after movie windows are closed
    QTApp_Stop(kStopAppPhase_AfterDestroyWindows);
 
    // release our list of valid file types
    if (gValidFileTypes != NULL)
        DisposeHandle(gValidFileTypes);
 
#if !TARGET_API_MAC_CARBON  
    // release the grow zone memory
    if (gEmergencyMemory != NULL)
        DisposeHandle(gEmergencyMemory);
#endif
    
#if USE_CARBON_EVENTS
    QuitApplicationEventLoop();
 
    if (gAppEventHandlerUPP != NULL)
        DisposeEventHandlerUPP(gAppEventHandlerUPP);
 
    if (gWinEventHandlerUPP != NULL)
        DisposeEventHandlerUPP(gWinEventHandlerUPP);
    
    if (gWinEventModalHandlerUPP != NULL)
        DisposeEventHandlerUPP(gWinEventModalHandlerUPP);
 
    if (gWinTimerHandlerUPP != NULL)
        DisposeEventLoopTimerUPP(gWinTimerHandlerUPP);
#endif
 
#if USE_TASK_MGMT
    if (gQTTaskSoonerUPP != NULL)
        DisposeQTNextTaskNeededSoonerCallbackUPP(gQTTaskSoonerUPP);
#endif
 
    // release any routine descriptors
    if (gAppGrowZoneUPP != NULL)
        DisposeGrowZoneUPP(gAppGrowZoneUPP);
        
    if (gModalFilterUPP != NULL)
        DisposeModalFilterUPP(gModalFilterUPP);
        
    if (gUserItemProcUPP != NULL)
        DisposeUserItemUPP(gUserItemProcUPP);   
}
 
 
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Framework utilities.
//
// The framework uses the following functions to create movies and handle dialog boxes. You probably won't
// need to use them directly.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
//////////
//
// QTFrame_CreateMovieWindow
// Create a new window to display the movie in.
//
//////////
 
WindowReference QTFrame_CreateMovieWindow (void)
{
    WindowReference     myWindow = NULL;
    
    // create a new window to display the movie in
    myWindow = NewCWindow(NULL, &gWindowRect, gWindowTitle, false, noGrowDocProc, (WindowPtr)-1L, true, 0);
 
    // create a new window object associated with the new window
    QTFrame_CreateWindowObject(myWindow);
 
#if USE_CARBON_EVENTS
{
    WindowObject        myWindowObject = NULL;
    EventTypeSpec       myEventSpec[] = {   
                                            {kEventClassKeyboard, kEventRawKeyDown},
                                            {kEventClassKeyboard, kEventRawKeyRepeat},
                                            {kEventClassKeyboard, kEventRawKeyUp},
                                            {kEventClassWindow, kEventWindowUpdate},
                                            {kEventClassWindow, kEventWindowDrawContent},
                                            {kEventClassWindow, kEventWindowActivated},
                                            {kEventClassWindow, kEventWindowDeactivated},
                                            {kEventClassWindow, kEventWindowHandleContentClick},
                                            {kEventClassWindow, kEventWindowClose}
                                        };
                                        
    // install Carbon event handlers for this window
    InstallStandardEventHandler(GetWindowEventTarget(myWindow));
    if (gWinEventHandlerUPP != NULL)
        InstallEventHandler(GetWindowEventTarget(myWindow), gWinEventHandlerUPP, GetEventTypeCount(myEventSpec), myEventSpec, QTFrame_GetWindowObjectFromWindow(myWindow), NULL);
 
    #if !USE_CARBON_MOVIE_CONTROL
    myWindowObject = QTFrame_GetWindowObjectFromWindow(myWindow);
    if (myWindowObject == NULL)
        return(myWindow);
    
    if (gWinTimerHandlerUPP != NULL)
        InstallEventLoopTimer(GetMainEventLoop(), 0, TicksToEventTime(kWNEMinimumSleep), gWinTimerHandlerUPP, myWindowObject, &(**myWindowObject).fTimerRef);
    #if USE_TASK_MGMT
    if ((gQTTaskSoonerUPP != NULL) && ((**myWindowObject).fTimerRef != NULL))
        QTInstallNextTaskNeededSoonerCallback(gQTTaskSoonerUPP, 1000, 0, (void *)(**myWindowObject).fTimerRef);
    #endif // USE_TASK_MGMT
    #endif // !USE_CARBON_MOVIE_CONTROL
}
#endif
 
    return(myWindow);
}
 
 
//////////
//
// QTFrame_DestroyMovieWindow
// Close the specified movie window.
//
//////////
 
void QTFrame_DestroyMovieWindow (WindowReference theWindow)
{
    WindowObject        myWindowObject = NULL;
    OSErr               myErr = noErr;
    
    // get the window object associated with the specified window
    myWindowObject = QTFrame_GetWindowObjectFromWindow(theWindow);
    if (myWindowObject == NULL) {
        // if the window passed in isn't a movie window, just dispose of it and return
        if (theWindow != NULL) {
            DisposeWindow(theWindow);
            theWindow = NULL;
        }
        return;
    }
    
    // if the window's data is "dirty", give the user a chance to save it
    if ((**myWindowObject).fIsDirty) {
        Str255                      myString;
        NavAskSaveChangesAction     myAction;
        NavAskSaveChangesResult     myResult;
        NavDialogOptions            myDialogOptions;
        NavEventUPP                 myEventUPP = NewNavEventUPP(QTFrame_HandleNavEvent);
 
        // get the title of the window
        GetWTitle(theWindow, myString);
        
        // install the application and document names
        NavGetDefaultDialogOptions(&myDialogOptions);
        BlockMoveData(gAppName, myDialogOptions.clientName, gAppName[0] + 1);
        BlockMoveData(myString, myDialogOptions.savedFileName, myString[0] + 1);
        
        // specify the action
        myAction = gShuttingDown ? kNavSaveChangesQuittingApplication : kNavSaveChangesClosingDocument;
        
        // display the "Save changes" dialog box
        myErr = NavAskSaveChanges(&myDialogOptions, myAction, &myResult, myEventUPP, NULL);
        if (myErr != noErr)
            myResult = kNavAskSaveChangesCancel;
            
        switch (myResult) {
            case kNavAskSaveChangesSave:
                // save the data in the window
                QTFrame_UpdateMovieFile(theWindow);
                break;
                
            case kNavAskSaveChangesCancel:
                // do not close the window, and do not quit the application
                gShuttingDown = false;
                return;
                
            case kNavAskSaveChangesDontSave:
                // discard any unsaved changes (that is, don't do anything)
                break;
        }
 
        DisposeNavEventUPP(myEventUPP);
    }
 
    // if we got to this point, it's okay to hide, close, and destroy the window
#if USE_CARBON_EVENTS
    if ((**myWindowObject).fTimerRef != NULL)
        RemoveEventLoopTimer((**myWindowObject).fTimerRef);
#endif
 
    HideWindow(theWindow);
    QTFrame_CloseWindowObject(myWindowObject);
 
    DisposeWindow(theWindow);
}
 
 
//////////
//
// QTFrame_StandardUserItemProcedure
// A standard user-item procedure to outline the OK button in a modal dialog.
//
//////////
 
PASCAL_RTN void QTFrame_StandardUserItemProcedure (DialogPtr theDialog, short theItem)
{
#pragma unused(theItem)
 
    short               myItemKind;         // for GetDialogItem
    Handle              myItemHandle;       // for GetDialogItem
    Rect                myItemRect;         // for GetDialogItem
 
    if (!gHasNewDialogCalls) {      // no need to do any of this if the new Dialog Manager calls are available
        GetDialogItem(theDialog, kStdOkItemIndex, &myItemKind, &myItemHandle, &myItemRect);     
        MacInsetRect(&myItemRect, -4, -4);
        PenSize(3, 3);
        FrameRoundRect(&myItemRect, 16, 16);
        PenSize(1, 1);
    }
}
 
 
//////////
//
// QTFrame_StandardModalDialogEventFilter
// A standard modal dialog event filter. 
//
//////////
 
PASCAL_RTN Boolean QTFrame_StandardModalDialogEventFilter (DialogPtr theDialog, EventRecord *theEvent, short *theItemHit)
{
    Boolean             myEventHandled = false;
    short               myItemKind;         // for GetDialogItem
    Handle              myItemHandle;       // for GetDialogItem
    Rect                myItemRect;         // for GetDialogItem
    unsigned long       myTicks;            // for Delay
    char                myKey;      
    WindowReference     myWindow = NULL;
    short               myPart; 
        
    switch (theEvent->what) {
        case updateEvt:
            // update the specified window, if it's behind the modal dialog box
            myWindow = (WindowReference)theEvent->message;
            if ((myWindow != NULL) && (myWindow != GetDialogWindow(theDialog))) {
                QTFrame_HandleEvent(theEvent);
                myEventHandled = false;     // so sayeth IM
            }
            break;
 
        case nullEvent:
            // do idle-time processing for all open windows in our window list
            if (gAppInForeground)
                QTFrame_IdleMovieWindows();
 
            myEventHandled = false;
            break;
            
        case keyDown:
        case autoKey:
            // if new Dialog Manager calls are NOT available, handle certain key presses
            if (!gHasNewDialogCalls) {
                // first, map Command-period to Escape key...
                myKey = theEvent->message & charCodeMask;
                if (theEvent->modifiers & cmdKey)
                    if (myKey == kPeriod)
                        myKey = kEscapeKey;
                        
                // ...then, handle the standard keyboard equivalents of OK and Cancel buttons
                switch (myKey) {
                    case kReturnKey:
                    case kEnterKey:
                        *theItemHit = kStdOkItemIndex;
                        GetDialogItem(theDialog, kStdOkItemIndex, &myItemKind, &myItemHandle, &myItemRect);
                        HiliteControl((ControlHandle)myItemHandle, kControlButtonPart);
                        Delay(kMyButtonDelay, &myTicks);
                        HiliteControl((ControlHandle)myItemHandle, kControlNoPart);
                        myEventHandled = true;
                        break;
                    case kEscapeKey:
                        *theItemHit = kStdCancelItemIndex;
                        GetDialogItem(theDialog, kStdCancelItemIndex, &myItemKind, &myItemHandle, &myItemRect);
                        HiliteControl((ControlHandle)myItemHandle, kControlButtonPart);
                        Delay(kMyButtonDelay, &myTicks);
                        HiliteControl((ControlHandle)myItemHandle, kControlNoPart);
                        myEventHandled = true;
                        break;
                    default:
                        break;
                }
            }
            break;
            
        case mouseDown:
            myPart = FindWindow(theEvent->where, &myWindow);
            if ((myPart == inDrag) && (myWindow == GetDialogWindow(theDialog))) {
                Rect        myScreenRect;
                
                GetRegionBounds(GetGrayRgn(), &myScreenRect);
                DragWindow(myWindow, theEvent->where, &myScreenRect);
                myEventHandled = true;
            }
            break;
            
        default:
            myEventHandled = false;
            break;
    }   
    
    // let the OS's standard filter proc handle the event, if it hasn't already been handled
    if (gHasNewDialogCalls && (myEventHandled == false))
        myEventHandled = StdFilterProc(theDialog, theEvent, theItemHit);
    
    return(myEventHandled);
}
 
 
//////////
//
// QTFrame_CheckMovieControllers
// Let all movie controllers have a chance to process the event.
//
// Returns true if the event was handled by some movie controller, false otherwise
//
//////////
 
static Boolean QTFrame_CheckMovieControllers (EventRecord *theEvent)
{   
    WindowPtr               myWindow = NULL;
    MovieController         myMC = NULL;
    
    myWindow = QTFrame_GetFrontMovieWindow();
    while (myWindow != NULL) {
        myMC = QTFrame_GetMCFromWindow(myWindow);
        if (myMC != NULL)
            if (MCIsPlayerEvent(myMC, theEvent))
                return(true);
        
        myWindow = QTFrame_GetNextMovieWindow(myWindow);
    }
    
    return(false);
}
 
 
//////////
//
// QTFrame_ShowAboutBox
// Display and manage the About dialog box.
//
//////////
 
void QTFrame_ShowAboutBox (void)
{
    DialogPtr           myDialog = NULL;
    WindowRef           myWindow = NULL;
    short               mySavedResFile;
    GrafPtr             mySavedPort;
    short               myItemKind;
    Handle              myItemHandle;
    Rect                myItemRect;
#if USE_CARBON_EVENTS
    EventTypeSpec       myEventSpec[] = {   
                                            {kEventClassWindow, kEventWindowDrawContent},
                                            {kEventClassControl, kEventControlHit}
                                        };
#else
    short               myItem;
#endif
    
    // get the current resource file and port
    mySavedResFile = CurResFile();
    GetPort(&mySavedPort);
    
    // set the application's resource file;
    // otherwise, we'd get the dialog's resources from the current resource file,
    // which might not be the correct one....
    UseResFile(gAppResFile);
    
    // deactivate any frontmost movie window
    QTFrame_ActivateController(QTFrame_GetFrontMovieWindow(), false);
    
    myDialog = GetNewDialog(kAboutBoxID, NULL, (WindowPtr)-1L);
    if (myDialog == NULL)
        goto bail;
        
    myWindow = GetDialogWindow(myDialog);
    if (myWindow == NULL)
        goto bail;
        
    SetPortDialogPort(myDialog);
        
    if (gHasNewDialogCalls)
        SetDialogDefaultItem(myDialog, kStdOkItemIndex);
    
    // make sure that the OK button is outlined in bold, even if new Dialog Manager calls not available
    GetDialogItem(myDialog, kOKButtonUserItem, &myItemKind, &myItemHandle, &myItemRect);
    SetDialogItem(myDialog, kOKButtonUserItem, myItemKind, (Handle)gUserItemProcUPP, &myItemRect);
 
#if USE_CARBON_EVENTS
    // install a window handler for the dialog window
    GetDialogItem(myDialog, kStdOkItemIndex, &myItemKind, &myItemHandle, &myItemRect);
    if (myItemHandle != NULL)
        SetWindowDefaultButton(myWindow, (ControlHandle)myItemHandle);
 
    InstallStandardEventHandler(GetWindowEventTarget(myWindow));
    if (gWinEventModalHandlerUPP != NULL)
        InstallEventHandler(GetWindowEventTarget(myWindow), gWinEventModalHandlerUPP, GetEventTypeCount(myEventSpec), myEventSpec, (void *)myDialog, NULL);
 
    // display and handle events in the dialog box until the user clicks OK
    RunAppModalLoopForWindow(myWindow);
#else
    // display and handle events in the dialog box until the user clicks OK
    do {
        ModalDialog(gModalFilterUPP, &myItem);
    } while (myItem != kStdOkItemIndex);
#endif
 
bail:
    // restore the previous resource file and port
    MacSetPort(mySavedPort);
    UseResFile(mySavedResFile);
    
    if (myDialog != NULL)
        DisposeDialog(myDialog);
}
 
 
//////////
//
// QTFrame_ShowWarning
// Display a warning box.
//
//////////
 
void QTFrame_ShowWarning (Str255 theMessage, OSErr theErr)
{
    Str255              myString;
    short               mySavedResFile;
    
    // get the current resource file and set the application's resource file
    mySavedResFile = CurResFile();
    UseResFile(gAppResFile);
 
    // insert argument into the message text template, to get the message text
    NumToString(theErr, myString);
    ParamText("\pWarning!", theMessage, theErr ? myString: NULL, NULL);
 
    // display the dialog box
    Alert(kAlertErrorID, gModalFilterUPP);
    
    // restore the original resource file
    UseResFile(mySavedResFile);
}
 
 
#if USE_CARBON_EVENTS
//////////
//
// QTFrame_CarbonEventAppHandler
// Handle Carbon events targeted at the application.
//
//////////
 
PASCAL_RTN OSStatus QTFrame_CarbonEventAppHandler (EventHandlerCallRef theCallRef, EventRef theEvent, void *theRefCon)
{
#pragma unused(theCallRef, theRefCon)
    UInt32              myClass, myKind;
    HICommand           myCommand;
    OSStatus            myErr = eventNotHandledErr;
    
    myClass = GetEventClass(theEvent);
    myKind = GetEventKind(theEvent);
    
    switch (myClass) {
        case kEventClassCommand:
            switch (myKind) {
                case kEventCommandProcess:
                    myErr = GetEventParameter(theEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(myCommand), NULL, &myCommand);
                    if ((myErr == noErr) && ((myCommand.attributes & kHICommandFromMenu) != 0))
                        myErr = QTFrame_HandleMenuCommand(myCommand.commandID) ? noErr : eventNotHandledErr;
                    break;
                    
                case kEventCommandUpdateStatus:
                    myErr = GetEventParameter(theEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(myCommand), NULL, &myCommand);
                    if ((myErr == noErr) && ((myCommand.attributes & kHICommandFromMenu) != 0))
                        QTFrame_AdjustMenus(FrontWindow(), NULL, 0L);
                    break;
            }
            break;
            
        case kEventClassMenu:
            switch (myKind) {
                case kEventMenuBeginTracking:
                    gMenuIsTracking = true;
                    break;
 
                case kEventMenuEndTracking:
                    gMenuIsTracking = false;
                    break;
            }
            break;
    }
 
    return(myErr);
}
 
 
//////////
//
// QTFrame_CarbonEventWindowHandler
// Handle Carbon events targeted at a movie window.
//
// On entry, theRefCon is the WindowObject for the window.
//
//////////
 
PASCAL_RTN OSStatus QTFrame_CarbonEventWindowHandler (EventHandlerCallRef theCallRef, EventRef theEvent, void *theRefCon)
{
#pragma unused(theCallRef)
    UInt32              myClass, myKind;
    UInt32              myModifiers;
    WindowRef           myWindow = NULL;
    EventRecord         myEvent;
    WindowObject        myWindowObject = (WindowObject)theRefCon;
    OSStatus            myErr = eventNotHandledErr;
    
    myClass = GetEventClass(theEvent);
    myKind = GetEventKind(theEvent);
    
    switch (myClass) {
        case kEventClassKeyboard:
            switch (myKind) {
                case kEventRawKeyDown:
                case kEventRawKeyRepeat:
                case kEventRawKeyUp:
                    if (ConvertEventRefToEventRecord(theEvent, &myEvent))
                        QTFrame_HandleEvent(&myEvent);
                    myErr = noErr;
                    break;
            }
            break;
            
        case kEventClassWindow:
            switch (myKind) {
                case kEventWindowUpdate:
                case kEventWindowDrawContent:
                case kEventWindowActivated:
                case kEventWindowDeactivated:
                    if (ConvertEventRefToEventRecord(theEvent, &myEvent))
                        QTFrame_HandleEvent(&myEvent);
                    myErr = noErr;
                    break;
                    
                case kEventWindowHandleContentClick:
                    myErr = GetEventParameter(theEvent, kEventParamDirectObject, typeWindowRef, NULL, sizeof(myWindow), NULL, &myWindow);
                    if (myErr == noErr) {
                        
                        GetEventParameter(theEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(myModifiers), NULL, &myModifiers);
                        GetEventParameter(theEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &myEvent.where);
                        GetEventParameter(theEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &myEvent.when);
                        
                        myEvent.what = mouseDown;
                        myEvent.message = (long)myWindow;
                        myEvent.modifiers = myModifiers;
                        myEvent.when = EventTimeToTicks(GetCurrentEventTime());
                                                
                        QTFrame_HandleEvent(&myEvent);
                        myErr = noErr;
                    }
                    break;
 
                case kEventWindowClose:
                    if (myWindowObject != NULL) {
                        QTFrame_DestroyMovieWindow((**myWindowObject).fWindow);
                        myErr = noErr;
                    }
                    break;
                    
                default:
                    break;
            }
            break;
    }
 
    return(myErr);
}
 
 
//////////
//
// QTFrame_CarbonEventModalWindowHandler
// Handle Carbon events targeted at a modal dialog window.
//
// On entry, theRefCon is the DialogPtr for the dialog box.
//
//////////
 
PASCAL_RTN OSStatus QTFrame_CarbonEventModalWindowHandler (EventHandlerCallRef theCallRef, EventRef theEvent, void *theRefCon)
{
#pragma unused(theCallRef)
    UInt32      myClass, myKind;
    DialogPtr   myDialog = (DialogPtr)theRefCon;
    OSStatus    myErr = eventNotHandledErr;
    
    myClass = GetEventClass(theEvent);
    myKind = GetEventKind(theEvent);
        
    switch (myClass) {
        case kEventClassWindow:
            switch (myKind) {
                case kEventWindowDrawContent:
                    if (myDialog != NULL)
                        DrawDialog(myDialog);
                    myErr = noErr;
                    break;
            }
            break;
 
        case kEventClassControl:
            switch (myKind) {
                case kEventControlHit:
                    if (myDialog != NULL)
                        myErr = QuitAppModalLoopForWindow(GetDialogWindow(myDialog));                   
                    break;
            }
            break;
    }
 
    return(myErr);
}
 
 
//////////
//
// QTFrame_CarbonEventWindowTimer
// Handle time-triggered actions for a specific window.
//
// The theRefCon paramter is a window object for the window to be tasked.
//
//////////
 
PASCAL_RTN void QTFrame_CarbonEventWindowTimer (EventLoopTimerRef theTimer, void *theRefCon)
{
    WindowObject    myWindowObject = (WindowObject)theRefCon;
    
#if USE_TASK_MGMT
    long            myDuration = 0L;
 
    // get the number of milliseconds until QuickTime's next task
    QTGetTimeUntilNextTask(&myDuration, 1000);
 
    if (myDuration == 0)
        myDuration = kMinAppTaskInMillisecs;
 
    // set the timer to fire at that time
    if (theTimer != NULL)
        SetEventLoopTimerNextFireTime(theTimer, myDuration * kEventDurationMillisecond);
#endif
 
    // just pretend a null event has been received....
    if ((myWindowObject != NULL) && ((**myWindowObject).fController != NULL))
        if (!gMenuIsTracking || gRunningUnderX)
            MCIdle((**myWindowObject).fController);
}
#endif // USE_CARBON_EVENTS
 
 
#if USE_TASK_MGMT
//////////
//
// QTFrame_NextTaskNeededSoonerProcedure
// Handle task-sooner notifications.
//
// We assume that theRefCon is an event loop timer reference.
//
//////////
 
PASCAL_RTN void QTFrame_NextTaskNeededSoonerProcedure (TimeValue theDuration, unsigned long theFlags, void *theRefCon)
{
#pragma unused(theFlags)
 
    EventLoopTimerRef   myTimer = (EventLoopTimerRef)theRefCon;
    
    if (myTimer != NULL)
        SetEventLoopTimerNextFireTime(myTimer, theDuration * kEventDurationMillisecond);
}
#endif // USE_TASK_MGMT