SlideShare una empresa de Scribd logo
1 de 22
Descargar para leer sin conexión
頁首在這裡




               大家來學GObject
Revision 2
傅書煜 (shuyufu at gmail.com)




頁尾在這裡
頁首在這裡
 為什麼會有這份文件?
 GObject是什麼?
   學會GObject有什麼用?
   哪裡取得/         GObject?
 學習GObject前必需俱備的知識
   結構(Struct)
   指標(Pointer)
   函式指標(Function Pointer)
   在沒有GObject的情況下
 GObject基礎課程
        GObject
   公有實體結構變數和私有實體結構變數
   存取資料成員
   公有成員函式和私有成員函式,(純)虛擬函式和預設實作
   存取父類別結構
   抽象類別
   介面
 GObject進階課程
   類別的建構與解構
   訊號
          GObject
 什麼是沒有在這份文件提到的
   vtable
   Closure
 工具
   glib-genmarshal
   GObject Generator
 參考資料




頁尾在這裡
頁首在這裡



為什麼會有這份文件?
基於工作上的需要,我必需瞭解如何使用GObject,在學習的過程中,我發現正體中文資料較少[1],簡中倒有一
些.在對GObject有一些瞭解後,我覺得GObject是不錯的框架,所以,我決定要寫一份正體中文的教學文件,
讓更多人瞭解它。文件內容主要是來自於[2]再加上個人經驗撰寫,如果有錯誤或建議請告訴我以進行修正。




頁尾在這裡
頁首在這裡




GObject是什麼?
GObject是開源專案GLib中的一部份,它用C語言實作出物件導向的框架。這份文件是基於GObject Reference
Manual 2.26.1[2]製作的,你可以在[2]觀看線上版或下載在本機上瀏覽。


學會GObject有什麼用?
有許多開源專案是基於GObject開發的,例如:GIO、GTK+、GStreamer等。學會GObject後再看這些開源專
案的源碼或進行開發會更容易。同時也有輔助性的函式庫,比如json-glib[3],它可以將一個GObject序列化成
JSON的格式.


哪裡取得/安裝GObject?
你可以到GTK+的網站下載到你想要GLib的源碼。




頁尾在這裡
頁首在這裡




學習GObject前必需俱備的知識
我們假設讀者對C語言有一定程度的瞭解,如果你對C語言不熟的話,請務必先複習以下主題。


結構(Struct)
結構是變數的集合體,可以放置許多的變數。


指標(Pointer)
指標是一個變數,和一般變數不一樣的是它所儲存的是一個位址。


函式指標(Function Pointer)
一般指標所指向的位址是資料,而函式指標所指向的位址則是函式。


在沒有GObject的情況下
先開始看GObject之前,試想如果要你用C語言實作類別,你會怎麼實做資料成員(Data Member)和成員函式
(Member Function)?




頁尾在這裡
頁首在這裡




GObject基礎課程
在基礎課程裡,我們將藉由實作一個簡單的GObject來介紹我們在類別裡常用的物件變數、類別變數和(abstract)
method如何宣告和定義。


第一個GObject
我們先來實作一個最簡單的GObject吧!
  1.    /* maman-bar.h */
  2.    #ifndef __MAMAN_BAR_H__
  3.    #define __MAMAN_BAR_H__
  4.
  5.    #include <glib-object.h>
  6.
  7.    G_BEGIN_DECLS
  8.
  9.    #define   MAMAN_TYPE_BAR              (maman_bar_get_type ())
  10.   #define   MAMAN_BAR(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar))
  11.   #define   MAMAN_BAR_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass))
  12.   #define   MAMAN_IS_BAR(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR))
  13.   #define   MAMAN_IS_BAR_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR))
  14.   #define   MAMAN_BAR_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR, MamanBarClass))
  15.
  16.   typedef struct _MamanBar      MamanBar;
  17.   typedef struct _MamanBarClass MamanBarClass;
  18.
  19.   struct _MamanBar {
  20.      GObject parent_instance;
  21.      /* instance members */
  22.   };
  23.
  24.   struct _MamanBarClass {
  25.      GObjectClass parent_class;
  26.      /* class members */
  27.   };
  28.
  29.   GType maman_bar_get_type (void);
  30.   MamanBar * maman_bar_new (void);
  31.
  32.   G_END_DECLS
  33.
  34.   #endif /* __MAMAN_BAR_H__ */
  35.
  36.   /* maman-bar.c */
  37.   #include “maman-bar.h”
  38.
  39.   /* will create maman_bar_get_type and set maman_bar_parent_class */
  40.   G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT);
  41.
  42.   static void maman_bar_class_init (MamanBarClass *klass) {
  43.     GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  44.   }
  45.
  46.   static void maman_bar_init (MamanBar *self) {
  47.     /* initialize the object */
  48.   }
  49.
  50.   MamanBar * maman_bar_new (void) {
  51.     return MAMAN_BAR (g_object_new (MAMAN_TYPE_BAR, NULL));
  52.   }



這是一個僅實作出最基本架構的GObject。在GObject裡,實體結構(_MamanBar;第19~22行)和類別結構
(_MamanBarClass;第24~27行)是分開宣告的。實體結構是每產生一個實體就有一份,而類別結構則是被
所有實體共享.這邊要注意的是實體(類別)結構裡的第一個變數必須是父類別的實體(類別)結構(第20、

頁尾在這裡
頁首在這裡
25行),接下來才是自己想宣告的變數。
glib-object.h是每個GObject都必需include的標頭標(第5行),而一開始的巨集是用來取得類別ID(第9行)、
替實體(類別)結構轉型(第10~11行)、檢查指標所指的位置是否為某個類別的實體結構(第12行)或類別
結構(第13行),和從實體結構取得對應的類別結構(第14行).這些巨集我們會在之後的例子看到它們的用
處.
G_DEFINE_TYPE是一個幫助我們快速定義一個GObject的巨集(第70行),第一個參數是將類別名稱以
Camel case的方式帶入,第二個參數是將類別名稱以小寫並以底線符號做區隔帶入,第三個則是父類別的類
別ID.我們將巨集展開後會發現其中定義一個指向父類別結構的指標和定義取得ID的函式,也就是第29行的
maman_bar_get_type,這也是為什麼我們僅在標頭檔宣告而沒實作卻又可以呼叫的原因.在取得ID的函式中會
自動引用以第二個參考為前置符號並以_class_init和_init的兩個函式._class_init是類別結構的初始化函式只有
在產生第一個實體之前會被呼叫,而_init則是實體初始化函式,因為每產生一個實體都會呼叫一次.
慣例上,為了方便產生GObject,還會提供一個產生GObject的函式(第30行宣告,第50~52行實作).因此第
51行是在產生一個MamanBar的實體,但,g_object_new回傳的型態為gpointer,所以使用MAMAN_BAR巨集
將指標的型別轉為MamanBar*.最後,我們該怎麼操作MamanBar這個GObject呢?


     1. #include “maman-bar.h”
     2.
     3. int main (void) {
     4.    MamanBar *bar = NULL;
     5.    MamanBarClass *bar_class = NULL;
     6.    g_type_init ();
     7.    bar = maman_bar_new ();
     8.    bar_class = MAMAN_BAR_GET_CLASS (bar);
     9.    g_object_unref (bar);
     10.   return 0;
     11. }




第6行的g_type_init ()是使用任何一個GObject前都必需呼叫的函式,否則會產生錯誤.GObject使用參
考計數[?]作為記憶體管理策略,換句話說,不會有malloc或free這類的函式,取而代之的是g_object_ref和
g_object_unref.當第7行剛透過maman_bar_new產生實體結構時,參考計數為1(事實上是g_object_new產生
實體時會將參考計數設為1),最後main函式結束前用g_object_unref把參考計劃減1,歸零後GObject會自行解
構/回收記憶體.


公有實體結構變數和私有實體結構變數
要宣告公有資料成員很簡單,只要在實體結構內宣告即可.而私有則較為麻煩,有兩種做法,第一種是道德性
的勸說,在宣告實體結構時一併加上註解,告訴使用的人不應該存取這些變數.另一種則是真正的隱藏.以下
列出程式碼,並將新增的部份加上紅色.


     1.    /* maman-bar.h */
     2.    #ifndef __MAMAN_BAR_H__
     3.    #define __MAMAN_BAR_H__
     4.
     5.    #include <glib-object.h>
     6.
     7.    G_BEGIN_DECLS
     8.
     9.    #define MAMAN_TYPE_BAR         (maman_bar_get_type ())
     10.   #define MAMAN_BAR(obj)         (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar))


頁尾在這裡
頁首在這裡
  11.   #define   MAMAN_BAR_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass))
  12.   #define   MAMAN_IS_BAR(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR))
  13.   #define   MAMAN_IS_BAR_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR))
  14.   #define   MAMAN_BAR_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR, MamanBarClass))
  15.
  16.   typedef struct _MamanBar      MamanBar;
  17.   typedef struct _MamanBarClass MamanBarClass;
  18.   typedef struct _MamanBarPrivate MamanBarPrivate;
  19.
  20.   struct _MamanBar {
  21.      GObject parent_instance;
  22.      /* instance members */
  23.      gint public_count;
  24.      /*< private >*/
  25.      gint private_count;
  26.      /*< private >*/
  27.      MamanBarPrivate *priv;
  28.   };
  29.
  30.   struct _MamanBarClass {
  31.      GObjectClass parent_class;
  32.      /* class members */
  33.   };
  34.
  35.   GType maman_bar_get_type (void);
  36.   MamanBar * maman_bar_new (void);
  37.
  38.   G_END_DECLS
  39.
  40.   #endif /* __MAMAN_BAR_H__ */
  41.
  42.   /* maman-bar.c */
  43.   #include “maman-bar.h”
  44.
  45.   /* will create maman_bar_get_type and set maman_bar_parent_class */
  46.   G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT);
  47.
  48.   #define MAMAN_BAR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MAMAN_TYPE_BAR,
        MamanBarPrivate))
  49.
  50.   struct _MamanBarPrivate {
  51.      gint a;
  52.      gint b;
  53.   };
  54.
  55.   static void maman_bar_class_init (MamanBarClass *klass) {
  56.     GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  57.     g_type_class_add_private (klass, sizeof (MamanBarPrivate));
  58.   }
  59.
  60.   static void maman_bar_init (MamanBar *self) {
  61.     /* initialize the object */
  62.     self->priv = MAMAN_BAR_GET_PRIVATE (self);
  63.   }
  64.
  65.   MamanBar * maman_bar_new (void) {
  66.     return MAMAN_BAR (g_object_new (MAMAN_TYPE_BAR, NULL));
  67.   }



第23行的public_count就是屬於公有實體結構變數,而第25行的private_count則是勸說型的私有實體結構變數,
所以我們在第24行加上註解/*< private >*/告訴使用的人不應該存取這些變數,這兩種實體結構變數只要使用
MamanBar的人include標頭檔就很清楚struct的宣告時的內容,都無法防止外部直接存取.而確實隱藏的方法是
在.c檔內宣告私有結構(第50~53行)並在maman_bar_class_init時將私有結構加入類別裡(第57行),之後要
存取時則是透過第48行宣告的巨集將私有結構的位置取出來,像第66行做的事.這邊要注意的是,在實體結構
內不一定要有一個指標指向私有結構(第27行)的位置,這例子中只是為了示範(其實也可以做為快取,之後
就不用再透過巨集取得位置),所以在實體結構內宣告了一個私有結構的指標.


存取資料成員

頁尾在這裡
頁首在這裡
當有了結構變數後接下來就是如何存取它們?當然,最簡單的就是直接用->的方式存取,不過,這不僅有違封
裝性,也不是我們要講的方法.我們要介紹的是如何利用GObject提供的介面替一個GObject安裝(install)屬性
(property)並使用特定的函式存取它們.但,為什麼要這麼麻煩?直接用->就好了啊.事實上,GObject對屬性的
存取可以提供一定的規範,以及當搭配其它以GObject為基礎的函式庫時就會明顯感受到它的作用,不需要額外
寫code就可以發揮作用.如json-glib可以將一個GObject序列化為JSON格式,但,它僅能作用在安裝好的屬性
上.


     1.    /* maman-bar.h */
     2.    #ifndef __MAMAN_BAR_H__
     3.    #define __MAMAN_BAR_H__
     4.
     5.    #include <glib-object.h>
     6.
     7.    G_BEGIN_DECLS
     8.
     9.    #define   MAMAN_TYPE_BAR              (maman_bar_get_type ())
     10.   #define   MAMAN_BAR(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar))
     11.   #define   MAMAN_BAR_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass))
     12.   #define   MAMAN_IS_BAR(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR))
     13.   #define   MAMAN_IS_BAR_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR))
     14.   #define   MAMAN_BAR_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR, MamanBarClass))
     15.
     16.   typedef struct _MamanBar      MamanBar;
     17.   typedef struct _MamanBarClass MamanBarClass;
     18.   typedef struct _MamanBarPrivate MamanBarPrivate;
     19.
     20.   struct _MamanBar {
     21.      GObject parent_instance;
     22.      /* instance members */
     23.      gint public_count;
     24.      /*< private >*/
     25.      gint private_count;
     26.      /*< private >*/
     27.      MamanBarPrivate *priv;
     28.   };
     29.
     30.   struct _MamanBarClass {
     31.      GObjectClass parent_class;
     32.      /* class members */
     33.   };
     34.
     35.   GType maman_bar_get_type (void);
     36.   MamanBar * maman_bar_new (void);
     37.
     38.   G_END_DECLS
     39.
     40.   #endif /* __MAMAN_BAR_H__ */
     41.
     42.   /* maman-bar.c */
     43.   #include “maman-bar.h”
     44.
     45.   /* will create maman_bar_get_type and set maman_bar_parent_class */
     46.   G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT);
     47.
     48.   #define MAMAN_BAR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MAMAN_TYPE_BAR,
           MamanBarPrivate))
     49.
     50.   #define DEFAULT_PRIV_COUNT 0
     51.
     52.   struct _MamanBarPrivate {
     53.      gint a;
     54.      gint b;
     55.   };
     56.
     57.   static void maman_bar_get_property (GObject *object, guint property_id, GValue *value, GParamSpec
           *pspec) {
     58.     MamanBar *bar = MAMAN_BAR (object);
     59.     switch (property_id) {
     60.       case PROP_PRIV_COUNT:
     61.         g_value_set_int (value, bar->private_count);
     62.         break;
     63.       default:
     64.         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);


頁尾在這裡
頁首在這裡
   65.   }
   66. }
   67.
   68. static void maman_bar_set_property (GObject *object, guint property_id, const GValue *value,
       GParamSpec *pspec) {
   69.   MamanBar *bar = MAMAN_BAR (object);
   70.   switch (property_id) {
   71.      case PROP_PRIV_COUNT:
   72.        bar->private_count = g_value_get_int (value);
   73.        break;
   74.      default:
   75.        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
   76.   }
   77. }
   78.
   79. static void maman_bar_class_init (MamanBarClass *klass) {
   80.   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
   81.   gobject_class->get_property = maman_bar_get_property;
   82.   gobject_class->set_property = maman_bar_set_property;
   83.   g_object_class_install_property (
   84.      gobject_class,
   85.      PROP_PRIV_COUNT,
   86.      g_param_spec_int (
   87.        “priv-count”,
   88.        “MamanBar private count prop”,
   89.        “MamanBar’s private count”,
   90.        G_MININT,
   91.        G_MAXINT,
   92.        DEFAULT_PRIV_COUNT,
   93.        G_PARAM_READWRITE
   94.      )
   95.   );
   96.   g_type_class_add_private (klass, sizeof (MamanBarPrivate));
   97. }
   98.
   99. static void maman_bar_init (MamanBar *self) {
   100.           /* initialize the object */
   101.           self->priv = MAMAN_BAR_GET_PRIVATE (self);
   102.         }
   103.
   104.         MamanBar * maman_bar_new (void) {
   105.           return MAMAN_BAR (g_object_new (MAMAN_TYPE_BAR, NULL));
   106.         }



GObject要安裝(install)屬性(property)(第80~93行)之前,必需先覆寫GObjectClass的get_property和
set_property兩個函式指標(第79~80行),否則會發生錯誤.在這例子中我們安裝了priv-count這個屬性
的ID為PROP_PRIV_COUNT,其型別為int,可接受的範圍介於G_MININT和G_MAXINT之間,預設值為
DEFAULT_PRIV_COUNT並且可以READ-WRITE.之後透過GObject所提供的函式存取屬性時就會呼叫
到maman_bar_get_property和maman_bar_set_property並將需要的資訊一併傳入.而在get_property和
set_property兩個函式中只要用switch敘述判斷property_id就可以知道要用什麼函式存取GValue了.
GValue在GObject中扮演一個泛型(generic)的容器(contaier),當承載的資料為原始資料型態,我們不需要特別
做什麼,但,當承載的資料為自訂的型別時,就需要提供一些函式了[???],GValue我們會在[???]做一次介紹,
目前僅需要知道GValue是一個泛型的容器就好.
最後,我們來看要怎麼存取MamanBar的屬性.


   1. #include "maman-bar.h"
   2.
   3. int main (void) {
   4.   MamanBar *bar = NULL;
   5.   MamanBarClass *bar_class = NULL;
   6.   gint count = 0;
   7.   GValue val = {0, };
   8.
   9.   g_type_init ();
   10.
   11.  bar = maman_bar_new ();
   12.
   13.  g_value_init (&val, G_TYPE_INT);

頁尾在這裡
頁首在這裡
   14.     g_value_set_int (&val, count);
   15.
   16.     g_object_set_property (G_OBJECT (bar), “priv-count”, &val);
   17.     g_object_get_property (G_OBJECT (bar), “priv_count”, &val);
   18.     count = g_value_get_int (&val);
   19.
   20.     g_object_set (G_OBJECT (bar), “priv_count”, count, NULL);
   21.     g_object_get (G_OBJECT (bar), “priv-count”, &count, NULL);
   22.
   23.     g_object_unref (bar);
   24.
   25.     return 0;
   26. }



我們可以透過g_object_set_property和g_object_get_property一次存取一個屬性(第16~17行),或者
透過g_object_set和g_object_get一次存取多個屬性(第20~21行).當使用g_object_set_property和
g_object_get_property,必需以GValue作為媒介將值封裝起來或從其中將值取出.而g_object_set和
g_object_get則不然,直接將要存取的屬性名和儲存位置以一對的方式傳入,並允許多對,最後以NULL結束,
也可以達到同樣的效果.


公有成員函式和私有成員函式,(純)虛擬函式和預設實作
成員函式的作法是在類別結構內宣告函式指標,然後在_class_init裡覆寫函式指標.而公有/私有成員函式兩者
在GObject實作上很像,只差在於能不能直接呼叫到而已,事實上,在其它的OO實作上,不也是這樣嗎?


   1.    /* maman-bar.h */
   2.    #ifndef __MAMAN_BAR_H__
   3.    #define __MAMAN_BAR_H__
   4.
   5.    #include <glib-object.h>
   6.
   7.    G_BEGIN_DECLS
   8.
   9.    #define   MAMAN_TYPE_BAR              (maman_bar_get_type ())
   10.   #define   MAMAN_BAR(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar))
   11.   #define   MAMAN_BAR_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass))
   12.   #define   MAMAN_IS_BAR(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR))
   13.   #define   MAMAN_IS_BAR_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR))
   14.   #define   MAMAN_BAR_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR, MamanBarClass))
   15.
   16.   typedef struct _MamanBar      MamanBar;
   17.   typedef struct _MamanBarClass MamanBarClass;
   18.   typedef struct _MamanBarPrivate MamanBarPrivate;
   19.
   20.   struct _MamanBar {
   21.      GObject parent_instance;
   22.      /* instance members */
   23.      gint public_count;
   24.      /*< private >*/
   25.      gint private_count;
   26.      /*< private >*/
   27.      MamanBarPrivate *priv;
   28.   };
   29.
   30.   struct _MamanBarClass {
   31.      GObjectClass parent_class;
   32.      /* class members */
   33.      void (*public_func) (MamanBar *);
   34.      void (*priv_func) (MamanBar *);
   35.   };
   36.
   37.   GType maman_bar_get_type (void);
   38.   MamanBar * maman_bar_new (void);
   39.   void maman_bar_public_func (MamanBar *self);
   40.   void maman_bar_other_func (MamanBar *self);
   41.
   42.   G_END_DECLS
   43.


頁尾在這裡
頁首在這裡
  44.   #endif /* __MAMAN_BAR_H__ */
  45.
  46.   /* maman-bar.c */
  47.   #include “maman-bar.h”
  48.
  49.   /* will create maman_bar_get_type and set maman_bar_parent_class */
  50.   G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT);
  51.
  52.   #define MAMAN_BAR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MAMAN_TYPE_BAR,
        MamanBarPrivate))
  53.
  54.   #define DEFAULT_PRIV_COUNT 0
  55.
  56.   struct _MamanBarPrivate {
  57.      gint a;
  58.      gint b;
  59.   };
  60.
  61.   static void maman_bar_public_func_default (MamanBar *self) {
  62.   }
  63.
  64.   static void maman_bar_priv_func_default (MamanBar *self) {
  65.   }
  66.
  67.   static void maman_bar_get_property (GObject *object, guint property_id, GValue *value, GParamSpec
        *pspec) {
  68.     MamanBar *bar = MAMAN_BAR (object);
  69.     switch (property_id) {
  70.       case PROP_PRIV_COUNT:
  71.         g_value_set_int (value, bar->private_count);
  72.         break;
  73.       default:
  74.         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
  75.     }
  76.   }
  77.
  78. static void maman_bar_set_property (GObject *object, guint property_id, const GValue *value,
      GParamSpec *pspec) {
  79.   MamanBar *bar = MAMAN_BAR (object);
  80.   switch (property_id) {
  81.     case PROP_PRIV_COUNT:
  82.       bar->private_count = g_value_get_int (value);
  83.       break;
  84.     default:
  85.       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
  86.   }
  87. }
  88.
  89. static void maman_bar_class_init (MamanBarClass *klass) {
  90.   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  91.   gobject_class->get_property = maman_bar_get_property;
  92.   gobject_class->set_property = maman_bar_set_property;
  93.   klass->public_func = maman_bar_public_func_default;
  94.   klass->priv_func = maman_bar_priv_func_default;
  95.   g_object_class_install_property (
  96.     gobject_class,
  97.     PROP_PRIV_COUNT,
  98.     g_param_spec_int (
  99.       “priv-count”,
  100.               “MamanBar private count prop”,
  101.               “MamanBar’s private count”,
  102.               G_MININT,
  103.               G_MAXINT,
  104.               DEFAULT_PRIV_COUNT,
  105.               G_PARAM_READWRITE
  106.             )
  107.          );
  108.          g_type_class_add_private (klass, sizeof (MamanBarPrivate));
  109.        }
  110.
  111.        static void maman_bar_init (MamanBar *self) {
  112.          /* initialize the object */
  113.          self->priv = MAMAN_BAR_GET_PRIVATE (self);
  114.        }
  115.
  116.        MamanBar * maman_bar_new (void) {
  117.          return MAMAN_BAR (g_object_new (MAMAN_TYPE_BAR, NULL));
  118.        }
  119.


頁尾在這裡
頁首在這裡
     120.          void maman_bar_public_func (MamanBar *self) {
     121.            g_return_if_fail (MAMAN_IS_BAR (self));
     122.            MAMAN_BAR_GET_CLASS (self)->public_func (self);
     123.          }
     124.
     125.          void maman_bar_other_func (MamanBar *self) {
     126.            g_return_if_fail (MAMAN_IS_BAR (self));
     127.            /* pre-priv-func code here */
     128.            MAMAN_BAR_GET_CLASS (self)->priv_func (self);
     129.            /* post-priv-func code here */
     130.          }



在標題頭裡提供maman_bar_public_func和maman_bar_other_func兩函式(宣告在第39~40行),用以
存取類別結構裡的public_func和priv_func函式指標.在_class_init裡,我們將public_func和priv_func函
式指標分別指向maman_bar_public_func_default和maman_bar_priv_func_default(第93~94行).在
maman_bar_public_func裡(第120~123行),我們僅檢查傳入的指標是否確實指向一個MamanBar的實體,
之後便呼叫類別結構裡的public_func函式指標,這就是公有成員函式.而在maman_bar_other_func裡(第
125~130行),我們除了檢查傳入的指標以外,更在呼叫priv_func這個私有成員的前後加入一些其它的處理邏
輯.


存取父類別結構
存取父類別結構讓我們得以呼叫父類別的成員函式,哪該怎麼實作呢?這並不難,只要將某個類別結構傳入
g_type_class_peek_parent這個函式就會回傳一個父類別結構的指標, 之後就能透過這指標存取父類別結構.
還記得之前提到的G_DEFINE_TYPE嗎?這個巨集幫我們做的其中一件事就是宣告一個父類別結構的變數並指
向父類別結構,而這變數的名字是以第G_DEFINE_TYPE的第二個變數開頭並以_parent_class結尾.


     1. G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT);


在這例子裡,則是maman_bar_parent_class.


抽象類別
有了之前的基礎,要宣告一個抽象類別更是簡單了,只要把G_DEFINE_TYPE換成
G_DEFINE_ABSTRACT_TYPE就可以了.


介面
介面宣告的方式和類別大同小異,差在於介面是繼承自GTypeInterface而不是GObjectClass.


     1.    /* maman-ibaz.h */
     2.    #ifndef __MAMAN_IBAZ_H__
     3.    #define __MAMAN_IBAZ_H__
     4.
     5.    #include <glib-object.h>
     6.
     7.    G_BEGIN_DECLS
     8.
     9.  #define   MAMAN_IBAZ_TYPE                (maman_ibaz_get_type ())
     10. #define   MAMAN_IBAZ(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_IBAZ_TYPE, MamanIbaz)
         )
     11. #define   MAMAN_IS_IBAZ(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_IBAZ_TYPE))
     12. #define   MAMAN_IBAZ_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), MAMAN_IBAZ_TYPE,

頁尾在這裡
頁首在這裡
             MamanIbazInterface))
       13.
       14.   typedef struct _MamanIbaz MamanIbaz; /* dummy object */
       15.   typedef struct _MamanIbazInterface MamanIbazInterface;
       16.
       17.   struct _MamanIbazInterface {
       18.     GTypeInterface parent;
       19.
       20.       void (*do_action) (MamanIbaz *self);
       21.   };
       22.
       23.   GType maman_ibaz_get_type (void);
       24.
       25.   void maman_ibaz_do_action (MamanIbaz *self);
       26.
       27.   G_END_DECLS
       28.
       29.   #endif /* __MAMAN_IBAZ_H__ */
       30.
       31.   /* maman-ibaz.c */
       32.   #include “maman-ibaz.h”
       33.
       34.   G_DEFINE_INTERFACE (MamanIbaz, maman_ibaz, G_TYPE_INVALID)
       35.
       36.   static void maman_ibaz_default_init (MamanIbazInterface *klass)
       37.   {
       38.   }
       39.
       40.   void maman_ibaz_do_action (MamanIbaz *self)
       41.   {
       42.     g_return_if_fail (MAMAN_IS_IBAZ (self));
       43.
       44.       MAMAN_IBAZ_GET_INTERFACE (self)->do_action (self);
       45.   }



jjjj




頁尾在這裡
頁首在這裡




GObject進階課程
在進階課程裡,我們會瞭解GObject建構和解構的順序,和GObject中的訊號.


類別的建構與解構
在[2]裡有兩張表在解釋GObjec和GObject Interfacet的建構和解構.我們這邊簡單的在這邊再出現一次.

GObject的解構和解構

Invocation time                  Function Invoked                    Function's parameters

First call                       type's base_init function           On the inheritance tree of
tog_type_create_instancefor                                          classes from fundamental
target type                                                          type to target type. base_init
                                                                     is invoked once for each class
                                                                     structure.

                                 target type's class_init function   On target type's class structure

                                 interface initialization, see
                                 the section called “Interface
                                 Initialization”

Each call                        target type's instance_init         On object's instance
tog_type_create_instancefor      function
target type

Last call                        interface destruction, see
tog_type_free_instance for       the section called “Interface
target type                      Destruction”

                                 target type's class_finalize        On target type's class structure
                                 function

                                 type's base_finalize function       On the inheritance tree of
                                                                     classes from fundamental type
                                                                     to target type. base_finalize is
                                                                     invoked once for each class
                                                                     structure.


GObject Interface的建構

Invocation time         Function Invoked           Function's parameters     Remark

First call              interface' base_init       On interface' vtable      Register interface'

頁尾在這裡
頁首在這裡
tog_type_create_            function                                                 signals here (use a
instance for type                                                                    local static boolean
implementing interface                                                               variable as described
                                                                                     above to make sure
                                                                                     not to register them
                                                                                     twice.).

                            interface' interface_init    On interface' vtable        Initialize interface'
                            function                                                 implementation.
                                                                                     That is, initialize the
                                                                                     interface method
                                                                                     pointers in the
                                                                                     interface structure
                                                                                     to the function's
                                                                                     implementation.


GObject Interface的解構

Invocation time                        Function Invoked                     Function's parameters

Last call to                           interface' interface_finalize        On interface' vtable
g_type_free_instance for type          function
implementing interface

                                       interface' base_finalize function    On interface' vtable




訊號
在GObject提供了訊號(Signal)這個機制,讓物件操作者可以透過callback函式得知物件狀態改變了,更簡單
的說,訊號是GObject中的觀察者模式(Observer Pattern).

GObject必需在class_init函式裡使用g_signal_new註冊要提供外界觀察的訊號,之後物件操作者才能註冊
callback函式.首先我們在類別結構裡宣告預設的訊號處理函式和一個變數儲存訊號的ID(第27~28行),然後在
class_init函式裡先指定訊號處理函式的位置(第100行)然後再註冊一個訊號(第115~127行),比較特殊的
是,除了訊號處理函式,我們還額外註冊了一個accumulator函式(第120行),緊接著每一次的訊號calback函
式之後accumulator函式就會接著被呼叫一次.


   1.   /* maman-bar.h */
   2.   #ifndef __MAMAN_BAR_H__
   3.   #define __MAMAN_BAR_H__
   4.   #include <glib-object.h>
   5.   G_BEGIN_DECLS
   6.   #define MAMAN_TYPE_BAR             (maman_bar_get_type ())
   7.   #define MAMAN_BAR(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar))
   8.   #define MAMAN_BAR_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass))
   9.   #define MAMAN_IS_BAR(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR))



頁尾在這裡
頁首在這裡
  10.        #define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR))
  11.        #define MAMAN_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR,
     MamanBarClass))
  12.        typedef struct _MamanBar      MamanBar;
  13.        typedef struct _MamanBarClass MamanBarClass;
  14.        typedef struct _MamanBarPrivate MamanBarPrivate;
  15.        struct _MamanBar {
  16.            GObject parent_instance;
  17.            /* instance members */
  18.            gint public_count;
  19.            /*< private >*/
  20.            gint private_count;
  21.            /*< private >*/
  22.            MamanBarPrivate *priv;
  23.        };
  24.        struct _MamanBarClass {
  25.            GObjectClass parent_class;
  26.            /* class members */
  27.             guint my_signal_id;
  28.            gint (*my_signal_handler) (GObject *, gint, gpointer, gpointer);
  29.            void (*public_func) (MamanBar *);
  30.            void (*priv_func) (MamanBar *);
  31.        };
  32.        GType maman_bar_get_type (void);
  33.        MamanBar * maman_bar_new (void);
  34.        void maman_bar_public_func (MamanBar *self);
  35.        void maman_bar_other_func (MamanBar *self);
  36.        G_END_DECLS
  37.        #endif /* __MAMAN_BAR_H__ */
  38.        /* maman-bar.c */
  39.        #include “maman-bar.h”
  40.        #include “mamanmarshal.h”
  41.
  42.        /* will create maman_bar_get_type and set maman_bar_parent_class */
  43.        G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT);
  44.        #define MAMAN_BAR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MAMAN_TYPE_BAR,
     MamanBarPrivate))
  45.        #define DEFAULT_PRIV_COUNT 0
  46.        struct _MamanBarPrivate {
  47.            gint a;
  48.            gint b;
  49.        };
  50.        static void maman_bar_public_func_default (MamanBar *self) {
  51.        }
  52.        static void maman_bar_priv_func_default (MamanBar *self) {
  53.        }
  54.        static void maman_bar_get_property (GObject *object, guint property_id, GValue *value,
     GParamSpec *pspec) {
  55.          MamanBar *bar = MAMAN_BAR (object);
  56.            switch (property_id) {
  57.                case PROP_PRIV_COUNT:
  58.                  g_value_set_int (value, bar->private_count);
  59.                  break;
  60.                default:
  61.                  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
  62.            }
  63.        }
  64.        static void maman_bar_set_property (GObject *object, guint property_id, const GValue *value,
     GParamSpec *pspec) {
  65.          MamanBar *bar = MAMAN_BAR (object);


頁尾在這裡
頁首在這裡
  66.            switch (property_id) {
  67.                case PROP_PRIV_COUNT:
  68.                    bar->private_count = g_value_get_int (value);
  69.                    break;
  70.                default:
  71.                    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
  72.            }
  73.        }
  74.
  75.        static gboolean maman_bar_my_signal_accumulator (GSignalInvocationHint *ihint, GValue
     *return_accu, const GValue *handler_return, gpointer data)
  76.        {
  77.            static gint ret = 0;
  78.
  79.            g_print ("%s : %dn", __FUNCTION__, g_value_get_int (handler_return));
  80.
  81.            ret += g_value_get_int (handler_return);
  82.
  83.            g_value_set_int (return_accu, ret);
  84.
  85.            return TRUE;
  86.        }
  87.
  88.        static gint maman_bar_my_signal_handler (GObject *obj, gint i, gpointer data, gpointer
     user_data)
  89.        {
  90.            /* Here, we trigger the real rotate. */
  91.            g_print ("%s on %pn", __FUNCTION__, obj);
  92.
  93.            return 2;
  94.        }
  95.
  96.        static void maman_bar_class_init (MamanBarClass *klass) {
  97.            GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  98.            gobject_class->get_property = maman_bar_get_property;
  99.            gobject_class->set_property = maman_bar_set_property;
  100.           klass->public_func = maman_bar_public_func_default;
  101.           klass->priv_func = maman_bar_priv_func_default;
  102.           klass->my_signal_handler = maman_bar_my_signal_handler;
  103.           g_object_class_install_property (
  104.               gobject_class,
  105.               PROP_PRIV_COUNT,
  106.               g_param_spec_int (
  107.                   “priv-count”,
  108.                   “MamanBar private count prop”,
  109.                   “MamanBar’s private count”,
  110.                   G_MININT,
  111.                   G_MAXINT,
  112.                   DEFAULT_PRIV_COUNT,
  113.                   G_PARAM_READWRITE
  114.               )
  115.           );
  116.
  117.           klass->my_signal_id = g_signal_new (
  118.                     "mysignal",
  119.                     G_TYPE_FROM_CLASS (klass),
  120.                     G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED,
  121.                     G_STRUCT_OFFSET (MamanBarClass, my_signal_handler),      /* class_offset */
  122.                     maman_bar_my_signal_accumulator,                         /* accumulator */


頁尾在這裡
頁首在這裡
  123.              NULL,                                                   /* accu_data */
  124.              maman_cclosure_marshal_INT__INT_POINTER,                /* g_signal_newv */
  125.              G_TYPE_INT,                                             /* return_type */
  126.              2,                                                      /* n_params */
  127.              G_TYPE_INT,                                             /* param_types */
  128.              G_TYPE_POINTER
  129.         );
  130.
  131.        g_type_class_add_private (klass, sizeof (MamanBarPrivate));
  132.    }
  133.    static void maman_bar_init (MamanBar *self) {
  134.        /* initialize the object */
  135.        self->priv = MAMAN_BAR_GET_PRIVATE (self);
  136.    }
  137.    MamanBar * maman_bar_new (void) {
  138.        return MAMAN_BAR (g_object_new (MAMAN_TYPE_BAR, NULL));
  139.    }
  140.    void maman_bar_public_func (MamanBar *self) {
  141.        g_return_if_fail (MAMAN_IS_BAR (self));
  142.        MAMAN_BAR_GET_CLASS (self)->public_func (self);
  143.    }
  144.    void maman_bar_other_func (MamanBar *self) {
  145.        g_return_if_fail (MAMAN_IS_BAR (self));
  146.        /* pre-priv-func code here */
  147.        MAMAN_BAR_GET_CLASS (self)->priv_func (self);
  148.        /* post-priv-func code here */
  149.    }



物件操作者便可以使用訊號得知物件的狀態改變.


加快你的GObject
在編譯GObject時,只要定義G_DISABLE_CHECKS、G_DISABLE_CAST_CHECKS和
G_DISABLE_ASSERT,我們就可以將MAMAN_IS_BAR和MAMAN_BAR這類的巨集變的簡單(單純的
casting)達成加速的目的.




頁尾在這裡
頁首在這裡



什麼是沒有在這份文件提到的
vtable
這不是C++的vtable


Closure
closure是GObject實作callback的抽象層.




頁尾在這裡
頁首在這裡



工具
glib-genmarshal
在註冊一個GObject的訊號時,預設的marshaler僅針對常用的型態,當預設的marshaler無法滿足需求時,可以
用glib-genmarshal幫你產生一個.


GObject Generator
在[4]的工具只要輸入一些基本的資訊就可以幫你產生一個GObject最基本需要的源碼.




頁尾在這裡
頁首在這裡



參考資料
[1] gobject-learning
[2] GObject Reference Manual (2.26.1)
[3] JSON-GLib
[4] GObject Generator




頁尾在這裡

Más contenido relacionado

La actualidad más candente

Linux Porting
Linux PortingLinux Porting
Linux PortingChamp Yen
 
BKK16-110 A Gentle Introduction to Trusted Execution and OP-TEE
BKK16-110 A Gentle Introduction to Trusted Execution and OP-TEEBKK16-110 A Gentle Introduction to Trusted Execution and OP-TEE
BKK16-110 A Gentle Introduction to Trusted Execution and OP-TEELinaro
 
SystemVerilog OOP Ovm Features Summary
SystemVerilog OOP Ovm Features SummarySystemVerilog OOP Ovm Features Summary
SystemVerilog OOP Ovm Features SummaryAmal Khailtash
 
Slideshare - PCIe
Slideshare - PCIeSlideshare - PCIe
Slideshare - PCIeJin Wu
 
froglogic Coco Code Coverage Presentation
froglogic Coco Code Coverage Presentationfroglogic Coco Code Coverage Presentation
froglogic Coco Code Coverage PresentationReginald Stadlbauer
 
Lcu14 101- coresight overview
Lcu14 101- coresight overviewLcu14 101- coresight overview
Lcu14 101- coresight overviewLinaro
 
Implementation of c string functions
Implementation of c string functionsImplementation of c string functions
Implementation of c string functionsmohamed sikander
 
U Boot or Universal Bootloader
U Boot or Universal BootloaderU Boot or Universal Bootloader
U Boot or Universal BootloaderSatpal Parmar
 
Q4.11: Using GCC Auto-Vectorizer
Q4.11: Using GCC Auto-VectorizerQ4.11: Using GCC Auto-Vectorizer
Q4.11: Using GCC Auto-VectorizerLinaro
 
More on Lex
More on LexMore on Lex
More on LexTech_MX
 
SFO15-200: Linux kernel generic TEE driver
SFO15-200: Linux kernel generic TEE driverSFO15-200: Linux kernel generic TEE driver
SFO15-200: Linux kernel generic TEE driverLinaro
 
(Www.entrance exam.net)-tcs placement sample paper 2
(Www.entrance exam.net)-tcs placement sample paper 2(Www.entrance exam.net)-tcs placement sample paper 2
(Www.entrance exam.net)-tcs placement sample paper 2Pamidimukkala Sivani
 
C++ Function
C++ FunctionC++ Function
C++ FunctionHajar
 
Porting a new architecture (NDS32) to open wrt project
Porting a new architecture (NDS32) to open wrt projectPorting a new architecture (NDS32) to open wrt project
Porting a new architecture (NDS32) to open wrt projectMacpaul Lin
 
UVM Ral model usage
UVM Ral model usageUVM Ral model usage
UVM Ral model usageParth Pandya
 
LAS16-210: Hardware Assisted Tracing on ARM with CoreSight and OpenCSD
LAS16-210: Hardware Assisted Tracing on ARM with CoreSight and OpenCSDLAS16-210: Hardware Assisted Tracing on ARM with CoreSight and OpenCSD
LAS16-210: Hardware Assisted Tracing on ARM with CoreSight and OpenCSDLinaro
 

La actualidad más candente (20)

Linux Porting
Linux PortingLinux Porting
Linux Porting
 
BKK16-110 A Gentle Introduction to Trusted Execution and OP-TEE
BKK16-110 A Gentle Introduction to Trusted Execution and OP-TEEBKK16-110 A Gentle Introduction to Trusted Execution and OP-TEE
BKK16-110 A Gentle Introduction to Trusted Execution and OP-TEE
 
SystemVerilog OOP Ovm Features Summary
SystemVerilog OOP Ovm Features SummarySystemVerilog OOP Ovm Features Summary
SystemVerilog OOP Ovm Features Summary
 
EGL 1.4 Reference Card
EGL 1.4 Reference CardEGL 1.4 Reference Card
EGL 1.4 Reference Card
 
Slideshare - PCIe
Slideshare - PCIeSlideshare - PCIe
Slideshare - PCIe
 
froglogic Coco Code Coverage Presentation
froglogic Coco Code Coverage Presentationfroglogic Coco Code Coverage Presentation
froglogic Coco Code Coverage Presentation
 
Lcu14 101- coresight overview
Lcu14 101- coresight overviewLcu14 101- coresight overview
Lcu14 101- coresight overview
 
Implementation of c string functions
Implementation of c string functionsImplementation of c string functions
Implementation of c string functions
 
U Boot or Universal Bootloader
U Boot or Universal BootloaderU Boot or Universal Bootloader
U Boot or Universal Bootloader
 
Q4.11: Using GCC Auto-Vectorizer
Q4.11: Using GCC Auto-VectorizerQ4.11: Using GCC Auto-Vectorizer
Q4.11: Using GCC Auto-Vectorizer
 
More on Lex
More on LexMore on Lex
More on Lex
 
SFO15-200: Linux kernel generic TEE driver
SFO15-200: Linux kernel generic TEE driverSFO15-200: Linux kernel generic TEE driver
SFO15-200: Linux kernel generic TEE driver
 
(Www.entrance exam.net)-tcs placement sample paper 2
(Www.entrance exam.net)-tcs placement sample paper 2(Www.entrance exam.net)-tcs placement sample paper 2
(Www.entrance exam.net)-tcs placement sample paper 2
 
C++ Function
C++ FunctionC++ Function
C++ Function
 
Porting a new architecture (NDS32) to open wrt project
Porting a new architecture (NDS32) to open wrt projectPorting a new architecture (NDS32) to open wrt project
Porting a new architecture (NDS32) to open wrt project
 
Qemu Pcie
Qemu PcieQemu Pcie
Qemu Pcie
 
VERILOG CODE
VERILOG CODEVERILOG CODE
VERILOG CODE
 
UVM Ral model usage
UVM Ral model usageUVM Ral model usage
UVM Ral model usage
 
LAS16-210: Hardware Assisted Tracing on ARM with CoreSight and OpenCSD
LAS16-210: Hardware Assisted Tracing on ARM with CoreSight and OpenCSDLAS16-210: Hardware Assisted Tracing on ARM with CoreSight and OpenCSD
LAS16-210: Hardware Assisted Tracing on ARM with CoreSight and OpenCSD
 
Fiduccia mattheyses
Fiduccia mattheysesFiduccia mattheyses
Fiduccia mattheyses
 

Más de Shu-Yu Fu

TLPI - Chapter 44 Pipe and Fifos
TLPI - Chapter 44 Pipe and FifosTLPI - Chapter 44 Pipe and Fifos
TLPI - Chapter 44 Pipe and FifosShu-Yu Fu
 
Tlpi chapter 38 writing secure privileged programs
Tlpi   chapter 38 writing secure privileged programsTlpi   chapter 38 writing secure privileged programs
Tlpi chapter 38 writing secure privileged programsShu-Yu Fu
 
TLPI Chapter 14 File Systems
TLPI Chapter 14 File SystemsTLPI Chapter 14 File Systems
TLPI Chapter 14 File SystemsShu-Yu Fu
 
團隊之美 第三篇 實踐 (Part 1)
團隊之美 第三篇 實踐 (Part 1)團隊之美 第三篇 實踐 (Part 1)
團隊之美 第三篇 實踐 (Part 1)Shu-Yu Fu
 
團隊之美 第二篇 目標
團隊之美 第二篇 目標團隊之美 第二篇 目標
團隊之美 第二篇 目標Shu-Yu Fu
 
TLPI - 7 Memory Allocation
TLPI - 7 Memory AllocationTLPI - 7 Memory Allocation
TLPI - 7 Memory AllocationShu-Yu Fu
 
TLPI - 6 Process
TLPI - 6 ProcessTLPI - 6 Process
TLPI - 6 ProcessShu-Yu Fu
 
程式設計師的自我修養 Chapter 10 記憶體
程式設計師的自我修養 Chapter 10 記憶體程式設計師的自我修養 Chapter 10 記憶體
程式設計師的自我修養 Chapter 10 記憶體Shu-Yu Fu
 
程式設計師的自我修養 Chapter 3.4
程式設計師的自我修養 Chapter 3.4程式設計師的自我修養 Chapter 3.4
程式設計師的自我修養 Chapter 3.4Shu-Yu Fu
 
程式設計師的自我修養 Chapter 1
程式設計師的自我修養 Chapter 1程式設計師的自我修養 Chapter 1
程式設計師的自我修養 Chapter 1Shu-Yu Fu
 
程式設計師的自我修養 Chapter 5
程式設計師的自我修養 Chapter 5程式設計師的自我修養 Chapter 5
程式設計師的自我修養 Chapter 5Shu-Yu Fu
 
程式設計師的自我修養 Chapter 8
程式設計師的自我修養 Chapter 8程式設計師的自我修養 Chapter 8
程式設計師的自我修養 Chapter 8Shu-Yu Fu
 

Más de Shu-Yu Fu (12)

TLPI - Chapter 44 Pipe and Fifos
TLPI - Chapter 44 Pipe and FifosTLPI - Chapter 44 Pipe and Fifos
TLPI - Chapter 44 Pipe and Fifos
 
Tlpi chapter 38 writing secure privileged programs
Tlpi   chapter 38 writing secure privileged programsTlpi   chapter 38 writing secure privileged programs
Tlpi chapter 38 writing secure privileged programs
 
TLPI Chapter 14 File Systems
TLPI Chapter 14 File SystemsTLPI Chapter 14 File Systems
TLPI Chapter 14 File Systems
 
團隊之美 第三篇 實踐 (Part 1)
團隊之美 第三篇 實踐 (Part 1)團隊之美 第三篇 實踐 (Part 1)
團隊之美 第三篇 實踐 (Part 1)
 
團隊之美 第二篇 目標
團隊之美 第二篇 目標團隊之美 第二篇 目標
團隊之美 第二篇 目標
 
TLPI - 7 Memory Allocation
TLPI - 7 Memory AllocationTLPI - 7 Memory Allocation
TLPI - 7 Memory Allocation
 
TLPI - 6 Process
TLPI - 6 ProcessTLPI - 6 Process
TLPI - 6 Process
 
程式設計師的自我修養 Chapter 10 記憶體
程式設計師的自我修養 Chapter 10 記憶體程式設計師的自我修養 Chapter 10 記憶體
程式設計師的自我修養 Chapter 10 記憶體
 
程式設計師的自我修養 Chapter 3.4
程式設計師的自我修養 Chapter 3.4程式設計師的自我修養 Chapter 3.4
程式設計師的自我修養 Chapter 3.4
 
程式設計師的自我修養 Chapter 1
程式設計師的自我修養 Chapter 1程式設計師的自我修養 Chapter 1
程式設計師的自我修養 Chapter 1
 
程式設計師的自我修養 Chapter 5
程式設計師的自我修養 Chapter 5程式設計師的自我修養 Chapter 5
程式設計師的自我修養 Chapter 5
 
程式設計師的自我修養 Chapter 8
程式設計師的自我修養 Chapter 8程式設計師的自我修養 Chapter 8
程式設計師的自我修養 Chapter 8
 

大家來學GObject

  • 1. 頁首在這裡 大家來學GObject Revision 2 傅書煜 (shuyufu at gmail.com) 頁尾在這裡
  • 2. 頁首在這裡 為什麼會有這份文件? GObject是什麼? 學會GObject有什麼用? 哪裡取得/ GObject? 學習GObject前必需俱備的知識 結構(Struct) 指標(Pointer) 函式指標(Function Pointer) 在沒有GObject的情況下 GObject基礎課程 GObject 公有實體結構變數和私有實體結構變數 存取資料成員 公有成員函式和私有成員函式,(純)虛擬函式和預設實作 存取父類別結構 抽象類別 介面 GObject進階課程 類別的建構與解構 訊號 GObject 什麼是沒有在這份文件提到的 vtable Closure 工具 glib-genmarshal GObject Generator 參考資料 頁尾在這裡
  • 6. 頁首在這裡 GObject基礎課程 在基礎課程裡,我們將藉由實作一個簡單的GObject來介紹我們在類別裡常用的物件變數、類別變數和(abstract) method如何宣告和定義。 第一個GObject 我們先來實作一個最簡單的GObject吧! 1. /* maman-bar.h */ 2. #ifndef __MAMAN_BAR_H__ 3. #define __MAMAN_BAR_H__ 4. 5. #include <glib-object.h> 6. 7. G_BEGIN_DECLS 8. 9. #define MAMAN_TYPE_BAR (maman_bar_get_type ()) 10. #define MAMAN_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar)) 11. #define MAMAN_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass)) 12. #define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR)) 13. #define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR)) 14. #define MAMAN_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR, MamanBarClass)) 15. 16. typedef struct _MamanBar MamanBar; 17. typedef struct _MamanBarClass MamanBarClass; 18. 19. struct _MamanBar { 20. GObject parent_instance; 21. /* instance members */ 22. }; 23. 24. struct _MamanBarClass { 25. GObjectClass parent_class; 26. /* class members */ 27. }; 28. 29. GType maman_bar_get_type (void); 30. MamanBar * maman_bar_new (void); 31. 32. G_END_DECLS 33. 34. #endif /* __MAMAN_BAR_H__ */ 35. 36. /* maman-bar.c */ 37. #include “maman-bar.h” 38. 39. /* will create maman_bar_get_type and set maman_bar_parent_class */ 40. G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT); 41. 42. static void maman_bar_class_init (MamanBarClass *klass) { 43. GObjectClass *gobject_class = G_OBJECT_CLASS (klass); 44. } 45. 46. static void maman_bar_init (MamanBar *self) { 47. /* initialize the object */ 48. } 49. 50. MamanBar * maman_bar_new (void) { 51. return MAMAN_BAR (g_object_new (MAMAN_TYPE_BAR, NULL)); 52. } 這是一個僅實作出最基本架構的GObject。在GObject裡,實體結構(_MamanBar;第19~22行)和類別結構 (_MamanBarClass;第24~27行)是分開宣告的。實體結構是每產生一個實體就有一份,而類別結構則是被 所有實體共享.這邊要注意的是實體(類別)結構裡的第一個變數必須是父類別的實體(類別)結構(第20、 頁尾在這裡
  • 7. 頁首在這裡 25行),接下來才是自己想宣告的變數。 glib-object.h是每個GObject都必需include的標頭標(第5行),而一開始的巨集是用來取得類別ID(第9行)、 替實體(類別)結構轉型(第10~11行)、檢查指標所指的位置是否為某個類別的實體結構(第12行)或類別 結構(第13行),和從實體結構取得對應的類別結構(第14行).這些巨集我們會在之後的例子看到它們的用 處. G_DEFINE_TYPE是一個幫助我們快速定義一個GObject的巨集(第70行),第一個參數是將類別名稱以 Camel case的方式帶入,第二個參數是將類別名稱以小寫並以底線符號做區隔帶入,第三個則是父類別的類 別ID.我們將巨集展開後會發現其中定義一個指向父類別結構的指標和定義取得ID的函式,也就是第29行的 maman_bar_get_type,這也是為什麼我們僅在標頭檔宣告而沒實作卻又可以呼叫的原因.在取得ID的函式中會 自動引用以第二個參考為前置符號並以_class_init和_init的兩個函式._class_init是類別結構的初始化函式只有 在產生第一個實體之前會被呼叫,而_init則是實體初始化函式,因為每產生一個實體都會呼叫一次. 慣例上,為了方便產生GObject,還會提供一個產生GObject的函式(第30行宣告,第50~52行實作).因此第 51行是在產生一個MamanBar的實體,但,g_object_new回傳的型態為gpointer,所以使用MAMAN_BAR巨集 將指標的型別轉為MamanBar*.最後,我們該怎麼操作MamanBar這個GObject呢? 1. #include “maman-bar.h” 2. 3. int main (void) { 4. MamanBar *bar = NULL; 5. MamanBarClass *bar_class = NULL; 6. g_type_init (); 7. bar = maman_bar_new (); 8. bar_class = MAMAN_BAR_GET_CLASS (bar); 9. g_object_unref (bar); 10. return 0; 11. } 第6行的g_type_init ()是使用任何一個GObject前都必需呼叫的函式,否則會產生錯誤.GObject使用參 考計數[?]作為記憶體管理策略,換句話說,不會有malloc或free這類的函式,取而代之的是g_object_ref和 g_object_unref.當第7行剛透過maman_bar_new產生實體結構時,參考計數為1(事實上是g_object_new產生 實體時會將參考計數設為1),最後main函式結束前用g_object_unref把參考計劃減1,歸零後GObject會自行解 構/回收記憶體. 公有實體結構變數和私有實體結構變數 要宣告公有資料成員很簡單,只要在實體結構內宣告即可.而私有則較為麻煩,有兩種做法,第一種是道德性 的勸說,在宣告實體結構時一併加上註解,告訴使用的人不應該存取這些變數.另一種則是真正的隱藏.以下 列出程式碼,並將新增的部份加上紅色. 1. /* maman-bar.h */ 2. #ifndef __MAMAN_BAR_H__ 3. #define __MAMAN_BAR_H__ 4. 5. #include <glib-object.h> 6. 7. G_BEGIN_DECLS 8. 9. #define MAMAN_TYPE_BAR (maman_bar_get_type ()) 10. #define MAMAN_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar)) 頁尾在這裡
  • 8. 頁首在這裡 11. #define MAMAN_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass)) 12. #define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR)) 13. #define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR)) 14. #define MAMAN_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR, MamanBarClass)) 15. 16. typedef struct _MamanBar MamanBar; 17. typedef struct _MamanBarClass MamanBarClass; 18. typedef struct _MamanBarPrivate MamanBarPrivate; 19. 20. struct _MamanBar { 21. GObject parent_instance; 22. /* instance members */ 23. gint public_count; 24. /*< private >*/ 25. gint private_count; 26. /*< private >*/ 27. MamanBarPrivate *priv; 28. }; 29. 30. struct _MamanBarClass { 31. GObjectClass parent_class; 32. /* class members */ 33. }; 34. 35. GType maman_bar_get_type (void); 36. MamanBar * maman_bar_new (void); 37. 38. G_END_DECLS 39. 40. #endif /* __MAMAN_BAR_H__ */ 41. 42. /* maman-bar.c */ 43. #include “maman-bar.h” 44. 45. /* will create maman_bar_get_type and set maman_bar_parent_class */ 46. G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT); 47. 48. #define MAMAN_BAR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MAMAN_TYPE_BAR, MamanBarPrivate)) 49. 50. struct _MamanBarPrivate { 51. gint a; 52. gint b; 53. }; 54. 55. static void maman_bar_class_init (MamanBarClass *klass) { 56. GObjectClass *gobject_class = G_OBJECT_CLASS (klass); 57. g_type_class_add_private (klass, sizeof (MamanBarPrivate)); 58. } 59. 60. static void maman_bar_init (MamanBar *self) { 61. /* initialize the object */ 62. self->priv = MAMAN_BAR_GET_PRIVATE (self); 63. } 64. 65. MamanBar * maman_bar_new (void) { 66. return MAMAN_BAR (g_object_new (MAMAN_TYPE_BAR, NULL)); 67. } 第23行的public_count就是屬於公有實體結構變數,而第25行的private_count則是勸說型的私有實體結構變數, 所以我們在第24行加上註解/*< private >*/告訴使用的人不應該存取這些變數,這兩種實體結構變數只要使用 MamanBar的人include標頭檔就很清楚struct的宣告時的內容,都無法防止外部直接存取.而確實隱藏的方法是 在.c檔內宣告私有結構(第50~53行)並在maman_bar_class_init時將私有結構加入類別裡(第57行),之後要 存取時則是透過第48行宣告的巨集將私有結構的位置取出來,像第66行做的事.這邊要注意的是,在實體結構 內不一定要有一個指標指向私有結構(第27行)的位置,這例子中只是為了示範(其實也可以做為快取,之後 就不用再透過巨集取得位置),所以在實體結構內宣告了一個私有結構的指標. 存取資料成員 頁尾在這裡
  • 9. 頁首在這裡 當有了結構變數後接下來就是如何存取它們?當然,最簡單的就是直接用->的方式存取,不過,這不僅有違封 裝性,也不是我們要講的方法.我們要介紹的是如何利用GObject提供的介面替一個GObject安裝(install)屬性 (property)並使用特定的函式存取它們.但,為什麼要這麼麻煩?直接用->就好了啊.事實上,GObject對屬性的 存取可以提供一定的規範,以及當搭配其它以GObject為基礎的函式庫時就會明顯感受到它的作用,不需要額外 寫code就可以發揮作用.如json-glib可以將一個GObject序列化為JSON格式,但,它僅能作用在安裝好的屬性 上. 1. /* maman-bar.h */ 2. #ifndef __MAMAN_BAR_H__ 3. #define __MAMAN_BAR_H__ 4. 5. #include <glib-object.h> 6. 7. G_BEGIN_DECLS 8. 9. #define MAMAN_TYPE_BAR (maman_bar_get_type ()) 10. #define MAMAN_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar)) 11. #define MAMAN_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass)) 12. #define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR)) 13. #define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR)) 14. #define MAMAN_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR, MamanBarClass)) 15. 16. typedef struct _MamanBar MamanBar; 17. typedef struct _MamanBarClass MamanBarClass; 18. typedef struct _MamanBarPrivate MamanBarPrivate; 19. 20. struct _MamanBar { 21. GObject parent_instance; 22. /* instance members */ 23. gint public_count; 24. /*< private >*/ 25. gint private_count; 26. /*< private >*/ 27. MamanBarPrivate *priv; 28. }; 29. 30. struct _MamanBarClass { 31. GObjectClass parent_class; 32. /* class members */ 33. }; 34. 35. GType maman_bar_get_type (void); 36. MamanBar * maman_bar_new (void); 37. 38. G_END_DECLS 39. 40. #endif /* __MAMAN_BAR_H__ */ 41. 42. /* maman-bar.c */ 43. #include “maman-bar.h” 44. 45. /* will create maman_bar_get_type and set maman_bar_parent_class */ 46. G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT); 47. 48. #define MAMAN_BAR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MAMAN_TYPE_BAR, MamanBarPrivate)) 49. 50. #define DEFAULT_PRIV_COUNT 0 51. 52. struct _MamanBarPrivate { 53. gint a; 54. gint b; 55. }; 56. 57. static void maman_bar_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { 58. MamanBar *bar = MAMAN_BAR (object); 59. switch (property_id) { 60. case PROP_PRIV_COUNT: 61. g_value_set_int (value, bar->private_count); 62. break; 63. default: 64. G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); 頁尾在這裡
  • 10. 頁首在這裡 65. } 66. } 67. 68. static void maman_bar_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { 69. MamanBar *bar = MAMAN_BAR (object); 70. switch (property_id) { 71. case PROP_PRIV_COUNT: 72. bar->private_count = g_value_get_int (value); 73. break; 74. default: 75. G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); 76. } 77. } 78. 79. static void maman_bar_class_init (MamanBarClass *klass) { 80. GObjectClass *gobject_class = G_OBJECT_CLASS (klass); 81. gobject_class->get_property = maman_bar_get_property; 82. gobject_class->set_property = maman_bar_set_property; 83. g_object_class_install_property ( 84. gobject_class, 85. PROP_PRIV_COUNT, 86. g_param_spec_int ( 87. “priv-count”, 88. “MamanBar private count prop”, 89. “MamanBar’s private count”, 90. G_MININT, 91. G_MAXINT, 92. DEFAULT_PRIV_COUNT, 93. G_PARAM_READWRITE 94. ) 95. ); 96. g_type_class_add_private (klass, sizeof (MamanBarPrivate)); 97. } 98. 99. static void maman_bar_init (MamanBar *self) { 100. /* initialize the object */ 101. self->priv = MAMAN_BAR_GET_PRIVATE (self); 102. } 103. 104. MamanBar * maman_bar_new (void) { 105. return MAMAN_BAR (g_object_new (MAMAN_TYPE_BAR, NULL)); 106. } GObject要安裝(install)屬性(property)(第80~93行)之前,必需先覆寫GObjectClass的get_property和 set_property兩個函式指標(第79~80行),否則會發生錯誤.在這例子中我們安裝了priv-count這個屬性 的ID為PROP_PRIV_COUNT,其型別為int,可接受的範圍介於G_MININT和G_MAXINT之間,預設值為 DEFAULT_PRIV_COUNT並且可以READ-WRITE.之後透過GObject所提供的函式存取屬性時就會呼叫 到maman_bar_get_property和maman_bar_set_property並將需要的資訊一併傳入.而在get_property和 set_property兩個函式中只要用switch敘述判斷property_id就可以知道要用什麼函式存取GValue了. GValue在GObject中扮演一個泛型(generic)的容器(contaier),當承載的資料為原始資料型態,我們不需要特別 做什麼,但,當承載的資料為自訂的型別時,就需要提供一些函式了[???],GValue我們會在[???]做一次介紹, 目前僅需要知道GValue是一個泛型的容器就好. 最後,我們來看要怎麼存取MamanBar的屬性. 1. #include "maman-bar.h" 2. 3. int main (void) { 4. MamanBar *bar = NULL; 5. MamanBarClass *bar_class = NULL; 6. gint count = 0; 7. GValue val = {0, }; 8. 9. g_type_init (); 10. 11. bar = maman_bar_new (); 12. 13. g_value_init (&val, G_TYPE_INT); 頁尾在這裡
  • 11. 頁首在這裡 14. g_value_set_int (&val, count); 15. 16. g_object_set_property (G_OBJECT (bar), “priv-count”, &val); 17. g_object_get_property (G_OBJECT (bar), “priv_count”, &val); 18. count = g_value_get_int (&val); 19. 20. g_object_set (G_OBJECT (bar), “priv_count”, count, NULL); 21. g_object_get (G_OBJECT (bar), “priv-count”, &count, NULL); 22. 23. g_object_unref (bar); 24. 25. return 0; 26. } 我們可以透過g_object_set_property和g_object_get_property一次存取一個屬性(第16~17行),或者 透過g_object_set和g_object_get一次存取多個屬性(第20~21行).當使用g_object_set_property和 g_object_get_property,必需以GValue作為媒介將值封裝起來或從其中將值取出.而g_object_set和 g_object_get則不然,直接將要存取的屬性名和儲存位置以一對的方式傳入,並允許多對,最後以NULL結束, 也可以達到同樣的效果. 公有成員函式和私有成員函式,(純)虛擬函式和預設實作 成員函式的作法是在類別結構內宣告函式指標,然後在_class_init裡覆寫函式指標.而公有/私有成員函式兩者 在GObject實作上很像,只差在於能不能直接呼叫到而已,事實上,在其它的OO實作上,不也是這樣嗎? 1. /* maman-bar.h */ 2. #ifndef __MAMAN_BAR_H__ 3. #define __MAMAN_BAR_H__ 4. 5. #include <glib-object.h> 6. 7. G_BEGIN_DECLS 8. 9. #define MAMAN_TYPE_BAR (maman_bar_get_type ()) 10. #define MAMAN_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar)) 11. #define MAMAN_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass)) 12. #define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR)) 13. #define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR)) 14. #define MAMAN_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR, MamanBarClass)) 15. 16. typedef struct _MamanBar MamanBar; 17. typedef struct _MamanBarClass MamanBarClass; 18. typedef struct _MamanBarPrivate MamanBarPrivate; 19. 20. struct _MamanBar { 21. GObject parent_instance; 22. /* instance members */ 23. gint public_count; 24. /*< private >*/ 25. gint private_count; 26. /*< private >*/ 27. MamanBarPrivate *priv; 28. }; 29. 30. struct _MamanBarClass { 31. GObjectClass parent_class; 32. /* class members */ 33. void (*public_func) (MamanBar *); 34. void (*priv_func) (MamanBar *); 35. }; 36. 37. GType maman_bar_get_type (void); 38. MamanBar * maman_bar_new (void); 39. void maman_bar_public_func (MamanBar *self); 40. void maman_bar_other_func (MamanBar *self); 41. 42. G_END_DECLS 43. 頁尾在這裡
  • 12. 頁首在這裡 44. #endif /* __MAMAN_BAR_H__ */ 45. 46. /* maman-bar.c */ 47. #include “maman-bar.h” 48. 49. /* will create maman_bar_get_type and set maman_bar_parent_class */ 50. G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT); 51. 52. #define MAMAN_BAR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MAMAN_TYPE_BAR, MamanBarPrivate)) 53. 54. #define DEFAULT_PRIV_COUNT 0 55. 56. struct _MamanBarPrivate { 57. gint a; 58. gint b; 59. }; 60. 61. static void maman_bar_public_func_default (MamanBar *self) { 62. } 63. 64. static void maman_bar_priv_func_default (MamanBar *self) { 65. } 66. 67. static void maman_bar_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { 68. MamanBar *bar = MAMAN_BAR (object); 69. switch (property_id) { 70. case PROP_PRIV_COUNT: 71. g_value_set_int (value, bar->private_count); 72. break; 73. default: 74. G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); 75. } 76. } 77. 78. static void maman_bar_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { 79. MamanBar *bar = MAMAN_BAR (object); 80. switch (property_id) { 81. case PROP_PRIV_COUNT: 82. bar->private_count = g_value_get_int (value); 83. break; 84. default: 85. G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); 86. } 87. } 88. 89. static void maman_bar_class_init (MamanBarClass *klass) { 90. GObjectClass *gobject_class = G_OBJECT_CLASS (klass); 91. gobject_class->get_property = maman_bar_get_property; 92. gobject_class->set_property = maman_bar_set_property; 93. klass->public_func = maman_bar_public_func_default; 94. klass->priv_func = maman_bar_priv_func_default; 95. g_object_class_install_property ( 96. gobject_class, 97. PROP_PRIV_COUNT, 98. g_param_spec_int ( 99. “priv-count”, 100. “MamanBar private count prop”, 101. “MamanBar’s private count”, 102. G_MININT, 103. G_MAXINT, 104. DEFAULT_PRIV_COUNT, 105. G_PARAM_READWRITE 106. ) 107. ); 108. g_type_class_add_private (klass, sizeof (MamanBarPrivate)); 109. } 110. 111. static void maman_bar_init (MamanBar *self) { 112. /* initialize the object */ 113. self->priv = MAMAN_BAR_GET_PRIVATE (self); 114. } 115. 116. MamanBar * maman_bar_new (void) { 117. return MAMAN_BAR (g_object_new (MAMAN_TYPE_BAR, NULL)); 118. } 119. 頁尾在這裡
  • 13. 頁首在這裡 120. void maman_bar_public_func (MamanBar *self) { 121. g_return_if_fail (MAMAN_IS_BAR (self)); 122. MAMAN_BAR_GET_CLASS (self)->public_func (self); 123. } 124. 125. void maman_bar_other_func (MamanBar *self) { 126. g_return_if_fail (MAMAN_IS_BAR (self)); 127. /* pre-priv-func code here */ 128. MAMAN_BAR_GET_CLASS (self)->priv_func (self); 129. /* post-priv-func code here */ 130. } 在標題頭裡提供maman_bar_public_func和maman_bar_other_func兩函式(宣告在第39~40行),用以 存取類別結構裡的public_func和priv_func函式指標.在_class_init裡,我們將public_func和priv_func函 式指標分別指向maman_bar_public_func_default和maman_bar_priv_func_default(第93~94行).在 maman_bar_public_func裡(第120~123行),我們僅檢查傳入的指標是否確實指向一個MamanBar的實體, 之後便呼叫類別結構裡的public_func函式指標,這就是公有成員函式.而在maman_bar_other_func裡(第 125~130行),我們除了檢查傳入的指標以外,更在呼叫priv_func這個私有成員的前後加入一些其它的處理邏 輯. 存取父類別結構 存取父類別結構讓我們得以呼叫父類別的成員函式,哪該怎麼實作呢?這並不難,只要將某個類別結構傳入 g_type_class_peek_parent這個函式就會回傳一個父類別結構的指標, 之後就能透過這指標存取父類別結構. 還記得之前提到的G_DEFINE_TYPE嗎?這個巨集幫我們做的其中一件事就是宣告一個父類別結構的變數並指 向父類別結構,而這變數的名字是以第G_DEFINE_TYPE的第二個變數開頭並以_parent_class結尾. 1. G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT); 在這例子裡,則是maman_bar_parent_class. 抽象類別 有了之前的基礎,要宣告一個抽象類別更是簡單了,只要把G_DEFINE_TYPE換成 G_DEFINE_ABSTRACT_TYPE就可以了. 介面 介面宣告的方式和類別大同小異,差在於介面是繼承自GTypeInterface而不是GObjectClass. 1. /* maman-ibaz.h */ 2. #ifndef __MAMAN_IBAZ_H__ 3. #define __MAMAN_IBAZ_H__ 4. 5. #include <glib-object.h> 6. 7. G_BEGIN_DECLS 8. 9. #define MAMAN_IBAZ_TYPE (maman_ibaz_get_type ()) 10. #define MAMAN_IBAZ(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_IBAZ_TYPE, MamanIbaz) ) 11. #define MAMAN_IS_IBAZ(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_IBAZ_TYPE)) 12. #define MAMAN_IBAZ_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), MAMAN_IBAZ_TYPE, 頁尾在這裡
  • 14. 頁首在這裡 MamanIbazInterface)) 13. 14. typedef struct _MamanIbaz MamanIbaz; /* dummy object */ 15. typedef struct _MamanIbazInterface MamanIbazInterface; 16. 17. struct _MamanIbazInterface { 18. GTypeInterface parent; 19. 20. void (*do_action) (MamanIbaz *self); 21. }; 22. 23. GType maman_ibaz_get_type (void); 24. 25. void maman_ibaz_do_action (MamanIbaz *self); 26. 27. G_END_DECLS 28. 29. #endif /* __MAMAN_IBAZ_H__ */ 30. 31. /* maman-ibaz.c */ 32. #include “maman-ibaz.h” 33. 34. G_DEFINE_INTERFACE (MamanIbaz, maman_ibaz, G_TYPE_INVALID) 35. 36. static void maman_ibaz_default_init (MamanIbazInterface *klass) 37. { 38. } 39. 40. void maman_ibaz_do_action (MamanIbaz *self) 41. { 42. g_return_if_fail (MAMAN_IS_IBAZ (self)); 43. 44. MAMAN_IBAZ_GET_INTERFACE (self)->do_action (self); 45. } jjjj 頁尾在這裡
  • 15. 頁首在這裡 GObject進階課程 在進階課程裡,我們會瞭解GObject建構和解構的順序,和GObject中的訊號. 類別的建構與解構 在[2]裡有兩張表在解釋GObjec和GObject Interfacet的建構和解構.我們這邊簡單的在這邊再出現一次. GObject的解構和解構 Invocation time Function Invoked Function's parameters First call type's base_init function On the inheritance tree of tog_type_create_instancefor classes from fundamental target type type to target type. base_init is invoked once for each class structure. target type's class_init function On target type's class structure interface initialization, see the section called “Interface Initialization” Each call target type's instance_init On object's instance tog_type_create_instancefor function target type Last call interface destruction, see tog_type_free_instance for the section called “Interface target type Destruction” target type's class_finalize On target type's class structure function type's base_finalize function On the inheritance tree of classes from fundamental type to target type. base_finalize is invoked once for each class structure. GObject Interface的建構 Invocation time Function Invoked Function's parameters Remark First call interface' base_init On interface' vtable Register interface' 頁尾在這裡
  • 16. 頁首在這裡 tog_type_create_ function signals here (use a instance for type local static boolean implementing interface variable as described above to make sure not to register them twice.). interface' interface_init On interface' vtable Initialize interface' function implementation. That is, initialize the interface method pointers in the interface structure to the function's implementation. GObject Interface的解構 Invocation time Function Invoked Function's parameters Last call to interface' interface_finalize On interface' vtable g_type_free_instance for type function implementing interface interface' base_finalize function On interface' vtable 訊號 在GObject提供了訊號(Signal)這個機制,讓物件操作者可以透過callback函式得知物件狀態改變了,更簡單 的說,訊號是GObject中的觀察者模式(Observer Pattern). GObject必需在class_init函式裡使用g_signal_new註冊要提供外界觀察的訊號,之後物件操作者才能註冊 callback函式.首先我們在類別結構裡宣告預設的訊號處理函式和一個變數儲存訊號的ID(第27~28行),然後在 class_init函式裡先指定訊號處理函式的位置(第100行)然後再註冊一個訊號(第115~127行),比較特殊的 是,除了訊號處理函式,我們還額外註冊了一個accumulator函式(第120行),緊接著每一次的訊號calback函 式之後accumulator函式就會接著被呼叫一次. 1. /* maman-bar.h */ 2. #ifndef __MAMAN_BAR_H__ 3. #define __MAMAN_BAR_H__ 4. #include <glib-object.h> 5. G_BEGIN_DECLS 6. #define MAMAN_TYPE_BAR (maman_bar_get_type ()) 7. #define MAMAN_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar)) 8. #define MAMAN_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass)) 9. #define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR)) 頁尾在這裡
  • 17. 頁首在這裡 10. #define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR)) 11. #define MAMAN_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR, MamanBarClass)) 12. typedef struct _MamanBar MamanBar; 13. typedef struct _MamanBarClass MamanBarClass; 14. typedef struct _MamanBarPrivate MamanBarPrivate; 15. struct _MamanBar { 16. GObject parent_instance; 17. /* instance members */ 18. gint public_count; 19. /*< private >*/ 20. gint private_count; 21. /*< private >*/ 22. MamanBarPrivate *priv; 23. }; 24. struct _MamanBarClass { 25. GObjectClass parent_class; 26. /* class members */ 27. guint my_signal_id; 28. gint (*my_signal_handler) (GObject *, gint, gpointer, gpointer); 29. void (*public_func) (MamanBar *); 30. void (*priv_func) (MamanBar *); 31. }; 32. GType maman_bar_get_type (void); 33. MamanBar * maman_bar_new (void); 34. void maman_bar_public_func (MamanBar *self); 35. void maman_bar_other_func (MamanBar *self); 36. G_END_DECLS 37. #endif /* __MAMAN_BAR_H__ */ 38. /* maman-bar.c */ 39. #include “maman-bar.h” 40. #include “mamanmarshal.h” 41. 42. /* will create maman_bar_get_type and set maman_bar_parent_class */ 43. G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT); 44. #define MAMAN_BAR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MAMAN_TYPE_BAR, MamanBarPrivate)) 45. #define DEFAULT_PRIV_COUNT 0 46. struct _MamanBarPrivate { 47. gint a; 48. gint b; 49. }; 50. static void maman_bar_public_func_default (MamanBar *self) { 51. } 52. static void maman_bar_priv_func_default (MamanBar *self) { 53. } 54. static void maman_bar_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { 55. MamanBar *bar = MAMAN_BAR (object); 56. switch (property_id) { 57. case PROP_PRIV_COUNT: 58. g_value_set_int (value, bar->private_count); 59. break; 60. default: 61. G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); 62. } 63. } 64. static void maman_bar_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { 65. MamanBar *bar = MAMAN_BAR (object); 頁尾在這裡
  • 18. 頁首在這裡 66. switch (property_id) { 67. case PROP_PRIV_COUNT: 68. bar->private_count = g_value_get_int (value); 69. break; 70. default: 71. G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); 72. } 73. } 74. 75. static gboolean maman_bar_my_signal_accumulator (GSignalInvocationHint *ihint, GValue *return_accu, const GValue *handler_return, gpointer data) 76. { 77. static gint ret = 0; 78. 79. g_print ("%s : %dn", __FUNCTION__, g_value_get_int (handler_return)); 80. 81. ret += g_value_get_int (handler_return); 82. 83. g_value_set_int (return_accu, ret); 84. 85. return TRUE; 86. } 87. 88. static gint maman_bar_my_signal_handler (GObject *obj, gint i, gpointer data, gpointer user_data) 89. { 90. /* Here, we trigger the real rotate. */ 91. g_print ("%s on %pn", __FUNCTION__, obj); 92. 93. return 2; 94. } 95. 96. static void maman_bar_class_init (MamanBarClass *klass) { 97. GObjectClass *gobject_class = G_OBJECT_CLASS (klass); 98. gobject_class->get_property = maman_bar_get_property; 99. gobject_class->set_property = maman_bar_set_property; 100. klass->public_func = maman_bar_public_func_default; 101. klass->priv_func = maman_bar_priv_func_default; 102. klass->my_signal_handler = maman_bar_my_signal_handler; 103. g_object_class_install_property ( 104. gobject_class, 105. PROP_PRIV_COUNT, 106. g_param_spec_int ( 107. “priv-count”, 108. “MamanBar private count prop”, 109. “MamanBar’s private count”, 110. G_MININT, 111. G_MAXINT, 112. DEFAULT_PRIV_COUNT, 113. G_PARAM_READWRITE 114. ) 115. ); 116. 117. klass->my_signal_id = g_signal_new ( 118. "mysignal", 119. G_TYPE_FROM_CLASS (klass), 120. G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED, 121. G_STRUCT_OFFSET (MamanBarClass, my_signal_handler), /* class_offset */ 122. maman_bar_my_signal_accumulator, /* accumulator */ 頁尾在這裡
  • 19. 頁首在這裡 123. NULL, /* accu_data */ 124. maman_cclosure_marshal_INT__INT_POINTER, /* g_signal_newv */ 125. G_TYPE_INT, /* return_type */ 126. 2, /* n_params */ 127. G_TYPE_INT, /* param_types */ 128. G_TYPE_POINTER 129. ); 130. 131. g_type_class_add_private (klass, sizeof (MamanBarPrivate)); 132. } 133. static void maman_bar_init (MamanBar *self) { 134. /* initialize the object */ 135. self->priv = MAMAN_BAR_GET_PRIVATE (self); 136. } 137. MamanBar * maman_bar_new (void) { 138. return MAMAN_BAR (g_object_new (MAMAN_TYPE_BAR, NULL)); 139. } 140. void maman_bar_public_func (MamanBar *self) { 141. g_return_if_fail (MAMAN_IS_BAR (self)); 142. MAMAN_BAR_GET_CLASS (self)->public_func (self); 143. } 144. void maman_bar_other_func (MamanBar *self) { 145. g_return_if_fail (MAMAN_IS_BAR (self)); 146. /* pre-priv-func code here */ 147. MAMAN_BAR_GET_CLASS (self)->priv_func (self); 148. /* post-priv-func code here */ 149. } 物件操作者便可以使用訊號得知物件的狀態改變. 加快你的GObject 在編譯GObject時,只要定義G_DISABLE_CHECKS、G_DISABLE_CAST_CHECKS和 G_DISABLE_ASSERT,我們就可以將MAMAN_IS_BAR和MAMAN_BAR這類的巨集變的簡單(單純的 casting)達成加速的目的. 頁尾在這裡
  • 22. 頁首在這裡 參考資料 [1] gobject-learning [2] GObject Reference Manual (2.26.1) [3] JSON-GLib [4] GObject Generator 頁尾在這裡