最近想用GTK实现一个系统托盘,我使用的开发工具是Anjuta+Glade,很自然就会用到GtkBuilder。结果问题来了,弹出式菜单显示不了, 出现了如下的错误:
(monitor:3810): Gtk-CRITICAL **: gtk_status_icon_set_visible: assertion `GTK_IS_STATUS_ICON (status_icon)' failed
(monitor:3810): Gtk-CRITICAL **: gtk_menu_popup: assertion `GTK_IS_MENU (menu)' failed
A GtkBuilder holds a reference to all objects that it has constructed and drops these references when it is finalized. This finalization can cause the destruction of non-widget objects or widgets which are not contained in a toplevel window. For toplevel windows constructed by a builder, it is the responsibility of the user to call
gtk_widget_destroy()
to get rid of them and all the widgets they contain.The functions
gtk_builder_get_object()
andgtk_builder_get_objects()
can be used to access the widgets in the interface by the names assigned to them inside the UI description. Toplevel windows returned by these functions will stay around until the user explicitly destroys them withgtk_widget_destroy()
. Other widgets will either be part of a larger hierarchy constructed by the builder (in which case you should not have to worry about their lifecycle), or without a parent, in which case they have to be added to some container to make use of them. Non-widget objects need to be reffed withg_object_ref()
to keep them beyond the lifespan of the builder.
原来GtkStatusIcon和GtkMenu一个是non-widget,一个是widget,但不是toplevel,一旦GtkBuilder的对象被回收,它们也会被释放.所以在使用完GtkBuilder后,我们不能让系统将它回收,不然,GtkStatusIcon和GtkMenu的对象也会被释放的。因此,将g_object_unref改成g_object_ref,让GtkBuilder的reference count不为0,等到释放GtkStatusIcon和GtkMenu对象后,系统就会回收GtkBuilder对象的。在这里,也不能不加g_object_ref,不然,就很容易造成内存泄漏。