Chinaunix首页 | 论坛 | 博客
  • 博客访问: 52713
  • 博文数量: 13
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 80
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-29 17:07
文章分类

全部博文(13)

文章存档

2014年(3)

2013年(10)

我的朋友

分类: 嵌入式

2013-10-22 17:28:49

在GObject中,如果想给自己写的类加上signal,一般需要在*_class_init函数中使用g_signal_new函数,但是这个函数的参数比较复杂:

点击(此处)折叠或打开

  1. guint g_signal_new(const gchar *signal_name,
  2.                       GType itype,
  3.                       GSignalFlags signal_flags,
  4.                       guint class_offset,
  5.                       GSignalAccumulator accumulator,
  6.                       gpointer accu_data,
  7.                       GSignalCMarshaller c_marshaller,
  8.                       GType return_type,
  9.                       guint n_params,
  10.                       ...);

    从该函数的原型中,我们可以看出,该函数的参数个数是可变的。

    下面,我姑妄从前往后依次解释一下各个参数的含义:

  • const gchar *signal_name:该参数是信号的名字,由分隔符以及ASCII码中的字母和数字构成,并且第一个字符必须是字母。分隔符可以是"-"或"_" ——事实上,系统会先调用g_strdelimit把"_"转化为"-"再存储signal_name。因此,在调用 g_singal_emit_by_name时,detailed_signal参数中的分隔符必须是"-"。
  • GType itype:该参数是signal所依附的类的在GType类型系统中注册时得到的ID,也就是*_get_type()函数的返回值。
  • GSignalFlags signal_flags:该参数是信号的属性标记,有七种,我将在最后解释:
    • G_SIGNAL_RUN_FIRST
    • G_SIGNAL_RUN_LAST
    • G_SIGNAL_RUN_CLEANUP
    • G_SIGNAL_NO_RECURSE
    • G_SIGNAL_DETAILED
    • G_SIGNAL_ACTION
    • G_SIGNAL_NO_HOOKS
  • guint class_offset:该参数是itype对应的类的class结构中的一个函数指针相对于class结构的实例的首地址的偏移量。该函数指针所对应 的函数常被称为"per-object handler","default (signal) handler"或"object methond handler",并将在信号发出后被调用(如调用g_signal_emit_by_name)。常配合宏G_STRUCT_OFFSET使用(该宏能 够返回结构体变量的成员相对于该结构体的变量的首地址的偏移量)。如果设为0,则表示该类没有"per-object handler"。
  • GSignalAccumulator accumulator:该参数是一个函数指针,其对应的函数将在该信号的每个handler执行完以后执行。GSignalAccumulator类型的定义如下:

    点击(此处)折叠或打开

    1. typedef gboolean (*GSignalAccumulator) (GSignalInvocationHint *ihint,
    2.                                          GValue *return_accu,
    3.                                          const GValue *handler_return,
    4.                                          gpointer data);
    从中可以看出该函数指针类型有4个参数:
  • GSignalInvocationHint *ihint:该参数是一个GSignalInvocationHint类型的指针,而GSignalInvocation结构的定义如下:


点击(此处)折叠或打开

  1. typedef struct {
  2.   guint signal_id;
  3.   GQuark detail;
  4.   GSignalFlags run_type;
  5. } GSignalInvocationHint;


其中,signal_id是导致GSignalAccumulator所指函数被调用的signal的ID(因为该信号signal调用了某个 handler)。detail是该signal的detail部分对应的GQuark(其实就是字符串的散列值)。run_type则反映了 handler被调用时signal发射进行到的阶段,其值为 G_SIGNAL_RUN_FIRST,G_SIGNAL_RUN_LAST或G_SIGNAL_CLEANUP。


  • GValue *return_accu:该参数是一个GValue类型的指针,可以被程序员用来返回任何在GType类型系统注册的,带有value_table的类型。
  • const GValue *handler_return:该参数是一个GValue类型的指针,指向一个GValue变量,该变量存储了GSignalAccumulator所 指函数被调用前,信号调用的handler的返回值,可以用g_value_get_*系列函数获取其存储的值。
  • gpointer data:该参数即为g_signal_new的参数gpointer accu_data的值

显然,该函数的返回类型为gboolean。如果其返回值为FASLE,则signal发射过程就会被中止(即不再调用后面的hander),否则会继续 下去。事实上,"delete-event"等带有event后缀的signal就是利用了这一点——这些信号的某个回调函数如果返回了TRUE,则以后 的回调函数就不会被调用。

我们可以看一下"delete-event"的accumulator, _gtk_boolean_handled_accumulator的代码:

点击(此处)折叠或打开

  1. gboolean
  2. _gtk_boolean_handled_accumulator (GSignalInvocationHint *ihint,
  3.                   GValue *return_accu,
  4.                   const GValue *handler_return,
  5.                   gpointer dummy)
  6. {
  7.   gboolean continue_emission;
  8.   gboolean signal_handled;
  9.    
  10.   signal_handled = g_value_get_boolean (handler_return);
  11.   g_value_set_boolean (return_accu, signal_handled);
  12.   continue_emission = !signal_handled;
  13.    
  14.   return continue_emission;
  15. }
           注意,如果该signal有accumulator,该signal的回调函数类型(由c_marshaller反映)必须有返回值,否则该signal不能有accumulator,也即在调用g_signal_new时以NULL作为该形参的实参。
  • gpointer accu_data:该参数将作为用户自定义参数传入accumulator所指向的函数中。
  • GSignalCMarshaller c_marshaller:该参数是一个GSignalCMarshall类型的函数指针,其值反映了回调函数的返回值类型和额外参数类型(所谓“额外参 数”,即指除回调函数中instance和user_data以外的参数)。            

例如,g_closure_marshal_VOID_VOID说明该signal的回调函数为以下的callback类型:

typedef void (*callback)  (gpointer instance, gpointer user_data);

而g_closure_marshal_VOID_POINTER则说明该signal的回调函数为以下的callback类型:

typedef void (*callback)  (gpointer instance, gpointer arg1, gpointer user_data);

如果默认提供的GClosureMarshall中没有你需要的,你可以用glib-genmarshall生成它,具体可参见devhelp中有关glib-genmarshall的说明。

  • GType return_type:该参数的值应为回调函数的返回值在GType类型系统中的ID。
  • guint n_params:该参数的值应为回调函数的额外参数的个数。
  • ...:这一系列的参数的值应为回调函数的额外参数在GType类型系统中的ID,且这一系列参数中第一个参数的值为回调函数的第一个额外参数在GType类型系统中的ID,依次类推。

 

最后,我们来解释一下GSignalFlags中各个特征标志的含义:

  • G_SIGNAL_RUN_FIRST:调用回调函数时,"per-object handler"对应的回调函数将第一个调用
  • G_SIGNAL_RUN_LAST:调用回调函数时,"per-object handler"对应的回调函数将在用户用g_signal_connect连接的回调函数之后调用,并在用户用g_signal_connect_after连接的回调函数之前调用
  • G_SIGNAL_RUN_CLEANUP:调用回调函数时,"per-object handler"对应的回调函数将最后一个调用
  • G_SIGNAL_NO_RECURSE:信号发射时,如果信号的上次发射还没有结束,那么本次信号发射将不再进行,而只是使上次的信号发射重新开始。
  • G_SIGNAL_DETAILED:信号名字可以使用"signal_name::detailed"的形式。
  • G_SIGNAL_ACTION:程序员可以在代码中自由地调用g_signal_emit族的函数来发射信号,而不需要把g_signal_emit族的函数放在一段代码中再来调用。
  • G_SIGNAL_NO_HOOKS:信号发射过程中不支持钩子函数。

 

例子请看cloverprice的文章:《GObject 08: A class with a signal》

传送门:http://cloverprince.javaeye.com/blog/500964

阅读(2090) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~