Widget Destruction

Widget destruction, and resource management in general, is one of the trickier things to get right in a Tk widget implementation. There are more bugs per square foot in this area of the core than anywhere else.

What I'm looking for is a recipe for how to properly handle the widget lifecycle. (When I asked about this on the chatroom, DGP said: "typically there's a "deleted" flag in the struct, and lots of Tcl_Preserve()'s around." But there are apparently no formalized guidelines anywhere...)

There are several cases to handle:

  • The widget instance command is deleted, in which case the command deletion proc is responsible for calling Tk_DestroyWindow (this falls through to the next case)
  • Someone calls Tk_DestroyWindow() on the widget or one of its ancestors, in which case the widget will receive precisely one <Destroy> event. In this case the event handler is responsible for deleting the widget command.
  • Some other process calls XDestroyWindow, in which case the widget will receive precisely one <Destroy> event.
  • A script calls [exit]
  • Someone deletes the Tcl_Interp in which the widget was created

There are probably more ....

more to come ...

Another complication: When the event handler destroys the widget command, thanks to command deletion traces it's possible for the interpreter to be recursively reentered.

TV Wasn't there an issue where a widget doesnt get deleted when unpacked or de-parented because it can reappear, dats like -text can linger around or be prepared based on an invisible widget, so that explicit destroys or redefinitions are needed?

MAK This seems to be mostly about practices for C based widgets, but.. For pure Tcl I typically use Namespace MegaWidgets for collections of widgets that maintain their own data. The version I use has an extra feature in the proc to automatically set up a <Destroy> handler that checks for a commonly-named function in each of the extending namespaces. The namespace has one or more arrays for data storage (keyed off the widget pathname for the megawidget so it can be used with multiple instances), and this event handler takes care of unsetting array elements when the associated megawidget is destroyed. It works pretty much the same way as C++ destructors, but every instance shares the same namespace. It's a poor-man's object orientation for widgets.