The widget private header file serves the same purpose in Motif that it does for all Intrinsics-based widgets. Follow these steps to create a private header file that is compatible with other Motif widgets:
The following subsections detail these steps by examining the private header file for the ExmSimple widget. This file is stored online in the demos/widgets/Exm/lib directory at pathname SimpleP.h.
You must encase the contents of the file inside a conditional compilation directive, as follows:
#ifndef _ExmSimpleP_h #define _ExmSimpleP_h ... #endif /* _ExmSimpleP_h */
These lines prevent compiler errors by ensuring that the code inside the file will only be included once per compilation.
You must include the following two header files:
For example, the ExmSimple widget derives from the XmPrimitive class. Therefore, the widget private header file of ExmSimple includes the following two files:
#include <ExmSimple.h> #include <Xm/PrimitiveP.h>
You should encase the remaining code of the file inside the following pair of conditional compilation directives:
#ifdef __cplusplus extern "C" { #endif ... #ifdef __cplusplus } /* Close scope of 'extern "C"' declaration which encloses file. */ #endif
If the application program using your widget is written in C++, then allowing for C++ compilation is mandatory. Otherwise, allowing for C++ compilation is merely a good idea.
You must define inheritance class method macros. Once defined, your widget's subclasses can inherit your widget's methods simply by specifying the inheritance macro in the appropriate field of the class record. For example, the ExmSimple widget creates the following eight inheritance macros:
#define ExmInheritDrawVisual ((XtWidgetProc) _XtInherit) #define ExmInheritDrawShadow ((XtWidgetProc) _XtInherit) #define ExmInheritCreateGC ((XtWidgetProc) _XtInherit) #define ExmInheritDestroyGC ((XtWidgetProc) _XtInherit) #define ExmInheritSelectGC ((ExmSelectGCProc) _XtInherit) #define ExmInheritCalcVisualSize ((XtWidgetProc) _XtInherit) #define ExmInheritCalcWidgetSize ((XtWidgetProc) _XtInherit) #define ExmInheritReconfigure ((ExmReconfigureProc) _XtInherit)
If an inheritance macro requires a new data type definition, you must provide it here. For example, ExmInheritSelectGC and ExmInheritReconfigure both require new data type definitions, as follows:
typedef GC (*ExmSelectGCProc)( Widget); typedef void (*ExmReconfigureProc)( WidgetClass, Widget, Widget) ;
The inheritance macros should follow Motif naming conventions. The inheritance macro names should begin with the widget set prefix (in this case, Exm) followed by the word Inherit. Similarly, the new data type definitions should begin with the widget set prefix and end with Proc.
The widget class part defines the inheritable methods and data members of the widget. For example, following is the widget class part of the ExmSimple widget:
typedef struct _ExmSimpleClassPart { XtWidgetProc draw_visual; XtWidgetProc draw_shadow; XtWidgetProc create_gc; XtWidgetProc destroy_gc; ExmSelectGCProc select_gc; XtWidgetProc calc_visual_size; XtWidgetProc calc_widget_size; ExmReconfigureProc reconfigure; XtPointer extension; } ExmSimpleClassPart;
Motif strongly recommends specifying an extension field as the last field of every widget class part. Providing an extension field helps implement binary compatibility if you add methods to the widget in future releases. The extension field should have the XtPointer data type.
You must define the widget's full class record. This structure specifies the class parts of all widget classes in the current widget's hierarchy. The first field in the full class record specifies the class part of the top widget in the hierarchy (Core). The next field specifies the class part of the widget below the top widget, and so on. The final field specifies the class part of the current widget.
For example, the ExmSimple widget derives from Core and XmPrimitive. Therefore, the class record structure of ExmSimple is as follows:
typedef struct _ExmSimpleClassRec { CoreClassPart core_class; XmPrimitiveClassPart primitive_class; ExmSimpleClassPart simple_class; } ExmSimpleClassRec;
There are a few conventions that you should follow in the full class record:
After defining the data type, you must now declare an externalref variable having this data type; for example:
externalref ExmSimpleClassRec exmSimpleClassRec;
By convention, the variable has the same name as the data type except that the first character of the variable is always lowercase.
All manager widgets derive from Core, Composite, Constraint, and XmManager. Therefore, the class record structure of the sample manager widget ExmGrid is the following:
typedef struct _ExmGridClassRec { CoreClassPart core_class; CompositeClassPart composite_class; ConstraintClassPart constraint_class; XmManagerClassPart manager_class; ExmGridClassPart grid_class; } ExmGridClassRec; externalref ExmGridClassRec exmGridClassRec;
Your private header file typically declares a widget instance record. The widget instance record describes the inheritable data members of your widget. The inheritable data members consist of your widget's resources plus those variables that subclasses may need access to. For example, following is the widget instance record for the ExmSimple widget:
typedef struct _ExmSimplePart { unsigned char simple_shape; Dimension margin_height; Dimension margin_width; GC normal_gc; GC insensitive_gc; Dimension pref_width; Dimension pref_height; Boolean need_to_compute_width; Boolean need_to_compute_height; XRectangle visual; Boolean need_to_reconfigure; Pixel saved_foreground; } ExmSimplePart;
By convention, the top fields in the widget instance part are declarations of the widget's resources. The ExmSimple widget declares three new resources, so the widget instance part declares them in the top three fields.
The fields below the resource fields declare variables that are accessible to subclasses of ExmSimple. For example, the ExmString widget is a subclass of ExmSimple, so any function in ExmString can access any of these variables. Conversely, a widget that is not a subclass of ExmSimple should not access any of these variables.
You must declare a full instance record for your widget private header file. The full instance record of ExmSimple appears as follows:
typedef struct _ExmSimpleRec { CorePart core; XmPrimitivePart primitive; ExmSimplePart simple; } ExmSimpleRec;
All Motif manager widgets derive from Core, Composite, Constraint, and XmManager. Therefore, the full instance record of the ExmGrid sample manager widget is as follows:
typedef struct _ExmGridRec { CorePart core; CompositePart composite; ConstraintPart constraint; XmManagerPart manager; ExmGridPart grid; } ExmGridRec;
Note: | If you are writing a primitive widget, you can skip this section. |
If you are writing a manager widget, you should always define the following two structures:
You should define these structures even if the widget does not currently support any constraint resources. Declaring these constraint structures now will prevent source compatibility problems if a future subclass wants to provide constraint resources.
The following subsections detail the two constraint structures.
The constraint part structure defines the constraints themselves, one constraint per field. For example, the ExmGrid widget defines two constraints, so its constraint part structure is as follows:
typedef struct _ExmGridConstraintPart { Dimension grid_margin_width_within_cell; Dimension grid_margin_height_within_cell; } ExmGridConstraintPart, * ExmGridConstraint;
You should follow these conventions:
The full constraint structure specifies the widgets in the current widget hierarchy that define constraints. The last field in the structure specifies the current widget (assuming it defines constraints). For example, the ExmGrid widget defines the following full constraint structure:
typedef struct _ExmGridConstraintRec { XmManagerConstraintPart manager; ExmGridConstraintPart grid; } ExmGridConstraintRec, *ExmGridConstraintPtr;
You may be wondering why we specified XmManagerConstraintPart as one of the fields. After all, the XmManager widget does not currently have any constraints. However, in order to allow for the future possibility of constraints in XmManager, the XmManager widget defines a constraint part structure. The first field of your full constraint structure should always contain XmManagerConstraintPart.
If you are writing a manager widget that provides constraints, your private header file should define a constraint access macro. The constraint access macro should be named widget_nameCPart. For example, the ExmGrid widget defines a macro named ExmGridCPart. Here is its definition:
#define ExmGridCPart(w) \ (&((ExmGridConstraintPtr) (w)->core.constraints)->grid)
In the course of writing your own widgets, you can create convenience functions that could help other widget writers (or perhaps yourself when writing a subsequent widget). Prototypes for these convenience functions must appear in the widget private header file.
Think about it this way. If you want a function to be accessible to application programmers, define it in the widget public header file. If you want a function to be inaccessible to application programmers, define it in the widget private header file.