cgobjectgtk4

Gtk4 GObject, ClosureMarshal how can I use "return value"?


"A GClosure represents a callback supplied by the programmer.

It will generally comprise a function of some kind and a marshaller used to call it. It is the responsibility of the marshaller to convert the arguments for the invocation from GValues into a suitable form, perform the callback on the converted arguments, and transform the return value back into a GValue." This is how it is in the documentation.

To test and try it out, I wrote a small program that is intended to use the following structure:

struct GClosure {
  guint in_marshal : 1;
  guint is_invalid : 1;
  void (* marshal) (
    GClosure* closure,
    GValue* return_value,
    guint n_param_values,
    const GValue* param_values,
    gpointer invocation_hint,
    gpointer marshal_data
  );
}

My problem is that I have not yet managed to find a way to use "return-value".

Unfortunately, all my previous attempts ended with a memory error.

Here is the Script:

 
#include<gtk/gtk.h>

typedef struct _MyClosure 
{
    GClosure closure;
    int closure_data;
} MyClosure;

static void
my_closure_finalize(gpointer notify_data, GClosure *closure)
{
    MyClosure * my_closure = (MyClosure*)closure;
    printf("Finalizing closure with closure_data: %d\n",my_closure->closure_data);
}

GValue* my_callback(GClosure *closure, const GValue *param_values)

{   
    MyClosure *my_closure = (MyClosure*)closure;
    printf("In Callback with closure_data. %d\n", my_closure->closure_data);
    if (&param_values[0] != NULL) 
    {
    printf("In Callback with value: %s\n", g_value_get_string(&param_values[0]));
    }
        /* Return */
    GValue value = G_VALUE_INIT;
    g_value_init(&value, G_TYPE_STRING);
    g_value_set_static_string(&value, "The End");
    /* edit */
    printf("Return from Callback %s\n",g_value_get_string(&value));
    return value;

}

static void
my_closure_marshal(GClosure *closure, 
        GValue *return_value, 
        guint n_params_values, 
        const GValue *param_values, 
        gpointer invocation_hint, 
        gpointer marshal_data)
{
    MyClosure *my_closure = (MyClosure*)closure;
    printf("mashalling closure with closure_data. %d\n", my_closure->closure_data);
    if (&param_values[0] != NULL) 
    {
        printf("Callback called with value: %s\n", g_value_get_string(&param_values[0]));
    }
   /* edit */    
  *return_value = my_callback(closure,param_values);
        // Segmentation fault (core dumped)
        /*
        printf("after Callback\n");
        GType type = G_VALUE_TYPE(return_value);
        g_print("Return type %s\n",g_type_name(type));
        g_print("Result in Mashaller %s\n",g_value_get_string(return_value));
        */

}   

MyClosure *
my_closure_new(gpointer data)
{
    GClosure *closure;
    MyClosure *my_closure;
    closure = g_closure_new_simple(sizeof(MyClosure), data);
    my_closure = (MyClosure*)closure;
    my_closure->closure_data = 42; 
    g_closure_add_finalize_notifier(closure,NULL, my_closure_finalize);
    g_closure_set_marshal(closure, my_closure_marshal); 
    return my_closure;
}

int main(int argc, char* argv[])
{
    MyClosure *my_closure = my_closure_new(NULL);
       
    GValue* return_value;
    GValue value = G_VALUE_INIT;
    g_value_init(&value, G_TYPE_STRING);
    g_value_set_string(&value, "Hello");

    g_closure_invoke((GClosure*)my_closure,return_value, 1,&value , NULL);

    /* How can I further process here "return_value" */
    /*It should be the string "The End". */
    
    g_closure_unref((GClosure*)my_closure);

    return 0;
}

Does anyone have an idea?

Having edited according to the proposal of 'Bodo', I get the following result:

mashalling closure with closure_data. 42
Callback called with value: Hello
In Callback with closure_data. 42
In Callback with value: Hello
Return from Callback The End
Segmentation fault (core dumped)

Solution

  • After many attempts, I have now succeeded in creating a test program for using GClosure that no longer generates errors.

    In addition to the indications from @bodo, it was still important, return_value before calling g_closure_invoke((GClosure*)my_closure,return_value, 1,&value , NULL); with GValue * return_value = g_new0(GValue, 1);to create.

    The whole script now looks like this:

    #include<gtk/gtk.h>
    
    typedef struct _MyClosure 
    {
        GClosure closure;
        int closure_data;
    } MyClosure;
    
    static void
    my_closure_finalize(gpointer notify_data, GClosure *closure)
    {
        MyClosure * my_closure = (MyClosure*)closure;
        printf("Finalizing closure with closure_data: %d\n",my_closure->closure_data);
    
    }
    
    gchar *
    my_callback(GClosure *closure, const GValue *param_values)
    {   
        MyClosure *my_closure = (MyClosure*)closure;
        gchar *result;
        printf("Callback use:\n");
        printf(" -- closure_data: %d\n", my_closure->closure_data);
        if (&param_values[0] != NULL) 
        {
            printf(" -- &value:       %s\n", g_value_get_string(&param_values[0]));
            result = g_strdup_printf("%s %d %s",g_value_get_string(&param_values[0]) ,  my_closure->closure_data, "The Ende");
        }
            else
            result = g_strdup_printf("%s" , "The Ende");
    
        /*Return*/
        return result;
    }
    
    static void
    my_closure_marshal(GClosure *closure, 
            GValue *return_value, 
            guint n_params_values, 
            const GValue *param_values, 
            gpointer invocation_hint, 
            gpointer marshal_data)
    {
        MyClosure *my_closure = (MyClosure*)closure;
    
        g_value_init(return_value,G_TYPE_STRING);
        
        gchar *result = my_callback((GClosure*)my_closure,param_values);
    
        g_value_set_string(return_value,result);
    
    }   
    
    MyClosure *
    my_closure_new(int data)
    {
        GClosure *closure;
        MyClosure *my_closure;
        closure = g_closure_new_simple(sizeof(MyClosure), &data);
        my_closure = (MyClosure*)closure;
        my_closure->closure_data = data; 
        g_closure_add_finalize_notifier((GClosure*)my_closure,NULL, my_closure_finalize);
        g_closure_set_marshal((GClosure*)my_closure, my_closure_marshal); 
        return my_closure;
    }
    
    int main(int argc, char* argv[])
    {
        MyClosure *my_closure = my_closure_new(42);
           
        GValue * return_value = g_new0(GValue, 1);
    
        GValue value = G_VALUE_INIT;
        g_value_init(&value, G_TYPE_STRING);
        g_value_set_string(&value, "Hello");
    
        g_closure_invoke((GClosure*)my_closure,return_value, 1,&value , NULL);
    
        g_print("Result: %s\n",g_value_get_string(return_value));
    
        g_value_unset(&value);
        g_free(return_value);
        g_closure_unref((GClosure*)my_closure);
        
        return 0;
    }