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.

567 lines
14 KiB

  1. #include "ctlspriv.h"
  2. #include "rlefile.h"
  3. #define RectWid(_rc) ((_rc).right-(_rc).left)
  4. #define RectHgt(_rc) ((_rc).bottom-(_rc).top)
  5. typedef struct {
  6. HWND hwnd; // my window
  7. int id; // my id
  8. HWND hwndP; // my owner (get notify messages)
  9. DWORD style;
  10. BOOL fFirstPaint; // TRUE until first paint.
  11. RLEFILE *prle;
  12. #ifdef WIN32
  13. CRITICAL_SECTION crit;
  14. #endif
  15. RECT rc;
  16. int NumFrames;
  17. int Rate;
  18. int iFrame;
  19. int PlayCount;
  20. int PlayFrom;
  21. int PlayTo;
  22. HANDLE PaintThread;
  23. HANDLE hStopEvent;
  24. } ANIMATE;
  25. #ifdef WIN32
  26. #define Enter(p) EnterCriticalSection(&p->crit)
  27. #define Leave(p) LeaveCriticalSection(&p->crit)
  28. #else
  29. #define Enter(p)
  30. #define Leave(p)
  31. #endif
  32. #define OPEN_WINDOW_TEXT 42
  33. #define Ani_UseThread(p) (!((p)->style & ACS_TIMER))
  34. LRESULT CALLBACK AnimateWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  35. BOOL HandleOpen(ANIMATE *p, HINSTANCE hInst, LPCTSTR pszName, UINT flags);
  36. BOOL HandleStop(ANIMATE *p);
  37. BOOL HandlePlay(ANIMATE *p, int from, int to, int count);
  38. void HandlePaint(ANIMATE *p, HDC hdc);
  39. int HandleTick(ANIMATE *p);
  40. #pragma code_seg(CODESEG_INIT)
  41. TCHAR c_szAnimateClass[] = ANIMATE_CLASS;
  42. BOOL FAR PASCAL InitAnimateClass(HINSTANCE hInstance)
  43. {
  44. WNDCLASS wc;
  45. if (!GetClassInfo(hInstance, c_szAnimateClass, &wc)) {
  46. #ifndef WIN32
  47. extern LRESULT CALLBACK _AnimateWndProc(HWND, UINT, WPARAM, LPARAM);
  48. wc.lpfnWndProc = _AnimateWndProc;
  49. #else
  50. wc.lpfnWndProc = AnimateWndProc;
  51. #endif
  52. wc.lpszClassName = c_szAnimateClass;
  53. wc.style = CS_DBLCLKS | CS_GLOBALCLASS;
  54. wc.cbClsExtra = 0;
  55. wc.cbWndExtra = sizeof(LPVOID);
  56. wc.hInstance = hInstance; // use DLL instance if in DLL
  57. wc.hIcon = NULL;
  58. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  59. wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
  60. wc.lpszMenuName = NULL;
  61. if (!RegisterClass(&wc))
  62. return FALSE;
  63. }
  64. return TRUE;
  65. }
  66. #pragma code_seg()
  67. BOOL HandleOpen(ANIMATE *p, HINSTANCE hInst, LPCTSTR pszName, UINT flags)
  68. {
  69. TCHAR ach[MAX_PATH];
  70. //
  71. // use window text as file name
  72. //
  73. if (flags == OPEN_WINDOW_TEXT)
  74. {
  75. GetWindowText(p->hwnd, ach, ARRAYSIZE(ach));
  76. pszName = ach;
  77. }
  78. if (hInst == NULL)
  79. hInst = (HINSTANCE)GetWindowLongPtr(p->hwnd, GWLP_HINSTANCE);
  80. HandleStop(p); // stop a play first
  81. if (p->prle)
  82. {
  83. RleFile_Free(p->prle);
  84. p->prle = NULL;
  85. }
  86. p->iFrame = 0;
  87. p->NumFrames = 0;
  88. if (pszName == NULL || (!IS_INTRESOURCE(pszName) && *pszName == 0))
  89. return FALSE;
  90. //
  91. // now open the file/resource we got.
  92. //
  93. p->prle = RleFile_New();
  94. if (p->prle == NULL)
  95. return FALSE;
  96. if (!RleFile_OpenFromResource(p->prle, hInst, pszName, TEXT("AVI")) &&
  97. !RleFile_OpenFromFile(p->prle, pszName))
  98. {
  99. RleFile_Free(p->prle);
  100. p->prle = NULL;
  101. return FALSE;
  102. }
  103. else
  104. {
  105. p->NumFrames = RleFile_NumFrames(p->prle);
  106. p->Rate = (int)RleFile_Rate(p->prle);
  107. SetRect(&p->rc, 0, 0, RleFile_Width(p->prle), RleFile_Height(p->prle));
  108. }
  109. //
  110. // handle a transparent color
  111. //
  112. if ((p->style & ACS_TRANSPARENT) && p->hwndP)
  113. {
  114. HDC hdc;
  115. HDC hdcM;
  116. HBITMAP hbm;
  117. COLORREF rgbS, rgbD;
  118. hdc = GetDC(p->hwnd);
  119. //
  120. // create a bitmap and draw image into it.
  121. // get upper left pixel and make that transparent.
  122. //
  123. hdcM= CreateCompatibleDC(hdc);
  124. hbm = CreateCompatibleBitmap(hdc, 1, 1);
  125. SelectObject(hdcM, hbm);
  126. HandlePaint(p, hdcM);
  127. rgbS = GetPixel(hdcM, 0, 0);
  128. DeleteDC(hdcM);
  129. DeleteObject(hbm);
  130. SendMessage(p->hwndP, GET_WM_CTLCOLOR_MSG(CTLCOLOR_STATIC),
  131. GET_WM_CTLCOLOR_MPS(hdc, p->hwnd, CTLCOLOR_STATIC));
  132. rgbD = GetBkColor(hdc);
  133. ReleaseDC(p->hwnd, hdc);
  134. //
  135. // now replace the color
  136. //
  137. RleFile_ChangeColor(p->prle, rgbS, rgbD);
  138. }
  139. //
  140. // ok it worked, resize window.
  141. //
  142. if (p->style & ACS_CENTER)
  143. {
  144. RECT rc;
  145. GetClientRect(p->hwnd, &rc);
  146. OffsetRect(&p->rc, (rc.right-p->rc.right)/2,(rc.bottom-p->rc.bottom)/2);
  147. }
  148. else
  149. {
  150. RECT rc;
  151. rc = p->rc;
  152. AdjustWindowRectEx(&rc, GetWindowStyle(p->hwnd), FALSE, GetWindowExStyle(p->hwnd));
  153. SetWindowPos(p->hwnd, NULL, 0, 0, RectWid(rc), RectHgt(rc),
  154. SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
  155. }
  156. if (p->style & ACS_AUTOPLAY)
  157. {
  158. PostMessage(p->hwnd, ACM_PLAY, (UINT_PTR)-1, MAKELONG(0, -1));
  159. }
  160. else
  161. {
  162. InvalidateRect(p->hwnd, NULL, TRUE);
  163. }
  164. return TRUE;
  165. }
  166. void DoNotify(ANIMATE *p, int cmd)
  167. {
  168. if (p->hwndP)
  169. PostMessage(p->hwndP, WM_COMMAND, GET_WM_COMMAND_MPS(p->id, p->hwnd, cmd));
  170. }
  171. BOOL HandleStop(ANIMATE *p)
  172. {
  173. if (p == NULL || !p->PaintThread)
  174. return FALSE;
  175. if (Ani_UseThread(p)) {
  176. // set thread up to terminate between frames
  177. Enter( p );
  178. p->PlayCount = 0;
  179. Leave( p );
  180. if (p->hStopEvent)
  181. SetEvent(p->hStopEvent);
  182. WaitForSingleObject(p->PaintThread, INFINITE);
  183. // PORT QSY RAID 4167
  184. // Under certain situations, both the CloseHandle()
  185. // and ExitThread() call try to remove MainWin internal
  186. // objects.
  187. // This is a work-around for preview 1.
  188. // I've raised another bug RAID 4250 for OE RTW
  189. #ifndef UNIX
  190. CloseHandle(p->PaintThread);
  191. #endif
  192. // PORT QSY
  193. p->PaintThread = NULL;
  194. if (p->hStopEvent)
  195. CloseHandle(p->hStopEvent);
  196. p->hStopEvent = NULL;
  197. } else {
  198. KillTimer(p->hwnd, HandleToUlong(p->PaintThread)); // really was a UINT
  199. p->PaintThread = 0;
  200. DoNotify(p, ACN_STOP);
  201. }
  202. return TRUE;
  203. }
  204. int PlayThread(ANIMATE *p)
  205. {
  206. int result;
  207. DoNotify(p, ACN_START);
  208. while (result = HandleTick(p))
  209. {
  210. // Sleep for a bit (4 seconds) longer if we are hidden
  211. //
  212. // Old code here slept, which can block the UI thread
  213. // if the app tries to stop/shutdown/change the animation
  214. // right near the beginning of the sleep.
  215. // Sleep((result < 0 ? p->Rate+4000 : p->Rate));
  216. // Do a timed wait for the stop event instead
  217. //
  218. if (p->hStopEvent)
  219. WaitForSingleObject(p->hStopEvent, (result < 0 ? p->Rate+4000 : p->Rate));
  220. else
  221. Sleep((result < 0 ? p->Rate+4000 : p->Rate));
  222. }
  223. DoNotify(p, ACN_STOP);
  224. return 0;
  225. }
  226. BOOL HandlePlay(ANIMATE *p, int from, int to, int count)
  227. {
  228. if (p == NULL || p->prle == NULL)
  229. return FALSE;
  230. HandleStop(p);
  231. if (from >= p->NumFrames)
  232. from = p->NumFrames-1;
  233. if (to == -1)
  234. to = p->NumFrames-1;
  235. if (to < 0)
  236. to = 0;
  237. if (to >= p->NumFrames)
  238. to = p->NumFrames-1;
  239. p->PlayCount = count;
  240. p->PlayTo = to;
  241. if (from >= 0) {
  242. p->iFrame = from;
  243. p->PlayFrom = from;
  244. } else
  245. from = p->PlayFrom;
  246. if ( (from == to) || !count )
  247. {
  248. InvalidateRect(p->hwnd, NULL, TRUE);
  249. return TRUE;
  250. }
  251. InvalidateRect(p->hwnd, NULL, FALSE);
  252. UpdateWindow(p->hwnd);
  253. if (Ani_UseThread(p))
  254. {
  255. DWORD dw;
  256. p->hStopEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  257. p->PaintThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PlayThread, (void*)p, 0, &dw);
  258. }
  259. else
  260. {
  261. DoNotify(p, ACN_START);
  262. p->PaintThread = (HANDLE)SetTimer(p->hwnd, 42, (UINT)p->Rate, NULL);
  263. }
  264. return TRUE;
  265. }
  266. void HandleFirstPaint(ANIMATE *p)
  267. {
  268. if (p->fFirstPaint)
  269. {
  270. p->fFirstPaint = FALSE;
  271. if (p->NumFrames == 0 &&
  272. (p->style & WS_CHILD))
  273. {
  274. HandleOpen(p, NULL, NULL, OPEN_WINDOW_TEXT);
  275. }
  276. }
  277. }
  278. void HandlePaint(ANIMATE *p, HDC hdc)
  279. {
  280. if( p && p->prle )
  281. {
  282. Enter( p );
  283. RleFile_Paint( p->prle, hdc, p->iFrame, p->rc.left, p->rc.top );
  284. Leave( p );
  285. }
  286. }
  287. void HandleErase(ANIMATE * p, HDC hdc)
  288. {
  289. HBRUSH hbr;
  290. RECT rc;
  291. hbr = (HBRUSH)SendMessage(p->hwndP, GET_WM_CTLCOLOR_MSG(CTLCOLOR_STATIC),
  292. GET_WM_CTLCOLOR_MPS(hdc, p->hwnd, CTLCOLOR_STATIC));
  293. GetClientRect(p->hwnd, &rc);
  294. FillRect(hdc, &rc, hbr);
  295. }
  296. void HandlePrint(ANIMATE *p, HDC hdc)
  297. {
  298. HandleFirstPaint(p);
  299. HandlePaint(p, hdc);
  300. }
  301. int HandleTick(ANIMATE *p)
  302. // - if something to do but we are hidden
  303. // returns 0 if nothing left
  304. // + if something to do
  305. {
  306. int result = 0;
  307. if( p && p->prle )
  308. {
  309. HDC hdc;
  310. RECT dummy;
  311. Enter( p );
  312. hdc = GetDC( p->hwnd );
  313. if( GetClipBox( hdc, &dummy ) != NULLREGION )
  314. {
  315. // do a full repaint on first frame
  316. if( p->iFrame == p->PlayFrom )
  317. HandlePaint( p, hdc );
  318. else
  319. RleFile_Draw( p->prle, hdc, p->iFrame, p->rc.left, p->rc.top );
  320. if( p->iFrame >= p->PlayTo )
  321. {
  322. if( p->PlayCount > 0 )
  323. p->PlayCount--;
  324. if( p->PlayCount != 0 )
  325. p->iFrame = p->PlayFrom;
  326. }
  327. else
  328. p->iFrame++;
  329. // Something to do? and visible, return + value
  330. result = ( p->PlayCount != 0 );
  331. }
  332. else
  333. {
  334. // Something to do? but hidden, so return - value
  335. p->iFrame = p->PlayFrom;
  336. result = -( p->PlayCount != 0 );
  337. }
  338. ReleaseDC( p->hwnd, hdc );
  339. Leave( p );
  340. }
  341. return result;
  342. }
  343. void NEAR Ani_OnStyleChanged(ANIMATE* p, WPARAM gwl, LPSTYLESTRUCT pinfo)
  344. {
  345. if (gwl == GWL_STYLE) {
  346. p->style = pinfo->styleNew;
  347. }
  348. }
  349. LRESULT CALLBACK AnimateWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  350. {
  351. ANIMATE *p = (ANIMATE *)GetWindowPtr(hwnd, 0);
  352. HDC hdc;
  353. PAINTSTRUCT ps;
  354. // First, the messages that can handle p == NULL.
  355. // All these handlers must end with a "return" or a "goto DoDefault".
  356. switch (msg) {
  357. case WM_NCCREATE:
  358. #define lpcs ((LPCREATESTRUCT)lParam)
  359. p = (ANIMATE *)LocalAlloc(LPTR, sizeof(ANIMATE));
  360. if (!p)
  361. return 0; // WM_NCCREATE failure is 0
  362. // note, zero init memory from above
  363. p->hwnd = hwnd;
  364. p->hwndP = lpcs->hwndParent;
  365. p->id = PtrToUlong(lpcs->hMenu); // really was an int
  366. p->fFirstPaint = TRUE;
  367. p->style = lpcs->style;
  368. // Must do this before SetWindowBits because that will recursively
  369. // cause us to receive WM_STYLECHANGED and possibly even WM_SIZE
  370. // messages.
  371. #ifdef WIN32
  372. InitializeCriticalSection(&p->crit);
  373. #endif
  374. SetWindowPtr(hwnd, 0, p);
  375. //
  376. // UnMirror the control, if it is mirrored. We shouldn't mirror
  377. // a movie! [samera]
  378. //
  379. SetWindowBits(hwnd, GWL_EXSTYLE, RTL_MIRRORED_WINDOW, 0);
  380. goto DoDefault;
  381. case WM_CLOSE:
  382. Animate_Stop(hwnd);
  383. goto DoDefault;
  384. case WM_NCHITTEST:
  385. return HTTRANSPARENT;
  386. case WM_GETOBJECT:
  387. if( lParam == OBJID_QUERYCLASSNAMEIDX )
  388. return MSAA_CLASSNAMEIDX_ANIMATE;
  389. goto DoDefault;
  390. }
  391. // Okay, now the messages that cannot handle p == NULL.
  392. // We check p == NULL once and for all.
  393. if (!p) goto DoDefault;
  394. switch (msg) {
  395. case WM_DESTROY:
  396. Animate_Close(hwnd);
  397. DeleteCriticalSection(&p->crit);
  398. LocalFree((HLOCAL)p);
  399. SetWindowPtr(hwnd, 0, 0);
  400. break;
  401. case WM_ERASEBKGND:
  402. HandleErase(p, (HDC)wParam);
  403. return(1);
  404. case WM_PAINT:
  405. HandleFirstPaint(p);
  406. hdc = BeginPaint(hwnd, &ps);
  407. HandlePaint(p, hdc);
  408. EndPaint(hwnd, &ps);
  409. return 0;
  410. case WM_PRINTCLIENT:
  411. HandlePrint(p, (HDC)wParam);
  412. return 0;
  413. case WM_STYLECHANGED:
  414. Ani_OnStyleChanged(p, wParam, (LPSTYLESTRUCT)lParam);
  415. return 0L;
  416. case WM_SIZE:
  417. if (p->style & ACS_CENTER)
  418. {
  419. OffsetRect(&p->rc, (LOWORD(lParam)-RectWid(p->rc))/2-p->rc.left,
  420. (HIWORD(lParam)-RectHgt(p->rc))/2-p->rc.top);
  421. InvalidateRect(hwnd, NULL, TRUE);
  422. }
  423. break;
  424. case WM_TIMER:
  425. {
  426. int result;
  427. result = HandleTick(p);
  428. if (!result)
  429. {
  430. HandleStop(p);
  431. }
  432. else if (result < 0)
  433. {
  434. p->PaintThread = (HANDLE)SetTimer(p->hwnd, 42, (UINT)p->Rate+4000, NULL);
  435. } else
  436. {
  437. p->PaintThread = (HANDLE)SetTimer(p->hwnd, 42, (UINT)p->Rate, NULL);
  438. }
  439. }
  440. break;
  441. #ifdef UNICODE
  442. case ACM_OPENA:
  443. {
  444. WCHAR szFileNameW[MAX_PATH];
  445. LPTSTR lpFileName = szFileNameW;
  446. if (!IS_INTRESOURCE(lParam)) {
  447. MultiByteToWideChar (CP_ACP, 0, (LPCSTR)lParam, -1,
  448. szFileNameW, MAX_PATH);
  449. } else {
  450. lpFileName = (LPTSTR) lParam;
  451. }
  452. return HandleOpen(p, (HINSTANCE)wParam, lpFileName, 0);
  453. }
  454. #endif
  455. case ACM_OPEN:
  456. return HandleOpen(p, (HINSTANCE)wParam, (LPCTSTR)lParam, 0);
  457. case ACM_STOP:
  458. return HandleStop(p);
  459. case ACM_PLAY:
  460. return HandlePlay(p, (int)(SHORT)LOWORD(lParam), (int)(SHORT)HIWORD(lParam), (int)wParam);
  461. }
  462. DoDefault:
  463. return DefWindowProc(hwnd, msg, wParam, lParam);
  464. }