I'm using GTK+ in my paid work, which is being cool because I like this library. It's not the first time I use it for paid work, and I like these opportunities to learn more about it and possibly report bugs. It's not easy to find bugs in such a widely used library, so much of them end up being simple cosmetic mistakes, like this one. Some others are only a question of interpretation, like this other, which even when I submitted a patch, it was not applied.

Yesterday I couldn't make popup-menu create a, well, popup menu. It was working with button-press-event, but not with popup-menu. I created a small code sample to illustrate this problem and asked about it in #pygtk@irc.gimp.org --- yes, I'm using Python:

import gtk
import gobject

def menu():
  item = gtk.ImageMenuItem('gtk-add')
  item.show()

  menu = gtk.Menu()
  menu.add(item)

  return menu

def on_view_popup_menu(obj, *data):
  print 'popup-menu'
  menu().popup(None, None, None, 0, 0)

def on_view_button_press_event(obj, *data):
  print 'button-press-event'
  menu().popup(None, None, None, 0, 0)

store = gtk.ListStore(gobject.TYPE_STRING)
store.append(('teste',))

view = gtk.TreeView(store)
view.append_column(gtk.TreeViewColumn('Coluna', gtk.CellRendererText(), text=0))
view.connect('button-press-event', on_view_button_press_event)
view.connect('popup-menu', on_view_popup_menu)
view.show()

window = gtk.Window()
window.add(view)
window.show()

gtk.main()

When I clicked in the window, with any button in this case, 'button-press-event' is printed to stdout and the menu is displayed. When I press the Menu key, or Shift+F10, 'popup-menu' is printed to stdout, but the menu is not displayed. After getting no response in #pygtk, I decided to try #gtk+. Before that, I thought about trying the same problem in C to see if it was not a problem in the bindings, or in how I was using it. The code:

#include <gtk/gtk.h>

GtkMenu *menu() {
  GtkImageMenuItem *image_menu_item =
      GTK_IMAGE_MENU_ITEM(
          gtk_image_menu_item_new_from_stock(GTK_STOCK_ADD, NULL));
  gtk_widget_show(GTK_WIDGET(image_menu_item));

  GtkMenu *menu = GTK_MENU(gtk_menu_new());
  gtk_container_add(GTK_CONTAINER(menu), GTK_WIDGET(image_menu_item));

  return menu;
}

void on_tree_view_popup_menu(GtkWidget *widget, gpointer user_data) {
  printf("popup-menu\n");
  gtk_menu_popup(
      menu(), NULL, NULL, NULL, NULL, 0, gdk_event_get_time(NULL));
}

void
on_tree_view_button_press_event(
  GtkWidget *widget, GdkEventButton *event, gpointer user_data) {
  printf("button-press-event\n");
  gtk_menu_popup(
      menu(), NULL, NULL, NULL, NULL, 0, gdk_event_get_time(NULL));
}

int main(int argc, char **argv) {
  gtk_init(&argc, &argv);

  GtkListStore *list_store = gtk_list_store_new(1, G_TYPE_STRING);
  GtkTreeIter iter;
  gtk_list_store_append(list_store, &iter);
  gtk_list_store_set(list_store, &iter, 0, "teste", -1);

  GtkTreeView *tree_view =
      GTK_TREE_VIEW(
          gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store)));
  gtk_tree_view_append_column(
      tree_view,
      gtk_tree_view_column_new_with_attributes(
          "Coluna", gtk_cell_renderer_text_new(), "text", 0, NULL));
  g_signal_connect(
      tree_view, "popup-menu", G_CALLBACK(on_tree_view_popup_menu), NULL);
  g_signal_connect(
      tree_view,
      "button-press-event",
      G_CALLBACK(on_tree_view_button_press_event),
      NULL);
  gtk_widget_show(GTK_WIDGET(tree_view));

  GtkWindow *window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
  gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(tree_view));
  gtk_widget_show(GTK_WIDGET(window));

  gtk_main();
}

Wow. The difference between the codes is impressive. I'm not that used to code in GTK+ using C, and I may have missed something here, but the C code is so verbose that I get tired only by looking at it. I'm glad we have other languages, and GTK+ bindings for them. As expected, the behavior was the same, and I asked in #gtk+ and got no answer.

Yes, I did read the documentation before asking, and no, I didn't read it carefully enough. Maybe because of coming from Python, I didn't checked very much the type of the callback function for the signals, and didn't notice the point about the return value: "Returns: TRUE if a menu was activated". And that was not where I was looking for the problem, since I thought the return value was usually related to the treatment of the signal by another functions. Anyway, I changed the type of on_tree_view_popup_menu to return gboolean and returned TRUE. It works! I also updated the type of on_tree_view_button_press_event to do the same, just for compliance. In Python, a simple return True would do it.

I know I could use the event parameter in on_tree_view_button_press_event, but the point was exactly to run the same code and see if it would work in one case and not in the other, as happened.

The popup failing to appear is related to the default handling of the popup-menu signal [1]. You need to prevent the popup-menu event propagating to the default handler, so on_view_popup_menu must return True. This is somewhat implied by the documentation about the popup-menu signal.

[1] I can't state exactly how, as following the logic in the gtk+ code-base requires care and attention, both of which are in short supply at this late in the week.

Comment by Anonymous Sex 10 Dez 2010 12:26:53 UTC