[ Previous | Next | Contents | Glossary | Home | Search ]
Motif 2.1 Widget Writer's Guide



Binary Compatibility

In order to make a widget binary compatible with future releases of XmPrimitive and XmManager that have expanded their instance records, you must do the following:

  1. Define an index macro in the widget private header file

  2. Define XmField access macros in the widget source code file

  3. Use the proper offset macros and data types when you declare resources and constraints in the widget source code file

  4. Set the version field of the CoreClassPart to XtVersionDontCheck.

  5. Declare an XmOffsetPtr variable in the widget source code file

  6. Call XmeResolvePartOffsets when you initialize the widget, probably in the class_initialize method

  7. Access all members of the widget instance record through the XmField macros you created in Step 2

    By doing all these steps, a widget written and compiled at the current release of Motif should continue to work without recoding or recompiling at future releases. If you do not do these steps when writing a widget, it is probable that your widgets will have to be recompiled for future releases.

    The only Exm widget that is binary compatible with future releases is the ExmTabButton widget.

  8. Step 1: Define an Index Macro

    The index macro represents your widget's place in the hierarchy. The index macro is defined in the widget private header file. Use the following syntax to define the index macro:

    #define YourWidgetNameIndex (SuperclassIndexMacro + 1)

    For example, XmPrimitive is the superclass of ExmSimple. The SuperclassIndexMacro associated with XmPrimitive is called XmPrimitiveIndex. Therefore, the index macro of ExmSimple is defined as follows:

    #define ExmSimpleIndex (XmPrimitiveIndex + 1)

    Similarly, the index macro of ExmString is defined as follows:

    #define ExmStringIndex (ExmSimpleIndex + 1)

    Note that, although ExmTabButton is the only binary-compatible Exm widget, all the widgets that precede it in the widget hierarchy must define index macros.

    Step 2: Define XmField Access Macros

    To ensure binary compatibility, your widget source code file must define an XmField access macro for each field that your source code file accesses. In this context, a "field" means a member of a widget instance record in any subclass of XmPrimitive and XmManager. For example, ExmTabButton access the following three members of widget instance records of subclasses of XmPrimitive:

    1. tab_button.open_side (from ExmTabButton)

    2. tab_button.draw_bevel (from ExmTabButton)

    3. command_button.visual_armed (from ExmCommandButton)

      Therefore, the source code file of ExmTabButton contains the following 5 macro definitions:

      #define OpenSide(w)
          XmField(w, offsets, ExmTabButton, open_side, XtEnum)
      #define JoinShadowThickness(w)
          XmField(w, offsets, ExmTabButton, join_shadow_thickness, Dimension)
      #define VisualArmed(w)
          XmField(w, offsets, ExmCommandButton, visual_armed, Boolean)
      #define SimpleShape(w)
          XmField(w, offsets, ExmSimple, simple_shape, unsigned char)
      #define NeedToReconfigure(w)
          XmField(w, offsets, ExmSimple, need_to_reconfigure,
      Boolean)

    4. Step 3: Declare Resources Properly

      To ensure binary compatibility, you must define the resources array as an array of XmPartResource instead of an array of XtResource. In addition, the fifth field of each resource record should access offsets through the XmPartOffset macro instead of the XtOffsetOf macro.

      For example, following is the resources array of ExmTabButton:

      static XmPartResource resources[] = {
          {
           ExmNopenSide,
           ExmCOpenSide,
           ExmROpenSide,
           sizeof (XtEnum),
           XmPartOffset (ExmTabButton, open_side),
           XmRImmediate,
           (XtPointer) XmLEFT
         },
      };

      Step 4: Set version to XtVersionDontCheck

      To ensure binary compatibility, you must set the version field of the CoreClassPart to XtVersionDontCheck instead of XtVersion. For example, the CoreClassPart of ExmTabButton contains the following version field:

      /* version */                XtVersionDontCheck,

      Step 5: Declare an XmOffsetPtr Variable

      For binary compatibility, a widget must declare an XmOffsetPtr variable. By convention, the XmOffsetPtr is declared immediately following the declaration of trait record variables in the widget source code file.

      For example, following is the declaration of the XmOffsetPtr variable that appears in ExmTabButton:

      /* Part Offset table for XmResolvePartOffsets */
      static XmOffsetPtr offsets;

      Step 6: Call XmeResolvePartOffsets

      Your widget must call XmeResolvePartOffsets prior to the first time that an XmField macro (defined in Step 2) is used in a widget method. In other words, in order for an XmField macro to work properly, XmeResolvePartOffsets must already have been called.

      For example, following is the call to XmeResolvePartOffsets that appears in the ClassInitialize method of ExmTabButton:

      XmeResolvePartOffsets(exmTabButtonWidgetClass, &offsets,
      NULL);

      Step 7: Access Fields Through Macros

      Instead of using any fields from widget instance parts directly, you must access them through the XmField access macros you created back in Step 2.

      For example, the Initialize method of ExmStringTransfer accesses the draw_bevel field as follows:

      DrawBevel(new) = False;  /* right */

      rather than as follows:

      nw->tab_button.draw_bevel = False;  /* wrong */

      The latter way of accessing draw_bevel is adequate for creating a working widget but does not create a binary-compatible widget.


      [ Previous | Next | Contents | Glossary | Home | Search ]