Search code examples
cpointersgtk3gtkmm

The pointer in signal_connect function is not working correct


I want to use the g_signal_connect() function to change data in a specific struct/class. So, in my opinion, the best way is to use a pointer to the struct. the problem is that the information of the pointer seems to be changing all the time.

I spent a lot of time to figure out why is that happening, but I have no idea. I can compile and run the code without any error but the output is always different.

Later I want to use several event_box to connect to an array of struct or an array of a class (event_box[0] connect to data[0],...).

I hope someone understands what I mean and I would be happy about any help.

#include<gtk/gtk.h>

struct d
{
bool status;
int ID;
};

void end_program(GtkWidget *wid, gpointer ptr)
{
gtk_main_quit();
}

void box_click(GtkWidget *wid, gpointer user_data)
{
    struct d *data = (struct d*)user_data;
    printf("status  = %i\n", data->status);
    printf("ID      = %i\n", data->ID);
}

int main (int argc, char *argv[])
{
    struct d data;
    data.status = 0;
    data.ID = 1;

    gtk_init(&argc, &argv);

    GtkWidget *win = gtk_window_new (GTK_WINDOW_TOPLEVEL);

    GtkWidget *event_box  = gtk_event_box_new();
    g_signal_connect(G_OBJECT(event_box), "button_press_event", G_CALLBACK(box_click), &data); 

    gtk_container_add(GTK_CONTAINER(win), event_box);
    gtk_widget_show_all(win);
    g_signal_connect(win, "delete_event", G_CALLBACK(end_program),NULL);

    gtk_main();

    return 0;
}

Output if I click the box several times:

status  = 4
ID      = 32193184
status  = 5
ID      = 32193184
status  = 4
ID      = 32193184
status  = 6
ID      = 32193184
status  = 4
ID      = 32193184

Solution

  • I hope someone understands what I mean and I would be happy about any help.

    Well, yes.. You are using the wrong function prototype for a button-press-event. The prototype for a button-press-event is:

    The “button-press-event” signal
    
    gboolean
    user_function (GtkWidget *widget,
                   GdkEvent  *event,
                   gpointer   user_data)
    

    (note: the signal is properly "button-press-event" instead of "button_press_event", though there is a #define allowing the second form to work)

    See GtkWidget (Gtk+3 Manual). So what your function should look like is:

    gboolean box_click(GtkWidget *wid, GdkEvent *event, gpointer user_data)
    {
        struct d *data = user_data;            /* no need for cast, gpointer is void* */
        g_print("status  = %d\n", data->status);
        g_print("ID      = %d\n", data->ID);
    
        return TRUE;    /* to prevent further handling, FALSE otherwise */
    
        (void)wid;      /* cast to void to avoid unused var warning */
        (void)event;
    }
    

    Additional Nits

    Use g_print instead of printf, use gboolean instead of bool. While passing the address of is fine for small structs, for large structs you should allocate with g_slice_new.