Release 960521
[wine/multimedia.git] / windows / message.c
blob7e1799ba42162d0a9e71ade49c41dce652805bc9
1 /*
2 * Message queues related functions
4 * Copyright 1993, 1994 Alexandre Julliard
5 */
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/time.h>
10 #include <sys/types.h>
11 #include <errno.h>
13 #include "message.h"
14 #include "win.h"
15 #include "gdi.h"
16 #include "sysmetrics.h"
17 #include "hook.h"
18 #include "event.h"
19 #include "spy.h"
20 #include "winpos.h"
21 #include "atom.h"
22 #include "dde.h"
23 #include "queue.h"
24 #include "stddebug.h"
25 /* #define DEBUG_MSG */
26 #include "debug.h"
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
46 * to the user.
47 * Actions performed:
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 )
58 WND *pWnd;
59 BOOL eatMsg = FALSE;
60 INT16 hittest;
61 static DWORD lastClickTime = 0;
62 static WORD lastClickMsg = 0;
63 static POINT16 lastClickPos = { 0, 0 };
64 POINT16 pt = msg->pt;
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));
71 /* Find the window */
73 if (GetCapture())
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))
103 eatMsg = TRUE;
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 */
119 if (mouseClick)
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))
127 dbl_click = TRUE;
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;
142 if (remove)
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 );
154 else
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
173 * to the user.
175 static BOOL MSG_TranslateKeyboardMsg( MSG *msg, BOOL remove )
177 /* Should check Ctrl-Esc and PrintScreen here */
179 msg->hwnd = GetFocus();
180 if (!msg->hwnd)
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,
201 BOOL remove )
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 */
240 if (remove)
242 MSG tmpMsg = *msg; /* FIXME */
243 HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION,
244 0, (LPARAM)MAKE_SEGPTR(&tmpMsg) );
245 QUEUE_RemoveMsg( sysMsgQueue, pos );
247 return TRUE;
249 return FALSE;
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 )
281 int pos;
282 XEvent event;
283 MESSAGEQUEUE *sysMsgQueue = QUEUE_GetSysQueue();
285 while(1)
287 if ((pos = QUEUE_FindMsg( sysMsgQueue, 0, 0, 0 )) != -1)
289 *msg = sysMsgQueue->messages[pos].msg;
290 QUEUE_RemoveMsg( sysMsgQueue, pos );
291 break;
293 XNextEvent( display, &event );
294 EVENT_ProcessEvent( &event );
296 return TRUE;
300 /***********************************************************************
301 * MSG_Synchronize
303 * Synchronize with the X server. Should not be used too often.
305 void MSG_Synchronize()
307 XEvent event;
309 XSync( display, False );
310 while (XPending( display ))
312 XNextEvent( display, &event );
313 EVENT_ProcessEvent( &event );
318 /***********************************************************************
319 * MSG_WaitXEvent
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 )
327 fd_set read_set;
328 struct timeval timeout;
329 XEvent event;
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;
340 #ifdef CONFIG_IPC
341 sigsetjmp(env_wait_x, 1);
342 stop_wait_op= CONT;
344 if (DDE_GetRemoteMessage()) {
345 while(DDE_GetRemoteMessage())
347 return TRUE;
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)) {
353 stop_wait_op= CONT;
354 return FALSE;
355 } else {
356 stop_wait_op= CONT;
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) */
369 #ifdef CONFIG_IPC
370 if (DDE_GetRemoteMessage())
372 while(DDE_GetRemoteMessage()) ;
373 return TRUE;
375 #endif /* CONFIG_IPC */
377 XNextEvent( display, &event );
378 EVENT_ProcessEvent( &event );
380 while (XPending( display ));
381 return TRUE;
385 /***********************************************************************
386 * MSG_PeekMessage
388 static BOOL MSG_PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last,
389 WORD flags, BOOL peek )
391 int pos, mask;
392 MESSAGEQUEUE *msgQueue;
393 HQUEUE hQueue;
394 LONG nextExp; /* Next timer expiration time */
396 #ifdef CONFIG_IPC
397 DDE_TestDDE(hwnd); /* do we have dde handling in the window ?*/
398 DDE_GetRemoteMessage();
399 #endif /* CONFIG_IPC */
401 if (first || last)
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;
412 while(1)
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;
431 break;
436 /* Now find a normal message */
437 pos = QUEUE_FindMsg( msgQueue, hwnd, first, last );
438 if (pos != -1)
440 QMSG *qmsg = &msgQueue->messages[pos];
441 *msg = qmsg->msg;
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 );
447 break;
450 /* Now find a hardware event */
451 if (MSG_PeekHardwareMsg( msg, hwnd, first, last, flags & PM_REMOVE ))
453 /* Got one */
454 msgQueue->GetMessageTimeVal = msg->time;
455 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
456 msgQueue->GetMessageExtraInfoVal = 0; /* Always 0 for now */
457 break;
460 /* Now handle a WM_QUIT message */
461 if (msgQueue->wPostQMsg)
463 msg->hwnd = hwnd;
464 msg->message = WM_QUIT;
465 msg->wParam = msgQueue->wExitCode;
466 msg->lParam = 0;
467 break;
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;
475 msg->wParam = 0;
476 msg->lParam = 0;
477 if( msg->hwnd &&
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 );
489 break;
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 */
501 Yield();
503 /* Wait until something happens */
504 if (peek)
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 )
529 for (;;)
531 if (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,
577 hwnd, first, last );
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 )
588 MSG msg;
589 WND *wndPtr;
591 msg.hwnd = hwnd;
592 msg.message = message;
593 msg.wParam = wParam;
594 msg.lParam = lParam;
595 msg.time = GetTickCount();
596 msg.pt.x = 0;
597 msg.pt.y = 0;
599 #ifdef CONFIG_IPC
600 if (DDE_PostMessage(&msg))
601 return TRUE;
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");
617 return TRUE;
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 )
631 MSG msg;
633 if (GetTaskQueue(hTask) == 0) return FALSE;
634 msg.hwnd = 0;
635 msg.message = message;
636 msg.wParam = wParam;
637 msg.lParam = lParam;
638 msg.time = GetTickCount();
639 msg.pt.x = 0;
640 msg.pt.y = 0;
642 return QUEUE_AddMsg( GetTaskQueue(hTask), &msg, 0 );
646 /***********************************************************************
647 * SendMessage16 (USER.111)
649 LRESULT SendMessage16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam)
651 WND * wndPtr;
652 LRESULT ret;
653 struct
655 LPARAM lParam;
656 WPARAM16 wParam;
657 UINT16 wMsg;
658 HWND16 hWnd;
659 } msgstruct = { lParam, wParam, msg, hwnd };
661 #ifdef CONFIG_IPC
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");
679 return TRUE;
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 );
693 return 0;
695 ret = CallWindowProc16( wndPtr->lpfnWndProc, hwnd, msg, wParam, lParam );
696 SPY_ExitMessage( SPY_RESULT_OK16, hwnd, msg, ret );
697 return ret;
701 /***********************************************************************
702 * SendMessage32A (USER32.453)
704 LRESULT SendMessage32A(HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
706 WND * wndPtr;
707 LRESULT ret;
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 );
717 return TRUE;
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 );
726 return 0;
728 ret = CallWindowProc32A( (WNDPROC32)wndPtr->lpfnWndProc,
729 hwnd, msg, wParam, lParam );
730 SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
731 return ret;
735 /***********************************************************************
736 * SendMessage32W (USER32.458)
738 LRESULT SendMessage32W(HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
740 WND * wndPtr;
741 LRESULT ret;
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 );
751 return TRUE;
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 );
760 return 0;
762 ret = CallWindowProc32W( (WNDPROC32)wndPtr->lpfnWndProc,
763 hwnd, msg, wParam, lParam );
764 SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
765 return ret;
769 /***********************************************************************
770 * WaitMessage (USER.112)
772 void WaitMessage( void )
774 MSG msg;
775 MESSAGEQUEUE *queue;
776 LONG nextExp = -1; /* Next timer expiration time */
778 #ifdef CONFIG_IPC
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) )
786 return;
787 if ((queue->status & QS_TIMER) &&
788 TIMER_CheckTimer( &nextExp, &msg, 0, FALSE))
789 return;
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,
817 wparam, 0 ) )
820 message += 2 - (message & 0x0001);
822 PostMessage( msg->hwnd, message, lastEventChar, msg->lParam );
824 return TRUE;
827 return FALSE;
831 /***********************************************************************
832 * DispatchMessage (USER.114)
834 LONG DispatchMessage( const MSG* msg )
836 WND * wndPtr;
837 LONG retval;
838 int painting;
840 /* Process timer messages */
841 if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
843 if (msg->lParam)
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",
868 msg->hwnd);
869 wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
870 /* Validate the update region to avoid infinite WM_PAINT loop */
871 ValidateRect32( msg->hwnd, NULL );
873 return retval;
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)
912 struct timeval t;
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.
937 BOOL InSendMessage()
939 return FALSE;