Windows NT 4.0 source code leak
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.

1162 lines
31 KiB

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