#include "priv.h" #include "fadetsk.h" #include "apithk.h" /// Fade Rect Support // {2DECD184-21B0-11d2-8385-00C04FD918D0} const GUID TASKID_Fader = { 0x2decd184, 0x21b0, 0x11d2, { 0x83, 0x85, 0x0, 0xc0, 0x4f, 0xd9, 0x18, 0xd0 } }; CFadeTask::CFadeTask() : CRunnableTask(RTF_DEFAULT) { ASSERT(g_bRunOnNT5); // This should only get created on NT5 WNDCLASSEX wc = {0}; if (!GetClassInfoEx(g_hinst, TEXT("SysFader"), &wc)) { wc.cbSize = sizeof(wc); wc.lpfnWndProc = DefWindowProc; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hInstance = g_hinst; wc.lpszClassName = TEXT("SysFader"); wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); // NULL; if (!RegisterClassEx(&wc)) return; } _hwndFader = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_TOPMOST | WS_EX_TOOLWINDOW, TEXT("SysFader"), TEXT("SysFader"), WS_POPUP, 0, 0, 0, 0, NULL, (HMENU) 0, g_hinst, NULL); } CFadeTask::~CFadeTask() { if (_hwndFader) DestroyWindow(_hwndFader); } #define ALPHASTART (200) BOOL CFadeTask::FadeRect(PRECT prc, PFNFADESCREENRECT pfn, LPVOID pvParam) { if (IsRunning() == IRTIR_TASK_RUNNING) return FALSE; InterlockedExchange(&_lState, IRTIR_TASK_NOT_RUNNING); _rect = *prc; _pfn = pfn; _pvParam = pvParam; POINT pt; POINT ptSrc = {0, 0}; SIZE size; // prc and pt are in screen coordinates. pt.x = _rect.left; pt.y = _rect.top; // Get the size of the rectangle for the blits. size.cx = RECTWIDTH(_rect); size.cy = RECTHEIGHT(_rect); // Get the DC for the screen and window. HDC hdcScreen = GetDC(NULL); if (hdcScreen) { HDC hdcWin = GetDC(_hwndFader); if (hdcWin) { // If we don't have a HDC for the fade, then create one. if (!_hdcFade) { _hdcFade = CreateCompatibleDC(hdcScreen); if (!_hdcFade) goto Stop; // Create a bitmap that covers the fade region, instead of the whole screen. _hbm = CreateCompatibleBitmap(hdcScreen, size.cx, size.cy); if (!_hbm) goto Stop; // select it in, saving the old bitmap's handle _hbmOld = (HBITMAP)SelectBitmap(_hdcFade, _hbm); } // Get the stuff from the screen and squirt it into the fade dc. BitBlt(_hdcFade, 0, 0, size.cx, size.cy, hdcScreen, pt.x, pt.y, SRCCOPY); // Now let user do it's magic. We're going to mimic user and start with a slightly // faded, instead of opaque, rendering (Looks smoother and cleaner. BlendLayeredWindow(_hwndFader, hdcWin, &pt, &size, _hdcFade, &ptSrc, ALPHASTART); // Now that we have it all build up, display it on screen. SetWindowPos(_hwndFader, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); Stop: ReleaseDC(_hwndFader, hdcWin); } ReleaseDC(NULL, hdcScreen); } if (_pfn) _pfn(FADE_BEGIN, _pvParam); return TRUE; } #define FADE_TIMER_ID 10 #define FADE_TIMER_TIMEOUT 10 // milliseconds #define FADE_TIMEOUT 350 // milliseconds #define FADE_ITERATIONS 35 #define QUAD_PART(a) ((a)##.QuadPart) void CFadeTask::_StopFade() { if (_hwndFader) { SetWindowPos(_hwndFader, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW); } if (_pfn) _pfn(FADE_END, _pvParam); if (_hdcFade) { if (_hbmOld) { SelectBitmap(_hdcFade, _hbmOld); } DeleteDC(_hdcFade); _hdcFade = NULL; } if (_hbm) { DeleteObject(_hbm); _hbm = NULL; } } STDMETHODIMP CFadeTask::RunInitRT(void) { BOOL fRet = FALSE; LARGE_INTEGER liDiff; LARGE_INTEGER liFreq; LARGE_INTEGER liStart; DWORD dwElapsed; BYTE bBlendConst; // Start the fade timer and the count-down for the fade. QueryPerformanceFrequency(&liFreq); QueryPerformanceCounter(&liStart); // Do this until the conditions specified in the loop. while ( TRUE ) { // Calculate the elapsed time in milliseconds. QueryPerformanceCounter(&liDiff); QUAD_PART(liDiff) -= QUAD_PART(liStart); dwElapsed = (DWORD)((QUAD_PART(liDiff) * 1000) / QUAD_PART(liFreq)); if (dwElapsed >= FADE_TIMEOUT) { goto Stop; } bBlendConst = (BYTE)(ALPHASTART * (FADE_TIMEOUT - dwElapsed) / FADE_TIMEOUT); if (bBlendConst <= 1) { goto Stop; } // Since only the alpha is updated, there is no need to pass // anything but the new alpha function. This saves a source copy. BlendLayeredWindow(_hwndFader, NULL, NULL, NULL, NULL, NULL, bBlendConst); Sleep(FADE_TIMER_TIMEOUT); } Stop: _StopFade(); return S_OK; }