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



The Widget Source Code File

The most time consuming portion of writing a widget is, of course, writing the widget source code file itself. The steps for creating a widget source code file are as follows:

  1. Include the appropriate header files.

  2. Define any macros that your widget may need. However, if a subclass might need a macro, define it in the widget private header file instead of the widget source code file.

  3. Declare all the widget methods as static functions.

  4. Define the widget's translations string and its actions table.

  5. Declare the widget's resources.

  6. Declare the widget class record.

  7. Provide external definitions of the widget class record and the widget class.

  8. Declare any static variables needed throughout the widget.

  9. Declare any trait record variables.

  10. Provide the code for all the widget methods.

    The Simple.c file is an example of a widget source code file. The following subsections examine selected portions of this file.

  11. Step 1: Include the Appropriate Header Files

    The typical widget source code file begins by including several header files. The order of inclusion is important. You should include

    1. Any operating system or C header files first

    2. Any Xlib or Xt header files next

    3. Your widget's private header file (required)

    4. Any Motif header files

      For example, the widget source code file for the ExmSimple widget does not specify any operating system, C, Xlib, or Xt header files. (Actually, a lot of these header files will be automatically included by Motif header files.) Simple.c does require its private header file (SimpleP.h). Simple.c also needs a bunch of other Motif header files in order for Xme calls and traits to work properly. The entire collection of header files included in Simple.c is as follows:

      #include <Exm/SimpleP.h>    /* widget private header file for
      ExmSimple */
      #include <Xm/DrawP.h>       /* for Xme drawing functions */
      #include <Xm/RepType.h>     /* for representation type facility */
      #include <Xm/Screen.h>      /* for screen information */
      #include <Xm/TraitP.h>      /* for installing traits */
      #include <Xm/CareVisualT.h> /* for XmQTcareParentVisual trait */
      #include <Xm/ContItemT.h>   /* for XmQTcontainerItem trait */
      #include <Xm/ContainerT.h>  /* for XmQTcontainer trait */

      Table 2-1 lists some of the files that are more commonly used by widget writers.

      Table 2. Helpful Header Files For Motif Widget Writers

      File Contains:
      DrawP.h Definitions for Motif-style internal drawing functions
      RepTypeP.h Definitions for representation type facility
      TraitP.h Definitions for trait installation and access routines
      XmP.h Widget private header file for XmPrimitive widget; definitions for many Motif macros and constants; definitions to support XmPartOffset binary compatibility; definitions of many data types used by Motif widgets; definitions of many enumerated constants used by Motif widgets
      Xm.h Typedefs for callback structures and representation types; this file includes XmP.h
      XmStrDefs.h String definitions for all Motif XmN, XmC, and XmR data types; this file includes Xm.h

    5. Step 2 (Optional): Define Your Macros

      After specifying header files, you can optionally define any macros useful to your widget. Motif makes the following stylistic suggestions regarding your macros:

      1. Try to avoid duplicating macros that Motif already defines. The Motif header file Xm/XmP.h defines several macros that your widget can access. The wise widget writer always looks at this file prior to creating a new macro. Some of these macros (such as XtWidth) are required for any Intrinsics-based widget set. Other macros (like XmLOOK_AT_BACKGROUND) are specific to Motif. All Motif-specific macros begin with the Xm prefix.

      2. Format the code for long macros as you would format the code for a function. In other words, make the macro easy to understand.

      3. Comment your macros.

      4. Place all macros in this section, even if the macro is only used in one function. (In other words, do not define local macros.)

      5. Step 3: Declare All static Functions

        You should declare all static functions.

        We recommend that you use ANSI C style function prototypes when declaring functions.

        You should name class methods after their class record field names. For example, if the class record field name is class_initialize, then the class method should be named ClassInitialize. The class method name differs from the class record field name in only two respects:

        1. The class method name should not contain any underscores.

        2. The first letter of every word in the class method name should be uppercase.

          There is only one exception to these naming rules and it concerns the class record field named expose. The preceding conventions suggest that you should name the associated class method Expose. Unfortunately, Xlib already defines a macro named Expose. Therefore, by convention, you should name this class method Redisplay instead of Expose.

          By convention, you should declare the functions in the following order:

          1. If your widget defines any XmRCallProc resources, then declare the dynamic resource defaulting methods first.

          2. If your widget defines any synthetic resources, declare the synthetic resource methods next.

          3. Declare all your class methods in superclass-to-subclass order. For example, when writing a primitive widget you declare any class methods from Core first, from XmPrimitive second, and from your own widget third.

          4. Declare any trait methods last.

          5. Step 4: Define Translations and Actions

            Chapter 7 details Motif translations and actions. Motif makes the following stylistic demands on widget writers:

            1. You should give the translations string a name ending with Translations. For example, defaultTranslations is a good name.

            2. You should use the name actions for the XtActionsRec array.

            3. You should list exactly one action per line.

            4. You should not declare the actions array as a constant.

            5. Step 5: Declare Resources

              Chapter 6 details resources. For now, you should be aware of the following Motif resource naming conventions:

              1. The resource structure should be named resources.

              2. The synthetic resource structure should be named syn_resources.

              3. The constraint resource structure should be named constraint_resources.

              4. The constraint synthetic resource structure should be named syn_constraint_resources.

              5. You should not declare the resources array or the syn_resources array as a constant.

                The fifth field of each resource structure defines an offset. If you want to create a widget that will be a binary compatible with future releases, then you should use the XmPartOffset macro to define the offset. (See Chapter 15 for details on binary compatibility.) If binary compatibility is not a goal, then you should use the XmPartOffset macro to define the offset.

              6. Step 6: Declare the Class Record

                The widget class record is your widget's table of contents. Chapter 3 details the class record for Motif primitive widgets; Chapter 4 details the class record for Motif manager widgets. For now, you should concentrate on a few stylistic points.

                Make sure that all fields in the class record are commented with the formal names of the fields. For the portions of the class record defined by the Intrinsics, refer to Intrinsics documentation to find the formal names. For the portions of the class record defined by Motif, refer to Chapters 3 and 4. For example, the following excerpt from ExmSimple shows the proper way to comment the fields:

                ...
                /* class_part_initialize */      ClassPartInitialize,
                /* class_inited */               FALSE,
                /* initialize */                 Initialize,
                /* initialize_hook */            NULL,
                /* realize */                    XtInheritRealize,

                Motif recommends that the last field of every Motif class record be an extension field. An extension field must contain one of the following:

                1. The name of a class extension record

                2. NULL, to indicate the absence of a class extension record

                  Motif and the Intrinsics provide the following class extension record data types:

                  1. XmBaseClassExtRec Motif strongly recommends that your widget not define this extension record.

                  2. CompositeClassExtensionRec This is an Xt extension record. (See documentation on the Intrinsics for details.)

                  3. XmPrimitiveClassExtRec This is a Motif extension record. (See Chapter 3 for details on its fields.) If you declare an XmPrimitiveClassExtRec variable in your widget, it should be named primClassExtRec.

                  4. XmManagerClassExtRec This is a Motif extension record. (See Chapter 4 for details on its fields.) If you declare a XmManagerClassExtRec variable in your widget, it should be named managerClassExtRec.

                    Motif strongly recommends that all class extension record variables be declared as static; for example:

                    static XmPrimitiveClassExtRec  primitiveClassExtRec = ...

                    You should not declare the class record as a constant.

                  5. Step 7: Provide the External Definitions

                    Your widget must provide an external definition of the widget class record and the widget class. For example, the external definition of the widget class record for the ExmSimple widget is as follows:

                    externaldef (exmsimpleclassrec) ExmSimpleClassRec exmSimpleClassRec
                    = {

                    and the external definition of the widget class pointer is as follows:

                    externaldef (exmsimplewidgetclass) WidgetClass exmSimpleWidgetClass
                    =
                                                                             (WidgetClass)
                    &exmSimpleClassRec;

                    Motif recommends using the externaldef macro instead of the extern keyword when declaring variables. The externaldef macro handles a few portability problems.

                    Step 8: Declare Any Static Variables

                    If your source code file requires any static (file scope) variables, declare them next. For instance, if your widget uses representation types, you will probably have to declare at least one static representation type variable. For example, the ExmSimple widget creates a new representation type. Therefore, it provides the following static variables:

                    /* The SimpleShapeNames variable holds some normalized values.
                       The XmRepTypeRegister function will use these values to determine the
                       legal values for a given representation type. */
                    static String SimpleShapeNames[] = {
                            "simple_oval",
                            "simple_rectangle"
                    };
                    /* Declare a representation type variable. */
                    static XmRepTypeId simpleShapeId;

                    Step 9: Declare Any Trait Record Variables

                    If your widget installs any traits, you should declare the trait record variable(s) here. (See Chapter 5 for details about traits. For example, the ExmString widget installs the XmQTaccessTextual trait, so it requires the following trait record variable declaration:

                    static XmConst XmAccessTextualTraitRec StringATT = {
                      0,                            /* version */
                      StringGetValue,
                      StringSetValue,
                      StringPreferredFormat,
                    };

                    Notice that the variable declaration contained the XmConst macro. If your C compiler supports the const keyword, then XmConst resolves to const. If your C compiler does not support the const keyword, then XmConst resolves to nothing.

                    Step 10: Write the Widget's Methods

                    The majority of code in most widget source code files is taken up by the code for the widget's methods. Place the widget's methods in the following order:

                    1. All static functions (in the order in which they were declared).

                    2. Any private global functions (in the order in which they were declared in the private header file).

                    3. Public functions (in the order in which they were declared in the public header file).

                      Table 2-2 lists all the methods of the Simple.c source code file in the order in which they appear in the file:

                      Table 3. Functions in ExmSimple

                      Method What the Method Does in ExmSimple:
                      ClassInitialize Creates a new representation type
                      ClassPartInitialize Establishes method inheritance
                      Initialize Validates resources, sets certain geometry management fields
                      Destroy Calls the DestroyGC method in response to the widget's destruction
                      Realize Creates the window for the widget
                      Resize Determines what parts of the widget will be reduced in size when there is not enough space to display everything
                      Redisplay Renders the widget after an Exposure event
                      SetValues Responds to changes in resource values
                      QueryGeometry Returns the preferred size of the widget
                      DrawVisual Draws the widget's visual (its filled arc or filled rectangle)
                      DrawShadow Draws a Motif-style shadow at the widget's outer edge
                      CreateGC Creates a sensitive GC and an insensitive GC
                      DestroyGC Deallocates the two GCs
                      SelectGC Picks one of the two GCs
                      CalcVisualSize Calculates the ideal size of the widget's visual
                      CalcWidgetSize Calculates the widget's ideal size
                      WidgetDisplayRect Determines the bounding box of the widget's visual
                      Reconfigure Orchestrates several aspects of geometry management
                      ContItemSetValues Sets new visual attributes on ExmSimple
                      ContItemGetValues Gets the values of the current visual attributes of ExmSimple
                      SetSelectedVisual Gets the select color of the parent
                      HandleRedraw Adjusts the select color under certain situations
                      ExmCreateSimple Instantiates an ExmSimple widget; accessible to applications

                      You should precede each widget method with a comment describing the purpose of the method. Following is a conventional Motif method comment:

                      /************************************************************************
                       *
                       *  ClassPartInitialize
                       *      Processes the class fields which need to be inherited.
                       *
                       
                      ************************************************************************/

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