Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

572 lines
17 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: DimmedWindow.cpp
  3. //
  4. // Copyright (c) 2000, Microsoft Corporation
  5. //
  6. // Class that implements the dimmed window when displaying logoff / shut down
  7. // dialog.
  8. //
  9. // History: 2000-05-18 vtan created
  10. // --------------------------------------------------------------------------
  11. #include "StandardHeader.h"
  12. #include "DimmedWindow.h"
  13. #include "RegistryResources.h"
  14. // --------------------------------------------------------------------------
  15. // CDimmedWindow::s_szWindowClassName
  16. //
  17. // Purpose: static member variables.
  18. //
  19. // History: 2000-05-17 vtan created
  20. // --------------------------------------------------------------------------
  21. const TCHAR CDimmedWindow::s_szWindowClassName[] = TEXT("DimmedWindowClass");
  22. const TCHAR CDimmedWindow::s_szExplorerKeyName[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer");
  23. const TCHAR CDimmedWindow::s_szExplorerPolicyKeyName[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer");
  24. const TCHAR CDimmedWindow::s_szForceDimValueName[] = TEXT("ForceDimScreen");
  25. #define RCW(rc) ((rc).right - (rc).left)
  26. #define RCH(r) ((r).bottom - (r).top)
  27. #define CHUNK_SIZE 20
  28. void DimPixels(void* pvBitmapBits, int cLen, int Amount)
  29. {
  30. ULONG* pulSrc = (ULONG*)pvBitmapBits;
  31. for (int i = cLen - 1; i >= 0; i--)
  32. {
  33. ULONG ulR = GetRValue(*pulSrc);
  34. ULONG ulG = GetGValue(*pulSrc);
  35. ULONG ulB = GetBValue(*pulSrc);
  36. ULONG ulGray = (54 * ulR + 183 * ulG + 19 * ulB) >> 8;
  37. ULONG ulTemp = ulGray * (0xff - Amount);
  38. ulR = (ulR * Amount + ulTemp) >> 8;
  39. ulG = (ulG * Amount + ulTemp) >> 8;
  40. ulB = (ulB * Amount + ulTemp) >> 8;
  41. *pulSrc = (*pulSrc & 0xff000000) | RGB(ulR, ulG, ulB);
  42. pulSrc++;
  43. }
  44. }
  45. // --------------------------------------------------------------------------
  46. // CDimmedWindow::CDimmedWindow
  47. //
  48. // Arguments: hInstance = HINSTANCE of the hosting process/DLL.
  49. //
  50. // Returns: <none>
  51. //
  52. // Purpose: Constructor for CDimmedWindow. Registers the window class
  53. // DimmedWindowClass.
  54. //
  55. // History: 2000-05-17 vtan created
  56. // --------------------------------------------------------------------------
  57. CDimmedWindow::CDimmedWindow (HINSTANCE hInstance) :
  58. _lReferenceCount(1),
  59. _hInstance(hInstance),
  60. _atom(0),
  61. _hwnd(NULL),
  62. _fDithered(false),
  63. _pvPixels(NULL),
  64. _idxChunk(0),
  65. _idxSaturation(0),
  66. _hdcDimmed(NULL),
  67. _hbmOldDimmed(NULL),
  68. _hbmDimmed(NULL)
  69. {
  70. WNDCLASSEX wndClassEx;
  71. ZeroMemory(&wndClassEx, sizeof(wndClassEx));
  72. wndClassEx.cbSize = sizeof(wndClassEx);
  73. wndClassEx.lpfnWndProc = WndProc;
  74. wndClassEx.hInstance = hInstance;
  75. wndClassEx.lpszClassName = s_szWindowClassName;
  76. wndClassEx.hCursor = LoadCursor(NULL, IDC_ARROW);
  77. _atom = RegisterClassEx(&wndClassEx);
  78. }
  79. // --------------------------------------------------------------------------
  80. // CDimmedWindow::~CDimmedWindow
  81. //
  82. // Arguments: <none>
  83. //
  84. // Returns: <none>
  85. //
  86. // Purpose: Destructor for CDimmedWindow. Destroys the dimmed window and
  87. // unregisters the window class.
  88. //
  89. // History: 2000-05-17 vtan created
  90. // --------------------------------------------------------------------------
  91. CDimmedWindow::~CDimmedWindow (void)
  92. {
  93. if (_hdcDimmed)
  94. {
  95. SelectObject(_hdcDimmed, _hbmOldDimmed);
  96. DeleteDC(_hdcDimmed);
  97. }
  98. if (_hbmDimmed)
  99. {
  100. DeleteObject(_hbmDimmed);
  101. }
  102. if (_hwnd != NULL)
  103. {
  104. (BOOL)DestroyWindow(_hwnd);
  105. }
  106. if (_atom != 0)
  107. {
  108. TBOOL(UnregisterClass(MAKEINTRESOURCE(_atom), _hInstance));
  109. }
  110. }
  111. // --------------------------------------------------------------------------
  112. // CDimmedWindow::QueryInterface
  113. //
  114. // Arguments: riid = Interface to query support of.
  115. // ppvObject = Returned interface if successful.
  116. //
  117. // Returns: HRESULT
  118. //
  119. // Purpose: Returns the specified interface implemented by this object.
  120. //
  121. // History: 2000-05-18 vtan created
  122. // --------------------------------------------------------------------------
  123. HRESULT CDimmedWindow::QueryInterface (REFIID riid, void **ppvObject)
  124. {
  125. HRESULT hr;
  126. if (IsEqualGUID(riid, IID_IUnknown))
  127. {
  128. *ppvObject = static_cast<IUnknown*>(this);
  129. (LONG)InterlockedIncrement(&_lReferenceCount);
  130. hr = S_OK;
  131. }
  132. else
  133. {
  134. *ppvObject = NULL;
  135. hr = E_NOINTERFACE;
  136. }
  137. return(hr);
  138. }
  139. // --------------------------------------------------------------------------
  140. // CDimmedWindow::AddRef
  141. //
  142. // Arguments: <none>
  143. //
  144. // Returns: ULONG
  145. //
  146. // Purpose: Increments the reference count and returns that value.
  147. //
  148. // History: 2000-05-18 vtan created
  149. // --------------------------------------------------------------------------
  150. ULONG CDimmedWindow::AddRef (void)
  151. {
  152. return(static_cast<ULONG>(InterlockedIncrement(&_lReferenceCount)));
  153. }
  154. // --------------------------------------------------------------------------
  155. // CDimmedWindow::Release
  156. //
  157. // Arguments: <none>
  158. //
  159. // Returns: ULONG
  160. //
  161. // Purpose: Decrements the reference count and if it reaches zero deletes
  162. // the object.
  163. //
  164. // History: 2000-05-18 vtan created
  165. // --------------------------------------------------------------------------
  166. ULONG CDimmedWindow::Release (void)
  167. {
  168. LONG lReferenceCount;
  169. ASSERTMSG(_lReferenceCount > 0, "Reference count negative or zero in CDimmedWindow::Release");
  170. lReferenceCount = InterlockedDecrement(&_lReferenceCount);
  171. if (lReferenceCount == 0)
  172. {
  173. delete this;
  174. }
  175. return(lReferenceCount);
  176. }
  177. // --------------------------------------------------------------------------
  178. // CDimmedWindow::Create
  179. //
  180. // Arguments: <none>
  181. //
  182. // Returns: HWND
  183. //
  184. // Purpose: Creates the dimmed window. Creates the window so that it
  185. // covers the whole screen area.
  186. //
  187. // History: 2000-05-17 vtan created
  188. // --------------------------------------------------------------------------
  189. HWND CDimmedWindow::Create (void)
  190. {
  191. BOOL fScreenReader;
  192. bool fNoDebuggerPresent, fConsoleSession, fNoScreenReaderPresent;
  193. fNoDebuggerPresent = !IsDebuggerPresent();
  194. fConsoleSession = (GetSystemMetrics(SM_REMOTESESSION) == FALSE);
  195. fNoScreenReaderPresent = ((SystemParametersInfo(SPI_GETSCREENREADER, 0, &fScreenReader, 0) == FALSE) || (fScreenReader == FALSE));
  196. if (fNoDebuggerPresent &&
  197. fConsoleSession &&
  198. fNoScreenReaderPresent)
  199. {
  200. _xVirtualScreen = GetSystemMetrics(SM_XVIRTUALSCREEN);
  201. _yVirtualScreen = GetSystemMetrics(SM_YVIRTUALSCREEN);
  202. _cxVirtualScreen = GetSystemMetrics(SM_CXVIRTUALSCREEN);
  203. _cyVirtualScreen = GetSystemMetrics(SM_CYVIRTUALSCREEN);
  204. _hwnd = CreateWindowEx(WS_EX_TOPMOST,
  205. s_szWindowClassName,
  206. NULL,
  207. WS_POPUP,
  208. _xVirtualScreen, _yVirtualScreen,
  209. _cxVirtualScreen, _cyVirtualScreen,
  210. NULL, NULL, _hInstance, this);
  211. if (_hwnd != NULL)
  212. {
  213. bool fDimmed;
  214. fDimmed = false;
  215. (BOOL)ShowWindow(_hwnd, SW_SHOW);
  216. TBOOL(SetForegroundWindow(_hwnd));
  217. // For beta: Always use a dither
  218. // if ((GetLowestScreenBitDepth() <= 8) || !IsDimScreen())
  219. {
  220. _fDithered = true;
  221. }
  222. (BOOL)EnableWindow(_hwnd, FALSE);
  223. }
  224. }
  225. return(_hwnd);
  226. }
  227. // --------------------------------------------------------------------------
  228. // CDimmedWindow::GetLowestScreenBitDepth
  229. //
  230. // Arguments: <none>
  231. //
  232. // Returns: int
  233. //
  234. // Purpose: Iterates the display devices looking the display with the
  235. // lowest bit depth.
  236. //
  237. // History: 2000-05-22 vtan created
  238. // --------------------------------------------------------------------------
  239. int CDimmedWindow::GetLowestScreenBitDepth (void) const
  240. {
  241. enum
  242. {
  243. INITIAL_VALUE = 256
  244. };
  245. BOOL fResult;
  246. int iLowestScreenBitDepth, iDeviceNumber;
  247. DISPLAY_DEVICE displayDevice;
  248. iLowestScreenBitDepth = INITIAL_VALUE; // Start at beyond 32-bit depth.
  249. iDeviceNumber = 0;
  250. displayDevice.cb = sizeof(displayDevice);
  251. fResult = EnumDisplayDevices(NULL, iDeviceNumber, &displayDevice, 0);
  252. while (fResult != FALSE)
  253. {
  254. if ((displayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) != 0)
  255. {
  256. HDC hdcDisplay;
  257. hdcDisplay = CreateDC(displayDevice.DeviceName, displayDevice.DeviceName, NULL, NULL);
  258. if (hdcDisplay != NULL)
  259. {
  260. int iResult;
  261. iResult = GetDeviceCaps(hdcDisplay, BITSPIXEL);
  262. if (iResult < iLowestScreenBitDepth)
  263. {
  264. iLowestScreenBitDepth = iResult;
  265. }
  266. TBOOL(DeleteDC(hdcDisplay));
  267. }
  268. }
  269. displayDevice.cb = sizeof(displayDevice);
  270. fResult = EnumDisplayDevices(NULL, ++iDeviceNumber, &displayDevice, 0);
  271. }
  272. if (INITIAL_VALUE == iLowestScreenBitDepth)
  273. {
  274. iLowestScreenBitDepth = 8;
  275. }
  276. return(iLowestScreenBitDepth);
  277. }
  278. // --------------------------------------------------------------------------
  279. // CDimmedWindow::IsForcedDimScreen
  280. //
  281. // Arguments: <none>
  282. //
  283. // Returns: bool
  284. //
  285. // Purpose: Returns whether the force override of dimming is set on this
  286. // user or this machine. Check the local machine first. Then
  287. // check the user setting. Then check the user policy. Then
  288. // check the local machine policy.
  289. //
  290. // History: 2000-05-23 vtan created
  291. // --------------------------------------------------------------------------
  292. bool CDimmedWindow::IsForcedDimScreen (void) const
  293. {
  294. DWORD dwForceDimScreen;
  295. CRegKey regKey;
  296. dwForceDimScreen = 0;
  297. if (ERROR_SUCCESS == regKey.Open(HKEY_LOCAL_MACHINE, s_szExplorerKeyName, KEY_QUERY_VALUE))
  298. {
  299. (LONG)regKey.GetDWORD(s_szForceDimValueName, dwForceDimScreen);
  300. }
  301. if (ERROR_SUCCESS == regKey.OpenCurrentUser(s_szExplorerKeyName, KEY_QUERY_VALUE))
  302. {
  303. (LONG)regKey.GetDWORD(s_szForceDimValueName, dwForceDimScreen);
  304. }
  305. if (ERROR_SUCCESS == regKey.OpenCurrentUser(s_szExplorerPolicyKeyName, KEY_QUERY_VALUE))
  306. {
  307. (LONG)regKey.GetDWORD(s_szForceDimValueName, dwForceDimScreen);
  308. }
  309. if (ERROR_SUCCESS == regKey.Open(HKEY_LOCAL_MACHINE, s_szExplorerPolicyKeyName, KEY_QUERY_VALUE))
  310. {
  311. (LONG)regKey.GetDWORD(s_szForceDimValueName, dwForceDimScreen);
  312. }
  313. return(dwForceDimScreen != 0);
  314. }
  315. // --------------------------------------------------------------------------
  316. // CDimmedWindow::IsDimScreen
  317. //
  318. // Arguments: <none>
  319. //
  320. // Returns: bool
  321. //
  322. // Purpose: Returns whether the screen should be dimmed. If not then the
  323. // screen will be dithered instead which is a cheaper operation
  324. // by doesn't look as nice.
  325. //
  326. // 1) If UI effects are disabled then don't ever dim.
  327. // 2) Dim if screen area is small enough OR forced to dim.
  328. //
  329. // History: 2000-05-23 vtan created
  330. // --------------------------------------------------------------------------
  331. bool CDimmedWindow::IsDimScreen (void) const
  332. {
  333. bool fIsUIEffectsActive;
  334. BOOL fTemp;
  335. fIsUIEffectsActive = (SystemParametersInfo(SPI_GETUIEFFECTS, 0, &fTemp, 0) != FALSE) && (fTemp != FALSE);
  336. return(fIsUIEffectsActive && IsForcedDimScreen());
  337. }
  338. BOOL CDimmedWindow::StepDim()
  339. {
  340. HDC hdcWindow = GetDC(_hwnd);
  341. if (_idxChunk >= 0 )
  342. {
  343. //
  344. // In the first couple of passes, we slowly collect the screen
  345. // into our bitmap. We do this because Blt-ing the whole thing
  346. // causes the system to hang. By doing it this way, we continue
  347. // to pump messages, the UI stays responsive and it keeps the
  348. // mouse alive.
  349. //
  350. int y = _idxChunk * CHUNK_SIZE;
  351. BitBlt(_hdcDimmed, 0, y, _cxVirtualScreen, CHUNK_SIZE, hdcWindow, 0, y, SRCCOPY);
  352. _idxChunk--;
  353. if (_idxChunk < 0)
  354. {
  355. //
  356. // We're done getting the bitmap, now reset the timer
  357. // so we slowly fade to grey.
  358. //
  359. SetTimer(_hwnd, 1, 250, NULL);
  360. _idxSaturation = 16;
  361. }
  362. return TRUE; // don't kill the timer.
  363. }
  364. else
  365. {
  366. //
  367. // In these passes, we are making the image more and more grey and
  368. // then Blt-ing the result to the screen.
  369. //
  370. DimPixels(_pvPixels, _cxVirtualScreen * _cyVirtualScreen, 0xd5);
  371. BitBlt(hdcWindow, 0, 0, _cxVirtualScreen, _cyVirtualScreen, _hdcDimmed, 0, 0, SRCCOPY);
  372. _idxSaturation--;
  373. return (_idxSaturation > 0); // when we hit zero, kill the timer.
  374. }
  375. }
  376. void CDimmedWindow::SetupDim()
  377. {
  378. HDC hdcWindow = GetDC(_hwnd);
  379. if (hdcWindow != NULL)
  380. {
  381. _hdcDimmed = CreateCompatibleDC(hdcWindow);
  382. if (_hdcDimmed != NULL)
  383. {
  384. BITMAPINFO bmi;
  385. ZeroMemory(&bmi, sizeof(bmi));
  386. bmi.bmiHeader.biSize = sizeof(bmi);
  387. bmi.bmiHeader.biWidth = _cxVirtualScreen;
  388. bmi.bmiHeader.biHeight = _cyVirtualScreen;
  389. bmi.bmiHeader.biPlanes = 1;
  390. bmi.bmiHeader.biBitCount = 32;
  391. bmi.bmiHeader.biCompression = BI_RGB;
  392. bmi.bmiHeader.biSizeImage = 0;
  393. _hbmDimmed = CreateDIBSection(_hdcDimmed, &bmi, DIB_RGB_COLORS, &_pvPixels, NULL, 0);
  394. if (_hbmDimmed != NULL)
  395. {
  396. _hbmOldDimmed = (HBITMAP) SelectObject(_hdcDimmed, _hbmDimmed);
  397. _idxChunk = _cyVirtualScreen / CHUNK_SIZE;
  398. }
  399. else
  400. {
  401. ASSERT( NULL == _pvPixels );
  402. DeleteDC(_hdcDimmed);
  403. _hdcDimmed = NULL;
  404. }
  405. }
  406. ReleaseDC(_hwnd, hdcWindow);
  407. }
  408. }
  409. void CDimmedWindow::Dither()
  410. {
  411. static const WORD s_dwGrayBits[] =
  412. {
  413. 0x5555, 0xAAAA, 0x5555, 0xAAAA, 0x5555, 0xAAAA, 0x5555, 0xAAAA
  414. };
  415. HDC hdcWindow = GetDC(_hwnd);
  416. if (hdcWindow != NULL)
  417. {
  418. HBITMAP hbmDimmed = CreateBitmap(8, 8, 1, 1, s_dwGrayBits);
  419. if (hbmDimmed != NULL)
  420. {
  421. HBRUSH hbrDimmed = CreatePatternBrush(hbmDimmed);
  422. if (hbrDimmed != NULL)
  423. {
  424. static const int ROP_DPna = 0x000A0329;
  425. RECT rc;
  426. HBRUSH hbrSelected = static_cast<HBRUSH>(SelectObject(hdcWindow, hbrDimmed));
  427. TBOOL(GetClientRect(_hwnd, &rc));
  428. TBOOL(PatBlt(hdcWindow, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, ROP_DPna));
  429. SelectObject(hdcWindow, hbrSelected);
  430. TBOOL(DeleteObject(hbrDimmed));
  431. }
  432. TBOOL(DeleteObject(hbmDimmed));
  433. }
  434. TBOOL(ReleaseDC(_hwnd, hdcWindow));
  435. }
  436. }
  437. // --------------------------------------------------------------------------
  438. // CDimmedWindow::WndProc
  439. //
  440. // Arguments: See the platform SDK under WindowProc.
  441. //
  442. // Returns: See the platform SDK under WindowProc.
  443. //
  444. // Purpose: WindowProc for the dimmed window. This just passes the
  445. // messages thru to DefWindowProc.
  446. //
  447. // History: 2000-05-17 vtan created
  448. // --------------------------------------------------------------------------
  449. LRESULT CALLBACK CDimmedWindow::WndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  450. {
  451. LRESULT lResult = 0;
  452. CDimmedWindow *pThis;
  453. pThis = reinterpret_cast<CDimmedWindow*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
  454. switch (uMsg)
  455. {
  456. case WM_CREATE:
  457. {
  458. CREATESTRUCT *pCreateStruct;
  459. pCreateStruct = reinterpret_cast<CREATESTRUCT*>(lParam);
  460. pThis = reinterpret_cast<CDimmedWindow*>(pCreateStruct->lpCreateParams);
  461. (LONG_PTR)SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pThis));
  462. lResult = 0;
  463. if (pThis->_fDithered)
  464. pThis->Dither();
  465. else
  466. {
  467. pThis->SetupDim();
  468. if (pThis->_hdcDimmed)
  469. {
  470. SetTimer(hwnd, 1, 30, NULL);
  471. }
  472. }
  473. break;
  474. }
  475. case WM_TIMER:
  476. if (!pThis->StepDim())
  477. KillTimer(hwnd, 1);
  478. break;
  479. case WM_PAINT:
  480. {
  481. HDC hdcPaint;
  482. PAINTSTRUCT ps;
  483. hdcPaint = BeginPaint(hwnd, &ps);
  484. TBOOL(EndPaint(hwnd, &ps));
  485. lResult = 0;
  486. break;
  487. }
  488. default:
  489. lResult = DefWindowProc(hwnd, uMsg, wParam, lParam);
  490. break;
  491. }
  492. return(lResult);
  493. }