文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>恶心的GObject[Part I][v0.1]

恶心的GObject[Part I][v0.1]

时间:2010-09-18  来源:平繁

恶心的GObject[Part I][v0.1]

转载请注明出处 http://www.pingf.me

虽然GObject最初是为了简化C语言的OO开发而设立的,但毕竟C不是天生的OO语言,而其中有太多抽象的东西,反而让其难以入门.....

虽然以前花了很长时间去研究这东西,但限于当时的水平,一些东西并没有弄透彻,甚至有不少错误....

因为前段自己尝试用C语言来模拟OO,积累了不少经验,最近偶然又回顾了下GObject,一些似懂非懂的概念明朗了许多.....

Part I. GObject中最恶心的概念

下面罗列几个概念,都是难以弄明白的....

GCClosure,GClosure,GClosureMarshal,

GClosureNotifyData,GClosureNotify,SignalAccumulator,GSignalAccumulator...

晕了吧,估计不少学了一段Gtk的人对上面的概念还是一知半解...

在具体展开前,我们需要知道GObject是怎么描述类,以及如何进行类型的判定和转换的....

我们知道C语言进行OO编程的时候要大量用到结构体和函数指针,GObject也不例外,

而GObject中每一个类也是一到多个结构体[多个结构体是干嘛的后面会解释],GObject本身用多个int型变量来表示各个类型,类型的检测就是 一个int型变量的检查,而类型的转换也是根据这个int型的变量[需要判断是否可以转换],进行结构体或指针的强制转换.

而GCClosure,GClosure就是两个结构体!

前面的GCClosure多了个C,自然是C语言用的,不难想到GCClosure是GClosure一个封装,提供针对C语言的一种绑定,自 然,GObject可以绑定到多种语言,比如Python,Ruby等等,目前绑定的比较好的是C[原生]/CPP/VALA/PYTHON

仔细看下

?
1 2 3 4 5 struct _GCClosure {   GClosure  closure;   gpointer  callback; };

 

注意,_GCClosure会用typedef在定义成GCClosure,这一点后面都类似,以后不再特殊说明,

通过GCClosure定义,不难发现其封装了一个GClosure的同时,还有一个callback,猜到了吧!GCClosure的主要功能就是回调!

估计不够淡定的朋友会觉得这也太扯淡了,回调的本质就是一个函数指针,包装这么多层干嘛?GObject这样设计自然有它的道理,

我们知道不同语言有不同的类型,比如C语言里就没有原生的String,

而即便是C语言我们仅在C语言,我们在定义回调函数时也可能要用到不同的形式,比如有的返回int,有的返回void,我们怎么区别这些呢?

不急,待我一步一步分析,

GOBject中GClosureMarshal是一个函数指针,但是要注意它是用来定义回调函数类型的而不是直接调用的!

?
1 2 3 4 5 6 typedef void  (*GClosureMarshal)    (GClosure   *closure,                      GValue         *return_value,                      guint           n_param_values,                      const GValue   *param_values,                      gpointer        invocation_hint,                      gpointer    marshal_data);

 

看到它的参数没有,指定了回调返回值类型,回调函数参数的个数等等

而每一个GClosure都要有一个绑定的GClosureMarshal,

具体来看看

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 struct _GClosure {   /*< private >*/   volatile          guint    ref_count : 15;   volatile          guint    meta_marshal : 1;   volatile          guint    n_guards : 1;   volatile          guint    n_fnotifiers : 2;  /* finalization notifiers */   volatile          guint    n_inotifiers : 8;  /* invalidation notifiers */   volatile          guint    in_inotify : 1;   volatile          guint    floating : 1;   /*< protected >*/   volatile          guint    derivative_flag : 1;   /*< public >*/   volatile          guint    in_marshal : 1;   volatile          guint    is_invalid : 1;     /*< private >*/ void   (*marshal)  (GClosure       *closure,                         GValue /*out*/ *return_value,                         guint           n_param_values,                         const GValue   *param_values,                         gpointer        invocation_hint,                         gpointer        marshal_data);   /*< protected >*/   gpointer data;     /*< private >*/ GClosureNotifyData *notifiers;   };

 

注意,官方网上的Manual可能描述上过老,容易误导初学者,上面的源自GOjbect源码

罗列上面代码并不是大家一个一个分析的,只是要大家知道前面我说的一个Closure绑定一个Marshaller.....

我前面说过GClosureMarshal是用来定义回调函数类型的,不是用来调用的,GObject中真正的回调是marshal_data[够抽象的,这个是一个void *指针] ,关于这个我不多说什么[因为自己也没时间研究],因为一般不常用,主要用于其它语言间的绑定.

对于C语言,GObject本身已经提供了很多现成的C语言专用的Marshaller,下面给出一个最简单的C专用的Marshaller

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 /* VOID:VOID (./gmarshal.list:26) */ void g_cclosure_marshal_VOID__VOID (GClosure     *closure,                                GValue       *return_value G_GNUC_UNUSED,                                guint         n_param_values,                                const GValue *param_values,                                gpointer      invocation_hint G_GNUC_UNUSED,                                gpointer      marshal_data) {   typedef void (*GMarshalFunc_VOID__VOID) (gpointer     data1,                                            gpointer     data2);   register GMarshalFunc_VOID__VOID callback;   register GCClosure *cc = (GCClosure*) closure;   register gpointer data1, data2;     g_return_if_fail (n_param_values == 1);     if (G_CCLOSURE_SWAP_DATA (closure))     {       data1 = closure->data;       data2 = g_value_peek_pointer (param_values + 0);     }   else     {       data1 = g_value_peek_pointer (param_values + 0);       data2 = closure->data;     }   callback = (GMarshalFunc_VOID__VOID) (marshal_data ? marshal_data : cc->callback);     callback (data1,             data2); }

看到了吧那个callback可以指向marshal_data,而marshal_data也是一个函数指针,一般来说它应指向GCClosure中的callback,只是真正调用时是从GClosure中来调用而已.

而原始的GClosureMarshal本质上也是这样的......

注意VOID_VOID表示回调返回VOID,额外的参数为VOID[就是没有额外的参数]

 

好了,分析的差不多了,有了上面的基础我们就不难理解signal的链接与回调

对于C语言,

一个SIGNAL在CONNECT时,实际创建了一个C语言的Closure,并绑定了一个C语言的Marshaller,而C语言Marshaller 的类型,要在SIGNAL 创建时来定义[注意常见的Gtk中g_signal_connect的常见SIGNAL都是已经定义好回调的类型的,所以你在定义已知信号的回调是要按类 型定义],回调函数是在GCClosure中定义的,但本质上是通过GClosure来调用....

简单表示下

?
1 2 3 4 5 6 7 8 9 10 11 GCClosure{   GClosure {       ...      其它很多和类型相关的东西;       ...       GClosureMarshal marshal; //这是个函数指针,       //这个的参数中有一个要指向下面定义的callback      ...   }  void *callback; }

而我们在ui使用回调是将SIGNAL发送[EMIT]出去,若在signal队列中有绑定的HANDLER[就是我们的callback],就由其处理...

signal的发送非常复杂,这里不再赘述[如果要研究这个,可以从SignalNode结构入手].....

我们仅需要知道[对于C语言]一旦找到了相应的SIGNAL的ID,就会找到指定GClosure[不是GCClosure],然后通过其找到GClosure并调用其中的marshall函数[传入的参数有何callback相关的],进而调用回调函数.

如果是C语言,可以调用类似g_cclosure_marshal_VOID__VOID的一个定义好的marshal,其内部会调用对应的指向 callback的函数[具体参考上面那个C语言VOID_VOID型marshal,调用了传入marshal_data函数指针,也就是我们绑定到 GCClosure的callback指针]

好了最扯淡的部分结束了,还有四个[GClosureNotifyData , GClosureNotify , SignalAccumulator , GSignalAccumulator]没说,不过这四个比较简单,理解起来也容易些,下面为了节约时间,一并说了.

GClosureNotifyData 是一个结构体,它包含了一个函数指针GClosureNotify

SignalAccumulator 也是一个结构体,他也包含了一个函数指针GSignalAccumulator

具体代码

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 struct _GClosureNotifyData {   gpointer       data;   GClosureNotify notify; };   typedef void  (*GClosureNotify)     (gpointer    data,                      GClosure   *closure);   typedef struct {   GSignalAccumulator func;   gpointer           data; } SignalAccumulator;   typedef gboolean (*GSignalAccumulator)  (GSignalInvocationHint *ihint,                      GValue            *return_accu,                      const GValue          *handler_return,                      gpointer               data);

上面的data即回调函数传入的参数

如果我们回调的参数中有定义在堆上的,并且调用完要释放,那么应该通过绑定一个GClosureNotify型的指针,而GSignalAccumulator指针则是用来控制某个信号响应后是否继续向下传递用的.

注意: GClosure中有指向GClosureNotifyData的指针,而SignalNode结构体中有个指向SignalAccumulator结构体的指针.

 

好了,本篇就到此为止,基本分析了GObject中最难理解的概念,因为写的仓促和个人水平有限希望发现问题的朋友能够给予指正.

我的邮件地址 [email protected]

相关阅读 更多 +
排行榜 更多 +
宝宝情商养成宝宝巴士

宝宝情商养成宝宝巴士

休闲益智 下载
燥热手机版

燥热手机版

飞行射击 下载
巨人狙击手安卓版

巨人狙击手安卓版

飞行射击 下载