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.

271 lines
7.3 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. ASSERT( 0 != _cRef );
  77. ULONG cRef = InterlockedDecrement(&_cRef);
  78. if ( 0 == cRef )
  79. {
  80. delete this;
  81. }
  82. return cRef;
  83. }
  84. #define ALPHASTART (200)
  85. HRESULT CFadeTask::FadeRect(LPCRECT prc)
  86. {
  87. BOOL fThreadStarted = FALSE;
  88. if (_hwndFader)
  89. {
  90. _rect = *prc;
  91. POINT pt;
  92. POINT ptSrc = {0, 0};
  93. SIZE size;
  94. // prc and pt are in screen coordinates.
  95. pt.x = _rect.left;
  96. pt.y = _rect.top;
  97. // Get the size of the rectangle for the blits.
  98. size.cx = RECTWIDTH(_rect);
  99. size.cy = RECTHEIGHT(_rect);
  100. // Get the DC for the screen and window.
  101. HDC hdcScreen = GetDC(NULL);
  102. if (hdcScreen)
  103. {
  104. HDC hdcWin = GetDC(_hwndFader);
  105. if (hdcWin)
  106. {
  107. // If we don't have a HDC for the fade, then create one.
  108. if (!_hdcFade)
  109. {
  110. _hdcFade = CreateCompatibleDC(hdcScreen);
  111. if (!_hdcFade)
  112. goto Stop;
  113. // Create a bitmap that covers the fade region, instead of the whole screen.
  114. _hbm = CreateCompatibleBitmap(hdcScreen, size.cx, size.cy);
  115. if (!_hbm)
  116. goto Stop;
  117. // select it in, saving the old bitmap's handle
  118. _hbmOld = (HBITMAP)SelectBitmap(_hdcFade, _hbm);
  119. }
  120. // Get the stuff from the screen and squirt it into the fade dc.
  121. BitBlt(_hdcFade, 0, 0, size.cx, size.cy, hdcScreen, pt.x, pt.y, SRCCOPY);
  122. // Now let user do it's magic. We're going to mimic user and start with a slightly
  123. // faded, instead of opaque, rendering (Looks smoother and cleaner.
  124. BlendLayeredWindow(_hwndFader, hdcWin, &pt, &size, _hdcFade, &ptSrc, ALPHASTART);
  125. fThreadStarted = SHCreateThread(s_FadeThreadProc, this, 0, s_FadeSyncProc);
  126. Stop:
  127. ReleaseDC(_hwndFader, hdcWin);
  128. }
  129. ReleaseDC(NULL, hdcScreen);
  130. }
  131. if (!fThreadStarted)
  132. {
  133. // clean up member variables on failure
  134. _StopFade();
  135. }
  136. }
  137. return fThreadStarted ? S_OK : E_FAIL;
  138. }
  139. #define FADE_TIMER_ID 10
  140. #define FADE_TIMER_TIMEOUT 10 // milliseconds
  141. #define FADE_TIMEOUT 350 // milliseconds
  142. #define FADE_ITERATIONS 35
  143. #define QUAD_PART(a) ((a)##.QuadPart)
  144. void CFadeTask::_StopFade()
  145. {
  146. if (_hdcFade)
  147. {
  148. if (_hbmOld)
  149. {
  150. SelectBitmap(_hdcFade, _hbmOld);
  151. }
  152. DeleteDC(_hdcFade);
  153. _hdcFade = NULL;
  154. }
  155. if (_hbm)
  156. {
  157. DeleteObject(_hbm);
  158. _hbm = NULL;
  159. }
  160. }
  161. DWORD CFadeTask::s_FadeSyncProc(LPVOID lpThreadParameter)
  162. {
  163. CFadeTask* pThis = (CFadeTask*)lpThreadParameter;
  164. pThis->AddRef();
  165. pThis->_DoPreFade();
  166. return 0;
  167. }
  168. DWORD CFadeTask::s_FadeThreadProc(LPVOID lpThreadParameter)
  169. {
  170. CFadeTask* pThis = (CFadeTask*)lpThreadParameter;
  171. pThis->_DoFade();
  172. pThis->Release();
  173. return 0;
  174. }
  175. void CFadeTask::_DoPreFade()
  176. {
  177. // Now that we have it all build up, display it on screen.
  178. SetWindowPos(_hwndFader, HWND_TOPMOST, 0, 0, 0, 0,
  179. SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
  180. }
  181. void CFadeTask::_DoFade()
  182. {
  183. LARGE_INTEGER liDiff;
  184. LARGE_INTEGER liFreq;
  185. LARGE_INTEGER liStart;
  186. DWORD dwElapsed;
  187. BYTE bBlendConst;
  188. // Start the fade timer and the count-down for the fade.
  189. QueryPerformanceFrequency(&liFreq);
  190. QueryPerformanceCounter(&liStart);
  191. // Do this until the conditions specified in the loop.
  192. while ( TRUE )
  193. {
  194. // Calculate the elapsed time in milliseconds.
  195. QueryPerformanceCounter(&liDiff);
  196. QUAD_PART(liDiff) -= QUAD_PART(liStart);
  197. dwElapsed = (DWORD)((QUAD_PART(liDiff) * 1000) / QUAD_PART(liFreq));
  198. if (dwElapsed >= FADE_TIMEOUT)
  199. {
  200. goto Stop;
  201. }
  202. bBlendConst = (BYTE)(ALPHASTART * (FADE_TIMEOUT -
  203. dwElapsed) / FADE_TIMEOUT);
  204. if (bBlendConst <= 1)
  205. {
  206. goto Stop;
  207. }
  208. // Since only the alpha is updated, there is no need to pass
  209. // anything but the new alpha function. This saves a source copy.
  210. if (!BlendLayeredWindow(_hwndFader, NULL, NULL, NULL, NULL, NULL, bBlendConst))
  211. {
  212. // The app we just launched probably switched the screen into
  213. // a video mode that doesn't support layered windows, so just bail.
  214. goto Stop;
  215. }
  216. Sleep(FADE_TIMER_TIMEOUT);
  217. }
  218. Stop:
  219. SetWindowPos(_hwndFader, HWND_BOTTOM, 0, 0, 0, 0,
  220. SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW);
  221. _StopFade();
  222. }