Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1168 lines
32 KiB

  1. /******************************************************************************
  2. Copyright (C) Microsoft Corporation 1985-1991. All rights reserved.
  3. Title: window.c - Multimedia Systems Media Control Interface
  4. driver for AVI.
  5. *****************************************************************************/
  6. #include "graphic.h"
  7. #include "avitask.h" // for TASKIDLE
  8. //#define IDM_CONFIG 0x100
  9. //#define IDM_SKIPFRAMES 0x110
  10. #define IDM_MUTE 0x120
  11. #define IDM_STRETCH 0x130
  12. #ifdef _WIN32
  13. // Use a different class name on 32 bit systems to ease the 16/32
  14. // coexistence problem. (We might want both classes defined at once.)
  15. TCHAR szClassName[] = TEXT("AVIWnd32");
  16. #else
  17. char szClassName[] = "AVIWnd";
  18. #endif
  19. DWORD NEAR PASCAL GraphicStop (NPMCIGRAPHIC npMCI, DWORD dwFlags);
  20. DWORD NEAR PASCAL GraphicPause (NPMCIGRAPHIC npMCI, DWORD dwFlags);
  21. DWORD NEAR PASCAL GraphicPlay (NPMCIGRAPHIC npMCI, DWORD dwFlags,
  22. LPMCI_ANIM_PLAY_PARMS lpPlay );
  23. DWORD NEAR PASCAL GraphicSeek (NPMCIGRAPHIC npMCI, DWORD dwFlags,
  24. LPMCI_SEEK_PARMS lpSeek);
  25. BOOL NEAR PASCAL GraphicWindowInit (void)
  26. {
  27. WNDCLASS cls;
  28. // define the class of window we want to register
  29. cls.lpszClassName = szClassName;
  30. cls.style = CS_GLOBALCLASS | CS_OWNDC;
  31. cls.hCursor = LoadCursor (NULL, IDC_ARROW);
  32. cls.hIcon = NULL;
  33. cls.lpszMenuName = NULL;
  34. ////cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  35. cls.hbrBackground = GetStockObject(BLACK_BRUSH);
  36. cls.hInstance = ghModule;
  37. cls.lpfnWndProc = GraphicWndProc;
  38. cls.cbClsExtra = 0;
  39. cls.cbWndExtra = sizeof (NPMCIGRAPHIC);
  40. return RegisterClass (&cls);
  41. }
  42. #ifdef _WIN32
  43. /*
  44. * de-register the class on unloading the dll so that we can
  45. * successfully re-register the class next time we are loaded.
  46. * note that nt only unregisters a class when the app exits.
  47. */
  48. BOOL NEAR PASCAL GraphicWindowFree(void)
  49. {
  50. return(UnregisterClass(szClassName, ghModule));
  51. }
  52. /**************************************************************************
  53. ***************************************************************************/
  54. //-----------------------------------------------------------------------
  55. // this is the winproc thread's main function.
  56. // we create the window and signal the event once initialization
  57. // is complete. We then block either processing messages or waiting for
  58. // hEventWinProcDie. When this is set, we clean up and exit
  59. void aviWinProcTask(DWORD_PTR dwInst)
  60. {
  61. NPMCIGRAPHIC npMCI = (NPMCIGRAPHIC) dwInst;
  62. HWND hWnd;
  63. MSG msg;
  64. // Create the default window - the caller may
  65. // supply style and parent window.
  66. #ifdef DEBUG
  67. if (npMCI->hwndParent) {
  68. if ( !IsWindow(npMCI->hwndParent)) {
  69. //DebugBreak();
  70. // This should have been trapped before getting here
  71. }
  72. }
  73. #endif
  74. if (npMCI->dwStyle != (DWORD) -1) {
  75. // CW_USEDEFAULT can't be used with popups or children so
  76. // if the user provides the style, default to full-screen.
  77. hWnd =
  78. // Note: The CreateWindow/Ex call is written this way as on Win32
  79. // CreateWindow is a MACRO, and hence the call must be contained
  80. // within the preprocessor block.
  81. CreateWindowEx(
  82. #ifdef BIDI
  83. WS_EX_BIDI_SCROLL | WS_EX_BIDI_MENU |WS_EX_BIDI_NOICON,
  84. #else
  85. 0,
  86. #endif
  87. szClassName,
  88. FileName(npMCI->szFilename),
  89. npMCI->dwStyle,
  90. 0, 0,
  91. GetSystemMetrics (SM_CXSCREEN),
  92. GetSystemMetrics (SM_CYSCREEN),
  93. npMCI->hwndParent,
  94. NULL, ghModule, (LPTSTR)npMCI);
  95. } else {
  96. npMCI->dwStyle = WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX |
  97. WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
  98. hWnd =
  99. CreateWindowEx(
  100. #ifdef BIDI
  101. WS_EX_BIDI_SCROLL | WS_EX_BIDI_MENU |WS_EX_BIDI_NOICON,
  102. #else
  103. 0,
  104. #endif
  105. szClassName,
  106. FileName(npMCI->szFilename),
  107. npMCI->dwStyle,
  108. CW_USEDEFAULT, 0,
  109. CW_USEDEFAULT, 0,
  110. npMCI->hwndParent,
  111. NULL, ghModule, (LPTSTR)npMCI);
  112. }
  113. npMCI->hwndDefault = hWnd;
  114. npMCI->hwndPlayback = hWnd;
  115. if (!hWnd) {
  116. // fail to start up - just exit this function and the caller
  117. // will detect thread exit
  118. DPF(("CreateWindow failed, LastError=%d\n", GetLastError()));
  119. npMCI->dwReturn = MCIERR_CREATEWINDOW;
  120. return;
  121. }
  122. // window created ok - signal worker thread to continue
  123. SetEvent(npMCI->hEventWinProcOK);
  124. while (GetMessage(&msg, NULL, 0, 0)) {
  125. TranslateMessage(&msg);
  126. DispatchMessage(&msg);
  127. }
  128. // WM_QUIT received - exit now
  129. GdiFlush();
  130. return;
  131. }
  132. //
  133. // Pass request bit(s) to worker thread.
  134. // Use WinProcRequestEx when the WinCrit critical section is already held
  135. // and WINPROC_ACTIVE/INACTIVE is not being used
  136. //
  137. // Use WinProcRequest when the WinCrit critical section is required
  138. //
  139. void INLINE
  140. WinProcRequestEx(NPMCIGRAPHIC npMCI, DWORD dwFlag)
  141. {
  142. DPF2(("WinProcRequestEx... request %8x", dwFlag));
  143. npMCI->dwWinProcRequests |= dwFlag;
  144. SetEvent(npMCI->heWinProcRequest);
  145. DPF2(("!...Ex request %8x done\n", dwFlag));
  146. }
  147. void
  148. WinProcRequest(NPMCIGRAPHIC npMCI, DWORD dwFlag)
  149. {
  150. DPF2(("WinProcRequest... request %8x", dwFlag));
  151. EnterWinCrit(npMCI);
  152. DPF2(("!... request %8x ...", dwFlag));
  153. // If we are being made active or inactive, then ensure that only
  154. // one of the WINPROC_ACTIVE/WINPROC_INACTIVE bits is switched on.
  155. if (dwFlag & (WINPROC_ACTIVE | WINPROC_INACTIVE)) {
  156. npMCI->dwWinProcRequests &= ~(WINPROC_ACTIVE | WINPROC_INACTIVE);
  157. }
  158. npMCI->dwWinProcRequests |= dwFlag;
  159. SetEvent(npMCI->heWinProcRequest);
  160. DPF2(("!... request %8x done\n", dwFlag));
  161. LeaveWinCrit(npMCI);
  162. }
  163. #endif
  164. DWORD FAR PASCAL GraphicConfig(NPMCIGRAPHIC npMCI, DWORD dwFlags);
  165. #if 0
  166. static void NEAR PASCAL Credits(HWND hwnd);
  167. #endif
  168. //
  169. // Window proc is always run on the winproc thread. We hold
  170. // a critical section during all paint/palette code to protect us
  171. // against interaction with the worker thread. We do not hold this
  172. // critical section for the whole winproc.
  173. //
  174. LRESULT FAR PASCAL _LOADDS GraphicWndProc (HWND hwnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  175. {
  176. PAINTSTRUCT ps;
  177. NPMCIGRAPHIC npMCI;
  178. HMENU hmenu;
  179. HDC hdc;
  180. RECT rc;
  181. MINMAXINFO FAR * lpmmi;
  182. TCHAR ach[80];
  183. #ifndef _WIN32
  184. npMCI = (NPMCIGRAPHIC)GetWindowWord (hwnd, 0);
  185. #else
  186. npMCI = (NPMCIGRAPHIC)GetWindowLongPtr (hwnd, 0);
  187. if (npMCI) {
  188. if (IsBadReadPtr(npMCI, sizeof(MCIGRAPHIC))
  189. || !IsTask(npMCI->hTask)) {
  190. DPF2(("WndProc called with msg %04x after task npMCI=%08x is dead\n", wMsg, npMCI));
  191. // if the device is in some sort of shutdown state, only the
  192. // messages below are safe to process. Note: not processing
  193. // AVIM_DESTROY can lead to deadlock.
  194. switch (wMsg) {
  195. case AVIM_DESTROY:
  196. DestroyWindow(hwnd);
  197. return 1L;
  198. case WM_DESTROY:
  199. PostQuitMessage(0);
  200. break;
  201. default:
  202. return DefWindowProc(hwnd, wMsg, wParam, lParam);
  203. }
  204. }
  205. Assert(wMsg != WM_CREATE);
  206. } else {
  207. // npMCI is NULL - only WM_CREATE can safely be processed
  208. // I think we can also safely process AVIM_DESTROY and that
  209. // will avoid a few potential hangs...
  210. if ((wMsg != WM_CREATE) && (wMsg != AVIM_DESTROY)) {
  211. return DefWindowProc(hwnd, wMsg, wParam, lParam);
  212. }
  213. }
  214. #endif
  215. switch (wMsg)
  216. {
  217. case WM_CREATE:
  218. npMCI = (NPMCIGRAPHIC)(UINT_PTR)(DWORD_PTR)
  219. ((LPCREATESTRUCT)lParam)->lpCreateParams;
  220. #ifdef _WIN32
  221. SetWindowLongPtr (hwnd, 0, (UINT_PTR)npMCI);
  222. #else
  223. SetWindowWord (hwnd, 0, (WORD)npMCI);
  224. #endif
  225. hmenu = GetSystemMenu(hwnd, 0);
  226. if (hmenu) {
  227. /* Our system menu is too long--get rid of extra stuff. */
  228. // DeleteMenu(hmenu, SC_RESTORE, MF_BYCOMMAND);
  229. // DeleteMenu(hmenu, SC_MINIMIZE, MF_BYCOMMAND);
  230. DeleteMenu(hmenu, SC_MAXIMIZE, MF_BYCOMMAND);
  231. DeleteMenu(hmenu, SC_TASKLIST, MF_BYCOMMAND);
  232. /* Add additional menu items to the end of the system menu */
  233. // AppendMenu(hmenu, MF_SEPARATOR, 0, 0L);
  234. #ifdef IDM_CONFIG
  235. LoadString(ghModule, MCIAVI_MENU_CONFIG, ach, NUMELMS(ach));
  236. AppendMenu(hmenu, MF_STRING, IDM_CONFIG, ach);
  237. #endif
  238. LoadString(ghModule, MCIAVI_MENU_STRETCH, ach, NUMELMS(ach));
  239. AppendMenu(hmenu, MF_STRING, IDM_STRETCH, ach);
  240. LoadString(ghModule, MCIAVI_MENU_MUTE, ach, NUMELMS(ach));
  241. AppendMenu(hmenu, MF_STRING, IDM_MUTE, ach);
  242. }
  243. break;
  244. case WM_INITMENU:
  245. hmenu = GetSystemMenu(hwnd, 0);
  246. if (hmenu) {
  247. #ifdef IDM_SKIPFRAMES
  248. CheckMenuItem(hmenu, IDM_SKIPFRAMES, MF_BYCOMMAND |
  249. ((npMCI->dwOptionFlags & MCIAVIO_SKIPFRAMES) ?
  250. MF_CHECKED : MF_UNCHECKED));
  251. #endif
  252. CheckMenuItem(hmenu, IDM_STRETCH, MF_BYCOMMAND |
  253. ((npMCI->dwOptionFlags & MCIAVIO_STRETCHTOWINDOW) ?
  254. MF_CHECKED : MF_UNCHECKED));
  255. #ifdef IDM_CONFIG
  256. /* If in configure box, disable menu item. */
  257. EnableMenuItem(hmenu, IDM_CONFIG, MF_BYCOMMAND |
  258. (npMCI->wMessageCurrent == 0 ?
  259. MF_ENABLED : MF_GRAYED));
  260. #endif
  261. /* If in stupid mode, disable stretch menu item. */
  262. EnableMenuItem(hmenu, IDM_STRETCH, MF_BYCOMMAND |
  263. ((!(npMCI->dwOptionFlags & MCIAVIO_STUPIDMODE)) ?
  264. MF_ENABLED : MF_GRAYED));
  265. EnableMenuItem(hmenu, IDM_MUTE, MF_BYCOMMAND |
  266. (npMCI->nAudioStreams ?
  267. MF_ENABLED : MF_GRAYED));
  268. CheckMenuItem(hmenu, IDM_MUTE, MF_BYCOMMAND |
  269. (!(npMCI->dwFlags & MCIAVI_PLAYAUDIO) ?
  270. MF_CHECKED : MF_UNCHECKED));
  271. }
  272. break;
  273. case WM_SYSCOMMAND:
  274. switch (wParam & 0xfff0) {
  275. case SC_KEYMENU:
  276. case SC_MOUSEMENU:
  277. gfEvilSysMenu++;
  278. lParam = DefWindowProc(hwnd, wMsg, wParam, lParam);
  279. gfEvilSysMenu--;
  280. return lParam;
  281. #ifdef IDM_SKIPFRAMES
  282. case IDM_SKIPFRAMES:
  283. EnterWinCrit(npMCI);
  284. npMCI->dwOptionFlags ^= MCIAVIO_SKIPFRAMES;
  285. LeaveWinCrit(npMCI);
  286. break;
  287. #endif
  288. case IDM_STRETCH:
  289. EnterWinCrit(npMCI);
  290. npMCI->dwOptionFlags ^= MCIAVIO_STRETCHTOWINDOW;
  291. if (!(npMCI->dwOptionFlags & MCIAVIO_STRETCHTOWINDOW)) {
  292. SetWindowToDefaultSize(npMCI, FALSE);
  293. }
  294. Winproc_DestRect(npMCI, FALSE);
  295. LeaveWinCrit(npMCI);
  296. break;
  297. case IDM_MUTE:
  298. // just set request flag in npMCI
  299. WinProcRequest(npMCI, WINPROC_MUTE);
  300. break;
  301. #ifdef IDM_CONFIG
  302. case IDM_CONFIG:
  303. npMCI->wMessageCurrent = MCI_CONFIGURE;
  304. gfEvil++;
  305. dwOptions = npMCI->dwOptions;
  306. f = ConfigDialog(NULL, npMCI);
  307. if (f) {
  308. #ifdef DEBUG
  309. //
  310. // in DEBUG always reset the dest rect because the user may
  311. // have played with the DEBUG DrawDib options and we will
  312. // need to call DrawDibBegin() again.
  313. //
  314. if (TRUE)
  315. #else
  316. if ((npMCI->dwOptionFlags & (MCIAVIO_STUPIDMODE|MCIAVIO_ZOOMBY2
  317. |MCIAVIO_WINDOWSIZEMASK))
  318. != (dwOptions & (MCIAVIO_STUPIDMODE|MCIAVIO_ZOOMBY2
  319. |MCIAVIO_WINDOWSIZEMASK)) )
  320. #endif
  321. {
  322. npMCI->lFrameDrawn =
  323. (- (LONG) npMCI->wEarlyRecords) - 1;
  324. //EnterWinCrit(npMCI);
  325. SetWindowToDefaultSize(npMCI, FALSE);
  326. Winproc_DestRect(npMCI, FALSE);
  327. //LeaveWinCrit(npMCI);
  328. }
  329. } else {
  330. npMCI->dwOptionFlags = dwOptions;
  331. }
  332. GraphicConfig(npMCI, 0L);
  333. gfEvil--;
  334. npMCI->wMessageCurrent = 0;
  335. break;
  336. #endif
  337. }
  338. break;
  339. case WM_CLOSE:
  340. // Hide default window
  341. WinProcRequest(npMCI, WINPROC_STOP);
  342. ShowWindow(hwnd, SW_HIDE);
  343. return 0L;
  344. // this stuff is here because of some bizarre inter-thread rules in nt
  345. case AVIM_DESTROY:
  346. DestroyWindow(hwnd);
  347. return 1L;
  348. case AVIM_SHOWSTAGE:
  349. {
  350. BOOL bIsVis;
  351. // activate if not visible. force activation if requested
  352. // (if palette changes)
  353. if (wParam) {
  354. bIsVis = FALSE;
  355. } else {
  356. bIsVis = IsWindowVisible(hwnd);
  357. }
  358. SetWindowPos(npMCI->hwndPlayback, HWND_TOP, 0, 0, 0, 0,
  359. SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW |
  360. (bIsVis ? SWP_NOACTIVATE : 0));
  361. if (!bIsVis) {
  362. SetForegroundWindow(hwnd);
  363. }
  364. }
  365. return 1L;
  366. case WM_DESTROY:
  367. // The window may be destroyed 2 ways.
  368. // a. the device is closed. In this case the animation is
  369. // freed in DeviceClose which is called from GraphicClose
  370. // and the animation ID is NULL by the time this window is
  371. // destroyed.
  372. // b. the window is closed. In this case, the animation is
  373. // not closed and we should set the stage to NULL. A new
  374. // default window will be created if needed.
  375. EnterWinCrit(npMCI);
  376. if (IsTask(npMCI->hTask)) {
  377. WinProcRequestEx(npMCI, WINPROC_STOP);
  378. }
  379. if (npMCI->hwndPlayback == npMCI->hwndDefault)
  380. npMCI->hwndPlayback = NULL;
  381. npMCI->hwndDefault = NULL;
  382. LeaveWinCrit(npMCI);
  383. // winproc thread can now exit
  384. PostQuitMessage(0);
  385. break;
  386. case WM_ERASEBKGND:
  387. hdc = (HDC) wParam;
  388. // We should not need any critical section as the system
  389. // has given us a HDC as a message parameter.
  390. Assert(hdc && (hdc != npMCI->hdc));
  391. //EnterWinCrit(npMCI);
  392. if (!(npMCI->dwFlags & MCIAVI_SHOWVIDEO)) {
  393. FillRect(hdc, &npMCI->rcDest, GetStockObject(GRAY_BRUSH));
  394. }
  395. SaveDC(hdc);
  396. ExcludeClipRect(hdc,
  397. npMCI->rcDest.left, npMCI->rcDest.top,
  398. npMCI->rcDest.right, npMCI->rcDest.bottom);
  399. GetClientRect(hwnd, &rc);
  400. FillRect(hdc, &rc, GetStockObject(BLACK_BRUSH));
  401. RestoreDC(hdc, -1);
  402. #if 0
  403. /* Hack: if we're in a WAIT state, we won't get
  404. ** a WM_PAINT, so we need to invalidate the streams here
  405. */
  406. GetClipBox(hdc, &rc);
  407. StreamInvalidate(npMCI, &rc);
  408. #endif
  409. //LeaveWinCrit(npMCI);
  410. return 0L;
  411. case WM_PAINT:
  412. // we always do this even if we leave it to the
  413. // worker to paint, since otherwise we'll loop endlessly
  414. // processing WM_PAINT
  415. hdc = BeginPaint(hwnd, &ps);
  416. rc = ps.rcPaint;
  417. // if the worker thread is cueing, seeking or playing we don't
  418. // actually want to paint (in case it is doing rle delta paints).
  419. // now we've got the window critsec, it is safe to check
  420. // the task state
  421. if ((npMCI->wTaskState == TASKPLAYING) ||
  422. (npMCI->wTaskState == TASKCUEING)) {
  423. npMCI->dwFlags |= MCIAVI_NEEDUPDATE;
  424. } else {
  425. StreamInvalidate(npMCI, &rc);
  426. // we don't need to pass rc in as we are clipped to this
  427. // already and all they do is clip to it.
  428. // don't paint if there is a 'pf' since we only ever
  429. // reference this on the worker thread (OLE threading rules)
  430. if (npMCI->pf) {
  431. WinProcRequest(npMCI, WINPROC_UPDATE);
  432. } else {
  433. // note: TryStreamUpdate will get the HDC critical section
  434. if (!TryStreamUpdate(npMCI, MCI_DGV_UPDATE_PAINT, hdc, NULL)) {
  435. // requires full play - ask worker thread to do this
  436. // to paint the frame at this point, we would have
  437. // to call mciaviPlayFile. This can only be safely called
  438. // on the worker thread. To avoid potential deadlock,
  439. // this paint has to be done asynchronously from us, and
  440. // also we lose the update rect information - the
  441. // worker will paint the entire destination rect.
  442. #if 0 // looks bad - don't bother
  443. // paint gray first, in case the worker thread is busy
  444. // or it fails
  445. GetClientRect(hwnd, &rc);
  446. FillRect(hdc, &rc, GetStockObject(DKGRAY_BRUSH));
  447. #endif
  448. WinProcRequest(npMCI, WINPROC_UPDATE);
  449. } else {
  450. // painted successfully on this thread
  451. // if we are playing and so have an hdc then we need to
  452. // reprepare the orig dc after switching back to it
  453. if (npMCI->wTaskState == TASKPAUSED) {
  454. EnterHDCCrit(npMCI);
  455. // if a new command has arrived the state may have changed
  456. // underneath us. If so, the dc may have been released. We
  457. // only want to call PrepareDC if npMCI->hdc is non null.
  458. if(npMCI->hdc) PrepareDC(npMCI);
  459. LeaveHDCCrit(npMCI); // remember to release the critical section
  460. }
  461. }
  462. }
  463. }
  464. EndPaint(hwnd, &ps);
  465. return 0L; // we do NOT call DefWindowProc
  466. case WM_PALETTECHANGED:
  467. // We're not using the default window. We have no business here.
  468. if (npMCI->hwndPlayback != hwnd)
  469. break;
  470. //
  471. // someone has realized a palette - so we need to re-realize our
  472. // palette (note that this will also cause drawdib to
  473. // check for PAL_INDICES vs PAL_COLOURS.
  474. //
  475. if ((HWND) wParam != hwnd) {
  476. WinProcRequest(npMCI, WINPROC_REALIZE);
  477. // invalidate is done in InternalRealize
  478. //InvalidateRect(hwnd, NULL, FALSE);
  479. }
  480. break;
  481. case WM_QUERYNEWPALETTE:
  482. {
  483. #if 0
  484. LONG lRet;
  485. #endif
  486. // We're not using the default window. We have no business here.
  487. if (npMCI->hwndPlayback != hwnd)
  488. break;
  489. #if 0
  490. // not true = internalrealize has always returned 0, so why do this
  491. // on this thread?
  492. EnterHDCCrit(npMCI);
  493. // need to do this on winproc thread to get
  494. // correct return value.
  495. lRet = InternalRealize(npMCI);
  496. LeaveHDCCrit(npMCI);
  497. return(lRet);
  498. #else
  499. WinProcRequest(npMCI, WINPROC_REALIZE);
  500. return 0;
  501. #endif
  502. }
  503. case WM_WINDOWPOSCHANGED:
  504. //EnterWinCrit(npMCI);
  505. //CheckWindowMove grabs the critical section when it needs it
  506. CheckWindowMove(npMCI, TRUE);
  507. //LeaveWinCrit(npMCI);
  508. break;
  509. case WM_SIZE:
  510. EnterWinCrit(npMCI);
  511. Winproc_DestRect(npMCI, FALSE);
  512. LeaveWinCrit(npMCI);
  513. break;
  514. case WM_QUERYENDSESSION:
  515. WinProcRequest(npMCI, WINPROC_STOP);
  516. break;
  517. case WM_ENDSESSION:
  518. if (wParam) {
  519. DestroyWindow(hwnd); // we may not be able to destroy window?
  520. }
  521. break;
  522. case WM_GETMINMAXINFO:
  523. lpmmi = (MINMAXINFO FAR *)(lParam);
  524. lpmmi->ptMinTrackSize.x = GetSystemMetrics(SM_CXSIZE) * 2;
  525. break;
  526. case WM_NCACTIVATE:
  527. WinProcRequest(npMCI, wParam?WINPROC_ACTIVE : WINPROC_INACTIVE);
  528. break;
  529. #if 0
  530. We should not need both ACTIVATE and NCACTIVATE - use the one that
  531. arrives first (to give us a little more time and reduce the start up
  532. latency)
  533. case WM_ACTIVATE:
  534. WinProcRequest(npMCI, wParam?WINPROC_ACTIVE : WINPROC_INACTIVE);
  535. break;
  536. #endif
  537. #ifdef REMOTESTEAL
  538. case WM_AUDIO_ON: // Someone has released the wave device
  539. {
  540. extern HWND hwndLostAudio;
  541. //Assert(npMCI->dwFlags & MCIAVI_PLAYAUDIO);
  542. //Assert(npMCI->dwFlags & MCIAVI_LOSTAUDIO);
  543. //Assert(npMCI->hWave == NULL);
  544. // Timing might be such that these assertions are invalid
  545. // If we are not playing then we might be able to forward
  546. // the message to another... OR, tell the one giving up the
  547. // audio that it can be reclaimed because we no longer have
  548. // a use for it.
  549. if (npMCI->wTaskState != TASKPLAYING) {
  550. if (!hwndLostAudio) {
  551. hwndLostAudio = (HWND)wParam;
  552. }
  553. if (hwndLostAudio) {
  554. DPF2(("Forwarding WM_AUDIO_ON message to %x...\n", hwndLostAudio));
  555. if (IsWindow(hwndLostAudio)) {
  556. PostMessage(hwndLostAudio, WM_AUDIO_ON, 0, 0);
  557. }
  558. hwndLostAudio = 0; // Prevent further messages
  559. }
  560. } else {
  561. // we are playing
  562. // Save the window handle of the window releasing the sound
  563. DPF2(("Setting hwndLostAudio to %x (was %x)\n", wParam, hwndLostAudio));
  564. hwndLostAudio = (HWND)wParam;
  565. // if hwndLostAudio==0 then we do not return it to anyone
  566. WinProcRequest(npMCI, WINPROC_SOUND);
  567. }
  568. return 0;
  569. break;
  570. }
  571. case WM_AUDIO_OFF: // Someone wants our wave device
  572. {
  573. extern HWND hwndWantAudio;
  574. //Assert(npMCI->dwFlags & MCIAVI_PLAYAUDIO);
  575. //Assert(!(npMCI->dwFlags & MCIAVI_LOSTAUDIO));
  576. //Assert(npMCI->hWave != NULL);
  577. // Timing might be such that these assertions are invalid
  578. SetNTFlags(npMCI, NTF_AUDIO_OFF);
  579. // Save the window handle of the window which wants sound
  580. DPF2(("WM_AUDIO_OFF... hwndWantAudio set to %x (was %x)\n", wParam, hwndWantAudio));
  581. hwndWantAudio = (HWND)wParam;
  582. // if hwndWantAudio==0 then we do not release the wave device
  583. if (IsWindow(hwndWantAudio)) {
  584. WinProcRequest(npMCI, WINPROC_SILENT);
  585. } else {
  586. DPF(("WM_AUDIO_OFF... but the target window is invalid\n"));
  587. }
  588. ResetNTFlags(npMCI, NTF_AUDIO_OFF);
  589. return 0;
  590. break;
  591. }
  592. #endif // REMOTESTEAL
  593. #if 0
  594. case WM_LBUTTONDOWN:
  595. {
  596. DWORD dw;
  597. static DWORD dwLastClick;
  598. static DWORD dwClicks = 0;
  599. #define MAX_CLICKS 7
  600. /* . = (0,300) - = (300,1000) word = (500,1500) */
  601. /* AVI: .- ...- .. */
  602. static DWORD adwClickHigh[MAX_CLICKS] =
  603. { 300, 1500, 300, 300, 300, 1500, 300 };
  604. static DWORD adwClickLow[MAX_CLICKS] =
  605. { 0, 500, 0, 0, 0, 500, 0 };
  606. dw = timeGetTime();
  607. if (((dw - dwLastClick) > adwClickLow[dwClicks]) &&
  608. ((dw - dwLastClick) <= adwClickHigh[dwClicks]))
  609. dwClicks++;
  610. else
  611. dwClicks = 0;
  612. dwLastClick = dw;
  613. if (dwClicks == MAX_CLICKS) {
  614. WinProcRequest(npMCI, WINPROC_STOP);
  615. Credits(hwnd);
  616. dwClicks = 0;
  617. }
  618. }
  619. #endif
  620. } // switch(wMsg)
  621. return DefWindowProc(hwnd, wMsg, wParam, lParam);
  622. }
  623. #if 0
  624. static void NEAR PASCAL Credits(HWND hwnd)
  625. {
  626. /* Credits... */
  627. RECT rc;
  628. RECT rcUpdate;
  629. HDC hdc;
  630. MSG msg;
  631. int dyLine;
  632. int yLine;
  633. TEXTMETRIC tm;
  634. DWORD dwNextTime;
  635. long lScroll;
  636. DWORD rgb;
  637. HANDLE hResInfo;
  638. HANDLE hResData;
  639. LPSTR pchSrc, pchDst;
  640. char achLine[100];
  641. int iEncrypt;
  642. #define EOFCHAR '@' // end of credits file
  643. /* load the credits */
  644. if ((hResInfo = FindResource(ghModule, TEXT("MMS"), TEXT("MMSCR"))) == NULL)
  645. return;
  646. if ((hResData = LoadResource(ghModule, hResInfo)) == NULL)
  647. return;
  648. if ((pchSrc = LockResource(hResData)) == NULL)
  649. return;
  650. /* we want to get all mouse and keyboard events, to make
  651. * sure we stop the animation when the user clicks or
  652. * hits a key
  653. */
  654. SetFocus(hwnd);
  655. SetCapture(hwnd);
  656. /* Scroll the credits up, one pixel at a time. pchSrc
  657. * points to the encrypted data; achLine contains a decrypted
  658. * line (null-terminated). dyLine is the height of each
  659. * line (constant), and yLine is between 0 and dyLine,
  660. * indicating how many pixels of the line have been scrolled
  661. * in vertically from the bottom
  662. */
  663. hdc = GetDC(hwnd);
  664. SelectObject(hdc, GetStockObject(ANSI_VAR_FONT));
  665. GetClientRect(hwnd, &rc);
  666. SetTextAlign(hdc, TA_CENTER);
  667. SetBkColor(hdc, RGB(0, 0, 0));
  668. SetRect(&rcUpdate, 0, rc.bottom - 1, rc.right, rc.bottom);
  669. GetTextMetrics(hdc, &tm);
  670. if ((dyLine = tm.tmHeight + tm.tmExternalLeading) == 0)
  671. dyLine = 1;
  672. yLine = dyLine;
  673. dwNextTime = GetCurrentTime(); // time to do the next scroll
  674. lScroll = 0;
  675. iEncrypt = 0;
  676. while (TRUE) {
  677. /* If the user clicks the mouse or hits a key, exit.
  678. * However, ignore WM_LBUTTONUP because they will have
  679. * to let go of the mouse after clicking the icon.
  680. * Also, ignore mouse move messages.
  681. */
  682. if (PeekMessage(&msg, hwnd, WM_KEYFIRST, WM_KEYLAST,
  683. PM_NOREMOVE | PM_NOYIELD))
  684. break; // exit on key hit
  685. if (PeekMessage(&msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
  686. PM_NOREMOVE | PM_NOYIELD)) {
  687. if ((msg.message == WM_MOUSEMOVE) ||
  688. (msg.message == WM_LBUTTONUP)) {
  689. /* remove and ignore message */
  690. PeekMessage(&msg, hwnd, msg.message,
  691. msg.message,
  692. PM_REMOVE | PM_NOYIELD);
  693. }
  694. else
  695. break; // exit on click
  696. }
  697. /* scroll at a fixed no. of vertical pixels per sec. */
  698. if (dwNextTime > GetCurrentTime())
  699. continue;
  700. dwNextTime += 50L; // millseconds per scroll
  701. if (yLine == dyLine) {
  702. /* decrypt a line and copy to achLine */
  703. pchDst = achLine;
  704. while (TRUE) {
  705. *pchDst = (char) (*pchSrc++ ^
  706. (128 | (iEncrypt++ & 127)));
  707. if ((*pchDst == '\r') ||
  708. (*pchDst == EOFCHAR))
  709. break;
  710. pchDst++;
  711. }
  712. if (*pchDst == EOFCHAR)
  713. break; // no more lines
  714. *pchDst = 0; // null-terminate
  715. pchSrc++, iEncrypt++; // skip '\n'
  716. yLine = 0;
  717. }
  718. /* scroll screen up one pixel */
  719. BitBlt(hdc, 0, 0, rcUpdate.right, rcUpdate.top,
  720. hdc, 0, 1, SRCCOPY);
  721. /* vary the text colors through a "rainbow" */
  722. switch ((int) (lScroll++ / 4) % 5/*num-of-cases*/) {
  723. case 0: rgb = RGB(255, 0, 0); break;
  724. case 1: rgb = RGB(255, 255, 0); break;
  725. case 2: rgb = RGB( 0, 255, 0); break;
  726. case 3: rgb = RGB( 0, 255, 255); break;
  727. case 4: rgb = RGB(255, 0, 255); break;
  728. }
  729. SetTextColor(hdc, rgb);
  730. /* fill in the bottom pixel */
  731. SaveDC(hdc);
  732. yLine++;
  733. IntersectClipRect(hdc, rcUpdate.left, rcUpdate.top,
  734. rcUpdate.right, rcUpdate.bottom);
  735. #ifdef _WIN32
  736. ExtTextOutA(hdc, rc.right / 2, rc.bottom - yLine,
  737. ETO_OPAQUE, &rcUpdate,
  738. achLine, lstrlenA(achLine), NULL);
  739. #else
  740. ExtTextOut(hdc, rc.right / 2, rc.bottom - yLine,
  741. ETO_OPAQUE, &rcUpdate,
  742. achLine, lstrlen(achLine), NULL);
  743. #endif
  744. RestoreDC(hdc, -1);
  745. }
  746. ReleaseDC(hwnd, hdc);
  747. ReleaseCapture();
  748. UnlockResource(hResData);
  749. FreeResource(hResData);
  750. InvalidateRect(hwnd, NULL, TRUE);
  751. }
  752. #endif
  753. //
  754. // Obey the registry default sizing of Zoom by 2 and Fixed screen %.
  755. // Takes a Rect and either zooms it by 2 or replaces it with a constant size
  756. // or leaves it alone.
  757. //
  758. void FAR PASCAL AlterRectUsingDefaults(NPMCIGRAPHIC npMCI, LPRECT lprc)
  759. {
  760. if (npMCI->dwOptionFlags & MCIAVIO_ZOOMBY2) {
  761. SetRect(lprc, 0, 0, lprc->right*2, lprc->bottom*2);
  762. } else {
  763. if (npMCI->dwOptionFlags & MCIAVIO_WINDOWSIZEMASK) {
  764. lprc->right = GetSystemMetrics (SM_CXSCREEN);
  765. lprc->bottom = GetSystemMetrics (SM_CYSCREEN);
  766. switch(npMCI->dwOptionFlags & MCIAVIO_WINDOWSIZEMASK)
  767. {
  768. case MCIAVIO_1QSCREENSIZE:
  769. SetRect(lprc, 0, 0, lprc->right/4, lprc->bottom/4);
  770. break;
  771. case MCIAVIO_2QSCREENSIZE:
  772. SetRect(lprc, 0, 0, lprc->right/2, lprc->bottom/2);
  773. break;
  774. case MCIAVIO_3QSCREENSIZE:
  775. SetRect(lprc, 0, 0, lprc->right*3/4, lprc->bottom*3/4);
  776. break;
  777. case MCIAVIO_MAXWINDOWSIZE:
  778. SetRect(lprc, 0, 0, lprc->right, lprc->bottom);
  779. break;
  780. }
  781. }
  782. }
  783. }
  784. // Set the size of the default window to be the rcMovie size (default
  785. // destination size). Keep in mind a top level window might grow off screen,
  786. // so adjust the position so that it remains on screen.
  787. void FAR PASCAL SetWindowToDefaultSize(NPMCIGRAPHIC npMCI, BOOL fUseDefaultSizing)
  788. {
  789. RECT rc, rcW;
  790. int xScreen, yScreen, x, y;
  791. WINDOWPLACEMENT wp;
  792. wp.length = sizeof(wp);
  793. if (npMCI->hwndPlayback && npMCI->hwndPlayback == npMCI->hwndDefault) {
  794. // Get the size of the movie, maybe alter it if the configure options
  795. // tell us to play zoomed or fullscreen or something, and adjust for
  796. // non-client area.
  797. //
  798. rc = npMCI->rcMovie;
  799. if (fUseDefaultSizing)
  800. AlterRectUsingDefaults(npMCI, &rc);
  801. AdjustWindowRect(&rc, GetWindowLong(npMCI->hwndPlayback, GWL_STYLE), FALSE);
  802. // For top-level windows, get the position where the playback window is
  803. // (or will be) on the screen. Make it fit on the screen if possible.
  804. // Dorking with the position of the default window if it's a
  805. // child window is a bad idea. First of all, SetWindowPos is going to
  806. // position it relative to its parent, and these calculations figure
  807. // out where we want it in screen coordinates. Second of all, trying
  808. // to move a child so that it's on screen when the parent could be
  809. // offscreen itself or hiding the child window is just asking for
  810. // trouble.
  811. //
  812. if (!(GetWindowLong(npMCI->hwndPlayback, GWL_STYLE) & WS_CHILD)) {
  813. if (IsIconic(npMCI->hwndPlayback)) {
  814. GetWindowPlacement(npMCI->hwndPlayback, &wp);
  815. rcW = wp.rcNormalPosition;
  816. } else {
  817. GetWindowRect(npMCI->hwndPlayback, &rcW);
  818. }
  819. rcW.right = rcW.left + rc.right - rc.left;
  820. rcW.bottom = rcW.top + rc.bottom - rc.top;
  821. xScreen = GetSystemMetrics(SM_CXSCREEN);
  822. yScreen = GetSystemMetrics(SM_CYSCREEN);
  823. if (rcW.right > xScreen) {
  824. x = min(rcW.left, rcW.right - xScreen);
  825. rcW.left -= x;
  826. rcW.right -= x;
  827. }
  828. if (rcW.bottom > yScreen) {
  829. y = min(rcW.top, rcW.bottom - yScreen);
  830. rcW.top -= y;
  831. rcW.bottom -= y;
  832. }
  833. if (IsIconic(npMCI->hwndPlayback)) {
  834. wp.rcNormalPosition = rcW;
  835. SetWindowPlacement(npMCI->hwndPlayback, &wp);
  836. } else {
  837. SetWindowPos(npMCI->hwndPlayback, NULL, rcW.left, rcW.top,
  838. rcW.right - rcW.left, rcW.bottom - rcW.top,
  839. SWP_NOZORDER | SWP_NOACTIVATE);
  840. }
  841. // For a child window, we don't move it, we just size it.
  842. //
  843. } else {
  844. if (IsIconic(npMCI->hwndPlayback)) {
  845. GetWindowPlacement(npMCI->hwndPlayback, &wp);
  846. wp.rcNormalPosition.right = wp.rcNormalPosition.left +
  847. (rc.right - rc.left);
  848. wp.rcNormalPosition.bottom = wp.rcNormalPosition.top +
  849. (rc.bottom - rc.top);
  850. SetWindowPlacement(npMCI->hwndPlayback, &wp);
  851. } else {
  852. SetWindowPos(npMCI->hwndPlayback, NULL, 0, 0,
  853. rc.right - rc.left, rc.bottom - rc.top,
  854. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  855. }
  856. }
  857. }
  858. }
  859. void FAR PASCAL Winproc_DestRect(NPMCIGRAPHIC npMCI, BOOL fUseDefaultSizing)
  860. {
  861. RECT rc;
  862. /* WM_SIZE messages (on NT at least) are sometimes sent
  863. * during CreateWindow processing (eg if the initial window size
  864. * is not CW_DEFAULT). Some fields in npMCI are only filled in
  865. * after CreateWindow has returned. So there is a danger that at this
  866. * point some fields are not valid.
  867. */
  868. if (npMCI->hwndPlayback &&
  869. npMCI->hwndPlayback == npMCI->hwndDefault &&
  870. (npMCI->dwOptionFlags & MCIAVIO_STRETCHTOWINDOW)) {
  871. GetClientRect(npMCI->hwndPlayback, &rc);
  872. }
  873. // Only allow ZOOMBY2 and fixed % defaults for our default playback window
  874. else if (npMCI->streams > 0 && npMCI->hwndPlayback == npMCI->hwndDefault) {
  875. rc = npMCI->rcMovie;
  876. // Note: irrelevant on winproc thread
  877. //if (fUseDefaultSizing)
  878. // AlterRectUsingDefaults(npMCI, &rc);
  879. }
  880. else {
  881. return;
  882. }
  883. if (!IsRectEmpty(&rc)) {
  884. WinCritCheckIn(npMCI);
  885. WinProcRequestEx(npMCI, WINPROC_RESETDEST); // faster form... we have the critical section
  886. }
  887. }
  888. #ifdef _WIN32
  889. #define DWORG POINT
  890. #define GETDCORG(hdc, dwOrg) GetDCOrgEx(hdc, &dwOrg)
  891. #else
  892. #define DWORG DWORD
  893. #define GETDCORG(hdc, dwOrg) dwOrg = GetDCOrg(hdc)
  894. #endif
  895. void CheckWindowMove(NPMCIGRAPHIC npMCI, BOOL fForce)
  896. {
  897. DWORG dwOrg;
  898. UINT wRgn;
  899. HDC hdc;
  900. RECT rc;
  901. BOOL fNull;
  902. BOOL fGetDC;
  903. if (!(npMCI->dwFlags & MCIAVI_WANTMOVE))
  904. return;
  905. if (!npMCI->hicDraw || !npMCI->hwndPlayback || npMCI->nVideoStreams == 0)
  906. return;
  907. Assert(IsWindow(npMCI->hwndPlayback));
  908. Assert(npMCI->paStreamInfo);
  909. Assert(npMCI->nVideoStreams > 0);
  910. //
  911. // when the screen is locked for update by a window move operation
  912. // we dont want to turn off the video.
  913. //
  914. // we can tell if the screen is locked by checking a DC to the screen.
  915. //
  916. hdc = GetDC(NULL);
  917. fNull = GetClipBox(hdc, &rc);
  918. ReleaseDC(NULL, hdc);
  919. if (NULLREGION == fNull)
  920. {
  921. npMCI->wRgnType = (UINT) -1;
  922. return;
  923. }
  924. if (fForce)
  925. npMCI->wRgnType = (UINT) -1;
  926. // sync worker thread/winproc thread interaction
  927. EnterHDCCrit(npMCI);
  928. if (fGetDC = (npMCI->hdc == NULL)) {
  929. hdc = GetDC (npMCI->hwndPlayback);
  930. } else {
  931. hdc = npMCI->hdc;
  932. }
  933. wRgn = GetClipBox(hdc, &rc);
  934. GETDCORG(hdc, dwOrg);
  935. if (fGetDC)
  936. ReleaseDC(npMCI->hwndPlayback, hdc);
  937. if (wRgn == npMCI->wRgnType &&
  938. #ifdef _WIN32
  939. dwOrg.x == npMCI->dwOrg.x &&
  940. dwOrg.y == npMCI->dwOrg.y &&
  941. #else
  942. dwOrg == npMCI->dwOrg &&
  943. #endif
  944. EqualRect(&rc, &npMCI->rcClip)) {
  945. LeaveHDCCrit(npMCI);
  946. return;
  947. }
  948. npMCI->wRgnType = wRgn;
  949. npMCI->dwOrg = dwOrg;
  950. npMCI->rcClip = rc;
  951. rc = npMCI->psiVideo->rcDest;
  952. ClientToScreen(npMCI->hwndPlayback, (LPPOINT)&rc);
  953. ClientToScreen(npMCI->hwndPlayback, (LPPOINT)&rc+1);
  954. if (wRgn == NULLREGION)
  955. SetRectEmpty(&rc);
  956. DPF2(("Sending ICM_DRAW_WINDOW message Rgn=%d, Org=(%d,%d) [%d, %d, %d, %d]\n", wRgn, dwOrg, rc));
  957. if (ICDrawWindow(npMCI->hicDraw, &rc) != ICERR_OK) {
  958. DPF2(("Draw device does not want ICM_DRAW_WINDOW messages!\n"));
  959. npMCI->dwFlags &= ~MCIAVI_WANTMOVE;
  960. }
  961. LeaveHDCCrit(npMCI);
  962. }