:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[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   UNIMPLEMENTED;
329     
330   return 0;
331 }
332
333 BOOL STDCALL
334 NtUserPostThreadMessage(DWORD idThread,
335                         UINT Msg,
336                         WPARAM wParam,
337                         LPARAM lParam)
338 {
339   UNIMPLEMENTED;
340
341   return 0;
342 }
343
344 DWORD STDCALL
345 NtUserQuerySendMessage(DWORD Unknown0)
346 {
347   UNIMPLEMENTED;
348
349   return 0;
350 }
351
352 LRESULT STDCALL
353 W32kSendMessage(HWND hWnd,
354                 UINT Msg,
355                 WPARAM wParam,
356                 LPARAM lParam,
357                 BOOL KernelMessage)
358 {
359   LRESULT Result;
360   NTSTATUS Status;
361   PWINDOW_OBJECT Window;
362
363   /* FIXME: Check for a broadcast or topmost destination. */
364
365   /* FIXME: Call hooks. */
366
367   Status = 
368     ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable,
369                                hWnd,
370                                otWindow,
371                                (PVOID*)&Window);
372   if (!NT_SUCCESS(Status))
373     {
374       return(FALSE);
375     }
376
377   /* FIXME: Check for an exiting window. */
378
379   if (Window->MessageQueue == PsGetWin32Thread()->MessageQueue)
380     {
381       if (KernelMessage)
382         {
383           Result = W32kCallTrampolineWindowProc(NULL, hWnd, Msg, wParam,
384                                                 lParam);
385           return(Result);
386         }
387       else
388         {
389           Result = W32kCallWindowProc(NULL, hWnd, Msg, wParam, lParam);
390           return(Result);
391         }
392     }
393   else
394     {
395       PUSER_SENT_MESSAGE Message;
396       PKEVENT CompletionEvent;
397       
398       CompletionEvent = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
399       KeInitializeEvent(CompletionEvent, NotificationEvent, FALSE);
400
401       Message = ExAllocatePool(NonPagedPool, sizeof(USER_SENT_MESSAGE));
402       Message->Msg.hwnd = hWnd;
403       Message->Msg.message = Msg;
404       Message->Msg.wParam = wParam;
405       Message->Msg.lParam = lParam;
406       Message->CompletionEvent = CompletionEvent;
407       Message->Result = &Result;
408       Message->CompletionQueue = NULL;
409       Message->CompletionCallback = NULL;
410       MsqSendMessage(Window->MessageQueue, Message);
411
412       ObmDereferenceObject(Window);
413       Status = KeWaitForSingleObject(CompletionEvent,
414                                      UserRequest,
415                                      UserMode,
416                                      FALSE,
417                                      NULL);
418       if (Status == STATUS_WAIT_0)
419         {
420           return(Result);
421         }
422       else
423         {
424           return(FALSE);
425         }
426     }
427 }
428
429 LRESULT STDCALL
430 NtUserSendMessage(HWND hWnd,
431                   UINT Msg,
432                   WPARAM wParam,
433                   LPARAM lParam)
434 {
435   return(W32kSendMessage(hWnd, Msg, wParam, lParam, FALSE));
436 }
437
438 BOOL STDCALL
439 NtUserSendMessageCallback(HWND hWnd,
440                           UINT Msg,
441                           WPARAM wParam,
442                           LPARAM lParam,
443                           SENDASYNCPROC lpCallBack,
444                           ULONG_PTR dwData)
445 {
446   return(0);
447 }
448
449 BOOL STDCALL
450 NtUserSendNotifyMessage(HWND hWnd,
451                         UINT Msg,
452                         WPARAM wParam,
453                         LPARAM lParam)
454 {
455   UNIMPLEMENTED;
456
457   return 0;
458 }
459
460 BOOL STDCALL
461 NtUserWaitMessage(VOID)
462 {
463   UNIMPLEMENTED;
464
465   return 0;
466 }
467
468 /* EOF */