193 lines
5.1 KiB
C++
193 lines
5.1 KiB
C++
|
#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;
|
||
|
}
|