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:
The Simple.c file is an example of a widget source code file. The following subsections examine selected portions of this file.
The typical widget source code file begins by including several header files. The order of inclusion is important. You should include
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 |
After specifying header files, you can optionally define any macros useful to your widget. Motif makes the following stylistic suggestions regarding your macros:
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.
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:
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:
Chapter 7 details Motif translations and actions. Motif makes the following stylistic demands on widget writers:
Chapter 6 details resources. For now, you should be aware of the following Motif resource naming conventions:
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.
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:
Motif and the Intrinsics provide the following class extension record data types:
XmBaseClassExtRec Motif strongly recommends that your widget not define this extension record.
CompositeClassExtensionRec This is an Xt extension record. (See documentation on the Intrinsics for details.)
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.
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.
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.
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;
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.
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:
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. * ************************************************************************/