Mikumiku747
Mikumiku747

Reputation: 51

GTK2 callback data getting lost (set to 0/garbage)

I'm making a OneNote-like application in GTK, but I've run into a problem implementing something basic. I've got a menu button for loading in a file to work on, but for some reason, the data I'm sending storing with my callbacks isn't getting retreived by GTK when it runs the callback. I've used GDB to track the problem down, and it seems that whenever any of my callback functions get called, the data argument is always zero, regardless of what I set it to when I connect the callback to a signal.

Here's a few snippets of what I think the relevant code, but the full source is at a GitHub repo here.

notekeeper.c (The main program logic file. I create the main window, the other widget which I need a reference to, and the array to hold those references. Then I proceed to set up the menu.)

/* Storage variables for some important widgets */
GtkWidget *topWindow;
GtkWidget *sectionNotebook;
GtkWidget *important[2];
...
/* Set up the main window */
topWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
...
/* Add the section notebook */
sectionNotebook = gtk_notebook_new();
...
/* Set up the menu */
important[0] = topWindow;
important[1] = sectionNotebook;
menuBar = setupMenu(important);

menu.c (Where I create the menu bar and link the callbacks to the menu buttons. I used the debugger to check, and the reference to the main window and sectionNotebook still seem to be valid when they get used as data for the callback.)

GtkWidget *setupMenu(GtkWidget **importantWidgets) {
    ...
    FileMenuItems[0] = gtk_menu_item_new_with_mnemonic("Open");
    g_signal_connect(FileMenuItems[0], "activate", 
        G_CALLBACK(fileMenuOpenCallback), 
        (gpointer)importantWidgets);
    ...
}

callbacks.c (Where I'm implementing widget callback routines for various widgets.) This is where I seem to be having problems...

gint fileMenuOpenCallback(GtkWidget *widget, GdkEvent *event, 
gpointer calldata) {
    GtkWidget *openNotebookDialog;
    char *filename;
    GtkWidget **importantWidgets = (GtkWidget**)calldata;

    openNotebookDialog = gtk_file_chooser_dialog_new("Open Notebook...", 
        GTK_WINDOW(importantWidgets[0]), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, 
        GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
        NULL);
    ...
}

I put in a breakpoint at the third line of the callback, as well as a few other places in the code, and used gdb to see what the values of some variables were. Here's what happened when I used gdb:

GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1
Reading symbols from bin/notekeeper...done.
(gdb) b notekeeper.c:46
Breakpoint 1 at 0x80490f3: file src/notekeeper.c, line 46.
(gdb) b menu.c:37
Breakpoint 2 at 0x804945b: file src/menu.c, line 37.
(gdb) b callbacks.c:38
Breakpoint 3 at 0x8049319: file src/callbacks.c, line 38.
(gdb) run
Starting program: [PROJECT DIRECTORY]/bin/notekeeper 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/i686/cmov/libthread_db.so.1".
Gtk-Message: Failed to load module "canberra-gtk-module"

Breakpoint 1, main (argc=1, argv=0xbffff3f4 "x\365\377\277")
    at src/notekeeper.c:46
46      topWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
(gdb) next
47      g_signal_connect(G_OBJECT(topWindow), "delete_event", 
(gdb) print topWindow
$1 = (GtkWidget *) 0x8072248
(gdb) continue
Continuing.

Breakpoint 2, setupMenu (importantWidgets=0xbffff324) at src/menu.c:37
37      FileMenuItems[0] = gtk_menu_item_new_with_mnemonic("Open");
(gdb) print importantWidgets
$2 = (GtkWidget **) 0xbffff324
(gdb) print importantWidgets[0]
$3 = (GtkWidget *) 0x8072248
(gdb) continue
Continuing.

Breakpoint 3, fileMenuOpenCallback (widget=0x80abc28, event=0xbffff324, 
    calldata=0x14) at src/callbacks.c:38
38      GtkWidget **importantWidgets = (GtkWidget**)calldata;
(gdb) p calldata
$4 = (gpointer) 0x14
(gdb) p (GtkWidget **)calldata
$5 = (GtkWidget **) 0x14
(gdb) p (GtkWidget **)calldata[0]
Attempt to dereference a generic pointer.
(gdb) continue
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x08049329 in fileMenuOpenCallback (widget=0x80abc28, event=0xbffff324, 
    calldata=0x14) at src/callbacks.c:42
42          GTK_WINDOW(importantWidgets[0]), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, 
(gdb) kill
Kill the program being debugged? (y or n) yes
(gdb) 

We can see at breakpoint 1 that topWindow (Which is the value I'm trying to use in my callback) gets set to a real address. Then, at breakpoint two, we're inside the setupMenu function, where I set up the menubar and connect the signals to the callbacks for the menu.

After that, the application appears onscreen and I click on the Open button on the menu, causing it to run my callback. This is where breakpoint 3 stops the application. You can see here that the function argument for my data is 0x14 at this point, and doesn't point to my list of widget references any more. I even cast it back into the proper type like in the program and try to reference it, but the debugger won't do it. So, I continue, and the program tries to use the value, but of course, it's broken, and I get a segfault for trying to access some memory I shouldn't.

I'm not really concerned too much with the crash, because I can stop it from crashing by putting NULL in instead of GTK_WINDOW(importantWidgets[0]) which should be a reference to my root window. My main concern is why the data argument, calldata in this case, is getting set to 0x14. I'm assigning it a completely different value when I connect the signal to the callback, so I'm not sure what's happening. Has this data argument been deprecated or removed in GTK2? Or is it functioning properly and I'm using it wrong. I'd just like to know why GTK is behaving the way it is.

In order to test my theory, I even added some dummy data to one of the other callback functions, which just runs gtk_main_quit(). But when I debugged with GDB, the dummy data wasn't there. It was set to 0 again, or some other small number. So the problem seems to affect all of GTK.

If you have any ideas, please let me know, I'm kind of new to GTK, so I'm wondering why it seems to be behaving erratically like this, and whether it's my fault or there's a bug in GTK. Again, the full code is in the Github repo if you need to take a closer look or run it for yourself. It should just need autoconf, make, a C compiler, GTK2 (not 3) and libxml2 to build and run.

Upvotes: 1

Views: 94

Answers (1)

Mikumiku747
Mikumiku747

Reputation: 51

See Johannes' comment on the original post. It turns out not all GTK signals have the same callback function arguments. This one doesn't have a GDKEvent argument. Thanks for the help!

Upvotes: 1

Related Questions