|
|
#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); }
|