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