Widget writers can mark certain resources as synthetic resources. A synthetic resource can automatically convert a resource value between two formats: external format and internal format.
Users and applications specify resource values in external format. As a widget designer, you should pick an external format that makes it easy for a user or application to convey information. However, an easy format for a widget user or application programmer may be a cumbersome or inefficient format for the widget writer. Therefore, Motif provides a synthetic resources mechanism. This mechanism automatically converts cumbersome external formats to a more efficient internal format. A well-chosen internal format expedites processing of the data or reduces its storage requirements.
Synthetic resources are the domain of the widget writer. An application programmer or user need never know that synthetic resources exist.
Defining a synthetic resource is a four-step process:
The first step is to define the resource as you would define any Motif resource, synthetic or not. In other words, you specify a resource record inside the resources array. For example, following is the resource definition of a resource named XmNsomething:
static XtResource resources[] = { ... { XmNsomething, XmCSomething, XmRHorizontalDimension, sizeof (Dimension), XtOffsetOf(WidgetRec, widget.something), XmRImmediate, (XtPointer)42 }, ... }
The second step is to generate a synthetic resource array. The base data type of the array is XmSyntheticResource. By convention, you should name the array variable syn_resources. Therefore, the framework of the synthetic resources array definition should appear as follows:
static XmSyntheticResource syn_resources[] = { /* one or more synthetic resource records */ }
Each synthetic resource record contains the following five fields:
For example, following is a sample synthetic resource definition:
static XmSyntheticResource syn_resources[] = { ... { /* Here is a synthetic resource record. */ XmNsomething, sizeof (ResourceDatatype), XtOffsetOf(WidgetRec, widget.something), FromInternalToExternalFormat, FromExternalToInternalFormat }, /* End of synthetic resource record. */ ... };
You can set either the fourth or fifth field to NULL. Doing so tells Motif that you will not be supplying part of the conversion process. For example, if the fourth field is set to NULL, then this widget is not supplying a function to convert the resource value from internal format to external format. If the fourth field is NULL, a call to XtGetValues returns the resource's value in internal format.
You must specify the name of the synthetic resource array in the appropriate portion of the class record. You must also specify the number of synthetic resources. For example:
/* syn_resources */ syn_resources, /* num_syn_resources */ XtNumber(syn_resources),
The final step is to provide the synthetic resource conversion routines themselves. In some cases, you can use one of Motif's existing routines (such as, XmeFromHorizontalPixels). In other cases, you will have to write the synthetic resource conversion routines yourself. There are two kinds of conversion routines you can write:
An XmExportProc conversion routine has the following prototype:
void MyExportProcConversionRoutine( Widget wid, int offset, XtArgVal *value)
An XmImportProc conversion routine has the following prototype:
XmImportOperator MyImportProcConversionRoutine( Widget wid, int offset, XtArgVal *value)
An XmImportProc conversion routine must return an XmImportOperator value, which is an enumerated type having the following possible values:
Motif's synthetic resource mechanism is typically the caller of the XmImportProc. Therefore, if your XmImportProc conversion routine returns XmSYTHETIC_LOAD, Motif synthetic resource mechanism will take care of copying (and casting) value into the resource specified by offset.
The synthetic resource implementation is particularly helpful for converting resource values from real-world units (like millimeters) to pixels and back again.
The Xlib and Xme drawing routines all expect pixel arguments. Unfortunately, pixels are not always a very handy unit for widget users to work in. One important problem with pixel units is that a pixel's size depends on the resolution of the screen.
To solve this problem the Motif base classes XmPrimitive and XmManager both provide the XmNunitType resource. This resource holds the kind of units that a given distance or position is measured in. By default, the unit type is pixels. However, the application may specify a unit type of some real-world unit, like millimeters, instead. Any resource whose value symbolizes a size, position, or distance must be able to convert these real-world units to and from pixels.
The synthetic resource mechanism provides a way to do these conversions. In fact, you do not even have to write conversion routines because Motif provides four unit conversion routines for you:
For example, the ExmSimple widget uses all four of these routines in its syn_resources array as follows:
static XmSyntheticResource syn_resources[] = { { XmNmarginWidth, sizeof (Dimension), XtOffsetOf( ExmSimpleRec, simple.margin_width), XmeFromHorizontalPixels, XmeToHorizontalPixels }, { XmNmarginHeight, sizeof (Dimension), XtOffsetOf( ExmSimpleRec, simple.margin_height), XmeFromVerticalPixels, XmeToVerticalPixels }, };
The synthetic resource mechanism is completely transparent to the widget writer. This is because the Motif base classes, XmPrimitive and XmManager, call the appropriate conversion routines at the appropriate times.
For example, the class_part_initialize method of XmPrimitive and XmManager both contain code that initializes the synthetic resource. In other words, both base classes call the routine that converts all the synthetic resource values from external to internal format Similarly, both base classes contain code in their set_values routines to call the external to internal format conversion routine whenever one of the resource values is changed. Finally, both base classes contain code in their get_values_hook routines to call the internal-to-external format conversion routine whenever an application requests the resource value.
Since the class_part_initialize, set_values, and get_values_hook methods are all chained, these conversion routines are automatically called for all primitive and manager widgets.