The BaseClass module provides hooks that are activated before and after a chain of widget methods have been called in superclass-to-subclass order. Prehooks and posthooks can be registered for arbitrary widget classes. They are available for:
For example, the XmLabel class uses the hooks to do some pre- and post-processing when initializating a new widget instance - regardless of whether the new widget is a XmLabel or any subclass of (like XmPushButton). But also most gadgets make heavy use of the hook mechanism to manage their secondary objects that work as cache parts.
Unfortunately, while the concept of the hook mechanism looks straightforward at first glance, the implementation is definitely not. The difficulty is that the hook concept must be merged into the existing object orientated concept of the Xt Intrinsics without any chance of modifying and recompiling the Xt Intrinsics. Thus, the only way out is to twist method pointers.
But when twisting pointers, you can't simply hook up the first and last method pointer for any widget class, for example XmLabel. If some derived class, like XmPushButton, would hook up its method pointers too, the posthooks would interfere with each other. The reason is that the parameters supplied to the aforementioned four kinds of methods aren't enough to do the check whether the end of the method-chain has been reached and the posthook method must be called. Such a check could only be done using code generated at run-time - a practice which is definitely not portable across different systems. Later on, when looking at the wrappers for the realize(), resize() and geometry_handler() methods, you'll come across another solution to a quite similiar problem, but the solution there is even worse than what I'll present next.
_XmInitializeExtensionsinitializemethodclass_part_initializemethodget_valuesmethodset_valuesmethodTo solve the hook problem, LESSTIF installs prehook wrappers as replacements for the methods initialize(), class_part_initialize(), get_values() and set_values() of the Object class. This insures that the hook wrappers are called first before any other subclass-method. This twisting of the method pointers is carried out by _XmInitializeExtensions() when the first VendorShell is created. The pointers to the old methods of the Object class are saved, so the prehook wrappers can chain them up. Note that there are no posthook (wrappers) installed at this time.
Now let us see what is happening lateron. I'll discuss this based on figure for the initialize() method-chain of the XmLabel class. For this example, I assume that there is a prehook method 2 as well as a posthook method 6 registered for the XmLabel class.
Whenever the initialize() method is invoked, the prehook wrapper 1 is called first. In turn, it calls the prehook method 2 - if there is one present for the widget class in question. Next, the prehook wrapper checks for the presence of a posthook method 6 - and if there is one, the prehook wrapper replaces the pointer to the final initialize() method 5 with a pointer to the posthook wrapper 4. The old pointer is saved using the ``wrapper data stack'' (you can find out more about this in the next section). Finally, the prehook wrapper calls the original initialize() method 3 of the Object class.
After this, the initialize() methods are called (as usual) in superclass-to-subclass order with the exception of the leaf method. If there is a posthook method registered, then - and only then - will the posthook wrapper 4 be called instead of the leaf method. The posthook wrapper restores the old method pointer, calls the leaf method 5, and finally activates the posthook method 6.
In one particular case the method-chains for initialize() and set_values() look different: whenever a widget is not a shell and it has a Constraint parent (or any subclass of) then the leaf method isn't the method of the widget's class but instead the parent's constraint leaf method (constraint_initialize() respective constraint_set_values()).
If you look close at the whole hook concept then it should be clear that this concept is error prone in certain situations when recursion is involved. The tradegy begins as soon as you enter the same prehook wrapper for a second time and the widget class of the second turn is a subclass of the widget class from the first visit to the prehook wrapper. In this case the first prehook wrapper method, which belongs to the superclass, is erroneously taken instead of the intended second prehook wrapper. Fortunately, there is no great chance to tap into this trap as long as you don't issue - for example - from the get_values() method of a XmLabel widget a call to XtGetValues() using another XmPushButton widget.