1

I have a callback function that needs to access several GTK widgets. To enable this I am trying to send pointers to the relevant GTK widgets packaged in a structure as an argument to the callback function (instead of using global variables to enable access). To structure the data in a nice way I use a structure of pointers to structures of pointers to GTK widgets.

My problem is that I get segmentation fault when trying to read from or write to the GTK widgets in the callback function. How can I avoid this? As I just started learning C and GTK my approach may be inappropriate altogether, so I would also appreciate pointers on the more general of problem of accessing several GTK widgets from callback functions.

In trying to fix the problem I have managed to boil down the code that presents the problem to the following. It segfaults when changing the value of the spinbutton. It also segfault if one lets the last line in widget_change_value execute instead.

/* Compile with gcc foo.c `pkg-config --cflags --libs gtk+-2.0` */
#include <gtk/gtk.h> /* Get e.g. via sudo apt-get install libgtk2.0-dev */

typedef struct {
    GtkWidget *widget;
} s_input;

typedef struct {
    s_input *input;
} s_data;

void widget_change_value(s_data *data) {
    /* Segfault when trying to read from data  */
    int number = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(data->input->widget));

    /* /\* Segfault when trying to write to data *\/ */
    /* gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->input->widget), (gdouble) 2.0); */
}

int main(int argc, char *argv[])
{
    GtkWidget *window;
    s_input input;
    s_data data = { &input };

    gtk_init(&argc, &argv);

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    input.widget = gtk_spin_button_new_with_range(0, 3, 1);
    gtk_container_add(GTK_CONTAINER(window), input.widget);
    g_signal_connect(GTK_OBJECT(input.widget), "value_changed", GTK_SIGNAL_FUNC(widget_change_value), (gpointer *) &data);

    gtk_widget_show_all(window);
    gtk_main();

    return 0;
}
4

1 回答 1

3

Your crash is because your callback function's prototype is all wrong.

You have:

void widget_change_value(s_data *data);

but looking at the docs, the value-changed signal handler callback is declared as:

void user_function(GtkSpinButton *spinbutton, gpointer user_data);

You need to add the missing widget pointer argument.

Also:

  1. Your callback should be static, since it's very local to the C file it's in.
  2. You don't need to cast things to gpointer.
  3. The cast to (gpointer *) is doubly wrong, since you're passing a pointer (&data) which you want to convert to gpointer, not to "pointer to gpointer". The asterisk is wrong. But, as I said above, the entire cast is pointless and should be removed.
  4. Consider porting to a more recent GTK+ version, you're using some obsolete things (GTK_OBJECT() instead of G_OBJECT(), GTK_SIGNAL_FUNC() instead of G_CALLBACK(), for instance).
于 2012-10-31T11:57:32.083 回答