PageRenderTime 59ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/Miranda IM - CK Release/Miranda/Plugins/Modernb/src/modern_aniavatars.cpp

http://miranda-dev.googlecode.com/
C++ | 1315 lines | 1131 code | 86 blank | 98 comment | 167 complexity | fe5d6b738a9581276d18c16e7a4bf7ea MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception, LGPL-3.0, AGPL-1.0, BSD-3-Clause, LGPL-2.1
  1. /**************************************************************************\
  2. Miranda IM: the free IM client for Microsoft* Windows*
  3. Copyright 2000-2008 Miranda ICQ/IM project,
  4. all portions of this codebase are copyrighted to the people
  5. listed in contributors.txt.
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. ****************************************************************************
  18. Created: Mar 9, 2007
  19. Author: Artem Shpynov aka FYR: ashpynov@gmail.com
  20. ****************************************************************************
  21. File contains implementation of animated avatars in contact list
  22. \**************************************************************************/
  23. #include "../hdr/modern_commonheaders.h"
  24. #define IMMEDIATE_DRAW (!AniAva.bSeparateWindow)
  25. void GDIPlus_ExtractAnimatedGIF(TCHAR * szName, int width, int height, HBITMAP * pBmp, int ** pframesDelay, int * pframesCount, SIZE * sizeAvatar);
  26. BOOL GDIPlus_IsAnimatedGIF(TCHAR * szName);
  27. /* Next is module */
  28. #define ANIAVAWINDOWCLASS _T("MirandaModernAniAvatar")
  29. #define aacheck if (!AniAva.bModuleStarted) return
  30. #define aalock EnterCriticalSection(&AniAva.CS)
  31. #define aaunlock LeaveCriticalSection(&AniAva.CS)
  32. #define AAO_HAS_BORDER 0x01
  33. #define AAO_ROUND_CORNERS 0x02
  34. #define AAO_HAS_OVERLAY 0x04
  35. #define AAO_OPAQUE 0x08
  36. //messages
  37. enum {
  38. AAM_FIRST = WM_USER,
  39. AAM_SETAVATAR , //sync WPARAM: TCHAR * filename, LPARAM: SIZE * size, RESULT: actual size
  40. AAM_SETPOSITION, //async LPARAM: pointer to set pos info - the handler will empty it, RESULT: 0
  41. AAM_REDRAW, //async
  42. AAM_STOP, //async stops animation, timer, hide window - prepeare for deleting
  43. AAM_PAUSE, //sync keep timer and window, but do not process painting -need before graphics change
  44. AAM_RESUME, //async remobe previous flag. repaints if required
  45. AAM_REMOVEAVATAR, //sync WPARAM: if y more then wParam, LPARAM: shift up to lParam( remove if values is same)
  46. AAM_SETPARENT, //async WPARAM: handle of new parent window
  47. AAM_SELFDESTROY, //sync
  48. AAM_RENDER, //sync
  49. AAM_LAST,
  50. };
  51. typedef struct _tagAniAva_Object
  52. {
  53. HANDLE hContact;
  54. HWND hWindow;
  55. BOOL bInvalidPos;
  56. BOOL bToBeDeleted;
  57. DWORD dwAvatarUniqId;
  58. SIZE ObjectSize;
  59. } ANIAVA_OBJECT;
  60. typedef struct _tagAniAva_Info
  61. {
  62. DWORD dwAvatarUniqId;
  63. TCHAR * tcsFilename;
  64. int nRefCount;
  65. int nStripTop;
  66. int nFrameCount;
  67. int * pFrameDelays;
  68. SIZE FrameSize;
  69. } ANIAVA_INFO;
  70. typedef struct _tagAniAva_WindowInfo
  71. {
  72. HWND hWindow;
  73. RECT rcPos;
  74. SIZE sizeAvatar;
  75. BOOL StopTimer;
  76. int TimerId;
  77. int nFramesCount;
  78. int * delaysInterval;
  79. int currentFrame;
  80. POINT ptFromPoint;
  81. BOOL bPlaying;
  82. int overlayIconIdx;
  83. BYTE bAlpha;
  84. BOOL bOrderTop;
  85. BOOL bPaused; // was request do not draw
  86. BOOL bPended; // till do not draw - was painting - need to be repaint
  87. } ANIAVA_WINDOWINFO;
  88. typedef struct _tagAniAva_PosInfo
  89. {
  90. RECT rcPos;
  91. int idxOverlay;
  92. BYTE bAlpha;
  93. } ANIAVA_POSINFO;
  94. typedef struct _tagAniAvaSyncCallItem
  95. {
  96. WPARAM wParam;
  97. LPARAM lParam;
  98. INT_PTR nResult;
  99. HANDLE hDoneEvent;
  100. PSYNCCALLBACKPROC pfnProc;
  101. } ANIAVA_SYNCCALLITEM;
  102. typedef struct _tagAniAvatarImageInfo
  103. {
  104. POINT ptImagePos;
  105. int nFramesCount;
  106. int * pFrameDelays;
  107. SIZE szSize;
  108. } ANIAVATARIMAGEINFO;
  109. //main structure to handle global
  110. typedef struct _tagAniAva
  111. {
  112. //protection
  113. BOOL bModuleStarted;
  114. CRITICAL_SECTION CS;
  115. //options
  116. BYTE bFlags; // 0x1 has border, 0x2 has round corners, 0x4 has overlay, 0x8 background color
  117. COLORREF borderColor;
  118. BYTE cornerRadius;
  119. COLORREF bkgColor;
  120. HIMAGELIST overlayIconImageList;
  121. //animations
  122. HDC hAniAvaDC;
  123. HBITMAP hAniAvaBitmap;
  124. HBITMAP hAniAvaOldBitmap;
  125. int width;
  126. int height;
  127. SortedList * AniAvatarList;
  128. DWORD AnimationThreadID;
  129. HANDLE AnimationThreadHandle;
  130. HANDLE hExitEvent;
  131. //Objects
  132. SortedList * Objects;
  133. BOOL bSeparateWindow;
  134. } ANIAVA;
  135. //module static declarations
  136. static void __AniAva_DebugRenderStrip();
  137. static void _AniAva_DestroyAvatarWindow( HWND hwnd);
  138. static void _AniAva_Clear_ANIAVA_WINDOWINFO(ANIAVA_WINDOWINFO * pavwi );
  139. static void _AniAva_RenderAvatar(ANIAVA_WINDOWINFO * dat, HDC hdcParent = NULL, RECT * rcInParent = NULL );
  140. static void _AniAva_PausePainting();
  141. static void _AniAva_ResumePainting();
  142. static void _AniAva_LoadOptions();
  143. static void _AniAva_ReduceAvatarImages(int startY, int dY, BOOL bDestroyWindow);
  144. static void _AniAva_AnimationTreadProc(HANDLE hExitEvent);
  145. static void _AniAva_RemoveAniAvaDC(ANIAVA * pAniAva);
  146. static void _AniAva_RealRemoveAvatar(DWORD UniqueID);
  147. static int _AniAva_LoadAvatarFromImage(TCHAR * szFileName, int width, int height, ANIAVATARIMAGEINFO * pRetAII);
  148. static int _AniAva_SortAvatarInfo(void * first, void * last);
  149. static BOOL _AniAva_GetAvatarImageInfo(DWORD dwAvatarUniqId, ANIAVATARIMAGEINFO * avii);
  150. static HWND _AniAva_CreateAvatarWindowSync(TCHAR *szFileName);
  151. static LRESULT CALLBACK _AniAva_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  152. //module variables
  153. static ANIAVA AniAva={0};
  154. /// IMPLEMENTATION
  155. int _AniAva_OnModulesUnload(WPARAM wParam,LPARAM lParam)
  156. {
  157. SetEvent(AniAva.hExitEvent);
  158. return 0;
  159. }
  160. // Init AniAva module
  161. int AniAva_InitModule()
  162. {
  163. memset(&AniAva,0,sizeof(AniAva));
  164. if (g_CluiData.fGDIPlusFail) return 0;
  165. if (!( ModernGetSettingByte(NULL,"CList","AvatarsAnimated",(ServiceExists(MS_AV_GETAVATARBITMAP)&&!g_CluiData.fGDIPlusFail))
  166. && ModernGetSettingByte(NULL,"CList","AvatarsShow",SETTINGS_SHOWAVATARS_DEFAULT) ) ) return 0;
  167. {
  168. WNDCLASSEX wc;
  169. ZeroMemory(&wc, sizeof(wc));
  170. wc.cbSize = sizeof(wc);
  171. wc.lpszClassName = ANIAVAWINDOWCLASS;
  172. wc.lpfnWndProc = _AniAva_WndProc;
  173. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  174. wc.cbWndExtra = sizeof(ANIAVA_WINDOWINFO*);
  175. wc.hbrBackground = 0;
  176. wc.style = CS_GLOBALCLASS;
  177. RegisterClassEx(&wc);
  178. }
  179. InitializeCriticalSection(&AniAva.CS);
  180. AniAva.Objects=li.List_Create(0,2);
  181. AniAva.AniAvatarList=li.List_Create(0,1);
  182. AniAva.AniAvatarList->sortFunc=_AniAva_SortAvatarInfo;
  183. AniAva.bModuleStarted=TRUE;
  184. AniAva.hExitEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
  185. AniAva.AnimationThreadID=(DWORD)mir_forkthread(_AniAva_AnimationTreadProc, (void*)AniAva.hExitEvent);
  186. ModernHookEvent(ME_SYSTEM_PRESHUTDOWN, _AniAva_OnModulesUnload);
  187. _AniAva_LoadOptions();
  188. return 1;
  189. }
  190. // Unload AniAva module
  191. int AniAva_UnloadModule()
  192. {
  193. aacheck 0;
  194. aalock;
  195. {
  196. int i;
  197. AniAva.bModuleStarted=FALSE;
  198. for (i=0; i<AniAva.Objects->realCount; i++)
  199. {
  200. if (AniAva.Objects->items[i])
  201. {
  202. _AniAva_DestroyAvatarWindow(((ANIAVA_OBJECT*)AniAva.Objects->items[i])->hWindow);
  203. }
  204. mir_free(AniAva.Objects->items[i]);
  205. }
  206. li.List_Destroy(AniAva.Objects);
  207. mir_free(AniAva.Objects);
  208. for (i=0; i<AniAva.AniAvatarList->realCount; i++)
  209. {
  210. ANIAVA_INFO * aai=(ANIAVA_INFO *)AniAva.AniAvatarList->items[i];
  211. if (aai->tcsFilename) mir_free(aai->tcsFilename);
  212. if (aai->pFrameDelays) free(aai->pFrameDelays);
  213. mir_free(aai);
  214. }
  215. li.List_Destroy(AniAva.AniAvatarList);
  216. mir_free(AniAva.AniAvatarList);
  217. _AniAva_RemoveAniAvaDC(&AniAva);
  218. SetEvent(AniAva.hExitEvent);
  219. CloseHandle(AniAva.hExitEvent);
  220. }
  221. aaunlock;
  222. DeleteCriticalSection(&AniAva.CS);
  223. return 1;
  224. }
  225. // Update options
  226. int AniAva_UpdateOptions()
  227. {
  228. BOOL bReloadAvatars=FALSE;
  229. BOOL bBeEnabled=(!g_CluiData.fGDIPlusFail
  230. && ModernGetSettingByte(NULL,"CList","AvatarsAnimated",(ServiceExists(MS_AV_GETAVATARBITMAP)&&!g_CluiData.fGDIPlusFail))
  231. && ModernGetSettingByte(NULL,"CList","AvatarsShow",SETTINGS_SHOWAVATARS_DEFAULT) );
  232. if (bBeEnabled && !AniAva.bModuleStarted)
  233. {
  234. AniAva_InitModule();
  235. bReloadAvatars=TRUE;
  236. }
  237. else if (!bBeEnabled && AniAva.bModuleStarted)
  238. {
  239. AniAva_UnloadModule();
  240. bReloadAvatars=TRUE;
  241. }
  242. BOOL oldSeparate = AniAva.bSeparateWindow;
  243. _AniAva_LoadOptions();
  244. if ( oldSeparate != AniAva.bSeparateWindow )
  245. {
  246. AniAva_InvalidateAvatarPositions(NULL);
  247. AniAva_RemoveInvalidatedAvatars();
  248. }
  249. if ( bReloadAvatars ) PostMessage(pcli->hwndContactTree,INTM_AVATARCHANGED,0,0);
  250. else AniAva_RedrawAllAvatars(TRUE);
  251. return 0;
  252. }
  253. // adds avatars to be displayed
  254. int AniAva_AddAvatar(HANDLE hContact, TCHAR * szFilename, int width, int heigth)
  255. {
  256. int res=0;
  257. aacheck 0;
  258. if (!GDIPlus_IsAnimatedGIF(szFilename))
  259. return 0;
  260. aalock;
  261. {
  262. //first try to find window for contact avatar
  263. HWND hwnd=NULL;
  264. int i;
  265. ANIAVA_OBJECT * pavi;
  266. ANIAVATARIMAGEINFO avii={0};
  267. SIZE szAva={ width, heigth };
  268. for (i=0; i<AniAva.Objects->realCount; i++)
  269. {
  270. pavi=(ANIAVA_OBJECT *)AniAva.Objects->items[i];
  271. if (pavi->hContact==hContact)
  272. {
  273. if (pavi->ObjectSize.cx==width && pavi->ObjectSize.cy==heigth)
  274. {
  275. hwnd=pavi->hWindow;
  276. break;
  277. }
  278. else
  279. {
  280. _AniAva_DestroyAvatarWindow(pavi->hWindow);
  281. pavi->hWindow=NULL;
  282. _AniAva_RealRemoveAvatar(pavi->dwAvatarUniqId);
  283. pavi->dwAvatarUniqId=0;
  284. break;
  285. }
  286. }
  287. }
  288. if (i==AniAva.Objects->realCount)
  289. {
  290. pavi = (ANIAVA_OBJECT *) mir_calloc( sizeof(ANIAVA_OBJECT) );
  291. pavi->hWindow = NULL;
  292. pavi->hContact = hContact;
  293. pavi->bInvalidPos = 0;
  294. li.List_Insert( AniAva.Objects, pavi, AniAva.Objects->realCount);
  295. }
  296. //change avatar
  297. pavi->bToBeDeleted=FALSE;
  298. pavi->bInvalidPos = 0;
  299. // now CreateAvatar
  300. if (pavi->dwAvatarUniqId)
  301. _AniAva_GetAvatarImageInfo(pavi->dwAvatarUniqId,&avii);
  302. else
  303. pavi->dwAvatarUniqId=_AniAva_LoadAvatarFromImage(szFilename, width, heigth, &avii);
  304. if (hwnd)
  305. SendMessage(hwnd, AAM_SETAVATAR, (WPARAM)&avii, (LPARAM) 0);
  306. pavi->ObjectSize=avii.szSize;
  307. res=MAKELONG(avii.szSize.cx, avii.szSize.cy);
  308. }
  309. aaunlock;
  310. return res;
  311. }
  312. // call windows to set they parent in order to ensure valid zorder
  313. void AniAva_UpdateParent()
  314. {
  315. aacheck;
  316. aalock;
  317. {
  318. int i;
  319. HWND parent = fnGetAncestor(pcli->hwndContactList,GA_PARENT);
  320. for (i=0; i<AniAva.Objects->realCount; i++)
  321. {
  322. ANIAVA_OBJECT * pai=(ANIAVA_OBJECT *)AniAva.Objects->items[i];
  323. SendMessage(pai->hWindow, AAM_SETPARENT, (WPARAM)parent,0);
  324. }
  325. }
  326. aaunlock;
  327. }
  328. ANIAVA_OBJECT * FindAvatarByContact( HANDLE hContact )
  329. {
  330. for ( int i=0; i<AniAva.Objects->realCount; i++)
  331. {
  332. ANIAVA_OBJECT * pai=((ANIAVA_OBJECT *)AniAva.Objects->items[i]);
  333. if (pai->hContact==hContact)
  334. return pai;
  335. }
  336. return NULL;
  337. }
  338. int AniAva_RenderAvatar( HANDLE hContact, HDC hdcMem, RECT * rc )
  339. {
  340. aacheck 0;
  341. aalock;
  342. ANIAVA_OBJECT * pai=FindAvatarByContact( hContact );
  343. if ( pai )
  344. SendMessage(pai->hWindow, AAM_RENDER, (WPARAM)hdcMem, (LPARAM) rc);
  345. aaunlock;
  346. return 0;
  347. }
  348. // update avatars pos
  349. int AniAva_SetAvatarPos(HANDLE hContact, RECT * rc, int overlayIdx, BYTE bAlpha)
  350. {
  351. aacheck 0;
  352. aalock;
  353. if (AniAva.CS.LockCount>0)
  354. {
  355. aaunlock;
  356. return 0;
  357. }
  358. {
  359. ANIAVA_OBJECT * pai=FindAvatarByContact( hContact );
  360. if ( pai )
  361. {
  362. ANIAVA_POSINFO * api=(ANIAVA_POSINFO *)malloc(sizeof(ANIAVA_POSINFO));
  363. if (!pai->hWindow)
  364. {
  365. HWND hwnd;
  366. HWND parent;
  367. ANIAVATARIMAGEINFO avii={0};
  368. //not found -> create window
  369. char szName[150] = "AniAvaWnd_";
  370. TCHAR * tszName;
  371. _itoa((int)hContact,szName+10,16);
  372. #ifdef _DEBUG
  373. {
  374. char *temp;
  375. PDNCE pdnce=(PDNCE)pcli->pfnGetCacheEntry(hContact);
  376. if ( pdnce && pdnce->m_cache_tcsName )
  377. {
  378. temp=mir_t2a(pdnce->m_cache_tcsName);
  379. strcat(szName,"_");
  380. strcat(szName,temp);
  381. mir_free(temp);
  382. }
  383. }
  384. #endif
  385. tszName = mir_a2t( szName );
  386. hwnd=_AniAva_CreateAvatarWindowSync(tszName);
  387. mir_free( tszName );
  388. parent=fnGetAncestor(pcli->hwndContactList,GA_PARENT);
  389. pai->hWindow=hwnd;
  390. SendMessage(hwnd,AAM_SETPARENT,(WPARAM)parent,0);
  391. if (_AniAva_GetAvatarImageInfo(pai->dwAvatarUniqId,&avii))
  392. SendMessage(pai->hWindow, AAM_SETAVATAR, (WPARAM)&avii, (LPARAM) 0);
  393. }
  394. api->bAlpha=bAlpha;
  395. api->idxOverlay=overlayIdx;
  396. api->rcPos=*rc;
  397. SendNotifyMessage(pai->hWindow, AAM_SETPOSITION, (WPARAM)0, (LPARAM) api);
  398. // the AAM_SETPOSITION is responsible to destroy memory under api
  399. pai->bInvalidPos=FALSE;
  400. pai->bToBeDeleted=FALSE;
  401. }
  402. }
  403. aaunlock;
  404. return 1;
  405. }
  406. // remove avatar
  407. int AniAva_RemoveAvatar(HANDLE hContact)
  408. {
  409. aacheck 0;
  410. aalock;
  411. {
  412. int i;
  413. for (i=0; i<AniAva.Objects->realCount; i++)
  414. {
  415. ANIAVA_OBJECT * pai=(ANIAVA_OBJECT *)AniAva.Objects->items[i];
  416. if (pai->hContact == hContact)
  417. {
  418. pai->bToBeDeleted=TRUE;
  419. break;
  420. }
  421. }
  422. }
  423. aaunlock;
  424. return 1;
  425. }
  426. // reset positions of avatars to be drawn (still be painted at same place)
  427. int AniAva_InvalidateAvatarPositions(HANDLE hContact)
  428. {
  429. int i;
  430. aacheck 0;
  431. aalock;
  432. for (i=0; i<AniAva.Objects->realCount; i++)
  433. {
  434. ANIAVA_OBJECT * pai=(ANIAVA_OBJECT *)AniAva.Objects->items[i];
  435. if (pai->hContact==hContact || !hContact)
  436. {
  437. pai->bInvalidPos++;
  438. if (hContact) break;
  439. }
  440. }
  441. aaunlock;
  442. return 1;
  443. }
  444. // all avatars without validated position will be stop painted and probably removed
  445. int AniAva_RemoveInvalidatedAvatars()
  446. {
  447. BOOL keepAvatar=FALSE;
  448. aacheck 0;
  449. aalock;
  450. {
  451. int i;
  452. for (i=0; i<AniAva.Objects->realCount; i++)
  453. {
  454. ANIAVA_OBJECT * pai=(ANIAVA_OBJECT *)AniAva.Objects->items[i];
  455. if (pai->hWindow && (pai->bInvalidPos) )
  456. {
  457. SendMessage(pai->hWindow,AAM_STOP,0,0);
  458. if (pai->bInvalidPos)//>3)
  459. {
  460. //keepAvatar=TRUE;
  461. //pai->bToBeDeleted=TRUE;
  462. pai->bInvalidPos=0;
  463. _AniAva_DestroyAvatarWindow(pai->hWindow);
  464. pai->hWindow=NULL;
  465. }
  466. }
  467. if (pai->bToBeDeleted)
  468. {
  469. if (pai->hWindow) _AniAva_DestroyAvatarWindow(pai->hWindow);
  470. pai->hWindow=NULL;
  471. if (!keepAvatar) _AniAva_RealRemoveAvatar(pai->dwAvatarUniqId);
  472. mir_free(pai);
  473. li.List_Remove(AniAva.Objects,i);
  474. i--;
  475. }
  476. }
  477. }
  478. aaunlock;
  479. return 1;
  480. }
  481. // repaint all avatars at positions (eg on main window movement)
  482. int AniAva_RedrawAllAvatars(BOOL updateZOrder)
  483. {
  484. int i;
  485. aacheck 0;
  486. aalock;
  487. updateZOrder=1;
  488. for (i=0; i<AniAva.Objects->realCount; i++)
  489. {
  490. ANIAVA_OBJECT * pai=(ANIAVA_OBJECT *)AniAva.Objects->items[i];
  491. if (updateZOrder)
  492. SendMessage(pai->hWindow,AAM_REDRAW,(WPARAM)updateZOrder,0);
  493. else
  494. SendNotifyMessage(pai->hWindow,AAM_REDRAW,(WPARAM)updateZOrder,0);
  495. }
  496. aaunlock;
  497. return 1;
  498. }
  499. //Static procedures
  500. static void CALLBACK _AniAva_SyncCallerUserAPCProc(DWORD_PTR dwParam)
  501. {
  502. ANIAVA_SYNCCALLITEM* item = (ANIAVA_SYNCCALLITEM*) dwParam;
  503. item->nResult = item->pfnProc(item->wParam, item->lParam);
  504. SetEvent(item->hDoneEvent);
  505. }
  506. static INT_PTR _AniAva_CreateAvatarWindowSync_Worker(WPARAM tszName, LPARAM lParam)
  507. {
  508. HWND hwnd=CreateWindowEx( WS_EX_TOPMOST | WS_EX_TRANSPARENT | WS_EX_NOPARENTNOTIFY,ANIAVAWINDOWCLASS,(TCHAR*)tszName,WS_POPUP,
  509. 0,0,1,1,pcli->hwndContactList, NULL, pcli->hInst, NULL );
  510. return (INT_PTR)hwnd;
  511. }
  512. static HWND _AniAva_CreateAvatarWindowSync(TCHAR *szFileName)
  513. {
  514. ANIAVA_SYNCCALLITEM item={0};
  515. int res=0;
  516. if (!AniAva.AnimationThreadHandle) return NULL;
  517. if (AniAva.AnimationThreadID==0) return NULL;
  518. item.wParam = (WPARAM) szFileName;
  519. item.lParam = 0;
  520. item.pfnProc = _AniAva_CreateAvatarWindowSync_Worker;
  521. item.hDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  522. if (GetCurrentThreadId()!=AniAva.AnimationThreadID)
  523. QueueUserAPC(_AniAva_SyncCallerUserAPCProc, AniAva.AnimationThreadHandle, (DWORD_PTR) &item);
  524. else
  525. _AniAva_SyncCallerUserAPCProc((DWORD_PTR) &item);
  526. WaitForSingleObject(item.hDoneEvent, INFINITE);
  527. CloseHandle(item.hDoneEvent);
  528. return (HWND)item.nResult;
  529. }
  530. static void _AniAva_RealRemoveAvatar(DWORD UniqueID)
  531. {
  532. int j,k;
  533. for (j=0; j<AniAva.AniAvatarList->realCount; j++)
  534. {
  535. ANIAVA_INFO * aai=(ANIAVA_INFO *) AniAva.AniAvatarList->items[j];
  536. if (aai->dwAvatarUniqId==UniqueID)
  537. {
  538. aai->nRefCount--;
  539. if (aai->nRefCount==0)
  540. {
  541. _AniAva_PausePainting();
  542. #ifdef _DEBUG
  543. __AniAva_DebugRenderStrip();
  544. #endif
  545. if (aai->tcsFilename) mir_free(aai->tcsFilename);
  546. if (aai->pFrameDelays) free(aai->pFrameDelays);
  547. _AniAva_ReduceAvatarImages(aai->nStripTop,aai->FrameSize.cx*aai->nFrameCount, FALSE);
  548. for (k=0; k<AniAva.AniAvatarList->realCount; k++)
  549. if (k!=j) {
  550. ANIAVA_INFO * taai=(ANIAVA_INFO *) AniAva.AniAvatarList->items[k];
  551. if (taai->nStripTop>aai->nStripTop)
  552. taai->nStripTop-=aai->FrameSize.cx*aai->nFrameCount;
  553. }
  554. if (AniAva.AniAvatarList->realCount>0)
  555. {
  556. //lets create hNewDC
  557. HDC hNewDC;
  558. HBITMAP hNewBmp, hNewOldBmp;
  559. int newWidth=AniAva.width-aai->FrameSize.cx*aai->nFrameCount;
  560. int newHeight=0;
  561. int i;
  562. for (i=0; i<AniAva.AniAvatarList->realCount; i++)
  563. if (i!=j)
  564. {
  565. newHeight=max(newHeight,((ANIAVA_INFO *) AniAva.AniAvatarList->items[i])->FrameSize.cy);
  566. }
  567. hNewDC=CreateCompatibleDC(NULL);
  568. hNewBmp=ske_CreateDIB32(newWidth,newHeight);
  569. hNewOldBmp=(HBITMAP)SelectObject(hNewDC,hNewBmp);
  570. // copy from old and from new strip
  571. if (aai->nStripTop>0)
  572. BitBlt(hNewDC,0,0,aai->nStripTop,newHeight,AniAva.hAniAvaDC,0,0, SRCCOPY);
  573. if (aai->nStripTop+aai->FrameSize.cx*aai->nFrameCount<AniAva.width)
  574. BitBlt(hNewDC,aai->nStripTop,0,AniAva.width-(aai->nStripTop+aai->FrameSize.cx*aai->nFrameCount),newHeight,AniAva.hAniAvaDC,aai->nStripTop+aai->FrameSize.cx*aai->nFrameCount,0, SRCCOPY);
  575. _AniAva_RemoveAniAvaDC(&AniAva);
  576. AniAva.hAniAvaDC =hNewDC;
  577. AniAva.hAniAvaBitmap =hNewBmp;
  578. AniAva.hAniAvaOldBitmap =hNewOldBmp;
  579. AniAva.width =newWidth;
  580. AniAva.height =newHeight;
  581. }
  582. else
  583. {
  584. _AniAva_RemoveAniAvaDC(&AniAva);
  585. }
  586. #ifdef _DEBUG
  587. __AniAva_DebugRenderStrip();
  588. #endif
  589. li.List_Remove(AniAva.AniAvatarList, j);
  590. mir_free(aai);
  591. _AniAva_ResumePainting();
  592. break;
  593. }
  594. }
  595. }
  596. }
  597. static void _AniAva_RemoveAniAvaDC(ANIAVA * pAniAva)
  598. {
  599. if(pAniAva->hAniAvaDC)
  600. {
  601. SelectObject(pAniAva->hAniAvaDC, pAniAva->hAniAvaOldBitmap);
  602. DeleteObject(pAniAva->hAniAvaBitmap);
  603. DeleteDC(pAniAva->hAniAvaDC);
  604. pAniAva->hAniAvaDC=NULL;
  605. pAniAva->height=0;
  606. pAniAva->width=0;
  607. pAniAva->hAniAvaBitmap=NULL;
  608. }
  609. };
  610. static void _AniAva_DestroyAvatarWindow( HWND hwnd)
  611. {
  612. SendMessage(hwnd,AAM_SELFDESTROY,0,0);
  613. }
  614. static int _AniAva_LoadAvatarFromImage(TCHAR * szFileName, int width, int height, ANIAVATARIMAGEINFO * pRetAII)
  615. {
  616. ANIAVA_INFO aai={0};
  617. ANIAVA_INFO * paai=NULL;
  618. BOOL fNeedInsertToList=FALSE;
  619. int idx=0;
  620. aai.tcsFilename=szFileName;
  621. aai.FrameSize.cx=width;
  622. aai.FrameSize.cy=height;
  623. if (!li.List_GetIndex(AniAva.AniAvatarList,(void*)&aai,&idx)) idx=-1;
  624. if (idx==-1) //item not present in list
  625. {
  626. HBITMAP hBitmap=NULL;
  627. HDC hTempDC;
  628. HBITMAP hOldBitmap;
  629. HDC hNewDC;
  630. HBITMAP hNewBmp;
  631. HBITMAP hNewOldBmp;
  632. int newWidth;
  633. int newHeight;
  634. paai=(ANIAVA_INFO *)mir_calloc(sizeof(ANIAVA_INFO));
  635. paai->tcsFilename=mir_tstrdup(szFileName);
  636. paai->dwAvatarUniqId=rand();
  637. fNeedInsertToList=TRUE;
  638. //get image strip
  639. GDIPlus_ExtractAnimatedGIF(szFileName, width, height, &hBitmap, &(paai->pFrameDelays), &(paai->nFrameCount), &(paai->FrameSize));
  640. //copy image to temp DC
  641. hTempDC=CreateCompatibleDC(NULL);
  642. hOldBitmap=(HBITMAP)SelectObject(hTempDC,hBitmap);
  643. //lets create hNewDC
  644. /*
  645. newWidth=max(paai->FrameSize.cx*paai->nFrameCount,AniAva.width);
  646. newHeight=AniAva.height+paai->FrameSize.cy;
  647. */
  648. newWidth=AniAva.width+paai->FrameSize.cx*paai->nFrameCount;
  649. newHeight=max(paai->FrameSize.cy,AniAva.height);
  650. hNewDC=CreateCompatibleDC(NULL);
  651. hNewBmp=ske_CreateDIB32(newWidth,newHeight);
  652. hNewOldBmp=(HBITMAP)SelectObject(hNewDC,hNewBmp);
  653. _AniAva_PausePainting();
  654. GdiFlush();
  655. // copy from old and from new strip
  656. BitBlt(hNewDC,0,0,AniAva.width,AniAva.height,AniAva.hAniAvaDC,0,0, SRCCOPY);
  657. BitBlt(hNewDC,AniAva.width,0,paai->FrameSize.cx*paai->nFrameCount,paai->FrameSize.cy,hTempDC,0,0, SRCCOPY);
  658. paai->nStripTop=AniAva.width;
  659. GdiFlush();
  660. //remove temp DC
  661. SelectObject(hTempDC,hOldBitmap);
  662. DeleteObject(hNewBmp);
  663. DeleteDC(hTempDC);
  664. DeleteObject(hBitmap);
  665. //delete old
  666. _AniAva_RemoveAniAvaDC(&AniAva);
  667. //setNewDC;
  668. AniAva.hAniAvaDC =hNewDC;
  669. AniAva.hAniAvaBitmap =hNewBmp;
  670. AniAva.hAniAvaOldBitmap =hNewOldBmp;
  671. AniAva.width =newWidth;
  672. AniAva.height =newHeight;
  673. GdiFlush();
  674. _AniAva_ResumePainting();
  675. }
  676. else
  677. {
  678. paai=(ANIAVA_INFO *)AniAva.AniAvatarList->items[idx];
  679. }
  680. if (paai)
  681. {
  682. paai->nRefCount++;
  683. pRetAII->nFramesCount=paai->nFrameCount;
  684. pRetAII->pFrameDelays=paai->pFrameDelays;
  685. pRetAII->ptImagePos.x=paai->nStripTop;
  686. pRetAII->ptImagePos.y=0;
  687. pRetAII->szSize=paai->FrameSize;
  688. if (fNeedInsertToList)
  689. {
  690. //add to list
  691. int idx=AniAva.AniAvatarList->realCount;
  692. li.List_GetIndex(AniAva.AniAvatarList, paai,&idx);
  693. li.List_Insert(AniAva.AniAvatarList, (void*)paai, idx);
  694. }
  695. return paai->dwAvatarUniqId;
  696. }
  697. return 0;
  698. }
  699. static BOOL _AniAva_GetAvatarImageInfo(DWORD dwAvatarUniqId, ANIAVATARIMAGEINFO * avii)
  700. {
  701. int j;
  702. BOOL res=FALSE;
  703. for (j=0; j<AniAva.AniAvatarList->realCount; j++)
  704. {
  705. ANIAVA_INFO * aai=(ANIAVA_INFO *) AniAva.AniAvatarList->items[j];
  706. if (aai->dwAvatarUniqId==dwAvatarUniqId)
  707. {
  708. avii->nFramesCount=aai->nFrameCount;
  709. avii->pFrameDelays=aai->pFrameDelays;
  710. avii->ptImagePos.x=aai->nStripTop;
  711. avii->ptImagePos.y=0;
  712. avii->szSize=aai->FrameSize;
  713. res=TRUE;
  714. break;
  715. }
  716. }
  717. return res;
  718. }
  719. static void _AniAva_Clear_ANIAVA_WINDOWINFO(ANIAVA_WINDOWINFO * pavwi )
  720. {
  721. pavwi->delaysInterval=NULL;
  722. pavwi->nFramesCount=0;
  723. KillTimer(pavwi->hWindow,2);
  724. pavwi->bPlaying =FALSE;
  725. pavwi->TimerId=0;
  726. }
  727. static void __AniAva_DebugRenderStrip()
  728. {
  729. return;
  730. #ifdef _DEBUG
  731. {
  732. HDC hDC_debug=GetDC(NULL);
  733. BitBlt(hDC_debug,0,0,AniAva.width, AniAva.height,AniAva.hAniAvaDC,0,0,SRCCOPY);
  734. DeleteDC(hDC_debug);
  735. }
  736. #endif
  737. }
  738. static void _AniAva_RenderAvatar(ANIAVA_WINDOWINFO * dat, HDC hdcParent /* = NULL*/, RECT * rcInParent /* = NULL */ )
  739. {
  740. if (dat->bPaused>0) { dat->bPended=TRUE; return; }
  741. else dat->bPended=FALSE;
  742. if ( IMMEDIATE_DRAW && hdcParent == NULL ) return;
  743. GdiFlush();
  744. #ifdef _DEBUG
  745. __AniAva_DebugRenderStrip();
  746. #endif
  747. if (dat->bPlaying && IsWindowVisible(dat->hWindow))
  748. {
  749. POINT ptWnd={0};
  750. SIZE szWnd={dat->rcPos.right-dat->rcPos.left,dat->rcPos.bottom-dat->rcPos.top};
  751. BLENDFUNCTION bf={AC_SRC_OVER, 0,g_CluiData.bCurrentAlpha*dat->bAlpha/256, AC_SRC_ALPHA };
  752. POINT pt_from={0,0};
  753. HDC hDC_animation=GetDC(NULL);
  754. HDC copyFromDC;
  755. RECT clistRect;
  756. HDC tempDC=NULL;
  757. HBITMAP hBmp;
  758. HBITMAP hOldBmp;
  759. /*
  760. int x=bf.SourceConstantAlpha;
  761. x=(49152/(383-x))-129;
  762. x=min(x,255); x=max(x,0);
  763. bf.SourceConstantAlpha=x;
  764. */
  765. if ( AniAva.bFlags == 0 ) //simple and fastest method - no borders, round corners and etc. just copy
  766. {
  767. pt_from.x=dat->ptFromPoint.x+dat->currentFrame*dat->sizeAvatar.cx;
  768. pt_from.y=dat->ptFromPoint.y;
  769. copyFromDC=AniAva.hAniAvaDC;
  770. }
  771. else
  772. {
  773. // ... need to create additional hDC_animation
  774. HRGN hRgn=NULL;
  775. int cornerRadius= AniAva.cornerRadius;
  776. tempDC = CreateCompatibleDC( NULL );
  777. hBmp = ske_CreateDIB32( szWnd.cx, szWnd.cy );
  778. hOldBmp = (HBITMAP)SelectObject(tempDC,hBmp);
  779. if ( AniAva.bFlags & AAO_ROUND_CORNERS )
  780. {
  781. if (!cornerRadius) //auto radius
  782. cornerRadius = min(szWnd.cx, szWnd.cy )/5;
  783. }
  784. if ( AniAva.bFlags & AAO_HAS_BORDER )
  785. {
  786. // if has borders - create region (round corners) and fill it, remember internal as clipping
  787. HBRUSH hBrush = CreateSolidBrush( AniAva.borderColor );
  788. HBRUSH hOldBrush = (HBRUSH)SelectObject( tempDC, hBrush );
  789. HRGN rgnOutside = CreateRoundRectRgn( 0, 0, szWnd.cx+1, szWnd.cy+1, cornerRadius<<1, cornerRadius<<1);
  790. hRgn=CreateRoundRectRgn( 1, 1, szWnd.cx, szWnd.cy, cornerRadius<<1, cornerRadius<<1);
  791. CombineRgn( rgnOutside,rgnOutside,hRgn,RGN_DIFF);
  792. FillRgn( tempDC, rgnOutside, hBrush);
  793. ske_SetRgnOpaque( tempDC, rgnOutside, TRUE);
  794. SelectObject(tempDC, hOldBrush);
  795. DeleteObject(hBrush);
  796. DeleteObject(rgnOutside);
  797. }
  798. else if ( cornerRadius > 0 )
  799. {
  800. // else create clipping area (round corners)
  801. hRgn=CreateRoundRectRgn(0, 0, szWnd.cx+1, szWnd.cy+1, cornerRadius<<1, cornerRadius<<1);
  802. }
  803. else
  804. {
  805. hRgn=CreateRectRgn(0, 0, szWnd.cx+1, szWnd.cy+1);
  806. }
  807. // select clip area
  808. if ( hRgn )
  809. ExtSelectClipRgn(tempDC, hRgn, RGN_AND);
  810. if ( AniAva.bFlags & AAO_OPAQUE)
  811. {
  812. // if back color - fill clipping area
  813. HBRUSH hBrush = CreateSolidBrush( AniAva.bkgColor );
  814. HBRUSH hOldBrush = (HBRUSH)SelectObject( tempDC, hBrush );
  815. FillRgn( tempDC, hRgn, hBrush );
  816. ske_SetRgnOpaque( tempDC, hRgn, TRUE );
  817. }
  818. // draw avatar
  819. if ( !(AniAva.bFlags & AAO_OPAQUE) )
  820. BitBlt(tempDC,0, 0, szWnd.cx, szWnd.cy , AniAva.hAniAvaDC , dat->ptFromPoint.x+dat->sizeAvatar.cx*dat->currentFrame, dat->ptFromPoint.y, SRCCOPY);
  821. else
  822. {
  823. BLENDFUNCTION abf={AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
  824. ske_AlphaBlend(tempDC,0, 0, szWnd.cx, szWnd.cy , AniAva.hAniAvaDC, dat->ptFromPoint.x+dat->sizeAvatar.cx*dat->currentFrame, dat->ptFromPoint.y, szWnd.cx, szWnd.cy, abf);
  825. }
  826. // reset clip area
  827. if ( hRgn )
  828. {
  829. DeleteObject(hRgn);
  830. hRgn = CreateRectRgn(0, 0, szWnd.cx, szWnd.cy);
  831. SelectClipRgn(tempDC, hRgn);
  832. DeleteObject(hRgn);
  833. }
  834. if ( ( AniAva.bFlags & AAO_HAS_OVERLAY )
  835. && ( dat->overlayIconIdx != -1 )
  836. && ( AniAva.overlayIconImageList ) )
  837. {
  838. // if overlay - draw overlay icon
  839. // position - on avatar
  840. int x=szWnd.cx-ICON_WIDTH;
  841. int y=szWnd.cy-ICON_HEIGHT;
  842. ske_ImageList_DrawEx(AniAva.overlayIconImageList,
  843. dat->overlayIconIdx&0xFFFF,
  844. tempDC, x, y, ICON_WIDTH, ICON_HEIGHT,
  845. CLR_NONE, CLR_NONE, ILD_NORMAL);
  846. }
  847. copyFromDC=tempDC;
  848. }
  849. // intersect visible area
  850. // update layered window
  851. GetWindowRect(pcli->hwndContactTree, &clistRect);
  852. if (dat->rcPos.top<0)
  853. {
  854. pt_from.y+=-dat->rcPos.top;
  855. szWnd.cy+=dat->rcPos.top;
  856. }
  857. if (dat->rcPos.bottom>clistRect.bottom-clistRect.top)
  858. {
  859. szWnd.cy-=(dat->rcPos.bottom-(clistRect.bottom-clistRect.top));
  860. }
  861. ptWnd.x=dat->rcPos.left+clistRect.left;
  862. ptWnd.y=(dat->rcPos.top>0 ? dat->rcPos.top :0)+clistRect.top;
  863. if (szWnd.cy>0)
  864. {
  865. if ( hdcParent && rcInParent && IMMEDIATE_DRAW )
  866. {
  867. if ( AniAva.bFlags & AAO_OPAQUE )
  868. BitBlt( hdcParent, rcInParent->left, rcInParent->top, szWnd.cx, szWnd.cy, copyFromDC, pt_from.x, pt_from.y, SRCCOPY);
  869. else
  870. {
  871. BLENDFUNCTION abf={AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
  872. ske_AlphaBlend( hdcParent, rcInParent->left, rcInParent->top, szWnd.cx, szWnd.cy, copyFromDC, pt_from.x, pt_from.y, szWnd.cx, szWnd.cy, abf);
  873. }
  874. }
  875. else if (!g_proc_UpdateLayeredWindow(dat->hWindow, hDC_animation, &ptWnd, &szWnd, copyFromDC, &pt_from, RGB(0,0,0), &bf, ULW_ALPHA ))
  876. {
  877. LONG exStyle;
  878. exStyle=GetWindowLong(dat->hWindow,GWL_EXSTYLE);
  879. exStyle|=WS_EX_LAYERED;
  880. SetWindowLong(dat->hWindow,GWL_EXSTYLE,exStyle);
  881. if ( !IMMEDIATE_DRAW )
  882. SetWindowPos( pcli->hwndContactTree, dat->hWindow, 0, 0, 0, 0, SWP_ASYNCWINDOWPOS | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSENDCHANGING );
  883. g_proc_UpdateLayeredWindow(dat->hWindow, hDC_animation, &ptWnd, &szWnd, copyFromDC, &pt_from, RGB(0,0,0), &bf, ULW_ALPHA );
  884. }
  885. g_CluiData.fAeroGlass = false;
  886. CLUI_UpdateAeroGlass();
  887. }
  888. else
  889. {
  890. dat->bPlaying=FALSE;
  891. }
  892. ReleaseDC(NULL,hDC_animation);
  893. if (tempDC)
  894. {
  895. SelectObject(tempDC, hOldBmp);
  896. DeleteObject(hBmp);
  897. DeleteDC(tempDC);
  898. }
  899. }
  900. if (!dat->bPlaying)
  901. {
  902. ShowWindow(dat->hWindow, SW_HIDE);
  903. KillTimer(dat->hWindow,2); //stop animation till set pos will be called
  904. }
  905. GdiFlush();
  906. }
  907. static void _AniAva_PausePainting()
  908. {
  909. int i;
  910. for (i=0; i<AniAva.Objects->realCount; i++)
  911. {
  912. ANIAVA_OBJECT * pai=(ANIAVA_OBJECT *)AniAva.Objects->items[i];
  913. SendMessage(pai->hWindow,AAM_PAUSE,0,0);
  914. }
  915. }
  916. static void _AniAva_ResumePainting()
  917. {
  918. int i;
  919. for (i=0; i<AniAva.Objects->realCount; i++)
  920. {
  921. ANIAVA_OBJECT * pai=(ANIAVA_OBJECT *)AniAva.Objects->items[i];
  922. SendNotifyMessage(pai->hWindow,AAM_RESUME,0,0);
  923. }
  924. }
  925. static void _AniAva_ReduceAvatarImages(int startY, int dY, BOOL bDestroyWindow)
  926. {
  927. int i;
  928. for (i=0; i<AniAva.Objects->realCount; i++)
  929. {
  930. ANIAVA_OBJECT * pai=(ANIAVA_OBJECT *)AniAva.Objects->items[i];
  931. int res=SendMessage(pai->hWindow,AAM_REMOVEAVATAR,(WPARAM)startY,(LPARAM)dY);
  932. if (res==0xDEAD && bDestroyWindow)
  933. {
  934. _AniAva_DestroyAvatarWindow(pai->hWindow);
  935. mir_free(pai);
  936. li.List_Remove(AniAva.Objects,i);
  937. i--;
  938. }
  939. }
  940. }
  941. static void _AniAva_LoadOptions()
  942. {
  943. aacheck;
  944. aalock;
  945. {
  946. AniAva.bFlags= (ModernGetSettingByte(NULL,"CList","AvatarsDrawBorders",SETTINGS_AVATARDRAWBORDER_DEFAULT)? AAO_HAS_BORDER :0) |
  947. (ModernGetSettingByte(NULL,"CList","AvatarsRoundCorners",SETTINGS_AVATARROUNDCORNERS_DEFAULT)? AAO_ROUND_CORNERS :0) |
  948. (ModernGetSettingByte(NULL,"CList","AvatarsDrawOverlay",SETTINGS_AVATARDRAWOVERLAY_DEFAULT)? AAO_HAS_OVERLAY :0) |
  949. ( (0) ? AAO_OPAQUE :0);
  950. if (AniAva.bFlags & AAO_HAS_BORDER)
  951. AniAva.borderColor=(COLORREF)ModernGetSettingDword(NULL,"CList","AvatarsBorderColor",SETTINGS_AVATARBORDERCOLOR_DEFAULT);;
  952. if (AniAva.bFlags & AAO_ROUND_CORNERS)
  953. AniAva.cornerRadius=ModernGetSettingByte(NULL,"CList","AvatarsUseCustomCornerSize",SETTINGS_AVATARUSECUTOMCORNERSIZE_DEFAULT)? ModernGetSettingWord(NULL,"CList","AvatarsCustomCornerSize",SETTINGS_AVATARCORNERSIZE_DEFAULT) : 0;
  954. if (AniAva.bFlags & AAO_HAS_OVERLAY)
  955. {
  956. //check image list
  957. BYTE type=ModernGetSettingByte(NULL,"CList","AvatarsOverlayType",SETTINGS_AVATAROVERLAYTYPE_DEFAULT);
  958. switch(type)
  959. {
  960. case SETTING_AVATAR_OVERLAY_TYPE_NORMAL:
  961. AniAva.overlayIconImageList=hAvatarOverlays;
  962. break;
  963. case SETTING_AVATAR_OVERLAY_TYPE_PROTOCOL:
  964. case SETTING_AVATAR_OVERLAY_TYPE_CONTACT:
  965. AniAva.overlayIconImageList=g_himlCListClc;
  966. break;
  967. default:
  968. AniAva.overlayIconImageList=NULL;
  969. }
  970. }
  971. if (AniAva.bFlags & AAO_OPAQUE)
  972. AniAva.bkgColor=0;
  973. AniAva.bSeparateWindow = ModernGetSettingByte(NULL,"CList","AvatarsInSeparateWnd",SETTINGS_AVATARINSEPARATE_DEFAULT);
  974. }
  975. aaunlock;
  976. }
  977. static void _AniAva_AnimationTreadProc(HANDLE hExitEvent)
  978. {
  979. //wait forever till hExitEvent signalled
  980. DWORD rc;
  981. HANDLE hThread=0;
  982. DuplicateHandle(GetCurrentProcess(),GetCurrentThread(),GetCurrentProcess(),&hThread,0,FALSE,DUPLICATE_SAME_ACCESS);
  983. AniAva.AnimationThreadHandle=hThread;
  984. SetThreadPriority(hThread,THREAD_PRIORITY_LOWEST);
  985. for (;;)
  986. {
  987. if ( fnMsgWaitForMultipleObjectsEx )
  988. rc = fnMsgWaitForMultipleObjectsEx(1,&hExitEvent, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE);
  989. else
  990. rc = MsgWaitForMultipleObjects(1,&hExitEvent, FALSE, INFINITE, QS_ALLINPUT);
  991. ResetEvent(hExitEvent);
  992. if ( rc == WAIT_OBJECT_0 + 1 )
  993. {
  994. MSG msg;
  995. while ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
  996. {
  997. if ( IsDialogMessage(msg.hwnd, &msg) ) continue;
  998. TranslateMessage(&msg);
  999. DispatchMessage(&msg);
  1000. }
  1001. }
  1002. else if ( rc==WAIT_OBJECT_0 )
  1003. {
  1004. break;
  1005. }
  1006. }
  1007. CloseHandle(AniAva.AnimationThreadHandle);
  1008. AniAva.AnimationThreadHandle=NULL;
  1009. }
  1010. static int _AniAva_SortAvatarInfo(void * first, void * last)
  1011. {
  1012. int res=0;
  1013. ANIAVA_INFO * aai1=(ANIAVA_INFO *)first;
  1014. ANIAVA_INFO * aai2=(ANIAVA_INFO *)last;
  1015. if (aai1 && aai1->tcsFilename &&
  1016. aai2 && aai2->tcsFilename)
  1017. {
  1018. res=_tcsicmp(aai2->tcsFilename, aai1->tcsFilename);
  1019. }
  1020. else
  1021. {
  1022. int a1=(aai1 && aai1->tcsFilename)? 1:0;
  1023. int a2=(aai2 && aai2->tcsFilename)? 1:0;
  1024. res=a1-a2;
  1025. }
  1026. if (res==0)
  1027. {
  1028. if ( aai1->FrameSize.cx==aai2->FrameSize.cx && aai1->FrameSize.cy==aai2->FrameSize.cy )
  1029. return 0;
  1030. else
  1031. return 1;
  1032. }
  1033. else
  1034. return res;
  1035. }
  1036. void _AniAva_InvalidateParent(ANIAVA_WINDOWINFO * dat)
  1037. {
  1038. if ( !IMMEDIATE_DRAW ) return;
  1039. HWND hwndParent = pcli->hwndContactTree;
  1040. RECT rcPos = dat->rcPos;
  1041. pcli->pfnInvalidateRect( hwndParent, &rcPos, FALSE );
  1042. }
  1043. static LRESULT CALLBACK _AniAva_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  1044. {
  1045. ANIAVA_WINDOWINFO * dat=NULL;
  1046. if (msg==WM_TIMER || msg==WM_DESTROY || (msg>AAM_FIRST && msg<AAM_LAST) )
  1047. dat=(ANIAVA_WINDOWINFO *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1048. switch (msg)
  1049. {
  1050. case AAM_REMOVEAVATAR:
  1051. if (dat->ptFromPoint.x==(int)wParam) return 0xDEAD; //need to destroy window
  1052. else if (dat->ptFromPoint.x>(int)wParam) dat->ptFromPoint.x-=(int)lParam;
  1053. return 0;
  1054. case AAM_PAUSE:
  1055. dat->bPaused++;
  1056. return 0;
  1057. case AAM_RESUME:
  1058. dat->bPaused--;
  1059. if (dat->bPaused) return 0;
  1060. if (dat->bPended)
  1061. {
  1062. if ( !IMMEDIATE_DRAW )
  1063. _AniAva_RenderAvatar(dat);
  1064. }
  1065. dat->bPended=FALSE;
  1066. return 0;
  1067. case AAM_STOP:
  1068. if (dat->bPlaying)
  1069. {
  1070. dat->bPlaying=FALSE;
  1071. KillTimer(hwnd,2);
  1072. ShowWindow(hwnd, SW_HIDE);
  1073. }
  1074. return 0;
  1075. case AAM_SETAVATAR:
  1076. {
  1077. ANIAVATARIMAGEINFO *paaii=(ANIAVATARIMAGEINFO*)wParam;
  1078. _AniAva_Clear_ANIAVA_WINDOWINFO(dat);
  1079. dat->nFramesCount=paaii->nFramesCount;
  1080. dat->delaysInterval=paaii->pFrameDelays;
  1081. dat->sizeAvatar=paaii->szSize;
  1082. dat->ptFromPoint=paaii->ptImagePos;
  1083. dat->currentFrame=0;
  1084. dat->bPlaying=FALSE;
  1085. return MAKELONG(dat->sizeAvatar.cx,dat->sizeAvatar.cy);
  1086. }
  1087. case AAM_SETPOSITION:
  1088. {
  1089. ANIAVA_POSINFO * papi=(ANIAVA_POSINFO *)lParam;
  1090. if (!dat->delaysInterval) return 0;
  1091. if (!papi) return 0;
  1092. dat->rcPos=papi->rcPos;
  1093. dat->overlayIconIdx=papi->idxOverlay;
  1094. dat->bAlpha=papi->bAlpha;
  1095. free(papi);
  1096. if (!dat->bPlaying)
  1097. {
  1098. dat->bPlaying=TRUE;
  1099. ShowWindow(hwnd,SW_SHOWNA);
  1100. dat->currentFrame=0;
  1101. KillTimer(hwnd,2);
  1102. SetTimer(hwnd,2,dat->delaysInterval[0],NULL);
  1103. }
  1104. if ( !IMMEDIATE_DRAW )
  1105. _AniAva_RenderAvatar(dat);
  1106. return 0;
  1107. }
  1108. case AAM_SETPARENT:
  1109. if ( IMMEDIATE_DRAW ) return 0;
  1110. dat->bOrderTop=((HWND)wParam!=GetDesktopWindow());
  1111. SetParent(hwnd,(HWND)wParam);
  1112. if (dat->bOrderTop)
  1113. {
  1114. SetWindowPos(hwnd,HWND_TOP,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_ASYNCWINDOWPOS);
  1115. }
  1116. else
  1117. {
  1118. LONG exStyle;
  1119. exStyle=GetWindowLong(pcli->hwndContactList,GWL_EXSTYLE);
  1120. SetWindowPos(pcli->hwndContactList,hwnd,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE/*|SWP_ASYNCWINDOWPOS*/);
  1121. if (!(exStyle&WS_EX_TOPMOST))
  1122. SetWindowPos(pcli->hwndContactList,HWND_NOTOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE/*|SWP_ASYNCWINDOWPOS*/);
  1123. }
  1124. return 0;
  1125. case AAM_REDRAW:
  1126. if ( IMMEDIATE_DRAW )
  1127. return 0;
  1128. if ( wParam )
  1129. {
  1130. if (dat->bOrderTop)
  1131. {
  1132. SetWindowPos(hwnd,HWND_TOP,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_ASYNCWINDOWPOS);
  1133. }
  1134. else
  1135. {
  1136. LONG exStyle;
  1137. exStyle=GetWindowLong(pcli->hwndContactList,GWL_EXSTYLE);
  1138. SetWindowPos(pcli->hwndContactList,hwnd,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE/*|SWP_ASYNCWINDOWPOS*/);
  1139. if (!(exStyle&WS_EX_TOPMOST))
  1140. SetWindowPos(pcli->hwndContactList,HWND_NOTOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE/*|SWP_ASYNCWINDOWPOS*/);
  1141. }
  1142. }
  1143. _AniAva_RenderAvatar( dat );
  1144. return 0;
  1145. case AAM_RENDER:
  1146. {
  1147. HDC hdc = ( HDC )wParam;
  1148. RECT* rect = ( RECT* )lParam;
  1149. _AniAva_RenderAvatar( dat, hdc, rect );
  1150. }
  1151. return 0;
  1152. case AAM_SELFDESTROY:
  1153. return DestroyWindow(hwnd);
  1154. case WM_CREATE:
  1155. {
  1156. LONG exStyle;
  1157. ANIAVA_WINDOWINFO * dat = (ANIAVA_WINDOWINFO *) mir_calloc(sizeof (ANIAVA_WINDOWINFO));
  1158. SetWindowLongPtr(hwnd,GWLP_USERDATA,(LONG_PTR)dat);
  1159. dat->hWindow=hwnd;
  1160. //ShowWindow(dat->hWindow,SW_SHOW);
  1161. //change layered mode
  1162. exStyle=GetWindowLongPtr(dat->hWindow,GWL_EXSTYLE);
  1163. exStyle|=WS_EX_LAYERED;
  1164. SetWindowLong(dat->hWindow,GWL_EXSTYLE,exStyle);
  1165. exStyle=GetWindowLong(dat->hWindow,GWL_STYLE);
  1166. exStyle&=~WS_POPUP;
  1167. exStyle|=WS_CHILD;
  1168. SetWindowLong(dat->hWindow,GWL_STYLE,exStyle);
  1169. break;
  1170. }
  1171. case WM_TIMER:
  1172. {
  1173. if (!IsWindowVisible(hwnd))
  1174. {
  1175. DestroyWindow(hwnd);
  1176. return 0;
  1177. }
  1178. dat->currentFrame++;
  1179. if (dat->currentFrame>=dat->nFramesCount)
  1180. dat->currentFrame=0;
  1181. if ( !IMMEDIATE_DRAW )
  1182. _AniAva_RenderAvatar( dat );
  1183. else
  1184. _AniAva_InvalidateParent( dat );
  1185. KillTimer(hwnd,2);
  1186. SetTimer(hwnd,2,dat->delaysInterval[dat->currentFrame]+1,NULL);
  1187. return 0;
  1188. }
  1189. case WM_DESTROY:
  1190. {
  1191. _AniAva_Clear_ANIAVA_WINDOWINFO(dat);
  1192. mir_free(dat);
  1193. SetWindowLongPtr(hwnd,GWLP_USERDATA,(LONG_PTR)NULL);
  1194. break;
  1195. }
  1196. }
  1197. return DefWindowProc(hwnd, msg, wParam, lParam);
  1198. }
  1199. #undef aacheck
  1200. #undef aalock
  1201. #undef aaunlock
  1202. /////////////////////////////////////////////////////////////////
  1203. // some stub
  1204. HWND WINAPI MyGetAncestor( HWND hWnd, UINT option )
  1205. {
  1206. if ( option == GA_PARENT )
  1207. return GetParent( hWnd );
  1208. if ( option == GA_ROOTOWNER ) {
  1209. HWND result = hWnd;
  1210. while( true ) {
  1211. HWND hParent = GetParent( result );
  1212. if ( !hParent )
  1213. return result;
  1214. result = hParent;
  1215. }
  1216. }
  1217. return NULL;
  1218. }