//---------------------------------------------------------------------------------------------------
//	MDIPlayer.c
//
//	A rudimentary MDI movie player application
//  Created Aug 5, 1996 by Brian S. Friedkin
//	Copyright 1996 Apple Computer Inc.
//---------------------------------------------------------------------------------------------------
//
//	Change History (most recent first):
//
//	   <2>	 	03/19/98	rtm		added !IsIconic(hwnd) before call to MCIsPlayerEvent in MovieWndProc
//									to fix drawing problems when arranging icons
//	   <1>	 	03/18/98	rtm		added !IsIconic(hwnd) to test in WM_SIZE message processing in MovieWndProc
//									to fix sizing problems when minimized; added WM_WINDOWPOSCHANGED processing to
//									MovieWndProc to stop movies from playing in minimized windows


// Macintosh headers
#include "QTML.h"
#include "Movies.h"
#include "Scrap.h"

// Windows headers
#include <windows.h>
#include "resource.h"

#define kMovieControllerHeight	16
#define	RECT_WIDTH(r)	(r.right-r.left)
#define	RECT_HEIGHT(r)	(r.bottom-r.top)
#define	WM_PUMPMOVIE	(WM_USER+0)

long FAR PASCAL FrameWndProc  (HWND, UINT, UINT, LONG) ;
long FAR PASCAL MovieWndProc  (HWND, UINT, UINT, LONG) ;
BOOL			DoOpenMovie();
int				DoIdleMenus(HWND hWnd, HMENU hMenu);
Boolean			MyPlayerFilter(MovieController theController, short action, void *params, long refCon);
void			SizeWindowToMovie(HWND hWnd);
static long		GetWindowBorderWidth(HWND hWnd);
static long		GetWindowMenuHeight(HWND hWnd);
static void		DoCut(HWND);
static void		DoCopy(HWND);
static void		DoPaste(HWND);
static void		DoClear(HWND);
static void		DoUndo(HWND);
static void		DoAbout(void);
static void		CalcWindowMinMaxInfo(HWND theWnd, LPMINMAXINFO lpMinMax);

// Data held in each child movie window
typedef struct {
	Movie			m;
	MovieController	mc;
	HWND			hWnd;
	short			resID;
	short			refNum;
} ChildWindowRecord, **ChildWindowHand;

HANDLE	ghInst;
HWND	ghWnd;
HWND	ghWndMDIClient;
char	szAppName[20];
char	szChildName[] = "MdiChild";
Rect	gMCResizeBounds;
int		cOpen = 0;
BOOL	gWeAreSizingWindow = 0;
BOOL	gWeAreCreatingWindow = 0;
BOOL	gShuttingDown = FALSE;

/* ------------------------------------------------------------- */

int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,
                    LPSTR lpszCmdLine, int nCmdShow)
{
	HANDLE		hAccel ;
	HWND		hwndFrame;
	MSG			msg ;
    WNDCLASSEX	wc;

	ghInst = hInstance ;

	if (!hPrevInstance) 
	{
		LoadString(hInstance, IDS_APPNAME, szAppName, sizeof(szAppName));
		
		// 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  = szAppName;
		wc.lpszClassName = szAppName;
		wc.hIconSm       = LoadImage(hInstance,
									 MAKEINTRESOURCE(IDI_APPICON),
									 IMAGE_ICON,
									 16, 16,
									 0);
		if (!RegisterClassEx(&wc))
		{
			if (!RegisterClass((LPWNDCLASS)&wc.style))
        		return FALSE;
		}

		// Register the Movie child window class
		wc.cbSize        = sizeof(WNDCLASSEX);
		wc.style         = 0;
		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 = (HBRUSH)(COLOR_WINDOW + 1);
		wc.lpszMenuName  = NULL;
		wc.lpszClassName = szChildName;
		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, szAppName);

	// Initialize QuickTime Media Layer
	InitializeQTML(0);

	// Initialize QuickTime
	EnterMovies();

	// Create the main frame window
	ghWnd = hwndFrame = CreateWindow (szAppName, szAppName,
                               WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
                               CW_USEDEFAULT, CW_USEDEFAULT,
                               CW_USEDEFAULT, CW_USEDEFAULT,
                               NULL, NULL, hInstance, NULL) ;

	// Show the window
	ShowWindow(hwndFrame, nCmdShow);
	UpdateWindow(hwndFrame);

	// Process messages
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!TranslateMDISysAccel(ghWndMDIClient, &msg))
            if (!TranslateAccelerator(hwndFrame, hAccel, &msg))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
    }

	// Clean up
	ExitMovies();
	TerminateQTML();

	return msg.wParam;
}

/* ------------------------------------------------------------- */

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:
					gShuttingDown = TRUE;
					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) ;
}

/* ------------------------------------------------------------- */

long FAR PASCAL MovieWndProc (HWND hwnd, UINT message, UINT wParam, LONG lParam)
{
	WPARAM			nWidth, nHeight;
	MovieController	mc = 0;
	Movie			m = 0;
	ChildWindowHand	hStorage;
	MSG				msg = {0};

	if (hStorage = (ChildWindowHand)GetWindowLong(hwnd, GWL_USERDATA))
	{
		mc = (**hStorage).mc;
		m = (**hStorage).m;
	}

	// Give the movie controller this message first
	if (!gShuttingDown && mc)
	{
		EventRecord	macEvent;

		msg.hwnd = hwnd;
		msg.message = message;
		msg.wParam = wParam;
		msg.lParam = lParam;
		msg.time = 0;
		msg.pt.x = 0;
		msg.pt.y = 0;

		// tranlate a windows event to a mac event
		WinEventToMacEvent(&msg, &macEvent);

		// pass in a mac event
		if (!IsIconic(hwnd))
			MCIsPlayerEvent(mc, (EventRecord*)&macEvent);
	}

	switch (message)
	{
		case WM_CREATE:
			// Tuck away some private storage
			hStorage = (ChildWindowHand)NewHandleClear(sizeof(ChildWindowRecord));
			(**hStorage).hWnd = hwnd;
			SetWindowLong(hwnd, GWL_USERDATA, (LPARAM)hStorage);

			// Associate a GrafPort with this window
			CreatePortAssociation(hwnd, NULL, 0);
			break;

		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;
			}
			break;

		case WM_WINDOWPOSCHANGED:
			// If a movie window has become minimized, stop the movie.
			if (IsIconic(hwnd))
				StopMovie(m);
			break;

		case WM_SIZE:
			// Resize the movie and controller to fit the window
			nWidth = LOWORD(lParam);
			nHeight = HIWORD(lParam);
			if (!gWeAreSizingWindow && mc && !IsIconic(hwnd))
			{
				Rect	r = {0};
				GrafPtr	port = (GrafPtr)MCGetControllerPort(mc);
				r.right = nWidth;
				r.bottom = nHeight;
				MCSetControllerBoundsRect(mc, &r);
			}
			break;

		case WM_PUMPMOVIE:					// We receive this message only to idle the movie
			break;

		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_GETMINMAXINFO:
			CalcWindowMinMaxInfo(hwnd, (LPMINMAXINFO)lParam);
			return 0;

		case WM_DESTROY:
			// One less movie open
			--cOpen;

			// Dispose movie and controller
			hStorage = (ChildWindowHand)GetWindowLong(hwnd, GWL_USERDATA);
			if ((**hStorage).refNum) CloseMovieFile((**hStorage).refNum);

			// Set a player filter proc to nil before closing it because
			// in some instances it gets called after we shut down.
			if (mc) {
				MCSetActionFilterWithRefCon(mc, MyPlayerFilter, 0);
				DisposeMovieController(mc);
			}
			if (m) DisposeMovie(m);
			DisposeHandle((Handle)GetWindowLong(hwnd, GWL_USERDATA));
			SetWindowLong(hwnd, GWL_USERDATA, 0);

			// Destroy the port association
			DestroyPortAssociation((CGrafPtr)GetHWNDPort(hwnd));
			return 0;
	}

	return DefMDIChildProc (hwnd, message, wParam, lParam);
}

/* ------------------------------------------------------------- */

BOOL DoOpenMovie()
{
    DWORD			dwVersion;
	FSSpec			fileSpec;
	OSErr			err;
	long			mcFlags;
	short			len, movieRefNum, movieResId;
    char            szPathName[256], szFileName[256];
	Rect			movieBounds;
	ChildWindowHand	hStorage;
	RECT			rcWindow;
	HWND			hWndDesktop;
    HWND			hwndChild = 0;
	Movie			theMovie=0;
	MovieController	theMC=0;
    OPENFILENAME    ofn = {0};

	// Present the dialog...
	*szPathName = 0;
	ofn.lStructSize = sizeof(OPENFILENAME);
    ofn.hwndOwner = ghWnd;
    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;

	// 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 = szChildName;
		mcs.szTitle = szFileName; 
		mcs.hOwner  = ghInst;
		mcs.x       = CW_USEDEFAULT;
		mcs.y       = CW_USEDEFAULT;
		mcs.cx      = CW_USEDEFAULT;
		mcs.cy      = CW_USEDEFAULT;
		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,
								   szChildName,
								   szFileName,
								   0,
								   CW_USEDEFAULT,
								   CW_USEDEFAULT,
								   CW_USEDEFAULT,
								   CW_USEDEFAULT,
								   ghWndMDIClient, 
								   NULL,
								   ghInst,
								   0);
	}
	gWeAreCreatingWindow = FALSE;
	if (!hwndChild) goto bail;

	MacSetPort(GetHWNDPort(hwndChild));
	hStorage = (ChildWindowHand)GetWindowLong(hwndChild, GWL_USERDATA);

	// 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);

	// Open up the movie file...

	// Fill in a FSSpec.  Currently the vRefNum and parID are not used under Windows.
	// Note the name must be a full pathname P-string!
	fileSpec.vRefNum = 0;
	fileSpec.parID = 0;
	strcpy((char*)&fileSpec.name[1], szPathName);
	fileSpec.name[0] = strlen(szPathName);
	err = OpenMovieFile(&fileSpec, &movieRefNum, fsRdWrPerm);
	if (err)
		err = OpenMovieFile(&fileSpec, &movieRefNum, fsRdPerm);
	if (!err)
	{
		movieResId = 0;
		err = NewMovieFromFile(&theMovie, movieRefNum, &movieResId, NULL,newMovieActive,NULL);
	}
	if (err) goto bail;

	// Offset the movie box to (0,0)
	GetMovieBox(theMovie, &movieBounds);
	movieBounds.right = RECT_WIDTH(movieBounds);
	movieBounds.bottom = RECT_HEIGHT(movieBounds);
	movieBounds.left = movieBounds.top = 0;
	
	// Audio only movies need some width for the controller!
	if (!movieBounds.right) movieBounds.right = 320;
	SetMovieBox(theMovie, &movieBounds);

	// Create and initialize the movie controller
	movieBounds.bottom += kMovieControllerHeight;
	theMC = NewMovieController(theMovie, &movieBounds, mcTopLeftMovie);
	if (!theMC) goto bail;

	MCDoAction(theMC, mcActionGetFlags, &mcFlags);
	mcFlags |= (mcFlagSuppressMovieFrame | mcFlagsUseWindowPalette);
	MCDoAction(theMC, mcActionSetFlags, (void*)mcFlags);
	MCEnableEditing(theMC, true);

	// Make a growbox
	// Set the mc resize bounds
	hWndDesktop = GetDesktopWindow();
	GetWindowRect(hWndDesktop, &rcWindow);
	gMCResizeBounds.right = (short)rcWindow.right;
	gMCResizeBounds.bottom = (short)rcWindow.bottom;
	gMCResizeBounds.top = 48+16;			// Min height + mc
	gMCResizeBounds.left = (16+16+16);	// Speaker+mc+grow icon widths
	if (gMCResizeBounds.left < GetSystemMetrics(SM_CXMINTRACK))
		gMCResizeBounds.left = GetSystemMetrics(SM_CXMINTRACK);
	if (gMCResizeBounds.top < GetSystemMetrics(SM_CYMINTRACK))
		gMCResizeBounds.top = GetSystemMetrics(SM_CYMINTRACK);
	MCDoAction(theMC, mcActionSetGrowBoxBounds, &gMCResizeBounds);

	// Allow the controller to accept keyboard events
	MCDoAction(theMC, mcActionSetKeysEnabled, (void*)1);

	// Store movie info in private window record
	(**hStorage).m = theMovie;
	(**hStorage).mc = theMC;
	(**hStorage).resID = movieResId;
	(**hStorage).refNum = movieRefNum;

	// Set a player filter proc to trap certain events
	MCSetActionFilterWithRefCon(theMC, MyPlayerFilter, (long)hStorage);

	// Size the window to fit the movie and controller
	SizeWindowToMovie(hwndChild);

	// Show the window
	ShowWindow(hwndChild, SW_SHOW);
	UpdateWindow(hwndChild);
	SetFocus(hwndChild);


	// One more window has been opened
	cOpen += 1;

	return TRUE;

bail:
	if (hwndChild) SendMessage(ghWndMDIClient, WM_MDIDESTROY, (WPARAM)hwndChild, 0L);
	if (theMovie) DisposeMovie(theMovie);
	if (theMC) DisposeMovieController(theMC);
	return FALSE;
}

/* ------------------------------------------------------------- */

static void DoCut(HWND hwnd)
{
	MovieController	mc = 0;
	ChildWindowHand	hStorage = (ChildWindowHand)GetWindowLong(hwnd, GWL_USERDATA);

	if (hStorage)
	{
		if (mc = (**hStorage).mc)
		{
			// Cut the segment
			Movie	scrapMovie = MCCut(mc);

			// Place the segment into the scrap
			if (scrapMovie)
			{
				PutMovieOnScrap(scrapMovie, 0L);
				DisposeMovie(scrapMovie);
			}
		}
	}
}

/* ------------------------------------------------------------- */

static void DoCopy(HWND hwnd)
{
	MovieController	mc = 0;
	ChildWindowHand	hStorage = (ChildWindowHand)GetWindowLong(hwnd, GWL_USERDATA);

	if (hStorage)
	{
		if (mc = (**hStorage).mc)
		{
			// Copy the segment
			Movie	scrapMovie = MCCopy(mc);

			// Place the segment into the scrap
			if (scrapMovie)
			{
				PutMovieOnScrap(scrapMovie, 0L);
				DisposeMovie(scrapMovie);
			}
		}
	}
}

/* ------------------------------------------------------------- */

static void DoPaste(HWND hwnd)
{
	MovieController	mc = 0;
	ChildWindowHand	hStorage = (ChildWindowHand)GetWindowLong(hwnd, GWL_USERDATA);

	if (hStorage)
	{
		if (mc = (**hStorage).mc)
			MCPaste(mc, nil);
	}
}

/* ------------------------------------------------------------- */

static void DoClear(HWND hwnd)
{
	MovieController	mc = 0;
	ChildWindowHand	hStorage = (ChildWindowHand)GetWindowLong(hwnd, GWL_USERDATA);

	if (hStorage)
	{
		if (mc = (**hStorage).mc)
			MCClear(mc);
	}
}

/* ------------------------------------------------------------- */

static void DoUndo(HWND hwnd)
{
	MovieController	mc = 0;
	ChildWindowHand	hStorage = (ChildWindowHand)GetWindowLong(hwnd, GWL_USERDATA);

	if (hStorage)
	{
		if (mc = (**hStorage).mc)
			MCUndo(mc);
	}
}

/* ------------------------------------------------------------- */

// Size the HWND to exactly fit the movie and controller
void SizeWindowToMovie(HWND hWnd)
{
	ChildWindowHand	hStorage = (ChildWindowHand)GetWindowLong(hWnd, GWL_USERDATA);
	Movie		theMovie = (**hStorage).m;
	MovieController	mc = (**hStorage).mc;
	CGrafPtr	wPort = (CGrafPtr)GetHWNDPort(hWnd);
	Rect		movieBounds;

	gWeAreSizingWindow = TRUE;

	MCGetControllerBoundsRect(mc, &movieBounds);
	if (!RECT_WIDTH(movieBounds))
	{
		movieBounds.left = 0;
		movieBounds.right = 320;
	}

	// Size our window
	SizeWindow((WindowPtr)wPort, movieBounds.right, movieBounds.bottom, FALSE);

	gWeAreSizingWindow = FALSE;

	MacSetPort((GrafPtr)wPort);
}

/* ------------------------------------------------------------- */

Boolean MyPlayerFilter(MovieController theController, short action, void *params, long refCon)
{
#define mcActionControllerSizeChanged 26
	ChildWindowHand	hStorage;

	switch (action) {
	case  mcActionControllerSizeChanged:
		if ( (hStorage = (ChildWindowHand)refCon) ) {
			SizeWindowToMovie((**hStorage).hWnd);
		}
		break;
	}
	return 0;
}

/* ------------------------------------------------------------- */

int DoIdleMenus(HWND hWnd, HMENU hMenu)
{
	ChildWindowHand	hStorage = (ChildWindowHand)GetWindowLong(hWnd, GWL_USERDATA);
	MovieController	mc = 0;

	if (hStorage) mc = (**hStorage).mc;

	// Enable the close item if there are any movie windows opened
	EnableMenuItem(hMenu, IDM_FILECLOSE, (cOpen) ? MF_ENABLED : MF_GRAYED);

	// Idle the edit menu
	if (mc)
	{
		long	controllerFlags;

		MCGetControllerInfo(mc,&controllerFlags);

		EnableMenuItem(hMenu, IDM_EDITUNDO, controllerFlags & mcInfoUndoAvailable ? MF_ENABLED : MF_GRAYED);
		EnableMenuItem(hMenu, IDM_EDITCUT, controllerFlags & mcInfoCutAvailable ? MF_ENABLED : MF_GRAYED);
		EnableMenuItem(hMenu, IDM_EDITCOPY, controllerFlags & mcInfoCopyAvailable ? MF_ENABLED : MF_GRAYED);
		EnableMenuItem(hMenu, IDM_EDITPASTE, controllerFlags & mcInfoPasteAvailable ? MF_ENABLED : MF_GRAYED);
		EnableMenuItem(hMenu, IDM_EDITCLEAR, controllerFlags & mcInfoClearAvailable ? MF_ENABLED : MF_GRAYED);
	}

	return 0;
}

/* ------------------------------------------------------------- */

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;
}

static void DoAbout()
{
	DialogBox(ghInst, MAKEINTRESOURCE(IDD_ABOUT), ghWnd, (DLGPROC)DialogProc);
}

/* ------------------------------------------------------------- */

// Get width of the window (vertical) borders
static long GetWindowBorderWidth(HWND hWnd)
{
	RECT	rcWindow, rcClient;
	
	GetWindowRect(hWnd, &rcWindow);
	GetClientRect(hWnd, &rcClient);

	return RECT_WIDTH(rcWindow) - RECT_WIDTH(rcClient);
}

/* ------------------------------------------------------------- */

// Get height of the menubar contained by this window
static long GetWindowMenuHeight(HWND hWnd)
{
	RECT	rcWindow, rcClient;
	
	GetWindowRect(hWnd, &rcWindow);
	GetClientRect(hWnd, &rcClient);

	// Our MDI child windows have no menu
	return (RECT_HEIGHT(rcWindow) - RECT_HEIGHT(rcClient)) - GetSystemMetrics(SM_CYCAPTION);
}

/* ------------------------------------------------------------- */

static void CalcWindowMinMaxInfo(HWND theWnd, LPMINMAXINFO lpMinMax)
{
	ChildWindowHand	hStorage = (ChildWindowHand)GetWindowLong(theWnd, GWL_USERDATA);
	MovieController	mc = 0;
	Movie	m = 0;

	if (hStorage)
	{
		mc = (**hStorage).mc;
		m = (**hStorage).m;
	}

	if (mc && m)
	{
		Rect	movieBox;

		lpMinMax->ptMinTrackSize.x = gMCResizeBounds.left + (2 * GetSystemMetrics(SM_CXFRAME));
		GetMovieBox(m, &movieBox);
		if (RECT_HEIGHT(movieBox))
			lpMinMax->ptMinTrackSize.y = gMCResizeBounds.top +	// growbounds height +
				(2 * GetSystemMetrics(SM_CXFRAME)) +			// frame wthickness +
				GetSystemMetrics(SM_CYCAPTION) +				// caption height +
				-1 +											// fudge factor
				kMovieControllerHeight;							// movie controller height
		else
			lpMinMax->ptMaxSize.y =
			lpMinMax->ptMaxTrackSize.y =
			lpMinMax->ptMinTrackSize.y = 0 +					// height of audio only movie +
				(2 * GetSystemMetrics(SM_CXFRAME)) +			// frame wthickness +
				GetSystemMetrics(SM_CYCAPTION) +				// caption height +
				-1 +											// fudge factor
				kMovieControllerHeight;							// movie controller height
	}
}
