2 * Message queues related functions
4 * Copyright 1993 Alexandre Julliard
8 * This code assumes that there is only one Windows task (hence
12 static char Copyright
[] = "Copyright Alexandre Julliard, 1993";
16 #include <sys/types.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 /***********************************************************************
41 * Create a message queue.
43 static HANDLE
MSG_CreateMsgQueue( int size
)
46 MESSAGEQUEUE
* msgQueue
;
49 queueSize
= sizeof(MESSAGEQUEUE
) + size
* sizeof(QMSG
);
50 if (!(hQueue
= GlobalAlloc( GMEM_FIXED
, queueSize
))) return 0;
51 msgQueue
= (MESSAGEQUEUE
*) GlobalLock( hQueue
);
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;
66 msgQueue
->wPostQMsg
= 0;
67 msgQueue
->wExitCode
= 0;
68 msgQueue
->InSendMessageHandle
= 0;
69 msgQueue
->wPaintCount
= 0;
70 msgQueue
->wTimerCount
= 0;
71 msgQueue
->tempStatus
= 0;
73 GlobalUnlock( 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
);
93 /***********************************************************************
96 * Add a message to the queue. Return FALSE if queue is full.
98 static int MSG_AddMsg( MESSAGEQUEUE
* msgQueue
, MSG
* msg
, DWORD extraInfo
)
102 if (!msgQueue
) return FALSE
;
103 pos
= msgQueue
->nextFreeMessage
;
105 /* Check if queue is full */
106 if ((pos
== msgQueue
->nextMessage
) && (msgQueue
->msgCount
> 0))
110 msgQueue
->messages
[pos
].msg
= *msg
;
111 msgQueue
->messages
[pos
].extraInfo
= extraInfo
;
112 if (pos
< msgQueue
->queueSize
-1) pos
++;
114 msgQueue
->nextFreeMessage
= pos
;
115 msgQueue
->msgCount
++;
116 msgQueue
->status
|= QS_POSTMESSAGE
;
117 msgQueue
->tempStatus
|= QS_POSTMESSAGE
;
122 /***********************************************************************
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
++;
150 /***********************************************************************
153 * Remove a message from the queue (pos must be a valid position).
155 static void MSG_RemoveMsg( MESSAGEQUEUE
* msgQueue
, int pos
)
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;
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 /***********************************************************************
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 /***********************************************************************
201 void MSG_DecPaintCount( HANDLE hQueue
)
203 if (hQueue
!= hmemAppMsgQueue
) return;
204 appMsgQueue
->wPaintCount
--;
205 if (!appMsgQueue
->wPaintCount
) appMsgQueue
->status
&= ~QS_PAINT
;
209 /***********************************************************************
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 /***********************************************************************
224 void MSG_DecTimerCount( HANDLE hQueue
)
226 if (hQueue
!= hmemAppMsgQueue
) return;
227 appMsgQueue
->wTimerCount
--;
228 if (!appMsgQueue
->wTimerCount
) appMsgQueue
->status
&= ~QS_TIMER
;
232 /***********************************************************************
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
)
243 msg
.message
= message
;
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
;
265 /***********************************************************************
266 * GetTaskQueue (KERNEL.35)
268 WORD
GetTaskQueue( HANDLE hTask
)
270 return hmemAppMsgQueue
;
274 /***********************************************************************
275 * SetMessageQueue (USER.266)
277 BOOL
SetMessageQueue( int size
)
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
);
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)
324 return appMsgQueue
->status
& (QS_KEY
| QS_MOUSEBUTTON
);
329 static XtIntervalId xt_timer
= 0;
331 /***********************************************************************
334 static void MSG_TimerCallback( XtPointer data
, XtIntervalId
* xtid
)
337 TIMER_CheckTimer( &nextExp
);
338 if (nextExp
!= (DWORD
)-1)
339 xt_timer
= XtAppAddTimeOut( XT_app_context
, nextExp
,
340 MSG_TimerCallback
, NULL
);
343 #endif /* USE_XLIB */
346 /***********************************************************************
349 static BOOL
MSG_PeekMessage( MESSAGEQUEUE
* msgQueue
, LPMSG msg
, HWND hwnd
,
350 WORD first
, WORD last
, WORD flags
, BOOL peek
)
353 DWORD nextExp
; /* Next timer expiration time */
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
;
370 while (XPending( XT_display
))
372 XNextEvent( XT_display
, &event
);
373 EVENT_ProcessEvent( &event
);
376 while (XtAppPending( XT_app_context
))
377 XtAppProcessEvent( XT_app_context
, XtIMAll
);
382 /* First handle a WM_QUIT message */
383 if (msgQueue
->wPostQMsg
)
386 msg
->message
= WM_QUIT
;
387 msg
->wParam
= msgQueue
->wExitCode
;
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
;
410 /* Now find a normal message */
411 pos
= MSG_FindMsg( msgQueue
, hwnd
, first
, last
);
414 QMSG
*qmsg
= &msgQueue
->messages
[pos
];
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
);
424 /* Now find a hardware event */
425 pos
= MSG_FindMsg( sysMsgQueue
, hwnd
, first
, last
);
428 QMSG
*qmsg
= &sysMsgQueue
->messages
[pos
];
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
);
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
;
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
);
453 if (xt_timer
) XtRemoveTimeOut( xt_timer
);
454 if (nextExp
!= (DWORD
)-1)
455 xt_timer
= XtAppAddTimeOut( XT_app_context
, nextExp
,
456 MSG_TimerCallback
, NULL
);
459 if (posted
) continue; /* Restart the whole thing */
462 /* Wait until something happens */
463 if (peek
) return FALSE
;
465 if (!XPending( XT_display
) && (nextExp
!= -1))
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
);
480 XtAppProcessEvent( XT_app_context
, XtIMAll
);
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
)
516 msg
.message
= message
;
519 msg
.time
= GetTickCount();
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
))
549 printf( "Translating key message\n" );
557 /***********************************************************************
558 * DispatchMessage (USER.114)
560 LONG
DispatchMessage( LPMSG 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
);
572 /* Process timer messages */
573 if ((msg
->message
== WM_TIMER
) || (msg
->message
== WM_SYSTIMER
))
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
))
590 printf( "BeginPaint not called on WM_PAINT!\n" );
592 wndPtr
->flags
&= ~WIN_NEEDS_BEGINPAINT
;
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
)
631 printf( "RegisterWindowMessage: '%s'\n", str
);
633 return GlobalAddAtom( str
);