Application.c

/*
    File:       Offscreen.c
 
    Contains:   QuickTime 3.0 Offscreen sample application.
 
    Written by: Scott Kuechle
                based on MDIPlayer code by Brian S. Friedkin
 
    Copyright:  © 1998 by Apple Computer, Inc., all rights reserved.
 
    Change History (most recent first):
 
       <2>      5/18/98     rtm     minor tweaks to GetBitDepthOfBitmap and DrawBackgroundBitmap to get this code
                                    working with the Metrowerks compiler
       <1>      4/24/98     srk     first file; revised to personal coding style
        
 
 NOTES:
 
 
 TO DO:
 
*/
 
 
#include "Application.h"
#include "QTCode.h"
 
 
long FAR PASCAL FrameWndProc  (HWND, UINT, UINT, LONG) ;
long FAR PASCAL MovieWndProc  (HWND, UINT, UINT, LONG) ;
BOOL            DoOpenMovie();
int             DoIdleMenus(HWND hWnd, HMENU hMenu);
static void     DoCut(HWND);
static void     DoCopy(HWND);
static void     DoPaste(HWND);
static void     DoClear(HWND);
static void     DoUndo(HWND);
static void     DoAbout(void);
HPALETTE        DoCreatePaletteFromBitMap(HMODULE appInstance, WORD bitMapID);
void            SetMovieFrameTimeValue(Movie theMovie, TimeValue thisPoint);
WORD            GetBitDepthOfBitmap(HMODULE appInstance, WORD bitMapID);
void            GetRBGColorsFromBitmap(HDC  hDC, HANDLE hInst, WORD bitMapID, LPRGBQUAD *srcRgbQuadArray, HPALETTE  *hPalette);
void            DoEraseRect(HDC hDC, RECT *theRect);
int             GetLineHeight(HDC hDC);
void            DrawMovieAndBackground(HGLOBAL hWinStorage, HDC hDC, HWND hwnd);
 
 
    /* globals for this module */
HANDLE      ghInst                  = NULL;
HWND        ghWndFrame              = NULL;
HWND        ghWndMDIClient          = NULL;
BOOL        gWeAreSizingWindow      = 0;
BOOL        gWeAreCreatingWindow    = 0;
int         gOpenMovieCount         = 0;
char        gAppName[20];
char        gChildName[20];
LPRGBQUAD   gSrcRgbQuadArray        = NULL;     /* rbg color values for our window background bitmap */
HPALETTE    gHBackgroundPalette     = NULL;     /* color palette for our window background */
HANDLE      ghBkgrndBitMap          = NULL;     /* bitmap we paint on the background of our client windows */
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    WinMain()                                                     */
/*                                                                  */
/*                                                                  */
/*    The main function for this application                        */
/*                                                                  */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    LPSTR lpszCmdLine, int nCmdShow)
    {
    HANDLE      hAccel ;
    HWND        hwndFrame;
    MSG         msg ;
    WNDCLASSEX  wc;
    BOOL        success;
 
        ghInst = hInstance ;
 
        if (!hPrevInstance) 
        {
            LoadString(hInstance, IDS_APPNAME, gAppName, sizeof(gAppName));
            
            // Register the frame window class
            wc.cbSize        = sizeof(WNDCLASSEX);
            wc.style         = CS_HREDRAW | CS_VREDRAW;
            wc.lpfnWndProc   = (WNDPROC)FrameWndProc;
            wc.cbClsExtra    = 0;
            wc.cbWndExtra    = 0;
            wc.hInstance     = hInstance;
            wc.hIcon         = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPICON));
            wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
            wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
            wc.lpszMenuName  = gAppName;
            wc.lpszClassName = gAppName;
            wc.hIconSm       = LoadImage(hInstance,
                                         MAKEINTRESOURCE(IDI_APPICON),
                                         IMAGE_ICON,
                                         16, 16,
                                         0);
            if (!RegisterClassEx(&wc))
            {
                if (!RegisterClass((LPWNDCLASS)&wc.style))
                    return FALSE;
            }
 
            LoadString(hInstance, IDS_MDICHILD, gChildName, sizeof(gChildName));
 
            // Register the Movie child window class
            wc.cbSize        = sizeof(WNDCLASSEX);
            wc.style         = CS_HREDRAW | CS_VREDRAW;
            wc.lpfnWndProc   = (WNDPROC)MovieWndProc;
            wc.cbClsExtra    = 0;
            wc.cbWndExtra    = 0;
            wc.hInstance     = hInstance;
            wc.hIcon         = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CHILDICON));
            wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
            wc.hbrBackground = NULL /* we want to handle erasing of the background ourselves */;
            wc.lpszMenuName  = NULL;
            wc.lpszClassName = gChildName;
            wc.hIconSm       = LoadImage(hInstance,
                                         MAKEINTRESOURCE(IDI_CHILDICON),
                                         IMAGE_ICON,
                                         16, 16,
                                         0);
            if (!RegisterClassEx(&wc))
            {
                if (!RegisterClass((LPWNDCLASS)&wc.style))
                    return FALSE;
            }
        }
 
        // Load accelerators
        hAccel = LoadAccelerators (hInstance, gAppName);
 
        // Create the main frame window
        ghWndFrame = hwndFrame = CreateWindow (gAppName, gAppName,
                                               WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
                                               CW_USEDEFAULT, CW_USEDEFAULT,
                                               CW_USEDEFAULT, CW_USEDEFAULT,
                                               NULL, NULL, hInstance, NULL) ;
 
            /* get background bitmap for use with our client windows */
        ghBkgrndBitMap = LoadResource(ghInst, FindResource(ghInst, MAKEINTRESOURCE(IDB_BITMAP2), RT_BITMAP) );
 
            /* Show the window */
        ShowWindow(hwndFrame, nCmdShow);
        UpdateWindow(hwndFrame);
 
            /* Initialize QuickTime */
        success = QTCode_DoQTInit();
        if (success)
        {
                /* Process messages */
            while (GetMessage(&msg, NULL, 0, 0))
            {
                if (!TranslateMDISysAccel(ghWndMDIClient, &msg))
                    if (!TranslateAccelerator(hwndFrame, hAccel, &msg))
                    {
                        TranslateMessage(&msg);
                        DispatchMessage(&msg);
                    }
            }
        }
        else
        {
            MessageBox(hwndFrame, "Quicktime 3.0 not available", "", MB_OK);
        }
 
            /* QuickTime clean up */
        QTCode_QTCleanUp();
 
        return msg.wParam;
}
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    FrameWndProc()                                                */
/*                                                                  */
/*                                                                  */
/*    The window procedure for the MDI frame window                 */
/*                                                                  */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
long FAR PASCAL FrameWndProc (HWND hwnd, UINT message, UINT wParam, LONG lParam)
{
    HWND               hwndChild ;
 
    switch (message)
    {
        case WM_CREATE:          // Create the client window
        {
            CLIENTCREATESTRUCT ccs = {0};
 
            ccs.hWindowMenu  = GetSubMenu(GetMenu(hwnd), WINDOWMENU);
            ccs.idFirstChild = IDM_WINDOWCHILD;
 
            // Create the MDI client filling the client area
            ghWndMDIClient = CreateWindow("mdiclient",
                                         NULL,
                                         WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL |
                                         WS_HSCROLL,
                                         0, 0, 0, 0,
                                         hwnd,
                                         (HMENU)0xCAC,
                                         ghInst,
                                         (LPVOID)&ccs);
 
            ShowWindow(ghWndMDIClient, SW_SHOW);
        }
        return 0 ;
 
        case WM_COMMAND:
            switch (LOWORD(wParam))
            {
                case IDM_FILEOPEN:
                    DoOpenMovie();
                    return 0 ;
 
                case IDM_FILECLOSE:
                    hwndChild = (HWND)SendMessage(ghWndMDIClient, WM_MDIGETACTIVE, 0, 0L) ;
                    if (SendMessage (hwndChild, WM_QUERYENDSESSION, 0, 0L))
                    {
                        SendMessage (ghWndMDIClient, WM_MDIDESTROY, (WPARAM)hwndChild, 0L) ;
                    }
                    return 0 ;
 
                case IDM_EXIT:
                    SendMessage (hwnd, WM_CLOSE, 0, 0L) ;
                    return 0 ;
 
                case IDM_WINDOWTILE:
                    SendMessage (ghWndMDIClient, WM_MDITILE, 0, 0L) ;
                    return 0 ;
 
                case IDM_WINDOWCASCADE:
                    SendMessage (ghWndMDIClient, WM_MDICASCADE, 0, 0L) ;
                    return 0 ;
 
                case IDM_WINDOWICONS:
                    SendMessage (ghWndMDIClient, WM_MDIICONARRANGE, 0, 0L) ;
                    return 0 ;
 
                case IDM_WINDOWCLOSEALL:
                    {
                        HWND    hwndT;
            
                        while (hwndT = GetWindow(ghWndMDIClient, GW_CHILD))
                        {
                            // Skip the icon and title windows
                            while (hwndT && GetWindow(hwndT, GW_OWNER))
                                hwndT = GetWindow(hwndT, GW_HWNDNEXT);
 
                            if (!hwndT) break;
 
                            SendMessage(ghWndMDIClient, WM_MDIDESTROY, (WPARAM)hwndT, 0L);
                        }
                    }
                    return 0;
 
                case IDM_ABOUT:
                    DoAbout();
                    return 0;
 
                default:            // Pass to active child
                    hwndChild = (HWND)SendMessage (ghWndMDIClient, WM_MDIGETACTIVE, 0, 0L) ;
                    if (IsWindow (ghWndMDIClient))
                        SendMessage (hwndChild, WM_COMMAND, wParam, lParam) ;
 
                    break ;        // and then to DefFrameProc
            }
            break ;
 
        case WM_INITMENU:
            if (GetMenu(hwnd) == (HMENU)wParam)
                return DoIdleMenus((HWND)SendMessage(ghWndMDIClient, WM_MDIGETACTIVE, 0, 0), (HMENU)wParam);
            return 1;
 
        case WM_DESTROY :
            PostQuitMessage (0) ;
            return 0 ;
    }
 
    return DefFrameProc (hwnd, ghWndMDIClient, message, wParam, lParam) ;
}
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    MovieWndProc()                                                */
/*                                                                  */
/*                                                                  */
/*    The window procedure for our movie window                     */
/*                                                                  */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
long FAR PASCAL MovieWndProc (HWND hwnd, UINT message, UINT wParam, LONG lParam)
{
    HGLOBAL         hWinStorage = NULL;
    ChildWindowPtr  childWinPtr = NULL;
    MSG             msg = {0};
 
 
    hWinStorage = (HGLOBAL)GetWindowLong(hwnd, GWL_USERDATA);
 
    switch (message)
    {
        case WM_CREATE:
            {
                GrafPtr gp;
 
                        /* Tuck away some private storage */
                    hWinStorage = GlobalAlloc(GMEM_MOVEABLE + GMEM_ZEROINIT, sizeof(ChildWindowRecord));
                    SetWindowLong(hwnd, GWL_USERDATA, (LPARAM)hWinStorage);
 
                        /* Associate a GrafPort with this window */
                    gp = QTCode_DoCreatePortAssociation(hwnd, NULL, 0);
 
            }
            return 0;
 
        case WM_GETMINMAXINFO:
            {               
                if (hWinStorage != NULL)
                {
                    childWinPtr = (ChildWindowPtr)GlobalLock(hWinStorage);
                    if (childWinPtr != NULL)
                    {
                        LPMINMAXINFO lpmmi;
 
                            lpmmi = (LPMINMAXINFO) lParam;
                                /* we restrict the grow size of our window */
                            lpmmi->ptMaxSize.x = childWinPtr->maxWindowWidth;
                            lpmmi->ptMaxSize.y = childWinPtr->maxWindowHeight;
                            lpmmi->ptMaxTrackSize.x = childWinPtr->maxWindowWidth;
                            lpmmi->ptMaxTrackSize.y = childWinPtr->maxWindowHeight;
 
                            GlobalUnlock(hWinStorage);
                    }
                }
            }
            return 0;
 
        case WM_PAINT:
            {
                PAINTSTRUCT lPaint;
                HDC         hDC;
 
                    hDC = BeginPaint(hwnd, &lPaint);
                    if (hDC != NULL)
                    {
                        DrawMovieAndBackground(hWinStorage, hDC, hwnd);
                    }
                    EndPaint(hwnd, &lPaint);
            }
            return 0;
 
        case WM_WINDOWPOSCHANGING:
            // Don't show the window until we have created a movie and therefore
            // can properly size the window to contain the movie.
            if (gWeAreCreatingWindow)
            {
                WINDOWPOS   *lpWindowPos = (WINDOWPOS*)lParam;
                lpWindowPos->flags &= ~SWP_SHOWWINDOW;
                return 0;
            }
 
 
            return 0;
    
        case WM_KEYDOWN:
            if (wParam == VK_RETURN)    /* return key was pressed */
            {
                HDC     hDC         = NULL;
                OSType  mediaType   = VideoMediaType;
 
                    if (hWinStorage != NULL)
                    {
                        childWinPtr = (ChildWindowPtr)GlobalLock(hWinStorage);
                        if (childWinPtr != NULL)
                        {
                                /* move to next interesting movie time to display */
                            childWinPtr->currentTime = 
                                QTCode_DoGetMovieNextInterestingTime(childWinPtr->currentTime, childWinPtr->movie,
                                                                        VideoMediaType);
                            GlobalUnlock(hWinStorage);
 
                            hDC = GetDC(hwnd);
                            if (hDC != NULL)
                            {
                                DrawMovieAndBackground(hWinStorage, hDC, hwnd);
                                ReleaseDC(hwnd, hDC);
                            }
                        }
                    }
            }
 
            return 0;
 
        case WM_SIZE:
            {               
                if (hWinStorage != NULL)
                {
                    childWinPtr = (ChildWindowPtr)GlobalLock(hWinStorage);
                    if (childWinPtr != NULL)
                    {
                        if (childWinPtr->movie)
                        {
                            QTCode_PositionMovieRectInClientWindow(childWinPtr->movie, hwnd);
                        }
                        GlobalUnlock(hWinStorage);
                    }
                }
            }
            return 0;
 
        case WM_ERASEBKGND:
            {
                /* we don't want the background erased when the window is
                    re-sized, so we'll trap calls here for the WM_ERASEBKGND
                    event */
            }
            return (1); /* tell GDI we've handled erasing ourselves */
 
        case WM_COMMAND:
            {
                switch(LOWORD(wParam))      // Undo, Cut, Copy, Paste and Clear
                {
                    case IDM_EDITUNDO:
                        DoUndo(hwnd);
                        break;
 
                    case IDM_EDITCUT:
                        DoCut(hwnd);
                        break;
 
                    case IDM_EDITCOPY:
                        DoCopy(hwnd);
                        break;
 
                    case IDM_EDITPASTE:
                        DoPaste(hwnd);
                        break;
 
                    case IDM_EDITCLEAR:
                        DoClear(hwnd);
                        break;
                }
            }
            break;
 
        case WM_DESTROY:
            {       
                if (hWinStorage != NULL)
                {
                    childWinPtr = (ChildWindowPtr)GlobalLock(hWinStorage);
                    if (childWinPtr != NULL)
                    {
                            /* One less movie open */
                        --gOpenMovieCount;
 
                        QTCode_DisposeMovieAndController(childWinPtr->movie, childWinPtr->refNum);
                            /* Destroy the port association */
                        QTCode_DoDestroyPortAssociation(hwnd);
                            /* clean up offscreen GWorld */
                        QTCode_DoDestroyOffscreen(childWinPtr->offscreenGWorld, childWinPtr->hBitmap);
 
                        SetWindowLong(hwnd, GWL_USERDATA, 0);
                        GlobalUnlock(hWinStorage);
                        GlobalFree((HGLOBAL)GetWindowLong(hwnd, GWL_USERDATA));
                    }
                }
            }
            return 0;
    }
 
    return DefMDIChildProc (hwnd, message, wParam, lParam);
}
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    DoOpenMovie()                                                 */
/*                                                                  */
/*                                                                  */
/*    Code to open a given movie and prepare it for display in a    */
/*    window                                                        */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
BOOL DoOpenMovie()
{
    DWORD           dwVersion;
    short           len;
    char            szPathName[256], szFileName[256];
    HWND            hwndChild = 0;
    OPENFILENAME    ofn = {0};
    HDC             hDC;
    HGLOBAL         hWinStorage = NULL;
    OSErr           err;
    Movie           movie = NULL;
    short           movieRefNum;
    short           movieResId;
    int             movWidth, movHeight;
 
        // Present the dialog...
        *szPathName = 0;
        ofn.lStructSize = sizeof(OPENFILENAME);
        ofn.hwndOwner = ghWndFrame;
        ofn.lpstrFile = (LPSTR)szPathName;
        ofn.nMaxFile  = sizeof(szPathName);
        ofn.lpstrFilter  = "QuickTime Movies (*.mov) \0 *.mov\0All Files (*.*) \0 *.*\0";
        ofn.nFilterIndex = 1;
        ofn.lpstrInitialDir = NULL;
        ofn.Flags        = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
        if (!GetOpenFileName(&ofn)) goto bail;
 
        err = QTCode_NewMovieFromWinPathname(szPathName,    /* c-string path to movie */
                                            &movie,         /* Movie returned here */
                                            &movieRefNum,   /* Movie RefNum returned here */
                                            &movieResId);   /* Movie Resource ID returned here */
        if (err == noErr)
        {
            Rect    movieBounds;
 
                GetMovieBox(movie, &movieBounds);
                movWidth = RECT_WIDTH(movieBounds);
                movHeight = RECT_HEIGHT(movieBounds);
        }
        // Create the child movie window
        dwVersion = GetVersion();
        gWeAreCreatingWindow = TRUE;
        if ((dwVersion < 0x80000000) || (LOBYTE(LOWORD(dwVersion)) < 4))
        {
            // This is Windows NT or Win32s, so use the WM_MDICREATE message
            MDICREATESTRUCT mcs;
 
            mcs.szClass = gChildName;
            mcs.szTitle = szFileName; 
            mcs.hOwner  = ghInst;
            mcs.x       = CW_USEDEFAULT;
            mcs.y       = CW_USEDEFAULT;
            mcs.cx      = movWidth + kWinSpacer;    /* set an appropriate width for our movie window */
            mcs.cy      = movHeight + kWinSpacer;   /* set an appropriate height for our movie window */
            mcs.style   = 0;
            mcs.lParam  = 0;
 
            hwndChild = (HWND) SendMessage(ghWndMDIClient,
                                           WM_MDICREATE,
                                           0,
                                           (LPARAM)(LPMDICREATESTRUCT) &mcs);
        }
        else
        {
            // This method will only work with Windows 95, not Windows NT or Win32s
            hwndChild = CreateWindowEx(WS_EX_MDICHILD,
                                       gChildName,
                                       szFileName,
                                       0,
                                       CW_USEDEFAULT,
                                       CW_USEDEFAULT,
                                       movWidth + kWinSpacer,   /* set an appropriate width for our movie window */
                                       movHeight + kWinSpacer,  /* set an appropriate height for our movie window */
                                       ghWndMDIClient, 
                                       NULL,
                                       ghInst,
                                       0);
        }
        gWeAreCreatingWindow = FALSE;
        if (!hwndChild) goto bail;
 
        // Set the window title to the movie filename
        len = strlen(szPathName);
        while (len--)
        {
            char c = szPathName[len];
            if (c == 0x5c || c == '/')
            {
                strcpy(szFileName, &szPathName[len+1]);
                break;
            }
        }
        SetWindowText(hwndChild, szFileName);
 
            // Store movie info in private window record
        hWinStorage = (HGLOBAL)GetWindowLong(hwndChild, GWL_USERDATA);
        if (hWinStorage != NULL)
        {
            ChildWindowPtr  childWinPtr = NULL;
 
            childWinPtr = (ChildWindowPtr)GlobalLock(hWinStorage);
            if (childWinPtr != NULL)
            {
 
                childWinPtr->ghInst = ghInst;
 
                if (movie != NULL)
                {
                    childWinPtr->movie = movie;
                    childWinPtr->refNum = movieRefNum;
                    childWinPtr->hBkgrndBitmap = ghBkgrndBitMap;
                    childWinPtr->maxWindowWidth = movWidth + kWinSpacer;
                    childWinPtr->maxWindowHeight = movHeight + kWinSpacer;
 
 
                    QTCode_PositionMovieRectInClientWindow(childWinPtr->movie, hwndChild);
                    err = QTCode_GetStartPointOfFirstVideoSample(childWinPtr->movie, &childWinPtr->currentTime);
                }
 
 
                hDC = GetDC(hwndChild);
                if (hDC != NULL)
                {
                    WORD bitDepthDC;
                    RECT windowRect;
                    QDErr err;
 
                        GetRBGColorsFromBitmap( hDC,
                                                ghInst,
                                                IDB_BITMAP2,        /* ID of background bitmap we want to use */
                                                &childWinPtr->srcRgbQuadArray,  /* on return, a pointer to a rgbquad
                                                                                structure for this bitmap */
                                                &childWinPtr->hBackgroundPalette);  /* if bitmap bit depth <= 8, a custom palette */
                        bitDepthDC = GetDCBitDepth(hDC);
                        GetWindowRect(hwndChild, &windowRect);
                        childWinPtr->hBitmap = DoCreateDIBSection(hDC,              /* the device context for this HWND */
                                                                    childWinPtr->srcRgbQuadArray,       /* pointer to RGBQUAD array to use when creating
                                                                                                            DIB - NULL if bit depth > 8 */
                                                                    bitDepthDC,             /* screen depth setting */
                                                                    RECT_WIDTH(windowRect), /* window width */
                                                                    RECT_HEIGHT(windowRect) /* window height */
                                                                    );
                        childWinPtr->hMemDC = DoCreateMemoryDC(hwndChild);
                        SelectObject(childWinPtr->hMemDC, childWinPtr->hBitmap);
                        err = QTCode_CreateOffscreen(&childWinPtr->offscreenGWorld,
                                                    NULL,
                                                    NULL,
                                                    0,
                                                    childWinPtr->hBitmap,/* a pointer to a valid bitmap or NULL */
                                                    childWinPtr->hMemDC);   /* a pointer to a valid device context or NULL */
                        QTCode_SetMovieGWorld(childWinPtr->movie, childWinPtr->offscreenGWorld);
 
                        ReleaseDC(hwndChild, hDC);
                }
 
                GlobalUnlock(hWinStorage);
            }
        }
        SetWindowLong(hwndChild, GWL_USERDATA, (LPARAM)hWinStorage);
 
        // Show the window
        ShowWindow(hwndChild, SW_SHOW);
        UpdateWindow(hwndChild);
        SetFocus(hwndChild);
 
        // One more window has been opened
        gOpenMovieCount += 1;
 
        return TRUE;
 
        bail:
            if (hwndChild) SendMessage(ghWndMDIClient, WM_MDIDESTROY, (WPARAM)hwndChild, 0L);
 
        return FALSE;
}
 
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    DrawMovieAndBackground()                                      */
/*                                                                  */
/*                                                                  */
/*    Code to display a movie and background image in a given       */
/*    window                                                        */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
void DrawMovieAndBackground(HGLOBAL hWinStorage, HDC hDC, HWND hwnd)
{
    HPALETTE        previousPalette = NULL;
    ChildWindowPtr  childWinPtr;
 
        if ((childWinPtr = (ChildWindowPtr)GlobalLock(hWinStorage)) != NULL)
            {
                RECT    clientRect, windowRect;
                Rect    movieBounds;
                
                    previousPalette = UseCustomPalette(hDC, childWinPtr->hBackgroundPalette);
 
                    GetClientRect(hwnd, &clientRect);
                    GetWindowRect(hwnd, &windowRect);
 
                    DrawBackgroundBitmap(childWinPtr->hMemDC, hwnd, childWinPtr->hBkgrndBitmap, &clientRect);
                    DrawHelpMessage(childWinPtr->hMemDC, hwnd);
 
                    GetMovieBox(childWinPtr->movie, &movieBounds);
                    DoDrawFrameInfo(childWinPtr->hMemDC, hwnd, &movieBounds, childWinPtr->currentTime);
 
                    SetMovieTimeValue(childWinPtr->movie, childWinPtr->currentTime);
                    QTCode_ForceMovieRedraw(childWinPtr->movie);
 
                        /* copy our memory DC image to the display DC */
                    BitBlt(hDC, 0, 0, RECT_WIDTH(windowRect), RECT_HEIGHT(windowRect), childWinPtr->hMemDC,
                            0, 0, SRCCOPY);
 
                    GlobalUnlock(hWinStorage);
            }
 
}
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    DoCut()                                                       */
/*                                                                  */
/*                                                                  */
/*    Handles clipboard "cut" operations                            */
/*                                                                  */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
static void DoCut(HWND hwnd)
{
}
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    DoCopy()                                                      */
/*                                                                  */
/*                                                                  */
/*    Handles clipboard "copy" operations                           */
/*                                                                  */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
static void DoCopy(HWND hwnd)
{
}
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    DoPaste()                                                     */
/*                                                                  */
/*                                                                  */
/*    Handles clipboard "paste" operations                          */
/*                                                                  */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
static void DoPaste(HWND hwnd)
{
}
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    DoClear()                                                     */
/*                                                                  */
/*                                                                  */
/*    Handles clipboard "clear" operations                          */
/*                                                                  */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
static void DoClear(HWND hwnd)
{
}
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    DoUndo()                                                      */
/*                                                                  */
/*                                                                  */
/*    Handles clipboard "undo" operations                           */
/*                                                                  */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
static void DoUndo(HWND hwnd)
{
}
 
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    DoIdleMenus()                                                 */
/*                                                                  */
/*                                                                  */
/*    Enable the close item if there are any movie windows opened   */
/*                                                                  */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
int DoIdleMenus(HWND hWnd, HMENU hMenu)
{
        /* Enable the close item if there are any movie windows opened */
    EnableMenuItem(hMenu, IDM_FILECLOSE, (gOpenMovieCount) ? MF_ENABLED : MF_GRAYED);
 
    return 0;
}
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    DialogProc()                                                  */
/*                                                                  */
/*                                                                  */
/*    Callback for our dialog box                                   */
/*                                                                  */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
static LRESULT CALLBACK DialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_COMMAND:
            switch (LOWORD(wParam))
            {
                case IDOK:
                    EndDialog(hDlg, IDOK);
                    break;
            }
            break;
    }
 
    return 0;
}
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    DoAbout()                                                     */
/*                                                                  */
/*                                                                  */
/*    Displays a dialog box with information about our program      */
/*                                                                  */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
static void DoAbout()
{
    DialogBox(ghInst, MAKEINTRESOURCE(IDD_ABOUT), ghWndFrame, (DLGPROC)DialogProc);
}
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    DrawBackgroundBitmap()                                        */
/*                                                                  */
/*                                                                  */
/*    Sets the pixels in the target device context to those from    */
/*    a given DIB                                                   */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
void DrawBackgroundBitmap(  HDC     hDC,
                            HWND    hwnd,
                            HANDLE  hBitMap,
                            RECT    *updateRect)
{
    if ((hBitMap != NULL) && (hDC != NULL) && (hwnd != NULL))
    {
        LPBITMAPINFO    lpBi;
        LPTSTR          lpBits;
        int             x, y, width, height;
        int             success = FALSE;
        RECT            clientRect;
        int             childHeight, childWidth;
 
            GetClientRect(hwnd, &clientRect);
            childWidth = RECT_WIDTH(clientRect);
            childHeight = RECT_HEIGHT(clientRect);
 
            lpBi = (LPBITMAPINFO)LockResource(hBitMap);
 
            lpBits = (LPSTR)lpBi;
            lpBits += lpBi->bmiHeader.biSize + ((1 << lpBi->bmiHeader.biBitCount) * sizeof(RGBQUAD));
            width = lpBi->bmiHeader.biWidth;
            height = lpBi->bmiHeader.biHeight;
 
            for (y = 0; y <= childHeight; y += lpBi->bmiHeader.biHeight)
            {
                for (x = 0; x <= childWidth; x += lpBi->bmiHeader.biWidth)
                {
                    BOOL    intersectRect = FALSE;
                    RECT    bitMapRect;
                    RECT    destRect;
                    
                    SetRect(&bitMapRect, x, y, x+lpBi->bmiHeader.biWidth, y+lpBi->bmiHeader.biHeight);
                    
                        intersectRect = IntersectRect( &destRect, // address of structure for intersection 
                                                        updateRect, // address of structure with first rectangle 
                                                        &bitMapRect // address of structure with second rectangle 
                                                    ); 
                            /* does the current rectangle intersect with the update
                                rectangle? If so, draw it, otherwise, don't */
                        if (intersectRect)
                        {
                            success = SetDIBitsToDevice(hDC, x, y,
                                                        lpBi->bmiHeader.biWidth,
                                                        lpBi->bmiHeader.biHeight,
                                                        0,0,
                                                        0, lpBi->bmiHeader.biHeight,
                                                        lpBits, lpBi,
                                                        DIB_RGB_COLORS);
                        }
                }
            }
    }
 
}
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    DoCreatePaletteFromBitMap()                                   */
/*                                                                  */
/*                                                                  */
/*    Builds a palette from a given bitmap                          */
/*                                                                  */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
HPALETTE DoCreatePaletteFromBitMap( HMODULE     appInstance,
                                    WORD        bitMapID)
{
    HANDLE hBitMap;
    HPALETTE hPalette = NULL;
 
 
        hBitMap = LoadResource(appInstance,
                                FindResource(appInstance, MAKEINTRESOURCE(bitMapID), RT_BITMAP) );
        if (hBitMap != NULL)
        {
            LPBITMAPINFO    lpBi;
            HANDLE          hPal;
            LPLOGPALETTE    lpPal;
            int             i, nColorData;
 
                lpBi = (LPBITMAPINFO)LockResource(hBitMap);
 
                if (lpBi->bmiHeader.biClrUsed != 0)
                {
                    nColorData = lpBi->bmiHeader.biClrUsed;
                }
                else
                {
                    switch( lpBi->bmiHeader.biBitCount)
                    {
                        case 1 :
                            nColorData = 2;
                        break;
                    
                        case 4 :
                            nColorData = 16;
                        break;
                    
                        case 8 :
                            nColorData = 256;
                        break;
                    
                        case 24 :
                        case 32 : 
                            nColorData = 0;
                        break;
                    }
                }
 
                hPal = GlobalAlloc( GHND, sizeof (LOGPALETTE) + (nColorData * sizeof (PALETTEENTRY)) );
                lpPal = (LPLOGPALETTE)GlobalLock(hPal);
 
                lpPal->palVersion = 0x300;
                lpPal->palNumEntries = nColorData;
 
                for (i = 0; i < nColorData; i++)
                {
                    lpPal->palPalEntry[i].peRed     = lpBi->bmiColors[i].rgbRed;
                    lpPal->palPalEntry[i].peGreen   = lpBi->bmiColors[i].rgbGreen;
                    lpPal->palPalEntry[i].peBlue    = lpBi->bmiColors[i].rgbBlue;
 
                }
 
                hPalette = CreatePalette( lpPal );
 
                GlobalUnlock(hPal);
                GlobalFree(hPal);
 
        }
 
        return hPalette;
}
 
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    DoEraseRect()                                                 */
/*                                                                  */
/*                                                                  */
/*    Code to erase a given windows rectangle                       */
/*                                                                  */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
void DoEraseRect(HDC    hDC,
                RECT    *theRect)
{
    if (hDC != NULL)
    {
        HBRUSH      aBrush;
            
                /* erase rect. for string before redraw */
            aBrush = CreateSolidBrush(RGB(255,255,255));
            if (aBrush != NULL)
            {
                FillRect(hDC, theRect, aBrush);
                DeleteObject(aBrush);
            }
 
    }
}
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    GetLineHeight()                                               */
/*                                                                  */
/*                                                                  */
/*    Returns the line height for a given device context            */
/*                                                                  */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
int GetLineHeight(HDC   hDC)
{
    TEXTMETRIC  tm;
 
        GetTextMetrics(hDC, &tm);
        return(tm.tmExternalLeading + tm.tmHeight);
}
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    DrawHelpMessage()                                             */
/*                                                                  */
/*                                                                  */
/*    Draws our help text in a window                               */
/*                                                                  */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
void DrawHelpMessage(   HDC     hDC,
                        HWND    hwnd)
{
 
    if (hDC != NULL)
    {
        RECT        clientRect, targetRect;
        char        helpText[100] = "Press <enter> to advance to next movie frame";
        TEXTMETRIC  tm;
        int         nLineHeight, strWidth;
 
            GetClientRect(hwnd, &clientRect);
            GetTextMetrics(hDC, &tm);
            nLineHeight = tm.tmExternalLeading + tm.tmHeight;
 
            strWidth =  strlen( (LPCTSTR)&helpText ) * tm.tmAveCharWidth;
            SetRect(&targetRect,    clientRect.left + ((RECT_WIDTH(clientRect) - strWidth)/2),
                                    clientRect.bottom - nLineHeight,
                                    clientRect.left + ((RECT_WIDTH(clientRect) - strWidth)/2) + strWidth,
                                    clientRect.bottom);
            DoEraseRect(hDC, &targetRect);
 
                /* draw help message */
            DrawText(hDC, (LPCTSTR)&helpText, -1, &targetRect, DT_CENTER);
    }
}
 
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    DoCreateDIBSection()                                          */
/*                                                                  */
/*                                                                  */
/*    Creates a device independent bitmap using CreateDIBSection    */
/*                                                                  */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
HBITMAP DoCreateDIBSection( HDC             dc,
                            LPRGBQUAD       srcRgbQuadArray,    /* if (depth > 8), this param ignored */
                            WORD            depth,
                            LONG            width,
                            LONG            height
                            )
{
    UINT    usage;
    LPTSTR  bits = NULL;
    
        // a struct large enough to hold the largest bitmapinfo ...
    struct BITMAPINFO_256
    {   
        BITMAPINFOHEADER bmiHeader;
        long bmiColors[256];
    };
    typedef struct BITMAPINFO_256 BITMAPINFO_256;
 
    BITMAPINFO_256 bmi;
 
 
        memset(&bmi, 0, sizeof(bmi));
 
        bmi.bmiHeader.biSize            = sizeof(BITMAPINFOHEADER);
        bmi.bmiHeader.biWidth           = width;
            /* important!!! - we specify a top-down DIB (by passing a negative height value)
                with origin in the upper left, otherwise our movie image will show up as inverted */
        bmi.bmiHeader.biHeight          = -1 * height;
        bmi.bmiHeader.biPlanes          = 1;
        bmi.bmiHeader.biBitCount        = depth;
        bmi.bmiHeader.biSizeImage       = 0;
        bmi.bmiHeader.biClrUsed         = 0;
        bmi.bmiHeader.biClrImportant    = 0;
 
 
        switch ( depth )
        {
            case 4:
            case 8:
                {
                    long        num_colors = (1 << depth),
                                i;
                    LPRGBQUAD   lpQuadDest, lpQuadSource;
 
 
                        bmi.bmiHeader.biCompression = BI_RGB;
                        usage = DIB_RGB_COLORS;
 
                        lpQuadSource = srcRgbQuadArray;
                        
                        for (i=0; i<num_colors; i++)
                        {
                            lpQuadDest = (LPRGBQUAD)&bmi.bmiColors[i];
 
                            lpQuadDest->rgbBlue     = lpQuadSource->rgbBlue;
                            lpQuadDest->rgbRed      = lpQuadSource->rgbRed;
                            lpQuadDest->rgbGreen    = lpQuadSource->rgbGreen;
                            lpQuadDest->rgbReserved = lpQuadSource->rgbReserved;
 
                            ++lpQuadSource;
                        }
                }
                break;
 
            case 16:
            case 24:
            case 32:
                {                   
                    bmi.bmiHeader.biCompression = BI_RGB;
                    usage = DIB_RGB_COLORS;
        
                    bmi.bmiColors[0] = 0;
                    bmi.bmiColors[1] = 0;
                    bmi.bmiColors[2] = 0;
                }
                break;
   
            default:
                break;
        }
 
        return CreateDIBSection(dc, (BITMAPINFO *) &bmi, usage, &bits, NULL, 0);
}
 
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    GetDCBitDepth()                                               */
/*                                                                  */
/*                                                                  */
/*    Returns the bit depth of a device context                     */
/*                                                                  */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
WORD    GetDCBitDepth(HDC   hDC)
{
    return(GetDeviceCaps( hDC, BITSPIXEL)); 
}
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    GetBitDepthOfBitmap()                                         */
/*                                                                  */
/*                                                                  */
/*    Returns the bit depth of a bitmap                             */
/*                                                                  */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
WORD    GetBitDepthOfBitmap(HMODULE appInstance,    /* application instance */
                            WORD bitMapID           /* resource ID of bit map */
                            )
{
    HBITMAP hBitMap;
 
        hBitMap = LoadResource(appInstance, FindResource(appInstance, MAKEINTRESOURCE(bitMapID), RT_BITMAP) );
        if (hBitMap != NULL)
        {
            LPBITMAPINFO    lpBi;
 
                lpBi = (LPBITMAPINFO)LockResource(hBitMap);
 
                return (lpBi->bmiHeader.biBitCount);
        }
        else
        {
            return 0;
        }
 
}
 
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    GetRBGColorsFromBitmap()                                      */
/*                                                                  */
/*                                                                  */
/*    Returns the RGBQUAD array for a bitmap                        */
/*                                                                  */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
void GetRBGColorsFromBitmap(HDC         hDC,
                            HANDLE      hInst,
                            WORD        bitMapID,
                            LPRGBQUAD   *srcRgbQuadArray,   /* on return, a pointer to a rgbquad
                                                            structure for this bitmap */
                            HPALETTE    *hPalette)  /* if bitmap bit depth <= 8, a custom palette
                                                    for the bitmap will be returned here */
{
    WORD            bitDepthDC, bitDepthBITMAP;
    LPBITMAPINFO    srcBITMAPINFO;
    HANDLE          hBitMapTemp;
 
        bitDepthDC      =   GetDCBitDepth(hDC);
        bitDepthBITMAP  =   GetBitDepthOfBitmap(hInst,      /* application instance */
                                                bitMapID    /* resource ID of bit map */
                                                );
        srcBITMAPINFO = NULL;
        *srcRgbQuadArray = NULL;
        *hPalette = NULL;
 
            /* does the device context have a bit depth <= 8? */
        if (bitDepthDC <= 8)
        {
                /* does our bitmap have a depth <= 8? */
            if (bitDepthBITMAP <= 8)
            {
                    /* create custom palette for use with this bitmap */
                *hPalette = DoCreatePaletteFromBitMap(hInst, bitMapID);
 
                    /* get color data to use when calling CreateDIBSection */
                hBitMapTemp = LoadResource(hInst,
                                            FindResource(hInst, MAKEINTRESOURCE(bitMapID),
                                            RT_BITMAP) );
                if (hBitMapTemp != NULL)
                {
                        /* get bitmapinfo data */
                    srcBITMAPINFO = (LPBITMAPINFO)LockResource(hBitMapTemp);
                        /* get pointer to rgbquad array for this bitmap */
                    *srcRgbQuadArray = &srcBITMAPINFO->bmiColors[0];
                }
            }
        }
 
}
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    DoCreateMemoryDC()                                            */
/*                                                                  */
/*                                                                  */
/*    Creates a memory device context                               */
/*                                                                  */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
HDC DoCreateMemoryDC(HWND   hwnd)
{
    HDC hMemDC, hDC;
 
        hDC = GetDC(hwnd);
        if (hDC)
        {
            hMemDC = CreateCompatibleDC(hDC);
            SetMapMode(hMemDC, GetMapMode(hDC));
            ReleaseDC(hwnd, hDC);
 
            return hMemDC;
        }
 
        return NULL;
}
 
 
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    UseCustomPalette()                                            */
/*                                                                  */
/*                                                                  */
/*    Selects/Realizes a logical palette                            */
/*                                                                  */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
HPALETTE UseCustomPalette(HDC   hDC, HPALETTE   newPalette)
{
    HPALETTE    previousPalette;
    UINT        nEntries;
 
            /* use a custom palette if need be */
        if (newPalette)
        {
            previousPalette = SelectPalette(hDC, newPalette, FALSE);
            nEntries = RealizePalette(hDC);
        }
 
        return previousPalette;
}
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    DoDrawFrameInfo()                                             */
/*                                                                  */
/*                                                                  */
/*    Draws our help text messages into a window                    */
/*                                                                  */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
void DoDrawFrameInfo(HDC        hMemDC,
                     HWND       hwnd,
                     Rect       *movieBounds,
                     TimeValue  theTime)
{
    RECT        destRect;
    int         nLineHeight;
    Str255      theString;
    char        frameText[25] = "Frame ";
    Rect        centeredRect;
 
 
        nLineHeight = GetLineHeight(hMemDC);
 
        CenterMovieRectInWindow(hwnd,                   /* window where we are placing the image */
                              (movieBounds->right - movieBounds->left),
                              (movieBounds->bottom - movieBounds->top), /* width, height, of the movie */
                              &centeredRect         /* on output, a Mac Rect centered in the window */
                              );
        SetRect(&destRect,  (int)centeredRect.left - nLineHeight,
                            (int)centeredRect.top - nLineHeight /*- menuSize*/,
                            (int)centeredRect.right + nLineHeight,
                            (int)centeredRect.bottom + nLineHeight /*- menuSize*/);
        DoEraseRect(hMemDC, &destRect);
 
        SetRect(&destRect,  (int)centeredRect.left,
                            (int)centeredRect.bottom /*- menuSize*/,
                            (int)centeredRect.right,
                            (int)centeredRect.bottom + nLineHeight /*- menuSize*/);
        DoEraseRect(hMemDC, &destRect);
 
            /* draw new frame # */
        NumToString((long)theTime, theString);
        p2cstr(theString);
        lstrcat((LPSTR)frameText, (LPCSTR)&theString);
        DrawText(hMemDC, (LPCTSTR)&frameText, -1, &destRect, DT_CENTER);
 
}
 
 
/* ---------------------------------------------------------------- */
/*                                                                  */
/*    CenterMovieRectInWindow()                                     */
/*                                                                  */
/*                                                                  */
/*    Given height/width values for a movie, returns a Mac rect     */
/*    for the movie centered in a window                            */
/*                                                                  */
/*                                                                  */
/* ---------------------------------------------------------------- */
 
void CenterMovieRectInWindow(HWND   hwnd,                   /* window where we are placing the image */
                              int   movWidth, int movHeight,    /* width, height, of the movie */
                              Rect  *centeredRect           /* on output, a Mac Rect centered in the window */
                              )
{
    RECT    clientRect;
    int     availSpace;
    BOOL    success;
 
        success = GetClientRect(hwnd, // handle of window 
                                &clientRect// address of structure for client coordinates 
                                );  
 
        availSpace = RECT_WIDTH(clientRect) - movWidth;
        if (availSpace < 0)
        {
            /* movie is bigger than client space? */
        }
        centeredRect->left = clientRect.left + availSpace/2;
 
        availSpace = RECT_HEIGHT(clientRect) - movHeight;
        if (availSpace < 0)
        {
            /* movie is bigger than client space? */
        }
        centeredRect->top = clientRect.top + availSpace/2;
        centeredRect->right = centeredRect->left + movWidth;
        centeredRect->bottom = centeredRect->top + movHeight;
 
}