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