mirror of
https://github.com/VincentWei/MiniGUI.git
synced 2026-02-08 20:03:04 +08:00
1372 lines
33 KiB
C
1372 lines
33 KiB
C
/*
|
|
** $Id: message.c 13674 2010-12-06 06:45:01Z wanzheng $
|
|
**
|
|
** message.c: The messaging module.
|
|
**
|
|
** Copyright (C) 2003 ~ 2008 Feynman Software.
|
|
** Copyright (C) 2000 ~ 2002 Wei Yongming.
|
|
**
|
|
** All right reserved by Feynman Software.
|
|
**
|
|
** Current maintainer: Wei Yongming.
|
|
**
|
|
** Create date: 2000/11/05
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "common.h"
|
|
#include "minigui.h"
|
|
#include "gdi.h"
|
|
#include "window.h"
|
|
|
|
#include "blockheap.h"
|
|
#include "cliprect.h"
|
|
#include "gal.h"
|
|
#include "internals.h"
|
|
#include "ctrlclass.h"
|
|
#include "timer.h"
|
|
|
|
#include "license.h"
|
|
#ifdef _MG_ENABLE_LICENSE
|
|
# include "../sysres/license/c_files/02_feiman.dat.c"
|
|
#endif
|
|
|
|
/******************************************************************************/
|
|
|
|
#ifdef _MGRM_THREADS
|
|
|
|
#define SET_PADD(value) pMsg->pAdd = value
|
|
#define SYNMSGNAME pMsg->pAdd?"Sync":"Normal"
|
|
|
|
#else
|
|
|
|
#define SET_PADD(value)
|
|
#define SYNMSGNAME "Normal"
|
|
|
|
#endif
|
|
|
|
#ifdef _MGRM_THREADS
|
|
/* XXX: Need desktop thread keep alive to wakeup sem_wait() by delivering messages */
|
|
# define TEST_NEED_TO_QUIT(queue) ((__mg_quiting_stage <= _MG_QUITING_STAGE_FORCE) && ((queue)!=__mg_dsk_msg_queue))
|
|
#else
|
|
# define TEST_NEED_TO_QUIT(queue) (__mg_quiting_stage <= _MG_QUITING_STAGE_FORCE)
|
|
#endif
|
|
#define TEST_IF_QUIT(queue, hWnd) do { \
|
|
if (TEST_NEED_TO_QUIT(queue)) { \
|
|
/* printf("force to quit, queue=%p\n", queue); */ \
|
|
LOCK_MSGQ (queue); \
|
|
if (!(queue->dwState & QS_QUIT)){ \
|
|
queue->loop_depth ++; \
|
|
queue->dwState |= QS_QUIT; \
|
|
UNLOCK_MSGQ (queue); \
|
|
if (IsDialog(hWnd)) { \
|
|
EndDialog (hWnd, IDCANCEL); \
|
|
} else { \
|
|
DestroyMainWindow (hWnd); \
|
|
} \
|
|
} else { \
|
|
UNLOCK_MSGQ (queue); \
|
|
} \
|
|
} \
|
|
} while (0)
|
|
|
|
#define ERR_MSG_CANCELED ERR_QUEUE_FULL
|
|
|
|
/****************************** Message Allocation ****************************/
|
|
static BLOCKHEAP QMSGHeap;
|
|
|
|
/* QMSG allocation */
|
|
BOOL mg_InitFreeQMSGList (void)
|
|
{
|
|
InitBlockDataHeap (&QMSGHeap, sizeof (QMSG), SIZE_QMSG_HEAP);
|
|
return TRUE;
|
|
}
|
|
|
|
void mg_DestroyFreeQMSGList (void)
|
|
{
|
|
DestroyBlockDataHeap (&QMSGHeap);
|
|
}
|
|
|
|
inline static PQMSG QMSGAlloc (void)
|
|
{
|
|
return (PQMSG) BlockDataAlloc (&QMSGHeap);
|
|
}
|
|
|
|
inline static void FreeQMSG (PQMSG pqmsg)
|
|
{
|
|
BlockDataFree (&QMSGHeap, pqmsg);
|
|
}
|
|
|
|
/****************************** Message Queue Management ************************/
|
|
|
|
BOOL mg_InitMsgQueue (PMSGQUEUE pMsgQueue, int iBufferLen)
|
|
{
|
|
memset (pMsgQueue, 0, sizeof(MSGQUEUE));
|
|
|
|
pMsgQueue->dwState = QS_EMPTY;
|
|
|
|
#ifdef _MGRM_THREADS
|
|
pthread_mutex_init (&pMsgQueue->lock, NULL);
|
|
sem_init (&pMsgQueue->wait, 0, 0);
|
|
sem_init (&pMsgQueue->sync_msg, 0, 0);
|
|
#endif
|
|
|
|
if (iBufferLen <= 0)
|
|
iBufferLen = DEF_MSGQUEUE_LEN;
|
|
|
|
pMsgQueue->msg = malloc (sizeof (MSG) * iBufferLen);
|
|
|
|
if (!pMsgQueue->msg) {
|
|
#ifdef _MGRM_THREADS
|
|
pthread_mutex_destroy (&pMsgQueue->lock);
|
|
sem_destroy (&pMsgQueue->wait);
|
|
sem_destroy (&pMsgQueue->sync_msg);
|
|
return FALSE;
|
|
#endif
|
|
}
|
|
|
|
pMsgQueue->len = iBufferLen;
|
|
|
|
pMsgQueue->FirstTimerSlot = 0;
|
|
pMsgQueue->TimerMask = 0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void mg_DestroyMsgQueue (PMSGQUEUE pMsgQueue)
|
|
{
|
|
PQMSG head;
|
|
PQMSG next;
|
|
|
|
head = next = pMsgQueue->pFirstNotifyMsg;
|
|
while (head) {
|
|
next = head->next;
|
|
|
|
FreeQMSG (head);
|
|
head = next;
|
|
}
|
|
|
|
#ifdef _MGRM_THREADS
|
|
pthread_mutex_destroy (&pMsgQueue->lock);
|
|
sem_destroy (&pMsgQueue->wait);
|
|
sem_destroy (&pMsgQueue->sync_msg);
|
|
#endif
|
|
|
|
mg_remove_timers_by_msg_queue (pMsgQueue);
|
|
|
|
if (pMsgQueue->msg)
|
|
free (pMsgQueue->msg);
|
|
pMsgQueue->msg = NULL;
|
|
}
|
|
|
|
/*
|
|
* hWnd may belong to a different thread,
|
|
* so this function should be thread-safe
|
|
*/
|
|
PMSGQUEUE kernel_GetMsgQueue (HWND hWnd)
|
|
{
|
|
PMAINWIN pWin;
|
|
|
|
pWin = getMainWindowPtr(hWnd);
|
|
|
|
if (pWin)
|
|
return pWin->pMessages;
|
|
return NULL;
|
|
}
|
|
|
|
/* post a message to a message queue */
|
|
BOOL kernel_QueueMessage (PMSGQUEUE msg_que, PMSG msg)
|
|
{
|
|
if (msg_que == NULL || msg == NULL)
|
|
return FALSE;
|
|
|
|
LOCK_MSGQ(msg_que);
|
|
|
|
msg->time = __mg_timer_counter;
|
|
|
|
/* check for the duplicated messages */
|
|
if (msg->message == MSG_MOUSEMOVE
|
|
|| msg->message == MSG_NCMOUSEMOVE
|
|
|| msg->message == MSG_DT_MOUSEMOVE) {
|
|
int readpos = msg_que->readpos;
|
|
PMSG a_msg, last_msg = NULL;
|
|
|
|
while (readpos != msg_que->writepos) {
|
|
a_msg = msg_que->msg + readpos;
|
|
|
|
if (a_msg->message == msg->message
|
|
&& a_msg->wParam == msg->wParam
|
|
&& a_msg->hwnd == msg->hwnd) {
|
|
last_msg = a_msg;
|
|
}
|
|
|
|
readpos ++;
|
|
readpos %= msg_que->len;
|
|
}
|
|
|
|
if (last_msg) {
|
|
last_msg->lParam = msg->lParam;
|
|
last_msg->time = msg->time;
|
|
goto ret;
|
|
}
|
|
}
|
|
else if (msg->message == MSG_TIMEOUT
|
|
|| msg->message == MSG_IDLE
|
|
|| msg->message == MSG_CARETBLINK) {
|
|
int readpos = msg_que->readpos;
|
|
PMSG a_msg;
|
|
|
|
while (readpos != msg_que->writepos) {
|
|
a_msg = msg_que->msg + readpos;
|
|
|
|
if (a_msg->message == msg->message
|
|
&& a_msg->hwnd == msg->hwnd) {
|
|
a_msg->wParam = msg->wParam;
|
|
a_msg->lParam = msg->lParam;
|
|
a_msg->time = msg->time;
|
|
goto ret;
|
|
}
|
|
|
|
readpos ++;
|
|
readpos %= msg_que->len;
|
|
}
|
|
}
|
|
|
|
if ((msg_que->writepos + 1) % msg_que->len == msg_que->readpos) {
|
|
UNLOCK_MSGQ(msg_que);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Write the data and advance write pointer */
|
|
msg_que->msg [msg_que->writepos] = *msg;
|
|
msg_que->writepos++;
|
|
#if 0
|
|
if (msg_que->writepos >= msg_que->len) msg_que->writepos = 0;
|
|
#else
|
|
msg_que->writepos %= msg_que->len;
|
|
#endif
|
|
|
|
ret:
|
|
msg_que->dwState |= QS_POSTMSG;
|
|
|
|
UNLOCK_MSGQ (msg_que);
|
|
|
|
#ifdef _MGRM_THREADS
|
|
if (!BE_THIS_THREAD (msg->hwnd))
|
|
POST_MSGQ (msg_que);
|
|
#endif
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
|
|
static inline WNDPROC GetWndProc (HWND hWnd)
|
|
{
|
|
return ((PMAINWIN)hWnd)->MainWindowProc;
|
|
}
|
|
|
|
HWND kernel_CheckInvalidRegion (PMAINWIN pWin)
|
|
{
|
|
PCONTROL pCtrl = (PCONTROL)pWin;
|
|
HWND hwnd;
|
|
|
|
if (pCtrl->InvRgn.rgn.head)
|
|
return (HWND)pCtrl;
|
|
|
|
pCtrl = pCtrl->children;
|
|
while (pCtrl) {
|
|
|
|
if ((hwnd = kernel_CheckInvalidRegion ((PMAINWIN) pCtrl)))
|
|
return hwnd;
|
|
|
|
pCtrl = pCtrl->next;
|
|
}
|
|
|
|
return HWND_NULL;
|
|
}
|
|
|
|
#if 0
|
|
static PMAINWIN msgGetHostingRoot (PMAINWIN pHosted)
|
|
{
|
|
PMAINWIN pHosting;
|
|
|
|
pHosting = pHosted->pHosting;
|
|
if (pHosting)
|
|
return msgGetHostingRoot (pHosting);
|
|
|
|
return pHosted;
|
|
}
|
|
#endif
|
|
|
|
static HWND msgCheckHostedTree (PMAINWIN pHosting)
|
|
{
|
|
HWND hNeedPaint;
|
|
PMAINWIN pHosted;
|
|
|
|
if ((hNeedPaint = kernel_CheckInvalidRegion (pHosting)))
|
|
return hNeedPaint;
|
|
|
|
pHosted = pHosting->pFirstHosted;
|
|
while (pHosted) {
|
|
if ((hNeedPaint = msgCheckHostedTree (pHosted)))
|
|
return hNeedPaint;
|
|
|
|
pHosted = pHosted->pNextHosted;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
BOOL GUIAPI HavePendingMessageEx (HWND hWnd, BOOL bNoDeskTimer)
|
|
{
|
|
PMSGQUEUE pMsgQueue;
|
|
|
|
if (hWnd == 0) {
|
|
#ifdef _MGRM_THREADS
|
|
if (!(pMsgQueue = GetMsgQueueThisThread ()))
|
|
return FALSE;
|
|
#else
|
|
pMsgQueue = __mg_dsk_msg_queue;
|
|
#endif
|
|
}
|
|
else {
|
|
if (!(pMsgQueue = kernel_GetMsgQueue(hWnd)))
|
|
return FALSE;
|
|
}
|
|
|
|
TEST_IF_QUIT(pMsgQueue, hWnd);
|
|
|
|
LOCK_MSGQ (pMsgQueue);
|
|
|
|
#ifdef _MGRM_THREADS
|
|
if (pMsgQueue->dwState & QS_SYNCMSG) {
|
|
if (pMsgQueue->pFirstSyncMsg) goto retok;
|
|
}
|
|
#endif
|
|
|
|
if (pMsgQueue->dwState & QS_NOTIFYMSG) {
|
|
if (pMsgQueue->pFirstNotifyMsg) goto retok;
|
|
}
|
|
|
|
if (pMsgQueue->dwState & QS_POSTMSG) {
|
|
if (pMsgQueue->readpos != pMsgQueue->writepos) goto retok;
|
|
}
|
|
|
|
if (pMsgQueue->dwState & (QS_QUIT | QS_PAINT)) {
|
|
goto retok;
|
|
}
|
|
|
|
if (pMsgQueue->TimerMask)
|
|
goto retok;
|
|
#ifndef _MGRM_THREADS
|
|
/*
|
|
* FIXME
|
|
* We do not need to check QS_DESKTIMER, because it is for the
|
|
* desktop window, and user don't care it.
|
|
*/
|
|
if (!bNoDeskTimer && (pMsgQueue->dwState & QS_DESKTIMER)) {
|
|
goto retok;
|
|
}
|
|
#endif
|
|
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
#ifndef _MGRM_THREADS
|
|
return pMsgQueue->OnIdle (NULL);
|
|
#else
|
|
return FALSE;
|
|
#endif
|
|
|
|
retok:
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL GUIAPI HavePendingMessage (HWND hWnd)
|
|
{
|
|
return HavePendingMessageEx (hWnd, FALSE);
|
|
}
|
|
|
|
int GUIAPI BroadcastMessage (UINT nMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
MSG msg;
|
|
|
|
msg.message = nMsg;
|
|
msg.wParam = wParam;
|
|
msg.lParam = lParam;
|
|
|
|
return SendMessage (HWND_DESKTOP, MSG_BROADCASTMSG, 0, (LPARAM)(&msg));
|
|
}
|
|
|
|
#ifdef _MGHAVE_MSG_STRING
|
|
#include "msgstr.h"
|
|
|
|
const char* GUIAPI Message2Str (UINT message)
|
|
{
|
|
if (message >= 0x0000 && message <= 0x006F)
|
|
return __mg_msgstr1 [message];
|
|
else if (message >= 0x00A0 && message <= 0x010F)
|
|
return __mg_msgstr2 [message - 0x00A0];
|
|
else if (message >= 0x0120 && message <= 0x017F)
|
|
return __mg_msgstr3 [message - 0x0120];
|
|
else if (message >= 0xF000)
|
|
return "Control Messages";
|
|
else
|
|
return "MSG_USER";
|
|
}
|
|
|
|
void GUIAPI PrintMessage (FILE* fp, HWND hWnd,
|
|
UINT nMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
fprintf (fp, "Message %s: hWnd: %p, wP: %p, lP: %p.\n",
|
|
Message2Str (nMsg), hWnd, (PVOID)wParam, (PVOID)lParam);
|
|
}
|
|
|
|
#endif
|
|
|
|
static inline void CheckCapturedMouseMessage (PMSG pMsg)
|
|
{
|
|
if (__mg_capture_wnd == pMsg->hwnd
|
|
&& pMsg->message >= MSG_FIRSTMOUSEMSG
|
|
&& pMsg->message <= MSG_LASTMOUSEMSG
|
|
&& !(pMsg->wParam & KS_CAPTURED)) {
|
|
int x, y;
|
|
x = LOSWORD (pMsg->lParam);
|
|
y = HISWORD (pMsg->lParam);
|
|
|
|
ClientToScreen (pMsg->hwnd, &x, &y);
|
|
|
|
pMsg->lParam = MAKELONG (x, y);
|
|
pMsg->wParam |= KS_CAPTURED;
|
|
}
|
|
}
|
|
|
|
#define IS_MSG_WANTED(message) \
|
|
( (nMsgFilterMin <= 0 && nMsgFilterMax <= 0) || \
|
|
(nMsgFilterMin > 0 && nMsgFilterMax >= nMsgFilterMin && \
|
|
message >= nMsgFilterMin && message <= nMsgFilterMax) )
|
|
|
|
BOOL PeekMessageEx (PMSG pMsg, HWND hWnd, UINT nMsgFilterMin, UINT nMsgFilterMax,
|
|
BOOL bWait, UINT uRemoveMsg)
|
|
{
|
|
PMSGQUEUE pMsgQueue;
|
|
PQMSG phead;
|
|
|
|
if (!pMsg || (hWnd != HWND_DESKTOP && !MG_IS_MAIN_WINDOW(hWnd)))
|
|
return FALSE;
|
|
|
|
#ifdef _MGRM_THREADS
|
|
if (!(pMsgQueue = GetMsgQueueThisThread ()))
|
|
return FALSE;
|
|
#else
|
|
pMsgQueue = __mg_dsk_msg_queue;
|
|
#endif
|
|
|
|
memset (pMsg, 0, sizeof(MSG));
|
|
|
|
checkagain:
|
|
|
|
TEST_IF_QUIT(pMsgQueue, hWnd);
|
|
|
|
LOCK_MSGQ (pMsgQueue);
|
|
|
|
if ((pMsgQueue->dwState & QS_QUIT)) {
|
|
pMsg->hwnd = hWnd;
|
|
pMsg->message = MSG_QUIT;
|
|
pMsg->wParam = 0;
|
|
pMsg->lParam = 0;
|
|
SET_PADD (NULL);
|
|
|
|
if (uRemoveMsg == PM_REMOVE) {
|
|
pMsgQueue->loop_depth --;
|
|
if (pMsgQueue->loop_depth == 0) {
|
|
pMsgQueue->dwState &= ~QS_QUIT;
|
|
}
|
|
}
|
|
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Dealing with sync messages before notify messages is better ? */
|
|
#ifdef _MGRM_THREADS
|
|
if (pMsgQueue->dwState & QS_SYNCMSG) {
|
|
if (pMsgQueue->pFirstSyncMsg) {
|
|
*pMsg = pMsgQueue->pFirstSyncMsg->Msg;
|
|
SET_PADD (pMsgQueue->pFirstSyncMsg);
|
|
if (IS_MSG_WANTED(pMsg->message)) {
|
|
if (uRemoveMsg == PM_REMOVE) {
|
|
pMsgQueue->pFirstSyncMsg = pMsgQueue->pFirstSyncMsg->pNext;
|
|
}
|
|
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
return TRUE;
|
|
}
|
|
}
|
|
else
|
|
pMsgQueue->dwState &= ~QS_SYNCMSG;
|
|
}
|
|
#endif
|
|
|
|
if (pMsgQueue->dwState & QS_NOTIFYMSG) {
|
|
if (pMsgQueue->pFirstNotifyMsg) {
|
|
phead = pMsgQueue->pFirstNotifyMsg;
|
|
*pMsg = phead->Msg;
|
|
SET_PADD (NULL);
|
|
|
|
if (IS_MSG_WANTED(pMsg->message)) {
|
|
if (uRemoveMsg == PM_REMOVE) {
|
|
pMsgQueue->pFirstNotifyMsg = phead->next;
|
|
FreeQMSG (phead);
|
|
}
|
|
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
return TRUE;
|
|
}
|
|
}
|
|
else
|
|
pMsgQueue->dwState &= ~QS_NOTIFYMSG;
|
|
}
|
|
|
|
if (pMsgQueue->dwState & QS_POSTMSG) {
|
|
if (pMsgQueue->readpos != pMsgQueue->writepos) {
|
|
*pMsg = pMsgQueue->msg[pMsgQueue->readpos];
|
|
SET_PADD (NULL);
|
|
if (IS_MSG_WANTED(pMsg->message)) {
|
|
CheckCapturedMouseMessage (pMsg);
|
|
if (uRemoveMsg == PM_REMOVE) {
|
|
pMsgQueue->readpos++;
|
|
#if 0
|
|
if (pMsgQueue->readpos >= pMsgQueue->len)
|
|
pMsgQueue->readpos = 0;
|
|
#else
|
|
pMsgQueue->readpos %= pMsgQueue->len;
|
|
#endif
|
|
}
|
|
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
return TRUE;
|
|
}
|
|
}
|
|
else
|
|
pMsgQueue->dwState &= ~QS_POSTMSG;
|
|
}
|
|
|
|
/*
|
|
* check invalidate region of the windows
|
|
*/
|
|
|
|
if (pMsgQueue->dwState & QS_PAINT && IS_MSG_WANTED(MSG_PAINT)) {
|
|
PMAINWIN pHostingRoot;
|
|
HWND hNeedPaint;
|
|
PMAINWIN pWin;
|
|
|
|
#ifdef _MGRM_THREADS
|
|
/* REMIND this */
|
|
if (hWnd == HWND_DESKTOP) {
|
|
pMsg->hwnd = hWnd;
|
|
pMsg->message = MSG_PAINT;
|
|
pMsg->wParam = 0;
|
|
pMsg->lParam = 0;
|
|
SET_PADD (NULL);
|
|
|
|
if (uRemoveMsg == PM_REMOVE) {
|
|
pMsgQueue->dwState &= ~QS_PAINT;
|
|
}
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
pMsg->message = MSG_PAINT;
|
|
pMsg->wParam = 0;
|
|
pMsg->lParam = 0;
|
|
SET_PADD (NULL);
|
|
|
|
#ifndef _MGRM_THREADS
|
|
pHostingRoot = __mg_dsk_win;
|
|
#else
|
|
pHostingRoot = pMsgQueue->pRootMainWin;
|
|
#endif
|
|
|
|
if ( (hNeedPaint = msgCheckHostedTree (pHostingRoot)) ) {
|
|
pMsg->hwnd = hNeedPaint;
|
|
pWin = (PMAINWIN) hNeedPaint;
|
|
pMsg->lParam = (LPARAM)(&pWin->InvRgn.rgn);
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
return TRUE;
|
|
}
|
|
|
|
/* no paint message */
|
|
pMsgQueue->dwState &= ~QS_PAINT;
|
|
}
|
|
|
|
/*
|
|
* handle timer here
|
|
*/
|
|
#ifndef _MGRM_THREADS
|
|
if (pMsgQueue->dwState & QS_DESKTIMER) {
|
|
pMsg->hwnd = HWND_DESKTOP;
|
|
pMsg->message = MSG_TIMER;
|
|
pMsg->wParam = 0;
|
|
pMsg->lParam = 0;
|
|
|
|
if (uRemoveMsg == PM_REMOVE) {
|
|
pMsgQueue->dwState &= ~QS_DESKTIMER;
|
|
}
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
if (pMsgQueue->TimerMask && IS_MSG_WANTED(MSG_TIMER)) {
|
|
int slot;
|
|
TIMER* timer;
|
|
|
|
#ifdef _MGRM_THREADS
|
|
if (hWnd == HWND_DESKTOP) {
|
|
pMsg->hwnd = hWnd;
|
|
pMsg->message = MSG_TIMER;
|
|
pMsg->wParam = 0;
|
|
pMsg->lParam = 0;
|
|
SET_PADD (NULL);
|
|
|
|
if (uRemoveMsg == PM_REMOVE) {
|
|
pMsgQueue->TimerMask = 0;
|
|
}
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
/* get the first expired timer slot */
|
|
slot = pMsgQueue->FirstTimerSlot;
|
|
do {
|
|
if (pMsgQueue->TimerMask & (0x01 << slot))
|
|
break;
|
|
|
|
slot ++;
|
|
slot %= DEF_NR_TIMERS;
|
|
if (slot == pMsgQueue->FirstTimerSlot) {
|
|
slot = -1;
|
|
break;
|
|
}
|
|
} while (TRUE);
|
|
|
|
pMsgQueue->FirstTimerSlot ++;
|
|
pMsgQueue->FirstTimerSlot %= DEF_NR_TIMERS;
|
|
|
|
if ((timer = __mg_get_timer (slot))) {
|
|
|
|
unsigned int tick_count = timer->tick_count;
|
|
|
|
timer->tick_count = 0;
|
|
pMsgQueue->TimerMask &= ~(0x01 << slot);
|
|
|
|
if (timer->proc) {
|
|
BOOL ret_timer_proc;
|
|
|
|
/* unlock the message queue when calling timer proc */
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
|
|
/* calling the timer callback procedure */
|
|
ret_timer_proc = timer->proc (timer->hWnd,
|
|
timer->id, tick_count);
|
|
|
|
/* lock the message queue again */
|
|
LOCK_MSGQ (pMsgQueue);
|
|
|
|
if (!ret_timer_proc) {
|
|
/* remove the timer */
|
|
__mg_remove_timer (timer, slot);
|
|
}
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
goto checkagain;
|
|
}
|
|
else {
|
|
pMsg->message = MSG_TIMER;
|
|
pMsg->hwnd = timer->hWnd;
|
|
pMsg->wParam = timer->id;
|
|
pMsg->lParam = tick_count;
|
|
SET_PADD (NULL);
|
|
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
|
|
#ifdef _MGRM_THREADS
|
|
if (bWait) {
|
|
/* no message, wait again. */
|
|
sem_wait (&pMsgQueue->wait);
|
|
goto checkagain;
|
|
}
|
|
#else
|
|
/* no message, idle */
|
|
if (bWait) {
|
|
pMsgQueue->OnIdle (pMsgQueue);
|
|
goto checkagain;
|
|
}
|
|
#endif
|
|
|
|
/* no message */
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
The following two functions are moved to window.h as inline functions.
|
|
int GUIAPI GetMessage (PMSG pMsg, HWND hWnd)
|
|
{
|
|
return PeekMessageEx (pMsg, hWnd, 0, 0, TRUE, PM_REMOVE);
|
|
}
|
|
|
|
BOOL GUIAPI PeekMessage (PMSG pMsg, HWND hWnd, UINT nMsgFilterMin,
|
|
UINT nMsgFilterMax, UINT uRemoveMsg)
|
|
{
|
|
return PeekMessageEx (pMsg, hWnd, nMsgFilterMin, nMsgFilterMax,
|
|
FALSE, uRemoveMsg);
|
|
}
|
|
*/
|
|
|
|
/* wait for message */
|
|
BOOL GUIAPI WaitMessage (PMSG pMsg, HWND hWnd)
|
|
{
|
|
PMSGQUEUE pMsgQueue;
|
|
|
|
if (!pMsg)
|
|
return FALSE;
|
|
|
|
if (!(pMsgQueue = kernel_GetMsgQueue(hWnd)))
|
|
return FALSE;
|
|
|
|
memset (pMsg, 0, sizeof(MSG));
|
|
|
|
checkagain:
|
|
|
|
TEST_IF_QUIT(pMsgQueue, hWnd);
|
|
|
|
LOCK_MSGQ (pMsgQueue);
|
|
|
|
if ((pMsgQueue->dwState & QS_QUIT)) {
|
|
goto getit;
|
|
}
|
|
|
|
#ifdef _MGRM_THREADS
|
|
if (pMsgQueue->dwState & QS_SYNCMSG) {
|
|
if (pMsgQueue->pFirstSyncMsg) {
|
|
goto getit;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (pMsgQueue->dwState & QS_NOTIFYMSG) {
|
|
if (pMsgQueue->pFirstNotifyMsg) {
|
|
goto getit;
|
|
}
|
|
}
|
|
|
|
if (pMsgQueue->dwState & QS_POSTMSG) {
|
|
if (pMsgQueue->readpos != pMsgQueue->writepos) {
|
|
goto getit;
|
|
}
|
|
}
|
|
|
|
if (pMsgQueue->dwState & QS_PAINT) {
|
|
goto getit;
|
|
}
|
|
|
|
#ifndef _MGRM_THREADS
|
|
if (pMsgQueue->dwState & QS_DESKTIMER) {
|
|
goto getit;
|
|
}
|
|
#endif
|
|
|
|
if (pMsgQueue->TimerMask) {
|
|
goto getit;
|
|
}
|
|
|
|
#ifdef _MGRM_THREADS
|
|
/* no message, wait again. */
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
sem_wait (&pMsgQueue->wait);
|
|
#else
|
|
/* no message, idle */
|
|
pMsgQueue->OnIdle (pMsgQueue);
|
|
#endif
|
|
|
|
goto checkagain;
|
|
|
|
getit:
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL GUIAPI PeekPostMessage (PMSG pMsg, HWND hWnd, UINT nMsgFilterMin,
|
|
UINT nMsgFilterMax, UINT uRemoveMsg)
|
|
{
|
|
PMSGQUEUE pMsgQueue;
|
|
PMSG pPostMsg;
|
|
|
|
if (!pMsg)
|
|
return FALSE;
|
|
|
|
if (!(pMsgQueue = kernel_GetMsgQueue(hWnd)))
|
|
return FALSE;
|
|
|
|
LOCK_MSGQ (pMsgQueue);
|
|
memset (pMsg, 0, sizeof(MSG));
|
|
|
|
if (pMsgQueue->dwState & QS_POSTMSG) {
|
|
|
|
if (pMsgQueue->readpos != pMsgQueue->writepos) {
|
|
|
|
pPostMsg = pMsgQueue->msg + pMsgQueue->readpos;
|
|
if (nMsgFilterMin == 0 && nMsgFilterMax == 0)
|
|
*pMsg = *pPostMsg;
|
|
else if (pPostMsg->message <= nMsgFilterMax &&
|
|
pPostMsg->message >= nMsgFilterMin)
|
|
*pMsg = *pPostMsg;
|
|
else {
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
return FALSE;
|
|
}
|
|
|
|
SET_PADD (NULL);
|
|
|
|
if (uRemoveMsg == PM_REMOVE) {
|
|
pMsgQueue->readpos++;
|
|
#if 0
|
|
if (pMsgQueue->readpos >= pMsgQueue->len)
|
|
pMsgQueue->readpos = 0;
|
|
#else
|
|
pMsgQueue->readpos %= pMsgQueue->len;
|
|
#endif
|
|
}
|
|
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
return FALSE;
|
|
}
|
|
|
|
LRESULT GUIAPI SendMessage (HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
WNDPROC WndProc;
|
|
|
|
MG_CHECK_RET (MG_IS_WINDOW(hWnd), -1);
|
|
|
|
#ifdef _MGRM_THREADS
|
|
if (!BE_THIS_THREAD(hWnd))
|
|
return SendSyncMessage (hWnd, nMsg, wParam, lParam);
|
|
#endif
|
|
|
|
if ( !(WndProc = GetWndProc(hWnd)) )
|
|
return ERR_INV_HWND;
|
|
|
|
return (*WndProc)(hWnd, nMsg, wParam, lParam);
|
|
|
|
}
|
|
|
|
/* houhh 20090619, send notify message to topmost of queue.*/
|
|
LRESULT SendTopNotifyMessage (HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PMSGQUEUE pMsgQueue;
|
|
PQMSG pqmsg;
|
|
|
|
MG_CHECK_RET (MG_IS_WINDOW(hWnd), ERR_INV_HWND);
|
|
|
|
if (!(pMsgQueue = kernel_GetMsgQueue(hWnd)))
|
|
return ERR_INV_HWND;
|
|
|
|
pqmsg = QMSGAlloc();
|
|
|
|
LOCK_MSGQ (pMsgQueue);
|
|
|
|
/* queue the notification message. */
|
|
pqmsg->Msg.hwnd = hWnd;
|
|
pqmsg->Msg.message = nMsg;
|
|
pqmsg->Msg.wParam = wParam;
|
|
pqmsg->Msg.lParam = lParam;
|
|
pqmsg->next = NULL;
|
|
|
|
if (pMsgQueue->pFirstNotifyMsg == NULL) {
|
|
pMsgQueue->pFirstNotifyMsg = pMsgQueue->pLastNotifyMsg = pqmsg;
|
|
}
|
|
else {
|
|
pqmsg->next = pMsgQueue->pFirstNotifyMsg;
|
|
pMsgQueue->pFirstNotifyMsg = pqmsg;
|
|
}
|
|
|
|
pMsgQueue->dwState |= QS_NOTIFYMSG;
|
|
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
#ifdef _MGRM_THREADS
|
|
if ( !BE_THIS_THREAD(hWnd) )
|
|
POST_MSGQ(pMsgQueue);
|
|
#endif
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
int GUIAPI SendNotifyMessage (HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PMSGQUEUE pMsgQueue;
|
|
PQMSG pqmsg;
|
|
|
|
MG_CHECK_RET (MG_IS_WINDOW(hWnd), ERR_INV_HWND);
|
|
|
|
if (!(pMsgQueue = kernel_GetMsgQueue(hWnd)))
|
|
return ERR_INV_HWND;
|
|
|
|
pqmsg = QMSGAlloc();
|
|
|
|
LOCK_MSGQ (pMsgQueue);
|
|
|
|
/* queue the notification message. */
|
|
pqmsg->Msg.hwnd = hWnd;
|
|
pqmsg->Msg.message = nMsg;
|
|
pqmsg->Msg.wParam = wParam;
|
|
pqmsg->Msg.lParam = lParam;
|
|
pqmsg->next = NULL;
|
|
|
|
if (pMsgQueue->pFirstNotifyMsg == NULL) {
|
|
pMsgQueue->pFirstNotifyMsg = pMsgQueue->pLastNotifyMsg = pqmsg;
|
|
}
|
|
else {
|
|
pMsgQueue->pLastNotifyMsg->next = pqmsg;
|
|
pMsgQueue->pLastNotifyMsg = pqmsg;
|
|
}
|
|
|
|
pMsgQueue->dwState |= QS_NOTIFYMSG;
|
|
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
#ifdef _MGRM_THREADS
|
|
if ( !BE_THIS_THREAD(hWnd) )
|
|
POST_MSGQ(pMsgQueue);
|
|
#endif
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
int GUIAPI PostMessage (HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PMSGQUEUE pMsgQueue;
|
|
MSG msg;
|
|
|
|
if (!(pMsgQueue = kernel_GetMsgQueue(hWnd)))
|
|
return ERR_INV_HWND;
|
|
|
|
if (nMsg == MSG_PAINT) {
|
|
LOCK_MSGQ (pMsgQueue);
|
|
pMsgQueue->dwState |= QS_PAINT;
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
#ifdef _MGRM_THREADS
|
|
if ( !BE_THIS_THREAD(hWnd) )
|
|
POST_MSGQ(pMsgQueue);
|
|
#endif
|
|
return ERR_OK;
|
|
}
|
|
|
|
msg.hwnd = hWnd;
|
|
msg.message = nMsg;
|
|
msg.wParam = wParam;
|
|
msg.lParam = lParam;
|
|
|
|
if (!kernel_QueueMessage(pMsgQueue, &msg))
|
|
return ERR_QUEUE_FULL;
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
int GUIAPI PostQuitMessage (HWND hWnd)
|
|
{
|
|
PMSGQUEUE pMsgQueue = NULL;
|
|
|
|
if (hWnd && hWnd != HWND_INVALID) {
|
|
PMAINWIN pWin = (PMAINWIN)hWnd;
|
|
if (pWin->DataType == TYPE_HWND || pWin->DataType == TYPE_WINTODEL) {
|
|
pMsgQueue = pWin->pMainWin->pMessages;
|
|
}
|
|
}
|
|
|
|
if (pMsgQueue == NULL)
|
|
return ERR_INV_HWND;
|
|
|
|
LOCK_MSGQ (pMsgQueue);
|
|
if (!(pMsgQueue->dwState & QS_QUIT)){
|
|
pMsgQueue->loop_depth ++;
|
|
pMsgQueue->dwState |= QS_QUIT;
|
|
}
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
|
|
#ifdef _MGRM_THREADS
|
|
if (!BE_THIS_THREAD (hWnd))
|
|
POST_MSGQ (pMsgQueue);
|
|
#endif
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
#include "license.h"
|
|
|
|
LRESULT GUIAPI DispatchMessage (PMSG pMsg)
|
|
{
|
|
WNDPROC WndProc;
|
|
#ifdef _MGRM_THREADS
|
|
PSYNCMSG pSyncMsg;
|
|
#endif
|
|
LRESULT lRet;
|
|
|
|
LICENSE_MODIFY_MESSAGE(pMsg);
|
|
|
|
#ifdef _MGHAVE_TRACE_MSG
|
|
if (pMsg->message != MSG_TIMEOUT && pMsg->message != MSG_CARETBLINK) {
|
|
fprintf (stderr, "Message %u (%s): hWnd: %p, wP: %p, lP: %p. %s\n",
|
|
pMsg->message, Message2Str (pMsg->message),
|
|
pMsg->hwnd, (PVOID)pMsg->wParam, (PVOID)pMsg->lParam, SYNMSGNAME);
|
|
}
|
|
#endif
|
|
|
|
if (pMsg->hwnd == HWND_INVALID) {
|
|
#ifdef _MGRM_THREADS
|
|
if (pMsg->pAdd) {
|
|
pSyncMsg = (PSYNCMSG)pMsg->pAdd;
|
|
pSyncMsg->retval = ERR_MSG_CANCELED;
|
|
sem_post (pSyncMsg->sem_handle);
|
|
}
|
|
#endif
|
|
|
|
#ifdef _MGHAVE_TRACE_MSG
|
|
if (pMsg->message != MSG_TIMEOUT && pMsg->message != MSG_CARETBLINK) {
|
|
fprintf (stderr, "Message %u (%s) has been thrown away.\n",
|
|
pMsg->message, Message2Str (pMsg->message));
|
|
}
|
|
#endif
|
|
return -1;
|
|
}
|
|
|
|
if (pMsg->hwnd == 0)
|
|
return -1;
|
|
|
|
if (!(WndProc = GetWndProc (pMsg->hwnd)))
|
|
return -1;
|
|
|
|
lRet = WndProc (pMsg->hwnd, pMsg->message, pMsg->wParam, pMsg->lParam);
|
|
|
|
#ifdef _MGRM_THREADS
|
|
/* this is a sync message. */
|
|
if (pMsg->pAdd) {
|
|
pSyncMsg = (PSYNCMSG)pMsg->pAdd;
|
|
pSyncMsg->retval = lRet;
|
|
sem_post (pSyncMsg->sem_handle);
|
|
}
|
|
#endif
|
|
|
|
#ifdef _MGHAVE_TRACE_MSG
|
|
if (pMsg->message != MSG_TIMEOUT && pMsg->message != MSG_CARETBLINK) {
|
|
fprintf (stderr, "Message %u (%s) done, return value: %p\n",
|
|
pMsg->message, Message2Str (pMsg->message), (PVOID)lRet);
|
|
}
|
|
#endif
|
|
|
|
return lRet;
|
|
}
|
|
|
|
/* define this to print debug info of ThrowAwayMessages */
|
|
/* #define _DEBUG_TAM 1 */
|
|
#undef _DEBUG_TAM
|
|
|
|
int GUIAPI ThrowAwayMessages (HWND hWnd)
|
|
{
|
|
PMSG pMsg;
|
|
PMSGQUEUE pMsgQueue = NULL;
|
|
PQMSG pQMsg;
|
|
int nCountN = 0;
|
|
int nCountS = 0;
|
|
int nCountP = 0;
|
|
int readpos;
|
|
int slot;
|
|
|
|
if (hWnd && hWnd != HWND_INVALID) {
|
|
PMAINWIN pWin = (PMAINWIN)hWnd;
|
|
if (pWin->DataType == TYPE_HWND || pWin->DataType == TYPE_WINTODEL) {
|
|
pMsgQueue = pWin->pMainWin->pMessages;
|
|
}
|
|
}
|
|
|
|
if (pMsgQueue == NULL)
|
|
return ERR_INV_HWND;
|
|
|
|
LOCK_MSGQ (pMsgQueue);
|
|
|
|
if (pMsgQueue->pFirstNotifyMsg) {
|
|
pQMsg = pMsgQueue->pFirstNotifyMsg;
|
|
|
|
while (pQMsg) {
|
|
pMsg = &pQMsg->Msg;
|
|
|
|
if (pMsg->hwnd == hWnd || gui_GetMainWindowPtrOfControl (pMsg->hwnd)
|
|
== (PMAINWIN)hWnd) {
|
|
pMsg->hwnd = HWND_INVALID;
|
|
nCountN ++;
|
|
}
|
|
|
|
pQMsg = pQMsg->next;
|
|
}
|
|
}
|
|
|
|
#ifdef _DEBUG_TAM
|
|
printf ("ThrowAwayMessages: %d notification messages thrown\n", nCountN);
|
|
#endif
|
|
|
|
#ifdef _MGRM_THREADS
|
|
if (pMsgQueue->pFirstSyncMsg) {
|
|
PSYNCMSG pSyncMsg, pSyncPrev = NULL;
|
|
pSyncMsg = pMsgQueue->pFirstSyncMsg;
|
|
|
|
while (pSyncMsg) {
|
|
pMsg = &pSyncMsg->Msg;
|
|
|
|
if (pMsg->hwnd == hWnd || gui_GetMainWindowPtrOfControl (pMsg->hwnd)
|
|
== (PMAINWIN)hWnd) {
|
|
pMsg->hwnd = HWND_INVALID;
|
|
nCountS ++;
|
|
|
|
/*
|
|
* notify the waiting thread and remove the node from
|
|
* msg queue
|
|
*/
|
|
pSyncMsg->retval = ERR_MSG_CANCELED;
|
|
if (pSyncPrev) {
|
|
pSyncPrev->pNext = pSyncMsg->pNext ? pSyncMsg->pNext : NULL;
|
|
}
|
|
else {
|
|
pSyncPrev = pSyncMsg;
|
|
pSyncMsg = pSyncMsg->pNext;
|
|
pMsgQueue->pFirstSyncMsg = pSyncMsg;
|
|
sem_post (pSyncPrev->sem_handle);
|
|
pSyncPrev = NULL;
|
|
continue;
|
|
}
|
|
sem_post (pSyncMsg->sem_handle);
|
|
}
|
|
|
|
pSyncPrev = pSyncMsg;
|
|
pSyncMsg = pSyncMsg->pNext;
|
|
}
|
|
}
|
|
|
|
#ifdef _DEBUG_TAM
|
|
printf ("ThrowAwayMessages: %d sync messages thrown\n", nCountS);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
readpos = pMsgQueue->readpos;
|
|
while (readpos != pMsgQueue->writepos) {
|
|
pMsg = pMsgQueue->msg + readpos;
|
|
|
|
if (pMsg->hwnd == hWnd
|
|
|| gui_GetMainWindowPtrOfControl (pMsg->hwnd) == (PMAINWIN)hWnd) {
|
|
pMsg->hwnd = HWND_INVALID;
|
|
nCountP ++;
|
|
}
|
|
|
|
readpos++;
|
|
#if 0
|
|
if (readpos >= pMsgQueue->len) readpos = 0;
|
|
#else
|
|
readpos %= pMsgQueue->len;
|
|
#endif
|
|
}
|
|
|
|
#ifdef _DEBUG_TAM
|
|
printf ("ThrowAwayMessages: %d post messages thrown\n", nCountP);
|
|
#endif
|
|
|
|
/* clear timer message flags of this window */
|
|
for (slot = 0; slot < DEF_NR_TIMERS; slot++) {
|
|
if (pMsgQueue->TimerMask & (0x01 << slot)) {
|
|
HWND timer_wnd = __mg_get_timer_hwnd (slot);
|
|
if (timer_wnd == hWnd
|
|
|| gui_GetMainWindowPtrOfControl (timer_wnd) == (PMAINWIN)hWnd){
|
|
RemoveMsgQueueTimerFlag (pMsgQueue, slot);
|
|
}
|
|
}
|
|
}
|
|
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
|
|
return nCountN + nCountS + nCountP;
|
|
}
|
|
|
|
#ifndef _MGRM_THREADS
|
|
|
|
BOOL GUIAPI EmptyMessageQueue (HWND hWnd)
|
|
{
|
|
PMSGQUEUE pMsgQueue;
|
|
PQMSG pQMsg, temp;
|
|
|
|
if (!(pMsgQueue = kernel_GetMsgQueue(hWnd)))
|
|
return FALSE;
|
|
|
|
if (pMsgQueue->pFirstNotifyMsg) {
|
|
pQMsg = pMsgQueue->pFirstNotifyMsg;
|
|
while (pQMsg) {
|
|
temp = pQMsg->next;
|
|
FreeQMSG (pQMsg);
|
|
pQMsg = temp;
|
|
}
|
|
}
|
|
|
|
pMsgQueue->pFirstNotifyMsg = NULL;
|
|
pMsgQueue->pLastNotifyMsg = NULL;
|
|
|
|
pMsgQueue->readpos = 0;
|
|
pMsgQueue->writepos = 0;
|
|
|
|
mg_TerminateTimer ();
|
|
|
|
pMsgQueue->dwState = QS_EMPTY;
|
|
pMsgQueue->TimerMask = 0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#else
|
|
|
|
/* send a synchronous message to a window in a different thread */
|
|
LRESULT SendSyncMessage (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PMSGQUEUE pMsgQueue, thinfo = NULL;
|
|
SYNCMSG SyncMsg;
|
|
sem_t sync_msg;
|
|
|
|
if (!(pMsgQueue = kernel_GetMsgQueue(hWnd)))
|
|
return ERR_INV_HWND;
|
|
|
|
#define _SYNC_NEED_REENTERABLE
|
|
#ifndef _SYNC_NEED_REENTERABLE
|
|
if ((thinfo = GetMsgQueueThisThread ())) {
|
|
/* avoid to create a new semaphore object, Note: it's not reenterable.*/
|
|
SyncMsg.sem_handle = &thinfo->sync_msg;
|
|
}
|
|
else {
|
|
/* this is not a GUI thread */
|
|
sem_init (&sync_msg, 0, 0);
|
|
SyncMsg.sem_handle = &sync_msg;
|
|
}
|
|
#else
|
|
//The following DispatchMessage will need this function is reentrant function,
|
|
//so we must use unique semaphore.
|
|
thinfo = GetMsgQueueThisThread ();
|
|
sem_init (&sync_msg, 0, 0);
|
|
SyncMsg.sem_handle = &sync_msg;
|
|
#endif
|
|
|
|
/* queue the sync message. */
|
|
SyncMsg.Msg.hwnd = hWnd;
|
|
SyncMsg.Msg.message = msg;
|
|
SyncMsg.Msg.wParam = wParam;
|
|
SyncMsg.Msg.lParam = lParam;
|
|
SyncMsg.retval = ERR_MSG_CANCELED;
|
|
SyncMsg.pNext = NULL;
|
|
|
|
#if 1
|
|
/* add by houhh 20081030, deal with itself's SyncMsg first before
|
|
* SendSyncMessage to other thread, because other thread maybe wait
|
|
* for SyncMsg for you.*/
|
|
if (thinfo) {
|
|
MSG msg;
|
|
PMSGQUEUE pMsgQueue = thinfo;
|
|
|
|
while (TRUE) {
|
|
LOCK_MSGQ (pMsgQueue);
|
|
if (pMsgQueue->dwState & QS_SYNCMSG) {
|
|
if (pMsgQueue->pFirstSyncMsg) {
|
|
msg = pMsgQueue->pFirstSyncMsg->Msg;
|
|
msg.pAdd = (pMsgQueue->pFirstSyncMsg);
|
|
pMsgQueue->pFirstSyncMsg = pMsgQueue->pFirstSyncMsg->pNext;
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
else {
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
pMsgQueue->dwState &= ~QS_SYNCMSG;
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
LOCK_MSGQ (pMsgQueue);
|
|
|
|
if (pMsgQueue->pFirstSyncMsg == NULL) {
|
|
pMsgQueue->pFirstSyncMsg = pMsgQueue->pLastSyncMsg = &SyncMsg;
|
|
}
|
|
else {
|
|
pMsgQueue->pLastSyncMsg->pNext = &SyncMsg;
|
|
pMsgQueue->pLastSyncMsg = &SyncMsg;
|
|
}
|
|
|
|
pMsgQueue->dwState |= QS_SYNCMSG;
|
|
|
|
UNLOCK_MSGQ (pMsgQueue);
|
|
POST_MSGQ (pMsgQueue);
|
|
|
|
/* suspend until the message has been handled. */
|
|
if (sem_wait (SyncMsg.sem_handle) < 0) {
|
|
fprintf (stderr,
|
|
"KERNEL>SendSyncMessage: thread is interrupted abnormally!\n");
|
|
}
|
|
|
|
#ifndef _SYNC_NEED_REENTERABLE
|
|
if (thinfo == NULL)
|
|
sem_destroy (&sync_msg);
|
|
#else
|
|
sem_destroy (&sync_msg);
|
|
#endif
|
|
|
|
#undef _SYNC_NEED_REENTERABLE
|
|
return SyncMsg.retval;
|
|
}
|
|
|
|
LRESULT GUIAPI PostSyncMessage (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
MG_CHECK_RET (MG_IS_WINDOW(hWnd), -1);
|
|
if (BE_THIS_THREAD(hWnd))
|
|
return -1;
|
|
|
|
return SendSyncMessage (hWnd, msg, wParam, lParam);
|
|
}
|
|
|
|
LRESULT GUIAPI SendAsyncMessage (HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
WNDPROC WndProc;
|
|
|
|
MG_CHECK_RET (MG_IS_WINDOW(hWnd), -1);
|
|
|
|
if (!(WndProc = GetWndProc(hWnd)))
|
|
return -1;
|
|
|
|
return WndProc (hWnd, nMsg, wParam, lParam);
|
|
}
|
|
|
|
#endif /* !LITE_VERSION */
|
|
|