1169 lines
32 KiB
C
1169 lines
32 KiB
C
|
/******************************************************************************
|
||
|
|
||
|
Copyright (C) Microsoft Corporation 1985-1991. All rights reserved.
|
||
|
|
||
|
Title: window.c - Multimedia Systems Media Control Interface
|
||
|
driver for AVI.
|
||
|
|
||
|
*****************************************************************************/
|
||
|
#include "graphic.h"
|
||
|
|
||
|
#include "avitask.h" // for TASKIDLE
|
||
|
|
||
|
//#define IDM_CONFIG 0x100
|
||
|
//#define IDM_SKIPFRAMES 0x110
|
||
|
#define IDM_MUTE 0x120
|
||
|
#define IDM_STRETCH 0x130
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
// Use a different class name on 32 bit systems to ease the 16/32
|
||
|
// coexistence problem. (We might want both classes defined at once.)
|
||
|
TCHAR szClassName[] = TEXT("AVIWnd32");
|
||
|
#else
|
||
|
char szClassName[] = "AVIWnd";
|
||
|
#endif
|
||
|
|
||
|
|
||
|
DWORD NEAR PASCAL GraphicStop (NPMCIGRAPHIC npMCI, DWORD dwFlags);
|
||
|
DWORD NEAR PASCAL GraphicPause (NPMCIGRAPHIC npMCI, DWORD dwFlags);
|
||
|
DWORD NEAR PASCAL GraphicPlay (NPMCIGRAPHIC npMCI, DWORD dwFlags,
|
||
|
LPMCI_ANIM_PLAY_PARMS lpPlay );
|
||
|
DWORD NEAR PASCAL GraphicSeek (NPMCIGRAPHIC npMCI, DWORD dwFlags,
|
||
|
LPMCI_SEEK_PARMS lpSeek);
|
||
|
|
||
|
BOOL NEAR PASCAL GraphicWindowInit (void)
|
||
|
{
|
||
|
WNDCLASS cls;
|
||
|
|
||
|
// define the class of window we want to register
|
||
|
|
||
|
cls.lpszClassName = szClassName;
|
||
|
cls.style = CS_GLOBALCLASS | CS_OWNDC;
|
||
|
cls.hCursor = LoadCursor (NULL, IDC_ARROW);
|
||
|
cls.hIcon = NULL;
|
||
|
cls.lpszMenuName = NULL;
|
||
|
////cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||
|
cls.hbrBackground = GetStockObject(BLACK_BRUSH);
|
||
|
cls.hInstance = ghModule;
|
||
|
cls.lpfnWndProc = GraphicWndProc;
|
||
|
cls.cbClsExtra = 0;
|
||
|
cls.cbWndExtra = sizeof (NPMCIGRAPHIC);
|
||
|
|
||
|
return RegisterClass (&cls);
|
||
|
}
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
/*
|
||
|
* de-register the class on unloading the dll so that we can
|
||
|
* successfully re-register the class next time we are loaded.
|
||
|
* note that nt only unregisters a class when the app exits.
|
||
|
*/
|
||
|
BOOL NEAR PASCAL GraphicWindowFree(void)
|
||
|
{
|
||
|
return(UnregisterClass(szClassName, ghModule));
|
||
|
}
|
||
|
|
||
|
|
||
|
/**************************************************************************
|
||
|
***************************************************************************/
|
||
|
|
||
|
//-----------------------------------------------------------------------
|
||
|
// this is the winproc thread's main function.
|
||
|
// we create the window and signal the event once initialization
|
||
|
// is complete. We then block either processing messages or waiting for
|
||
|
// hEventWinProcDie. When this is set, we clean up and exit
|
||
|
|
||
|
void aviWinProcTask(DWORD_PTR dwInst)
|
||
|
{
|
||
|
NPMCIGRAPHIC npMCI = (NPMCIGRAPHIC) dwInst;
|
||
|
HWND hWnd;
|
||
|
MSG msg;
|
||
|
|
||
|
// Create the default window - the caller may
|
||
|
// supply style and parent window.
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
if (npMCI->hwndParent) {
|
||
|
if ( !IsWindow(npMCI->hwndParent)) {
|
||
|
//DebugBreak();
|
||
|
// This should have been trapped before getting here
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (npMCI->dwStyle != (DWORD) -1) {
|
||
|
// CW_USEDEFAULT can't be used with popups or children so
|
||
|
// if the user provides the style, default to full-screen.
|
||
|
|
||
|
hWnd =
|
||
|
|
||
|
// Note: The CreateWindow/Ex call is written this way as on Win32
|
||
|
// CreateWindow is a MACRO, and hence the call must be contained
|
||
|
// within the preprocessor block.
|
||
|
CreateWindowEx(
|
||
|
#ifdef BIDI
|
||
|
WS_EX_BIDI_SCROLL | WS_EX_BIDI_MENU |WS_EX_BIDI_NOICON,
|
||
|
#else
|
||
|
0,
|
||
|
#endif
|
||
|
szClassName,
|
||
|
FileName(npMCI->szFilename),
|
||
|
npMCI->dwStyle,
|
||
|
0, 0,
|
||
|
GetSystemMetrics (SM_CXSCREEN),
|
||
|
GetSystemMetrics (SM_CYSCREEN),
|
||
|
npMCI->hwndParent,
|
||
|
NULL, ghModule, (LPTSTR)npMCI);
|
||
|
} else {
|
||
|
npMCI->dwStyle = WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX |
|
||
|
WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
|
||
|
hWnd =
|
||
|
CreateWindowEx(
|
||
|
#ifdef BIDI
|
||
|
WS_EX_BIDI_SCROLL | WS_EX_BIDI_MENU |WS_EX_BIDI_NOICON,
|
||
|
#else
|
||
|
0,
|
||
|
#endif
|
||
|
szClassName,
|
||
|
FileName(npMCI->szFilename),
|
||
|
npMCI->dwStyle,
|
||
|
CW_USEDEFAULT, 0,
|
||
|
CW_USEDEFAULT, 0,
|
||
|
npMCI->hwndParent,
|
||
|
NULL, ghModule, (LPTSTR)npMCI);
|
||
|
}
|
||
|
|
||
|
npMCI->hwndDefault = hWnd;
|
||
|
npMCI->hwndPlayback = hWnd;
|
||
|
|
||
|
|
||
|
if (!hWnd) {
|
||
|
// fail to start up - just exit this function and the caller
|
||
|
// will detect thread exit
|
||
|
DPF(("CreateWindow failed, LastError=%d\n", GetLastError()));
|
||
|
npMCI->dwReturn = MCIERR_CREATEWINDOW;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// window created ok - signal worker thread to continue
|
||
|
SetEvent(npMCI->hEventWinProcOK);
|
||
|
|
||
|
while (GetMessage(&msg, NULL, 0, 0)) {
|
||
|
TranslateMessage(&msg);
|
||
|
DispatchMessage(&msg);
|
||
|
}
|
||
|
|
||
|
// WM_QUIT received - exit now
|
||
|
GdiFlush();
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Pass request bit(s) to worker thread.
|
||
|
// Use WinProcRequestEx when the WinCrit critical section is already held
|
||
|
// and WINPROC_ACTIVE/INACTIVE is not being used
|
||
|
//
|
||
|
// Use WinProcRequest when the WinCrit critical section is required
|
||
|
//
|
||
|
|
||
|
void INLINE
|
||
|
WinProcRequestEx(NPMCIGRAPHIC npMCI, DWORD dwFlag)
|
||
|
{
|
||
|
DPF2(("WinProcRequestEx... request %8x", dwFlag));
|
||
|
npMCI->dwWinProcRequests |= dwFlag;
|
||
|
SetEvent(npMCI->heWinProcRequest);
|
||
|
DPF2(("!...Ex request %8x done\n", dwFlag));
|
||
|
}
|
||
|
|
||
|
void
|
||
|
WinProcRequest(NPMCIGRAPHIC npMCI, DWORD dwFlag)
|
||
|
{
|
||
|
DPF2(("WinProcRequest... request %8x", dwFlag));
|
||
|
EnterWinCrit(npMCI);
|
||
|
DPF2(("!... request %8x ...", dwFlag));
|
||
|
|
||
|
// If we are being made active or inactive, then ensure that only
|
||
|
// one of the WINPROC_ACTIVE/WINPROC_INACTIVE bits is switched on.
|
||
|
if (dwFlag & (WINPROC_ACTIVE | WINPROC_INACTIVE)) {
|
||
|
npMCI->dwWinProcRequests &= ~(WINPROC_ACTIVE | WINPROC_INACTIVE);
|
||
|
}
|
||
|
npMCI->dwWinProcRequests |= dwFlag;
|
||
|
|
||
|
SetEvent(npMCI->heWinProcRequest);
|
||
|
|
||
|
DPF2(("!... request %8x done\n", dwFlag));
|
||
|
LeaveWinCrit(npMCI);
|
||
|
}
|
||
|
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
DWORD FAR PASCAL GraphicConfig(NPMCIGRAPHIC npMCI, DWORD dwFlags);
|
||
|
#if 0
|
||
|
static void NEAR PASCAL Credits(HWND hwnd);
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Window proc is always run on the winproc thread. We hold
|
||
|
// a critical section during all paint/palette code to protect us
|
||
|
// against interaction with the worker thread. We do not hold this
|
||
|
// critical section for the whole winproc.
|
||
|
//
|
||
|
LRESULT FAR PASCAL _LOADDS GraphicWndProc (HWND hwnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
PAINTSTRUCT ps;
|
||
|
NPMCIGRAPHIC npMCI;
|
||
|
HMENU hmenu;
|
||
|
HDC hdc;
|
||
|
RECT rc;
|
||
|
MINMAXINFO FAR * lpmmi;
|
||
|
TCHAR ach[80];
|
||
|
|
||
|
#ifndef _WIN32
|
||
|
npMCI = (NPMCIGRAPHIC)GetWindowWord (hwnd, 0);
|
||
|
#else
|
||
|
npMCI = (NPMCIGRAPHIC)GetWindowLongPtr (hwnd, 0);
|
||
|
|
||
|
if (npMCI) {
|
||
|
if (IsBadReadPtr(npMCI, sizeof(MCIGRAPHIC))
|
||
|
|| !IsTask(npMCI->hTask)) {
|
||
|
DPF2(("WndProc called with msg %04x after task npMCI=%08x is dead\n", wMsg, npMCI));
|
||
|
|
||
|
// if the device is in some sort of shutdown state, only the
|
||
|
// messages below are safe to process. Note: not processing
|
||
|
// AVIM_DESTROY can lead to deadlock.
|
||
|
switch (wMsg) {
|
||
|
case AVIM_DESTROY:
|
||
|
DestroyWindow(hwnd);
|
||
|
return 1L;
|
||
|
case WM_DESTROY:
|
||
|
PostQuitMessage(0);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return DefWindowProc(hwnd, wMsg, wParam, lParam);
|
||
|
}
|
||
|
}
|
||
|
Assert(wMsg != WM_CREATE);
|
||
|
} else {
|
||
|
|
||
|
// npMCI is NULL - only WM_CREATE can safely be processed
|
||
|
|
||
|
// I think we can also safely process AVIM_DESTROY and that
|
||
|
// will avoid a few potential hangs...
|
||
|
if ((wMsg != WM_CREATE) && (wMsg != AVIM_DESTROY)) {
|
||
|
return DefWindowProc(hwnd, wMsg, wParam, lParam);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
switch (wMsg)
|
||
|
{
|
||
|
|
||
|
case WM_CREATE:
|
||
|
|
||
|
npMCI = (NPMCIGRAPHIC)(UINT_PTR)(DWORD_PTR)
|
||
|
((LPCREATESTRUCT)lParam)->lpCreateParams;
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
SetWindowLongPtr (hwnd, 0, (UINT_PTR)npMCI);
|
||
|
#else
|
||
|
SetWindowWord (hwnd, 0, (WORD)npMCI);
|
||
|
#endif
|
||
|
|
||
|
hmenu = GetSystemMenu(hwnd, 0);
|
||
|
|
||
|
if (hmenu) {
|
||
|
/* Our system menu is too long--get rid of extra stuff. */
|
||
|
// DeleteMenu(hmenu, SC_RESTORE, MF_BYCOMMAND);
|
||
|
// DeleteMenu(hmenu, SC_MINIMIZE, MF_BYCOMMAND);
|
||
|
DeleteMenu(hmenu, SC_MAXIMIZE, MF_BYCOMMAND);
|
||
|
DeleteMenu(hmenu, SC_TASKLIST, MF_BYCOMMAND);
|
||
|
|
||
|
/* Add additional menu items to the end of the system menu */
|
||
|
// AppendMenu(hmenu, MF_SEPARATOR, 0, 0L);
|
||
|
|
||
|
#ifdef IDM_CONFIG
|
||
|
LoadString(ghModule, MCIAVI_MENU_CONFIG, ach, NUMELMS(ach));
|
||
|
AppendMenu(hmenu, MF_STRING, IDM_CONFIG, ach);
|
||
|
#endif
|
||
|
|
||
|
LoadString(ghModule, MCIAVI_MENU_STRETCH, ach, NUMELMS(ach));
|
||
|
AppendMenu(hmenu, MF_STRING, IDM_STRETCH, ach);
|
||
|
|
||
|
LoadString(ghModule, MCIAVI_MENU_MUTE, ach, NUMELMS(ach));
|
||
|
AppendMenu(hmenu, MF_STRING, IDM_MUTE, ach);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case WM_INITMENU:
|
||
|
|
||
|
hmenu = GetSystemMenu(hwnd, 0);
|
||
|
|
||
|
if (hmenu) {
|
||
|
#ifdef IDM_SKIPFRAMES
|
||
|
CheckMenuItem(hmenu, IDM_SKIPFRAMES, MF_BYCOMMAND |
|
||
|
((npMCI->dwOptionFlags & MCIAVIO_SKIPFRAMES) ?
|
||
|
MF_CHECKED : MF_UNCHECKED));
|
||
|
#endif
|
||
|
CheckMenuItem(hmenu, IDM_STRETCH, MF_BYCOMMAND |
|
||
|
((npMCI->dwOptionFlags & MCIAVIO_STRETCHTOWINDOW) ?
|
||
|
MF_CHECKED : MF_UNCHECKED));
|
||
|
|
||
|
#ifdef IDM_CONFIG
|
||
|
/* If in configure box, disable menu item. */
|
||
|
EnableMenuItem(hmenu, IDM_CONFIG, MF_BYCOMMAND |
|
||
|
(npMCI->wMessageCurrent == 0 ?
|
||
|
MF_ENABLED : MF_GRAYED));
|
||
|
#endif
|
||
|
|
||
|
/* If in stupid mode, disable stretch menu item. */
|
||
|
EnableMenuItem(hmenu, IDM_STRETCH, MF_BYCOMMAND |
|
||
|
((!(npMCI->dwOptionFlags & MCIAVIO_STUPIDMODE)) ?
|
||
|
MF_ENABLED : MF_GRAYED));
|
||
|
|
||
|
EnableMenuItem(hmenu, IDM_MUTE, MF_BYCOMMAND |
|
||
|
(npMCI->nAudioStreams ?
|
||
|
MF_ENABLED : MF_GRAYED));
|
||
|
|
||
|
CheckMenuItem(hmenu, IDM_MUTE, MF_BYCOMMAND |
|
||
|
(!(npMCI->dwFlags & MCIAVI_PLAYAUDIO) ?
|
||
|
MF_CHECKED : MF_UNCHECKED));
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_SYSCOMMAND:
|
||
|
switch (wParam & 0xfff0) {
|
||
|
case SC_KEYMENU:
|
||
|
case SC_MOUSEMENU:
|
||
|
gfEvilSysMenu++;
|
||
|
lParam = DefWindowProc(hwnd, wMsg, wParam, lParam);
|
||
|
gfEvilSysMenu--;
|
||
|
return lParam;
|
||
|
|
||
|
#ifdef IDM_SKIPFRAMES
|
||
|
case IDM_SKIPFRAMES:
|
||
|
EnterWinCrit(npMCI);
|
||
|
npMCI->dwOptionFlags ^= MCIAVIO_SKIPFRAMES;
|
||
|
LeaveWinCrit(npMCI);
|
||
|
break;
|
||
|
#endif
|
||
|
case IDM_STRETCH:
|
||
|
EnterWinCrit(npMCI);
|
||
|
|
||
|
npMCI->dwOptionFlags ^= MCIAVIO_STRETCHTOWINDOW;
|
||
|
|
||
|
if (!(npMCI->dwOptionFlags & MCIAVIO_STRETCHTOWINDOW)) {
|
||
|
SetWindowToDefaultSize(npMCI, FALSE);
|
||
|
}
|
||
|
|
||
|
Winproc_DestRect(npMCI, FALSE);
|
||
|
LeaveWinCrit(npMCI);
|
||
|
break;
|
||
|
|
||
|
case IDM_MUTE:
|
||
|
// just set request flag in npMCI
|
||
|
WinProcRequest(npMCI, WINPROC_MUTE);
|
||
|
break;
|
||
|
|
||
|
#ifdef IDM_CONFIG
|
||
|
case IDM_CONFIG:
|
||
|
npMCI->wMessageCurrent = MCI_CONFIGURE;
|
||
|
gfEvil++;
|
||
|
dwOptions = npMCI->dwOptions;
|
||
|
f = ConfigDialog(NULL, npMCI);
|
||
|
if (f) {
|
||
|
#ifdef DEBUG
|
||
|
//
|
||
|
// in DEBUG always reset the dest rect because the user may
|
||
|
// have played with the DEBUG DrawDib options and we will
|
||
|
// need to call DrawDibBegin() again.
|
||
|
//
|
||
|
if (TRUE)
|
||
|
#else
|
||
|
if ((npMCI->dwOptionFlags & (MCIAVIO_STUPIDMODE|MCIAVIO_ZOOMBY2
|
||
|
|MCIAVIO_WINDOWSIZEMASK))
|
||
|
!= (dwOptions & (MCIAVIO_STUPIDMODE|MCIAVIO_ZOOMBY2
|
||
|
|MCIAVIO_WINDOWSIZEMASK)) )
|
||
|
#endif
|
||
|
{
|
||
|
|
||
|
npMCI->lFrameDrawn =
|
||
|
(- (LONG) npMCI->wEarlyRecords) - 1;
|
||
|
//EnterWinCrit(npMCI);
|
||
|
SetWindowToDefaultSize(npMCI, FALSE);
|
||
|
Winproc_DestRect(npMCI, FALSE);
|
||
|
//LeaveWinCrit(npMCI);
|
||
|
}
|
||
|
} else {
|
||
|
npMCI->dwOptionFlags = dwOptions;
|
||
|
}
|
||
|
|
||
|
|
||
|
GraphicConfig(npMCI, 0L);
|
||
|
gfEvil--;
|
||
|
npMCI->wMessageCurrent = 0;
|
||
|
break;
|
||
|
#endif
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_CLOSE:
|
||
|
|
||
|
// Hide default window
|
||
|
|
||
|
WinProcRequest(npMCI, WINPROC_STOP);
|
||
|
ShowWindow(hwnd, SW_HIDE);
|
||
|
return 0L;
|
||
|
|
||
|
// this stuff is here because of some bizarre inter-thread rules in nt
|
||
|
case AVIM_DESTROY:
|
||
|
DestroyWindow(hwnd);
|
||
|
return 1L;
|
||
|
|
||
|
case AVIM_SHOWSTAGE:
|
||
|
{
|
||
|
BOOL bIsVis;
|
||
|
|
||
|
// activate if not visible. force activation if requested
|
||
|
// (if palette changes)
|
||
|
if (wParam) {
|
||
|
bIsVis = FALSE;
|
||
|
} else {
|
||
|
bIsVis = IsWindowVisible(hwnd);
|
||
|
}
|
||
|
|
||
|
SetWindowPos(npMCI->hwndPlayback, HWND_TOP, 0, 0, 0, 0,
|
||
|
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW |
|
||
|
(bIsVis ? SWP_NOACTIVATE : 0));
|
||
|
|
||
|
if (!bIsVis) {
|
||
|
SetForegroundWindow(hwnd);
|
||
|
}
|
||
|
}
|
||
|
return 1L;
|
||
|
|
||
|
|
||
|
|
||
|
case WM_DESTROY:
|
||
|
|
||
|
// The window may be destroyed 2 ways.
|
||
|
// a. the device is closed. In this case the animation is
|
||
|
// freed in DeviceClose which is called from GraphicClose
|
||
|
// and the animation ID is NULL by the time this window is
|
||
|
// destroyed.
|
||
|
// b. the window is closed. In this case, the animation is
|
||
|
// not closed and we should set the stage to NULL. A new
|
||
|
// default window will be created if needed.
|
||
|
|
||
|
EnterWinCrit(npMCI);
|
||
|
if (IsTask(npMCI->hTask)) {
|
||
|
WinProcRequestEx(npMCI, WINPROC_STOP);
|
||
|
}
|
||
|
|
||
|
if (npMCI->hwndPlayback == npMCI->hwndDefault)
|
||
|
npMCI->hwndPlayback = NULL;
|
||
|
npMCI->hwndDefault = NULL;
|
||
|
|
||
|
LeaveWinCrit(npMCI);
|
||
|
|
||
|
// winproc thread can now exit
|
||
|
PostQuitMessage(0);
|
||
|
break;
|
||
|
|
||
|
case WM_ERASEBKGND:
|
||
|
|
||
|
hdc = (HDC) wParam;
|
||
|
|
||
|
// We should not need any critical section as the system
|
||
|
// has given us a HDC as a message parameter.
|
||
|
Assert(hdc && (hdc != npMCI->hdc));
|
||
|
//EnterWinCrit(npMCI);
|
||
|
|
||
|
if (!(npMCI->dwFlags & MCIAVI_SHOWVIDEO)) {
|
||
|
FillRect(hdc, &npMCI->rcDest, GetStockObject(GRAY_BRUSH));
|
||
|
}
|
||
|
|
||
|
SaveDC(hdc);
|
||
|
|
||
|
ExcludeClipRect(hdc,
|
||
|
npMCI->rcDest.left, npMCI->rcDest.top,
|
||
|
npMCI->rcDest.right, npMCI->rcDest.bottom);
|
||
|
|
||
|
GetClientRect(hwnd, &rc);
|
||
|
FillRect(hdc, &rc, GetStockObject(BLACK_BRUSH));
|
||
|
|
||
|
RestoreDC(hdc, -1);
|
||
|
|
||
|
#if 0
|
||
|
/* Hack: if we're in a WAIT state, we won't get
|
||
|
** a WM_PAINT, so we need to invalidate the streams here
|
||
|
*/
|
||
|
GetClipBox(hdc, &rc);
|
||
|
StreamInvalidate(npMCI, &rc);
|
||
|
#endif
|
||
|
|
||
|
//LeaveWinCrit(npMCI);
|
||
|
|
||
|
return 0L;
|
||
|
|
||
|
case WM_PAINT:
|
||
|
|
||
|
|
||
|
// we always do this even if we leave it to the
|
||
|
// worker to paint, since otherwise we'll loop endlessly
|
||
|
// processing WM_PAINT
|
||
|
hdc = BeginPaint(hwnd, &ps);
|
||
|
|
||
|
rc = ps.rcPaint;
|
||
|
|
||
|
// if the worker thread is cueing, seeking or playing we don't
|
||
|
// actually want to paint (in case it is doing rle delta paints).
|
||
|
// now we've got the window critsec, it is safe to check
|
||
|
// the task state
|
||
|
if ((npMCI->wTaskState == TASKPLAYING) ||
|
||
|
(npMCI->wTaskState == TASKCUEING)) {
|
||
|
npMCI->dwFlags |= MCIAVI_NEEDUPDATE;
|
||
|
} else {
|
||
|
|
||
|
StreamInvalidate(npMCI, &rc);
|
||
|
// we don't need to pass rc in as we are clipped to this
|
||
|
// already and all they do is clip to it.
|
||
|
|
||
|
// don't paint if there is a 'pf' since we only ever
|
||
|
// reference this on the worker thread (OLE threading rules)
|
||
|
if (npMCI->pf) {
|
||
|
WinProcRequest(npMCI, WINPROC_UPDATE);
|
||
|
} else {
|
||
|
|
||
|
// note: TryStreamUpdate will get the HDC critical section
|
||
|
if (!TryStreamUpdate(npMCI, MCI_DGV_UPDATE_PAINT, hdc, NULL)) {
|
||
|
|
||
|
// requires full play - ask worker thread to do this
|
||
|
|
||
|
// to paint the frame at this point, we would have
|
||
|
// to call mciaviPlayFile. This can only be safely called
|
||
|
// on the worker thread. To avoid potential deadlock,
|
||
|
// this paint has to be done asynchronously from us, and
|
||
|
// also we lose the update rect information - the
|
||
|
// worker will paint the entire destination rect.
|
||
|
|
||
|
#if 0 // looks bad - don't bother
|
||
|
// paint gray first, in case the worker thread is busy
|
||
|
// or it fails
|
||
|
GetClientRect(hwnd, &rc);
|
||
|
FillRect(hdc, &rc, GetStockObject(DKGRAY_BRUSH));
|
||
|
#endif
|
||
|
WinProcRequest(npMCI, WINPROC_UPDATE);
|
||
|
|
||
|
} else {
|
||
|
// painted successfully on this thread
|
||
|
|
||
|
// if we are playing and so have an hdc then we need to
|
||
|
// reprepare the orig dc after switching back to it
|
||
|
if (npMCI->wTaskState == TASKPAUSED) {
|
||
|
EnterHDCCrit(npMCI);
|
||
|
// if a new command has arrived the state may have changed
|
||
|
// underneath us. If so, the dc may have been released. We
|
||
|
// only want to call PrepareDC if npMCI->hdc is non null.
|
||
|
if(npMCI->hdc) PrepareDC(npMCI);
|
||
|
LeaveHDCCrit(npMCI); // remember to release the critical section
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
EndPaint(hwnd, &ps);
|
||
|
return 0L; // we do NOT call DefWindowProc
|
||
|
|
||
|
case WM_PALETTECHANGED:
|
||
|
|
||
|
// We're not using the default window. We have no business here.
|
||
|
if (npMCI->hwndPlayback != hwnd)
|
||
|
break;
|
||
|
|
||
|
//
|
||
|
// someone has realized a palette - so we need to re-realize our
|
||
|
// palette (note that this will also cause drawdib to
|
||
|
// check for PAL_INDICES vs PAL_COLOURS.
|
||
|
//
|
||
|
if ((HWND) wParam != hwnd) {
|
||
|
WinProcRequest(npMCI, WINPROC_REALIZE);
|
||
|
|
||
|
// invalidate is done in InternalRealize
|
||
|
//InvalidateRect(hwnd, NULL, FALSE);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_QUERYNEWPALETTE:
|
||
|
{
|
||
|
#if 0
|
||
|
LONG lRet;
|
||
|
#endif
|
||
|
// We're not using the default window. We have no business here.
|
||
|
if (npMCI->hwndPlayback != hwnd)
|
||
|
break;
|
||
|
|
||
|
#if 0
|
||
|
// not true = internalrealize has always returned 0, so why do this
|
||
|
// on this thread?
|
||
|
EnterHDCCrit(npMCI);
|
||
|
|
||
|
// need to do this on winproc thread to get
|
||
|
// correct return value.
|
||
|
lRet = InternalRealize(npMCI);
|
||
|
LeaveHDCCrit(npMCI);
|
||
|
return(lRet);
|
||
|
#else
|
||
|
WinProcRequest(npMCI, WINPROC_REALIZE);
|
||
|
return 0;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
case WM_WINDOWPOSCHANGED:
|
||
|
//EnterWinCrit(npMCI);
|
||
|
//CheckWindowMove grabs the critical section when it needs it
|
||
|
CheckWindowMove(npMCI, TRUE);
|
||
|
//LeaveWinCrit(npMCI);
|
||
|
break;
|
||
|
|
||
|
case WM_SIZE:
|
||
|
EnterWinCrit(npMCI);
|
||
|
Winproc_DestRect(npMCI, FALSE);
|
||
|
LeaveWinCrit(npMCI);
|
||
|
break;
|
||
|
|
||
|
case WM_QUERYENDSESSION:
|
||
|
|
||
|
WinProcRequest(npMCI, WINPROC_STOP);
|
||
|
|
||
|
break;
|
||
|
|
||
|
case WM_ENDSESSION:
|
||
|
if (wParam) {
|
||
|
DestroyWindow(hwnd); // we may not be able to destroy window?
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_GETMINMAXINFO:
|
||
|
lpmmi = (MINMAXINFO FAR *)(lParam);
|
||
|
|
||
|
lpmmi->ptMinTrackSize.x = GetSystemMetrics(SM_CXSIZE) * 2;
|
||
|
break;
|
||
|
|
||
|
case WM_NCACTIVATE:
|
||
|
WinProcRequest(npMCI, wParam?WINPROC_ACTIVE : WINPROC_INACTIVE);
|
||
|
break;
|
||
|
|
||
|
#if 0
|
||
|
We should not need both ACTIVATE and NCACTIVATE - use the one that
|
||
|
arrives first (to give us a little more time and reduce the start up
|
||
|
latency)
|
||
|
case WM_ACTIVATE:
|
||
|
WinProcRequest(npMCI, wParam?WINPROC_ACTIVE : WINPROC_INACTIVE);
|
||
|
break;
|
||
|
#endif
|
||
|
|
||
|
#ifdef REMOTESTEAL
|
||
|
case WM_AUDIO_ON: // Someone has released the wave device
|
||
|
{
|
||
|
extern HWND hwndLostAudio;
|
||
|
//Assert(npMCI->dwFlags & MCIAVI_PLAYAUDIO);
|
||
|
//Assert(npMCI->dwFlags & MCIAVI_LOSTAUDIO);
|
||
|
//Assert(npMCI->hWave == NULL);
|
||
|
// Timing might be such that these assertions are invalid
|
||
|
|
||
|
// If we are not playing then we might be able to forward
|
||
|
// the message to another... OR, tell the one giving up the
|
||
|
// audio that it can be reclaimed because we no longer have
|
||
|
// a use for it.
|
||
|
if (npMCI->wTaskState != TASKPLAYING) {
|
||
|
if (!hwndLostAudio) {
|
||
|
hwndLostAudio = (HWND)wParam;
|
||
|
}
|
||
|
if (hwndLostAudio) {
|
||
|
DPF2(("Forwarding WM_AUDIO_ON message to %x...\n", hwndLostAudio));
|
||
|
if (IsWindow(hwndLostAudio)) {
|
||
|
PostMessage(hwndLostAudio, WM_AUDIO_ON, 0, 0);
|
||
|
}
|
||
|
hwndLostAudio = 0; // Prevent further messages
|
||
|
}
|
||
|
} else {
|
||
|
// we are playing
|
||
|
// Save the window handle of the window releasing the sound
|
||
|
DPF2(("Setting hwndLostAudio to %x (was %x)\n", wParam, hwndLostAudio));
|
||
|
hwndLostAudio = (HWND)wParam;
|
||
|
// if hwndLostAudio==0 then we do not return it to anyone
|
||
|
|
||
|
WinProcRequest(npMCI, WINPROC_SOUND);
|
||
|
}
|
||
|
return 0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case WM_AUDIO_OFF: // Someone wants our wave device
|
||
|
{
|
||
|
extern HWND hwndWantAudio;
|
||
|
//Assert(npMCI->dwFlags & MCIAVI_PLAYAUDIO);
|
||
|
//Assert(!(npMCI->dwFlags & MCIAVI_LOSTAUDIO));
|
||
|
//Assert(npMCI->hWave != NULL);
|
||
|
// Timing might be such that these assertions are invalid
|
||
|
|
||
|
SetNTFlags(npMCI, NTF_AUDIO_OFF);
|
||
|
// Save the window handle of the window which wants sound
|
||
|
DPF2(("WM_AUDIO_OFF... hwndWantAudio set to %x (was %x)\n", wParam, hwndWantAudio));
|
||
|
hwndWantAudio = (HWND)wParam;
|
||
|
// if hwndWantAudio==0 then we do not release the wave device
|
||
|
|
||
|
if (IsWindow(hwndWantAudio)) {
|
||
|
WinProcRequest(npMCI, WINPROC_SILENT);
|
||
|
} else {
|
||
|
DPF(("WM_AUDIO_OFF... but the target window is invalid\n"));
|
||
|
}
|
||
|
ResetNTFlags(npMCI, NTF_AUDIO_OFF);
|
||
|
return 0;
|
||
|
break;
|
||
|
}
|
||
|
#endif // REMOTESTEAL
|
||
|
|
||
|
#if 0
|
||
|
case WM_LBUTTONDOWN:
|
||
|
{
|
||
|
DWORD dw;
|
||
|
static DWORD dwLastClick;
|
||
|
static DWORD dwClicks = 0;
|
||
|
#define MAX_CLICKS 7
|
||
|
/* . = (0,300) - = (300,1000) word = (500,1500) */
|
||
|
/* AVI: .- ...- .. */
|
||
|
static DWORD adwClickHigh[MAX_CLICKS] =
|
||
|
{ 300, 1500, 300, 300, 300, 1500, 300 };
|
||
|
static DWORD adwClickLow[MAX_CLICKS] =
|
||
|
{ 0, 500, 0, 0, 0, 500, 0 };
|
||
|
|
||
|
dw = timeGetTime();
|
||
|
if (((dw - dwLastClick) > adwClickLow[dwClicks]) &&
|
||
|
((dw - dwLastClick) <= adwClickHigh[dwClicks]))
|
||
|
dwClicks++;
|
||
|
else
|
||
|
dwClicks = 0;
|
||
|
|
||
|
dwLastClick = dw;
|
||
|
|
||
|
if (dwClicks == MAX_CLICKS) {
|
||
|
WinProcRequest(npMCI, WINPROC_STOP);
|
||
|
Credits(hwnd);
|
||
|
dwClicks = 0;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
} // switch(wMsg)
|
||
|
|
||
|
return DefWindowProc(hwnd, wMsg, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
static void NEAR PASCAL Credits(HWND hwnd)
|
||
|
{
|
||
|
/* Credits... */
|
||
|
RECT rc;
|
||
|
RECT rcUpdate;
|
||
|
HDC hdc;
|
||
|
MSG msg;
|
||
|
int dyLine;
|
||
|
int yLine;
|
||
|
TEXTMETRIC tm;
|
||
|
DWORD dwNextTime;
|
||
|
long lScroll;
|
||
|
DWORD rgb;
|
||
|
HANDLE hResInfo;
|
||
|
HANDLE hResData;
|
||
|
LPSTR pchSrc, pchDst;
|
||
|
char achLine[100];
|
||
|
int iEncrypt;
|
||
|
|
||
|
#define EOFCHAR '@' // end of credits file
|
||
|
|
||
|
/* load the credits */
|
||
|
if ((hResInfo = FindResource(ghModule, TEXT("MMS"), TEXT("MMSCR"))) == NULL)
|
||
|
return;
|
||
|
if ((hResData = LoadResource(ghModule, hResInfo)) == NULL)
|
||
|
return;
|
||
|
if ((pchSrc = LockResource(hResData)) == NULL)
|
||
|
return;
|
||
|
|
||
|
/* we want to get all mouse and keyboard events, to make
|
||
|
* sure we stop the animation when the user clicks or
|
||
|
* hits a key
|
||
|
*/
|
||
|
SetFocus(hwnd);
|
||
|
SetCapture(hwnd);
|
||
|
|
||
|
/* Scroll the credits up, one pixel at a time. pchSrc
|
||
|
* points to the encrypted data; achLine contains a decrypted
|
||
|
* line (null-terminated). dyLine is the height of each
|
||
|
* line (constant), and yLine is between 0 and dyLine,
|
||
|
* indicating how many pixels of the line have been scrolled
|
||
|
* in vertically from the bottom
|
||
|
*/
|
||
|
hdc = GetDC(hwnd);
|
||
|
SelectObject(hdc, GetStockObject(ANSI_VAR_FONT));
|
||
|
GetClientRect(hwnd, &rc);
|
||
|
SetTextAlign(hdc, TA_CENTER);
|
||
|
SetBkColor(hdc, RGB(0, 0, 0));
|
||
|
SetRect(&rcUpdate, 0, rc.bottom - 1, rc.right, rc.bottom);
|
||
|
GetTextMetrics(hdc, &tm);
|
||
|
if ((dyLine = tm.tmHeight + tm.tmExternalLeading) == 0)
|
||
|
dyLine = 1;
|
||
|
yLine = dyLine;
|
||
|
dwNextTime = GetCurrentTime(); // time to do the next scroll
|
||
|
lScroll = 0;
|
||
|
iEncrypt = 0;
|
||
|
while (TRUE) {
|
||
|
/* If the user clicks the mouse or hits a key, exit.
|
||
|
* However, ignore WM_LBUTTONUP because they will have
|
||
|
* to let go of the mouse after clicking the icon.
|
||
|
* Also, ignore mouse move messages.
|
||
|
*/
|
||
|
if (PeekMessage(&msg, hwnd, WM_KEYFIRST, WM_KEYLAST,
|
||
|
PM_NOREMOVE | PM_NOYIELD))
|
||
|
break; // exit on key hit
|
||
|
|
||
|
if (PeekMessage(&msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
|
||
|
PM_NOREMOVE | PM_NOYIELD)) {
|
||
|
if ((msg.message == WM_MOUSEMOVE) ||
|
||
|
(msg.message == WM_LBUTTONUP)) {
|
||
|
/* remove and ignore message */
|
||
|
PeekMessage(&msg, hwnd, msg.message,
|
||
|
msg.message,
|
||
|
PM_REMOVE | PM_NOYIELD);
|
||
|
}
|
||
|
else
|
||
|
break; // exit on click
|
||
|
}
|
||
|
|
||
|
/* scroll at a fixed no. of vertical pixels per sec. */
|
||
|
if (dwNextTime > GetCurrentTime())
|
||
|
continue;
|
||
|
dwNextTime += 50L; // millseconds per scroll
|
||
|
|
||
|
if (yLine == dyLine) {
|
||
|
/* decrypt a line and copy to achLine */
|
||
|
pchDst = achLine;
|
||
|
while (TRUE) {
|
||
|
*pchDst = (char) (*pchSrc++ ^
|
||
|
(128 | (iEncrypt++ & 127)));
|
||
|
if ((*pchDst == '\r') ||
|
||
|
(*pchDst == EOFCHAR))
|
||
|
break;
|
||
|
pchDst++;
|
||
|
}
|
||
|
|
||
|
if (*pchDst == EOFCHAR)
|
||
|
break; // no more lines
|
||
|
*pchDst = 0; // null-terminate
|
||
|
pchSrc++, iEncrypt++; // skip '\n'
|
||
|
yLine = 0;
|
||
|
}
|
||
|
|
||
|
/* scroll screen up one pixel */
|
||
|
BitBlt(hdc, 0, 0, rcUpdate.right, rcUpdate.top,
|
||
|
hdc, 0, 1, SRCCOPY);
|
||
|
|
||
|
/* vary the text colors through a "rainbow" */
|
||
|
switch ((int) (lScroll++ / 4) % 5/*num-of-cases*/) {
|
||
|
case 0: rgb = RGB(255, 0, 0); break;
|
||
|
case 1: rgb = RGB(255, 255, 0); break;
|
||
|
case 2: rgb = RGB( 0, 255, 0); break;
|
||
|
case 3: rgb = RGB( 0, 255, 255); break;
|
||
|
case 4: rgb = RGB(255, 0, 255); break;
|
||
|
}
|
||
|
SetTextColor(hdc, rgb);
|
||
|
|
||
|
/* fill in the bottom pixel */
|
||
|
SaveDC(hdc);
|
||
|
yLine++;
|
||
|
IntersectClipRect(hdc, rcUpdate.left, rcUpdate.top,
|
||
|
rcUpdate.right, rcUpdate.bottom);
|
||
|
#ifdef _WIN32
|
||
|
ExtTextOutA(hdc, rc.right / 2, rc.bottom - yLine,
|
||
|
ETO_OPAQUE, &rcUpdate,
|
||
|
achLine, lstrlenA(achLine), NULL);
|
||
|
#else
|
||
|
ExtTextOut(hdc, rc.right / 2, rc.bottom - yLine,
|
||
|
ETO_OPAQUE, &rcUpdate,
|
||
|
achLine, lstrlen(achLine), NULL);
|
||
|
#endif
|
||
|
RestoreDC(hdc, -1);
|
||
|
}
|
||
|
|
||
|
ReleaseDC(hwnd, hdc);
|
||
|
ReleaseCapture();
|
||
|
UnlockResource(hResData);
|
||
|
FreeResource(hResData);
|
||
|
InvalidateRect(hwnd, NULL, TRUE);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Obey the registry default sizing of Zoom by 2 and Fixed screen %.
|
||
|
// Takes a Rect and either zooms it by 2 or replaces it with a constant size
|
||
|
// or leaves it alone.
|
||
|
//
|
||
|
void FAR PASCAL AlterRectUsingDefaults(NPMCIGRAPHIC npMCI, LPRECT lprc)
|
||
|
{
|
||
|
if (npMCI->dwOptionFlags & MCIAVIO_ZOOMBY2) {
|
||
|
SetRect(lprc, 0, 0, lprc->right*2, lprc->bottom*2);
|
||
|
} else {
|
||
|
if (npMCI->dwOptionFlags & MCIAVIO_WINDOWSIZEMASK) {
|
||
|
lprc->right = GetSystemMetrics (SM_CXSCREEN);
|
||
|
lprc->bottom = GetSystemMetrics (SM_CYSCREEN);
|
||
|
|
||
|
switch(npMCI->dwOptionFlags & MCIAVIO_WINDOWSIZEMASK)
|
||
|
{
|
||
|
case MCIAVIO_1QSCREENSIZE:
|
||
|
SetRect(lprc, 0, 0, lprc->right/4, lprc->bottom/4);
|
||
|
break;
|
||
|
|
||
|
case MCIAVIO_2QSCREENSIZE:
|
||
|
SetRect(lprc, 0, 0, lprc->right/2, lprc->bottom/2);
|
||
|
break;
|
||
|
|
||
|
case MCIAVIO_3QSCREENSIZE:
|
||
|
SetRect(lprc, 0, 0, lprc->right*3/4, lprc->bottom*3/4);
|
||
|
break;
|
||
|
|
||
|
case MCIAVIO_MAXWINDOWSIZE:
|
||
|
SetRect(lprc, 0, 0, lprc->right, lprc->bottom);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Set the size of the default window to be the rcMovie size (default
|
||
|
// destination size). Keep in mind a top level window might grow off screen,
|
||
|
// so adjust the position so that it remains on screen.
|
||
|
void FAR PASCAL SetWindowToDefaultSize(NPMCIGRAPHIC npMCI, BOOL fUseDefaultSizing)
|
||
|
{
|
||
|
RECT rc, rcW;
|
||
|
int xScreen, yScreen, x, y;
|
||
|
WINDOWPLACEMENT wp;
|
||
|
|
||
|
wp.length = sizeof(wp);
|
||
|
|
||
|
if (npMCI->hwndPlayback && npMCI->hwndPlayback == npMCI->hwndDefault) {
|
||
|
|
||
|
// Get the size of the movie, maybe alter it if the configure options
|
||
|
// tell us to play zoomed or fullscreen or something, and adjust for
|
||
|
// non-client area.
|
||
|
//
|
||
|
|
||
|
rc = npMCI->rcMovie;
|
||
|
if (fUseDefaultSizing)
|
||
|
AlterRectUsingDefaults(npMCI, &rc);
|
||
|
AdjustWindowRect(&rc, GetWindowLong(npMCI->hwndPlayback, GWL_STYLE), FALSE);
|
||
|
|
||
|
|
||
|
// For top-level windows, get the position where the playback window is
|
||
|
// (or will be) on the screen. Make it fit on the screen if possible.
|
||
|
// Dorking with the position of the default window if it's a
|
||
|
// child window is a bad idea. First of all, SetWindowPos is going to
|
||
|
// position it relative to its parent, and these calculations figure
|
||
|
// out where we want it in screen coordinates. Second of all, trying
|
||
|
// to move a child so that it's on screen when the parent could be
|
||
|
// offscreen itself or hiding the child window is just asking for
|
||
|
// trouble.
|
||
|
//
|
||
|
|
||
|
if (!(GetWindowLong(npMCI->hwndPlayback, GWL_STYLE) & WS_CHILD)) {
|
||
|
if (IsIconic(npMCI->hwndPlayback)) {
|
||
|
GetWindowPlacement(npMCI->hwndPlayback, &wp);
|
||
|
rcW = wp.rcNormalPosition;
|
||
|
} else {
|
||
|
GetWindowRect(npMCI->hwndPlayback, &rcW);
|
||
|
}
|
||
|
|
||
|
rcW.right = rcW.left + rc.right - rc.left;
|
||
|
rcW.bottom = rcW.top + rc.bottom - rc.top;
|
||
|
xScreen = GetSystemMetrics(SM_CXSCREEN);
|
||
|
yScreen = GetSystemMetrics(SM_CYSCREEN);
|
||
|
|
||
|
if (rcW.right > xScreen) {
|
||
|
x = min(rcW.left, rcW.right - xScreen);
|
||
|
rcW.left -= x;
|
||
|
rcW.right -= x;
|
||
|
}
|
||
|
|
||
|
if (rcW.bottom > yScreen) {
|
||
|
y = min(rcW.top, rcW.bottom - yScreen);
|
||
|
rcW.top -= y;
|
||
|
rcW.bottom -= y;
|
||
|
}
|
||
|
|
||
|
if (IsIconic(npMCI->hwndPlayback)) {
|
||
|
wp.rcNormalPosition = rcW;
|
||
|
SetWindowPlacement(npMCI->hwndPlayback, &wp);
|
||
|
} else {
|
||
|
SetWindowPos(npMCI->hwndPlayback, NULL, rcW.left, rcW.top,
|
||
|
rcW.right - rcW.left, rcW.bottom - rcW.top,
|
||
|
SWP_NOZORDER | SWP_NOACTIVATE);
|
||
|
}
|
||
|
|
||
|
// For a child window, we don't move it, we just size it.
|
||
|
//
|
||
|
} else {
|
||
|
if (IsIconic(npMCI->hwndPlayback)) {
|
||
|
GetWindowPlacement(npMCI->hwndPlayback, &wp);
|
||
|
wp.rcNormalPosition.right = wp.rcNormalPosition.left +
|
||
|
(rc.right - rc.left);
|
||
|
wp.rcNormalPosition.bottom = wp.rcNormalPosition.top +
|
||
|
(rc.bottom - rc.top);
|
||
|
SetWindowPlacement(npMCI->hwndPlayback, &wp);
|
||
|
} else {
|
||
|
SetWindowPos(npMCI->hwndPlayback, NULL, 0, 0,
|
||
|
rc.right - rc.left, rc.bottom - rc.top,
|
||
|
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void FAR PASCAL Winproc_DestRect(NPMCIGRAPHIC npMCI, BOOL fUseDefaultSizing)
|
||
|
{
|
||
|
RECT rc;
|
||
|
|
||
|
/* WM_SIZE messages (on NT at least) are sometimes sent
|
||
|
* during CreateWindow processing (eg if the initial window size
|
||
|
* is not CW_DEFAULT). Some fields in npMCI are only filled in
|
||
|
* after CreateWindow has returned. So there is a danger that at this
|
||
|
* point some fields are not valid.
|
||
|
*/
|
||
|
|
||
|
if (npMCI->hwndPlayback &&
|
||
|
npMCI->hwndPlayback == npMCI->hwndDefault &&
|
||
|
(npMCI->dwOptionFlags & MCIAVIO_STRETCHTOWINDOW)) {
|
||
|
GetClientRect(npMCI->hwndPlayback, &rc);
|
||
|
}
|
||
|
|
||
|
// Only allow ZOOMBY2 and fixed % defaults for our default playback window
|
||
|
else if (npMCI->streams > 0 && npMCI->hwndPlayback == npMCI->hwndDefault) {
|
||
|
rc = npMCI->rcMovie;
|
||
|
|
||
|
// Note: irrelevant on winproc thread
|
||
|
//if (fUseDefaultSizing)
|
||
|
// AlterRectUsingDefaults(npMCI, &rc);
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!IsRectEmpty(&rc)) {
|
||
|
WinCritCheckIn(npMCI);
|
||
|
WinProcRequestEx(npMCI, WINPROC_RESETDEST); // faster form... we have the critical section
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
#define DWORG POINT
|
||
|
#define GETDCORG(hdc, dwOrg) GetDCOrgEx(hdc, &dwOrg)
|
||
|
#else
|
||
|
#define DWORG DWORD
|
||
|
#define GETDCORG(hdc, dwOrg) dwOrg = GetDCOrg(hdc)
|
||
|
#endif
|
||
|
|
||
|
void CheckWindowMove(NPMCIGRAPHIC npMCI, BOOL fForce)
|
||
|
{
|
||
|
DWORG dwOrg;
|
||
|
UINT wRgn;
|
||
|
HDC hdc;
|
||
|
RECT rc;
|
||
|
BOOL fNull;
|
||
|
BOOL fGetDC;
|
||
|
|
||
|
if (!(npMCI->dwFlags & MCIAVI_WANTMOVE))
|
||
|
return;
|
||
|
|
||
|
if (!npMCI->hicDraw || !npMCI->hwndPlayback || npMCI->nVideoStreams == 0)
|
||
|
return;
|
||
|
|
||
|
Assert(IsWindow(npMCI->hwndPlayback));
|
||
|
Assert(npMCI->paStreamInfo);
|
||
|
Assert(npMCI->nVideoStreams > 0);
|
||
|
|
||
|
//
|
||
|
// when the screen is locked for update by a window move operation
|
||
|
// we dont want to turn off the video.
|
||
|
//
|
||
|
// we can tell if the screen is locked by checking a DC to the screen.
|
||
|
//
|
||
|
hdc = GetDC(NULL);
|
||
|
fNull = GetClipBox(hdc, &rc);
|
||
|
ReleaseDC(NULL, hdc);
|
||
|
|
||
|
if (NULLREGION == fNull)
|
||
|
{
|
||
|
npMCI->wRgnType = (UINT) -1;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (fForce)
|
||
|
npMCI->wRgnType = (UINT) -1;
|
||
|
|
||
|
|
||
|
// sync worker thread/winproc thread interaction
|
||
|
EnterHDCCrit(npMCI);
|
||
|
|
||
|
if (fGetDC = (npMCI->hdc == NULL)) {
|
||
|
hdc = GetDC (npMCI->hwndPlayback);
|
||
|
} else {
|
||
|
hdc = npMCI->hdc;
|
||
|
}
|
||
|
|
||
|
wRgn = GetClipBox(hdc, &rc);
|
||
|
|
||
|
GETDCORG(hdc, dwOrg);
|
||
|
|
||
|
if (fGetDC)
|
||
|
ReleaseDC(npMCI->hwndPlayback, hdc);
|
||
|
|
||
|
if (wRgn == npMCI->wRgnType &&
|
||
|
#ifdef _WIN32
|
||
|
dwOrg.x == npMCI->dwOrg.x &&
|
||
|
dwOrg.y == npMCI->dwOrg.y &&
|
||
|
#else
|
||
|
dwOrg == npMCI->dwOrg &&
|
||
|
#endif
|
||
|
EqualRect(&rc, &npMCI->rcClip)) {
|
||
|
|
||
|
LeaveHDCCrit(npMCI);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
npMCI->wRgnType = wRgn;
|
||
|
npMCI->dwOrg = dwOrg;
|
||
|
npMCI->rcClip = rc;
|
||
|
|
||
|
rc = npMCI->psiVideo->rcDest;
|
||
|
ClientToScreen(npMCI->hwndPlayback, (LPPOINT)&rc);
|
||
|
ClientToScreen(npMCI->hwndPlayback, (LPPOINT)&rc+1);
|
||
|
|
||
|
if (wRgn == NULLREGION)
|
||
|
SetRectEmpty(&rc);
|
||
|
|
||
|
DPF2(("Sending ICM_DRAW_WINDOW message Rgn=%d, Org=(%d,%d) [%d, %d, %d, %d]\n", wRgn, dwOrg, rc));
|
||
|
|
||
|
if (ICDrawWindow(npMCI->hicDraw, &rc) != ICERR_OK) {
|
||
|
DPF2(("Draw device does not want ICM_DRAW_WINDOW messages!\n"));
|
||
|
npMCI->dwFlags &= ~MCIAVI_WANTMOVE;
|
||
|
}
|
||
|
LeaveHDCCrit(npMCI);
|
||
|
}
|