clutter中的GSource

轉載時請註明出處和作者聯繫方式
文章出處:
http://blog.csdn.net/jack0106 
作者聯繫方式:馮牮 
[email protected]

 

clutter是一個GUI庫,使用opengl作爲底層的繪圖引擎。整個庫使用c語言開發,基於glib和gobject對象系統。通常情況,main函數的形式如下:

 

 

熟悉gtk的朋友可以看出,main函數中的這種代碼結構,和gtk程序中的main函數結構很類似,這是因爲clutter和gtk中的主事件循環,都是基於GMainLoop以及GSource,而且他們的設計上,本身就有某種相似性。

 

最近把clutter-0.2,clutter-0.4和clutter-1.0版本的源代碼翻出來看了看,主要是看其中事件循環這一部分的代碼,學習一下其中的代碼實現方法。

 

gui程序,從原理上來說,就是接收用戶的輸入(比如鍵盤輸入,鼠標輸入等),然後針對這些不同的輸入事件,做出不同的處理。在GMainLoop這個框架中,就需要繼承GSource,並且重新實現prepare/check/dispatch這三個虛函數,然後把這個子類GSource添加到主事件循環中。clutter-0.2的代碼量最小,所以以此作爲分析學習的切入點。下面是從clutter-0.2中取出的代碼片段,我們重點看一下clutter中實現的一個GSource子類--ClutterXEventSource

 

 

這個版本的clutter,是運行在X11環境上的。Xserver管理了所有的輸入設備,將所有的輸入事件轉換成Xevent,然後分發給對應的Xclient。Xclietn和Xserver之間,則是通過一個socket進行協議通信。所以ClutterXEventSource中,定義了一個GPollFD  event_poll_fd,這個變量中,保存的就是cultter和Xserver建立的socket連接的文件描述符。

 

prepare/check/dispatch這三個函數的代碼,也比較簡單,原理上看,就是等待XServer發送過來的用戶輸入事件,然後就進入dispatch函數,在dispatch函數,獲取Xserver發送過來的XEvent,緊接着就調用clutter_dispatch_x_event()。

 

到這一步爲止,用戶通過鍵盤或鼠標的輸入,就已經傳遞到了clutter內部,ClutterXEventSource的工作,就算是完成了。剩下的操作,是clutter對這個XEvent的轉換(數據類型轉換等等),以及在內部的分發,傳遞和處理(將event分發到對應的ClutterActor,然後對應的ClutterActor處理這個event),這個分發過程的細節,不在此次的討論範圍內。當分發和處理結束後,就將進入GMainLoop的下一次循環調度,當用戶再次輸入的時候,dispatch函數,將被再次調用。這樣的話,整個GUI圖形環境就運行起來了,ClutterXEventSource接收用戶的輸入,然後clutter處理這個輸入事件,使用opengl重新繪製圖形,然後這一次事件處理結束,clutter等待下一次用戶輸入。

 

clutter這個庫的一個優勢,就是可以方便的製作出動畫效果。動畫的原理,就是在固定的時間間隔上,重新繪製視圖,只要這個時間間隔選取的合適,就可以產生動畫效果。要在GMainLoop中實現動畫,就需要用到另外一個GSource的子類--GTimeoutSource(GTimeoutSource是一個內部對象,作爲使用者,我們只需要使用g_timeout_*這一簇函數就行了),設置好合適的時間間隔後,類似的,在GTimeoutSource的dispatch函數中,調用clutter的繪圖引擎重新渲染視圖,就可以產生動畫的效果。

 

clutter中事件循環的基本原理就是這樣,因爲參考的是clutter-0.2版本的代碼,代碼量比較小,所以分析起來也比較容易。熟悉了這個版本的代碼後,就可以看更高版本的代碼實現細節了,我選的是0.4和1.0版本的源代碼,看完這兩版代碼後發現,從0.4版本開始,event相關的代碼部分,就已經成型並且基本穩定,考慮到1.0纔是clutter的正式版,因此選取clutter-1.0來進行說明。

 

clutter-0.2只能運行在X11環境中,因此在構造ClutterXEventSource的時候,代碼沒有設計更多的層次,在初始化代碼中,直接就初始化了ClutterXEventSource。到了clutter-1.0中,採用面向對象思想進行了更好的設計,並且匹配了多種後端,包括X11/win32/sdl/egl等等。在clutter的初始化階段,直接調用後端的初始化代碼,然後再由每個後端各自初始化自己的事件循環。因此,在clutter中定義了一個純虛類,ClutterBackend,這個純虛類有如下的一系列函數接口,不同的後端,只要繼承這個ClutterBackend並且實現如下的函數就可以了。

 

 

ClutterBackendX11結構體,就是ClutterBackend的一個子類,clutter_backend_x11_init_events函數,就是這個子類重新實現的init_events虛函數。

 

ClutterEventSource以及它的prepare/check/dispatch這3個函數,和clutter-0.2版本中的區別不大,結構都是一致的,clutter_event_dispatch函數,是用戶輸入事件對應的代碼的入口點,在這個函數中,clutter獲取Xevent,然後轉換event並且分發處理,事件處理結束後,函數返回,進入poll下一次循環調度。

 

需要特別說明的一點是,從結構上來看,由於事件循環的初始化,是包含在後端的初始化過程中的,所以ClutterEventSource可以設計成ClutterBackendX11的一個成員變量,ClutterBackendX11中的event_source指針,就是指向這個成員變量。但是,從代碼中可以看到,在ClutterEventSource中,也有一個指針backend,指向包含該source的ClutterBackend,這是因爲clutter_event_dispatch這個函數的第一個參數是GSource,在dispatch函數中,如果要使用backend,就只能通過ClutterEventSource->backend這個指針來獲取。

 

寫到這裏,還想起一件事,順便一起記錄下來,clutter整體的框架,和qt中的Graphics View Framework很類似。clutter中的ClutterStage,相當於qt中的QGraphicsScene,clutter中的ClutterActor,相當於qt中的QGraphicsItem。這兩套框架的接口設計,差不多都是一樣的,如果熟悉其中的一套框架,那麼另外一套框架上手起來也是比較容易的。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章