Merge freeldr from amd64 branch:
[reactos.git] / reactos / subsystems / win32 / csrss / win32csr / desktopbg.c
1 /* $Id$
2 *
3 * reactos/subsys/csrss/win32csr/desktopbg.c
4 *
5 * Desktop background window functions
6 *
7 * ReactOS Operating System
8 */
9
10 #define NDEBUG
11 #include "w32csr.h"
12 #include <debug.h>
13
14 #define DESKTOP_WINDOW_ATOM 32880
15
16 #define PM_SHOW_DESKTOP 1
17 #define PM_HIDE_DESKTOP 2
18
19 typedef struct tagDTBG_THREAD_DATA
20 {
21 HDESK Desktop;
22 HANDLE Event;
23 NTSTATUS Status;
24 } DTBG_THREAD_DATA, *PDTBG_THREAD_DATA;
25
26 typedef struct tagPRIVATE_NOTIFY_DESKTOP
27 {
28 NMHDR hdr;
29 union
30 {
31 struct /* PM_SHOW_DESKTOP */
32 {
33 int Width;
34 int Height;
35 } ShowDesktop;
36 };
37 } PRIVATE_NOTIFY_DESKTOP, *PPRIVATE_NOTIFY_DESKTOP;
38
39 static BOOL BgInitialized = FALSE;
40 static HWND VisibleDesktopWindow = NULL;
41
42 static LRESULT CALLBACK
43 DtbgWindowProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam)
44 {
45 switch(Msg)
46 {
47 case WM_ERASEBKGND:
48 return 1;
49
50 case WM_PAINT:
51 {
52 PAINTSTRUCT PS;
53 RECT rc;
54 HDC hDC;
55
56 if(GetUpdateRect(Wnd, &rc, FALSE) &&
57 (hDC = BeginPaint(Wnd, &PS)))
58 {
59 PaintDesktop(hDC);
60 EndPaint(Wnd, &PS);
61 }
62 return 0;
63 }
64
65 case WM_SETCURSOR:
66 return (LRESULT) SetCursor(LoadCursorW(0, (LPCWSTR)IDC_ARROW));
67
68 case WM_NCCREATE:
69 return (LRESULT) TRUE;
70
71 case WM_CREATE:
72 return 0;
73
74 case WM_NOTIFY:
75 {
76 PPRIVATE_NOTIFY_DESKTOP nmh = (PPRIVATE_NOTIFY_DESKTOP)lParam;
77
78 /* Use WM_NOTIFY for private messages since it can't be sent between
79 processes! */
80 switch(nmh->hdr.code)
81 {
82 case PM_SHOW_DESKTOP:
83 {
84 LRESULT Result;
85
86 Result = ! SetWindowPos(Wnd,
87 NULL, 0, 0,
88 nmh->ShowDesktop.Width,
89 nmh->ShowDesktop.Height,
90 SWP_NOACTIVATE | SWP_NOZORDER | SWP_SHOWWINDOW);
91 UpdateWindow(Wnd);
92 VisibleDesktopWindow = Wnd;
93 return Result;
94 }
95
96 case PM_HIDE_DESKTOP:
97 {
98 LRESULT Result;
99
100 Result = ! SetWindowPos(Wnd,
101 NULL, 0, 0, 0, 0,
102 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE |
103 SWP_HIDEWINDOW);
104 UpdateWindow(Wnd);
105 VisibleDesktopWindow = NULL;
106 return Result;
107 }
108
109 default:
110 DPRINT("Unknown notification code 0x%x sent to the desktop window!\n", nmh->hdr.code);
111 return 0;
112 }
113 }
114 }
115
116 return 0;
117 }
118
119 static BOOL FASTCALL
120 DtbgInit()
121 {
122 WNDCLASSEXW Class;
123 ATOM ClassAtom;
124
125 /*
126 * Create the desktop window class
127 */
128 Class.cbSize = sizeof(WNDCLASSEXW);
129 Class.style = 0;
130 Class.lpfnWndProc = DtbgWindowProc;
131 Class.cbClsExtra = 0;
132 Class.cbWndExtra = 0;
133 Class.hInstance = (HINSTANCE) GetModuleHandleW(NULL);
134 Class.hIcon = NULL;
135 Class.hCursor = NULL;
136 Class.hbrBackground = GetSysColorBrush(COLOR_BACKGROUND);
137 Class.lpszMenuName = NULL;
138 Class.lpszClassName = (LPCWSTR) DESKTOP_WINDOW_ATOM;
139 ClassAtom = RegisterClassExW(&Class);
140 if ((ATOM) 0 == ClassAtom)
141 {
142 DPRINT1("Unable to register desktop background class (error %d)\n",
143 GetLastError());
144 return FALSE;
145 }
146 VisibleDesktopWindow = NULL;
147
148 return TRUE;
149 }
150
151 static DWORD WINAPI
152 DtbgDesktopThread(PVOID Data)
153 {
154 HWND BackgroundWnd;
155 MSG msg;
156 PDTBG_THREAD_DATA ThreadData = (PDTBG_THREAD_DATA) Data;
157
158 if (! SetThreadDesktop(ThreadData->Desktop))
159 {
160 DPRINT1("Failed to set thread desktop\n");
161 ThreadData->Status = STATUS_UNSUCCESSFUL;
162 SetEvent(ThreadData->Event);
163 return 1;
164 }
165 BackgroundWnd = CreateWindowW((LPCWSTR) DESKTOP_WINDOW_ATOM,
166 L"",
167 WS_POPUP | WS_CLIPCHILDREN,
168 0,
169 0,
170 0,
171 0,
172 NULL,
173 NULL,
174 (HINSTANCE) GetModuleHandleW(NULL),
175 NULL);
176 if (NULL == BackgroundWnd)
177 {
178 DPRINT1("Failed to create desktop background window\n");
179 ThreadData->Status = STATUS_UNSUCCESSFUL;
180 SetEvent(ThreadData->Event);
181 return 1;
182 }
183
184 ThreadData->Status = STATUS_SUCCESS;
185 SetEvent(ThreadData->Event);
186
187 while (GetMessageW(&msg, NULL, 0, 0))
188 {
189 TranslateMessage(&msg);
190 DispatchMessageW(&msg);
191 }
192
193 return 1;
194 }
195
196 CSR_API(CsrCreateDesktop)
197 {
198 DTBG_THREAD_DATA ThreadData;
199 HANDLE ThreadHandle;
200
201 DPRINT("CsrCreateDesktop\n");
202
203 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
204 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
205
206 if (! BgInitialized)
207 {
208 BgInitialized = TRUE;
209 if (! DtbgInit())
210 {
211 return STATUS_UNSUCCESSFUL;
212 }
213 }
214
215 /*
216 * the desktop handle we got from win32k is in the scope of CSRSS so we can just use it
217 */
218 ThreadData.Desktop = Request->Data.CreateDesktopRequest.DesktopHandle;
219
220 ThreadData.Event = CreateEventW(NULL, FALSE, FALSE, NULL);
221 if (NULL == ThreadData.Event)
222 {
223 DPRINT1("Failed to create event (error %d)\n", GetLastError());
224 return STATUS_UNSUCCESSFUL;
225 }
226 ThreadHandle = CreateThread(NULL,
227 0,
228 DtbgDesktopThread,
229 (PVOID) &ThreadData,
230 0,
231 NULL);
232 if (NULL == ThreadHandle)
233 {
234 CloseHandle(ThreadData.Event);
235 DPRINT1("Failed to create desktop window thread.\n");
236 return STATUS_UNSUCCESSFUL;
237 }
238 CloseHandle(ThreadHandle);
239
240 WaitForSingleObject(ThreadData.Event, INFINITE);
241 CloseHandle(ThreadData.Event);
242
243 return ThreadData.Status;
244 }
245
246 CSR_API(CsrShowDesktop)
247 {
248 PRIVATE_NOTIFY_DESKTOP nmh;
249 DPRINT("CsrShowDesktop\n");
250
251 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
252 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
253
254 nmh.hdr.hwndFrom = Request->Data.ShowDesktopRequest.DesktopWindow;
255 nmh.hdr.idFrom = 0;
256 nmh.hdr.code = PM_SHOW_DESKTOP;
257
258 nmh.ShowDesktop.Width = (int)Request->Data.ShowDesktopRequest.Width;
259 nmh.ShowDesktop.Height = (int)Request->Data.ShowDesktopRequest.Height;
260
261 return SendMessageW(Request->Data.ShowDesktopRequest.DesktopWindow,
262 WM_NOTIFY,
263 (WPARAM)nmh.hdr.hwndFrom,
264 (LPARAM)&nmh)
265 ? STATUS_UNSUCCESSFUL : STATUS_SUCCESS;
266 }
267
268 CSR_API(CsrHideDesktop)
269 {
270 PRIVATE_NOTIFY_DESKTOP nmh;
271 DPRINT("CsrHideDesktop\n");
272
273 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
274 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
275
276 nmh.hdr.hwndFrom = Request->Data.ShowDesktopRequest.DesktopWindow;
277 nmh.hdr.idFrom = 0;
278 nmh.hdr.code = PM_HIDE_DESKTOP;
279
280 return SendMessageW(Request->Data.ShowDesktopRequest.DesktopWindow,
281 WM_NOTIFY,
282 (WPARAM)nmh.hdr.hwndFrom,
283 (LPARAM)&nmh)
284 ? STATUS_UNSUCCESSFUL : STATUS_SUCCESS;
285 }
286
287 BOOL FASTCALL
288 DtbgIsDesktopVisible(VOID)
289 {
290 if (NULL != VisibleDesktopWindow && ! IsWindowVisible(VisibleDesktopWindow))
291 {
292 VisibleDesktopWindow = NULL;
293 }
294
295 return NULL != VisibleDesktopWindow;
296 }
297
298 /* EOF */