GObject 信号机制——信号连接[转]

参考文档

原文链接

文档 [1, 2] 讲述了 GObject 信号注册的相关细节,本文进一步分析信号与闭包的关联问题,即信号连接。
事实上,在文档 [1, 2] 中我们已对信号连接有所接触,例如:

g_signal_connect (sd_obj, "hello",
                          G_CALLBACK (my_signal_handler),
                          userdata);

g_signal_connect 是一个宏,用于信号与回调函数的连接。在这个宏的内部,通过 g_signal_connect_data 函数将回调函数封装为闭包,并关联到指定的信号。

使用 g_signal_connect 为信号设定的闭包会在信号的默认闭包执行之前被调用,且 g_signal_connect 的第 4 个参数是用户传递给闭包的参数,它是一个 void * 类型的万能指针。

还有一个宏 g_signal_connect_after,它为信号设定的闭包会在信号的默认闭包执行之后被调用。

注意,上文接连两次提到“信号的默认闭包”,文档 [1] 对此有较为详细的阐释,即信号注册阶段与信号相连接的闭包,通常是信号所属对象的某个方法。

对于 GObject 的普通用户而言,上述知识已足够。

在文档 [3] 中,为了能够在 GtkWidget 对象对应的 X 窗口构建完毕后的某个恰当的时机正确生成 GLXContext 渲染环境,我们选择了 “show” 信号。事实上,GtkWidget 对象有一个“realize”信号,与该信号连接的闭包会在 GtkWidget 对象的 X 窗口创建时被调用。如果我们使用 g_signal_connect 连接 “realize” 信号,那么我们定义的闭包会先于“realize”信号的默认闭包(即 GtkWidget 对象的 realize 方法)被调用,因此不能正确生成 GLXContext 渲染环境,这就是我们为什么选择了“show”信号的主要原因。但是,如果我们使用 g_signal_connect_after 连接“realize”信号,那么 GtkWidget 对象的 realize 方法会先于我们的闭包被调用,因此也可以正确的生成 GLXContext 渲染环境。