While hacking on Empathy, I discovered that most GtkMenu were leaked everywhere in the code. It looks like a common mistake so I decided to blog about it. Maybe other projects are doing that as well. For me it’s something new I learned recently, sorry if everybody was already aware of that 🙂
How it works
gtk_menu_new() returns an initially unowned widget. It means that its refcount is 1 and the floating flag is set. When you call gtk_menu_popup() on it, an ref is temporarily added as long as the menu is shown. That means that its refcount is now 2 and the floating flag is still set.
Popup and forget
If you want to show the menu and forget, then after calling gtk_menu_popup() you have to clear the floating flag using g_object_ref_sink() then drop the ref you own using g_object_unref(). Like that the menu will only have 1 ref that will be dropped as soon as the menu is popped down. So your menu will be finalized.
Reuse your menu
If you want to keep a pointer to your menu to reuse it, you have to attach the menu to a widget, using gtk_menu_attach_to_widget(). That means the widget will become owner of your menu because it calls g_object_ref_sink() and will make sure the GdkScreen on the menu is the same than on the attach widget. So if ‘self’ is your widget on which you want to popup a menu, simply do priv->menu = gtk_menu_new(); gtk_menu_attach_to_widget (menu, self, NULL); then you can do gtk_menu_popup(priv->menu) when you want. Like that your menu will be finalized in the same time as self.
Using GtkUIManager
If your menu comes from a GtkUIManager, then it is already owned by the ui manager. That means that as long as you own a ref to the manager, you can use the menu. I think you should still attach the menu to your widget to make sure the GdkScreen is handled correctly. Can someone confirm this?
Interesting. If I’m using pygtk and at various points creating gtk.Menu() things and calling popup() on them, do I also need to explicitly kill them?
I don’t know how pygtk deals with this. But you shouldn’t care about memory management in python, so probably they do the right thing… or it is a bug in pygtk…