This document describes the way in which LessTif widgets handle their geometry negotiations. As geometry management is a subject that has much to do with Xt, part of this document describes (what I understand of) the Xt geometry model.
All feedback is, as always, welcomed at u27113@kb.be.
The Xt geometry model is based on geometry negotiations. This really means that every change that a widget wants to apply to its geometry, must be approved by the widget's parent. The resources in the widget that are part of this geometry are
A widget can request a geometry change by using XtMakeGeometryRequest or XtMakeResizeRequest. XtMakeResizeRequest only allows a widget to request a different size (width/height), whereas XtMakeGeometryRequest can be used to alter all five resources mentioned above.
LessTif has a convenience function called _XmMakeGeometryRequest which calls XtMakeGeometryRequest.
The signature of XtMakeGeometryRequest is
XtGeometryResult XtMakeGeometryRequest( Widget w, XtWidgetGeometry *desired, XtWidgetGeometry *allowed)
It should be called from the widget which is passed as parameter 1. The second parameter described the geometry that the widget would like to have. The last parameter returns the geometry that the widget got, in some circumstances. Finally, the result of the function is a value indicating whether the request has been granted.
XtWidgetGeometry is a structure which holds the five fields indicated above, and a bitset in which you can indicate which fields have been initialized. In the return parameter, the bitset will also indicate how much information is valid. A common mistake is to assume that the parent widget will always set width and height values, and to just read those fields without looking at the flags.
The bitset field is called request_mode. It can be set using an OR of zero or more of the macros CWX, CWY, CWWidth, CWHeight, CWBorderWidth, each of which has exactly one bit set. A final bit XtCWQueryOnly is not currently used in Lesstif. When set, the call to XtMakeGeometryRequest will return a result without changing anything to the widget.
The result of XtMakeGeometryRequest can have four values :
XtGeometryResult _XmMakeGeometryRequest(Widget w, XtWidgetGeometry *g)This function calls XtMakeGeometryRequest. If the return value is XtGeometryAlmost, it'll call it a second time, with the value just obtained. Then it returns.
Another programming mistake (introduced by Asente & Swick) : given the Xt rule about XtGeometryAlmost, you could program a loop in which you keep calling XtMakeGeometryRequest until the value is different from XtGeometryAlmost. The trouble is that this kind of a loop is only guaranteed to be finite if the parent widget(s) are bug-free. Need I say more?
_XmMakeGeometryRequest detects this problem and is verbose about it (if you set DEBUGSOURCES to print information about GeoUtils.c). It is known to happen with XmForm (i.e. XmForm currently doesn't always grant a geometry that it just suggested).
If anybody wants a good exercise in understanding this document, he or she is invited to find this bug. Really. I'll only start tracking it myself when I have no serious bugs to attend to. A couple of beers can be had in Leuven, Belgium, by the first person to fix this.
The geometry_manager method is inherited from Composite. Hence, all LessTif manager widgets (subclasses of XmManager) have it. It is called in those widgets whenever a child widget asks the manager whether it (the child) is allowed to resize.
The signature of geometry_manager is
XtGeometryResult GeometryManager(Widget w, XtWidgetGeometry *desired, XtWidgetGeometry *allowed)
The widget w in geometry_manager is a child of the manager widget whose layout needs to be examined. Another hard rule in Xt is that the child widget calling geometry_manager must not be resized in geometry_manager. Ignoring this rule will probably get you into (almost) infinite loops. You'll get programs crashing because they exceed their stack size. What happens is that geometry_manager (incorrectly) resizes the calling widget, which will see that in its resize method, which will probably ask its parent to resize, and we're back in (another invocation of) geometry_manager.
Note that the calling widget, as we called it just now, is often referred to as the instigator.
As most manager widgets manage the layout of other widgets (their children), a layout algorithm is usually (read: always) called from geometry_manager.
One of the results of a geometry request by a child can be that the parent widget needs to adapt its own size. According to what we know now, our parent widget needs its own parents' permission to do that. If it does not get that permission (there are many reasons why this can happen), then the consequence is almost certainly that geometry_manager in the parent widget will end up returning XtGeometryNo.
As we've seen above in the description of XtMakeGeometryRequest, one of the more important things to do in geometry_manager is to return a sensible suggested geometry in an XtGeometryAlmost case.
Note that these are unchained methods, which means they are not automatically called for all the superclasses of a manager widget. XmRowColumn's insert_child needs to call XmManager's insert_child, which in turn calls the one in its superclass.
Here's an example of the signature of such a function :
static void _XmMainWindowLayout(Widget w, Boolean ParentResize, Widget child, Boolean TestMode, XtWidgetGeometry *cg, XtWidgetGeometry *mwg)The parameters are used as follows :
The structure of these functions is such that they can be called in a number of circumstances. A high level description of what they do is :