GObject消息系统之Signals

GObject的信号与标准UNIX信号无关:它们将任意特定于应用程序的事件与任意数量的监听者连接起来。 例如,在GTK +中,从窗口系统接收到每个用户事件(按键或鼠标移动),并在窗口小部件对象实例上以信号发射的形式生成GTK+事件。
每个信号在类型系统中与其可以发射的类型一起注册:当用户注册的信号发射时指定的实例类型的闭合被调用。用户还可以自己发射信号,或者从连接到信号的闭合件之一内停止信号的发射。
当给定类型的实例发出信号时,将会调用在此类型实例上连接到该信号的所有闭包。 所有闭包关联的信号回调函数形式如下:

return_type function_callback (gpointer instance, …, gpointer user_data);

1、信号注册

要在现有类型上注册新的信号,我们可以使用g_signal_newv,g_signal_new_valist或g_signal_new函数:
guint g_signal_newv (const gchar        *signal_name,
                     GType               itype,
                     GSignalFlags        signal_flags,
                     GClosure           *class_closure,
                     GSignalAccumulator  accumulator,
                     gpointer            accu_data,
                     GSignalCMarshaller  c_marshaller,
                     GType               return_type,
                     guint               n_params,
                     GType              *param_types);
这些功能的参数数量有点吓人,但是比较简单:
signal_name:可以用于唯一标识给定信号的字符串。
itype:是可以发射此信号的实例类型。
signal_flags:部分定义了调用连接到信号的闭包的顺序。
class_closure:这是信号的默认闭包:如果在信号发射时它不为空,则在信号发射时将被调用。与连接到该信号的其他闭包相比,调用闭合的时间部分取决于signal_flags。
累加器:这是一个函数指针,它在每个闭包被调用后被调用。如果返回FALSE,信号发射停止。如果返回TRUE,则信号发射正常进行。它还用于根据所有调用闭包
的返回值来计算信号的返回值。例如,累加器可以忽略来自闭包的NULL返回;或者它可以构建由闭包返回的值的列表。
cumulative_data:该指针将在发射期间传递给累加器的每次调用。
c_marshaller:这是连接到该信号的任何闭包的默认C编组器。
return_type:这是信号返回值的类型。
n_params:这是该信号所需的参数数。
param_types:这是一个GTypes数组,指示信号的每个参数的类型。这个数组的长度用n_params表示。
2、信号连接:
如果你想连接到一个封闭的信号,你有三种可能性:
(1)您可以在注册类闭包时信号注册:这是一个全系统的操作。 即:在支持该信号的类型的任何实例上发射指定信号时该类闭包将会被调用。
(2)您可以使用覆盖给定类型的类闭包的g_signal_override_class_closure。 只能在信号注册类型的派生类型上调用此函数。 此功能仅适用于语言绑定。
(3)您可以使用g_signal_connect系列函数注册一个闭包。 这是一个实例特定的操作:只有在给定实例发出给定信号时才会调用闭包。
也可以在给定信号上连接不同类型的回调:不论哪个实例何时发出给定信号emission hook都将会被调用。 例如,使用emission hook来使应用程序中的所有鼠标点击能够发出小的鼠标点击声音。 
emission hook使用g_signal_add_emission_hook连接,并使用g_signal_remove_emission_hook进行删除。
3、信号发射
void g_signal_emitv (const GValue *instance_and_params,
                     guint         signal_id,
                     GQuark        detail,
                     GValue       *return_value);
信号发射可以分解5步:
RUN_FIRST:如果在信号注册期间使用了G_SIGNAL_RUN_FIRST标志,并且如果此信号存在类闭包,则会调用类闭包。
EMISSION_HOOK:如果有任何发射hook被添加到信号中,它们将从第一个到最后一次被添加,累积返回值。
HANDLER_RUN_FIRST:如果任何闭包与g_signal_connect系列函数连接,并且如果它们没有被阻止(使用g_signal_handler_block系列函数),那么它们将从第一个连接到最后一个连接运行。
RUN_LAST:如果在注册期间设置了G_SIGNAL_RUN_LAST标志,并且如果设置了类闭包,则在此处调用它。
HANDLER_RUN_LAST:如果任何闭包与g_signal_connect_after系列函数相关联,如果在HANDLER_RUN_FIRST期间未调用它们,并且如果它们未被阻止,则它们将从第一个连接到上一个连接运行。
RUN_CLEANUP:如果在注册期间设置了G_SIGNAL_RUN_CLEANUP标志,并且如果设置了类闭包,则在此处调用它。信号发射在此完成。
如果在发射过程中的任何一点(RUN_CLEANUP状态除外),其中一个闭包或emission hook发射停止信号,并发出g_signal_stop_emission,则发射步骤跳到RUN_CLEANUP状态。
如果在发射期间的任何一点,闭包或emission hook中的一个在相同的情况下发出相同的信号,则发射从RUN_FIRST状态重新开始。
在每个闭包经过每个状态(RUN_EMISSION_HOOK和RUN_CLEANUP除外)之后都会调用累加器函数。它将闭包返回值累加到信号返回值中,并返回TRUE或FALSE。 如果在任何时候它不返回TRUE,则发射跳到RUN_CLEANUP状态。
如果没有提供累加器函数,则最后处理程序运行返回的值将由g_signal_emit返回。
detail参数:
所有与信号发射或信号连接相关的函数都有一个名为“detail”的参数。有时候,这个参数是由API隐藏了,但它总是存在于一种形式中。
在主要connect系列函数中,只有一个具有显式detail参数作为GQuark:g_signal_connect_closure_by_id。
其他函数g_signal_connect、g_signal_connect_closure和g_signal_connect_data等在信号名称标识中隐藏detail参数。它们的detailed_signal参数是一个字符串,用于标识要连接的信号的名称。此字符串的格式为signal_name::detail_name。 例如,连接到名为notify::cursor_position的信号实际上将使用cursor_position细节连接到名为notify的信号。在内部如果细节字符串存在,则将其转换为GQuark。
在四个主要信号发射函数中,g_signal_emit_by_name在信号名称参数中隐藏detail。另外三个有一个显式的detail参数作为GQuark:g_signal_emit,g_signal_emitv和g_signal_emit_valist。
如果使用者向发射函数提供detail参数,那么在发射过程中使用此参数与提供detail参数的闭包相匹配。如果闭包的detail与用户提供的不符,则不会调用它(即使它被连接到被发射过的信号)。
这种完全可选的过滤机制主要用来通常由于许多不同原因而发出的信号的优化:客户端可以在闭包marshalling代码运行之前过滤出感兴趣的事件。例如,GObject的notify信号广泛使用:每当一个属性在GObject上被修改,GObject将这个被修改的属性名称作为detail和信号发送关联起来,而不是只发送notify信号。
这样允许让只希望一个属性有改变被通知的客户在接收信号之前过滤掉大多数事件。
作为一个简单的规则,用户可以并且应该将detail参数设置为零:这将完全禁用该信号的可选过滤。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值