Release 960516
[wine] / windows / queue.c
1 /*
2  * Message queues related functions
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  */
6
7 #include <stdlib.h>
8 #include "module.h"
9 #include "queue.h"
10 #include "win.h"
11 #include "stddebug.h"
12 #include "debug.h"
13
14 #define MAX_QUEUE_SIZE   120  /* Max. size of a message queue */
15
16 static HQUEUE hFirstQueue = 0;
17 static HQUEUE hmemSysMsgQueue = 0;
18 static HQUEUE hDoomedQueue = 0;
19 static MESSAGEQUEUE *sysMsgQueue = NULL;
20
21 /***********************************************************************
22  *           QUEUE_GetDoomedQueue/QUEUE_SetDoomedQueue
23  */
24 HQUEUE QUEUE_GetDoomedQueue()
25 {
26   return hDoomedQueue;
27 }
28 void QUEUE_SetDoomedQueue(HQUEUE hQueue)
29 {
30   hDoomedQueue = hQueue;
31 }
32
33 /***********************************************************************
34  *           QUEUE_DumpQueue
35  */
36 void QUEUE_DumpQueue( HQUEUE hQueue )
37 {
38     MESSAGEQUEUE *pq; 
39
40     if (!(pq = (MESSAGEQUEUE*) GlobalLock16( hQueue )) ||
41         GlobalSize16(hQueue) < sizeof(MESSAGEQUEUE)+pq->queueSize*sizeof(QMSG))
42     {
43         fprintf( stderr, "%04x is not a queue handle\n", hQueue );
44         return;
45     }
46
47     fprintf( stderr,
48              "next: %12.4x  Intertask SendMessage:\n"
49              "hTask: %11.4x  ----------------------\n"
50              "msgSize: %9.4x  hWnd: %10.4x\n"
51              "msgCount: %8.4x  msg: %11.4x\n"
52              "msgNext: %9.4x  wParam: %8.4x\n"
53              "msgFree: %9.4x  lParam: %8.8x\n"
54              "qSize: %11.4x  lRet: %10.8x\n"
55              "wWinVer: %9.4x  ISMH: %10.4x\n"
56              "paints: %10.4x  hSendTask: %5.4x\n"
57              "timers: %10.4x  hPrevSend: %5.4x\n"
58              "wakeBits: %8.4x\n"
59              "wakeMask: %8.4x\n"
60              "hCurHook: %8.4x\n",
61              pq->next, pq->hTask, pq->msgSize, pq->hWnd, 
62              pq->msgCount, pq->msg, pq->nextMessage, pq->wParam,
63              pq->nextFreeMessage, (unsigned)pq->lParam, pq->queueSize,
64              (unsigned)pq->SendMessageReturn, pq->wWinVersion, pq->InSendMessageHandle,
65              pq->wPaintCount, pq->hSendingTask, pq->wTimerCount,
66              pq->hPrevSendingTask, pq->status, pq->wakeMask, pq->hCurHook);
67 }
68
69
70 /***********************************************************************
71  *           QUEUE_WalkQueues
72  */
73 void QUEUE_WalkQueues(void)
74 {
75     HQUEUE hQueue = hFirstQueue;
76
77     fprintf( stderr, "Queue Size Msgs Task\n" );
78     while (hQueue)
79     {
80         MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
81         if (!queue)
82         {
83             fprintf( stderr, "*** Bad queue handle %04x\n", hQueue );
84             return;
85         }
86         fprintf( stderr, "%04x %5d %4d %04x %s\n",
87                  hQueue, queue->msgSize, queue->msgCount, queue->hTask,
88                  MODULE_GetModuleName( GetExePtr(queue->hTask) ) );
89         hQueue = queue->next;
90     }
91     fprintf( stderr, "\n" );
92 }
93
94
95 /***********************************************************************
96  *           QUEUE_CreateMsgQueue
97  *
98  * Creates a message queue. Doesn't link it into queue list!
99  */
100 static HQUEUE QUEUE_CreateMsgQueue( int size )
101 {
102     HQUEUE hQueue;
103     MESSAGEQUEUE * msgQueue;
104     int queueSize;
105
106     dprintf_msg(stddeb,"Creating message queue...\n");
107
108     queueSize = sizeof(MESSAGEQUEUE) + size * sizeof(QMSG);
109     if (!(hQueue = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT, queueSize )))
110         return 0;
111     msgQueue = (MESSAGEQUEUE *) GlobalLock16( hQueue );
112     msgQueue->msgSize = sizeof(QMSG);
113     msgQueue->queueSize = size;
114     msgQueue->wWinVersion = 0;  /* FIXME? */
115     GlobalUnlock16( hQueue );
116     return hQueue;
117 }
118
119
120 /***********************************************************************
121  *           QUEUE_DeleteMsgQueue
122  *
123  * Unlinks and deletes a message queue.
124  */
125 BOOL QUEUE_DeleteMsgQueue( HQUEUE hQueue )
126 {
127     MESSAGEQUEUE * msgQueue = (MESSAGEQUEUE*)GlobalLock16(hQueue);
128     HQUEUE *pPrev;
129
130     dprintf_msg(stddeb,"Deleting message queue %04x\n", hQueue);
131
132     if (!hQueue || !msgQueue)
133     {
134         dprintf_msg(stddeb,"DeleteMsgQueue: invalid argument.\n");
135         return 0;
136     }
137
138     pPrev = &hFirstQueue;
139     while (*pPrev && (*pPrev != hQueue))
140     {
141         MESSAGEQUEUE *msgQ = (MESSAGEQUEUE*)GlobalLock16(*pPrev);
142         pPrev = &msgQ->next;
143     }
144     if (*pPrev) *pPrev = msgQueue->next;
145     GlobalFree16( hQueue );
146     return 1;
147 }
148
149
150 /***********************************************************************
151  *           QUEUE_CreateSysMsgQueue
152  *
153  * Create the system message queue, and set the double-click speed.
154  * Must be called only once.
155  */
156 BOOL QUEUE_CreateSysMsgQueue( int size )
157 {
158     if (size > MAX_QUEUE_SIZE) size = MAX_QUEUE_SIZE;
159     else if (size <= 0) size = 1;
160     if (!(hmemSysMsgQueue = QUEUE_CreateMsgQueue( size ))) return FALSE;
161     sysMsgQueue = (MESSAGEQUEUE *) GlobalLock16( hmemSysMsgQueue );
162     return TRUE;
163 }
164
165
166 /***********************************************************************
167  *           QUEUE_GetSysQueue
168  */
169 MESSAGEQUEUE *QUEUE_GetSysQueue(void)
170 {
171     return sysMsgQueue;
172 }
173
174
175 /***********************************************************************
176  *           QUEUE_AddMsg
177  *
178  * Add a message to the queue. Return FALSE if queue is full.
179  */
180 BOOL QUEUE_AddMsg( HQUEUE hQueue, MSG * msg, DWORD extraInfo )
181 {
182     int pos;
183     MESSAGEQUEUE *msgQueue;
184
185     if (!(msgQueue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return FALSE;
186     pos = msgQueue->nextFreeMessage;
187
188       /* Check if queue is full */
189     if ((pos == msgQueue->nextMessage) && (msgQueue->msgCount > 0))
190     {
191         fprintf(stderr,"MSG_AddMsg // queue is full !\n");
192         return FALSE;
193     }
194
195       /* Store message */
196     msgQueue->messages[pos].msg = *msg;
197     msgQueue->messages[pos].extraInfo = extraInfo;
198     if (pos < msgQueue->queueSize-1) pos++;
199     else pos = 0;
200     msgQueue->nextFreeMessage = pos;
201     msgQueue->msgCount++;
202     msgQueue->status |= QS_POSTMESSAGE;
203     msgQueue->tempStatus |= QS_POSTMESSAGE;
204     return TRUE;
205 }
206
207
208 /***********************************************************************
209  *           QUEUE_FindMsg
210  *
211  * Find a message matching the given parameters. Return -1 if none available.
212  */
213 int QUEUE_FindMsg( MESSAGEQUEUE * msgQueue, HWND hwnd, int first, int last )
214 {
215     int i, pos = msgQueue->nextMessage;
216
217     dprintf_msg(stddeb,"QUEUE_FindMsg: hwnd=%04x pos=%d\n", hwnd, pos );
218
219     if (!msgQueue->msgCount) return -1;
220     if (!hwnd && !first && !last) return pos;
221         
222     for (i = 0; i < msgQueue->msgCount; i++)
223     {
224         MSG * msg = &msgQueue->messages[pos].msg;
225
226         if (!hwnd || (msg->hwnd == hwnd))
227         {
228             if (!first && !last) return pos;
229             if ((msg->message >= first) && (msg->message <= last)) return pos;
230         }
231         if (pos < msgQueue->queueSize-1) pos++;
232         else pos = 0;
233     }
234     return -1;
235 }
236
237
238 /***********************************************************************
239  *           QUEUE_RemoveMsg
240  *
241  * Remove a message from the queue (pos must be a valid position).
242  */
243 void QUEUE_RemoveMsg( MESSAGEQUEUE * msgQueue, int pos )
244 {
245     if (pos >= msgQueue->nextMessage)
246     {
247         for ( ; pos > msgQueue->nextMessage; pos--)
248             msgQueue->messages[pos] = msgQueue->messages[pos-1];
249         msgQueue->nextMessage++;
250         if (msgQueue->nextMessage >= msgQueue->queueSize)
251             msgQueue->nextMessage = 0;
252     }
253     else
254     {
255         for ( ; pos < msgQueue->nextFreeMessage; pos++)
256             msgQueue->messages[pos] = msgQueue->messages[pos+1];
257         if (msgQueue->nextFreeMessage) msgQueue->nextFreeMessage--;
258         else msgQueue->nextFreeMessage = msgQueue->queueSize-1;
259     }
260     msgQueue->msgCount--;
261     if (!msgQueue->msgCount) msgQueue->status &= ~QS_POSTMESSAGE;
262     msgQueue->tempStatus = 0;
263 }
264
265
266 /***********************************************************************
267  *           hardware_event
268  *
269  * Add an event to the system message queue.
270  * Note: the position is relative to the desktop window.
271  */
272 void hardware_event( WORD message, WORD wParam, LONG lParam,
273                      int xPos, int yPos, DWORD time, DWORD extraInfo )
274 {
275     MSG *msg;
276     int pos;
277   
278     if (!sysMsgQueue) return;
279     pos = sysMsgQueue->nextFreeMessage;
280
281       /* Merge with previous event if possible */
282
283     if ((message == WM_MOUSEMOVE) && sysMsgQueue->msgCount)
284     {
285         if (pos > 0) pos--;
286         else pos = sysMsgQueue->queueSize - 1;
287         msg = &sysMsgQueue->messages[pos].msg;
288         if ((msg->message == message) && (msg->wParam == wParam))
289             sysMsgQueue->msgCount--;  /* Merge events */
290         else
291             pos = sysMsgQueue->nextFreeMessage;  /* Don't merge */
292     }
293
294       /* Check if queue is full */
295
296     if ((pos == sysMsgQueue->nextMessage) && sysMsgQueue->msgCount)
297     {
298         /* Queue is full, beep (but not on every mouse motion...) */
299         if (message != WM_MOUSEMOVE) MessageBeep(0);
300         return;
301     }
302
303       /* Store message */
304
305     msg = &sysMsgQueue->messages[pos].msg;
306     msg->hwnd    = 0;
307     msg->message = message;
308     msg->wParam  = wParam;
309     msg->lParam  = lParam;
310     msg->time    = time;
311     msg->pt.x    = xPos & 0xffff;
312     msg->pt.y    = yPos & 0xffff;
313     sysMsgQueue->messages[pos].extraInfo = extraInfo;
314     if (pos < sysMsgQueue->queueSize - 1) pos++;
315     else pos = 0;
316     sysMsgQueue->nextFreeMessage = pos;
317     sysMsgQueue->msgCount++;
318 }
319
320                     
321 /***********************************************************************
322  *           QUEUE_GetQueueTask
323  */
324 HTASK QUEUE_GetQueueTask( HQUEUE hQueue )
325 {
326     MESSAGEQUEUE *queue = GlobalLock16( hQueue );
327     return (queue) ? queue->hTask : 0 ;
328 }
329
330
331 /***********************************************************************
332  *           QUEUE_IncPaintCount
333  */
334 void QUEUE_IncPaintCount( HQUEUE hQueue )
335 {
336     MESSAGEQUEUE *queue;
337
338     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return;
339     queue->wPaintCount++;
340     queue->status |= QS_PAINT;
341     queue->tempStatus |= QS_PAINT;    
342 }
343
344
345 /***********************************************************************
346  *           QUEUE_DecPaintCount
347  */
348 void QUEUE_DecPaintCount( HQUEUE hQueue )
349 {
350     MESSAGEQUEUE *queue;
351
352     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return;
353     queue->wPaintCount--;
354     if (!queue->wPaintCount) queue->status &= ~QS_PAINT;
355 }
356
357
358 /***********************************************************************
359  *           QUEUE_IncTimerCount
360  */
361 void QUEUE_IncTimerCount( HQUEUE hQueue )
362 {
363     MESSAGEQUEUE *queue;
364
365     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return;
366     queue->wTimerCount++;
367     queue->status |= QS_TIMER;
368     queue->tempStatus |= QS_TIMER;
369 }
370
371
372 /***********************************************************************
373  *           QUEUE_DecTimerCount
374  */
375 void QUEUE_DecTimerCount( HQUEUE hQueue )
376 {
377     MESSAGEQUEUE *queue;
378
379     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return;
380     queue->wTimerCount--;
381     if (!queue->wTimerCount) queue->status &= ~QS_TIMER;
382 }
383
384
385 /***********************************************************************
386  *           PostQuitMessage   (USER.6)
387  */
388 void PostQuitMessage( INT exitCode )
389 {
390     MESSAGEQUEUE *queue;
391
392     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return;
393     queue->wPostQMsg = TRUE;
394     queue->wExitCode = (WORD)exitCode;
395 }
396
397
398 /***********************************************************************
399  *           GetWindowTask   (USER.224)
400  */
401 HTASK GetWindowTask( HWND hwnd )
402 {
403     WND *wndPtr = WIN_FindWndPtr( hwnd );
404
405     if (!wndPtr) return 0;
406     return QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
407 }
408
409
410 /***********************************************************************
411  *           SetMessageQueue   (USER.266)
412  */
413 BOOL SetMessageQueue( int size )
414 {
415     HQUEUE hQueue, hNewQueue;
416     MESSAGEQUEUE *queuePtr;
417
418     dprintf_msg(stddeb,"SetMessageQueue: task %04x size %i\n", GetCurrentTask(), size); 
419
420     if ((size > MAX_QUEUE_SIZE) || (size <= 0)) return TRUE;
421
422     if( !(hNewQueue = QUEUE_CreateMsgQueue( size ))) 
423     {
424         dprintf_msg(stddeb,"SetMessageQueue: failed!\n");
425         return FALSE;
426     }
427
428     /* Free the old message queue */
429     if ((hQueue = GetTaskQueue(0)) != 0) QUEUE_DeleteMsgQueue( hQueue );
430
431     /* Link new queue into list */
432     queuePtr = (MESSAGEQUEUE *)GlobalLock16( hNewQueue );
433     queuePtr->hTask = GetCurrentTask();
434     queuePtr->next  = hFirstQueue;
435     hFirstQueue = hNewQueue;
436
437     SetTaskQueue( 0, hNewQueue );
438     return TRUE;
439 }
440
441
442 /***********************************************************************
443  *           GetQueueStatus   (USER.334)
444  */
445 DWORD GetQueueStatus( UINT flags )
446 {
447     MESSAGEQUEUE *queue;
448     DWORD ret;
449
450     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return 0;
451     ret = MAKELONG( queue->tempStatus, queue->status );
452     queue->tempStatus = 0;
453     return ret & MAKELONG( flags, flags );
454 }
455
456
457 /***********************************************************************
458  *           GetInputState   (USER.335)
459  */
460 BOOL GetInputState()
461 {
462     MESSAGEQUEUE *queue;
463
464     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return FALSE;
465     return queue->status & (QS_KEY | QS_MOUSEBUTTON);
466 }
467
468
469 /***********************************************************************
470  *           GetMessagePos   (USER.119)
471  */
472 DWORD GetMessagePos(void)
473 {
474     MESSAGEQUEUE *queue;
475
476     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return 0;
477     return queue->GetMessagePosVal;
478 }
479
480
481 /***********************************************************************
482  *           GetMessageTime   (USER.120)
483  */
484 LONG GetMessageTime(void)
485 {
486     MESSAGEQUEUE *queue;
487
488     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return 0;
489     return queue->GetMessageTimeVal;
490 }
491
492
493 /***********************************************************************
494  *           GetMessageExtraInfo   (USER.288)
495  */
496 LONG GetMessageExtraInfo(void)
497 {
498     MESSAGEQUEUE *queue;
499
500     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return 0;
501     return queue->GetMessageExtraInfoVal;
502 }