ccallbackgtk

Passing more than one variable into G_CALLBACK callback function when signal is triggered


I want to pass additional arguments into a function when using G_CALLBACK, for example this is a simple line of code that will trigger callback_function when the popup button is clicked:

GtkWidget *mini_button(const gchar * pixmapfile, const gchar * tooltip)
{
    GtkWidget *button;
    GtkWidget *image;
    gchar *path;
    
    path = icon_file_name(pixmapfile);
    image = gtk_image_new_from_file(path);
    g_free(path);
    
    button = gtk_button_new();
    gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
    gtk_widget_set_tooltip_text(button, tooltip);
    gtk_container_add(GTK_CONTAINER(button), image);
    
    return button;
}
    
popup_button = mini_button("some_icon.png", "Options");
g_signal_connect(popup_button, "clicked", G_CALLBACK(callback_function), widget);

By right, I understand that the callback_function should look something like this:

static void callback_function(GtkWidget * button, gpointer data)
{
    // Do something
}

However, I want to be able to pass additional variables into the callback_function which will be used by the callback_function to do additional operation based on the variable passed:

static void callback_function(GtkWidget * button, gpointer data, gint i)
{
    // Do something with i
}

What is the correct way to approach this?


Solution

  • You can utilize the gpointer data parameter of the callback to pass as many values as you need:

    1. Create a struct with all the values you need, e.g.:
      typedef struct {
          gint        i;
          // ...
      } MyValues;
      
    2. Create an object of that struct with the values, and pass its address as an argument for gpointer data of the callback when you register the callback:
      MyValue myVals;
      // Initialize myVals.i etc.
      //...
      //-----------------------------------------------------------------------vvvvvvv-
      g_signal_connect(popup_button, "clicked", G_CALLBACK(callback_function), &myvals);
      
    3. In the callback cast gpointer data back to MyValues* and access the values:
      static void callback_function(GtkWidget * button, gpointer data) {
          MyValues* pMyVals = (MyValues*)data;
          // Use pMyVals->i etc.
      } 
      

    Note: the myVals object MUST outlive the callback calls that will use it.