minigui 时钟


libminigui-1.6.8 配置为线程版
 
minigui定时器的创建、销毁及定时器消息MSG_TIMER的传递
 
1 、时钟初始化
 
在minigui的初始化期间,调用函数__mg_timer_init()对时钟进行初始化。
 
src/kernel/timer.c  line 136-162
  1. static void* TimerEntry (void* data)
  2. {
  3.     if (!InitTimer ()) {
  4.         fprintf (stderr, "TIMER: Init Timer failure!/n"); 
  5. #ifndef __NOUNIX__ 
  6.         exit (1); 
  7. #endif 
  8.         return NULL;
  9.     }
  10.     sem_post ((sem_t*)data);
  11.     __mg_os_timer_loop ();
  12.     return NULL;
  13. }
  14. int __mg_timer_init (void)
  15. {
  16.     sem_t wait;
  17.     sem_init (&wait, 0, 0);
  18.     pthread_create (&__mg_timer, NULL, TimerEntry, &wait);
  19.     sem_wait (&wait);
  20.     sem_destroy (&wait);
  21.     return 0;
  22. }

函数__mg_timer_init()主要负责创建一个线程,来执行函数TimerEntry( )。在TimerEntry()函数中会通过InitTimer调用函数InstallIntervalTimer( )初始化系统时钟。
 
src/kernel/timer.c line 184-210
  1. BOOL InstallIntervalTimer (void)
  2. {
  3.     struct itimerval timerv;
  4.     struct sigaction siga;
  5.     
  6.     sigaction (SIGALRM, NULL, &old_alarm_handler);
  7.     siga = old_alarm_handler;
  8.     siga.sa_handler = (void(*)(int))__mg_timer_action;
  9.     siga.sa_flags = SA_RESTART;
  10.     sigaction (SIGALRM, &siga, NULL);
  11.     timerv.it_interval.tv_sec = 0; 
  12. #if defined(__uClinux__) && defined(_STAND_ALONE) 
  13.     timerv.it_interval.tv_usec = 100000;     // 100 ms 
  14. #else 
  15.     timerv.it_interval.tv_usec = 10000;     // 10 ms 
  16. #endif 
  17.     timerv.it_value = timerv.it_interval;
  18.     if (setitimer (ITIMER_REAL, &timerv, &old_timer) == -1) {
  19.         TIMER_LOG_SYS ("setitimer call failed!/n");
  20.         return FALSE;
  21.     }
  22.     return TRUE;
  23. }
这里将时钟的时间间隔设置为10ms。也就是每10ms会向系统发送一次信号SIGALRM。这个信号的处理函数是__mg_timer_action(),通过sigaction (SIGALRM, &siga, NULL);和siga.sa_handler = (void(*)(int))__mg_timer_action;这两行设定。到此,系统时钟已经初始化好了。
 
2 、创建定时器
 
minigui定时器的创建由函数SetTimer (HWND hWnd, int id, unsigned int speed)完成,这个函数主要初始化一个TIMER数据结构,然后向桌面线程发送添加时钟的消息并传递这个定时器数据结构。
 
src/include/timer.h  line 28-34 

  1. typedef struct _timer {
  2.     HWND    hWnd;
  3.     int     id;
  4.     unsigned int speed;
  5.     unsigned int count;
  6. }TIMER;
  7. typedef TIMER* PTIMER;
 
src/kernel/timer.c  line 537-546


  1. BOOL GUIAPI SetTimer (HWND hWnd, int id, unsigned int speed)
  2. {
  3.     TIMER timer;
  4.     timer.hWnd = hWnd;
  5.     timer.id = id;
  6.     timer.speed = speed;
  7.     return SendMessage (HWND_DESKTOP, MSG_ADDTIMER, 0, (LPARAM)&timer);
  8. }
桌面线程是在初始化时创建的,这个线程执行函数DesktopMain().

 
src/kernel/desktop.c line 144-197

 


  1. void* DesktopMain(void* data)
  2. {
  3.     MSG Msg;
  4.     /* init message queue of desktop thread */
  5.     if ( !(__mg_dsk_threadinfo = InitThreadInfo()) ) {
  6.         fprintf (stderr, "DESKTOP: Init Thread Info error!/n");
  7.         return NULL;
  8.     }
  9.     __mg_dsk_msgs = __mg_dsk_threadinfo->pMsgQueue;
  10.     __mg_desktop = __mg_dsk_threadinfo->th;
  11.     /* init desktop window */
  12.     if (!initDesktopWindow()) return NULL;
  13.     __mg_dsk_threadinfo->pMainWin = __mg_dsk_win;
  14.     DesktopWinProc (HWND_DESKTOP, MSG_STARTSESSION, 0, 0);
  15.     PostMessage (HWND_DESKTOP, MSG_ERASEDESKTOP, 0, 0);
  16.     /* desktop thread is ready now */
  17.     sem_post ((sem_t*)data);
  18.     /* process messages of desktop thread */
  19.     while (GetMessage(&Msg, HWND_DESKTOP)) {
  20.         int iRet = 0; 
  21. #ifdef _TRACE_MSG 
  22.         fprintf (stderr, "Message, %s: hWnd: %#x, wP: %#x, lP: %#lx. %s/n",
  23.             Message2Str (Msg.message),
  24.             Msg.hwnd,
  25.             Msg.wParam,
  26.             Msg.lParam,
  27.             Msg.pAdd?"Sync":"Normal"); 
  28. #endif 
  29.         iRet = DesktopWinProc(HWND_DESKTOP, Msg.message, Msg.wParam, Msg.lParam);
  30.         if (Msg.pAdd) // this is a sync message. 
  31.         {
  32.             PSYNCMSG pSyncMsg = (PSYNCMSG)(Msg.pAdd);
  33.             pSyncMsg->retval = iRet;
  34.             sem_post(&pSyncMsg->sem_handle);
  35.         } 
  36. #ifdef _TRACE_MSG 
  37.         fprintf (stderr, "Message, %s done, return value: %#x/n",
  38.             Message2Str (Msg.message), iRet); 
  39. #endif 
  40.     }
  41.     freeDesktopWindow ();
  42.     FreeThreadInfo (__mg_dsk_threadinfo);
  43.     return NULL;
  44. }
 这个线程中有一个消息循环(line 167-192)会获得添加定时器的消息MSG_ADDTIMER,并调用其回调函数进行处理,
 
src/kernel/desktop-comm.c line 3104-3117


  1.         case MSG_ADDTIMER: 
  2. #ifdef _LITE_VERSION 
  3. #ifdef _STAND_ALONE 
  4.             if (sg_old_counter == 0)
  5.                 sg_old_counter = __mg_timer_counter; 
  6. #else 
  7.             if (sg_old_counter == 0)
  8.                 sg_old_counter = SHAREDRES_TIMER_COUNTER; 
  9. #endif 
  10. #endif 
  11.             return AddTimer (((PTIMER)lParam)->hWnd,
  12.                       ((PTIMER)lParam)->id,
  13.                       ((PTIMER)lParam)->speed);
  14.         break;
在处理消息MSG_ADDTIMER时,主要是调用函数AddTimer(),在定时器结构数组timerstr[]中添加一个定时器结构。

 
src/kernel/timer.c line 311-386 

  1. BOOL AddTimer (HWND hWnd, int id, unsigned int speed)
  2. #if 0 
  3.     sigset_t sa_mask; 
  4. #endif 
  5.     int i;
  6.     PMAINWIN pWin;
  7.     PMSGQUEUE pMsgQueue;
  8.     int slot;
  9.     if (!(pWin = GetMainWindowPtrOfControl (hWnd))) return FALSE; 
  10. #if 0 
  11.     // block SIGALRM temporarily 
  12.     sigemptyset (&sa_mask);
  13.     sigaddset (&sa_mask, SIGALRM);
  14.     pthread_sigmask (SIG_BLOCK, &sa_mask, NULL); 
  15. #endif 
  16.     pMsgQueue = pWin->pMessages;
  17.     // Is there a empty timer slot? 
  18.     for (slot=0; slot<DEF_NR_TIMERS; slot++) {
  19.         if ((pMsgQueue->TimerMask >> slot) & 0x01)
  20.             break;
  21.     }
  22.     if (slot == DEF_NR_TIMERS) goto badret;
  23.     for (i=0; i<MAX_TIMERS; i++)
  24.         if (timerstr[i] != NULL)
  25.             if (timerstr[i]->hWnd == hWnd && timerstr[i]->id == id)
  26.                 goto badret;
  27.     for (i=0; i<MAX_TIMERS; i++)
  28.         if (timerstr[i] == NULL)
  29.             break;
  30.     if (i == MAX_TIMERS)
  31.         goto badret ;
  32.     timerstr[i] = malloc (sizeof (TIMER)); 
  33. #if _TIMER_UNIT_10MS 
  34.     timerstr[i]->speed = speed; 
  35. #else 
  36.     timerstr[i]->speed = (1000<<7)/speed; 
  37. #endif 
  38.     timerstr[i]->hWnd = hWnd;
  39.     timerstr[i]->id = id;
  40.     timerstr[i]->count = 0;
  41.     pMsgQueue->TimerOwner[slot] = hWnd;
  42.     pMsgQueue->TimerID[slot] = id;
  43.     pMsgQueue->TimerMask &= ~(0x01 << slot); 
  44. #if 0 
  45.     // unblock SIGALRM 
  46.     pthread_sigmask (SIG_UNBLOCK, &sa_mask, NULL); 
  47. #endif 
  48. #if defined(_LITE_VERSION) && !defined(_STAND_ALONE) 
  49.     if (!mgIsServer)
  50.         set_select_timeout (USEC_10MS * speed); 
  51. #endif 
  52.     return TRUE;
  53.     
  54. badret: 
  55. #if 0 
  56.     // unblock SIGALRM 
  57.     pthread_sigmask (SIG_UNBLOCK, &sa_mask, NULL); 
  58. #endif 
  59.     return FALSE;
  60. }
 
3 、定时器消息的传递 

 
前面在时钟初始化的最后提到,SIGALRM信号的处理函数是__mg_timer_action。现在看看这个函数都做了哪些事情
 
src/kernel/timer.c line 75-93 
  1. static void __mg_timer_action (void *data)
  2. #if defined(_LITE_VERSION) && !defined(_STAND_ALONE) 
  3.     SHAREDRES_TIMER_COUNTER += 1; 
  4. #else 
  5. #if defined(__uClinux__) && defined(_STAND_ALONE) 
  6.     __mg_timer_counter += 10; 
  7. #else 
  8.     __mg_timer_counter ++; 
  9. #endif 
  10. #endif 
  11. #ifndef _LITE_VERSION 
  12.     // alert desktop 
  13.     AlertDesktopTimerEvent (); 
  14. #endif 
  15. }


首先将__mg_timer_counter加1,然后调用AlertDesktopTimerEvent()通知桌面线程过去了一个时钟间隔,
 
src/kernel/message.c line 195-199


  1. void AlertDesktopTimerEvent (void)
  2. {
  3.     __mg_dsk_msgs->dwState |= 0x01;
  4.     POST_MSGQ(__mg_dsk_msgs); 
  5. }
 
注意这里通过 __mg_dsk_msgs->dwState |= 0x01; 标识消息队列中有了一个定时器消息。在桌面线程的消息循环中会检测这个标记
 
src/kernel/message.c line 571-586 
  1. if (pMsgQueue->dwState & QS_TIMER && IS_MSG_WANTED(MSG_TIMER)) { 
  2. #ifndef _LITE_VERSION 
  3.         if (hWnd == HWND_DESKTOP) {
  4.             pMsg->hwnd = hWnd;
  5.             pMsg->message = MSG_TIMER;
  6.             pMsg->wParam = 0;
  7.             pMsg->lParam = 0;
  8.             SET_PADD (NULL);
  9.             if (uRemoveMsg == PM_REMOVE) {
  10.                 pMsgQueue->dwState &= ~0x01;
  11.             }
  12.             UNLOCK_MSGQ (pMsgQueue);
  13.             return 1;
  14.         } 
  15. #endif 
  16.        ……
 
可以看到,这段代码的开头就对状态标志进行检测,QS_TIMR这window.h中定义
 
include/window.h line 1667 
  1. #define QS_TIMER    0x0000FFFF

这样就可以检测到AlertDesktopTimerEvent函数中设置的标志位。然后将这个消息放到一个消息数据结构中,发送给相应的消息处理函数。桌面线程的消息处理函数是DesktopWinProc,在desktop-comm.c文件中定义
 
src/kernel/desktop.c line 3243-3248 
  1.             DispatchTimerMessage (1);
  2.             if (__mg_timer_counter % 10 != 0)
  3.                 break;
  4.             uCounter += 100;
  
这段代码就是处理MSG_TIMER消息的,它调用了函数DispatchTimerMessage(),
 
src/kernel/timer.c line 273-309 

  1. void DispatchTimerMessage (unsigned int inter)
  2. {
  3.     PMAINWIN pWin;
  4.     PMSGQUEUE pMsgQueue;
  5.     int i, slot;
  6.     for ( i=0; i<MAX_TIMERS; i++ ) {
  7.         if ( timerstr[i] ) { 
  8. #if _TIMER_UNIT_10MS 
  9.             timerstr[i]->count += inter; 
  10. #else 
  11.             timerstr[i]->count += 1<<7; 
  12. #endif 
  13.             if ( timerstr[i]->count >= timerstr[i]->speed ) {
  14.                 pWin = GetMainWindowPtrOfControl (timerstr[i]->hWnd);
  15.                 if (pWin == NULL) continue;
  16.                 pMsgQueue = pWin->pMessages;
  17.                 LOCK_MSGQ (pMsgQueue);
  18.                 /* optimization: save slot in timerstr[i] */
  19.                 for (slot=0; slot<DEF_NR_TIMERS; slot++) {
  20.                     if (pMsgQueue->TimerID[slot] == timerstr[i]->id
  21.                         && pMsgQueue->TimerOwner[slot] == timerstr[i]->hWnd)
  22.                         break;
  23.                 }
  24.                 if (slot != DEF_NR_TIMERS) {
  25.                     SetMsgQueueTimerFlag (pMsgQueue, slot);
  26.                 }
  27.                 UNLOCK_MSGQ (pMsgQueue);
  28.                 
  29.                 timerstr[i]->count -= timerstr[i]->speed;
  30.             }
  31.         }
  32.     }
  33. }
 
在创建定时器(SetTimer (HWND hWnd, int id, unsigned int speed))时,传递的参数speed就是这个定时的长度有多少个时钟时间间隔,每个时间间隔是10ms。这个在初始化时钟时设置好的。在上的函数中先将时钟间隔计数的值加上传递进来的时间间隔数(line 282).然后与对应的speed进行比较,如果达到或超过这个间隔数就在对应的窗口消息队列标记中添加标记(line 301). 
  

在创建定时器(SetTimer (HWND hWnd, int id, unsigned int speed))时,传递的参数hWnd就是想要获得定时器消息的那个窗口,在把定时器消息放到这个窗口的消息队列后,就可以由它的消息循环获得定时器消息MSG_TIMER了。注意,MSG_TIMER对应的wParam是定时器的id。如果同时有几个定时器发送MSG_TIMER消息,通过这个id可判断来自哪个定时器,以便做出相应处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值