// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved #include "Private.h" #include "Globals.h" #include "BaseWindow.h" #include "ShadowWindow.h" #define SHADOW_ALPHANUMBER (5) #define ALPHA(x) (255 - (x)) //// Gray scale values for the shadow grades #define GS01 255 #define GS02 254 #define GS03 253 #define GS04 252 #define GS05 250 #define GS06 246 #define GS07 245 #define GS08 242 #define GS09 241 #define GS10 227 #define GS11 217 #define GS12 213 #define GS13 212 #define GS14 199 #define GS15 180 #define GS16 172 #define GS17 171 #define GS18 155 #define GS19 144 #define GS20 142 // pre-computed alpha values for the shadow const BYTE AlphaTable[SHADOW_ALPHANUMBER] = { ALPHA(GS04), ALPHA(GS09), ALPHA(GS13), ALPHA(GS17), ALPHA(GS20) }; const BYTE CornerShadowAlphaMetric[SHADOW_ALPHANUMBER][SHADOW_ALPHANUMBER] = { ALPHA(GS08), ALPHA(GS06), ALPHA(GS05), ALPHA(GS03), ALPHA(GS02), ALPHA(GS11), ALPHA(GS10), ALPHA(GS09), ALPHA(GS05), ALPHA(GS02), ALPHA(GS15), ALPHA(GS14), ALPHA(GS10), ALPHA(GS07), ALPHA(GS03), ALPHA(GS18), ALPHA(GS15), ALPHA(GS11), ALPHA(GS08), ALPHA(GS03), ALPHA(GS19), ALPHA(GS16), ALPHA(GS12), ALPHA(GS09), ALPHA(GS04), }; //+--------------------------------------------------------------------------- // // _Create // //---------------------------------------------------------------------------- BOOL CShadowWindow::_Create(ATOM atom, DWORD dwExStyle, DWORD dwStyle, _In_opt_ CBaseWindow *pParent, int wndWidth, int wndHeight) { if (!CBaseWindow::_Create(atom, dwExStyle, dwStyle, pParent, wndWidth, wndHeight)) { return FALSE; } return _Initialize(); } //+--------------------------------------------------------------------------- // // _WindowProcCallback // // Shadow window proc. //---------------------------------------------------------------------------- LRESULT CALLBACK CShadowWindow::_WindowProcCallback(_In_ HWND wndHandle, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_PAINT: { HDC dcHandle; PAINTSTRUCT ps; dcHandle = BeginPaint(wndHandle, &ps); HBRUSH hBrush = CreateSolidBrush(_color); FillRect(dcHandle, &ps.rcPaint, hBrush); DeleteObject(hBrush); EndPaint(wndHandle, &ps); } return 0; case WM_SETTINGCHANGE: _OnSettingChange(); break; } return DefWindowProc(wndHandle, uMsg, wParam, lParam); } //+--------------------------------------------------------------------------- // // _OnSettingChange // //---------------------------------------------------------------------------- void CShadowWindow::_OnSettingChange() { _InitSettings(); DWORD dwWndStyleEx = GetWindowLong(_GetWnd(), GWL_EXSTYLE); if (_isGradient) { SetWindowLong(_GetWnd(), GWL_EXSTYLE, (dwWndStyleEx | WS_EX_LAYERED)); } else { SetWindowLong(_GetWnd(), GWL_EXSTYLE, (dwWndStyleEx & ~WS_EX_LAYERED)); } _AdjustWindowPos(); _InitShadow(); } //+--------------------------------------------------------------------------- // // _OnOwnerWndMoved // //---------------------------------------------------------------------------- void CShadowWindow::_OnOwnerWndMoved(BOOL isResized) { if (IsWindow(_GetWnd()) && _IsWindowVisible()) { _AdjustWindowPos(); if (isResized) { _InitShadow(); } } } //+--------------------------------------------------------------------------- // // _Show // //---------------------------------------------------------------------------- void CShadowWindow::_Show(BOOL isShowWnd) { _OnOwnerWndMoved(TRUE); CBaseWindow::_Show(isShowWnd); } //+--------------------------------------------------------------------------- // // _Initialize // //---------------------------------------------------------------------------- BOOL CShadowWindow::_Initialize() { _InitSettings(); return TRUE; } //+--------------------------------------------------------------------------- // // _InitSettings // //---------------------------------------------------------------------------- void CShadowWindow::_InitSettings() { HDC dcHandle = GetDC(nullptr); // device caps int cBitsPixelScreen = GetDeviceCaps(dcHandle, BITSPIXEL); _isGradient = cBitsPixelScreen > 8; ReleaseDC(nullptr, dcHandle); if (_isGradient) { _color = RGB(0, 0, 0); _sizeShift.cx = SHADOW_ALPHANUMBER; _sizeShift.cy = SHADOW_ALPHANUMBER; } else { _color = RGB(128, 128, 128); _sizeShift.cx = 2; _sizeShift.cy = 2; } } //+--------------------------------------------------------------------------- // // _AdjustWindowPos // //---------------------------------------------------------------------------- void CShadowWindow::_AdjustWindowPos() { if (!IsWindow(_GetWnd())) { return; } HWND hWndOwner = _pWndOwner->_GetWnd(); RECT rc = {0, 0, 0, 0}; GetWindowRect(hWndOwner, &rc); SetWindowPos(_GetWnd(), hWndOwner, rc.left + _sizeShift.cx, rc.top + _sizeShift.cy, rc.right - rc.left, rc.bottom - rc.top, SWP_NOOWNERZORDER | SWP_NOACTIVATE); } //+--------------------------------------------------------------------------- // // _InitShadow // //---------------------------------------------------------------------------- #define GETRGBALPHA(_x_, _y_) ((RGBALPHA *)pDIBits + (_y_) * size.cx + (_x_)) void CShadowWindow::_InitShadow() { typedef struct _RGBAPLHA { BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; BYTE rgbAlpha; } RGBALPHA; HDC dcScreenHandle = nullptr; HDC dcLayeredHandle = nullptr; RECT rcWindow = {0, 0, 0, 0}; SIZE size = {0, 0}; BITMAPINFO bitmapInfo; HBITMAP bitmapMemHandle = nullptr; HBITMAP bitmapOldHandle = nullptr; void* pDIBits = nullptr; int i = 0; int j = 0; POINT ptSrc = {0, 0}; POINT ptDst = {0, 0}; BLENDFUNCTION Blend; if (!_isGradient) { return; } SetWindowLong(_GetWnd(), GWL_EXSTYLE, (GetWindowLong(_GetWnd(), GWL_EXSTYLE) | WS_EX_LAYERED)); _GetWindowRect(&rcWindow); size.cx = rcWindow.right - rcWindow.left; size.cy = rcWindow.bottom - rcWindow.top; dcScreenHandle = GetDC(nullptr); if (dcScreenHandle == nullptr) { return; } dcLayeredHandle = CreateCompatibleDC(dcScreenHandle); if (dcLayeredHandle == nullptr) { ReleaseDC(nullptr, dcScreenHandle); return; } // create bitmap bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bitmapInfo.bmiHeader.biWidth = size.cx; bitmapInfo.bmiHeader.biHeight = size.cy; bitmapInfo.bmiHeader.biPlanes = 1; bitmapInfo.bmiHeader.biBitCount = 32; bitmapInfo.bmiHeader.biCompression = BI_RGB; bitmapInfo.bmiHeader.biSizeImage = 0; bitmapInfo.bmiHeader.biXPelsPerMeter = 100; bitmapInfo.bmiHeader.biYPelsPerMeter = 100; bitmapInfo.bmiHeader.biClrUsed = 0; bitmapInfo.bmiHeader.biClrImportant = 0; bitmapMemHandle = CreateDIBSection(dcScreenHandle, &bitmapInfo, DIB_RGB_COLORS, &pDIBits, nullptr, 0); if (pDIBits == nullptr || bitmapMemHandle == nullptr) { ReleaseDC(nullptr, dcScreenHandle); DeleteDC(dcLayeredHandle); return; } memset(pDIBits, 0, ((((32 * size.cx) + 31) & ~31) / 8) * size.cy); // edges for (i = 0; i < SHADOW_ALPHANUMBER; i++) { RGBALPHA *ppxl; BYTE bAlpha = AlphaTable[i]; // bottom if (i <= (size.cy + 1)/2) { for (j = SHADOW_ALPHANUMBER; j < size.cx - SHADOW_ALPHANUMBER; j++) { ppxl = GETRGBALPHA(j, i); ppxl->rgbAlpha = bAlpha; } } // right if (i <= (size.cx + 1)/2) { for (j = SHADOW_ALPHANUMBER; j < size.cy - SHADOW_ALPHANUMBER; j++) { ppxl = GETRGBALPHA(size.cx - 1 - i, j); ppxl->rgbAlpha = bAlpha; } } } // corners for (i = 0; i < SHADOW_ALPHANUMBER; i++) { for (j = 0; j < SHADOW_ALPHANUMBER; j++) { RGBALPHA *ppxl; BYTE bAlpha; bAlpha = CornerShadowAlphaMetric[i][SHADOW_ALPHANUMBER - j - 1]; // top-right if ((i <= (size.cy + 1)/2) && (j <= (size.cx + 1)/2)) { ppxl = GETRGBALPHA(size.cx - 1 - j, size.cy - 1 - i); ppxl->rgbAlpha = bAlpha; } // bottom-left if ((i <= (size.cy + 1)/2) && (j <= (size.cx + 1)/2)) { ppxl = GETRGBALPHA(j, i + 1); ppxl->rgbAlpha = bAlpha; } // bottom-right if ((i <= (size.cy + 1)/2) && (j <= (size.cx + 1)/2)) { ppxl = GETRGBALPHA(size.cx - 1 - j, i + 1); ppxl->rgbAlpha = bAlpha; } } } ptSrc.x = 0; ptSrc.y = 0; ptDst.x = rcWindow.left; ptDst.y = rcWindow.top; Blend.BlendOp = AC_SRC_OVER; Blend.BlendFlags = 0; Blend.SourceConstantAlpha = 255; Blend.AlphaFormat = AC_SRC_ALPHA; bitmapOldHandle = (HBITMAP)SelectObject(dcLayeredHandle, bitmapMemHandle); UpdateLayeredWindow(_GetWnd(), dcScreenHandle, nullptr, &size, dcLayeredHandle, &ptSrc, 0, &Blend, ULW_ALPHA); SelectObject(dcLayeredHandle, bitmapOldHandle); // done ReleaseDC(nullptr, dcScreenHandle); DeleteDC(dcLayeredHandle); DeleteObject(bitmapMemHandle); }