XmSyntheticResourceXmImportOperatorXmImportProcXmExportProcThe XmSyntheticResource structure looks suspiciously like the Xt resource structure, and in fact operates in much the same way. Here's the structure, and some associated information:
typedef enum { XmSYNTHETIC_NONE, XmSYNTHETIC_LOAD } XmImportOperator; typedef void (*XmExportProc)(Widget w, int offset, XtArgVal *value); typedef XmImportOperator (*XmImportProc)(Widget w, int offset, XtArgVal *value); typedef struct _XmSyntheticResource { String resource_name; Cardinal resource_size; Cardinal resource_offset; XmExportProc export_proc; XmImportProc import_proc; } XmSyntheticResource;
The import and export procedures (import_proc and export_proc respectively) each take three parameters: the widget for which the value has to be im- or exported, the offset of the resource value within the widget's instance structure, and finally a pointer. In case of a XmImportProc it points to the place where the new resource value can be found. In the other case (XmExportProc) the third parameter value points to the place where the converted result should be stored.
Here's an example right from Primitive.c:
/* Resources of the primitive class */ static XtResource resources[] = { /* ... */ { XmNhighlightThickness, sizeof(Dimension), XtOffset(XmPrimitiveWidget, primitive.highlight_thickness), _XmFromHorizontalPixels, _XmToHorizontalPixels }, /* ... */ };
This implements the resource XmNhighlightThickness as a synthetic resource. The import procedure _XmToHorizontalPixels as well as the export procedure _XmFromHorizontalPixels convert to/from the internal pixel based highlight thickness.
Note that the XmImportProc has a return type. This type is a clue to the synthetic resource implementation for whether or not the imported value should be loaded into the widget structure directly, or just into the argument list. Most would suspect that this should always go into the widget structure; however, remember that many manager widgets have associated children defined as part of their functionality (e.g., SelectionBox), and don't have direct visibility into some of the resources that can be specified.
XmSYNTHETIC_LOADXmSYNTHETIC_NONELet's go into a little more detail about that. When an import procedure wants a value to go directly into a resource variable, it returns XmSYNTHETIC_LOAD (see figure ). This is typically returned by such functions as _XmToHorizontalPixels(), which implements resolution independence into widgets. This has the effect of modifying directly the width (or x) instance variable of a widget.
However, consider the XmNlistItems in a SelectionBox. This import function typically wants to copy the XmStringTable provided by the user (as a ``sensitive'' resource that the user may or may not free). At any rate, the SelectionBox doesn't have visibility into this resource directly. The implementor has two choices: they can copy the XmStringTable and store it in the subpart in the import procedure (and return XmSYNTHETIC_LOAD), or they can simply make a copy of the XmStringTable, store it in the XtArgVal pointer, and return XmSYNTHETIC_NONE. In practice, they'll usually want to choose the latter, as they probably already have code in their set_values() or initialize() method to set the ListItems instance variable, and the synthetic resource mechanism will take care of the nuisance of making a copy first (at least, it will if that's how they've coded the import procedure). However, if they don't have code already, they can save some simply by coding the import procedure to do it for them; then they never need worry about the subpart (beyond checking to see if set_values() need return True).
For export procedures, much of the same logic applies, except that there is no return value, so only the resource values can be modified. The export procedures typically want to make a copy of ``sensitive'' resources, however (such as XmNlabelString in the Label widget - if the user frees this (as they should), it won't matter to the instance they got the value from. The same idea applies to things like XmStringTable's in the List, etc. This can be a performance win, as well, as calls to GetValues can be avoided.
Also note that export procedures can play games. For example, consider the Gadget class, and what it should return for the value of XmNtopShadowColor. Take a look at the export procedure of the Gadget class for the TopShadowColor color:
static XmSyntheticResource syn_resources[] = { /* ... */ { XmNtopShadowColor, sizeof(Pixel), XtOffset(XmGadget, object.parent), _XmGetParentTopShadowColor, NULL }, /* ... */ }; static void _XmGetParentTopShadowColor(Widget w, int offset, XtArgVal *value) { *value = XmParentTopShadowColor(w); }
Here, we cheat. We know that the parent is a Manager, and that the TopShadowColor a Gadget uses is the TopShadowColor defined by the parent, so we can just return that. In this way, we can specify a value, even though we don't directly have an instance variable to define that value.