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.

485 lines
13 KiB

  1. /*****************************************************************************\
  2. FILE: pictures.cpp
  3. DESCRIPTION:
  4. Manage the pictures in the user's directories. Convert them when needed.
  5. Handle caching and making sure we don't use too much diskspace. Also add
  6. picture frame when needed.
  7. BryanSt 12/24/2000
  8. Copyright (C) Microsoft Corp 2000-2001. All rights reserved.
  9. \*****************************************************************************/
  10. #include "stdafx.h"
  11. #include <shlobj.h>
  12. #include "pictures.h"
  13. #include "util.h"
  14. #undef __IShellFolder2_FWD_DEFINED__
  15. #include <ccstock.h>
  16. CPictureManager * g_pPictureMgr = NULL;
  17. int CALLBACK DSACallback_FreePainting(LPVOID p, LPVOID pData)
  18. {
  19. SSPICTURE_INFO * pPInfo = (SSPICTURE_INFO *) p;
  20. if (pPInfo)
  21. {
  22. Str_SetPtr(&pPInfo->pszPath, NULL);
  23. }
  24. return 1;
  25. }
  26. CPictureManager::CPictureManager(CMSLogoDXScreenSaver * pMain)
  27. {
  28. m_nCurrent = 0;
  29. m_hdsaPictures = NULL;
  30. m_pMain = pMain;
  31. m_hdsaBatches = 0;
  32. m_nCurrentBatch = 0;
  33. _EnumPaintings();
  34. }
  35. CPictureManager::~CPictureManager()
  36. {
  37. if (m_hdsaBatches)
  38. {
  39. DSA_Destroy(m_hdsaBatches);
  40. m_hdsaBatches = NULL;
  41. }
  42. if (m_hdsaPictures)
  43. {
  44. DSA_DestroyCallback(m_hdsaPictures, DSACallback_FreePainting, NULL);
  45. m_hdsaPictures = NULL;
  46. }
  47. m_pMain = NULL;
  48. }
  49. HRESULT CPictureManager::_PInfoCreate(int nIndex, LPCTSTR pszPath)
  50. {
  51. HRESULT hr = S_OK;
  52. SSPICTURE_INFO pInfo = {0};
  53. pInfo.fInABatch = FALSE;
  54. pInfo.pszPath = NULL;
  55. Str_SetPtr(&pInfo.pszPath, pszPath);
  56. // We add them in a random order so the pattern doesn't get boring.
  57. if (-1 == DSA_InsertItem(m_hdsaPictures, nIndex, &pInfo))
  58. {
  59. // We failed so free the memory
  60. Str_SetPtr(&pInfo.pszPath, NULL);
  61. hr = E_OUTOFMEMORY;
  62. }
  63. return S_OK;
  64. }
  65. HRESULT CPictureManager::_AddPaintingsFromDir(LPCTSTR pszPath)
  66. {
  67. HRESULT hr = E_OUTOFMEMORY;
  68. if (!m_hdsaPictures)
  69. {
  70. m_hdsaPictures = DSA_Create(sizeof(SSPICTURE_INFO), 20);
  71. }
  72. if (m_hdsaPictures)
  73. {
  74. TCHAR szSearch[MAX_PATH];
  75. WIN32_FIND_DATA findFileData;
  76. hr = S_OK;
  77. StrCpyN(szSearch, pszPath, ARRAYSIZE(szSearch));
  78. PathAppend(szSearch, TEXT("*.*"));
  79. HANDLE hFindFiles = FindFirstFile(szSearch, &findFileData);
  80. if (INVALID_HANDLE_VALUE != hFindFiles)
  81. {
  82. while ((INVALID_HANDLE_VALUE != hFindFiles))
  83. {
  84. if (!PathIsDotOrDotDot(findFileData.cFileName))
  85. {
  86. if (!(FILE_ATTRIBUTE_DIRECTORY & findFileData.dwFileAttributes))
  87. {
  88. LPCTSTR pszExt = PathFindExtension(findFileData.cFileName);
  89. if (pszExt && pszExt[0] &&
  90. (!StrCmpI(pszExt, TEXT(".bmp"))
  91. || !StrCmpI(pszExt, TEXT(".jpg"))
  92. || !StrCmpI(pszExt, TEXT(".jpeg"))
  93. || !StrCmpI(pszExt, TEXT(".png"))
  94. // || !StrCmpI(pszExt, TEXT(".gif"))
  95. || !StrCmpI(pszExt, TEXT(".tiff"))
  96. ))
  97. {
  98. int nInsertLoc = GetRandomInt(0, max(0, DSA_GetItemCount(m_hdsaPictures) - 1));
  99. StrCpyN(szSearch, pszPath, ARRAYSIZE(szSearch));
  100. PathAppend(szSearch, findFileData.cFileName);
  101. hr = _PInfoCreate(nInsertLoc, szSearch);
  102. }
  103. }
  104. else
  105. {
  106. StrCpyN(szSearch, pszPath, ARRAYSIZE(szSearch));
  107. PathAppend(szSearch, findFileData.cFileName);
  108. hr = _AddPaintingsFromDir(szSearch);
  109. }
  110. }
  111. if (!FindNextFile(hFindFiles, &findFileData))
  112. {
  113. break;
  114. }
  115. }
  116. FindClose(hFindFiles);
  117. }
  118. }
  119. return hr;
  120. }
  121. HRESULT CPictureManager::_EnumPaintings(void)
  122. {
  123. HRESULT hr = E_FAIL;
  124. TCHAR szDir[MAX_PATH];
  125. if (g_pConfig)
  126. {
  127. hr = S_OK;
  128. if (g_pConfig->GetFolderOn(CONFIG_FOLDER_MYPICTS) &&
  129. SHGetSpecialFolderPath(NULL, szDir, CSIDL_MYPICTURES, TRUE))
  130. {
  131. hr = _AddPaintingsFromDir(szDir);
  132. }
  133. if (g_pConfig->GetFolderOn(CONFIG_FOLDER_COMMONPICTS))
  134. {
  135. // TODO: When Common Pictures are added.
  136. }
  137. if (g_pConfig->GetFolderOn(CONFIG_FOLDER_OTHER) &&
  138. SUCCEEDED(g_pConfig->GetOtherDir(szDir, ARRAYSIZE(szDir))))
  139. {
  140. hr = _AddPaintingsFromDir(szDir);
  141. }
  142. // If we have less than 10 paintings, then we force add the
  143. // Windows wallpapers.
  144. if ((g_pConfig->GetFolderOn(CONFIG_FOLDER_WINPICTS) ||
  145. (10 > DSA_GetItemCount(m_hdsaPictures))) &&
  146. SHGetSpecialFolderPath(NULL, szDir, CSIDL_WINDOWS, TRUE))
  147. {
  148. PathAppend(szDir, TEXT("Web\\Wallpaper"));
  149. hr = _AddPaintingsFromDir(szDir);
  150. }
  151. if (m_hdsaPictures)
  152. {
  153. m_nCurrent = GetRandomInt(0, max(0, DSA_GetItemCount(m_hdsaPictures) - 1));
  154. }
  155. }
  156. return hr;
  157. }
  158. HRESULT CPictureManager::_LoadTexture(SSPICTURE_INFO * pInfo, BOOL fFaultInTexture)
  159. {
  160. // We keep trying until we hit the end. We give up after that.
  161. HRESULT hr = E_INVALIDARG;
  162. if (pInfo)
  163. {
  164. if (!pInfo->pTexture)
  165. {
  166. pInfo->pTexture = new CTexture(m_pMain, pInfo->pszPath, NULL, 1.0f);
  167. }
  168. hr = (pInfo->pTexture ? S_OK : E_OUTOFMEMORY);
  169. if (pInfo->pTexture && fFaultInTexture)
  170. {
  171. pInfo->pTexture->GetTexture(NULL); // Force the image to be paged in.
  172. }
  173. }
  174. return hr;
  175. }
  176. #define GNPF_NONE 0x00000000
  177. #define GNPF_ALREADYLOADED 0x00000001
  178. #define GNPF_FAULTINTEXTURE 0x00000002
  179. #define GNPF_ALLOWALREADYINBATCH 0x00000004
  180. HRESULT CPictureManager::_TryGetNextPainting(SSPICTURE_INFO ** ppInfo, DWORD dwFlags)
  181. {
  182. // We keep trying until we hit the end. We give up after that.
  183. HRESULT hr = E_FAIL;
  184. while (m_hdsaPictures &&
  185. FAILED(hr) && (m_nCurrent < DSA_GetItemCount(m_hdsaPictures)))
  186. {
  187. SSPICTURE_INFO * pPInfo = (SSPICTURE_INFO *) DSA_GetItemPtr(m_hdsaPictures, m_nCurrent);
  188. if (pPInfo && pPInfo->pszPath)
  189. {
  190. if (!pPInfo->fInABatch || (dwFlags & GNPF_ALLOWALREADYINBATCH))
  191. {
  192. if (dwFlags & GNPF_ALREADYLOADED)
  193. {
  194. if (pPInfo->pTexture && pPInfo->pTexture->IsLoadedInAnyDevice())
  195. {
  196. // The caller only wants an object that's already pre-fetched, and we just found one.
  197. *ppInfo = pPInfo;
  198. pPInfo->fInABatch = TRUE;
  199. hr = S_OK;
  200. }
  201. }
  202. else
  203. {
  204. // The caller is happen to this now. We only get this far if we failed to load it.
  205. hr = _LoadTexture(pPInfo, (dwFlags & GNPF_FAULTINTEXTURE));
  206. if (SUCCEEDED(hr))
  207. {
  208. *ppInfo = pPInfo;
  209. pPInfo->fInABatch = TRUE;
  210. }
  211. }
  212. }
  213. }
  214. m_nCurrent++;
  215. }
  216. return hr;
  217. }
  218. HRESULT CPictureManager::_GetNextWithWrap(SSPICTURE_INFO ** ppInfo, BOOL fAlreadyLoaded, BOOL fFaultInTexture)
  219. {
  220. DWORD dwFlags = ((fAlreadyLoaded ? GNPF_ALREADYLOADED : GNPF_NONE) | (fFaultInTexture ? GNPF_FAULTINTEXTURE : GNPF_NONE));
  221. *ppInfo = NULL;
  222. HRESULT hr = _TryGetNextPainting(ppInfo, dwFlags);
  223. if (m_nCurrent >= DSA_GetItemCount(m_hdsaPictures))
  224. {
  225. m_nCurrent = 0;
  226. if (FAILED(hr))
  227. {
  228. // Maybe it was necessary to wrap. We don't loop to prevent infinite recursion in corner cases.
  229. hr = _TryGetNextPainting(ppInfo, dwFlags);
  230. if (FAILED(hr))
  231. {
  232. // Maybe we have so few paintings available that we need to reuse.
  233. m_nCurrent = 0;
  234. hr = _TryGetNextPainting(ppInfo, (dwFlags | GNPF_ALLOWALREADYINBATCH));
  235. }
  236. }
  237. }
  238. if (SUCCEEDED(hr) && (10 < DSA_GetItemCount(m_hdsaPictures)) &&
  239. (1 == GetRandomInt(0, 4)))
  240. {
  241. // There is a one in for chance we want to skip pictures. This will keep the order somewhat random
  242. // while still not always going in the same order. We only do this if the user has more than 10
  243. // pictures or it may lap and the user will have the same picture twice in the same room.
  244. m_nCurrent += GetRandomInt(1, 5);
  245. if (m_nCurrent >= DSA_GetItemCount(m_hdsaPictures))
  246. {
  247. m_nCurrent = 0;
  248. }
  249. }
  250. return hr;
  251. }
  252. HRESULT CPictureManager::_CreateNewBatch(int nBatch, BOOL fFaultInTexture)
  253. {
  254. HRESULT hr = S_OK;
  255. SSPICTURES_BATCH batch = {0};
  256. int nIndex;
  257. for (nIndex = 0; (nIndex < ARRAYSIZE(batch.pInfo)) && SUCCEEDED(hr); nIndex++)
  258. {
  259. // First try and not get any dups
  260. hr = _GetNextWithWrap(&(batch.pInfo[nIndex]), FALSE, fFaultInTexture);
  261. }
  262. if (SUCCEEDED(hr))
  263. {
  264. if (-1 == DSA_AppendItem(m_hdsaBatches, &batch))
  265. {
  266. // We failed so free the memory
  267. hr = E_OUTOFMEMORY;
  268. }
  269. }
  270. return hr;
  271. }
  272. ///////////////////////////////////////////////////////////////////////
  273. // FUNCTION: GetPainting
  274. ///////////////////////////////////////////////////////////////////////
  275. HRESULT CPictureManager::GetPainting(int nBatch, int nIndex, DWORD dwFlags, CTexture ** ppTexture)
  276. {
  277. HRESULT hr = E_FAIL;
  278. if (!m_hdsaBatches)
  279. {
  280. m_hdsaBatches = DSA_Create(sizeof(SSPICTURES_BATCH), 20);
  281. }
  282. m_nCurrentBatch = max(m_nCurrentBatch, nBatch);
  283. *ppTexture = NULL;
  284. if (m_hdsaPictures && m_hdsaBatches)
  285. {
  286. hr = S_OK;
  287. while ((nBatch >= DSA_GetItemCount(m_hdsaBatches)) && SUCCEEDED(hr))
  288. {
  289. hr = _CreateNewBatch(nBatch, TRUE);
  290. }
  291. if (SUCCEEDED(hr))
  292. {
  293. SSPICTURES_BATCH * pBatch = (SSPICTURES_BATCH *) DSA_GetItemPtr(m_hdsaBatches, nBatch);
  294. if (pBatch && ((void *)-1 != pBatch) && pBatch->pInfo[nIndex] && pBatch->pInfo[nIndex]->pTexture)
  295. {
  296. IUnknown_Set((IUnknown **) ppTexture, (IUnknown *) pBatch->pInfo[nIndex]->pTexture);
  297. }
  298. else
  299. {
  300. hr = E_FAIL;
  301. }
  302. }
  303. }
  304. return hr;
  305. }
  306. ///////////////////////////////////////////////////////////////////////
  307. // FUNCTION: PreFetch
  308. ///////////////////////////////////////////////////////////////////////
  309. HRESULT CPictureManager::PreFetch(int nBatch, int nToFetch)
  310. {
  311. HRESULT hr = S_OK;
  312. while ((nBatch >= DSA_GetItemCount(m_hdsaBatches)) && SUCCEEDED(hr))
  313. {
  314. hr = _CreateNewBatch(nBatch, FALSE);
  315. if (FAILED(hr))
  316. {
  317. DXUtil_Trace(TEXT("ERROR: PreFetch() _CreateNewBatch failed. nBatch=%d\n"), nBatch);
  318. }
  319. }
  320. SSPICTURES_BATCH * pBatch = (SSPICTURES_BATCH *) DSA_GetItemPtr(m_hdsaBatches, nBatch);
  321. if (pBatch && (nToFetch < ARRAYSIZE(pBatch->pInfo)))
  322. {
  323. int nIndex;
  324. for (nIndex = 0; (nIndex < ARRAYSIZE(pBatch->pInfo)) && nToFetch; nIndex++)
  325. {
  326. if (pBatch->pInfo[nIndex] &&
  327. (!pBatch->pInfo[nIndex]->pTexture ||
  328. !pBatch->pInfo[nIndex]->pTexture->IsLoadedForThisDevice()))
  329. {
  330. hr = _LoadTexture(pBatch->pInfo[nIndex], TRUE);
  331. nToFetch--;
  332. }
  333. }
  334. }
  335. else
  336. {
  337. hr = E_FAIL;
  338. }
  339. return hr;
  340. }
  341. ///////////////////////////////////////////////////////////////////////
  342. // FUNCTION: ReleaseBatch
  343. ///////////////////////////////////////////////////////////////////////
  344. HRESULT CPictureManager::ReleaseBatch(int nBatch)
  345. {
  346. HRESULT hr = E_INVALIDARG;
  347. for (int nIndex = 0; nIndex < nBatch; nIndex++)
  348. {
  349. SSPICTURES_BATCH * pBatch = (SSPICTURES_BATCH *) DSA_GetItemPtr(m_hdsaBatches, nIndex);
  350. for (int nIndex2 = 0; nIndex2 < ARRAYSIZE(pBatch->pInfo); nIndex2++)
  351. {
  352. if (pBatch && pBatch->pInfo[nIndex2] && (pBatch->pInfo[nIndex2]->fInABatch || pBatch->pInfo[nIndex2]->pTexture))
  353. {
  354. ReleaseBatch(nIndex);
  355. DXUtil_Trace(TEXT("ERROR: ReleaseBatch() and previous batch aren't released. nBatch=%d, nIndex=%d\n"), nBatch, nIndex);
  356. break;
  357. }
  358. }
  359. }
  360. if (nBatch < m_nCurrentBatch)
  361. {
  362. SSPICTURES_BATCH * pBatch = (SSPICTURES_BATCH *) DSA_GetItemPtr(m_hdsaBatches, nBatch);
  363. if (pBatch && ((void *)-1 != pBatch))
  364. {
  365. hr = S_OK;
  366. for (int nIndex = 0; (nIndex < ARRAYSIZE(pBatch->pInfo)); nIndex++)
  367. {
  368. if (pBatch->pInfo[nIndex])
  369. {
  370. SAFE_RELEASE(pBatch->pInfo[nIndex]->pTexture);
  371. pBatch->pInfo[nIndex]->fInABatch = FALSE;
  372. pBatch->pInfo[nIndex] = NULL;
  373. }
  374. }
  375. }
  376. }
  377. else
  378. {
  379. DXUtil_Trace(TEXT("ERROR: ReleaseBatch() and batch is bad. nBatch=%d, m_nCurrentBatch=%d\n"), nBatch, m_nCurrentBatch);
  380. hr = E_UNEXPECTED;
  381. }
  382. return hr;
  383. }