2 * Message queues related functions
4 * Copyright 1993, 1994 Alexandre Julliard
10 #include <sys/types.h>
16 #include "sysmetrics.h"
25 /* #define DEBUG_MSG */
28 #define HWND_BROADCAST16 ((HWND16)0xffff)
29 #define HWND_BROADCAST32 ((HWND32)0xffffffff)
31 extern BYTE
* KeyStateTable
; /* event.c */
32 extern WPARAM lastEventChar
; /* event.c */
34 extern BOOL
TIMER_CheckTimer( LONG
*next
, MSG
*msg
,
35 HWND hwnd
, BOOL remove
); /* timer.c */
37 DWORD MSG_WineStartTicks
; /* Ticks at Wine startup */
39 static WORD doubleClickSpeed
= 452;
41 /***********************************************************************
42 * MSG_TranslateMouseMsg
44 * Translate an mouse hardware event into a real mouse message.
45 * Return value indicates whether the translated message must be passed
48 * - Find the window for this message.
49 * - Translate button-down messages in double-clicks.
50 * - Send the WM_NCHITTEST message to find where the cursor is.
51 * - Activate the window if needed.
52 * - Translate the message into a non-client message, or translate
53 * the coordinates to client coordinates.
54 * - Send the WM_SETCURSOR message.
56 static BOOL
MSG_TranslateMouseMsg( MSG
*msg
, BOOL remove
)
61 static DWORD lastClickTime
= 0;
62 static WORD lastClickMsg
= 0;
63 static POINT16 lastClickPos
= { 0, 0 };
65 MOUSEHOOKSTRUCT hook
= { msg
->pt
, 0, HTCLIENT
, 0 };
67 BOOL mouseClick
= ((msg
->message
== WM_LBUTTONDOWN
) ||
68 (msg
->message
== WM_RBUTTONDOWN
) ||
69 (msg
->message
== WM_MBUTTONDOWN
));
75 msg
->hwnd
= GetCapture();
76 ScreenToClient16( msg
->hwnd
, &pt
);
77 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
78 /* No need to further process the message */
79 hook
.hwnd
= msg
->hwnd
;
80 return !HOOK_CallHooks( WH_MOUSE
, remove
? HC_ACTION
: HC_NOREMOVE
,
81 msg
->message
, (LPARAM
)MAKE_SEGPTR(&hook
));
84 hittest
= WINPOS_WindowFromPoint( msg
->pt
, &pWnd
);
85 msg
->hwnd
= pWnd
->hwndSelf
;
86 if ((hittest
!= HTERROR
) && mouseClick
)
88 HWND hwndTop
= WIN_GetTopParent( msg
->hwnd
);
90 /* Send the WM_PARENTNOTIFY message */
92 WIN_SendParentNotify( msg
->hwnd
, msg
->message
, 0,
93 MAKELONG( msg
->pt
.x
, msg
->pt
.y
) );
95 /* Activate the window if needed */
97 if (msg
->hwnd
!= GetActiveWindow() && msg
->hwnd
!= GetDesktopWindow())
99 LONG ret
= SendMessage16( msg
->hwnd
, WM_MOUSEACTIVATE
, hwndTop
,
100 MAKELONG( hittest
, msg
->message
) );
102 if ((ret
== MA_ACTIVATEANDEAT
) || (ret
== MA_NOACTIVATEANDEAT
))
105 if (((ret
== MA_ACTIVATE
) || (ret
== MA_ACTIVATEANDEAT
))
106 && hwndTop
!= GetActiveWindow() )
107 WINPOS_SetActiveWindow( hwndTop
, TRUE
, TRUE
);
111 /* Send the WM_SETCURSOR message */
113 SendMessage16( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
114 MAKELONG( hittest
, msg
->message
));
115 if (eatMsg
) return FALSE
;
117 /* Check for double-click */
121 BOOL dbl_click
= FALSE
;
123 if ((msg
->message
== lastClickMsg
) &&
124 (msg
->time
- lastClickTime
< doubleClickSpeed
) &&
125 (abs(msg
->pt
.x
- lastClickPos
.x
) < SYSMETRICS_CXDOUBLECLK
/2) &&
126 (abs(msg
->pt
.y
- lastClickPos
.y
) < SYSMETRICS_CYDOUBLECLK
/2))
129 if (dbl_click
&& (hittest
== HTCLIENT
))
131 /* Check whether window wants the double click message. */
132 dbl_click
= (pWnd
->class->style
& CS_DBLCLKS
) != 0;
135 if (dbl_click
) switch(msg
->message
)
137 case WM_LBUTTONDOWN
: msg
->message
= WM_LBUTTONDBLCLK
; break;
138 case WM_RBUTTONDOWN
: msg
->message
= WM_RBUTTONDBLCLK
; break;
139 case WM_MBUTTONDOWN
: msg
->message
= WM_MBUTTONDBLCLK
; break;
144 lastClickTime
= msg
->time
;
145 lastClickMsg
= msg
->message
;
146 lastClickPos
= msg
->pt
;
150 /* Build the translated message */
152 if (hittest
== HTCLIENT
)
153 ScreenToClient16( msg
->hwnd
, &pt
);
156 msg
->wParam
= hittest
;
157 msg
->message
+= WM_NCLBUTTONDOWN
- WM_LBUTTONDOWN
;
159 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
161 hook
.hwnd
= msg
->hwnd
;
162 hook
.wHitTestCode
= hittest
;
163 return !HOOK_CallHooks( WH_MOUSE
, remove
? HC_ACTION
: HC_NOREMOVE
,
164 msg
->message
, (LPARAM
)MAKE_SEGPTR(&hook
));
168 /***********************************************************************
169 * MSG_TranslateKeyboardMsg
171 * Translate an keyboard hardware event into a real message.
172 * Return value indicates whether the translated message must be passed
175 static BOOL
MSG_TranslateKeyboardMsg( MSG
*msg
, BOOL remove
)
177 /* Should check Ctrl-Esc and PrintScreen here */
179 msg
->hwnd
= GetFocus();
182 /* Send the message to the active window instead, */
183 /* translating messages to their WM_SYS equivalent */
185 msg
->hwnd
= GetActiveWindow();
187 if( msg
->message
< WM_SYSKEYDOWN
)
188 msg
->message
+= WM_SYSKEYDOWN
- WM_KEYDOWN
;
190 return !HOOK_CallHooks( WH_KEYBOARD
, remove
? HC_ACTION
: HC_NOREMOVE
,
191 msg
->wParam
, msg
->lParam
);
195 /***********************************************************************
196 * MSG_PeekHardwareMsg
198 * Peek for a hardware message matching the hwnd and message filters.
200 static BOOL
MSG_PeekHardwareMsg( MSG
*msg
, HWND hwnd
, WORD first
, WORD last
,
203 MESSAGEQUEUE
*sysMsgQueue
= QUEUE_GetSysQueue();
204 int i
, pos
= sysMsgQueue
->nextMessage
;
206 /* If the queue is empty, attempt to fill it */
207 if (!sysMsgQueue
->msgCount
&& XPending(display
)) MSG_WaitXEvent( 0 );
209 for (i
= 0; i
< sysMsgQueue
->msgCount
; i
++, pos
++)
211 if (pos
>= sysMsgQueue
->queueSize
) pos
= 0;
212 *msg
= sysMsgQueue
->messages
[pos
].msg
;
214 /* Translate message */
216 if ((msg
->message
>= WM_MOUSEFIRST
) && (msg
->message
<= WM_MOUSELAST
))
218 if (!MSG_TranslateMouseMsg( msg
, remove
)) continue;
220 else if ((msg
->message
>= WM_KEYFIRST
) && (msg
->message
<= WM_KEYLAST
))
222 if (!MSG_TranslateKeyboardMsg( msg
, remove
)) continue;
224 else /* Non-standard hardware event */
226 HARDWAREHOOKSTRUCT hook
= { msg
->hwnd
, msg
->message
,
227 msg
->wParam
, msg
->lParam
};
228 if (HOOK_CallHooks( WH_HARDWARE
, remove
? HC_ACTION
: HC_NOREMOVE
,
229 0, (LPARAM
)MAKE_SEGPTR(&hook
) )) continue;
232 /* Check message against filters */
234 if (hwnd
&& (msg
->hwnd
!= hwnd
)) continue;
235 if ((first
|| last
) &&
236 ((msg
->message
< first
) || (msg
->message
> last
))) continue;
237 if ((msg
->hwnd
!= GetDesktopWindow()) &&
238 (GetWindowTask(msg
->hwnd
) != GetCurrentTask()))
239 continue; /* Not for this task */
242 MSG tmpMsg
= *msg
; /* FIXME */
243 HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
,
244 0, (LPARAM
)MAKE_SEGPTR(&tmpMsg
) );
245 QUEUE_RemoveMsg( sysMsgQueue
, pos
);
253 /**********************************************************************
254 * SetDoubleClickTime (USER.20)
256 void SetDoubleClickTime( WORD interval
)
258 doubleClickSpeed
= interval
? interval
: 500;
262 /**********************************************************************
263 * GetDoubleClickTime (USER.21)
265 WORD
GetDoubleClickTime()
267 return doubleClickSpeed
;
271 /***********************************************************************
272 * MSG_GetHardwareMessage
274 * Like GetMessage(), but only return mouse and keyboard events.
275 * Used internally for window moving and resizing. Mouse messages
276 * are not translated.
277 * Warning: msg->hwnd is always 0.
279 BOOL
MSG_GetHardwareMessage( LPMSG msg
)
283 MESSAGEQUEUE
*sysMsgQueue
= QUEUE_GetSysQueue();
287 if ((pos
= QUEUE_FindMsg( sysMsgQueue
, 0, 0, 0 )) != -1)
289 *msg
= sysMsgQueue
->messages
[pos
].msg
;
290 QUEUE_RemoveMsg( sysMsgQueue
, pos
);
293 XNextEvent( display
, &event
);
294 EVENT_ProcessEvent( &event
);
300 /***********************************************************************
303 * Synchronize with the X server. Should not be used too often.
305 void MSG_Synchronize()
309 XSync( display
, False
);
310 while (XPending( display
))
312 XNextEvent( display
, &event
);
313 EVENT_ProcessEvent( &event
);
318 /***********************************************************************
321 * Wait for an X event, but at most maxWait milliseconds (-1 for no timeout).
322 * Return TRUE if an event is pending, FALSE on timeout or error
323 * (for instance lost connection with the server).
325 BOOL
MSG_WaitXEvent( LONG maxWait
)
328 struct timeval timeout
;
330 int fd
= ConnectionNumber(display
);
332 if (!XPending(display
) && (maxWait
!= -1))
334 FD_ZERO( &read_set
);
335 FD_SET( fd
, &read_set
);
337 timeout
.tv_usec
= (maxWait
% 1000) * 1000;
338 timeout
.tv_sec
= maxWait
/ 1000;
341 sigsetjmp(env_wait_x
, 1);
344 if (DDE_GetRemoteMessage()) {
345 while(DDE_GetRemoteMessage())
349 stop_wait_op
= STOP_WAIT_X
;
350 /* The code up to the next "stop_wait_op= CONT" must be reentrant */
351 if (select( fd
+1, &read_set
, NULL
, NULL
, &timeout
) != 1 &&
352 !XPending(display
)) {
358 #else /* CONFIG_IPC */
359 if (select( fd
+1, &read_set
, NULL
, NULL
, &timeout
) != 1)
360 return FALSE
; /* Timeout or error */
361 #endif /* CONFIG_IPC */
365 /* Process the event (and possibly others that occurred in the meantime) */
370 if (DDE_GetRemoteMessage())
372 while(DDE_GetRemoteMessage()) ;
375 #endif /* CONFIG_IPC */
377 XNextEvent( display
, &event
);
378 EVENT_ProcessEvent( &event
);
380 while (XPending( display
));
385 /***********************************************************************
388 static BOOL
MSG_PeekMessage( LPMSG msg
, HWND hwnd
, WORD first
, WORD last
,
389 WORD flags
, BOOL peek
)
392 MESSAGEQUEUE
*msgQueue
;
394 LONG nextExp
; /* Next timer expiration time */
397 DDE_TestDDE(hwnd
); /* do we have dde handling in the window ?*/
398 DDE_GetRemoteMessage();
399 #endif /* CONFIG_IPC */
403 mask
= QS_POSTMESSAGE
; /* Always selectioned */
404 if ((first
<= WM_KEYLAST
) && (last
>= WM_KEYFIRST
)) mask
|= QS_KEY
;
405 if ((first
<= WM_MOUSELAST
) && (last
>= WM_MOUSEFIRST
)) mask
|= QS_MOUSE
;
406 if ((first
<= WM_TIMER
) && (last
>= WM_TIMER
)) mask
|= QS_TIMER
;
407 if ((first
<= WM_SYSTIMER
) && (last
>= WM_SYSTIMER
)) mask
|= QS_TIMER
;
408 if ((first
<= WM_PAINT
) && (last
>= WM_PAINT
)) mask
|= QS_PAINT
;
410 else mask
= QS_MOUSE
| QS_KEY
| QS_POSTMESSAGE
| QS_TIMER
| QS_PAINT
;
414 hQueue
= GetTaskQueue(0);
415 msgQueue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
);
416 if (!msgQueue
) return FALSE
;
418 /* First handle a message put by SendMessage() */
419 if (msgQueue
->status
& QS_SENDMESSAGE
)
421 if (!hwnd
|| (msgQueue
->hWnd
== hwnd
))
423 if ((!first
&& !last
) ||
424 ((msgQueue
->msg
>= first
) && (msgQueue
->msg
<= last
)))
426 msg
->hwnd
= msgQueue
->hWnd
;
427 msg
->message
= msgQueue
->msg
;
428 msg
->wParam
= msgQueue
->wParam
;
429 msg
->lParam
= msgQueue
->lParam
;
430 if (flags
& PM_REMOVE
) msgQueue
->status
&= ~QS_SENDMESSAGE
;
436 /* Now find a normal message */
437 pos
= QUEUE_FindMsg( msgQueue
, hwnd
, first
, last
);
440 QMSG
*qmsg
= &msgQueue
->messages
[pos
];
442 msgQueue
->GetMessageTimeVal
= msg
->time
;
443 msgQueue
->GetMessagePosVal
= *(DWORD
*)&msg
->pt
;
444 msgQueue
->GetMessageExtraInfoVal
= qmsg
->extraInfo
;
446 if (flags
& PM_REMOVE
) QUEUE_RemoveMsg( msgQueue
, pos
);
450 /* Now find a hardware event */
451 if (MSG_PeekHardwareMsg( msg
, hwnd
, first
, last
, flags
& PM_REMOVE
))
454 msgQueue
->GetMessageTimeVal
= msg
->time
;
455 msgQueue
->GetMessagePosVal
= *(DWORD
*)&msg
->pt
;
456 msgQueue
->GetMessageExtraInfoVal
= 0; /* Always 0 for now */
460 /* Now handle a WM_QUIT message */
461 if (msgQueue
->wPostQMsg
)
464 msg
->message
= WM_QUIT
;
465 msg
->wParam
= msgQueue
->wExitCode
;
470 /* Now find a WM_PAINT message */
471 if ((msgQueue
->status
& QS_PAINT
) && (mask
& QS_PAINT
))
473 msg
->hwnd
= WIN_FindWinToRepaint( hwnd
, hQueue
);
474 msg
->message
= WM_PAINT
;
478 (!hwnd
|| msg
->hwnd
== hwnd
|| IsChild(hwnd
,msg
->hwnd
)) )
480 WND
* wndPtr
= WIN_FindWndPtr(msg
->hwnd
);
482 /* FIXME: WM_PAINTICON should be sent sometimes */
484 if( wndPtr
->flags
& WIN_INTERNAL_PAINT
&& !wndPtr
->hrgnUpdate
)
486 wndPtr
->flags
&= ~WIN_INTERNAL_PAINT
;
487 QUEUE_DecPaintCount( hQueue
);
493 /* Finally handle WM_TIMER messages */
494 if ((msgQueue
->status
& QS_TIMER
) && (mask
& QS_TIMER
))
496 if (TIMER_CheckTimer( &nextExp
, msg
, hwnd
, flags
& PM_REMOVE
))
497 break; /* Got a timer msg */
499 else nextExp
= -1; /* No timeout needed */
503 /* Wait until something happens */
506 if (!MSG_WaitXEvent( 0 )) return FALSE
; /* No pending event */
508 else /* Wait for an event, then restart the loop */
509 MSG_WaitXEvent( nextExp
);
512 /* We got a message */
513 if (peek
) return TRUE
;
514 else return (msg
->message
!= WM_QUIT
);
518 /***********************************************************************
519 * MSG_InternalGetMessage
521 * GetMessage() function for internal use. Behave like GetMessage(),
522 * but also call message filters and optionally send WM_ENTERIDLE messages.
523 * 'hwnd' must be the handle of the dialog or menu window.
524 * 'code' is the message filter value (MSGF_??? codes).
526 BOOL
MSG_InternalGetMessage( SEGPTR msg
, HWND hwnd
, HWND hwndOwner
, short code
,
527 WORD flags
, BOOL sendIdle
)
533 if (!MSG_PeekMessage( (MSG
*)PTR_SEG_TO_LIN(msg
),
534 0, 0, 0, flags
, TRUE
))
536 /* No message present -> send ENTERIDLE and wait */
537 SendMessage16( hwndOwner
, WM_ENTERIDLE
, code
, (LPARAM
)hwnd
);
538 MSG_PeekMessage( (MSG
*)PTR_SEG_TO_LIN(msg
),
539 0, 0, 0, flags
, FALSE
);
542 else /* Always wait for a message */
543 MSG_PeekMessage( (MSG
*)PTR_SEG_TO_LIN(msg
),
544 0, 0, 0, flags
, FALSE
);
546 if (!CallMsgFilter( msg
, code
))
547 return (((MSG
*)PTR_SEG_TO_LIN(msg
))->message
!= WM_QUIT
);
549 /* Message filtered -> remove it from the queue */
550 /* if it's still there. */
551 if (!(flags
& PM_REMOVE
))
552 MSG_PeekMessage( (MSG
*)PTR_SEG_TO_LIN(msg
),
553 0, 0, 0, PM_REMOVE
, TRUE
);
558 /***********************************************************************
559 * PeekMessage (USER.109)
561 BOOL
PeekMessage( LPMSG msg
, HWND hwnd
, WORD first
, WORD last
, WORD flags
)
563 return MSG_PeekMessage( msg
, hwnd
, first
, last
, flags
, TRUE
);
567 /***********************************************************************
568 * GetMessage (USER.108)
570 BOOL
GetMessage( SEGPTR msg
, HWND hwnd
, UINT first
, UINT last
)
572 MSG
* lpmsg
= (MSG
*)PTR_SEG_TO_LIN(msg
);
573 MSG_PeekMessage( lpmsg
,
574 hwnd
, first
, last
, PM_REMOVE
, FALSE
);
576 dprintf_msg(stddeb
,"message %04x, hwnd %04x, filter(%04x - %04x)\n", lpmsg
->message
,
578 HOOK_CallHooks( WH_GETMESSAGE
, HC_ACTION
, 0, (LPARAM
)msg
);
579 return (lpmsg
->message
!= WM_QUIT
);
583 /***********************************************************************
584 * PostMessage (USER.110)
586 BOOL
PostMessage( HWND hwnd
, WORD message
, WORD wParam
, LONG lParam
)
592 msg
.message
= message
;
595 msg
.time
= GetTickCount();
600 if (DDE_PostMessage(&msg
))
602 #endif /* CONFIG_IPC */
604 if (hwnd
== HWND_BROADCAST16
)
606 dprintf_msg(stddeb
,"PostMessage // HWND_BROADCAST !\n");
607 for (wndPtr
= WIN_GetDesktop()->child
; wndPtr
; wndPtr
= wndPtr
->next
)
609 if (wndPtr
->dwStyle
& WS_POPUP
|| wndPtr
->dwStyle
& WS_CAPTION
)
611 dprintf_msg(stddeb
,"BROADCAST Message to hWnd=%04x m=%04X w=%04X l=%08lX !\n",
612 wndPtr
->hwndSelf
, message
, wParam
, lParam
);
613 PostMessage( wndPtr
->hwndSelf
, message
, wParam
, lParam
);
616 dprintf_msg(stddeb
,"PostMessage // End of HWND_BROADCAST !\n");
620 wndPtr
= WIN_FindWndPtr( hwnd
);
621 if (!wndPtr
|| !wndPtr
->hmemTaskQ
) return FALSE
;
623 return QUEUE_AddMsg( wndPtr
->hmemTaskQ
, &msg
, 0 );
626 /***********************************************************************
627 * PostAppMessage (USER.116)
629 BOOL
PostAppMessage( HTASK hTask
, WORD message
, WORD wParam
, LONG lParam
)
633 if (GetTaskQueue(hTask
) == 0) return FALSE
;
635 msg
.message
= message
;
638 msg
.time
= GetTickCount();
642 return QUEUE_AddMsg( GetTaskQueue(hTask
), &msg
, 0 );
646 /***********************************************************************
647 * SendMessage16 (USER.111)
649 LRESULT
SendMessage16( HWND16 hwnd
, UINT16 msg
, WPARAM16 wParam
, LPARAM lParam
)
659 } msgstruct
= { lParam
, wParam
, msg
, hwnd
};
662 MSG DDE_msg
= { hwnd
, msg
, wParam
, lParam
};
663 if (DDE_SendMessage(&DDE_msg
)) return TRUE
;
664 #endif /* CONFIG_IPC */
666 if (hwnd
== HWND_BROADCAST16
)
668 dprintf_msg(stddeb
,"SendMessage // HWND_BROADCAST !\n");
669 for (wndPtr
= WIN_GetDesktop()->child
; wndPtr
; wndPtr
= wndPtr
->next
)
671 if (wndPtr
->dwStyle
& WS_POPUP
|| wndPtr
->dwStyle
& WS_CAPTION
)
673 dprintf_msg(stddeb
,"BROADCAST Message to hWnd=%04x m=%04X w=%04lX l=%08lX !\n",
674 wndPtr
->hwndSelf
, msg
, (DWORD
)wParam
, lParam
);
675 SendMessage16( wndPtr
->hwndSelf
, msg
, wParam
, lParam
);
678 dprintf_msg(stddeb
,"SendMessage // End of HWND_BROADCAST !\n");
682 HOOK_CallHooks( WH_CALLWNDPROC
, HC_ACTION
, 1,
683 (LPARAM
)MAKE_SEGPTR(&msgstruct
) );
684 hwnd
= msgstruct
.hWnd
;
685 msg
= msgstruct
.wMsg
;
686 wParam
= msgstruct
.wParam
;
687 lParam
= msgstruct
.lParam
;
689 SPY_EnterMessage( SPY_SENDMESSAGE16
, hwnd
, msg
, wParam
, lParam
);
690 if (!(wndPtr
= WIN_FindWndPtr( hwnd
)))
692 SPY_ExitMessage( SPY_RESULT_INVALIDHWND16
, hwnd
, msg
, 0 );
695 ret
= CallWindowProc16( wndPtr
->lpfnWndProc
, hwnd
, msg
, wParam
, lParam
);
696 SPY_ExitMessage( SPY_RESULT_OK16
, hwnd
, msg
, ret
);
701 /***********************************************************************
702 * SendMessage32A (USER32.453)
704 LRESULT
SendMessage32A(HWND32 hwnd
, UINT32 msg
, WPARAM32 wParam
, LPARAM lParam
)
709 if (hwnd
== HWND_BROADCAST32
)
711 for (wndPtr
= WIN_GetDesktop()->child
; wndPtr
; wndPtr
= wndPtr
->next
)
713 /* FIXME: should use something like EnumWindows here */
714 if (wndPtr
->dwStyle
& WS_POPUP
|| wndPtr
->dwStyle
& WS_CAPTION
)
715 SendMessage32A( wndPtr
->hwndSelf
, msg
, wParam
, lParam
);
720 /* FIXME: call hooks */
722 SPY_EnterMessage( SPY_SENDMESSAGE32
, hwnd
, msg
, wParam
, lParam
);
723 if (!(wndPtr
= WIN_FindWndPtr( hwnd
)))
725 SPY_ExitMessage( SPY_RESULT_INVALIDHWND32
, hwnd
, msg
, 0 );
728 ret
= CallWindowProc32A( (WNDPROC32
)wndPtr
->lpfnWndProc
,
729 hwnd
, msg
, wParam
, lParam
);
730 SPY_ExitMessage( SPY_RESULT_OK32
, hwnd
, msg
, ret
);
735 /***********************************************************************
736 * SendMessage32W (USER32.458)
738 LRESULT
SendMessage32W(HWND32 hwnd
, UINT32 msg
, WPARAM32 wParam
, LPARAM lParam
)
743 if (hwnd
== HWND_BROADCAST32
)
745 for (wndPtr
= WIN_GetDesktop()->child
; wndPtr
; wndPtr
= wndPtr
->next
)
747 /* FIXME: should use something like EnumWindows here */
748 if (wndPtr
->dwStyle
& WS_POPUP
|| wndPtr
->dwStyle
& WS_CAPTION
)
749 SendMessage32W( wndPtr
->hwndSelf
, msg
, wParam
, lParam
);
754 /* FIXME: call hooks */
756 SPY_EnterMessage( SPY_SENDMESSAGE32
, hwnd
, msg
, wParam
, lParam
);
757 if (!(wndPtr
= WIN_FindWndPtr( hwnd
)))
759 SPY_ExitMessage( SPY_RESULT_INVALIDHWND32
, hwnd
, msg
, 0 );
762 ret
= CallWindowProc32W( (WNDPROC32
)wndPtr
->lpfnWndProc
,
763 hwnd
, msg
, wParam
, lParam
);
764 SPY_ExitMessage( SPY_RESULT_OK32
, hwnd
, msg
, ret
);
769 /***********************************************************************
770 * WaitMessage (USER.112)
772 void WaitMessage( void )
776 LONG nextExp
= -1; /* Next timer expiration time */
779 DDE_GetRemoteMessage();
780 #endif /* CONFIG_IPC */
782 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return;
783 if ((queue
->wPostQMsg
) ||
784 (queue
->status
& (QS_SENDMESSAGE
| QS_PAINT
)) ||
785 (queue
->msgCount
) || (QUEUE_GetSysQueue()->msgCount
) )
787 if ((queue
->status
& QS_TIMER
) &&
788 TIMER_CheckTimer( &nextExp
, &msg
, 0, FALSE
))
790 /* FIXME: (dde) must check DDE & X-events simultaneously */
791 MSG_WaitXEvent( nextExp
);
795 /***********************************************************************
796 * TranslateMessage (USER.113)
798 * This should call ToAscii but it is currently broken
801 #define ASCII_CHAR_HACK 0x0800
803 BOOL
TranslateMessage( LPMSG msg
)
805 UINT message
= msg
->message
;
806 /* BYTE wparam[2]; */
808 if ((message
== WM_KEYDOWN
) || (message
== WM_KEYUP
) ||
809 (message
== WM_SYSKEYDOWN
) || (message
== WM_SYSKEYUP
))
811 dprintf_msg(stddeb
, "Translating key %04x, scancode %04x\n", msg
->wParam
,
812 HIWORD(msg
->lParam
) );
814 if( HIWORD(msg
->lParam
) & ASCII_CHAR_HACK
)
816 /* if( ToAscii( msg->wParam, HIWORD(msg->lParam), (LPSTR)&KeyStateTable,
820 message
+= 2 - (message
& 0x0001);
822 PostMessage( msg
->hwnd
, message
, lastEventChar
, msg
->lParam
);
831 /***********************************************************************
832 * DispatchMessage (USER.114)
834 LONG
DispatchMessage( const MSG
* msg
)
840 /* Process timer messages */
841 if ((msg
->message
== WM_TIMER
) || (msg
->message
== WM_SYSTIMER
))
845 /* HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
846 return CallWindowProc16( (WNDPROC
)msg
->lParam
, msg
->hwnd
,
847 msg
->message
, msg
->wParam
, GetTickCount() );
851 if (!msg
->hwnd
) return 0;
852 if (!(wndPtr
= WIN_FindWndPtr( msg
->hwnd
))) return 0;
853 if (!wndPtr
->lpfnWndProc
) return 0;
854 painting
= (msg
->message
== WM_PAINT
);
855 if (painting
) wndPtr
->flags
|= WIN_NEEDS_BEGINPAINT
;
856 /* HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
858 SPY_EnterMessage( SPY_DISPATCHMESSAGE16
, msg
->hwnd
, msg
->message
,
859 msg
->wParam
, msg
->lParam
);
860 retval
= CallWindowProc16( wndPtr
->lpfnWndProc
, msg
->hwnd
, msg
->message
,
861 msg
->wParam
, msg
->lParam
);
862 SPY_ExitMessage( SPY_RESULT_OK16
, msg
->hwnd
, msg
->message
, retval
);
864 if (painting
&& (wndPtr
= WIN_FindWndPtr( msg
->hwnd
)) &&
865 (wndPtr
->flags
& WIN_NEEDS_BEGINPAINT
) && wndPtr
->hrgnUpdate
)
867 fprintf(stderr
, "BeginPaint not called on WM_PAINT for hwnd %04x!\n",
869 wndPtr
->flags
&= ~WIN_NEEDS_BEGINPAINT
;
870 /* Validate the update region to avoid infinite WM_PAINT loop */
871 ValidateRect32( msg
->hwnd
, NULL
);
877 /***********************************************************************
878 * RegisterWindowMessage16 (USER.118)
880 WORD
RegisterWindowMessage16( SEGPTR str
)
882 dprintf_msg(stddeb
, "RegisterWindowMessage16: %08lx\n", (DWORD
)str
);
883 return GlobalAddAtom16( str
);
887 /***********************************************************************
888 * RegisterWindowMessage32A (USER32.436)
890 WORD
RegisterWindowMessage32A( LPCSTR str
)
892 dprintf_msg(stddeb
, "RegisterWindowMessage32A: %s\n", str
);
893 return GlobalAddAtom32A( str
);
897 /***********************************************************************
898 * RegisterWindowMessage32W (USER32.437)
900 WORD
RegisterWindowMessage32W( LPCWSTR str
)
902 dprintf_msg(stddeb
, "RegisterWindowMessage32W: %p\n", str
);
903 return GlobalAddAtom32W( str
);
907 /***********************************************************************
908 * GetTickCount (USER.13) (KERNEL32.299)
910 DWORD
GetTickCount(void)
913 gettimeofday( &t
, NULL
);
914 return ((t
.tv_sec
* 1000) + (t
.tv_usec
/ 1000)) - MSG_WineStartTicks
;
918 /***********************************************************************
919 * GetCurrentTime (USER.15)
921 * (effectively identical to GetTickCount)
923 DWORD
GetCurrentTime(void)
925 return GetTickCount();
929 /***********************************************************************
930 * InSendMessage (USER.192
932 * According to the book, this should return true iff the current message
933 * was send from another application. In that case, the application should
934 * invoke ReplyMessage before calling message relevant API.
935 * Currently, Wine will always return FALSE, as there is no other app.