I am creating a plug-in to a GTK3 program. This plug-in can be enabled or disabled at runtime. When enabled, it should populate its GUI in a given area (a GtkBin) in the host program. When disabled, it should remove itself from that area.
This simple program depicts the usage:
#!/usr/bin/python2
from gi.repository import Gtk
window = Gtk.Window()
class Plugin(object):
def __init__(self, host):
assert(isinstance(host, Gtk.Bin))
self.host = host
self.guest = None
def enable(self):
box = Gtk.Box(orientation = Gtk.Orientation.VERTICAL)
for x in range(10):
box.add(Gtk.Button("Button {}".format(x)))
self.guest = box
self.host.add(self.guest)
def disable(self):
self.host.remove(self.guest)
# self.guest.destroy() # is this better?
self.guest = None
plugin = Plugin(window)
plugin.enable()
#plugin.disable()
window.connect("destroy", Gtk.main_quit)
window.show_all()
Gtk.main()
I wish that when the plug-in is disabled, all widgets it added to the host should be properly disposed.
I have found this question quite similar: Free object/widget in GTK? It proposed gtk_container_remove
and gtk_widget_destroy
. But I am worrying:
Consider gtk_container_remove
. It removes the direct child of the host container. In my case, the child is also a composition of many other widgets and they may be referencing each other. Will removing the direct child enough for all the widgets to be disposed?
Consider gtk_widget_destroy
. It is recursive and appears to be what I need, but also seems too brutal. Is this really necessary to manually destroy a widget? Would it be better to leave that job to the reference-counter?
I am willing to hear the "best practice" for this case.
Best practice is to never rely on a garbage collector to collect an object that controls a limited resource in a timely fashion. It could delay collecting any particular garbage indefinitely. You wouldn't want to leave a file open for the garbage collector to clean up, because there's a limit to the number of file handles you can have open at once.
It happens that Python's garbage collector has a reference counter and will free objects with no references immediately, but that is an implementation detail. If you use another implementation, such as PyPy or IronPython, this does not apply. I've had a program break when I moved it to another implementation, because I had inadvertently relied on Python's reference counting to clean up resources. Also, you can end up with bugs that happen because you accidentally create a cycle somewhere.
I don't know of any best practices for widgets specifically. I hadn't considered the possibility that I should be cleaning those up. If a widget has a window associated with it, that is an OS handle that you should theoretically clean up. Usually, only a GtkWindow will have a real window, but it's possible for your plugin to create a widget with a window. So, I would say that in that one specific unlikely case, you should theoretically destroy the widget. Otherwise, it's fine to destroy them manually if you don't need them, but I would say don't go out of your way to do so.