MiniGUI Messge (一)

      消息循环是事件驱动的 GUI 编程基础。在循环中,程序从外部输入设备获取某些事件,比如按键或鼠标移动。然后根据这些事情做出某种响应,并完成一定的功能。这个循环直到程序接受到某个消息为止。窗口是 MiniGUI 当中最基本的 GUI 元素,一旦窗口建立之后,窗口就会从消息队列当中获取属于自己的消息,然后交由它的窗口过程进行处理。这些消息当中,有一些是基本的输入设备事件,而有一些则是与窗口管理相关的逻辑消息。

MSG

●PROTOTYPE

typedef struct _MSG

{

    /** The handle to the window which receives this message. */

    HWND             hwnd;

    /** The message identifier. */

    int              message;

    /** The first parameter of the message (32-bit integer). */

    WPARAM           wParam;

    /** The second parameter of the message (32-bit integer). */

    LPARAM           lParam;

    /** Time*/

    unsigned int     time;

#ifdef _MGRM_THREADS

    /** Addtional data*/

    void*            pAdd;

#endif

} MSG;

●MEMBERS

hwnd        : 接受消息的窗口句柄

message     : 消息编号

wParam      : 第一个消息参数

lParam      : 第二个消息参数

time        : 时间

pAdd        : 附加数据

●DESCRIPTION

_MSG用于描述消息信息

 

GetMessage:从自己的消息队列中取出一条消息,其关键代码如下,

GetMessage(PMSG pMsg, HWND hWnd)

    PeekMessageEx(pMsg, hWnd, 0, 0, TRUE, PM_REMOVE)

        PMSGQUEUE pMsgQueue

        PQMSG phead

        pMsgQueue = GetMsgQueueThisThread()

            MSGQUEUE* pMsgQueue

        pMsgQueue = (MSGQUEUE*) pthread_getspecific(__mg_threadinfo_key)    //get the key

        return pMsgQueue

    memset(pMsg, 0, sizeof(MSG))

    if((pMsgQueue->dwState & QS_QUIT))  //QUIT msg

    {

        hwnd:hWnd

        message:MSG_QUIT

        wParam:0

        lParam:0

        pAdd:NULL

        if (uRemoveMsg == PM_REMOVE)

        {

              pMsgQueue->loop_depth--;

              if (pMsgQueue->loop_depth == 0)

              {

                  pMsgQueue->dwState &= ~QS_QUIT;

              }

        }

    }

    if(pMsgQueue->dwState & QS_SYNCMSG) //SYNC msg

    {

        if(pMsgQueue->pFirstSyncMsg)

        {

            *pMsg = pMsgQueue->pFirstSyncMsg->Msg

            pMsg->pAdd = pMsgQueue->pFirstSyncMsg

            if(uRemoveMsg == PM_REMOVE)

            {

                  pMsgQueue->pFirstSyncMsg = pMsgQueue->pFirstSyncMsg->pNext

                  }

        }

            else

        {

            pMsgQueue->dwState &= ~QS_SYNCMSG

        }

    }

    if(pMsgQueue->dwState & QS_NOTIFYMSG)   //NOTIFY MSG

    {

        if(pMsgQueue->pFirstNotifyMsg)

        {

            phead = pMsgQueue->pFirstNotifyMsg

              *pMsg = phead->Msg

              pMsg->pAdd = NULL

              if (IS_MSG_WANTED(pMsg->message))

              {

                  if (uRemoveMsg == PM_REMOVE)

                      {

                      pMsgQueue->pFirstNotifyMsg = phead->next;

                      FreeQMSG (phead);

                     }

                 }  

        }

        else

              pMsgQueue->dwState &= ~QS_NOTIFYMSG

    }

    if(pMsgQueue->dwState & QS_POSTMSG) //POST MSG

    {

        if(pMsgQueue->readpos != pMsgQueue->writepos)

        {

            *pMsg = pMsgQueue->msg[pMsgQueue->readpos]

            pMsg->pAdd = NULL

            if(IS_MSG_WANTED(pMsg->message))

            {

                  CheckCapturedMouseMessage(pMsg)

                  if(uRemoveMsg == PM_REMOVE)

                  {

                       pMsgQueue->readpos++

                       pMsgQueue->readpos %= pMsgQueue->len

                  }

              }

        }

        else

              pMsgQueue->dwState &= ~QS_POSTMSG

    }

    /* check invalidate region of the windows */

    if(pMsgQueue->dwState & QS_PAINT && IS_MSG_WANTED(MSG_PAINT))

    {

        if(hWnd == HWND_DESKTOP)

        {

            pMsg->hwnd = hWnd;

              pMsg->message = MSG_PAINT;

                  pMsg->wParam = 0;

              pMsg->lParam = 0;

              pMsg->pAdd = NULL;

              if(uRemoveMsg == PM_REMOVE)

              {

                  pMsgQueue->dwState &= ~QS_PAINT;

              }

        }

        pMsg->message = MSG_PAINT;

             pMsg->wParam = 0;

        pMsg->lParam = 0;

        pMsg->pAdd = NULL;

        pHostingRoot = pMsgQueue->pRootMainWin

        if((hNeedPaint = msgCheckHostedTree(pHostingRoot)))

        {

            pMsg->hwnd = hNeedPaint

              pWin = (PMAINWIN) hNeedPaint

              pMsg->lParam = (LPARAM)(&pWin->InvRgn.rgn)

                  return TRUE

        }

        pMsgQueue->dwState &= ~QS_PAINT

    }

    if(pMsgQueue->TimerMask && IS_MSG_WANTED(MSG_TIMER))

    {

        if(hWnd == HWND_DESKTOP)

        {

            pMsg->hwnd = hWnd

                pMsg->message = MSG_TIMER

                pMsg->wParam = 0

                pMsg->lParam = 0

                pMsg->pAdd = NULL

             if(uRemoveMsg == PM_REMOVE)

            {

                    pMsgQueue->TimerMask = 0

                }

              }

              /* 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)))

        {

            ...

            if(timer->proc)

            {

                /* calling the timer callback procedure */

                  ret_timer_proc = timer->proc(timer->hWnd, timer->id, tick_count);

                  ...

              }

              else

              {

                  pMsg->message = MSG_TIMER;

                  pMsg->hwnd = timer->hWnd;

                  pMsg->wParam = timer->id;

                  pMsg->lParam = tick_count;

                  pMsg->pAdd = NULL;

              }

        }

    }

    if(bWait)   //TRUE

    {

        /* no message, wait again. */

        sem_wait(&pMsgQueue->wait) //P2

    }

    return FALSE

TranslateMessage:把击键消息转换为 MSG_CHAR 消息,然后直接发送到窗口过程函数。其关键代码如下,

TranslateMessage(PMSG pMsg)

    if((pMsg->hwnd != HWND_DESKTOP))

    {

        ...

        handle_scancode_on_keydown

        ...

        handle_scancode_on_keyup

    }

    ...

     SendNotifyMessage(pMsg->hwnd, MSG_CHAR, kinfo.buff[0], pMsg->lParam)

    ...

DispatchMessage:最终把消息发往消息的目标窗口的窗口过程,让窗口过程进行处理。其关键代码如下,

WndProc = GetWndProc(pMsg->hwnd)

    (*WndProc)(pMsg->hwnd, pMsg->message, pMsg->wParam, pMsg->lParam)   //call the callback func

    if(pMsg->pAdd)

    {

        pSyncMsg = (PSYNCMSG)pMsg->pAdd

        pSyncMsg->retval = iRet

        sem_post(pSyncMsg->sem_handle)   //V3

    }

2.4.2  Message Loop

在这个循环体中,程序利用 GetMessage 函数不停地从消息队列中获得消息,然后利用 DispatchMessage 函数将消息发送到指定的窗口,也就是调用指定窗口的窗口过程,并传递消息及其参数。程序中一般使用下列语句进行消息循环:

while (GetMessage (&Msg, hMainWnd)) {

       TranslateMessage (&Msg);

       DispatchMessage (&Msg);

}

GetMessage 函数从 hMainWnd 窗口所属的消息队列当中获得消息,然后调用 TranslateMessage 函数将 MSG_KEYDOWN 和 MSG_KEYUP 消息翻译成 MSG_CHAR 消息,最后调用 DispatchMessage 函数将消息发送到指定的窗口。

 

在MiniGUI消息机制中,主要提供了以下几个消息处理函数。

PostMessage:字面理解为邮寄消息。将消息放到指定窗口的消息队列后立即返回。此消息在消息队列的存储形式为消息缓冲区。存在缓冲区满的情况。PostMessage 一般用于发送一些非关键性的消息。例如鼠标和键盘消息。其关键代码如下,

PostMessage(HWND hWnd, int iMsg, WPARAM wParam, LPARAM lParam)

    pMsgQueue = kernel_GetMsgQueue(hWnd)

    if(iMsg == MSG_PAINT)

    {

        pMsgQueue->dwState |= QS_PAINT

        if(!BE_THIS_THREAD(hWnd))

        POST_MSGQ(pMsgQueue)

            sem_post(&(pMsgQueue)->wait)    //V1

    }

    msg.hwnd = hWnd

    msg.message = iMsg

    msg.wParam = wParam

    msg.lParam = lParam

    kernel_QueueMessage(pMsgQueue, &msg)

    ...

    /* Write the data and advance write pointer */

    msg_que->msg [msg_que->writepos] = *msg

    msg_que->writepos++

    msg_que->writepos %= msg_que->len

    msg_que->dwState |= QS_POSTMSG

    if (!BE_THIS_THREAD (msg->hwnd))

        POST_MSGQ(msg_que)

SendNotifyMessage:和PostMessage类似,发送即返回,不等待消息被处理。两者区别是SendNotifyMessage发送的消息在消息队列的存储形式是链表,不存在消息队列满而丢失消息的情况。一般用来从控件向其父窗口发送通知。其关键代码如下,

SendNotifyMessage(HWND hWnd, int iMsg, WPARAM wParam, LPARAM lParam)

    pMsgQueue = kernel_GetMsgQueue(hWnd)

    /* queue the notification message. */

    pqmsg->Msg.hwnd = hWnd

    pqmsg->Msg.message = iMsg

    pqmsg->Msg.wParam = wParam

    pqmsg->Msg.lParam = lParam

    pqmsg->next = NULL

    if(pMsgQueue->pFirstNotifyMsg == NULL) //added to the list

    {

        pMsgQueue->pFirstNotifyMsg = pMsgQueue->pLastNotifyMsg = pqmsg;

    }

    else

    {

        pMsgQueue->pLastNotifyMsg->next = pqmsg;

        pMsgQueue->pLastNotifyMsg = pqmsg;

    }

    pMsgQueue->dwState |= QS_NOTIFYMSG

    if( !BE_THIS_THREAD(hWnd) )

        POST_MSGQ(pMsgQueue)

        sem_post(&(pMsgQueue)->wait) //V2

SendSyncMessage:发送同步消息,即将要发送的同步消息加入消息队列后,等待消息被处理之后才返回。其关键代码如下,

SendSyncMessage(HWND hWnd, int msg, WPARAM wParam, LPARAM lParam)

    pMsgQueue = kernel_GetMsgQueue(hWnd)

    if((thinfo = GetMsgQueueThisThread()))

    {

        /* avoid to create a new semaphore object */

        SyncMsg.sem_handle = &thinfo->sync_msg

    }

    else

    {

        /* this is not a GUI thread */

        sem_init (&sync_msg, 0, 0)

        SyncMsg.sem_handle = &sync_msg

    }

    /* 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(thinfo)

    {

        MSG msg

        PMSGQUEUE pMsgQueue = thinfo

        while(TRUE)

        {

            if(pMsgQueue->dwState & QS_SYNCMSG)

            {

                if(pMsgQueue->pFirstSyncMsg)

                {

                    msg = pMsgQueue->pFirstSyncMsg->Msg

                    msg.pAdd = (pMsgQueue->pFirstSyncMsg)

                    pMsgQueue->pFirstSyncMsg = pMsgQueue->pFirstSyncMsg->pNext

                    TranslateMessage(&msg)

                       SendNotifyMessage(pMsg->hwnd, MSG_CHAR, kinfo.buff[0], pMsg->lParam)

                    DispatchMessage(&msg)

                       sem_post(pSyncMsg->sem_handle)  //V3

                      

                }

                else

                {

                    pMsgQueue->dwState &= ~QS_SYNCMSG

                    break;

                }

            }

            else

                break;

        }

    }

    if(pMsgQueue->pFirstSyncMsg == NULL)

    {

        pMsgQueue->pFirstSyncMsg = pMsgQueue->pLastSyncMsg = &SyncMsg;

    }

    else

    {

        pMsgQueue->pLastSyncMsg->pNext = &SyncMsg;

        pMsgQueue->pLastSyncMsg = &SyncMsg;

    }

    pMsgQueue->dwState |= QS_SYNCMSG

    POST_MSGQ(pMsgQueue)

        sem_post(&(pMsgQueue)->wait) //V2

    sem_wait(SyncMsg.sem_handle) //P3

    if(thinfo == NULL)

    sem_destroy(&sync_msg)

SendMessage:与PostMessage不同,它在发送一条消息给指定窗口时,将等待该消息被处理之后才会返回。当需要知道某个消息的处理结果时,使用该函数发送消息,然后根据其返回值进行处理。在MG-T模式中,如果发送消息的线程和接收消息的线程不是同一个线程,发送消息的线程将阻塞并等待另一个线程的处理结果,然后继续运行;否则,SendMessage 函数将直接调用接收消息窗口的窗口过程函数。其关键代码如下,

SendMessage(HWND hWnd, int iMsg, WPARAM wParam, LPARAM lParam)

    if(!BE_THIS_THREAD(hWnd))

        return SendSyncMessage(hWnd, iMsg, wParam, lParam)

       

    WndProc = GetWndProc(hWnd)

    return (*WndProc)(hWnd, iMsg, wParam, lParam)

SendAsyncMessage:发送异步消息,如果窗口处理函数存在,则直接调用窗口处理函数。其关键代码如下,

SendAsyncMessage(HWND hWnd, int iMsg, WPARAM wParam, LPARAM lParam)

    WndProc = GetWndProc(hWnd)

    return (*WndProc)(hWnd, iMsg, wParam, lParam)

PostSyncMessage:如果发送消息的线程和接收消息的线程是同一个线程,则不做处理。不同线程则调用SendSyncMessage发送同步消息。其关键代码如下,

PostSyncMessage(HWND hWnd, int msg, WPARAM wParam, LPARAM lParam)

    if(BE_THIS_THREAD(hWnd))

        return -1

    return SendSyncMessage(hWnd, msg, wParam, lParam)

PostQuitMessage:该消息在消息队列中设置一个 QS_QUIT 标志。GetMessage 在从指定消息队列中获取消息时,会检查该标志,如果有 QS_QUIT 标志,GetMessage 消息将返回 FALSE,从而可以利用该返回值终止消息循环。其关键代码如下,

    if(hWnd && hWnd != HWND_INVALID)

    {

        PMAINWIN pWin = (PMAINWIN)hWnd

        if (pWin->DataType == TYPE_HWND || pWin->DataType == TYPE_WINTODEL)

        {

            pMsgQueue = pWin->pMainWin->pMessages

        }

    }

    if(!(pMsgQueue->dwState & QS_QUIT))

    {

        pMsgQueue->loop_depth ++

        pMsgQueue->dwState |= QS_QUIT

    }

    if(!BE_THIS_THREAD(hWnd))

        POST_MSGQ(pMsgQueue)

        sem_post(&(pMsgQueue)->wait) //V1

ThrowAwayMessages:丢弃和指定窗口相关的消息队列中的所有消息,并返回所丢弃的消息个数。其关键代码如下,

ThrowAwayMessages(HWND hWnd)

    if(pMsgQueue->pFirstNotifyMsg)  //notification messages thrown

    {

        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

        }

    }

    if(pMsgQueue->pFirstSyncMsg) //sync messages thrown

    {

        pSyncMsg = pMsgQueue->pFirstSyncMsg

        while(pSyncMsg)

        {

            pMsg = &pSyncMsg->Msg

            if(pMsg->hwnd == hWnd || gui_GetMainWindowPtrOfControl(pMsg->hwnd) == (PMAINWIN)hWnd)

            {

                pMsg->hwnd = HWND_INVALID

                nCountS ++

                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);   //V3

                    pSyncPrev = NULL;

                    continue;

                }

                sem_post(pSyncMsg->sem_handle) //V3

            }

            pSyncPrev = pSyncMsg

            pSyncMsg = pSyncMsg->pNext

        }

    }

    readpos = pMsgQueue->readpos

    while(readpos != pMsgQueue->writepos) //post messages thrown

    {

        pMsg = pMsgQueue->msg + readpos

 

        if(pMsg->hwnd == hWnd || gui_GetMainWindowPtrOfControl (pMsg->hwnd) == (PMAINWIN)hWnd)

        {

            pMsg->hwnd = HWND_INVALID

            nCountP ++

        }

        readpos++

        readpos %= pMsgQueue->len

    }

    /* 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)

            }

        }

    }

    return nCountN + nCountS + nCountP

BroadcastMessage:调用SendMessage将指定消息广播给桌面上的所有主窗口。其关键代码如下,

BroadcastMessage(int iMsg, WPARAM wParam, LPARAM lParam)

    SendMessage(HWND_DESKTOP, MSG_BROADCASTMSG, 0, (LPARAM)(&msg))

 

你可能感兴趣的:(miniGUI)