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