Release 0.5
[wine/multimedia.git] / windows / message.c
blob09b49e7861cfbd826e7267957398a26b7c155d93
1 /*
2 * Message queues related functions
4 * Copyright 1993 Alexandre Julliard
5 */
7 /*
8 * This code assumes that there is only one Windows task (hence
9 * one message queue).
12 static char Copyright[] = "Copyright Alexandre Julliard, 1993";
14 #include <stdlib.h>
15 #include <sys/time.h>
16 #include <sys/types.h>
18 #include "message.h"
19 #include "win.h"
22 #define MAX_QUEUE_SIZE 120 /* Max. size of a message queue */
24 extern BOOL TIMER_CheckTimer( DWORD *next ); /* timer.c */
26 extern Display * XT_display;
27 extern Screen * XT_screen;
28 extern XtAppContext XT_app_context;
30 /* System message queue (for hardware events) */
31 static HANDLE hmemSysMsgQueue = 0;
32 static MESSAGEQUEUE * sysMsgQueue = NULL;
34 /* Application message queue (should be a list, one queue per task) */
35 static HANDLE hmemAppMsgQueue = 0;
36 static MESSAGEQUEUE * appMsgQueue = NULL;
38 /***********************************************************************
39 * MSG_CreateMsgQueue
41 * Create a message queue.
43 static HANDLE MSG_CreateMsgQueue( int size )
45 HANDLE hQueue;
46 MESSAGEQUEUE * msgQueue;
47 int queueSize;
49 queueSize = sizeof(MESSAGEQUEUE) + size * sizeof(QMSG);
50 if (!(hQueue = GlobalAlloc( GMEM_FIXED, queueSize ))) return 0;
51 msgQueue = (MESSAGEQUEUE *) GlobalLock( hQueue );
52 msgQueue->next = 0;
53 msgQueue->hTask = 0;
54 msgQueue->msgSize = sizeof(QMSG);
55 msgQueue->msgCount = 0;
56 msgQueue->nextMessage = 0;
57 msgQueue->nextFreeMessage = 0;
58 msgQueue->queueSize = size;
59 msgQueue->GetMessageTimeVal = 0;
60 msgQueue->GetMessagePosVal = 0;
61 msgQueue->GetMessageExtraInfoVal = 0;
62 msgQueue->lParam = 0;
63 msgQueue->wParam = 0;
64 msgQueue->msg = 0;
65 msgQueue->hWnd = 0;
66 msgQueue->wPostQMsg = 0;
67 msgQueue->wExitCode = 0;
68 msgQueue->InSendMessageHandle = 0;
69 msgQueue->wPaintCount = 0;
70 msgQueue->wTimerCount = 0;
71 msgQueue->tempStatus = 0;
72 msgQueue->status = 0;
73 GlobalUnlock( hQueue );
74 return hQueue;
78 /***********************************************************************
79 * MSG_CreateSysMsgQueue
81 * Create the system message queue. Must be called only once.
83 BOOL MSG_CreateSysMsgQueue( int size )
85 if (size > MAX_QUEUE_SIZE) size = MAX_QUEUE_SIZE;
86 else if (size <= 0) size = 1;
87 if (!(hmemSysMsgQueue = MSG_CreateMsgQueue( size ))) return FALSE;
88 sysMsgQueue = (MESSAGEQUEUE *) GlobalLock( hmemSysMsgQueue );
89 return TRUE;
93 /***********************************************************************
94 * MSG_AddMsg
96 * Add a message to the queue. Return FALSE if queue is full.
98 static int MSG_AddMsg( MESSAGEQUEUE * msgQueue, MSG * msg, DWORD extraInfo )
100 int pos;
102 if (!msgQueue) return FALSE;
103 pos = msgQueue->nextFreeMessage;
105 /* Check if queue is full */
106 if ((pos == msgQueue->nextMessage) && (msgQueue->msgCount > 0))
107 return FALSE;
109 /* Store message */
110 msgQueue->messages[pos].msg = *msg;
111 msgQueue->messages[pos].extraInfo = extraInfo;
112 if (pos < msgQueue->queueSize-1) pos++;
113 else pos = 0;
114 msgQueue->nextFreeMessage = pos;
115 msgQueue->msgCount++;
116 msgQueue->status |= QS_POSTMESSAGE;
117 msgQueue->tempStatus |= QS_POSTMESSAGE;
118 return TRUE;
122 /***********************************************************************
123 * MSG_FindMsg
125 * Find a message matching the given parameters. Return -1 if none available.
127 static int MSG_FindMsg(MESSAGEQUEUE * msgQueue, HWND hwnd, int first, int last)
129 int i, pos = msgQueue->nextMessage;
131 if (!msgQueue->msgCount) return -1;
132 if (!hwnd && !first && !last) return pos;
134 for (i = 0; i < msgQueue->msgCount; i++)
136 MSG * msg = &msgQueue->messages[pos].msg;
138 if (!hwnd || (msg->hwnd == hwnd))
140 if (!first && !last) return pos;
141 if ((msg->message >= first) && (msg->message <= last)) return pos;
143 if (pos < msgQueue->queueSize-1) pos++;
144 else pos = 0;
146 return -1;
150 /***********************************************************************
151 * MSG_RemoveMsg
153 * Remove a message from the queue (pos must be a valid position).
155 static void MSG_RemoveMsg( MESSAGEQUEUE * msgQueue, int pos )
157 QMSG * qmsg;
159 if (!msgQueue) return;
160 qmsg = &msgQueue->messages[pos];
162 if (pos >= msgQueue->nextMessage)
164 int count = pos - msgQueue->nextMessage;
165 if (count) memmove( &msgQueue->messages[msgQueue->nextMessage+1],
166 &msgQueue->messages[msgQueue->nextMessage],
167 count * sizeof(QMSG) );
168 msgQueue->nextMessage++;
169 if (msgQueue->nextMessage >= msgQueue->queueSize)
170 msgQueue->nextMessage = 0;
172 else
174 int count = msgQueue->nextFreeMessage - pos;
175 if (count) memmove( &msgQueue->messages[pos],
176 &msgQueue->messages[pos+1], count * sizeof(QMSG) );
177 if (msgQueue->nextFreeMessage) msgQueue->nextFreeMessage--;
178 else msgQueue->nextFreeMessage = msgQueue->queueSize-1;
180 msgQueue->msgCount--;
181 if (!msgQueue->msgCount) msgQueue->status &= ~QS_POSTMESSAGE;
182 msgQueue->tempStatus = 0;
186 /***********************************************************************
187 * MSG_IncPaintCount
189 void MSG_IncPaintCount( HANDLE hQueue )
191 if (hQueue != hmemAppMsgQueue) return;
192 appMsgQueue->wPaintCount++;
193 appMsgQueue->status |= QS_PAINT;
194 appMsgQueue->tempStatus |= QS_PAINT;
198 /***********************************************************************
199 * MSG_DecPaintCount
201 void MSG_DecPaintCount( HANDLE hQueue )
203 if (hQueue != hmemAppMsgQueue) return;
204 appMsgQueue->wPaintCount--;
205 if (!appMsgQueue->wPaintCount) appMsgQueue->status &= ~QS_PAINT;
209 /***********************************************************************
210 * MSG_IncTimerCount
212 void MSG_IncTimerCount( HANDLE hQueue )
214 if (hQueue != hmemAppMsgQueue) return;
215 appMsgQueue->wTimerCount++;
216 appMsgQueue->status |= QS_TIMER;
217 appMsgQueue->tempStatus |= QS_TIMER;
221 /***********************************************************************
222 * MSG_DecTimerCount
224 void MSG_DecTimerCount( HANDLE hQueue )
226 if (hQueue != hmemAppMsgQueue) return;
227 appMsgQueue->wTimerCount--;
228 if (!appMsgQueue->wTimerCount) appMsgQueue->status &= ~QS_TIMER;
232 /***********************************************************************
233 * hardware_event
235 * Add an event to the system message queue.
237 void hardware_event( HWND hwnd, WORD message, WORD wParam, LONG lParam,
238 WORD xPos, WORD yPos, DWORD time, DWORD extraInfo )
240 MSG msg;
242 msg.hwnd = hwnd;
243 msg.message = message;
244 msg.wParam = wParam;
245 msg.lParam = lParam;
246 msg.time = time;
247 msg.pt.x = xPos;
248 msg.pt.y = yPos;
249 if (!MSG_AddMsg( sysMsgQueue, &msg, extraInfo ))
250 printf( "hardware_event: Queue is full\n" );
254 /***********************************************************************
255 * SetTaskQueue (KERNEL.34)
257 WORD SetTaskQueue( HANDLE hTask, HANDLE hQueue )
259 HANDLE prev = hmemAppMsgQueue;
260 hmemAppMsgQueue = hQueue;
261 return prev;
265 /***********************************************************************
266 * GetTaskQueue (KERNEL.35)
268 WORD GetTaskQueue( HANDLE hTask )
270 return hmemAppMsgQueue;
274 /***********************************************************************
275 * SetMessageQueue (USER.266)
277 BOOL SetMessageQueue( int size )
279 HANDLE hQueue;
281 if ((size > MAX_QUEUE_SIZE) || (size <= 0)) return TRUE;
283 /* Free the old message queue */
284 if ((hQueue = GetTaskQueue(0)) != 0)
286 GlobalUnlock( hQueue );
287 GlobalFree( hQueue );
290 if (!(hQueue = MSG_CreateMsgQueue( size ))) return FALSE;
291 SetTaskQueue( 0, hQueue );
292 appMsgQueue = (MESSAGEQUEUE *)GlobalLock( hQueue );
293 return TRUE;
297 /***********************************************************************
298 * PostQuitMessage (USER.6)
300 void PostQuitMessage( int exitCode )
302 if (!appMsgQueue) return;
303 appMsgQueue->wPostQMsg = TRUE;
304 appMsgQueue->wExitCode = exitCode;
308 /***********************************************************************
309 * GetQueueStatus (USER.334)
311 DWORD GetQueueStatus( int flags )
313 unsigned long ret = (appMsgQueue->status << 16) | appMsgQueue->tempStatus;
314 appMsgQueue->tempStatus = 0;
315 return ret & ((flags << 16) | flags);
319 /***********************************************************************
320 * GetInputState (USER.335)
322 BOOL GetInputState()
324 return appMsgQueue->status & (QS_KEY | QS_MOUSEBUTTON);
328 #ifndef USE_XLIB
329 static XtIntervalId xt_timer = 0;
331 /***********************************************************************
332 * MSG_TimerCallback
334 static void MSG_TimerCallback( XtPointer data, XtIntervalId * xtid )
336 DWORD nextExp;
337 TIMER_CheckTimer( &nextExp );
338 if (nextExp != (DWORD)-1)
339 xt_timer = XtAppAddTimeOut( XT_app_context, nextExp,
340 MSG_TimerCallback, NULL );
341 else xt_timer = 0;
343 #endif /* USE_XLIB */
346 /***********************************************************************
347 * MSG_PeekMessage
349 static BOOL MSG_PeekMessage( MESSAGEQUEUE * msgQueue, LPMSG msg, HWND hwnd,
350 WORD first, WORD last, WORD flags, BOOL peek )
352 int pos, mask;
353 DWORD nextExp; /* Next timer expiration time */
354 #ifdef USE_XLIB
355 XEvent event;
356 #endif
358 if (first || last)
360 mask = QS_POSTMESSAGE; /* Always selectioned */
361 if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
362 if ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) mask |= QS_MOUSE;
363 if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= WM_TIMER;
364 if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= WM_TIMER;
365 if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= WM_PAINT;
367 else mask = QS_MOUSE | QS_KEY | QS_POSTMESSAGE | QS_TIMER | QS_PAINT;
369 #ifdef USE_XLIB
370 while (XPending( XT_display ))
372 XNextEvent( XT_display, &event );
373 EVENT_ProcessEvent( &event );
375 #else
376 while (XtAppPending( XT_app_context ))
377 XtAppProcessEvent( XT_app_context, XtIMAll );
378 #endif
380 while(1)
382 /* First handle a WM_QUIT message */
383 if (msgQueue->wPostQMsg)
385 msg->hwnd = hwnd;
386 msg->message = WM_QUIT;
387 msg->wParam = msgQueue->wExitCode;
388 msg->lParam = 0;
389 break;
392 /* Then handle a message put by SendMessage() */
393 if (msgQueue->status & QS_SENDMESSAGE)
395 if (!hwnd || (msgQueue->hWnd == hwnd))
397 if ((!first && !last) ||
398 ((msgQueue->msg >= first) && (msgQueue->msg <= last)))
400 msg->hwnd = msgQueue->hWnd;
401 msg->message = msgQueue->msg;
402 msg->wParam = msgQueue->wParam;
403 msg->lParam = msgQueue->lParam;
404 if (flags & PM_REMOVE) msgQueue->status &= ~QS_SENDMESSAGE;
405 break;
410 /* Now find a normal message */
411 pos = MSG_FindMsg( msgQueue, hwnd, first, last );
412 if (pos != -1)
414 QMSG *qmsg = &msgQueue->messages[pos];
415 *msg = qmsg->msg;
416 msgQueue->GetMessageTimeVal = msg->time;
417 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
418 msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
420 if (flags & PM_REMOVE) MSG_RemoveMsg( msgQueue, pos );
421 break;
424 /* Now find a hardware event */
425 pos = MSG_FindMsg( sysMsgQueue, hwnd, first, last );
426 if (pos != -1)
428 QMSG *qmsg = &sysMsgQueue->messages[pos];
429 *msg = qmsg->msg;
430 msgQueue->GetMessageTimeVal = msg->time;
431 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
432 msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
434 if (flags & PM_REMOVE) MSG_RemoveMsg( sysMsgQueue, pos );
435 break;
438 /* Now find a WM_PAINT message */
439 if ((msgQueue->status & QS_PAINT) && (mask & QS_PAINT))
441 msg->hwnd = WIN_FindWinToRepaint( hwnd );
442 msg->message = WM_PAINT;
443 msg->wParam = 0;
444 msg->lParam = 0;
445 if (msg->hwnd != 0) break;
448 /* Finally handle WM_TIMER messages */
449 if ((msgQueue->status & QS_TIMER) && (mask & QS_TIMER))
451 BOOL posted = TIMER_CheckTimer( &nextExp );
452 #ifndef USE_XLIB
453 if (xt_timer) XtRemoveTimeOut( xt_timer );
454 if (nextExp != (DWORD)-1)
455 xt_timer = XtAppAddTimeOut( XT_app_context, nextExp,
456 MSG_TimerCallback, NULL );
457 else xt_timer = 0;
458 #endif
459 if (posted) continue; /* Restart the whole thing */
462 /* Wait until something happens */
463 if (peek) return FALSE;
464 #ifdef USE_XLIB
465 if (!XPending( XT_display ) && (nextExp != -1))
467 fd_set read_set;
468 struct timeval timeout;
469 int fd = ConnectionNumber(XT_display);
470 FD_ZERO( &read_set );
471 FD_SET( fd, &read_set );
472 timeout.tv_sec = nextExp / 1000;
473 timeout.tv_usec = (nextExp % 1000) * 1000;
474 if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1)
475 continue; /* On timeout or error, restart from the start */
477 XNextEvent( XT_display, &event );
478 EVENT_ProcessEvent( &event );
479 #else
480 XtAppProcessEvent( XT_app_context, XtIMAll );
481 #endif
484 /* We got a message */
485 if (peek) return TRUE;
486 else return (msg->message != WM_QUIT);
490 /***********************************************************************
491 * PeekMessage (USER.109)
493 BOOL PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last, WORD flags )
495 return MSG_PeekMessage( appMsgQueue, msg, hwnd, first, last, flags, TRUE );
499 /***********************************************************************
500 * GetMessage (USER.108)
502 BOOL GetMessage( LPMSG msg, HWND hwnd, WORD first, WORD last )
504 return MSG_PeekMessage( appMsgQueue, msg, hwnd, first, last, PM_REMOVE, FALSE );
508 /***********************************************************************
509 * PostMessage (USER.110)
511 BOOL PostMessage( HWND hwnd, WORD message, WORD wParam, LONG lParam )
513 MSG msg;
515 msg.hwnd = hwnd;
516 msg.message = message;
517 msg.wParam = wParam;
518 msg.lParam = lParam;
519 msg.time = GetTickCount();
520 msg.pt.x = 0;
521 msg.pt.y = 0;
523 return MSG_AddMsg( appMsgQueue, &msg, 0 );
527 /***********************************************************************
528 * SendMessage (USER.111)
530 LONG SendMessage( HWND hwnd, WORD msg, WORD wParam, LONG lParam )
532 WND * wndPtr = WIN_FindWndPtr( hwnd );
533 if (!wndPtr) return 0;
534 return CallWindowProc( wndPtr->lpfnWndProc, hwnd, msg, wParam, lParam );
538 /***********************************************************************
539 * TranslateMessage (USER.113)
541 BOOL TranslateMessage( LPMSG msg )
543 int message = msg->message;
545 if ((message == WM_KEYDOWN) || (message == WM_KEYUP) ||
546 (message == WM_SYSKEYDOWN) || (message == WM_SYSKEYUP))
548 #ifdef DEBUG_MSG
549 printf( "Translating key message\n" );
550 #endif
551 return TRUE;
553 return FALSE;
557 /***********************************************************************
558 * DispatchMessage (USER.114)
560 LONG DispatchMessage( LPMSG msg )
562 WND * wndPtr;
563 LONG retval;
564 int painting;
566 #ifdef DEBUG_MSG
567 printf( "Dispatch message hwnd=%08x msg=%d w=%d l=%d time=%u pt=%d,%d\n",
568 msg->hwnd, msg->message, msg->wParam, msg->lParam,
569 msg->time, msg->pt.x, msg->pt.y );
570 #endif
572 /* Process timer messages */
573 if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
575 if (msg->lParam)
576 return CallWindowProc( (FARPROC)msg->lParam, msg->hwnd,
577 msg->message, msg->wParam, GetTickCount() );
580 if (!msg->hwnd) return 0;
581 if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
582 if (!wndPtr->lpfnWndProc) return 0;
583 painting = (msg->message == WM_PAINT);
584 if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
585 retval = CallWindowProc( wndPtr->lpfnWndProc, msg->hwnd, msg->message,
586 msg->wParam, msg->lParam );
587 if (painting && (wndPtr->flags & WIN_NEEDS_BEGINPAINT))
589 #ifdef DEBUG_WIN
590 printf( "BeginPaint not called on WM_PAINT!\n" );
591 #endif
592 wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
594 return retval;
598 /***********************************************************************
599 * GetMessagePos (USER.119)
601 DWORD GetMessagePos(void)
603 return appMsgQueue->GetMessagePosVal;
607 /***********************************************************************
608 * GetMessageTime (USER.120)
610 LONG GetMessageTime(void)
612 return appMsgQueue->GetMessageTimeVal;
616 /***********************************************************************
617 * GetMessageExtraInfo (USER.288)
619 LONG GetMessageExtraInfo(void)
621 return appMsgQueue->GetMessageExtraInfoVal;
625 /***********************************************************************
626 * RegisterWindowMessage (USER.118)
628 WORD RegisterWindowMessage( LPCSTR str )
630 #ifdef DEBUG_MSG
631 printf( "RegisterWindowMessage: '%s'\n", str );
632 #endif
633 return GlobalAddAtom( str );