Leaked source code of windows server 2003
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.

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