/* $XConsortium: README /main/2 1996/07/15 14:04:15 drk $ */
This directory contains the sources of the Dog widget, the Square widget,
and the dogs demo.
DOG WIDGET
----------
The Dog widget demonstrates how to subclass a primitive widget which
will remain binary compatible with future versions of Motif. It uses
XmResolvePartOffsets(), and associated macros, and implements all
the recommendations in the XmResolvePartOffsets manpage.
The Dog widget is a subclass of XmPrimitive. It can bark and wag its
tail. If you want more exotic tricks - feel free to subclass it, or
replace up.bm, down.bm and bark.bm with more interesting bitmaps.
It has the following resources:
DogNwagTime - time in milliseconds between each wag.
DogNbarkTime - time in milliseconds the bark graphic is displayed.
DogNbarkCallback - callback called by the bark action.
It has the following translations:
osfActivate/Return/Space/MB1 = Bark
W/MB2 = Wag tail.
S/Shift-MB2 = Stop wagging tail.
osfHelp = Help
SQUARE WIDGET
-------------
The Square widget demonstrates how to subclass a constraint widget which
will remain binary compatible with future versions of Motif. It uses
XmResolveAllPartOffsets(), and associated macros, and implements all
the recommendations in the XmResolveAllPartOffsets manpage.
The Square Widget is a subclass of XmBulletinBoard. It forces its children
to be square using a constraint resource.
It has one resource:
SquareNmajorDimension - determines which dimension will be used
for the new size of the child. Values are
SquareWIDTH or SquareHEIGHT.
It has one constraint resource:
SquareNmakeSquare - determines whether the child is forced
to be square or set to its preferred size.
DOGS DEMO
---------
The dogs demo uses the Dog and Square widgets. It illustrates how
to incorporate new widgets into UIL source, using the user_defined
function.
It allows you to dynamically change the DogNwagTime and SquareNmakeSquare
resources.
If you have a machine with any sound generation features at all, you may
want to change the bark callback to something better than XBell().
ADDITIONAL INFORMATION ON THE MOTIF BINARY COMPATIBILITY MECHANISM
------------------------------------------------------------------
Why is it needed?:
Motif custom widget subclasses compiled against Motif 1.2 may
not be binary compatible with future major releases of Motif, and
will cause fatal errors when used. To fix the problem the widget will
need to be recompiled against the new version of Motif.
The incompatibility will occur because a subclass must contain
compiled-in references to its instance fields which will be
specified relative to the start address of the widget instance.
When a new Motif library is installed in which the widget's
superclass instance structures have been extended, the compiled-in
references will point to the wrong memory location, and general
chaos will ensue.
The solution:
Motif provides a solution to this problem in the form of a new
mechanism for defining resources and accessing widget fields.
The mechanism allows all references to fields in the instance and
constraint structures to be specified relative to the start of the
widget *part* structure instead of the overall widget structures
(which include the superclass part structures.) The mechanism resolves
these relative references at runtime when the widget class is
first initialized. This involves factoring in the true size of
the widget's superclass instance structures read from the currently-
linked Motif library.
Converting a Widget To Use The Motif Widget Binary Compatibility Mechanism
--------------------------------------------------------------------------
The guidelines for converting a widget to use the mechanism illustrate
each stage with examples from a hypothetical widget named 'XmpNew'.
The mechanism requires changes only to the widget's source file and
not to any public header file.
For additional information, see the Motif 1.2 man pages for
XmResolvePartOffsets() and XmResolveAllPartOffsets().
Edit your widget source file and proceed through the file, implementing
these guidelines:
1) Provide a clear indication that the widget uses the Motif widget
binary compatibility mechanism. The Motif changes are not part of the
standard Xt widget-writing specification, and may be confusing
to the future maintainers of the widget. Add the following comment
near the start of the file and tag each change in the file with
a brief comment:
/*
* The XmpNew widget is rigged with the Motif widget binary compatibility
* mechanism. All Motif-specific changes for this mechanism are preceded
* by a comment including the string "MotifBc".
*
* For a description of the Motif widget binary compatibility mechanism,
* see the reference manual entry on XmResolveAllPartOffsets().
*
*/
2) Define an index value for your class. The value should be one
greater than the predefined index for your widget's superclass:
For a subclass of XmPrimitive:
#define XmpNewIndex (XmPrimitiveIndex + 1)
For a subclass of XmManager:
#define XmpNewIndex (XmManagerIndex + 1)
3) Define variables to hold the dynamic offset tables. They
should be statically defined, but global to the widget source
file:
static XmOffsetPtr ipot; /* Instance part offset table */
For subclasses of XmManager, you also need:
static XmOffsetPtr cpot; /* Constraint part offset table */
4) Define macros to provide access to your widget's fields:
For all widget instance fields:
#define MarginWidth(w) XmField(w,ipot,XmpNew,margin_width,Dimension)
For all widget constraint fields:
#define ChildType(w) \
XmConstraintField(w,cpot,XmpNew,child_type,unsigned char)
(The last parameter is the data type of the instance or constraint field.)
5) Modify the definition of all widget resources, synthetic resources,
constraint resources and synthetic constraint resources to use dynamic
offset calculation macros:
Change the type of widget resource lists and constraint resource
lists from:
XtResource foo[] = { };
to:
XmPartResource foo[] = { };
Change all widget resource and synthetic resource offset entries from:
XtOffsetOf( struct _XmpNewRec, new.margin_width)
to:
XmPartOffset(XmpNew,margin_width)
Change all widget constraint resource and synthetic constraint resource
offset entries from:
XtOffsetOf( struct _XmpNewConstraintRec, new.child_type),
to:
XmConstraintPartOffset(XmpNew,child_type)
6) In the widget class record change the widget 'size' and 'constraint_size'
fields to be the size of the widget part structure, not the size
of the entire widget structure:
Change the Core class 'size' field from:
sizeof(XmpNewWidgetRec) /* widget size */
to:
sizeof(XmpNewWidgetPart), /* widget size */
Change the Constraint class 'constraint_size' field from:
sizeof(XmpNewConstraintRec), /* constraint_size */
to:
sizeof(XmpNewConstraintPart), /* constraint_size */
7) Change the Core class 'version' field to disable version checking:
XtVersion, /* version */
becomes:
XtVersionDontCheck /* version */
8) In the widget's ClassInitialize method, add the call which will
resolve the part-relative references:
For a subclass of XmPrimitive:
XmResolvePartOffsets(xmpNewWidgetClass, &ipot);
For a subclass of XmManager:
XmResolveAllPartOffsets(xmpNewWidgetClass, &ipot, &cpot);
9) Ensure that references to all instance and constraint fields in the
widget source use the macros defined in (4) above. There must be no direct
access to these fields.
Superclass instance and constraint fields can still be accessed normally,
however, to keep the widget source readable and consistent it is
recommended that macros are also defined and used for those fields. e.g
#define Width(w) ((w)->core.width)
#define NumChildren(w) ((w)->composite.num_children)
#define ShadowThickness(w) ((w)->manager.shadow_thickness)
10) Test the results. The easiest way to do this is go to the lib/Xm
directory, add some new fields to PrimitiveP.h and ManagerP.h, and rebuild
the libXm library. Test your widget with this new library (without
recompiling the widget source!)
----- End Included Message -----