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.

582 lines
17 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // File: plustab.cpp
  4. //
  5. // Main Implementation of the Effects page
  6. //
  7. //---------------------------------------------------------------------------
  8. #include "priv.h"
  9. #pragma hdrstop
  10. #include "shlwapip.h"
  11. #include "shlguidp.h"
  12. #include "EffectsAdvPg.h"
  13. #include "store.h"
  14. #include "regutil.h"
  15. // OLE-Registry magic number
  16. GUID CLSID_EffectsPage = { 0x41e300e0, 0x78b6, 0x11ce,{0x84, 0x9b, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
  17. #define SPI_GETKEYBOARDINDICATORS SPI_GETMENUUNDERLINES//0x100A
  18. #define SPI_SETKEYBOARDINDICATORS SPI_SETMENUUNDERLINES//0x100B
  19. #define SPI_GETFONTCLEARTYPE 116
  20. #define SPI_SETFONTCLEARTYPE 117
  21. // Handle to the DLL
  22. extern HINSTANCE g_hInst;
  23. // vars needed for new shell api
  24. #define SZ_SHELL32 TEXT("shell32.dll")
  25. #define SZ_SHUPDATERECYCLEBINICON "SHUpdateRecycleBinIcon" // Parameter for GetProcAddr()... DO NOT TEXT("") IT!
  26. typedef void (* PFNSHUPDATERECYCLEBINICON)( void );
  27. // Function prototype
  28. BOOL CALLBACK PlusPackDlgProc( HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam );
  29. // Icon Stuff
  30. int GetIconState (void);
  31. BOOL ChangeIconSizes(int iOldState, int iNewState);
  32. // animation stuff
  33. WPARAM GetAnimations(DWORD *pdwEffect);
  34. void SetAnimations(WPARAM wVal, DWORD dwEffect, DWORD dwBroadCast);
  35. BOOL DisplayFontSmoothingDetails(DWORD *pdwSetting)
  36. {
  37. return FALSE;
  38. }
  39. int GetBitsPerPixel(void)
  40. {
  41. int iBitsPerPixel = 8;
  42. HDC hDC = GetDC(NULL);
  43. if (hDC)
  44. {
  45. iBitsPerPixel = GetDeviceCaps(hDC, BITSPIXEL);
  46. ReleaseDC(NULL, hDC);
  47. }
  48. return iBitsPerPixel;
  49. }
  50. int GetIconState(void)
  51. {
  52. BOOL bRet;
  53. int iSize;
  54. bRet = GetRegValueInt(HKEY_CURRENT_USER, SZ_REGKEY_USERMETRICS, SZ_REGVALUE_ICONSIZE, &iSize);
  55. if (bRet == FALSE)
  56. return ICON_DEFAULT;
  57. if (iSize == ICON_DEFAULT_NORMAL)
  58. return ICON_DEFAULT;
  59. else if (iSize == ICON_DEFAULT_LARGE)
  60. return ICON_LARGE;
  61. return ICON_INDETERMINATE;
  62. }
  63. BOOL ChangeIconSizes(int iOldState, int iNewState)
  64. {
  65. BOOL bRet;
  66. int iOldSize, iNewSize;
  67. int iHorz;
  68. int iVert;
  69. // Don't bother if nothing changed
  70. if (iOldState == iNewState)
  71. return FALSE;
  72. // Get New Size
  73. switch (iNewState)
  74. {
  75. case ICON_DEFAULT:
  76. iNewSize = ICON_DEFAULT_NORMAL;
  77. break;
  78. case ICON_LARGE:
  79. iNewSize = ICON_DEFAULT_LARGE;
  80. break;
  81. case ICON_INDETERMINATE:
  82. // Don't bother to change anything
  83. return FALSE;
  84. default:
  85. return FALSE;
  86. }
  87. // Get Original Size
  88. bRet = GetRegValueInt(HKEY_CURRENT_USER, SZ_REGKEY_USERMETRICS, SZ_REGVALUE_ICONSIZE, &iOldSize);
  89. if (!bRet)
  90. {
  91. // Try geting system default instead
  92. iOldSize = ClassicGetSystemMetrics(SM_CXICON);
  93. }
  94. // Don't need to change size if nothing has really changed
  95. if (iNewSize == iOldSize)
  96. return FALSE;
  97. // Get new horizontal spacing
  98. iHorz = ClassicGetSystemMetrics(SM_CXICONSPACING);
  99. iHorz -= iOldSize;
  100. if (iHorz < 0)
  101. {
  102. iHorz = 0;
  103. }
  104. iHorz += iNewSize;
  105. // Get new vertical spacing
  106. iVert = ClassicGetSystemMetrics(SM_CYICONSPACING);
  107. iVert -= iOldSize;
  108. if (iVert < 0)
  109. {
  110. iVert = 0;
  111. }
  112. iVert += iNewSize;
  113. // Set New sizes and spacing
  114. bRet = SetRegValueInt(HKEY_CURRENT_USER, SZ_REGKEY_USERMETRICS, SZ_REGVALUE_ICONSIZE, iNewSize);
  115. if (!bRet)
  116. return FALSE;
  117. // We don't need to call the Async version because this function is called on a background thread.
  118. ClassicSystemParametersInfo(SPI_ICONHORIZONTALSPACING, iHorz, NULL, (SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE));
  119. ClassicSystemParametersInfo(SPI_ICONVERTICALSPACING, iVert, NULL, (SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE));
  120. // We need to do this in order to force DefView to update.
  121. // BUG:194437
  122. ICONMETRICS iconMetrics;
  123. iconMetrics.cbSize = sizeof(iconMetrics);
  124. ClassicSystemParametersInfo(SPI_GETICONMETRICS, sizeof(iconMetrics), &iconMetrics, 0);
  125. ClassicSystemParametersInfo(SPI_SETICONMETRICS, sizeof(iconMetrics), &iconMetrics, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
  126. // We did change the sizes
  127. return TRUE;
  128. }
  129. //
  130. // GetAnimations
  131. //
  132. // Get current state of animations (windows / menus / etc.).
  133. //
  134. WPARAM GetAnimations(DWORD *pdwEffect)
  135. {
  136. BOOL fMenu = FALSE, fWindow = FALSE, fCombo = FALSE, fSmooth = FALSE, fList = FALSE, fFade = FALSE;
  137. ANIMATIONINFO ai;
  138. ai.cbSize = sizeof(ai);
  139. if (ClassicSystemParametersInfo(SPI_GETANIMATION, sizeof(ai), (PVOID)&ai, 0 ))
  140. {
  141. fWindow = (ai.iMinAnimate) ? TRUE : FALSE;
  142. }
  143. ClassicSystemParametersInfo(SPI_GETCOMBOBOXANIMATION, 0, (PVOID)&fCombo, 0 );
  144. ClassicSystemParametersInfo(SPI_GETLISTBOXSMOOTHSCROLLING, 0, (PVOID)&fList, 0 );
  145. ClassicSystemParametersInfo(SPI_GETMENUANIMATION, 0, (PVOID)&fMenu, 0 );
  146. fSmooth = GetRegValueDword(HKEY_CURRENT_USER, SZ_REGKEY_CPDESKTOP, SZ_REGVALUE_SMOOTHSCROLL);
  147. if (fSmooth == REG_BAD_DWORD)
  148. {
  149. fSmooth = 1;
  150. }
  151. ClassicSystemParametersInfo(SPI_GETMENUFADE, 0, (PVOID)&fFade, 0 );
  152. *pdwEffect = (fFade ? MENU_EFFECT_FADE : MENU_EFFECT_SCROLL);
  153. if (fMenu && fWindow && fCombo && fSmooth && fList)
  154. return BST_CHECKED;
  155. if ((!fMenu) && (!fWindow) && (!fCombo) && (!fSmooth) && (!fList))
  156. return BST_UNCHECKED;
  157. return BST_INDETERMINATE;
  158. }
  159. //
  160. // SetAnimations
  161. //
  162. // Set animations according (windows / menus / etc.) according to flag.
  163. //
  164. void SetAnimations(WPARAM wVal, DWORD dwEffect, DWORD dwBroadcast)
  165. {
  166. if (!IsTSPerfFlagEnabled(TSPerFlag_NoAnimation))
  167. {
  168. ANIMATIONINFO ai;
  169. // Note, if the checkbox is indeterminate, we treat it like it was checked.
  170. // We should never get this far if the user didn't change something so this should be okay.
  171. BOOL bVal = (wVal == BST_UNCHECKED) ? 0 : 1;
  172. BOOL bEfx = (dwEffect == MENU_EFFECT_FADE) ? 1 : 0;
  173. ai.cbSize = sizeof(ai);
  174. ai.iMinAnimate = bVal;
  175. ClassicSystemParametersInfo(SPI_SETANIMATION, sizeof(ai), (PVOID)&ai, dwBroadcast);
  176. ClassicSystemParametersInfo(SPI_SETCOMBOBOXANIMATION, 0, IntToPtr(bVal), dwBroadcast);
  177. ClassicSystemParametersInfo(SPI_SETLISTBOXSMOOTHSCROLLING, 0, IntToPtr(bVal), dwBroadcast);
  178. ClassicSystemParametersInfo(SPI_SETMENUANIMATION, 0, IntToPtr(bVal), dwBroadcast);
  179. ClassicSystemParametersInfo(SPI_SETTOOLTIPANIMATION, 0, IntToPtr(bVal), dwBroadcast);
  180. SetRegValueDword(HKEY_CURRENT_USER, SZ_REGKEY_CPDESKTOP, SZ_REGVALUE_SMOOTHSCROLL, bVal);
  181. ClassicSystemParametersInfo(SPI_SETMENUFADE, 0, IntToPtr(bEfx), dwBroadcast);
  182. ClassicSystemParametersInfo(SPI_SETTOOLTIPFADE, 0, IntToPtr(bEfx), dwBroadcast);
  183. ClassicSystemParametersInfo(SPI_SETSELECTIONFADE, 0, bVal ? IntToPtr(bEfx) : 0, dwBroadcast);
  184. }
  185. }
  186. CEffectState::CEffectState() : m_cRef(1)
  187. {
  188. }
  189. CEffectState::~CEffectState()
  190. {
  191. }
  192. HRESULT CEffectState::Load(void)
  193. {
  194. HRESULT hr = S_OK;
  195. // Get the values for the settings from the registry and set the checkboxes
  196. // Large Icons
  197. _nLargeIcon = GetIconState();
  198. // Full Color Icons
  199. if(FALSE == GetRegValueInt(HKEY_CURRENT_USER, SZ_REGKEY_USERMETRICS, SZ_REGVALUE_ICONCOLORDEPTH, &_nHighIconColor)) // Key not in registry yet
  200. {
  201. _nHighIconColor = 4;
  202. }
  203. // Use animations
  204. _wpMenuAnimation = GetAnimations(&_dwAnimationEffect);
  205. // Smooth edges of screen fonts
  206. _fFontSmoothing = FALSE;
  207. ClassicSystemParametersInfo(SPI_GETFONTSMOOTHING, 0, (PVOID)&_fFontSmoothing, 0);
  208. _dwFontSmoothingType = FONT_SMOOTHING_AA;
  209. if (ClassicSystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, (PVOID)&_dwFontSmoothingType, 0))
  210. {
  211. }
  212. if (FONT_SMOOTHING_MONO == _dwFontSmoothingType)
  213. {
  214. _dwFontSmoothingType = FONT_SMOOTHING_AA;
  215. }
  216. // Show contents while dragging
  217. _fDragWindow = FALSE;
  218. ClassicSystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, (PVOID)&_fDragWindow, 0);
  219. _fKeyboardIndicators = FALSE;
  220. ClassicSystemParametersInfo(SPI_GETKEYBOARDINDICATORS, 0, (PVOID)&_fKeyboardIndicators, 0);
  221. _fMenuShadows = TRUE;
  222. ClassicSystemParametersInfo(SPI_GETDROPSHADOW, 0, (PVOID)&_fMenuShadows, 0);
  223. // Set the old values so we know when they changed.
  224. _nOldLargeIcon = _nLargeIcon;
  225. _nOldHighIconColor = _nHighIconColor;
  226. _wpOldMenuAnimation = _wpMenuAnimation;
  227. _fOldFontSmoothing = _fFontSmoothing;
  228. _dwOldFontSmoothingType = _dwFontSmoothingType;
  229. _fOldDragWindow = _fDragWindow;
  230. _fOldKeyboardIndicators = _fKeyboardIndicators;
  231. _dwOldAnimationEffect = _dwAnimationEffect;
  232. _fOldMenuShadows = _fMenuShadows;
  233. return hr;
  234. }
  235. HRESULT CEffectState::Save(void)
  236. {
  237. // ClassicSystemParametersInfo() will hang if a top level window is hung (#162570) and USER will not fix that bug.
  238. // Therefore, we need to make that API call on a background thread because we need to
  239. // be more rebust than to hang.
  240. AddRef();
  241. SPICreateThread(Save_WorkerProc, (void *)this);
  242. return S_OK;
  243. }
  244. DWORD CEffectState::Save_WorkerProc(void * pvThis)
  245. {
  246. CEffectState * pThis = (CEffectState *) pvThis;
  247. if (pThis)
  248. {
  249. pThis->_SaveWorkerProc();
  250. }
  251. return 0;
  252. }
  253. HRESULT CEffectState::_SaveWorkerProc(void)
  254. {
  255. HRESULT hr = S_OK;
  256. // First pass to persist the settings.
  257. hr = _SaveSettings(FALSE);
  258. if (SUCCEEDED(hr))
  259. {
  260. // Second pass to broadcast the change. This may hang if apps are hung.
  261. // This pass may only make it half way thru before it aborts. In some cases
  262. // it's only given 30 seconds to do it's work. If no apps are hung, that should be
  263. // fine. This is cancelled after a period of time because we need this process to go
  264. // away, or the Display CPL will not open again if the user launches it again.
  265. hr = _SaveSettings(TRUE);
  266. }
  267. Release();
  268. return hr;
  269. }
  270. // POSSIBLE FUTURE PERF REFINEMENT:
  271. // We could optimize this by checking if we have more than 5 or so
  272. // broadcasts to make. Then don't send the broadcasts on SystemParametersInfo()
  273. // but instead with WM_WININICHANGE with 0,0. This may reduce flicker.
  274. HRESULT CEffectState::_SaveSettings(BOOL fBroadcast)
  275. {
  276. HRESULT hr = S_OK;
  277. BOOL bDorked = FALSE;
  278. DWORD dwUpdateFlags = (fBroadcast ? (SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE) : SPIF_UPDATEINIFILE);
  279. BOOL bSendSettingsChange = FALSE;
  280. // Full Color Icons
  281. if(_nOldHighIconColor != _nHighIconColor)
  282. {
  283. SetRegValueInt(HKEY_CURRENT_USER, SZ_REGKEY_USERMETRICS, SZ_REGVALUE_ICONCOLORDEPTH, _nHighIconColor);
  284. if ((GetBitsPerPixel() < 16) && (_nHighIconColor == 16)) // Display mode won't support icon high colors
  285. {
  286. }
  287. else
  288. {
  289. _nOldHighIconColor = _nHighIconColor;
  290. bSendSettingsChange = TRUE;
  291. }
  292. }
  293. // Full window drag
  294. if (_fOldDragWindow != _fDragWindow)
  295. {
  296. if (fBroadcast)
  297. {
  298. _fOldDragWindow = _fDragWindow;
  299. }
  300. if (!IsTSPerfFlagEnabled(TSPerFlag_NoWindowDrag))
  301. {
  302. ClassicSystemParametersInfo(SPI_SETDRAGFULLWINDOWS, _fDragWindow, 0, dwUpdateFlags);
  303. }
  304. // we need to send this because the tray's autohide switches off this
  305. bSendSettingsChange = TRUE;
  306. }
  307. // Show Menu Shadows
  308. if (_fOldMenuShadows != _fMenuShadows)
  309. {
  310. if (fBroadcast)
  311. {
  312. _fOldMenuShadows = _fMenuShadows;
  313. }
  314. ClassicSystemParametersInfo(SPI_SETDROPSHADOW, 0, IntToPtr(_fMenuShadows), dwUpdateFlags);
  315. // we need to send this because the tray's autohide switches off this
  316. PostMessageBroadAsync(WM_SETTINGCHANGE, 0, 0);
  317. bSendSettingsChange = TRUE;
  318. }
  319. // Font smoothing
  320. if ((_fOldFontSmoothing != _fFontSmoothing) || (_dwOldFontSmoothingType != _dwFontSmoothingType))
  321. {
  322. if (!_fFontSmoothing)
  323. {
  324. // #168059: If font smoothing is off, we need to set SPI_SETFONTSMOOTHINGTYPE to xxx
  325. // Otherwise, it will still use ClearType.
  326. _dwFontSmoothingType = FONT_SMOOTHING_MONO;
  327. }
  328. ClassicSystemParametersInfo(SPI_SETFONTSMOOTHINGTYPE, 0, (PVOID)UlongToPtr(_dwFontSmoothingType), dwUpdateFlags);
  329. if (fBroadcast)
  330. {
  331. _dwOldFontSmoothingType = _dwFontSmoothingType;
  332. _fOldFontSmoothing = _fFontSmoothing;
  333. }
  334. ClassicSystemParametersInfo(SPI_SETFONTSMOOTHING, _fFontSmoothing, 0, dwUpdateFlags);
  335. if (fBroadcast)
  336. {
  337. // Now have the windows repaint with the change. Whistler #179531
  338. RedrawWindow(NULL, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_ERASENOW | RDW_UPDATENOW | RDW_ALLCHILDREN);
  339. }
  340. }
  341. // Menu animations
  342. if ((_wpOldMenuAnimation != _wpMenuAnimation) || (_dwOldAnimationEffect != _dwAnimationEffect))
  343. {
  344. if (fBroadcast)
  345. {
  346. _wpOldMenuAnimation = _wpMenuAnimation;
  347. }
  348. SetAnimations(_wpMenuAnimation, _dwAnimationEffect, dwUpdateFlags);
  349. if (fBroadcast)
  350. {
  351. _dwOldAnimationEffect = _dwAnimationEffect;
  352. }
  353. }
  354. // Keyboard indicators
  355. if (_fOldKeyboardIndicators != _fKeyboardIndicators)
  356. {
  357. if (fBroadcast)
  358. {
  359. _fOldKeyboardIndicators = _fKeyboardIndicators;
  360. }
  361. // Are we turning this on? (!_fKeyboardIndicators means "don't show" -> hide)
  362. if (!_fKeyboardIndicators)
  363. {
  364. // Yes, on: hide the key cues, turn on the mechanism
  365. ClassicSystemParametersInfo(SPI_SETKEYBOARDINDICATORS, 0, IntToPtr(_fKeyboardIndicators), dwUpdateFlags);
  366. PostMessageBroadAsync(WM_CHANGEUISTATE, MAKEWPARAM(UIS_SET, UISF_HIDEFOCUS | UISF_HIDEACCEL), 0);
  367. }
  368. else
  369. {
  370. // No, off: means show the keycues, turn off the mechanism
  371. PostMessageBroadAsync(WM_CHANGEUISTATE, MAKEWPARAM(UIS_CLEAR, UISF_HIDEFOCUS | UISF_HIDEACCEL), 0);
  372. ClassicSystemParametersInfo(SPI_SETKEYBOARDINDICATORS, 0, IntToPtr(_fKeyboardIndicators), dwUpdateFlags);
  373. }
  374. }
  375. // Large Icons
  376. bSendSettingsChange = ChangeIconSizes(_nOldLargeIcon, _nLargeIcon);
  377. if (bSendSettingsChange)
  378. {
  379. if (fBroadcast)
  380. {
  381. _nOldLargeIcon = _nLargeIcon;
  382. }
  383. bDorked = TRUE;
  384. }
  385. // Make the system notice we changed the system icons
  386. if (bDorked)
  387. {
  388. PFNSHUPDATERECYCLEBINICON pfnSHUpdateRecycleBinIcon = NULL;
  389. SHChangeNotify(SHCNE_ASSOCCHANGED, 0, NULL, NULL); // should do the trick!
  390. // Load SHUpdateRecycleBinIcon() if it exists
  391. HINSTANCE hmodShell32 = LoadLibrary(SZ_SHELL32);
  392. if (hmodShell32)
  393. {
  394. pfnSHUpdateRecycleBinIcon = (PFNSHUPDATERECYCLEBINICON)GetProcAddress(hmodShell32, SZ_SHUPDATERECYCLEBINICON);
  395. if (pfnSHUpdateRecycleBinIcon != NULL)
  396. {
  397. pfnSHUpdateRecycleBinIcon();
  398. }
  399. FreeLibrary(hmodShell32);
  400. }
  401. }
  402. if (bSendSettingsChange)
  403. {
  404. // We post this message because if an app is hung or slow, we don't want to hang.
  405. PostMessageBroadAsync(WM_SETTINGCHANGE, 0, 0);
  406. }
  407. return hr;
  408. }
  409. HRESULT CEffectState::Clone(OUT CEffectState ** ppEffectClone)
  410. {
  411. HRESULT hr = E_OUTOFMEMORY;
  412. *ppEffectClone = new CEffectState();
  413. if (*ppEffectClone)
  414. {
  415. hr = S_OK;
  416. (*ppEffectClone)->_nLargeIcon = _nLargeIcon;
  417. (*ppEffectClone)->_nHighIconColor = _nHighIconColor;
  418. (*ppEffectClone)->_wpMenuAnimation = _wpMenuAnimation;
  419. (*ppEffectClone)->_fFontSmoothing = _fFontSmoothing;
  420. (*ppEffectClone)->_dwFontSmoothingType = _dwFontSmoothingType;
  421. (*ppEffectClone)->_fDragWindow = _fDragWindow;
  422. (*ppEffectClone)->_fKeyboardIndicators = _fKeyboardIndicators;
  423. (*ppEffectClone)->_dwAnimationEffect = _dwAnimationEffect;
  424. (*ppEffectClone)->_fMenuShadows = _fMenuShadows;
  425. (*ppEffectClone)->_nOldLargeIcon = _nOldLargeIcon;
  426. (*ppEffectClone)->_nOldHighIconColor = _nOldHighIconColor;
  427. (*ppEffectClone)->_wpOldMenuAnimation = _wpOldMenuAnimation;
  428. (*ppEffectClone)->_fOldFontSmoothing = _fOldFontSmoothing;
  429. (*ppEffectClone)->_dwOldFontSmoothingType = _dwOldFontSmoothingType;
  430. (*ppEffectClone)->_fOldDragWindow = _fOldDragWindow;
  431. (*ppEffectClone)->_fOldKeyboardIndicators = _fOldKeyboardIndicators;
  432. (*ppEffectClone)->_dwOldAnimationEffect = _dwOldAnimationEffect;
  433. (*ppEffectClone)->_fOldMenuShadows = _fOldMenuShadows;
  434. }
  435. return hr;
  436. }
  437. BOOL CEffectState::IsDirty(void)
  438. {
  439. BOOL fDirty = FALSE;
  440. if ((_nLargeIcon != _nOldLargeIcon) ||
  441. (_nHighIconColor != _nOldHighIconColor) ||
  442. (_wpMenuAnimation != _wpOldMenuAnimation) ||
  443. (_fFontSmoothing != _fOldFontSmoothing) ||
  444. (_dwFontSmoothingType != _dwOldFontSmoothingType) ||
  445. (_fDragWindow != _fOldDragWindow) ||
  446. (_fMenuShadows != _fOldMenuShadows) ||
  447. (_fKeyboardIndicators != _fOldKeyboardIndicators) ||
  448. (_dwAnimationEffect != _dwOldAnimationEffect))
  449. {
  450. fDirty = TRUE;
  451. }
  452. return fDirty;
  453. }
  454. ULONG CEffectState::AddRef()
  455. {
  456. return InterlockedIncrement(&m_cRef);
  457. }
  458. ULONG CEffectState::Release()
  459. {
  460. if (InterlockedDecrement(&m_cRef))
  461. return m_cRef;
  462. delete this;
  463. return 0;
  464. }