Why do I get a segmentation fault in my GTK+ signa

2019-01-20 05:12发布

问题:

I am trying to measure the size of a GTK label:

#include <gtk/gtk.h>

static void map_event(GtkWidget *window, gpointer lab) {
    g_print( "In the callback..\n" );
    GtkWidget *label = GTK_WIDGET(lab);
    g_print( "Everything is ok..\n" );
}

static void activate (GtkApplication* app, gpointer user_data)
{
    GtkWidget *window = gtk_application_window_new (app);
    gtk_window_set_title (GTK_WINDOW (window), "Window1");
    gtk_window_set_default_size (GTK_WINDOW (window), 200, 280);
    GtkWidget *grid = gtk_grid_new ();
    gtk_container_add (GTK_CONTAINER (window), grid);
    GtkWidget *label = gtk_label_new("Hello world!");
    gtk_grid_attach(GTK_GRID (grid), label, 0,0,1,1);
    g_signal_connect (window, "map-event", G_CALLBACK(map_event), label);
    gtk_widget_show_all (window);
}

int main (int argc, char **argv) {
    GtkApplication *app = gtk_application_new (
        "org.gtk.example", G_APPLICATION_FLAGS_NONE );
    g_signal_connect( app, "activate", G_CALLBACK(activate), NULL);
    int status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref (app);

    return status;
}

This gives output:

In the callback..
Segmentation fault (core dumped)

If I comment out the line:

GtkWidget *label = GTK_WIDGET(lab);

there is no segmentation fault, the label shows up and the output is:

In the callback..
Everything is ok..

What am I missing here?

回答1:

map-event has following signature, so you are missing GdkEvent* argument:

gboolean
user_function (GtkWidget *widget,
               GdkEvent  *event,
               gpointer   user_data)

Unfortunately, GTK+ is written in C, so it lacks type-safe callback functions, so it's easy to make mistakes such as this.



回答2:

You don't respect the signal signature. Each signal is associated with a pre-defined function prototype you must respect, otherwise you'll just read garbage. Here you just made up out of your mind the callback signature so things won't work as expected.

The signal is like a delicious fruit delivery service. By connecting to that signal, you signed a contract that subscribe you to the fruit delivery service. Fruit will be delivered only when the fruit is ripe. The delivery man will:

  • come in front of your home
  • drop some fruit boxes for you
  • knock at your door
  • go back to its truck

The contract also specifies that:

  • box #1 will contain bananas
  • box #2 will contain apples
  • box #3 will contain oranges

Those boxes are like the arguments of your callback. The map-event takes 3 arguments, thus the 3 boxes.

One day, you hear knocking at the door. You open the door, see the boxes, open box #2 and get annoyed saying "damn, I said I wanted oranges!". The thing is that you're mixing apples and oranges: by contract, oranges are in box #3 and you're looking for them in box #2.

So give a look at the documentation of each signal you want to connect to. That's the only way to write the right callback. Here you forgot one input parameter as well as the return value. In the case of map-event, that return value can be seen as you going to the truck to say if you want to continue or stop the deliveries.