0

I have a struct that looks like the one below

struct dc_callback
{ 
    int
    my_configure_event(
        GtkWidget *widget,
        GdkEventConfigure *event,
        struct LoadData *myData)
    {
        ...others

        return TRUE;
    }

    //Parametrized Constructor 
    int
    my_draw(
        GtkWidget *widget,
        cairo_t *cr,
        struct LoadData *myData)
    {
        ...others
        return TRUE;
    }
};

It has two parametrized member function that I intend to call from g_signal_connect for some nth time.

main(){
    int i;
    dc_callback dc_callback_instance[nth];
    for(i=0;i<nth;i++){
        g_signal_connect(widget_list[i],"draw",G_CALLBACK(dc_callback_instance[i].my_draw),myData);
        g_signal_connect(widget_list[i],"configure-event",G_CALLBACK(dc_callback_instance[i].my_configure_event),myData);
    }
}

However, during compile time, I get an error regarding invalid use of member function int dc_callback::my_draw(args). It ask me to add () but that could not be done since the G_CALLBACK accepts function name without its attached argument.

How to I accomplish this?

Jones G
  • 301
  • 5
  • 17
  • That is not how callback works, callbacks are pointer to function. If you need to customize the behavior of each callback, use the user_data (myData in your case) –  Oct 10 '19 at 18:19
  • Possible duplicate of [How can I pass a member function where a free function is expected?](https://stackoverflow.com/questions/12662891/how-can-i-pass-a-member-function-where-a-free-function-is-expected) – Yksisarvinen Oct 10 '19 at 18:32
  • @Nico238 while that is applicable, the callback requires a unique function for each behavior you intend, it might sound unusual, then that might be a bug, that is why I need to pass a unique function by using a struct. – Jones G Oct 10 '19 at 19:31
  • @JamesGuana I'm sure to understand what you mean by "the callback requires a unique function for each behavior you intend". When you connect a callback, you have to give a function pointer (which dc_callback_instance[i].my_draw is not). You can set a different behavior to each widget by giving a different user data to each wigdet with the same function –  Oct 10 '19 at 20:03
  • Hi, yes we did that, but its not working, it registers the last behavior for all the widget. I think this is a bug. I believe you are the best person to help us here https://gitlab.gnome.org/GNOME/gnome-system-monitor/merge_requests/11#note_620737 – Jones G Oct 10 '19 at 20:16
  • @JamesGuana I've added comments in gitlab –  Oct 10 '19 at 20:43

2 Answers2

2

The answer of @0x5453 is correct except for my_draw_cbk and its call : it shall be

gboolean my_draw_cbk ( GtkWidget *widget,
        cairo_t *cr,
        struct CallbackData *cbData)
{
    cbData->dc_callback_inst.my_draw(widget, cr, cbData->otherData);
    return TRUE;
}

and to connect the signal :

 // cbData shall be free with g_free when no longer needed
 CallbackData* cbData = g_new(CallbackData, 1); 
 // set the cbData values..
 g_signal_connect(widget_list[i],"draw",G_CALLBACK(my_draw_cb),cbData);
1

G_CALLBACK expects a (non-member) function pointer, and you are not using the proper syntax for passing a function pointer. However, there is a bigger issue: Function pointers and member function pointers are different concepts in C++. You cannot pass a member function pointer to an interface that expects a standard function pointer. So, how to associate the invocation of the callback with your dc_callback instance?

Traditionally when working with C-style API's, you have to provide a free function for the callback that takes your instance (and any extra data) as a void* parameter. Then inside the callback, you can cast the void* back to the original type. In your case, this could look something like:

struct CallbackData {
    dc_callback& dc_callback_inst;
    Foo otherData; // whatever else you need to capture here
};

void my_draw_cb(void* data) { // g_signal_connect might pass more params to cb in addition to data
    CallbackData& cbData = *(CallbackData*)data;
    cbData->dc_callback_inst.my_draw(cbData->otherData);
}

// ...
for(i=0;i<nth;i++){
    CallbackData cbData{dc_callback_instance[i], myData};
    g_signal_connect(widget_list[i],"draw",G_CALLBACK(&my_draw_cb),cbData);
    // ...
}
0x5453
  • 12,753
  • 1
  • 32
  • 61
  • I get this error during compile time: cannot convert ‘CallbackData’ to ‘gpointer’ {aka ‘void*’} – Jones G Oct 10 '19 at 19:45