Chapter 3. The Widget Class Record of Primitive Widgets

The heart of every Intrinsics-based widget is its class record. The widget class record defines fields required by both the Intrinsics and Motif. The purpose of this chapter is to explain how to write a class record for subclasses of the XmPrimitive widget. Therefore, the widget class records described by this chapter will have the class hierarchy shown in the following figure.

Figure 3-1. Class Hierarchy of Primitive Widgets

Therefore, the class record of your primitive widget consists of

This chapter details all these fields from a Motif widget writer's perspective. In addition, this chapter describes the instance data members of XmPrimitive that are accessible to your widget.

The CoreClassPart Structure

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 superclass Field

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,

The class_name Field

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

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

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.

The class_part_initialize Field (Chained)

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.

  • border_highlight method

  • border_unhighlight method

  • arm_and_activate method

  • translations

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.

The class_inited Field

All Motif widgets must set the value of this field to False.

The initialize Field (Chained)

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:

  • The name of your widget instance initialize method

  • NULL, to indicate the absence of an initialize method

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:

  • Merges the keyboard traversal translations (specified in the translations field) with the regular widget translations (specified in the tm_table field). (See Chapter 7 for more details.)

  • Helps implement the virtual key mechanism of Motif.

  • Sets the values of the following two primitive flag variables to False: primitive.have_traversal and primitive.highlighted. Both variables are detailed later in this chapter.

  • Validates the XmNnavigationType and XmNunitType resources.

  • Initializes keyboard traversal.

  • Establishes synthetic resources.

  • Establishes a starting widget width or height if the user or application has not requested one. This is important for ensuring that window creation can happen safely whenever a subclass of XmPrimitive is realized.

  • Creates the following three GCs: primitive.highlight_GC , primitive.top_shadow_GC, and primitive.bottom_shadow_GC.

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 (Chained)

The initialize_hook field is obsolete. Motif ignores this value. Set it to NULL.

The realize Field

The realize field is responsible for creating the widget's window. You typically specify either

  • XtInheritRealize, to inherit the realize method of your superclass

  • The name of a realize method defined by your widget

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

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

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),

The resources Field

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

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),

The xrm_class Field

Your widget must always specify NULLQUARK as the value of the xrm_class field.

The compress_motion 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

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

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

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 destroy Field (Chained)

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:

  • primitive.top_shadow_GC

  • primitive.bottom_shadow_GC

  • primitive.highlight_GC

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 resize Field

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 expose (Redisplay) Field

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:

  • XtInheritExpose, to indicate that you are inheriting the expose method of your superclass. The XmPrimitive widget provides an expose method, and your primitive widget can inherit this method.

  • The name of your widget's expose method. If you do provide an expose method, you should name it Redisplay.

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:

  • Call the method responsible for redrawing the visible portions of the widget. For example, the Redisplay method of ExmSimple calls the DrawVisual method. In ExmSimple, the DrawVisual method renders a geometric shape.

  • Call the method responsible for drawing shadow, if appropriate. The Motif Style Guide should help you determine whether shadows are appropriate for your widget. For example, shadows are appropriate for the ExmSimple widget. Therefore, the expose method of ExmSimple calls its DrawShadow method. The DrawShadow method of ExmSimple calls XmeDrawShadow to draw a Motif-style shadow. See Chapter 17 for syntactic details on the XmeDrawShadow and XmeDrawPolygonShadow routines.

  • Call the method responsible for handling border highlights, if appropriate. The Motif Style Guide should help you determine whether border highlights are appropriate for your widget. You may write your own method to handle border highlights; however, we recommend that you call the expose method of XmPrimitive instead.

See Chapter 12 for more details on the expose method.

The set_values Field (Chained)

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:

  • The name of your widget's set_values method

  • NULL, which symbolizes the absence of a set_values method

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:

  • Validates changes to XmNnavigationType and XmNunitType.

  • Updates keyboard traversals.

  • Examines the primitive.shadow_thickness and primitive.highlight_thickness fields. If either field's value has changed, set_values sets its return value to True.

  • Examines the primitive.highlight_color and primitive.highlight_pixmap fields. If either field's value has changed, set_values destroys the existing primitive.highlight_GC and then creates a new one from the updated values. If either field's value has changed, set_values sets its return value to True.

  • Examines the primitive.top_shadow_color and primitive.top_shadow_pixmap fields. If either field's value has changed, set_values destroys the existing primitive.top_shadow_GC and then creates a new one from the updated values. If either field's value has changed, set_values sets its return value to True.

  • Examines the primitive.bottom_shadow_color and primitive.bottom_shadow_pixmap fields. If either field's value has changed, set_values destroys the existing primitive.bottom_shadow_GC and then creates a new one from the updated values. If either field's value has changed, set_values sets its return value to True.

  • Calls the border_unhighlight method when all of the following conditions are True:

    • The border highlight is drawn or the widget is insensitive.

    • The focus policy is XmImplicit.

    • The value of the XmNhighlightOnEnter resource changes from True to False.

The set_values_hook Field (Chained)

This is an obsolete field; Motif ignores its value. Your widget should set it to NULL.

The set_values_almost Field

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 name of your widget's set_values_almost field.

  • XtInheritSetValuesAlmost, to inherit the set_values_almost method of your superclass.

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 (Chained)

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.)

The accept_focus Field

Motif ignores the value of the accept_focus field; set it to NULL.

The version Field

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.)

The callback_private Field

Motif ignores the value of the callback_private field; you should set this field to NULL.

The tm_table Field

The tm_table field holds the primary translations string of your widget. Your widget should probably set this field to one of the following:

  • The name of your widget's tm_table translations string.

  • XtInheritTranslations, to inherit the tm_table translations of your superclass. The XmPrimitive widget does not provide any tm_table translations to inherit.

If your widget does not provide any translations, Motif recommends setting the tm_table field to XtInheritTranslations.

(See Chapter 7 for more details.)

The query_geometry Field

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:

  • The name of your widget's query_geometry method.

  • XtInheritQueryGeometry, to inherit the query_geometry method of your superclass. The XmPrimitive widget does not provide a query_geometry method to inherit.

  • NULL, which indicates the absence of a query_geometry method.

(See Chapter 12 for details on geometry management.)

The display_accelerator Field

Motif ignores the value of the display_accelerator field; set it to NULL.

The Base Class extension Field

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.

The PrimitiveClassPart Structure

The PrimitiveClassPart structure is the second chunk of the widget class record. In the PrimitiveClassPart structure, you must define values for seven different fields. For example, following is the PrimitiveClassPart structure of the ExmSimple widget:

{
 /* border_highlight */           XmInheritBorderHighlight,
 /* border_unhighlight */         XmInheritBorderUnhighlight,
 /* translations */               XtInheritTranslations,
 /* arm_and_activate */           NULL,
 /* syn_resources */              syn_resources,
 /* num_syn_resources */          XtNumber(syn_resources),
 /* extension */                  (XtPointer)&primClassExtRec,
},

The following subsections detail the fields of the PrimitiveClassPart structure.

The border_highlight Field

The border_highlight field holds the name of a method that highlights the perimeter of the widget. The border_highlight method is typically called by the Redisplay method.

You should probably set the border_highlight field to one of the following:

  • The name of your widget's border_highlight method

  • XmInheritBorderHighlight, to indicate that you are inheriting the border_highlight method of your superclass

Most primitive widgets should inherit the border_highlight method of XmPrimitive. The border_highlight method of XmPrimitive provides the standard Motif highlighting style for primitive widgets. In particular, the border_highlight method of XmPrimitive does the following:

  • Sets the value of internal field primitive.highlighted to True.

  • Examines the widget's dimensions and resources to determine whether or not the widget needs a border. For example, there is no need to draw a border if the value of the XmNhighlightThickness resource is 0.

  • If the widget does need a border, the method draws it. The drawing characteristics (color, pixmap, and so forth) are governed by the GC stored in instance data member primitive.highlight_GC.

If you do write your own border_highlight method, it must have the following prototype:

void BorderHighlight(
        Widget  w)

where widget specifies the widget ID.

If you do write your own border_highlight method, you should probably use the XmeDrawHighlight function to draw the border highlight. In addition, your border_highlight method must set the value of instance data member primitive.highlighted to True immediately after drawing the border highlight.

The ExmTabButton and ExmMenuButton widgets both have special requirements for border highlights. Therefore, both of these widgets provide their own border_highlight methods rather than inherit them.

The border_unhighlight Field

The border_unhighlight field holds the name of a method that removes a widget's border. For example, if your primitive widget has a different background color than its parent, then it may be wise to remove the border (possibly in preparation for a redraw of the border). You should probably set the border_unhighlight field to one of the following:

  • XmInheritBorderUnhighlight, to inherit the border_unhighlight method of your superclass. The XmPrimitive widget provides a border_unhighlight method, which your primitive widget can inherit.

  • The name of your widget's border_unhighlight method.

If the border_highlight field of your widget is set to XmInheritBorderHighlight, then you should set the border_unhighlight field to XmInheritBorderUnhighlight.

The border_unhighlight method of XmPrimitive does the following:

  • Sets the value of internal field primitive.highlighted to False.

  • Examines the widget's dimensions and resources to determine whether or not there is indeed a border to erase.

  • If the widget does have a border, the border_unhighlight method calls an internal function that unhighlights the border.

If you do write your own border_unhighlight method, it must have the following prototype:

void BorderUnhighlight(
        Widget  w)

where widget specifies the widget ID.

If your widget provides its own border_unhighlight method, then it must set the value of instance data member primitive.highlighted to False. To remove highlights, your method should probably call the same internal function that drew the highlights, namely, XmeDrawHighlight . One trick to unhighlighting is to paint over the existing highlight with the background color and background pixmap of your widget's parent. Your widget's parent stores its background color and background pixmap in the manager.background_GC instance data member.

The translations Field

The translations field holds a string that implements your widget's keyboard traversals. The complete keyboard traversal policy depends not only on the value of the translations field but also on the values of two resources.

You can set this field to one of the following:

  • XtInheritTranslations, to inherit the traversal translations string of your superclass. The XmPrimitive widget provides a traversal translations string that your widget can inherit.

  • The name of your widget's own traveral translations string.

  • NULL, to indicate the absence of any traversal translations.

(See Chapter 7 for details.)

The arm_and_activate Field

The arm_and_activate field holds the name of a method that is activated by an osfActivate event. The named method must provide the visual simulation of a push button being pushed in as a response to the osfActivate event.

Your widget should specify one of the following for the arm_and_activate field:

  • The name of your widget's arm_and_activate method.

  • XmInheritArmAndActivate, to inherit the arm_and_activate method of your superclass. The XmPrimitive widget does not provide an arm_and_activate method, so you cannot inherit from it.

  • NULL, to indicate the absence of an arm_and_activate method.

In the standard Motif widget set, all the button widgets provide an arm_and_activate method. All other primitive widgets set this field to NULL.

The ExmCommandButton widget provides the following arm_and_activate method:

static void
ArmAndActivate (
       Widget w,
       XEvent *event,
       String *params,
       Cardinal *num_params)
{
   ExmCommandButtonWidgetClass wc = (ExmCommandButtonWidgetClass)XtClass(w);
   ExmCommandButtonWidget cw = (ExmCommandButtonWidget)w;
   XmAnyCallbackStruct cb;
   /* Call DrawShadow. */
     cw->command_button.visual_armed = True;
     if (wc->simple_class.draw_shadow)
       (*(wc->simple_class.draw_shadow)) (w);

/* Eliminate any data waiting in the X Window's output buffer. */
  XFlush (XtDisplay (cw));

/* Assuming that the XmNactivateCallback resource is set, call the
   callback routine. */
  if (cw->command_button.activate_callback) {
    cb.reason = XmCR_ACTIVATE;
    cb.event = event;
    XtCallCallbackList((Widget)cw, cw->command_button.activate_callback, &cb);
  }

/* Provide a short delay prior to the appearance of any new windows created
   by the callback. The net effect is that the ExmCommandButton will appear
   to flash on and off immediately prior to the appearance of any window that
   may overwrite it. */
  if ((cw->core.being_destroyed == False) &&
      (cw->command_button.visual_timer == 0))
    cw->command_button.visual_timer =
      XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)cw),
                    (unsigned long) VISUAL_DELAY,
                     VisualDisarm, /* method that disarms */
                    (XtPointer)(cw)); /* pass this widget to VisualDisarm */
}

The syn_resources Field

The syn_resources field holds the name of the array that defines the widget's synthetic resources. Synthetic resources provide a mechanism for translating widget resource values between different formats. (See Chapter 6 for information on synthetic resources.)

Most primitive widgets in the standard Motif widget set provide a syn_resources array.

If you do not wish to define synthetic resources for your widget, set the value of this field to NULL.

The num_syn_resources Field

The num_syn_resources field holds the number of synthetic resources defined by the array in the syn_resources field. If your widget does not provide a syn_resources array, then you should specify 0 for the num_syn_resources field. If your widget does provide a syn_resources array, then your widget should use the the XtNumber macro to count these resources.

The extension Field

Nearly every primitive widget displays text or graphics. Any widget that does must specify a primitive class extension record. The extension field holds an XtPointer to the name of this record. You should always name your primitive class extension record primClassExtRec; for example:

/* extension */                  (XtPointer)&primClassExtRec,

If your primitive widget does not display any text or graphics, then you should set the extensions field to NULL. If your primitive widget does need to define an extension record, see the next section for details.

The Primitive Class Extension Record

Nearly every primitive widget should define a primitive class extension record. The primitive class extension record currently consists of seven fields. Future releases may add more fields.

The following is the primitive class extension record for the ExmString widget:

/* Here is the primitive class extension record. */
static XmPrimitiveClassExtRec primClassExtRec = {
   /* next_extension */             NULL,
   /* record_type */                NULLQUARK,
   /* version */                    XmPrimitiveClassExtVersion,
   /* record_size */                sizeof(XmPrimitiveClassExtRec),
   /* widget_baseline */            WidgetBaselines,
   /* widget_display_rect */        WidgetDisplayRect,
   /* widget_margins */             NULL,
};

The following subsections detail each of the fields in this structure.

The next_extension Field

Your widget should always set the next_extension field to NULL.

The record_type Field

Your widget should always set the record_type field to NULLQUARK.

The version Field

Your widget must set the version field to XmPrimitiveClassExtVersion.

The record_size Field

The record_size field holds the size of the primitive class extension record. You should set it as follows:

/* record_size */                 sizeof(XmPrimitiveClassExtRec),

The widget_baseline Field

Your widget must set the widget_baseline field to one of the following:

  • NULL, to indicate the absence of a widget_baseline method. Set the field to NULL if your widget does not render text to the screen.

  • XmInheritBaselineProc, to inherit the widget_baseline method of your widget's superclass. XmPrimitive does not provide a widget_baseline method, so you cannot inherit from it.

  • The name of your widget's widget_baseline method.

If your widget renders text, it must provide or inherit a widget_baseline method. The purpose of this method is to create a table of text baselines. That is, each entry in the table must hold the baseline of a different line of text. For example, a widget that displays six lines of text would require a six-entry baseline table. The baseline of any given line of text is a vertical offset in pixels from the origin of the widget's bounding box to the given baseline.

Several manager widgets use baseline tables. The RowColumn widget, for example, uses the information in the baseline tables of its children widgets to align text properly. The baseline tables are also used by the XmWidgetGetBaselines and XmTextGetBaseline functions.

In order to be compatible with other Motif widgets and functions, your widget_baseline method must have the following prototype:

Boolean WidgetBaseline(
        Widget          w,
        Dimension       **baselines,
        int             *line_count)

Upon the function's completion, the following must occur:

  • The baselines variable must return a pointer to an array that contains the value of each baseline of text in the widget. Note that your widget's widget_baseline method must call XtMalloc to allocate space to hold the baselines. Conversely, the caller of the widget_baseline method must call XtFree to free the allocated space.

  • The line_count variable must return the number of lines in the widget. You may want to use the XmStringLineCount function to determine the line count.

  • The method itself must return a Boolean value that indicates whether the widget contains a baseline. If the value is True, the function returns a value for each baseline of text. If it is False, the function was unable to return a baseline value.

(See the ExmString demonstration widget for an example of a widget_baseline method.)

Several standard Motif widgets, including XmText, XmTextField, XmLabel, and XmIconGadget provide a widget_baseline method.

The widget_display_rect Field

Your widget must set the widget_display_rect field to one of the following:

  • NULL, to indicate the absence of a widget_display_rect method. Set the field to NULL if your widget does not render any graphics, pixmaps, or text to the screen.

  • XmInheritDisplayRectProc, to inherit the widget_display_rect method of your widget's superclass. XmPrimitive does not provide a widget_display_rect method, so you cannot inherit from it.

  • The name of your widget's widget_display_rect method.

If your widget does render graphics, pixmaps, or text, then it should provide a widget_display_rect method. The purpose of this method is to define the bounding rectangle of the visible information inside the widget. The bounding rectangle is stored in an XRectangle structure. The x and y coordinates that are stored inside this structure represent offsets from the upper left of the widget.

If a widget displays a pixmap, then the bounding rectangle defines the perimeter of the pixmap. If the widget displays text, then the first text character marks the upper left of the bounding rectangle. The coordinates of the lower right of the bounding rectangle are defined by the last line of text and the longest line of any text in the widget. If the widget displays graphics, then the bounding rectangle is undefined. However, if the graphics area spans a clearly defined rectangle, then this rectangle should mark the range of the bounding box.

Several Motif managers use the widget_display_rect method to determine how to align their children. In addition, Motif applications can access the widget_display_rect method by calling the XmWidgetGetDisplayRect function.

Your widget_display_rect method must have the following prototype:

Boolean WidgetDisplayRect(
        Widget  w,
        XRectangle      *displayrect)

Upon the function's completion, the displayrect variable must describe the dimensions of the bounding rectangle. (See the XmWidgetGetDisplayRect(3) reference page of the Motif Programmer's Referencefor details on the returned bounding rectangle.)

For an example of a complete widget_display_rect method, see the demonstration widgets ExmSimple or ExmString.

Several standard Motif widgets provide a widget_display_rect method, including XmText, XmTextField, XmLabel, and XmIconGadget.

The widget_margins Method

You should set the widget_margins field to NULL.

The Instance Data Members of XmPrimitive

The XmPrimitive widget maintains the values of its resources inside the fields of the primitive structure. For example, the value of the XmNhighlightThickness resource is stored in the primitive.highlight_thickness field. Your primitive widget can access any of these fields. For example, the following code accesses the primitive.highlight_thickness field:

total_width_of_highlight = primitive.highlight_thickness * 2;

In addition to all the resource values, the primitive structure also holds several fields that are not tied to resources. Widget writers should become familiar with the fields shown in the following subsections.

The primitive.have_traversal Field

The have_traversal field is declared as follows:

Boolean   have_traversal;

This is a flag whose initial value is False. This flag becomes True only when both of the following happen:

  • The keyboard focus policy is XmEXPLICIT.

  • The widget gets the keyboard focus.

When the widget loses keyboard focus, this flag is reset to False. Similarly, if the keyboard focus policy becomes XmPOINTER, this flag is reset to False.

The primitive.highlighted Field

The highlighted field is declared as follows:

Boolean   highlighted;

This is a flag. Widgets must set this flag to True after drawing a highlight around the widget's border. Widgets must set this flag to False after removing the highlight. The flag's initial value is False.

The primitive.highlight_GC Field

The highlight_GC field is declared as follows:

GC        highlight_GC;

The border_highlight method of the XmPrimitive widget uses this GC when rendering the border highlight.

The primitive.highlight_GC contains the default GC generated by XtGetGC, except for the following differences:

  • XmPrimitive sets the foreground field of the GC to the value of the XmNhighlightColor resource of XmPrimitive.

  • XmPrimitive sets the background field of the GC to the value of the XmNbackground resource of Core.

If the XmNhighlightPixmap resource of XmPrimitive contains something other than XmUNSPECIFIED_PIXMAP or None, then the highlight_GC also contains the following:

  • If the depth of the pixmap in XmNhighlightPixmap is 1, then the fill_style field of the GC is set to FillOpaqueStipple. Furthermore, the stipple field of the GC is set to the pixmap in XmNhighlightPixmap.

  • If the depth of the pixmap in XmNhighlightPixmap is greater than 1, then the fill_style field of the GC is set to FillTiled. Furthermore, the tile field of the GC is set to the pixmap in XmNhighlightPixmap.

The primitive.top_shadow_GC Field

The top_shadow_GC field is declared as follows:

GC        top_shadow_GC;

XmPrimitive uses primitive.top_shadow_GC when rendering the top shadow. The primitive.top_shadow_GC field contains the default GC generated by XtGetGC, except for the following differences:

  • XmPrimitive sets the foreground field of the GC to the value of the XmNtopShadowColor resource of XmPrimitive.

  • XmPrimitive sets the background field of the GC to the value of the XmNbackground resource of Core.

If the XmNtopShadowPixmap resource of XmPrimitive contains something other than XmUNSPECIFIED_PIXMAP or None, then the highlight_GC also contains the following:

  • If the depth of the pixmap in XmNtopShadowPixmap is 1, then the fill_style field of the GC is set to FillOpaqueStipple. Furthermore, the stipple field of the GC is set to the pixmap in XmNtopShadowPixmap.

  • If the depth of the pixmap in XmNtopShadowPixmap is greater than 1, then the fill_style field of the GC is set to FillTiled. Furthermore, the tile field of the GC is set to the pixmap in XmNtopShadowPixmap.

The primitive.bottom_shadow_GC Field

The bottom_shadow_GC field is declared as follows:

GC        bottom_shadow_GC;

XmPrimitive uses primitive.bottom_shadow_GC when rendering the bottom shadow. The primitive..bottom_shadow_GC field contains the default GC generated by XtGetGC, except for the following differences:

  • XmPrimitive sets the foreground field of the GC to the value of the XmNbottomShadowColor resource of XmPrimitive.

  • XmPrimitive sets the background field of the GC to the value of the XmNbackground resource of Core.

If the XmNbottomShadowPixmap resource of XmPrimitive contains something other than XmUNSPECIFIED_PIXMAP or None, then the highlight_GC also contains the following:

  • If the depth of the pixmap in XmNbottomShadowPixmap is 1, then the fill_style field of the GC is set to FillOpaqueStipple. Furthermore, the stipple field of the GC is set to the pixmap in XmNbottomShadowPixmap.

  • If the depth of the pixmap in XmNbottomShadowPixmap is greater than 1, then the fill_style field of the GC is set to FillTiled. Furthermore, the tile field of the GC is set to the pixmap in XmNbottomShadowPixmap.