八、GObject信号机制

1 编写SignalDemo类

/* file name : signal-demo.h */
#ifndef SIGNAL_DEMO_H
#define SIGNAL_DEMO_H
  
#include <glib-object.h>
  
#define SIGNAL_TYPE_DEMO (signal_demo_get_type ())
#define SIGNAL_DEMO(object) \
        G_TYPE_CHECK_INSTANCE_CAST ((object), SIGNAL_TYPE_DEMO, SignalDemo)
#define SIGNAL_IS_DEMO(object) \
        G_TYPE_CHECK_INSTANCE_TYPE ((object), SIGNAL_TYPE_DEMO))
#define SIGNAL_DEMO_CLASS(klass) \
        (G_TYPE_CHECK_CLASS_CAST ((klass), SIGNAL_TYPE_DEMO, SignalDemoClass))
#define SIGNAL_IS_DEMO_CLASS(klass) \
        (G_TYPE_CHECK_CLASS_TYPE ((klass), SIGNAL_TYPE_DEMO))
#define SIGNAL_DEMO_GET_CLASS(object) (\
                G_TYPE_INSTANCE_GET_CLASS ((object), SIGNAL_TYPE_DEMO, SignalDemoClass))
  
typedef struct _SignalDemo SignalDemo;
struct _SignalDemo {
        GObject parent;
};
  
typedef struct _SignalDemoClass SignalDemoClass;
struct _SignalDemoClass {
        GObjectClass parent_class;
        void (*default_handler) (gpointer instance, const gchar *buffer, gpointer userdata);
};
  
GType signal_demo_get_type (void);
 
#endif
/* file name : signal-demo.c */
#include "signal-demo.h"

G_DEFINE_TYPE (SignalDemo, signal_demo, G_TYPE_OBJECT);

static void
signal_demo_default_handler(gpointer instance, const gchar *buffer, gpointer userdata)
{
  g_printf("Default handler said: %s\n", buffer);
}

void signal_demo_init(SignalDemo *self)
{

}

void
signal_demo_class_init(SignalDemoClass *klass)
{
  klass->default_handler=signal_demo_default_handler;
  g_signal_new ("hello",
                G_TYPE_FROM_CLASS (klass),
                G_SIGNAL_RUN_FIRST,
                G_STRUCT_OFFSET (SignalDemoClass, default_handler),
                NULL,
                NULL,
                g_cclosure_marshal_VOID__STRING,
                G_TYPE_NONE,
                1, 
                G_TYPE_STRING);
}
/* file name : main.c */
#include "signal-demo.h"

static void
my_signal_handler(gpointer *instance, gchar *buffer, gpointer userdata)
{
  g_printf ("my_signal_handler said: %s\n", buffer);
  g_printf ("my_signal_handler said: %s\n", (gchar *)userdata);
}

int
main(void)
{
  g_type_init();
  gchar *userdata = "This is userdata";
  SignalDemo *sd_obj = g_object_new(SIGNAL_TYPE_DEMO, NULL);

  /* 信号连接 */
  g_signal_connect(sd_obj, "hello",
                   G_CALLBACK (my_signal_handler),
                   userdata);

  /* 发射信号 */
  g_signal_emit_by_name (sd_obj, 
                          "hello", 
                          "This is the second param", 
                          G_TYPE_NONE);

  return 0;
}

2 分析 g_signal_new 函数的参数

  • Param 1 :字符串"hello",它表示信号
  • Param 2:SignalDemo类的类型ID,可以使用 G_TYPE_FROM_CLASS 宏从 SignalDemoClass 结构体中获取,也可直接使用 signal-demo.h 中定义的宏 SIGNAL_TYPE_DEMO。
  • Param 3:两个闭包的先把运行顺序。
  • Param 4:它是一个内存偏移量,主要用于从 SignalDemoClass 结构体中找到 default_handler 指针的位置,可以使用 G_STRUCT_OFFSET 宏来获取,也可以直接根据 signal-demo.h 中的 SignalDemoClass 结构体的定义,使用 sizeof (GObjectClass) 来得到内存偏移量,因为 default_handler 指针之前只有一个 GObjectClass 结构体成员。
  • Param 5:NULL
  • Param 6:NULL
  • Param 7:事实上 marshal 主要是用来“翻译”闭包的参数和返回值类型的,它将翻译的结果传递给闭包。之所以不直接调用闭包,而是在其外加了一层 marshal 的包装,主要是方便 GObject 库与其他语言的绑定。例如,我们可以写一个 pyg_closure_marshal_VOID__STRING 函数,其中可以调用 python 语言编写的“闭包”并将其计算结果传递给 GValue 容器,然后再从 GValue 容器中提取计算结果。
  • Param 8:marshal 函数的返回值类型。由于本例的第 7 个参数所指定的 marshal 是 g_cclosure_marshal_VOID__STRING 函数的返回值是 void,而 void 类型在 GObject 库的类型管理系统是 G_TYPE_NONE 类型。
  • Param 9:指定 g_signal_new 函数向 marshal 函数传递的参数个数,由于本例使用的 marshal 函数是 g_cclosure_marshal_VOID__STRING 函数,g_signal_new 函数只向其传递 1 个参数。
  • Param 10:是可变参数,其数量由第 8 个参数决定,用于指定 g_signal_new 函数向 marshal 函数传递的参数类型。由于本例使用的 marshal 函数是 g_cclosure_marshal_VOID__STRING 函数,并且 g_signal_new 函数只向其传递一个参数,所以传入的参数类型为 G_TYPE_STRING(GObject 库类型管理系统中的字符串类型)。

3 g_cclosure_marshal_VOID__STRING约定的回调函数

  g_cclosure_marshal_VOID__STRING是g_signal_new的参数。需要注意,g_cclosure_marshal_VOID__STRING 所约定的回调函数类型为:

void (*callback) (gpointer instance, const gchar *arg1, gpointer user_data)
  • Param 1:信号的默认闭包(信号注册阶段出现)和信号使用者提供的闭包(信号连接阶段出现)所必须的,但是这个参数是隐式存在的,由g_signal_new暗自向闭包传递。
  • Param 2:参数是显式的,同时也是信号的默认闭包和信号使用者提供的闭包所必须的,这个参数由信号的发射函数(例如 g_signal_emit_by_name)向闭包传递,本文中是”This is the second param"。
  • Param 3:第 3 个参数也是显式的,且只被信号使用者提供的闭包所关注,这个参数由信号的连接函数(例如 g_signal_connect)向闭包传递
  • gchar *userdata = “This is userdata”;。
      总的来说,发射信号后会运行两个闭包,一个是用户自定义的闭包(通过g_signal_connect传入的闭包),另一个是新建信号的时候传入的闭包(g_signal_new传入的闭包)。
      闭包的第二和第三个参数分别是g_signal_emit_by_name的第三个参数和g_signal_connect第三个参数传入。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值