Release 0.4.3
[wine] / windows / message.c
1 /*
2  * Message queues related functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  */
6
7 /*
8  * This code assumes that there is only one Windows task (hence
9  * one message queue).
10  */
11
12 static char Copyright[] = "Copyright  Alexandre Julliard, 1993";
13
14 #include <stdlib.h>
15
16 #ifdef __NetBSD__
17 #define HZ 100
18 #endif
19
20 #include "message.h"
21 #include "win.h"
22
23
24 #define MAX_QUEUE_SIZE   120  /* Max. size of a message queue */
25
26 extern HWND WIN_FindWinToRepaint( HWND hwnd );
27
28 extern Display * XT_display;
29 extern Screen * XT_screen;
30 extern XtAppContext XT_app_context;
31
32 static MESSAGEQUEUE * msgQueue = NULL;
33
34
35 /***********************************************************************
36  *           MSG_GetMessageType
37  *
38  */
39 int MSG_GetMessageType( int msg )
40 {
41     if ((msg >= WM_KEYFIRST) && (msg <= WM_KEYLAST)) return QS_KEY;
42     else if ((msg >= WM_MOUSEFIRST) && (msg <= WM_MOUSELAST))
43     {
44         if (msg == WM_MOUSEMOVE) return QS_MOUSEMOVE;
45         else return QS_MOUSEBUTTON;
46     }
47     else if (msg == WM_PAINT) return QS_PAINT;
48     else if (msg == WM_TIMER) return QS_TIMER;
49     return QS_POSTMESSAGE;
50 }
51
52
53 /***********************************************************************
54  *           MSG_AddMsg
55  *
56  * Add a message to the queue. Return FALSE if queue is full.
57  */
58 int MSG_AddMsg( MSG * msg, DWORD extraInfo )
59 {
60     int pos, type;
61   
62     if (!msgQueue) return FALSE;
63     pos = msgQueue->nextFreeMessage;
64
65       /* No need to store WM_PAINT messages */
66     if (msg->message == WM_PAINT) return TRUE;
67         
68       /* Check if queue is full */
69     if ((pos == msgQueue->nextMessage) && (msgQueue->msgCount > 0))
70         return FALSE;
71
72       /* Store message */
73     msgQueue->messages[pos].msg = *msg;
74     msgQueue->messages[pos].extraInfo = extraInfo;
75
76       /* Store message type */
77     type = MSG_GetMessageType( msg->message );   
78     msgQueue->status |= type;
79     msgQueue->tempStatus |= type;
80     
81     if (pos < msgQueue->queueSize-1) pos++;
82     else pos = 0;
83     msgQueue->nextFreeMessage = pos;
84     msgQueue->msgCount++;
85     
86     return TRUE;
87 }
88
89
90 /***********************************************************************
91  *           MSG_FindMsg
92  *
93  * Find a message matching the given parameters. Return -1 if none available.
94  */
95 int MSG_FindMsg( HWND hwnd, int first, int last )
96 {
97     int i, pos = msgQueue->nextMessage;
98
99     if (!msgQueue->msgCount) return -1;
100     if (!hwnd && !first && !last) return pos;
101         
102     for (i = 0; i < msgQueue->msgCount; i++)
103     {
104         MSG * msg = &msgQueue->messages[pos].msg;
105
106         if (!hwnd || (msg->hwnd == hwnd))
107         {
108             if (!first && !last) return pos;
109             if ((msg->message >= first) && (msg->message <= last)) return pos;
110         }
111         if (pos < msgQueue->queueSize-1) pos++;
112         else pos = 0;
113     }
114     return -1;
115 }
116
117
118 /***********************************************************************
119  *           MSG_RemoveMsg
120  *
121  * Remove a message from the queue (pos must be a valid position).
122  */
123 void MSG_RemoveMsg( int pos )
124 {
125     int i, type;
126     QMSG * qmsg;
127     
128     if (!msgQueue) return;
129     qmsg = &msgQueue->messages[pos];
130
131     if (pos >= msgQueue->nextMessage)
132     {
133         int count = pos - msgQueue->nextMessage;
134         if (count) memmove( &msgQueue->messages[msgQueue->nextMessage+1],
135                             &msgQueue->messages[msgQueue->nextMessage],
136                             count * sizeof(QMSG) );
137         msgQueue->nextMessage++;
138         if (msgQueue->nextMessage >= msgQueue->queueSize)
139             msgQueue->nextMessage = 0;
140     }
141     else
142     {
143         int count = msgQueue->nextFreeMessage - pos;
144         if (count) memmove( &msgQueue->messages[pos],
145                             &msgQueue->messages[pos+1], count * sizeof(QMSG) );
146         if (msgQueue->nextFreeMessage) msgQueue->nextFreeMessage--;
147         else msgQueue->nextFreeMessage = msgQueue->queueSize-1;
148     }
149     msgQueue->msgCount--;
150
151       /* Recalc status */
152     type = 0;
153     pos = msgQueue->nextMessage;
154     for (i = 0; i < msgQueue->msgCount; i++)
155     {
156         type |= MSG_GetMessageType( msgQueue->messages[pos].msg.message );
157         if (++pos >= msgQueue->queueSize-1) pos = 0;
158     }
159     msgQueue->status = (msgQueue->status & QS_SENDMESSAGE) | type;
160     msgQueue->tempStatus = 0;
161 }
162
163
164 /***********************************************************************
165  *           SetMessageQueue  (USER.266)
166  */
167 BOOL SetMessageQueue( int size )
168 {
169     int queueSize;
170   
171       /* Free the old message queue */
172     if (msgQueue) free(msgQueue);
173   
174     if ((size > MAX_QUEUE_SIZE) || (size <= 0)) return FALSE;
175   
176     queueSize = sizeof(MESSAGEQUEUE) + size * sizeof(QMSG);
177     msgQueue = (MESSAGEQUEUE *) malloc(queueSize);
178     if (!msgQueue) return FALSE;
179
180     msgQueue->next = 0;
181     msgQueue->hTask = 0;
182     msgQueue->msgSize = sizeof(QMSG);
183     msgQueue->msgCount = 0;
184     msgQueue->nextMessage = 0;
185     msgQueue->nextFreeMessage = 0;
186     msgQueue->queueSize = size;
187     msgQueue->GetMessageTimeVal = 0;
188     msgQueue->GetMessagePosVal = 0;
189     msgQueue->GetMessageExtraInfoVal = 0;
190     msgQueue->lParam = 0;
191     msgQueue->wParam = 0;
192     msgQueue->msg = 0;
193     msgQueue->hWnd = 0;
194     msgQueue->wPostQMsg = 0;
195     msgQueue->wExitCode = 0;
196     msgQueue->InSendMessageHandle = 0;
197     msgQueue->tempStatus = 0;
198     msgQueue->status = 0;
199
200     return TRUE;
201 }
202
203
204 /***********************************************************************
205  *           PostQuitMessage   (USER.6)
206  */
207 void PostQuitMessage( int exitCode )
208 {
209     if (!msgQueue) return;
210     msgQueue->wPostQMsg = TRUE;
211     msgQueue->wExitCode = exitCode;
212 }
213
214
215 /***********************************************************************
216  *           GetQueueStatus   (USER.334)
217  */
218 DWORD GetQueueStatus( int flags )
219 {
220     unsigned long ret = (msgQueue->status << 16) | msgQueue->tempStatus;
221     if (flags & QS_PAINT)
222     {
223         if (WIN_FindWinToRepaint(0)) ret |= QS_PAINT | (QS_PAINT << 16);
224     }
225     msgQueue->tempStatus = 0;
226     return ret & ((flags << 16) | flags);
227 }
228
229
230 /***********************************************************************
231  *           GetInputState   (USER.335)
232  */
233 BOOL GetInputState()
234 {
235     return msgQueue->status & (QS_KEY | QS_MOUSEBUTTON);
236 }
237
238
239 /***********************************************************************
240  *           MSG_PeekMessage
241  */
242 BOOL MSG_PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last, WORD flags )
243 {
244     int pos;
245
246       /* First handle a WM_QUIT message */
247     if (msgQueue->wPostQMsg)
248     {
249         msg->hwnd    = hwnd;
250         msg->message = WM_QUIT;
251         msg->wParam  = msgQueue->wExitCode;
252         msg->lParam  = 0;
253         return TRUE;
254     }
255
256       /* Then handle a message put by SendMessage() */
257     if (msgQueue->status & QS_SENDMESSAGE)
258     {
259         if (!hwnd || (msgQueue->hWnd == hwnd))
260         {
261             if ((!first && !last) || 
262                 ((msgQueue->msg >= first) && (msgQueue->msg <= last)))
263             {
264                 msg->hwnd    = msgQueue->hWnd;
265                 msg->message = msgQueue->msg;
266                 msg->wParam  = msgQueue->wParam;
267                 msg->lParam  = msgQueue->lParam;
268                 if (flags & PM_REMOVE) msgQueue->status &= ~QS_SENDMESSAGE;
269                 return TRUE;
270             }
271         }
272         
273     }
274     
275       /* Now find a normal message */
276     pos = MSG_FindMsg( hwnd, first, last );
277     if (pos != -1)
278     {
279         QMSG *qmsg = &msgQueue->messages[pos];
280         *msg = qmsg->msg;
281         msgQueue->GetMessageTimeVal      = msg->time;
282         msgQueue->GetMessagePosVal       = *(DWORD *)&msg->pt;
283         msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
284
285         if (flags & PM_REMOVE) MSG_RemoveMsg(pos);
286         return TRUE;
287     }
288
289       /* If nothing else, return a WM_PAINT message */
290     if ((!first && !last) || ((first <= WM_PAINT) && (last >= WM_PAINT)))
291     {
292         msg->hwnd = WIN_FindWinToRepaint( hwnd );
293         msg->message = WM_PAINT;
294         msg->wParam = 0;
295         msg->lParam = 0;
296         return (msg->hwnd != 0);
297     }   
298     return FALSE;
299 }
300
301
302 /***********************************************************************
303  *           PeekMessage   (USER.109)
304  */
305 BOOL PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last, WORD flags )
306 {
307     while (XtAppPending( XT_app_context ))
308         XtAppProcessEvent( XT_app_context, XtIMAll );
309
310     return MSG_PeekMessage( msg, hwnd, first, last, flags );
311 }
312
313
314 /***********************************************************************
315  *           GetMessage   (USER.108)
316  */
317 BOOL GetMessage( LPMSG msg, HWND hwnd, WORD first, WORD last ) 
318 {
319     while(1)
320     {
321         if (MSG_PeekMessage( msg, hwnd, first, last, PM_REMOVE )) break;
322         XtAppProcessEvent( XT_app_context, XtIMAll );
323     }
324
325     return (msg->message != WM_QUIT);
326 }
327
328
329 /***********************************************************************
330  *           PostMessage   (USER.110)
331  */
332 BOOL PostMessage( HWND hwnd, WORD message, WORD wParam, LONG lParam )
333 {
334     MSG msg;
335     
336     msg.hwnd    = hwnd;
337     msg.message = message;
338     msg.wParam  = wParam;
339     msg.lParam  = lParam;
340     msg.time    = GetTickCount();
341     msg.pt.x    = 0;
342     msg.pt.y    = 0;
343     
344     return MSG_AddMsg( &msg, 0 );
345 }
346
347
348 /***********************************************************************
349  *           SendMessage   (USER.111)
350  */
351 LONG SendMessage( HWND hwnd, WORD msg, WORD wParam, LONG lParam )
352 {
353     WND * wndPtr = WIN_FindWndPtr( hwnd );
354     if (!wndPtr) return 0;
355     return CallWindowProc( wndPtr->lpfnWndProc, hwnd, msg, wParam, lParam );
356 }
357
358
359 /***********************************************************************
360  *           TranslateMessage   (USER.113)
361  */
362 BOOL TranslateMessage( LPMSG msg )
363 {
364     int message = msg->message;
365     
366     if ((message == WM_KEYDOWN) || (message == WM_KEYUP) ||
367         (message == WM_SYSKEYDOWN) || (message == WM_SYSKEYUP))
368     {
369 #ifdef DEBUG_MSG
370         printf( "Translating key message\n" );
371 #endif
372         return TRUE;
373     }
374     return FALSE;
375 }
376
377
378 /***********************************************************************
379  *           DispatchMessage   (USER.114)
380  */
381 LONG DispatchMessage( LPMSG msg )
382 {
383     WND * wndPtr = WIN_FindWndPtr( msg->hwnd );
384
385 #ifdef DEBUG_MSG
386     printf( "Dispatch message hwnd=%08x msg=%d w=%d l=%d time=%u pt=%d,%d\n",
387             msg->hwnd, msg->message, msg->wParam, msg->lParam, 
388             msg->time, msg->pt.x, msg->pt.y );
389 #endif
390     if (!wndPtr)  return 0;
391     return CallWindowProc( wndPtr->lpfnWndProc, msg->hwnd, msg->message,
392                            msg->wParam, msg->lParam );
393 }
394
395
396 /***********************************************************************
397  *           GetMessagePos   (USER.119)
398  */
399 DWORD GetMessagePos(void)
400 {
401     return msgQueue->GetMessagePosVal;
402 }
403
404
405 /***********************************************************************
406  *           GetMessageTime   (USER.120)
407  */
408 LONG GetMessageTime(void)
409 {
410     return msgQueue->GetMessageTimeVal;
411 }
412
413 /***********************************************************************
414  *           GetMessageExtraInfo   (USER.288)
415  */
416 LONG GetMessageExtraInfo(void)
417 {
418     return msgQueue->GetMessageExtraInfoVal;
419 }
420