|
|
#include "shellprv.h"
#include "common.h"
#include "fadetsk.h"
BOOL BlendLayeredWindow(HWND hwnd, HDC hdcDest, POINT* ppt, SIZE* psize, HDC hdc, POINT* pptSrc, BYTE bBlendConst) { BLENDFUNCTION blend; blend.BlendOp = AC_SRC_OVER; blend.BlendFlags = 0; blend.AlphaFormat = 0; blend.SourceConstantAlpha = bBlendConst;
return UpdateLayeredWindow(hwnd, hdcDest, ppt, psize, hdc, pptSrc, 0, &blend, ULW_ALPHA); }
/// Fade Rect Support
CFadeTask::CFadeTask() { _cRef = 1;
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 this fails we just wind up with a NULL _hwndFader
RegisterClassEx(&wc); } _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); }
STDAPI CFadeTask_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv) { HRESULT hr; *ppv = NULL;
ASSERT(!punkOuter); // clsobj.c should've filtered this out already
CFadeTask *ptFader = new CFadeTask(); if (ptFader) { hr = ptFader->QueryInterface(riid, ppv); ptFader->Release(); } else { hr = E_OUTOFMEMORY; } return hr; }
CFadeTask::~CFadeTask() { // Must use WM_CLOSE instead of DestroyWindow to ensure proper
// destruction in case the final release occurs from the background
// thread. (Threads are not allowed to DestroyWindow windows that
// are owned by other threads.)
if (_hwndFader) SendNotifyMessage(_hwndFader, WM_CLOSE, 0, 0); }
HRESULT CFadeTask::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CFadeTask, IFadeTask), { 0 }, };
return QISearch(this, qit, riid, ppv); }
ULONG CFadeTask::AddRef(void) { return InterlockedIncrement(&_cRef); }
ULONG CFadeTask::Release(void) { ULONG cRef = InterlockedDecrement(&_cRef); if (cRef) return cRef;
delete this; return 0; }
#define ALPHASTART (200)
HRESULT CFadeTask::FadeRect(LPCRECT prc) { BOOL fThreadStarted = FALSE;
if (_hwndFader) { _rect = *prc;
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);
fThreadStarted = SHCreateThread(s_FadeThreadProc, this, 0, s_FadeSyncProc); Stop: ReleaseDC(_hwndFader, hdcWin); }
ReleaseDC(NULL, hdcScreen); }
if (!fThreadStarted) { // clean up member variables on failure
_StopFade(); } }
return fThreadStarted ? S_OK : E_FAIL; }
#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 (_hdcFade) { if (_hbmOld) { SelectBitmap(_hdcFade, _hbmOld); } DeleteDC(_hdcFade); _hdcFade = NULL; } if (_hbm) { DeleteObject(_hbm); _hbm = NULL; } }
DWORD CFadeTask::s_FadeSyncProc(LPVOID lpThreadParameter) { CFadeTask* pThis = (CFadeTask*)lpThreadParameter; pThis->AddRef(); pThis->_DoPreFade(); return 0; }
DWORD CFadeTask::s_FadeThreadProc(LPVOID lpThreadParameter) { CFadeTask* pThis = (CFadeTask*)lpThreadParameter; pThis->_DoFade(); pThis->Release(); return 0; }
void CFadeTask::_DoPreFade() { // 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); }
void CFadeTask::_DoFade() { 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.
if (!BlendLayeredWindow(_hwndFader, NULL, NULL, NULL, NULL, NULL, bBlendConst)) { // The app we just launched probably switched the screen into
// a video mode that doesn't support layered windows, so just bail.
goto Stop; } Sleep(FADE_TIMER_TIMEOUT); }
Stop: SetWindowPos(_hwndFader, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW);
_StopFade(); }
|