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.

270 lines
7.0 KiB

  1. #include "shellprv.h"
  2. #include "common.h"
  3. #include "fadetsk.h"
  4. BOOL BlendLayeredWindow(HWND hwnd, HDC hdcDest, POINT* ppt, SIZE* psize, HDC hdc, POINT* pptSrc, BYTE bBlendConst)
  5. {
  6. BLENDFUNCTION blend;
  7. blend.BlendOp = AC_SRC_OVER;
  8. blend.BlendFlags = 0;
  9. blend.AlphaFormat = 0;
  10. blend.SourceConstantAlpha = bBlendConst;
  11. return UpdateLayeredWindow(hwnd, hdcDest, ppt, psize, hdc, pptSrc, 0, &blend, ULW_ALPHA);
  12. }
  13. /// Fade Rect Support
  14. CFadeTask::CFadeTask()
  15. {
  16. _cRef = 1;
  17. WNDCLASSEX wc = {0};
  18. if (!GetClassInfoEx(g_hinst, TEXT("SysFader"), &wc))
  19. {
  20. wc.cbSize = sizeof(wc);
  21. wc.lpfnWndProc = DefWindowProc;
  22. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  23. wc.hInstance = g_hinst;
  24. wc.lpszClassName = TEXT("SysFader");
  25. wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); // NULL;
  26. // If this fails we just wind up with a NULL _hwndFader
  27. RegisterClassEx(&wc);
  28. }
  29. _hwndFader = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT |
  30. WS_EX_TOPMOST | WS_EX_TOOLWINDOW,
  31. TEXT("SysFader"), TEXT("SysFader"),
  32. WS_POPUP,
  33. 0, 0, 0, 0, NULL, (HMENU) 0,
  34. g_hinst, NULL);
  35. }
  36. STDAPI CFadeTask_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
  37. {
  38. HRESULT hr;
  39. *ppv = NULL;
  40. ASSERT(!punkOuter); // clsobj.c should've filtered this out already
  41. CFadeTask *ptFader = new CFadeTask();
  42. if (ptFader)
  43. {
  44. hr = ptFader->QueryInterface(riid, ppv);
  45. ptFader->Release();
  46. }
  47. else
  48. {
  49. hr = E_OUTOFMEMORY;
  50. }
  51. return hr;
  52. }
  53. CFadeTask::~CFadeTask()
  54. {
  55. // Must use WM_CLOSE instead of DestroyWindow to ensure proper
  56. // destruction in case the final release occurs from the background
  57. // thread. (Threads are not allowed to DestroyWindow windows that
  58. // are owned by other threads.)
  59. if (_hwndFader)
  60. SendNotifyMessage(_hwndFader, WM_CLOSE, 0, 0);
  61. }
  62. HRESULT CFadeTask::QueryInterface(REFIID riid, void **ppv)
  63. {
  64. static const QITAB qit[] = {
  65. QITABENT(CFadeTask, IFadeTask),
  66. { 0 },
  67. };
  68. return QISearch(this, qit, riid, ppv);
  69. }
  70. ULONG CFadeTask::AddRef(void)
  71. {
  72. return InterlockedIncrement(&_cRef);
  73. }
  74. ULONG CFadeTask::Release(void)
  75. {
  76. ULONG cRef = InterlockedDecrement(&_cRef);
  77. if (cRef)
  78. return cRef;
  79. delete this;
  80. return 0;
  81. }
  82. #define ALPHASTART (200)
  83. HRESULT CFadeTask::FadeRect(LPCRECT prc)
  84. {
  85. BOOL fThreadStarted = FALSE;
  86. if (_hwndFader)
  87. {
  88. _rect = *prc;
  89. POINT pt;
  90. POINT ptSrc = {0, 0};
  91. SIZE size;
  92. // prc and pt are in screen coordinates.
  93. pt.x = _rect.left;
  94. pt.y = _rect.top;
  95. // Get the size of the rectangle for the blits.
  96. size.cx = RECTWIDTH(_rect);
  97. size.cy = RECTHEIGHT(_rect);
  98. // Get the DC for the screen and window.
  99. HDC hdcScreen = GetDC(NULL);
  100. if (hdcScreen)
  101. {
  102. HDC hdcWin = GetDC(_hwndFader);
  103. if (hdcWin)
  104. {
  105. // If we don't have a HDC for the fade, then create one.
  106. if (!_hdcFade)
  107. {
  108. _hdcFade = CreateCompatibleDC(hdcScreen);
  109. if (!_hdcFade)
  110. goto Stop;
  111. // Create a bitmap that covers the fade region, instead of the whole screen.
  112. _hbm = CreateCompatibleBitmap(hdcScreen, size.cx, size.cy);
  113. if (!_hbm)
  114. goto Stop;
  115. // select it in, saving the old bitmap's handle
  116. _hbmOld = (HBITMAP)SelectBitmap(_hdcFade, _hbm);
  117. }
  118. // Get the stuff from the screen and squirt it into the fade dc.
  119. BitBlt(_hdcFade, 0, 0, size.cx, size.cy, hdcScreen, pt.x, pt.y, SRCCOPY);
  120. // Now let user do it's magic. We're going to mimic user and start with a slightly
  121. // faded, instead of opaque, rendering (Looks smoother and cleaner.
  122. BlendLayeredWindow(_hwndFader, hdcWin, &pt, &size, _hdcFade, &ptSrc, ALPHASTART);
  123. fThreadStarted = SHCreateThread(s_FadeThreadProc, this, 0, s_FadeSyncProc);
  124. Stop:
  125. ReleaseDC(_hwndFader, hdcWin);
  126. }
  127. ReleaseDC(NULL, hdcScreen);
  128. }
  129. if (!fThreadStarted)
  130. {
  131. // clean up member variables on failure
  132. _StopFade();
  133. }
  134. }
  135. return fThreadStarted ? S_OK : E_FAIL;
  136. }
  137. #define FADE_TIMER_ID 10
  138. #define FADE_TIMER_TIMEOUT 10 // milliseconds
  139. #define FADE_TIMEOUT 350 // milliseconds
  140. #define FADE_ITERATIONS 35
  141. #define QUAD_PART(a) ((a)##.QuadPart)
  142. void CFadeTask::_StopFade()
  143. {
  144. if (_hdcFade)
  145. {
  146. if (_hbmOld)
  147. {
  148. SelectBitmap(_hdcFade, _hbmOld);
  149. }
  150. DeleteDC(_hdcFade);
  151. _hdcFade = NULL;
  152. }
  153. if (_hbm)
  154. {
  155. DeleteObject(_hbm);
  156. _hbm = NULL;
  157. }
  158. }
  159. DWORD CFadeTask::s_FadeSyncProc(LPVOID lpThreadParameter)
  160. {
  161. CFadeTask* pThis = (CFadeTask*)lpThreadParameter;
  162. pThis->AddRef();
  163. pThis->_DoPreFade();
  164. return 0;
  165. }
  166. DWORD CFadeTask::s_FadeThreadProc(LPVOID lpThreadParameter)
  167. {
  168. CFadeTask* pThis = (CFadeTask*)lpThreadParameter;
  169. pThis->_DoFade();
  170. pThis->Release();
  171. return 0;
  172. }
  173. void CFadeTask::_DoPreFade()
  174. {
  175. // Now that we have it all build up, display it on screen.
  176. SetWindowPos(_hwndFader, HWND_TOPMOST, 0, 0, 0, 0,
  177. SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
  178. }
  179. void CFadeTask::_DoFade()
  180. {
  181. LARGE_INTEGER liDiff;
  182. LARGE_INTEGER liFreq;
  183. LARGE_INTEGER liStart;
  184. DWORD dwElapsed;
  185. BYTE bBlendConst;
  186. // Start the fade timer and the count-down for the fade.
  187. QueryPerformanceFrequency(&liFreq);
  188. QueryPerformanceCounter(&liStart);
  189. // Do this until the conditions specified in the loop.
  190. while ( TRUE )
  191. {
  192. // Calculate the elapsed time in milliseconds.
  193. QueryPerformanceCounter(&liDiff);
  194. QUAD_PART(liDiff) -= QUAD_PART(liStart);
  195. dwElapsed = (DWORD)((QUAD_PART(liDiff) * 1000) / QUAD_PART(liFreq));
  196. if (dwElapsed >= FADE_TIMEOUT)
  197. {
  198. goto Stop;
  199. }
  200. bBlendConst = (BYTE)(ALPHASTART * (FADE_TIMEOUT -
  201. dwElapsed) / FADE_TIMEOUT);
  202. if (bBlendConst <= 1)
  203. {
  204. goto Stop;
  205. }
  206. // Since only the alpha is updated, there is no need to pass
  207. // anything but the new alpha function. This saves a source copy.
  208. if (!BlendLayeredWindow(_hwndFader, NULL, NULL, NULL, NULL, NULL, bBlendConst))
  209. {
  210. // The app we just launched probably switched the screen into
  211. // a video mode that doesn't support layered windows, so just bail.
  212. goto Stop;
  213. }
  214. Sleep(FADE_TIMER_TIMEOUT);
  215. }
  216. Stop:
  217. SetWindowPos(_hwndFader, HWND_BOTTOM, 0, 0, 0, 0,
  218. SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW);
  219. _StopFade();
  220. }