Search code examples
gtk2

Why does GTK2's gtk_widget_add_accelerator not add a shortcut sometimes?


I'm seeing this issue where gtk_widget_add_accelerator doesn't work intermittently. Some menu items have a short cut and some don't on a GTK2 application running on Ubuntu 16.04. I installed the symbols and source to see what is going on and the signal check inside gtk_widget_add_accelerator is failing:

g_signal_query (g_signal_lookup (accel_signal, G_OBJECT_TYPE (widget)), &query);
if (!query.signal_id ||
    !(query.signal_flags & G_SIGNAL_ACTION) ||
    query.return_type != G_TYPE_NONE ||
    query.n_params)
{
    /* hmm, should be elaborate enough */
    g_warning (G_STRLOC ": widget `%s' has no activatable signal \"%s\" without arguments",
     G_OBJECT_TYPE_NAME (widget), accel_signal);
    return;
}

So I copied that block of code to just before I call gtk_widget_add_accelerator like this:

const char *Signal = "activate";
GSignalQuery query;
g_signal_query (g_signal_lookup (Signal, G_OBJECT_TYPE (w)), &query);

if (!stricmp(Sc, "Ctrl+C")) // This is the short cut that doesn't work
{
    if (!query.signal_id)
        printf("Bad sig id\n");
    else if (!(query.signal_flags & G_SIGNAL_ACTION))
        printf("No sig act\n");
    else if (query.return_type != G_TYPE_NONE)
        printf("Ret type err\n");
    else if (query.n_params)
        printf("Param err.\n");
    else
        printf("Pre-cond ok.\n");
}

gtk_widget_add_accelerator( w,
                            Signal,
                            Menu->AccelGrp,
                            GtkKey,
                            mod,
                            Gtk::GTK_ACCEL_VISIBLE
                        );

And it prints 'Pre-cond ok.' which means there is a valid signal at my application level but NOT inside the GTK2 library. So is there a build problem? Mismatched headers? IDK.

So I started looking at exactly what I'm building against. The make file uses these flags:

Libs =  \
    -lmagic \
    -static-libgcc  \
    `pkg-config --libs gtk+-2.0`
Inc =  \
    -I./include/common \
    -I./include/linux/Gtk \
    -I/usr/include/gstreamer-1.0 \
    -I/usr/lib/x86_64-linux-gnu/gstreamer-1.0/include \
    `pkg-config --cflags gtk+-2.0` \
    -Iinclude/common \
    -Iinclude/linux \
    -Iinclude/linux/Gtk

Seems pretty standard stuff right?

So I'm somewhat at a loss as to why this isn't working. Any ideas?

For reference this is the code that creates the signal:

Info = GTK_MENU_ITEM(gtk_menu_item_new_with_mnemonic(Txt));

Gtk::gulong ret = Gtk::g_signal_connect_data(Info,
                                            "activate",
                                            (Gtk::GCallback) MenuItemCallback,
                                            this,
                                            NULL,
                                            Gtk::G_CONNECT_SWAPPED);

And the contents of 'query' in my app:

(gdb) p query
$1 = {signal_id = 132, signal_name = 0x7ffff76c4859 "activate", 
  itype = 17714704, 
  signal_flags = (Gtk::G_SIGNAL_RUN_FIRST | Gtk::G_SIGNAL_ACTION), 
  return_type = 4, n_params = 0, param_types = 0x0}

And when I step into the GTK2 library:

(gdb) p query
$3 = {signal_id = 132, signal_name = 0x7ffff76c4859 "activate", 
  itype = 17714704, signal_flags = (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION), 
  return_type = 4, n_params = 0, param_types = 0x0}

But it only gets to that stage after the g_warning line. Maybe that's due to compiler optimization though.


Solution

  • Ok. It seems the debug symbols for Gtk were leading me down the wrong path. I built and installed GTK2 from source and it was much better.

    gtk_widget_add_accelerator is actually doing the right thing and not falling into it's signal error handler. The real issue is that I'm replacing the menu item with a different object in LgiMenuItem::Icon when I convert the item to one that supports an icon as well. This deletes the accelerator that I added earlier. I noticed this when all the missing accelerators had icons.

    So the "solution" as such is to re-add the shortcut after converting the menu item to one that supports an icon. Maybe down the track I'll re-factor the code to be more efficient but at this point I'm just happy it works.