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