xref: /reactos/dll/win32/msgina/dimmedwindow.cpp (revision c2c66aff)
1*c2c66affSColin Finck /*
2*c2c66affSColin Finck  * COPYRIGHT:       See COPYING in the top level directory
3*c2c66affSColin Finck  * PROJECT:         ReactOS msgina.dll
4*c2c66affSColin Finck  * FILE:            dll/win32/msgina/dimmedwindow.cpp
5*c2c66affSColin Finck  * PURPOSE:         Implementation of ShellDimScreen
6*c2c66affSColin Finck  * PROGRAMMER:      Mark Jansen
7*c2c66affSColin Finck  */
8*c2c66affSColin Finck 
9*c2c66affSColin Finck #define COM_NO_WINDOWS_H
10*c2c66affSColin Finck #include "msgina.h"
11*c2c66affSColin Finck #include <wingdi.h>
12*c2c66affSColin Finck #include <atlbase.h>
13*c2c66affSColin Finck #include <atlcom.h>
14*c2c66affSColin Finck #include <pseh/pseh2.h>
15*c2c66affSColin Finck 
16*c2c66affSColin Finck CComModule gModule;
17*c2c66affSColin Finck 
18*c2c66affSColin Finck // Please note: The INIT_TIMER is a workaround because ReactOS does not redraw the desktop in time,
19*c2c66affSColin Finck //              so the start menu is still visible on the dimmed screen.
20*c2c66affSColin Finck #define INIT_TIMER_ID   0x112233
21*c2c66affSColin Finck #define FADE_TIMER_ID   0x12345
22*c2c66affSColin Finck 
23*c2c66affSColin Finck class CDimmedWindow :
24*c2c66affSColin Finck     public CComObjectRootEx<CComMultiThreadModelNoCS>,
25*c2c66affSColin Finck     IUnknown
26*c2c66affSColin Finck {
27*c2c66affSColin Finck private:
28*c2c66affSColin Finck     HWND m_hwnd;
29*c2c66affSColin Finck     HDC m_hdc;
30*c2c66affSColin Finck     HBITMAP m_hbitmap;
31*c2c66affSColin Finck     HGDIOBJ m_oldbitmap;
32*c2c66affSColin Finck     LONG m_width;
33*c2c66affSColin Finck     LONG m_height;
34*c2c66affSColin Finck     BITMAPINFO m_bi;
35*c2c66affSColin Finck     UCHAR* m_bytes;
36*c2c66affSColin Finck     int m_step;
37*c2c66affSColin Finck 
38*c2c66affSColin Finck     static LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
39*c2c66affSColin Finck 
40*c2c66affSColin Finck public:
CDimmedWindow()41*c2c66affSColin Finck     CDimmedWindow()
42*c2c66affSColin Finck         : m_hwnd(NULL)
43*c2c66affSColin Finck         , m_hdc(NULL)
44*c2c66affSColin Finck         , m_hbitmap(NULL)
45*c2c66affSColin Finck         , m_oldbitmap(NULL)
46*c2c66affSColin Finck         , m_width(0)
47*c2c66affSColin Finck         , m_height(0)
48*c2c66affSColin Finck         , m_bytes(NULL)
49*c2c66affSColin Finck         , m_step(0)
50*c2c66affSColin Finck     {
51*c2c66affSColin Finck         WNDCLASSEXW wndclass = {sizeof(wndclass)};
52*c2c66affSColin Finck         wndclass.lpfnWndProc = WndProc;
53*c2c66affSColin Finck         wndclass.hInstance = hDllInstance;
54*c2c66affSColin Finck         wndclass.hCursor = LoadCursor(0, IDC_ARROW);
55*c2c66affSColin Finck         wndclass.lpszClassName = L"DimmedWindowClass";
56*c2c66affSColin Finck 
57*c2c66affSColin Finck         if (!RegisterClassExW(&wndclass))
58*c2c66affSColin Finck             return;
59*c2c66affSColin Finck 
60*c2c66affSColin Finck         m_width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
61*c2c66affSColin Finck         m_height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
62*c2c66affSColin Finck 
63*c2c66affSColin Finck         memset(&m_bi, 0, sizeof(m_bi));
64*c2c66affSColin Finck         m_bi.bmiHeader.biSize = sizeof(m_bi);
65*c2c66affSColin Finck         m_bi.bmiHeader.biWidth = m_width;
66*c2c66affSColin Finck         m_bi.bmiHeader.biHeight = m_height;
67*c2c66affSColin Finck         m_bi.bmiHeader.biPlanes = 1;
68*c2c66affSColin Finck         m_bi.bmiHeader.biBitCount = 32;
69*c2c66affSColin Finck         m_bi.bmiHeader.biCompression = BI_RGB;
70*c2c66affSColin Finck         m_bi.bmiHeader.biSizeImage = m_width * 4 * m_height;
71*c2c66affSColin Finck         m_bytes = new UCHAR[m_width * 4 * m_height];
72*c2c66affSColin Finck 
73*c2c66affSColin Finck         LONG x = GetSystemMetrics(SM_XVIRTUALSCREEN);
74*c2c66affSColin Finck         LONG y = GetSystemMetrics(SM_YVIRTUALSCREEN);
75*c2c66affSColin Finck 
76*c2c66affSColin Finck         m_hwnd = CreateWindowExW(WS_EX_TOPMOST,
77*c2c66affSColin Finck                                  L"DimmedWindowClass",
78*c2c66affSColin Finck                                  NULL,
79*c2c66affSColin Finck                                  WS_POPUP,
80*c2c66affSColin Finck                                  x, y,
81*c2c66affSColin Finck                                  m_width, m_height,
82*c2c66affSColin Finck                                  NULL, NULL,
83*c2c66affSColin Finck                                  hDllInstance,
84*c2c66affSColin Finck                                  (LPVOID)this);
85*c2c66affSColin Finck     }
86*c2c66affSColin Finck 
~CDimmedWindow()87*c2c66affSColin Finck     ~CDimmedWindow()
88*c2c66affSColin Finck     {
89*c2c66affSColin Finck         if (m_hwnd)
90*c2c66affSColin Finck             DestroyWindow(m_hwnd);
91*c2c66affSColin Finck         UnregisterClassW(L"DimmedWindowClass", hDllInstance);
92*c2c66affSColin Finck         if (m_oldbitmap)
93*c2c66affSColin Finck              SelectObject(m_hdc, m_oldbitmap);
94*c2c66affSColin Finck         if (m_hbitmap)
95*c2c66affSColin Finck             DeleteObject(m_hbitmap);
96*c2c66affSColin Finck         if (m_hdc)
97*c2c66affSColin Finck             DeleteObject(m_hdc);
98*c2c66affSColin Finck         if (m_bytes)
99*c2c66affSColin Finck             delete[] m_bytes;
100*c2c66affSColin Finck     }
101*c2c66affSColin Finck 
102*c2c66affSColin Finck     // This is needed so that we do not capture the start menu while it's closing.
WaitForInit()103*c2c66affSColin Finck     void WaitForInit()
104*c2c66affSColin Finck     {
105*c2c66affSColin Finck         MSG msg;
106*c2c66affSColin Finck 
107*c2c66affSColin Finck         while (IsWindow(m_hwnd) && !IsWindowVisible(m_hwnd))
108*c2c66affSColin Finck         {
109*c2c66affSColin Finck             while (::PeekMessage(&msg, m_hwnd, 0, 0, PM_REMOVE))
110*c2c66affSColin Finck             {
111*c2c66affSColin Finck                 ::TranslateMessage(&msg);
112*c2c66affSColin Finck                 ::DispatchMessage(&msg);
113*c2c66affSColin Finck 
114*c2c66affSColin Finck                 if (IsWindowVisible(m_hwnd))
115*c2c66affSColin Finck                     break;
116*c2c66affSColin Finck             }
117*c2c66affSColin Finck         }
118*c2c66affSColin Finck     }
119*c2c66affSColin Finck 
Init()120*c2c66affSColin Finck     void Init()
121*c2c66affSColin Finck     {
122*c2c66affSColin Finck         Capture();
123*c2c66affSColin Finck 
124*c2c66affSColin Finck         ShowWindow(m_hwnd, SW_SHOW);
125*c2c66affSColin Finck         SetForegroundWindow(m_hwnd);
126*c2c66affSColin Finck         EnableWindow(m_hwnd, FALSE);
127*c2c66affSColin Finck 
128*c2c66affSColin Finck         SetTimer(m_hwnd, FADE_TIMER_ID, 200, NULL);
129*c2c66affSColin Finck     }
130*c2c66affSColin Finck 
Capture()131*c2c66affSColin Finck     void Capture()
132*c2c66affSColin Finck     {
133*c2c66affSColin Finck         HWND desktopWnd = GetDesktopWindow();
134*c2c66affSColin Finck         HDC desktopDC = GetDC(desktopWnd);
135*c2c66affSColin Finck 
136*c2c66affSColin Finck         m_hdc = CreateCompatibleDC(desktopDC);
137*c2c66affSColin Finck 
138*c2c66affSColin Finck         m_hbitmap = CreateCompatibleBitmap(desktopDC, m_width, m_height);
139*c2c66affSColin Finck         m_oldbitmap = SelectObject(m_hdc, m_hbitmap);
140*c2c66affSColin Finck         BitBlt(m_hdc, 0, 0, m_width, m_height, desktopDC, 0, 0, SRCCOPY);
141*c2c66affSColin Finck 
142*c2c66affSColin Finck         ReleaseDC(desktopWnd, desktopDC);
143*c2c66affSColin Finck     }
144*c2c66affSColin Finck 
Step()145*c2c66affSColin Finck     bool Step()
146*c2c66affSColin Finck     {
147*c2c66affSColin Finck         // Stop after 10 steps
148*c2c66affSColin Finck         if (m_step++ > 10 || !m_bytes)
149*c2c66affSColin Finck             return false;
150*c2c66affSColin Finck 
151*c2c66affSColin Finck         int lines = GetDIBits(m_hdc, m_hbitmap, 0, m_height, m_bytes, &m_bi, DIB_RGB_COLORS);
152*c2c66affSColin Finck         if (lines)
153*c2c66affSColin Finck         {
154*c2c66affSColin Finck             for (int xh = 0; xh < m_height; ++xh)
155*c2c66affSColin Finck             {
156*c2c66affSColin Finck                 int h = m_width * 4 * xh;
157*c2c66affSColin Finck                 for (int w = 0; w < m_width; ++w)
158*c2c66affSColin Finck                 {
159*c2c66affSColin Finck                     UCHAR b = m_bytes[(h + w * 4) + 0];
160*c2c66affSColin Finck                     UCHAR g = m_bytes[(h + w * 4) + 1];
161*c2c66affSColin Finck                     UCHAR r = m_bytes[(h + w * 4) + 2];
162*c2c66affSColin Finck 
163*c2c66affSColin Finck                     // Standard formula to convert a color.
164*c2c66affSColin Finck                     int gray = (r * 30 + g * 59 + b * 11) / 100;
165*c2c66affSColin Finck                     if (gray < 0)
166*c2c66affSColin Finck                         gray = 0;
167*c2c66affSColin Finck 
168*c2c66affSColin Finck                     // Do not fade too fast.
169*c2c66affSColin Finck                     r = (r*2 + gray) / 3;
170*c2c66affSColin Finck                     g = (g*2 + gray) / 3;
171*c2c66affSColin Finck                     b = (b*2 + gray) / 3;
172*c2c66affSColin Finck 
173*c2c66affSColin Finck                     m_bytes[(h + w * 4) + 0] = b;
174*c2c66affSColin Finck                     m_bytes[(h + w * 4) + 1] = g;
175*c2c66affSColin Finck                     m_bytes[(h + w * 4) + 2] = r;
176*c2c66affSColin Finck                 }
177*c2c66affSColin Finck             }
178*c2c66affSColin Finck             SetDIBits(m_hdc, m_hbitmap, 0, lines, m_bytes, &m_bi, DIB_RGB_COLORS);
179*c2c66affSColin Finck         }
180*c2c66affSColin Finck         return true;
181*c2c66affSColin Finck     }
182*c2c66affSColin Finck 
Blt(HDC hdc)183*c2c66affSColin Finck     void Blt(HDC hdc)
184*c2c66affSColin Finck     {
185*c2c66affSColin Finck         BitBlt(hdc, 0, 0, m_width, m_height, m_hdc, 0, 0, SRCCOPY);
186*c2c66affSColin Finck     }
187*c2c66affSColin Finck 
Wnd()188*c2c66affSColin Finck     HWND Wnd()
189*c2c66affSColin Finck     {
190*c2c66affSColin Finck         return m_hwnd;
191*c2c66affSColin Finck     }
192*c2c66affSColin Finck 
193*c2c66affSColin Finck 
194*c2c66affSColin Finck     BEGIN_COM_MAP(CDimmedWindow)
195*c2c66affSColin Finck         COM_INTERFACE_ENTRY_IID(IID_IUnknown, IUnknown)
196*c2c66affSColin Finck     END_COM_MAP()
197*c2c66affSColin Finck 
198*c2c66affSColin Finck };
199*c2c66affSColin Finck 
200*c2c66affSColin Finck 
WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)201*c2c66affSColin Finck LRESULT WINAPI CDimmedWindow::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
202*c2c66affSColin Finck {
203*c2c66affSColin Finck     switch (uMsg)
204*c2c66affSColin Finck     {
205*c2c66affSColin Finck     case WM_NCCREATE:
206*c2c66affSColin Finck     {
207*c2c66affSColin Finck         LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
208*c2c66affSColin Finck         CDimmedWindow* info = static_cast<CDimmedWindow*>(lpcs->lpCreateParams);
209*c2c66affSColin Finck         SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)info);
210*c2c66affSColin Finck         SetTimer(hWnd, INIT_TIMER_ID, 50, NULL);
211*c2c66affSColin Finck         break;
212*c2c66affSColin Finck     }
213*c2c66affSColin Finck 
214*c2c66affSColin Finck     case WM_PAINT:
215*c2c66affSColin Finck     {
216*c2c66affSColin Finck         CDimmedWindow* info = reinterpret_cast<CDimmedWindow*>(GetWindowLongPtrW(hWnd, GWLP_USERDATA));
217*c2c66affSColin Finck         if (info)
218*c2c66affSColin Finck         {
219*c2c66affSColin Finck             PAINTSTRUCT ps;
220*c2c66affSColin Finck             BeginPaint(hWnd, &ps);
221*c2c66affSColin Finck             info->Blt(ps.hdc);
222*c2c66affSColin Finck             EndPaint(hWnd, &ps);
223*c2c66affSColin Finck         }
224*c2c66affSColin Finck         return 0;
225*c2c66affSColin Finck     }
226*c2c66affSColin Finck 
227*c2c66affSColin Finck     case WM_TIMER:
228*c2c66affSColin Finck     {
229*c2c66affSColin Finck         if (wParam == INIT_TIMER_ID)
230*c2c66affSColin Finck         {
231*c2c66affSColin Finck             CDimmedWindow* info = reinterpret_cast<CDimmedWindow*>(GetWindowLongPtrW(hWnd, GWLP_USERDATA));
232*c2c66affSColin Finck             KillTimer(hWnd, INIT_TIMER_ID);
233*c2c66affSColin Finck             info->Init();
234*c2c66affSColin Finck         }
235*c2c66affSColin Finck         else if (wParam == FADE_TIMER_ID)
236*c2c66affSColin Finck         {
237*c2c66affSColin Finck             CDimmedWindow* info = reinterpret_cast<CDimmedWindow*>(GetWindowLongPtrW(hWnd, GWLP_USERDATA));
238*c2c66affSColin Finck             if (info && info->Step())
239*c2c66affSColin Finck                 InvalidateRect(hWnd, NULL, TRUE);
240*c2c66affSColin Finck             else
241*c2c66affSColin Finck                 KillTimer(hWnd, FADE_TIMER_ID);
242*c2c66affSColin Finck         }
243*c2c66affSColin Finck         return 0;
244*c2c66affSColin Finck     }
245*c2c66affSColin Finck 
246*c2c66affSColin Finck     default:
247*c2c66affSColin Finck         break;
248*c2c66affSColin Finck     }
249*c2c66affSColin Finck 
250*c2c66affSColin Finck     return DefWindowProc(hWnd, uMsg, wParam, lParam);
251*c2c66affSColin Finck }
252*c2c66affSColin Finck 
253*c2c66affSColin Finck 
254*c2c66affSColin Finck extern "C"
255*c2c66affSColin Finck HRESULT WINAPI
ShellDimScreen(void ** pUnknown,HWND * hWindow)256*c2c66affSColin Finck ShellDimScreen(void** pUnknown, HWND* hWindow)
257*c2c66affSColin Finck {
258*c2c66affSColin Finck     CComObject<CDimmedWindow> *pWindow;
259*c2c66affSColin Finck     HRESULT hr = CComObject<CDimmedWindow>::CreateInstance(&pWindow);
260*c2c66affSColin Finck     ULONG refcount;
261*c2c66affSColin Finck 
262*c2c66affSColin Finck     pWindow->WaitForInit();
263*c2c66affSColin Finck 
264*c2c66affSColin Finck     if (!IsWindow(pWindow->Wnd()))
265*c2c66affSColin Finck     {
266*c2c66affSColin Finck         refcount = pWindow->AddRef();
267*c2c66affSColin Finck         while (refcount)
268*c2c66affSColin Finck             refcount = pWindow->Release();
269*c2c66affSColin Finck 
270*c2c66affSColin Finck         return E_FAIL;
271*c2c66affSColin Finck     }
272*c2c66affSColin Finck 
273*c2c66affSColin Finck     _SEH2_TRY
274*c2c66affSColin Finck     {
275*c2c66affSColin Finck         hr = pWindow->QueryInterface(IID_IUnknown, pUnknown);
276*c2c66affSColin Finck         *hWindow = pWindow->Wnd();
277*c2c66affSColin Finck         hr = S_OK;
278*c2c66affSColin Finck     }
279*c2c66affSColin Finck     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
280*c2c66affSColin Finck     {
281*c2c66affSColin Finck         hr = E_INVALIDARG;
282*c2c66affSColin Finck         refcount = pWindow->AddRef();
283*c2c66affSColin Finck         while (refcount)
284*c2c66affSColin Finck             refcount = pWindow->Release();
285*c2c66affSColin Finck     }
286*c2c66affSColin Finck     _SEH2_END
287*c2c66affSColin Finck 
288*c2c66affSColin Finck     return hr;
289*c2c66affSColin Finck }
290