windows-nt/Source/XPSP1/NT/shell/themes/themeui/coverwnd.cpp
2020-09-26 16:20:57 +08:00

636 lines
22 KiB
C++

#include "priv.h"
#include "CoverWnd.h"
#include <ginarcid.h>
#undef IDB_BACKGROUND_24
#define IDB_BACKGROUND_24 0x3812
#undef IDB_FLAG_24
#define IDB_FLAG_24 0x3813
const TCHAR g_szWindowClassName[] = TEXT("CoverWindowClass");
const TCHAR g_szPleaseWaitName[] = TEXT("PleaseWaitWindowClass");
#define CHUNK_SIZE 20
#define IDT_KILLYOURSELF 1
#define IDT_UPDATE 2
#define WM_DESTORYYOURSELF (WM_USER + 0)
void DimPixels(ULONG* pulSrc, int cLen, int Amount)
{
for (int i = cLen - 1; i >= 0; i--)
{
ULONG ulR = GetRValue(*pulSrc);
ULONG ulG = GetGValue(*pulSrc);
ULONG ulB = GetBValue(*pulSrc);
ULONG ulGray = (54 * ulR + 183 * ulG + 19 * ulB) >> 8;
ULONG ulTemp = ulGray * (0xff - Amount);
ulR = (ulR * Amount + ulTemp) >> 8;
ulG = (ulG * Amount + ulTemp) >> 8;
ulB = (ulB * Amount + ulTemp) >> 8;
*pulSrc = (*pulSrc & 0xff000000) | RGB(ulR, ulG, ulB);
pulSrc++;
}
}
LRESULT CALLBACK PleaseWaitWndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lParam)
{
switch ( msg )
{
case WM_CREATE:
{
CREATESTRUCT* pCS = (CREATESTRUCT*)lParam;
SetWindowLongPtr( hwnd, GWLP_USERDATA, (LPARAM) pCS->lpCreateParams );
HBITMAP hbmBackground = (HBITMAP) pCS->lpCreateParams;
BITMAP bm;
if ( GetObject( hbmBackground, sizeof(bm), &bm ) )
{
RECT rc;
HWND hwndParent = GetParent( hwnd );
GetClientRect( hwndParent, &rc );
POINT pt = {0,0};
HMONITOR hmon = MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
if (hmon)
{
MONITORINFO mi = {sizeof(mi)};
GetMonitorInfo(hmon, &mi);
rc = mi.rcMonitor;
MapWindowPoints(HWND_DESKTOP, hwndParent, (LPPOINT)&rc, 2);
}
// Center dialog in the center of the virtual screen
int x = ( rc.right - rc.left - bm.bmWidth ) / 2;
int y = ( rc.bottom - rc.top - bm.bmHeight ) / 2;
SetWindowPos( hwnd, NULL, x, y, bm.bmWidth, bm.bmHeight, SWP_NOZORDER | SWP_NOACTIVATE );
}
}
return TRUE;
case WM_PAINT:
{
HBITMAP hbmBackground = (HBITMAP) GetWindowLongPtr( hwnd, GWLP_USERDATA );
PAINTSTRUCT ps;
HDC hdc = BeginPaint( hwnd, &ps );
BITMAP bm;
if ( hbmBackground )
{
DWORD dwLayout = SetLayout(hdc, LAYOUT_BITMAPORIENTATIONPRESERVED);
if ( GetObject( hbmBackground, sizeof(bm), &bm ) )
{
HDC hdcBackground = CreateCompatibleDC( hdc );
if (hdcBackground)
{
HBITMAP hbmOld = (HBITMAP) SelectObject( hdcBackground, hbmBackground );
BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdcBackground, 0, 0, SRCCOPY);
SelectObject( hdcBackground, hbmOld );
DeleteDC( hdcBackground );
}
}
SetLayout(hdc, dwLayout);
// Don't draw more the once, no one will be on top of us
DeleteObject(hbmBackground);
SetWindowLongPtr( hwnd, GWLP_USERDATA, NULL );
HFONT hfntSelected = NULL;
HFONT hfntButton = NULL;
HINSTANCE hMsGina = LoadLibrary( L"msgina.dll" );
if ( hMsGina )
{
CHAR szPixelSize[ 32 ];
if (LoadStringA(hMsGina,
IDS_TURNOFF_TITLE_FACESIZE,
szPixelSize,
ARRAYSIZE(szPixelSize)) != 0)
{
LOGFONT logFont = { 0 };
logFont.lfHeight = -MulDiv(atoi(szPixelSize), GetDeviceCaps(hdc, LOGPIXELSY), 72);
if (LoadString(hMsGina,
IDS_TURNOFF_TITLE_FACENAME,
logFont.lfFaceName,
LF_FACESIZE) != 0)
{
logFont.lfWeight = FW_BOLD;
logFont.lfQuality = DEFAULT_QUALITY;
hfntButton = CreateFontIndirect(&logFont);
hfntSelected = static_cast<HFONT>(SelectObject(hdc, hfntButton));
}
}
}
COLORREF colorButtonText = RGB(255, 255, 255);
COLORREF colorText = SetTextColor(hdc, colorButtonText);
int iBkMode = SetBkMode(hdc, TRANSPARENT);
WCHAR szText[MAX_PATH];
szText[0] = 0;
LoadString((HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), IDS_PLEASEWAIT, szText, ARRAYSIZE(szText));
RECT rcText;
RECT rcClient;
RECT rc;
TBOOL(GetClientRect( hwnd, &rcClient ));
TBOOL(CopyRect(&rcText, &rcClient));
DWORD dwFlags = DT_HIDEPREFIX | (IS_MIRRORING_ENABLED() ? DT_RTLREADING : 0);
int iPixelHeight = DrawText( hdc, szText, -1, &rcText, DT_CALCRECT | dwFlags);
TBOOL(CopyRect(&rc, &rcClient));
TBOOL(InflateRect(&rc, -((rc.right - rc.left - (rcText.right - rcText.left)) / 2), -((rc.bottom - rc.top - iPixelHeight) / 2)));
(int)DrawText(hdc, szText, -1, &rc, dwFlags );
(int)SetBkMode(hdc, iBkMode);
(COLORREF)SetTextColor(hdc, colorText);
if ( hfntButton )
{
(HGDIOBJ)SelectObject(hdc, hfntSelected);
DeleteObject( hfntButton );
}
}
EndPaint( hwnd, &ps );
}
break;
case WM_ERASEBKGND:
return TRUE;
default:
return DefWindowProc( hwnd, msg, wp, lParam );
break;
}
return 0;
}
CDimmedWindow::CDimmedWindow (HINSTANCE hInstance) :
_lReferenceCount(1),
_hInstance(hInstance)
{
WNDCLASSEX wndClassEx;
ZeroMemory(&wndClassEx, sizeof(wndClassEx));
wndClassEx.cbSize = sizeof(wndClassEx);
wndClassEx.lpfnWndProc = WndProc;
wndClassEx.hInstance = hInstance;
wndClassEx.lpszClassName = g_szWindowClassName;
wndClassEx.hCursor = LoadCursor(NULL, IDC_WAIT);
_atom = RegisterClassEx(&wndClassEx);
wndClassEx.lpszClassName = g_szPleaseWaitName;
wndClassEx.lpfnWndProc = PleaseWaitWndProc;
_atomPleaseWait = RegisterClassEx(&wndClassEx);
}
CDimmedWindow::~CDimmedWindow (void)
{
if (_hwnd)
{
PostMessage(_hwnd, WM_DESTORYYOURSELF, 0, 0);
}
if (_atom != 0)
{
TBOOL(UnregisterClass(MAKEINTRESOURCE(_atom), _hInstance));
}
if (_atomPleaseWait != 0 )
{
TBOOL(UnregisterClass(MAKEINTRESOURCE(_atomPleaseWait), _hInstance));
}
}
ULONG CDimmedWindow::AddRef (void)
{
return(InterlockedIncrement(&_lReferenceCount));
}
ULONG CDimmedWindow::Release (void)
{
LONG lReferenceCount;
lReferenceCount = InterlockedDecrement(&_lReferenceCount);
ASSERTMSG(lReferenceCount >= 0, "Reference count negative or zero in CDimmedWindow::Release");
if (lReferenceCount == 0)
{
delete this;
}
return(lReferenceCount);
}
DWORD CDimmedWindow::WorkerThread(IN void *pv)
{
ASSERT(pv);
HWND hwnd = NULL;
CDimmedWindow* pDimmedWindow = (CDimmedWindow*)pv;
BOOL fScreenReader;
bool fNoDebuggerPresent, fNoScreenReaderPresent;
BOOL fUserTurnedOffWindow = SHRegGetBoolUSValue(SZ_THEMES, L"NoCoverWindow", FALSE, FALSE); // Needed for perf testing
fNoDebuggerPresent = !IsDebuggerPresent();
fNoScreenReaderPresent = ((SystemParametersInfo(SPI_GETSCREENREADER, 0, &fScreenReader, 0) == FALSE) || (fScreenReader == FALSE));
if (fNoDebuggerPresent &&
fNoScreenReaderPresent &&
!fUserTurnedOffWindow)
{
int xVirtualScreen = GetSystemMetrics(SM_XVIRTUALSCREEN);
int yVirtualScreen = GetSystemMetrics(SM_YVIRTUALSCREEN);
int cxVirtualScreen = GetSystemMetrics(SM_CXVIRTUALSCREEN);
int cyVirtualScreen = GetSystemMetrics(SM_CYVIRTUALSCREEN);
HWND hwnd = CreateWindowEx(WS_EX_TOPMOST,
g_szWindowClassName,
NULL,
WS_POPUP | WS_CLIPCHILDREN,
xVirtualScreen, yVirtualScreen,
cxVirtualScreen, cyVirtualScreen,
NULL, NULL, pDimmedWindow->_hInstance, NULL);
if (hwnd != NULL)
{
bool fDimmed;
HBITMAP hbmBackground = NULL;
fDimmed = false;
(BOOL)ShowWindow(hwnd, SW_SHOW);
TBOOL(SetForegroundWindow(hwnd));
(BOOL)EnableWindow(hwnd, FALSE);
SetTimer(hwnd, IDT_KILLYOURSELF, pDimmedWindow->_ulKillTimer, NULL);
// Now create bitmap with background image and the windows flag
HINSTANCE hShell32 = LoadLibrary( L"shell32.dll" );
if ( NULL != hShell32 )
{
hbmBackground = (HBITMAP) LoadImage( hShell32, MAKEINTRESOURCE( IDB_BACKGROUND_24 ), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE );
if (hbmBackground)
{
HDC hdcMem1 = CreateCompatibleDC(NULL);
if (hdcMem1)
{
HDC hdcMem2 = CreateCompatibleDC(NULL);
if (hdcMem2)
{
HBITMAP hbmFlag = (HBITMAP) LoadImage( hShell32, MAKEINTRESOURCE( IDB_FLAG_24 ), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE );
if (hbmFlag)
{
HBITMAP hbmOld1 = (HBITMAP)SelectObject(hdcMem1, hbmBackground);
HBITMAP hbmOld2 = (HBITMAP)SelectObject(hdcMem2, hbmFlag);
BITMAP bm1;
if (GetObject(hbmBackground, sizeof(bm1), &bm1))
{
BITMAP bm2;
if (GetObject(hbmFlag, sizeof(bm2), &bm2))
{
BitBlt(hdcMem1, bm1.bmWidth - bm2.bmWidth - 8, 0, bm2.bmWidth, bm2.bmHeight, hdcMem2, 0, 0, SRCCOPY);
}
}
SelectObject(hdcMem1, hbmOld1);
SelectObject(hdcMem2, hbmOld2);
DeleteObject(hbmFlag);
}
DeleteDC(hdcMem2);
}
DeleteDC(hdcMem1);
}
}
FreeLibrary( hShell32 );
}
HWND hwndPleaseWait = CreateWindowEx( 0
, g_szPleaseWaitName
, NULL
, WS_CHILD | WS_VISIBLE | WS_BORDER
, 0
, 0
, 100
, 100
, hwnd
, NULL
, pDimmedWindow->_hInstance
, hbmBackground // the window is responsible for freeing it.
);
if ( NULL == hwndPleaseWait )
{
DeleteObject( hbmBackground );
}
pDimmedWindow->_hwnd = hwnd;
// This Release matches the addref during ::Create to guarantee that the object does not die before the HWND
// is created.
pDimmedWindow->Release();
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if ((msg.message == WM_DESTORYYOURSELF) && (msg.hwnd == hwnd))
{
break;
}
}
}
}
return (hwnd == NULL ? E_FAIL : S_OK);
}
HRESULT CDimmedWindow::Create (UINT ulKillTimer)
{
BOOL fSucceeded = FALSE;
if (!_hwnd)
{
_ulKillTimer = ulKillTimer;
AddRef();
fSucceeded = SHCreateThread(CDimmedWindow::WorkerThread, (void *)this, CTF_INSIST, NULL);
if (!fSucceeded)
{
Release();
}
}
return fSucceeded ? S_OK : E_FAIL;
}
typedef struct
{
HDC hdcDimmed;
HBITMAP hbmDimmed;
HBITMAP hbmOldDimmed;
HDC hdcTemp;
HBITMAP hbmTemp;
HBITMAP hbmOldTemp;
ULONG* pulSrc;
int idxSaturation;
int idxChunk;
int idxProgress;
} DIMMEDWINDOWDATA;
LRESULT CALLBACK CDimmedWindow::WndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT lResult = 0;
DIMMEDWINDOWDATA *pData;
pData = (DIMMEDWINDOWDATA *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
switch (uMsg)
{
case WM_CREATE:
{
CREATESTRUCT* pCS = (CREATESTRUCT*)lParam;
if (pCS)
{
pData = new DIMMEDWINDOWDATA;
if (pData)
{
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pData);
// On remote session we don't gray out the screen, yeah :-)
if (!GetSystemMetrics(SM_REMOTESESSION))
{
HDC hdcWindow = GetDC(hwnd);
if (hdcWindow != NULL )
{
pData->hdcDimmed = CreateCompatibleDC(hdcWindow);
if (pData->hdcDimmed)
{
BITMAPINFO bmi;
ZeroMemory(&bmi, sizeof(bmi));
bmi.bmiHeader.biSize = sizeof(bmi);
bmi.bmiHeader.biWidth = pCS->cx;
bmi.bmiHeader.biHeight = pCS->cy;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = 0;
pData->hbmDimmed = CreateDIBSection(pData->hdcDimmed, &bmi, DIB_RGB_COLORS, (LPVOID*)&pData->pulSrc, NULL, 0);
if (pData->hbmDimmed != NULL)
{
pData->hbmOldDimmed = (HBITMAP) SelectObject(pData->hdcDimmed, pData->hbmDimmed);
pData->idxSaturation = 8;
pData->idxChunk = pCS->cy / CHUNK_SIZE;
}
else
{
DeleteDC(pData->hdcDimmed);
pData->hdcDimmed = NULL;
}
}
pData->hdcTemp = CreateCompatibleDC(hdcWindow);
if (pData->hdcTemp)
{
pData->hbmTemp = CreateCompatibleBitmap(hdcWindow, pCS->cx, pCS->cy);
if (pData->hbmTemp)
{
pData->hbmOldTemp = (HBITMAP) SelectObject(pData->hdcTemp, pData->hbmTemp);
}
else
{
DeleteDC(pData->hdcTemp);
pData->hdcTemp = NULL;
}
}
ReleaseDC(hwnd, hdcWindow);
}
}
if (pData->hdcDimmed)
{
SetTimer(hwnd, IDT_UPDATE, 30, NULL);
}
}
}
break;
}
case WM_DESTORYYOURSELF:
{
DestroyWindow(hwnd);
break;
}
case WM_DESTROY:
{
if (pData)
{
SetWindowLongPtr(hwnd, GWLP_USERDATA, NULL);
KillTimer(hwnd, IDT_UPDATE);
KillTimer(hwnd, IDT_KILLYOURSELF);
if (pData->hdcDimmed)
{
SelectObject(pData->hdcDimmed, pData->hbmOldDimmed);
DeleteDC(pData->hdcDimmed);
pData->hdcDimmed = NULL;
}
if (pData->hbmDimmed)
{
DeleteObject(pData->hbmDimmed);
pData->hbmDimmed = NULL;
}
if (pData->hdcTemp)
{
SelectObject(pData->hdcTemp, pData->hbmOldTemp);
DeleteDC(pData->hdcTemp);
pData->hdcTemp = NULL;
}
if (pData->hbmTemp)
{
DeleteObject(pData->hbmTemp);
pData->hbmTemp = NULL;
}
delete pData;
}
break;
}
case WM_TIMER:
if (pData)
{
BOOL fDestroyBitmaps = FALSE;
if (wParam == IDT_KILLYOURSELF)
{
ShowWindow(hwnd, SW_HIDE);
fDestroyBitmaps = TRUE;
}
else if (pData->hdcDimmed && pData->hbmDimmed)
{
HDC hdcWindow = GetDC(hwnd);
BITMAP bm;
GetObject(pData->hbmDimmed, sizeof(BITMAP), &bm);
if (pData->idxChunk >= 0 )
{
//
// In the first couple of passes, we slowly collect the screen
// into our bitmap. We do this because Blt-ing the whole thing
// causes the system to hang. By doing it this way, we continue
// to pump messages, the UI stays responsive and it keeps the
// mouse alive.
//
int y = pData->idxChunk * CHUNK_SIZE;
if (pData->hdcTemp)
{
BitBlt(pData->hdcTemp, 0, y, bm.bmWidth, CHUNK_SIZE, hdcWindow, 0, y, SRCCOPY);
BitBlt(pData->hdcDimmed, 0, y, bm.bmWidth, CHUNK_SIZE, pData->hdcTemp, 0, y, SRCCOPY);
}
else
{
BitBlt(pData->hdcDimmed, 0, y, bm.bmWidth, CHUNK_SIZE, hdcWindow, 0, y, SRCCOPY);
}
pData->idxChunk--;
if (pData->idxChunk < 0)
{
//
// We're done getting the bitmap, now reset the timer
// so we slowly fade to grey.
//
SetTimer(hwnd, IDT_UPDATE, 250, NULL);
pData->idxSaturation = 16;
}
}
else
{
//
// In these passes, we are making the image more and more grey and
// then Blt-ing the result to the screen.
//
DimPixels(pData->pulSrc, bm.bmWidth * bm.bmHeight, 0xd5);
BitBlt(hdcWindow, 0, 0, bm.bmWidth, bm.bmHeight, pData->hdcDimmed, 0, 0, SRCCOPY);
pData->idxSaturation--;
if (pData->idxSaturation <= 0) // when we hit zero, kill the timer.
{
KillTimer(hwnd, IDT_UPDATE);
fDestroyBitmaps = TRUE;
}
}
}
if (fDestroyBitmaps)
{
if (pData->hdcDimmed)
{
SelectObject(pData->hdcDimmed, pData->hbmOldDimmed);
DeleteDC(pData->hdcDimmed);
pData->hdcDimmed = NULL;
}
if (pData->hbmDimmed)
{
DeleteObject(pData->hbmDimmed);
pData->hbmDimmed = NULL;
}
if (pData->hdcTemp)
{
SelectObject(pData->hdcTemp, pData->hbmOldTemp);
DeleteDC(pData->hdcTemp);
pData->hdcTemp = NULL;
}
if (pData->hbmTemp)
{
DeleteObject(pData->hbmTemp);
pData->hbmTemp = NULL;
}
}
}
break;
case WM_WINDOWPOSCHANGING:
{
LPWINDOWPOS pwp = (LPWINDOWPOS) lParam;
pwp->flags |= SWP_NOSIZE | SWP_NOMOVE;
}
break;
case WM_PAINT:
{
HDC hdcPaint;
PAINTSTRUCT ps;
hdcPaint = BeginPaint(hwnd, &ps);
TBOOL(EndPaint(hwnd, &ps));
lResult = 0;
break;
}
default:
lResult = DefWindowProc(hwnd, uMsg, wParam, lParam);
break;
}
return(lResult);
}