WIN32K code cleanup.
[reactos.git] / reactos / subsys / win32k / ntuser / message.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: message.c,v 1.18 2003/05/18 17:16:17 ea Exp $
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Messages
24 * FILE: subsys/win32k/ntuser/message.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * REVISION HISTORY:
27 * 06-06-2001 CSH Created
28 */
29
30 /* INCLUDES ******************************************************************/
31
32 #include <ddk/ntddk.h>
33 #include <win32k/win32k.h>
34 #include <include/guicheck.h>
35 #include <include/msgqueue.h>
36 #include <include/window.h>
37 #include <include/class.h>
38 #include <include/error.h>
39 #include <include/object.h>
40 #include <include/winsta.h>
41 #include <include/callback.h>
42 #include <include/painting.h>
43
44 #define NDEBUG
45 #include <debug.h>
46
47 /* FUNCTIONS *****************************************************************/
48
49 NTSTATUS FASTCALL
50 W32kInitMessageImpl(VOID)
51 {
52 return(STATUS_SUCCESS);
53 }
54
55 NTSTATUS FASTCALL
56 W32kCleanupMessageImpl(VOID)
57 {
58 return(STATUS_SUCCESS);
59 }
60
61
62 LRESULT STDCALL
63 NtUserDispatchMessage(CONST MSG* lpMsg)
64 {
65 LRESULT Result;
66 ULONG PaintingFlag;
67 PWINDOW_OBJECT WindowObject;
68 NTSTATUS Status;
69
70 /* Process timer messages. */
71 if (lpMsg->message == WM_TIMER)
72 {
73 if (lpMsg->lParam)
74 {
75 /* FIXME: Call hooks. */
76
77 /* FIXME: Check for continuing validity of timer. */
78
79 return(W32kCallWindowProc((WNDPROC)lpMsg->lParam,
80 lpMsg->hwnd,
81 lpMsg->message,
82 lpMsg->wParam,
83 0 /* GetTickCount() */));
84 }
85 }
86
87 /* Get the window object. */
88 Status =
89 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable,
90 lpMsg->hwnd,
91 otWindow,
92 (PVOID*)&WindowObject);
93 if (!NT_SUCCESS(Status))
94 {
95 return(0);
96 }
97
98 /* FIXME: Check for paint message. */
99 PaintingFlag = (lpMsg->message == WM_PAINT);
100 if (PaintingFlag)
101 {
102 WindowObject->Flags |= WINDOWOBJECT_NEED_BEGINPAINT;
103 }
104
105 /* FIXME: Call hook procedures. */
106
107 /* Call the window procedure. */
108 Result = W32kCallWindowProc(NULL /* WndProc */,
109 lpMsg->hwnd,
110 lpMsg->message,
111 lpMsg->wParam,
112 lpMsg->lParam);
113
114 if (PaintingFlag && WindowObject->Flags & WINDOWOBJECT_NEED_BEGINPAINT &&
115 WindowObject->UpdateRegion)
116 {
117 DbgBreakPoint();
118 }
119
120 return(Result);
121 }
122
123 BOOL STDCALL
124 NtUserGetMessage(LPMSG lpMsg,
125 HWND hWnd,
126 UINT wMsgFilterMin,
127 UINT wMsgFilterMax)
128 /*
129 * FUNCTION: Get a message from the calling thread's message queue.
130 * ARGUMENTS:
131 * lpMsg - Pointer to the structure which receives the returned message.
132 * hWnd - Window whose messages are to be retrieved.
133 * wMsgFilterMin - Integer value of the lowest message value to be
134 * retrieved.
135 * wMsgFilterMax - Integer value of the highest message value to be
136 * retrieved.
137 */
138 {
139 PUSER_MESSAGE_QUEUE ThreadQueue;
140 BOOLEAN Present;
141 PUSER_MESSAGE Message;
142 NTSTATUS Status;
143
144 /* Initialize the thread's win32 state if necessary. */
145 W32kGuiCheck();
146
147 ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
148
149 do
150 {
151 /* Dispatch sent messages here. */
152 while (MsqDispatchOneSentMessage(ThreadQueue));
153
154 /* Now look for a quit message. */
155 /* FIXME: WINE checks the message number filter here. */
156 if (ThreadQueue->QuitPosted)
157 {
158 lpMsg->hwnd = hWnd;
159 lpMsg->message = WM_QUIT;
160 lpMsg->wParam = ThreadQueue->QuitExitCode;
161 lpMsg->lParam = 0;
162 ThreadQueue->QuitPosted = FALSE;
163 return(FALSE);
164 }
165
166 /* Now check for normal messages. */
167 Present = MsqFindMessage(ThreadQueue,
168 FALSE,
169 TRUE,
170 hWnd,
171 wMsgFilterMin,
172 wMsgFilterMax,
173 &Message);
174 if (Present)
175 {
176 RtlCopyMemory(lpMsg, &Message->Msg, sizeof(MSG));
177 ExFreePool(Message);
178 return(TRUE);
179 }
180
181 /* Check for hardware events. */
182 Present = MsqFindMessage(ThreadQueue,
183 TRUE,
184 TRUE,
185 hWnd,
186 wMsgFilterMin,
187 wMsgFilterMax,
188 &Message);
189 if (Present)
190 {
191 RtlCopyMemory(lpMsg, &Message->Msg, sizeof(MSG));
192 ExFreePool(Message);
193 return(TRUE);
194 }
195
196 /* Check for sent messages again. */
197 while (MsqDispatchOneSentMessage(ThreadQueue));
198
199 /* Check for paint messages. */
200 if (ThreadQueue->PaintPosted)
201 {
202 PWINDOW_OBJECT WindowObject;
203
204 lpMsg->hwnd = PaintingFindWinToRepaint(hWnd, PsGetWin32Thread());
205 lpMsg->message = WM_PAINT;
206 lpMsg->wParam = lpMsg->lParam = 0;
207
208 WindowObject = W32kGetWindowObject(lpMsg->hwnd);
209 if (WindowObject != NULL)
210 {
211 if (WindowObject->Style & WS_MINIMIZE &&
212 (HICON)NtUserGetClassLong(lpMsg->hwnd, GCL_HICON) != NULL)
213 {
214 lpMsg->message = WM_PAINTICON;
215 lpMsg->wParam = 1;
216 }
217
218 if (lpMsg->hwnd == NULL || lpMsg->hwnd == hWnd ||
219 W32kIsChildWindow(hWnd, lpMsg->hwnd))
220 {
221 if (WindowObject->Flags & WINDOWOBJECT_NEED_INTERNALPAINT &&
222 WindowObject->UpdateRegion == NULL)
223 {
224 WindowObject->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
225 MsqDecPaintCountQueue(WindowObject->MessageQueue);
226 }
227 }
228 W32kReleaseWindowObject(WindowObject);
229 }
230
231 return(TRUE);
232 }
233
234 /* Nothing found so far. Wait for new messages. */
235 Status = MsqWaitForNewMessages(ThreadQueue);
236 }
237 while (Status >= STATUS_WAIT_0 && Status <= STATUS_WAIT_63);
238 return((BOOLEAN)(-1));
239 }
240
241 DWORD
242 STDCALL
243 NtUserMessageCall(
244 DWORD Unknown0,
245 DWORD Unknown1,
246 DWORD Unknown2,
247 DWORD Unknown3,
248 DWORD Unknown4,
249 DWORD Unknown5,
250 DWORD Unknown6)
251 {
252 UNIMPLEMENTED
253
254 return 0;
255 }
256
257 BOOL STDCALL
258 NtUserPeekMessage(LPMSG lpMsg,
259 HWND hWnd,
260 UINT wMsgFilterMin,
261 UINT wMsgFilterMax,
262 UINT wRemoveMsg)
263 /*
264 * FUNCTION: Get a message from the calling thread's message queue.
265 * ARGUMENTS:
266 * lpMsg - Pointer to the structure which receives the returned message.
267 * hWnd - Window whose messages are to be retrieved.
268 * wMsgFilterMin - Integer value of the lowest message value to be
269 * retrieved.
270 * wMsgFilterMax - Integer value of the highest message value to be
271 * retrieved.
272 * wRemoveMsg - Specificies whether or not to remove messages from the queue after processing
273 */
274 {
275 PUSER_MESSAGE_QUEUE ThreadQueue;
276 BOOLEAN Present;
277 PUSER_MESSAGE Message;
278 BOOLEAN RemoveMessages;
279
280 /* Initialize the thread's win32 state if necessary. */
281 W32kGuiCheck();
282
283 ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
284
285 /* Inspect wRemoveMsg flags */
286 /* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
287 RemoveMessages = wRemoveMsg & PM_REMOVE;
288
289 /* Dispatch sent messages here. */
290 while (MsqDispatchOneSentMessage(ThreadQueue));
291
292 /* Now look for a quit message. */
293 /* FIXME: WINE checks the message number filter here. */
294 if (ThreadQueue->QuitPosted)
295 {
296 lpMsg->hwnd = hWnd;
297 lpMsg->message = WM_QUIT;
298 lpMsg->wParam = ThreadQueue->QuitExitCode;
299 lpMsg->lParam = 0;
300 ThreadQueue->QuitPosted = FALSE;
301 return(FALSE);
302 }
303
304 /* Now check for normal messages. */
305 Present = MsqFindMessage(ThreadQueue,
306 FALSE,
307 RemoveMessages,
308 hWnd,
309 wMsgFilterMin,
310 wMsgFilterMax,
311 &Message);
312 if (Present)
313 {
314 RtlCopyMemory(lpMsg, &Message->Msg, sizeof(MSG));
315 ExFreePool(Message);
316 return(TRUE);
317 }
318
319 /* Check for hardware events. */
320 Present = MsqFindMessage(ThreadQueue,
321 TRUE,
322 RemoveMessages,
323 hWnd,
324 wMsgFilterMin,
325 wMsgFilterMax,
326 &Message);
327 if (Present)
328 {
329 RtlCopyMemory(lpMsg, &Message->Msg, sizeof(MSG));
330 ExFreePool(Message);
331 return(TRUE);
332 }
333
334 /* Check for sent messages again. */
335 while (MsqDispatchOneSentMessage(ThreadQueue));
336
337 /* Check for paint messages. */
338
339 /* Check for paint messages. */
340 if (ThreadQueue->PaintPosted)
341 {
342 PWINDOW_OBJECT WindowObject;
343
344 lpMsg->hwnd = PaintingFindWinToRepaint(hWnd, PsGetWin32Thread());
345 lpMsg->message = WM_PAINT;
346 lpMsg->wParam = lpMsg->lParam = 0;
347
348 WindowObject = W32kGetWindowObject(lpMsg->hwnd);
349 if (WindowObject != NULL)
350 {
351 if (WindowObject->Style & WS_MINIMIZE &&
352 (HICON)NtUserGetClassLong(lpMsg->hwnd, GCL_HICON) != NULL)
353 {
354 lpMsg->message = WM_PAINTICON;
355 lpMsg->wParam = 1;
356 }
357
358 if (lpMsg->hwnd == NULL || lpMsg->hwnd == hWnd ||
359 W32kIsChildWindow(hWnd, lpMsg->hwnd))
360 {
361 if (WindowObject->Flags & WINDOWOBJECT_NEED_INTERNALPAINT &&
362 WindowObject->UpdateRegion == NULL)
363 {
364 WindowObject->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
365 MsqDecPaintCountQueue(WindowObject->MessageQueue);
366 }
367 }
368 W32kReleaseWindowObject(WindowObject);
369 }
370
371 return(TRUE);
372 }
373
374 return FALSE;
375 }
376
377 BOOL STDCALL
378 NtUserPostMessage(HWND hWnd,
379 UINT Msg,
380 WPARAM wParam,
381 LPARAM lParam)
382 {
383 PUSER_MESSAGE_QUEUE ThreadQueue;
384
385 switch (Msg)
386 {
387 case WM_NULL:
388 break;
389
390 case WM_QUIT:
391 ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
392 ThreadQueue->QuitPosted = TRUE;
393 ThreadQueue->QuitExitCode = wParam;
394 break;
395
396 default:
397 DPRINT1("Unhandled message: %u\n", Msg);
398 return FALSE;
399 }
400
401 return TRUE;
402 }
403
404 BOOL STDCALL
405 NtUserPostThreadMessage(DWORD idThread,
406 UINT Msg,
407 WPARAM wParam,
408 LPARAM lParam)
409 {
410 UNIMPLEMENTED;
411
412 return 0;
413 }
414
415 DWORD STDCALL
416 NtUserQuerySendMessage(DWORD Unknown0)
417 {
418 UNIMPLEMENTED;
419
420 return 0;
421 }
422
423 LRESULT STDCALL
424 W32kSendMessage(HWND hWnd,
425 UINT Msg,
426 WPARAM wParam,
427 LPARAM lParam,
428 BOOL KernelMessage)
429 {
430 LRESULT Result;
431 NTSTATUS Status;
432 PWINDOW_OBJECT Window;
433
434 /* FIXME: Check for a broadcast or topmost destination. */
435
436 /* FIXME: Call hooks. */
437
438 Status =
439 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable,
440 hWnd,
441 otWindow,
442 (PVOID*)&Window);
443 if (!NT_SUCCESS(Status))
444 {
445 return(FALSE);
446 }
447
448 /* FIXME: Check for an exiting window. */
449
450 if (NULL != PsGetWin32Thread() &&
451 Window->MessageQueue == PsGetWin32Thread()->MessageQueue)
452 {
453 if (KernelMessage)
454 {
455 Result = W32kCallTrampolineWindowProc(NULL, hWnd, Msg, wParam,
456 lParam);
457 return(Result);
458 }
459 else
460 {
461 Result = W32kCallWindowProc(NULL, hWnd, Msg, wParam, lParam);
462 return(Result);
463 }
464 }
465 else
466 {
467 PUSER_SENT_MESSAGE Message;
468 PKEVENT CompletionEvent;
469
470 CompletionEvent = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
471 KeInitializeEvent(CompletionEvent, NotificationEvent, FALSE);
472
473 Message = ExAllocatePool(NonPagedPool, sizeof(USER_SENT_MESSAGE));
474 Message->Msg.hwnd = hWnd;
475 Message->Msg.message = Msg;
476 Message->Msg.wParam = wParam;
477 Message->Msg.lParam = lParam;
478 Message->CompletionEvent = CompletionEvent;
479 Message->Result = &Result;
480 Message->CompletionQueue = NULL;
481 Message->CompletionCallback = NULL;
482 MsqSendMessage(Window->MessageQueue, Message);
483
484 ObmDereferenceObject(Window);
485 Status = KeWaitForSingleObject(CompletionEvent,
486 UserRequest,
487 UserMode,
488 FALSE,
489 NULL);
490 if (Status == STATUS_WAIT_0)
491 {
492 return(Result);
493 }
494 else
495 {
496 return(FALSE);
497 }
498 }
499 }
500
501 LRESULT STDCALL
502 NtUserSendMessage(HWND hWnd,
503 UINT Msg,
504 WPARAM wParam,
505 LPARAM lParam)
506 {
507 return(W32kSendMessage(hWnd, Msg, wParam, lParam, FALSE));
508 }
509
510 BOOL STDCALL
511 NtUserSendMessageCallback(HWND hWnd,
512 UINT Msg,
513 WPARAM wParam,
514 LPARAM lParam,
515 SENDASYNCPROC lpCallBack,
516 ULONG_PTR dwData)
517 {
518 UNIMPLEMENTED;
519
520 return(0);
521 }
522
523 BOOL STDCALL
524 NtUserSendNotifyMessage(HWND hWnd,
525 UINT Msg,
526 WPARAM wParam,
527 LPARAM lParam)
528 {
529 UNIMPLEMENTED;
530
531 return 0;
532 }
533
534 BOOL STDCALL
535 NtUserWaitMessage(VOID)
536 {
537 UNIMPLEMENTED;
538
539 return 0;
540 }
541
542 /* EOF */