Because your custom interface is associated with an iTool, destruction of the interface may entail shutting down and cleaning up the entire iTools system. This means that in addition to normal cleanup of pointers and objects used by the interface, you will need to instruct the iTools system to shut itself down when your interface is destroyed.
You must set the TLB_KILL_REQUEST_EVENTS keyword when creating the top-level widget base that holds your interface. With this keyword set, when the user destroys the top-level base, a WIDGET_KILL_REQUEST event is generated, allowing you to perform the actions necessary to shut down the iTools system.
When the user destroys the top-level base of your custom interface, you may want to prompt the user to save the current iTool state before shutting down. The standard iTool interface uses an iTool system service named "Shutdown" to both prompt the user for confirmation that a shutdown is requested and offer to let the user save the current state. The Shutdown service then handles other cleanup tasks before exiting the iTool.
The following code, from the event handling routine in the
example2_wdtool.pro interface definition (developed in Example: a Custom iTool Interface), calls the iTools Shutdown service.
; Destroy the widget. 'WIDGET_KILL_REQUEST': BEGIN ; Get the shutdown service and call DoAction. ; This code must be here, and not in the _cleanup routine, ; because the tool may not actually be killed. (For example ; the user may be asked if they want to save, and they may ; hit "Cancel" instead.) IF OBJ_VALID((*pState).oUI) THEN BEGIN oTool = (*pState).oUI->GetTool() oShutdown = oTool->GetService('SHUTDOWN') void = (*pState).oUI->DoAction(oShutdown->getFullIdentifier()) ENDIF END
Your code should not assume that the top-level base widget will actually be destroyed, because the user may decide to cancel the close operation. Since the process of actually destroying the widget hierarchy is divorced from the generation of the WIDGET_KILL_REQUEST event, you may also need to supply a cleanup routine that is invoked only when the widget hierarchy is actually destroyed.
A cleanup routine is necessary if your widget interface uses heap variables (pointers or objects) to store information about itself - the heap variables will need to be cleaned up separately when the interface itself is destroyed. The following code, from the cleanup routine in the
example2_wdtool.pro interface definition (developed in Example: a Custom iTool Interface), frees the pointer used to store the widget interface's state structure.
PRO example2_wdtool_cleanup, wChild ; Make sure we have a valid widget ID. IF (~WIDGET_INFO(wChild, /VALID)) THEN $ RETURN ; Retrieve the pointer to the state structure, and ; free it. WIDGET_CONTROL, wChild, GET_UVALUE = pState IF (PTR_VALID(pState)) THEN $ PTR_FREE, pState END
The final step is to specify when the cleanup routine should be called. Since the user can cancel out of the shutdown operation, the cleanup routine should only be called when the widget hierarchy is actually destroyed, not when the WIDGET_KILL_REQUEST event is handled. We accomplish this by specifying the cleanup routine as the value of the KILL_NOTIFY keyword to the WIDGET_BASE function.
In the standard iTool widget interface and in our example code, we set the KILL_NOTIFY keyword on the first child widget of the top-level base widget. The following statement, near the end of the interface definition routine, specifies the name of the cleanup routine in the
example2_wdtool.pro interface definition (developed in Example: a Custom iTool Interface):
WIDGET_CONTROL, wChild, KILL_NOTIFY = "example2_wdtool_cleanup"