The top portion of the widget class record, which is the portion containing the 32 fields from Core, is called the CoreClassPart structure. For example, following is the CoreClassPart structure of the ExmSimple widget:
externaldef (exmsimpleclassrec) ExmSimpleClassRec exmSimpleClassRec = { { /* Here is the core class record. */ /* superclass */ (WidgetClass)&xmPrimitiveClassRec, /* class_name */ "ExmSimple", /* widget_size */ sizeof(ExmSimpleRec), /* class_initialize */ ClassInitialize, /* class_part_initialize */ ClassPartInitialize, /* class_inited */ FALSE, /* initialize */ Initialize, /* initialize_hook */ NULL, /* realize */ Realize, /* actions */ NULL, /* num_actions */ 0, /* resources */ resources, /* num_resources */ XtNumber(resources), /* xrm_class */ NULLQUARK, /* compress_motion */ TRUE, /* compress_exposure */ XtExposeCompressMaximal, /* compress_enterleave */ TRUE, /* visible_interest */ FALSE, /* destroy */ Destroy, /* resize */ Resize, /* expose */ Redisplay, /* set_values */ SetValues, /* set_values_hook */ NULL, /* set_values_almost */ XtInheritSetValuesAlmost, /* get_values_hook */ NULL, /* accept_focus */ NULL, /* version */ XtVersion, /* callback_private */ NULL, /* tm_table */ XtInheritTranslations, /* query_geometry */ QueryGeometry, /* display_accelerator */ NULL, /* extension */ NULL, },
These are the same 32 fields that every Intrinsics-based widget defines. A good Intrinsics book can explain what each of these fields means to the Intrinsics. However, we need to go beyond that. You need to explore what Motif widget writers need to know about these fields.
The first field of the CoreClassPart structure is the superclass field. This field holds the name of the class record of your widget's immediate superclass. If XmPrimitive is the immediate superclass of your widget, then your widget would specify the superclass field as follows:
/* superclass */ (WidgetClass)&xmPrimitiveClassRec,
Set the class_name field to a string containing the name of the class; for example:
/* class_name */ "ExmSimple",
Motif will not make any attempt to interpret the characters in the string. However, it is a good idea to use alphanumeric characters only in the string. The string can be any length.
The string should begin with some prefix that uniquely symbolizes the widget group you are creating. For example, all the sample widgets associated with this group start with the Exm prefix. Do not pick a prefix that is used by other groups. For example, Motif reserves the prefixes xm, Xm, _Xm, Xme, XmQT, and Exm. See Chapter 2 for more information on namespace.
The widget_size field of primitive widgets holds the size of the full instance record. For example, the full instance record of the ExmSimple demonstration widget is named ExmSimpleRec; therefore, the Core class record of ExmSimple defines the widget_size field as follows:
/* widget_size */ sizeof(ExmSimpleRec);
The class_initialize field holds the name of the widget's class initialization method. If your widget does not supply a class initialization method, you should set this field to NULL.
The Intrinsics call the class initialization method only once, at the first instantiation of a widget of this class. Most Motif widgets use the class_initialize method to register representation types. Motif provides a set of functions for registration, the most important of which is XmRepTypeRegister. For example, the class_initialize method of the ExmSimple widget registers the ExmRSimpleShape representation type as follows:
void ClassInitialize( void) { simpleShapeId = XmRepTypeRegister (ExmRSimpleShape, SimpleShapeNames, NULL, XtNumber(SimpleShapeNames)); }
See Chapter 6 for more information on representation types.
You can either set the class_part_initialize field to the name of your class part initialization method or you can set it to NULL. A NULL value indicates the absence of a class part initialization method.
This class_part_initialize method is chained; therefore, the Intrinsics call the class_part_initialize method of the XmPrimitive widget before calling the class_part_initialize method of your own widget. The class_part_initialize method of XmPrimitive contains code that allows its subclasses to inherit the following features of XmPrimitive. This is not to say that all primitive widgets automatically inherit these methods; the code merely makes it possible for any primitive widget that wants to inherit these features to be able to do so.
The class_part_initialize method of your own widget should provide the code that allows subclasses to inherit your widget's methods. For example, the ExmSimple widget allows its subclasses to inherit its DrawVisual and DrawShadow methods as follows:
if (wc->simple_class.draw_visual == ExmInheritDrawVisual) wc->simple_class.draw_visual = sc->simple_class.draw_visual; if (wc->simple_class.draw_shadow == ExmInheritDrawShadow) wc->simple_class.draw_shadow = sc->simple_class.draw_shadow;
Many Motif widgets use the class_part_initialize method to install traits. For example, the class_part_initialize method of ExmSimple uses the following code to install the XmQTcontainerItem trait:
XmeTraitSet((XtPointer) wc, XmQTcontainerItem, (XtPointer) &simpleCIT);
XmeTraitSet is a routine that installs traits. (See Chapter 5 for complete details.) If you install a trait in your widget's class_part_initialize method, then this trait is automatically installed in all subclasses of your widget.
The class_part_initialize method of XmPrimitive installs the XmQTcareParentVisual trait and installs several undocumented traits.
All Motif widgets must set the value of this field to False.
The Intrinsics call your widget's initialize method when an application instantiates your widget. You typically specify one of the following for the initialize field:
Since the initialize method is chained, the Intrinsics will call the initialize method of the XmPrimitive widget before calling the initialize method in your own widget. ( Core does not provide an initialize method.) Broadly speaking, the initialize method of XmPrimitive does the following:
The code in the initialize method of your own widget should check resource values and perform other start-up tasks that are relevant to your widget's creation. If any resources are expecting representation type values, you can validate the representation type values with XmRepTypeValidValue. For example, the ExmSimple widget contains one resource ( ExmNsimpleShape) that expects an ExmRSimpleShape value. Therefore, the initialize method of ExmSimple validates the starting value of ExmNsimpleShape with the following code:
if (!XmRepTypeValidValue (simpleShapeId, nw->simple.simple_shape, (Widget)nw)) /* If the widget has been created without an appropriate starting value for XmNsimpleShape, force its starting value to ExmSHAPE_OVAL. */ nw->simple.simple_shape = ExmSHAPE_OVAL;
The initialize_hook field is obsolete. Motif ignores this value. Set it to NULL.
The realize field is responsible for creating the widget's window. You typically specify either
The realize method of XmPrimitive calls XtCreateWindow to generate a window. The window class of the created window will be InputOutput. The generated window will not propagate any button, key, or pointer motion events to its parent window(s). In order to inherit this code for your own widget, simply set the value of the realize field to XtInheritRealize. By so doing, your widget's window will behave like other Motif primitive windows.
The Motif Style Guide does not demand that all windows conform to a certain standard. For that matter, the Motif Style Guide does not even insist that all windows be rectangular. Therefore, you are free to create your own realize method.
The actions field contains the name of the actions array. The actions array provides a correspondence between action names (as defined in the translations string) and action methods. For example, the ExmCommandButton demonstration widget defines the following actions array:
/* Declare the actions array. */ static XtActionsRec actions[] = { {"ExmCommandButtonEnter", ExmCommandButtonEnter}, {"ExmCommandButtonLeave", ExmCommandButtonLeave}, {"ExmCommandButtonArmAndActivate", ExmCommandButtonArmAndActivate}, {"ExmCommandButtonArm", ExmCommandButtonArm}, {"ExmCommandButtonActivate", ExmCommandButtonActivate}, {"ExmCommandButtonDisarm", ExmCommandButtonDisarm} };
The preceding actions array defines six actions.
If your widget does not define any action methods, then you should set the actions field to NULL.
(See Chapter 7 for more details about actions.)
The num_actions field holds the number of actions defined by the array in the actions field. If your widget does not provide an actions array, then you should specify 0 for the num_actions field. If your widget does provide an actions array, then you should use the XtNumber macro to count these actions. For example, the ExmCommandButton widget does provide an actions array, so its num_actions field looks as follows:
/* num_actions */ XtNumber(actions),
If your widget defines new resources, then the resources field must contain the name of the resources array. If your widget does not define any new resources, specify NULL.
(See Chapter 6 for information and recommendations.)
The num_resources field holds the number of resources defined by the array in the resources field. If your widget does not provide a resources array, then you should specify 0 for the num_resources field. If your widget does provide a resources array, then your widget should use the XtNumber macro to count these resources. For example, the ExmSimple widget does provide a resources array, so its num_resources field looks as follows:
/* num_resources */ XtNumber(resources),
Your widget must always specify NULLQUARK as the value of the xrm_class field.
The compress_motion field requires a Boolean value. Setting this value to True eliminates certain redundant pointer motion events from the event queue. Setting this value to False imposes a performance penalty but produces more accurate pointer tracking. (See documentation on the Intrinsics for more complete information.)
Motif makes no recommendation on the value of the compress_motion field. Within the standard Motif widget set, the value of the compress_motion field is generally True. The XmPrimitive widget sets this field to True.
The compress_exposure field requires a constant value. This value tells the Intrinsics how to respond to multiple exposure events. (See documentation on the Intrinsics for more complete information.)
Motif makes no recommendation on the value of the compress_exposure field. The XmPrimitive widget sets this field to XtExposeCompressMaximal, with the XtExposeNoRegion modifier enabled.
The compress_enterleave field requires a Boolean value. Setting this value to True means that the Intrinsics will ignore unimportant enter event/leave event pairs. (See documentation on the Intrinsics for more complete information.)
Motif makes no recommendation on the value of the compress_enterleave field. However, most standard Motif primitive widgets (including the XmPrimitive widget itself) set this field to True.
The visible_interest field requires a Boolean value. This value provides hints to the Intrinsics on the redisplay of partially exposed widgets. Motif does not layer any extra meaning on top of the standard Intrinsics meaning of this field.
Motif makes no recommendation on the value of this field. However, every standard Motif widget specifies False for this field.
The Intrinsics automatically call your widget's destroy method when your widget goes out of scope or is explicitly destroyed. The destroy method is chained up from subclass to superclass; therefore, the destroy method of XmPrimitive will be called after any destroy method that your own widget supplies. The destroy method of XmPrimitive deallocates the following three graphics contexts:
In addition, the destroy method of XmPrimitive deallocates all the widget traversal information held by this widget.
If your widget provides a destroy method (as it typically should), make sure it deallocates all strings, fonts, GCs, and so on, that your widget allocates.
If you do not want your widget to supply a destroy method, set the destroy field to NULL.
The Intrinsics automatically call the function specified in the resize field in response to a resize action from the parent widget. The XmPrimitive widget does not provide a resize method, so your widget cannot inherit from it.
The resize method of your widget lays out the widget's visual components. One of the duties of the resize method is to determine what parts of the widget to display when there is not enough space to display everything. Chapter 12 details Motif's recommendations for handling this situation. Sample code that demonstrates these recommendations is available in the ExmSimple and ExmString widgets.
The Intrinsics automatically invoke the expose method upon receiving an exposure event. The interpretation of exposure events can be altered by the values of the compress_exposure and visible_interest fields. (See documentation on the Intrinsics for details.)
Your widget should set the expose field to one of the following:
All standard Motif primitive widgets provide their own expose method. However, you should not feel obligated to write an expose method for your own widget. In fact, most of the primitive widgets in the Exm demonstration widget set inherit the expose method of ExmSimple.
This Redisplay method of XmPrimitive examines the value of the Boolean field primitive.highlighted. If this field is set to True, Redisplay calls the border_highlight method of XmPrimitive. If this field is False, the expose method calls the border_unhighlight method of XmPrimitive. (The border_highlight and border_unhighlight methods are detailed later in this chapter.) In brief, border_highlight and border_unhighlight of XmPrimitive provide Motif-appropriate border highlighting and unhighlighting.
Your Redisplay method should do the following:
See Chapter 12 for more details on the expose method.
The Intrinsics automatically call the set_values method whenever an application calls XtSetValues to change any of the resources in your widget.
You typically specify one of the following for the set_values field:
Most of the widgets you write will specify a set_values method.
Your widget's set_values method is responsible for validating changes to resource values. Your widget can call XmRepTypeValidValue to validate changes to representation type resources. (See Chapter 6 for details.)
The code in a set_values method is usually quite similar to the code in an initialize method.
The set_values method returns a Boolean value. The Intrinsics monitor this returned value. If the returned value is True, the Intrinsics automatically invoke the widget's expose (Redisplay) method. There are many reasons why widget redisplay is necessary. For example, one subtle reason is that a widget GC has changed.
The set_values method is chained. Therefore, the Intrinsics will call the set_values method of XmPrimitive prior to calling the set_values method of your own widget. The set_values method of XmPrimitive:
This is an obsolete field; Motif ignores its value. Your widget should set it to NULL.
The Intrinsics call the method named in the set_values_almost field when certain geometry requests cannot be fulfilled by the parent geometry manager.
You should probably set the set_values_almost field to one of the following:
The XmPrimitive widget itself sets the set_values_almost field to XtInheritSetValuesAlmost, meaning that it inherits the set_values_almost method of Core.
Motif makes no recommendations for this method. However, all standard Motif primitive widgets except XmLabel and XmFormlset this field to XtInheritSetValuesAlmost.
The get_values_hook field holds the name of a method responsible for doing preprocessing on XtGetValues calls. If your widget has no need to do this, you should set the get_values_hook field to NULL. In fact, most standard Motif primitive widgets do set this field to NULL.
The get_values_hook field is chained; therefore, the Intrinsics will call the get_values_hook method of XmPrimitive prior to the get_values_hook method of your widget. The get_values_hook method of XmPrimitive implements synthetic resources for primitive widgets. (See Chapter 6 for details on synthetic resources.)
Motif ignores the value of the accept_focus field; set it to NULL.
The version field holds an enumerated constant pertaining to the compatibility of the Intrinsics themselves. The version field does not express any information regarding Motif compatibility, nor does Motif interpret the version field in any way.
Most widgets set this field to XtVersion. However, if you do not want your widget to check binary compatibility with future releases of the Intrinsics, set this field to XtVersionDontCheck. (See Chapter 15 for details on binary compatibility.)
Motif ignores the value of the callback_private field; you should set this field to NULL.
The tm_table field holds the primary translations string of your widget. Your widget should probably set this field to one of the following:
If your widget does not provide any translations, Motif recommends setting the tm_table field to XtInheritTranslations.
(See Chapter 7 for more details.)
The Intrinsics call the query_geometry method when another widget (most likely the parent) or an application calls XtQueryGeometry to determine your widget's geometry preferences.
Your widget must specify one of the following in the query_geometry field:
(See Chapter 12 for details on geometry management.)
Motif ignores the value of the display_accelerator field; set it to NULL.
Motif strongly recommends that you set the value of the extension field to NULL. By so doing, Motif will install the correct extension record for you at runtime.