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