有没有办法忽略信号签名?

时间:2019-05-13 02:52:08

标签: c++ gtk3

我正在尝试使用相同的user_function回调连接一些小部件。在某些情况下,信号具有不同的签名。

我认为搜索我发现gtk_signal_connect_full。

例如我的代码:

int MyObject::connect()
{
    callback_object ....

    // Create the callback
    int ret = g_signal_connect(instance, "clicked", G_CALLBACK (connect_callback), callback_object);
    int ret = g_signal_connect(instance, "button-release-event", G_CALLBACK (connect_callback), callback_object);

    // Return handler id
    return ret;
}

void MyObject::connect_callback(GObject *passedInstance, gpointer param1, gpointer param2)
{
    // Return to st_callback
    struct st_callback *callback_object = (struct st_callback *) param2;
    if(sizeof(param1) == 0) {
        callback_object = (struct st_callback *) param1;
    }

}

我可以像这样“抽象”用户功能吗?如果可以的话,如何获取额外的参数,例如GdkEvent或GdkEventButton或gchar,...

编辑 -这个问题是GTK +问题,因为在第一个g_signal_connect中,param1是我的结构。我还可以,我知道我的结构会回退。在第二个g_signal_connect中,param1是一个GdkEventButton。也可以,因为我知道这是要回退的GdkEventButton。但是,如果我不知道param1是我的结构,如果它是GdkEvent,GdkEventButton,gchar或其他所有可能的正弦签名,该怎么做?

编辑2 -我在Closures doc

上找到了此信息
  

闭包允许被调用方获取回调参数的类型,这意味着语言绑定不必为每种回调类型编写单独的粘胶。

对于我要找的东西来说,这看起来很完美,但是我一无所获

编辑3

关于ebassi想法,我需要g_signal_query。我这样做是为了抽象:

1-使用g_signal_query查询信号的参数,设置为我的结构以通过回调user_data传递 2-使用g_cclosure_new_swap和g_signal_connect_closure连接,这会将gpointer user_data设置为第一个参数 3-创建的回调如下:connect_callback(gpointer user_data, ...),带有可变参数列表 4-内部回调,使用custom + g_signal_query结果返回我的结构 5-循环到GSignalQuery的param_types中,验证每个基本类型 6-使用正确的类型获取va_arg

用于完成回调的完整代码

    // Create gpoint param
    struct st_callback *callback_object = (struct st_callback *)malloc(sizeof(struct st_callback));
    memset(callback_object, 0, sizeof(struct st_callback));

    callback_object->callback_name = callback_name;
    callback_object->callback_params = callback_params;

    // Get params of signal
    GSignalQuery signal_info;
    g_signal_query(g_signal_lookup (callback_signal, G_OBJECT_TYPE (instance)), &signal_info);

    // Save 
    callback_object->signal_id = signal_info.signal_id;
    callback_object->signal_name = signal_info.signal_name;
    callback_object->itype = signal_info.itype;
    callback_object->signal_flags = signal_info.signal_flags;
    callback_object->return_type = signal_info.return_type;
    callback_object->n_params = signal_info.n_params;
    callback_object->param_types = signal_info.param_types;

    GClosure  *closure;
    closure = g_cclosure_new_swap (G_CALLBACK (connect_callback), callback_object, NULL);
    int ret = g_signal_connect_closure (instance, callback_event, closure, TRUE);

和回调

static bool connect_callback(gpointer user_data, ...)
{
    // Return to st_callback
    struct st_callback *callback_object = (struct st_callback *) user_data;

    // get parameters count
    int param_count = callback_object->n_params;
    va_list ap;
    va_start(ap, param_count);

    // loop paramters
    for (int i=0; i<param_count; i++) {

        switch (G_TYPE_FUNDAMENTAL(callback_object->param_types[i])) {
            case G_TYPE_CHAR:

                break;
            case G_TYPE_UCHAR:

                break;
            case G_TYPE_STRING:
            {
                char *path = va_arg(ap, char *);
                break;
            }
            case G_TYPE_OBJECT:

                break;
            case G_TYPE_POINTER:

                break;
            case G_TYPE_INTERFACE: 

                break;
            case G_TYPE_PARAM:

                break;
            case G_TYPE_BOXED:
            {
                // Example, try to cast correct boxed
                GdkEvent *e = va_arg(ap, GdkEvent *);

                break;
            }
        }
    }

    va_end(ap);
}

需要纠正退货和装箱的情况,但是我可以正常工作

1 个答案:

答案 0 :(得分:2)

您不应将相同的函数用于不同类型的回调。某些回调采用不同的参数,而其他回调则具有不同的返回值-例如,在您的示例中,clicked不返回任何值,而button-press-event返回布尔值。

如果您需要在不同的信号处理程序中执行通用代码,请编写一个函数,然后从各个处理程序中调用它。